Skip to content

Commit

Permalink
Onboard multi swap conduit for RWA015-A & Cleanup old conduits (#357)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xdecr1pto committed Jul 10, 2023
1 parent 4af4b64 commit 483421a
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 14 deletions.
74 changes: 74 additions & 0 deletions src/DssSpell.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,26 @@ pragma solidity 0.8.16;
import "dss-exec-lib/DssExec.sol";
import "dss-exec-lib/DssAction.sol";

interface RwaOutputConduitLike {
function deny(address usr) external;
function hope(address usr) external;
function nope(address usr) external;
function mate(address usr) external;
function hate(address usr) external;
function kiss(address who) external;
function diss(address who) external;
function file(bytes32 what, address data) external;
function clap(address _psm) external;
}

interface RwaUrnLike {
function file(bytes32 what, address data) external;
}

interface ChainlogLike {
function removeAddress(bytes32) external;
}

interface VestLike {
function file(bytes32 what, uint256 data) external;
function create(address, uint256, uint256, uint256, uint256, address) external returns (uint256);
Expand All @@ -43,6 +63,14 @@ contract DssSpellAction is DssAction {
string public constant override description =
"2023-07-12 MakerDAO Executive Spell | Hash: TODO";

address internal immutable RWA015_A_URN = DssExecLib.getChangelogAddress("RWA015_A_URN");
address internal immutable RWA015_A_OUTPUT_CONDUIT_PAX = DssExecLib.getChangelogAddress("RWA015_A_OUTPUT_CONDUIT");
address internal immutable RWA015_A_OUTPUT_CONDUIT_USDC = DssExecLib.getChangelogAddress("RWA015_A_OUTPUT_CONDUIT_LEGACY");
address internal immutable MCD_PSM_PAX_A = DssExecLib.getChangelogAddress("MCD_PSM_PAX_A");
address internal immutable MCD_PSM_GUSD_A = DssExecLib.getChangelogAddress("MCD_PSM_GUSD_A");
address internal immutable MCD_PSM_USDC_A = DssExecLib.getChangelogAddress("MCD_PSM_USDC_A");
address internal immutable MCD_ESM = DssExecLib.esm();

// Set office hours according to the summary
function officeHours() public pure override returns (bool) {
return true;
Expand All @@ -61,6 +89,13 @@ contract DssSpellAction is DssAction {
//
// uint256 internal constant X_PCT_RATE = ;


// Operator address
address internal constant RWA015_A_OPERATOR = 0x23a10f09Fac6CCDbfb6d9f0215C795F9591D7476;
// Custody address
address internal constant RWA015_A_CUSTODY = 0x65729807485F6f7695AF863d97D62140B7d69d83;
address internal constant RWA015_A_OUTPUT_CONDUIT = 0x1E86CB085f249772f7e7443631a87c6BDba2aCEb;

uint256 internal constant THREE_PT_ONE_NINE_PCT_RATE = 1000000000995743377573746041;
uint256 internal constant THREE_PT_FOUR_FOUR_PCT_RATE = 1000000001072474267302354182;
uint256 internal constant THREE_PT_NINE_FOUR_PCT_RATE = 1000000001225381266358479708;
Expand Down Expand Up @@ -110,6 +145,45 @@ contract DssSpellAction is DssAction {
function actions() public override {
// ----- Deploy Multiswap Conduit for RWA015-A -----

// OPERATOR permission on RWA015_A_OUTPUT_CONDUIT
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT).hope(RWA015_A_OPERATOR);
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT).mate(RWA015_A_OPERATOR);
// Custody whitelist for output conduit destination address
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT).kiss(RWA015_A_CUSTODY);
// Whitelist PSM's
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT).clap(MCD_PSM_PAX_A);
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT).clap(MCD_PSM_GUSD_A);
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT).clap(MCD_PSM_USDC_A);
// Set "quitTo" address for RWA015_A_OUTPUT_CONDUIT
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT).file("quitTo", RWA015_A_URN);
// Route URN to new conduit
RwaUrnLike(RWA015_A_URN).file("outputConduit", RWA015_A_OUTPUT_CONDUIT);
// Additional ESM authorization
DssExecLib.authorize(RWA015_A_OUTPUT_CONDUIT, MCD_ESM);

DssExecLib.setChangelogAddress("RWA015_A_OUTPUT_CONDUIT", RWA015_A_OUTPUT_CONDUIT);

// Unwind Permissions from old Conduits and remove them from Chainlog

// Revoke permissions on RWA015_A_OUTPUT_CONDUIT_PAX
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_PAX).nope(RWA015_A_OPERATOR);
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_PAX).hate(RWA015_A_OPERATOR);
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_PAX).diss(RWA015_A_CUSTODY);
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_PAX).file("quitTo", address(0));
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_PAX).deny(MCD_ESM);
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_PAX).deny(address(this));

// Revoke permissions on RWA015_A_OUTPUT_CONDUIT_USDC
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_USDC).nope(RWA015_A_OPERATOR);
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_USDC).hate(RWA015_A_OPERATOR);
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_USDC).diss(RWA015_A_CUSTODY);
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_USDC).file("quitTo", address(0));
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_USDC).deny(MCD_ESM);
RwaOutputConduitLike(RWA015_A_OUTPUT_CONDUIT_USDC).deny(address(this));

// Remove Legacy Conduit From Chainlog
ChainlogLike(DssExecLib.LOG).removeAddress("RWA015_A_OUTPUT_CONDUIT_LEGACY");

// ----- Deploy FlapperUniV2 -----

// ----- Scope Defined Parameter Changes -----
Expand Down
154 changes: 142 additions & 12 deletions src/DssSpell.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,30 @@ interface BridgeLike {
function l2TeleportGateway() external view returns (address);
}

interface RwaUrnLike {
function outputConduit() external view returns (address);
function can(address) external view returns (uint256);
function draw(uint256) external;
}

interface RwaOutputConduitLike {
function wards(address) external view returns (uint256);
function can(address) external view returns (uint256);
function may(address) external view returns (uint256);
function pal(address) external view returns (uint256);
function bud(address) external view returns (uint256);
function dai() external view returns (address);
function gem() external view returns (address);
function mate(address) external;
function hope(address) external;
function kiss(address) external;
function hook(address) external;
function quitTo() external view returns (address);
function pick(address) external;
function push(uint256) external;
function quit() external;
}

contract DssSpellTest is DssSpellTestBase {
string config;
RootDomain rootDomain;
Expand Down Expand Up @@ -163,18 +187,18 @@ contract DssSpellTest is DssSpellTestBase {
//assertEq(OsmAbstract(0xF15993A5C5BE496b8e1c9657Fd2233b579Cd3Bc6).wards(ORACLE_WALLET01), 1);
}

function testRemoveChainlogValues() private { // make private to disable
function testRemoveChainlogValues() public { // make private to disable
_vote(address(spell));
_scheduleWaitAndCast(address(spell));
assertTrue(spell.done());

// try chainLog.getAddress("RWA007_A_INPUT_CONDUIT_URN") {
// assertTrue(false);
// } catch Error(string memory errmsg) {
// assertTrue(cmpStr(errmsg, "dss-chain-log/invalid-key"));
// } catch {
// assertTrue(false);
// }
try chainLog.getAddress("RWA015_A_OUTPUT_CONDUIT_LEGACY") {
assertTrue(false);
} catch Error(string memory errmsg) {
assertTrue(_cmpStr(errmsg, "dss-chain-log/invalid-key"));
} catch {
assertTrue(false);
}
}

function testCollateralIntegrations() private { // make private to disable
Expand Down Expand Up @@ -257,15 +281,13 @@ contract DssSpellTest is DssSpellTestBase {
assertTrue(lerp.done());
}

function testNewChainlogValues() private { // make private to disable
function testNewChainlogValues() public { // make private to disable
_vote(address(spell));
_scheduleWaitAndCast(address(spell));
assertTrue(spell.done());

// Insert new chainlog values tests here
_checkChainlogKey("XXX");

_checkChainlogVersion("1.X.X");
_checkChainlogKey("RWA015_A_OUTPUT_CONDUIT");
}

function testNewIlkRegistryValues() private { // make private to disable
Expand Down Expand Up @@ -852,5 +874,113 @@ contract DssSpellTest is DssSpellTestBase {
(Art,,,,) = vat.ilks("GUSD-A");
assertEq(Art, 0, "GUSD-A Art is not 0");
}

// RWA tests

address RWA015_A_OPERATOR = addr.addr("RWA015_A_OPERATOR");
address RWA015_A_CUSTODY = addr.addr("RWA015_A_CUSTODY");
address MCD_PSM_PAX_A = addr.addr("MCD_PSM_PAX_A");
address MCD_PSM_GUSD_A = addr.addr("MCD_PSM_GUSD_A");
address MCD_PSM_USDC_A = addr.addr("MCD_PSM_USDC_A");

RwaUrnLike rwa015AUrn = RwaUrnLike(addr.addr("RWA015_A_URN"));
RwaOutputConduitLike rwa015AOutputConduit = RwaOutputConduitLike(addr.addr("RWA015_A_OUTPUT_CONDUIT"));

function testRWA015_OUTPUT_CONDUIT_DEPLOYMENT_SETUP() public {
assertEq(rwa015AOutputConduit.dai(), addr.addr("MCD_DAI"), "output-conduit-dai-not-match");
}

function testRWA015_INTEGRATION_CONDUITS_SETUP() public {
_vote(address(spell));
_scheduleWaitAndCast(address(spell));
assertTrue(spell.done());

assertEq(rwa015AUrn.outputConduit(), address(rwa015AOutputConduit), "RwaUrn/urn-outputconduit-not-match");

assertEq(rwa015AOutputConduit.wards(pauseProxy), 1, "OutputConduit/ward-pause-proxy-not-set");
assertEq(rwa015AOutputConduit.wards(address(esm)), 1, "OutputConduit/ward-esm-not-set");
assertEq(rwa015AOutputConduit.can(pauseProxy), 0, "OutputConduit/pause-proxy-hoped");
assertEq(rwa015AOutputConduit.can(RWA015_A_OPERATOR), 1, "OutputConduit/operator-not-hope");
assertEq(rwa015AOutputConduit.may(pauseProxy), 0, "OutputConduit/pause-proxy-mated");
assertEq(rwa015AOutputConduit.may(RWA015_A_OPERATOR), 1, "OutputConduit/operator-not-mate");
assertEq(rwa015AOutputConduit.bud(RWA015_A_CUSTODY), 1, "OutputConduit/destination-address-not-whitelisted-for-pick");
assertEq(rwa015AOutputConduit.pal(MCD_PSM_PAX_A), 1, "OutputConduit/pax-psm-address-not-whitelisted-for-hook");
assertEq(rwa015AOutputConduit.pal(MCD_PSM_GUSD_A), 1, "OutputConduit/gusd-a-address-not-whitelisted-for-hook");
assertEq(rwa015AOutputConduit.pal(MCD_PSM_USDC_A), 1, "OutputConduit/usdc-psm-address-not-whitelisted-for-hook");
assertEq(rwa015AOutputConduit.quitTo(), address(rwa015AUrn), "OutputConduit/quit-to-not-urn");
}

function testRWA015_REVOKE_OLD_CONDUITS_PERMISSIONS() public {
address RWA015_OUTPUT_CONDUIT_PAX = chainLog.getAddress("RWA015_A_OUTPUT_CONDUIT");
address RWA015_OUTPUT_CONDUIT_USDC = chainLog.getAddress("RWA015_A_OUTPUT_CONDUIT_LEGACY");

_vote(address(spell));
_scheduleWaitAndCast(address(spell));
assertTrue(spell.done());

assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_PAX).wards(pauseProxy), 0, "OutputConduit/ward-pause-proxy-relied");
assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_PAX).wards(address(esm)), 0, "OutputConduit/ward-esm-relied");
assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_PAX).can(RWA015_A_OPERATOR), 0, "OutputConduit/operator-hoped");
assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_PAX).may(RWA015_A_OPERATOR), 0, "OutputConduit/operator-mated");
assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_PAX).bud(RWA015_A_CUSTODY), 0, "OutputConduit/destination-address-whitelisted-for-pick");
assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_PAX).quitTo(), address(0), "OutputConduit/quit-to-not-zero");

assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_USDC).wards(pauseProxy), 0, "OutputConduit/ward-pause-proxy-relied");
assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_USDC).wards(address(esm)), 0, "OutputConduit/ward-esm-relied");
assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_USDC).can(RWA015_A_OPERATOR), 0, "OutputConduit/operator-hoped");
assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_USDC).may(RWA015_A_OPERATOR), 0, "OutputConduit/operator-mated");
assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_USDC).bud(RWA015_A_CUSTODY), 0, "OutputConduit/destination-address-whitelisted-for-pick");
assertEq(RwaOutputConduitLike(RWA015_OUTPUT_CONDUIT_USDC).quitTo(), address(0), "OutputConduit/quit-to-not-zero");
}

function testRWA015_OPERATOR_DRAW_CONDUIT_PUSH() public {
_vote(address(spell));
_scheduleWaitAndCast(address(spell));
assertTrue(spell.done());

uint256 drawAmount = 1_000_000 * WAD;

// Increas line of RWA015 to be able to draw some DAI
(,,,uint256 line,) = vat.ilks("RWA015-A");
GodMode.setWard(address(vat), address(this), 1);
vat.file("RWA015-A", "line", line + 1_000_000 * RAD);

// setting address(this) as operator
vm.store(address(rwa015AUrn), keccak256(abi.encode(address(this), uint256(1))), bytes32(uint256(1)));
assertEq(rwa015AUrn.can(address(this)), 1);

// 0 DAI in Output Conduit
assertEq(dai.balanceOf(address(rwa015AOutputConduit)), 0, "RWA015-A: Dangling Dai in input conduit before draw()");

// Draw 1m to test output conduit
rwa015AUrn.draw(drawAmount);

// DAI in Output Conduit
assertEq(dai.balanceOf(address(rwa015AOutputConduit)), drawAmount, "RWA015-A: Dai drawn was not send to the recipient");

// wards
GodMode.setWard(address(rwa015AOutputConduit), address(this), 1);
// may
rwa015AOutputConduit.mate(address(this));
assertEq(rwa015AOutputConduit.may(address(this)), 1);
rwa015AOutputConduit.hope(address(this));
assertEq(rwa015AOutputConduit.can(address(this)), 1);

rwa015AOutputConduit.kiss(address(this));
assertEq(rwa015AOutputConduit.bud(address(this)), 1);
rwa015AOutputConduit.pick(address(this));
rwa015AOutputConduit.hook(MCD_PSM_USDC_A);

GemAbstract psmGem = GemAbstract(rwa015AOutputConduit.gem());
uint256 daiPsmGemDiffDecimals = 10**(18 - uint256(psmGem.decimals()));

uint256 pushAmount = drawAmount;
rwa015AOutputConduit.push(pushAmount);
rwa015AOutputConduit.quit();

assertEq(dai.balanceOf(address(rwa015AOutputConduit)), 0, "RWA015-A: Output conduit still holds Dai after quit()");
assertEq(psmGem.balanceOf(address(this)), pushAmount / daiPsmGemDiffDecimals, "RWA015-A: Psm GEM not sent to destination after push()");
assertEq(dai.balanceOf(address(rwa015AOutputConduit)), drawAmount - pushAmount, "RWA015-A: Dai not sent to destination after push()");
}
}

3 changes: 1 addition & 2 deletions src/test/addresses_mainnet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,7 @@ contract Addresses {
addr["RWA015_A_JAR"] = 0xc27C3D3130563C1171feCC4F76C217Db603997cf;
addr["RWA015_A_INPUT_CONDUIT_URN"] = 0xe08cb5E24862eA86328295D5E5c08972203C20D8;
addr["RWA015_A_INPUT_CONDUIT_JAR"] = 0xB9373C557f3aE8cDdD068c1644ED226CfB18A997;
addr["RWA015_A_OUTPUT_CONDUIT"] = 0x1a976926bF6105Ff6dA1F7b1667bBe825974961E;
addr["RWA015_A_OUTPUT_CONDUIT_LEGACY"] = 0xC35E60736ec2E3de612535dba2dFB1f4130C82c3;
addr["RWA015_A_OUTPUT_CONDUIT"] = 0x1E86CB085f249772f7e7443631a87c6BDba2aCEb;
addr["RWA015_A_OPERATOR"] = 0x23a10f09Fac6CCDbfb6d9f0215C795F9591D7476;
addr["RWA015_A_CUSTODY"] = 0x65729807485F6f7695AF863d97D62140B7d69d83;
addr["GUNIV3DAIUSDC1"] = 0xAbDDAfB225e10B90D798bB8A886238Fb835e2053;
Expand Down

0 comments on commit 483421a

Please sign in to comment.