-
Notifications
You must be signed in to change notification settings - Fork 26
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
March 20th, 2025 Spell #87
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intermediate review, so far:
Mainnet
- Verify LBTC onboarding params match March 6 spell
- Verify tBTC onboarding params match March 6 spell
- Verify emode configuration matches March 6 spell
- Verify cbBTC emode configuration matches March 6 spell
- Verify supply/borrow cap config for LBTC and tBTC matches March 6 spell
- Verify emode test matches March 6 spell
- Verify cbBTC emode test matches March 6 spell
- Verify LBTC and tBTC onboarding params test matches March 6 spell
- Onboard ezETH as collateral
- Verify ezETH oracle address bytecode against sparklend-advanced v1.5.0 commit (partial matches)
- Onboard rsETH as collateral
- Verify rsETH oracle address bytecode against sparklend-advanced v1.5.0 commit (full matches)
- Check all new assets’ markets are seeded
- Morpho Spark DAI Vault - Onboard May eUSDe PT
- Morpho Spark DAI Vault - Onboard July USDe PT
- Update USDS and DAI IRM to 50bps spread
- Review forum links
- Review addresses
Base
- Review equivalence with old base spell
- Review forum links
- Review addresses
Arbitrum
- Onboard Aave USDC
- Review forum links
- Review addresses
We should put this into a helper function to always use with PT token oracles to make sure they are configured as expected (from SparkEthereum_20250109.t.sol): // --- Test the May PT Oracle in more detail ---
uint256 ptSUSDE29MAY2025Price = IMorphoChainlinkOracle(PT_SUSDE_29MAY2025_PRICE_FEED).price();
assertEq(ptSUSDE29MAY2025Price, 0.903243903792491122e36);
uint256 timeSkip = 60 days;
skip(timeSkip);
uint256 newPTSUSDE29MAY2025Price = IMorphoChainlinkOracle(PT_SUSDE_29MAY2025_PRICE_FEED).price();
// Price for both feeds increases over time
assertGt(newPTSUSDE29MAY2025Price, ptSUSDE29MAY2025Price);
uint256 ptSUSDE29MAY2025YearlyPriceIncrease = (newPTSUSDE29MAY2025Price - ptSUSDE29MAY2025Price) * 365 days / (timeSkip);
// Calculated yield should equal the expected one
assertApproxEqAbs(ptSUSDE29MAY2025YearlyPriceIncrease / 1e18, PT_SUSDE_29MAY2025_YIELD, 4);
assertLt(IMorphoChainlinkOracle(PT_SUSDE_29MAY2025_PRICE_FEED).price(), 1e36);
// Prices on maturity should be 1e36
vm.warp(IPendlePT(PT_SUSDE_29MAY2025).expiry());
assertEq(IMorphoChainlinkOracle(PT_SUSDE_29MAY2025_PRICE_FEED).price(), 1e36);
skip(365 days);
// Prices should remain to be 1e36
assertEq(IMorphoChainlinkOracle(PT_SUSDE_29MAY2025_PRICE_FEED).price(), 1e36); Can remove first hard value assertion and pass in an expected annual yield and due date as params |
I've added the pt oracle tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spell logic LGTM, don't we need to update deployed spell with updated links? I know no logic will change but for verified contract. Also note to self still need to review PT helper tests.
But yeah spell LGTM.
assertEq(ausdc.balanceOf(Arbitrum.ALM_PROXY), 0); | ||
} | ||
|
||
function test_ARBITRUM_AaveRateLimits() public onChain(ChainIdUtils.ArbitrumOne()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be in a helper function, along with the logic in test_ARBITRUM_AaveOnboardingIntegration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switched to match the morpho onboarding style
ForeignController controller = ForeignController(Arbitrum.ALM_CONTROLLER); | ||
IRateLimits rateLimits = IRateLimits(Arbitrum.ALM_RATE_LIMITS); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ForeignController controller = ForeignController(Arbitrum.ALM_CONTROLLER);
IRateLimits rateLimits = IRateLimits(Arbitrum.ALM_RATE_LIMITS);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not relevant anymore.
Review of code finished, spell LGTM. Still some small outstanding stuff so we can have easier onboardings in the future. Not a blocker for Sky spell. Mainnet
Base
Arbitrum
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting and a TODO comment and LGTM
function _testAaveOnboarding( | ||
address atoken, | ||
uint256 expectedDepositAmount, | ||
uint256 depositMax, | ||
uint256 depositSlope | ||
) internal { | ||
SparkLiquidityLayerContext memory ctx = _getSparkLiquidityLayerContext(); | ||
bool unlimitedDeposit = depositMax == type(uint256).max; | ||
|
||
// Note: Aave signature is the same for mainnet and foreign | ||
deal(IAToken(atoken).UNDERLYING_ASSET_ADDRESS(), address(ctx.proxy), expectedDepositAmount); | ||
bytes32 depositKey = RateLimitHelpers.makeAssetKey( | ||
MainnetController(ctx.controller).LIMIT_AAVE_DEPOSIT(), | ||
atoken | ||
); | ||
bytes32 withdrawKey = RateLimitHelpers.makeAssetKey( | ||
MainnetController(ctx.controller).LIMIT_AAVE_WITHDRAW(), | ||
atoken | ||
); | ||
|
||
_assertRateLimit(depositKey, 0, 0); | ||
_assertRateLimit(withdrawKey, 0, 0); | ||
|
||
vm.prank(ctx.relayer); | ||
vm.expectRevert("RateLimits/zero-maxAmount"); | ||
MainnetController(ctx.controller).depositAave(atoken, expectedDepositAmount); | ||
|
||
executeAllPayloadsAndBridges(); | ||
|
||
_assertRateLimit(depositKey, depositMax, depositSlope); | ||
_assertRateLimit(withdrawKey, type(uint256).max, 0); | ||
|
||
if (!unlimitedDeposit) { | ||
vm.prank(ctx.relayer); | ||
vm.expectRevert("RateLimits/rate-limit-exceeded"); | ||
MainnetController(ctx.controller).depositAave(atoken, depositMax + 1); | ||
} | ||
|
||
assertEq(ctx.rateLimits.getCurrentRateLimit(depositKey), depositMax); | ||
assertEq(ctx.rateLimits.getCurrentRateLimit(withdrawKey), type(uint256).max); | ||
|
||
vm.prank(ctx.relayer); | ||
MainnetController(ctx.controller).depositAave(atoken, expectedDepositAmount); | ||
|
||
assertEq(ctx.rateLimits.getCurrentRateLimit(depositKey), unlimitedDeposit ? type(uint256).max : depositMax - expectedDepositAmount); | ||
assertEq(ctx.rateLimits.getCurrentRateLimit(withdrawKey), type(uint256).max); | ||
|
||
vm.prank(ctx.relayer); | ||
MainnetController(ctx.controller).withdrawAave(atoken, expectedDepositAmount / 2); | ||
|
||
assertEq(ctx.rateLimits.getCurrentRateLimit(depositKey), unlimitedDeposit ? type(uint256).max : depositMax - expectedDepositAmount); | ||
assertEq(ctx.rateLimits.getCurrentRateLimit(withdrawKey), type(uint256).max); | ||
|
||
if (!unlimitedDeposit) { | ||
// Do some sanity checks on the slope | ||
// This is to catch things like forgetting to divide to a per-second time, etc | ||
|
||
// We assume it takes at least 1 day to recharge to max | ||
uint256 dailySlope = depositSlope * 1 days; | ||
assertLe(dailySlope, depositMax); | ||
|
||
// It shouldn't take more than 30 days to recharge to max | ||
uint256 monthlySlope = depositSlope * 30 days; | ||
assertGe(monthlySlope, depositMax); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting and LGTM
// TODO: Add balance assertions to all helper functions
function _testAaveOnboarding(
address aToken,
uint256 expectedDepositAmount,
uint256 depositMax,
uint256 depositSlope
) internal {
SparkLiquidityLayerContext memory ctx = _getSparkLiquidityLayerContext();
MainnetController controller = MainnetController(ctx.controller);
bool unlimitedDeposit = depositMax == type(uint256).max;
// Note: Aave signature is the same for mainnet and foreign
deal(IAToken(aToken).UNDERLYING_ASSET_ADDRESS(), address(ctx.proxy), expectedDepositAmount);
bytes32 depositKey = RateLimitHelpers.makeAssetKey(controller.LIMIT_AAVE_DEPOSIT(), aToken);
bytes32 withdrawKey = RateLimitHelpers.makeAssetKey(controller.LIMIT_AAVE_WITHDRAW(), aToken);
_assertRateLimit(depositKey, 0, 0);
_assertRateLimit(withdrawKey, 0, 0);
vm.prank(ctx.relayer);
vm.expectRevert("RateLimits/zero-maxAmount");
controller.depositAave(aToken, expectedDepositAmount);
executeAllPayloadsAndBridges();
_assertRateLimit(depositKey, depositMax, depositSlope);
_assertRateLimit(withdrawKey, type(uint256).max, 0);
if (!unlimitedDeposit) {
vm.prank(ctx.relayer);
vm.expectRevert("RateLimits/rate-limit-exceeded");
controller.depositAave(aToken, depositMax + 1);
}
assertEq(ctx.rateLimits.getCurrentRateLimit(depositKey), depositMax);
assertEq(ctx.rateLimits.getCurrentRateLimit(withdrawKey), type(uint256).max);
vm.prank(ctx.relayer);
controller.depositAave(aToken, expectedDepositAmount);
assertEq(ctx.rateLimits.getCurrentRateLimit(depositKey), unlimitedDeposit ? type(uint256).max : depositMax - expectedDepositAmount);
assertEq(ctx.rateLimits.getCurrentRateLimit(withdrawKey), type(uint256).max);
vm.prank(ctx.relayer);
controller.withdrawAave(aToken, expectedDepositAmount / 2);
assertEq(ctx.rateLimits.getCurrentRateLimit(depositKey), unlimitedDeposit ? type(uint256).max : depositMax - expectedDepositAmount);
assertEq(ctx.rateLimits.getCurrentRateLimit(withdrawKey), type(uint256).max);
if (!unlimitedDeposit) {
// Do some sanity checks on the slope
// This is to catch things like forgetting to divide to a per-second time, etc
// We assume it takes at least 1 day to recharge to max
uint256 dailySlope = depositSlope * 1 days;
assertLe(dailySlope, depositMax);
// It shouldn't take more than 30 days to recharge to max
uint256 monthlySlope = depositSlope * 30 days;
assertGe(monthlySlope, depositMax);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2025-03-20 Spark Spell
Please note this combines the last spell and the current one because the previous one did not execute.
Forum Post
https://forum.sky.money/t/march-6-2025-proposed-changes-to-spark-for-upcoming-spell/26036
https://forum.sky.money/t/march-20-2025-proposed-changes-to-spark-for-upcoming-spell/26113
Dependencies on Maker Core spell
None
List of intended changes
Mainnet
Base
Arbitrum
Addresses
AGGOR_BTCUSD_ORACLE
0x4219aA1A99f3fe90C2ACB97fCbc1204f6485B537
mainnet
CBBTC_USDC_ORACLE
0x663BECd10daE6C4A3Dcd89F1d76c1174199639B9
base
EZETH_ORACLE
0x52E85eB49e07dF74c8A9466D2164b4C4cA60014A
mainnet
RSETH_ORACLE
0x70942D6b580741CF50A7906f4100063EE037b8eb
mainnet
PT_EUSDE_29MAY2025
0x50D2C7992b802Eef16c04FeADAB310f31866a545
mainnet
PT_EUSDE_29MAY2025_PRICE_FEED
0x39a695Eb6d0C01F6977521E5E79EA8bc232b506a
mainnet
PT_USDE_31JUL2025
0x917459337CaAC939D41d7493B3999f571D20D667
mainnet
PT_USDE_31JUL2025_PRICE_FEED
0xFCaE69BEF9B6c96D89D58664d8aeA84BddCe2E5c
mainnet
DAI_IRM
0x5a7E7a32331189a794ac33Fec76C0A1dD3dDCF9c
mainnet
USDS_IRM
0xD94BA511284d2c56F59a687C3338441d33304E07
mainnet