Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mainnet spell 2024-07-25 #417

Merged
merged 24 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0c1f14a
chore: cleanup previous spell
amusingaxl Jul 19, 2024
d80e239
feat: add contents from exec sheet
amusingaxl Jul 19, 2024
2ce718c
test: add test coverage for spell items
amusingaxl Jul 19, 2024
bcc5f1a
refactor: address further review comments
amusingaxl Jul 22, 2024
acaac1e
test: add missing test coverage for cronjob
amusingaxl Jul 22, 2024
c6b4185
chore: alignment adjustments
amusingaxl Jul 22, 2024
64def4b
refactor: reorganize items to match exec sheet order
amusingaxl Jul 22, 2024
a0cfb6e
fix: remove trailing comma
amusingaxl Jul 22, 2024
24c213b
refactor: reorg spell action internal structure
amusingaxl Jul 23, 2024
cdc1904
refactor: address remaining review items
amusingaxl Jul 23, 2024
c51a01b
refactor: adjust items description to match latest exec sheet
amusingaxl Jul 23, 2024
e06339b
chore: add exec hash
amusingaxl Jul 23, 2024
586e4ec
chore: address remaining review comments
amusingaxl Jul 23, 2024
a92a49b
tests: add coverage for LitePSM jar
amusingaxl Jul 24, 2024
301d75b
chore: fix broken alignment [skip ci]
amusingaxl Jul 24, 2024
6be0945
refactor: fix struct name
amusingaxl Jul 24, 2024
b30e456
fix: add misssing empty line above instruction [ci skip]
amusingaxl Jul 24, 2024
6d01c2b
feat: add ESM authorization for input conduit
amusingaxl Jul 24, 2024
40e8623
chore: remove outdated exec doc hash
amusingaxl Jul 24, 2024
e98255e
chore: add updated exec doc link and hash [ci skip]
amusingaxl Jul 24, 2024
f685cec
tests: add missing coverage for cronjob test
amusingaxl Jul 25, 2024
2a714a7
add deployed spell info
amusingaxl Jul 25, 2024
1192dd3
chore: archive spell
amusingaxl Jul 25, 2024
f750e59
fix: wrong archive date
amusingaxl Jul 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 113 additions & 97 deletions src/DssSpell.sol

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/DssSpell.t.base.sol
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ contract DssSpellTestBase is Config, DssTest {
{
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");
assertTrue(esm.min() > WAD && esm.min() < 400 * THOUSAND * WAD, "TestError/esm-min-range");
amusingaxl marked this conversation as resolved.
Show resolved Hide resolved
}

// check Pause authority
Expand Down
219 changes: 208 additions & 11 deletions src/DssSpell.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,43 @@ interface SpellActionLike {
function dao_resolutions() external view returns (string memory);
}

interface NetworkPaymentAdapterLike {
function treasury() external view returns (address);
interface DssCronSequencerLike {
function hasJob(address) external view returns (bool);
}

interface LitePsmJobLike {
function cutThreshold() external view returns (uint256);
function gushThreshold() external view returns (uint256);
function litePsm() external view returns (address);
function rushThreshold() external view returns (uint256);
function sequencer() external view returns (address);
}

interface LitePsmMomLike {
function authority() external view returns (address);
}

interface PsmLike {
function gemJoin() external view returns (address);
function tin() external view returns (uint256);
function tout() external view returns (uint256);
function vow() external view returns (address);
}

interface LitePsmLike {
function bud(address) external view returns (uint256);
function buf() external view returns (uint256);
function pocket() external view returns (address);
function to18ConversionFactor() external view returns (uint256);
function vow() external view returns (address);
function wards(address) external view returns (uint256);
}

interface GemLike {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint256);
function balanceOf(address) external view returns (uint256);
}

contract DssSpellTest is DssSpellTestBase {
Expand Down Expand Up @@ -408,7 +443,7 @@ contract DssSpellTest is DssSpellTestBase {
uint256 amount;
}

function testDAIPayments() public { // add the `skipped` modifier to skip
function testDAIPayments() public skipped { // add the `skipped` modifier to skip
// For each payment, create a Payee object with
// the Payee address,
// the amount to be paid in whole Dai units
Expand Down Expand Up @@ -591,7 +626,7 @@ contract DssSpellTest is DssSpellTestBase {
}
}

function testMKRPayments() public { // add the `skipped` modifier to skip
function testMKRPayments() public skipped { // add the `skipped` modifier to skip
// For each payment, create a Payee object with
// the Payee address,
// the amount to be paid
Expand Down Expand Up @@ -847,7 +882,7 @@ contract DssSpellTest is DssSpellTestBase {

function testSparkSpellIsExecuted() public { // add the `skipped` modifier to skip
address SPARK_PROXY = addr.addr('SPARK_PROXY');
address SPARK_SPELL = address(0x91824fa4fd51E8440a122ffDd49C701F5C56D58e);
address SPARK_SPELL = address(0x18427dB17D3113309a0406284aC738f4E649613B);

vm.expectCall(
SPARK_PROXY,
Expand All @@ -865,17 +900,179 @@ contract DssSpellTest is DssSpellTestBase {

// SPELL-SPECIFIC TESTS GO BELOW

function testChainlinkPaymentAdapterNewTreasury() public {
address CHAINLINK_PAYMENT_ADAPTER = wallets.addr("CHAINLINK_PAYMENT_ADAPTER");
address CHAINLINK_TREASURY_NEW = wallets.addr("CHAINLINK_TREASURY");
address CHAINLINK_TREASURY_OLD = 0xaBAbd5e7d6d05672391aB2A914F57ce343D5CFA6;
function testLitePsmJob() public {
DssCronSequencerLike sequencer = DssCronSequencerLike(addr.addr("CRON_SEQUENCER"));
LitePsmJobLike litePsmJob = LitePsmJobLike( addr.addr("CRON_LITE_PSM_JOB"));

// Sanity checks
// Sequencer matches
assertEq(litePsmJob.sequencer(), addr.addr("CRON_SEQUENCER"), "invalid sequencer");
// LitePsm matches
assertEq(litePsmJob.litePsm(), addr.addr("MCD_LITE_PSM_USDC_A"), "invalid litePsm");
// fill: Set threshold at 15M DAI
assertEq(litePsmJob.rushThreshold(), 15_000_000 * WAD, "invalid rush threshold");
// trim: Set threshold at 30M DAI
assertEq(litePsmJob.gushThreshold(), 30_000_000 * WAD, "invalid rush threshold");
// chug: Set threshold at 300k DAI
assertEq(litePsmJob.cutThreshold(), 300_000 * WAD, "invalid rush threshold");

assertTrue(!sequencer.hasJob(address(litePsmJob)));

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

assertTrue(sequencer.hasJob(address(litePsmJob)));
}

uint256 constant REG_CLASS_JOINLESS = 6;
bytes32 constant SRC_ILK = "PSM-USDC-A";
bytes32 constant DST_ILK = "LITE-PSM-USDC-A";
LitePsmMomLike immutable litePsmMom = LitePsmMomLike(addr.addr("LITE_PSM_MOM"));
PsmLike immutable srcPsm = PsmLike( addr.addr("MCD_PSM_USDC_A"));
LitePsmLike immutable dstPsm = LitePsmLike( addr.addr("MCD_LITE_PSM_USDC_A"));
address immutable pocket = addr.addr("MCD_LITE_PSM_USDC_A_POCKET");
GemLike immutable gem = GemLike( addr.addr("USDC"));
address immutable pip = addr.addr("PIP_USDC");
uint256 constant dstBuf = 20_000_000 * WAD;
uint256 constant dstWant = 20_000_000 * WAD;
uint256 constant srcKeep = 200_000_000 * WAD;

function testLitePsmInit() public {
// execute spell
_vote(address(spell));
_scheduleWaitAndCast(address(spell));
assertTrue(spell.done());

// dstPsm params are properly set
assertEq(dstPsm.pocket(), pocket, "after: invalid dst pocket");
assertEq(dstPsm.buf(), dstBuf, "after: invalid dst buf");
assertEq(dstPsm.vow(), address(vow), "after: unexpected dst vow value");

// pauseProxy can execute swaps with no fees
assertEq(dstPsm.bud(address(pauseProxy)), 1, "after: MCD_PAUSE_PROXY not kissed in dstPsm");

// Mom is authed in dstPsm
assertEq(dstPsm.wards(address(litePsmMom)), 1, "after: LITE_PSM_MOM not authed in dstPsm");

// Mom authority is set to the Chief
assertEq(litePsmMom.authority(), address(chief), "after: chief not set as the authority of LITE_PSM_MOM");

// Vat is properly initialized
{
// litePsm is given "unlimited" ink
(uint256 dstInk, ) = vat.urns(DST_ILK, address(dstPsm));
assertEq(dstInk, type(uint256).max / RAY, "after: vat ink for dstPsm not properly set");
}

// Spotter is properly initialized
{
(address _pip,) = spotter.ilks(DST_ILK);
assertEq(_pip, pip, "after: spotter pip for DST_ILK not properly set");
}

assertTrue(NetworkPaymentAdapterLike(CHAINLINK_PAYMENT_ADAPTER).treasury() == CHAINLINK_TREASURY_OLD, "ChainLink/incorrect-treasury");
// New PSM info is added to IlkRegistry
{
(
string memory name,
string memory symbol,
uint256 _class,
uint256 decimals,
address _gem,
address _pip,
address gemJoin,
address clip
) = reg.info(DST_ILK);

assertEq(name, gem.name(), "after: reg name mismatch");
assertEq(symbol, gem.symbol(), "after: reg symbol mismatch");
assertEq(_class, REG_CLASS_JOINLESS, "after: reg class mismatch");
assertEq(decimals, gem.decimals(), "after: reg dec mismatch");
assertEq(_gem, address(gem), "after: reg gem mismatch");
assertEq(_pip, pip, "after: reg pip mismatch");
assertEq(gemJoin, address(0), "after: invalid reg gemJoin");
assertEq(clip, address(0), "after: invalid reg xlip");
}
}

function testLitePsmMigrationPhase1() public {
(uint256 psrcInk, uint256 psrcArt) = vat.urns(SRC_ILK, address(srcPsm));
(, uint256 pdstArt) = vat.urns(DST_ILK, address(dstPsm));
uint256 psrcTin = srcPsm.tin();
uint256 psrcTout = srcPsm.tout();
uint256 psrcGemBalance = gem.balanceOf(srcPsm.gemJoin());
uint256 pdstGemBalance = gem.balanceOf(dstPsm.pocket());
uint256 pvatSinPauseProxy = vat.sin(address(pauseProxy));
uint256 pvice = vat.vice();

uint256 expectedMoveWad = _min(dstWant, _subcap(psrcInk, srcKeep));

// Pre-conditions
{
(uint256 psrcIlkArt,,, uint256 psrcLine,) = vat.ilks(SRC_ILK);
assertGt(psrcIlkArt, 0, "before: src ilk Art is zero");
assertGt(psrcLine, 0, "before: src line is zero");
assertGt(psrcArt, 0, "before: src art is zero");
assertGt(psrcInk, 0, "before: src ink is zero");
}

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

assertTrue(NetworkPaymentAdapterLike(CHAINLINK_PAYMENT_ADAPTER).treasury() == CHAINLINK_TREASURY_NEW, "ChainLink/treasury-not-updated");
// Old PSM state is set correctly
{
(uint256 srcInk, uint256 srcArt) = vat.urns(SRC_ILK, address(srcPsm));
assertEq(srcInk, psrcInk - expectedMoveWad, "after: src ink is not decreased by dst want");
assertEq(srcArt, psrcArt - expectedMoveWad, "after: src art is not decreased by dst want");

assertEq(
gem.balanceOf(srcPsm.gemJoin()),
psrcGemBalance - _wadToAmt(expectedMoveWad),
"after: src gem-join balance is not decreased by dst want"
);

// srcPsm sanity checks
assertEq(srcPsm.tin(), psrcTin, "after: unexpected src tin update");
assertEq(srcPsm.tout(), psrcTout, "after: unexpected src tout update");
assertEq(srcPsm.vow(), address(vow), "after: unexpected src vow update");
}

// New PSM state is set correctly
{
(, uint256 dstArt) = vat.urns(DST_ILK, address(dstPsm));
// There might be extra `art` because of the calls to `fill`.
assertGe(dstArt, pdstArt + expectedMoveWad, "after: dst art is not increased at least by the moved amount");

assertEq(
_amtToWad(gem.balanceOf(address(pocket))),
_amtToWad(pdstGemBalance) + expectedMoveWad,
"after: invalid gem balance for dst pocket"
);
assertEq(dai.balanceOf(address(dstPsm)), dstBuf, "after: invalid dst psm dai balance");
}

// Vat sin for MCD_PAUSE_PROXY has not changed
assertEq(vat.sin(address(pauseProxy)), pvatSinPauseProxy, "after: unexpected vat sin change for pause proxy");
// Vat vice has not changed
assertEq(vat.vice(), pvice, "after: unexpected vat vice change");
}

function _amtToWad(uint256 amt) internal view returns (uint256) {
return amt * dstPsm.to18ConversionFactor();
}

function _wadToAmt(uint256 wad) internal view returns (uint256) {
return wad / dstPsm.to18ConversionFactor();
}

function _min(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = x < y ? x : y;
}

function _subcap(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = x < y ? 0 : x - y;
}
}
Loading
Loading