diff --git a/archive/2023-08-18-DssSpell/DssSpell.sol b/archive/2023-08-18-DssSpell/DssSpell.sol new file mode 100644 index 00000000..806e0769 --- /dev/null +++ b/archive/2023-08-18-DssSpell/DssSpell.sol @@ -0,0 +1,286 @@ +// SPDX-FileCopyrightText: © 2020 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.16; + +import "dss-exec-lib/DssExec.sol"; +import "dss-exec-lib/DssAction.sol"; + +interface TransferOwnershipLike { + function transferOwnership(address newOwner) external; +} + +interface ChangeAdminLike { + function changeAdmin(address newAdmin) external; +} + +interface ACLManagerLike { + function DEFAULT_ADMIN_ROLE() external view returns (bytes32); + function addEmergencyAdmin(address admin) external; + function removeEmergencyAdmin(address admin) external; + function removePoolAdmin(address admin) external; + function grantRole(bytes32 role, address account) external; + function revokeRole(bytes32 role, address account) external; +} + +interface PoolAddressProviderLike { + function setACLAdmin(address newAclAdmin) external; +} + +interface RwaLiquidationLike { + function bump(bytes32 ilk, uint256 val) 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 + string public constant override description = "Goerli Spell"; + + // Always keep office hours off on goerli + function officeHours() public pure override returns (bool) { + return false; + } + + // ---------- DAO Resolution for BlockTower Andromeda ---------- + // Forum: https://forum.makerdao.com/t/dao-resolution-to-facilitate-onboarding-of-taco-with-additional-third-parties/21572 + // Forum: https://forum.makerdao.com/t/dao-resolution-to-facilitate-onboarding-of-taco-with-additional-third-parties/21572/2 + + // Include IPFS hash QmUNrCwKK2iK2ki5Spn97jrTCDKqFjDZWKk3wxQ2psgMP5 (not a `doc` update) + // NOTE: by the previous convention it should be a comma-separated list of DAO resolutions IPFS hashes + string public constant dao_resolutions = "QmUNrCwKK2iK2ki5Spn97jrTCDKqFjDZWKk3wxQ2psgMP5"; + + // ---------- Rates ---------- + // Many of the settings that change weekly rely on the rate accumulator + // described at https://docs.makerdao.com/smart-contract-modules/rates-module + // To check this yourself, use the following rate calculation (example 8%): + // + // $ bc -l <<< 'scale=27; e( l(1.08)/(60 * 60 * 24 * 365) )' + // + // A table of rates can be found at + // https://ipfs.io/ipfs/QmVp4mhhbwWGTfbh2BzwQB9eiBrQBKiqcPRZCaAxNUaar6 + // + // uint256 internal constant X_PCT_RATE = ; + uint256 internal constant THREE_PT_THREE_THREE_PCT_RATE = 1000000001038735548426731741; + uint256 internal constant THREE_PT_FIVE_EIGHT_PCT_RATE = 1000000001115362602336059074; + uint256 internal constant FOUR_PT_ZERO_EIGHT_PCT_RATE = 1000000001268063427242299977; + uint256 internal constant FIVE_PCT_RATE = 1000000001547125957863212448; + uint256 internal constant FIVE_PT_TWO_FIVE_PCT_RATE = 1000000001622535724756171269; + uint256 internal constant FIVE_PT_FIVE_FIVE_PCT_RATE = 1000000001712791360746325100; + uint256 internal constant FIVE_PT_EIGHT_PCT_RATE = 1000000001787808646832390371; + uint256 internal constant SIX_PT_THREE_PCT_RATE = 1000000001937312893803622469; + uint256 internal constant SEVEN_PCT_RATE = 1000000002145441671308778766; + + // ---------- Math ---------- + uint256 internal constant THOUSAND = 10 ** 3; + uint256 internal constant MILLION = 10 ** 6; + uint256 internal constant BILLION = 10 ** 9; + uint256 internal constant RAD = 10 ** 45; + + // ---------- Smart Burn Engine Parameter Updates ---------- + address internal immutable MCD_VOW = DssExecLib.vow(); + address internal immutable MCD_FLAP = DssExecLib.flap(); + + // ---------- New Silver Parameter Changes ---------- + address internal immutable MIP21_LIQUIDATION_ORACLE = DssExecLib.getChangelogAddress("MIP21_LIQUIDATION_ORACLE"); + + // ---------- Transfer Spark Proxy Admin Controls ---------- + // Contracts pulled from Spark official deployment repository + // https://github.com/marsfoundation/sparklend/blob/ca2b72af7c5fb790cc91eaca5d8d4c83fa37e74b/script/output/5/primary-latest.json + // Spark Proxy: https://github.com/marsfoundation/sparklend/blob/ca2b72af7c5fb790cc91eaca5d8d4c83fa37e74b/script/output/5/primary-sce-latest.json#L2 + address internal constant SPARK_PROXY = 0x4e847915D8a9f2Ab0cDf2FC2FD0A30428F25665d; + address internal constant SPARK_TREASURY_CONTROLLER = 0x98e6BcBA7d5daFbfa4a92dAF08d3d7512820c30C; + address internal constant SPARK_TREASURY = 0x0D56700c90a690D8795D6C148aCD94b12932f4E3; + address internal constant SPARK_TREASURY_DAI = 0x44816381990B6613c7A96ca1937f3902D8eA3F5b; + address internal constant SPARK_INCENTIVES = 0xF028c2F4b19898718fD0F77b9b881CbfdAa5e8Bb; + address internal constant SPARK_WETH_GATEWAY = 0xe6fC577E87F7c977c4393300417dCC592D90acF8; + address internal constant SPARK_ACL_MANAGER = 0xb137E7d16564c81ae2b0C8ee6B55De81dd46ECe5; + address internal constant SPARK_POOL_ADDRESS_PROVIDER = 0x026a5B6114431d8F3eF2fA0E1B2EDdDccA9c540E; + address internal constant SPARK_POOL_ADDRESS_PROVIDER_REGISTRY = 0x1ad570fDEA255a3c1d8Cf56ec76ebA2b7bFDFfea; + address internal constant SPARK_EMISSION_MANAGER = 0xA7F8A757C4f7696c015B595F51B2901AC0121B18; + + // ---------- Trigger Spark Proxy Spell ---------- + address internal constant SPARK_SPELL = 0x13176Ad78eC3d2b6E32908B019D0F772EC0b4dFd; + + function actions() public override { + // ---------- EDSR Update ---------- + // Forum: https://forum.makerdao.com/t/request-for-gov12-1-2-edit-to-the-stability-scope-to-quickly-modify-enhanced-dsr-based-on-observed-data/21581 + + // Reduce DSR by 3% from 8% to 5% + DssExecLib.setDSR(FIVE_PCT_RATE, /* doDrip = */ true); + + // ---------- DSR-based Stability Fee Updates ---------- + // Forum: https://forum.makerdao.com/t/request-for-gov12-1-2-edit-to-the-stability-scope-to-quickly-modify-enhanced-dsr-based-on-observed-data/21581 + + // Increase ETH-A SF by 0.14% from 3.44% to 3.58% + DssExecLib.setIlkStabilityFee("ETH-A", THREE_PT_FIVE_EIGHT_PCT_RATE, /* doDrip = */ true); + + // Increase ETH-B SF by 0.14% from 3.94%% to 4.08% + DssExecLib.setIlkStabilityFee("ETH-B", FOUR_PT_ZERO_EIGHT_PCT_RATE, /* doDrip = */ true); + + // Increase ETH-C SF by 0.14% from 3.19% to 3.33% + DssExecLib.setIlkStabilityFee("ETH-C", THREE_PT_THREE_THREE_PCT_RATE, /* doDrip = */ true); + + // Increase WSTETH-A SF by 1.81% from 3.44% to 5.25% + DssExecLib.setIlkStabilityFee("WSTETH-A", FIVE_PT_TWO_FIVE_PCT_RATE, /* doDrip = */ true); + + // Increase WSTETH-B SF by 1.81% from 3.19% to 5.00% + DssExecLib.setIlkStabilityFee("WSTETH-B", FIVE_PCT_RATE, /* doDrip = */ true); + + // Increase RETH-A SF by 1.81% from 3.44% to 5.25% + DssExecLib.setIlkStabilityFee("RETH-A", FIVE_PT_TWO_FIVE_PCT_RATE, /* doDrip = */ true); + + // Increase WBTC-A SF by 0.11% from 5.69% to 5.80% + DssExecLib.setIlkStabilityFee("WBTC-A", FIVE_PT_EIGHT_PCT_RATE, /* doDrip = */ true); + + // Increase WBTC-B SF by 0.11% from 6.19% to 6.30% + DssExecLib.setIlkStabilityFee("WBTC-B", SIX_PT_THREE_PCT_RATE, /* doDrip = */ true); + + // Increase WBTC-C SF by 0.11% from 5.44% to 5.55% + DssExecLib.setIlkStabilityFee("WBTC-C", FIVE_PT_FIVE_FIVE_PCT_RATE, /* doDrip = */ true); + + // ---------- Smart Burn Engine Parameter Updates ---------- + // Poll: https://vote.makerdao.com/polling/QmTRJNNH + // Forum: https://forum.makerdao.com/t/smart-burn-engine-parameters-update-1/21545 + + // Increase vow.bump by 15,000 DAI from 5,000 DAI to 20,000 DAI + DssExecLib.setValue(MCD_VOW, "bump", 20 * THOUSAND * RAD); + + // Increase hop by 4,731 seconds from 1,577 seconds to 6,308 seconds + DssExecLib.setValue(MCD_FLAP, "hop", 6_308); + + // ---------- Non-DSR Related Parameter Changes ---------- + // Forum: https://forum.makerdao.com/t/stability-scope-parameter-changes-4/21567 + // Mip: https://mips.makerdao.com/mips/details/MIP104#14-3-native-vault-engine + + // Increase WSTETH-A line by 250 million DAI from 500 million DAI to 750 million DAI (no change to gap or ttl) + DssExecLib.setIlkAutoLineDebtCeiling("WSTETH-A", 750 * MILLION); + + // Increase WSTETH-B line by 500 million DAi from 500 million DAI to 1 billion DAI + // Increase WSTETH-B gap by 15 million DAI from 30 million DAI to 45 million DAI + // Reduce WSTETH-B ttl by 14,400 seconds from 57,600 seconds to 43,200 seconds + // Forum: https://forum.makerdao.com/t/non-scope-defined-parameter-changes-wsteth-b-dc-iam/21568 + // Poll: https://vote.makerdao.com/polling/QmPxbrBZ#poll-detail + DssExecLib.setIlkAutoLineParameters("WSTETH-B", 1 * BILLION, 45 * MILLION, 12 hours); + + // Increase RETH-A line by 25 million DAI from 50 million DAI to 75 million DAI + DssExecLib.setIlkAutoLineDebtCeiling("RETH-A", 75 * MILLION); + + // ---------- CRVV1ETHSTETH-A 2nd Stage Offboarding ---------- + // Forum: https://forum.makerdao.com/t/stability-scope-parameter-changes-4/21567#crvv1ethsteth-a-offboarding-parameters-13 + // Mip: https://mips.makerdao.com/mips/details/MIP104#14-3-native-vault-engine + // NOTE: ignore on goerli (since there is no CRVV1ETHSTETH-A) + + // Set chop to 0% + // Set tip to 0% + // Set chip to 0% + // Set Liquidation Ratio to 10,000% + // Reduce Global Debt Ceiling by 100 million DAI to account for offboarded collateral + + // ---------- Aligned Delegate Compensation for July 2023 ---------- + // Forum: https://forum.makerdao.com/t/july-2023-aligned-delegate-compensation/21632 + // NOTE: ignore on goerli + + // 0xDefensor - 29.76 MKR - 0x9542b441d65B6BF4dDdd3d4D2a66D8dCB9EE07a9 + // BONAPUBLICA - 29.76 MKR - 0x167c1a762B08D7e78dbF8f24e5C3f1Ab415021D3 + // QGov - 29.76 MKR - 0xB0524D8707F76c681901b782372EbeD2d4bA28a6 + // TRUE NAME - 29.76 MKR - 0x612f7924c367575a0edf21333d96b15f1b345a5d + // UPMaker - 29.76 MKR - 0xbb819df169670dc71a16f58f55956fe642cc6bcd + // vigilant - 29.76 MKR - 0x2474937cB55500601BCCE9f4cb0A0A72Dc226F61 + // WBC - 14.82 MKR - 0xeBcE83e491947aDB1396Ee7E55d3c81414fB0D47 + // PALC - 13.89 MKR - 0x78Deac4F87BD8007b9cb56B8d53889ed5374e83A + // Navigator - 11.24 MKR - 0x11406a9CC2e37425F15f920F494A51133ac93072 + // PBG - 9.92 MKR - 0x8D4df847dB7FfE0B46AF084fE031F7691C6478c2 + // VoteWizard - 9.92 MKR - 0x9E72629dF4fcaA2c2F5813FbbDc55064345431b1 + // Libertas - 9.92 MKR - 0xE1eBfFa01883EF2b4A9f59b587fFf1a5B44dbb2f + // Harmony - 8.93 MKR - 0xF4704Aa4Ad22cAA2A3Dd7A7C529B4C32f7A421F2 + // JAG - 7.61 MKR - 0x58D1ec57E4294E4fe650D1CB12b96AE34349556f + // Cloaky - 4.30 MKR - 0x869b6d5d8FA7f4FFdaCA4D23FFE0735c5eD1F818 + // Skynet - 3.64 MKR - 0xd4d1A446cD5976a11bd32D3e815A9F85FED2F9F3 + + // ---------- Old D3M Parameter Housekeeping ---------- + // Forum: https://forum.makerdao.com/t/notice-of-executive-vote-date-change-and-housekeeping-changes/21613 + // NOTE: ignore on goerli + + // Remove DIRECT-AAVEV2-DAI from autoline + // Set DIRECT-AAVEV2-DAI Debt Ceiling to 0 + // Remove DIRECT-COMPV2-DAI from autoline + // Set DIRECT-COMPV2-DAI Debt Ceiling to 0 + // Reduce Global Debt Ceiling? Yes + + // ---------- New Silver Parameter Changes ---------- + // Forum: https://forum.makerdao.com/t/rwa-002-new-silver-restructuring-risk-and-legal-assessment/21417 + // Poll: https://vote.makerdao.com/polling/QmaU1eaD#poll-detail + + // Increase RWA002-A Debt Ceiling by 30 million DAI from 20 million DAI to 50 million DAI + DssExecLib.increaseIlkDebtCeiling( + "RWA002-A", + 30 * MILLION, + true // Increase global Line + ); + + // Increase RWA002-A Stability Fee by 3.5% from 3.5% to 7% + DssExecLib.setIlkStabilityFee("RWA002-A", SEVEN_PCT_RATE, /* doDrip = */ true); + + // Reduce Liquidation Ratio by 5% from 105% to 100% + // Forum: https://forum.makerdao.com/t/notice-of-executive-vote-date-change-and-housekeeping-changes/21613 + DssExecLib.setIlkLiquidationRatio("RWA002-A", 100_00); + + // Bump Oracle price to account for new DC and SF + // NOTE: the formula is `Debt ceiling * [ (1 + RWA stability fee ) ^ (minimum deal duration in years) ] * liquidation ratio` + // Since RWA002-A Termination Date is `October 11, 2032`, and spell execution time is `2023-08-18`, the distance is `3342` days + // bc -l <<< 'scale=18; 50000000 * e(l(1.07) * (3342/365)) * 1.00' | cast --to-wei + RwaLiquidationLike(MIP21_LIQUIDATION_ORACLE).bump( + "RWA002-A", + 92_899_355_926924134500000000 + ); + + // NOTE: Update collateral price to propagate the changes + DssExecLib.updateCollateralPrice("RWA002-A"); + + // ---------- Transfer Spark Proxy Admin Controls ---------- + // Forum: https://forum.makerdao.com/t/phoenix-labs-proposed-changes-for-spark-for-august-18th-spell/21612 + // Poll: https://vote.makerdao.com/polling/Qmc9fd3j + + TransferOwnershipLike(SPARK_TREASURY_CONTROLLER).transferOwnership(SPARK_PROXY); + ChangeAdminLike(SPARK_TREASURY).changeAdmin(SPARK_PROXY); + ChangeAdminLike(SPARK_TREASURY_DAI).changeAdmin(SPARK_PROXY); + ChangeAdminLike(SPARK_INCENTIVES).changeAdmin(SPARK_PROXY); + TransferOwnershipLike(SPARK_WETH_GATEWAY).transferOwnership(SPARK_PROXY); + ACLManagerLike(SPARK_ACL_MANAGER).addEmergencyAdmin(SPARK_PROXY); + ACLManagerLike(SPARK_ACL_MANAGER).removeEmergencyAdmin(address(this)); + ACLManagerLike(SPARK_ACL_MANAGER).removePoolAdmin(address(this)); + bytes32 defaultAdminRole = ACLManagerLike(SPARK_ACL_MANAGER).DEFAULT_ADMIN_ROLE(); + ACLManagerLike(SPARK_ACL_MANAGER).grantRole(defaultAdminRole, SPARK_PROXY); + ACLManagerLike(SPARK_ACL_MANAGER).revokeRole(defaultAdminRole, address(this)); + PoolAddressProviderLike(SPARK_POOL_ADDRESS_PROVIDER).setACLAdmin(SPARK_PROXY); + TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER).transferOwnership(SPARK_PROXY); + TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER_REGISTRY).transferOwnership(SPARK_PROXY); + TransferOwnershipLike(SPARK_EMISSION_MANAGER).transferOwnership(SPARK_PROXY); + + // ---------- Trigger Spark Proxy Spell ---------- + // Forum: https://forum.makerdao.com/t/phoenix-labs-proposed-changes-for-spark-for-august-18th-spell/21612 + + // Goerli - 0x13176ad78ec3d2b6e32908b019d0f772ec0b4dfd + ProxyLike(SPARK_PROXY).exec(SPARK_SPELL, abi.encodeWithSignature("execute()")); + } +} + +contract DssSpell is DssExec { + constructor() DssExec(block.timestamp + 30 days, address(new DssSpellAction())) {} +} diff --git a/archive/2023-08-18-DssSpell/DssSpell.t.base.sol b/archive/2023-08-18-DssSpell/DssSpell.t.base.sol new file mode 100644 index 00000000..54fc3ab4 --- /dev/null +++ b/archive/2023-08-18-DssSpell/DssSpell.t.base.sol @@ -0,0 +1,1826 @@ +// SPDX-FileCopyrightText: © 2020 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.16; + +import "dss-interfaces/Interfaces.sol"; +import {DssTest, GodMode} from "dss-test/DssTest.sol"; + +import "./test/rates.sol"; +import "./test/addresses_goerli.sol"; +import "./test/addresses_deployers.sol"; +import "./test/config.sol"; + +import {DssSpell} from "./DssSpell.sol"; + +struct TeleportGUID { + bytes32 sourceDomain; + bytes32 targetDomain; + bytes32 receiver; + bytes32 operator; + uint128 amount; + uint80 nonce; + uint48 timestamp; +} + +interface DirectDepositLike is GemJoinAbstract { + function file(bytes32, uint256) external; + function exec() external; + function tau() external view returns (uint256); + function bar() external view returns (uint256); + function king() external view returns (address); +} + +interface TeleportJoinLike { + function wards(address) external view returns (uint256); + function fees(bytes32) external view returns (address); + function line(bytes32) external view returns (uint256); + function debt(bytes32) external view returns (int256); + function vow() external view returns (address); + function vat() external view returns (address); + function daiJoin() external view returns (address); + function ilk() external view returns (bytes32); + function domain() external view returns (bytes32); +} + +interface TeleportFeeLike { + function fee() external view returns (uint256); + function ttl() external view returns (uint256); +} + +interface TeleportOracleAuthLike { + function wards(address) external view returns (uint256); + function signers(address) external view returns (uint256); + function teleportJoin() external view returns (address); + function threshold() external view returns (uint256); + function addSigners(address[] calldata) external; + function getSignHash(TeleportGUID calldata) external pure returns (bytes32); + function requestMint( + TeleportGUID calldata, + bytes calldata, + uint256, + uint256 + ) external returns (uint256, uint256); +} + +interface TeleportRouterLike { + function wards(address) external view returns (uint256); + function file(bytes32, bytes32, address) external; + function gateways(bytes32) external view returns (address); + function domains(address) external view returns (bytes32); + function numDomains() external view returns (uint256); + function dai() external view returns (address); + function requestMint( + TeleportGUID calldata, + uint256, + uint256 + ) external returns (uint256, uint256); + function settle(bytes32, uint256) external; +} + +interface TeleportBridgeLike { + function l1Escrow() external view returns (address); + function l1TeleportRouter() external view returns (address); + function l1Token() external view returns (address); +} + +interface OptimismTeleportBridgeLike is TeleportBridgeLike { + function l2TeleportGateway() external view returns (address); + function messenger() external view returns (address); +} + +interface ArbitrumTeleportBridgeLike is TeleportBridgeLike { + function l2TeleportGateway() external view returns (address); + function inbox() external view returns (address); +} + +interface StarknetTeleportBridgeLike { + function l2TeleportGateway() external view returns (uint256); + function starkNet() external view returns (address); +} + +interface RwaLiquidationLike { + function ilks(bytes32) external view returns (string memory, address, uint48, uint48); +} + +// TODO: add full interfaces to dss-interfaces and remove from here +interface FlapUniV2Abstract { + function gem() external view returns (address); + function hop() external view returns (uint256); + function pair() external view returns (address); + function pip() external view returns (address); + function want() external view returns (uint256); +} + +interface FlapperMomAbstract { + function stop() external; +} + +contract DssSpellTestBase is Config, DssTest { + Rates rates = new Rates(); + Addresses addr = new Addresses(); + Deployers deployers = new Deployers(); + + // ADDRESSES + ChainlogAbstract chainLog = ChainlogAbstract( addr.addr("CHANGELOG")); + DSPauseAbstract pause = DSPauseAbstract( addr.addr("MCD_PAUSE")); + address pauseProxy = addr.addr("MCD_PAUSE_PROXY"); + DSChiefAbstract chief = DSChiefAbstract( addr.addr("MCD_ADM")); + VatAbstract vat = VatAbstract( addr.addr("MCD_VAT")); + VowAbstract vow = VowAbstract( addr.addr("MCD_VOW")); + CatAbstract cat = CatAbstract( addr.addr("MCD_CAT")); + DogAbstract dog = DogAbstract( addr.addr("MCD_DOG")); + PotAbstract pot = PotAbstract( addr.addr("MCD_POT")); + JugAbstract jug = JugAbstract( addr.addr("MCD_JUG")); + SpotAbstract spotter = SpotAbstract( addr.addr("MCD_SPOT")); + DaiAbstract dai = DaiAbstract( addr.addr("MCD_DAI")); + DaiJoinAbstract daiJoin = DaiJoinAbstract( addr.addr("MCD_JOIN_DAI")); + DSTokenAbstract gov = DSTokenAbstract( addr.addr("MCD_GOV")); + EndAbstract end = EndAbstract( addr.addr("MCD_END")); + ESMAbstract esm = ESMAbstract( addr.addr("MCD_ESM")); + CureAbstract cure = CureAbstract( addr.addr("MCD_CURE")); + IlkRegistryAbstract reg = IlkRegistryAbstract(addr.addr("ILK_REGISTRY")); + FlapUniV2Abstract flap = FlapUniV2Abstract( addr.addr("MCD_FLAP")); + + OsmMomAbstract osmMom = OsmMomAbstract( addr.addr("OSM_MOM")); + FlipperMomAbstract flipMom = FlipperMomAbstract( addr.addr("FLIPPER_MOM")); + ClipperMomAbstract clipMom = ClipperMomAbstract( addr.addr("CLIPPER_MOM")); + FlapperMomAbstract flapMom = FlapperMomAbstract( addr.addr("FLAPPER_MOM")); + DssAutoLineAbstract autoLine = DssAutoLineAbstract(addr.addr("MCD_IAM_AUTO_LINE")); + LerpFactoryAbstract lerpFactory = LerpFactoryAbstract(addr.addr("LERP_FAB")); + VestAbstract vestDai = VestAbstract( addr.addr("MCD_VEST_DAI")); + RwaLiquidationLike liquidationOracle = RwaLiquidationLike( addr.addr("MIP21_LIQUIDATION_ORACLE")); + + DssSpell spell; + + event Debug(uint256 index, uint256 val); + event Debug(uint256 index, address addr); + event Debug(uint256 index, bytes32 what); + + function _rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = (x * y + RAY / 2) / RAY; + } + + // not provided in DSMath + function _rpow(uint256 x, uint256 n, uint256 b) internal pure returns (uint256 z) { + assembly { + switch x case 0 {switch n case 0 {z := b} default {z := 0}} + default { + switch mod(n, 2) case 0 { z := b } default { z := x } + let half := div(b, 2) // for rounding. + for { n := div(n, 2) } n { n := div(n,2) } { + let xx := mul(x, x) + if iszero(eq(div(xx, x), x)) { revert(0,0) } + let xxRound := add(xx, half) + if lt(xxRound, xx) { revert(0,0) } + x := div(xxRound, b) + if mod(n,2) { + let zx := mul(z, x) + if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } + let zxRound := add(zx, half) + if lt(zxRound, zx) { revert(0,0) } + z := div(zxRound, b) + } + } + } + } + } + + function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { + unchecked { + z = x != 0 ? ((x - 1) / y) + 1 : 0; + } + } + + // not provided in DSTest + function _assertEqApprox(uint256 _a, uint256 _b, uint256 _tolerance) internal { + uint256 a = _a; + uint256 b = _b; + if (a < b) { + uint256 tmp = a; + a = b; + b = tmp; + } + if (a - b > _tolerance) { + emit log_bytes32("Error: Wrong `uint' value"); + emit log_named_uint(" Expected", _b); + emit log_named_uint(" Actual", _a); + fail(); + } + } + + function _cmpStr(string memory a, string memory b) internal pure returns (bool) { + return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)))); + } + + function _concat(string memory a, string memory b) internal pure returns (string memory) { + return string.concat(a, b); + } + + function _concat(string memory a, bytes32 b) internal pure returns (string memory) { + return string.concat(a, _bytes32ToStr(b)); + } + + function _bytes32ToStr(bytes32 _bytes32) internal pure returns (string memory) { + bytes memory bytesArray = new bytes(32); + for (uint256 i; i < 32; i++) { + bytesArray[i] = _bytes32[i]; + } + return string(bytesArray); + } + + // 10^-5 (tenth of a basis point) as a RAY + uint256 TOLERANCE = 10 ** 22; + + function _yearlyYield(uint256 duty) internal pure returns (uint256) { + return _rpow(duty, (365 * 24 * 60 * 60), RAY); + } + + function _expectedRate(uint256 percentValue) internal pure returns (uint256) { + return (10000 + percentValue) * (10 ** 23); + } + + function _diffCalc( + uint256 expectedRate_, + uint256 yearlyYield_ + ) internal pure returns (uint256) { + return (expectedRate_ > yearlyYield_) ? + expectedRate_ - yearlyYield_ : yearlyYield_ - expectedRate_; + } + + function _castPreviousSpell() internal { + address[] memory prevSpells = spellValues.previous_spells; + + // warp and cast previous spells so values are up-to-date to test against + for (uint256 i; i < prevSpells.length; i++) { + DssSpell prevSpell = DssSpell(prevSpells[i]); + if (prevSpell != DssSpell(address(0)) && !prevSpell.done()) { + if (prevSpell.eta() == 0) { + _vote(address(prevSpell)); + _scheduleWaitAndCast(address(prevSpell)); + } + else { + // jump to nextCastTime to be a little more forgiving on the spell execution time + vm.warp(prevSpell.nextCastTime()); + prevSpell.cast(); + } + } + } + } + + function setUp() public { + setValues(address(chief)); + + spellValues.deployed_spell_created = spellValues.deployed_spell != address(0) ? spellValues.deployed_spell_created : block.timestamp; + _castPreviousSpell(); + spell = spellValues.deployed_spell != address(0) ? + DssSpell(spellValues.deployed_spell) : new DssSpell(); + + if (spellValues.deployed_spell_block != 0 && spell.eta() != 0) { + // if we have a deployed spell in the config + // we want to roll our fork to the block where it was deployed + // this means the test suite will continue to accurately pass/fail + // even if mainnet has already scheduled/cast the spell + vm.makePersistent(address(this)); + vm.makePersistent(address(rates)); + vm.makePersistent(address(addr)); + vm.makePersistent(address(deployers)); + vm.rollFork(spellValues.deployed_spell_block); + } + } + + function _vote(address spell_) internal { + if (chief.hat() != spell_) { + _giveTokens(address(gov), 999999999999 ether); + gov.approve(address(chief), type(uint256).max); + chief.lock(999999999999 ether); + + address[] memory slate = new address[](1); + + assertTrue(!DssSpell(spell_).done()); + + slate[0] = spell_; + + chief.vote(slate); + chief.lift(spell_); + } + assertEq(chief.hat(), spell_); + } + + function _scheduleWaitAndCast(address spell_) internal { + DssSpell(spell_).schedule(); + + vm.warp(DssSpell(spell_).nextCastTime()); + + DssSpell(spell_).cast(); + } + + function _stringToBytes32(string memory source) internal pure returns (bytes32 result) { + assembly { + result := mload(add(source, 32)) + } + } + + function _checkSystemValues(SystemValues storage values) internal { + // dsr + uint256 expectedDSRRate = rates.rates(values.pot_dsr); + // make sure dsr is less than 100% APR + // bc -l <<< 'scale=27; e( l(2.00)/(60 * 60 * 24 * 365) )' + // 1000000021979553151239153027 + assertEq(pot.dsr(), expectedDSRRate, "TestError/pot-dsr-expected-value"); + assertTrue( + pot.dsr() >= RAY && pot.dsr() < 1000000021979553151239153027, + "TestError/pot-dsr-range" + ); + assertTrue( + _diffCalc(_expectedRate(values.pot_dsr), _yearlyYield(expectedDSRRate)) <= TOLERANCE, + "TestError/pot-dsr-rates-table" + ); + + { + // Line values in RAD + assertTrue( + (vat.Line() >= RAD && vat.Line() < 100 * BILLION * RAD) || + vat.Line() == 0, + "TestError/vat-Line-range" + ); + } + + // Pause delay + assertEq(pause.delay(), values.pause_delay, "TestError/pause-delay"); + + // wait + assertEq(vow.wait(), values.vow_wait, "TestError/vow-wait"); + { + // dump values in WAD + uint256 normalizedDump = values.vow_dump * WAD; + assertEq(vow.dump(), normalizedDump, "TestError/vow-dump"); + assertTrue( + (vow.dump() >= WAD && vow.dump() < 2 * THOUSAND * WAD) || + vow.dump() == 0, + "TestError/vow-dump-range" + ); + } + { + // sump values in RAD + uint256 normalizedSump = values.vow_sump * RAD; + assertEq(vow.sump(), normalizedSump, "TestError/vow-sump"); + assertTrue( + (vow.sump() >= RAD && vow.sump() < 500 * THOUSAND * RAD) || + vow.sump() == 0, + "TestError/vow-sump-range" + ); + } + { + // bump values in RAD + uint256 normalizedBump = values.vow_bump * RAD; + assertEq(vow.bump(), normalizedBump, "TestError/vow-bump"); + assertTrue( + (vow.bump() >= RAD && vow.bump() < 100 * THOUSAND * RAD) || + vow.bump() == 0, + "TestError/vow-bump-range" + ); + } + { + // hump values in RAD + uint256 normalizedHumpMin = values.vow_hump_min * RAD; + uint256 normalizedHumpMax = values.vow_hump_max * RAD; + assertTrue(vow.hump() >= normalizedHumpMin && vow.hump() <= normalizedHumpMax, "TestError/vow-hump-min-max"); + assertTrue( + (vow.hump() >= RAD && vow.hump() < 1 * BILLION * RAD) || + vow.hump() == 0, + "TestError/vow-hump-range" + ); + } + + // box value in RAD + { + uint256 normalizedBox = values.cat_box * RAD; + assertEq(cat.box(), normalizedBox, "TestError/cat-box"); + assertTrue(cat.box() >= MILLION * RAD && cat.box() <= 50 * MILLION * RAD, "TestError/cat-box-range"); + } + + // Hole value in RAD + { + uint256 normalizedHole = values.dog_Hole * RAD; + assertEq(dog.Hole(), normalizedHole, "TestError/dog-Hole"); + assertTrue(dog.Hole() >= MILLION * RAD && dog.Hole() <= 200 * MILLION * RAD, "TestError/dog-Hole-range"); + } + + // ESM min in WAD + { + uint256 normalizedMin = values.esm_min * WAD; + assertEq(esm.min(), normalizedMin, "TestError/esm-min"); + assertTrue(esm.min() > WAD && esm.min() < 200 * THOUSAND * WAD, "TestError/esm-min-range"); + } + + // check Pause authority + assertEq(pause.authority(), values.pause_authority, "TestError/pause-authority"); + + // check OsmMom authority + assertEq(osmMom.authority(), values.osm_mom_authority, "TestError/osmMom-authority"); + + // check FlipperMom authority + assertEq(flipMom.authority(), values.flipper_mom_authority, "TestError/flipperMom-authority"); + + // check ClipperMom authority + assertEq(clipMom.authority(), values.clipper_mom_authority, "TestError/clipperMom-authority"); + + // check number of ilks + assertEq(reg.count(), values.ilk_count, "TestError/ilks-count"); + + // flap + // Check flap hop and sanity checks + assertEq(flap.hop(), values.flap_hop, "TestError/flap-hop"); + assertTrue(flap.hop() > 0 && flap.hop() < 86400, "TestError/flap-hop-range"); // gt 0 && lt 1 day + // check want value + uint256 normalizedTestWant = values.flap_want * 10**14; + assertEq(flap.want(), normalizedTestWant, "TestError/flap-want"); + assertTrue(flap.want() >= 90 * WAD / 100 && flap.want() <= 110 * WAD / 100, "TestError/flap-want-range"); // gte 90% and lte 110% + + assertEq(vat.wards(pauseProxy), uint256(1), "TestError/pause-proxy-deauthed-on-vat"); + } + + function _checkCollateralValues(SystemValues storage values) internal { + // Using an array to work around stack depth limitations. + // sums[0] : sum of all lines + // sums[1] : sum over ilks of (line - Art * rate)--i.e. debt that could be drawn at any time + uint256[] memory sums = new uint256[](2); + bytes32[] memory ilks = reg.list(); + for(uint256 i = 0; i < ilks.length; i++) { + bytes32 ilk = ilks[i]; + (uint256 duty,) = jug.ilks(ilk); + + assertEq(duty, rates.rates(values.collaterals[ilk].pct), _concat("TestError/jug-duty-", ilk)); + // make sure duty is less than 1000% APR + // bc -l <<< 'scale=27; e( l(10.00)/(60 * 60 * 24 * 365) )' + // 1000000073014496989316680335 + assertTrue(duty >= RAY && duty < 1000000073014496989316680335, _concat("TestError/jug-duty-range-", ilk)); // gt 0 and lt 1000% + assertTrue( + _diffCalc(_expectedRate(values.collaterals[ilk].pct), _yearlyYield(rates.rates(values.collaterals[ilk].pct))) <= TOLERANCE, + _concat("TestError/rates-", ilk) + ); + assertTrue(values.collaterals[ilk].pct < THOUSAND * THOUSAND, _concat("TestError/pct-max-", ilk)); // check value lt 1000% + { + uint256 line; + uint256 dust; + { + uint256 Art; + uint256 rate; + (Art, rate,, line, dust) = vat.ilks(ilk); + if (Art * rate < line) { + sums[1] += line - Art * rate; + } + } + // Convert whole Dai units to expected RAD + uint256 normalizedTestLine = values.collaterals[ilk].line * RAD; + sums[0] += line; + (uint256 aL_line, uint256 aL_gap, uint256 aL_ttl,,) = autoLine.ilks(ilk); + if (values.collaterals[ilk].aL_enabled) { + assertTrue(aL_line > 0, _concat("TestError/al-line-is-zero-", ilk)); + assertTrue(aL_line >= RAD && aL_line < 20 * BILLION * RAD, _concat("TestError/al-line-range-", ilk)); + + assertEq(aL_line, values.collaterals[ilk].aL_line * RAD, _concat("TestError/al-line-", ilk)); + assertEq(aL_gap, values.collaterals[ilk].aL_gap * RAD, _concat("TestError/al-gap-", ilk)); + assertEq(aL_ttl, values.collaterals[ilk].aL_ttl, _concat("TestError/al-ttl-", ilk)); + } else { + assertTrue(aL_line == 0, _concat("TestError/al-Line-not-zero-", ilk)); + + assertTrue((line >= RAD && line < 10 * BILLION * RAD) || line == 0, _concat("TestError/vat-line-range-", ilk)); + assertEq(line, normalizedTestLine, _concat("TestError/vat-line-", ilk)); + + // Check if the config was properly cleaned up: + assertEq(values.collaterals[ilk].aL_line, 0, _concat("TestError/config-al-line-", ilk)); + assertEq(values.collaterals[ilk].aL_gap, 0, _concat("TestError/config-al-gap-", ilk)); + assertEq(values.collaterals[ilk].aL_ttl, 0, _concat("TestError/config-al-ttl-", ilk)); + } + uint256 normalizedTestDust = values.collaterals[ilk].dust * RAD; + assertEq(dust, normalizedTestDust, _concat("TestError/vat-dust-", ilk)); + assertTrue((dust >= RAD && dust <= 100 * THOUSAND * RAD) || dust == 0, _concat("TestError/vat-dust-range-", ilk)); // eq 0 or gt eq 1 and lte 100k + } + + { + (address pip, uint256 mat) = spotter.ilks(ilk); + if (pip != address(0)) { + // Convert BP to system expected value + uint256 normalizedTestMat = (values.collaterals[ilk].mat * 10**23); + if (values.collaterals[ilk].offboarding) { + assertTrue(mat <= normalizedTestMat, _concat("TestError/vat-lerping-mat-", ilk)); + assertTrue(mat >= RAY && mat <= 300 * RAY, _concat("TestError/vat-mat-range-", ilk)); // cr gt 100% and lt 30000% + } else { + assertEq(mat, normalizedTestMat, _concat("TestError/vat-mat-", ilk)); + assertTrue(mat >= RAY && mat < 10 * RAY, _concat("TestError/vat-mat-range-", ilk)); // cr gt 100% and lt 1000% + } + } + } + + if (values.collaterals[ilk].liqType == "flip") { + { + assertEq(reg.class(ilk), 2, _concat("TestError/reg-class-", ilk)); + (bool ok, bytes memory val) = reg.xlip(ilk).call(abi.encodeWithSignature("cat()")); + assertTrue(ok, _concat("TestError/reg-xlip-cat-", ilk)); + assertEq(abi.decode(val, (address)), address(cat), _concat("TestError/reg-xlip-cat-", ilk)); + } + { + (, uint256 chop, uint256 dunk) = cat.ilks(ilk); + // Convert BP to system expected value + uint256 normalizedTestChop = (values.collaterals[ilk].chop * 10**14) + WAD; + assertEq(chop, normalizedTestChop, _concat("TestError/cat-chop-", ilk)); + // make sure chop is less than 100% + assertTrue(chop >= WAD && chop < 2 * WAD, _concat("TestError/cat-chop-range-", ilk)); // penalty gt eq 0% and lt 100% + + // Convert whole Dai units to expected RAD + uint256 normalizedTestDunk = values.collaterals[ilk].cat_dunk * RAD; + assertEq(dunk, normalizedTestDunk, _concat("TestError/cat-dunk-", ilk)); + assertTrue(dunk >= RAD && dunk < MILLION * RAD, _concat("TestError/cat-dunk-range-", ilk)); + + (address flipper,,) = cat.ilks(ilk); + assertTrue(flipper != address(0), _concat("TestError/invalid-flip-address-", ilk)); + FlipAbstract flip = FlipAbstract(flipper); + // Convert BP to system expected value + uint256 normalizedTestBeg = (values.collaterals[ilk].flip_beg + 10000) * 10**14; + assertEq(uint256(flip.beg()), normalizedTestBeg, _concat("TestError/flip-beg-", ilk)); + assertTrue(flip.beg() >= WAD && flip.beg() <= 110 * WAD / 100, _concat("TestError/flip-beg-range-", ilk)); // gte 0% and lte 10% + assertEq(uint256(flip.ttl()), values.collaterals[ilk].flip_ttl, _concat("TestError/flip-ttl-", ilk)); + assertTrue(flip.ttl() >= 600 && flip.ttl() < 10 hours, _concat("TestError/flip-ttl-range-", ilk)); // gt eq 10 minutes and lt 10 hours + assertEq(uint256(flip.tau()), values.collaterals[ilk].flip_tau, _concat("TestError/flip-tau-", ilk)); + assertTrue(flip.tau() >= 600 && flip.tau() <= 3 days, _concat("TestError/flip-tau-range-", ilk)); // gt eq 10 minutes and lt eq 3 days + + assertEq(flip.wards(address(flipMom)), values.collaterals[ilk].flipper_mom, _concat("TestError/flip-flipperMom-auth-", ilk)); + + assertEq(flip.wards(address(cat)), values.collaterals[ilk].liqOn ? 1 : 0, _concat("TestError/flip-liqOn-", ilk)); + assertEq(flip.wards(address(end)), 1, _concat("TestError/flip-end-auth-", ilk)); + assertEq(flip.wards(address(pauseProxy)), 1, _concat("TestError/flip-pause-proxy-auth-", ilk)); // Check pause_proxy ward + } + } + if (values.collaterals[ilk].liqType == "clip") { + { + assertEq(reg.class(ilk), 1, _concat("TestError/reg-class-", ilk)); + (bool ok, bytes memory val) = reg.xlip(ilk).call(abi.encodeWithSignature("dog()")); + assertTrue(ok, _concat("TestError/reg-xlip-dog-", ilk)); + assertEq(abi.decode(val, (address)), address(dog), _concat("TestError/reg-xlip-dog-", ilk)); + } + { + (, uint256 chop, uint256 hole,) = dog.ilks(ilk); + // Convert BP to system expected value + uint256 normalizedTestChop = (values.collaterals[ilk].chop * 10**14) + WAD; + assertEq(chop, normalizedTestChop, _concat("TestError/dog-chop-", ilk)); + // make sure chop is less than 100% + assertTrue(chop >= WAD && chop < 2 * WAD, _concat("TestError/dog-chop-range-", ilk)); // penalty gt eq 0% and lt 100% + + // Convert whole Dai units to expected RAD + uint256 normalizedTesthole = values.collaterals[ilk].dog_hole * RAD; + assertEq(hole, normalizedTesthole, _concat("TestError/dog-hole-", ilk)); + assertTrue(hole == 0 || hole >= RAD && hole <= 100 * MILLION * RAD, _concat("TestError/dog-hole-range-", ilk)); + } + (address clipper,,,) = dog.ilks(ilk); + assertTrue(clipper != address(0), _concat("TestError/invalid-clip-address-", ilk)); + ClipAbstract clip = ClipAbstract(clipper); + { + // Convert BP to system expected value + uint256 normalizedTestBuf = values.collaterals[ilk].clip_buf * 10**23; + assertEq(uint256(clip.buf()), normalizedTestBuf, _concat("TestError/clip-buf-", ilk)); + assertTrue(clip.buf() >= RAY && clip.buf() <= 2 * RAY, _concat("TestError/clip-buf-range-", ilk)); // gte 0% and lte 100% + assertEq(uint256(clip.tail()), values.collaterals[ilk].clip_tail, _concat("TestError/clip-tail-", ilk)); + if (ilk == "TUSD-A") { // long tail liquidation + assertTrue(clip.tail() >= 1200 && clip.tail() <= 30 days, _concat("TestError/TUSD-clip-tail-range-", ilk)); // gt eq 20 minutes and lt eq 30 days + } else { + assertTrue(clip.tail() >= 1200 && clip.tail() <= 12 hours, _concat("TestError/clip-tail-range-", ilk)); // gt eq 20 minutes and lt eq 12 hours + } + uint256 normalizedTestCusp = (values.collaterals[ilk].clip_cusp) * 10**23; + assertEq(uint256(clip.cusp()), normalizedTestCusp, _concat("TestError/clip-cusp-", ilk)); + assertTrue(clip.cusp() >= RAY / 10 && clip.cusp() < RAY, _concat("TestError/clip-cusp-range-", ilk)); // gte 10% and lt 100% + assertTrue(_rmul(clip.buf(), clip.cusp()) <= RAY, _concat("TestError/clip-buf-cusp-limit-", ilk)); + uint256 normalizedTestChip = (values.collaterals[ilk].clip_chip) * 10**14; + assertEq(uint256(clip.chip()), normalizedTestChip, _concat("TestError/clip-chip-", ilk)); + assertTrue(clip.chip() < 1 * WAD / 100, _concat("TestError/clip-chip-range-", ilk)); // lt 1% + uint256 normalizedTestTip = values.collaterals[ilk].clip_tip * RAD; + assertEq(uint256(clip.tip()), normalizedTestTip, _concat("TestError/clip-tip-", ilk)); + assertTrue(clip.tip() == 0 || clip.tip() >= RAD && clip.tip() <= 500 * RAD, _concat("TestError/clip-tip-range-", ilk)); + + assertEq(clip.wards(address(clipMom)), values.collaterals[ilk].clipper_mom, _concat("TestError/clip-clipperMom-auth-", ilk)); + + assertEq(clipMom.tolerance(address(clip)), values.collaterals[ilk].cm_tolerance * RAY / 10000, _concat("TestError/clipperMom-tolerance-", ilk)); + + if (values.collaterals[ilk].liqOn) { + assertEq(clip.stopped(), 0, _concat("TestError/clip-liqOn-", ilk)); + } else { + assertTrue(clip.stopped() > 0, _concat("TestError/clip-liqOn-", ilk)); + } + + assertEq(clip.wards(address(end)), 1, _concat("TestError/clip-end-auth-", ilk)); + assertEq(clip.wards(address(pauseProxy)), 1, _concat("TestError/clip-pause-proxy-auth-", ilk)); // Check pause_proxy ward + } + { + (bool exists, bytes memory value) = clip.calc().call(abi.encodeWithSignature("tau()")); + assertEq(exists ? abi.decode(value, (uint256)) : 0, values.collaterals[ilk].calc_tau, _concat("TestError/calc-tau-", ilk)); + (exists, value) = clip.calc().call(abi.encodeWithSignature("step()")); + assertEq(exists ? abi.decode(value, (uint256)) : 0, values.collaterals[ilk].calc_step, _concat("TestError/calc-step-", ilk)); + if (exists) { + assertTrue(abi.decode(value, (uint256)) > 0, _concat("TestError/calc-step-is-zero-", ilk)); + } + (exists, value) = clip.calc().call(abi.encodeWithSignature("cut()")); + uint256 normalizedTestCut = values.collaterals[ilk].calc_cut * 10**23; + assertEq(exists ? abi.decode(value, (uint256)) : 0, normalizedTestCut, _concat("TestError/calc-cut-", ilk)); + if (exists) { + assertTrue(abi.decode(value, (uint256)) > 0 && abi.decode(value, (uint256)) < RAY, _concat("TestError/calc-cut-range-", ilk)); + } + } + { + uint256 normalizedTestChop = (values.collaterals[ilk].chop * 10**14) + WAD; + uint256 _chost = (values.collaterals[ilk].dust * RAD) * normalizedTestChop / WAD; + assertEq(clip.chost(), _chost, _concat("TestError/calc-chost-incorrect-", ilk)); // Ensure clip.upchost() is called when dust changes + } + + } + if (reg.class(ilk) < 3) { + { + GemJoinAbstract join = GemJoinAbstract(reg.join(ilk)); + assertEq(join.wards(address(pauseProxy)), 1, _concat("TestError/join-pause-proxy-auth-", ilk)); // Check pause_proxy ward + } + } + } + // Require that debt + (debt that could be drawn) does not exceed Line. + // TODO: consider a buffer for fee accrual + assertTrue(vat.debt() + sums[1] <= vat.Line(), "TestError/vat-Line-1"); + + // Enforce the global Line also falls between (sum of lines) + offset and (sum of lines) + 2*offset. + assertTrue(sums[0] + values.line_offset * RAD <= vat.Line(), "TestError/vat-Line-2"); + assertTrue(sums[0] + 2 * values.line_offset * RAD >= vat.Line(), "TestError/vat-Line-3"); + + // TODO: have a discussion about how we want to manage the global Line going forward. + } + + function _getOSMPrice(address pip) internal returns (uint256) { + // vm.load is to pull the price from the LP Oracle storage bypassing the whitelist + uint256 price = uint256(vm.load( + pip, + bytes32(uint256(3)) + )) & type(uint128).max; // Price is in the second half of the 32-byte storage slot + + // Price is bounded in the spot by around 10^23 + // Give a 10^9 buffer for price appreciation over time + // Note: This currently can't be hit due to the uint112, but we want to backstop + // once the PIP uint256 size is increased + assertTrue(price <= (10 ** 14) * WAD); + + return price; + } + + function _getUNIV2LPPrice(address pip) internal returns (uint256) { + // vm.load is to pull the price from the LP Oracle storage bypassing the whitelist + uint256 price = uint256(vm.load( + pip, + bytes32(uint256(3)) + )) & type(uint128).max; // Price is in the second half of the 32-byte storage slot + + // Price is bounded in the spot by around 10^23 + // Give a 10^9 buffer for price appreciation over time + // Note: This currently can't be hit due to the uint112, but we want to backstop + // once the PIP uint256 size is increased + assertTrue(price <= (10 ** 14) * WAD); + + return price; + } + + function _giveTokens(address token, uint256 amount) internal { + // This passes through to the GodMode function. Because we have another logic branch + // in spells-mainnet, we're keeping this wrapper here for consistency + GodMode.setBalance(token, address(this), amount); + } + + function _checkIlkIntegration( + bytes32 _ilk, + GemJoinAbstract join, + ClipAbstract clip, + address pip, + bool _isOSM, + bool _checkLiquidations, + bool _transferFee + ) internal { + GemAbstract token = GemAbstract(join.gem()); + + vm.warp(block.timestamp + 3601); // Avoid OSM delay errors on Görli + if (_isOSM) OsmAbstract(pip).poke(); + vm.warp(block.timestamp + 3601); + if (_isOSM) OsmAbstract(pip).poke(); + spotter.poke(_ilk); + + // Authorization + assertEq(join.wards(pauseProxy), 1, _concat("TestError/checkIlkIntegration-pauseProxy-not-auth-on-join-", _ilk)); + assertEq(vat.wards(address(join)), 1, _concat("TestError/checkIlkIntegration-join-not-auth-on-vat-", _ilk)); + assertEq(vat.wards(address(clip)), 1, _concat("TestError/checkIlkIntegration-clip-not-auth-on-vat-", _ilk)); + assertEq(dog.wards(address(clip)), 1, _concat("TestError/checkIlkIntegration-clip-not-auth-on-dog-", _ilk)); + assertEq(clip.wards(address(dog)), 1, _concat("TestError/checkIlkIntegration-dog-not-auth-on-clip-", _ilk)); + assertEq(clip.wards(address(end)), 1, _concat("TestError/checkIlkIntegration-end-not-auth-on-clip-", _ilk)); + assertEq(clip.wards(address(clipMom)), 1, _concat("TestError/checkIlkIntegration-clipMom-not-auth-on-clip-", _ilk)); + assertEq(clip.wards(address(esm)), 1, _concat("TestError/checkIlkIntegration-esm-not-auth-on-clip-", _ilk)); + if (_isOSM) { + assertEq(OsmAbstract(pip).wards(address(osmMom)), 1, _concat("TestError/checkIlkIntegration-osmMom-not-auth-on-pip-", _ilk)); + assertEq(OsmAbstract(pip).bud(address(spotter)), 1, _concat("TestError/checkIlkIntegration-spot-not-bud-on-pip-", _ilk)); + assertEq(OsmAbstract(pip).bud(address(clip)), 1, _concat("TestError/checkIlkIntegration-spot-not-bud-on-pip-", _ilk)); + assertEq(OsmAbstract(pip).bud(address(clipMom)), 1, _concat("TestError/checkIlkIntegration-spot-not-bud-on-pip-", _ilk)); + assertEq(OsmAbstract(pip).bud(address(end)), 1, _concat("TestError/checkIlkIntegration-spot-not-bud-on-pip-", _ilk)); + assertEq(MedianAbstract(OsmAbstract(pip).src()).bud(pip), 1, _concat("TestError/checkIlkIntegration-pip-not-bud-on-osm-", _ilk)); + assertEq(OsmMomAbstract(osmMom).osms(_ilk), pip, _concat("TestError/checkIlkIntegration-pip-not-bud-on-osmMom-", _ilk)); + } + + (,,,, uint256 dust) = vat.ilks(_ilk); + dust /= RAY; + uint256 amount = 4 * dust * 10 ** uint256(token.decimals()) / (_isOSM ? _getOSMPrice(pip) : uint256(DSValueAbstract(pip).read())); + uint256 amount18 = token.decimals() == 18 ? amount : amount * 10**(18 - uint256(token.decimals())); + _giveTokens(address(token), amount); + + assertEq(token.balanceOf(address(this)), amount); + assertEq(vat.gem(_ilk, address(this)), 0); + token.approve(address(join), amount); + join.join(address(this), amount); + assertEq(token.balanceOf(address(this)), 0); + if (_transferFee) { + amount = vat.gem(_ilk, address(this)); + assertTrue(amount > 0); + } + assertEq(vat.gem(_ilk, address(this)), amount18); + + // Tick the fees forward so that art != dai in wad units + vm.warp(block.timestamp + 1); + jug.drip(_ilk); + + // Deposit collateral, generate DAI + (,uint256 rate,,uint256 line,) = vat.ilks(_ilk); + + assertEq(vat.dai(address(this)), 0); + // Set max line to ensure we can create a new position + _setIlkLine(_ilk, type(uint256).max); + vat.frob(_ilk, address(this), address(this), address(this), int256(amount18), int256(_divup(RAY * dust, rate))); + // Revert ilk line to proceed with testing + _setIlkLine(_ilk, line); + assertEq(vat.gem(_ilk, address(this)), 0); + assertTrue(vat.dai(address(this)) >= dust * RAY); + assertTrue(vat.dai(address(this)) <= (dust + 1) * RAY); + + // Payback DAI, withdraw collateral + vat.frob(_ilk, address(this), address(this), address(this), -int256(amount18), -int256(_divup(RAY * dust, rate))); + assertEq(vat.gem(_ilk, address(this)), amount18); + assertEq(vat.dai(address(this)), 0); + + // Withdraw from adapter + join.exit(address(this), amount); + if (_transferFee) { + amount = token.balanceOf(address(this)); + } + assertEq(token.balanceOf(address(this)), amount); + assertEq(vat.gem(_ilk, address(this)), 0); + + // Generate new DAI to force a liquidation + token.approve(address(join), amount); + join.join(address(this), amount); + if (_transferFee) { + amount = vat.gem(_ilk, address(this)); + } + // dart max amount of DAI + (,,uint256 spot,,) = vat.ilks(_ilk); + + // Set max line to ensure we can draw dai + _setIlkLine(_ilk, type(uint256).max); + vat.frob(_ilk, address(this), address(this), address(this), int256(amount18), int256(amount18 * spot / rate)); + // Revert ilk line to proceed with testing + _setIlkLine(_ilk, line); + + vm.warp(block.timestamp + 1); + jug.drip(_ilk); + assertEq(clip.kicks(), 0); + if (_checkLiquidations) { + if (_getIlkDuty(_ilk) == rates.rates(0)) { + // Rates wont accrue if 0, raise the mat to make the vault unsafe + _setIlkMat(_ilk, 100000 * RAY); + vm.warp(block.timestamp + 10 days); + spotter.poke(_ilk); + } + dog.bark(_ilk, address(this), address(this)); + assertEq(clip.kicks(), 1); + } + + // Dump all dai for next run + vat.move(address(this), address(0x0), vat.dai(address(this))); + } + + function _checkIlkClipper( + bytes32 ilk, + GemJoinAbstract join, + ClipAbstract clipper, + address calc, + OsmAbstract pip, + uint256 ilkAmt + ) internal { + + // Contracts set + assertEq(dog.vat(), address(vat)); + assertEq(dog.vow(), address(vow)); + { + (address clip,,,) = dog.ilks(ilk); + assertEq(clip, address(clipper)); + } + assertEq(clipper.ilk(), ilk); + assertEq(clipper.vat(), address(vat)); + assertEq(clipper.vow(), address(vow)); + assertEq(clipper.dog(), address(dog)); + assertEq(clipper.spotter(), address(spotter)); + assertEq(clipper.calc(), calc); + + // Authorization + assertEq(vat.wards(address(clipper)) , 1); + assertEq(dog.wards(address(clipper)) , 1); + assertEq(clipper.wards(address(dog)) , 1); + assertEq(clipper.wards(address(end)) , 1); + assertEq(clipper.wards(address(clipMom)), 1); + assertEq(clipper.wards(address(esm)), 1); + + try pip.bud(address(spotter)) returns (uint256 bud) { + assertEq(bud, 1); + } catch {} + try pip.bud(address(clipper)) returns (uint256 bud) { + assertEq(bud, 1); + } catch {} + try pip.bud(address(clipMom)) returns (uint256 bud) { + assertEq(bud, 1); + } catch {} + try pip.bud(address(end)) returns (uint256 bud) { + assertEq(bud, 1); + } catch {} + + // Force max Hole + vm.store( + address(dog), + bytes32(uint256(4)), + bytes32(type(uint256).max) + ); + + // Initially this test assume that's we are using freshly deployed Cliiper contract without any past auctions + if (clipper.kicks() > 0) { + // Cleanup clipper auction counter + vm.store( + address(clipper), + bytes32(uint256(10)), + bytes32(uint256(0)) + ); + + assertEq(clipper.kicks(), 0); + } + + // ----------------------- Check Clipper works and bids can be made ----------------------- + + { + GemAbstract token = GemAbstract(join.gem()); + uint256 tknAmt = ilkAmt / 10 ** (18 - join.dec()); + _giveTokens(address(token), tknAmt); + assertEq(token.balanceOf(address(this)), tknAmt); + + // Join to adapter + assertEq(vat.gem(ilk, address(this)), 0); + assertEq(token.allowance(address(this), address(join)), 0); + token.approve(address(join), tknAmt); + join.join(address(this), tknAmt); + assertEq(token.balanceOf(address(this)), 0); + assertEq(vat.gem(ilk, address(this)), ilkAmt); + } + + { + // Generate new DAI to force a liquidation + uint256 rate; + int256 art; + uint256 spot; + uint256 line; + (,rate, spot, line,) = vat.ilks(ilk); + art = int256(ilkAmt * spot / rate); + + // dart max amount of DAI + _setIlkLine(ilk, type(uint256).max); + vat.frob(ilk, address(this), address(this), address(this), int256(ilkAmt), art); + _setIlkLine(ilk, line); + _setIlkMat(ilk, 100000 * RAY); + vm.warp(block.timestamp + 10 days); + spotter.poke(ilk); + assertEq(clipper.kicks(), 0); + dog.bark(ilk, address(this), address(this)); + assertEq(clipper.kicks(), 1); + + (, rate,,,) = vat.ilks(ilk); + uint256 debt = rate * uint256(art) * dog.chop(ilk) / WAD; + vm.store( + address(vat), + keccak256(abi.encode(address(this), uint256(5))), + bytes32(debt) + ); + assertEq(vat.dai(address(this)), debt); + assertEq(vat.gem(ilk, address(this)), 0); + + vm.warp(block.timestamp + 20 minutes); + (, uint256 tab, uint256 lot, address usr,, uint256 top) = clipper.sales(1); + + assertEq(usr, address(this)); + assertEq(tab, debt); + assertEq(lot, ilkAmt); + assertTrue(lot * top > tab); // There is enough collateral to cover the debt at current price + + vat.hope(address(clipper)); + clipper.take(1, lot, top, address(this), bytes("")); + } + + { + (, uint256 tab, uint256 lot, address usr,,) = clipper.sales(1); + assertEq(usr, address(0)); + assertEq(tab, 0); + assertEq(lot, 0); + assertEq(vat.dai(address(this)), 0); + assertEq(vat.gem(ilk, address(this)), ilkAmt); // What was purchased + returned back as it is the owner of the vault + } + } + + function _checkUNILPIntegration( + bytes32 _ilk, + GemJoinAbstract join, + ClipAbstract clip, + LPOsmAbstract pip, + address _medianizer1, + address _medianizer2, + bool _isMedian1, + bool _isMedian2, + bool _checkLiquidations + ) internal { + GemAbstract token = GemAbstract(join.gem()); + + pip.poke(); + vm.warp(block.timestamp + 3601); + pip.poke(); + spotter.poke(_ilk); + + // Check medianizer sources + assertEq(pip.src(), address(token)); + assertEq(pip.orb0(), _medianizer1); + assertEq(pip.orb1(), _medianizer2); + + // Authorization + assertEq(join.wards(pauseProxy), 1); + assertEq(vat.wards(address(join)), 1); + assertEq(clip.wards(address(end)), 1); + assertEq(pip.wards(address(osmMom)), 1); + assertEq(pip.bud(address(spotter)), 1); + assertEq(pip.bud(address(end)), 1); + if (_isMedian1) assertEq(MedianAbstract(_medianizer1).bud(address(pip)), 1); + if (_isMedian2) assertEq(MedianAbstract(_medianizer2).bud(address(pip)), 1); + + (,,,, uint256 dust) = vat.ilks(_ilk); + dust /= RAY; + uint256 amount = 2 * dust * WAD / _getUNIV2LPPrice(address(pip)); + _giveTokens(address(token), amount); + + assertEq(token.balanceOf(address(this)), amount); + assertEq(vat.gem(_ilk, address(this)), 0); + token.approve(address(join), amount); + join.join(address(this), amount); + assertEq(token.balanceOf(address(this)), 0); + assertEq(vat.gem(_ilk, address(this)), amount); + + // Tick the fees forward so that art != dai in wad units + vm.warp(block.timestamp + 1); + jug.drip(_ilk); + + // Deposit collateral, generate DAI + (,uint256 rate,,,) = vat.ilks(_ilk); + assertEq(vat.dai(address(this)), 0); + vat.frob(_ilk, address(this), address(this), address(this), int256(amount), int256(_divup(RAY * dust, rate))); + assertEq(vat.gem(_ilk, address(this)), 0); + assertTrue(vat.dai(address(this)) >= dust * RAY && vat.dai(address(this)) <= (dust + 1) * RAY); + + // Payback DAI, withdraw collateral + vat.frob(_ilk, address(this), address(this), address(this), -int256(amount), -int256(_divup(RAY * dust, rate))); + assertEq(vat.gem(_ilk, address(this)), amount); + assertEq(vat.dai(address(this)), 0); + + // Withdraw from adapter + join.exit(address(this), amount); + assertEq(token.balanceOf(address(this)), amount); + assertEq(vat.gem(_ilk, address(this)), 0); + + // Generate new DAI to force a liquidation + token.approve(address(join), amount); + join.join(address(this), amount); + // dart max amount of DAI + (,,uint256 spot,,) = vat.ilks(_ilk); + vat.frob(_ilk, address(this), address(this), address(this), int256(amount), int256(amount * spot / rate)); + vm.warp(block.timestamp + 1); + jug.drip(_ilk); + assertEq(clip.kicks(), 0); + if (_checkLiquidations) { + dog.bark(_ilk, address(this), address(this)); + assertEq(clip.kicks(), 1); + } + + // Dump all dai for next run + vat.move(address(this), address(0x0), vat.dai(address(this))); + } + + function _checkPsmIlkIntegration( + bytes32 _ilk, + GemJoinAbstract join, + ClipAbstract clip, + address pip, + PsmAbstract psm, + uint256 tinBps, + uint256 toutBps + ) internal { + uint256 tin = tinBps * WAD / 100_00; + uint256 tout = toutBps * WAD / 100_00; + GemAbstract token = GemAbstract(join.gem()); + + // Check PIP is set (ilk exists) + assertTrue(pip != address(0)); + + // Update price (poke spotter) + spotter.poke(_ilk); + + // Authorization (check wards) + assertEq(join.wards(pauseProxy), 1); + assertEq(join.wards(address(psm)), 1); + assertEq(psm.wards(pauseProxy), 1); + assertEq(vat.wards(address(join)), 1); + assertEq(clip.wards(address(end)), 1); + + // Check tin / tout values of PSM + assertEq(psm.tin(), tin, _concat("Incorrect-tin-", _ilk)); + assertEq(psm.tout(), tout, _concat("Incorrect-tout-", _ilk)); + + // Arbitrary amount of TOKEN to test PSM sellGem and buyGem with (in whole units) + // `amount` is the amount of _TOKEN_ we are selling/buying (NOT measured in Dai) + uint256 amount = 100_000; + + // Amount should be more than 10,000 as `tin` and `tout` are basis point measurements + require(amount >= 10_000, "checkPsmIlkIntegration/amount-too-low-for-precision-checks"); + + // Increase line where necessary to allow for coverage for both `buyGem` and `sellGem` + { + // Get the Art (current debt) and line (debt ceiling) for this PSM + (uint256 Art ,,, uint256 line,) = vat.ilks(_ilk); + // Normalize values to whole units so we can compare them + Art = Art / WAD; // `rate` is 1 * RAY for all PSMs + line = line / RAD; + + // If not enough room below line (e.g. Maxed out PSM) + if(Art + amount > line){ + _setIlkLine(_ilk, (Art + amount + 1) * RAD); // Increase `line` to `Art`+`amount` + } + } + + // Scale up `amount` to the correct Gem decimals value (buyGem and sellGem both use Gem decimals for precision) + amount = amount * (10 ** uint256(token.decimals())); + _giveTokens(address(token), amount); + + // Approvals + token.approve(address(join), amount); + dai.approve(address(psm), type(uint256).max); + + // Sell TOKEN _to_ the PSM for DAI (increases debt) + psm.sellGem(address(this), amount); + + amount = amount * (10 ** (18 - uint256(token.decimals()))); // Scale to Dai decimals (18) for Dai balance check + amount -= amount * tin / WAD; // Subtract `tin` fee (was deducted by PSM) + + assertEq(token.balanceOf(address(this)), 0, _concat("PSM.sellGem-token-balance-", _ilk)); + assertEq(dai.balanceOf(address(this)), amount, _concat("PSM.sellGem-dai-balance-", _ilk)); + + // For `sellGem` we had `amount` TOKENS, so there is no issue calling it + // For `buyGem` we have `amount` Dai, but `buyGem` takes `gemAmt` as TOKENS + // So we need to calculate the `gemAmt` of TOKEN we want to buy (i.e. subtract `tout` in advance) + amount -= _divup(amount * tout, WAD); // Subtract `tout` fee (i.e. convert to `gemAmt`) + amount = amount / (10 ** (18 - uint256(token.decimals()))); // Scale to Gem decimals for `buyGem()` + + // Buy TOKEN _from_ the PSM for DAI (decreases debt) + psm.buyGem(address(this), amount); + + // There may be some Dai dust left over depending on tout and decimals + // This should always be less than some dust limit + assertTrue(dai.balanceOf(address(this)) < 1 * WAD); // TODO lower this + assertEq(token.balanceOf(address(this)), amount, _concat("PSM.buyGem-token-balance-", _ilk)); + + // Dump all dai for next run + dai.transfer(address(0x0), dai.balanceOf(address(this))); + } + + function _checkDirectIlkIntegration( + bytes32 _ilk, + DirectDepositLike join, + ClipAbstract clip, + address pip, + uint256 bar, + uint256 tau + ) internal { + GemAbstract token = GemAbstract(join.gem()); + assertTrue(pip != address(0)); + + spotter.poke(_ilk); + + // Authorization + assertEq(join.wards(pauseProxy), 1); + assertEq(vat.wards(address(join)), 1); + assertEq(clip.wards(address(end)), 1); + assertEq(join.wards(address(esm)), 1); // Required in case of gov. attack + assertEq(join.wards(addr.addr("DIRECT_MOM")), 1); // Zero-delay shutdown for Aave gov. attack + + // Check the bar/tau/king are set correctly + assertEq(join.bar(), bar); + assertEq(join.tau(), tau); + assertEq(join.king(), pauseProxy); + + // Set the target bar to be super low to max out the debt ceiling + GodMode.setWard(address(join), address(this), 1); + join.file("bar", 1 * RAY / 10000); // 0.01% + join.deny(address(this)); + join.exec(); + + // Module should be maxed out + (,,, uint256 line,) = vat.ilks(_ilk); + (uint256 ink, uint256 art) = vat.urns(_ilk, address(join)); + assertEq(ink*RAY, line); + assertEq(art*RAY, line); + assertGe(token.balanceOf(address(join)), ink - 1); // Allow for small rounding error + + // Disable the module + GodMode.setWard(address(join), address(this), 1); + join.file("bar", 0); + join.deny(address(this)); + join.exec(); + + // Module should clear out + (ink, art) = vat.urns(_ilk, address(join)); + assertLe(ink, 1); + assertLe(art, 1); + assertEq(token.balanceOf(address(join)), 0); + } + + function _getSignatures(bytes32 signHash) internal returns (bytes memory signatures, address[] memory signers) { + // seeds chosen s.t. corresponding addresses are in ascending order + uint8[30] memory seeds = [8,10,6,2,9,15,14,20,7,29,24,13,12,25,16,26,21,22,0,18,17,27,3,28,23,19,4,5,1,11]; + uint256 numSigners = seeds.length; + signers = new address[](numSigners); + for(uint256 i; i < numSigners; i++) { + uint256 sk = uint256(keccak256(abi.encode(seeds[i]))); + signers[i] = vm.addr(sk); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(sk, signHash); + signatures = abi.encodePacked(signatures, r, s, v); + } + assertEq(signatures.length, numSigners * 65); + } + + function _oracleAuthRequestMint( + bytes32 sourceDomain, + bytes32 targetDomain, + uint256 toMint, + uint256 expectedFee + ) internal { + TeleportOracleAuthLike oracleAuth = TeleportOracleAuthLike(addr.addr("MCD_ORACLE_AUTH_TELEPORT_FW_A")); + GodMode.setWard(address(oracleAuth), address(this), 1); + (bytes memory signatures, address[] memory signers) = _getSignatures(oracleAuth.getSignHash(TeleportGUID({ + sourceDomain: sourceDomain, + targetDomain: targetDomain, + receiver: bytes32(uint256(uint160(address(this)))), + operator: bytes32(0), + amount: uint128(toMint), + nonce: 1, + timestamp: uint48(block.timestamp) + }))); + oracleAuth.addSigners(signers); + oracleAuth.requestMint(TeleportGUID({ + sourceDomain: sourceDomain, + targetDomain: targetDomain, + receiver: bytes32(uint256(uint160(address(this)))), + operator: bytes32(0), + amount: uint128(toMint), + nonce: 1, + timestamp: uint48(block.timestamp) + }), signatures, expectedFee, 0); + } + + function _checkTeleportFWIntegration( + bytes32 sourceDomain, + bytes32 targetDomain, + uint256 line, + address gateway, + address fee, + address escrow, + uint256 toMint, + uint256 expectedFee, + uint256 expectedTtl + ) internal { + TeleportJoinLike join = TeleportJoinLike(addr.addr("MCD_JOIN_TELEPORT_FW_A")); + TeleportRouterLike router = TeleportRouterLike(addr.addr("MCD_ROUTER_TELEPORT_FW_A")); + + // Sanity checks + assertEq(join.line(sourceDomain), line); + assertEq(join.fees(sourceDomain), address(fee)); + assertEq(dai.allowance(escrow, gateway), type(uint256).max); + assertEq(dai.allowance(gateway, address(router)), type(uint256).max); + assertEq(TeleportFeeLike(fee).fee(), expectedFee); + assertEq(TeleportFeeLike(fee).ttl(), expectedTtl); + assertEq(router.gateways(sourceDomain), gateway); + assertEq(router.domains(gateway), sourceDomain); + assertEq(TeleportBridgeLike(gateway).l1Escrow(), escrow); + assertEq(TeleportBridgeLike(gateway).l1TeleportRouter(), address(router)); + assertEq(TeleportBridgeLike(gateway).l1Token(), address(dai)); + + { + // NOTE: We are calling the router directly because the bridge code is minimal and unique to each domain + // This tests the slow path via the router + vm.startPrank(gateway); + router.requestMint(TeleportGUID({ + sourceDomain: sourceDomain, + targetDomain: targetDomain, + receiver: bytes32(uint256(uint160(address(this)))), + operator: bytes32(0), + amount: uint128(toMint), + nonce: 0, + timestamp: uint48(block.timestamp - TeleportFeeLike(fee).ttl()) + }), 0, 0); + vm.stopPrank(); + assertEq(dai.balanceOf(address(this)), toMint); + assertEq(join.debt(sourceDomain), int256(toMint)); + } + + // Check oracle auth mint -- add custom signatures to test + uint256 _fee = toMint * expectedFee / WAD; + { + uint256 prevDai = vat.dai(address(vow)); + _oracleAuthRequestMint(sourceDomain, targetDomain, toMint, expectedFee); + assertEq(dai.balanceOf(address(this)), toMint * 2 - _fee); + assertEq(join.debt(sourceDomain), int256(toMint * 2)); + assertEq(vat.dai(address(vow)) - prevDai, _fee * RAY); + } + + // Check settle + dai.transfer(gateway, toMint * 2 - _fee); + vm.startPrank(gateway); + router.settle(targetDomain, toMint * 2 - _fee); + vm.stopPrank(); + assertEq(dai.balanceOf(gateway), 0); + assertEq(join.debt(sourceDomain), int256(_fee)); + } + + function _checkCureLoadTeleport( + bytes32 sourceDomain, + bytes32 targetDomain, + uint256 toMint, + uint256 expectedFee, + uint256 expectedTell, + bool cage + ) internal { + TeleportJoinLike join = TeleportJoinLike(addr.addr("MCD_JOIN_TELEPORT_FW_A")); + + // Oracle auth mint -- add custom signatures to test + _oracleAuthRequestMint(sourceDomain, targetDomain, toMint, expectedFee); + assertEq(join.debt(sourceDomain), int256(toMint)); + + // Emulate Global Settlement + if (cage) { + assertEq(cure.live(), 1); + vm.store( + address(cure), + keccak256(abi.encode(address(this), uint256(0))), + bytes32(uint256(1)) + ); + cure.cage(); + assertEq(cure.tell(), 0); + } + assertEq(cure.live(), 0); + + // Check cure tells the teleport source correctly + cure.load(address(join)); + assertEq(cure.tell(), expectedTell); + } + + function _checkDaiVest( + uint256 _index, + address _wallet, + uint256 _start, + uint256 _cliff, + uint256 _end, + uint256 _days, + address _manager, + uint256 _restricted, + uint256 _reward, + uint256 _claimed + ) internal { + assertEq(vestDai.usr(_index), _wallet, "usr"); + assertEq(vestDai.bgn(_index), _start, "bgn"); + assertEq(vestDai.clf(_index), _cliff, "clf"); + assertEq(vestDai.fin(_index), _end, "fin"); + assertEq(vestDai.fin(_index), _start + _days - 1, "fin"); + assertEq(vestDai.mgr(_index), _manager, "mgr"); + assertEq(vestDai.res(_index), _restricted, "res"); + assertEq(vestDai.tot(_index), _reward, "tot"); + assertEq(vestDai.rxd(_index), _claimed, "rxd"); + } + + function _getIlkMat(bytes32 _ilk) internal view returns (uint256 mat) { + (, mat) = spotter.ilks(_ilk); + } + + function _getIlkDuty(bytes32 _ilk) internal view returns (uint256 duty) { + (duty,) = jug.ilks(_ilk); + } + + function _setIlkMat(bytes32 ilk, uint256 amount) internal { + vm.store( + address(spotter), + bytes32(uint256(keccak256(abi.encode(ilk, uint256(1)))) + 1), + bytes32(amount) + ); + assertEq(_getIlkMat(ilk), amount, _concat("TestError/setIlkMat-", ilk)); + } + + function _setIlkRate(bytes32 ilk, uint256 amount) internal { + vm.store( + address(vat), + bytes32(uint256(keccak256(abi.encode(ilk, uint256(2)))) + 1), + bytes32(amount) + ); + (,uint256 rate,,,) = vat.ilks(ilk); + assertEq(rate, amount, _concat("TestError/setIlkRate-", ilk)); + } + + function _setIlkLine(bytes32 ilk, uint256 amount) internal { + vm.store( + address(vat), + bytes32(uint256(keccak256(abi.encode(ilk, uint256(2)))) + 3), + bytes32(amount) + ); + (,,,uint256 line,) = vat.ilks(ilk); + assertEq(line, amount, _concat("TestError/setIlkLine-", ilk)); + } + + function _checkIlkLerpOffboarding(bytes32 _ilk, bytes32 _lerp, uint256 _startMat, uint256 _endMat) internal { + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + LerpAbstract lerp = LerpAbstract(lerpFactory.lerps(_lerp)); + + vm.warp(block.timestamp + lerp.duration() / 2); + assertEq(_getIlkMat(_ilk), _startMat * RAY / 100); + lerp.tick(); + _assertEqApprox(_getIlkMat(_ilk), ((_startMat + _endMat) / 2) * RAY / 100, RAY / 100); + + vm.warp(block.timestamp + lerp.duration()); + lerp.tick(); + assertEq(_getIlkMat(_ilk), _endMat * RAY / 100); + } + + function _checkIlkLerpIncreaseMatOffboarding(bytes32 _ilk, bytes32 _oldLerp, bytes32 _newLerp, uint256 _newEndMat) internal { + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + LerpFactoryAbstract OLD_LERP_FAB = LerpFactoryAbstract(0xbBD821c291c492c40Db2577D9b6E5B1bdAEBD207); + LerpAbstract oldLerp = LerpAbstract(OLD_LERP_FAB.lerps(_oldLerp)); + + uint256 t = (block.timestamp - oldLerp.startTime()) * WAD / oldLerp.duration(); + uint256 tickMat = oldLerp.end() * t / WAD + oldLerp.start() - oldLerp.start() * t / WAD; + assertEq(_getIlkMat(_ilk), tickMat); + assertEq(spotter.wards(address(oldLerp)), 0); + + LerpAbstract newLerp = LerpAbstract(lerpFactory.lerps(_newLerp)); + + vm.warp(block.timestamp + newLerp.duration() / 2); + assertEq(_getIlkMat(_ilk), tickMat); + newLerp.tick(); + _assertEqApprox(_getIlkMat(_ilk), (tickMat + _newEndMat * RAY / 100) / 2, RAY / 100); + + vm.warp(block.timestamp + newLerp.duration()); + newLerp.tick(); + assertEq(_getIlkMat(_ilk), _newEndMat * RAY / 100); + } + + function _getExtcodesize(address target) internal view returns (uint256 exsize) { + assembly { + exsize := extcodesize(target) + } + } + + function _getBytecodeMetadataLength(address a) internal view returns (uint256 length) { + // The Solidity compiler encodes the metadata length in the last two bytes of the contract bytecode. + assembly { + let ptr := mload(0x40) + let size := extcodesize(a) + if iszero(lt(size, 2)) { + extcodecopy(a, ptr, sub(size, 2), 2) + length := mload(ptr) + length := shr(240, length) + length := add(length, 2) // the two bytes used to specify the length are not counted in the length + } + // We'll return zero if the bytecode is shorter than two bytes. + } + } + + function _skipWards(address target, address deployer) internal view returns (bool ok) { + ok = ( + target == address(chainLog) && + deployer == deployers.PE_CURRENT() + ) || + ( + deployer == deployers.ORACLES_1() + ) || + ( + deployer == deployers.ORACLES_2() + ); + } + + function _checkWards(address _addr, string memory contractName) internal { + for (uint256 i = 0; i < deployers.count(); i ++) { + address deployer = deployers.addr(i); + (bool ok, bytes memory data) = _addr.call( + abi.encodeWithSignature("wards(address)", deployer) + ); + if (!ok || data.length != 32) return; + uint256 ward = abi.decode(data, (uint256)); + if (ward > 0) { + if (_skipWards(_addr, deployer)) continue; + emit log("Error: Bad Auth"); + emit log_named_address(" Deployer Address", deployer); + emit log_named_string(" Affected Contract", contractName); + fail(); + } + } + } + + function _checkSource(address _addr, string memory contractName) internal { + (bool ok, bytes memory data) = + _addr.call(abi.encodeWithSignature("src()")); + if (!ok || data.length != 32) return; + address source = abi.decode(data, (address)); + string memory sourceName = string( + abi.encodePacked("source of ", contractName) + ); + _checkWards(source, sourceName); + } + + function _checkAuth(bool onlySource) internal { + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done(), "TestError/spell-not-done"); + + bytes32[] memory contractNames = chainLog.list(); + for(uint256 i = 0; i < contractNames.length; i++) { + address _addr = chainLog.getAddress(contractNames[i]); + string memory contractName = string( + abi.encodePacked(contractNames[i]) + ); + if (onlySource) _checkSource(_addr, contractName); + else _checkWards(_addr, contractName); + } + } + + function _checkChainlogKey(bytes32 key) internal { + assertEq(chainLog.getAddress(key), addr.addr(key), _concat("TestError/Chainlog-key-mismatch-", key)); + } + + function _checkChainlogVersion(string memory key) internal { + assertEq(chainLog.version(), key, _concat("TestError/Chainlog-version-mismatch-", key)); + } + + function _checkRWADocUpdate(bytes32 ilk, string memory currentDoc, string memory newDoc) internal { + (string memory doc, address pip, uint48 tau, uint48 toc) = liquidationOracle.ilks(ilk); + + assertEq(doc, currentDoc, _concat("TestError/bad-old-document-for-", ilk)); + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + (string memory docNew, address pipNew, uint48 tauNew, uint48 tocNew) = liquidationOracle.ilks(ilk); + + assertEq(docNew, newDoc, _concat("TestError/bad-new-document-for-", ilk)); + assertEq(pip, pipNew, _concat("TestError/pip-is-not-the-same-for-", ilk)); + assertTrue(tau == tauNew, _concat("TestError/tau-is-not-the-same-for-", ilk)); + assertTrue(toc == tocNew, _concat("TestError/toc-is-not-the-same-for", ilk)); + } + + function _testGeneral() internal { + string memory description = new DssSpell().description(); + assertTrue(bytes(description).length > 0, "TestError/spell-description-length"); + // DS-Test can't handle strings directly, so cast to a bytes32. + assertEq(_stringToBytes32(spell.description()), + _stringToBytes32(description), "TestError/spell-description"); + + if(address(spell) != address(spellValues.deployed_spell)) { + assertEq(spell.expiration(), block.timestamp + spellValues.expiration_threshold, "TestError/spell-expiration"); + } else { + assertEq(spell.expiration(), spellValues.deployed_spell_created + spellValues.expiration_threshold, "TestError/spell-expiration"); + } + + assertTrue(spell.officeHours() == spellValues.office_hours_enabled, "TestError/spell-office-hours"); + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done(), "TestError/spell-not-done"); + + _checkSystemValues(afterSpell); + + _checkCollateralValues(afterSpell); + } + + function _testFailWrongDay() internal { + require(spell.officeHours() == spellValues.office_hours_enabled); + if (spell.officeHours()) { + _vote(address(spell)); + spell.schedule(); + + uint256 castTime = block.timestamp + pause.delay(); + uint256 day = (castTime / 1 days + 3) % 7; + if (day < 5) { + castTime += 5 days - day * 86400; + } + + vm.warp(castTime); + spell.cast(); + } else { + revert("Office Hours Disabled"); + } + } + + function _testFailTooEarly() internal { + require(spell.officeHours() == spellValues.office_hours_enabled); + if (spell.officeHours()) { + _vote(address(spell)); + spell.schedule(); + + uint256 castTime = block.timestamp + pause.delay() + 24 hours; + uint256 hour = castTime / 1 hours % 24; + if (hour >= 14) { + castTime -= hour * 3600 - 13 hours; + } + + vm.warp(castTime); + spell.cast(); + } else { + revert("Office Hours Disabled"); + } + } + + function _testFailTooLate() internal { + require(spell.officeHours() == spellValues.office_hours_enabled); + if (spell.officeHours()) { + _vote(address(spell)); + spell.schedule(); + + uint256 castTime = block.timestamp + pause.delay(); + uint256 hour = castTime / 1 hours % 24; + if (hour < 21) { + castTime += 21 hours - hour * 3600; + } + + vm.warp(castTime); + spell.cast(); + } else { + revert("Office Hours Disabled"); + } + } + + function _testOnTime() internal { + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + } + + function _testCastCost() internal { + _vote(address(spell)); + spell.schedule(); + + _castPreviousSpell(); + vm.warp(spell.nextCastTime()); + uint256 startGas = gasleft(); + spell.cast(); + uint256 endGas = gasleft(); + uint256 totalGas = startGas - endGas; + + assertTrue(spell.done()); + // Fail if cast is too expensive + assertLe(totalGas, 15 * MILLION); + } + + function _testDeployCost() internal { + uint256 startGas = gasleft(); + new DssSpell(); + uint256 endGas = gasleft(); + uint256 totalGas = startGas - endGas; + + // Warn if deploy exceeds block target size + if (totalGas > 15 * MILLION) { + emit log("Warn: deploy gas exceeds average block target"); + emit log_named_uint(" deploy gas", totalGas); + emit log_named_uint(" block target", 15 * MILLION); + } + + // Fail if deploy is too expensive + assertLe(totalGas, 30 * MILLION, "testDeployCost/DssSpell-exceeds-max-block-size"); + } + + // Fail when contract code size exceeds 24576 bytes (a limit introduced in Spurious Dragon). + // This contract may not be deployable. + // Consider enabling the optimizer (with a low "runs" value!), + // turning off revert strings, or using libraries. + function _testContractSize() internal { + uint256 _sizeSpell; + address _spellAddr = address(spell); + assembly { + _sizeSpell := extcodesize(_spellAddr) + } + assertLe(_sizeSpell, 24576, "testContractSize/DssSpell-exceeds-max-contract-size"); + + uint256 _sizeAction; + address _actionAddr = spell.action(); + assembly { + _sizeAction := extcodesize(_actionAddr) + } + assertLe(_sizeAction, 24576, "testContractSize/DssSpellAction-exceeds-max-contract-size"); + + } + + // The specific date doesn't matter that much since function is checking for difference between warps + function _testNextCastTime() internal { + vm.warp(1606161600); // Nov 23, 20 UTC (could be cast Nov 26) + + _vote(address(spell)); + spell.schedule(); + + uint256 monday_1400_UTC = 1606744800; // Nov 30, 2020 + uint256 monday_2100_UTC = 1606770000; // Nov 30, 2020 + + // Day tests + vm.warp(monday_1400_UTC); // Monday, 14:00 UTC + assertEq(spell.nextCastTime(), monday_1400_UTC); // Monday, 14:00 UTC + + if (spell.officeHours()) { + vm.warp(monday_1400_UTC - 1 days); // Sunday, 14:00 UTC + assertEq(spell.nextCastTime(), monday_1400_UTC); // Monday, 14:00 UTC + + vm.warp(monday_1400_UTC - 2 days); // Saturday, 14:00 UTC + assertEq(spell.nextCastTime(), monday_1400_UTC); // Monday, 14:00 UTC + + vm.warp(monday_1400_UTC - 3 days); // Friday, 14:00 UTC + assertEq(spell.nextCastTime(), monday_1400_UTC - 3 days); // Able to cast + + vm.warp(monday_2100_UTC); // Monday, 21:00 UTC + assertEq(spell.nextCastTime(), monday_1400_UTC + 1 days); // Tuesday, 14:00 UTC + + vm.warp(monday_2100_UTC - 1 days); // Sunday, 21:00 UTC + assertEq(spell.nextCastTime(), monday_1400_UTC); // Monday, 14:00 UTC + + vm.warp(monday_2100_UTC - 2 days); // Saturday, 21:00 UTC + assertEq(spell.nextCastTime(), monday_1400_UTC); // Monday, 14:00 UTC + + vm.warp(monday_2100_UTC - 3 days); // Friday, 21:00 UTC + assertEq(spell.nextCastTime(), monday_1400_UTC); // Monday, 14:00 UTC + + // Time tests + uint256 castTime; + + for(uint256 i = 0; i < 5; i++) { + castTime = monday_1400_UTC + i * 1 days; // Next day at 14:00 UTC + vm.warp(castTime - 1 seconds); // 13:59:59 UTC + assertEq(spell.nextCastTime(), castTime); + + vm.warp(castTime + 7 hours + 1 seconds); // 21:00:01 UTC + if (i < 4) { + assertEq(spell.nextCastTime(), monday_1400_UTC + (i + 1) * 1 days); // Next day at 14:00 UTC + } else { + assertEq(spell.nextCastTime(), monday_1400_UTC + 7 days); // Next monday at 14:00 UTC (friday case) + } + } + } + } + + function _testFailNotScheduled() internal view { + spell.nextCastTime(); + } + + function _testUseEta() internal { + vm.warp(1606161600); // Nov 23, 20 UTC (could be cast Nov 26) + + _vote(address(spell)); + spell.schedule(); + + uint256 castTime = spell.nextCastTime(); + assertEq(castTime, spell.eta()); + } + + // Verifies that the bytecode of the action of the spell used for testing + // matches what we'd expect. + // + // Not a complete replacement for Etherscan verification, unfortunately. + // This is because the DssSpell bytecode is non-deterministic because it + // deploys the action in its constructor and incorporates the action + // address as an immutable variable--but the action address depends on the + // address of the DssSpell which depends on the address+nonce of the + // deploying address. If we had a way to simulate a contract creation by + // an arbitrary address+nonce, we could verify the bytecode of the DssSpell + // instead. + // + // Vacuous until the deployed_spell value is non-zero. + function _testBytecodeMatches() internal { + // The DssSpell bytecode is non-deterministic, compare only code size + DssSpell expectedSpell = new DssSpell(); + assertEq(_getExtcodesize(address(spell)), _getExtcodesize(address(expectedSpell)), "TestError/spell-codesize"); + + // The SpellAction bytecode can be compared after chopping off the metada + address expectedAction = expectedSpell.action(); + address actualAction = spell.action(); + uint256 expectedBytecodeSize; + uint256 actualBytecodeSize; + assembly { + expectedBytecodeSize := extcodesize(expectedAction) + actualBytecodeSize := extcodesize(actualAction) + } + + uint256 metadataLength = _getBytecodeMetadataLength(expectedAction); + assertTrue(metadataLength <= expectedBytecodeSize); + expectedBytecodeSize -= metadataLength; + + metadataLength = _getBytecodeMetadataLength(actualAction); + assertTrue(metadataLength <= actualBytecodeSize); + actualBytecodeSize -= metadataLength; + + assertEq(actualBytecodeSize, expectedBytecodeSize); + uint256 size = actualBytecodeSize; + uint256 expectedHash; + uint256 actualHash; + assembly { + let ptr := mload(0x40) + + extcodecopy(expectedAction, ptr, 0, size) + expectedHash := keccak256(ptr, size) + + extcodecopy(actualAction, ptr, 0, size) + actualHash := keccak256(ptr, size) + } + assertEq(actualHash, expectedHash); + } + + // Validate addresses in test harness match chainlog + function _testChainlogValues() internal { + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + for(uint256 i = 0; i < chainLog.count(); i++) { + (bytes32 _key, address _val) = chainLog.get(i); + assertEq(_val, addr.addr(_key), _concat("TestError/chainlog-addr-mismatch-", _key)); + } + + _checkChainlogVersion(afterSpell.chainlog_version); + } + + // Ensure version is updated if chainlog changes + function _testChainlogVersionBump() internal { + uint256 _count = chainLog.count(); + string memory _version = chainLog.version(); + address[] memory _chainlog_addrs = new address[](_count); + + for(uint256 i = 0; i < _count; i++) { + (, address _val) = chainLog.get(i); + _chainlog_addrs[i] = _val; + } + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + if (keccak256(abi.encodePacked(_version)) == keccak256(abi.encodePacked(chainLog.version()))) { + // Fail if the version is not updated and the chainlog count has changed + if (_count != chainLog.count()) { + emit log_named_string("Error", _concat("TestError/chainlog-version-not-updated-count-change-", _version)); + fail(); + return; + } + // Fail if the chainlog is the same size but local keys don't match the chainlog. + for(uint256 i = 0; i < _count; i++) { + (, address _val) = chainLog.get(i); + if (_chainlog_addrs[i] != _val) { + emit log_named_string("Error", _concat("TestError/chainlog-version-not-updated-address-change-", _version)); + fail(); + return; + } + } + } + } +} diff --git a/archive/2023-08-18-DssSpell/DssSpell.t.sol b/archive/2023-08-18-DssSpell/DssSpell.t.sol new file mode 100644 index 00000000..e6da92da --- /dev/null +++ b/archive/2023-08-18-DssSpell/DssSpell.t.sol @@ -0,0 +1,686 @@ +// SPDX-FileCopyrightText: © 2020 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.16; + +import "./DssSpell.t.base.sol"; +import {ScriptTools, StdStorage, stdStorage} from "dss-test/DssTest.sol"; + +import {RootDomain} from "dss-test/domains/RootDomain.sol"; +import {OptimismDomain} from "dss-test/domains/OptimismDomain.sol"; +import {ArbitrumDomain} from "dss-test/domains/ArbitrumDomain.sol"; + +interface L2Spell { + function dstDomain() external returns (bytes32); + function gateway() external returns (address); +} + +interface L2Gateway { + function validDomains(bytes32) external returns (uint256); +} + +interface BridgeLike { + function l2TeleportGateway() external view returns (address); +} + +interface RwaLiquidationOracleLike { + function ilks(bytes32 ilk) external view returns (string memory doc, address pip, uint48 tau, uint48 toc); + function good(bytes32 ilk) external view returns (bool); +} + +interface RwaUrnLike { + function vat() external view returns (address); + function jug() external view returns (address); + function daiJoin() external view returns (address); + function outputConduit() external view returns (address); + function wards(address) external view returns (uint256); + function hope(address) external; + function can(address) external view returns (uint256); + function gemJoin() external view returns (address); + function lock(uint256) external; + function draw(uint256) external; + function wipe(uint256) external; + function free(uint256) external; +} + +interface ProxyLike { + function exec(address target, bytes calldata args) external payable returns (bytes memory out); +} + +interface TransferOwnershipLike { + function owner() external view returns (address); +} + +interface ChangeAdminLike { + function admin() external view returns (address); +} + +interface ACLManagerLike { + function DEFAULT_ADMIN_ROLE() external view returns (bytes32); + function isEmergencyAdmin(address admin) external view returns (bool); + function isPoolAdmin(address admin) external view returns (bool); + function hasRole(bytes32 role, address account) external view returns (bool); +} + +interface PoolAddressProviderLike { + function getACLAdmin() external view returns (address); +} + +contract DssSpellTest is DssSpellTestBase { + using stdStorage for StdStorage; + + string config; + RootDomain rootDomain; + OptimismDomain optimismDomain; + ArbitrumDomain arbitrumDomain; + + // DO NOT TOUCH THE FOLLOWING TESTS, THEY SHOULD BE RUN ON EVERY SPELL + function testGeneral() public { + _testGeneral(); + } + + function testFailWrongDay() public { + _testFailWrongDay(); + } + + function testFailTooEarly() public { + _testFailTooEarly(); + } + + function testFailTooLate() public { + _testFailTooLate(); + } + + function testOnTime() public { + _testOnTime(); + } + + function testCastCost() public { + _testCastCost(); + } + + function testDeployCost() public { + _testDeployCost(); + } + + function testContractSize() public { + _testContractSize(); + } + + function testNextCastTime() public { + _testNextCastTime(); + } + + function testFailNotScheduled() public view { + _testFailNotScheduled(); + } + + function testUseEta() public { + _testUseEta(); + } + + function testAuth() public { + _checkAuth(false); + } + + function testAuthInSources() public { + _checkAuth(true); + } + + function testBytecodeMatches() public { + _testBytecodeMatches(); + } + + function testChainlogValues() public { + _testChainlogValues(); + } + + function testChainlogVersionBump() public { + _testChainlogVersionBump(); + } + + function testOsmAuth() private { // make private to disable + // address ORACLE_WALLET01 = 0x4D6fbF888c374D7964D56144dE0C0cFBd49750D3; + + // validate the spell does what we told it to + //bytes32[] memory ilks = reg.list(); + + //for(uint256 i = 0; i < ilks.length; i++) { + // uint256 class = reg.class(ilks[i]); + // if (class != 1) { continue; } + + // address pip = reg.pip(ilks[i]); + // // skip USDC, TUSD, PAXUSD, GUSD + // if (pip == 0x838212865E2c2f4F7226fCc0A3EFc3EB139eC661 || + // pip == 0x0ce19eA2C568890e63083652f205554C927a0caa || + // pip == 0xdF8474337c9D3f66C0b71d31C7D3596E4F517457 || + // pip == 0x57A00620Ba1f5f81F20565ce72df4Ad695B389d7) { + // continue; + // } + + // assertEq(OsmAbstract(pip).wards(ORACLE_WALLET01), 0); + //} + + //_vote(address(spell)); + //_scheduleWaitAndCast(address(spell)); + //assertTrue(spell.done()); + + //for(uint256 i = 0; i < ilks.length; i++) { + // uint256 class = reg.class(ilks[i]); + // if (class != 1) { continue; } + + // address pip = reg.pip(ilks[i]); + // // skip USDC, TUSD, PAXUSD, GUSD + // if (pip == 0x838212865E2c2f4F7226fCc0A3EFc3EB139eC661 || + // pip == 0x0ce19eA2C568890e63083652f205554C927a0caa || + // pip == 0xdF8474337c9D3f66C0b71d31C7D3596E4F517457 || + // pip == 0x57A00620Ba1f5f81F20565ce72df4Ad695B389d7) { + // continue; + // } + + // assertEq(OsmAbstract(pip).wards(ORACLE_WALLET01), 1); + //} + } + + function testOracleList() private { // make private to disable + // address ORACLE_WALLET01 = 0x4D6fbF888c374D7964D56144dE0C0cFBd49750D3; + + //assertEq(OsmAbstract(0xF15993A5C5BE496b8e1c9657Fd2233b579Cd3Bc6).wards(ORACLE_WALLET01), 0); + + //_vote(address(spell)); + //_scheduleWaitAndCast(address(spell)); + //assertTrue(spell.done()); + + //assertEq(OsmAbstract(0xF15993A5C5BE496b8e1c9657Fd2233b579Cd3Bc6).wards(ORACLE_WALLET01), 1); + } + + function testRemoveChainlogValues() private { // make private to disable + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + try chainLog.getAddress("INSERT_DELETED_CHAINLOG_KEY_HERE") { + assertTrue(false); + } catch Error(string memory errmsg) { + assertTrue(_cmpStr(errmsg, "dss-chain-log/invalid-key")); + } catch { + assertTrue(false); + } + } + + function testCollateralIntegrations() private { // make public to enable + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + // Insert new collateral tests here + _checkIlkIntegration( + "GNO-A", + GemJoinAbstract(addr.addr("MCD_JOIN_GNO_A")), + ClipAbstract(addr.addr("MCD_CLIP_GNO_A")), + addr.addr("PIP_GNO"), + true, /* _isOSM */ + true, /* _checkLiquidations */ + false /* _transferFee */ + ); + } + + function testIlkClipper() private { // make public to enable + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + // _checkIlkClipper( + // "LINK-A", + // GemJoinAbstract(addr.addr("MCD_JOIN_LINK_A")), + // ClipAbstract(addr.addr("MCD_CLIP_LINK_A")), + // addr.addr("MCD_CLIP_CALC_LINK_A"), + // OsmAbstract(addr.addr("PIP_LINK")), + // 1_000_000 * WAD + // ); + + // _checkIlkClipper( + // "MATIC-A", + // GemJoinAbstract(addr.addr("MCD_JOIN_MATIC_A")), + // ClipAbstract(addr.addr("MCD_CLIP_MATIC_A")), + // addr.addr("MCD_CLIP_CALC_MATIC_A"), + // OsmAbstract(addr.addr("PIP_MATIC")), + // 10_000_000 * WAD + // ); + + // _checkIlkClipper( + // "YFI-A", + // GemJoinAbstract(addr.addr("MCD_JOIN_YFI_A")), + // ClipAbstract(addr.addr("MCD_CLIP_YFI_A")), + // addr.addr("MCD_CLIP_CALC_YFI_A"), + // OsmAbstract(addr.addr("PIP_YFI")), + // 1_000 * WAD + // ); + + // _checkIlkClipper( + // "UNIV2USDCETH-A", + // GemJoinAbstract(addr.addr("MCD_JOIN_UNIV2USDCETH_A")), + // ClipAbstract(addr.addr("MCD_CLIP_UNIV2USDCETH_A")), + // addr.addr("MCD_CLIP_CALC_UNIV2USDCETH_A"), + // OsmAbstract(addr.addr("PIP_UNIV2USDCETH")), + // 1 * WAD + // ); + } + + function testLerpSurplusBuffer() private { // make private to disable + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + // Insert new SB lerp tests here + + LerpAbstract lerp = LerpAbstract(lerpFactory.lerps("NAME")); + + uint256 duration = 210 days; + vm.warp(block.timestamp + duration / 2); + assertEq(vow.hump(), 60 * MILLION * RAD); + lerp.tick(); + assertEq(vow.hump(), 75 * MILLION * RAD); + vm.warp(block.timestamp + duration / 2); + lerp.tick(); + assertEq(vow.hump(), 90 * MILLION * RAD); + assertTrue(lerp.done()); + } + + function testNewChainlogValues() private { // make private to disable + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + _checkChainlogKey("INSERT_NEW_CHAINLOG_KEY_HERE"); + _checkChainlogVersion("1.15.0"); + } + + function testNewIlkRegistryValues() private { // make private to disable + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + // Insert new ilk registry values tests here + // RWA015 + // (, address pipRwa015,,) = oracle.ilks("RWA015-A"); + + // assertEq(reg.pos("RWA015-A"), 62); + // assertEq(reg.join("RWA015-A"), addr.addr("MCD_JOIN_RWA015_A")); + // assertEq(reg.gem("RWA015-A"), addr.addr("RWA015")); + // assertEq(reg.dec("RWA015-A"), GemAbstract(addr.addr("RWA015")).decimals()); + // assertEq(reg.class("RWA015-A"), 3); + // assertEq(reg.pip("RWA015-A"), pipRwa015); + // assertEq(reg.name("RWA015-A"), "RWA015-A: BlockTower Andromeda"); + // assertEq(reg.symbol("RWA015-A"), GemAbstract(addr.addr("RWA015")).symbol()); + } + + function testOSMs() private { // make private to disable + address READER = address(0); + + // Track OSM authorizations here + assertEq(OsmAbstract(addr.addr("PIP_TOKEN")).bud(READER), 0); + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + assertEq(OsmAbstract(addr.addr("PIP_TOKEN")).bud(READER), 1); + } + + function testMedianizers() private { // make private to disable + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + // Track Median authorizations here + address SET_TOKEN = address(0); + address TOKENUSD_MED = OsmAbstract(addr.addr("PIP_TOKEN")).src(); + assertEq(MedianAbstract(TOKENUSD_MED).bud(SET_TOKEN), 1); + } + + // Leave this test public (for now) as this is acting like a config test + function testPSMs() public { + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + bytes32 _ilk; + + // USDC + _ilk = "PSM-USDC-A"; + assertEq(addr.addr("MCD_JOIN_PSM_USDC_A"), reg.join(_ilk)); + assertEq(addr.addr("MCD_CLIP_PSM_USDC_A"), reg.xlip(_ilk)); + assertEq(addr.addr("PIP_USDC"), reg.pip(_ilk)); + assertEq(addr.addr("MCD_PSM_USDC_A"), chainLog.getAddress("MCD_PSM_USDC_A")); + _checkPsmIlkIntegration( + _ilk, + GemJoinAbstract(addr.addr("MCD_JOIN_PSM_USDC_A")), + ClipAbstract(addr.addr("MCD_CLIP_PSM_USDC_A")), + addr.addr("PIP_USDC"), + PsmAbstract(addr.addr("MCD_PSM_USDC_A")), + 0, // tin + 0 // tout + ); + + // GUSD + _ilk = "PSM-GUSD-A"; + assertEq(addr.addr("MCD_JOIN_PSM_GUSD_A"), reg.join(_ilk)); + assertEq(addr.addr("MCD_CLIP_PSM_GUSD_A"), reg.xlip(_ilk)); + assertEq(addr.addr("PIP_GUSD"), reg.pip(_ilk)); + assertEq(addr.addr("MCD_PSM_GUSD_A"), chainLog.getAddress("MCD_PSM_GUSD_A")); + _checkPsmIlkIntegration( + _ilk, + GemJoinAbstract(addr.addr("MCD_JOIN_PSM_GUSD_A")), + ClipAbstract(addr.addr("MCD_CLIP_PSM_GUSD_A")), + addr.addr("PIP_GUSD"), + PsmAbstract(addr.addr("MCD_PSM_GUSD_A")), + 0, // tin + 0 // tout + ); + + // USDP + _ilk = "PSM-PAX-A"; + assertEq(addr.addr("MCD_JOIN_PSM_PAX_A"), reg.join(_ilk)); + assertEq(addr.addr("MCD_CLIP_PSM_PAX_A"), reg.xlip(_ilk)); + assertEq(addr.addr("PIP_PAX"), reg.pip(_ilk)); + assertEq(addr.addr("MCD_PSM_PAX_A"), chainLog.getAddress("MCD_PSM_PAX_A")); + _checkPsmIlkIntegration( + _ilk, + GemJoinAbstract(addr.addr("MCD_JOIN_PSM_PAX_A")), + ClipAbstract(addr.addr("MCD_CLIP_PSM_PAX_A")), + addr.addr("PIP_PAX"), + PsmAbstract(addr.addr("MCD_PSM_PAX_A")), + 0, // tin + 0 // tout + ); + } + + // @dev when testing new vest contracts, use the explicit id when testing to assist in + // identifying streams later for modification or removal + function testVestDAI() private { // make private to disable + // VestAbstract vest = VestAbstract(addr.addr("MCD_VEST_DAI")); + + // All times in GMT + // uint256 OCT_01_2022 = 1664582400; // Saturday, October 1, 2022 12:00:00 AM + // uint256 OCT_31_2022 = 1667260799; // Monday, October 31, 2022 11:59:59 PM + + // assertEq(vest.ids(), 9); + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + // assertEq(vest.ids(), 9 + 1); + + // assertEq(vest.cap(), 1 * MILLION * WAD / 30 days); + + // assertTrue(vest.valid(10)); // check for valid contract + // _checkDaiVest({ + // _index: 10, // id + // _wallet: wallets.addr("DAIF_WALLET"), // usr + // _start: OCT_01_2022, // bgn + // _cliff: OCT_01_2022, // clf + // _end: OCT_31_2022, // fin + // _days: 31 days, // fin + // _manager: address(0), // mgr + // _restricted: 1, // res + // _reward: 67_863 * WAD, // tot + // _claimed: 0 // rxd + // }); + + // // Give admin powers to Test contract address and make the vesting unrestricted for testing + // GodMode.setWard(address(vest), address(this), 1); + // uint256 prevBalance; + + // vest.unrestrict(10); + // prevBalance = dai.balanceOf(wallets.addr("DAIF_WALLET")); + // vm.warp(OCT_01_2022 + 31 days); + // vest.vest(10); + // assertEq(dai.balanceOf(wallets.addr("DAIF_WALLET")), prevBalance + 67_863 * WAD); + } + + function _setupRootDomain() internal { + vm.makePersistent(address(spell), address(spell.action())); + + string memory root = string.concat(vm.projectRoot(), "/lib/dss-test"); + config = ScriptTools.readInput(root, "integration"); + + rootDomain = new RootDomain(config, getRelativeChain("mainnet")); + } + + function testL2OptimismSpell() private { + address l2TeleportGateway = BridgeLike( + chainLog.getAddress("OPTIMISM_TELEPORT_BRIDGE") + ).l2TeleportGateway(); + + _setupRootDomain(); + + optimismDomain = new OptimismDomain(config, getRelativeChain("optimism"), rootDomain); + optimismDomain.selectFork(); + + // Check that the L2 Optimism Spell is there and configured + L2Spell optimismSpell = L2Spell(0xC077Eb64285b40C86B40769e99Eb1E61d682a6B4); + + L2Gateway optimismGateway = L2Gateway(optimismSpell.gateway()); + assertEq(address(optimismGateway), l2TeleportGateway, "l2-optimism-wrong-gateway"); + + bytes32 optDstDomain = optimismSpell.dstDomain(); + assertEq(optDstDomain, bytes32("ETH-GOER-A"), "l2-optimism-wrong-dst-domain"); + + // Validate pre-spell optimism state + assertEq(optimismGateway.validDomains(optDstDomain), 1, "l2-optimism-invalid-dst-domain"); + // Cast the L1 Spell + rootDomain.selectFork(); + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + // switch to Optimism domain and relay the spell from L1 + // the `true` keeps us on Optimism rather than `rootDomain.selectFork() + optimismDomain.relayFromHost(true); + + // Validate post-spell state + assertEq(optimismGateway.validDomains(optDstDomain), 0, "l2-optimism-invalid-dst-domain"); + } + + function testL2ArbitrumSpell() private { + // Ensure the Arbitrum Gov Relay has some ETH to pay for the Arbitrum spell + assertGt(chainLog.getAddress("ARBITRUM_GOV_RELAY").balance, 0); + + address l2TeleportGateway = BridgeLike( + chainLog.getAddress("ARBITRUM_TELEPORT_BRIDGE") + ).l2TeleportGateway(); + + _setupRootDomain(); + + arbitrumDomain = new ArbitrumDomain(config, getRelativeChain("arbitrum_one"), rootDomain); + arbitrumDomain.selectFork(); + + // Check that the L2 Arbitrum Spell is there and configured + L2Spell arbitrumSpell = L2Spell(0x11Dc6Ed4C08Da38B36709a6C8DBaAC0eAeDD48cA); + + L2Gateway arbitrumGateway = L2Gateway(arbitrumSpell.gateway()); + assertEq(address(arbitrumGateway), l2TeleportGateway, "l2-arbitrum-wrong-gateway"); + + bytes32 arbDstDomain = arbitrumSpell.dstDomain(); + assertEq(arbDstDomain, bytes32("ETH-GOER-A"), "l2-arbitrum-wrong-dst-domain"); + + // Validate pre-spell arbitrum state + assertEq(arbitrumGateway.validDomains(arbDstDomain), 1, "l2-arbitrum-invalid-dst-domain"); + + // Cast the L1 Spell + rootDomain.selectFork(); + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + // switch to Arbitrum domain and relay the spell from L1 + // the `true` keeps us on Arbitrum rather than `rootDomain.selectFork() + arbitrumDomain.relayFromHost(true); + + // Validate post-spell state + assertEq(arbitrumGateway.validDomains(arbDstDomain), 0, "l2-arbitrum-invalid-dst-domain"); + } + + // RWA tests + function test_RWA002_Update() public { + // Read the pip address + (,address pip,, ) = liquidationOracle.ilks("RWA002-A"); + + // Load RWA002-A output conduit address + address conduit = addr.addr("RWA002_A_OUTPUT_CONDUIT"); + + // Check the conduit balance is 0 before cast + assertEq(dai.balanceOf(address(conduit)), 0); + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + // Read the pip address and spot value after cast, as well as Art and rate + (uint256 Art, uint256 rate, uint256 spotAfter, uint256 line,) = vat.ilks("RWA002-A"); + + // Check the pip and spot values after cast + assertEq(uint256(DSValueAbstract(pip).read()), 92_899_355_926924134500000000, "RWA002: Bad PIP value after bump()"); + assertEq(spotAfter, 92_899_355_926924134500000000 * (RAY / WAD), "RWA002: Bad spot value after bump()"); + + // Test that a draw() can be performed + address urn = addr.addr("RWA002_A_URN"); + // Give ourselves operator status, noting that setWard() has replaced giveAuth() + GodMode.setWard(urn, address(this), 1); + RwaUrnLike(urn).hope(address(this)); + + // Calculate how much 'room' we can draw to get close to line + uint256 room = line - (Art * rate); + uint256 drawAmt = room / RAY; + + // Correct our draw amount if it is too large + if ((_divup((drawAmt * RAY), rate) * rate) > room) { + drawAmt = (room - rate) / RAY; + } + + // NOTE: only on goerli, remove on mainnet + // This fix is needed becuause RWA002 was never locked into RwaUrn on Goerli + GodMode.setBalance(addr.addr("RWA002"), address(this), 1 * WAD); + GemAbstract(addr.addr("RWA002")).approve(urn, 1 * WAD); + RwaUrnLike(urn).lock(1 * WAD); + + // Check if RWA002 is locked into the RwaUrn + (uint256 ink,) = vat.urns("RWA002-A", urn); + assertEq(ink, 1 * WAD, "RWA002: bad ink in RwaUrn"); + + // Perform draw() + RwaUrnLike(urn).draw(drawAmt); + + // Check the conduit balance after cast + assertEq(dai.balanceOf(address(conduit)), drawAmt); + + // Read new Art + (Art,,,,) = vat.ilks("RWA002-A"); + + // Assert that we are within 2 `rate` of line + assertTrue(line - (Art * rate) < (2 * rate)); + } + + // Spark Tests + function testSparkSpellIsExecuted() public { // make private to disable + address SPARK_PROXY = 0x4e847915D8a9f2Ab0cDf2FC2FD0A30428F25665d; + address SPARK_SPELL = 0x13176Ad78eC3d2b6E32908B019D0F772EC0b4dFd; + + vm.expectCall( + SPARK_PROXY, + /* value = */ 0, + abi.encodeCall( + ProxyLike(SPARK_PROXY).exec, + (SPARK_SPELL, abi.encodeWithSignature("execute()")) + ) + ); + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + } + + function testSparkAdminTransfer() public { + address SPARK_PROXY = 0x4e847915D8a9f2Ab0cDf2FC2FD0A30428F25665d; + address SPARK_TREASURY_CONTROLLER = 0x98e6BcBA7d5daFbfa4a92dAF08d3d7512820c30C; + address SPARK_TREASURY = 0x0D56700c90a690D8795D6C148aCD94b12932f4E3; + address SPARK_TREASURY_DAI = 0x44816381990B6613c7A96ca1937f3902D8eA3F5b; + address SPARK_INCENTIVES = 0xF028c2F4b19898718fD0F77b9b881CbfdAa5e8Bb; + address SPARK_WETH_GATEWAY = 0xe6fC577E87F7c977c4393300417dCC592D90acF8; + address SPARK_ACL_MANAGER = 0xb137E7d16564c81ae2b0C8ee6B55De81dd46ECe5; + address SPARK_POOL_ADDRESS_PROVIDER = 0x026a5B6114431d8F3eF2fA0E1B2EDdDccA9c540E; + address SPARK_POOL_ADDRESS_PROVIDER_REGISTRY = 0x1ad570fDEA255a3c1d8Cf56ec76ebA2b7bFDFfea; + address SPARK_EMISSION_MANAGER = 0xA7F8A757C4f7696c015B595F51B2901AC0121B18; + + bytes32 defaultAdminRole = ACLManagerLike(SPARK_ACL_MANAGER).DEFAULT_ADMIN_ROLE(); + + assertEq(TransferOwnershipLike(SPARK_TREASURY_CONTROLLER).owner(), pauseProxy); + + // Transparent proxy dictates that admin() function is only exposed to the admin + vm.startPrank(pauseProxy); + + assertEq(ChangeAdminLike(SPARK_TREASURY).admin(), pauseProxy); + assertEq(ChangeAdminLike(SPARK_TREASURY_DAI).admin(), pauseProxy); + assertEq(ChangeAdminLike(SPARK_INCENTIVES).admin(), pauseProxy); + + vm.stopPrank(); + + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).isEmergencyAdmin(pauseProxy)); + assertTrue(!ACLManagerLike(SPARK_ACL_MANAGER).isEmergencyAdmin(SPARK_PROXY)); + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).isPoolAdmin(pauseProxy)); + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).isPoolAdmin(SPARK_PROXY)); // Already added from previous spell + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).hasRole(defaultAdminRole, pauseProxy)); + assertTrue(!ACLManagerLike(SPARK_ACL_MANAGER).hasRole(defaultAdminRole, SPARK_PROXY)); + + assertEq(TransferOwnershipLike(SPARK_WETH_GATEWAY).owner(), pauseProxy); + assertEq(PoolAddressProviderLike(SPARK_POOL_ADDRESS_PROVIDER).getACLAdmin(), pauseProxy); + assertEq(TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER).owner(), pauseProxy); + assertEq(TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER_REGISTRY).owner(), pauseProxy); + assertEq(TransferOwnershipLike(SPARK_EMISSION_MANAGER).owner(), pauseProxy); + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + assertEq(TransferOwnershipLike(SPARK_TREASURY_CONTROLLER).owner(), SPARK_PROXY); + + // Transparent proxy dictates that admin() function is only exposed to the admin + vm.startPrank(SPARK_PROXY); + + assertEq(ChangeAdminLike(SPARK_TREASURY).admin(), SPARK_PROXY); + assertEq(ChangeAdminLike(SPARK_TREASURY_DAI).admin(), SPARK_PROXY); + assertEq(ChangeAdminLike(SPARK_INCENTIVES).admin(), SPARK_PROXY); + + vm.stopPrank(); + + assertTrue(!ACLManagerLike(SPARK_ACL_MANAGER).isEmergencyAdmin(pauseProxy)); + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).isEmergencyAdmin(SPARK_PROXY)); + assertTrue(!ACLManagerLike(SPARK_ACL_MANAGER).isPoolAdmin(pauseProxy)); + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).isPoolAdmin(SPARK_PROXY)); + assertTrue(!ACLManagerLike(SPARK_ACL_MANAGER).hasRole(defaultAdminRole, pauseProxy)); + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).hasRole(defaultAdminRole, SPARK_PROXY)); + + assertEq(TransferOwnershipLike(SPARK_WETH_GATEWAY).owner(), SPARK_PROXY); + assertEq(PoolAddressProviderLike(SPARK_POOL_ADDRESS_PROVIDER).getACLAdmin(), SPARK_PROXY); + assertEq(TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER).owner(), SPARK_PROXY); + assertEq(TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER_REGISTRY).owner(), SPARK_PROXY); + assertEq(TransferOwnershipLike(SPARK_EMISSION_MANAGER).owner(), SPARK_PROXY); + } +} diff --git a/archive/2023-08-18-DssSpell/test/addresses_deployers.sol b/archive/2023-08-18-DssSpell/test/addresses_deployers.sol new file mode 100644 index 00000000..0d2377a8 --- /dev/null +++ b/archive/2023-08-18-DssSpell/test/addresses_deployers.sol @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: © 2021 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.16; + +contract Deployers { + + address[] public addr; + + // Skip Ward Deployers see DssSpell.t.base.sol#skipWards(address,address) + address public constant PE_CURRENT = 0xa22A61c233d7242728b4255420063c92fc1AEBb9; // PE_09 + address public constant ORACLES_1 = 0x1f42e41A34B71606FcC60b4e624243b365D99745; + address public constant ORACLES_2 = 0x39aBD7819E5632Fa06D2ECBba45Dca5c90687EE3; + + // Known Team Deployers + address public constant PE_01 = 0xda0fab060e6cc7b1C0AA105d29Bd50D71f036711; + address public constant PE_02 = 0xDA0FaB0700A4389F6E6679aBAb1692B4601ce9bf; + address public constant PE_03 = 0xdA0C0de01d90A5933692Edf03c7cE946C7c50445; + address public constant PE_04 = 0xdB33dFD3D61308C33C63209845DaD3e6bfb2c674; + address public constant PE_05 = 0xDA01018eA05D98aBb66cb21a85d6019a311570eE; + address public constant PE_06 = 0xDA0111100cb6080b43926253AB88bE719C60Be13; + address public constant PE_07 = 0xDa0c0De020F80d43dde58c2653aa73d28Df1fBe1; + address public constant PE_08 = 0xC1E6d8136441FC66612Df3584007f7CB68765e5D; + address public constant PE_09 = 0xa22A61c233d7242728b4255420063c92fc1AEBb9; + address public constant PE_10 = 0x92723e0bF280942B98bf2d1e832Bde9A3Bd2F2c2; + address public constant CES_01 = 0x9956fca5a8994737f124c481cEDC6BB3dc5BF010; + address public constant CES_02 = 0xc0b362cbb0117Ec6A4b589f744d4dECb2768A2eB; + address public constant CES_03 = 0xb27B6fa77D7FBf3C1BD34B0f7DA59b39D3DB0f7e; + address public constant CES_04 = 0x3ec4699bEc79F8FF862C220Ef0a718689A1d09f4; + address public constant STARKNET_01 = 0x8aa7c51A6D380F4d9E273adD4298D913416031Ec; + address public constant STARKNET_02 = 0x38F8e3b67FA8329FE4BaA1775e5480807f78887B; + address public constant CENTRIFUGE_01 = 0x9956fca5a8994737f124c481cEDC6BB3dc5BF010; // NOTE: need to cleanup this as it has same address as CES_01 + address public constant CENTRIFUGE_02 = 0x0A735602a357802f553113F5831FE2fbf2F0E2e0; + address public constant SIDESTREAM_01 = 0x47f1aaC8c1BDD49B0c2438c1754518695E9f08d3; + address public constant PHOENIX_LABS_01 = 0xd1236a6A111879d9862f8374BA15344b6B233Fbd; + address public constant ECO_DEPLOY_01 = 0x694047b514Ae125d528eDE99048a75592B830256; + // address public constant SPARK_01 = 0x02416B99202081F6b90851e35682Ca90D547054c; // Deployer for Spark 2023-08-02 + + + constructor() { + addr = [ + PE_CURRENT, + ORACLES_1, + ORACLES_2, + PE_01, + PE_02, + PE_03, + PE_04, + PE_05, + PE_06, + PE_07, + PE_08, + PE_09, + CES_01, + CES_02, + CES_03, + CES_04, + STARKNET_01, + STARKNET_02, + CENTRIFUGE_01, + CENTRIFUGE_02, + SIDESTREAM_01, + PHOENIX_LABS_01, + ECO_DEPLOY_01 + ]; + } + + function count() external view returns (uint256) { + return addr.length; + } +} diff --git a/archive/2023-08-18-DssSpell/test/addresses_goerli.sol b/archive/2023-08-18-DssSpell/test/addresses_goerli.sol new file mode 100644 index 00000000..d83831a9 --- /dev/null +++ b/archive/2023-08-18-DssSpell/test/addresses_goerli.sol @@ -0,0 +1,433 @@ +// SPDX-FileCopyrightText: © 2020 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.16; + +contract Addresses { + + mapping (bytes32 => address) public addr; + + constructor() { + addr["CHANGELOG"] = 0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F; + addr["MULTICALL"] = 0xb8c864B60e9467398800Df34da39BF4f0c459461; + addr["FAUCET"] = 0xa473CdDD6E4FAc72481dc36f39A409D86980D187; + addr["MCD_DEPLOY"] = 0xc09880a0D6d06fa18C8bDC9dF2E203F0d0124fa1; + addr["JOIN_FAB"] = 0x0aaA1E0f026c194E0F951a7763F9edc796c6eDeE; + addr["FLIP_FAB"] = 0x333Ec4d92b546d6107Dc931156139A76dFAfD938; + addr["CLIP_FAB"] = 0xcfAab43101A01548A95F0f7dBB0CeF6f6490A389; + addr["CALC_FAB"] = 0x579f007Fb7151162e3095606232ef9029E090366; + addr["LERP_FAB"] = 0xE7988B75a19D8690272D65882Ab0D07D492f7002; + addr["MCD_GOV"] = 0xc5E4eaB513A7CD12b2335e8a0D57273e13D499f7; + addr["PIP_MKR"] = 0x496C851B2A9567DfEeE0ACBf04365F3ba00Eb8dC; + addr["GOV_GUARD"] = 0xB9b861e8F9b29322815260B6883Bbe1DBC91dA8A; + addr["MCD_IOU"] = 0x651D1B91e4F657392a51Dba7A6A1A1a72eC6aD1c; + addr["MCD_ADM"] = 0x33Ed584fc655b08b2bca45E1C5b5f07c98053bC1; + addr["VOTE_PROXY_FACTORY"] = 0x1a7c1ee5eE2A3B67778ff1eA8c719A3fA1b02b6f; + addr["VOTE_DELEGATE_PROXY_FACTORY"] = 0xE2d249AE3c156b132C40D07bd4d34e73c1712947; + addr["MCD_VAT"] = 0xB966002DDAa2Baf48369f5015329750019736031; + addr["MCD_JUG"] = 0xC90C99FE9B5d5207A03b9F28A6E8A19C0e558916; + addr["MCD_CAT"] = 0xd744377001FD3411d7d0018F66E2271CB215f6fd; + addr["MCD_DOG"] = 0x5cf85A37Dbd28A239698B4F9aA9a03D55C04F292; + addr["MCD_VOW"] = 0x23f78612769b9013b3145E43896Fa1578cAa2c2a; + addr["MCD_JOIN_DAI"] = 0x6a60b7070befb2bfc964F646efDF70388320f4E0; + addr["MCD_FLAP"] = 0x584491031764f94a97a0f98bBe536B004Ab9467b; + addr["FLAPPER_MOM"] = 0x7316C080BFd1c8857605627a251A2F0ae511E4A1; + addr["MCD_FLOP"] = 0x742D041dFBA61110Bd886509CB299DF6A521B352; + addr["MCD_PAUSE"] = 0xefcd235B1f13e7fC5eab1d05C910d3c390b3439F; + addr["MCD_PAUSE_PROXY"] = 0x5DCdbD3cCF9B09EAAD03bc5f50fA2B3d3ACA0121; + addr["MCD_GOV_ACTIONS"] = 0x5857F3e0e6Fb75658037b3c3410b7446b985B353; + addr["MCD_DAI"] = 0x11fE4B6AE13d2a6055C8D9cF65c55bac32B5d844; + addr["MCD_SPOT"] = 0xACe2A9106ec175bd56ec05C9E38FE1FDa8a1d758; + addr["MCD_POT"] = 0x50672F0a14B40051B65958818a7AcA3D54Bd81Af; + addr["MCD_END"] = 0xb82F60bAf6980b9fE035A82cF6Acb770C06d3896; + addr["MCD_CURE"] = 0xFA5d993DdA243A57eefbbF86Cb3a1c817Dfc7e4E; + addr["MCD_ESM"] = 0x023A960cb9BE7eDE35B433256f4AfE9013334b55; + addr["PROXY_ACTIONS"] = 0x4023f89983Ece35e227c49806aFc13Bc0248d178; + addr["PROXY_ACTIONS_END"] = 0xBbA4aBF0a12738f093cFD2199C5497044bAa68A8; + addr["PROXY_ACTIONS_DSR"] = 0x15679CdbDb284fe07Eff3809150126697c6e3Dd6; + addr["CDP_MANAGER"] = 0xdcBf58c9640A7bd0e062f8092d70fb981Bb52032; + addr["DSR_MANAGER"] = 0xF7F0de3744C82825D77EdA8ce78f07A916fB6bE7; + addr["GET_CDPS"] = 0x7843fd599F5382328DeBB45255deB3E2e0DEC876; + addr["ILK_REGISTRY"] = 0x525FaC4CEc48a4eF2FBb0A72355B6255f8D5f79e; + addr["OSM_MOM"] = 0xEdB6b497D2e18A33130CB0D2b70343E6Dcd9EE86; + addr["FLIPPER_MOM"] = 0x7ceCdf6b214a3eBA1589eB8B844fB6Cb12B67Bd7; + addr["CLIPPER_MOM"] = 0xC67fFD490903521F778b2A3B2A13D0FC0Be96F98; + addr["LINE_MOM"] = 0x5D54E2d56BA83C42f63a10642DcFa073EBD9D92E; + addr["MCD_IAM_AUTO_LINE"] = 0x21DaD87779D9FfA8Ed3E1036cBEA8784cec4fB83; + addr["MCD_FLASH"] = 0xAa5F7d5b29Fa366BB04F6E4c39ACF569d5214075; + addr["MCD_FLASH_LEGACY"] = 0x0a6861D6200B519a8B9CFA1E7Edd582DD1573581; + addr["FLASH_KILLER"] = 0xa95FaD7948079df3c579DDb0752E39dC29Eb1AFf; + addr["PROXY_FACTORY"] = 0x84eFB9c18059394172D0d69A3E58B03320001871; + addr["PROXY_REGISTRY"] = 0x46759093D8158db8BB555aC7C6F98070c56169ce; + addr["MCD_VEST_DAI"] = 0x7520970Bd0f63D4EA4AA5E4Be05F22e0b8b09BD4; + addr["MCD_VEST_DAI_LEGACY"] = 0x59B1a603cAC9e38EA2AC2C479FFE42Ce48123Fd4; + addr["MCD_VEST_MKR"] = 0x183bE7a75B8b5F35236270b060e95C65D82f5fF9; + addr["MCD_VEST_MKR_TREASURY"] = 0xd1B8dFF41F3268fAC524869f4C7dA27232044916; + addr["ETH"] = 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6; + addr["PIP_ETH"] = 0x94588e35fF4d2E99ffb8D5095F35d1E37d6dDf12; + addr["MCD_JOIN_ETH_A"] = 0x2372031bB0fC735722AA4009AeBf66E8BEAF4BA1; + addr["MCD_CLIP_ETH_A"] = 0x2603c6EC5878dC70f53aD3a90e4330ba536d2385; + addr["MCD_CLIP_CALC_ETH_A"] = 0xfD7d0BaB582EC2FA031A0d0a6Aee6493934b1B04; + addr["MCD_JOIN_ETH_B"] = 0x1710BB6dF1967679bb1f247135794692F7963B46; + addr["MCD_CLIP_ETH_B"] = 0xA5d173b77965F2A58B0686b5683f3277de8d3D66; + addr["MCD_CLIP_CALC_ETH_B"] = 0xa4b7e9E5E342af456378576e46a52670E4f58517; + addr["MCD_JOIN_ETH_C"] = 0x16e6490744d4B3728966f8e72416c005EB3dEa79; + addr["MCD_CLIP_ETH_C"] = 0xDdAfCbed3A02617EbE1eEAC86eae701870747649; + addr["MCD_CLIP_CALC_ETH_C"] = 0xB90197A17d9A90ECa634954e393F51ec74DBa93f; + addr["BAT"] = 0x75645f86e90a1169e697707C813419977ea26779; + addr["PIP_BAT"] = 0x2BA78cb27044edCb715b03685D4bf74261170a70; + addr["MCD_JOIN_BAT_A"] = 0xfea8C23D32e4bA46d90AeD2445fBD099010eAdF5; + addr["MCD_CLIP_BAT_A"] = 0x4B05c2A4EEef04D1eed017B9003a344bbDeb19DE; + addr["MCD_CLIP_CALC_BAT_A"] = 0xE1C16d3D5BC91E091A23Ad0a467D1c47DA53ED73; + addr["USDC"] = 0x6Fb5ef893d44F4f88026430d82d4ef269543cB23; + addr["PIP_USDC"] = 0x838212865E2c2f4F7226fCc0A3EFc3EB139eC661; + addr["MCD_JOIN_USDC_A"] = 0x33E88C8b3530e2f19050b24f44AcB78C7114AF46; + addr["MCD_CLIP_USDC_A"] = 0xA8566b54C3447A741B2aE6bF920859600507AC1A; + addr["MCD_CLIP_CALC_USDC_A"] = 0x3a278aA4264AD66c5DEaAfbC1fCf6E43ceD47325; + addr["MCD_JOIN_USDC_B"] = 0x0Dc70CC4505c1952e719C9C740608A75Ca9e299e; + addr["MCD_CLIP_USDC_B"] = 0x71e44e17359fFbC3626893D13A133870FEc9Fee6; + addr["MCD_CLIP_CALC_USDC_B"] = 0xae3c77F36436Ac242bf2BC3E1A271058529F207A; + addr["MCD_JOIN_PSM_USDC_A"] = 0xF2f86B76d1027f3777c522406faD710419C80bbB; + addr["MCD_CLIP_PSM_USDC_A"] = 0x8f570B146655Cd52173B0db2DDeb40B7b32c5A9C; + addr["MCD_CLIP_CALC_PSM_USDC_A"] = 0x6eB7f16842b13A1Fbb270Fc952Fb9a73D7c90a0e; + addr["MCD_PSM_USDC_A"] = 0xb480B8dD5A232Cb7B227989Eacda728D1F247dB6; + addr["TUSD"] = 0xe0B3D300E2e09c1Fd01252287dDbC70A7730ffB0; + addr["PIP_TUSD"] = 0x0ce19eA2C568890e63083652f205554C927a0caa; + addr["MCD_JOIN_TUSD_A"] = 0x5BC597f00d74fAcEE53Be784f0B7Ace63b4e2EBe; + addr["MCD_CLIP_TUSD_A"] = 0x22d843aE7121F399604D5C00863B95F9Af7e7E9C; + addr["MCD_CLIP_CALC_TUSD_A"] = 0xD4443E7CcB1Cf40DbE4E27C60Aef82054c7d27B3; + addr["WBTC"] = 0x7ccF0411c7932B99FC3704d68575250F032e3bB7; + addr["PIP_WBTC"] = 0xE7de200a3a29E9049E378b52BD36701A0Ce68C3b; + addr["MCD_JOIN_WBTC_A"] = 0x3cbE712a12e651eEAF430472c0C1BF1a2a18939D; + addr["MCD_CLIP_WBTC_A"] = 0x752c35fa3d21863257bbBCB7e2B344fd0948B61b; + addr["MCD_CLIP_CALC_WBTC_A"] = 0x87982983Bb0B843Ba41D593A3722E87734bb1d7F; + addr["MCD_JOIN_WBTC_B"] = 0x13B8EB3d2d40A00d65fD30abF247eb470dDF6C25; + addr["MCD_CLIP_WBTC_B"] = 0x4F51B15f8B86822d2Eca8a74BB4bA1e3c64F733F; + addr["MCD_CLIP_CALC_WBTC_B"] = 0x1b5a9aDaf15CAE0e3d0349be18b77180C1a0deCc; + addr["MCD_JOIN_WBTC_C"] = 0xe15E69F10E1A362F69d9672BFeA20B75CFf8574A; + addr["MCD_CLIP_WBTC_C"] = 0xDa3cd88f5FF7D2B9ED6Ab171C8218421916B6e10; + addr["MCD_CLIP_CALC_WBTC_C"] = 0xD26B140fdaA11c23b09230c24cBe71f456AC7ab6; + addr["ZRX"] = 0x96E0C18524789ED3e62CD9F56aAEc7cEAC78725a; + addr["PIP_ZRX"] = 0xe9245D25F3265E9A36DcCDC72B0B5dE1eeACD4cD; + addr["MCD_JOIN_ZRX_A"] = 0xC279765B3f930742167dB91271f13353336B6C72; + addr["MCD_CLIP_ZRX_A"] = 0xeF5931608d21D49fF014E17C8cfDD8d51c90b388; + addr["MCD_CLIP_CALC_ZRX_A"] = 0xA514d3dC8B7697a0Df26200591cfeaCF42e2DE6f; + addr["KNC"] = 0x9A58801cf901486Df9323bcE83A7684915DBAE54; + addr["PIP_KNC"] = 0xCB772363E2DEc06942edbc5E697F4A9114B5989c; + addr["MCD_JOIN_KNC_A"] = 0xA48f0d5DA642928BC1F5dB9De5F5d3D466500075; + addr["MCD_CLIP_KNC_A"] = 0x777871Fde2845a52F455642f5da2f7AC17563739; + addr["MCD_CLIP_CALC_KNC_A"] = 0x404521f9FB3ba305cd7a0DCbD9f86E4Bec9ad21d; + addr["MANA"] = 0x347fceA8b4fD1a46e2c0DB8F79e22d293c2F8513; + addr["PIP_MANA"] = 0x001eDD66a5Cc9268159Cf24F3dC0AdcE456AAAAb; + addr["MCD_JOIN_MANA_A"] = 0xF4a1E7Dd685b4EaFBE5d0E70e20c153dee2E290b; + addr["MCD_CLIP_MANA_A"] = 0x09231df919ce19E48bf552a33D9e7FaD9c939025; + addr["MCD_CLIP_CALC_MANA_A"] = 0xD14d44fE5006d4eb61E194256462E1593eb8DF2f; + addr["USDT"] = 0x5858f25cc225525A7494f76d90A6549749b3030B; + addr["PIP_USDT"] = 0x1fA3B8DAeE1BCEe33990f66F1a99993daD14D855; + addr["MCD_JOIN_USDT_A"] = 0xa8C62cC41AbF8A199FB484Ea363b90C3e9E01d86; + addr["MCD_CLIP_USDT_A"] = 0x057eF98FAf86562ce9aBc3Ad2e07Fd65B653cBFB; + addr["MCD_CLIP_CALC_USDT_A"] = 0x2e6cD41fc9B62190A9081a69cd1167ab59E0e89d; + addr["PAXUSD"] = 0x4547863912Fe2d17D3827704138957a8317E8dCD; + addr["PAX"] = 0x4547863912Fe2d17D3827704138957a8317E8dCD; + addr["PIP_PAXUSD"] = 0xdF8474337c9D3f66C0b71d31C7D3596E4F517457; + addr["PIP_PAX"] = 0xdF8474337c9D3f66C0b71d31C7D3596E4F517457; + addr["MCD_JOIN_PAXUSD_A"] = 0x8Ef390647A74150a79EC73FE120EaaF8bE9eEdf0; + addr["MCD_CLIP_PAXUSD_A"] = 0x80cb788cf316361B0998C3a831c9ea82C5274F6D; + addr["MCD_CLIP_CALC_PAXUSD_A"] = 0x8EE38002052CA938646F653831E9a6Af6Cc8BeBf; + addr["MCD_JOIN_PSM_PAX_A"] = 0xF27E1F580D5e82510b47C7B2A588A8A533787d38; + addr["MCD_CLIP_PSM_PAX_A"] = 0xfe0b736a8bDc01869c94a0799CDD10683404D78f; + addr["MCD_CLIP_CALC_PSM_PAX_A"] = 0x1e14F8ED0f1a6A908cACabb290Ef71a69cDe1abf; + addr["MCD_PSM_PAX_A"] = 0x934dAaa0778ee137993d2867340440d70a74A44e; + addr["COMP"] = 0x8032dce0b793C21B8F7B648C01224c3b557271ED; + addr["PIP_COMP"] = 0xc3d677a5451cAFED13f748d822418098593D3599; + addr["MCD_JOIN_COMP_A"] = 0x544EFa934f26cd6FdFD86883408538150Bdd6725; + addr["MCD_CLIP_COMP_A"] = 0x5fea7d7Fc72972D8bC65a49a5d19DfFF50f19d0D; + addr["MCD_CLIP_CALC_COMP_A"] = 0x782657Bf07cE2F100D14eD1cFa15151290947fCe; + addr["LRC"] = 0xe32aC5b19051728421A8F4A8a5757D0e127a14F6; + addr["PIP_LRC"] = 0x5AD3A560BB125d00db8E94915232BA8f6166967C; + addr["MCD_JOIN_LRC_A"] = 0x12af538aCf746c0BBe076E5eBAE678e022E1F5f6; + addr["MCD_CLIP_LRC_A"] = 0xe5C499CBB12fA65db469496e5966aCcBA5Fff3b9; + addr["MCD_CLIP_CALC_LRC_A"] = 0x238AbB8f221df1816d066b32b572066A320A13d0; + addr["LINK"] = 0x4724A967A4F7E42474Be58AbdF64bF38603422FF; + addr["PIP_LINK"] = 0x75B4e743772D25a7998F4230cb016ddCF2c52629; + addr["MCD_JOIN_LINK_A"] = 0x4420FD4E5C414189708376F3fBAA4dCA6277369a; + addr["MCD_CLIP_LINK_A"] = 0x42cbA983D2403003af554fec0e68dAC4920906CC; + addr["MCD_CLIP_CALC_LINK_A"] = 0xE3Cf29E132EFad92d604Fa5C86AA21b7c7fBB76e; + addr["BAL"] = 0x8c6e73CA229AB3933426aDb5cc829c1E4928551d; + addr["PIP_BAL"] = 0xF15993A5C5BE496b8e1c9657Fd2233b579Cd3Bc6; + addr["MCD_JOIN_BAL_A"] = 0xb31cE33511c2CCEfBc1713A783042eE670Cf5930; + addr["MCD_CLIP_BAL_A"] = 0x738040Bc6834835B04e80c3C3cB07f6010eab2e3; + addr["MCD_CLIP_CALC_BAL_A"] = 0xa798c71d899f4f687B51Cd3Dc6e461B3401eD76e; + addr["YFI"] = 0xd9510EF268F8273C9b7514F0bfFe18Fe1EFC0d43; + addr["PIP_YFI"] = 0xAafF0066D05cEe0D6a38b4dac77e73d9E0a5Cf46; + addr["MCD_JOIN_YFI_A"] = 0xa318E65982E80F54486f71965A0C320858759299; + addr["MCD_CLIP_YFI_A"] = 0x9B97923CDf21CdB898702EE6878960Db446Daa86; + addr["MCD_CLIP_CALC_YFI_A"] = 0x5682Dfc718107e5A81805fd089d2De422A130b93; + addr["GUSD"] = 0x67aeF79654D8F6CF44FdC08949c308a4F6b3c45B; + addr["PIP_GUSD"] = 0x57A00620Ba1f5f81F20565ce72df4Ad695B389d7; + addr["MCD_JOIN_GUSD_A"] = 0x455451293100C5c5355db10512DEE81F75E45Edf; + addr["MCD_CLIP_GUSD_A"] = 0xF535799F8b4Ac661cd33E37421A571c742ed9B19; + addr["MCD_CLIP_CALC_GUSD_A"] = 0x738EA932C2aFb1D8e47bebB7ed1c604399f2A99e; + addr["MCD_JOIN_PSM_GUSD_A"] = 0x4115fDa246e2583b91aD602213f2ac4fC6E437Ca; + addr["MCD_CLIP_PSM_GUSD_A"] = 0x7A58fF23D5437C99b44BB02D7e24213D6dA20DFa; + addr["MCD_CLIP_CALC_PSM_GUSD_A"] = 0xE99bd8c56d7B9d90A36C8a563a4CA375b144dD94; + addr["MCD_PSM_GUSD_A"] = 0x3B2dBE6767fD8B4f8334cE3E8EC3E2DF8aB3957b; + addr["UNI"] = 0x82D98aA89E391c6759012df39ccDA0d9d6b24143; + addr["PIP_UNI"] = 0xf1a5b808fbA8fF80982dACe88020d4a80c91aFe6; + addr["MCD_JOIN_UNI_A"] = 0x31aE6e37964f26f4112A8Fc70e0B680F18e4DC6A; + addr["MCD_CLIP_UNI_A"] = 0xE177B027030c1F691031451534bea409ff27b080; + addr["MCD_CLIP_CALC_UNI_A"] = 0xf9367E7cC9e4E547772312E60E238C35B7016C41; + addr["RENBTC"] = 0x30d0A215aef6DadA4771a2b30a59B842f969EfD4; + addr["PIP_RENBTC"] = 0xE7de200a3a29E9049E378b52BD36701A0Ce68C3b; + addr["MCD_JOIN_RENBTC_A"] = 0xb4576162aC5d1bC7C69bA85F39e8f694d44d09D0; + addr["MCD_CLIP_RENBTC_A"] = 0xFEff5d71D665A4C0712cd87d802380958b7Eb333; + addr["MCD_CLIP_CALC_RENBTC_A"] = 0x621b1c98132d32c077EA23fe93eCB999d07Df20b; + addr["AAVE"] = 0x251661BB7C6869165eF35810E5e1D25Ed57be2Fe; + addr["PIP_AAVE"] = 0xC26E53eF1F71481DE53bfb77875Ffb3aCf4d91f0; + addr["MCD_JOIN_AAVE_A"] = 0x71Ae3e3ac4412865A4E556230b92aB58d895b497; + addr["MCD_CLIP_AAVE_A"] = 0x962271248Db1F4c31318c11a89FD3b11f6047f32; + addr["MCD_CLIP_CALC_AAVE_A"] = 0x56f390b5DF5dDeBC1aDAd5cFEB65202CC6e2eaB6; + addr["MATIC"] = 0x5B3b6CF665Cc7B4552F4347623a2A9E00600CBB5; + addr["PIP_MATIC"] = 0xDe112F61b823e776B3439f2F39AfF41f57993045; + addr["MCD_JOIN_MATIC_A"] = 0xeb680839564F0F9bFB96fE2dF47a31cE31689e63; + addr["MCD_CLIP_MATIC_A"] = 0x2082c825b5311A2612c12e6DaF7EFa3Fb37BACbD; + addr["MCD_CLIP_CALC_MATIC_A"] = 0xB2dF4Ed2f6a665656CE3405E8f75b9DE8A6E24e9; + addr["STETH"] = 0x1643E812aE58766192Cf7D2Cf9567dF2C37e9B7F; + addr["WSTETH"] = 0x6320cD32aA674d2898A68ec82e869385Fc5f7E2f; + addr["PIP_WSTETH"] = 0x323eac5246d5BcB33d66e260E882fC9bF4B6bf41; + addr["MCD_JOIN_WSTETH_A"] = 0xF99834937715255079849BE25ba31BF8b5D5B45D; + addr["MCD_CLIP_WSTETH_A"] = 0x3673978974fC3fB1bA61aea0a6eb1Bac8e27182c; + addr["MCD_CLIP_CALC_WSTETH_A"] = 0xb4f2f0eDFc10e9084a8bba23d84aF2c23B312852; + addr["MCD_JOIN_WSTETH_B"] = 0x4a2dfbdFb0ea68823265FaB4dE55E22f751eD12C; + addr["MCD_CLIP_WSTETH_B"] = 0x11D962d87EB3718C8012b0A71627d60c923d36a8; + addr["MCD_CLIP_CALC_WSTETH_B"] = 0xF4ffD00E0821C28aE673B4134D142FD8e479b061; + addr["UNIV2DAIETH"] = 0x5dD9dec52a16d4d1Df10a66ac71d4731c9Dad984; + addr["PIP_UNIV2DAIETH"] = 0x044c9aeD56369aA3f696c898AEd0C38dC53c6C3D; + addr["MCD_JOIN_UNIV2DAIETH_A"] = 0x66931685b532CB4F31abfe804d2408dD34Cd419D; + addr["MCD_CLIP_UNIV2DAIETH_A"] = 0x76a4Ee8acEAAF7F92455277C6e10471F116ffF2c; + addr["MCD_CLIP_CALC_UNIV2DAIETH_A"] = 0x7DCA9CAE2Dc463eBBF05341727FB6ed181D690c2; + addr["UNIV2WBTCETH"] = 0x7883a92ac3e914F3400e8AE6a2FF05E6BA4Bd403; + addr["PIP_UNIV2WBTCETH"] = 0xD375daC26f7eF991878136b387ca959b9ac1DDaF; + addr["MCD_JOIN_UNIV2WBTCETH_A"] = 0x345a29Db10Aa5CF068D61Bb20F74771eC7DF66FE; + addr["MCD_CLIP_UNIV2WBTCETH_A"] = 0x8520AA6784d51B1984B6f693f1Ea646368d9f868; + addr["MCD_CLIP_CALC_UNIV2WBTCETH_A"] = 0xab5B4759c8D28d05c4cd335a0315A52981F93D04; + addr["UNIV2USDCETH"] = 0xD90313b3E43D9a922c71d26a0fBCa75A01Bb3Aeb; + addr["PIP_UNIV2USDCETH"] = 0x54ADcaB9B99b1B548764dAB637db751eC66835F0; + addr["MCD_JOIN_UNIV2USDCETH_A"] = 0x46267d84dA4D6e7b2F5A999518Cf5DAF91E204E3; + addr["MCD_CLIP_UNIV2USDCETH_A"] = 0x7424D5319172a3dC57add04dBb48E6323Da4B473; + addr["MCD_CLIP_CALC_UNIV2USDCETH_A"] = 0x83B20C43D92224E128c2b1e0ECb6305B1001FF4f; + addr["UNIV2DAIUSDC"] = 0x260719B2ef507A86116FC24341ff0994F2097D42; + addr["PIP_UNIV2DAIUSDC"] = 0xEf22289E240cFcCCdCD2B98fdefF167da10f452d; + addr["MCD_JOIN_UNIV2DAIUSDC_A"] = 0x4CEEf4EB4988cb374B0b288D685AeBE4c6d4C41E; + addr["MCD_CLIP_UNIV2DAIUSDC_A"] = 0x04254C28c09C8a09c76653acA92538EC04954341; + addr["MCD_CLIP_CALC_UNIV2DAIUSDC_A"] = 0x3dB02f19D2d1609661f9bD774De23a962642F25B; + addr["UNIV2ETHUSDT"] = 0xfcB32e1C4A4F1C820c9304B5CFfEDfB91aE2321C; + addr["PIP_UNIV2ETHUSDT"] = 0x974f7f4dC6D91f144c87cc03749c98f85F997bc7; + addr["MCD_JOIN_UNIV2ETHUSDT_A"] = 0x46A8f8e2C0B62f5D7E4c95297bB26a457F358C82; + addr["MCD_CLIP_UNIV2ETHUSDT_A"] = 0x4bBCD4dc8cD4bfc907268AB5AD3aE01e2567f0E1; + addr["MCD_CLIP_CALC_UNIV2ETHUSDT_A"] = 0x9e24c087EbBA685dFD4AF1fC6C31C414f6EfA74f; + addr["UNIV2LINKETH"] = 0x3361fB8f923D1Aa1A45B2d2eD4B8bdF313a3dA0c; + addr["PIP_UNIV2LINKETH"] = 0x11C884B3FEE1494A666Bb20b6F6144387beAf4A6; + addr["MCD_JOIN_UNIV2LINKETH_A"] = 0x98B7023Aced6D8B889Ad7D340243C3F9c81E8c5F; + addr["MCD_CLIP_UNIV2LINKETH_A"] = 0x71c6d999c54AB5C91589F45Aa5F0E2E782647268; + addr["MCD_CLIP_CALC_UNIV2LINKETH_A"] = 0x30747d2D2f9C23CBCc2ff318c31C15A6f0AA78bF; + addr["UNIV2UNIETH"] = 0xB80A38E50B2990Ac83e46Fe16631fFBb94F2780b; + addr["PIP_UNIV2UNIETH"] = 0xB18BC24e52C23A77225E7cf088756581EE257Ad8; + addr["MCD_JOIN_UNIV2UNIETH_A"] = 0x52c31E3592352Cd0CBa20Fa73Da42584EC693283; + addr["MCD_CLIP_UNIV2UNIETH_A"] = 0xaBb1F3fBe1c404829BC1807D67126286a71b85dE; + addr["MCD_CLIP_CALC_UNIV2UNIETH_A"] = 0x663D47b5AF171D7b54dfB2A234406903307721b8; + addr["UNIV2WBTCDAI"] = 0x3f78Bd3980c49611E5FA885f25Ca3a5fCbf0d7A0; + addr["PIP_UNIV2WBTCDAI"] = 0x916fc346910fd25867c81874f7F982a1FB69aac7; + addr["MCD_JOIN_UNIV2WBTCDAI_A"] = 0x04d23e99504d61050CAF46B4ce2dcb9D4135a7fD; + addr["MCD_CLIP_UNIV2WBTCDAI_A"] = 0xee139bB397211A21656046efb2c7a5b255d3bC07; + addr["MCD_CLIP_CALC_UNIV2WBTCDAI_A"] = 0xf89C3DDA6D0f496900ecC39e4a7D31075d360856; + addr["UNIV2AAVEETH"] = 0xaF2CC6F46d1d0AB30dd45F59B562394c3E21e6f3; + addr["PIP_UNIV2AAVEETH"] = 0xFADF05B56E4b211877248cF11C0847e7F8924e10; + addr["MCD_JOIN_UNIV2AAVEETH_A"] = 0x73C4E5430768e24Fd704291699823f35953bbbA2; + addr["MCD_CLIP_UNIV2AAVEETH_A"] = 0xeA4F6DA7Ac68F9244FCDd13AE2C36647829AfCa0; + addr["MCD_CLIP_CALC_UNIV2AAVEETH_A"] = 0x14F4D6cB78632535230D1591121E35108bbBdAAA; + addr["UNIV2DAIUSDT"] = 0xBF2C9aBbEC9755A0b6144051E19c6AD4e6fd6D71; + addr["PIP_UNIV2DAIUSDT"] = 0x2fc2706C61Fba5b941381e8838bC646908845db6; + addr["MCD_JOIN_UNIV2DAIUSDT_A"] = 0xBF70Ca17ce5032CCa7cD55a946e96f0E72f79452; + addr["MCD_CLIP_UNIV2DAIUSDT_A"] = 0xABB9ca15E7e261E255560153e312c98F638E57f4; + addr["MCD_CLIP_CALC_UNIV2DAIUSDT_A"] = 0xDD610087b4a029BD63e4990A6A29a077764B632B; + addr["MIP21_LIQUIDATION_ORACLE"] = 0x362dfE51E4f91a8257B8276435792095EE5d85C3; + addr["RWA_TOKEN_FAB"] = 0x8FCe002C320E85e4D8c111E6f46ee4CDb3eBc67E; + addr["RWA001"] = 0xeb7C7DE82c3b05BD4059f11aE8f43dD7f1595bce; + addr["PIP_RWA001"] = 0x95282c2cDE88b93F784E2485f885580275551387; + addr["MCD_JOIN_RWA001_A"] = 0x088D6b3f68Bc4F93F90006A1356A21145EDD96E2; + addr["RWA001_A_URN"] = 0xF1AAB03fc1d3588B5910a960f476DbE88D304b9B; + addr["RWA001_A_INPUT_CONDUIT"] = 0x4145774D007C88392118f32E2c31686faCc9486E; + addr["RWA001_A_OUTPUT_CONDUIT"] = 0x969b3701A17391f2906d8c5E5D816aBcD9D0f199; + addr["RWA002"] = 0x09fE0aE289553010D6EcBdFF98cc9C08030dE3b8; + addr["PIP_RWA002"] = 0xF1E8E72AE116193A9fA551beC1cda965147b31DA; + addr["MCD_JOIN_RWA002_A"] = 0xc0aeE42b5E77e931BAfd98EAdd321e704fD7CA1f; + addr["RWA002_A_URN"] = 0xD6953949b2B4Ab5Be19ed6283F4ca0AaEDDffec5; + addr["RWA002_A_INPUT_CONDUIT"] = 0x1d3402B809095c3320296f3A77c4be20C3b74d47; + addr["RWA002_A_OUTPUT_CONDUIT"] = 0x1d3402B809095c3320296f3A77c4be20C3b74d47; + addr["RWA003"] = 0x5cf15Cc2710aFc0EaBBD7e045f84F9556B204331; + addr["PIP_RWA003"] = 0x27E599C9D69e02477f5ffF4c8E4E42B97777eE52; + addr["MCD_JOIN_RWA003_A"] = 0x83fA1F7c423112aBC6B340e32564460eDcf6AD74; + addr["RWA003_A_URN"] = 0x438262Eb709d47b0B3d2524E75E63DBa9571962B; + addr["RWA003_A_INPUT_CONDUIT"] = 0x608050Cb6948A9835442E24a5B1964F76fd4acE4; + addr["RWA003_A_OUTPUT_CONDUIT"] = 0x608050Cb6948A9835442E24a5B1964F76fd4acE4; + addr["RWA004"] = 0xA7fbA77c4d18e12d1F385E2dcFfb377c9dBD91d2; + addr["PIP_RWA004"] = 0x3C191d5a74800A99D8747fdffAea42F60f7d3Bff; + addr["MCD_JOIN_RWA004_A"] = 0xA74036937413B799b2f620a3b6Ea61ad08F1D354; + addr["RWA004_A_URN"] = 0x1527A3B844ca194783BDeab8DF4F9264D1A9F529; + addr["RWA004_A_INPUT_CONDUIT"] = 0x551837D1C1638944A97a6476ffCD1bE4E1391Fc9; + addr["RWA004_A_OUTPUT_CONDUIT"] = 0x551837D1C1638944A97a6476ffCD1bE4E1391Fc9; + addr["RWA005"] = 0x650d168fC94B79Bb16898CAae773B0Ce1097Cc3F; + addr["PIP_RWA005"] = 0xa6A7f2408949cAbD13f254F8e77ad5C9896725aB; + addr["MCD_JOIN_RWA005_A"] = 0xc5052A70e00983ffa6894679f1d9c0cDAFe28416; + addr["RWA005_A_URN"] = 0x047E68a3c1F22f9BB3fB063b311dC76c6E308404; + addr["RWA005_A_INPUT_CONDUIT"] = 0x8347e6e08cAF1FB63428465b76BafD4Cf6fcA2e1; + addr["RWA005_A_OUTPUT_CONDUIT"] = 0x8347e6e08cAF1FB63428465b76BafD4Cf6fcA2e1; + addr["RWA006"] = 0xf754FD6611852eE94AC0614c51B8692cAE9fEe9F; + addr["PIP_RWA006"] = 0xA410A66313F943d022b79f2943C9A37CefdE2371; + addr["MCD_JOIN_RWA006_A"] = 0x5b4B7797FC41123578718AD4E3F04d1Bde9685DC; + addr["RWA006_A_URN"] = 0xd0d2Ef46b64C07b5Ce4f2634a82984C1B3804C22; + addr["RWA006_A_INPUT_CONDUIT"] = 0xd2Ef07535267D17d2314894f7821A43e9700A02e; + addr["RWA006_A_OUTPUT_CONDUIT"] = 0xd2Ef07535267D17d2314894f7821A43e9700A02e; + addr["RWA007"] = 0xD063270642ff718DA1c58E12BD6a2598f7e874B3; + addr["PIP_RWA007"] = 0xEB87118831B52B53FF11430c71B946fEafC903a2; + addr["MCD_JOIN_RWA007_A"] = 0x9C9E33E22b683F789411288497f8DC560f1F0466; + addr["RWA007_A_URN"] = 0xa1b1D392fCB99F8B39c7530a599bCfcd2f1fB22f; + addr["RWA007_A_JAR"] = 0x708bC8bF869c336ab6f04cf6A62a86a8DFc5f7c4; + addr["RWA007_A_INPUT_CONDUIT"] = 0x1C3faBF61B470B0e9aA4Ca5F1A08fcf44ADAb414; + addr["RWA007_A_JAR_INPUT_CONDUIT"] = 0xA7ae4F30f237BB8E8975d22eD777778202F64c91; + addr["RWA007_A_OUTPUT_CONDUIT"] = 0x87EaB54D118529Eb15a4286b8A96455ECBdbFD27; + addr["RWA007_A_OPERATOR"] = 0x94cfBF071f8be325A5821bFeAe00eEbE9CE7c279; + addr["RWA007_A_COINBASE_CUSTODY"] = 0xC3acf3B96E46Aa35dBD2aA3BD12D23c11295E774; + addr["RWA008"] = 0x9A900f506b88ae6C7F9C5fbEffC5AFEC24A6fAAA; + addr["PIP_RWA008"] = 0x98e62fFAf27C022283cB492f1bB05AfdE877b5ac; + addr["MCD_JOIN_RWA008_A"] = 0x36fA17FA0b4Be214cDc04faD2587dC85a7c2c086; + addr["RWA008_A_URN"] = 0xF50FE370839c295DADFADFCC5b6DC9b904604F7d; + addr["RWA008_A_INPUT_CONDUIT"] = 0x8c4295EF77e503E5fd0c8dE3f73985834bE85DE2; + addr["RWA008_A_OUTPUT_CONDUIT"] = 0x1aA21d2E39EC0da185CA04609c8868bC324d8553; + addr["RWA009"] = 0xfD775125701524461580Bf865f33068E4710591b; + addr["PIP_RWA009"] = 0xB78a90D7475e67F4e0Ac876C2e9b38AF2c538041; + addr["MCD_JOIN_RWA009_A"] = 0xE1ee48D4a7d28078a1BEb6b3C0fe8391669661Fb; + addr["RWA009_A_URN"] = 0xd334bbA9172a6F615Be93d194d1322148fb5222e; + addr["RWA009_A_JAR"] = 0xad4e1696d008A656F810498A974C5D3dC4A6150d; + addr["RWA009_A_OUTPUT_CONDUIT"] = 0x5DCdbD3cCF9B09EAAD03bc5f50fA2B3d3ACA0121; + addr["RWA010"] = 0x003DD0D987a315C7AEe2611B9b753b383B7a35bF; + addr["PIP_RWA010"] = 0x1C5f15c960B5e1F87041E5a0A8C9Aa9AB18a81B8; + addr["MCD_JOIN_RWA010_A"] = 0xeBAfcf1E0B1A6D0F91f41cD77d760AC56B431F05; + addr["RWA010_A_URN"] = 0x59417853EA7B47017c1e2C644C848e8Ef99Afa51; + addr["RWA010_A_OUTPUT_CONDUIT"] = 0x8828D2B96fa09864851244a8a2434C5A9a7B7AbD; + addr["RWA010_A_INPUT_CONDUIT"] = 0x8828D2B96fa09864851244a8a2434C5A9a7B7AbD; + addr["RWA011"] = 0x480e01A3621f557D99c75C4394Ac17238304e88C; + addr["PIP_RWA011"] = 0xC2926108429d7Ac98f4ce59D5E3cc5d9657D31b1; + addr["MCD_JOIN_RWA011_A"] = 0xfc1b3879B259C3561F4E654759D2Fd6Ba3C995de; + addr["RWA011_A_URN"] = 0x5A704B28d65a61E1070662B8cA353D260f36332E; + addr["RWA011_A_OUTPUT_CONDUIT"] = 0xcBd44c9Ec0D2b9c466887e700eD88D302281E098; + addr["RWA011_A_INPUT_CONDUIT"] = 0xcBd44c9Ec0D2b9c466887e700eD88D302281E098; + addr["RWA012"] = 0x2E4378eF2A6822cfB0d154BA497B351e31C3B89b; + addr["PIP_RWA012"] = 0x3d264f6dD5415E813cE945aA6a3680F9074b2191; + addr["MCD_JOIN_RWA012_A"] = 0x0D9a5a31f16164e256E4f8b616c9C57F9d5C12d7; + addr["RWA012_A_URN"] = 0xa35F51d91311F60C904a02E1b0493Fc256A3F6e3; + addr["RWA012_A_OUTPUT_CONDUIT"] = 0xaef64c80712d5959f240BE1339aa639CDFA858Ff; + addr["RWA012_A_INPUT_CONDUIT"] = 0xaef64c80712d5959f240BE1339aa639CDFA858Ff; + addr["RWA013"] = 0xc5Ac8B809a8De11D94b7Aa63b28b8fbBDF86Ea86; + addr["PIP_RWA013"] = 0xB87331af849c6474a69dDA4A9b7DBD417020b683; + addr["MCD_JOIN_RWA013_A"] = 0xD67131c06e93eDF3839C3ec5Bd92FF5D93A1e3df; + addr["RWA013_A_URN"] = 0xdC47d203753D3B5fb4fcD5900EBd96b0eC6761B6; + addr["RWA013_A_OUTPUT_CONDUIT"] = 0xc5A1418aC32B5f978460f1211B76B5D44e69B530; + addr["RWA013_A_INPUT_CONDUIT"] = 0xc5A1418aC32B5f978460f1211B76B5D44e69B530; + addr["RWA014"] = 0x22a7440DCfF0E8881Ec93cE519c34C15feB2A09a; + addr["PIP_RWA014"] = 0x0dC2eeaAbD3c8F6fD7FB62D690AfEEA8c7AE5A6F; + addr["MCD_JOIN_RWA014_A"] = 0xc7Ba0aBa8512199c816834351CC978cf684D7fD9; + addr["RWA014_A_URN"] = 0xb475F63163aE3b0D5f6e30Dd914F5aA7204B1169; + addr["RWA014_A_JAR"] = 0x398E36Ed3c6bEf85f78b03d08b1980c6c3dd5357; + addr["RWA014_A_INPUT_CONDUIT_URN"] = 0x3b749869f62694804B0411DA77F13e816C49A25F; + addr["RWA014_A_INPUT_CONDUIT_JAR"] = 0xa9C909eDD4ee06D625EaDD546CccDB1BB3e02D02; + addr["RWA014_A_OUTPUT_CONDUIT"] = 0x563c3CD928DB7cAf5B9872bFa2dd0E4F31158256; + addr["RWA014_A_OPERATOR"] = 0x3064D13712338Ee0E092b66Afb3B054F0b7779CB; + addr["RWA014_A_COINBASE_CUSTODY"] = 0x2E5F1f08EBC01d6136c95a40e19D4c64C0be772c; + addr["RWA015"] = 0x8384c55389f1ab6345dd4EF5fF2eF791D4875D2A; + addr["PIP_RWA015"] = 0x0E6Fa7bEAEff74403a72D5CeA803dcEA169C5048; + addr["MCD_JOIN_RWA015_A"] = 0x59ea019366FC8E8fBaf20EeA7F68F6557521FD20; + addr["RWA015_A_URN"] = 0xf24456f7132479cdABBD67511D2e985cE69BFd0D; + addr["RWA015_A_JAR"] = 0x3799FF53c20042BB9b0d2580Bc66257397e69CAE; + addr["RWA015_A_INPUT_CONDUIT_URN"] = 0xa737C5EB4aD00d30f92CFcdf3f92B8B1AE79383F; + addr["RWA015_A_INPUT_CONDUIT_JAR"] = 0xe7Bcb3E53db0E502B3E9127A703c44461ab2b09f; + addr["RWA015_A_OUTPUT_CONDUIT"] = 0xEff59711CbB16BCAdA3AA8B8f2Bbd26F5B38a8cA; + addr["RWA015_A_OPERATOR"] = 0x23a10f09Fac6CCDbfb6d9f0215C795F9591D7476; + addr["RWA015_A_CUSTODY"] = 0x65729807485F6f7695AF863d97D62140B7d69d83; + addr["PROXY_PAUSE_ACTIONS"] = 0x8D1187FCa9A104211bd25c689C08718AD8730C83; + addr["PROXY_DEPLOYER"] = 0xc9476Fd378de5b0de5C4280D4323f6F89f723c15; + addr["GUNIV3DAIUSDC1"] = 0xc5D83e829Ecdce4d67645EE1a1317451e0b4c68d; + addr["PIP_GUNIV3DAIUSDC1"] = 0xF953cdebbbf63607EeBc556438d86F2e1d47C8aA; + addr["MCD_JOIN_GUNIV3DAIUSDC1_A"] = 0xFBF4e3bB9B86d24F91Da185E6F4C8D903Fb63C86; + addr["MCD_CLIP_GUNIV3DAIUSDC1_A"] = 0xFb98C5A49eDd0888e85f6d2CCc7695b5202A6B32; + addr["MCD_CLIP_CALC_GUNIV3DAIUSDC1_A"] = 0x4652E3a6b4850a0fE50E60B0ac72aBd74199D973; + addr["GUNIV3DAIUSDC2"] = 0x540BBCcb890cEb6c539fA94a0d63fF7a6aA25762; + addr["MCD_JOIN_GUNIV3DAIUSDC2_A"] = 0xbd039ea6d63AC57F2cD051202dC4fB6BA6681489; + addr["MCD_CLIP_GUNIV3DAIUSDC2_A"] = 0x39aee8F2D5ea5dffE4b84529f0349743C71C07c3; + addr["MCD_CLIP_CALC_GUNIV3DAIUSDC2_A"] = 0xbF87fbA8ec2190E50Da297815A9A6Ae668306aFE; + addr["PIP_GUNIV3DAIUSDC2"] = 0x6Fb18806ff87B45220C2DB0941709142f2395069; + addr["PIP_DAI"] = 0xe7A915f8Db97f0dE219e0cEf60fF7886305a14ef; + addr["MCD_CHARTER"] = 0x7ea0d7ea31C544a472b55D19112e016Ba6708288; + addr["MCD_CHARTER_IMP"] = 0xf6a9bD36553208ee02049Dc8A9c44919383C9a6b; + addr["PROXY_ACTIONS_CHARTER"] = 0xfFb896D7BEf704DF73abc9A2EBf295CE236c5919; + addr["PROXY_ACTIONS_END_CHARTER"] = 0xDAdE5a1bAC92c539B886eeC82738Ff26b66Dc484; + addr["MCD_JOIN_INST_ETH_A"] = 0x99507A436aC9E8eB5A89001a2dFc80E343D82122; + addr["MCD_CLIP_INST_ETH_A"] = 0x6ECc35a9237a73022697976891Def7bAd87Be408; + addr["MCD_CLIP_CALC_INST_ETH_A"] = 0xea999A6381e78311Ff176751e00F46360F1562e9; + addr["MCD_JOIN_INST_WBTC_A"] = 0xbd5978308C9BbF6d8d1D26cD1df9AA3EA83F782a; + addr["MCD_CLIP_INST_WBTC_A"] = 0x81Bf27c821F24b6FC9Bcc0F7d4D7cc2651712E3c; + addr["MCD_CLIP_CALC_INST_WBTC_A"] = 0x32ff6F008eB4aA5780efF2e0436b7adCDECb213a; + addr["MCD_JOIN_TELEPORT_FW_A"] = 0xE2fddf4e0f5A4B6d0Cc1D162FBFbEF7B6c5D6f69; + addr["MCD_ROUTER_TELEPORT_FW_A"] = 0x5A16311D32662E71f1E0beAD41372f60cEb61b26; + addr["MCD_ORACLE_AUTH_TELEPORT_FW_A"] = 0x29d292E0773E484dbcA8626F432985630175763b; + addr["STARKNET_TELEPORT_BRIDGE"] = 0x6DcC2d81785B82f2d20eA9fD698d5738B5EE3589; + addr["STARKNET_TELEPORT_FEE"] = 0x95532D5c4e2064e8dC51F4D41C21f24B33c78BBC; + addr["STARKNET_DAI_BRIDGE"] = 0xaB00D7EE6cFE37cCCAd006cEC4Db6253D7ED3a22; + addr["STARKNET_DAI_BRIDGE_LEGACY"] = 0xd8beAa22894Cd33F24075459cFba287a10a104E4; + addr["STARKNET_ESCROW"] = 0x38c3DDF1eF3e045abDDEb94f4e7a1a0d5440EB44; + addr["STARKNET_ESCROW_MOM"] = 0x464379BD1aC523DdA45b7B78eCB1F703661cad2a; + addr["STARKNET_GOV_RELAY"] = 0x8919aefA417745F22c6af5AD6550E83159a373F3; + addr["STARKNET_GOV_RELAY_LEGACY"] = 0x73c0049Dd6560E644984Fa3Af30A55a02a7D81fB; + addr["STARKNET_CORE"] = 0xde29d060D45901Fb19ED6C6e959EB22d8626708e; + addr["OPTIMISM_TELEPORT_BRIDGE"] = 0x5d49a6BCEc49072D1612cA6d60c8D7985cfc4988; + addr["OPTIMISM_TELEPORT_FEE"] = 0x89bcDc64090ddAbB9AFBeeFB7999d564e2875907; + addr["OPTIMISM_DAI_BRIDGE"] = 0x05a388Db09C2D44ec0b00Ee188cD42365c42Df23; + addr["OPTIMISM_ESCROW"] = 0xbc892A208705862273008B2Fb7D01E968be42653; + addr["OPTIMISM_GOV_RELAY"] = 0xD9b2835A5bFC8bD5f54DB49707CF48101C66793a; + addr["ARBITRUM_TELEPORT_BRIDGE"] = 0x737D2B14571b58204403267A198BFa470F0D696e; + addr["ARBITRUM_TELEPORT_FEE"] = 0x89bcDc64090ddAbB9AFBeeFB7999d564e2875907; + addr["ARBITRUM_DAI_BRIDGE"] = 0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65; + addr["ARBITRUM_ESCROW"] = 0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1; + addr["ARBITRUM_GOV_RELAY"] = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F; + addr["RETH"] = 0x62BC478FFC429161115A6E4090f819CE5C50A5d9; + addr["PIP_RETH"] = 0x27a25935D8b0006A97E11cAdDc2b3bf3a6721c13; + addr["MCD_JOIN_RETH_A"] = 0xDEF7D394a4eD62273265CE983107B3748F775265; + addr["MCD_CLIP_RETH_A"] = 0xBa496CB9637d56466dc112033BF28CC7EC544E3A; + addr["MCD_CLIP_CALC_RETH_A"] = 0xC3A95477616c9Db6C772179e74a9A717E8B148a7; + addr["GNO"] = 0x86Bc432064d7F933184909975a384C7E4c9d0977; + addr["PIP_GNO"] = 0xf15221A159A4e7ba01E0d6e72111F0Ddff8Fa8Da; + addr["MCD_JOIN_GNO_A"] = 0x05a3b9D5F8098e558aF33c6b83557484f840055e; + addr["MCD_CLIP_GNO_A"] = 0x8274F3badD42C61B8bEa78Df941813D67d1942ED; + addr["MCD_CLIP_CALC_GNO_A"] = 0x08Ae3e0C0CAc87E1B4187D53F0231C97B5b4Ab3E; + addr["DIRECT_HUB"] = 0x79Dcb858D6af6FeD7A5AC9B189ea14bC94076dfb; + addr["DIRECT_MOM"] = 0x8aBafFe006205e306F4307EE7b839846CD1ff471; + addr["DIRECT_SPARK_DAI_POOL"] = 0x8b6Ae79852bcae012CBc2244e4ef85c61BAeCE35; + addr["DIRECT_SPARK_DAI_PLAN"] = 0x1fB2cF94D896bB50A17dD1Abd901172F088dF309; + addr["DIRECT_SPARK_DAI_ORACLE"] = 0xa07C4eDB18E4B3cfB9B94D9CD348BbF6d5a7f4c2; + } +} + diff --git a/archive/2023-08-18-DssSpell/test/config.sol b/archive/2023-08-18-DssSpell/test/config.sol new file mode 100644 index 00000000..8fce9aa3 --- /dev/null +++ b/archive/2023-08-18-DssSpell/test/config.sol @@ -0,0 +1,2062 @@ +// SPDX-FileCopyrightText: © 2020 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.16; + +contract Config { + + struct SpellValues { + address deployed_spell; + uint256 deployed_spell_created; + uint256 deployed_spell_block; + address[] previous_spells; + bool office_hours_enabled; + uint256 expiration_threshold; + } + + struct SystemValues { + uint256 line_offset; + uint256 pot_dsr; + uint256 pause_delay; + uint256 vow_wait; + uint256 vow_dump; + uint256 vow_sump; + uint256 vow_bump; + uint256 vow_hump_min; + uint256 vow_hump_max; + uint256 flap_hop; + uint256 flap_want; + uint256 cat_box; + uint256 dog_Hole; + uint256 esm_min; + address pause_authority; + address osm_mom_authority; + address flipper_mom_authority; + address clipper_mom_authority; + uint256 ilk_count; + string chainlog_version; + mapping (bytes32 => CollateralValues) collaterals; + } + + struct CollateralValues { + bool aL_enabled; + uint256 aL_line; + uint256 aL_gap; + uint256 aL_ttl; + uint256 line; + uint256 dust; + uint256 pct; + uint256 mat; + bytes32 liqType; + bool liqOn; + uint256 chop; + uint256 cat_dunk; + uint256 flip_beg; + uint48 flip_ttl; + uint48 flip_tau; + uint256 flipper_mom; + uint256 dog_hole; + uint256 clip_buf; + uint256 clip_tail; + uint256 clip_cusp; + uint256 clip_chip; + uint256 clip_tip; + uint256 clipper_mom; + uint256 cm_tolerance; + uint256 calc_tau; + uint256 calc_step; + uint256 calc_cut; + bool offboarding; + } + + uint256 constant private THOUSAND = 10 ** 3; + uint256 constant private MILLION = 10 ** 6; + uint256 constant private BILLION = 10 ** 9; + + SpellValues spellValues; + SystemValues afterSpell; + + function setValues(address chief) public { + // Add spells if there is a need to test prior to their cast() functions + // being called on-chain. They will be executed in order from index 0. + address[] memory prevSpells = new address[](0); + // prevSpells[0] = ; + + // + // Values for spell-specific parameters + // + spellValues = SpellValues({ + deployed_spell: address(0x341281316C53a6c9b099581C9f87665FA5815090), // populate with deployed spell if deployed + deployed_spell_created: 1692106800, // use `make deploy-info tx=` to obtain the timestamp + deployed_spell_block: 9522321, // use `make deploy-info tx=` to obtain the block number + previous_spells: prevSpells, // older spells to ensure are executed first + office_hours_enabled: false, // true if officehours is expected to be enabled in the spell + expiration_threshold: 30 days // Amount of time before spell expires + }); + + // + // Values for all system configuration changes + // + afterSpell.line_offset = 500 * MILLION; // Offset between the global line against the sum of local lines + afterSpell.pot_dsr = 5_00; // In basis points + afterSpell.pause_delay = 60 seconds; // In seconds + afterSpell.vow_wait = 156 hours; // In seconds + afterSpell.vow_dump = 250; // In whole Dai units + afterSpell.vow_sump = 50 * THOUSAND; // In whole Dai units + afterSpell.vow_bump = 20 * THOUSAND; // In whole Dai units + afterSpell.vow_hump_min = 50 * MILLION; // In whole Dai units + afterSpell.vow_hump_max = 50 * MILLION; // In whole Dai units + afterSpell.flap_hop = 6308 seconds; // In seconds + afterSpell.flap_want = 9800; // In basis points + afterSpell.cat_box = 20 * MILLION; // In whole Dai units + afterSpell.dog_Hole = 70 * MILLION; // In whole Dai units + afterSpell.esm_min = 150 * THOUSAND; // In whole MKR units + afterSpell.pause_authority = chief; // Pause authority + afterSpell.osm_mom_authority = chief; // OsmMom authority + afterSpell.flipper_mom_authority = chief; // FlipperMom authority + afterSpell.clipper_mom_authority = chief; // ClipperMom authority + afterSpell.ilk_count = 63; // Num expected in system + afterSpell.chainlog_version = "1.15.0"; // String expected in system + + // + // Values for all collateral + // Update when adding or modifying Collateral Values + // + + // + // Test for all collateral-based changes here + // + afterSpell.collaterals["ETH-A"] = CollateralValues({ + aL_enabled: true, // DssAutoLine is enabled? + aL_line: 15 * BILLION, // In whole Dai units + aL_gap: 150 * MILLION, // In whole Dai units + aL_ttl: 6 hours, // In seconds + line: 0, // In whole Dai units // Not checked here as there is auto line + dust: 7_500, // In whole Dai units + pct: 3_58, // In basis points + mat: 14500, // In basis points + liqType: "clip", // "" or "flip" or "clip" + liqOn: true, // If liquidations are enabled + chop: 1300, // In basis points + cat_dunk: 0, // In whole Dai units + flip_beg: 0, // In basis points + flip_ttl: 0, // In seconds + flip_tau: 0, // In seconds + flipper_mom: 0, // 1 if circuit breaker enabled + dog_hole: 40 * MILLION, // In whole Dai units + clip_buf: 110_00, // In basis points + clip_tail: 7200 seconds, // In seconds + clip_cusp: 45_00, // In basis points + clip_chip: 10, // In basis points + clip_tip: 250, // In whole Dai units + clipper_mom: 1, // 1 if circuit breaker enabled + cm_tolerance: 5000, // In basis points + calc_tau: 0, // In seconds + calc_step: 90, // In seconds + calc_cut: 9900, // In basis points + offboarding: false // If mat is being offboardinged + }); + afterSpell.collaterals["ETH-B"] = CollateralValues({ + aL_enabled: true, + aL_line: 250 * MILLION, + aL_gap: 20 * MILLION, + aL_ttl: 6 hours, + line: 0, + dust: 25 * THOUSAND, + pct: 4_08, + mat: 13000, + liqType: "clip", + liqOn: true, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 15 * MILLION, + clip_buf: 110_00, + clip_tail: 4800 seconds, + clip_cusp: 45_00, + clip_chip: 10, + clip_tip: 250, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 60, + calc_cut: 9900, + offboarding: false + }); + afterSpell.collaterals["ETH-C"] = CollateralValues({ + aL_enabled: true, + aL_line: 2 * BILLION, + aL_gap: 100 * MILLION, + aL_ttl: 8 hours, + line: 0, + dust: 3_500, + pct: 3_33, + mat: 17000, + liqType: "clip", + liqOn: true, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 35 * MILLION, + clip_buf: 110_00, + clip_tail: 7200 seconds, + clip_cusp: 45_00, + clip_chip: 10, + clip_tip: 250, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: false + }); + afterSpell.collaterals["BAT-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 400, + mat: 1120000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 1 * MILLION + 500 * THOUSAND, + clip_buf: 130_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["USDC-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 0, + mat: 150000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 20_000_000, + clip_buf: 100_00, + clip_tail: 720 minutes, + clip_cusp: 99_00, + clip_chip: 0, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 9500, + calc_tau: 4_320_000, + calc_step: 0, + calc_cut: 0, + offboarding: true + }); + afterSpell.collaterals["USDC-B"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 5000, + mat: 12000, + liqType: "clip", + liqOn: false, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 0, + clip_buf: 105_00, + clip_tail: 220 minutes, + clip_cusp: 90_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 0, + cm_tolerance: 9500, + calc_tau: 0, + calc_step: 120, + calc_cut: 9990, + offboarding: false + }); + afterSpell.collaterals["WBTC-A"] = CollateralValues({ + aL_enabled: true, + aL_line: 500 * MILLION, + aL_gap: 10 * MILLION, + aL_ttl: 24 hours, + line: 0, + dust: 7_500, + pct: 5_80, + mat: 14500, + liqType: "clip", + liqOn: true, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 30 * MILLION, + clip_buf: 110_00, + clip_tail: 7200 seconds, + clip_cusp: 45_00, + clip_chip: 10, + clip_tip: 250, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: false + }); + afterSpell.collaterals["WBTC-B"] = CollateralValues({ + aL_enabled: true, + aL_line: 250 * MILLION, + aL_gap: 5 * MILLION, + aL_ttl: 24 hours, + line: 0, + dust: 25 * THOUSAND, + pct: 6_30, + mat: 13000, + liqType: "clip", + liqOn: true, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 10 * MILLION, + clip_buf: 110_00, + clip_tail: 4800 seconds, + clip_cusp: 45_00, + clip_chip: 10, + clip_tip: 250, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 60, + calc_cut: 9900, + offboarding: false + }); + afterSpell.collaterals["WBTC-C"] = CollateralValues({ + aL_enabled: true, + aL_line: 500 * MILLION, + aL_gap: 10 * MILLION, + aL_ttl: 24 hours, + line: 0, + dust: 3_500, + pct: 5_55, + mat: 17500, + liqType: "clip", + liqOn: true, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 20 * MILLION, + clip_buf: 110_00, + clip_tail: 7200 seconds, + clip_cusp: 45_00, + clip_chip: 10, + clip_tip: 250, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: false + }); + afterSpell.collaterals["TUSD-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 0, + mat: 15000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 5 * MILLION, + clip_buf: 100_00, + clip_tail: 120 hours, + clip_cusp: 98_00, + clip_chip: 0, + clip_tip: 500, + clipper_mom: 1, + cm_tolerance: 9500, + calc_tau: 250 days, + calc_step: 0, + calc_cut: 0, + offboarding: false + }); + afterSpell.collaterals["KNC-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 500, + mat: 500000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 500 * THOUSAND, + clip_buf: 130_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["ZRX-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 400, + mat: 550000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 1 * MILLION, + clip_buf: 130_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["MANA-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 5000, + mat: 17500, + liqType: "clip", + liqOn: true, + chop: 3000, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 1 * MILLION, + clip_buf: 120_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 250, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: false + }); + afterSpell.collaterals["USDT-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 800, + mat: 30000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 15_000, + clip_buf: 105_00, + clip_tail: 220 minutes, + clip_cusp: 90_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 9500, + calc_tau: 0, + calc_step: 120, + calc_cut: 9990, + offboarding: false + }); + afterSpell.collaterals["PAXUSD-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 0, + mat: 150000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 3_000_000, + clip_buf: 100_00, + clip_tail: 720 minutes, + clip_cusp: 99_00, + clip_chip: 0, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 9500, + calc_tau: 4_320_000, + calc_step: 0, + calc_cut: 0, + offboarding: true + }); + afterSpell.collaterals["COMP-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 100, + mat: 200000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 2 * MILLION, + clip_buf: 130_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["LRC-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 400, + mat: 2430000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 500 * THOUSAND, + clip_buf: 130_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["LINK-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 250, + mat: 10000_00, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 3 * MILLION, + clip_buf: 120_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 0, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["BAL-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 100, + mat: 230000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 3 * MILLION, + clip_buf: 130_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["YFI-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 150, + mat: 10000_00, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 1 * MILLION, + clip_buf: 130_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 0, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["GUSD-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 100, + mat: 150000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 300_000, + clip_buf: 100_00, + clip_tail: 720 minutes, + clip_cusp: 99_00, + clip_chip: 0, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 9500, + calc_tau: 4_320_000, + calc_step: 0, + calc_cut: 0, + offboarding: true + }); + afterSpell.collaterals["UNI-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 300, + mat: 1300_00, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 5 * MILLION, + clip_buf: 130_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["RENBTC-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 225, + mat: 5000_00, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 350 * THOUSAND, + clip_buf: 120_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["AAVE-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 100, + mat: 210000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 5 * MILLION, + clip_buf: 130_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["UNIV2DAIETH-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 60 * THOUSAND, + pct: 100, + mat: 2000_00, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 5 * MILLION, + clip_buf: 115_00, + clip_tail: 215 minutes, + clip_cusp: 60_00, + clip_chip: 10, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 7000, + calc_tau: 0, + calc_step: 125, + calc_cut: 9950, + offboarding: true + }); + afterSpell.collaterals["PSM-USDC-A"] = CollateralValues({ + aL_enabled: true, + aL_line: 10 * BILLION, + aL_gap: 400 * MILLION, + aL_ttl: 24 hours, + line: 0, + dust: 0, + pct: 0, + mat: 10000, + liqType: "clip", + liqOn: false, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 0, + clip_buf: 105_00, + clip_tail: 220 minutes, + clip_cusp: 90_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 0, + cm_tolerance: 9500, + calc_tau: 0, + calc_step: 120, + calc_cut: 9990, + offboarding: false + }); + afterSpell.collaterals["UNIV2WBTCETH-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 25 * THOUSAND, + pct: 200, + mat: 2400_00, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 5 * MILLION, + clip_buf: 130_00, + clip_tail: 200 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 130, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["UNIV2USDCETH-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 60 * THOUSAND, + pct: 150, + mat: 10000_00, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 5 * MILLION, + clip_buf: 115_00, + clip_tail: 215 minutes, + clip_cusp: 60_00, + clip_chip: 0, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 7000, + calc_tau: 0, + calc_step: 125, + calc_cut: 9950, + offboarding: true + }); + afterSpell.collaterals["UNIV2DAIUSDC-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 2, + mat: 10200, + liqType: "clip", + liqOn: false, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 0, + clip_buf: 105_00, + clip_tail: 220 minutes, + clip_cusp: 90_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 0, + cm_tolerance: 9500, + calc_tau: 0, + calc_step: 120, + calc_cut: 9990, + offboarding: false + }); + afterSpell.collaterals["UNIV2ETHUSDT-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 200, + mat: 14000, + liqType: "clip", + liqOn: true, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 5 * MILLION, + clip_buf: 115_00, + clip_tail: 215 minutes, + clip_cusp: 60_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 7000, + calc_tau: 0, + calc_step: 125, + calc_cut: 9950, + offboarding: false + }); + afterSpell.collaterals["UNIV2LINKETH-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 300, + mat: 160000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 3 * MILLION, + clip_buf: 130_00, + clip_tail: 200 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 130, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["UNIV2UNIETH-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 25 * THOUSAND, + pct: 400, + mat: 16000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 3 * MILLION, + clip_buf: 130_00, + clip_tail: 200 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 130, + calc_cut: 9900, + offboarding: false + }); + afterSpell.collaterals["UNIV2WBTCDAI-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 60 * THOUSAND, + pct: 0, + mat: 800_00, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 5 * MILLION, + clip_buf: 115_00, + clip_tail: 215 minutes, + clip_cusp: 60_00, + clip_chip: 10, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 7000, + calc_tau: 0, + calc_step: 125, + calc_cut: 9950, + offboarding: true + }); + afterSpell.collaterals["UNIV2AAVEETH-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 300, + mat: 40000, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 3 * MILLION, + clip_buf: 130_00, + clip_tail: 200 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 130, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["UNIV2DAIUSDT-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 10 * THOUSAND, + pct: 200, + mat: 12500, + liqType: "clip", + liqOn: true, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 5 * MILLION, + clip_buf: 105_00, + clip_tail: 220 minutes, + clip_cusp: 90_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 9500, + calc_tau: 0, + calc_step: 120, + calc_cut: 9990, + offboarding: false + }); + afterSpell.collaterals["RWA001-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 15 * MILLION, + dust: 0, + pct: 300, + mat: 10000, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA002-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 50 * MILLION, + dust: 0, + pct: 7_00, + mat: 100_00, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA003-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0 * MILLION, + aL_gap: 0 * MILLION, + aL_ttl: 0, + line: 2 * MILLION, + dust: 0, + pct: 600, + mat: 10500, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA004-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0 * MILLION, + aL_gap: 0 * MILLION, + aL_ttl: 0, + line: 0, + dust: 0, + pct: 700, + mat: 11000, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA005-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0 * MILLION, + aL_gap: 0 * MILLION, + aL_ttl: 0, + line: 15 * MILLION, + dust: 0, + pct: 450, + mat: 10500, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA006-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0 * MILLION, + aL_gap: 0 * MILLION, + aL_ttl: 0, + line: 0 * MILLION, + dust: 0, + pct: 200, + mat: 10000, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA007-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 1_250 * MILLION, + dust: 0, + pct: 0, + mat: 10000, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA008-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 0, + pct: 5, + mat: 10000, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA009-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 100_000_000, + dust: 0, + pct: 0, + mat: 10000, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA010-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 0, + pct: 4_00, + mat: 100_00, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA011-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 0, + pct: 4_00, + mat: 100_00, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA012-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 80_000_000, + dust: 0, + pct: 4_00, + mat: 100_00, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA013-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 70_000_000, + dust: 0, + pct: 4_00, + mat: 100_00, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA014-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 500 * MILLION, + dust: 0, + pct: 0, + mat: 100_00, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RWA015-A"] = CollateralValues({ + aL_enabled: true, + aL_line: 1_280_000_000, + aL_gap: 50_000_000, + aL_ttl: 24 hours, + line: 0, + dust: 0, + pct: 0, + mat: 100_00, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["MATIC-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 300, + mat: 10000_00, + liqType: "clip", + liqOn: true, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 3 * MILLION, + clip_buf: 120_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 0, + clip_tip: 0, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: true + }); + afterSpell.collaterals["PSM-PAX-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 0, + pct: 0, + mat: 10000, + liqType: "clip", + liqOn: false, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 0, + clip_buf: 105_00, + clip_tail: 220 minutes, + clip_cusp: 90_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 0, + cm_tolerance: 9500, + calc_tau: 0, + calc_step: 120, + calc_cut: 9990, + offboarding: true + }); + afterSpell.collaterals["GUNIV3DAIUSDC1-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 2, + mat: 10200, + liqType: "clip", + liqOn: false, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 5 * MILLION, + clip_buf: 105_00, + clip_tail: 220 minutes, + clip_cusp: 90_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 0, + cm_tolerance: 9500, + calc_tau: 0, + calc_step: 120, + calc_cut: 9990, + offboarding: false + }); + afterSpell.collaterals["WSTETH-A"] = CollateralValues({ + aL_enabled: true, + aL_line: 750 * MILLION, + aL_gap: 30 * MILLION, + aL_ttl: 12 hours, + line: 0, + dust: 7_500, + pct: 5_25, + mat: 150_00, + liqType: "clip", + liqOn: true, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 15 * MILLION, + clip_buf: 110_00, + clip_tail: 7200 seconds, + clip_cusp: 45_00, + clip_chip: 10, + clip_tip: 250, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: false + }); + afterSpell.collaterals["WSTETH-B"] = CollateralValues({ + aL_enabled: true, + aL_line: 1 * BILLION, + aL_gap: 45 * MILLION, + aL_ttl: 12 hours, + line: 0, + dust: 3_500, + pct: 5_00, + mat: 175_00, + liqType: "clip", + liqOn: true, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 10 * MILLION, + clip_buf: 110_00, + clip_tail: 7200 seconds, + clip_cusp: 45_00, + clip_chip: 10, + clip_tip: 250, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: false + }); +// afterSpell.collaterals["DIRECT-AAVEV2-DAI"] = CollateralValues({ +// aL_enabled: true, +// aL_line: 300 * MILLION, +// aL_gap: 65 * MILLION, +// aL_ttl: 12 hours, +// line: 0, +// dust: 0, +// pct: 0, +// mat: 10000, +// liqType: "clip", +// liqOn: false, +// chop: 1300, +// cat_dunk: 0, +// flip_beg: 0, +// flip_ttl: 0, +// flip_tau: 0, +// flipper_mom: 0, +// dog_hole: 0, +// clip_buf: 105_00, +// clip_tail: 220 minutes, +// clip_cusp: 90_00, +// clip_chip: 10, +// clip_tip: 300, +// clipper_mom: 0, +// cm_tolerance: 9500, +// calc_tau: 0, +// calc_step: 120, +// calc_cut: 9990 +// }); + afterSpell.collaterals["PSM-GUSD-A"] = CollateralValues({ + aL_enabled: true, + aL_line: 110 * MILLION, + aL_gap: 50 * MILLION, + aL_ttl: 24 hours, + line: 0, + dust: 0, + pct: 0, + mat: 10000, + liqType: "clip", + liqOn: false, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 0, + clip_buf: 105_00, + clip_tail: 220 minutes, + clip_cusp: 90_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 0, + cm_tolerance: 9500, + calc_tau: 0, + calc_step: 120, + calc_cut: 9990, + offboarding: false + }); + afterSpell.collaterals["GUNIV3DAIUSDC2-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 15 * THOUSAND, + pct: 6, + mat: 10200, + liqType: "clip", + liqOn: false, + chop: 1300, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 5 * MILLION, + clip_buf: 105_00, + clip_tail: 220 minutes, + clip_cusp: 90_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 0, + cm_tolerance: 9500, + calc_tau: 0, + calc_step: 120, + calc_cut: 9990, + offboarding: false + }); + afterSpell.collaterals["INST-ETH-A"] = CollateralValues({ + aL_enabled: true, + aL_line: 900 * MILLION, + aL_gap: 50 * MILLION, + aL_ttl: 8 hours, + line: 0, + dust: 10 * THOUSAND, + pct: 150, + mat: 12000, + liqType: "clip", + liqOn: true, + chop: 2000, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 50 * MILLION, + clip_buf: 120_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: false + }); + afterSpell.collaterals["INST-WBTC-A"] = CollateralValues({ + aL_enabled: true, + aL_line: 600 * MILLION, + aL_gap: 50 * MILLION, + aL_ttl: 8 hours, + line: 0, + dust: 10 * THOUSAND, + pct: 150, + mat: 12000, + liqType: "clip", + liqOn: true, + chop: 2000, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 30 * MILLION, + clip_buf: 120_00, + clip_tail: 140 minutes, + clip_cusp: 40_00, + clip_chip: 10, + clip_tip: 300, + clipper_mom: 1, + cm_tolerance: 5000, + calc_tau: 0, + calc_step: 90, + calc_cut: 9900, + offboarding: false + }); + afterSpell.collaterals["TELEPORT-FW-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 2_100_000, + dust: 0, + pct: 0, + mat: 0, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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 + }); + afterSpell.collaterals["RETH-A"] = CollateralValues({ + aL_enabled: true, + aL_line: 75 * MILLION, + aL_gap: 5 * MILLION, + aL_ttl: 8 hours, + line: 0, + dust: 7_500, + pct: 5_25, + mat: 150_00, + liqType: "clip", + liqOn: true, + chop: 13_00, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 2 * MILLION, + clip_buf: 110_00, + clip_tail: 120 minutes, + clip_cusp: 45_00, + clip_chip: 10, + clip_tip: 250, + clipper_mom: 1, + cm_tolerance: 50_00, + calc_tau: 0, + calc_step: 90, + calc_cut: 99_00, + offboarding: false + }); + afterSpell.collaterals["GNO-A"] = CollateralValues({ + aL_enabled: false, + aL_line: 0, + aL_gap: 0, + aL_ttl: 0, + line: 0, + dust: 100 * THOUSAND, + pct: 4_90, + mat: 350_00, + liqType: "clip", + liqOn: true, + chop: 13_00, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 0, + dog_hole: 2 * MILLION, + clip_buf: 120_00, + clip_tail: 140 minutes, + clip_cusp: 25_00, + clip_chip: 10, + clip_tip: 250, + clipper_mom: 1, + cm_tolerance: 50_00, + calc_tau: 0, + calc_step: 60, + calc_cut: 99_00, + offboarding: false + }); + afterSpell.collaterals["DIRECT-SPARK-DAI"] = CollateralValues({ + aL_enabled: true, + aL_line: 200 * MILLION, + aL_gap: 20 * MILLION, + aL_ttl: 8 hours, + line: 0, + dust: 0, + pct: 0, + mat: 10000, + liqType: "", + liqOn: false, + chop: 0, + cat_dunk: 0, + flip_beg: 0, + flip_ttl: 0, + flip_tau: 0, + flipper_mom: 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/archive/2023-08-18-DssSpell/test/rates.sol b/archive/2023-08-18-DssSpell/test/rates.sol new file mode 100644 index 00000000..683c71c6 --- /dev/null +++ b/archive/2023-08-18-DssSpell/test/rates.sol @@ -0,0 +1,448 @@ +// SPDX-FileCopyrightText: © 2020 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.16; + +contract Rates { + + mapping (uint256 => uint256) public rates; + + constructor() { + rates[ 0] = 1000000000000000000000000000; + rates[ 1] = 1000000000003170820659990704; + rates[ 2] = 1000000000006341324285480111; + rates[ 5] = 1000000000015850933588756013; + rates[ 6] = 1000000000019020169709960675; + rates[ 10] = 1000000000031693947650284507; + rates[ 25] = 1000000000079175551708715274; + rates[ 50] = 1000000000158153903837946257; + rates[ 75] = 1000000000236936036262880196; + rates[ 100] = 1000000000315522921573372069; + rates[ 125] = 1000000000393915525145987602; + rates[ 150] = 1000000000472114805215157978; + rates[ 175] = 1000000000550121712943459312; + rates[ 200] = 1000000000627937192491029810; + rates[ 225] = 1000000000705562181084137268; + rates[ 250] = 1000000000782997609082909351; + rates[ 275] = 1000000000860244400048238898; + rates[ 300] = 1000000000937303470807876289; + rates[ 319] = 1000000000995743377573746041; + rates[ 325] = 1000000001014175731521720677; + rates[ 333] = 1000000001038735548426731741; + rates[ 344] = 1000000001072474267302354182; + rates[ 349] = 1000000001087798189708544327; + rates[ 350] = 1000000001090862085746321732; + rates[ 358] = 1000000001115362602336059074; + rates[ 374] = 1000000001164306917698440949; + rates[ 375] = 1000000001167363430498603315; + rates[ 394] = 1000000001225381266358479708; + rates[ 400] = 1000000001243680656318820312; + rates[ 408] = 1000000001268063427242299977; + rates[ 424] = 1000000001316772794769098706; + rates[ 425] = 1000000001319814647332759691; + rates[ 450] = 1000000001395766281313196627; + rates[ 475] = 1000000001471536429740616381; + rates[ 490] = 1000000001516911765932351183; + rates[ 500] = 1000000001547125957863212448; + rates[ 525] = 1000000001622535724756171269; + rates[ 544] = 1000000001679727448331902751; + rates[ 550] = 1000000001697766583380253701; + rates[ 555] = 1000000001712791360746325100; + rates[ 569] = 1000000001754822903403114680; + rates[ 575] = 1000000001772819380639683201; + rates[ 580] = 1000000001787808646832390371; + rates[ 600] = 1000000001847694957439350562; + rates[ 619] = 1000000001904482384730282575; + rates[ 625] = 1000000001922394148741344865; + rates[ 630] = 1000000001937312893803622469; + rates[ 650] = 1000000001996917783620820123; + rates[ 675] = 1000000002071266685321207000; + rates[ 700] = 1000000002145441671308778766; + rates[ 725] = 1000000002219443553326580536; + rates[ 750] = 1000000002293273137447730714; + rates[ 775] = 1000000002366931224128103346; + rates[ 800] = 1000000002440418608258400030; + rates[ 825] = 1000000002513736079215619839; + rates[ 850] = 1000000002586884420913935572; + rates[ 875] = 1000000002659864411854984565; + rates[ 900] = 1000000002732676825177582095; + rates[ 925] = 1000000002805322428706865331; + rates[ 950] = 1000000002877801985002875644; + rates[ 975] = 1000000002950116251408586949; + rates[ 1000] = 1000000003022265980097387650; + rates[ 1025] = 1000000003094251918120023627; + rates[ 1050] = 1000000003166074807451009595; + rates[ 1075] = 1000000003237735385034516037; + rates[ 1100] = 1000000003309234382829738808; + rates[ 1125] = 1000000003380572527855758393; + rates[ 1150] = 1000000003451750542235895695; + rates[ 1175] = 1000000003522769143241571114; + rates[ 1200] = 1000000003593629043335673582; + rates[ 1225] = 1000000003664330950215446102; + rates[ 1250] = 1000000003734875566854894261; + rates[ 1275] = 1000000003805263591546724039; + rates[ 1300] = 1000000003875495717943815211; + rates[ 1325] = 1000000003945572635100236468; + rates[ 1350] = 1000000004015495027511808328; + rates[ 1375] = 1000000004085263575156219812; + rates[ 1400] = 1000000004154878953532704765; + rates[ 1425] = 1000000004224341833701283597; + rates[ 1450] = 1000000004293652882321576158; + rates[ 1475] = 1000000004362812761691191350; + rates[ 1500] = 1000000004431822129783699001; + rates[ 1525] = 1000000004500681640286189459; + rates[ 1550] = 1000000004569391942636426248; + rates[ 1575] = 1000000004637953682059597074; + rates[ 1600] = 1000000004706367499604668374; + rates[ 1625] = 1000000004774634032180348552; + rates[ 1650] = 1000000004842753912590664903; + rates[ 1675] = 1000000004910727769570159235; + rates[ 1700] = 1000000004978556227818707070; + rates[ 1725] = 1000000005046239908035965222; + rates[ 1750] = 1000000005113779426955452540; + rates[ 1775] = 1000000005181175397378268462; + rates[ 1800] = 1000000005248428428206454010; + rates[ 1825] = 1000000005315539124475999751; + rates[ 1850] = 1000000005382508087389505206; + rates[ 1875] = 1000000005449335914348494113; + rates[ 1900] = 1000000005516023198985389892; + rates[ 1925] = 1000000005582570531195155575; + rates[ 1950] = 1000000005648978497166602432; + rates[ 1975] = 1000000005715247679413371444; + rates[ 2000] = 1000000005781378656804591712; + rates[ 2025] = 1000000005847372004595219844; + rates[ 2050] = 1000000005913228294456064283; + rates[ 2075] = 1000000005978948094503498507; + rates[ 2100] = 1000000006044531969328866955; + rates[ 2125] = 1000000006109980480027587488; + rates[ 2150] = 1000000006175294184227954125; + rates[ 2175] = 1000000006240473636119643770; + rates[ 2200] = 1000000006305519386481930552; + rates[ 2225] = 1000000006370431982711611382; + rates[ 2250] = 1000000006435211968850646270; + rates[ 2275] = 1000000006499859885613516871; + rates[ 2300] = 1000000006564376270414306730; + rates[ 2325] = 1000000006628761657393506584; + rates[ 2350] = 1000000006693016577444548094; + rates[ 2375] = 1000000006757141558240069277; + rates[ 2400] = 1000000006821137124257914908; + rates[ 2425] = 1000000006885003796806875073; + rates[ 2450] = 1000000006948742094052165050; + rates[ 2475] = 1000000007012352531040649627; + rates[ 2500] = 1000000007075835619725814915; + rates[ 2525] = 1000000007139191868992490695; + rates[ 2550] = 1000000007202421784681326287; + rates[ 2575] = 1000000007265525869613022867; + rates[ 2600] = 1000000007328504623612325153; + rates[ 2625] = 1000000007391358543531775311; + rates[ 2650] = 1000000007454088123275231904; + rates[ 2675] = 1000000007516693853821156670; + rates[ 2700] = 1000000007579176223245671878; + rates[ 2725] = 1000000007641535716745390957; + rates[ 2750] = 1000000007703772816660025079; + rates[ 2775] = 1000000007765888002494768329; + rates[ 2800] = 1000000007827881750942464045; + rates[ 2825] = 1000000007889754535905554913; + rates[ 2850] = 1000000007951506828517819323; + rates[ 2875] = 1000000008013139097165896490; + rates[ 2900] = 1000000008074651807510602798; + rates[ 2925] = 1000000008136045422508041783; + rates[ 2950] = 1000000008197320402430510158; + rates[ 2975] = 1000000008258477204887202245; + rates[ 3000] = 1000000008319516284844715115; + rates[ 3025] = 1000000008380438094647356774; + rates[ 3050] = 1000000008441243084037259619; + rates[ 3075] = 1000000008501931700174301437; + rates[ 3100] = 1000000008562504387655836125; + rates[ 3125] = 1000000008622961588536236324; + rates[ 3150] = 1000000008683303742346250114; + rates[ 3175] = 1000000008743531286112173869; + rates[ 3200] = 1000000008803644654374843395; + rates[ 3225] = 1000000008863644279208445392; + rates[ 3250] = 1000000008923530590239151272; + rates[ 3275] = 1000000008983304014663575373; + rates[ 3300] = 1000000009042964977267059505; + rates[ 3325] = 1000000009102513900441785827; + rates[ 3350] = 1000000009161951204204719966; + rates[ 3375] = 1000000009221277306215386279; + rates[ 3400] = 1000000009280492621793477151; + rates[ 3425] = 1000000009339597563936298181; + rates[ 3450] = 1000000009398592543336051086; + rates[ 3475] = 1000000009457477968396956129; + rates[ 3500] = 1000000009516254245252215861; + rates[ 3525] = 1000000009574921777780821942; + rates[ 3550] = 1000000009633480967624206760; + rates[ 3575] = 1000000009691932214202741592; + rates[ 3600] = 1000000009750275914732082986; + rates[ 3625] = 1000000009808512464239369028; + rates[ 3650] = 1000000009866642255579267166; + rates[ 3675] = 1000000009924665679449875210; + rates[ 3700] = 1000000009982583124408477109; + rates[ 3725] = 1000000010040394976887155106; + rates[ 3750] = 1000000010098101621208259840; + rates[ 3775] = 1000000010155703439599739931; + rates[ 3800] = 1000000010213200812210332586; + rates[ 3825] = 1000000010270594117124616733; + rates[ 3850] = 1000000010327883730377930177; + rates[ 3875] = 1000000010385070025971152244; + rates[ 3900] = 1000000010442153375885353361; + rates[ 3925] = 1000000010499134150096313024; + rates[ 3950] = 1000000010556012716588907553; + rates[ 3975] = 1000000010612789441371369043; + rates[ 4000] = 1000000010669464688489416886; + rates[ 4025] = 1000000010726038820040263233; + rates[ 4050] = 1000000010782512196186493739; + rates[ 4075] = 1000000010838885175169824929; + rates[ 4100] = 1000000010895158113324739488; + rates[ 4125] = 1000000010951331365092000772; + rates[ 4150] = 1000000011007405283032047846; + rates[ 4175] = 1000000011063380217838272275; + rates[ 4200] = 1000000011119256518350177948; + rates[ 4225] = 1000000011175034531566425160; + rates[ 4250] = 1000000011230714602657760176; + rates[ 4275] = 1000000011286297074979831462; + rates[ 4300] = 1000000011341782290085893805; + rates[ 4325] = 1000000011397170587739401474; + rates[ 4350] = 1000000011452462305926491579; + rates[ 4375] = 1000000011507657780868358802; + rates[ 4400] = 1000000011562757347033522598; + rates[ 4425] = 1000000011617761337149988016; + rates[ 4450] = 1000000011672670082217301219; + rates[ 4475] = 1000000011727483911518500818; + rates[ 4500] = 1000000011782203152631966084; + rates[ 4525] = 1000000011836828131443163102; + rates[ 4550] = 1000000011891359172156289942; + rates[ 4575] = 1000000011945796597305821848; + rates[ 4600] = 1000000012000140727767957524; + rates[ 4625] = 1000000012054391882771967477; + rates[ 4650] = 1000000012108550379911445472; + rates[ 4675] = 1000000012162616535155464050; + rates[ 4700] = 1000000012216590662859635112; + rates[ 4725] = 1000000012270473075777076530; + rates[ 4750] = 1000000012324264085069285747; + rates[ 4775] = 1000000012377964000316921287; + rates[ 4800] = 1000000012431573129530493155; + rates[ 4825] = 1000000012485091779160962996; + rates[ 4850] = 1000000012538520254110254976; + rates[ 4875] = 1000000012591858857741678240; + rates[ 4900] = 1000000012645107891890261872; + rates[ 4925] = 1000000012698267656873003228; + rates[ 4950] = 1000000012751338451499030498; + rates[ 4975] = 1000000012804320573079680371; + rates[ 5000] = 1000000012857214317438491659; + rates[ 5025] = 1000000012910019978921115695; + rates[ 5050] = 1000000012962737850405144363; + rates[ 5075] = 1000000013015368223309856554; + rates[ 5100] = 1000000013067911387605883890; + rates[ 5125] = 1000000013120367631824796485; + rates[ 5150] = 1000000013172737243068609553; + rates[ 5175] = 1000000013225020507019211652; + rates[ 5200] = 1000000013277217707947715318; + rates[ 5225] = 1000000013329329128723730871; + rates[ 5250] = 1000000013381355050824564143; + rates[ 5275] = 1000000013433295754344338876; + rates[ 5300] = 1000000013485151518003044532; + rates[ 5325] = 1000000013536922619155510237; + rates[ 5350] = 1000000013588609333800305597; + rates[ 5375] = 1000000013640211936588569081; + rates[ 5400] = 1000000013691730700832764691; + rates[ 5425] = 1000000013743165898515367617; + rates[ 5450] = 1000000013794517800297479554; + rates[ 5475] = 1000000013845786675527374380; + rates[ 5500] = 1000000013896972792248974855; + rates[ 5525] = 1000000013948076417210261020; + rates[ 5550] = 1000000013999097815871610946; + rates[ 5575] = 1000000014050037252414074493; + rates[ 5600] = 1000000014100894989747580713; + rates[ 5625] = 1000000014151671289519079548; + rates[ 5650] = 1000000014202366412120618444; + rates[ 5675] = 1000000014252980616697354502; + rates[ 5700] = 1000000014303514161155502800; + rates[ 5725] = 1000000014353967302170221464; + rates[ 5750] = 1000000014404340295193434124; + rates[ 5775] = 1000000014454633394461590334; + rates[ 5800] = 1000000014504846853003364537; + rates[ 5825] = 1000000014554980922647294184; + rates[ 5850] = 1000000014605035854029357558; + rates[ 5875] = 1000000014655011896600491882; + rates[ 5900] = 1000000014704909298634052283; + rates[ 5925] = 1000000014754728307233212158; + rates[ 5950] = 1000000014804469168338305494; + rates[ 5975] = 1000000014854132126734111701; + rates[ 6000] = 1000000014903717426057083481; + rates[ 6025] = 1000000014953225308802518272; + rates[ 6050] = 1000000015002656016331673799; + rates[ 6075] = 1000000015052009788878828253; + rates[ 6100] = 1000000015101286865558285606; + rates[ 6125] = 1000000015150487484371326590; + rates[ 6150] = 1000000015199611882213105818; + rates[ 6175] = 1000000015248660294879495575; + rates[ 6200] = 1000000015297632957073876761; + rates[ 6225] = 1000000015346530102413877471; + rates[ 6250] = 1000000015395351963438059699; + rates[ 6275] = 1000000015444098771612554646; + rates[ 6300] = 1000000015492770757337647112; + rates[ 6325] = 1000000015541368149954309419; + rates[ 6350] = 1000000015589891177750685357; + rates[ 6375] = 1000000015638340067968524580; + rates[ 6400] = 1000000015686715046809567945; + rates[ 6425] = 1000000015735016339441884188; + rates[ 6450] = 1000000015783244170006158447; + rates[ 6475] = 1000000015831398761621933006; + rates[ 6500] = 1000000015879480336393800741; + rates[ 6525] = 1000000015927489115417551681; + rates[ 6550] = 1000000015975425318786273105; + rates[ 6575] = 1000000016023289165596403599; + rates[ 6600] = 1000000016071080873953741499; + rates[ 6625] = 1000000016118800660979408115; + rates[ 6650] = 1000000016166448742815766155; + rates[ 6675] = 1000000016214025334632293755; + rates[ 6700] = 1000000016261530650631414500; + rates[ 6725] = 1000000016308964904054283846; + rates[ 6750] = 1000000016356328307186532328; + rates[ 6775] = 1000000016403621071363965932; + rates[ 6800] = 1000000016450843406978224029; + rates[ 6825] = 1000000016497995523482395247; + rates[ 6850] = 1000000016545077629396591637; + rates[ 6875] = 1000000016592089932313481533; + rates[ 6900] = 1000000016639032638903781446; + rates[ 6925] = 1000000016685905954921707380; + rates[ 6950] = 1000000016732710085210385903; + rates[ 6975] = 1000000016779445233707225354; + rates[ 7000] = 1000000016826111603449247521; + rates[ 7025] = 1000000016872709396578380147; + rates[ 7050] = 1000000016919238814346710603; + rates[ 7075] = 1000000016965700057121701072; + rates[ 7100] = 1000000017012093324391365593; + rates[ 7125] = 1000000017058418814769409273; + rates[ 7150] = 1000000017104676726000330021; + rates[ 7175] = 1000000017150867254964483131; + rates[ 7200] = 1000000017196990597683109018; + rates[ 7225] = 1000000017243046949323324453; + rates[ 7250] = 1000000017289036504203077600; + rates[ 7275] = 1000000017334959455796067168; + rates[ 7300] = 1000000017380815996736626004; + rates[ 7325] = 1000000017426606318824569415; + rates[ 7350] = 1000000017472330613030008543; + rates[ 7375] = 1000000017517989069498129080; + rates[ 7400] = 1000000017563581877553935633; + rates[ 7425] = 1000000017609109225706962029; + rates[ 7450] = 1000000017654571301655947851; + rates[ 7475] = 1000000017699968292293481503; + rates[ 7500] = 1000000017745300383710610088; + rates[ 7525] = 1000000017790567761201416374; + rates[ 7550] = 1000000017835770609267563142; + rates[ 7575] = 1000000017880909111622805195; + rates[ 7600] = 1000000017925983451197469286; + rates[ 7625] = 1000000017970993810142902264; + rates[ 7650] = 1000000018015940369835887686; + rates[ 7675] = 1000000018060823310883031179; + rates[ 7700] = 1000000018105642813125114801; + rates[ 7725] = 1000000018150399055641420686; + rates[ 7750] = 1000000018195092216754024201; + rates[ 7775] = 1000000018239722474032056911; + rates[ 7800] = 1000000018284290004295939569; + rates[ 7825] = 1000000018328794983621585414; + rates[ 7850] = 1000000018373237587344574003; + rates[ 7875] = 1000000018417617990064295840; + rates[ 7900] = 1000000018461936365648068049; + rates[ 7925] = 1000000018506192887235221305; + rates[ 7950] = 1000000018550387727241158310; + rates[ 7975] = 1000000018594521057361384012; + rates[ 8000] = 1000000018638593048575507813; + rates[ 8025] = 1000000018682603871151218019; + rates[ 8050] = 1000000018726553694648228732; + rates[ 8075] = 1000000018770442687922199432; + rates[ 8100] = 1000000018814271019128627481; + rates[ 8125] = 1000000018858038855726713746; + rates[ 8150] = 1000000018901746364483201594; + rates[ 8175] = 1000000018945393711476189463; + rates[ 8200] = 1000000018988981062098917230; + rates[ 8225] = 1000000019032508581063526585; + rates[ 8250] = 1000000019075976432404795643; + rates[ 8275] = 1000000019119384779483847985; + rates[ 8300] = 1000000019162733784991836346; + rates[ 8325] = 1000000019206023610953601168; + rates[ 8350] = 1000000019249254418731304205; + rates[ 8375] = 1000000019292426369028037391; + rates[ 8400] = 1000000019335539621891407188; + rates[ 8425] = 1000000019378594336717094581; + rates[ 8450] = 1000000019421590672252390959; + rates[ 8475] = 1000000019464528786599710033; + rates[ 8500] = 1000000019507408837220076029; + rates[ 8525] = 1000000019550230980936588320; + rates[ 8550] = 1000000019592995373937862689; + rates[ 8575] = 1000000019635702171781449432; + rates[ 8600] = 1000000019678351529397228463; + rates[ 8625] = 1000000019720943601090781625; + rates[ 8650] = 1000000019763478540546742376; + rates[ 8675] = 1000000019805956500832123050; + rates[ 8700] = 1000000019848377634399619849; + rates[ 8725] = 1000000019890742093090895767; + rates[ 8750] = 1000000019933050028139841613; + rates[ 8775] = 1000000019975301590175815296; + rates[ 8800] = 1000000020017496929226859581; + rates[ 8825] = 1000000020059636194722898437; + rates[ 8850] = 1000000020101719535498912200; + rates[ 8875] = 1000000020143747099798091677; + rates[ 8900] = 1000000020185719035274971385; + rates[ 8925] = 1000000020227635488998542076; + rates[ 8950] = 1000000020269496607455342719; + rates[ 8975] = 1000000020311302536552532106; + rates[ 9000] = 1000000020353053421620940223; + rates[ 9025] = 1000000020394749407418099573; + rates[ 9050] = 1000000020436390638131256590; + rates[ 9075] = 1000000020477977257380363298; + rates[ 9100] = 1000000020519509408221049399; + rates[ 9125] = 1000000020560987233147574896; + rates[ 9150] = 1000000020602410874095763456; + rates[ 9175] = 1000000020643780472445916617; + rates[ 9200] = 1000000020685096169025709028; + rates[ 9225] = 1000000020726358104113064837; + rates[ 9250] = 1000000020767566417439015395; + rates[ 9275] = 1000000020808721248190538424; + rates[ 9300] = 1000000020849822735013378765; + rates[ 9325] = 1000000020890871016014850891; + rates[ 9350] = 1000000020931866228766623286; + rates[ 9375] = 1000000020972808510307484860; + rates[ 9400] = 1000000021013697997146093523; + rates[ 9425] = 1000000021054534825263707061; + rates[ 9450] = 1000000021095319130116896449; + rates[ 9475] = 1000000021136051046640241741; + rates[ 9500] = 1000000021176730709249010667; + rates[ 9525] = 1000000021217358251841820063; + rates[ 9550] = 1000000021257933807803280285; + rates[ 9575] = 1000000021298457510006622716; + rates[ 9600] = 1000000021338929490816310513; + rates[ 9625] = 1000000021379349882090632705; + rates[ 9650] = 1000000021419718815184281790; + rates[ 9675] = 1000000021460036420950914938; + rates[ 9700] = 1000000021500302829745698932; + rates[ 9725] = 1000000021540518171427838973; + rates[ 9750] = 1000000021580682575363091474; + rates[ 9775] = 1000000021620796170426260951; + rates[ 9800] = 1000000021660859085003681151; + rates[ 9825] = 1000000021700871446995680519; + rates[ 9850] = 1000000021740833383819032127; + rates[ 9875] = 1000000021780745022409388199; + rates[ 9900] = 1000000021820606489223699321; + rates[ 9925] = 1000000021860417910242618463; + rates[ 9950] = 1000000021900179410972889943; + rates[ 9975] = 1000000021939891116449723415; + rates[10000] = 1000000021979553151239153027; + } + +} diff --git a/archive/2023-08-18-DssSpell/test/starknet.t.sol b/archive/2023-08-18-DssSpell/test/starknet.t.sol new file mode 100644 index 00000000..0ddd0b10 --- /dev/null +++ b/archive/2023-08-18-DssSpell/test/starknet.t.sol @@ -0,0 +1,242 @@ +// SPDX-FileCopyrightText: © 2022 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.16; + +import "../DssSpell.t.base.sol"; + +contract ConfigStarknet { + StarknetValues starknetValues; + + struct StarknetValues { + bytes32 l2_spell; + address core_implementation; + uint256 dai_bridge_isOpen; + uint256 dai_bridge_ceiling; + uint256 dai_bridge_maxDeposit; + uint256 l2_dai_bridge; + uint256 l2_gov_relay; + uint256 relay_selector; + } + + function setValues() public { + uint256 WAD = 10 ** 18; + + starknetValues = StarknetValues({ + l2_spell: 0, // Set to zero if no spell is set. + core_implementation: 0x3CeCEe6B359fAc09c79Ca4032826894F7e660B33, // As at 2023-05-17 + dai_bridge_isOpen: 1, // 1 open, 0 closed + dai_bridge_ceiling: 5_000_000 * WAD, // wei + dai_bridge_maxDeposit: type(uint256).max, // wei + l2_dai_bridge: 0x057b7fe4e59d295de5e7955c373023514ede5b972e872e9aa5dcdf563f5cfacb, + l2_gov_relay: 0x00275e3f018f7884f449a1fb418b6b1de77e01c74a9fefaed1599cb22322ff74, + relay_selector: 300224956480472355485152391090755024345070441743081995053718200325371913697 // Hardcoded in L1 gov relay, not public + }); + } +} + +interface StarknetEscrowMomLike { + function owner() external returns (address); + function authority() external returns (address); + function escrow() external returns (address); + function token() external returns (address); +} + +interface StarknetEscrowLike { + function wards(address) external returns(uint256); +} + +interface StarknetDaiBridgeLike { + function wards(address) external returns(uint256); + function isOpen() external returns (uint256); + function ceiling() external returns (uint256); + function maxDeposit() external returns (uint256); + function dai() external returns (address); + function starkNet() external returns (address); + function escrow() external returns (address); + function l2DaiBridge() external returns (uint256); +} + +interface StarknetGovRelayLike { + function wards(address) external returns (uint256); + function starkNet() external returns (address); + function l2GovernanceRelay() external returns (uint256); +} + +interface StarknetCoreLike { + function implementation() external returns (address); + function isNotFinalized() external returns (bool); + function l1ToL2Messages(bytes32) external returns (uint256); + function l1ToL2MessageNonce() external returns (uint256); +} + +interface DaiLike { + function allowance(address, address) external view returns (uint256); +} + +contract StarknetTests is DssSpellTestBase, ConfigStarknet { + + event LogMessageToL2( + address indexed fromAddress, + uint256 indexed toAddress, + uint256 indexed selector, + uint256[] payload, + uint256 nonce, + uint256 fee + ); + + constructor() { + setValues(); + } + + function testStarknet() public { + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + _checkStarknetEscrowMom(); + _checkStarknetEscrow(); + _checkStarknetDaiBridge(); + _checkStarknetGovRelay(); + _checkStarknetCore(); + } + + function testStarknetSpell() public { + + if (starknetValues.l2_spell != bytes32(0)) { + // Ensure the Pause Proxy has some ETH for the Starknet Spell + assertGt(pauseProxy.balance, 0); + _vote(address(spell)); + DssSpell(spell).schedule(); + + vm.warp(DssSpell(spell).nextCastTime()); + + vm.expectEmit(true, true, true, false, addr.addr("STARKNET_CORE")); + emit LogMessageToL2(addr.addr("STARKNET_GOV_RELAY"), starknetValues.l2_gov_relay, starknetValues.relay_selector, _payload(starknetValues.l2_spell), 0, 0); + DssSpell(spell).cast(); + + assertTrue(spell.done()); + + _checkStarknetMessage(starknetValues.l2_spell); + } + } + + function _checkStarknetEscrowMom() internal { + StarknetEscrowMomLike escrowMom = StarknetEscrowMomLike(addr.addr("STARKNET_ESCROW_MOM")); + + assertEq(escrowMom.owner(), addr.addr("MCD_PAUSE_PROXY"), "StarknetTest/pause-proxy-not-owner-on-escrow-mom"); + assertEq(escrowMom.authority(), addr.addr("MCD_ADM"), "StarknetTest/chief-not-authority-on-escrow-mom"); + assertEq(escrowMom.escrow(), addr.addr("STARKNET_ESCROW"), "StarknetTest/unexpected-escrow-on-escrow-mom"); + assertEq(escrowMom.token(), addr.addr("MCD_DAI"), "StarknetTest/unexpected-dai-on-escrow-mom"); + } + + function _checkStarknetEscrow() internal { + StarknetEscrowLike escrow = StarknetEscrowLike(addr.addr("STARKNET_ESCROW")); + + assertEq(escrow.wards(addr.addr("MCD_PAUSE_PROXY")), 1, "StarknetTest/pause-proxy-not-ward-on-escrow"); + assertEq(escrow.wards(addr.addr("MCD_ESM")), 1, "StarknetTest/esm-not-ward-on-escrow"); + assertEq(escrow.wards(addr.addr("STARKNET_ESCROW_MOM")), 1, "StarknetTest/escrow-mom-not-ward-on-escrow"); + + DaiLike dai = DaiLike(addr.addr("MCD_DAI")); + + assertEq(dai.allowance(addr.addr("STARKNET_ESCROW"), addr.addr("STARKNET_DAI_BRIDGE")), type(uint256).max, "StarknetTest/unexpected-escrow-allowance"); + assertEq(dai.allowance(addr.addr("STARKNET_ESCROW"), addr.addr("STARKNET_DAI_BRIDGE_LEGACY")), 0, "StarknetTest/unexpected-legacy-escrow-allowance"); + } + + function _checkStarknetDaiBridge() internal { + StarknetDaiBridgeLike daiBridge = StarknetDaiBridgeLike(addr.addr("STARKNET_DAI_BRIDGE")); + + assertEq(daiBridge.isOpen(), starknetValues.dai_bridge_isOpen, "StarknetTestError/dai-bridge-isOpen-unexpected"); + assertEq(daiBridge.ceiling(), starknetValues.dai_bridge_ceiling, "StarknetTestError/dai-bridge-ceiling-unexpected"); + assertEq(daiBridge.maxDeposit(), starknetValues.dai_bridge_maxDeposit, "StarknetTestError/dai-bridge-maxDeposit-unexpected"); + + assertEq(daiBridge.dai(), addr.addr("MCD_DAI"), "StarknetTest/dai-bridge-dai"); + assertEq(daiBridge.starkNet(), addr.addr("STARKNET_CORE"), "StarknetTest/dai-bridge-core"); + assertEq(daiBridge.escrow(), addr.addr("STARKNET_ESCROW"), "StarknetTest/dai-bridge-escrow"); + + assertEq(daiBridge.wards(addr.addr("MCD_PAUSE_PROXY")), 1, "StarknetTest/pause-proxy-not-ward-on-dai-bridge"); + assertEq(daiBridge.wards(addr.addr("MCD_ESM")), 1, "StarknetTest/esm-not-ward-on-dai-bridge"); + + assertEq(daiBridge.l2DaiBridge(), starknetValues.l2_dai_bridge, "StarknetTest/wrong-l2-dai-bridge-on-dai-bridge"); + } + + function _checkStarknetGovRelay() internal { + StarknetGovRelayLike govRelay = StarknetGovRelayLike(addr.addr("STARKNET_GOV_RELAY")); + + assertEq(govRelay.wards(addr.addr("MCD_PAUSE_PROXY")), 1, "StarknetTest/pause-proxy-not-ward-on-gov-relay"); + assertEq(govRelay.wards(addr.addr("MCD_ESM")), 1, "StarknetTest/esm-not-ward-on-gov-relay"); + + assertEq(govRelay.starkNet(), addr.addr("STARKNET_CORE"), "StarknetTest/unexpected-starknet-core-on-gov-relay"); + assertEq(govRelay.l2GovernanceRelay(), starknetValues.l2_gov_relay, "StarknetTest/unexpected-l2-gov-relay-on-gov-relay"); + } + + function _checkStarknetCore() internal { + StarknetCoreLike core = StarknetCoreLike(addr.addr("STARKNET_CORE")); + + // Checks to see that starknet core implementation matches core + // If the core implementation changes, inspect the new implementation for safety and update the config + // Note: message checks may fail if the message structure changes in the new implementation + assertEq(core.implementation(), starknetValues.core_implementation, _concat("StarknetTest/new-core-implementation-", bytes32(uint256(uint160(core.implementation()))))); + + assertTrue(core.isNotFinalized()); + } + + + function _checkStarknetMessage(bytes32 _spell) internal { + StarknetCoreLike core = StarknetCoreLike(addr.addr("STARKNET_CORE")); + + if (_spell != 0) { + + // Nonce increments each message, back up one + uint256 _nonce = core.l1ToL2MessageNonce() - 1; + + // Hash of message created by Starknet Core + bytes32 _message = _getL1ToL2MsgHash(addr.addr("STARKNET_GOV_RELAY"), starknetValues.l2_gov_relay, starknetValues.relay_selector, _payload(_spell), _nonce); + + // Assert message is scheduled, core returns 0 if not in message array + assertTrue(core.l1ToL2Messages(_message) > 0, "StarknetTest/SpellNotQueued"); + } + } + + function _payload(bytes32 _spell) internal pure returns (uint256[] memory) { + // Payload must be array + uint256[] memory payload_ = new uint256[](1); + payload_[0] = uint256(_spell); + return payload_; + } + + // Modified version of internal getL1ToL2MsgHash in Starknet Core implementation + function _getL1ToL2MsgHash( + address sender, + uint256 toAddress, + uint256 selector, + uint256[] memory payload, + uint256 nonce + ) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked( + uint256(uint160(sender)), + toAddress, + nonce, + selector, + payload.length, + payload + ) + ); + } +} diff --git a/src/DssSpell.sol b/src/DssSpell.sol index 40d91650..806e0769 100644 --- a/src/DssSpell.sol +++ b/src/DssSpell.sol @@ -19,18 +19,33 @@ pragma solidity 0.8.16; import "dss-exec-lib/DssExec.sol"; import "dss-exec-lib/DssAction.sol"; -interface RwaLiquidationOracleLike { - function ilks(bytes32 ilk) external view returns (string memory doc, address pip, uint48 tau, uint48 toc); - function init(bytes32 ilk, uint256 val, string memory doc, uint48 tau) external; - function tell(bytes32 ilk) external; +interface TransferOwnershipLike { + function transferOwnership(address newOwner) external; } -interface ProxyLike { - function exec(address target, bytes calldata args) external payable returns (bytes memory out); +interface ChangeAdminLike { + function changeAdmin(address newAdmin) external; +} + +interface ACLManagerLike { + function DEFAULT_ADMIN_ROLE() external view returns (bytes32); + function addEmergencyAdmin(address admin) external; + function removeEmergencyAdmin(address admin) external; + function removePoolAdmin(address admin) external; + function grantRole(bytes32 role, address account) external; + function revokeRole(bytes32 role, address account) external; } -interface ChainlogLike { - function removeAddress(bytes32 _key) external; +interface PoolAddressProviderLike { + function setACLAdmin(address newAclAdmin) external; +} + +interface RwaLiquidationLike { + function bump(bytes32 ilk, uint256 val) external; +} + +interface ProxyLike { + function exec(address target, bytes calldata args) external payable returns (bytes memory out); } contract DssSpellAction is DssAction { @@ -42,21 +57,15 @@ contract DssSpellAction is DssAction { return false; } - // ----- JAT1 DAO Resolution ----- - // Forum: https://forum.makerdao.com/t/clydesdale-quarterly-return-of-surplus-fund/21291 - // Poll: N/A - // Approve DAO Resolution hash QmaGTVioBsCPfNoz9rbW7LU6YuzfgqHDZd92Hny5ACfL3p + // ---------- DAO Resolution for BlockTower Andromeda ---------- + // Forum: https://forum.makerdao.com/t/dao-resolution-to-facilitate-onboarding-of-taco-with-additional-third-parties/21572 + // Forum: https://forum.makerdao.com/t/dao-resolution-to-facilitate-onboarding-of-taco-with-additional-third-parties/21572/2 - // Comma-separated list of DAO resolutions IPFS hashes. - string public constant dao_resolutions = "QmaGTVioBsCPfNoz9rbW7LU6YuzfgqHDZd92Hny5ACfL3p"; - - address internal immutable MIP21_LIQUIDATION_ORACLE = DssExecLib.getChangelogAddress("MIP21_LIQUIDATION_ORACLE"); - - // Spark - address internal immutable SUBPROXY_SPARK = DssExecLib.getChangelogAddress("SUBPROXY_SPARK"); - // NOTE: goerli spell address is originated from https://github.com/marsfoundation/spark-spells/blob/d41d58ccc974f8358b0df962ad1fb931fedb7e62/src/proposals/20230802/SparkGoerli_20230802.t.sol#L80 - address internal constant SPARK_SPELL = 0xEd3BF79737d3A469A29a7114cA1084e8340a2f20; + // Include IPFS hash QmUNrCwKK2iK2ki5Spn97jrTCDKqFjDZWKk3wxQ2psgMP5 (not a `doc` update) + // NOTE: by the previous convention it should be a comma-separated list of DAO resolutions IPFS hashes + string public constant dao_resolutions = "QmUNrCwKK2iK2ki5Spn97jrTCDKqFjDZWKk3wxQ2psgMP5"; + // ---------- Rates ---------- // Many of the settings that change weekly rely on the rate accumulator // described at https://docs.makerdao.com/smart-contract-modules/rates-module // To check this yourself, use the following rate calculation (example 8%): @@ -67,91 +76,208 @@ contract DssSpellAction is DssAction { // https://ipfs.io/ipfs/QmVp4mhhbwWGTfbh2BzwQB9eiBrQBKiqcPRZCaAxNUaar6 // // uint256 internal constant X_PCT_RATE = ; - uint256 internal constant EIGHT_PCT_RATE = 1000000002440418608258400030; - - // --- MATH --- - uint256 internal constant MILLION = 10 ** 6; - - function _updateDoc(bytes32 ilk, string memory doc) internal { - ( , address pip, uint48 tau, ) = RwaLiquidationOracleLike(MIP21_LIQUIDATION_ORACLE).ilks(ilk); - require(pip != address(0), "DssSpell/unexisting-rwa-ilk"); + uint256 internal constant THREE_PT_THREE_THREE_PCT_RATE = 1000000001038735548426731741; + uint256 internal constant THREE_PT_FIVE_EIGHT_PCT_RATE = 1000000001115362602336059074; + uint256 internal constant FOUR_PT_ZERO_EIGHT_PCT_RATE = 1000000001268063427242299977; + uint256 internal constant FIVE_PCT_RATE = 1000000001547125957863212448; + uint256 internal constant FIVE_PT_TWO_FIVE_PCT_RATE = 1000000001622535724756171269; + uint256 internal constant FIVE_PT_FIVE_FIVE_PCT_RATE = 1000000001712791360746325100; + uint256 internal constant FIVE_PT_EIGHT_PCT_RATE = 1000000001787808646832390371; + uint256 internal constant SIX_PT_THREE_PCT_RATE = 1000000001937312893803622469; + uint256 internal constant SEVEN_PCT_RATE = 1000000002145441671308778766; + + // ---------- Math ---------- + uint256 internal constant THOUSAND = 10 ** 3; + uint256 internal constant MILLION = 10 ** 6; + uint256 internal constant BILLION = 10 ** 9; + uint256 internal constant RAD = 10 ** 45; + + // ---------- Smart Burn Engine Parameter Updates ---------- + address internal immutable MCD_VOW = DssExecLib.vow(); + address internal immutable MCD_FLAP = DssExecLib.flap(); + + // ---------- New Silver Parameter Changes ---------- + address internal immutable MIP21_LIQUIDATION_ORACLE = DssExecLib.getChangelogAddress("MIP21_LIQUIDATION_ORACLE"); - // Init the RwaLiquidationOracle to reset the doc - RwaLiquidationOracleLike(MIP21_LIQUIDATION_ORACLE).init( - ilk, // ilk to update - 0, // price ignored if init() has already been called - doc, // new legal document - tau // old tau value - ); - } + // ---------- Transfer Spark Proxy Admin Controls ---------- + // Contracts pulled from Spark official deployment repository + // https://github.com/marsfoundation/sparklend/blob/ca2b72af7c5fb790cc91eaca5d8d4c83fa37e74b/script/output/5/primary-latest.json + // Spark Proxy: https://github.com/marsfoundation/sparklend/blob/ca2b72af7c5fb790cc91eaca5d8d4c83fa37e74b/script/output/5/primary-sce-latest.json#L2 + address internal constant SPARK_PROXY = 0x4e847915D8a9f2Ab0cDf2FC2FD0A30428F25665d; + address internal constant SPARK_TREASURY_CONTROLLER = 0x98e6BcBA7d5daFbfa4a92dAF08d3d7512820c30C; + address internal constant SPARK_TREASURY = 0x0D56700c90a690D8795D6C148aCD94b12932f4E3; + address internal constant SPARK_TREASURY_DAI = 0x44816381990B6613c7A96ca1937f3902D8eA3F5b; + address internal constant SPARK_INCENTIVES = 0xF028c2F4b19898718fD0F77b9b881CbfdAa5e8Bb; + address internal constant SPARK_WETH_GATEWAY = 0xe6fC577E87F7c977c4393300417dCC592D90acF8; + address internal constant SPARK_ACL_MANAGER = 0xb137E7d16564c81ae2b0C8ee6B55De81dd46ECe5; + address internal constant SPARK_POOL_ADDRESS_PROVIDER = 0x026a5B6114431d8F3eF2fA0E1B2EDdDccA9c540E; + address internal constant SPARK_POOL_ADDRESS_PROVIDER_REGISTRY = 0x1ad570fDEA255a3c1d8Cf56ec76ebA2b7bFDFfea; + address internal constant SPARK_EMISSION_MANAGER = 0xA7F8A757C4f7696c015B595F51B2901AC0121B18; + + // ---------- Trigger Spark Proxy Spell ---------- + address internal constant SPARK_SPELL = 0x13176Ad78eC3d2b6E32908B019D0F772EC0b4dFd; function actions() public override { - // ----- Enhanced DSR Activation ----- - // Poll: https://vote.makerdao.com/polling/QmcTRPLx - // Forum: https://forum.makerdao.com/t/request-for-gov12-1-2-edit-to-the-stability-scope-to-quickly-implement-enhanced-dsr/21405 - - // Increase the DSR by 4.81% from 3.19% to 8% - DssExecLib.setDSR(EIGHT_PCT_RATE, /* doDrip = */ true); - - // ----- Spark D3M DC Increase ----- - // Poll: https://vote.makerdao.com/polling/QmSLj3HS - // Forum: https://forum.makerdao.com/t/phoenix-labs-proposed-changes-for-spark/21422 - - // Increase the DIRECT-SPARK-DAI Maximum Debt Ceiling by 180 million DAI from 20 million DAI to 200 million DAI - // Keep gap and ttl at current settings (20 million and 8 hours respectively) - DssExecLib.setIlkAutoLineDebtCeiling("DIRECT-SPARK-DAI", 200 * MILLION); - - // ----- HTC-DROP (RWA004-A) Changes ----- - // Poll: https://vote.makerdao.com/polling/QmR8cYb1 - // Forum: https://forum.makerdao.com/t/request-to-poll-decrease-debt-ceiling-for-harbor-trade-credit-htc-drop-to-0/21373 - - // Set DC to 0 - // Note: it was agreed with GovAlpha that there will be no global DC reduction this time. - DssExecLib.setIlkDebtCeiling("RWA004-A", 0); - // Call tell() on RWALiquidationOracle - RwaLiquidationOracleLike(MIP21_LIQUIDATION_ORACLE).tell("RWA004-A"); - - // ----- New Silver (RWA002-A) Doc Update ----- - // Poll: https://vote.makerdao.com/polling/QmaU1eaD + // ---------- EDSR Update ---------- + // Forum: https://forum.makerdao.com/t/request-for-gov12-1-2-edit-to-the-stability-scope-to-quickly-modify-enhanced-dsr-based-on-observed-data/21581 + + // Reduce DSR by 3% from 8% to 5% + DssExecLib.setDSR(FIVE_PCT_RATE, /* doDrip = */ true); + + // ---------- DSR-based Stability Fee Updates ---------- + // Forum: https://forum.makerdao.com/t/request-for-gov12-1-2-edit-to-the-stability-scope-to-quickly-modify-enhanced-dsr-based-on-observed-data/21581 + + // Increase ETH-A SF by 0.14% from 3.44% to 3.58% + DssExecLib.setIlkStabilityFee("ETH-A", THREE_PT_FIVE_EIGHT_PCT_RATE, /* doDrip = */ true); + + // Increase ETH-B SF by 0.14% from 3.94%% to 4.08% + DssExecLib.setIlkStabilityFee("ETH-B", FOUR_PT_ZERO_EIGHT_PCT_RATE, /* doDrip = */ true); + + // Increase ETH-C SF by 0.14% from 3.19% to 3.33% + DssExecLib.setIlkStabilityFee("ETH-C", THREE_PT_THREE_THREE_PCT_RATE, /* doDrip = */ true); + + // Increase WSTETH-A SF by 1.81% from 3.44% to 5.25% + DssExecLib.setIlkStabilityFee("WSTETH-A", FIVE_PT_TWO_FIVE_PCT_RATE, /* doDrip = */ true); + + // Increase WSTETH-B SF by 1.81% from 3.19% to 5.00% + DssExecLib.setIlkStabilityFee("WSTETH-B", FIVE_PCT_RATE, /* doDrip = */ true); + + // Increase RETH-A SF by 1.81% from 3.44% to 5.25% + DssExecLib.setIlkStabilityFee("RETH-A", FIVE_PT_TWO_FIVE_PCT_RATE, /* doDrip = */ true); + + // Increase WBTC-A SF by 0.11% from 5.69% to 5.80% + DssExecLib.setIlkStabilityFee("WBTC-A", FIVE_PT_EIGHT_PCT_RATE, /* doDrip = */ true); + + // Increase WBTC-B SF by 0.11% from 6.19% to 6.30% + DssExecLib.setIlkStabilityFee("WBTC-B", SIX_PT_THREE_PCT_RATE, /* doDrip = */ true); + + // Increase WBTC-C SF by 0.11% from 5.44% to 5.55% + DssExecLib.setIlkStabilityFee("WBTC-C", FIVE_PT_FIVE_FIVE_PCT_RATE, /* doDrip = */ true); + + // ---------- Smart Burn Engine Parameter Updates ---------- + // Poll: https://vote.makerdao.com/polling/QmTRJNNH + // Forum: https://forum.makerdao.com/t/smart-burn-engine-parameters-update-1/21545 + + // Increase vow.bump by 15,000 DAI from 5,000 DAI to 20,000 DAI + DssExecLib.setValue(MCD_VOW, "bump", 20 * THOUSAND * RAD); + + // Increase hop by 4,731 seconds from 1,577 seconds to 6,308 seconds + DssExecLib.setValue(MCD_FLAP, "hop", 6_308); + + // ---------- Non-DSR Related Parameter Changes ---------- + // Forum: https://forum.makerdao.com/t/stability-scope-parameter-changes-4/21567 + // Mip: https://mips.makerdao.com/mips/details/MIP104#14-3-native-vault-engine + + // Increase WSTETH-A line by 250 million DAI from 500 million DAI to 750 million DAI (no change to gap or ttl) + DssExecLib.setIlkAutoLineDebtCeiling("WSTETH-A", 750 * MILLION); + + // Increase WSTETH-B line by 500 million DAi from 500 million DAI to 1 billion DAI + // Increase WSTETH-B gap by 15 million DAI from 30 million DAI to 45 million DAI + // Reduce WSTETH-B ttl by 14,400 seconds from 57,600 seconds to 43,200 seconds + // Forum: https://forum.makerdao.com/t/non-scope-defined-parameter-changes-wsteth-b-dc-iam/21568 + // Poll: https://vote.makerdao.com/polling/QmPxbrBZ#poll-detail + DssExecLib.setIlkAutoLineParameters("WSTETH-B", 1 * BILLION, 45 * MILLION, 12 hours); + + // Increase RETH-A line by 25 million DAI from 50 million DAI to 75 million DAI + DssExecLib.setIlkAutoLineDebtCeiling("RETH-A", 75 * MILLION); + + // ---------- CRVV1ETHSTETH-A 2nd Stage Offboarding ---------- + // Forum: https://forum.makerdao.com/t/stability-scope-parameter-changes-4/21567#crvv1ethsteth-a-offboarding-parameters-13 + // Mip: https://mips.makerdao.com/mips/details/MIP104#14-3-native-vault-engine + // NOTE: ignore on goerli (since there is no CRVV1ETHSTETH-A) + + // Set chop to 0% + // Set tip to 0% + // Set chip to 0% + // Set Liquidation Ratio to 10,000% + // Reduce Global Debt Ceiling by 100 million DAI to account for offboarded collateral + + // ---------- Aligned Delegate Compensation for July 2023 ---------- + // Forum: https://forum.makerdao.com/t/july-2023-aligned-delegate-compensation/21632 + // NOTE: ignore on goerli + + // 0xDefensor - 29.76 MKR - 0x9542b441d65B6BF4dDdd3d4D2a66D8dCB9EE07a9 + // BONAPUBLICA - 29.76 MKR - 0x167c1a762B08D7e78dbF8f24e5C3f1Ab415021D3 + // QGov - 29.76 MKR - 0xB0524D8707F76c681901b782372EbeD2d4bA28a6 + // TRUE NAME - 29.76 MKR - 0x612f7924c367575a0edf21333d96b15f1b345a5d + // UPMaker - 29.76 MKR - 0xbb819df169670dc71a16f58f55956fe642cc6bcd + // vigilant - 29.76 MKR - 0x2474937cB55500601BCCE9f4cb0A0A72Dc226F61 + // WBC - 14.82 MKR - 0xeBcE83e491947aDB1396Ee7E55d3c81414fB0D47 + // PALC - 13.89 MKR - 0x78Deac4F87BD8007b9cb56B8d53889ed5374e83A + // Navigator - 11.24 MKR - 0x11406a9CC2e37425F15f920F494A51133ac93072 + // PBG - 9.92 MKR - 0x8D4df847dB7FfE0B46AF084fE031F7691C6478c2 + // VoteWizard - 9.92 MKR - 0x9E72629dF4fcaA2c2F5813FbbDc55064345431b1 + // Libertas - 9.92 MKR - 0xE1eBfFa01883EF2b4A9f59b587fFf1a5B44dbb2f + // Harmony - 8.93 MKR - 0xF4704Aa4Ad22cAA2A3Dd7A7C529B4C32f7A421F2 + // JAG - 7.61 MKR - 0x58D1ec57E4294E4fe650D1CB12b96AE34349556f + // Cloaky - 4.30 MKR - 0x869b6d5d8FA7f4FFdaCA4D23FFE0735c5eD1F818 + // Skynet - 3.64 MKR - 0xd4d1A446cD5976a11bd32D3e815A9F85FED2F9F3 + + // ---------- Old D3M Parameter Housekeeping ---------- + // Forum: https://forum.makerdao.com/t/notice-of-executive-vote-date-change-and-housekeeping-changes/21613 + // NOTE: ignore on goerli + + // Remove DIRECT-AAVEV2-DAI from autoline + // Set DIRECT-AAVEV2-DAI Debt Ceiling to 0 + // Remove DIRECT-COMPV2-DAI from autoline + // Set DIRECT-COMPV2-DAI Debt Ceiling to 0 + // Reduce Global Debt Ceiling? Yes + + // ---------- New Silver Parameter Changes ---------- // Forum: https://forum.makerdao.com/t/rwa-002-new-silver-restructuring-risk-and-legal-assessment/21417 + // Poll: https://vote.makerdao.com/polling/QmaU1eaD#poll-detail - // Update doc to QmTrrwZpnSZ41rbrpx267R7vfDFktseQe2W5NJ5xB7kkn1 - _updateDoc("RWA002-A", "QmTrrwZpnSZ41rbrpx267R7vfDFktseQe2W5NJ5xB7kkn1"); - - // ----- AVC Member Compensation ----- - // Forum: https://forum.makerdao.com/t/avc-member-participation-rewards-q2-2023/21459 - // NOTE: ignore on Goerli - - // IamMeeoh - 14.90 MKR - 0x47f7A5d8D27f259582097E1eE59a07a816982AE9 - // ACRE DAOs - 14.90 MKR - 0xBF9226345F601150F64Ea4fEaAE7E40530763cbd - // Space Xponential - 11.92 MKR - 0xFF8eEB643C5bfDf6A925f2a5F9aDC9198AF07b78 - // Res - 14.90 MKR - 0x8c5c8d76372954922400e4654AF7694e158AB784 - // LDF - 11.92 MKR - 0xC322E8Ec33e9b0a34c7cD185C616087D9842ad50 - // opensky - 14.90 MKR - 0x8e67ee3bbeb1743dc63093af493f67c3c23c6f04 - // David Phelps - 8.94 MKR - 0xd56e3E325133EFEd6B1687C88571b8a91e517ab0 - // seedlatam.eth - 11.92 MKR - 0x0087a081a9b430fd8f688c6ac5dd24421bfb060d - // StableLab - 14.9 MKR - 0xbDE65cf2352ed1Dde959f290E973d0fC5cEDFD08 - // flipsidegov - 14.9 MKR - 0x300901243d6CB2E74c10f8aB4cc89a39cC222a29 - - // ----- Launch Project Funding ----- - // Forum: https://forum.makerdao.com/t/utilization-of-the-launch-project-under-the-accessibility-scope/21468 - // NOTE: ignore on Goerli - - // Launch Project - 2,000,000 DAI - 0x3C5142F28567E6a0F172fd0BaaF1f2847f49D02F + // Increase RWA002-A Debt Ceiling by 30 million DAI from 20 million DAI to 50 million DAI + DssExecLib.increaseIlkDebtCeiling( + "RWA002-A", + 30 * MILLION, + true // Increase global Line + ); - // ----- Trigger Spark Proxy Spell ----- - // Poll: https://vote.makerdao.com/polling/QmZyFH21 - // Forum: https://forum.makerdao.com/t/phoenix-labs-proposed-changes-for-spark/21422 + // Increase RWA002-A Stability Fee by 3.5% from 3.5% to 7% + DssExecLib.setIlkStabilityFee("RWA002-A", SEVEN_PCT_RATE, /* doDrip = */ true); - // Trigger Spark Proxy Spell at 0xEd3BF79737d3A469A29a7114cA1084e8340a2f20 (goerli) - ProxyLike(SUBPROXY_SPARK).exec(SPARK_SPELL, abi.encodeWithSignature("execute()")); + // Reduce Liquidation Ratio by 5% from 105% to 100% + // Forum: https://forum.makerdao.com/t/notice-of-executive-vote-date-change-and-housekeeping-changes/21613 + DssExecLib.setIlkLiquidationRatio("RWA002-A", 100_00); - // ----- Housekeeping ----- + // Bump Oracle price to account for new DC and SF + // NOTE: the formula is `Debt ceiling * [ (1 + RWA stability fee ) ^ (minimum deal duration in years) ] * liquidation ratio` + // Since RWA002-A Termination Date is `October 11, 2032`, and spell execution time is `2023-08-18`, the distance is `3342` days + // bc -l <<< 'scale=18; 50000000 * e(l(1.07) * (3342/365)) * 1.00' | cast --to-wei + RwaLiquidationLike(MIP21_LIQUIDATION_ORACLE).bump( + "RWA002-A", + 92_899_355_926924134500000000 + ); - // Remove SUBPROXY_SPARK from the chainlog on Goerli. - // Github Discussion: https://github.com/makerdao/spells-mainnet/pull/346#issuecomment-1591198793 - // Since this was added by mistake, we should not bump the version in the Chainlog. - ChainlogLike(DssExecLib.LOG).removeAddress("SUBPROXY_SPARK"); + // NOTE: Update collateral price to propagate the changes + DssExecLib.updateCollateralPrice("RWA002-A"); + + // ---------- Transfer Spark Proxy Admin Controls ---------- + // Forum: https://forum.makerdao.com/t/phoenix-labs-proposed-changes-for-spark-for-august-18th-spell/21612 + // Poll: https://vote.makerdao.com/polling/Qmc9fd3j + + TransferOwnershipLike(SPARK_TREASURY_CONTROLLER).transferOwnership(SPARK_PROXY); + ChangeAdminLike(SPARK_TREASURY).changeAdmin(SPARK_PROXY); + ChangeAdminLike(SPARK_TREASURY_DAI).changeAdmin(SPARK_PROXY); + ChangeAdminLike(SPARK_INCENTIVES).changeAdmin(SPARK_PROXY); + TransferOwnershipLike(SPARK_WETH_GATEWAY).transferOwnership(SPARK_PROXY); + ACLManagerLike(SPARK_ACL_MANAGER).addEmergencyAdmin(SPARK_PROXY); + ACLManagerLike(SPARK_ACL_MANAGER).removeEmergencyAdmin(address(this)); + ACLManagerLike(SPARK_ACL_MANAGER).removePoolAdmin(address(this)); + bytes32 defaultAdminRole = ACLManagerLike(SPARK_ACL_MANAGER).DEFAULT_ADMIN_ROLE(); + ACLManagerLike(SPARK_ACL_MANAGER).grantRole(defaultAdminRole, SPARK_PROXY); + ACLManagerLike(SPARK_ACL_MANAGER).revokeRole(defaultAdminRole, address(this)); + PoolAddressProviderLike(SPARK_POOL_ADDRESS_PROVIDER).setACLAdmin(SPARK_PROXY); + TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER).transferOwnership(SPARK_PROXY); + TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER_REGISTRY).transferOwnership(SPARK_PROXY); + TransferOwnershipLike(SPARK_EMISSION_MANAGER).transferOwnership(SPARK_PROXY); + + // ---------- Trigger Spark Proxy Spell ---------- + // Forum: https://forum.makerdao.com/t/phoenix-labs-proposed-changes-for-spark-for-august-18th-spell/21612 + + // Goerli - 0x13176ad78ec3d2b6e32908b019d0f772ec0b4dfd + ProxyLike(SPARK_PROXY).exec(SPARK_SPELL, abi.encodeWithSignature("execute()")); } } diff --git a/src/DssSpell.t.sol b/src/DssSpell.t.sol index b3fab489..e6da92da 100644 --- a/src/DssSpell.t.sol +++ b/src/DssSpell.t.sol @@ -41,10 +41,44 @@ interface RwaLiquidationOracleLike { function good(bytes32 ilk) external view returns (bool); } +interface RwaUrnLike { + function vat() external view returns (address); + function jug() external view returns (address); + function daiJoin() external view returns (address); + function outputConduit() external view returns (address); + function wards(address) external view returns (uint256); + function hope(address) external; + function can(address) external view returns (uint256); + function gemJoin() external view returns (address); + function lock(uint256) external; + function draw(uint256) external; + function wipe(uint256) external; + function free(uint256) external; +} + interface ProxyLike { function exec(address target, bytes calldata args) external payable returns (bytes memory out); } +interface TransferOwnershipLike { + function owner() external view returns (address); +} + +interface ChangeAdminLike { + function admin() external view returns (address); +} + +interface ACLManagerLike { + function DEFAULT_ADMIN_ROLE() external view returns (bytes32); + function isEmergencyAdmin(address admin) external view returns (bool); + function isPoolAdmin(address admin) external view returns (bool); + function hasRole(bytes32 role, address account) external view returns (bool); +} + +interface PoolAddressProviderLike { + function getACLAdmin() external view returns (address); +} + contract DssSpellTest is DssSpellTestBase { using stdStorage for StdStorage; @@ -114,11 +148,9 @@ contract DssSpellTest is DssSpellTestBase { _testChainlogValues(); } - // FIXME: This test was disabled for environment syncing purposes. Re-enable it in the next spell. - function testChainlogVersionBump() private { + function testChainlogVersionBump() public { _testChainlogVersionBump(); } - // END OF TESTS THAT SHOULD BE RUN ON EVERY SPELL function testOsmAuth() private { // make private to disable // address ORACLE_WALLET01 = 0x4D6fbF888c374D7964D56144dE0C0cFBd49750D3; @@ -175,12 +207,12 @@ contract DssSpellTest is DssSpellTestBase { //assertEq(OsmAbstract(0xF15993A5C5BE496b8e1c9657Fd2233b579Cd3Bc6).wards(ORACLE_WALLET01), 1); } - function testRemoveChainlogValues() public { // make private to disable + function testRemoveChainlogValues() private { // make private to disable _vote(address(spell)); _scheduleWaitAndCast(address(spell)); assertTrue(spell.done()); - try chainLog.getAddress("SUBPROXY_SPARK") { + try chainLog.getAddress("INSERT_DELETED_CHAINLOG_KEY_HERE") { assertTrue(false); } catch Error(string memory errmsg) { assertTrue(_cmpStr(errmsg, "dss-chain-log/invalid-key")); @@ -273,12 +305,7 @@ contract DssSpellTest is DssSpellTestBase { _scheduleWaitAndCast(address(spell)); assertTrue(spell.done()); - _checkChainlogKey("PIP_MKR"); - _checkChainlogKey("MCD_FLAP"); - _checkChainlogKey("FLAPPER_MOM"); - - _checkChainlogKey("RWA015_A_OUTPUT_CONDUIT"); - + _checkChainlogKey("INSERT_NEW_CHAINLOG_KEY_HERE"); _checkChainlogVersion("1.15.0"); } @@ -511,17 +538,76 @@ contract DssSpellTest is DssSpellTestBase { assertEq(arbitrumGateway.validDomains(arbDstDomain), 0, "l2-arbitrum-invalid-dst-domain"); } - // Spark Tests + // RWA tests + function test_RWA002_Update() public { + // Read the pip address + (,address pip,, ) = liquidationOracle.ilks("RWA002-A"); + + // Load RWA002-A output conduit address + address conduit = addr.addr("RWA002_A_OUTPUT_CONDUIT"); + + // Check the conduit balance is 0 before cast + assertEq(dai.balanceOf(address(conduit)), 0); + + _vote(address(spell)); + _scheduleWaitAndCast(address(spell)); + assertTrue(spell.done()); + + // Read the pip address and spot value after cast, as well as Art and rate + (uint256 Art, uint256 rate, uint256 spotAfter, uint256 line,) = vat.ilks("RWA002-A"); + + // Check the pip and spot values after cast + assertEq(uint256(DSValueAbstract(pip).read()), 92_899_355_926924134500000000, "RWA002: Bad PIP value after bump()"); + assertEq(spotAfter, 92_899_355_926924134500000000 * (RAY / WAD), "RWA002: Bad spot value after bump()"); + // Test that a draw() can be performed + address urn = addr.addr("RWA002_A_URN"); + // Give ourselves operator status, noting that setWard() has replaced giveAuth() + GodMode.setWard(urn, address(this), 1); + RwaUrnLike(urn).hope(address(this)); + + // Calculate how much 'room' we can draw to get close to line + uint256 room = line - (Art * rate); + uint256 drawAmt = room / RAY; + + // Correct our draw amount if it is too large + if ((_divup((drawAmt * RAY), rate) * rate) > room) { + drawAmt = (room - rate) / RAY; + } + + // NOTE: only on goerli, remove on mainnet + // This fix is needed becuause RWA002 was never locked into RwaUrn on Goerli + GodMode.setBalance(addr.addr("RWA002"), address(this), 1 * WAD); + GemAbstract(addr.addr("RWA002")).approve(urn, 1 * WAD); + RwaUrnLike(urn).lock(1 * WAD); + + // Check if RWA002 is locked into the RwaUrn + (uint256 ink,) = vat.urns("RWA002-A", urn); + assertEq(ink, 1 * WAD, "RWA002: bad ink in RwaUrn"); + + // Perform draw() + RwaUrnLike(urn).draw(drawAmt); + + // Check the conduit balance after cast + assertEq(dai.balanceOf(address(conduit)), drawAmt); + + // Read new Art + (Art,,,,) = vat.ilks("RWA002-A"); + + // Assert that we are within 2 `rate` of line + assertTrue(line - (Art * rate) < (2 * rate)); + } + + // Spark Tests function testSparkSpellIsExecuted() public { // make private to disable - address SUBPROXY_SPARK = 0x4e847915D8a9f2Ab0cDf2FC2FD0A30428F25665d; - address SPARK_SPELL = 0xEd3BF79737d3A469A29a7114cA1084e8340a2f20; + address SPARK_PROXY = 0x4e847915D8a9f2Ab0cDf2FC2FD0A30428F25665d; + address SPARK_SPELL = 0x13176Ad78eC3d2b6E32908B019D0F772EC0b4dFd; vm.expectCall( - SUBPROXY_SPARK, + SPARK_PROXY, /* value = */ 0, abi.encodeCall( - ProxyLike(SUBPROXY_SPARK).exec, + ProxyLike(SPARK_PROXY).exec, (SPARK_SPELL, abi.encodeWithSignature("execute()")) ) ); @@ -531,26 +617,70 @@ contract DssSpellTest is DssSpellTestBase { assertTrue(spell.done()); } - // RWA Tests + function testSparkAdminTransfer() public { + address SPARK_PROXY = 0x4e847915D8a9f2Ab0cDf2FC2FD0A30428F25665d; + address SPARK_TREASURY_CONTROLLER = 0x98e6BcBA7d5daFbfa4a92dAF08d3d7512820c30C; + address SPARK_TREASURY = 0x0D56700c90a690D8795D6C148aCD94b12932f4E3; + address SPARK_TREASURY_DAI = 0x44816381990B6613c7A96ca1937f3902D8eA3F5b; + address SPARK_INCENTIVES = 0xF028c2F4b19898718fD0F77b9b881CbfdAa5e8Bb; + address SPARK_WETH_GATEWAY = 0xe6fC577E87F7c977c4393300417dCC592D90acF8; + address SPARK_ACL_MANAGER = 0xb137E7d16564c81ae2b0C8ee6B55De81dd46ECe5; + address SPARK_POOL_ADDRESS_PROVIDER = 0x026a5B6114431d8F3eF2fA0E1B2EDdDccA9c540E; + address SPARK_POOL_ADDRESS_PROVIDER_REGISTRY = 0x1ad570fDEA255a3c1d8Cf56ec76ebA2b7bFDFfea; + address SPARK_EMISSION_MANAGER = 0xA7F8A757C4f7696c015B595F51B2901AC0121B18; - RwaLiquidationOracleLike oracle = RwaLiquidationOracleLike(addr.addr("MIP21_LIQUIDATION_ORACLE")); + bytes32 defaultAdminRole = ACLManagerLike(SPARK_ACL_MANAGER).DEFAULT_ADMIN_ROLE(); - function testRWA002DocChange() public { - string memory OLD_RWA002_DOC = "QmdfuQSLmNFHoxvMjXvv8qbJ2NWprrsvp5L3rGr3JHw18E"; - string memory NEW_RWA002_DOC = "QmTrrwZpnSZ41rbrpx267R7vfDFktseQe2W5NJ5xB7kkn1"; + assertEq(TransferOwnershipLike(SPARK_TREASURY_CONTROLLER).owner(), pauseProxy); - _checkRWADocUpdate("RWA002-A", OLD_RWA002_DOC, NEW_RWA002_DOC); - } + // Transparent proxy dictates that admin() function is only exposed to the admin + vm.startPrank(pauseProxy); + + assertEq(ChangeAdminLike(SPARK_TREASURY).admin(), pauseProxy); + assertEq(ChangeAdminLike(SPARK_TREASURY_DAI).admin(), pauseProxy); + assertEq(ChangeAdminLike(SPARK_INCENTIVES).admin(), pauseProxy); + + vm.stopPrank(); + + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).isEmergencyAdmin(pauseProxy)); + assertTrue(!ACLManagerLike(SPARK_ACL_MANAGER).isEmergencyAdmin(SPARK_PROXY)); + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).isPoolAdmin(pauseProxy)); + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).isPoolAdmin(SPARK_PROXY)); // Already added from previous spell + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).hasRole(defaultAdminRole, pauseProxy)); + assertTrue(!ACLManagerLike(SPARK_ACL_MANAGER).hasRole(defaultAdminRole, SPARK_PROXY)); + + assertEq(TransferOwnershipLike(SPARK_WETH_GATEWAY).owner(), pauseProxy); + assertEq(PoolAddressProviderLike(SPARK_POOL_ADDRESS_PROVIDER).getACLAdmin(), pauseProxy); + assertEq(TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER).owner(), pauseProxy); + assertEq(TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER_REGISTRY).owner(), pauseProxy); + assertEq(TransferOwnershipLike(SPARK_EMISSION_MANAGER).owner(), pauseProxy); - function testRWA004OracleTell() public { _vote(address(spell)); _scheduleWaitAndCast(address(spell)); assertTrue(spell.done()); - (, , uint tau, uint toc) = oracle.ilks("RWA004-A"); - assertGt(toc, 0, "RWA004-A: bad `toc` after `tell()`"); + assertEq(TransferOwnershipLike(SPARK_TREASURY_CONTROLLER).owner(), SPARK_PROXY); + + // Transparent proxy dictates that admin() function is only exposed to the admin + vm.startPrank(SPARK_PROXY); + + assertEq(ChangeAdminLike(SPARK_TREASURY).admin(), SPARK_PROXY); + assertEq(ChangeAdminLike(SPARK_TREASURY_DAI).admin(), SPARK_PROXY); + assertEq(ChangeAdminLike(SPARK_INCENTIVES).admin(), SPARK_PROXY); + + vm.stopPrank(); + + assertTrue(!ACLManagerLike(SPARK_ACL_MANAGER).isEmergencyAdmin(pauseProxy)); + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).isEmergencyAdmin(SPARK_PROXY)); + assertTrue(!ACLManagerLike(SPARK_ACL_MANAGER).isPoolAdmin(pauseProxy)); + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).isPoolAdmin(SPARK_PROXY)); + assertTrue(!ACLManagerLike(SPARK_ACL_MANAGER).hasRole(defaultAdminRole, pauseProxy)); + assertTrue(ACLManagerLike(SPARK_ACL_MANAGER).hasRole(defaultAdminRole, SPARK_PROXY)); - skip(tau); - assertEq(oracle.good("RWA004-A"), false, "RWA004-A: still `good` after `tell()` + `tau`"); + assertEq(TransferOwnershipLike(SPARK_WETH_GATEWAY).owner(), SPARK_PROXY); + assertEq(PoolAddressProviderLike(SPARK_POOL_ADDRESS_PROVIDER).getACLAdmin(), SPARK_PROXY); + assertEq(TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER).owner(), SPARK_PROXY); + assertEq(TransferOwnershipLike(SPARK_POOL_ADDRESS_PROVIDER_REGISTRY).owner(), SPARK_PROXY); + assertEq(TransferOwnershipLike(SPARK_EMISSION_MANAGER).owner(), SPARK_PROXY); } } diff --git a/src/test/config.sol b/src/test/config.sol index f29eb6fa..8fce9aa3 100644 --- a/src/test/config.sol +++ b/src/test/config.sol @@ -99,9 +99,9 @@ contract Config { // Values for spell-specific parameters // spellValues = SpellValues({ - deployed_spell: address(0x4Ca8451B5a598aba0160F35505402fad9713fb0c), // populate with deployed spell if deployed - deployed_spell_created: 1691061516, // use `make deploy-info tx=` to obtain the timestamp - deployed_spell_block: 9455398, // use `make deploy-info tx=` to obtain the block number + deployed_spell: address(0x341281316C53a6c9b099581C9f87665FA5815090), // populate with deployed spell if deployed + deployed_spell_created: 1692106800, // use `make deploy-info tx=` to obtain the timestamp + deployed_spell_block: 9522321, // use `make deploy-info tx=` to obtain the block number previous_spells: prevSpells, // older spells to ensure are executed first office_hours_enabled: false, // true if officehours is expected to be enabled in the spell expiration_threshold: 30 days // Amount of time before spell expires @@ -111,15 +111,15 @@ contract Config { // Values for all system configuration changes // afterSpell.line_offset = 500 * MILLION; // Offset between the global line against the sum of local lines - afterSpell.pot_dsr = 8_00; // In basis points + afterSpell.pot_dsr = 5_00; // In basis points afterSpell.pause_delay = 60 seconds; // In seconds afterSpell.vow_wait = 156 hours; // In seconds afterSpell.vow_dump = 250; // In whole Dai units afterSpell.vow_sump = 50 * THOUSAND; // In whole Dai units - afterSpell.vow_bump = 5 * THOUSAND; // In whole Dai units + afterSpell.vow_bump = 20 * THOUSAND; // In whole Dai units afterSpell.vow_hump_min = 50 * MILLION; // In whole Dai units afterSpell.vow_hump_max = 50 * MILLION; // In whole Dai units - afterSpell.flap_hop = 1577 seconds; // In seconds + afterSpell.flap_hop = 6308 seconds; // In seconds afterSpell.flap_want = 9800; // In basis points afterSpell.cat_box = 20 * MILLION; // In whole Dai units afterSpell.dog_Hole = 70 * MILLION; // In whole Dai units @@ -146,7 +146,7 @@ contract Config { aL_ttl: 6 hours, // In seconds line: 0, // In whole Dai units // Not checked here as there is auto line dust: 7_500, // In whole Dai units - pct: 3_44, // In basis points + pct: 3_58, // In basis points mat: 14500, // In basis points liqType: "clip", // "" or "flip" or "clip" liqOn: true, // If liquidations are enabled @@ -176,7 +176,7 @@ contract Config { aL_ttl: 6 hours, line: 0, dust: 25 * THOUSAND, - pct: 3_94, + pct: 4_08, mat: 13000, liqType: "clip", liqOn: true, @@ -206,7 +206,7 @@ contract Config { aL_ttl: 8 hours, line: 0, dust: 3_500, - pct: 3_19, + pct: 3_33, mat: 17000, liqType: "clip", liqOn: true, @@ -326,7 +326,7 @@ contract Config { aL_ttl: 24 hours, line: 0, dust: 7_500, - pct: 5_69, + pct: 5_80, mat: 14500, liqType: "clip", liqOn: true, @@ -356,7 +356,7 @@ contract Config { aL_ttl: 24 hours, line: 0, dust: 25 * THOUSAND, - pct: 6_19, + pct: 6_30, mat: 13000, liqType: "clip", liqOn: true, @@ -386,7 +386,7 @@ contract Config { aL_ttl: 24 hours, line: 0, dust: 3_500, - pct: 5_44, + pct: 5_55, mat: 17500, liqType: "clip", liqOn: true, @@ -1224,10 +1224,10 @@ contract Config { aL_line: 0, aL_gap: 0, aL_ttl: 0, - line: 20 * MILLION, + line: 50 * MILLION, dust: 0, - pct: 350, - mat: 10500, + pct: 7_00, + mat: 100_00, liqType: "", liqOn: false, chop: 0, @@ -1731,12 +1731,12 @@ contract Config { }); afterSpell.collaterals["WSTETH-A"] = CollateralValues({ aL_enabled: true, - aL_line: 500 * MILLION, + aL_line: 750 * MILLION, aL_gap: 30 * MILLION, aL_ttl: 12 hours, line: 0, dust: 7_500, - pct: 3_44, + pct: 5_25, mat: 150_00, liqType: "clip", liqOn: true, @@ -1761,12 +1761,12 @@ contract Config { }); afterSpell.collaterals["WSTETH-B"] = CollateralValues({ aL_enabled: true, - aL_line: 500 * MILLION, - aL_gap: 30 * MILLION, - aL_ttl: 16 hours, + aL_line: 1 * BILLION, + aL_gap: 45 * MILLION, + aL_ttl: 12 hours, line: 0, dust: 3_500, - pct: 3_19, + pct: 5_00, mat: 175_00, liqType: "clip", liqOn: true, @@ -1970,12 +1970,12 @@ contract Config { }); afterSpell.collaterals["RETH-A"] = CollateralValues({ aL_enabled: true, - aL_line: 50 * MILLION, + aL_line: 75 * MILLION, aL_gap: 5 * MILLION, aL_ttl: 8 hours, line: 0, dust: 7_500, - pct: 3_44, + pct: 5_25, mat: 150_00, liqType: "clip", liqOn: true, diff --git a/src/test/rates.sol b/src/test/rates.sol index 0702f7fd..683c71c6 100644 --- a/src/test/rates.sol +++ b/src/test/rates.sol @@ -41,13 +41,16 @@ contract Rates { rates[ 300] = 1000000000937303470807876289; rates[ 319] = 1000000000995743377573746041; rates[ 325] = 1000000001014175731521720677; + rates[ 333] = 1000000001038735548426731741; rates[ 344] = 1000000001072474267302354182; rates[ 349] = 1000000001087798189708544327; rates[ 350] = 1000000001090862085746321732; + rates[ 358] = 1000000001115362602336059074; rates[ 374] = 1000000001164306917698440949; rates[ 375] = 1000000001167363430498603315; rates[ 394] = 1000000001225381266358479708; rates[ 400] = 1000000001243680656318820312; + rates[ 408] = 1000000001268063427242299977; rates[ 424] = 1000000001316772794769098706; rates[ 425] = 1000000001319814647332759691; rates[ 450] = 1000000001395766281313196627;