From 201eee2f4294409ab7f9dab92a75c3a8f8b00701 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 18 Dec 2025 19:25:33 -0500 Subject: [PATCH 01/23] check new guardians are subset of old guardians --- contracts/spells/4_2_0.sol | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 493f88426..6891ba2ea 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -372,7 +372,9 @@ contract Upgrade4_2_0 is Versioned { // Deploy new governance, preserving all values { - uint256 minDelay = TimelockController(payable(msg.sender)).getMinDelay(); + TimelockController oldTimelock = TimelockController(payable(msg.sender)); + + uint256 minDelay = oldTimelock.getMinDelay(); require(minDelay != 0, "US: 15"); // Deploy new timelock @@ -399,6 +401,7 @@ contract Upgrade4_2_0 is Versioned { _newTimelock.grantRole(EXECUTOR_ROLE, newGovernor); // Gov only executor for (uint256 i = 0; i < guardians.length; i++) { + require(oldTimelock.hasRole(CANCELLER_ROLE, guardians[i]), "US: 16.5"); _newTimelock.grantRole(CANCELLER_ROLE, guardians[i]); // Guardian can cancel } _newTimelock.revokeRole(TIMELOCK_ADMIN_ROLE, address(this)); // Revoke admin role From 921397e14b1915b226ade5a00a07814d1a7ae4cb Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 18 Dec 2025 19:25:43 -0500 Subject: [PATCH 02/23] remove unused TestError --- contracts/spells/4_2_0.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 6891ba2ea..51e976180 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -43,8 +43,6 @@ bytes32 constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE"); contract Upgrade4_2_0 is Versioned { using EnumerableSet for EnumerableSet.Bytes32Set; - error TestError(); - event NewGovernanceDeployed( IRToken indexed rToken, address indexed newGovernor, From 016bd8ab8ee30dd6ce2c30ee8f2a04c47bd6d29a Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 18 Dec 2025 19:37:34 -0500 Subject: [PATCH 03/23] revoke old timelock PAUSER/SHORT_FREEZER/LONG_FREEZER --- contracts/spells/4_2_0.sol | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 51e976180..ea98562eb 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -14,6 +14,10 @@ import "../p1/BasketHandler.sol"; import "../p1/Main.sol"; bytes32 constant MAIN_OWNER_ROLE = bytes32("OWNER"); +bytes32 constant PAUSER_ROLE = bytes32("PAUSER"); +bytes32 constant SHORT_FREEZER_ROLE = bytes32("SHORT_FREEZER"); +bytes32 constant LONG_FREEZER_ROLE = bytes32("LONG_FREEZER"); + bytes32 constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE"); bytes32 constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); bytes32 constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); @@ -440,11 +444,17 @@ contract Upgrade4_2_0 is Versioned { main.grantRole(MAIN_OWNER_ROLE, newTimelock); main.revokeRole(MAIN_OWNER_ROLE, msg.sender); + main.revokeRole(PAUSER_ROLE, msg.sender); + main.revokeRole(SHORT_FREEZER_ROLE, msg.sender); + main.revokeRole(LONG_FREEZER_ROLE, msg.sender); main.renounceRole(MAIN_OWNER_ROLE, address(this)); require( main.hasRole(MAIN_OWNER_ROLE, newTimelock) && !main.hasRole(MAIN_OWNER_ROLE, msg.sender) && + !main.hasRole(PAUSER_ROLE, msg.sender) && + !main.hasRole(SHORT_FREEZER_ROLE, msg.sender) && + !main.hasRole(LONG_FREEZER_ROLE, msg.sender) && !main.hasRole(MAIN_OWNER_ROLE, address(this)), "US: 20" ); From a949c079ed6146edad7b87d52557f144a527df8a Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 18 Dec 2025 19:39:07 -0500 Subject: [PATCH 04/23] switch to custom errors for contract size --- contracts/spells/4_2_0.sol | 59 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index ea98562eb..5c0a9ea3e 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -47,6 +47,8 @@ bytes32 constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE"); contract Upgrade4_2_0 is Versioned { using EnumerableSet for EnumerableSet.Bytes32Set; + error Err(uint256 index); + event NewGovernanceDeployed( IRToken indexed rToken, address indexed newGovernor, @@ -167,10 +169,7 @@ contract Upgrade4_2_0 is Versioned { constructor(bool _mainnet) { // we have to pass-in `_mainnet` because chainid is not reliable during testing - require( - block.chainid == 1 || block.chainid == 31337 || block.chainid == 8453, - "unsupported chain" - ); + require(block.chainid == 1 || block.chainid == 31337 || block.chainid == 8453, Err(0)); mainnet = _mainnet; if (_mainnet) { @@ -189,11 +188,11 @@ contract Upgrade4_2_0 is Versioned { for (uint256 i = 0; i < MAINNET_ASSETS.length; i++) { require( keccak256(abi.encodePacked(MAINNET_ASSETS[i].version())) == NEW_VERSION_HASH, - "invalid asset" + Err(1) ); IERC20 erc20 = MAINNET_ASSETS[i].erc20(); - require(address(assets[erc20]) == address(0), "duplicate asset"); + require(address(assets[erc20]) == address(0), Err(2)); assets[erc20] = MAINNET_ASSETS[i]; } } else { @@ -212,11 +211,11 @@ contract Upgrade4_2_0 is Versioned { for (uint256 i = 0; i < BASE_ASSETS.length; i++) { require( keccak256(abi.encodePacked(BASE_ASSETS[i].version())) == NEW_VERSION_HASH, - "invalid asset" + Err(3) ); IERC20 erc20 = BASE_ASSETS[i].erc20(); - require(address(assets[erc20]) == address(0), "duplicate asset"); + require(address(assets[erc20]) == address(0), Err(4)); assets[erc20] = BASE_ASSETS[i]; } } @@ -232,15 +231,15 @@ contract Upgrade4_2_0 is Versioned { Governance oldGovernor, address[] calldata guardians ) external returns (address newGovernor, address newTimelock) { - require(keccak256(abi.encodePacked(rToken.version())) == PRIOR_VERSION_HASH, "US: 1"); + require(keccak256(abi.encodePacked(rToken.version())) == PRIOR_VERSION_HASH, Err(5)); // Can only be cast once per RToken - require(!cast[rToken], "repeat cast"); + require(!cast[rToken], Err(6)); cast[rToken] = true; MainP1 main = MainP1(address(rToken.main())); - require(main.hasRole(MAIN_OWNER_ROLE, msg.sender), "US: 2"); // security crux - require(main.hasRole(MAIN_OWNER_ROLE, address(this)), "US: 3"); + require(main.hasRole(MAIN_OWNER_ROLE, msg.sender), Err(7)); // security crux + require(main.hasRole(MAIN_OWNER_ROLE, address(this)), Err(8)); Components memory proxy; proxy.assetRegistry = main.assetRegistry(); @@ -260,7 +259,7 @@ contract Upgrade4_2_0 is Versioned { // Upgrade Main main.upgradeTo(address(impls.main)); - require(keccak256(abi.encodePacked(main.version())) == NEW_VERSION_HASH, "US: 4"); + require(keccak256(abi.encodePacked(main.version())) == NEW_VERSION_HASH, Err(9)); // Set registries // reverts on zero address @@ -274,7 +273,7 @@ contract Upgrade4_2_0 is Versioned { // Upgrade components main.upgradeRTokenTo(NEW_VERSION_HASH, false, false); main.cacheComponents(); - require(keccak256(abi.encodePacked(rToken.version())) == NEW_VERSION_HASH, "US: 5"); + require(keccak256(abi.encodePacked(rToken.version())) == NEW_VERSION_HASH, Err(10)); // Verify all components are upgraded require( @@ -290,12 +289,12 @@ contract Upgrade4_2_0 is Versioned { keccak256(abi.encodePacked(proxy.rTokenTrader.version())) == NEW_VERSION_HASH && keccak256(abi.encodePacked(proxy.rsrTrader.version())) == NEW_VERSION_HASH && keccak256(abi.encodePacked(proxy.stRSR.version())) == NEW_VERSION_HASH, - "US: 6" + Err(11) ); // Revoke OWNER from Main main.revokeRole(MAIN_OWNER_ROLE, address(main)); - require(!main.hasRole(MAIN_OWNER_ROLE, address(main)), "US: 7"); + require(!main.hasRole(MAIN_OWNER_ROLE, address(main)), Err(12)); // Turn on trusted fills TestIBroker(address(proxy.broker)).setTrustedFillerRegistry( @@ -306,7 +305,7 @@ contract Upgrade4_2_0 is Versioned { // Keep issuance premium off, should be off by default require( !TestIBasketHandler(address(proxy.basketHandler)).enableIssuancePremium(), - "US: 8" + Err(13) ); // Verify trading plugins are updated @@ -315,7 +314,7 @@ contract Upgrade4_2_0 is Versioned { address(impls.trading.dutchTrade) && address(TestIBroker(address(proxy.broker)).batchTradeImplementation()) == address(impls.trading.gnosisTrade), - "US: 9" + Err(14) ); } @@ -323,7 +322,7 @@ contract Upgrade4_2_0 is Versioned { // Context: frontend rounded down during early deployments and tables sum to 9,999 sometimes { RevenueTotals memory revTotals = proxy.distributor.totals(); - require(revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION - 1, "US: 10"); + require(revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION - 1, Err(15)); // add 1 to StRSR destination if necessary if (revTotals.rTokenTotal + revTotals.rsrTotal < MAX_DISTRIBUTION) { @@ -340,7 +339,7 @@ contract Upgrade4_2_0 is Versioned { } // Distributor invariant: table must sum to >=10000 - require(revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION, "US: 11"); + require(revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION, Err(16)); } // Rotate assets, erc20s should not change @@ -361,7 +360,7 @@ contract Upgrade4_2_0 is Versioned { proxy.assetRegistry.registerNewRTokenAsset( proxy.assetRegistry.toAsset(IERC20(address(rToken))).maxTradeVolume() ), - "US: 13" + Err(17) ); // Validate all assets @@ -369,7 +368,7 @@ contract Upgrade4_2_0 is Versioned { // Refresh basket proxy.basketHandler.refreshBasket(); - require(proxy.basketHandler.status() == CollateralStatus.SOUND, "US: 14"); + require(proxy.basketHandler.status() == CollateralStatus.SOUND, Err(18)); } // Deploy new governance, preserving all values @@ -377,7 +376,7 @@ contract Upgrade4_2_0 is Versioned { TimelockController oldTimelock = TimelockController(payable(msg.sender)); uint256 minDelay = oldTimelock.getMinDelay(); - require(minDelay != 0, "US: 15"); + require(minDelay != 0, Err(19)); // Deploy new timelock newTimelock = address( @@ -393,7 +392,7 @@ contract Upgrade4_2_0 is Versioned { 1e4, // all previous governors are set to 0.01% oldGovernor.quorumNumerator() ); - require(Governance(payable(newGovernor)).timelock() == newTimelock, "US: 16"); + require(Governance(payable(newGovernor)).timelock() == newTimelock, Err(20)); TimelockController _newTimelock = TimelockController(payable(newTimelock)); @@ -403,7 +402,7 @@ contract Upgrade4_2_0 is Versioned { _newTimelock.grantRole(EXECUTOR_ROLE, newGovernor); // Gov only executor for (uint256 i = 0; i < guardians.length; i++) { - require(oldTimelock.hasRole(CANCELLER_ROLE, guardians[i]), "US: 16.5"); + require(oldTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(21)); _newTimelock.grantRole(CANCELLER_ROLE, guardians[i]); // Guardian can cancel } _newTimelock.revokeRole(TIMELOCK_ADMIN_ROLE, address(this)); // Revoke admin role @@ -413,21 +412,21 @@ contract Upgrade4_2_0 is Versioned { _newTimelock.hasRole(PROPOSER_ROLE, newGovernor) && _newTimelock.hasRole(EXECUTOR_ROLE, newGovernor) && _newTimelock.hasRole(CANCELLER_ROLE, newGovernor), - "US: 17" + Err(22) ); require( !_newTimelock.hasRole(PROPOSER_ROLE, address(oldGovernor)) && !_newTimelock.hasRole(EXECUTOR_ROLE, address(oldGovernor)) && !_newTimelock.hasRole(CANCELLER_ROLE, address(oldGovernor)), - "US: 18" + Err(23) ); require( !_newTimelock.hasRole(PROPOSER_ROLE, address(0)) && !_newTimelock.hasRole(EXECUTOR_ROLE, address(0)) && !_newTimelock.hasRole(CANCELLER_ROLE, address(0)), - "US: 19" + Err(24) ); // setup `newGovs` for rToken, only used in testing but useful for onchain record @@ -456,13 +455,13 @@ contract Upgrade4_2_0 is Versioned { !main.hasRole(SHORT_FREEZER_ROLE, msg.sender) && !main.hasRole(LONG_FREEZER_ROLE, msg.sender) && !main.hasRole(MAIN_OWNER_ROLE, address(this)), - "US: 20" + Err(25) ); require( !main.hasRole(MAIN_OWNER_ROLE, address(oldGovernor)) && !main.hasRole(MAIN_OWNER_ROLE, newGovernor), - "US: 21" + Err(26) ); } } From 6fee1b541601024cb849c48902a2ece1eae09b26 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 18 Dec 2025 19:45:22 -0500 Subject: [PATCH 05/23] explicit RToken whitelist --- contracts/spells/4_2_0.sol | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 5c0a9ea3e..1449f5ab3 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -160,6 +160,9 @@ contract Upgrade4_2_0 is Versioned { // ERC20 => 4.2.0 Asset mapping(IERC20 => Asset) public assets; + // RToken => bool + mapping(IRToken => bool) public supported; + // RToken => bool mapping(IRToken => bool) public cast; @@ -184,6 +187,11 @@ contract Upgrade4_2_0 is Versioned { ITrustedFillerRegistry(0x279ccF56441fC74f1aAC39E7faC165Dec5A88B3A) ); + // Setup `supported` + supported[IRToken(0xA0d69E286B938e21CBf7E51D71F6A4c8918f482F)] = true; // eUSD + supported[IRToken(0xE72B141DF173b999AE7c1aDcbF60Cc9833Ce56a8)] = true; // ETH+ + supported[IRToken(0x0d86883FAf4FfD7aEb116390af37746F45b6f378)] = true; // USD3 + // Setup `assets` for (uint256 i = 0; i < MAINNET_ASSETS.length; i++) { require( @@ -207,6 +215,10 @@ contract Upgrade4_2_0 is Versioned { ITrustedFillerRegistry(0x72DB5f49D0599C314E2f2FEDf6Fe33E1bA6C7A18) ); + // Setup `supported` + supported[IRToken(0xCc7FF230365bD730eE4B352cC2492CEdAC49383e)] = true; // hyUSD (base) + supported[IRToken(0xCb327b99fF831bF8223cCEd12B1338FF3aA322Ff)] = true; // bsdETH + // Setup `assets` for (uint256 i = 0; i < BASE_ASSETS.length; i++) { require( @@ -231,10 +243,10 @@ contract Upgrade4_2_0 is Versioned { Governance oldGovernor, address[] calldata guardians ) external returns (address newGovernor, address newTimelock) { - require(keccak256(abi.encodePacked(rToken.version())) == PRIOR_VERSION_HASH, Err(5)); + require(keccak256(abi.encodePacked(rToken.version())) == PRIOR_VERSION_HASH, Err(6)); - // Can only be cast once per RToken - require(!cast[rToken], Err(6)); + // Can only be cast once per supported RToken + require(supported[rToken] && !cast[rToken], Err(6)); cast[rToken] = true; MainP1 main = MainP1(address(rToken.main())); From 8d3b984191b67aae8135259aca347a9420abcab4 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 18 Dec 2025 19:46:57 -0500 Subject: [PATCH 06/23] remove redundant RToken version check --- contracts/spells/4_2_0.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 1449f5ab3..43a2ed5ec 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -285,7 +285,6 @@ contract Upgrade4_2_0 is Versioned { // Upgrade components main.upgradeRTokenTo(NEW_VERSION_HASH, false, false); main.cacheComponents(); - require(keccak256(abi.encodePacked(rToken.version())) == NEW_VERSION_HASH, Err(10)); // Verify all components are upgraded require( From 8ba0da062680dfe4c00bc59ceb8ba43731128dab Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 18 Dec 2025 19:51:17 -0500 Subject: [PATCH 07/23] deployer version check --- contracts/spells/4_2_0.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 43a2ed5ec..50486c0ea 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -178,6 +178,7 @@ contract Upgrade4_2_0 is Versioned { if (_mainnet) { // 4.2.0 deployer (mainnet) deployer = IDeployer(0x8FcbD0BaaeB442F1f3F374FcB63933e6D4Cb8710); + require(keccak256(abi.encodePacked(deployer.version())) == NEW_VERSION_HASH, Err(1)); // DAO registries (mainnet) registries = IDeployer.Registries( @@ -206,6 +207,7 @@ contract Upgrade4_2_0 is Versioned { } else { // 4.2.0 deployer (base) deployer = IDeployer(0x5705F85A05c8b57818663C7AB6a11f88323a1A57); + require(keccak256(abi.encodePacked(deployer.version())) == NEW_VERSION_HASH, Err(1)); // DAO registries (base) registries = IDeployer.Registries( From 10a593039b097b316aba65cd0d25e6fb59c44d8c Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 18 Dec 2025 19:55:47 -0500 Subject: [PATCH 08/23] add missing new timelock checks --- contracts/spells/4_2_0.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 50486c0ea..bf3af9db5 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -417,8 +417,11 @@ contract Upgrade4_2_0 is Versioned { for (uint256 i = 0; i < guardians.length; i++) { require(oldTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(21)); _newTimelock.grantRole(CANCELLER_ROLE, guardians[i]); // Guardian can cancel + require(_newTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(22)); } + _newTimelock.revokeRole(TIMELOCK_ADMIN_ROLE, address(this)); // Revoke admin role + require(!_newTimelock.hasRole(TIMELOCK_ADMIN_ROLE, address(this)), Err(22)); // post validation require( From cd74c8cbd55301557bce1592a2ebd459f73801cf Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 18 Dec 2025 20:08:55 -0500 Subject: [PATCH 09/23] remove unneeded Distributor adjustment --- contracts/spells/4_2_0.sol | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index bf3af9db5..404606ae2 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -331,28 +331,10 @@ contract Upgrade4_2_0 is Versioned { ); } - // Make distributor table sum to 10000, adding 1 to StRSR destination if necessary - // Context: frontend rounded down during early deployments and tables sum to 9,999 sometimes + // Distributor invariant: table must sum to >=10000 { RevenueTotals memory revTotals = proxy.distributor.totals(); - require(revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION - 1, Err(15)); - - // add 1 to StRSR destination if necessary - if (revTotals.rTokenTotal + revTotals.rsrTotal < MAX_DISTRIBUTION) { - TestIDistributor distributor = TestIDistributor(address(proxy.distributor)); - - (uint16 rTokenDist, uint16 rsrDist) = distributor.distribution(address(2)); - // address(2) is the special-cased key for StRSR - - assert(rsrDist > 0); // sanity check; all RTokens direct _some_ RSR to StRSR - - distributor.setDistribution(address(2), RevenueShare(rTokenDist, rsrDist + 1)); - - revTotals = proxy.distributor.totals(); - } - - // Distributor invariant: table must sum to >=10000 - require(revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION, Err(16)); + require(revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION, Err(13)); } // Rotate assets, erc20s should not change From 827e252b68b7741b1c8367740d9429cdf48b23e4 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 18 Dec 2025 20:09:50 -0500 Subject: [PATCH 10/23] error ordering --- contracts/spells/4_2_0.sol | 50 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 404606ae2..6f2cdbb93 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -197,11 +197,11 @@ contract Upgrade4_2_0 is Versioned { for (uint256 i = 0; i < MAINNET_ASSETS.length; i++) { require( keccak256(abi.encodePacked(MAINNET_ASSETS[i].version())) == NEW_VERSION_HASH, - Err(1) + Err(2) ); IERC20 erc20 = MAINNET_ASSETS[i].erc20(); - require(address(assets[erc20]) == address(0), Err(2)); + require(address(assets[erc20]) == address(0), Err(3)); assets[erc20] = MAINNET_ASSETS[i]; } } else { @@ -225,11 +225,11 @@ contract Upgrade4_2_0 is Versioned { for (uint256 i = 0; i < BASE_ASSETS.length; i++) { require( keccak256(abi.encodePacked(BASE_ASSETS[i].version())) == NEW_VERSION_HASH, - Err(3) + Err(2) ); IERC20 erc20 = BASE_ASSETS[i].erc20(); - require(address(assets[erc20]) == address(0), Err(4)); + require(address(assets[erc20]) == address(0), Err(3)); assets[erc20] = BASE_ASSETS[i]; } } @@ -245,15 +245,15 @@ contract Upgrade4_2_0 is Versioned { Governance oldGovernor, address[] calldata guardians ) external returns (address newGovernor, address newTimelock) { - require(keccak256(abi.encodePacked(rToken.version())) == PRIOR_VERSION_HASH, Err(6)); + require(keccak256(abi.encodePacked(rToken.version())) == PRIOR_VERSION_HASH, Err(4)); // Can only be cast once per supported RToken - require(supported[rToken] && !cast[rToken], Err(6)); + require(supported[rToken] && !cast[rToken], Err(5)); cast[rToken] = true; MainP1 main = MainP1(address(rToken.main())); - require(main.hasRole(MAIN_OWNER_ROLE, msg.sender), Err(7)); // security crux - require(main.hasRole(MAIN_OWNER_ROLE, address(this)), Err(8)); + require(main.hasRole(MAIN_OWNER_ROLE, msg.sender), Err(6)); // security crux + require(main.hasRole(MAIN_OWNER_ROLE, address(this)), Err(7)); Components memory proxy; proxy.assetRegistry = main.assetRegistry(); @@ -273,7 +273,7 @@ contract Upgrade4_2_0 is Versioned { // Upgrade Main main.upgradeTo(address(impls.main)); - require(keccak256(abi.encodePacked(main.version())) == NEW_VERSION_HASH, Err(9)); + require(keccak256(abi.encodePacked(main.version())) == NEW_VERSION_HASH, Err(8)); // Set registries // reverts on zero address @@ -302,12 +302,12 @@ contract Upgrade4_2_0 is Versioned { keccak256(abi.encodePacked(proxy.rTokenTrader.version())) == NEW_VERSION_HASH && keccak256(abi.encodePacked(proxy.rsrTrader.version())) == NEW_VERSION_HASH && keccak256(abi.encodePacked(proxy.stRSR.version())) == NEW_VERSION_HASH, - Err(11) + Err(9) ); // Revoke OWNER from Main main.revokeRole(MAIN_OWNER_ROLE, address(main)); - require(!main.hasRole(MAIN_OWNER_ROLE, address(main)), Err(12)); + require(!main.hasRole(MAIN_OWNER_ROLE, address(main)), Err(10)); // Turn on trusted fills TestIBroker(address(proxy.broker)).setTrustedFillerRegistry( @@ -318,7 +318,7 @@ contract Upgrade4_2_0 is Versioned { // Keep issuance premium off, should be off by default require( !TestIBasketHandler(address(proxy.basketHandler)).enableIssuancePremium(), - Err(13) + Err(11) ); // Verify trading plugins are updated @@ -327,7 +327,7 @@ contract Upgrade4_2_0 is Versioned { address(impls.trading.dutchTrade) && address(TestIBroker(address(proxy.broker)).batchTradeImplementation()) == address(impls.trading.gnosisTrade), - Err(14) + Err(12) ); } @@ -355,7 +355,7 @@ contract Upgrade4_2_0 is Versioned { proxy.assetRegistry.registerNewRTokenAsset( proxy.assetRegistry.toAsset(IERC20(address(rToken))).maxTradeVolume() ), - Err(17) + Err(14) ); // Validate all assets @@ -363,7 +363,7 @@ contract Upgrade4_2_0 is Versioned { // Refresh basket proxy.basketHandler.refreshBasket(); - require(proxy.basketHandler.status() == CollateralStatus.SOUND, Err(18)); + require(proxy.basketHandler.status() == CollateralStatus.SOUND, Err(15)); } // Deploy new governance, preserving all values @@ -371,7 +371,7 @@ contract Upgrade4_2_0 is Versioned { TimelockController oldTimelock = TimelockController(payable(msg.sender)); uint256 minDelay = oldTimelock.getMinDelay(); - require(minDelay != 0, Err(19)); + require(minDelay != 0, Err(16)); // Deploy new timelock newTimelock = address( @@ -387,7 +387,7 @@ contract Upgrade4_2_0 is Versioned { 1e4, // all previous governors are set to 0.01% oldGovernor.quorumNumerator() ); - require(Governance(payable(newGovernor)).timelock() == newTimelock, Err(20)); + require(Governance(payable(newGovernor)).timelock() == newTimelock, Err(17)); TimelockController _newTimelock = TimelockController(payable(newTimelock)); @@ -397,34 +397,34 @@ contract Upgrade4_2_0 is Versioned { _newTimelock.grantRole(EXECUTOR_ROLE, newGovernor); // Gov only executor for (uint256 i = 0; i < guardians.length; i++) { - require(oldTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(21)); + require(oldTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(18)); _newTimelock.grantRole(CANCELLER_ROLE, guardians[i]); // Guardian can cancel - require(_newTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(22)); + require(_newTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(19)); } _newTimelock.revokeRole(TIMELOCK_ADMIN_ROLE, address(this)); // Revoke admin role - require(!_newTimelock.hasRole(TIMELOCK_ADMIN_ROLE, address(this)), Err(22)); + require(!_newTimelock.hasRole(TIMELOCK_ADMIN_ROLE, address(this)), Err(20)); // post validation require( _newTimelock.hasRole(PROPOSER_ROLE, newGovernor) && _newTimelock.hasRole(EXECUTOR_ROLE, newGovernor) && _newTimelock.hasRole(CANCELLER_ROLE, newGovernor), - Err(22) + Err(21) ); require( !_newTimelock.hasRole(PROPOSER_ROLE, address(oldGovernor)) && !_newTimelock.hasRole(EXECUTOR_ROLE, address(oldGovernor)) && !_newTimelock.hasRole(CANCELLER_ROLE, address(oldGovernor)), - Err(23) + Err(22) ); require( !_newTimelock.hasRole(PROPOSER_ROLE, address(0)) && !_newTimelock.hasRole(EXECUTOR_ROLE, address(0)) && !_newTimelock.hasRole(CANCELLER_ROLE, address(0)), - Err(24) + Err(23) ); // setup `newGovs` for rToken, only used in testing but useful for onchain record @@ -453,13 +453,13 @@ contract Upgrade4_2_0 is Versioned { !main.hasRole(SHORT_FREEZER_ROLE, msg.sender) && !main.hasRole(LONG_FREEZER_ROLE, msg.sender) && !main.hasRole(MAIN_OWNER_ROLE, address(this)), - Err(25) + Err(24) ); require( !main.hasRole(MAIN_OWNER_ROLE, address(oldGovernor)) && !main.hasRole(MAIN_OWNER_ROLE, newGovernor), - Err(26) + Err(25) ); } } From 154724225db73a45a057651444b48ba0ecd8ab96 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 19 Dec 2025 15:27:41 -0500 Subject: [PATCH 11/23] remove STG --- contracts/spells/4_2_0.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 6f2cdbb93..a278dbe01 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -120,11 +120,10 @@ contract Upgrade4_2_0 is Versioned { ]; // 4.2.0 Assets (base) - Asset[20] BASE_ASSETS = [ + Asset[19] BASE_ASSETS = [ Asset(0x22018D85BFdA9e2673FB4101e957562a1e952Cdf), // RSR Asset(0xC9c37FC53682207844B058026024853A9C0b8c7B), // COMP Asset(0x7f7B77e49d5b30445f222764a794AFE14af062eB), // AERO - Asset(0x3962695aCce0Efce11cFf997890f3D1D7467ec40), // STG Asset(0x49A44d50d3B1E098DAC9402c4aF8D0C0E499F250), // DAI Asset(0x33E840e5711549358f6d4D11F9Ab2896B36E9822), // USDC Asset(0xf003b8A8200F14db13f5F712EC8e76c41e7e9A7A), // USDbC From 18a1b91c0be27ad575c41a0862f56d9fc4a85612 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 19 Dec 2025 16:30:14 -0500 Subject: [PATCH 12/23] distributor rToken/RSR dest checks --- contracts/spells/4_2_0.sol | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index a278dbe01..c2922412b 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -330,10 +330,22 @@ contract Upgrade4_2_0 is Versioned { ); } - // Distributor invariant: table must sum to >=10000 + // Distributor checks { + // table invariant; must sum to >=10000 RevenueTotals memory revTotals = proxy.distributor.totals(); require(revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION, Err(13)); + + // new require: RToken contract should not be set as a destination + (uint16 rTokenDist, uint16 rsrDist) = TestIDistributor(address(proxy.distributor)) + .distribution(address(rToken)); + require(rTokenDist == 0 && rsrDist == 0, Err(14)); + + // new require: RSR contract should not be set as a destination + (rTokenDist, rsrDist) = TestIDistributor(address(proxy.distributor)).distribution( + address(main.rsr()) + ); + require(rTokenDist == 0 && rsrDist == 0, Err(15)); } // Rotate assets, erc20s should not change From 6481e75dbfb06de4a0f0e85af9863a7d64b3a720 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 19 Dec 2025 16:43:34 -0500 Subject: [PATCH 13/23] check oldGovernor validity --- contracts/spells/4_2_0.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index c2922412b..e0a551367 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -250,6 +250,7 @@ contract Upgrade4_2_0 is Versioned { require(supported[rToken] && !cast[rToken], Err(5)); cast[rToken] = true; + // validate caller is old timelock MainP1 main = MainP1(address(rToken.main())); require(main.hasRole(MAIN_OWNER_ROLE, msg.sender), Err(6)); // security crux require(main.hasRole(MAIN_OWNER_ROLE, address(this)), Err(7)); @@ -380,6 +381,7 @@ contract Upgrade4_2_0 is Versioned { // Deploy new governance, preserving all values { TimelockController oldTimelock = TimelockController(payable(msg.sender)); + require(oldTimelock.hasRole(PROPOSER_ROLE, address(oldGovernor)), Err(16)); uint256 minDelay = oldTimelock.getMinDelay(); require(minDelay != 0, Err(16)); From 92ff272f9fda0c108a5a2214b5a14c3b25d0b429 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 19 Dec 2025 16:49:14 -0500 Subject: [PATCH 14/23] contract size + error order --- contracts/spells/4_2_0.sol | 68 ++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index e0a551367..e2b8efb19 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -162,9 +162,6 @@ contract Upgrade4_2_0 is Versioned { // RToken => bool mapping(IRToken => bool) public supported; - // RToken => bool - mapping(IRToken => bool) public cast; - bool public mainnet; // !mainnet | base // ======================================================================================= @@ -247,13 +244,16 @@ contract Upgrade4_2_0 is Versioned { require(keccak256(abi.encodePacked(rToken.version())) == PRIOR_VERSION_HASH, Err(4)); // Can only be cast once per supported RToken - require(supported[rToken] && !cast[rToken], Err(5)); - cast[rToken] = true; + require(supported[rToken], Err(5)); + supported[rToken] = false; // validate caller is old timelock MainP1 main = MainP1(address(rToken.main())); - require(main.hasRole(MAIN_OWNER_ROLE, msg.sender), Err(6)); // security crux - require(main.hasRole(MAIN_OWNER_ROLE, address(this)), Err(7)); + require( + main.hasRole(MAIN_OWNER_ROLE, msg.sender) && // security crux + main.hasRole(MAIN_OWNER_ROLE, address(this)), + Err(5) + ); Components memory proxy; proxy.assetRegistry = main.assetRegistry(); @@ -273,7 +273,7 @@ contract Upgrade4_2_0 is Versioned { // Upgrade Main main.upgradeTo(address(impls.main)); - require(keccak256(abi.encodePacked(main.version())) == NEW_VERSION_HASH, Err(8)); + require(keccak256(abi.encodePacked(main.version())) == NEW_VERSION_HASH, Err(6)); // Set registries // reverts on zero address @@ -302,12 +302,12 @@ contract Upgrade4_2_0 is Versioned { keccak256(abi.encodePacked(proxy.rTokenTrader.version())) == NEW_VERSION_HASH && keccak256(abi.encodePacked(proxy.rsrTrader.version())) == NEW_VERSION_HASH && keccak256(abi.encodePacked(proxy.stRSR.version())) == NEW_VERSION_HASH, - Err(9) + Err(7) ); // Revoke OWNER from Main main.revokeRole(MAIN_OWNER_ROLE, address(main)); - require(!main.hasRole(MAIN_OWNER_ROLE, address(main)), Err(10)); + require(!main.hasRole(MAIN_OWNER_ROLE, address(main)), Err(8)); // Turn on trusted fills TestIBroker(address(proxy.broker)).setTrustedFillerRegistry( @@ -318,7 +318,7 @@ contract Upgrade4_2_0 is Versioned { // Keep issuance premium off, should be off by default require( !TestIBasketHandler(address(proxy.basketHandler)).enableIssuancePremium(), - Err(11) + Err(9) ); // Verify trading plugins are updated @@ -327,7 +327,7 @@ contract Upgrade4_2_0 is Versioned { address(impls.trading.dutchTrade) && address(TestIBroker(address(proxy.broker)).batchTradeImplementation()) == address(impls.trading.gnosisTrade), - Err(12) + Err(10) ); } @@ -335,18 +335,18 @@ contract Upgrade4_2_0 is Versioned { { // table invariant; must sum to >=10000 RevenueTotals memory revTotals = proxy.distributor.totals(); - require(revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION, Err(13)); + require(revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION, Err(11)); // new require: RToken contract should not be set as a destination (uint16 rTokenDist, uint16 rsrDist) = TestIDistributor(address(proxy.distributor)) .distribution(address(rToken)); - require(rTokenDist == 0 && rsrDist == 0, Err(14)); + require(rTokenDist == 0 && rsrDist == 0, Err(12)); // new require: RSR contract should not be set as a destination (rTokenDist, rsrDist) = TestIDistributor(address(proxy.distributor)).distribution( address(main.rsr()) ); - require(rTokenDist == 0 && rsrDist == 0, Err(15)); + require(rTokenDist == 0 && rsrDist == 0, Err(13)); } // Rotate assets, erc20s should not change @@ -384,7 +384,7 @@ contract Upgrade4_2_0 is Versioned { require(oldTimelock.hasRole(PROPOSER_ROLE, address(oldGovernor)), Err(16)); uint256 minDelay = oldTimelock.getMinDelay(); - require(minDelay != 0, Err(16)); + require(minDelay != 0, Err(17)); // Deploy new timelock newTimelock = address( @@ -400,7 +400,7 @@ contract Upgrade4_2_0 is Versioned { 1e4, // all previous governors are set to 0.01% oldGovernor.quorumNumerator() ); - require(Governance(payable(newGovernor)).timelock() == newTimelock, Err(17)); + require(Governance(payable(newGovernor)).timelock() == newTimelock, Err(18)); TimelockController _newTimelock = TimelockController(payable(newTimelock)); @@ -410,34 +410,26 @@ contract Upgrade4_2_0 is Versioned { _newTimelock.grantRole(EXECUTOR_ROLE, newGovernor); // Gov only executor for (uint256 i = 0; i < guardians.length; i++) { - require(oldTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(18)); + require(oldTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(19)); _newTimelock.grantRole(CANCELLER_ROLE, guardians[i]); // Guardian can cancel - require(_newTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(19)); + require(_newTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(20)); } _newTimelock.revokeRole(TIMELOCK_ADMIN_ROLE, address(this)); // Revoke admin role - require(!_newTimelock.hasRole(TIMELOCK_ADMIN_ROLE, address(this)), Err(20)); + require(!_newTimelock.hasRole(TIMELOCK_ADMIN_ROLE, address(this)), Err(21)); // post validation require( _newTimelock.hasRole(PROPOSER_ROLE, newGovernor) && _newTimelock.hasRole(EXECUTOR_ROLE, newGovernor) && - _newTimelock.hasRole(CANCELLER_ROLE, newGovernor), - Err(21) - ); - - require( - !_newTimelock.hasRole(PROPOSER_ROLE, address(oldGovernor)) && + _newTimelock.hasRole(CANCELLER_ROLE, newGovernor) && + !_newTimelock.hasRole(PROPOSER_ROLE, address(oldGovernor)) && !_newTimelock.hasRole(EXECUTOR_ROLE, address(oldGovernor)) && - !_newTimelock.hasRole(CANCELLER_ROLE, address(oldGovernor)), - Err(22) - ); - - require( - !_newTimelock.hasRole(PROPOSER_ROLE, address(0)) && + !_newTimelock.hasRole(CANCELLER_ROLE, address(oldGovernor)) && + !_newTimelock.hasRole(PROPOSER_ROLE, address(0)) && !_newTimelock.hasRole(EXECUTOR_ROLE, address(0)) && !_newTimelock.hasRole(CANCELLER_ROLE, address(0)), - Err(23) + Err(22) ); // setup `newGovs` for rToken, only used in testing but useful for onchain record @@ -465,14 +457,10 @@ contract Upgrade4_2_0 is Versioned { !main.hasRole(PAUSER_ROLE, msg.sender) && !main.hasRole(SHORT_FREEZER_ROLE, msg.sender) && !main.hasRole(LONG_FREEZER_ROLE, msg.sender) && - !main.hasRole(MAIN_OWNER_ROLE, address(this)), - Err(24) - ); - - require( - !main.hasRole(MAIN_OWNER_ROLE, address(oldGovernor)) && + !main.hasRole(MAIN_OWNER_ROLE, address(this)) && + !main.hasRole(MAIN_OWNER_ROLE, address(oldGovernor)) && !main.hasRole(MAIN_OWNER_ROLE, newGovernor), - Err(25) + Err(23) ); } } From fbe9d62510a86b754422f7add9077465a8c330f3 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 19 Dec 2025 16:58:11 -0500 Subject: [PATCH 15/23] new AssetPluginRegistry address --- common/registries.ts | 4 ++-- contracts/spells/4_2_0.sol | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/registries.ts b/common/registries.ts index 6a67986ba..e5392b67a 100644 --- a/common/registries.ts +++ b/common/registries.ts @@ -25,7 +25,7 @@ export const registryConfig: Record = { registries: { roleRegistry: '0xE1eC57C8EE970280f237863910B606059e9641C9', versionRegistry: '0x1895b15B3d0a70962be86Af0E337018aD63464e0', - assetPluginRegistry: '0x4a818c41131CB9FE65BadF2Bb8671dDE4D117135', + assetPluginRegistry: '0xA9145A22537B39b04fe91AA479c1b8e7a3569c98', daoFeeRegistry: '0xec716deD4eABa060937D1a915F166E237039342B', trustedFillerRegistry: '0x279ccF56441fC74f1aAC39E7faC165Dec5A88B3A', }, @@ -38,7 +38,7 @@ export const registryConfig: Record = { registries: { roleRegistry: '0xE1eC57C8EE970280f237863910B606059e9641C9', versionRegistry: '0xBbC532A80DD141449330c1232C953Da6801Aed01', - assetPluginRegistry: '0x7Ac954307356301A10adDb0dB4f61b4a475d3551', + assetPluginRegistry: '0x3312507BC3F22430B34D5841A472c767DC5C36e4', daoFeeRegistry: '0x3513D2c7D2F51c678889CeC083E7D7Ae27b219aD', trustedFillerRegistry: '0x72DB5f49D0599C314E2f2FEDf6Fe33E1bA6C7A18', }, diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index e2b8efb19..916dc6508 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -179,7 +179,7 @@ contract Upgrade4_2_0 is Versioned { // DAO registries (mainnet) registries = IDeployer.Registries( VersionRegistry(0x1895b15B3d0a70962be86Af0E337018aD63464e0), - AssetPluginRegistry(0x4a818c41131CB9FE65BadF2Bb8671dDE4D117135), + AssetPluginRegistry(0xA9145A22537B39b04fe91AA479c1b8e7a3569c98), DAOFeeRegistry(0xec716deD4eABa060937D1a915F166E237039342B), ITrustedFillerRegistry(0x279ccF56441fC74f1aAC39E7faC165Dec5A88B3A) ); @@ -208,7 +208,7 @@ contract Upgrade4_2_0 is Versioned { // DAO registries (base) registries = IDeployer.Registries( VersionRegistry(0xBbC532A80DD141449330c1232C953Da6801Aed01), - AssetPluginRegistry(0x7Ac954307356301A10adDb0dB4f61b4a475d3551), + AssetPluginRegistry(0x3312507BC3F22430B34D5841A472c767DC5C36e4), DAOFeeRegistry(0x3513D2c7D2F51c678889CeC083E7D7Ae27b219aD), ITrustedFillerRegistry(0x72DB5f49D0599C314E2f2FEDf6Fe33E1bA6C7A18) ); From 33444aea9da9a0e71a62e45821d829effcaba6ad Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 19 Dec 2025 17:22:33 -0500 Subject: [PATCH 16/23] check ongoing trades --- contracts/spells/4_2_0.sol | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 916dc6508..09beab305 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -267,6 +267,14 @@ contract Upgrade4_2_0 is Versioned { proxy.rsrTrader = main.rsrTrader(); proxy.stRSR = main.stRSR(); + // No ongoing trades + require( + proxy.backingManager.tradesOpen() == 0 && + proxy.rTokenTrader.tradesOpen() == 0 && + proxy.rsrTrader.tradesOpen() == 0, + Err(6) + ); + // Main + Component upgrades { Implementations memory impls = deployer.implementations(); From 15a2f3ce04f17a54b9376420ae4489a671be3386 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 19 Dec 2025 17:33:33 -0500 Subject: [PATCH 17/23] contract size + error order --- contracts/spells/4_2_0.sol | 86 +++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 09beab305..3b2ee3b4a 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -255,17 +255,18 @@ contract Upgrade4_2_0 is Versioned { Err(5) ); - Components memory proxy; - proxy.assetRegistry = main.assetRegistry(); - proxy.basketHandler = main.basketHandler(); - proxy.backingManager = main.backingManager(); - proxy.broker = main.broker(); - proxy.distributor = main.distributor(); - proxy.furnace = main.furnace(); - proxy.rToken = rToken; - proxy.rTokenTrader = main.rTokenTrader(); - proxy.rsrTrader = main.rsrTrader(); - proxy.stRSR = main.stRSR(); + Components memory proxy = Components({ + assetRegistry: main.assetRegistry(), + basketHandler: main.basketHandler(), + backingManager: main.backingManager(), + broker: main.broker(), + distributor: main.distributor(), + furnace: main.furnace(), + rToken: rToken, + rTokenTrader: main.rTokenTrader(), + rsrTrader: main.rsrTrader(), + stRSR: main.stRSR() + }); // No ongoing trades require( @@ -281,7 +282,7 @@ contract Upgrade4_2_0 is Versioned { // Upgrade Main main.upgradeTo(address(impls.main)); - require(keccak256(abi.encodePacked(main.version())) == NEW_VERSION_HASH, Err(6)); + require(keccak256(abi.encodePacked(main.version())) == NEW_VERSION_HASH, Err(7)); // Set registries // reverts on zero address @@ -310,12 +311,12 @@ contract Upgrade4_2_0 is Versioned { keccak256(abi.encodePacked(proxy.rTokenTrader.version())) == NEW_VERSION_HASH && keccak256(abi.encodePacked(proxy.rsrTrader.version())) == NEW_VERSION_HASH && keccak256(abi.encodePacked(proxy.stRSR.version())) == NEW_VERSION_HASH, - Err(7) + Err(8) ); // Revoke OWNER from Main main.revokeRole(MAIN_OWNER_ROLE, address(main)); - require(!main.hasRole(MAIN_OWNER_ROLE, address(main)), Err(8)); + require(!main.hasRole(MAIN_OWNER_ROLE, address(main)), Err(9)); // Turn on trusted fills TestIBroker(address(proxy.broker)).setTrustedFillerRegistry( @@ -326,7 +327,7 @@ contract Upgrade4_2_0 is Versioned { // Keep issuance premium off, should be off by default require( !TestIBasketHandler(address(proxy.basketHandler)).enableIssuancePremium(), - Err(9) + Err(10) ); // Verify trading plugins are updated @@ -335,26 +336,31 @@ contract Upgrade4_2_0 is Versioned { address(impls.trading.dutchTrade) && address(TestIBroker(address(proxy.broker)).batchTradeImplementation()) == address(impls.trading.gnosisTrade), - Err(10) + Err(11) ); } // Distributor checks { - // table invariant; must sum to >=10000 RevenueTotals memory revTotals = proxy.distributor.totals(); - require(revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION, Err(11)); - // new require: RToken contract should not be set as a destination - (uint16 rTokenDist, uint16 rsrDist) = TestIDistributor(address(proxy.distributor)) - .distribution(address(rToken)); - require(rTokenDist == 0 && rsrDist == 0, Err(12)); + (uint16 rTokenDistRToken, uint16 rsrDistRToken) = TestIDistributor( + address(proxy.distributor) + ).distribution(address(rToken)); - // new require: RSR contract should not be set as a destination - (rTokenDist, rsrDist) = TestIDistributor(address(proxy.distributor)).distribution( - address(main.rsr()) + (uint16 rTokenDistRSR, uint16 rsrDistRSR) = TestIDistributor(address(proxy.distributor)) + .distribution(address(main.rsr())); + + // table invariant; must sum to >=10000 + // new requires: RToken/RSR contracts should not be set as destinations + require( + revTotals.rTokenTotal + revTotals.rsrTotal >= MAX_DISTRIBUTION && + rTokenDistRToken == 0 && + rsrDistRToken == 0 && + rTokenDistRSR == 0 && + rsrDistRSR == 0, + Err(12) ); - require(rTokenDist == 0 && rsrDist == 0, Err(13)); } // Rotate assets, erc20s should not change @@ -375,7 +381,7 @@ contract Upgrade4_2_0 is Versioned { proxy.assetRegistry.registerNewRTokenAsset( proxy.assetRegistry.toAsset(IERC20(address(rToken))).maxTradeVolume() ), - Err(14) + Err(13) ); // Validate all assets @@ -383,16 +389,16 @@ contract Upgrade4_2_0 is Versioned { // Refresh basket proxy.basketHandler.refreshBasket(); - require(proxy.basketHandler.status() == CollateralStatus.SOUND, Err(15)); + require(proxy.basketHandler.status() == CollateralStatus.SOUND, Err(14)); } // Deploy new governance, preserving all values { TimelockController oldTimelock = TimelockController(payable(msg.sender)); - require(oldTimelock.hasRole(PROPOSER_ROLE, address(oldGovernor)), Err(16)); + require(oldTimelock.hasRole(PROPOSER_ROLE, address(oldGovernor)), Err(15)); uint256 minDelay = oldTimelock.getMinDelay(); - require(minDelay != 0, Err(17)); + require(minDelay != 0, Err(16)); // Deploy new timelock newTimelock = address( @@ -408,7 +414,7 @@ contract Upgrade4_2_0 is Versioned { 1e4, // all previous governors are set to 0.01% oldGovernor.quorumNumerator() ); - require(Governance(payable(newGovernor)).timelock() == newTimelock, Err(18)); + require(Governance(payable(newGovernor)).timelock() == newTimelock, Err(17)); TimelockController _newTimelock = TimelockController(payable(newTimelock)); @@ -418,17 +424,21 @@ contract Upgrade4_2_0 is Versioned { _newTimelock.grantRole(EXECUTOR_ROLE, newGovernor); // Gov only executor for (uint256 i = 0; i < guardians.length; i++) { - require(oldTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(19)); _newTimelock.grantRole(CANCELLER_ROLE, guardians[i]); // Guardian can cancel - require(_newTimelock.hasRole(CANCELLER_ROLE, guardians[i]), Err(20)); + + require( + oldTimelock.hasRole(CANCELLER_ROLE, guardians[i]) && + _newTimelock.hasRole(CANCELLER_ROLE, guardians[i]), + Err(18) + ); } _newTimelock.revokeRole(TIMELOCK_ADMIN_ROLE, address(this)); // Revoke admin role - require(!_newTimelock.hasRole(TIMELOCK_ADMIN_ROLE, address(this)), Err(21)); // post validation require( - _newTimelock.hasRole(PROPOSER_ROLE, newGovernor) && + !_newTimelock.hasRole(TIMELOCK_ADMIN_ROLE, address(this)) && + _newTimelock.hasRole(PROPOSER_ROLE, newGovernor) && _newTimelock.hasRole(EXECUTOR_ROLE, newGovernor) && _newTimelock.hasRole(CANCELLER_ROLE, newGovernor) && !_newTimelock.hasRole(PROPOSER_ROLE, address(oldGovernor)) && @@ -437,7 +447,7 @@ contract Upgrade4_2_0 is Versioned { !_newTimelock.hasRole(PROPOSER_ROLE, address(0)) && !_newTimelock.hasRole(EXECUTOR_ROLE, address(0)) && !_newTimelock.hasRole(CANCELLER_ROLE, address(0)), - Err(22) + Err(19) ); // setup `newGovs` for rToken, only used in testing but useful for onchain record @@ -450,8 +460,6 @@ contract Upgrade4_2_0 is Versioned { // Renounce adminships and validate final state { - assert(oldGovernor.timelock() == msg.sender); - main.grantRole(MAIN_OWNER_ROLE, newTimelock); main.revokeRole(MAIN_OWNER_ROLE, msg.sender); main.revokeRole(PAUSER_ROLE, msg.sender); @@ -468,7 +476,7 @@ contract Upgrade4_2_0 is Versioned { !main.hasRole(MAIN_OWNER_ROLE, address(this)) && !main.hasRole(MAIN_OWNER_ROLE, address(oldGovernor)) && !main.hasRole(MAIN_OWNER_ROLE, newGovernor), - Err(23) + Err(20) ); } } From 5ad5ee8b5e917de16f7a18256e860fae8f105aa1 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Wed, 7 Jan 2026 11:59:39 -0400 Subject: [PATCH 18/23] forceSettleTrade griefing --- contracts/p0/mixins/Trading.sol | 1 + contracts/p1/BackingManager.sol | 2 +- contracts/p1/mixins/Trading.sol | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/p0/mixins/Trading.sol b/contracts/p0/mixins/Trading.sol index 855741a0a..e96aa3dec 100644 --- a/contracts/p0/mixins/Trading.sol +++ b/contracts/p0/mixins/Trading.sol @@ -104,6 +104,7 @@ abstract contract TradingP0 is RewardableP0, ITrading { // should not call any ERC20 functions, in case bricked IERC20Metadata sell = trade.sell(); + require(trades[sell] == trade, "trade not found"); delete trades[sell]; tradesOpen--; emit TradeSettled(trade, sell, trade.buy(), 0, 0); diff --git a/contracts/p1/BackingManager.sol b/contracts/p1/BackingManager.sol index d2e5b6aea..69c792a09 100644 --- a/contracts/p1/BackingManager.sol +++ b/contracts/p1/BackingManager.sol @@ -315,8 +315,8 @@ contract BackingManagerP1 is TradingP1, IBackingManager { /// @param trade The trade address itself /// @custom:governance function forceSettleTrade(ITrade trade) public override(TradingP1, ITrading) { - super.forceSettleTrade(trade); // enforces governance only delete tokensOut[trade.sell()]; + super.forceSettleTrade(trade); // enforces governance only; nonReentrant } /// @custom:governance diff --git a/contracts/p1/mixins/Trading.sol b/contracts/p1/mixins/Trading.sol index 239be92dd..6eb40edc8 100644 --- a/contracts/p1/mixins/Trading.sol +++ b/contracts/p1/mixins/Trading.sol @@ -151,11 +151,12 @@ abstract contract TradingP1 is Multicall, ComponentP1, ReentrancyGuardUpgradeabl /// Should only be called in case of censorship /// @param trade The trade address itself /// @custom:governance - function forceSettleTrade(ITrade trade) public virtual { + function forceSettleTrade(ITrade trade) public virtual globalNonReentrant { requireGovernanceOnly(); // should not call any ERC20 functions, in case bricked IERC20Metadata sell = trade.sell(); + require(trades[sell] == trade, "wrong trade"); delete trades[sell]; tradesOpen--; emit TradeSettled(trade, sell, trade.buy(), 0, 0); From 76ec12346465a5f158b031e9100ffef2d8efd0e7 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Wed, 7 Jan 2026 15:32:32 -0400 Subject: [PATCH 19/23] contract size --- contracts/p1/BackingManager.sol | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/contracts/p1/BackingManager.sol b/contracts/p1/BackingManager.sol index 69c792a09..c2ddf852d 100644 --- a/contracts/p1/BackingManager.sol +++ b/contracts/p1/BackingManager.sol @@ -285,16 +285,20 @@ contract BackingManagerP1 is TradingP1, IBackingManager { ctx.minTradeVolume = minTradeVolume; ctx.maxTradeSlippage = maxTradeSlippage; ctx.quantities = new uint192[](reg.erc20s.length); - for (uint256 i = 0; i < reg.erc20s.length; ++i) { - ctx.quantities[i] = basketHandler.quantityUnsafe(reg.erc20s[i], reg.assets[i]); - // quantities round up, without any issuance premium - } ctx.bals = new uint192[](reg.erc20s.length); + for (uint256 i = 0; i < reg.erc20s.length; ++i) { - ctx.bals[i] = reg.assets[i].bal(address(this)) + tokensOut[reg.erc20s[i]]; + IERC20 erc20 = reg.erc20s[i]; + IAsset asset = reg.assets[i]; + + ctx.quantities[i] = basketHandler.quantityUnsafe(erc20, asset); + // quantities round up, and exclude issuance premium + + // include balances out on trade + ctx.bals[i] = asset.bal(address(this)) + tokensOut[erc20]; // include StRSR's balance for RSR - if (reg.erc20s[i] == rsr) ctx.bals[i] += reg.assets[i].bal(address(stRSR)); + if (erc20 == rsr) ctx.bals[i] += asset.bal(address(stRSR)); } } From c96912bacf7ce1722803c41dedff756261d76c17 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Wed, 7 Jan 2026 23:02:00 -0400 Subject: [PATCH 20/23] deploy new registries --- common/registries.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/registries.ts b/common/registries.ts index e5392b67a..68b817d50 100644 --- a/common/registries.ts +++ b/common/registries.ts @@ -24,8 +24,8 @@ export const registryConfig: Record = { }, registries: { roleRegistry: '0xE1eC57C8EE970280f237863910B606059e9641C9', - versionRegistry: '0x1895b15B3d0a70962be86Af0E337018aD63464e0', - assetPluginRegistry: '0xA9145A22537B39b04fe91AA479c1b8e7a3569c98', + versionRegistry: '0xB031D7742367B92CcBEd0653B9a6341EFa47dd04', + assetPluginRegistry: '0x15A9e0CF2Fd9842B99E015E05073b5F0f58A1C29', daoFeeRegistry: '0xec716deD4eABa060937D1a915F166E237039342B', trustedFillerRegistry: '0x279ccF56441fC74f1aAC39E7faC165Dec5A88B3A', }, @@ -37,8 +37,8 @@ export const registryConfig: Record = { }, registries: { roleRegistry: '0xE1eC57C8EE970280f237863910B606059e9641C9', - versionRegistry: '0xBbC532A80DD141449330c1232C953Da6801Aed01', - assetPluginRegistry: '0x3312507BC3F22430B34D5841A472c767DC5C36e4', + versionRegistry: '0xbD769ea5E93A4B232Cee08ED4C2a67Ff5Ba692Df', + assetPluginRegistry: '0x093c07787920eB34A0A0c7a09823510725Aee4Af', daoFeeRegistry: '0x3513D2c7D2F51c678889CeC083E7D7Ae27b219aD', trustedFillerRegistry: '0x72DB5f49D0599C314E2f2FEDf6Fe33E1bA6C7A18', }, From 8e2e4a96bec7b1a81fd3f54cfa8b3f198d7fb402 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Wed, 7 Jan 2026 23:02:21 -0400 Subject: [PATCH 21/23] deploy new BackingManager/RevenueTraders/Deployer --- .openzeppelin/mainnet.json | 632 ++++++++++++++++++ scripts/addresses/1-tmp-deployments.json | 8 +- scripts/addresses/8453-tmp-deployments.json | 8 +- .../base-4.2.0/8453-tmp-deployments.json | 8 +- .../mainnet-4.2.0/1-tmp-deployments.json | 8 +- 5 files changed, 648 insertions(+), 16 deletions(-) diff --git a/.openzeppelin/mainnet.json b/.openzeppelin/mainnet.json index d4d3edb8b..b6eebe908 100644 --- a/.openzeppelin/mainnet.json +++ b/.openzeppelin/mainnet.json @@ -17819,6 +17819,638 @@ } } } + }, + "4fb55e97ccb929ccafb3de632a704753ea61bf058e7dbd1bf7e15fb6f3ae43a9": { + "address": "0x62A574b9F4BCc1DDf877E154963C5B4E792985d6", + "txHash": "0xa48cafd37657623ea39d050451c66d39fd57f557039562b7466eef61cb64aae9", + "layout": { + "solcVersion": "0.8.28", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "main", + "offset": 0, + "slot": "151", + "type": "t_contract(IMain)6839", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:21" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:87" + }, + { + "label": "_status", + "offset": 0, + "slot": "201", + "type": "t_uint256", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "202", + "type": "t_array(t_uint256)49_storage", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:88" + }, + { + "label": "broker", + "offset": 0, + "slot": "251", + "type": "t_contract(IBroker)5935", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:29" + }, + { + "label": "trades", + "offset": 0, + "slot": "252", + "type": "t_mapping(t_contract(IERC20)2252,t_contract(ITrade)7573)", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:32" + }, + { + "label": "tradesOpen", + "offset": 0, + "slot": "253", + "type": "t_uint48", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:33" + }, + { + "label": "maxTradeSlippage", + "offset": 6, + "slot": "253", + "type": "t_uint192", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:36" + }, + { + "label": "minTradeVolume", + "offset": 0, + "slot": "254", + "type": "t_uint192", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:37" + }, + { + "label": "tradesNonce", + "offset": 0, + "slot": "255", + "type": "t_uint256", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "256", + "type": "t_array(t_uint256)45_storage", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:186" + }, + { + "label": "assetRegistry", + "offset": 0, + "slot": "301", + "type": "t_contract(IAssetRegistry)5368", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:25" + }, + { + "label": "basketHandler", + "offset": 0, + "slot": "302", + "type": "t_contract(IBasketHandler)5748", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:26" + }, + { + "label": "distributor", + "offset": 0, + "slot": "303", + "type": "t_contract(IDistributor)6299", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:27" + }, + { + "label": "rToken", + "offset": 0, + "slot": "304", + "type": "t_contract(IRToken)7083", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:28" + }, + { + "label": "rsr", + "offset": 0, + "slot": "305", + "type": "t_contract(IERC20)2252", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:29" + }, + { + "label": "stRSR", + "offset": 0, + "slot": "306", + "type": "t_contract(IStRSR)7457", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:30" + }, + { + "label": "rsrTrader", + "offset": 0, + "slot": "307", + "type": "t_contract(IRevenueTrader)7206", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:31" + }, + { + "label": "rTokenTrader", + "offset": 0, + "slot": "308", + "type": "t_contract(IRevenueTrader)7206", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:32" + }, + { + "label": "tradingDelay", + "offset": 20, + "slot": "308", + "type": "t_uint48", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:36" + }, + { + "label": "backingBuffer", + "offset": 0, + "slot": "309", + "type": "t_uint192", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:37" + }, + { + "label": "furnace", + "offset": 0, + "slot": "310", + "type": "t_contract(IFurnace)6360", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:40" + }, + { + "label": "tradeEnd", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_enum(TradeKind)5811,t_uint48)", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:41" + }, + { + "label": "tokensOut", + "offset": 0, + "slot": "312", + "type": "t_mapping(t_contract(IERC20)2252,t_uint192)", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:44" + }, + { + "label": "__gap", + "offset": 0, + "slot": "313", + "type": "t_array(t_uint256)38_storage", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:360" + } + ], + "types": { + "t_array(t_uint256)38_storage": { + "label": "uint256[38]", + "numberOfBytes": "1216" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(IAssetRegistry)5368": { + "label": "contract IAssetRegistry", + "numberOfBytes": "20" + }, + "t_contract(IBasketHandler)5748": { + "label": "contract IBasketHandler", + "numberOfBytes": "20" + }, + "t_contract(IBroker)5935": { + "label": "contract IBroker", + "numberOfBytes": "20" + }, + "t_contract(IDistributor)6299": { + "label": "contract IDistributor", + "numberOfBytes": "20" + }, + "t_contract(IERC20)2252": { + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IFurnace)6360": { + "label": "contract IFurnace", + "numberOfBytes": "20" + }, + "t_contract(IMain)6839": { + "label": "contract IMain", + "numberOfBytes": "20" + }, + "t_contract(IRToken)7083": { + "label": "contract IRToken", + "numberOfBytes": "20" + }, + "t_contract(IRevenueTrader)7206": { + "label": "contract IRevenueTrader", + "numberOfBytes": "20" + }, + "t_contract(IStRSR)7457": { + "label": "contract IStRSR", + "numberOfBytes": "20" + }, + "t_contract(ITrade)7573": { + "label": "contract ITrade", + "numberOfBytes": "20" + }, + "t_enum(TradeKind)5811": { + "label": "enum TradeKind", + "members": [ + "DUTCH_AUCTION", + "BATCH_AUCTION" + ], + "numberOfBytes": "1" + }, + "t_mapping(t_contract(IERC20)2252,t_contract(ITrade)7573)": { + "label": "mapping(contract IERC20 => contract ITrade)", + "numberOfBytes": "32" + }, + "t_mapping(t_contract(IERC20)2252,t_uint192)": { + "label": "mapping(contract IERC20 => uint192)", + "numberOfBytes": "32" + }, + "t_mapping(t_enum(TradeKind)5811,t_uint48)": { + "label": "mapping(enum TradeKind => uint48)", + "numberOfBytes": "32" + }, + "t_uint192": { + "label": "uint192", + "numberOfBytes": "24" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint48": { + "label": "uint48", + "numberOfBytes": "6" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "031e8b9b2cbee4e8f163ca1f107eeb056f1ab3f9cebe2075d36ffb3465cdf742": { + "address": "0xBaa47e33AB0d41024e9F271e29154d9688eB16AC", + "txHash": "0x7501b5ee6609aca226af82fd2b686ad75c9fa573ca7bf2d5ea9f4d2650b1564c", + "layout": { + "solcVersion": "0.8.28", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "main", + "offset": 0, + "slot": "151", + "type": "t_contract(IMain)6839", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:21" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:87" + }, + { + "label": "_status", + "offset": 0, + "slot": "201", + "type": "t_uint256", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "202", + "type": "t_array(t_uint256)49_storage", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:88" + }, + { + "label": "broker", + "offset": 0, + "slot": "251", + "type": "t_contract(IBroker)5935", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:29" + }, + { + "label": "trades", + "offset": 0, + "slot": "252", + "type": "t_mapping(t_contract(IERC20)2252,t_contract(ITrade)7573)", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:32" + }, + { + "label": "tradesOpen", + "offset": 0, + "slot": "253", + "type": "t_uint48", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:33" + }, + { + "label": "maxTradeSlippage", + "offset": 6, + "slot": "253", + "type": "t_uint192", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:36" + }, + { + "label": "minTradeVolume", + "offset": 0, + "slot": "254", + "type": "t_uint192", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:37" + }, + { + "label": "tradesNonce", + "offset": 0, + "slot": "255", + "type": "t_uint256", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "256", + "type": "t_array(t_uint256)45_storage", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:186" + }, + { + "label": "tokenToBuy", + "offset": 0, + "slot": "301", + "type": "t_contract(IERC20)2252", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:19" + }, + { + "label": "assetRegistry", + "offset": 0, + "slot": "302", + "type": "t_contract(IAssetRegistry)5368", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:20" + }, + { + "label": "distributor", + "offset": 0, + "slot": "303", + "type": "t_contract(IDistributor)6299", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:21" + }, + { + "label": "backingManager", + "offset": 0, + "slot": "304", + "type": "t_contract(IBackingManager)5476", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:22" + }, + { + "label": "furnace", + "offset": 0, + "slot": "305", + "type": "t_contract(IFurnace)6360", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:23" + }, + { + "label": "rToken", + "offset": 0, + "slot": "306", + "type": "t_contract(IRToken)7083", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:24" + }, + { + "label": "rsr", + "offset": 0, + "slot": "307", + "type": "t_contract(IERC20)2252", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:25" + }, + { + "label": "__gap", + "offset": 0, + "slot": "308", + "type": "t_array(t_uint256)43_storage", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:207" + } + ], + "types": { + "t_array(t_uint256)43_storage": { + "label": "uint256[43]", + "numberOfBytes": "1376" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(IAssetRegistry)5368": { + "label": "contract IAssetRegistry", + "numberOfBytes": "20" + }, + "t_contract(IBackingManager)5476": { + "label": "contract IBackingManager", + "numberOfBytes": "20" + }, + "t_contract(IBroker)5935": { + "label": "contract IBroker", + "numberOfBytes": "20" + }, + "t_contract(IDistributor)6299": { + "label": "contract IDistributor", + "numberOfBytes": "20" + }, + "t_contract(IERC20)2252": { + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IFurnace)6360": { + "label": "contract IFurnace", + "numberOfBytes": "20" + }, + "t_contract(IMain)6839": { + "label": "contract IMain", + "numberOfBytes": "20" + }, + "t_contract(IRToken)7083": { + "label": "contract IRToken", + "numberOfBytes": "20" + }, + "t_contract(ITrade)7573": { + "label": "contract ITrade", + "numberOfBytes": "20" + }, + "t_mapping(t_contract(IERC20)2252,t_contract(ITrade)7573)": { + "label": "mapping(contract IERC20 => contract ITrade)", + "numberOfBytes": "32" + }, + "t_uint192": { + "label": "uint192", + "numberOfBytes": "24" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint48": { + "label": "uint48", + "numberOfBytes": "6" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } } } } diff --git a/scripts/addresses/1-tmp-deployments.json b/scripts/addresses/1-tmp-deployments.json index 63bb69bea..91c700064 100644 --- a/scripts/addresses/1-tmp-deployments.json +++ b/scripts/addresses/1-tmp-deployments.json @@ -16,7 +16,7 @@ "facadeWriteLib": "0x2E749f12aE9e71f41c69cBaB1623f0359Aa4F740", "basketLib": "0x2fdD94F363644FEDE5106B22b1706E45D4dD9bea", "facadeWrite": "0x0A9D3D35055481BB67E5E145B07F6fb6cbeF9D4B", - "deployer": "0x8FcbD0BaaeB442F1f3F374FcB63933e6D4Cb8710", + "deployer": "0x30DBbe1969a357e46b640F1C5276569db4af9b84", "rsrAsset": "0xbCb71eE9c3372f3444cBBe3E1b263204967EdBE3", "implementations": { "main": "0xc5bf686CfB85786fcFfF557297D4afF8F4e15e44", @@ -26,13 +26,13 @@ }, "components": { "assetRegistry": "0xF683e671a7Bd91257A32079ca219Cc8398088AEc", - "backingManager": "0xc501c9074CE15A4B00dd0B51B3c372518e6D3BA2", + "backingManager": "0x62A574b9F4BCc1DDf877E154963C5B4E792985d6", "basketHandler": "0x54A8fa5217970e2040590DDD7c16f72B1fb57a3C", "broker": "0x63c61086418406eBB062c5C6dF80F46c6d052d4c", "distributor": "0x5593F9d1141E2dcae50a5315fa9Ee0Ad64d88F32", "furnace": "0x518fcA5e31eEea484276A68Ad5F7E5838F74F03F", - "rsrTrader": "0x9E240cb60627b49088c2E6152c4447F7181dC0eB", - "rTokenTrader": "0x9E240cb60627b49088c2E6152c4447F7181dC0eB", + "rsrTrader": "0xBaa47e33AB0d41024e9F271e29154d9688eB16AC", + "rTokenTrader": "0xBaa47e33AB0d41024e9F271e29154d9688eB16AC", "rToken": "0x258ce833CF9AD19208372763A00aA1565Dd40b3C", "stRSR": "0x8E594FFb702C48a9fF8ae56FAeC795D83A69B387" } diff --git a/scripts/addresses/8453-tmp-deployments.json b/scripts/addresses/8453-tmp-deployments.json index 37c4b43db..2f16db37b 100644 --- a/scripts/addresses/8453-tmp-deployments.json +++ b/scripts/addresses/8453-tmp-deployments.json @@ -16,7 +16,7 @@ "facadeWriteLib": "0x97E1586dAF469ceD46a956516BC5D2a4Bbb34356", "basketLib": "0x3700b22C742980be9D22740933d4a041A64f7314", "facadeWrite": "0x53d8D5B20607bf04b238463F28b222B0cc47DF4F", - "deployer": "0x5705F85A05c8b57818663C7AB6a11f88323a1A57", + "deployer": "0x7E4650af145f6a9146b91E8b363DF49ee32b0A58", "rsrAsset": "0x22018D85BFdA9e2673FB4101e957562a1e952Cdf", "implementations": { "main": "0x6D05CB2CB647B58189FA16f81784C05B4bcd4fe9", @@ -26,13 +26,13 @@ }, "components": { "assetRegistry": "0x29F2EB4A0D3dC211BB488E9aBe12740cafBCc49C", - "backingManager": "0xF73EB45d83AC86f8a6F75a6252ca1a59a9A3aED3", + "backingManager": "0x7Dee4DbeF75f93cCA06823Ac915Df990be3F1538", "basketHandler": "0x5c83CA710E72D130E3B74aEC5b739676ef5737c2", "broker": "0x714341800AD1913B5FCCBFd5d136553Ad1C314d6", "distributor": "0xE1fcCf8e23713Ed0497ED1a0E6Ae2b19ED443eCd", "furnace": "0x280Eb3B16A95a2F3CEDc2bDC4E6F91b43a3c396d", - "rsrTrader": "0x55590a1Bf90fbf7352A46c4af652A231AA5CbF13", - "rTokenTrader": "0x55590a1Bf90fbf7352A46c4af652A231AA5CbF13", + "rsrTrader": "0xf8CAE97837f79b7eA4DBACc14C4F547718CaC8Be", + "rTokenTrader": "0xf8CAE97837f79b7eA4DBACc14C4F547718CaC8Be", "rToken": "0x5CE95fAdb880B6a0BA5fFB0D76eD58D97f2A0DC0", "stRSR": "0xb3dCcEf35647A8821C76f796bE8B5426Cc953412" } diff --git a/scripts/addresses/base-4.2.0/8453-tmp-deployments.json b/scripts/addresses/base-4.2.0/8453-tmp-deployments.json index 3b1a14f13..bdc4e166b 100644 --- a/scripts/addresses/base-4.2.0/8453-tmp-deployments.json +++ b/scripts/addresses/base-4.2.0/8453-tmp-deployments.json @@ -16,7 +16,7 @@ "facadeWriteLib": "0x97E1586dAF469ceD46a956516BC5D2a4Bbb34356", "basketLib": "0x3700b22C742980be9D22740933d4a041A64f7314", "facadeWrite": "0x53d8D5B20607bf04b238463F28b222B0cc47DF4F", - "deployer": "0x5705F85A05c8b57818663C7AB6a11f88323a1A57", + "deployer": "0x7E4650af145f6a9146b91E8b363DF49ee32b0A58", "rsrAsset": "0x22018D85BFdA9e2673FB4101e957562a1e952Cdf", "implementations": { "main": "0x6D05CB2CB647B58189FA16f81784C05B4bcd4fe9", @@ -26,13 +26,13 @@ }, "components": { "assetRegistry": "0x29F2EB4A0D3dC211BB488E9aBe12740cafBCc49C", - "backingManager": "0xF73EB45d83AC86f8a6F75a6252ca1a59a9A3aED3", + "backingManager": "0x7Dee4DbeF75f93cCA06823Ac915Df990be3F1538", "basketHandler": "0x5c83CA710E72D130E3B74aEC5b739676ef5737c2", "broker": "0x714341800AD1913B5FCCBFd5d136553Ad1C314d6", "distributor": "0xE1fcCf8e23713Ed0497ED1a0E6Ae2b19ED443eCd", "furnace": "0x280Eb3B16A95a2F3CEDc2bDC4E6F91b43a3c396d", - "rsrTrader": "0x55590a1Bf90fbf7352A46c4af652A231AA5CbF13", - "rTokenTrader": "0x55590a1Bf90fbf7352A46c4af652A231AA5CbF13", + "rsrTrader": "0xf8CAE97837f79b7eA4DBACc14C4F547718CaC8Be", + "rTokenTrader": "0xf8CAE97837f79b7eA4DBACc14C4F547718CaC8Be", "rToken": "0x5CE95fAdb880B6a0BA5fFB0D76eD58D97f2A0DC0", "stRSR": "0xb3dCcEf35647A8821C76f796bE8B5426Cc953412" } diff --git a/scripts/addresses/mainnet-4.2.0/1-tmp-deployments.json b/scripts/addresses/mainnet-4.2.0/1-tmp-deployments.json index 0922e4050..a374de93a 100644 --- a/scripts/addresses/mainnet-4.2.0/1-tmp-deployments.json +++ b/scripts/addresses/mainnet-4.2.0/1-tmp-deployments.json @@ -16,7 +16,7 @@ "facadeWriteLib": "0x2E749f12aE9e71f41c69cBaB1623f0359Aa4F740", "basketLib": "0x2fdD94F363644FEDE5106B22b1706E45D4dD9bea", "facadeWrite": "0x0A9D3D35055481BB67E5E145B07F6fb6cbeF9D4B", - "deployer": "0x8FcbD0BaaeB442F1f3F374FcB63933e6D4Cb8710", + "deployer": "0x30DBbe1969a357e46b640F1C5276569db4af9b84", "rsrAsset": "0xbCb71eE9c3372f3444cBBe3E1b263204967EdBE3", "implementations": { "main": "0xc5bf686CfB85786fcFfF557297D4afF8F4e15e44", @@ -26,13 +26,13 @@ }, "components": { "assetRegistry": "0xF683e671a7Bd91257A32079ca219Cc8398088AEc", - "backingManager": "0xc501c9074CE15A4B00dd0B51B3c372518e6D3BA2", + "backingManager": "0x62A574b9F4BCc1DDf877E154963C5B4E792985d6", "basketHandler": "0x54A8fa5217970e2040590DDD7c16f72B1fb57a3C", "broker": "0x63c61086418406eBB062c5C6dF80F46c6d052d4c", "distributor": "0x5593F9d1141E2dcae50a5315fa9Ee0Ad64d88F32", "furnace": "0x518fcA5e31eEea484276A68Ad5F7E5838F74F03F", - "rsrTrader": "0x9E240cb60627b49088c2E6152c4447F7181dC0eB", - "rTokenTrader": "0x9E240cb60627b49088c2E6152c4447F7181dC0eB", + "rsrTrader": "0xBaa47e33AB0d41024e9F271e29154d9688eB16AC", + "rTokenTrader": "0xBaa47e33AB0d41024e9F271e29154d9688eB16AC", "rToken": "0x258ce833CF9AD19208372763A00aA1565Dd40b3C", "stRSR": "0x8E594FFb702C48a9fF8ae56FAeC795D83A69B387" } From 936e0c1072c40d8409a47982d3f068944f9b3fd0 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Wed, 7 Jan 2026 23:02:29 -0400 Subject: [PATCH 22/23] update spell --- contracts/spells/4_2_0.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/spells/4_2_0.sol b/contracts/spells/4_2_0.sol index 3b2ee3b4a..246ddce72 100644 --- a/contracts/spells/4_2_0.sol +++ b/contracts/spells/4_2_0.sol @@ -173,13 +173,13 @@ contract Upgrade4_2_0 is Versioned { if (_mainnet) { // 4.2.0 deployer (mainnet) - deployer = IDeployer(0x8FcbD0BaaeB442F1f3F374FcB63933e6D4Cb8710); + deployer = IDeployer(0x30DBbe1969a357e46b640F1C5276569db4af9b84); require(keccak256(abi.encodePacked(deployer.version())) == NEW_VERSION_HASH, Err(1)); // DAO registries (mainnet) registries = IDeployer.Registries( - VersionRegistry(0x1895b15B3d0a70962be86Af0E337018aD63464e0), - AssetPluginRegistry(0xA9145A22537B39b04fe91AA479c1b8e7a3569c98), + VersionRegistry(0xB031D7742367B92CcBEd0653B9a6341EFa47dd04), + AssetPluginRegistry(0x15A9e0CF2Fd9842B99E015E05073b5F0f58A1C29), DAOFeeRegistry(0xec716deD4eABa060937D1a915F166E237039342B), ITrustedFillerRegistry(0x279ccF56441fC74f1aAC39E7faC165Dec5A88B3A) ); @@ -202,13 +202,13 @@ contract Upgrade4_2_0 is Versioned { } } else { // 4.2.0 deployer (base) - deployer = IDeployer(0x5705F85A05c8b57818663C7AB6a11f88323a1A57); + deployer = IDeployer(0x7E4650af145f6a9146b91E8b363DF49ee32b0A58); require(keccak256(abi.encodePacked(deployer.version())) == NEW_VERSION_HASH, Err(1)); // DAO registries (base) registries = IDeployer.Registries( - VersionRegistry(0xBbC532A80DD141449330c1232C953Da6801Aed01), - AssetPluginRegistry(0x3312507BC3F22430B34D5841A472c767DC5C36e4), + VersionRegistry(0xbD769ea5E93A4B232Cee08ED4C2a67Ff5Ba692Df), + AssetPluginRegistry(0x093c07787920eB34A0A0c7a09823510725Aee4Af), DAOFeeRegistry(0x3513D2c7D2F51c678889CeC083E7D7Ae27b219aD), ITrustedFillerRegistry(0x72DB5f49D0599C314E2f2FEDf6Fe33E1bA6C7A18) ); From c008ef996656afcc91e5fff60f091d1d42f250be Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 8 Jan 2026 11:16:10 -0400 Subject: [PATCH 23/23] bump fork block --- test/integration/fork-block-numbers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/fork-block-numbers.ts b/test/integration/fork-block-numbers.ts index 351e9ec50..123fbacf4 100644 --- a/test/integration/fork-block-numbers.ts +++ b/test/integration/fork-block-numbers.ts @@ -11,7 +11,7 @@ const forkBlockNumber = { 'mainnet-3.4.0': 20328530, // Ethereum // TODO add all the block numbers we fork from to benefit from caching - default: 23992977, // Ethereum + default: 24190670, // Ethereum } export default forkBlockNumber