From 70be6ebb1578d93577a8c159f303caed480637eb Mon Sep 17 00:00:00 2001 From: 0xDecr1pto <0xdecr1pto@proton.me> Date: Fri, 25 Oct 2024 13:27:58 +0300 Subject: [PATCH 01/10] chore: cleanup --- lib/dss-test | 2 +- src/DssSpell.sol | 64 +---- src/DssSpell.t.sol | 65 +---- src/dependencies/dss-flappers/FlapperInit.sol | 211 -------------- .../dss-flappers/SplitterInstance.sol | 22 -- src/dependencies/lockstake/LockstakeInit.sol | 259 ------------------ .../lockstake/LockstakeInstance.sol | 24 -- src/test/config.sol | 6 +- 8 files changed, 14 insertions(+), 639 deletions(-) delete mode 100644 src/dependencies/dss-flappers/FlapperInit.sol delete mode 100644 src/dependencies/dss-flappers/SplitterInstance.sol delete mode 100644 src/dependencies/lockstake/LockstakeInit.sol delete mode 100644 src/dependencies/lockstake/LockstakeInstance.sol diff --git a/lib/dss-test b/lib/dss-test index 36ff4adbc..f2a2b2bbe 160000 --- a/lib/dss-test +++ b/lib/dss-test @@ -1 +1 @@ -Subproject commit 36ff4adbcb35760614e0d2df864026991c23d028 +Subproject commit f2a2b2bbea71921103c5b7cf3cb1d241b957bec7 diff --git a/src/DssSpell.sol b/src/DssSpell.sol index ffb647de1..edd9e14c8 100644 --- a/src/DssSpell.sol +++ b/src/DssSpell.sol @@ -20,49 +20,21 @@ import "dss-exec-lib/DssExec.sol"; import "dss-exec-lib/DssAction.sol"; import { DssInstance, MCD } from "dss-test/MCD.sol"; -import { VatAbstract } from "dss-interfaces/dss/VatAbstract.sol"; - -// Note: source code matches https://github.com/makerdao/dss-flappers/blob/95431f3d4da66babf81c6e1138bd05f5ddc5e516/deploy/FlapperInit.sol -import { FlapperInit, FarmConfig } from "src/dependencies/dss-flappers/FlapperInit.sol"; - -// Note: source code matches https://github.com/makerdao/lockstake/blob/7c71318623f5d6732457fd0c247a1f1760960011/deploy/LockstakeInit.sol -import { LockstakeInit, LockstakeConfig } from "src/dependencies/lockstake/LockstakeInit.sol"; -// Note: source code matches https://github.com/makerdao/lockstake/blob/7c71318623f5d6732457fd0c247a1f1760960011/deploy/LockstakeInstance.sol -import { LockstakeInstance } from "src/dependencies/lockstake/LockstakeInstance.sol"; - -interface SkyLike { - function mint(address to, uint256 value) external; -} - -interface RwaLiquidationOracleLike { - function cull(bytes32 ilk, address urn) external; - function tell(bytes32 ilk) external; -} - -interface ProxyLike { - function exec(address target, bytes calldata args) external payable returns (bytes memory out); -} contract DssSpellAction is DssAction { // Provides a descriptive tag for bot consumption // This should be modified weekly to provide a summary of the actions - // Hash: cast keccak -- "$(wget 'https://raw.githubusercontent.com/makerdao/community/7c7d7d16734407fdde827801ab4bbd6878560375/governance/votes/Executive%20vote%20-%20October%2017%2C%202024.md' -q -O - 2>/dev/null)" + // Hash: cast keccak -- "$(wget 'TODO' -q -O - 2>/dev/null)" string public constant override description = - "2024-10-17 MakerDAO Executive Spell | Hash: 0xa1e0345f807a0333170271e69caca6d384b3a715ccad597b8ad9502963eabd6f"; + "2024-10-31 MakerDAO Executive Spell | Hash: TODO"; // Set office hours according to the summary function officeHours() public pure override returns (bool) { return true; } - // Note: by the previous convention it should be a comma-separated list of DAO resolutions IPFS hashes - string public constant dao_resolutions = "QmYJUvw5xbAJmJknG2xUKDLe424JSTWQQhbJCnucRRjUv7"; - // ---------- Math ---------- - uint256 internal constant MILLION = 10 ** 6; - uint256 internal constant WAD = 10 ** 18; uint256 internal constant RAY = 10 ** 27; - uint256 internal constant RAD = 10 ** 45; // ---------- Rates ---------- // Many of the settings that change weekly rely on the rate accumulator @@ -75,38 +47,6 @@ contract DssSpellAction is DssAction { // https://ipfs.io/ipfs/QmVp4mhhbwWGTfbh2BzwQB9eiBrQBKiqcPRZCaAxNUaar6 // // uint256 internal constant X_PCT_RATE = ; - uint256 internal constant TWELVE_PCT_RATE = 1000000003593629043335673582; - - // ---------- Contracts ---------- - address internal immutable MCD_VAT = DssExecLib.vat(); - address internal immutable MCD_VOW = DssExecLib.vow(); - address internal immutable MCD_GOV = DssExecLib.mkr(); - address internal immutable MIP21_LIQUIDATION_ORACLE = DssExecLib.getChangelogAddress("MIP21_LIQUIDATION_ORACLE"); - address internal immutable RWA007_A_URN = DssExecLib.getChangelogAddress("RWA007_A_URN"); - address internal immutable RWA014_A_URN = DssExecLib.getChangelogAddress("RWA014_A_URN"); - address internal immutable PIP_MKR = DssExecLib.getChangelogAddress("PIP_MKR"); - address internal immutable VOTE_DELEGATE_PROXY_FACTORY = DssExecLib.getChangelogAddress("VOTE_DELEGATE_PROXY_FACTORY"); - address internal immutable MCD_SPLIT = DssExecLib.getChangelogAddress("MCD_SPLIT"); - address internal immutable USDS_JOIN = DssExecLib.getChangelogAddress("USDS_JOIN"); - address internal immutable USDS = DssExecLib.getChangelogAddress("USDS"); - address internal immutable MKR_SKY = DssExecLib.getChangelogAddress("MKR_SKY"); - address internal immutable SKY = DssExecLib.getChangelogAddress("SKY"); - address internal constant NEW_PIP_MKR = 0x4F94e33D0D74CfF5Ca0D3a66F1A650628551C56b; - address internal constant VOTE_DELEGATE_FACTORY = 0xC3D809E87A2C9da4F6d98fECea9135d834d6F5A0; - address internal constant REWARDS_LSMKR_USDS = 0x92282235a39bE957fF1f37619fD22A9aE5507CB1; - address internal constant LOCKSTAKE_MKR = 0xb4e0e45e142101dC3Ed768bac219fC35EDBED295; - address internal constant LOCKSTAKE_ENGINE = 0x2b16C07D5fD5cC701a0a871eae2aad6DA5fc8f12; - address internal constant LOCKSTAKE_CLIP = 0xA85621D35cAf9Cf5C146D2376Ce553D7B78A6239; - address internal constant LOCKSTAKE_CLIP_CALC = 0xf13cF3b39823CcfaE6C2354dA56416C80768474e; - - // ---------- Wallets ---------- - address internal constant AAVE_V3_TREASURY = 0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c; - address internal constant EARLY_BIRD_REWARDS = 0x14D98650d46BF7679BBD05D4f615A1547C87Bf68; - - // ---------- Spark Proxy Spell ---------- - // Spark Proxy: https://github.com/marsfoundation/sparklend-deployments/blob/bba4c57d54deb6a14490b897c12a949aa035a99b/script/output/1/primary-sce-latest.json#L2 - address internal constant SPARK_PROXY = 0x3300f198988e4C9C63F75dF86De36421f06af8c4; - address internal constant SPARK_SPELL = 0xcc3B9e79261A7064A0f734Cc749A8e3762e0a187; function actions() public override { // Note: multple actions in the spell depend on DssInstance diff --git a/src/DssSpell.t.sol b/src/DssSpell.t.sol index 5c668e7e8..a015a9b6f 100644 --- a/src/DssSpell.t.sol +++ b/src/DssSpell.t.sol @@ -49,11 +49,6 @@ interface SequencerLike { function hasJob(address job) external view returns (bool); } -interface RwaLiquidationOracleLike { - function good(bytes32 ilk) external view returns (bool); - function ilks(bytes32) external view returns (string memory doc, address pip, uint48 tau, uint48 toc); -} - contract DssSpellTest is DssSpellTestBase { string config; RootDomain rootDomain; @@ -215,7 +210,7 @@ contract DssSpellTest is DssSpellTestBase { //assertEq(OsmAbstract(0xF15993A5C5BE496b8e1c9657Fd2233b579Cd3Bc6).wards(ORACLE_WALLET01), 1); } - function testRemoveChainlogValues() public { // add the `skipped` modifier to skip + function testRemoveChainlogValues() public skipped { // add the `skipped` modifier to skip string[1] memory removedKeys = [ "VOTE_DELEGATE_PROXY_FACTORY" ]; @@ -281,7 +276,7 @@ contract DssSpellTest is DssSpellTestBase { ); } - function testLockstakeIlkIntegration() public { // add the `skipped` modifier to skip + function testLockstakeIlkIntegration() public skipped { // add the `skipped` modifier to skip _vote(address(spell)); _scheduleWaitAndCast(address(spell)); assertTrue(spell.done(), "TestError/spell-not-done"); @@ -349,7 +344,7 @@ contract DssSpellTest is DssSpellTestBase { } } - function testOsmReaders() public { // add the `skipped` modifier to skip + function testOsmReaders() public skipped { // add the `skipped` modifier to skip address OSM = addr.addr("PIP_MKR"); address[4] memory newReaders = [ addr.addr("MCD_SPOT"), @@ -371,7 +366,7 @@ contract DssSpellTest is DssSpellTestBase { } } - function testMedianReaders() public { // add the `skipped` modifier to skip + function testMedianReaders() public skipped { // add the `skipped` modifier to skip address median = chainLog.getAddress("PIP_MKR"); // PIP_MKR before spell address[1] memory newReaders = [ addr.addr('PIP_MKR') // PIP_MKR after spell @@ -395,7 +390,7 @@ contract DssSpellTest is DssSpellTestBase { bytes32 ward; } - function testNewAuthorizations() public { // add the `skipped` modifier to skip + function testNewAuthorizations() public skipped { // add the `skipped` modifier to skip Authorization[9] memory newAuthorizations = [ Authorization({ base: "MCD_VAT", ward: "LOCKSTAKE_ENGINE" }), Authorization({ base: "MCD_VAT", ward: "LOCKSTAKE_CLIP" }), @@ -596,7 +591,7 @@ contract DssSpellTest is DssSpellTestBase { int256 sky; } - function testPayments() public { // add the `skipped` modifier to skip + function testPayments() public skipped { // add the `skipped` modifier to skip // For each payment, create a Payee object with: // the address of the transferred token, // the destination address, @@ -936,7 +931,7 @@ contract DssSpellTest is DssSpellTestBase { assertEq(Art, 0, "GUSD-A Art is not 0"); } - function testDaoResolutions() public { // add the `skipped` modifier to skip + function testDaoResolutions() public skipped { // add the `skipped` modifier to skip // For each resolution, add IPFS hash as item to the resolutions array // Initialize the array with the number of resolutions string[1] memory resolutions = [ @@ -955,7 +950,7 @@ contract DssSpellTest is DssSpellTestBase { } // SPARK TESTS - function testSparkSpellIsExecuted() public { // add the `skipped` modifier to skip + function testSparkSpellIsExecuted() public skipped { // add the `skipped` modifier to skip address SPARK_PROXY = addr.addr('SPARK_PROXY'); address SPARK_SPELL = 0xcc3B9e79261A7064A0f734Cc749A8e3762e0a187; @@ -974,48 +969,4 @@ contract DssSpellTest is DssSpellTestBase { } // SPELL-SPECIFIC TESTS GO BELOW - - function testRwaTellAndCull() public { - bytes32[2] memory ilks = [ - bytes32("RWA007-A"), - bytes32("RWA014-A") - ]; - RwaLiquidationOracleLike oracle = RwaLiquidationOracleLike(addr.addr("MIP21_LIQUIDATION_ORACLE")); - - _vote(address(spell)); - _scheduleWaitAndCast(address(spell)); - assertTrue(spell.done()); - - for (uint256 i = 0; i < ilks.length; i++) { - bytes32 ilk = ilks[i]; - (, address pip, uint256 tau, uint256 toc) = oracle.ilks(ilk); - assertGt(toc, 0, _concat("TestError/bad-toc-after-tell-", ilk)); - assertEq(tau, 0, _concat("TestError/bad-tau-after-tell-", ilk)); - assertFalse(oracle.good(ilk), _concat("TestError/still-good-after-tell-", ilk)); - - uint256 price = uint256(DSValueAbstract(pip).read()); - assertEq(price, 0, _concat("TestError/non-zero-oracle-price-after-cull-", ilk)); - - (uint256 Art,, uint256 spot,,) = vat.ilks(ilk); - assertEq(Art, 0, _concat("TestError/non-zero-total-debt-after-cull-", ilk)); - assertEq(spot, 0, _concat("TestError/non-zero-spot-price-after-cull-", ilk)); - } - } - - function testNewOsmMomAddition() public { - bytes32 ilk = "LSE-MKR-A"; - address osm = addr.addr("PIP_MKR"); - - assertEq(osmMom.osms(ilk), address(0), "TestError/osm-already-in-mom"); - - _vote(address(spell)); - _scheduleWaitAndCast(address(spell)); - assertTrue(spell.done(), "TestError/spell-not-done"); - - assertEq(osmMom.osms(ilk), osm, "TestError/osm-not-in-mom"); - - assertEq(OsmAbstract(osm).stopped(), 0, "TestError/unexpected-stopped-before"); - vm.prank(chief.hat()); osmMom.stop(ilk); - assertEq(OsmAbstract(osm).stopped(), 1, "TestError/unexpected-stopped-after"); - } } diff --git a/src/dependencies/dss-flappers/FlapperInit.sol b/src/dependencies/dss-flappers/FlapperInit.sol deleted file mode 100644 index 4d7475efe..000000000 --- a/src/dependencies/dss-flappers/FlapperInit.sol +++ /dev/null @@ -1,211 +0,0 @@ -// SPDX-FileCopyrightText: © 2023 Dai Foundation -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -pragma solidity >=0.8.0; - -import { DssInstance } from "dss-test/MCD.sol"; -import { SplitterInstance } from "./SplitterInstance.sol"; - -interface FlapperUniV2Like { - function pip() external view returns (address); - function spotter() external view returns (address); - function usds() external view returns (address); - function gem() external view returns (address); - function receiver() external view returns (address); - function pair() external view returns (address); - function rely(address) external; - function file(bytes32, uint256) external; - function file(bytes32, address) external; -} - -interface SplitterMomLike { - function splitter() external view returns (address); - function setAuthority(address) external; -} - -interface OracleWrapperLike { - function pip() external view returns (address); - function divisor() external view returns (uint256); -} - -interface PipLike { - function kiss(address) external; -} - -interface PairLike { - function token0() external view returns (address); - function token1() external view returns (address); -} - -interface UsdsJoinLike { - function dai() external view returns (address); // TODO: Replace when new join is ready by the new getter -} - -interface SplitterLike { - function live() external view returns (uint256); - function vat() external view returns (address); - function usdsJoin() external view returns (address); - function hop() external view returns (uint256); - function rely(address) external; - function file(bytes32, uint256) external; - function file(bytes32, address) external; -} - -interface FarmLike { - function rewardsToken() external view returns (address); - function setRewardsDistribution(address) external; - function setRewardsDuration(uint256) external; -} - -struct FlapperUniV2Config { - uint256 want; - address pip; - address pair; - address usds; - address splitter; - bytes32 prevChainlogKey; - bytes32 chainlogKey; -} - -struct FarmConfig { - address splitter; - address usdsJoin; - uint256 hop; - bytes32 prevChainlogKey; - bytes32 chainlogKey; -} - -struct SplitterConfig { - uint256 hump; - uint256 bump; - uint256 hop; - uint256 burn; - address usdsJoin; - bytes32 splitterChainlogKey; - bytes32 prevMomChainlogKey; - bytes32 momChainlogKey; -} - -library FlapperInit { - uint256 constant WAD = 10 ** 18; - uint256 constant RAY = 10 ** 27; - - function initFlapperUniV2( - DssInstance memory dss, - address flapper_, - FlapperUniV2Config memory cfg - ) internal { - FlapperUniV2Like flapper = FlapperUniV2Like(flapper_); - - // Sanity checks - require(flapper.spotter() == address(dss.spotter), "Flapper spotter mismatch"); - require(flapper.usds() == cfg.usds, "Flapper usds mismatch"); - require(flapper.pair() == cfg.pair, "Flapper pair mismatch"); - require(flapper.receiver() == dss.chainlog.getAddress("MCD_PAUSE_PROXY"), "Flapper receiver mismatch"); - - PairLike pair = PairLike(flapper.pair()); - (address pairUsds, address pairGem) = pair.token0() == cfg.usds ? (pair.token0(), pair.token1()) - : (pair.token1(), pair.token0()); - require(pairUsds == cfg.usds, "Usds mismatch"); - require(pairGem == flapper.gem(), "Gem mismatch"); - - require(cfg.want >= WAD * 90 / 100, "want too low"); - - flapper.file("want", cfg.want); - flapper.file("pip", cfg.pip); - flapper.rely(cfg.splitter); - - SplitterLike(cfg.splitter).file("flapper", flapper_); - - if (cfg.prevChainlogKey != bytes32(0)) dss.chainlog.removeAddress(cfg.prevChainlogKey); - dss.chainlog.setAddress(cfg.chainlogKey, flapper_); - } - - function initDirectOracle(address flapper) internal { - PipLike(FlapperUniV2Like(flapper).pip()).kiss(flapper); - } - - function initOracleWrapper( - DssInstance memory dss, - address wrapper_, - uint256 divisor, - bytes32 clKey - ) internal { - OracleWrapperLike wrapper = OracleWrapperLike(wrapper_); - require(wrapper.divisor() == divisor, "Wrapper divisor mismatch"); // Sanity check - PipLike(wrapper.pip()).kiss(wrapper_); - dss.chainlog.setAddress(clKey, wrapper_); - } - - function setFarm( - DssInstance memory dss, - address farm_, - FarmConfig memory cfg - ) internal { - FarmLike farm = FarmLike(farm_); - SplitterLike splitter = SplitterLike(cfg.splitter); - - require(farm.rewardsToken() == UsdsJoinLike(cfg.usdsJoin).dai(), "Farm rewards not usds"); - // Staking token is checked in the Lockstake script - - // The following two checks enforce the initSplitter function has to be called first - require(cfg.hop >= 5 minutes, "hop too low"); - require(cfg.hop == splitter.hop(), "hop mismatch"); - - splitter.file("farm", farm_); - - farm.setRewardsDistribution(cfg.splitter); - farm.setRewardsDuration(cfg.hop); - - if (cfg.prevChainlogKey != bytes32(0)) dss.chainlog.removeAddress(cfg.prevChainlogKey); - dss.chainlog.setAddress(cfg.chainlogKey, farm_); - } - - function initSplitter( - DssInstance memory dss, - SplitterInstance memory splitterInstance, - SplitterConfig memory cfg - ) internal { - SplitterLike splitter = SplitterLike(splitterInstance.splitter); - SplitterMomLike mom = SplitterMomLike(splitterInstance.mom); - - // Sanity checks - require(splitter.live() == 1, "Splitter not live"); - require(splitter.vat() == address(dss.vat), "Splitter vat mismatch"); - require(splitter.usdsJoin() == cfg.usdsJoin, "Splitter usdsJoin mismatch"); - require(mom.splitter() == splitterInstance.splitter, "Mom splitter mismatch"); - - require(cfg.hump > 0, "hump too low"); - require(cfg.bump % RAY == 0, "bump not multiple of RAY"); - require(cfg.hop >= 5 minutes, "hop too low"); - require(cfg.burn <= WAD, "burn too high"); - - splitter.file("hop", cfg.hop); - splitter.file("burn", cfg.burn); - splitter.rely(address(mom)); - splitter.rely(address(dss.vow)); - - dss.vow.file("flapper", splitterInstance.splitter); - dss.vow.file("hump", cfg.hump); - dss.vow.file("bump", cfg.bump); - - mom.setAuthority(dss.chainlog.getAddress("MCD_ADM")); - - dss.chainlog.setAddress(cfg.splitterChainlogKey, splitterInstance.splitter); - if (cfg.prevMomChainlogKey != bytes32(0)) dss.chainlog.removeAddress(cfg.prevMomChainlogKey); - dss.chainlog.setAddress(cfg.momChainlogKey, address(mom)); - } -} diff --git a/src/dependencies/dss-flappers/SplitterInstance.sol b/src/dependencies/dss-flappers/SplitterInstance.sol deleted file mode 100644 index bb61fb721..000000000 --- a/src/dependencies/dss-flappers/SplitterInstance.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-FileCopyrightText: © 2023 Dai Foundation -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -pragma solidity >=0.8.0; - -struct SplitterInstance { - address splitter; - address mom; -} diff --git a/src/dependencies/lockstake/LockstakeInit.sol b/src/dependencies/lockstake/LockstakeInit.sol deleted file mode 100644 index 57809d25d..000000000 --- a/src/dependencies/lockstake/LockstakeInit.sol +++ /dev/null @@ -1,259 +0,0 @@ -// SPDX-FileCopyrightText: © 2023 Dai Foundation -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -pragma solidity >=0.8.0; - -import { DssInstance } from "dss-test/MCD.sol"; -import { LockstakeInstance } from "./LockstakeInstance.sol"; - -interface LockstakeMkrLike { - function rely(address) external; -} - -interface LockstakeEngineLike { - function voteDelegateFactory() external view returns (address); - function vat() external view returns (address); - function usdsJoin() external view returns (address); - function usds() external view returns (address); - function ilk() external view returns (bytes32); - function mkr() external view returns (address); - function lsmkr() external view returns (address); - function fee() external view returns (uint256); - function mkrSky() external view returns (address); - function sky() external view returns (address); - function rely(address) external; - function file(bytes32, address) external; - function file(bytes32, uint256) external; - function addFarm(address) external; -} - -interface LockstakeClipperLike { - function vat() external view returns (address); - function dog() external view returns (address); - function spotter() external view returns (address); - function engine() external view returns (address); - function ilk() external view returns (bytes32); - function rely(address) external; - function file(bytes32, address) external; - function file(bytes32, uint256) external; - function upchost() external; -} - -interface PipLike { - function kiss(address) external; - function rely(address) external; -} - -interface CalcLike { - function file(bytes32, uint256) external; -} - -interface AutoLineLike { - function setIlk(bytes32, uint256, uint256, uint256) external; -} - -interface OsmMomLike { - function setOsm(bytes32, address) external; -} - -interface LineMomLike { - function addIlk(bytes32) external; -} - -interface ClipperMomLike { - function setPriceTolerance(address, uint256) external; -} - -interface StakingRewardsLike { - function stakingToken() external view returns (address); -} - -interface IlkRegistryLike { - function put( - bytes32 _ilk, - address _join, - address _gem, - uint256 _dec, - uint256 _class, - address _pip, - address _xlip, - string memory _name, - string memory _symbol - ) external; -} - -struct LockstakeConfig { - bytes32 ilk; - address voteDelegateFactory; - address usdsJoin; - address usds; - address mkr; - address mkrSky; - address sky; - address[] farms; - uint256 fee; - uint256 maxLine; - uint256 gap; - uint256 ttl; - uint256 dust; - uint256 duty; - uint256 mat; - uint256 buf; - uint256 tail; - uint256 cusp; - uint256 chip; - uint256 tip; - uint256 stopped; - uint256 chop; - uint256 hole; - uint256 tau; - uint256 cut; - uint256 step; - bool lineMom; - uint256 tolerance; - string name; - string symbol; -} - -library LockstakeInit { - uint256 constant internal RATES_ONE_HUNDRED_PCT = 1000000021979553151239153027; - uint256 constant internal WAD = 10**18; - uint256 constant internal RAY = 10**27; - uint256 constant internal RAD = 10**45; - - function initLockstake( - DssInstance memory dss, - LockstakeInstance memory lockstakeInstance, - LockstakeConfig memory cfg - ) internal { - LockstakeEngineLike engine = LockstakeEngineLike(lockstakeInstance.engine); - LockstakeClipperLike clipper = LockstakeClipperLike(lockstakeInstance.clipper); - CalcLike calc = CalcLike(lockstakeInstance.clipperCalc); - - // Sanity checks - require(engine.voteDelegateFactory() == cfg.voteDelegateFactory, "Engine voteDelegateFactory mismatch"); - require(engine.vat() == address(dss.vat), "Engine vat mismatch"); - require(engine.usdsJoin() == cfg.usdsJoin, "Engine usdsJoin mismatch"); - require(engine.usds() == cfg.usds, "Engine usds mismatch"); - require(engine.ilk() == cfg.ilk, "Engine ilk mismatch"); - require(engine.mkr() == cfg.mkr, "Engine mkr mismatch"); - require(engine.lsmkr() == lockstakeInstance.lsmkr, "Engine lsmkr mismatch"); - require(engine.mkrSky() == cfg.mkrSky, "Engine mkrSky mismatch"); - require(engine.sky() == cfg.sky, "Engine sky mismatch"); - require(clipper.ilk() == cfg.ilk, "Clipper ilk mismatch"); - require(clipper.vat() == address(dss.vat), "Clipper vat mismatch"); - require(clipper.engine() == address(engine), "Clipper engine mismatch"); - require(clipper.dog() == address(dss.dog), "Clipper dog mismatch"); - require(clipper.spotter() == address(dss.spotter), "Clipper spotter mismatch"); - - require(cfg.gap <= cfg.maxLine, "gap greater than max line"); - require(cfg.dust <= cfg.hole, "dust greater than hole"); - require(cfg.duty >= RAY && cfg.duty <= RATES_ONE_HUNDRED_PCT, "duty out of boundaries"); - require(cfg.mat >= RAY && cfg.mat < 10 * RAY, "mat out of boundaries"); - require(cfg.buf >= RAY && cfg.buf < 10 * RAY, "buf out of boundaries"); - require(cfg.cusp < RAY, "cusp negative drop value"); - require(cfg.chip < WAD, "chip equal or greater than 100%"); - require(cfg.tip <= 1_000 * RAD, "tip out of boundaries"); - require(cfg.chop >= WAD && cfg.chop < 2 * WAD, "chop out of boundaries"); - require(cfg.tolerance < RAY, "tolerance equal or greater than 100%"); - - dss.vat.init(cfg.ilk); - dss.vat.file(cfg.ilk, "line", cfg.gap); - dss.vat.file("Line", dss.vat.Line() + cfg.gap); - dss.vat.file(cfg.ilk, "dust", cfg.dust); - dss.vat.rely(address(engine)); - dss.vat.rely(address(clipper)); - - AutoLineLike(dss.chainlog.getAddress("MCD_IAM_AUTO_LINE")).setIlk(cfg.ilk, cfg.maxLine, cfg.gap, cfg.ttl); - - dss.jug.init(cfg.ilk); - dss.jug.file(cfg.ilk, "duty", cfg.duty); - - address pip = dss.chainlog.getAddress("PIP_MKR"); - address clipperMom = dss.chainlog.getAddress("CLIPPER_MOM"); - PipLike(pip).kiss(address(dss.spotter)); - PipLike(pip).kiss(address(clipper)); - PipLike(pip).kiss(clipperMom); - PipLike(pip).kiss(address(dss.end)); - // This assumes pip is a standard Osm sourced by a Median - { - address osmMom = dss.chainlog.getAddress("OSM_MOM"); - PipLike(pip).rely(osmMom); - OsmMomLike(osmMom).setOsm(cfg.ilk, pip); - } - - dss.spotter.file(cfg.ilk, "mat", cfg.mat); - dss.spotter.file(cfg.ilk, "pip", pip); - dss.spotter.poke(cfg.ilk); - - dss.dog.file(cfg.ilk, "clip", address(clipper)); - dss.dog.file(cfg.ilk, "chop", cfg.chop); - dss.dog.file(cfg.ilk, "hole", cfg.hole); - dss.dog.rely(address(clipper)); - - LockstakeMkrLike(lockstakeInstance.lsmkr).rely(address(engine)); - - engine.file("jug", address(dss.jug)); - engine.file("fee", cfg.fee); - for (uint256 i = 0; i < cfg.farms.length; i++) { - require(StakingRewardsLike(cfg.farms[i]).stakingToken() == lockstakeInstance.lsmkr, "Farm staking token mismatch"); - engine.addFarm(cfg.farms[i]); - } - engine.rely(address(clipper)); - - clipper.file("buf", cfg.buf); - clipper.file("tail", cfg.tail); - clipper.file("cusp", cfg.cusp); - clipper.file("chip", cfg.chip); - clipper.file("tip", cfg.tip); - clipper.file("stopped", cfg.stopped); - clipper.file("vow", address(dss.vow)); - clipper.file("calc", address(calc)); - clipper.upchost(); - clipper.rely(address(dss.dog)); - clipper.rely(address(dss.end)); - clipper.rely(clipperMom); - - if (cfg.tau > 0) calc.file("tau", cfg.tau); - if (cfg.cut > 0) calc.file("cut", cfg.cut); - if (cfg.step > 0) calc.file("step", cfg.step); - - if (cfg.lineMom) { - LineMomLike(dss.chainlog.getAddress("LINE_MOM")).addIlk(cfg.ilk); - } - - if (cfg.tolerance > 0) { - ClipperMomLike(clipperMom).setPriceTolerance(address(clipper), cfg.tolerance); - } - - IlkRegistryLike(dss.chainlog.getAddress("ILK_REGISTRY")).put( - cfg.ilk, - address(0), - cfg.mkr, - 18, - 7, // New class - pip, - address(clipper), - cfg.name, - cfg.symbol - ); - - dss.chainlog.setAddress("LOCKSTAKE_MKR", lockstakeInstance.lsmkr); - dss.chainlog.setAddress("LOCKSTAKE_ENGINE", address(engine)); - dss.chainlog.setAddress("LOCKSTAKE_CLIP", address(clipper)); - dss.chainlog.setAddress("LOCKSTAKE_CLIP_CALC", address(calc)); - } -} diff --git a/src/dependencies/lockstake/LockstakeInstance.sol b/src/dependencies/lockstake/LockstakeInstance.sol deleted file mode 100644 index d249711d0..000000000 --- a/src/dependencies/lockstake/LockstakeInstance.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-FileCopyrightText: © 2023 Dai Foundation -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -pragma solidity >=0.8.0; - -struct LockstakeInstance { - address lsmkr; - address engine; - address clipper; - address clipperCalc; -} diff --git a/src/test/config.sol b/src/test/config.sol index d43259025..61257e581 100644 --- a/src/test/config.sol +++ b/src/test/config.sol @@ -104,9 +104,9 @@ contract Config { // Values for spell-specific parameters // spellValues = SpellValues({ - deployed_spell: address(0xACA9a90C92647e3d3f04095118192DC80C470955), // populate with deployed spell if deployed - deployed_spell_created: 1729197815, // use `make deploy-info tx=` to obtain the timestamp - deployed_spell_block: 20987749, // use `make deploy-info tx=` to obtain the block number + deployed_spell: address(0), // populate with deployed spell if deployed + deployed_spell_created: 0, // use `make deploy-info tx=` to obtain the timestamp + deployed_spell_block: 0, // use `make deploy-info tx=` to obtain the block number previous_spells: prevSpells, // older spells to ensure are executed first office_hours_enabled: true, // true if officehours is expected to be enabled in the spell expiration_threshold: 30 days // Amount of time before spell expires From 7f5e8ac77a9583c7f70f4b33e31990ccf9da0aa7 Mon Sep 17 00:00:00 2001 From: 0xDecr1pto <0xdecr1pto@proton.me> Date: Fri, 25 Oct 2024 14:49:32 +0300 Subject: [PATCH 02/10] chore: add spell content --- lib/dss-test | 2 +- src/DssSpell.sol | 504 ++++++++---------- src/DssSpell.t.sol | 333 ++++++++++++ .../L1TokenBridgeInstance.sol | 24 + .../L2TokenBridgeInstance.sol | 24 + .../base-token-bridge/L2TokenBridgeSpell.sol | 96 ++++ .../base-token-bridge/TokenBridgeInit.sol | 119 +++++ .../dss-allocator/AllocatorInit.sol | 165 ++++++ .../dss-allocator/AllocatorInstances.sol | 29 + src/test/addresses_mainnet.sol | 9 + src/test/config.sol | 29 +- src/test/rates.sol | 1 + 12 files changed, 1048 insertions(+), 287 deletions(-) create mode 100644 src/dependencies/base-token-bridge/L1TokenBridgeInstance.sol create mode 100644 src/dependencies/base-token-bridge/L2TokenBridgeInstance.sol create mode 100644 src/dependencies/base-token-bridge/L2TokenBridgeSpell.sol create mode 100644 src/dependencies/base-token-bridge/TokenBridgeInit.sol create mode 100644 src/dependencies/dss-allocator/AllocatorInit.sol create mode 100644 src/dependencies/dss-allocator/AllocatorInstances.sol diff --git a/lib/dss-test b/lib/dss-test index f2a2b2bbe..36ff4adbc 160000 --- a/lib/dss-test +++ b/lib/dss-test @@ -1 +1 @@ -Subproject commit f2a2b2bbea71921103c5b7cf3cb1d241b957bec7 +Subproject commit 36ff4adbcb35760614e0d2df864026991c23d028 diff --git a/src/DssSpell.sol b/src/DssSpell.sol index edd9e14c8..92a52858f 100644 --- a/src/DssSpell.sol +++ b/src/DssSpell.sol @@ -20,6 +20,19 @@ import "dss-exec-lib/DssExec.sol"; import "dss-exec-lib/DssAction.sol"; import { DssInstance, MCD } from "dss-test/MCD.sol"; +import { BridgesConfig, TokenBridgeInit } from "./dependencies/base-token-bridge/TokenBridgeInit.sol"; +import { L1TokenBridgeInstance } from "./dependencies/base-token-bridge/L1TokenBridgeInstance.sol"; +import { L2TokenBridgeInstance } from "./dependencies/base-token-bridge/L2TokenBridgeInstance.sol"; +import { AllocatorSharedInstance, AllocatorIlkInstance } from "./dependencies/dss-allocator/AllocatorInstances.sol"; +import { AllocatorInit, AllocatorIlkConfig } from "./dependencies/dss-allocator/AllocatorInit.sol"; + +interface DssLitePsmLike { + function kiss(address usr) external; +} + +interface MedianLike { + function lift(address[] memory a) external; +} contract DssSpellAction is DssAction { // Provides a descriptive tag for bot consumption @@ -47,302 +60,225 @@ contract DssSpellAction is DssAction { // https://ipfs.io/ipfs/QmVp4mhhbwWGTfbh2BzwQB9eiBrQBKiqcPRZCaAxNUaar6 // // uint256 internal constant X_PCT_RATE = ; + uint256 internal constant FIVE_PT_TWO_PCT_RATE = 1000000001607468111246255079; + + // --- Math --- + uint256 internal constant RAD = 10 ** 45; + + address internal immutable USDS = DssExecLib.getChangelogAddress("USDS"); + address internal immutable SUSDS = DssExecLib.getChangelogAddress("SUSDS"); + address internal immutable ILK_REGISTRY = DssExecLib.getChangelogAddress("ILK_REGISTRY"); + address internal immutable LITE_PSM = DssExecLib.getChangelogAddress("MCD_LITE_PSM_USDC_A"); + + // ---------- BASE Token Bridge ---------- + // Mainnet addresses + address internal constant BASE_GOV_RELAY = 0x1Ee0AE8A993F2f5abDB51EAF4AC2876202b65c3b; + address internal constant BASE_ESCROW = 0x7F311a4D48377030bD810395f4CCfC03bdbe9Ef3; + address internal constant BASE_TOKEN_BRIDGE = 0xA5874756416Fa632257eEA380CAbd2E87cED352A; + address internal constant BASE_TOKEN_BRIDGE_IMP = 0xaeFd31c2e593Dc971f9Cb42cBbD5d4AD7F1970b6; + address internal constant MESSANGER = 0x866E82a600A1414e583f7F13623F1aC5d58b0Afa; + // BASE addresses + address internal constant BASE_GOV_RELAY_L2 = 0xdD0BCc201C9E47c6F6eE68E4dB05b652Bb6aC255; + address internal constant BASE_TOKEN_BRIDGE_L2 = 0xee44cdb68D618d58F75d9fe0818B640BD7B8A7B7; + address internal constant BASE_TOKEN_BRIDGE_IMP_L2 = 0x289A37BE5D6CCeF7A8f2b90535B3BB6bD3905f72; + address internal constant USDS_L2 = 0x820C137fa70C8691f0e44Dc420a5e53c168921Dc; + address internal constant SUSDS_L2 = 0x5875eEE11Cf8398102FdAd704C9E96607675467a; + address internal constant SPELL_L2 = 0x6f29C3A29A3F056A71FB0714551C8D3547268D62; + address internal constant MESSANGER_L2 = 0x4200000000000000000000000000000000000007; + + // ---------- Allocator System ---------- + address internal constant ALLOCATOR_ROLES = 0x9A865A710399cea85dbD9144b7a09C889e94E803; + address internal constant ALLOCATOR_REGISTRY = 0xCdCFA95343DA7821fdD01dc4d0AeDA958051bB3B; + address internal constant PIP_ALLOCATOR_SPARK_A = 0xc7B91C401C02B73CBdF424dFaaa60950d5040dB7; + address internal constant ALLOCATOR_SPARK_BUFFER = 0xc395D150e71378B47A1b8E9de0c1a83b75a08324; + address internal constant ALLOCATOR_SPARK_VAULT = 0x691a6c29e9e96dd897718305427Ad5D534db16BA; + address internal constant ALLOCATOR_SPARK_OWNER = 0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB; + + // ---------- Medians and Validators ---------- + address internal constant ETH_GLOBAL_VALIDATOR = 0xcfC62b2269521e3212Ce1b6670caE6F0e34E8bF3; + address internal constant MANTLE_VALIDATOR = 0xFa6eb665e067759ADdE03a8E6bD259adBd1D70c9; + address internal constant NETHERMIND_VALIDATOR = 0x91242198eD62F9255F2048935D6AFb0C2302D147; + address internal constant EULER_VALIDATOR = 0x1DCB8CcC022938e102814F1A299C7ae48A8BAAf6; + address internal constant BTC_USD_MEDIAN = 0xe0F30cb149fAADC7247E953746Be9BbBB6B5751f; + address internal constant ETH_USD_MEDIAN = 0x64DE91F5A373Cd4c28de3600cB34C7C6cE410C85; + address internal constant WSTETH_USD_MEDIAN = 0x2F73b6567B866302e132273f67661fB89b5a66F2; + address internal constant MKR_USD_MEDIAN = 0xdbBe5e9B1dAa91430cF0772fCEbe53F6c6f137DF; + + // ---------- Spark Proxy Spell ---------- + // Spark Proxy: https://github.com/marsfoundation/sparklend-deployments/blob/bba4c57d54deb6a14490b897c12a949aa035a99b/script/output/1/primary-sce-latest.json#L2 + address internal constant SPARK_PROXY = 0x3300f198988e4C9C63F75dF86De36421f06af8c4; function actions() public override { // Note: multple actions in the spell depend on DssInstance DssInstance memory dss = MCD.loadFromChainlog(DssExecLib.LOG); - // ---------- Setup new MkrOsm ---------- - // Forum: https://forum.sky.money/t/atlas-weekly-cycle-edit-proposal-week-of-october-14-2024-01/25324 - // Poll: https://vote.makerdao.com/polling/QmUm8Krq - - // Whitelist MkrOsm to read from current PIP_MKR using `DssExecLib.addReaderToWhitelist` with the following parameters: - // Set parameter address _oracle: PIP_MKR address from chainlog (0xdbbe5e9b1daa91430cf0772fcebe53f6c6f137df) - // Set parameter address _reader: 0x4F94e33D0D74CfF5Ca0D3a66F1A650628551C56b - DssExecLib.addReaderToWhitelist(PIP_MKR, NEW_PIP_MKR); - - // Set MkrOsm as "PIP_MKR" in the chainlog using the following parameters: - // Set parameter bytes32 _key: "PIP_MKR" - // Set parameter address _val: 0x4F94e33D0D74CfF5Ca0D3a66F1A650628551C56b - DssExecLib.setChangelogAddress("PIP_MKR", NEW_PIP_MKR); - - // ---------- Setup new VoteDelegateFactory ---------- - // Forum: https://forum.sky.money/t/atlas-weekly-cycle-edit-proposal-week-of-october-14-2024-01/25324 - // Poll: https://vote.makerdao.com/polling/QmUm8Krq - - // Rename "VOTE_DELEGATE_PROXY_FACTORY" to "VOTE_DELEGATE_FACTORY_LEGACY" in chainlog: - // Note: this is a meta instruction, actual instructions are below - - // Call DssExecLib.setChangelogAddress with the following parameters: - // Set parameter bytes32 _key: "VOTE_DELEGATE_FACTORY_LEGACY" - // Set parameter address _val: VOTE_DELEGATE_PROXY_FACTORY address (0xd897f108670903d1d6070fcf818f9db3615af272) from the chainlog - DssExecLib.setChangelogAddress("VOTE_DELEGATE_FACTORY_LEGACY", VOTE_DELEGATE_PROXY_FACTORY); - - // Call CHAINLOG.removeAddress with the following parameters: - // Set parameter bytes32 _key: "VOTE_DELEGATE_PROXY_FACTORY" - dss.chainlog.removeAddress("VOTE_DELEGATE_PROXY_FACTORY"); - - // Set "VOTE_DELEGATE_FACTORY" in the chainlog to 0xC3D809E87A2C9da4F6d98fECea9135d834d6F5A0 - DssExecLib.setChangelogAddress("VOTE_DELEGATE_FACTORY", VOTE_DELEGATE_FACTORY); - - // ---------- Setup Lockstake Engine ---------- - // Forum: https://forum.sky.money/t/atlas-weekly-cycle-edit-proposal-week-of-october-14-2024-01/25324 - // Poll: https://vote.makerdao.com/polling/QmUm8Krq - - // SBE Parameter Changes - // Note: this is a subheading, actual instructions are below - - // Decrease splitter "burn" rate by 30% from 100% to 70% with the following parameters: - // Decrease splitter "burn" with address _base: MCD_SPLIT from chainlog - // Decrease splitter "burn" with bytes32 _what: "burn" - // Decrease splitter "burn" with uint256 _amt: 70% - DssExecLib.setValue(MCD_SPLIT, "burn", 70 * WAD / 100); - - // Increase vow.hump by 5 million DAI, from 55 million DAI to 60 million DAI - DssExecLib.setValue(MCD_VOW, "hump", 60 * MILLION * RAD); - - // Increase splitter.hop by 4,014 seconds, from 11,635 seconds to 15,649 seconds. - DssExecLib.setValue(MCD_SPLIT, "hop", 15_649); - - // Set Flapper farm by calling FlapperInit.setFarm with the following parameters: - FlapperInit.setFarm( - - // Note: FlapperInit.setFarm requires DssInstance - dss, - - // Set Flapper farm with address farm_ : 0x92282235a39bE957fF1f37619fD22A9aE5507CB1 - REWARDS_LSMKR_USDS, - - FarmConfig({ - // Set Flapper farm with address splitter: MCD_SPLIT from chainlog - splitter: MCD_SPLIT, - - // Set Flapper farm with address usdsJoin: USDS_JOIN from chainlog - usdsJoin: USDS_JOIN, - - // Set Flapper farm with uint256 hop: 15,649 - hop: 15_649 seconds, - - // Set Flapper farm with bytes32 prevChainlogKey: bytes32(0) - prevChainlogKey: bytes32(0), - - // Set Flapper farm with chainlogKey: "REWARDS_LSMKR_USDS" - chainlogKey: "REWARDS_LSMKR_USDS" - }) - ); - - // "Under the hood" actions for setting flapper: - // LsMkrUsdsFarm will be set as "farm" in MCD_SPLIT - // MCD_SPLIT will be set as "rewardsDistribution" in LsMkrUsdsFarm - // Provided "hop" will be set as "rewardsDuration" in LsMkrUsdsFarm - // New chainlog key REWARDS_LSMKR_USDS will be added - // Note: above instructions are taken inside FlapperInit.setFarm method - - // Note: prepare "farms" variable used inside Lockstake init call below - address[] memory farms = new address[](1); - farms[0] = REWARDS_LSMKR_USDS; - - // Init Lockstake Engine by calling LockstakeInit.initLockstake with the following parameters: - LockstakeInit.initLockstake( - - // Note: LockstakeInit.initLockstake requires DssInstance - dss, - - LockstakeInstance({ - // Init Lockstake Engine with address lsmkr: 0xb4e0e45e142101dC3Ed768bac219fC35EDBED295 - lsmkr: LOCKSTAKE_MKR, - - // Init Lockstake Engine with address engine: 0x2b16C07D5fD5cC701a0a871eae2aad6DA5fc8f12 - engine: LOCKSTAKE_ENGINE, - - // Init Lockstake Engine with address clipper: 0xA85621D35cAf9Cf5C146D2376Ce553D7B78A6239 - clipper: LOCKSTAKE_CLIP, - - // Init Lockstake Engine with address clipperCalc: 0xf13cF3b39823CcfaE6C2354dA56416C80768474e - clipperCalc: LOCKSTAKE_CLIP_CALC - }), - - LockstakeConfig({ - // Init Lockstake Engine with bytes32 ilk: "LSE-MKR-A" - ilk: "LSE-MKR-A", - - // Init Lockstake Engine with address voteDelegateFactory: 0xC3D809E87A2C9da4F6d98fECea9135d834d6F5A0 - voteDelegateFactory: VOTE_DELEGATE_FACTORY, - - // Init Lockstake Engine with address usdsJoin: USDS_JOIN from chainlog - usdsJoin: USDS_JOIN, - - // Init Lockstake Engine with address usds: USDS from chainlog - usds: USDS, - - // Init Lockstake Engine with address mkr: MCD_GOV from chainlog - mkr: MCD_GOV, - - // Init Lockstake Engine with address mkrSky: MKR_SKY from chainlog - mkrSky: MKR_SKY, - - // Init Lockstake Engine with address sky: SKY from chainlog - sky: SKY, - - // Init Lockstake Engine with address[] farms: 0x92282235a39bE957fF1f37619fD22A9aE5507CB1 - farms: farms, - - // Init Lockstake Engine with uint256 fee: 5% - fee: 5 * WAD / 100, - - // Init Lockstake Engine with uint256 maxLine: 20 million DAI - maxLine: 20 * MILLION * RAD, + // ---------- Init Base Token Bridge for USDS and sUSDS tokens ---------- + // Forum: TODO + // + // Set Escrow contract for L1 Bridge + // Register USDS, sUSDS on L1 Bridge + // Give max approval on Enscrow contract for L1 Bridge (USDS, sUSDS tokens) + // Execute L2 Bridge spell through Gov Relay (register nad set maxWithdrawals for USDS, sUSDS tokens on L2 Bridge) + // Set BASE_GOV_RELAY, BASE_ENSCROW, BASE_TOKEN_BRIDGE and BASE_TOKEN_BRIDGE_IMP ro CHAINLOG + + // Mainnet Token Bridge instace + L1TokenBridgeInstance memory l1BridgeInstance = L1TokenBridgeInstance({ + govRelay: BASE_GOV_RELAY, + escrow: BASE_ESCROW, + bridge: BASE_TOKEN_BRIDGE, + bridgeImp: BASE_TOKEN_BRIDGE_IMP + }); + + // Base Token Bridge instace + L2TokenBridgeInstance memory l2BridgeInstance = L2TokenBridgeInstance({ + govRelay: BASE_GOV_RELAY_L2, + bridge: BASE_TOKEN_BRIDGE_L2, + bridgeImp: BASE_TOKEN_BRIDGE_IMP_L2, + spell: SPELL_L2 + }); + + // Array with mainnet tokens + address[] memory l1Tokens = new address[](2); + l1Tokens[0] = USDS; + l1Tokens[1] = SUSDS; + + // Array with Base tokens + address[] memory l2Tokens = new address[](2); + l2Tokens[0] = USDS_L2; + l2Tokens[1] = SUSDS_L2; + + // Max withdrawals for Base tokens + uint256[] memory maxWithdrawals = new uint256[](2); + maxWithdrawals[0] = type(uint256).max; + maxWithdrawals[1] = type(uint256).max; + + BridgesConfig memory bridgeCfg = BridgesConfig({ + // Mainnet CrossDomain Messanger + l1Messenger: MESSANGER, + // Base CrossDomain Messanger + l2Messenger: MESSANGER_L2, + // Mainnet tokens (USDS, sUSDS) + l1Tokens: l1Tokens, + // Base tokens (USDS, sUSDS) + l2Tokens: l2Tokens, + // Max withdrawals for USDS, sUSDS + maxWithdraws: maxWithdrawals, + // Min gas for bridging + minGasLimit: 500_000, + // Chainlog key for Base Gov Relay Contract + govRelayCLKey: "BASE_GOV_RELAY", + // Chainlog key for Base Escrow Contract + escrowCLKey: "BASE_ESCROW", + // Chainlog key for Base Token Bridge Contract + l1BridgeCLKey: "BASE_TOKEN_BRIDGE", + // Chainlog key for Base Token Bridge Implementaion Contract + l1BridgeImpCLKey: "BASE_TOKEN_BRIDGE_IMP" + }); + + // Init Base Token Bridge for USDS and sUSDS + TokenBridgeInit.initBridges(dss, l1BridgeInstance, l2BridgeInstance, bridgeCfg); + + + // ---------- Init Allocator ILK for Spark Subdao ---------- + // Forum: TODO + // + // Init ALLOCATOR-SPARK-A ilk on vat, jug and spotter + // Set duty on jug to 5.2% + // Set line on vat + // Increase Global Line on vat + // Setup AutoLine for ALLOCATOR-SPARK-A: + // line: 10_000_000 + // gap: 2_500_000 + // ttl: 86_400 seconds + // Set spotter.pip for ALLOCATOR-SPARK-A to AllocatorOracle contract + // Set spotter.mat for ALLOCATOR-SPARK-A to RAY + // poke ALLOCATOR-SPARK-A (spotter.poke) + // Add AllocatorBuffer address to AllocatorRegistry + // Initiate the allocator vault by calling vat.slip & vat.grab + // Set jug on AllocatorVault + // Allow vault to pull funds from the buffer by giving max USDS approval + // Set the allocator proxy as the ALLOCATOR-SPARK-A ilk admin instead of the Pause Proxy on AllocatorRoles + // Move ownership of AllocatorVault & AllocatorBuffer to AllocatorProxy (SparkProxy) + // Add Allocator contracts to chainlog (ALLOCATOR_ROLES, ALLOCATOR_REGISTRY, ALLOCATOR_SPARK_A_VAULT, ALLOCATOR_SPARK_A_BUFFER, PIP_ALLOCATOR_SPARK_A) + // Add ALLOCATOR-SPARK-A ilk to IlkRegistry + + + // Allocator shared contracts instance + AllocatorSharedInstance memory allocatorSharedInstance = AllocatorSharedInstance({ + oracle: PIP_ALLOCATOR_SPARK_A, + roles: ALLOCATOR_ROLES, + registry: ALLOCATOR_REGISTRY + }); + + // Allocator ALLOCATOR-SPARK-A ilk contracts instance + AllocatorIlkInstance memory allocatorIlkInstance = AllocatorIlkInstance({ + owner: ALLOCATOR_SPARK_OWNER, + vault: ALLOCATOR_SPARK_VAULT, + buffer: ALLOCATOR_SPARK_BUFFER + }); + + // Allocator init config + AllocatorIlkConfig memory allocatorIlkCfg = AllocatorIlkConfig({ + // Init ilk for ALLOCATOR-SPARK-A + ilk : "ALLOCATOR-SPARK-A", + // jug.duty -> 5.2% + duty : FIVE_PT_TWO_PCT_RATE, + // Autoline line -> 10_000_000 + maxLine : 10_000_000 * RAD, + // Autoline gap -> 2_500_000 + gap : 2_500_000 * RAD, + // Autoline ttl -> 1 day + ttl : 86_400 seconds, + // Spark Proxy -> 0x3300f198988e4C9C63F75dF86De36421f06af8c4 + allocatorProxy : SPARK_PROXY, + // Ilk Registry -> 0x5a464c28d19848f44199d003bef5ecc87d090f87 + ilkRegistry : ILK_REGISTRY + }); + + // Init allocator shared contracts + AllocatorInit.initShared(dss, allocatorSharedInstance); + + // Init allocator system for ALLOCATOR-SPARK-A ilk + AllocatorInit.initIlk(dss, allocatorSharedInstance, allocatorIlkInstance, allocatorIlkCfg); + + + // ---------- Whitelist Spark ALM Proxy on the PSM ---------- + // Forum: TODO + DssLitePsmLike(LITE_PSM).kiss(SPARK_PROXY); + + + // ---------- Add new validators for Median (Medianizer) ---------- + // Forum: TODO + + address[] memory validators = new address[](4); + validators[0] = ETH_GLOBAL_VALIDATOR; + validators[1] = MANTLE_VALIDATOR; + validators[2] = NETHERMIND_VALIDATOR; + validators[3] = EULER_VALIDATOR; + + MedianLike(BTC_USD_MEDIAN).lift(validators); + MedianLike(ETH_USD_MEDIAN).lift(validators); + MedianLike(WSTETH_USD_MEDIAN).lift(validators); + MedianLike(MKR_USD_MEDIAN).lift(validators); + + + // ---------- Set up Governance Facilitator Streams ---------- + // Forum: TODO + + + // ---------- September 2024 AD compensation ---------- + // Forum: TODO - // Init Lockstake Engine with uint256 gap: 5 million - gap: 5 * MILLION * RAD, - // Init Lockstake Engine with uint256 ttl: 16 hours - ttl: 16 hours, - - // Init Lockstake Engine with uint256 dust: 30,000 DAI - dust: 30_000 * RAD, - - // Init Lockstake Engine with uint256 duty: 12% - duty: TWELVE_PCT_RATE, - - // Init Lockstake Engine with uint256 mat: 200% - mat: 200 * RAY / 100, - - // Init Lockstake Engine with uint256 buf: 1.20 - buf: 120 * RAY / 100, - - // Init Lockstake Engine with uint256 tail: 6,000 seconds - tail: 6_000 seconds, - - // Init Lockstake Engine with uint256 cusp: 0.40 - cusp: 40 * RAY / 100, - - // Init Lockstake Engine with uint256 chip: 0.1% - chip: 1 * WAD / 1000, - - // Init Lockstake Engine with uint256 tip: 300 DAI - tip: 300 * RAD, - - // Init Lockstake Engine with uint256 stopped: 0 - stopped: 0, - - // Init Lockstake Engine with uint256 chop: 8% - chop: 108 * WAD / 100, - - // Init Lockstake Engine with uint256 hole: 3 million DAI - hole: 3 * MILLION * RAD, - - // Init Lockstake Engine with uint256 tau: 0 - tau: 0, - - // Init Lockstake Engine with uint256 cut: 0.99 - cut: 99 * RAY / 100, - - // Init Lockstake Engine with uint256 step: 60 seconds - step: 60 seconds, - - // Init Lockstake Engine with bool lineMom: true - lineMom: true, - - // Init Lockstake Engine with uint256 tolerance: 0.5 - tolerance: 5 * RAY / 10, - - // Init Lockstake Engine with string name: "LockstakeMkr" - name: "LockstakeMkr", - - // Init Lockstake Engine with string symbol: "lsMKR" - symbol: "lsMKR" - }) - ); - - // "Under the hood" actions for Init Lockstake Engine: - // New collateral type "LSE-MKR-A" will be added to "vat", "jug", "spotter", "dog" contracts - // New collateral type "LSE-MKR-A" will be added to LINE_MOM - // New collateral type "LSE-MKR-A" will be added to auto-line using provided maxLine, gap and ttl - // New collateral type "LSE-MKR-A" will be added to ILK_REGISTRY with provided values ("name", "symbol") and the new ilk class 7 - // The new MKR OSM will allow MCD_SPOT, CLIPPER_MOM, LOCKSTAKE_CLIP, MCD_END to access its price. - // PIP_MKR will be added to OSM_MOM - // LockstakeClipper will be configured using provided values ("buf", "tail", "cusp", "chip", "tip", "stopped", "clip", "tolerance") - // StairstepExponentialDecrease calc contract will be configured using provided values ("cut", "step") - // The LsMkrUsdsFarm will be added to the LockstakeEngine as a first farm - // LockstakeEngine will be authorized to access "vat" - // LockstakeClipper will be authorized to access "vat" and LockstakeEngine - // CLIPPER_MOM, MCD_DOG and MCD_END will be authorized to access LockstakeClipper - // New chainlog keys LOCKSTAKE_MKR, LOCKSTAKE_ENGINE, LOCKSTAKE_CLIP and LOCKSTAKE_CLIP_CALC will be added - // OSM_MOM will be authorized to access the new MKR OSM - // Note: above instructions are taken inside LockstakeInit.initLockstake method - - // ---------- Fund Early Bird Rewards Multisig ---------- - // Forum: https://forum.sky.money/t/atlas-weekly-cycle-edit-proposal-week-of-october-14-2024-01/25324#p-99402-early-bird-bonus-3 - // Poll: https://vote.makerdao.com/polling/QmUm8Krq - - // Mint 27,222,832.80 SKY to 0x14D98650d46BF7679BBD05D4f615A1547C87Bf68 - SkyLike(SKY).mint(EARLY_BIRD_REWARDS, 27_222_832.80 ether); // Note: ether is only a keyword helper - - // ---------- Lower Deprecated RWA Debt Ceilings ---------- - // Forum: https://forum.sky.money/t/2024-10-17-expected-executive-contents-rwa-vault-changes/25323 - - // Remove RWA007-A from Debt Ceiling Instant Access Module - DssExecLib.removeIlkFromAutoLine("RWA007-A"); - - // Note: in order to decrease global debt ceiling, we need to fetch current `line` - (,,, uint256 line1,) = VatAbstract(MCD_VAT).ilks("RWA007-A"); - - // Set RWA007-A Debt Ceiling to 0 - DssExecLib.setIlkDebtCeiling("RWA007-A", 0); - - // Initiate RWA007-A soft liquidation by calling `tell()` - RwaLiquidationOracleLike(MIP21_LIQUIDATION_ORACLE).tell("RWA007-A"); - - // Write-off the debt of RWA007-A and set its oracle price to 0 by calling `cull()` - RwaLiquidationOracleLike(MIP21_LIQUIDATION_ORACLE).cull("RWA007-A", RWA007_A_URN); - - // Note: update the spot value in vat by propagating the price - DssExecLib.updateCollateralPrice("RWA007-A"); - - // Note: in order to decrease global debt ceiling, we need to fetch current `line` - (,,, uint256 line2,) = VatAbstract(MCD_VAT).ilks("RWA014-A"); - - // Reduce RWA014-A Debt Ceiling by 1.5 billion Dai from 1.5 billion Dai to 0 - DssExecLib.setIlkDebtCeiling("RWA014-A", 0); - - // Initiate RWA014-A soft liquidation by calling `tell()` - RwaLiquidationOracleLike(MIP21_LIQUIDATION_ORACLE).tell("RWA014-A"); - - // Write-off the debt of RWA014-A and set its oracle price to 0 by calling `cull()` - RwaLiquidationOracleLike(MIP21_LIQUIDATION_ORACLE).cull("RWA014-A", RWA014_A_URN); - - // Note: update the spot value in vat by propagating the price - DssExecLib.updateCollateralPrice("RWA014-A"); - - // Note: decrease global line - VatAbstract(MCD_VAT).file("Line", VatAbstract(MCD_VAT).Line() - (line1 + line2)); - - // ---------- Pinwheel DAO Resolution ---------- - // Forum: https://forum.sky.money/t/coinbase-web3-wallet-legal-overview/24577/3 - - // Approve DAO Resolution at QmYJUvw5xbAJmJknG2xUKDLe424JSTWQQhbJCnucRRjUv7 - // Note: see `dao_resolutions` public variable declared above - - // ---------- AAVE Revenue Share Payment ---------- - // Forum: https://forum.sky.money/t/spark-aave-revenue-share-calculation-payment-5-q3-2024/25286 - - // AAVE Revenue Share - 234089 DAI - 0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c - DssExecLib.sendPaymentFromSurplusBuffer(AAVE_V3_TREASURY, 234_089); - - // ---------- Spark Spell ---------- - // Forum: https://forum.sky.money/t/oct-3-2024-proposed-changes-to-spark-for-upcoming-spell/25293 - // Poll: https://vote.makerdao.com/polling/QmbHaA2G - // Poll: https://vote.makerdao.com/polling/QmShWccA - // Poll: https://vote.makerdao.com/polling/QmTksxrr + // ---------- Chainlog bump ---------- + // Note: we need to increase chainlog version as D3MInit.initCommon added new keys + DssExecLib.setChangelogVersion("1.19.3"); - // Execute Spark Proxy Spell at 0xcc3B9e79261A7064A0f734Cc749A8e3762e0a187 - ProxyLike(SPARK_PROXY).exec(SPARK_SPELL, abi.encodeWithSignature("execute()")); // ---------- Chainlog bump ---------- // Note: we have to patch chainlog version as new collateral is added - DssExecLib.setChangelogVersion("1.19.2"); + DssExecLib.setChangelogVersion("1.19.3"); } } diff --git a/src/DssSpell.t.sol b/src/DssSpell.t.sol index a015a9b6f..acfed5fa9 100644 --- a/src/DssSpell.t.sol +++ b/src/DssSpell.t.sol @@ -49,11 +49,91 @@ interface SequencerLike { function hasJob(address job) external view returns (bool); } +interface AuthLike { + function wards(address) external view returns (uint256); +} + +interface L1TokenBridgeLike { + function l1ToL2Token(address) external view returns (address); + function isOpen() external view returns (uint256); + function escrow() external view returns (address); + function otherBridge() external view returns (address); + function messenger() external view returns (address); + function version() external view returns (string memory); + function getImplementation() external view returns (address); + function bridgeERC20To( + address _localToken, + address _remoteToken, + address _to, + uint256 _amount, + uint32 _minGasLimit, + bytes memory _extraData + ) external; +} + +interface L2TokenBridgeLike { + function l1ToL2Token(address) external view returns (address); + function isOpen() external view returns (uint256); + function escrow() external view returns (address); + function otherBridge() external view returns (address); + function messenger() external view returns (address); + function version() external view returns (string memory); + function maxWithdraws(address) external view returns (uint256); + function getImplementation() external view returns (address); + function bridgeERC20To( + address _localToken, + address _remoteToken, + address _to, + uint256 _amount, + uint32 _minGasLimit, + bytes memory _extraData + ) external; +} + +interface BaseGovRelayLike { + function l2GovernanceRelay() external view returns (address); + function l1GovernanceRelay() external view returns (address); + function messenger() external view returns (address); +} + +interface L2BridgeSpell { + function l2Bridge() external view returns (address); +} + +interface AllocatorVaultLike { + function buffer() external view returns (address); + function draw(uint256 wad) external; + function ilk() external view returns (bytes32); + function jug() external view returns (address); + function roles() external view returns (address); + function usdsJoin() external view returns (address); + function vat() external view returns (address); + function wards(address) external view returns (uint256); + function wipe(uint256 wad) external; +} + +interface AllocatorRegistryLike { + function buffers(bytes32) external view returns (address); +} + +interface AllocatorRolesLike { + function ilkAdmins(bytes32) external view returns (address); +} + +interface DssLitePsm { + function bud(address) external view returns (uint256); +} + +interface MedianLike { + function orcl(address) external view returns (uint256); +} + contract DssSpellTest is DssSpellTestBase { string config; RootDomain rootDomain; OptimismDomain optimismDomain; ArbitrumDomain arbitrumDomain; + OptimismDomain baseDomain; // DO NOT TOUCH THE FOLLOWING TESTS, THEY SHOULD BE RUN ON EVERY SPELL function testGeneral() public { @@ -969,4 +1049,257 @@ contract DssSpellTest is DssSpellTestBase { } // SPELL-SPECIFIC TESTS GO BELOW + L2TokenBridgeLike immutable l2bridge = L2TokenBridgeLike( 0xee44cdb68D618d58F75d9fe0818B640BD7B8A7B7); + BaseGovRelayLike immutable l2govRelay = BaseGovRelayLike( 0xdD0BCc201C9E47c6F6eE68E4dB05b652Bb6aC255); + L2BridgeSpell immutable l2spell = L2BridgeSpell( 0x6f29C3A29A3F056A71FB0714551C8D3547268D62); + GemAbstract immutable l2usds = GemAbstract( 0x820C137fa70C8691f0e44Dc420a5e53c168921Dc); + GemAbstract immutable l2susds = GemAbstract( 0x5875eEE11Cf8398102FdAd704C9E96607675467a); + GemAbstract immutable susd = GemAbstract( addr.addr("SUSDS")); + L1TokenBridgeLike immutable l1bridge = L1TokenBridgeLike( addr.addr("BASE_TOKEN_BRIDGE")); + BaseGovRelayLike immutable l1govRelay = BaseGovRelayLike( addr.addr("BASE_GOV_RELAY")); + address immutable L1_ESCROW = addr.addr("BASE_ESCROW"); + address immutable L1_BRIDGE_IMP = addr.addr("BASE_TOKEN_BRIDGE_IMP"); + address constant L2_BRIDGE_IMP = 0x289A37BE5D6CCeF7A8f2b90535B3BB6bD3905f72; + address constant MESSANGER = 0x866E82a600A1414e583f7F13623F1aC5d58b0Afa; + address constant L2_MESSANGER = 0x4200000000000000000000000000000000000007; + + address immutable PIP_ALLOCATOR_SPARK = addr.addr("PIP_ALLOCATOR_SPARK_A"); + address immutable ALLOCATOR_ROLES = addr.addr("ALLOCATOR_ROLES"); + address immutable ALLOCATOR_REGISTRY = addr.addr("ALLOCATOR_REGISTRY"); + address immutable ALLOCATOR_SPARK_BUFFER = addr.addr("ALLOCATOR_SPARK_A_BUFFER"); + address immutable ALLOCATOR_SPARK_VAULT = addr.addr("ALLOCATOR_SPARK_A_VAULT"); + address immutable ALLOCATOR_SPARK_PROXY = addr.addr('SPARK_PROXY'); + bytes32 constant ALLOCATOR_ILK = "ALLOCATOR-SPARK-A"; + + address immutable LITE_PSM = addr.addr("MCD_LITE_PSM_USDC_A"); + + // ---------- Medians and Validators ---------- + address constant ETH_GLOBAL_VALIDATOR = 0xcfC62b2269521e3212Ce1b6670caE6F0e34E8bF3; + address constant MANTLE_VALIDATOR = 0xFa6eb665e067759ADdE03a8E6bD259adBd1D70c9; + address constant NETHERMIND_VALIDATOR = 0x91242198eD62F9255F2048935D6AFb0C2302D147; + address constant EULER_VALIDATOR = 0x1DCB8CcC022938e102814F1A299C7ae48A8BAAf6; + address constant BTC_USD_MEDIAN = 0xe0F30cb149fAADC7247E953746Be9BbBB6B5751f; + address constant ETH_USD_MEDIAN = 0x64DE91F5A373Cd4c28de3600cB34C7C6cE410C85; + address constant WSTETH_USD_MEDIAN = 0x2F73b6567B866302e132273f67661fB89b5a66F2; + address constant MKR_USD_MEDIAN = 0xdbBe5e9B1dAa91430cF0772fCEbe53F6c6f137DF; + + function testBaseTokenBridge() public { + _setupRootDomain(); + baseDomain = new OptimismDomain(config, getChain("base"), rootDomain); + + // ------ Sanity checks ------- + + baseDomain.selectFork(); + + require(l2bridge.isOpen() == 1, "L2BaseTokenBridge/not-open"); + require(l2bridge.otherBridge() == address(l1bridge), "L2BaseTokenBridge/other-bridge-mismatch"); + require(keccak256(bytes(l2bridge.version())) == keccak256("1"), "L2BaseTokenBridge/version-does-not-match"); + require(l2bridge.getImplementation() == L2_BRIDGE_IMP, "L2BaseTokenBridge/imp-does-not-match"); + require(l2bridge.messenger() == L2_MESSANGER, "L2BaseTokenBridge/l2-bridge-messenger-mismatch"); + require(l2govRelay.l1GovernanceRelay() == address(l1govRelay), "L2BaseGovRelay/l2-gov-relay-mismatch"); + require(l2govRelay.messenger() == L2_MESSANGER, "L2BaseGovRelay/l2-gov-relay-messenger-mismatch"); + require(l2spell.l2Bridge() == address(l2bridge), "L2Spell/l2-bridge-mismatch"); + + rootDomain.selectFork(); + + require(keccak256(bytes(l1bridge.version())) == keccak256("1"), "BaseTokenBridge/version-does-not-match"); + require(l1bridge.getImplementation() == L1_BRIDGE_IMP, "BaseTokenBridge/imp-does-not-match"); + require(l1bridge.isOpen() == 1, "BaseTokenBridge/not-open"); + require(l1bridge.otherBridge() == address(l2bridge), "BaseTokenBridge/other-bridge-mismatch"); + require(l1bridge.messenger() == MESSANGER, "BaseTokenBridge/l1-bridge-messenger-mismatch"); + require(l1govRelay.l2GovernanceRelay() == address(l2govRelay), "BaseGovRelay/l2-gov-relay-mismatch"); + require(l1govRelay.messenger() == MESSANGER, "BaseGovRelay/l1-gov-relay-messenger-mismatch"); + + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done(), "TestError/spell-not-done"); + + + require(l1bridge.escrow() == L1_ESCROW, "BaseTokenBridge/escrow-does-not-match"); + // // test tokens + assertEq(usds.allowance(L1_ESCROW, address(l1bridge)), type(uint256).max); + assertEq(l1bridge.l1ToL2Token(address(address(usds))), address(l2usds)); + + assertEq(susds.allowance(L1_ESCROW, address(l1bridge)), type(uint256).max); + assertEq(l1bridge.l1ToL2Token(address(address(susds))), address(l2susds)); + + + // switch to Optimism domain and relay the spell from L1 + // the `true` keeps us on Optimism rather than `rootDomain.selectFork() + baseDomain.relayFromHost(true); + + // // test L2 side of initBridges + assertEq(l2bridge.l1ToL2Token(address(susds)), address(l2susds)); + assertEq(l2bridge.maxWithdraws(address(l2susds)), type(uint256).max); + + assertEq(l2bridge.l1ToL2Token(address(usds)), address(l2usds)); + assertEq(l2bridge.maxWithdraws(address(l2usds)), type(uint256).max); + + assertEq(AuthLike(address(l2susds)).wards(address(l2bridge)), 1); + assertEq(AuthLike(address(l2usds)).wards(address(l2bridge)), 1); + + + // ------- Test Deposit ------- + + rootDomain.selectFork(); + + deal(address(usds), address(this), 100 ether); + deal(address(susds), address(this), 100 ether); + assertEq(usds.balanceOf(address(this)), 100 ether); + assertEq(susds.balanceOf(address(this)), 100 ether); + + usds.approve(address(l1bridge), 100 ether); + susds.approve(address(l1bridge), 100 ether); + uint256 escrowBeforeUsds = usds.balanceOf(L1_ESCROW); + uint256 escrowBeforesUsds = susds.balanceOf(L1_ESCROW); + + l1bridge.bridgeERC20To( + address(usds), + address(l2usds), + address(0xb0b), + 100 ether, + 1_000_000, + "" + ); + l1bridge.bridgeERC20To( + address(susds), + address(l2susds), + address(0xb0b), + 100 ether, + 1_000_000, + "" + ); + + assertEq(usds.balanceOf(address(this)), 0); + assertEq(usds.balanceOf(L1_ESCROW), escrowBeforeUsds + 100 ether); + assertEq(susds.balanceOf(address(this)), 0); + assertEq(susds.balanceOf(L1_ESCROW), escrowBeforesUsds + 100 ether); + + baseDomain.relayFromHost(true); + + assertEq(l2usds.balanceOf(address(0xb0b)), 100 ether); + assertEq(l2susds.balanceOf(address(0xb0b)), 100 ether); + + // ------- Test Withdrawal ------- + + vm.startPrank(address(0xb0b)); + + l2usds.approve(address(l2bridge), 100 ether); + l2susds.approve(address(l2bridge), 100 ether); + + l2bridge.bridgeERC20To( + address(l2usds), + address(usds), + address(0xced), + 100 ether, + 1_000_000, + "" + ); + l2bridge.bridgeERC20To( + address(l2susds), + address(susds), + address(0xced), + 100 ether, + 1_000_000, + "" + ); + vm.stopPrank(); + + assertEq(l2usds.balanceOf(address(0xb0b)), 0); + assertEq(l2susds.balanceOf(address(0xb0b)), 0); + + baseDomain.relayToHost(true); + + assertEq(usds.balanceOf(address(0xced)), 100 ether); + assertEq(susds.balanceOf(address(0xced)), 100 ether); + } + + function testSparkAllocator() public { + uint256 previousIlkRegistryCount = reg.count(); + + // Sanity checks + require(AllocatorVaultLike(ALLOCATOR_SPARK_VAULT).ilk() == ALLOCATOR_ILK, "AllocatorInit/vault-ilk-mismatch"); + require(AllocatorVaultLike(ALLOCATOR_SPARK_VAULT).roles() == ALLOCATOR_ROLES, "AllocatorInit/vault-roles-mismatch"); + require(AllocatorVaultLike(ALLOCATOR_SPARK_VAULT).buffer() == ALLOCATOR_SPARK_BUFFER, "AllocatorInit/vault-buffer-mismatch"); + require(AllocatorVaultLike(ALLOCATOR_SPARK_VAULT).vat() == address(vat), "AllocatorInit/vault-vat-mismatch"); + require(AllocatorVaultLike(ALLOCATOR_SPARK_VAULT).usdsJoin() == address(usdsJoin), "AllocatorInit/vault-usds-join-mismatch"); + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done(), "TestError/spell-not-done"); + + + (, uint256 rate, uint256 spot,,) = vat.ilks(ALLOCATOR_ILK); + assertEq(rate, RAY); + assertEq(spot, 10**18 * RAY * 10**9 / spotter.par()); + + (address pip,) = spotter.ilks(ALLOCATOR_ILK); + assertEq(pip, PIP_ALLOCATOR_SPARK); + + assertEq(vat.gem(ALLOCATOR_ILK, ALLOCATOR_SPARK_VAULT), 0); + (uint256 ink, uint256 art) = vat.urns(ALLOCATOR_ILK, ALLOCATOR_SPARK_VAULT); + assertEq(ink, 1_000_000_000_000 * WAD); + assertEq(art, 0); + + assertEq(AllocatorRegistryLike(ALLOCATOR_REGISTRY).buffers(ALLOCATOR_ILK), ALLOCATOR_SPARK_BUFFER); + assertEq(address(AllocatorVaultLike(ALLOCATOR_SPARK_VAULT).jug()), address(jug)); + + assertEq(usds.allowance(ALLOCATOR_SPARK_BUFFER, ALLOCATOR_SPARK_VAULT), type(uint256).max); + + assertEq(AllocatorRolesLike(ALLOCATOR_ROLES).ilkAdmins(ALLOCATOR_ILK), ALLOCATOR_SPARK_PROXY); + + assertEq(AllocatorVaultLike(ALLOCATOR_SPARK_VAULT).wards(pauseProxy), 0); + assertEq(AllocatorVaultLike(ALLOCATOR_SPARK_VAULT).wards(ALLOCATOR_SPARK_PROXY), 1); + + assertEq(AuthLike(ALLOCATOR_SPARK_BUFFER).wards(pauseProxy), 0); + assertEq(AuthLike(ALLOCATOR_SPARK_BUFFER).wards(ALLOCATOR_SPARK_PROXY), 1); + + assertEq(reg.count(), previousIlkRegistryCount + 1); + assertEq(reg.pos(ALLOCATOR_ILK), previousIlkRegistryCount); + assertEq(reg.join(ALLOCATOR_ILK), address(0)); + assertEq(reg.gem(ALLOCATOR_ILK), address(0)); + assertEq(reg.dec(ALLOCATOR_ILK), 0); + assertEq(reg.class(ALLOCATOR_ILK), 5); + assertEq(reg.pip(ALLOCATOR_ILK), PIP_ALLOCATOR_SPARK); + assertEq(reg.xlip(ALLOCATOR_ILK), address(0)); + assertEq(reg.name(ALLOCATOR_ILK), string("ALLOCATOR-SPARK-A")); + assertEq(reg.symbol(ALLOCATOR_ILK), string("ALLOCATOR-SPARK-A")); + + // Draw & Wipe from Vault + vm.prank(address(ALLOCATOR_SPARK_PROXY)); + AllocatorVaultLike(ALLOCATOR_SPARK_VAULT).draw(1_000 * WAD); + assertEq(usds.balanceOf(ALLOCATOR_SPARK_BUFFER), 1_000 * WAD); + + vm.prank(address(ALLOCATOR_SPARK_PROXY)); + AllocatorVaultLike(ALLOCATOR_SPARK_VAULT).wipe(1_000 * WAD); + assertEq(usds.balanceOf(ALLOCATOR_SPARK_BUFFER), 0); + } + + function testsWhitelistSparkProxyOnLitePsm() public { + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done(), "TestError/spell-not-done"); + + assertEq(LitePsmLike(LITE_PSM).bud(ALLOCATOR_SPARK_PROXY), 1); + } + + function testMedianValidators() public { + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done(), "TestError/spell-not-done"); + + address[] memory validators = new address[](4); + validators[0] = ETH_GLOBAL_VALIDATOR; + validators[1] = MANTLE_VALIDATOR; + validators[2] = NETHERMIND_VALIDATOR; + validators[3] = EULER_VALIDATOR; + + for (uint i = 0; i < validators.length; i++) { + assertEq(MedianLike(BTC_USD_MEDIAN).orcl(validators[1]), 1); + assertEq(MedianLike(ETH_USD_MEDIAN).orcl(validators[1]), 1); + assertEq(MedianLike(WSTETH_USD_MEDIAN).orcl(validators[1]), 1); + assertEq(MedianLike(MKR_USD_MEDIAN).orcl(validators[1]), 1); + } + } } diff --git a/src/dependencies/base-token-bridge/L1TokenBridgeInstance.sol b/src/dependencies/base-token-bridge/L1TokenBridgeInstance.sol new file mode 100644 index 000000000..e45f7b261 --- /dev/null +++ b/src/dependencies/base-token-bridge/L1TokenBridgeInstance.sol @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: © 2024 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity >=0.8.0; + +struct L1TokenBridgeInstance { + address govRelay; + address escrow; + address bridge; + address bridgeImp; +} \ No newline at end of file diff --git a/src/dependencies/base-token-bridge/L2TokenBridgeInstance.sol b/src/dependencies/base-token-bridge/L2TokenBridgeInstance.sol new file mode 100644 index 000000000..1e427cef9 --- /dev/null +++ b/src/dependencies/base-token-bridge/L2TokenBridgeInstance.sol @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: © 2024 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity >=0.8.0; + +struct L2TokenBridgeInstance { + address govRelay; + address bridge; + address bridgeImp; + address spell; +} \ No newline at end of file diff --git a/src/dependencies/base-token-bridge/L2TokenBridgeSpell.sol b/src/dependencies/base-token-bridge/L2TokenBridgeSpell.sol new file mode 100644 index 000000000..00fdd510c --- /dev/null +++ b/src/dependencies/base-token-bridge/L2TokenBridgeSpell.sol @@ -0,0 +1,96 @@ +// SPDX-FileCopyrightText: © 2024 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity >=0.8.0; + +interface L2GovRelayLike { + function l1GovernanceRelay() external view returns (address); + function messenger() external view returns (address); +} + +interface L2TokenBridgeLike { + function isOpen() external view returns (uint256); + function otherBridge() external view returns (address); + function messenger() external view returns (address); + function version() external view returns (string memory); + function getImplementation() external view returns (address); + function upgradeToAndCall(address, bytes memory) external; + function rely(address) external; + function deny(address) external; + function close() external; + function registerToken(address, address) external; + function setMaxWithdraw(address, uint256) external; +} + +interface AuthLike { + function rely(address usr) external; +} + +// A reusable L2 spell to be used by the L2GovernanceRelay to exert admin control over L2TokenBridge +contract L2TokenBridgeSpell { + L2TokenBridgeLike public immutable l2Bridge; + + constructor(address l2Bridge_) { + l2Bridge = L2TokenBridgeLike(l2Bridge_); + } + + function upgradeToAndCall(address newImp, bytes memory data) external { l2Bridge.upgradeToAndCall(newImp, data); } + function rely(address usr) external { l2Bridge.rely(usr); } + function deny(address usr) external { l2Bridge.deny(usr); } + function close() external { l2Bridge.close(); } + + function registerTokens(address[] memory l1Tokens, address[] memory l2Tokens) public { + for (uint256 i; i < l2Tokens.length;) { + l2Bridge.registerToken(l1Tokens[i], l2Tokens[i]); + AuthLike(l2Tokens[i]).rely(address(l2Bridge)); + unchecked { ++i; } + } + } + + function setMaxWithdraws(address[] memory l2Tokens, uint256[] memory maxWithdraws) public { + for (uint256 i; i < l2Tokens.length;) { + l2Bridge.setMaxWithdraw(l2Tokens[i], maxWithdraws[i]); + unchecked { ++i; } + } + } + + function init( + address l2GovRelay_, + address l2Bridge_, + address l2BridgeImp, + address l1GovRelay, + address l1Bridge, + address l2Messenger, + address[] calldata l1Tokens, + address[] calldata l2Tokens, + uint256[] calldata maxWithdraws + ) external { + L2GovRelayLike l2GovRelay = L2GovRelayLike(l2GovRelay_); + + // sanity checks + require(address(l2Bridge) == l2Bridge_, "L2TokenBridgeSpell/l2-bridge-mismatch"); + require(keccak256(bytes(l2Bridge.version())) == keccak256("1"), "L2TokenBridgeSpell/version-does-not-match"); + require(l2Bridge.getImplementation() == l2BridgeImp, "L2TokenBridgeSpell/imp-does-not-match"); + require(l2Bridge.isOpen() == 1, "L2TokenBridgeSpell/not-open"); + require(l2Bridge.otherBridge() == l1Bridge, "L2TokenBridgeSpell/other-bridge-mismatch"); + require(l2Bridge.messenger() == l2Messenger, "L2TokenBridgeSpell/l2-bridge-messenger-mismatch"); + require(l2GovRelay.l1GovernanceRelay() == l1GovRelay, "L2TokenBridgeSpell/l1-gov-relay-mismatch"); + require(l2GovRelay.messenger() == l2Messenger, "L2TokenBridgeSpell/l2-gov-relay-messenger-mismatch"); + + registerTokens(l1Tokens, l2Tokens); + setMaxWithdraws(l2Tokens, maxWithdraws); + } +} \ No newline at end of file diff --git a/src/dependencies/base-token-bridge/TokenBridgeInit.sol b/src/dependencies/base-token-bridge/TokenBridgeInit.sol new file mode 100644 index 000000000..daee06211 --- /dev/null +++ b/src/dependencies/base-token-bridge/TokenBridgeInit.sol @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: © 2024 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity >=0.8.0; + +import { DssInstance } from "dss-test/MCD.sol"; +import { L1TokenBridgeInstance } from "./L1TokenBridgeInstance.sol"; +import { L2TokenBridgeInstance } from "./L2TokenBridgeInstance.sol"; +import { L2TokenBridgeSpell } from "./L2TokenBridgeSpell.sol"; + +interface L1TokenBridgeLike { + function l1ToL2Token(address) external view returns (address); + function isOpen() external view returns (uint256); + function otherBridge() external view returns (address); + function messenger() external view returns (address); + function version() external view returns (string memory); + function getImplementation() external view returns (address); + function file(bytes32, address) external; + function registerToken(address, address) external; +} + +interface L1RelayLike { + function l2GovernanceRelay() external view returns (address); + function messenger() external view returns (address); + function relay( + address target, + bytes calldata targetData, + uint32 minGasLimit + ) external; +} + +interface EscrowLike { + function approve(address, address, uint256) external; +} + +struct BridgesConfig { + address l1Messenger; + address l2Messenger; + address[] l1Tokens; + address[] l2Tokens; + uint256[] maxWithdraws; + uint32 minGasLimit; + bytes32 govRelayCLKey; + bytes32 escrowCLKey; + bytes32 l1BridgeCLKey; + bytes32 l1BridgeImpCLKey; +} + +library TokenBridgeInit { + function initBridges( + DssInstance memory dss, + L1TokenBridgeInstance memory l1BridgeInstance, + L2TokenBridgeInstance memory l2BridgeInstance, + BridgesConfig memory cfg + ) internal { + L1RelayLike l1GovRelay = L1RelayLike(l1BridgeInstance.govRelay); + EscrowLike escrow = EscrowLike(l1BridgeInstance.escrow); + L1TokenBridgeLike l1Bridge = L1TokenBridgeLike(l1BridgeInstance.bridge); + + // sanity checks + require(keccak256(bytes(l1Bridge.version())) == keccak256("1"), "TokenBridgeInit/version-does-not-match"); + require(l1Bridge.getImplementation() == l1BridgeInstance.bridgeImp, "TokenBridgeInit/imp-does-not-match"); + require(l1Bridge.isOpen() == 1, "TokenBridgeInit/not-open"); + require(l1Bridge.otherBridge() == l2BridgeInstance.bridge, "TokenBridgeInit/other-bridge-mismatch"); + require(l1Bridge.messenger() == cfg.l1Messenger, "TokenBridgeInit/l1-bridge-messenger-mismatch"); + require(l1GovRelay.l2GovernanceRelay() == l2BridgeInstance.govRelay, "TokenBridgeInit/l2-gov-relay-mismatch"); + require(l1GovRelay.messenger() == cfg.l1Messenger, "TokenBridgeInit/l1-gov-relay-messenger-mismatch"); + require(cfg.l1Tokens.length == cfg.l2Tokens.length, "TokenBridgeInit/token-arrays-mismatch"); + require(cfg.maxWithdraws.length == cfg.l2Tokens.length, "TokenBridgeInit/max-withdraws-length-mismatch"); + require(cfg.minGasLimit <= 1_000_000_000, "TokenBridgeInit/min-gas-limit-out-of-bounds"); + + l1Bridge.file("escrow", address(escrow)); + + for (uint256 i; i < cfg.l1Tokens.length; ++i) { + (address l1Token, address l2Token) = (cfg.l1Tokens[i], cfg.l2Tokens[i]); + require(l1Token != address(0), "TokenBridgeInit/invalid-l1-token"); + require(l2Token != address(0), "TokenBridgeInit/invalid-l2-token"); + require(cfg.maxWithdraws[i] > 0, "TokenBridgeInit/max-withdraw-not-set"); + require(l1Bridge.l1ToL2Token(l1Token) == address(0), "TokenBridgeInit/existing-l1-token"); + + l1Bridge.registerToken(l1Token, l2Token); + escrow.approve(l1Token, address(l1Bridge), type(uint256).max); + } + + l1GovRelay.relay({ + target: l2BridgeInstance.spell, + targetData: abi.encodeCall(L2TokenBridgeSpell.init, ( + l2BridgeInstance.govRelay, + l2BridgeInstance.bridge, + l2BridgeInstance.bridgeImp, + address(l1GovRelay), + address(l1Bridge), + cfg.l2Messenger, + cfg.l1Tokens, + cfg.l2Tokens, + cfg.maxWithdraws + )), + minGasLimit: cfg.minGasLimit + }); + + dss.chainlog.setAddress(cfg.govRelayCLKey, address(l1GovRelay)); + dss.chainlog.setAddress(cfg.escrowCLKey, address(escrow)); + dss.chainlog.setAddress(cfg.l1BridgeCLKey, address(l1Bridge)); + dss.chainlog.setAddress(cfg.l1BridgeImpCLKey, l1BridgeInstance.bridgeImp); + } +} \ No newline at end of file diff --git a/src/dependencies/dss-allocator/AllocatorInit.sol b/src/dependencies/dss-allocator/AllocatorInit.sol new file mode 100644 index 000000000..b87d42ec1 --- /dev/null +++ b/src/dependencies/dss-allocator/AllocatorInit.sol @@ -0,0 +1,165 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity >=0.8.0; + +import { ScriptTools } from "dss-test/ScriptTools.sol"; +import { DssInstance } from "dss-test/MCD.sol"; +import { AllocatorSharedInstance, AllocatorIlkInstance } from "./AllocatorInstances.sol"; + +interface IlkRegistryLike { + function put( + bytes32 _ilk, + address _join, + address _gem, + uint256 _dec, + uint256 _class, + address _pip, + address _xlip, + string calldata _name, + string calldata _symbol + ) external; +} + +interface RolesLike { + function setIlkAdmin(bytes32, address) external; +} + +interface RegistryLike { + function file(bytes32, bytes32, address) external; +} + +interface VaultLike { + function ilk() external view returns (bytes32); + function roles() external view returns (address); + function buffer() external view returns (address); + function vat() external view returns (address); + function usds() external view returns (address); + function file(bytes32, address) external; +} + +interface BufferLike { + function approve(address, address, uint256) external; +} + +interface AutoLineLike { + function setIlk(bytes32, uint256, uint256, uint256) external; +} + +struct AllocatorIlkConfig { + bytes32 ilk; + uint256 duty; + uint256 gap; + uint256 maxLine; + uint256 ttl; + address allocatorProxy; + address ilkRegistry; +} + +function bytes32ToStr(bytes32 _bytes32) pure returns (string memory) { + uint256 len; + while(len < 32 && _bytes32[len] != 0) len++; + bytes memory bytesArray = new bytes(len); + for (uint256 i; i < len; i++) { + bytesArray[i] = _bytes32[i]; + } + return string(bytesArray); +} + +library AllocatorInit { + uint256 constant WAD = 10 ** 18; + uint256 constant RAY = 10 ** 27; + + uint256 constant RATES_ONE_HUNDRED_PCT = 1000000021979553151239153027; + + function initShared( + DssInstance memory dss, + AllocatorSharedInstance memory sharedInstance + ) internal { + dss.chainlog.setAddress("ALLOCATOR_ROLES", sharedInstance.roles); + dss.chainlog.setAddress("ALLOCATOR_REGISTRY", sharedInstance.registry); + } + + // Please note this should be executed by the pause proxy + function initIlk( + DssInstance memory dss, + AllocatorSharedInstance memory sharedInstance, + AllocatorIlkInstance memory ilkInstance, + AllocatorIlkConfig memory cfg + ) internal { + bytes32 ilk = cfg.ilk; + + // Sanity checks + require(VaultLike(ilkInstance.vault).ilk() == ilk, "AllocatorInit/vault-ilk-mismatch"); + require(VaultLike(ilkInstance.vault).roles() == sharedInstance.roles, "AllocatorInit/vault-roles-mismatch"); + require(VaultLike(ilkInstance.vault).buffer() == ilkInstance.buffer, "AllocatorInit/vault-buffer-mismatch"); + require(VaultLike(ilkInstance.vault).vat() == address(dss.vat), "AllocatorInit/vault-vat-mismatch"); + // Once usdsJoin is in the chainlog and adapted to dss-test should also check against it + + // Onboard the ilk + dss.vat.init(ilk); + dss.jug.init(ilk); + + require((cfg.duty >= RAY) && (cfg.duty <= RATES_ONE_HUNDRED_PCT), "AllocatorInit/ilk-duty-out-of-bounds"); + dss.jug.file(ilk, "duty", cfg.duty); + + dss.vat.file(ilk, "line", cfg.gap); + dss.vat.file("Line", dss.vat.Line() + cfg.gap); + AutoLineLike(dss.chainlog.getAddress("MCD_IAM_AUTO_LINE")).setIlk(ilk, cfg.maxLine, cfg.gap, cfg.ttl); + + dss.spotter.file(ilk, "pip", sharedInstance.oracle); + dss.spotter.file(ilk, "mat", RAY); + dss.spotter.poke(ilk); + + // Add buffer to registry + RegistryLike(sharedInstance.registry).file(ilk, "buffer", ilkInstance.buffer); + + // Initiate the allocator vault + dss.vat.slip(ilk, ilkInstance.vault, int256(10**12 * WAD)); + dss.vat.grab(ilk, ilkInstance.vault, ilkInstance.vault, address(0), int256(10**12 * WAD), 0); + + VaultLike(ilkInstance.vault).file("jug", address(dss.jug)); + + // Allow vault to pull funds from the buffer + BufferLike(ilkInstance.buffer).approve(VaultLike(ilkInstance.vault).usds(), ilkInstance.vault, type(uint256).max); + + // Set the allocator proxy as the ilk admin instead of the Pause Proxy + RolesLike(sharedInstance.roles).setIlkAdmin(ilk, cfg.allocatorProxy); + + // Move ownership of the ilk contracts to the allocator proxy + ScriptTools.switchOwner(ilkInstance.vault, ilkInstance.owner, cfg.allocatorProxy); + ScriptTools.switchOwner(ilkInstance.buffer, ilkInstance.owner, cfg.allocatorProxy); + + // Add allocator-specific contracts to changelog + string memory ilkString = ScriptTools.ilkToChainlogFormat(ilk); + dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked(ilkString, "_VAULT"))), ilkInstance.vault); + dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked(ilkString, "_BUFFER"))), ilkInstance.buffer); + dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked("PIP_", ilkString))), sharedInstance.oracle); + + // Add to ilk registry + IlkRegistryLike(cfg.ilkRegistry).put({ + _ilk : ilk, + _join : address(0), + _gem : address(0), + _dec : 0, + _class : 5, // RWAs are class 3, D3Ms and Teleport are class 4 + _pip : sharedInstance.oracle, + _xlip : address(0), + _name : bytes32ToStr(ilk), + _symbol : bytes32ToStr(ilk) + }); + } +} \ No newline at end of file diff --git a/src/dependencies/dss-allocator/AllocatorInstances.sol b/src/dependencies/dss-allocator/AllocatorInstances.sol new file mode 100644 index 000000000..d70193e5d --- /dev/null +++ b/src/dependencies/dss-allocator/AllocatorInstances.sol @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity >=0.8.0; + +struct AllocatorSharedInstance { + address oracle; + address roles; + address registry; +} + +struct AllocatorIlkInstance { + address owner; + address vault; + address buffer; +} \ No newline at end of file diff --git a/src/test/addresses_mainnet.sol b/src/test/addresses_mainnet.sol index 87f3bb6bd..d428f4deb 100644 --- a/src/test/addresses_mainnet.sol +++ b/src/test/addresses_mainnet.sol @@ -518,5 +518,14 @@ contract Addresses { addr["LOCKSTAKE_ENGINE"] = 0x2b16C07D5fD5cC701a0a871eae2aad6DA5fc8f12; addr["LOCKSTAKE_CLIP"] = 0xA85621D35cAf9Cf5C146D2376Ce553D7B78A6239; addr["LOCKSTAKE_CLIP_CALC"] = 0xf13cF3b39823CcfaE6C2354dA56416C80768474e; + addr["BASE_GOV_RELAY"] = 0x1Ee0AE8A993F2f5abDB51EAF4AC2876202b65c3b; + addr["BASE_ESCROW"] = 0x7F311a4D48377030bD810395f4CCfC03bdbe9Ef3; + addr["BASE_TOKEN_BRIDGE"] = 0xA5874756416Fa632257eEA380CAbd2E87cED352A; + addr["BASE_TOKEN_BRIDGE_IMP"] = 0xaeFd31c2e593Dc971f9Cb42cBbD5d4AD7F1970b6; + addr["ALLOCATOR_ROLES"] = 0x9A865A710399cea85dbD9144b7a09C889e94E803; + addr["ALLOCATOR_REGISTRY"] = 0xCdCFA95343DA7821fdD01dc4d0AeDA958051bB3B; + addr["ALLOCATOR_SPARK_A_VAULT"] = 0x691a6c29e9e96dd897718305427Ad5D534db16BA; + addr["ALLOCATOR_SPARK_A_BUFFER"] = 0xc395D150e71378B47A1b8E9de0c1a83b75a08324; + addr["PIP_ALLOCATOR_SPARK_A"] = 0xc7B91C401C02B73CBdF424dFaaa60950d5040dB7; } } diff --git a/src/test/config.sol b/src/test/config.sol index 61257e581..55f6aecbe 100644 --- a/src/test/config.sol +++ b/src/test/config.sol @@ -142,8 +142,8 @@ contract Config { afterSpell.vest_mkr_cap = 2_220 * WAD / 365 days; // In WAD MKR per second afterSpell.vest_sky_cap = 800 * MILLION * WAD / 365 days; // In WAD SKY per second afterSpell.sky_mkr_rate = 24_000; // In whole SKY/MKR units - afterSpell.ilk_count = 68; // Num expected in system - afterSpell.chainlog_version = "1.19.2"; // String expected in system + afterSpell.ilk_count = 69; // Num expected in system + afterSpell.chainlog_version = "1.19.3"; // String expected in system // // Values for all collateral @@ -1849,5 +1849,30 @@ contract Config { calc_cut: 99_00, offboarding: false }); + afterSpell.collaterals["ALLOCATOR-SPARK-A"] = CollateralValues({ + aL_enabled: true, + aL_line: 10 * MILLION, + aL_gap: 2_500_000, + aL_ttl: 24 hours, + line: 0, + dust: 0, + pct: 520, + mat: 10000, + liqType: "", + liqOn: false, + chop: 0, + dog_hole: 0, + clip_buf: 0, + clip_tail: 0, + clip_cusp: 0, + clip_chip: 0, + clip_tip: 0, + clipper_mom: 0, + cm_tolerance: 0, + calc_tau: 0, + calc_step: 0, + calc_cut: 0, + offboarding: false + }); } } diff --git a/src/test/rates.sol b/src/test/rates.sol index 3d20b1e22..79d1f8d1b 100644 --- a/src/test/rates.sol +++ b/src/test/rates.sol @@ -60,6 +60,7 @@ contract Rates { rates[ 475] = 1000000001471536429740616381; rates[ 490] = 1000000001516911765932351183; rates[ 500] = 1000000001547125957863212448; + rates[ 520] = 1000000001607468111246255079; rates[ 525] = 1000000001622535724756171269; rates[ 544] = 1000000001679727448331902751; rates[ 550] = 1000000001697766583380253701; From eeb72498216534fc588ce9933f1492b36e6a8de8 Mon Sep 17 00:00:00 2001 From: 0xDecr1pto <0xdecr1pto@proton.me> Date: Fri, 25 Oct 2024 17:05:35 +0300 Subject: [PATCH 03/10] chore: update dss-tests --- lib/dss-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dss-test b/lib/dss-test index 36ff4adbc..a8a7b151c 160000 --- a/lib/dss-test +++ b/lib/dss-test @@ -1 +1 @@ -Subproject commit 36ff4adbcb35760614e0d2df864026991c23d028 +Subproject commit a8a7b151c39282d4ddab8cb4ead2d80342df588f From c16d97a5c9e35c95b2e16ad436db5a9a22d1b5ed Mon Sep 17 00:00:00 2001 From: 0xDecr1pto <0xdecr1pto@proton.me> Date: Fri, 25 Oct 2024 17:59:00 +0300 Subject: [PATCH 04/10] chore: fix deprecated fail(msg) --- src/DssSpell.t.base.sol | 2 +- src/DssSpell.t.sol | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DssSpell.t.base.sol b/src/DssSpell.t.base.sol index b68430b99..20e45525a 100644 --- a/src/DssSpell.t.base.sol +++ b/src/DssSpell.t.base.sol @@ -2341,7 +2341,7 @@ contract DssSpellTestBase is Config, DssTest { if (ward > 0) { emit log_named_address(" Deployer Address", deployer); emit log_named_string(" Affected Contract", contractName); - fail("Error: Bad Auth"); + assertTrue(false, "Error: Bad Auth"); } } } diff --git a/src/DssSpell.t.sol b/src/DssSpell.t.sol index acfed5fa9..7da6fdcfd 100644 --- a/src/DssSpell.t.sol +++ b/src/DssSpell.t.sol @@ -299,9 +299,9 @@ contract DssSpellTest is DssSpellTestBase { try chainLog.getAddress(_stringToBytes32(removedKeys[i])) { } catch Error(string memory errmsg) { if (_cmpStr(errmsg, "dss-chain-log/invalid-key")) { - fail(_concat("TestError/key-to-remove-does-not-exist: ", removedKeys[i])); + assertTrue(false, _concat("TestError/key-to-remove-does-not-exist: ", removedKeys[i])); } else { - fail(errmsg); + assertTrue(false, errmsg); } } } @@ -312,14 +312,14 @@ contract DssSpellTest is DssSpellTestBase { for (uint256 i = 0; i < removedKeys.length; i++) { try chainLog.getAddress(_stringToBytes32(removedKeys[i])) { - fail(_concat("TestError/key-not-removed: ", removedKeys[i])); + assertTrue(false, _concat("TestError/key-not-removed: ", removedKeys[i])); } catch Error(string memory errmsg) { assertTrue( _cmpStr(errmsg, "dss-chain-log/invalid-key"), _concat("TestError/key-not-removed: ", removedKeys[i]) ); } catch { - fail(_concat("TestError/unknown-reason: ", removedKeys[i])); + assertTrue(false, _concat("TestError/unknown-reason: ", removedKeys[i])); } } } From 93c44555d70843b13cb0613080b979151801213e Mon Sep 17 00:00:00 2001 From: 0xDecr1pto <122160879+0xdecr1pto@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:59:42 +0300 Subject: [PATCH 05/10] Update src/DssSpell.sol Co-authored-by: amusingaxl <112016538+amusingaxl@users.noreply.github.com> --- src/DssSpell.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DssSpell.sol b/src/DssSpell.sol index 92a52858f..0c89ab13c 100644 --- a/src/DssSpell.sol +++ b/src/DssSpell.sol @@ -63,7 +63,7 @@ contract DssSpellAction is DssAction { uint256 internal constant FIVE_PT_TWO_PCT_RATE = 1000000001607468111246255079; // --- Math --- - uint256 internal constant RAD = 10 ** 45; + uint256 internal constant RAD = 10 ** 45; address internal immutable USDS = DssExecLib.getChangelogAddress("USDS"); address internal immutable SUSDS = DssExecLib.getChangelogAddress("SUSDS"); From 8cedb8d45ed9c4cbbf9010a606a32490618a547a Mon Sep 17 00:00:00 2001 From: 0xDecr1pto <122160879+0xdecr1pto@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:59:52 +0300 Subject: [PATCH 06/10] Update src/DssSpell.t.sol Co-authored-by: amusingaxl <112016538+amusingaxl@users.noreply.github.com> --- src/DssSpell.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DssSpell.t.sol b/src/DssSpell.t.sol index 7da6fdcfd..54a277277 100644 --- a/src/DssSpell.t.sol +++ b/src/DssSpell.t.sol @@ -1060,7 +1060,7 @@ contract DssSpellTest is DssSpellTestBase { address immutable L1_ESCROW = addr.addr("BASE_ESCROW"); address immutable L1_BRIDGE_IMP = addr.addr("BASE_TOKEN_BRIDGE_IMP"); address constant L2_BRIDGE_IMP = 0x289A37BE5D6CCeF7A8f2b90535B3BB6bD3905f72; - address constant MESSANGER = 0x866E82a600A1414e583f7F13623F1aC5d58b0Afa; + address constant MESSENGER = 0x866E82a600A1414e583f7F13623F1aC5d58b0Afa; address constant L2_MESSANGER = 0x4200000000000000000000000000000000000007; address immutable PIP_ALLOCATOR_SPARK = addr.addr("PIP_ALLOCATOR_SPARK_A"); From 4c9f94855ecfb8fd3f45ec862a34764563a025bc Mon Sep 17 00:00:00 2001 From: 0xDecr1pto <0xdecr1pto@proton.me> Date: Fri, 25 Oct 2024 18:02:49 +0300 Subject: [PATCH 07/10] chore: remove duplicated chainlog update --- src/DssSpell.sol | 13 ------------- src/DssSpell.t.sol | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/DssSpell.sol b/src/DssSpell.sol index 0c89ab13c..0192728f9 100644 --- a/src/DssSpell.sol +++ b/src/DssSpell.sol @@ -262,19 +262,6 @@ contract DssSpellAction is DssAction { MedianLike(MKR_USD_MEDIAN).lift(validators); - // ---------- Set up Governance Facilitator Streams ---------- - // Forum: TODO - - - // ---------- September 2024 AD compensation ---------- - // Forum: TODO - - - // ---------- Chainlog bump ---------- - // Note: we need to increase chainlog version as D3MInit.initCommon added new keys - DssExecLib.setChangelogVersion("1.19.3"); - - // ---------- Chainlog bump ---------- // Note: we have to patch chainlog version as new collateral is added diff --git a/src/DssSpell.t.sol b/src/DssSpell.t.sol index 54a277277..e7ff7b402 100644 --- a/src/DssSpell.t.sol +++ b/src/DssSpell.t.sol @@ -1106,9 +1106,9 @@ contract DssSpellTest is DssSpellTestBase { require(l1bridge.getImplementation() == L1_BRIDGE_IMP, "BaseTokenBridge/imp-does-not-match"); require(l1bridge.isOpen() == 1, "BaseTokenBridge/not-open"); require(l1bridge.otherBridge() == address(l2bridge), "BaseTokenBridge/other-bridge-mismatch"); - require(l1bridge.messenger() == MESSANGER, "BaseTokenBridge/l1-bridge-messenger-mismatch"); + require(l1bridge.messenger() == MESSENGER, "BaseTokenBridge/l1-bridge-messenger-mismatch"); require(l1govRelay.l2GovernanceRelay() == address(l2govRelay), "BaseGovRelay/l2-gov-relay-mismatch"); - require(l1govRelay.messenger() == MESSANGER, "BaseGovRelay/l1-gov-relay-messenger-mismatch"); + require(l1govRelay.messenger() == MESSENGER, "BaseGovRelay/l1-gov-relay-messenger-mismatch"); _vote(address(spell)); From 1817cdfa66e8ecf09678955223e79b372d3872f6 Mon Sep 17 00:00:00 2001 From: 0xDecr1pto <0xdecr1pto@proton.me> Date: Fri, 25 Oct 2024 19:04:22 +0300 Subject: [PATCH 08/10] chore: add Spark ALM Proxy --- src/DssSpell.sol | 10 ++++------ src/DssSpell.t.base.sol | 2 +- src/DssSpell.t.sol | 10 +++++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/DssSpell.sol b/src/DssSpell.sol index 0192728f9..438271ab9 100644 --- a/src/DssSpell.sol +++ b/src/DssSpell.sol @@ -93,6 +93,7 @@ contract DssSpellAction is DssAction { address internal constant ALLOCATOR_SPARK_BUFFER = 0xc395D150e71378B47A1b8E9de0c1a83b75a08324; address internal constant ALLOCATOR_SPARK_VAULT = 0x691a6c29e9e96dd897718305427Ad5D534db16BA; address internal constant ALLOCATOR_SPARK_OWNER = 0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB; + address internal constant SPARK_ALM_PROXY = 0x1601843c5E9bC251A3272907010AFa41Fa18347E; // ---------- Medians and Validators ---------- address internal constant ETH_GLOBAL_VALIDATOR = 0xcfC62b2269521e3212Ce1b6670caE6F0e34E8bF3; @@ -104,9 +105,6 @@ contract DssSpellAction is DssAction { address internal constant WSTETH_USD_MEDIAN = 0x2F73b6567B866302e132273f67661fB89b5a66F2; address internal constant MKR_USD_MEDIAN = 0xdbBe5e9B1dAa91430cF0772fCEbe53F6c6f137DF; - // ---------- Spark Proxy Spell ---------- - // Spark Proxy: https://github.com/marsfoundation/sparklend-deployments/blob/bba4c57d54deb6a14490b897c12a949aa035a99b/script/output/1/primary-sce-latest.json#L2 - address internal constant SPARK_PROXY = 0x3300f198988e4C9C63F75dF86De36421f06af8c4; function actions() public override { // Note: multple actions in the spell depend on DssInstance @@ -229,8 +227,8 @@ contract DssSpellAction is DssAction { gap : 2_500_000 * RAD, // Autoline ttl -> 1 day ttl : 86_400 seconds, - // Spark Proxy -> 0x3300f198988e4C9C63F75dF86De36421f06af8c4 - allocatorProxy : SPARK_PROXY, + // Spark Proxy -> 0x1601843c5E9bC251A3272907010AFa41Fa18347E + allocatorProxy : SPARK_ALM_PROXY, // Ilk Registry -> 0x5a464c28d19848f44199d003bef5ecc87d090f87 ilkRegistry : ILK_REGISTRY }); @@ -244,7 +242,7 @@ contract DssSpellAction is DssAction { // ---------- Whitelist Spark ALM Proxy on the PSM ---------- // Forum: TODO - DssLitePsmLike(LITE_PSM).kiss(SPARK_PROXY); + DssLitePsmLike(LITE_PSM).kiss(SPARK_ALM_PROXY); // ---------- Add new validators for Median (Medianizer) ---------- diff --git a/src/DssSpell.t.base.sol b/src/DssSpell.t.base.sol index 20e45525a..89ee125d6 100644 --- a/src/DssSpell.t.base.sol +++ b/src/DssSpell.t.base.sol @@ -2341,7 +2341,7 @@ contract DssSpellTestBase is Config, DssTest { if (ward > 0) { emit log_named_address(" Deployer Address", deployer); emit log_named_string(" Affected Contract", contractName); - assertTrue(false, "Error: Bad Auth"); + vm.revert("Error: Bad Auth"); } } } diff --git a/src/DssSpell.t.sol b/src/DssSpell.t.sol index e7ff7b402..4669f8740 100644 --- a/src/DssSpell.t.sol +++ b/src/DssSpell.t.sol @@ -299,9 +299,9 @@ contract DssSpellTest is DssSpellTestBase { try chainLog.getAddress(_stringToBytes32(removedKeys[i])) { } catch Error(string memory errmsg) { if (_cmpStr(errmsg, "dss-chain-log/invalid-key")) { - assertTrue(false, _concat("TestError/key-to-remove-does-not-exist: ", removedKeys[i])); + vm.revert(_concat("TestError/key-to-remove-does-not-exist: ", removedKeys[i])); } else { - assertTrue(false, errmsg); + vm.revert(errmsg); } } } @@ -312,14 +312,14 @@ contract DssSpellTest is DssSpellTestBase { for (uint256 i = 0; i < removedKeys.length; i++) { try chainLog.getAddress(_stringToBytes32(removedKeys[i])) { - assertTrue(false, _concat("TestError/key-not-removed: ", removedKeys[i])); + vm.revert(_concat("TestError/key-not-removed: ", removedKeys[i])); } catch Error(string memory errmsg) { assertTrue( _cmpStr(errmsg, "dss-chain-log/invalid-key"), _concat("TestError/key-not-removed: ", removedKeys[i]) ); } catch { - assertTrue(false, _concat("TestError/unknown-reason: ", removedKeys[i])); + vm.revert(_concat("TestError/unknown-reason: ", removedKeys[i])); } } } @@ -1068,7 +1068,7 @@ contract DssSpellTest is DssSpellTestBase { address immutable ALLOCATOR_REGISTRY = addr.addr("ALLOCATOR_REGISTRY"); address immutable ALLOCATOR_SPARK_BUFFER = addr.addr("ALLOCATOR_SPARK_A_BUFFER"); address immutable ALLOCATOR_SPARK_VAULT = addr.addr("ALLOCATOR_SPARK_A_VAULT"); - address immutable ALLOCATOR_SPARK_PROXY = addr.addr('SPARK_PROXY'); + address immutable ALLOCATOR_SPARK_PROXY = 0x1601843c5E9bC251A3272907010AFa41Fa18347E; bytes32 constant ALLOCATOR_ILK = "ALLOCATOR-SPARK-A"; address immutable LITE_PSM = addr.addr("MCD_LITE_PSM_USDC_A"); From 64a899a4018acbacb3bd97695791350cf50a3eb0 Mon Sep 17 00:00:00 2001 From: 0xDecr1pto <0xdecr1pto@proton.me> Date: Fri, 25 Oct 2024 19:11:19 +0300 Subject: [PATCH 09/10] chore: fix revert method --- src/DssSpell.t.base.sol | 2 +- src/DssSpell.t.sol | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DssSpell.t.base.sol b/src/DssSpell.t.base.sol index 89ee125d6..b59b03576 100644 --- a/src/DssSpell.t.base.sol +++ b/src/DssSpell.t.base.sol @@ -2341,7 +2341,7 @@ contract DssSpellTestBase is Config, DssTest { if (ward > 0) { emit log_named_address(" Deployer Address", deployer); emit log_named_string(" Affected Contract", contractName); - vm.revert("Error: Bad Auth"); + revert("Error: Bad Auth"); } } } diff --git a/src/DssSpell.t.sol b/src/DssSpell.t.sol index 4669f8740..1ef502f11 100644 --- a/src/DssSpell.t.sol +++ b/src/DssSpell.t.sol @@ -299,9 +299,9 @@ contract DssSpellTest is DssSpellTestBase { try chainLog.getAddress(_stringToBytes32(removedKeys[i])) { } catch Error(string memory errmsg) { if (_cmpStr(errmsg, "dss-chain-log/invalid-key")) { - vm.revert(_concat("TestError/key-to-remove-does-not-exist: ", removedKeys[i])); + revert(_concat("TestError/key-to-remove-does-not-exist: ", removedKeys[i])); } else { - vm.revert(errmsg); + revert(errmsg); } } } @@ -312,14 +312,14 @@ contract DssSpellTest is DssSpellTestBase { for (uint256 i = 0; i < removedKeys.length; i++) { try chainLog.getAddress(_stringToBytes32(removedKeys[i])) { - vm.revert(_concat("TestError/key-not-removed: ", removedKeys[i])); + revert(_concat("TestError/key-not-removed: ", removedKeys[i])); } catch Error(string memory errmsg) { assertTrue( _cmpStr(errmsg, "dss-chain-log/invalid-key"), _concat("TestError/key-not-removed: ", removedKeys[i]) ); } catch { - vm.revert(_concat("TestError/unknown-reason: ", removedKeys[i])); + revert(_concat("TestError/unknown-reason: ", removedKeys[i])); } } } From b2bbd99d182372a199f754b545abf8f47b88391a Mon Sep 17 00:00:00 2001 From: lucas-manuel Date: Fri, 25 Oct 2024 17:13:48 -0400 Subject: [PATCH 10/10] fix: updates to work with spark --- src/DssSpell.sol | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/DssSpell.sol b/src/DssSpell.sol index 438271ab9..53eaa92a1 100644 --- a/src/DssSpell.sol +++ b/src/DssSpell.sol @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -pragma solidity 0.8.16; +pragma solidity ^0.8.16; import "dss-exec-lib/DssExec.sol"; import "dss-exec-lib/DssAction.sol"; @@ -94,6 +94,7 @@ contract DssSpellAction is DssAction { address internal constant ALLOCATOR_SPARK_VAULT = 0x691a6c29e9e96dd897718305427Ad5D534db16BA; address internal constant ALLOCATOR_SPARK_OWNER = 0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB; address internal constant SPARK_ALM_PROXY = 0x1601843c5E9bC251A3272907010AFa41Fa18347E; + address internal constant SPARK_PROXY = 0x3300f198988e4C9C63F75dF86De36421f06af8c4; // ---------- Medians and Validators ---------- address internal constant ETH_GLOBAL_VALIDATOR = 0xcfC62b2269521e3212Ce1b6670caE6F0e34E8bF3; @@ -223,12 +224,12 @@ contract DssSpellAction is DssAction { duty : FIVE_PT_TWO_PCT_RATE, // Autoline line -> 10_000_000 maxLine : 10_000_000 * RAD, - // Autoline gap -> 2_500_000 - gap : 2_500_000 * RAD, + // Autoline gap -> 10_000_000 + gap : 10_000_000 * RAD, // Autoline ttl -> 1 day ttl : 86_400 seconds, // Spark Proxy -> 0x1601843c5E9bC251A3272907010AFa41Fa18347E - allocatorProxy : SPARK_ALM_PROXY, + allocatorProxy : SPARK_PROXY, // Ilk Registry -> 0x5a464c28d19848f44199d003bef5ecc87d090f87 ilkRegistry : ILK_REGISTRY });