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

March 20th, 2025 Spell #87

Merged
merged 15 commits into from
Mar 20, 2025
Merged

March 20th, 2025 Spell #87

merged 15 commits into from
Mar 20, 2025

Conversation

hexonaut
Copy link
Contributor

@hexonaut hexonaut commented Mar 12, 2025

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

  • Create new BTC emode category
  • Onboard LBTC as collateral, add to emode
  • Onboard tBTC as collateral, don't add to emode
  • Add cbBTC to new emode category
  • Onboard ezETH as collateral
  • Onboard rsETH as collateral
  • Morpho Spark DAI Vault - Onboard May eUSDe PT
  • Morpho Spark DAI Vault - Onboard July USDe PT
  • Update USDS and DAI IRM to 50bps spread

Base

  • Update the Morpho pending supply cap on cbBTC market to be 500m

Arbitrum

  • Onboard Aave USDC
  • Onboard Fluid sUSDS (!!! THIS IS BEING PUSHED BECAUSE NOT AVAILABLE !!!)

Addresses

variable name address network source of truth
AGGOR_BTCUSD_ORACLE 0x4219aA1A99f3fe90C2ACB97fCbc1204f6485B537 mainnet Specified in LBTC risk assessment (same in tBTC risk assessment)
CBBTC_USDC_ORACLE 0x663BECd10daE6C4A3Dcd89F1d76c1174199639B9 base Taken from previous spell payload, can be verified since the market params returned 100m for the existing supply cap with this value.
EZETH_ORACLE 0x52E85eB49e07dF74c8A9466D2164b4C4cA60014A mainnet Deployed by Phoenix Labs
RSETH_ORACLE 0x70942D6b580741CF50A7906f4100063EE037b8eb mainnet Deployed by Phoenix Labs
PT_EUSDE_29MAY2025 0x50D2C7992b802Eef16c04FeADAB310f31866a545 mainnet Address in Pendle Telegram
PT_EUSDE_29MAY2025_PRICE_FEED 0x39a695Eb6d0C01F6977521E5E79EA8bc232b506a mainnet Address in Pendle Telegram
PT_USDE_31JUL2025 0x917459337CaAC939D41d7493B3999f571D20D667 mainnet Address in Pendle Telegram
PT_USDE_31JUL2025_PRICE_FEED 0xFCaE69BEF9B6c96D89D58664d8aeA84BddCe2E5c mainnet Address in Pendle Telegram
DAI_IRM 0x5a7E7a32331189a794ac33Fec76C0A1dD3dDCF9c mainnet Deployed by Phoenix Labs
USDS_IRM 0xD94BA511284d2c56F59a687C3338441d33304E07 mainnet Deployed by Phoenix Labs

Sorry, something went wrong.

@hexonaut hexonaut marked this pull request as ready for review March 14, 2025 09:21
Copy link
Contributor

@lucas-manuel lucas-manuel left a 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

Sorry, something went wrong.

Copy link

github-actions bot commented Mar 17, 2025

Spell Caster

Inspect the impact of spell execution on forked networks:

Spell App URL RPC URL
SparkEthereum_20250320 🎇 App 🌎 RPC
SparkBase_20250320 🎇 App 🌎 RPC
SparkArbitrumOne_20250320 🎇 App 🌎 RPC

Deployed from 848d2dd on 2025-03-20T18:20:32.371Z

@lucas-manuel
Copy link
Contributor

lucas-manuel commented Mar 17, 2025

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

@hexonaut
Copy link
Contributor Author

I've added the pt oracle tests.

Copy link
Contributor

@lucas-manuel lucas-manuel left a 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()) {
Copy link
Contributor

@lucas-manuel lucas-manuel Mar 17, 2025

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

Copy link
Contributor Author

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

Comment on lines 366 to 367
ForeignController controller = ForeignController(Arbitrum.ALM_CONTROLLER);
IRateLimits rateLimits = IRateLimits(Arbitrum.ALM_RATE_LIMITS);
Copy link
Contributor

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);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not relevant anymore.

@lucas-manuel
Copy link
Contributor

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

  • 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
  • Check USDS and DAI IRM bytecode against sparklend-advanced v1.5.0 commit (full matches)
  • 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

Sorry, something went wrong.

Copy link
Contributor

@lucas-manuel lucas-manuel left a 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

Comment on lines 164 to 230
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);
}
}

Copy link
Contributor

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);
        }
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

RedLikeRosesss
RedLikeRosesss previously approved these changes Mar 20, 2025
Copy link
Collaborator

@RedLikeRosesss RedLikeRosesss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lucas-manuel
lucas-manuel previously approved these changes Mar 20, 2025
@hexonaut hexonaut merged commit 8609090 into master Mar 20, 2025
1 check passed
@hexonaut hexonaut deleted the spell-2025-03-20 branch March 20, 2025 18:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants