From ca290c7b1b29146cf3fd8784345385f4a1c9b122 Mon Sep 17 00:00:00 2001 From: phonktown Date: Tue, 4 Aug 2026 16:17:54 +0300 Subject: [PATCH] feat(Tests): adjust tests --- .../workflows/stonks_integration_tests.yml | 5 +- configs/config_mainnet.py | 1 + interfaces/Stonks.json | 1169 +++++++++++++++++ scripts/upgrade_2026_08_05.py | 2 +- tests/acceptance/test_locator.py | 8 + tests/test_2026_08_05.py | 70 +- utils/config.py | 4 + 7 files changed, 1252 insertions(+), 7 deletions(-) create mode 100644 interfaces/Stonks.json diff --git a/.github/workflows/stonks_integration_tests.yml b/.github/workflows/stonks_integration_tests.yml index 48d17e1c..e6a83d7a 100644 --- a/.github/workflows/stonks_integration_tests.yml +++ b/.github/workflows/stonks_integration_tests.yml @@ -7,9 +7,8 @@ on: workflow_dispatch: env: - # Stonks branch carrying the NEST V2 integration tests. - # TODO: switch to `main/master` once the tests land there. - STONKS_REF: feature/dao-898-nest-v2-develop-the-protocol + # Stonks branch the NEST V2 integration tests are run from. + STONKS_REF: main jobs: run-tests: diff --git a/configs/config_mainnet.py b/configs/config_mainnet.py index 3e4869b7..04c18e75 100644 --- a/configs/config_mainnet.py +++ b/configs/config_mainnet.py @@ -664,6 +664,7 @@ OPERATOR_GRID = "0xC69685E89Cefc327b43B7234AC646451B27c544d" LAZY_ORACLE = "0x5DB427080200c235F2Ae8Cd17A7be87921f7AD6c" PREDEPOSIT_GUARANTEE = "0xF4bF42c6D6A0E38825785048124DBAD6c9eaaac3" +VAULT_FACTORY = "0x02Ca7772FF14a9F6c1a08aF385aA96bb1b34175A" VAULTS_ADAPTER = "0x28F9Ac198C4E0FA6A9Ad2c2f97CB38F1A3120f27" GATE_SEAL_V3 = "0x881dAd714679A6FeaA636446A0499101375A365c" STAKING_VAULT_BEACON = "0x5FbE8cEf9CCc56ad245736D3C5bAf82ad54Ca789" diff --git a/interfaces/Stonks.json b/interfaces/Stonks.json new file mode 100644 index 00000000..aa240e5a --- /dev/null +++ b/interfaces/Stonks.json @@ -0,0 +1,1169 @@ +[ + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "admin", + "type": "address" + }, + { + "internalType": "address", + "name": "agent", + "type": "address" + }, + { + "internalType": "address", + "name": "manager", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenFrom", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenTo", + "type": "address" + }, + { + "internalType": "address", + "name": "amountConverter", + "type": "address" + }, + { + "internalType": "address", + "name": "orderSample", + "type": "address" + }, + { + "internalType": "uint256", + "name": "orderDurationInSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "marginInBasisPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceToleranceInBasisPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxImprovementInBasisPoints", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "allowPartialFill", + "type": "bool" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "internalType": "struct Stonks.InitParams", + "name": "initParams_", + "type": "tuple" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "admin", + "type": "address" + } + ], + "name": "InvalidAdminAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "agent", + "type": "address" + } + ], + "name": "InvalidAgentAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "InvalidAmount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "amountConverter", + "type": "address" + } + ], + "name": "InvalidAmountConverterAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "received", + "type": "uint256" + } + ], + "name": "InvalidOrderDuration", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "orderSample", + "type": "address" + } + ], + "name": "InvalidOrderSampleAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenFrom", + "type": "address" + } + ], + "name": "InvalidTokenFromAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenTo", + "type": "address" + } + ], + "name": "InvalidTokenToAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "received", + "type": "uint256" + } + ], + "name": "MarginOverflowsAllowedLimit", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "received", + "type": "uint256" + } + ], + "name": "MaxImprovementOverflowsAllowedLimit", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "received", + "type": "uint256" + } + ], + "name": "MinimumPossibleBalanceNotMet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "NotAdmin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "NotAdminOrManager", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "NotEmergencyOperator", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "received", + "type": "uint256" + } + ], + "name": "PriceToleranceOverflowsAllowedLimit", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "available", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requested", + "type": "uint256" + } + ], + "name": "SellAmountExceedsBalance", + "type": "error" + }, + { + "inputs": [], + "name": "StonksKilled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "TokenFromNotSupported", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "TokenToNotSupported", + "type": "error" + }, + { + "inputs": [], + "name": "TokensCannotBeSame", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "admin", + "type": "address" + } + ], + "name": "AdminSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "allowPartialFill", + "type": "bool" + } + ], + "name": "AllowPartialFillSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "amountConverter", + "type": "address" + } + ], + "name": "AmountConverterSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ERC1155Recovered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ERC20Recovered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "ERC721Recovered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "emergencyOperator", + "type": "address" + } + ], + "name": "EmergencyOperatorSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "EtherRecovered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "by", + "type": "address" + } + ], + "name": "KillEngaged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "ManagerSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "marginInBasisPoints", + "type": "uint256" + } + ], + "name": "MarginInBasisPointsSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "maxImprovementInBasisPoints", + "type": "uint256" + } + ], + "name": "MaxImprovementInBasisPointsSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "orderContract", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" + } + ], + "name": "OrderContractCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "orderDurationInSeconds", + "type": "uint256" + } + ], + "name": "OrderDurationInSecondsSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "orderSample", + "type": "address" + } + ], + "name": "OrderSampleSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "priceToleranceInBasisPoints", + "type": "uint256" + } + ], + "name": "PriceToleranceInBasisPointsSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ReceiverSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "by", + "type": "address" + } + ], + "name": "SignaturesPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "by", + "type": "address" + } + ], + "name": "SignaturesUnpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "tokenFrom", + "type": "address" + } + ], + "name": "TokenFromSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "tokenTo", + "type": "address" + } + ], + "name": "TokenToSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "ADMIN", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "AGENT", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ALLOW_PARTIAL_FILL", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "AMOUNT_CONVERTER", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MARGIN_DIFFERENCE_IN_BASIS_POINTS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MARGIN_IN_BASIS_POINTS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_IMPROVEMENT_IN_BASIS_POINTS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ORDER_DURATION_IN_SECONDS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ORDER_SAMPLE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PRICE_TOLERANCE_IN_BASIS_POINTS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RECEIVER", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TOKEN_FROM", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TOKEN_TO", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "areSignaturesPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "emergencyOperator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + } + ], + "name": "estimateTradeOutput", + "outputs": [ + { + "internalType": "uint256", + "name": "estimatedTradeOutput", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "estimateTradeOutputFromCurrentBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMaxImprovementBps", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOrderParameters", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPriceTolerance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isCreationPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isKilled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "killSwitch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "manager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pauseCreation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pauseSignatures", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "minBuyAmount_", + "type": "uint256" + } + ], + "name": "placeOrder", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sellAmount_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minBuyAmount_", + "type": "uint256" + } + ], + "name": "placeOrderWithAmount", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId_", + "type": "uint256" + } + ], + "name": "recoverERC1155", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + } + ], + "name": "recoverERC20", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId_", + "type": "uint256" + } + ], + "name": "recoverERC721", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "recoverEther", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "emergencyOperator_", + "type": "address" + } + ], + "name": "setEmergencyOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "manager_", + "type": "address" + } + ], + "name": "setManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpauseCreation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpauseSignatures", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/scripts/upgrade_2026_08_05.py b/scripts/upgrade_2026_08_05.py index 67b25441..dcfb1f4f 100644 --- a/scripts/upgrade_2026_08_05.py +++ b/scripts/upgrade_2026_08_05.py @@ -91,7 +91,7 @@ # NEST Activation, LOL stablecoins ET Payment Factories Activation, CSM Update Share Limits ET Factory Replacement 1. **Launch NEST (Automated LDO Buyback and Liquidity Provisioning)** in [treasury-only mode](https://research.lido.fi/t/liquid-buybacks-nest-execution-with-ldo-wsteth-liquidity/10894/109#p-25979-h-3-launch-mode-treasury-only-5), with all purchased LDO sent directly to the DAO Treasury. Under the [DAO-approved](https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x022e901a6368573d18b150eecda563dd2ee17ad2aa6a0ef9772151cc7ba55187) cumulative surplus model described in [LIP-36](https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-36.md#surplus-mechanics), NEST converts a fixed portion of staking revenue above the operating baseline into LDO via CoW Swap. Audit & deployment verification: [Ack3](https://github.com/lidofinance/audits/blob/main/Ack3%20Lido%20NEST%20Audit%20Report%2007-2026.pdf). Items 1.1 - 1.4, 2 - 9. 2. **Add LOL stablecoins Easy Track factories for payments and adding/removing allowed recipients**, with a limit of $8M per 6 months, [as per Snapshot decision](https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x863859d857c7429a0dcb85a4b324de803e2f66ddd8f50e4c2f04a31c35c6ae6f). Items 1.5, 1.6, 12 - 14. -3. **Replace CSM Update Share Limits Easy Track factory** to correct the per-motion change cap to 0.5%, [as proposed on the forum](https://research.lido.fi/t/community-staking-module/5917/231). Items 10, 11. +3. **Replace CSM Update Share Limits Easy Track factory** to correct the per-motion change cap to 0.5%, [as proposed on the forum](https://research.lido.fi/t/community-staking-module/5917/231). Audit & deployment verification: [MixBytes](https://github.com/lidofinance/audits/blob/main/MixBytes%20Lido%20Easy%20Track%20Factories%20(SRv3%20CSMv3%20CMv2)%20Security%20Audit%20Report%2007-2026.pdf). Items 10, 11. """ diff --git a/tests/acceptance/test_locator.py b/tests/acceptance/test_locator.py index 1c678255..f0e01273 100644 --- a/tests/acceptance/test_locator.py +++ b/tests/acceptance/test_locator.py @@ -32,6 +32,14 @@ def test_addresses(contract): assert contract.topUpGateway() == contracts.top_up_gateway assert contract.consolidationGateway() == contracts.consolidation_gateway assert contract.triggerableWithdrawalsGateway() == contracts.triggerable_withdrawals_gateway + assert contract.wstETH() == contracts.wsteth + assert contract.validatorExitDelayVerifier() == contracts.validator_exit_verifier + assert contract.accounting() == contracts.accounting + assert contract.vaultHub() == contracts.vault_hub + assert contract.vaultFactory() == contracts.vault_factory + assert contract.predepositGuarantee() == contracts.predeposit_guarantee + assert contract.operatorGrid() == contracts.operator_grid + assert contract.lazyOracle() == contracts.lazy_oracle assert contract.coreComponents() == ( contracts.execution_layer_rewards_vault, diff --git a/tests/test_2026_08_05.py b/tests/test_2026_08_05.py index 2d32d049..1bbaf588 100644 --- a/tests/test_2026_08_05.py +++ b/tests/test_2026_08_05.py @@ -126,6 +126,26 @@ ONE_DAY = 86400 +# --- NEST launch parameters the omnibus relies on but does not set itself --- +# BuybackExecutor order bounds +BUYBACK_MIN_ALLOWED_ORDER_AMOUNT = ETH(1) +BUYBACK_MAX_ALLOWED_ORDER_AMOUNT = ETH(20) +# BuybackAllocator spending caps +BUYBACK_DAILY_CAP_USD = 50_000 * 10**18 +BUYBACK_YEARLY_CAP_USD = 10_000_000 * 10**18 +BUYBACK_MIN_SPEND_PER_CALL_USD = 1_000 * 10**18 +BUYBACK_MIN_STETH_PRICE_USD = 0 # no price floor +BUYBACK_RESERVE_DAILY_RATE_USD = 109_589 * 10**18 # the LIP-36 operating baseline, ~$40M per year +BUYBACK_SURPLUS_SHARE_BP = 5_000 # 50% of the surplus above the baseline + +# --- treasury-mode Stonks 0xb368586CB980895E51e1D82102E63b3F69d3F151 --- +STONKS_ORDER_DURATION_SECONDS = 1_800 # 30 minutes +STONKS_MARGIN_BP = 110 +STONKS_PRICE_TOLERANCE_BP = 550 +STONKS_MAX_IMPROVEMENT_BP = 1_000 +STONKS_ORDER_SAMPLE = "0x2569633AdB492ca9327cb7433277aa7c68D69e28" +STONKS_AMOUNT_CONVERTER = "0x70dA04C5D0f325F5AF1426dE6672BF2424B4593d" + # --- NEST buyback scenario params --- QUOTE_DENOMINATION_ETH = 1 TOTAL_BASIS_POINTS = 10_000 @@ -162,7 +182,7 @@ EXPECTED_DG_EVENTS_FROM_AGENT = 6 EXPECTED_DG_EVENTS_COUNT = 1 -IPFS_DESCRIPTION_HASH = "bafkreiea5mkaprjkxfsxjv7vp6aireshqbvpy3iy5tcvwwhopujv6p25cy" +IPFS_DESCRIPTION_HASH = "bafkreiefjrubwk5hhikhc3s7wkivju3xpwzfanr5enljzimvxgrrmp6m7a" # ============================================================================ @@ -184,10 +204,11 @@ def validate_manager_set_event(event: EventDict, manager: str, emitted_by: str) _assert_emitted_by(e, emitted_by) -def validate_stonks_set_event(event: EventDict, new_stonks: str, emitted_by: str) -> None: +def validate_stonks_set_event(event: EventDict, new_stonks: str, lp_mode_enabled: bool, emitted_by: str) -> None: validate_events_chain([e.name for e in event], ["LogScriptCall", "StonksAndOperatingModeSet"]) e = _single_event(event, "StonksAndOperatingModeSet") assert convert.to_address(e["newStonks"]) == convert.to_address(new_stonks), "Wrong stonks set" + assert e["newLpModeEnabled"] == lp_mode_enabled, "Wrong operating mode set" _assert_emitted_by(e, emitted_by) @@ -272,6 +293,7 @@ def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env, stranger, dual_g oracle_router = interface.OracleRouter(ORACLE_ROUTER) buyback_executor = interface.BuybackExecutor(BUYBACK_EXECUTOR) buyback_allocator = interface.BuybackAllocator(BUYBACK_ALLOCATOR) + buyback_stonks = interface.Stonks(BUYBACK_STONKS_TREASURY) new_token_rate_notifier = interface.TokenRateNotifierV2(NEW_TOKEN_RATE_NOTIFIER) old_token_rate_notifier = interface.TokenRateNotifier(OLD_TOKEN_RATE_NOTIFIER) lido_locator_proxy = interface.OssifiableProxy(LIDO_LOCATOR) @@ -327,6 +349,7 @@ def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env, stranger, dual_g assert oracle_router.manager() != TMC, "OracleRouter manager already set to TMC" # vote item 3 assert buyback_executor.stonks() == ZERO_ADDRESS, "BuybackExecutor stonks already set" + assert buyback_executor.stonksOrderDurationSeconds() == 0, "BuybackExecutor already cached an order duration" # vote item 4 assert not buyback_executor.hasRole(ALLOCATOR_ROLE, BUYBACK_ALLOCATOR) assert buyback_executor.getRoleMemberCount(ALLOCATOR_ROLE) == 0 @@ -344,6 +367,39 @@ def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env, stranger, dual_g assert buyback_allocator.getRoleMemberCount(MANAGER_ROLE) == 0 # vote item 9 assert buyback_allocator.activationTS() == 0, "BuybackAllocator already activated" + # vote items 3-9: the buyback caps and wiring the launch inherits from the deployment. + # LP-mode parameters are left out — this launch is treasury-only (see lpModeEnabled below). + assert buyback_executor.minAllowedOrderAmount() == BUYBACK_MIN_ALLOWED_ORDER_AMOUNT + assert buyback_executor.maxAllowedOrderAmount() == BUYBACK_MAX_ALLOWED_ORDER_AMOUNT + assert buyback_executor.STETH() == contracts.lido + assert buyback_executor.LDO() == contracts.ldo_token + assert buyback_executor.TREASURY() == AGENT + assert not buyback_executor.paused(), "BuybackExecutor is paused" + assert buyback_allocator.dailyCapUSD() == BUYBACK_DAILY_CAP_USD + assert buyback_allocator.yearlyCapUSD() == BUYBACK_YEARLY_CAP_USD + assert buyback_allocator.minSpendPerCallUSD() == BUYBACK_MIN_SPEND_PER_CALL_USD + assert buyback_allocator.minStEthPriceUSD() == BUYBACK_MIN_STETH_PRICE_USD + assert buyback_allocator.reserveDailyRateUSD() == BUYBACK_RESERVE_DAILY_RATE_USD + assert buyback_allocator.surplusShareBP() == BUYBACK_SURPLUS_SHARE_BP + assert buyback_allocator.executor() == BUYBACK_EXECUTOR + assert buyback_allocator.TREASURY() == AGENT + # vote item 3: the treasury-mode Stonks as deployed — trades stETH for LDO, sends the LDO + # and any recovered assets to the Treasury, and is driven by the executor + assert buyback_stonks.TOKEN_FROM() == contracts.lido + assert buyback_stonks.TOKEN_TO() == contracts.ldo_token + assert buyback_stonks.RECEIVER() == AGENT + assert buyback_stonks.AGENT() == AGENT + assert buyback_stonks.manager() == BUYBACK_EXECUTOR + assert buyback_stonks.ADMIN() == VOTING + assert buyback_stonks.ORDER_SAMPLE() == STONKS_ORDER_SAMPLE + assert buyback_stonks.AMOUNT_CONVERTER() == STONKS_AMOUNT_CONVERTER + assert buyback_stonks.ORDER_DURATION_IN_SECONDS() == STONKS_ORDER_DURATION_SECONDS + assert buyback_stonks.MARGIN_IN_BASIS_POINTS() == STONKS_MARGIN_BP + assert buyback_stonks.PRICE_TOLERANCE_IN_BASIS_POINTS() == STONKS_PRICE_TOLERANCE_BP + assert buyback_stonks.MAX_IMPROVEMENT_IN_BASIS_POINTS() == STONKS_MAX_IMPROVEMENT_BP + assert buyback_stonks.ALLOW_PARTIAL_FILL() + assert not buyback_stonks.isCreationPaused(), "treasury-mode Stonks order creation is paused" + assert not buyback_stonks.areSignaturesPaused(), "treasury-mode Stonks signatures are paused" # vote items 10-11 initial_factories = easy_track.getEVMScriptFactories() assert OLD_UPDATE_STAKING_MODULE_SHARE_LIMITS_FACTORY in initial_factories @@ -404,6 +460,12 @@ def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env, stranger, dual_g assert oracle_router.manager() == TMC, "OracleRouter manager not set to TMC" # vote item 3 assert buyback_executor.stonks() == BUYBACK_STONKS_TREASURY, "BuybackExecutor stonks not set" + # setStonks only accepts a Stonks whose RECEIVER is either the executor (LP mode) or the + # Treasury (treasury mode), so a false lpModeEnabled is what pins the LDO proceeds to the Treasury + assert not buyback_executor.lpModeEnabled(), "BuybackExecutor launched in LP mode" + assert ( + buyback_executor.stonksOrderDurationSeconds() == STONKS_ORDER_DURATION_SECONDS + ), "BuybackExecutor did not cache the Stonks order duration" # vote item 4 assert buyback_executor.hasRole(ALLOCATOR_ROLE, BUYBACK_ALLOCATOR), "ALLOCATOR_ROLE not granted to allocator" assert buyback_executor.getRoleMemberCount(ALLOCATOR_ROLE) == 1, "extra ALLOCATOR_ROLE holder on the executor" @@ -481,7 +543,9 @@ def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env, stranger, dual_g # vote item 2 validate_manager_set_event(vote_events[1], manager=TMC, emitted_by=ORACLE_ROUTER) # vote item 3 - validate_stonks_set_event(vote_events[2], new_stonks=BUYBACK_STONKS_TREASURY, emitted_by=BUYBACK_EXECUTOR) + validate_stonks_set_event( + vote_events[2], new_stonks=BUYBACK_STONKS_TREASURY, lp_mode_enabled=False, emitted_by=BUYBACK_EXECUTOR + ) # vote item 4 validate_grant_role_event( vote_events[3], role=ALLOCATOR_ROLE, grant_to=BUYBACK_ALLOCATOR, sender=VOTING, diff --git a/utils/config.py b/utils/config.py index cec055ad..6166fc8e 100644 --- a/utils/config.py +++ b/utils/config.py @@ -370,6 +370,10 @@ def lazy_oracle(self) -> interface.LazyOracle: def predeposit_guarantee(self) -> interface.PredepositGuarantee: return interface.PredepositGuarantee(PREDEPOSIT_GUARANTEE) + @property + def vault_factory(self) -> interface.VaultFactory: + return interface.VaultFactory(VAULT_FACTORY) + @property def staking_vault_beacon(self) -> interface.UpgradeableBeacon: return interface.UpgradeableBeacon(STAKING_VAULT_BEACON)