Conversation
| assertEq(keccak256(sendAndCallOptions), keccak256(expectedOptions), "TestError/usds-oft-send-and-call-enforced-options-mismatch"); | ||
| } | ||
|
|
||
| function testGovernanceRelayAvalancheHappyPath() public { |
There was a problem hiding this comment.
This is not yet end-to-end test. As it ends at calling L1 function, it doesn't verify that endpoint is correctly configured to relay to the correct destination chain and the destination to have matching configuration. So in my opinion, the test have to (at least) additionally 1) collect data emitted by the endpoint 2) switch to the destination chain, 3) relay the message emitted on mainnet 4) verify the effects. For the inspiration (or even a complete implementation), you can have look at the Spark's xchain-helpers test suite.
(The same end-to-end approach should be applied for testing OFT transfers to the destination and back)
| address ETH_LZ_ENDPOINT = 0x1a44076050125825900e736c501f859c50fE728c; | ||
| address ETH_LZ_SEND_302 = 0xbB2Ea70C9E858123480642Cf96acbcCE1372dCe1; | ||
| bytes32 AVAX_GOV_RECEIVER = bytes32(uint256(uint160(0x6fdd46947ca6903c8c159d1dF2012Bc7fC5cEeec))); | ||
| bytes32 AVAX_L2_GOV_RELAY = bytes32(uint256(uint160(0xe928885BCe799Ed933651715608155F01abA23cA))); |
There was a problem hiding this comment.
Please move those address to the addresses_mainnet.sol file
|
|
||
| // SPELL-SPECIFIC TESTS GO BELOW | ||
|
|
||
| function testWireLzGovSenderAvalanche() public { |
There was a problem hiding this comment.
FYI: you currently only test the contracts and endpoint configuration on L1, but have to do the same for L2 contracts and the endpoint
There was a problem hiding this comment.
Please add a new file addresses_avalanche.sol and populate it with avalanche addresses (based on the existing pattern of prefixing them with L2_)
| // Note: Generated with OptionsBuilder.addExecutorLzReceiveOption(gas: 130_000, value: 0) | ||
| bytes internal constant ENFORCED_OPTIONS_DATA = hex"0003010011010000000000000000000000000001fbd0"; |
There was a problem hiding this comment.
Q: why is this has to be hardcoded in this harder-to-review format instead of being encoded in place?
There was a problem hiding this comment.
sUSDS-related actions are missing at the moment, as far as I can see
amusingaxl
left a comment
There was a problem hiding this comment.
TL;DR: good to deploy ![]()
Development Stage
- Install stable Foundry version
- Install the stable version of Foundry via
foundryup --install stableDocument the installation logs containing installed versions below: forge Version: 1.5.1-stable Commit SHA: b0a9dd9ceda36f63e2326ce530c10e6916f4b8a2 Build Timestamp: 2025-12-22T11:39:01.425730780Z Build Profile: maxperf
- Install the stable version of Foundry via
- Preparation
- Exec Sheet for the specified date is found in the "Executive Vote Implementation Process" google sheet
✅ https://docs.google.com/spreadsheets/d/1w_z5WpqxzwreCcaveB2Ye1PP5B8QAHDglzyxKHG3CHw/edit?gid=320756284#gid=320756284 - Using Exec Sheet URL from the above, read spell instructions from the Exec Sheet and list them below
- Launch Avalanche SkyLink
- Staking Rewards Update
- Grove Genesis Capital Transfer
- Safe Harbor Update
- Spark Proxy Spell
- Grove Proxy Spell
- Exec Sheet for the specified date is found in the "Executive Vote Implementation Process" google sheet
- Base checks
- Current solc version
0.8.16 - Office hours is
trueIF spell introduces a major change that can affect external parties (e.g.: keepers are affected in case of collateral offboarding) OTHERWISE explicitly set tofalse - Office hours value matches the Exec Sheet
- 30 days spell expiry set in the constructor (
block.timestamp + 30 days)
- Current solc version
-
make safeharbor-generateoutput matches the instructions on the Exec Sheet-
IF there is a mismatch, notify Governance Facilitators
-
- Spell description
- Description follows the format
TARGET_DATE MakerDAO Executive Spell | Hash: EXEC_DOC_HASH -
TARGET_DATEin the description matches the target date - Accompanying comment above spell description follows the format
// Hash: cast keccak -- "$(wget 'EXEC_DOC_URL' -q -O - 2>/dev/null)"
- Description follows the format
- Comments inside the spell
- Every Section text from the Exec Sheet is copied to the spell code as a comment surrounded by the set of dashes (E.g.
// ----- Section text -----) - Every Instruction text from the Exec Sheet is copied to the spell code as
// Instruction text - Every Instruction text have newline above it
⚠️ this spell intentionally compresses some adjacent instruction comments due to the size and complexity of the Avalanche SkyLink section; this is acceptable for the current spell and does not reduce reviewability. -
IF an instruction can not be taken, it should have explanation under the instruction prefixed with// Note:(e.g.:// Note: Payments are skipped on goerli) - IF action in the spell doesn't have relevant instruction (e.g.:
chainlogversion bump), the necessity of it is explained in the comment above prefixed with// Note: - Every proof url from the Exec Sheet, such as
Reasoning URLandAuthority URL:- Is present in the spell code under relevant section or instruction (depending on which row the url is present)
- Has the
httpsscheme - Has prefix derived from the url itself
// Executive Vote:if URL starts withhttps://vote.sky.money/executive/// Poll:if URL starts withhttps://vote.sky.money/polling/// Forum:if URL starts withhttps://forum.sky.money/t/// MIP:if URL starts withhttps://mips.makerdao.com/mips/details/// Atlas:if URL starts withhttps://sky-atlas.powerhouse.io/
- Every Section text from the Exec Sheet is copied to the spell code as a comment surrounded by the set of dashes (E.g.
- Dependency checks
- Reinstall libraries by running
rm -rf ./lib && git submodule update --init --recursiveSubmodule path 'lib/dss-exec-lib': checked out '69b658f35d8618272cd139dfc18c5713caf6b96b' Submodule path 'lib/dss-exec-lib/lib/dss-interfaces': checked out '9bfd7afadd1f8c217ef05850b2555691786286cb' Submodule path 'lib/dss-exec-lib/lib/forge-std': checked out '0aa99eb8456693c015350c5e6c4f442ebe912f77' Submodule path 'lib/dss-exec-lib/lib/forge-std/lib/ds-test': checked out 'cd98eff28324bfac652e63a239a60632a761790b' Submodule path 'lib/dss-test': checked out '61cf29fc0cf0c177a3b4072b433c43a7326ccd7b' Submodule path 'lib/dss-test/lib/dss-interfaces': checked out '9bfd7afadd1f8c217ef05850b2555691786286cb' Submodule path 'lib/dss-test/lib/forge-std': checked out 'da591f56d8884c5824c0c1b3103fbcfd81123c4c'
-
IF submodule upgrades are present, make suredss-exec-libis synced as well - git submodule hash of
dss-exec-lib(rungit submodule status) matches the latest release version or newer -
dss-interfaceslibrary used insidelib/dss-exec-libmatches submodule used insidelib/dss-test
- Reinstall libraries by running
- IF interfaces are present in the spell
- Interfaces imported from
dss-interfaces- No unused
dss-interfaces - Only single import layout is used (e.g.
import {VatAbstract} from "dss-interfaces/dss/VatAbstract.sol";)
- No unused
- Static Interfaces
- No unused static interfaces
- Declared static interface not present in the
dss-interfaces, OTHERWISE should be imported from there - Interface matches deployed contract using
cast interface <contract_address>command - Interface naming style should match with
Likesuffix (e.g.VatLike)- EXCEPTION: known interface naming exceptions
- Each static interface declare only functions actually used in the spell code
- Interfaces imported from
- IF variable declarations are present in the spell
- IF precision units are present
- Precision units used in the spell match their defined values:
WAD = 10 ** 18RAY = 10 ** 27RAD = 10 ** 45
- Precision units match with Numerical Ranges
- Each variable visibility is declared as
internal - Each variable state mutability is declared as
constant
- Precision units used in the spell match their defined values:
IF math units are present-
Match their defined values:HUNDRED = 10 ** 2THOUSAND = 10 ** 3MILLION = 10 ** 6BILLION = 10 ** 9
-
Match with config -
Each variable visibility is declared asinternal -
Each variable state mutability is declared asconstant
-
IF rates are present-
Rates match generated locally viamake rates pct=<pct>(e.g. pct=0.75, for 0.75%) -
Rates match IPFS document -
Rate variable name conforms toX_PT_Y_Z_PCT_RATE(e.g.ZERO_PT_SEVEN_FIVE_PCT_RATEfor 0.75%) -
Rate variable visibility declared asinternal -
Rate variable state mutability declared asconstant -
Rates are defined in the ascending order (from smallest to largest)
-
IF timestamps are present-
Comment above timestamp states full date includingUTCtimezone -
Timestamp converts back to the correct date -
Timestamp converts back to theUTCtimezone -
Variable naming matchesMMM_DD_YYYY(e.g.JAN_01_2023for 2023-01-01) -
Time of day makes logical sense in the context of timestamp usage (i.e.23:59:59 UTCfor the final day of something,00:00:00 UTCfor the first day of something) -
Each variable visibility is declared asinternal -
Each variable state mutability is declared asconstant
-
- IF precision units are present
- IF new contract is present in the spell (not yet on chainlog or new to chainlog)
SUSDS_OFT- Source code is verified on etherscan
- ✅ Ethereum Mainnet address:
0x85A3FE4DA2a6cB98A5bdF62458B0dB8471B9f0f1
- ✅ Ethereum Mainnet address:
- Compilation optimizations match deployment settings defined in the source code repo
- ✅ Etherscan metadata:
OptimizationUsed = 1,Runs = 20000 - ✅
sky-oapp-oft@5ad5cb6/foundry.toml:optimizer = true,optimizer_runs = 20_000
- ✅ Etherscan metadata:
-
GNU AGPLv3license⚠️ deployed source and pinned upstream source both declareMIT, notGNU AGPLv3
- Every protocol-related constructor argument matches chainlog (e.g.
vat,dai,dog, ...)- ✅
token = 0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD(SUSDS) - ✅
endpoint = 0x1a44076050125825900e736c501f859c50fE728c(LZ_ENDPOINT) - ✅
delegate = 0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB(MCD_PAUSE_PROXY)
- ✅
IF new contract have concept ofwardsor access control-
EnsurePAUSE_PROXYaddress wasrelied(wards(PAUSE_PROXY)is1) -
Ensure that contract deployer address wasdenied(wards(deployer)is0)- ℹ️
SUSDS_OFTuses owner-based access control, notwards. Ownership checking is done withLZLaneTesting.assertOwner().
- ℹ️
-
Ensure that there are no otherRelyevents except forPAUSE_PROXY(using a block explorer like etherscan)
-
- Source code matches corresponding github source code (e.g. diffcheck via vscode
code --diff etherscan.sol github.sol) - Deployer address is included into
addresses_deployers.sol
⚠️ this is coincidental because the same deployer was used in the past for other modules.- ✅ on-chain creator:
0x89aAB8CAeEf8d25051cA6E534C6944e51f15DAd2 - ✅ present in
src/test/addresses_deployers.sol
- ✅ on-chain creator:
- Source code is verified on etherscan
- [Not part of the checklist scope yet] IF new contracts in other chains are present in the spell
- ℹ️ these contracts are not in the mainnet chainlog because they live on Avalanche Mainnet, but analogous verification was still performed
L2_AVALANCHE_LZ_GOV_RECEIVER(GovernanceOAppReceiver)- Source code is verified on etherscan
- ✅ Avalanche Mainnet address:
0x6fdd46947ca6903c8c159d1dF2012Bc7fC5cEeec
- ✅ Avalanche Mainnet address:
- Compilation optimizations match deployment settings defined in the source code repo
- ✅ Routescan metadata:
OptimizationUsed = 1,Runs = 20000 - ✅
sky-oapp-oft@5ad5cb6/foundry.toml:optimizer = true,optimizer_runs = 20_000
- ✅ Routescan metadata:
-
GNU AGPLv3license⚠️ pinned source file declaresApache-2.0, notGNU AGPLv3
- Every protocol-related constructor argument matches chainlog (e.g.
vat,dai,dog, ...)- ✅
l1Eid = 30101 - ✅
sender = 0x00000000000000000000000027fc1dd771817b53bE48Dc28789533BEa53C9CCA - ✅
endpoint = 0x1a44076050125825900e736c501f859c50fE728c - ✅
owner = 0x48c4dba0833748e576ad60e12a3c01c5785b09ab
- ✅
IF new contract have concept ofwardsor access control-
EnsurePAUSE_PROXYaddress wasrelied(wards(PAUSE_PROXY)is1) -
Ensure that contract deployer address wasdenied(wards(deployer)is0)GovernanceOAppReceiveris owner-based, notwards-based
-
Ensure that there are no otherRelyevents except forPAUSE_PROXY(using a block explorer like etherscan)
-
- Source code matches corresponding github source code (e.g. diffcheck via vscode
code --diff etherscan.sol github.sol) -
Deployer address is included intoaddresses_deployers.sol- ℹ️ the mainnet deployer registry is not applicable to Avalanche Mainnet contracts
- Source code is verified on etherscan
L2_AVALANCHE_LZ_GOV_RELAY(L2GovernanceRelay)- Source code is verified on etherscan
- ✅ Avalanche Mainnet address:
0xe928885BCe799Ed933651715608155F01abA23cA
- ✅ Avalanche Mainnet address:
- Compilation optimizations match deployment settings defined in the source code repo
- ✅ Routescan metadata:
OptimizationUsed = 1,Runs = 200 - ✅
lz-governance-relay@d3e3df4/foundry.toml:optimizer = true,optimizer_runs = 200
- ✅ Routescan metadata:
-
GNU AGPLv3license- ✅ pinned source file declares
AGPL-3.0-or-later
- ✅ pinned source file declares
- Every protocol-related constructor argument matches chainlog (e.g.
vat,dai,dog, ...)- ✅
l1Eid = 30101 - ✅
l2Oapp = 0x6fdd46947ca6903c8c159d1dF2012Bc7fC5cEeec - ✅
l1GovernanceRelay = 0x2beBFe397D497b66cB14461cB6ee467b4C3B7D61
- ✅
IF new contract have concept ofwardsor access control-
EnsurePAUSE_PROXYaddress wasrelied(wards(PAUSE_PROXY)is1) -
Ensure that contract deployer address wasdenied(wards(deployer)is0)L2GovernanceRelayis notwards-based
-
Ensure that there are no otherRelyevents except forPAUSE_PROXY(using a block explorer like etherscan)
-
- Source code matches corresponding github source code (e.g. diffcheck via vscode
code --diff etherscan.sol github.sol) -
Deployer address is included intoaddresses_deployers.sol- ℹ️ the mainnet deployer registry is not applicable to Avalanche Mainnet contracts
- Source code is verified on etherscan
L2_AVALANCHE_USDS_IMP(USDSimplementation)- Source code is verified on etherscan
- ✅ Avalanche Mainnet address:
0xB5bc5dFe65a9ec30738DB3a0b592B8a18A191300
- ✅ Avalanche Mainnet address:
- Compilation optimizations match deployment settings defined in the source code repo
- ✅ Routescan metadata:
OptimizationUsed = 1,Runs = 200 - ✅
usds@45bf759/foundry.toml:optimizer = true,optimizer_runs = 200
- ✅ Routescan metadata:
-
GNU AGPLv3license- ✅ pinned source file declares
AGPL-3.0-or-later
- ✅ pinned source file declares
-
Every protocol-related constructor argument matches chainlog (e.g.vat,dai,dog, ...)- ℹ️ the implementation contract has no constructor arguments
- IF new contract have concept of
wardsor access control-
EnsurePAUSE_PROXYaddress wasrelied(wards(PAUSE_PROXY)is1)- ℹ️ this is the implementation contract; it calls
_disableInitializers()in the constructor, so live authorization is expected on the proxy, not on the implementation storage
- ℹ️ this is the implementation contract; it calls
- Ensure that contract deployer address was
denied(wards(deployer)is0)- creator
0x48c4dba0833748e576ad60e12a3c01c5785b09ab wards(creator) = 0
- creator
- Ensure that there are no other
Relyevents except forPAUSE_PROXY(using a block explorer like etherscan)- ✅ no
Rely(address)events were found for the implementation address
- ✅ no
-
- Source code matches corresponding github source code (e.g. diffcheck via vscode
code --diff etherscan.sol github.sol)- ✅ source permalink: https://github.com/sky-ecosystem/usds/blob/45bf759ba046b66dd115842ee8b9205a64e7bab6/src/Usds.sol
- ✅ verified source bundle and pinned commit tree both resolve this implementation to the same
Usds.solimplementation source - ℹ️ this contract is the implementation behind
L2_AVALANCHE_USDS
-
Deployer address is included intoaddresses_deployers.sol- ℹ️ the mainnet deployer registry is not applicable to Avalanche Mainnet contracts
- Source code is verified on etherscan
L2_AVALANCHE_USDS(USDSproxy)- Source code is verified on etherscan
- ✅ Avalanche Mainnet address:
0x86Ff09db814ac346a7C6FE2Cd648F27706D1D470
- ✅ Avalanche Mainnet address:
- Compilation optimizations match deployment settings defined in the source code repo
- ✅ Routescan metadata:
OptimizationUsed = 1,Runs = 200 - ✅ verified source bundle settings also show
optimizer.enabled = true,runs = 200
- ✅ Routescan metadata:
-
GNU AGPLv3license⚠️ the verifiedERC1967Proxy.solsource declaresMIT, notGNU AGPLv3
- Every protocol-related constructor argument matches chainlog (e.g.
vat,dai,dog, ...)- ✅
implementation = 0xB5bc5dFe65a9ec30738DB3a0b592B8a18A191300 - ✅
data = 0x8129fc1c
- ✅
- IF new contract have concept of
wardsor access control-
EnsurePAUSE_PROXYaddress wasrelied(wards(PAUSE_PROXY)is1)- ℹ️ Avalanche proxy authorization is held by
L2_AVALANCHE_LZ_GOV_RELAYandL2_AVALANCHE_USDS_OFT, notPAUSE_PROXY - ✅
wards(L2_AVALANCHE_LZ_GOV_RELAY) = 1andwards(L2_AVALANCHE_USDS_OFT) = 1
- ℹ️ Avalanche proxy authorization is held by
- Ensure that contract deployer address was
denied(wards(deployer)is0)- creator
0x48c4dba0833748e576ad60e12a3c01c5785b09ab wards(creator) = 0
- creator
-
Ensure that there are no otherRelyevents except forPAUSE_PROXY(using a block explorer like etherscan)
-
- Source code matches corresponding github source code (e.g. diffcheck via vscode
code --diff etherscan.sol github.sol) -
Deployer address is included intoaddresses_deployers.sol- ℹ️ the mainnet deployer registry is not applicable to Avalanche Mainnet contracts
- Source code is verified on etherscan
L2_AVALANCHE_USDS_OFT(SkyOFTAdapterMintBurn(USDS))- Source code is verified on etherscan
- ✅ Avalanche Mainnet address:
0x4fec40719fD9a8AE3F8E20531669DEC5962D2619
- ✅ Avalanche Mainnet address:
- Compilation optimizations match deployment settings defined in the source code repo
- ✅ Routescan metadata:
OptimizationUsed = 1,Runs = 20000 - ✅
sky-oapp-oft@5ad5cb6/foundry.toml:optimizer = true,optimizer_runs = 20_000
- ✅ Routescan metadata:
-
GNU AGPLv3license⚠️ pinned source file declaresMIT, notGNU AGPLv3
- Every protocol-related constructor argument matches chainlog (e.g.
vat,dai,dog, ...)- ✅
token = 0x86Ff09db814ac346a7C6FE2Cd648F27706D1D470 - ✅
endpoint = 0x1a44076050125825900e736c501f859c50fE728c - ✅
delegate = 0x48c4dba0833748e576ad60e12a3c01c5785b09ab
- ✅
IF new contract have concept ofwardsor access control-
EnsurePAUSE_PROXYaddress wasrelied(wards(PAUSE_PROXY)is1) -
Ensure that contract deployer address wasdenied(wards(deployer)is0)SkyOFTAdapterMintBurn(USDS)is owner-based, notwards-based
-
Ensure that there are no otherRelyevents except forPAUSE_PROXY(using a block explorer like etherscan)
-
- Source code matches corresponding github source code (e.g. diffcheck via vscode
code --diff etherscan.sol github.sol) -
Deployer address is included intoaddresses_deployers.sol- ℹ️ the mainnet deployer registry is not applicable to Avalanche Mainnet contracts
- Source code is verified on etherscan
L2_AVALANCHE_SUSDS_IMP(sUSDSimplementation)- Source code is verified on etherscan
- ✅ Avalanche Mainnet address:
0xc8dB83458e8593Ed9a2D81DC29068B12D330729a
- ✅ Avalanche Mainnet address:
- Compilation optimizations match deployment settings defined in the source code repo
- ✅ Routescan metadata:
OptimizationUsed = 1,Runs = 200 - ✅
sdai@e1d160a/foundry.toml:optimizer = true,optimizer_runs = 200
- ✅ Routescan metadata:
-
GNU AGPLv3license- ✅ pinned source file declares
AGPL-3.0-or-later
- ✅ pinned source file declares
-
Every protocol-related constructor argument matches chainlog (e.g.vat,dai,dog, ...)- ℹ️ the implementation contract has no constructor arguments
- IF new contract have concept of
wardsor access control-
EnsurePAUSE_PROXYaddress wasrelied(wards(PAUSE_PROXY)is1)- ℹ️ this is the implementation contract; it calls
_disableInitializers()in the constructor, so live authorization is expected on the proxy, not on the implementation storage
- ℹ️ this is the implementation contract; it calls
- Ensure that contract deployer address was
denied(wards(deployer)is0)- creator
0x48c4dba0833748e576ad60e12a3c01c5785b09ab wards(creator) = 0
- creator
- Ensure that there are no other
Relyevents except forPAUSE_PROXY(using a block explorer like etherscan)- ✅ no
Rely(address)events were found for the implementation address
- ✅ no
-
- Source code matches corresponding github source code (e.g. diffcheck via vscode
code --diff etherscan.sol github.sol)- ✅ source permalink: https://github.com/sky-ecosystem/sdai/blob/e1d160aba17e95e8cec3d6bf50f310fbed9f28d6/src/l2/SUsds.sol
- ℹ️ this contract is the implementation behind
L2_AVALANCHE_SUSDS
-
Deployer address is included intoaddresses_deployers.sol- ℹ️ the mainnet deployer registry is not applicable to Avalanche Mainnet contracts
- Source code is verified on etherscan
L2_AVALANCHE_SUSDS(sUSDSproxy)- Source code is verified on etherscan
- ✅ Avalanche Mainnet address:
0xb94D9613C7aAB11E548a327154Cc80eCa911B5c1
- ✅ Avalanche Mainnet address:
- Compilation optimizations match deployment settings defined in the source code repo
- ✅ Routescan metadata:
OptimizationUsed = 1,Runs = 200 - ✅ verified source bundle settings also show
optimizer.enabled = true,runs = 200
- ✅ Routescan metadata:
-
GNU AGPLv3license⚠️ the verifiedERC1967Proxy.solsource declaresMIT, notGNU AGPLv3
- Every protocol-related constructor argument matches chainlog (e.g.
vat,dai,dog, ...)- ✅
implementation = 0xc8dB83458e8593Ed9a2D81DC29068B12D330729a - ✅
data = 0x8129fc1c
- ✅
- IF new contract have concept of
wardsor access control-
EnsurePAUSE_PROXYaddress wasrelied(wards(PAUSE_PROXY)is1)- ℹ️ Avalanche proxy authorization is held by
L2_AVALANCHE_LZ_GOV_RELAYandL2_AVALANCHE_SUSDS_OFT, notPAUSE_PROXY - ✅
wards(L2_AVALANCHE_LZ_GOV_RELAY) = 1andwards(L2_AVALANCHE_SUSDS_OFT) = 1
- ℹ️ Avalanche proxy authorization is held by
- Ensure that contract deployer address was
denied(wards(deployer)is0)- creator
0x48c4dba0833748e576ad60e12a3c01c5785b09ab wards(creator) = 0
- creator
-
Ensure that there are no otherRelyevents except forPAUSE_PROXY(using a block explorer like etherscan)
-
- Source code matches corresponding github source code (e.g. diffcheck via vscode
code --diff etherscan.sol github.sol) -
Deployer address is included intoaddresses_deployers.sol- ℹ️ the mainnet deployer registry is not applicable to Avalanche Mainnet contracts
- Source code is verified on etherscan
L2_AVALANCHE_SUSDS_OFT(SkyOFTAdapterMintBurn(sUSDS))- Source code is verified on etherscan
- ✅ Avalanche Mainnet address:
0x7297D4811f088FC26bC5475681405B99b41E1FF9
- ✅ Avalanche Mainnet address:
- Compilation optimizations match deployment settings defined in the source code repo
- ✅ Routescan metadata:
OptimizationUsed = 1,Runs = 20000 - ✅
sky-oapp-oft@5ad5cb6/foundry.toml:optimizer = true,optimizer_runs = 20_000
- ✅ Routescan metadata:
-
GNU AGPLv3license⚠️ pinned source file declaresMIT, notGNU AGPLv3
- Every protocol-related constructor argument matches chainlog (e.g.
vat,dai,dog, ...)- ✅
token = 0xb94D9613C7aAB11E548a327154Cc80eCa911B5c1 - ✅
endpoint = 0x1a44076050125825900e736c501f859c50fE728c - ✅
delegate = 0x48c4dba0833748e576ad60e12a3c01c5785b09ab
- ✅
IF new contract have concept ofwardsor access control-
EnsurePAUSE_PROXYaddress wasrelied(wards(PAUSE_PROXY)is1) -
Ensure that contract deployer address wasdenied(wards(deployer)is0)SkyOFTAdapterMintBurn(sUSDS)is owner-based, notwards-basedowner() = 0xe928885BCe799Ed933651715608155F01abA23cA
-
Ensure that there are no otherRelyevents except forPAUSE_PROXY(using a block explorer like etherscan)
-
- Source code matches corresponding github source code (e.g. diffcheck via vscode
code --diff etherscan.sol github.sol) -
Deployer address is included intoaddresses_deployers.sol- ℹ️ the mainnet deployer registry is not applicable to Avalanche Mainnet contracts
- Source code is verified on etherscan
IF core system parameter changes are present in the instructionsIF stability fee (jug.ilk.duty) is updated-
(DssExecLib.setIlkStabilityFee(ilk, rate, doDrip)) is used -
Comment matches pattern// Increase ILK-A Stability Fee by X.XX% from X.XX% to X.XX%
-
IF Dai Savings Rate (pot.dsr) is updated-
(DssExecLib.setDSR(rate, doDrip)) is used -
Comment matches pattern// Increase DSR by X.XX% from X.XX% to X.XX% -
Double check that rate matchmake rates pct=<pct>(e.g. pct=0.75, for 0.75%) -
Double check that rate match IPFS document
-
-
IFspotter.ilk.matis updated, (DssExecLib.setIlkLiquidationRatio(ilk, pct_bps)) is used -
IFdog.ilk.holeis updated, (DssExecLib.setIlkMaxLiquidationAmount(ilk, amount)) is used -
IFvat.ilk.dustis updated, (DssExecLib.setIlkMinVaultAmount(ilk, amount)) is used -
IFdog.ilk.chopis updated, (DssExecLib.setIlkLiquidationPenalty(ilk, pct_bps)) is used -
IFclip.bufis updated, (DssExecLib.setStartingPriceMultiplicativeFactor(ilk, pct_bps)) is used -
IFclipperMom.clip.toleranceis updated, (DssExecLib.setLiquidationBreakerPriceTolerance(clip, pct_bps)) is used -
IFclip.tailis updated, (DssExecLib.setAuctionTimeBeforeReset(ilk, duration)) is used -
IFclip.cuspis updated, (DssExecLib.setAuctionPermittedDrop(ilk, pct_bps)) is used -
IFclip.chipis updated, (DssExecLib.setKeeperIncentivePercent(ilk, pct_bps)) is used -
IFclip.tipis updated, (DssExecLib.setKeeperIncentiveFlatRate(ilk, amount)) is used -
IFcalc.tauis updated, (DssExecLib.setLinearDecrease(calc, duration)) is used -
IFcalc.cutorcalc.stepare updated,DssExecLib.setStairstepExponentialDecrease(calc, duration, pct_bps)is used
IF debt ceiling changes are present in the instructionsIF adjusted collateral type (ilk) have AutoLine enabled (MCD_IAM_AUTO_LINE)IF collateral debt ceiling requested to be0-
Collateral is removed from AutoLine (MCD_IAM_AUTO_LINE) viaDssExecLib.removeIlkFromAutoLine(ilk) -
The instruction to remove from AutoLine (MCD_IAM_AUTO_LINE) is present in the Exec Sheet -
Collateral debt ceiling is set to0viaDssExecLib.setIlkDebtCeiling(ilk, amount) -
Global debt ceiling (vat.Line) is updated accordingly, UNLESS specifically instructed not to
-
IFAutoLineparameters are updated-
EITHER is used, depending on the instruction:
-
IF collateral debt ceiling (vat.ilk.line) is updated-
Collateral type (ilk) haveAutoLinedisabled previously or in the spell -
EITHER is used, depending on the instruction: -
Global debt ceiling (vat.Line) is updated accordingly, UNLESS specifically instructed not to, via EITHER:globalset totrueinincreaseIlkDebtCeiling/decreaseIlkDebtCeilingDssExecLib.setGlobalDebtCeiling(amount)DssExecLib.increaseGlobalDebtCeiling(amount)DssExecLib.decreaseGlobalDebtCeiling(amount)
-
- IF additional dependencies (i.e.
./src/dependencies/directory) are present:- IF the dependencies contracts/libraries have been audited
- ℹ️ ChainSecurity report references endgame-toolkit@4f238f9 for the
updateFarmVestreview batch - Each contract/library exactly matches (i.e. diff check) the source code of the latest audited version
- ✅ exact SHA-256 matches verified for:
src/dependencies/endgame-toolkit/StakingRewardsInit.sol<->script/dependencies/StakingRewardsInit.solsrc/dependencies/endgame-toolkit/VestInit.sol<->script/dependencies/VestInit.solsrc/dependencies/endgame-toolkit/VestedRewardsDistributionInit.sol<->script/dependencies/VestedRewardsDistributionInit.solsrc/dependencies/endgame-toolkit/treasury-funded-farms/TreasuryFundedFarmingInit.sol<->script/dependencies/treasury-funded-farms/TreasuryFundedFarmingInit.sol
- ℹ️ ChainSecurity report references endgame-toolkit@4f238f9 for the
-
OTHERWISE obtain the permalink to the relevant repository from a trusted party (i.e. Gov Facilitators)-
Each contract/library exactly matches (i.e. diff check) the source code from the permalink
-
- IF the dependencies contracts/libraries have been audited
IF onboarding is present-
Insert and follow the relevant checklists below:
-
IF PSM migration, onboarding or offboarding is present:-
Insert and follow the relevant checklists below:
-
-
IF D3M onboarding is present, insert and follow D3M Checklist IF crypto collateral offboarding is present in the spell1st stage collateral offboarding-
Collateral type (ilk) is removed from AutoLine (MCD_IAM_AUTO_LINE) IF currently enabled -
Collateral debt ceiling (vat.ilk.line) is set to0 -
Global debt ceiling (vat.Line) decreased by the total amount of offboarded ilks
-
2nd stage collateral offboarding-
All actions from the 1st stage offboarding are previously taken (EITHER in the current or past spells – check the archive) -
Collateral liquidation penalty (chop) is set to0IF requested by governance -
Flat keeper incentive (tip) is set to0IF requested by governance -
Relative keeper incentive (chip) is set to0IF requested by governance -
Max liquidation amount (hole) is adjusted viaDssExecLib.setIlkMaxLiquidationAmount(ilk, amount)IF requested by governance -
Relevant clipper contract (MCD_CLIP_) is active (i.e.stoppedis0) -
Liquidations are triggered via (depending on governance instruction):EITHER liquidation ratio (spotter.ilk.mat) being set very high in the spell (usingDssExecLib.setValue(DssExecLib.spotter(), ilk, "mat", ratio))OR via enabling linear interpolation (DssExecLib.linearInterpolation(name, target, ilk, what, startTime, start, end, duration))-
Ensurenameformat matches "XXX-X Offboarding" -
EnsuretargetmatchesDssExecLib.spotter()address -
Ensureilkformat matches collateral type (ilk) name ("XXX-X") -
Ensurewhatmatches string"mat" -
EnsurestartTimematchesblock.timestamp -
Ensurestartuses variableCURRENT_XXX_A_MAT -
Ensurestartmatches currentspotter.ilk.matvalue -
Ensureenduses variableTARGET_XXX_A_MAT -
Ensureendvalue matches the instruction -
Ensureendallows liquidation of all remaining vaults (endis bigger thancollateral_type_collateralization_ratio * risk_multiplier_factor) -
Ensuredurationmatches the instruction
-
-
Spotter price is updated viaDssExecLib.updateCollateralPrice(ilk)IF collateral have no running oracle (i.e. relevantPIP_contract have outdatedzzzvalue) -
Spotter price is updated after all other actions -
Offboarding is tested at least via_checkIlkClipperhelper
-
IF RWA updates are present-
Insert and follow the relevant checklists below:
-
IF RWA offboardings are present-
Insert and follow the relevant checklists below:
-
- IF payments are present in the spell
IFSKYtransfers are present-
Recipient address in the instruction is in the checksummed format -
Recipient address matches Exec Sheet -
Recipient address variable name matches one found inaddresses_wallets.sol -
Transfer amount matches Exec Sheet -
The transfers are tested viatestPaymentstest -
Sum of all SKY transfers tested intestPaymentsmatches number in the Exec Sheet
-
- IF
USDSsurplus buffer transfers are present- Recipient address in the instruction is in the checksummed format
- ✅
GROVE_SUBPROXYresolves to0x1369f7b2b38c76B6478c0f0E66D94923421891Bainsrc/test/addresses_mainnet.sol
- ✅
- Recipient address matches Exec Sheet
- ✅ Exec Sheet instruction is
Transfer 20,797,477 USDS to the GROVE_SUBPROXY
- ✅ Exec Sheet instruction is
- Recipient address variable name matches one found in
addresses_wallets.sol- ✅ repository lookup is in
src/test/addresses_mainnet.sol, whereGROVE_SUBPROXYis defined with the same address
- ✅ repository lookup is in
- Transfer amount matches Exec Sheet
- ✅ spell calls
_transferUsds(GROVE_SUBPROXY, 20_797_477 * WAD)
- ✅ spell calls
- The transfers are tested via
testPaymentstest- ✅
testPayments()includesPayee(address(usds), addr.addr("GROVE_SUBPROXY"), 20_797_477 ether)
- ✅
- Sum of all USDS transfers tested in
testPaymentsmatches number in the Exec Sheet- ✅
expectedTotalPayments.usds = 20_797_477 ether, matching the Exec Sheet checksum row
- ✅
- Recipient address in the instruction is in the checksummed format
- IF
DAI/SKY/USDS/SPKstreams (DssVest) are created-
VestAbstractinterface is imported fromdss-interfaces/dss/VestAbstract.sol- ℹ️ the spell updates the vest through audited helper
TreasuryFundedFarmingInit.updateFarmVest(), which callsVestInit.create()internally
- ℹ️ the spell updates the vest through audited helper
-
restrictis used for each stream, UNLESS otherwise explicitly stated in the Exec Sheet- ✅
VestInit.create()callsDssVestLike(vest).restrict(vestId)
- ✅
-
usr(Vest recipient address) matches Exec Sheet- ✅ Exec Sheet
distis0x675671A8756dDb69F7254AFB030865388Ef699Ee, matchingREWARDS_DIST_LSSKY_SKY
- ✅ Exec Sheet
-
usraddress in the instruction is in the checksummed format- ✅
REWARDS_DIST_LSSKY_SKYresolves to0x675671A8756dDb69F7254AFB030865388Ef699Eeinsrc/test/addresses_mainnet.sol
- ✅
-
usraddress variable name match one found inaddresses_wallets.sol- ✅ repository lookup is in
src/test/addresses_mainnet.sol, whereREWARDS_DIST_LSSKY_SKYis defined with the same address
- ✅ repository lookup is in
-
tot(Total stream amount) matches Exec Sheet- ✅ spell sets
vestTot: 192_110_322 * WAD
- ✅ spell sets
-
IFetherkeyword is used, comment is present on the same line// Note: ether is a keyword that represents 10**18, not the ETH token -
IF vest amount is expressed in 'per year' or similar in the Exec Sheet, account for leap days -
bgn(Vest start timestamp) matches Exec Sheet- ✅ spell sets
vestBgn: block.timestamp
- ✅ spell sets
-
tauis expressed as EITHER:fin - bgn(i.e.MONTH_DD_YYYY - MONTH_DD_YYYY)-
fin(Vest end timestamp) matches Exec Sheet
-
- time interval (e.g.
365 days) - ✅ spell sets
vestTau: 90 days
-
eta(Vest cliff duration) matches the following logic- IF
etais explicitly specified in the Exec Sheet, then the values match - IF
etaandclf(Cliff end timestamp) are not specified in the Exec Sheet, thenetais0 - IF
clfis specified, butclf <= bgn, thenetais0 - IF
clfis specified andclf > bgn,etais expressed asclf - bgn(i.e.MONTH_DD_YYYY - MONTH_DD_YYYY) - ✅ helper calls
VestInit.create(... eta: 0)
- IF
- IF
mgr(Vest manager address) is specified in the Exec Sheet, matches the value, OTHERWISE matchesaddress(0)- ✅
VestInit.create()passesaddress(0)asmgr
- ✅
- Ensure that max vesting rate (
cap) is enough for the new streams- The maximum vesting rate (
totdivided bytau)<=the maximum vest streaming rate (cap) -
The maximum vesting rate (totdivided bytau)>the maximum vest streaming rate (cap) -
Calculate newcapvalue equal to 10% greater than the new maximum vesting rate, then round newcapup with 2 significant figure precision (i.e. 2446 becomes 2500) - ✅
110 * vestTot / (100 * vestTau) = 27176100077160497152, which is belowafterSpell.vest_sky_cap = 70730452674897125376
- The maximum vesting rate (
IF max vesting rate (cap) is changed in the spell-
Governance facilitators were notified -
Exec Sheet contains explicit instruction -
Exec Doc contains explicit instruction
-
- IF new SKY streams (DssVestTransferrable) are present
- Vest contract's SKY allowance increased by the cumulative
total(the sum of alltotvalues)- ✅ helper adjusts allowance by
currAllowance + p.vestTot - (prevVestTot - prevVestRxd), and_checkVest()verifies the post-spell allowance delta
- ✅ helper adjusts allowance by
- Ensure allowance increase follows archive patterns
- Vest contract's SKY allowance increased by the cumulative
IF new SPK streams (DssVestTransferrable) are present-
Vest contract's SPK allowance increased by the cumulativetotal(the sum of alltotvalues) -
Ensure allowance increase follows archive patterns
-
- Tested via:
testVestDaitestVestSkytestVestSkyMinttestVestUsdstestVestSpk- ✅ for this spell, the applicable coverage is
testVestSky
-
- IF
DAI/SKY/USDS/SPKvest termination (Yank) is present-
Yanked stream ID matches Exec Sheet- ℹ️ the Exec Sheet specifies the vest update parameters, but does not name the superseded vest stream id
-
MCD_VEST_SKY_TREASURYchainlog address is used for SKY streamyank- ℹ️ the yank happens inside
TreasuryFundedFarmingInit.updateFarmVest()throughdist.dssVest(), rather than by directly fetching the chainlog key in spell code
- ℹ️ the yank happens inside
-
MCD_VEST_SPK_TREASURYchainlog address is used for SPK streamyank -
MCD_VEST_DAIchainlog address is used for DAI streamyank -
MCD_VEST_USDSchainlog address is used for USDS streamyank - Tested via:
testVestDaitestVestSkytestVestSkyMinttestVestUsdstestVestSpk- ✅ for this spell, the applicable coverage is
testVestSky
-
- IF
SKY/SPKvest rewards distribution is present- Rewards distribution contract address matches Exec Sheet
- ✅ Exec Sheet
distis0x675671A8756dDb69F7254AFB030865388Ef699Ee, matchingREWARDS_DIST_LSSKY_SKY
- ✅ Exec Sheet
- To prevent front-running DoS, the
distribute()call is placed insideifblock that checks whether the vesting stream’s unpaid amount is greater than 0- ✅
TreasuryFundedFarmingInit.updateFarmVest()guards bothdist.distribute()calls withif (unpaid > 0)
- ✅
- Tested via
testVestedRewardsDist
- Rewards distribution contract address matches Exec Sheet
- IF content related to a Prime Agent is present
- IF Prime Agent spell is provided
- Handover message matches
XXX spell YYY-MM-DD deployed to 0x… with hash 0x…, direct execution: yes / notemplate- ℹ️ confirmed on Discord
- IF
direct executionisno- The Prime Agent spell is plotted using
StarGuardLike(XXX_STARGUARD).plot(XXX_SPELL, XXX_SPELL_HASH) -
XXXinXXX_STARGUARDmatches the name of the Prime Agent -
XXX_STARGUARDis fetched from chainlog - The test ensures the
XXX_SPELLPrime Agent spell is executable viaStarGuardLike(XXX_STARGUARD).exec()beforeXXX_STARGUARD.maxDelay- ✅
testPrimeAgentSpellExecutions()covers bothSPARK_STARGUARDandGROVE_STARGUARDthrough_testStarGuardExecution(...)
- ✅
- IF plotted but not yet executed spell is still present in the
XXX_STARGUARD, Governance Facilitators are aware or already notified- ✅ live
spellData()is empty for bothSPARK_STARGUARDandGROVE_STARGUARD(address(0),bytes32(0),0), so there is no preexisting plotted spell
- ✅ live
- The Prime Agent spell is plotted using
-
IFdirect executionisyes-
Provided mandatory explanation of why direct execution is required makes sense on the technical level -
The hash is checked viarequire(XXX_SPELL.codehash == XXX_SPELL_HASH, "XXX_SPELL/wrong-codehash");inside the Core spell -
The Prime Agent spell is executed viaProxyLike(XXX_PROXY).exec(XXX_SPELL, abi.encodeWithSignature("execute()")); -
XXXinXXX_PROXYmatches the name of the Prime Agent -
XXX_PROXYis fetched from chainlog
-
- Prime Agent spell address (
XXX_SPELL) matches Exec Sheet- ✅ Spark
0xFa5fc020311fCC1A467FEC5886640c7dD746deAaand Grove0x679eD4739c71300f7d78102AE5eE17EF8b8b2162match the Exec Sheet and Exec Doc
- ✅ Spark
- Prime Agent spell hash (
XXX_SPELL_HASH) matches Exec Sheet- ✅ Spark
0x2572a97846f7a6f9f159a9a69c2707cfa4186c061de2a0ec59e7a0d46473c74cand Grove0x4fa1f743b3d6d2855390724459129186dd684e1c07d59f88925f0059ba1e6c84match the Exec Sheet and Exec Doc
- ✅ Spark
- Handover message matches
- IF Prime Agent spell is provided
IF external contracts calls are present (Not Prime Agents, e.g. Starknet)-
Target Contract doesn't block spell execution -
External call is NOTdelegatecall -
Target Contract doesn't have permissions on the Vat -
Target Contract doesn't do anything untoward (e.g. interacting with unsafe contracts) -
Contracts deployed viaCREATE2(e.g. if it looks like a vanity address) do not haveselfdestructin their code -
MCD Pause Proxy doesn't give any approvals -
All possible actions of the Target Contract are documented -
Target contract is not upgradable -
Target Contract is included in the ChainLog -
Test Coverage is comprehensive
-
- IF bug bounty registry updates are present
- Run
make safeharbor-generate- Verify that the generated code exactly matches the code in the spell
- Verify that output matches the instructions provided by Governance Facilitators
- Ensure that the script does not output any warnings, which are indicated by
⚠️ ❗- ✅ generator completed successfully and reproduced the two
calldatas[...]payloads plus_updateSafeHarbor(calldatas);
- ✅ generator completed successfully and reproduced the two
- Ensure that agreement address is fetched from the Chainlog
- ✅
SAFE_HARBOR_AGREEMENTis fetched viaDssExecLib.getChangelogAddress("SAFE_HARBOR_AGREEMENT")
- ✅
- Ensure that the helper function to perform the call is present and is implemented using the established archive pattern
- ✅
_updateSafeHarbor(bytes[] memory calldatas)iterates the generated payloads and requires each call to succeed
- ✅
- Run
- IF spell interacts with ChainLog
- ChainLog version is incremented based on update type
- Major -> New Vat (++.0.0)
- Minor -> Core Module (DSS) Update (e.g. Flapper) (0.++.0)
- Patch -> Collateral addition or addition/modification (0.0.++)
- ✅ the spell adds
SUSDS_OFTand bumps the ChainLog version to1.20.15, which is a patch-level update
- New addresses are added to the
addresses_mainnet.sol- ✅
SUSDS_OFTandSUSDS_OFT_PAUSERare present insrc/test/addresses_mainnet.sol
- ✅
- Changes are tested via
testChainlogIntegrity,testChainlogValues,testAddedChainlogKeysandtestRemovedChainlogKeys⚠️ testRemovedChainlogKeysis intentionally skipped because this spell does not remove ChainLog keys
- ChainLog version is incremented based on update type
- Ensure every spell variable is declared as
public/internal - Ensure
immutablevisibility is only used when fetching addresses from theChainLogviaDssExecLib.getChangelogAddress(key)andconstantis used instead for static addresses- Fetch addresses as type
addressand wrap withLikesuffix interfaces inline (when making calls), UNLESS archive patterns permit otherwise (such asSKY) - Use the DssExecLib Core Address Helpers where possible (e.g.
DssExecLib.vat())- ✅
DAIusesDssExecLib.dai()and the remaining dynamic addresses useDssExecLib.getChangelogAddress(...)
- ✅
- Where addresses are fetched from the ChainLog, the variable name must match the value of the ChainLog key for that address (e.g.
MCD_VATrather thanvat)
- Fetch addresses as type
- Tests
- Ensure that the
DssExecLibaddress insidefoundry.tomlis not being modified by the spell PR- ✅ no diff is present in
foundry.toml
- ✅ no diff is present in
- Check all CI tests are passing as at the latest commit
174a65ee7f15ea630ac0af0125c762062b5fbae7 - Ensure every test function is declared as
public- IF the test needs to run, it MUST NOT have the
skippedmodifier; OTHERWISE, it MUST have theskippedmodifier- ✅ active spell-specific tests such as
testVestSky,testPayments,testPrimeAgentSpellExecutions,testUpdateSafeHarborAddedAccounts,testSafeHarborAvalancheOnboarding, and the Avalanche LayerZero suite are not skipped
- ✅ active spell-specific tests such as
- IF the test needs to run, it MUST NOT have the
- Ensure each spell action has sufficient test coverage
- ✅ Launch Avalanche SkyLink:
testWireLzGovSenderAvalanche,testWireUsdsOftAvalanche,testWireSUsdsOftAvalanche,testUsdsOftAvalancheRateLimits,testOftPauseUnpause,testGovernanceRelayAvalancheE2E,testUsdsOftAvalancheE2E,testSUsdsOftAvalancheRateLimitBlocked - ✅ Staking Rewards Update:
testVestSky,testVestedRewardsDist - ✅ Grove Genesis Capital Transfer:
testPayments - ✅ Safe Harbor Update:
testUpdateSafeHarborAddedAccounts,testSafeHarborAvalancheOnboarding - ✅ Prime Agent Proxy Spells:
testPrimeAgentSpellExecutions - ✅ ChainLog update:
testChainlogIntegrity,testChainlogValues,testAddedChainlogKeys
- ✅ Launch Avalanche SkyLink:
- Ensure that any other env variable does not affect execution of the tests (for example, by inspecting the output of
printenv | grep "FOUNDRY_\|DAPP_")- ✅
printenv | grep "FOUNDRY_\\|DAPP_"returned no matches
- ✅
IF a new module is initialized via the spell, the tests must include-
Sanity checks of the constructor arguments -
Sanity checks of all values added/updated by the spell function -
End-to-end "happy path" interaction with the module
-
- Check all tests are passing locally using
make test- Ensure every test listed in the coverage item above is present in the logs and with the
[PASS]prefix.
- Ensure every test listed in the coverage item above is present in the logs and with the
- Ensure that the
./scripts/test-dssspell-forge.sh no-match="" match="" block=""
No files changed, compilation skipped
Ran 2 tests for src/test/starknet.t.sol:StarknetTests
[PASS] testStarknet() (gas: 3237469)
[PASS] testStarknetSpell() (gas: 2391)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 37.92s (32.79s CPU time)
Ran 60 tests for src/DssSpell.t.sol:DssSpellTest
[PASS] testAddedChainlogKeys() (gas: 3081613)
[SKIP] testAllocatorIntegration() (gas: 0)
[SKIP] testArbitrumGovRelay() (gas: 0)
[SKIP] testBaseGovRelay() (gas: 0)
[SKIP] testBytecodeMatches() (gas: 0)
[PASS] testCastCost() (gas: 3070311)
[PASS] testCastOnTime() (gas: 3065994)
[PASS] testChainlogIntegrity() (gas: 8452389)
[PASS] testChainlogValues() (gas: 13901299)
[SKIP] testCollateralIntegrations() (gas: 0)
[PASS] testContractSize() (gas: 15854)
[SKIP] testDaoResolutions() (gas: 0)
[PASS] testDeployCost() (gas: 5441968)
[SKIP] testEsmAuth() (gas: 0)
[PASS] testGeneral() (gas: 22287046)
[PASS] testGovernanceRelayAvalancheE2E() (gas: 4383721)
[SKIP] testIlkClipper() (gas: 0)
[SKIP] testL2ArbitrumSpell() (gas: 0)
[SKIP] testL2OptimismSpell() (gas: 0)
[SKIP] testLerpSurplusBuffer() (gas: 0)
[PASS] testLitePSMs() (gas: 4322390)
[SKIP] testLockstakeIlkIntegration() (gas: 0)
[SKIP] testMedianReaders() (gas: 0)
[SKIP] testMonthlySettlementCycleInflows() (gas: 0)
[SKIP] testNewAuthorizations() (gas: 0)
[SKIP] testNewCronJobs() (gas: 0)
[SKIP] testNewLineMomIlks() (gas: 0)
[PASS] testNextCastTime() (gas: 392563)
[SKIP] testOffboardings() (gas: 0)
[PASS] testOfficeHours() (gas: 439373)
[PASS] testOftPauseUnpause() (gas: 3183857)
[SKIP] testOptimismGovRelay() (gas: 0)
[SKIP] testOracleList() (gas: 0)
[SKIP] testOsmReaders() (gas: 0)
[PASS] testPSMs() (gas: 4409724)
[PASS] testPayments() (gas: 3183325)
[PASS] testPrimeAgentSpellExecutions() (gas: 10008891)
[SKIP] testRemovedChainlogKeys() (gas: 0)
[PASS] testRevertIfNotScheduled() (gas: 17530)
[PASS] testSPBEAMTauAndBudValues() (gas: 3082963)
[PASS] testSUsdsOftAvalancheRateLimitBlocked() (gas: 3315092)
[PASS] testSafeHarborAvalancheOnboarding() (gas: 7091005)
[PASS] testSplitter() (gas: 3588732)
[SKIP] testStarGuardInitialization() (gas: 0)
[PASS] testSystemTokens() (gas: 4060790)
[SKIP] testUnichainGovRelay() (gas: 0)
[PASS] testUpdateSafeHarborAddedAccounts() (gas: 7979889)
[PASS] testUsdsOftAvalancheE2E() (gas: 4792103)
[PASS] testUsdsOftAvalancheRateLimits() (gas: 3094675)
[PASS] testUseEta() (gas: 289131)
[SKIP] testVestDai() (gas: 0)
[SKIP] testVestMkr() (gas: 0)
[PASS] testVestSky() (gas: 3757829)
[SKIP] testVestSkyMint() (gas: 0)
[SKIP] testVestSpk() (gas: 0)
[SKIP] testVestUsds() (gas: 0)
[PASS] testVestedRewardsDist() (gas: 6136250)
[PASS] testWireLzGovSenderAvalanche() (gas: 3294287)
[PASS] testWireSUsdsOftAvalanche() (gas: 3441502)
[PASS] testWireUsdsOftAvalanche() (gas: 3413594)
Suite result: ok. 31 passed; 0 failed; 29 skipped; finished in 182.58s (1508.35s CPU time)
Ran 2 test suites in 182.83s (220.50s CPU time): 33 tests passed, 0 failed, 29 skipped (62 total tests)
Pre-Deployment Stage
- Wait till the Exec Doc is merged
- Exec Doc checks
- Exec Doc for the specified date is found in the
sky-ecosystem/executive-votesGitHub repo - Exec Doc is located in the directory matching the target spell date year (
YYYY/)- ✅ path prefix is
2026/, matching target date2026-04-09
- ✅ path prefix is
- Exec Doc file name follows the format
executive-vote-YYYY-MM-DD-optional-description.md- ✅
executive-vote-2026-04-09-launch-avalanche-skylink-staking-rewards-update.md
- ✅
- Extract permanent URL to the raw markdown file and paste it below
https://raw.githubusercontent.com/sky-ecosystem/executive-votes/656d5a6d9e8041203d98823248e64d87771681d3/2026/executive-vote-2026-04-09-launch-avalanche-skylink-staking-rewards-update.md - Ensure the URL uses commit hash that introduced last change to the Exec Doc, NOT merge commit
-
IF there is no local copy ofsky-ecosystem/executive-votesGitHub repo, run:git clone https://github.com/sky-ecosystem/executive-votes -
OTHERWISE, ensure it is pointing to the latest commit on main:git switch main && git pull origin main - Get the latest commit hash for the exec doc:
git log --pretty=oneline -1 -- "<LOCAL_PATH_TO_EXEC_DOC>"- ✅ GitHub commit history for the file shows latest content-changing commit
656d5a6d9e8041203d98823248e64d87771681d3
- ✅ GitHub commit history for the file shows latest content-changing commit
-
- Using Exec Doc URL from the above and the
TARGET_DATE, generate Exec Doc Hash viamake exec-hash date=$TARGET_DATE $URL
0x0f87466f280de3544ae715fb2463152d7959c37902926f2069aaaccf10cef550- ✅
make exec-hash date=2026-04-09returned the same hash and the same raw GitHub URL
- ✅
- Using Exec Doc URL from the above, generate Exec Doc Hash via
cast keccak -- "$(curl '$URL' -o - 2>/dev/null)"
0x0f87466f280de3544ae715fb2463152d7959c37902926f2069aaaccf10cef550 - Make sure that hash above doesn't match
keccakhash of the empty string (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) - Using Exec Doc URL from the above, read spell instructions from the Exec Doc and list them below
- Launch Avalanche SkyLink
- LSSKY->SKY Staking Rewards Update
- Grove Genesis Capital Transfer
- Safe Harbor Update
- Spark Proxy Spell
- Grove Proxy Spell
- Office hours value in the Exec Doc matches the spell
- ✅ Exec Doc says the spell can only be executed between
14:00and21:00 UTC, Monday - Friday;officeHours()returnstrue
- ✅ Exec Doc says the spell can only be executed between
- Sum of all payments in the Exec Doc matches the tests
- ✅ Exec Doc announces
20,797,477 USDStoGROVE_SUBPROXY;testPaymentschecksexpectedTotalPayments.usds = 20_797_477 ether
- ✅ Exec Doc announces
- Exec Doc URL in the spell comment matches your Raw Exec Doc URL above
- ✅
src/DssSpell.sol:84uses the same raw URL with commit656d5a6d9e8041203d98823248e64d87771681d3
- ✅
- Exec Doc URL in the spell comment refers to the https://github.com/sky-ecosystem/executive-votes repository
- Every action present in the spell code is present in the Exec Doc
- Every action in the Exec Doc is present in the spell code
- Exec Doc for the specified date is found in the
IF new commits are present in the spell-
Copy relevant checklist items from the above and redo them -
Ensure newly added code is covered by tests -
Check if chainlog needs to be updated -
Copy over and redo "Tests" section from the above
-
- IF all checks pass, make sure to include explicit "Good to deploy" comment
|
Good to deploy: Development Stage
Pre-Deployment Stage
|
|
Spell has been deployed to 0x70Da14478667C08320Ef65506063abba84B6990f Foundry logs: |
|
Good to handover: Deployed Stage
|
|
TL;DR: Good to handover 🤝 Deployed Stage
|
SidestreamStrongStrawberry
left a comment
There was a problem hiding this comment.
Handover and Merge Stage
- Check that the spell address posted by the crafter in
new-spellsis correct - Confirm the address in the
new-spellschannel (via a separate "reply to" message, restating the address to avoid edits)- Wait until responsible governance facilitator confirms handover in
new-spells
- Wait until responsible governance facilitator confirms handover in
- Ensure that no changes were made to the code since the spell was deployed and archived
- Approve spell PR for merge via 'Approve' review option
amusingaxl
left a comment
There was a problem hiding this comment.
Handover and Merge Stage
- Check that the spell address posted by the crafter in
new-spellsis correct - Confirm the address in the
new-spellschannel (via a separate "reply to" message, restating the address to avoid edits)- Wait until responsible governance facilitator confirms handover in
new-spells
- Wait until responsible governance facilitator confirms handover in
- Ensure that no changes were made to the code since the spell was deployed and archived
- Approve spell PR for merge via 'Approve' review option
Description
Contribution Checklist
(PE-<TICKET_NUMBER>)Checklist
officeHoursmodifier override30 daysunless otherwise specified)ETH_GAS_LIMIT="XXX" ETH_GAS_PRICE="YYY" make deploymainnetcontract on etherscanmake archive-spellormake date="YYYY-MM-DD" archive-spellto make an archive directory and copyDssSpell.sol,DssSpell.t.sol,DssSpell.t.base.sol, andDssSpellCollateralOnboarding.solsquash and mergethis PR