feat: Spell 2026-07-16 (SC-1573) - #174
Conversation
Summary by OctaneNew Contracts
Updated Contracts
🔗 Commit Hash: 20510f7 |
WalkthroughThis PR onboards Robinhood and XLayer chains into the Spark protocol: adding chain-id helpers, cross-chain payload dispatch, new mainnet and Robinhood proposal contracts, test-harness wiring (forks, bridges, LayerZero rework), and new integration/E2E test suites, alongside CI and submodule updates. ChangesCore chain support and proposal payloads
Test harness and E2E test coverage
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
feat: add rh test
Overview
🔗 Commit Hash: 20510f7 |
* feat: add xlayer integration tests * feat: update to merge latest
* fix: update e2e tests * fix: rm prompt diff
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (5)
src/proposals/20260716/XLayer_20260716.t.sol (2)
505-511: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueNo-op
skip(0)statement.
skip(0)performs no time advancement and the comment already explains the delay is 0; the call itself is dead weight.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/proposals/20260716/XLayer_20260716.t.sol` around lines 505 - 511, The test in XLayer_20260716.t.sol contains a no-op time advance in the relay flow, where the Executor delay is already documented as zero. Remove the redundant skip call from the sequence around relayMessagesToDestination so the step remains clear and only meaningful state changes are left.
40-208: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSignificant duplication between
XLayerConfigTestsandXLayerE2ETests.Both contracts redeclare identical constants (
ALM_PROXY,CONTROLLER,RATE_LIMITS,SPUSDT_VAULT,EXECUTOR,RELAYER_1,SETTER,USDT) and an almost-identicalsetUp(). Extracting a shared abstract base contract would reduce the risk of the two sets of constants drifting apart.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/proposals/20260716/XLayer_20260716.t.sol` around lines 40 - 208, The two test contracts duplicate the same environment constants and fork setup, so they can drift independently. Extract the shared addresses and `setUp()` logic into a common abstract base contract, then have `XLayerConfigTests` and `XLayerE2ETests` inherit from it and keep only contract-specific constants like `USER` or APY values in each subclass.src/proposals/20260716/Spell_20260716.t.sol (1)
44-44: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueImport
OptionsBuilderthrough a remapping
This hard-codeslib/xchain-helpers/lib/devtools/...and ties the file to xchain-helpers' internal layout. A package alias for the OApp library would keep the import stable if that subtree moves.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/proposals/20260716/Spell_20260716.t.sol` at line 44, The import of OptionsBuilder is hard-coded to the xchain-helpers internal path, which makes Spell_20260716.t.sol brittle if that layout changes. Update the import to use the existing remapping or package alias for the OApp library instead of referencing the nested lib/xchain-helpers/lib/devtools path directly, so the import is resolved through a stable symbol path.src/test-harness/SparkLiquidityLayerTests.sol (1)
4682-4689: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueOptional: this now duplicates
_getPostExecutionIntegrationsNoChange.After dropping the appended entries,
_getPostExecutionIntegrationsArbitrumOneis a plain copy identical to_getPostExecutionIntegrationsNoChange; the dispatcher could route ArbitrumOne there instead of keeping a near-duplicate helper.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test-harness/SparkLiquidityLayerTests.sol` around lines 4682 - 4689, The ArbitrumOne post-execution integrations helper is now a near-duplicate of the no-change helper, so remove the redundant copy by routing the ArbitrumOne branch through _getPostExecutionIntegrationsNoChange instead of keeping separate identical logic. Update the dispatcher and keep the shared behavior centralized in _getPostExecutionIntegrationsNoChange so future changes only need one implementation.src/test-harness/SpellRunner.sol (1)
114-117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider sourcing the XLayer RPC from an env var like the other chains.
Unichain and Robinhood read their RPC from
vm.envString(...), but XLayer hardcodes the public endpointhttps://rpc.xlayer.tech. Public endpoints tend to rate-limit/flake in CI (and this path already fans out ~20 forks per binary-search call). AnXLAYER_RPC_URLenv var would match the existing convention and improve CI reliability.♻️ Suggested change
setChain("xlayer", ChainData({ name : "XLayer", - rpcUrl : "https://rpc.xlayer.tech", + rpcUrl : vm.envString("XLAYER_RPC_URL"), chainId : 196 }));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test-harness/SpellRunner.sol` around lines 114 - 117, The XLayer chain setup in SpellRunner hardcodes the public RPC endpoint instead of following the env-based pattern used by the other chains. Update the XLayer entry in the chain registration logic to read the RPC URL from an XLAYER_RPC_URL environment variable via vm.envString, matching the existing Unichain and Robinhood setup and keeping the XLayer name/chainId configuration intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/libraries/DealUtils.sol`:
- Around line 81-87: The Robinhood/USDG branch in DealUtils.sol currently
subtracts amount - startingBalance unconditionally, which can underflow when
amount is below the starting balance. Update the balance adjustment logic in
that Robinhood USDG path to handle both directions explicitly: keep the top-up
flow for amount > startingBalance, and use the opposite delta for the drain case
when amount < startingBalance, so the transfer amount is always non-negative.
Refer to the Robinhood, USDG_ROBINHOOD, and USDG_ROBINHOOD_WHALE handling in the
balance adjustment helper to make the fix in the right branch.
In `@src/proposals/20260716/SparkEthereum_20260716.sol`:
- Around line 40-42: `SparkEthereum_20260716.sol` still uses placeholder dead
addresses for `ANCHORAGE_FEES_RECIPIENT` and `INCENTIVES_RECIPIENT`, so
`_postExecute()` in the proposal would transfer USDS to the wrong targets.
Replace those constants with the real recipient addresses (or wire them through
the intended configuration path) before execution, and verify the downstream
transfers in `_postExecute()` use the corrected values.
- Around line 56-58: The constructor in SparkEthereum_20260716 currently leaves
PAYLOAD_ROBINHOOD unset, so SparkPayloadEthereum.execute() will skip the
Robinhood leg. Update the SparkEthereum_20260716 constructor to initialize
PAYLOAD_ROBINHOOD with the deployed SparkRobinhood_20260716 address so the
payload is queued correctly.
In `@src/proposals/20260716/Spell_20260716.t.sol`:
- Around line 661-664: The fund-transfer test is still using placeholder
recipient constants, and both ANCHORAGE_FEES_RECIPIENT and INCENTIVES_RECIPIENT
point to the same dummy address marked TODO. Update the recipient values in
Spell_20260716.t.sol so the payload uses the finalized real addresses for the
treasury transfer flow, and verify the related
testETHEREUM_sparkTreasury_transfers assertions still match the intended
recipients before deployment.
In `@src/proposals/20260716/XLayer_20260716.t.sol`:
- Around line 210-341: The test still carries USDG/SPUSDG template leftovers,
which makes the USDT-based scenario confusing. In test_boundary_depositCap and
test_E2E, rename the misleading IERC20 variable and update the stale comments so
they consistently refer to USDT and the SPUSDT vault, using the identifiers
USDT, spusdtVault, and test_boundary_depositCap/test_E2E to locate the affected
spots. Keep the assertions and behavior unchanged, but make the narrative and
naming match the actual token/vault under test.
- Line 73: The XLayer fork setup is hardcoded to a public RPC endpoint, so
update both setUp() paths that call vm.createSelectFork in XLayer_20260716.t.sol
to read the URL from an environment variable instead of using the literal
xlayer.tech URL. Also change the XLayer chain config entry that currently pins
the same public endpoint to use that configurable value so the proposal tests no
longer depend on a public RPC.
---
Nitpick comments:
In `@src/proposals/20260716/Spell_20260716.t.sol`:
- Line 44: The import of OptionsBuilder is hard-coded to the xchain-helpers
internal path, which makes Spell_20260716.t.sol brittle if that layout changes.
Update the import to use the existing remapping or package alias for the OApp
library instead of referencing the nested lib/xchain-helpers/lib/devtools path
directly, so the import is resolved through a stable symbol path.
In `@src/proposals/20260716/XLayer_20260716.t.sol`:
- Around line 505-511: The test in XLayer_20260716.t.sol contains a no-op time
advance in the relay flow, where the Executor delay is already documented as
zero. Remove the redundant skip call from the sequence around
relayMessagesToDestination so the step remains clear and only meaningful state
changes are left.
- Around line 40-208: The two test contracts duplicate the same environment
constants and fork setup, so they can drift independently. Extract the shared
addresses and `setUp()` logic into a common abstract base contract, then have
`XLayerConfigTests` and `XLayerE2ETests` inherit from it and keep only
contract-specific constants like `USER` or APY values in each subclass.
In `@src/test-harness/SparkLiquidityLayerTests.sol`:
- Around line 4682-4689: The ArbitrumOne post-execution integrations helper is
now a near-duplicate of the no-change helper, so remove the redundant copy by
routing the ArbitrumOne branch through _getPostExecutionIntegrationsNoChange
instead of keeping separate identical logic. Update the dispatcher and keep the
shared behavior centralized in _getPostExecutionIntegrationsNoChange so future
changes only need one implementation.
In `@src/test-harness/SpellRunner.sol`:
- Around line 114-117: The XLayer chain setup in SpellRunner hardcodes the
public RPC endpoint instead of following the env-based pattern used by the other
chains. Update the XLayer entry in the chain registration logic to read the RPC
URL from an XLAYER_RPC_URL environment variable via vm.envString, matching the
existing Unichain and Robinhood setup and keeping the XLayer name/chainId
configuration intact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 6d9716e3-0c46-4f56-8029-9acb8d9f39a3
📒 Files selected for processing (22)
.github/workflows/test.ymlarchive/20260702/SparkArbitrumOne_20260702.solarchive/20260702/SparkAvalanche_20260702.solarchive/20260702/SparkBase_20260702.solarchive/20260702/SparkEthereum_20260702.solarchive/20260702/SparkOptimism_20260702.solarchive/20260702/SparkUnichain_20260702.solarchive/20260702/Spell_20260702.t.soldiffs/20260716-Ethereum-0xC13e21B648A5Ee794902342038FF3aDAB66BE987-pre_20260716-Ethereum-0xC13e21B648A5Ee794902342038FF3aDAB66BE987-post.mdlib/spark-address-registrylib/xchain-helperssrc/SparkPayloadEthereum.solsrc/interfaces/Interfaces.solsrc/libraries/ChainIdUtils.solsrc/libraries/DealUtils.solsrc/proposals/20260716/SparkEthereum_20260716.solsrc/proposals/20260716/SparkRobinhood_20260716.solsrc/proposals/20260716/Spell_20260716.t.solsrc/proposals/20260716/XLayer_20260716.t.solsrc/test-harness/SparkLiquidityLayerTests.solsrc/test-harness/SpellRunner.solsrc/test-harness/SpellTests.sol
| * Forum: https://forum.skyeco.com/t/july-16-2026-proposed-changes-to-spark-for-upcoming-spell/28029 | ||
| * Vote: https://snapshot.org/#/s:sparkfi.eth/proposal/0xd177bc28b65afb23dc39a5e7cfdded7084b3b722b230e08d7067b68fa0f4486a | ||
| */ | ||
| contract SparkXLayer_20260716 { |
There was a problem hiding this comment.
Need a test for this before after state
There was a problem hiding this comment.
Approving spell for the deployment
- SLL Activate SLL and Spark Savings Infra [Robinhood] - [1a] - DONE
- SLL roles
- Check new ALM_RELAYER address has RELAYER role on controller -
0x0ca8f938Aba2214eA11eb451e795A8ef7B720C18 - Check Old relayer is revoked
- Check new ALM_BACKSTOP_RELAYER address has RELAYER role on controller -
0x52CC27896e641Cbe88F0aD36480839961A47CdF8 - Check Old backstop relayer is revoked
- Check new ALM_FREEZER address has RELAYER role on controller -
0x2d5Aa449FB8C5646C81BC3C1D2034c2d37F17099 - Check Old freezer is revoked
- Verify the test that asserts role grants and revokes -
test_ROBINHOOD_controllerRoleChanges
- Check new ALM_RELAYER address has RELAYER role on controller -
- SLL roles
- SLL Activate SLL and Spark Savings Infra [Robinhood] - [1b] - DONE
- spUSDG config
- Verify deposit cap is unchanged
- Verify max rate is unchanged
- spUSDG config
- SLL Activate SLL and Spark Savings Infra [Robinhood] - [1c] - DONE
- SLL ratelimits
- Check asset address against forum post -
USDG=0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 - Check recipient address against forum post -
0x17C0F5345d1144fdF670D14719077be3842E5087 - Check maxAmount against forum post. -
50_000_000e6 - Check slope against forum post. -
250_000_000e6/day - Verify the precision of the rate limit against the underlying asset -
6 - Check rate limit before and after state in a test -
test_ETHEREUM_sll_enableUsdgTransferToPaxosDeposit - Ensure that
_testTransferAssetIntegrationis run with new integration in spell tests
- Check asset address against forum post -
- SLL ratelimits
- SLL Enable USDG Bridging to Robinhood [Ethereum] - [2] - DONE
- SLL ratelimits - (Bridging is done via Paxos centralized bridge)
- Check asset address against forum post -
Ethereum.USDG - Check recipient address against forum post -
PAXOS_USDG_DEPOSIT=0xf752cF318dfF2C01575c98741AA52e7a34d873Fd - Check maxAmount against forum post -
50_000_000e6 - Check slope against forum post -
250_000_000e6/day - Verify the precision of the rate limit against the underlying asset -
6 - Check rate limit before and after state in a test -
test_ETHEREUM_sll_enableUsdgTransferToPaxosDeposit - Ensure that
_testTransferAssetIntegrationis run with new integration in spell tests
- Check asset address against forum post -
- SLL ratelimits - (Bridging is done via Paxos centralized bridge)
- Deploy spUSDT [XLayer] - [3] - DONE
- Review
xlayer-deploymentscripts and tests- Verify ALMProxy - DONE
-
Check that contract is verified on Oklink -
0x83A914C361bB729EB6BEBC8C7bA993667A0E6Df8 -
Check the release tag from which the contract is deployed -
v1.10.0 -
Manually verify the bytecode of the contract
➜ xlayer-deployment git:(feat/verify) forge verify-bytecode 0x83A914C361bB729EB6BEBC8C7bA993667A0E6Df8 ALMProxy --constructor-args $DEPLOYER --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract ALMProxy at address 0x83A914C361bB729EB6BEBC8C7bA993667A0E6Df8 Creation code matched with status partial Runtime code matched with status partial
-
Verify constructor arguments
- admin : (DEPLOYER, but replaced with
EXECUTORlater)
- admin : (DEPLOYER, but replaced with
-
Check that ALMProxy has only one admin (EXECUTOR) after deploy
-
Validate the test where the post deployment roles and state of ALMProxy is asserted -
test_postDeployState
-
- Verify RateLimits - DONE
-
Check that contract is verified on Oklink -
0x7F7E2286983994c4403Cf2B86758cE0e7bA666a8 -
Check the release tag from which the contract is deployed -
v1.10.0 -
Manually verify the bytecode of the contract
➜ xlayer-deployment git:(feat/verify) forge verify-bytecode 0x7F7E2286983994c4403Cf2B86758cE0e7bA666a8 RateLimits --rpc-url https://rpc.xlayer.tech--verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract RateLimits at address 0x7F7E2286983994c4403Cf2B86758cE0e7bA666a8 Creation code matched with status partial Runtime code matched with status partial
-
Verify constructor arguments
- admin : (DEPLOYER, but replaced with
EXECUTORlater)
- admin : (DEPLOYER, but replaced with
-
Check that RateLimits has only one admin (EXECUTOR) after deploy
-
Validate the test where the post deployment roles and state of RateLimits is asserted -
test_postDeployState
-
- Verify Controller - DONE
-
Check that contract is verified on Oklink -
0xf9187C99Ee842beABE8e2e346d958315BFc9331f -
Check the release tag from which the contract is deployed -
v1.10.0 -
Check constructor arguments
- Admin : (DEPLOYER, but replaced with
EXECUTORlater) - Proxy:
XLayer.ALM_PROXY - RateLimits:
XLayer.ALM_RATE_LIMITS - PSM: address(0)
- USDC: address(0)
- CCTP: address(0)
- Admin : (DEPLOYER, but replaced with
-
Manually verify the bytecode of the contract
# foundry.toml libraries = [ "lib/spark-alm-controller/src/libraries/LayerZeroLib.sol:LayerZeroLib:0xa44a27901ee51d657f59c75a61521e332cdc2e2e" ]
➜ xlayer-deployment git:(feat/verify) forge verify-bytecode 0xf9187C99Ee842beABE8e2e346d958315BFc9331f ForeignController --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract ForeignController at address 0xf9187C99Ee842beABE8e2e346d958315BFc9331f Creation code matched with status partial Runtime code matched with status partial
-
Check that all libraries are verified on Oklink
- LayerZeroLib -
0xa44a27901ee51d657f59c75a61521e332cdc2e2e
- LayerZeroLib -
-
Verify bytecode of all libraries against latest production release
- LayerZeroLib
➜ xlayer-deployment git:(feat/verify) ✗ forge verify-bytecode 0xa44a27901ee51d657f59c75a61521e332cdc2e2e LayerZeroLib --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract LayerZeroLib at address 0xA44A27901Ee51d657f59c75a61521E332cDC2E2E Creation code matched with status full Runtime code matched with status full
-
Check that Controller has only one admin (EXECUTOR) after deploy
-
Check that ALMProxy, RateLimits contract addresses linked to Controller are valid
-
Verify Controller has CONTROLLER_ROLE on ALMProxy and RateLimits
-
Check RELAYER_ROLE holders on controller
- Relayer 1 :
XLayer.ALM_RELAYER_MULTISIG - Relayer 2:
XLayer.ALM_BACKSTOP_RELAYER_MULTISIG
- Relayer 1 :
-
Check FREEZER_ROLE holders on controller -
XLayer.ALM_FREEZER_MULTISIG -
Verify the test where post controller deployment state and roles are asserted -
test_postDeployState
-
- Verify ALMProxyFreezable - DONE
-
Check that contract is verified on oklink -
0x9449ed367C60ea757544fd990B57e1C2D0Ec3A94 -
Check the release tag from which the contract is deployed - diamond-pau
v.1.12.0 -
Constructor args on explorer match expected deployment params - SPARK_EXECUTOR -
-
Manually verify bytecode
➜ diamond-pau git:(v1.12.0) ✗ forge verify-bytecode 0x9449ed367C60ea757544fd990B57e1C2D0Ec3A94 ALMProxyFreezable --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract ALMProxyFreezable at address 0x9449ed367C60ea757544fd990B57e1C2D0Ec3A94 Creation code matched with status partial Runtime code matched with status partial
-
Ensure
ALM_RELAYER_MULTISIGis added asALLOCATOR -
Ensure
ALM_BACKSTOP_RELAYER_MULTISIGis added asALLOCATOR -
Ensure
ALM_FREEZER_MULTISIGis added asFREEZER -
Add ALMProxyFreezable configuration test to check assert:
- DEFAULT_ADMIN_ROLE is set to governance(executor)
-
ALM_RELAYER_MULTISIGis added asALLOCATOR -
ALM_BACKSTOP_RELAYER_MULTISIGis added asALLOCATOR -
ALM_FREEZER_MULTISIGis added asFREEZER - Check that all of the above are the ONLY roles set using events data
-
Test :
test_almProxyFreezable_config
-
- SparkVaultV2 deployment and onboarding - DONE
-
Verify contract on Oklink -
XLayer.SPARK_VAULT_V2_SPUSDT -
Verify bytecode against latest release -
v1.0.1# Implementation ➜ xlayer-deployment git:(feat/verify) ✗ forge verify-bytecode 0xdCe929A335C75a1676EF5957A4D7a3b928C48820 SparkVault --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract SparkVault at address 0xdCe929A335C75a1676EF5957A4D7a3b928C48820 Creation code matched with status full Runtime code matched with status full # Vault (Proxy) ➜ xlayer-deployment git:(feat/verify) ✗ forge verify-bytecode 0xc358c90D32375721Cb3924320Fdc2F8B694347Ca ERC1967Proxy --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract ERC1967Proxy at address 0xc358c90D32375721Cb3924320Fdc2F8B694347Ca Creation code matched with status full Runtime code matched with status full
-
Check that
SETTER_ROLEis set to the ALMProxyFreezable-
XLayer.ALM_PROXY_FREEZABLE
-
-
Check that the
TAKER_ROLEis set to the ALMProxy -XLAYER.ALM_PROXY -
Check that the VSR bounds are set
# minVSR = 1e27 # maxVSR = SIX_PCT_APY = 1.000000001847694957439350562e27
-
Check that the vault is seeded, sending shares to address(1)
-
Check vault initialization
- name :
Spark Savings USDT - symbol:
spUSDT - decimals:
6 - deposit cap:
750_000_000e6
- name :
-
Ensure that transferAsset rate limit is set:
- Check asset address is the underlying address of the vault - USDT
- Check recipient address is the vault
- Check maxAmount - unlimited
- Check slope - unlimted
- Verify the precision of the rate limit data against the underlying asset
-
Ensure that the take rate limit is set:
- Check vault address is used
- Check maxAmount - unlimited
- Check slope - unlimited
- Verify the precision of the rate limit data against the underlying asset
-
Verify the test where post deploy state config and roles are tested -
test_vault_config
-
- Verify Governance bridge setup - DONE
- Verify Executor
-
Check that Executor is deployed -
XLayer.SPARK_EXECUTOR -
Check that Executor contract is verified on explorer
-
Manually verify that Executor is deployed from latest release
➜ spark-gov-relay git:(v1.0.1) forge verify-bytecode 0xCF5af6F53ceC74B791cb4182aC778ca9CD323510 Executor --rpc-url https://rpc.xlayer.tech --verifier-url"http://localhost:8443" --chain 196 Warning: This is a nightly build of Foundry. It is recommended to use the latest stable version. To mute this warning set `FOUNDRY_DISABLE_NIGHTLY_WARNING` in your environment. Verifying bytecode for contract Executor at address 0xCF5af6F53ceC74B791cb4182aC778ca9CD323510 [⠊] Compiling... [⠊] Compiling 56 files with Solc 0.8.25 [⠢] Solc 0.8.25 finished in 5.14s Compiler run successful! Creation code matched with status partial Runtime code matched with status partial
-
Check constructor arguments and validate
- delay :
0 - gracePeriod:
7 days
- delay :
-
Verify the DEFAULT_ADMIN_ROLE holder - EXECUTOR
-
Verify GUARDIAN_ROLE holders - NO guardian
-
Verify SUBMISSION_ROLE holders - RECEIVER
-
- Verify Receiver
-
Check the type of the Receiver (LZ, Arbitrum, Gnosis, etc) - Optimism
-
Check that correct Receiver is deployed and verified on explorer -
XLayer.SPARK_RECEIVER -
Manually verify that Receiver is deployed from latest release tag
➜ xchain-helpers git:(96c35ce) ✗ forge verify-bytecode 0x4bd50B9c00Ae19e8B59723F27645C7A5cCe7a4A0 OptimismReceiver --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Warning: This is a nightly build of Foundry. It is recommended to use the latest stable version. To mute this warning set `FOUNDRY_DISABLE_NIGHTLY_WARNING` in your environment. Verifying bytecode for contract OptimismReceiver at address 0x4bd50B9c00Ae19e8B59723F27645C7A5cCe7a4A0 [⠊] Compiling... No files changed, compilation skipped Creation code matched with status partial Runtime code matched with status partial
-
Check constructor arguments and validate
- L1Authority should be SPARK_PROXY
- Target should be newly deployed Executor
-
- Verify the e2e test of governance flow -
test_crosschainE2E_setVsrBounds- Deploy payload on XLayer chain to set VSR
- Deploy payload on mainnet to call receiver
-
PAUSE_PROXYcallsSPARK_PROXY.exec()to execute mainnet payload - Relay messages over bridge
- Wait executor delay (immediate - zero seconds)
- Assert VSR values
- Execute on
EXECUTOR - Assert VSR values
- Verify Executor
- Enable USDT0 bridging to Ethereum - DONE
- Check layerZeroRecipient set in XLayer ForeignController
- Check endpoint ID against LZ docs -
30101 - Check ALMProxy address is Mainnet ALMProxy -
Ethereum.ALM_PROXY
- Check endpoint ID against LZ docs -
- Check LZ rate limit is set for XLayer
- Check OFT address -
0x94BCCa6bdfd6A61817Ab0E960bFedE4984505554 - Check mainnet endpoint ID -
30101 - maxAmount : unlimited
- slope : unlimited
- Test :
test_controller_config,test_rateLimits_config
- Check OFT address -
- Review full e2e test -
test_XLAYER_sll_spUSDT_usdt0RoundTrip
- Check layerZeroRecipient set in XLayer ForeignController
- Verify ALMProxy - DONE
- Review
- SLL Enable USDT0 Bridging to XLayer [Ethereum] - [4] - DONE
- Check layerZeroRecipient set in MainnetController
- Check endpoint ID against LZ docs -
30274 - Check ALMProxy address is XLayer ALMProxy -
0x83A914C361bB729EB6BEBC8C7bA993667A0E6Df8
- Check endpoint ID against LZ docs -
- Check LZ rate limit is set for mainnet
- Check OFT address -
0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee - Check XLayer endpoint ID -
30274 - maxAmount :
5_000_000e6 - slope :
100_000_000e6/day - Test :
test_ETHEREUM_sll_enableUSDTBridgingToXLayer
- Check OFT address -
- Review full end to end test -
test_XLAYER_sll_spUSDT_usdt0RoundTrip
- Check layerZeroRecipient set in MainnetController
- SLL Deactivate Old USDT Morpho V2 Vault [Ethereum] - [5] - DONE
- Check the address of old morpho vault v2 -
0xc7CDcFDEfC64631ED6799C95e3b110cd42F2bD22 - Check deposit and withdraw ratelimits are set to zero
- Verify test asserting old mopho vault have zero rate limits -
test_ETHEREUM_sll_deactivateOldMorphoUsdtVault
- Check the address of old morpho vault v2 -
- Treasury Transfer [Ethereum] - [6] - DONE
- Check receiver address against forum post or address registry -
SPARK_FOUNDATION_MULTISIG=0x92e4629a4510AF5819d7D1601464C233599fF5ec - Check amount against forum post -
2_000_000e18 - Review that test decrements and increments funds from correct addresses -
test_ETHEREUM_sparkTreasury_transfers
- Check receiver address against forum post or address registry -
- Treasury Transfer [Ethereum] - [7] - DONE
- Check receiver address against forum post or address registry -
SPARK_ASSET_FOUNDATION_MULTISIG=0xEabCb8C0346Ac072437362f1692706BA5768A911 - Check amount against forum post -
500_000e18 - Review that test decrements and increments funds from correct addresses -
test_ETHEREUM_sparkTreasury_transfers
- Check receiver address against forum post or address registry -
- SLL Transfer USDS to Grove [Ethereum] - [8] - DONE
- Check Grove ALMProxy address -
GROVE_ALM_PROXY=0x491EDFB0B8b608044e227225C715981a30F3A44E - Check syrupUSDC transfer amount -
85_943_747.637271e6 - Check the syrupUSDC is converted to USDS amount
- Check converted USDS amount is minted for spark ALMProxy
- Check that minted USDS is transferred to Grove ALMProxy
- Check temporary role (relayer, controller) grants of Payload is revoked after transfer
- Verify the test that asserts the balance changes of Proxies from this transfer -
test_ETHEREUM_sll_transferUsdsToGrove
- Check Grove ALMProxy address -
- Withdraw reserves [Ethereum] - [9] - DONE
- Review SparkPayloadEthereum code for claiming all reserves
- Ensure stablecoins go to ALMProxy and everything else goes to Liquidation multisig
- Review that test decrements and increments funds from correct addresses for all reserves
- Treasury Transfer [Ethereum] - [10a] - DONE
- Check receiver address against forum post or address registry -
SPARK_FOUNDATION_MULTISIG=0x92e4629a4510AF5819d7D1601464C233599fF5ec - Check amount against forum post -
1_100_000e18 - Review that test decrements and increments funds from correct addresses -
test_ETHEREUM_sparkTreasury_transfers
- Check receiver address against forum post or address registry -
- Treasury Transfer [Ethereum] - [10b] - DONE
- Check receiver address against forum post or address registry -
SPARK_ASSET_FOUNDATION_MULTISIG=0xEabCb8C0346Ac072437362f1692706BA5768A911 - Check amount against forum post -
155_000e18 - Review that test decrements and increments funds from correct addresses -
test_ETHEREUM_sparkTreasury_transfers
- Check receiver address against forum post or address registry -
- Treasury Transfer [Ethereum] - [11] - DONE
- Check receiver address against forum post or address registry -
ALM_OPS_MULTISIG=0x2E1b01adABB8D4981863394bEa23a1263CBaeDfC - Check amount against forum post -
64_231e18 - Review that test decrements and increments funds from correct addresses -
test_ETHEREUM_sparkTreasury_transfers
- Check receiver address against forum post or address registry -
|
Currently Robinhood tests have major gaps, including:
We recommend including these tests and have written a separate test file that can be just added to |
| // SPDX-License-Identifier: AGPL-3.0 | ||
| pragma solidity ^0.8.25; | ||
|
|
||
| import { IRateLimits } from "spark-alm-controller/src/interfaces/IRateLimits.sol"; |
There was a problem hiding this comment.
Redundant dependency
| bytes32 MORPHO_VAULT_V2_USDT_DEPOSIT_KEY = RateLimitHelpers.makeAddressKey(almController.LIMIT_4626_DEPOSIT(), OLD_MORPHO_VAULT_V2_USDT); | ||
| bytes32 MORPHO_VAULT_V2_USDT_WITHDRAW_KEY = RateLimitHelpers.makeAddressKey(almController.LIMIT_4626_WITHDRAW(), OLD_MORPHO_VAULT_V2_USDT); | ||
|
|
||
| rateLimits.setRateLimitData(MORPHO_VAULT_V2_USDT_DEPOSIT_KEY, 0, 0); |
There was a problem hiding this comment.
There is no “before” comment, although the spark-spell-checklist says: “Every parameter change is clearly commented with before/after values.”
Perhaps it should be added here and in other relevant places in the code as well.
|
|
||
| import { IALMProxy } from "spark-alm-controller/src/interfaces/IALMProxy.sol"; | ||
| import { IRateLimits } from "spark-alm-controller/src/interfaces/IRateLimits.sol"; | ||
| import { MainnetController } from "spark-alm-controller/src/MainnetController.sol"; |
There was a problem hiding this comment.
Currently, the repo pins spark-alm-controller @ 3dbc7cb, which corresponds to the v1.9.0 release, but Ethereum.ALM_CONTROLLER, Robinhood.ALM_CONTROLLER, and XLayer.ALM_CONTROLLER were deployed from v1.10.0. Since both the spells and the test suite import controller sources from this library, consider updating the pin to v1.10.0 (984ec54)
8f599b4
certora-spark-review
left a comment
There was a problem hiding this comment.
Approving the spell for deployment.
unvariant-dev
left a comment
There was a problem hiding this comment.
Overall, we consider the spell ready for deployment and safe:
- Since this spell activates SLL contracts on Robinhood Chain and X Layer that were deployed by EOAs, we additionally verified their bytecode against the audited releases, along with their configuration and pre-spell roles. Report: https://gist.github.com/unvariant-dev/0ad1ecab8416aa89cb80b7f4bd312f86
- We also completed the Spark spell reviewer checklist: https://gist.github.com/unvariant-dev/c93de21536018d806ccb5b52f442dc82
0f04e56
deluca-mike
left a comment
There was a problem hiding this comment.
- SLL Activate SLL and Spark Savings Infra [Robinhood] - [1a]
- SLL roles
- Check new ALM_RELAYER address has RELAYER role on controller -
0x0ca8f938Aba2214eA11eb451e795A8ef7B720C18 - Check Old relayer is revoked
- Check new ALM_BACKSTOP_RELAYER address has RELAYER role on controller -
0x52CC27896e641Cbe88F0aD36480839961A47CdF8 - Check Old backstop relayer is revoked
- Check new ALM_FREEZER address has RELAYER role on controller -
0x2d5Aa449FB8C5646C81BC3C1D2034c2d37F17099 - Check Old freezer is revoked
- Verify the test that asserts role grants and revokes -
test_ROBINHOOD_roleChanges
- Check new ALM_RELAYER address has RELAYER role on controller -
- SLL roles
- SLL Activate SLL and Spark Savings Infra [Robinhood] - [1b]
- spUSDG config
- Verify deposit cap is unchanged
- Verify max rate is unchanged
- spUSDG config
- SLL Activate SLL and Spark Savings Infra [Robinhood] - [1c]
- SLL ratelimits
- Check asset address against forum post -
USDG=0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 - Check recipient address against forum post -
0x17C0F5345d1144fdF670D14719077be3842E5087 - Check maxAmount against forum post. -
50_000_000e6 - Check slope against forum post. -
250_000_000e6/day - Verify the precision of the rate limit against the underlying asset -
6 - Check rate limit before and after state in a test -
test_ETHEREUM_sll_enableUsdgTransferToPaxosDeposit - Ensure that
_testTransferAssetIntegrationis run with new integration in spell tests
- Check asset address against forum post -
- SLL ratelimits
- SLL Enable USDG Bridging to Robinhood [Ethereum] - [2]
- SLL ratelimits - (Bridging is done via Paxos centralized bridge)
- Check asset address against forum post -
Ethereum.USDG - Check recipient address against forum post -
PAXOS_USDG_DEPOSIT=0xf752cF318dfF2C01575c98741AA52e7a34d873Fd - Check maxAmount against forum post -
50_000_000e6 - Check slope against forum post -
250_000_000e6/day - Verify the precision of the rate limit against the underlying asset -
6 - Check rate limit before and after state in a test -
test_ETHEREUM_sll_enableUsdgTransferToPaxosDeposit - Ensure that
_testTransferAssetIntegrationis run with new integration in spell tests
- Check asset address against forum post -
- SLL ratelimits - (Bridging is done via Paxos centralized bridge)
- Deploy spUSDT [XLayer] - [3]
- Review
xlayer-deploymentscripts and tests- Verify ALMProxy
-
Check that contract is verified on Oklink -
0x83A914C361bB729EB6BEBC8C7bA993667A0E6Df8 -
Check the release tag from which the contract is deployed -
v1.10.0 -
Manually verify the bytecode of the contract
➜ xlayer-deployment git:(feat/verify) forge verify-bytecode 0x83A914C361bB729EB6BEBC8C7bA993667A0E6Df8 ALMProxy --constructor-args $DEPLOYER --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract ALMProxy at address 0x83A914C361bB729EB6BEBC8C7bA993667A0E6Df8 Creation code matched with status partial Runtime code matched with status partial
-
Verify constructor arguments
- admin : (DEPLOYER, but replaced with
EXECUTORlater)
- admin : (DEPLOYER, but replaced with
-
Check that ALMProxy has only one admin (EXECUTOR) after deploy
-
Validate the test where the post deployment roles and state of ALMProxy is asserted -
test_postDeployState
-
- Verify RateLimits
-
Check that contract is verified on Oklink -
0x7F7E2286983994c4403Cf2B86758cE0e7bA666a8 -
Check the release tag from which the contract is deployed -
v1.10.0 -
Manually verify the bytecode of the contract
➜ xlayer-deployment git:(feat/verify) forge verify-bytecode 0x7F7E2286983994c4403Cf2B86758cE0e7bA666a8 RateLimits --rpc-url https://rpc.xlayer.tech--verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract RateLimits at address 0x7F7E2286983994c4403Cf2B86758cE0e7bA666a8 Creation code matched with status partial Runtime code matched with status partial
-
Verify constructor arguments
- admin : (DEPLOYER, but replaced with
EXECUTORlater)
- admin : (DEPLOYER, but replaced with
-
Check that RateLimits has only one admin (EXECUTOR) after deploy
-
Validate the test where the post deployment roles and state of RateLimits is asserted -
test_postDeployState
-
- Verify Controller
-
Check that contract is verified on Oklink -
0xf9187C99Ee842beABE8e2e346d958315BFc9331f -
Check the release tag from which the contract is deployed -
v1.10.0 -
Check constructor arguments
- Admin : (DEPLOYER, but replaced with
EXECUTORlater) - Proxy:
XLayer.ALM_PROXY - RateLimits:
XLayer.ALM_RATE_LIMITS - PSM: address(0)
- USDC: address(0)
- CCTP: address(0)
- Admin : (DEPLOYER, but replaced with
-
Manually verify the bytecode of the contract
# foundry.toml libraries = [ "lib/spark-alm-controller/src/libraries/LayerZeroLib.sol:LayerZeroLib:0xa44a27901ee51d657f59c75a61521e332cdc2e2e" ]
➜ xlayer-deployment git:(feat/verify) forge verify-bytecode 0xf9187C99Ee842beABE8e2e346d958315BFc9331f ForeignController --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract ForeignController at address 0xf9187C99Ee842beABE8e2e346d958315BFc9331f Creation code matched with status partial Runtime code matched with status partial
-
Check that all libraries are verified on Oklink
- LayerZeroLib -
0xa44a27901ee51d657f59c75a61521e332cdc2e2e
- LayerZeroLib -
-
Verify bytecode of all libraries against latest production release
- LayerZeroLib
➜ xlayer-deployment git:(feat/verify) ✗ forge verify-bytecode 0xa44a27901ee51d657f59c75a61521e332cdc2e2e LayerZeroLib --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract LayerZeroLib at address 0xA44A27901Ee51d657f59c75a61521E332cDC2E2E Creation code matched with status full Runtime code matched with status full
-
Check that Controller has only one admin (EXECUTOR) after deploy
-
Check that ALMProxy, RateLimits contract addresses linked to Controller are valid
-
Verify Controller has CONTROLLER_ROLE on ALMProxy and RateLimits
-
Check RELAYER_ROLE holders on controller
- Relayer 1 :
XLayer.ALM_RELAYER_MULTISIG - Relayer 2:
XLayer.ALM_BACKSTOP_RELAYER_MULTISIG
- Relayer 1 :
-
Check FREEZER_ROLE holders on controller -
XLayer.ALM_FREEZER_MULTISIG -
Verify the test where post controller deployment state and roles are asserted -
test_postDeployState
-
- Verify ALMProxyFreezable
-
Check that contract is verified on oklink -
0x9449ed367C60ea757544fd990B57e1C2D0Ec3A94 -
Check the release tag from which the contract is deployed - diamond-pau
v.1.12.0 -
Constructor args on explorer match expected deployment params - SPARK_EXECUTOR -
-
Manually verify bytecode
➜ diamond-pau git:(v1.12.0) ✗ forge verify-bytecode 0x9449ed367C60ea757544fd990B57e1C2D0Ec3A94 ALMProxyFreezable --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract ALMProxyFreezable at address 0x9449ed367C60ea757544fd990B57e1C2D0Ec3A94 Creation code matched with status partial Runtime code matched with status partial
-
Ensure
ALM_RELAYER_MULTISIGis added asALLOCATOR -
Ensure
ALM_BACKSTOP_RELAYER_MULTISIGis added asALLOCATOR -
Ensure
ALM_FREEZER_MULTISIGis added asFREEZER -
Add ALMProxyFreezable configuration test to check assert:
- DEFAULT_ADMIN_ROLE is set to governance(executor)
-
ALM_RELAYER_MULTISIGis added asALLOCATOR -
ALM_BACKSTOP_RELAYER_MULTISIGis added asALLOCATOR -
ALM_FREEZER_MULTISIGis added asFREEZER - Check that all of the above are the ONLY roles set using events data
-
Test :
test_almProxyFreezable_config
-
- SparkVaultV2 deployment and onboarding
-
Verify contract on Oklink -
XLayer.SPARK_VAULT_V2_SPUSDT -
Verify bytecode against latest release -
v1.0.1# Implementation ➜ xlayer-deployment git:(feat/verify) ✗ forge verify-bytecode 0xdCe929A335C75a1676EF5957A4D7a3b928C48820 SparkVault --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract SparkVault at address 0xdCe929A335C75a1676EF5957A4D7a3b928C48820 Creation code matched with status full Runtime code matched with status full # Vault (Proxy) ➜ xlayer-deployment git:(feat/verify) ✗ forge verify-bytecode 0xc358c90D32375721Cb3924320Fdc2F8B694347Ca ERC1967Proxy --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Verifying bytecode for contract ERC1967Proxy at address 0xc358c90D32375721Cb3924320Fdc2F8B694347Ca Creation code matched with status full Runtime code matched with status full
-
Check that
SETTER_ROLEis set to the ALMProxyFreezable-
XLayer.ALM_PROXY_FREEZABLE
-
-
Check that the
TAKER_ROLEis set to the ALMProxy -XLAYER.ALM_PROXY -
Check that the VSR bounds are set
# minVSR = 1e27 # maxVSR = SIX_PCT_APY = 1.000000001847694957439350562e27
-
Check that the vault is seeded, sending shares to address(1)
-
Check vault initialization
- name :
Spark Savings USDT - symbol:
spUSDT - decimals:
6 - deposit cap:
750_000_000e6
- name :
-
Ensure that transferAsset rate limit is set:
- Check asset address is the underlying address of the vault - USDT
- Check recipient address is the vault
- Check maxAmount - unlimited
- Check slope - unlimted
- Verify the precision of the rate limit data against the underlying asset
-
Ensure that the take rate limit is set:
- Check vault address is used
- Check maxAmount - unlimited
- Check slope - unlimited
- Verify the precision of the rate limit data against the underlying asset
-
Verify the test where post deploy state config and roles are tested -
test_vault_config
-
- Verify Governance bridge setup
- Verify Executor
-
Check that Executor is deployed -
XLayer.SPARK_EXECUTOR -
Check that Executor contract is verified on explorer
-
Manually verify that Executor is deployed from latest release
➜ spark-gov-relay git:(v1.0.1) forge verify-bytecode 0xCF5af6F53ceC74B791cb4182aC778ca9CD323510 Executor --rpc-url https://rpc.xlayer.tech --verifier-url"http://localhost:8443" --chain 196 Warning: This is a nightly build of Foundry. It is recommended to use the latest stable version. To mute this warning set `FOUNDRY_DISABLE_NIGHTLY_WARNING` in your environment. Verifying bytecode for contract Executor at address 0xCF5af6F53ceC74B791cb4182aC778ca9CD323510 [⠊] Compiling... [⠊] Compiling 56 files with Solc 0.8.25 [⠢] Solc 0.8.25 finished in 5.14s Compiler run successful! Creation code matched with status partial Runtime code matched with status partial
-
Check constructor arguments and validate
- delay :
0 - gracePeriod:
7 days
- delay :
-
Verify the DEFAULT_ADMIN_ROLE holder - EXECUTOR
-
Verify GUARDIAN_ROLE holders - NO guardian
-
Verify SUBMISSION_ROLE holders - RECEIVER
-
- Verify Receiver
-
Check the type of the Receiver (LZ, Arbitrum, Gnosis, etc) - Optimism
-
Check that correct Receiver is deployed and verified on explorer -
XLayer.SPARK_RECEIVER -
Manually verify that Receiver is deployed from latest release tag
➜ xchain-helpers git:(96c35ce) ✗ forge verify-bytecode 0x4bd50B9c00Ae19e8B59723F27645C7A5cCe7a4A0 OptimismReceiver --rpc-url https://rpc.xlayer.tech --verifier-url "http://localhost:8443" --chain 196 Warning: This is a nightly build of Foundry. It is recommended to use the latest stable version. To mute this warning set `FOUNDRY_DISABLE_NIGHTLY_WARNING` in your environment. Verifying bytecode for contract OptimismReceiver at address 0x4bd50B9c00Ae19e8B59723F27645C7A5cCe7a4A0 [⠊] Compiling... No files changed, compilation skipped Creation code matched with status partial Runtime code matched with status partial
-
Check constructor arguments and validate
- L1Authority should be SPARK_PROXY
- Target should be newly deployed Executor
-
- Verify the e2e test of governance flow -
test_crosschainE2E_setVsrBounds- Deploy payload on XLayer chain to set VSR
- Deploy payload on mainnet to call receiver
-
PAUSE_PROXYcallsSPARK_PROXY.exec()to execute mainnet payload - Relay messages over bridge
- Wait executor delay (immediate - zero seconds)
- Assert VSR values
- Execute on
EXECUTOR - Assert VSR values
- Verify Executor
- Enable USDT0 bridging to Ethereum
- Check layerZeroRecipient set in XLayer ForeignController
- Check endpoint ID against LZ docs -
30101 - Check ALMProxy address is Mainnet ALMProxy -
Ethereum.ALM_PROXY
- Check endpoint ID against LZ docs -
- Check LZ rate limit is set for XLayer
- Check OFT address -
0x94BCCa6bdfd6A61817Ab0E960bFedE4984505554 - Check mainnet endpoint ID -
30101 - maxAmount : unlimited
- slope : unlimited
- Test :
test_controller_config,test_rateLimits_config
- Check OFT address -
- Review full e2e test -
test_XLAYER_sll_spUSDT_usdt0RoundTrip
- Check layerZeroRecipient set in XLayer ForeignController
- Verify ALMProxy
- Review
- SLL Enable USDT0 Bridging to XLayer [Ethereum] - [4]
- Check layerZeroRecipient set in MainnetController
- Check endpoint ID against LZ docs -
30274 - Check ALMProxy address is XLayer ALMProxy -
0x83A914C361bB729EB6BEBC8C7bA993667A0E6Df8
- Check endpoint ID against LZ docs -
- Check LZ rate limit is set for mainnet
- Check OFT address -
0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee - Check XLayer endpoint ID -
30274 - maxAmount :
5_000_000e6 - slope :
100_000_000e6/day - Test :
test_ETHEREUM_sll_enableUSDTBridgingToXLayer
- Check OFT address -
- Review full end to end test -
test_XLAYER_sll_spUSDT_usdt0RoundTrip
- Check layerZeroRecipient set in MainnetController
- SLL Deactivate Old USDT Morpho V2 Vault [Ethereum] - [5]
- Check the address of old morpho vault v2 -
0xc7CDcFDEfC64631ED6799C95e3b110cd42F2bD22 - Check deposit and withdraw ratelimits are set to zero
- Verify test asserting old mopho vault have zero rate limits -
test_ETHEREUM_sll_deactivateOldMorphoUsdtVault
- Check the address of old morpho vault v2 -
- Treasury Transfer [Ethereum] - [6]
- Check receiver address against forum post or address registry
- Check amount against forum post -
2_000_000e18 - Review that test decrements and increments funds from correct addresses -
test_ETHEREUM_sparkTreasury_transfers
- Treasury Transfer [Ethereum] - [7]
- Check receiver address against forum post or address registry
- Check amount against forum post -
500_000e18 - Review that test decrements and increments funds from correct addresses -
test_ETHEREUM_sparkTreasury_transfers
- SLL Transfer USDS to Grove [Ethereum] - [8]
- Check Grove ALMProxy address -
GROVE_ALM_PROXY=0x491EDFB0B8b608044e227225C715981a30F3A44E - Check syrupUSDC transfer amount -
85_943_747.637271e6 - Check the syrupUSDC is converted to USDS amount
- Check converted USDS amount is minted for spark ALMProxy
- Check that minted USDS is transferred to Grove ALMProxy
- Check temporary role (relayer, controller) grants of Payload is revoked after transfer
- Verify the test that asserts the balance changes of Proxies from this transfer -
test_ETHEREUM_sll_transferUsdsToGrove
- Check Grove ALMProxy address -
- Withdraw reserves [Ethereum] - [9]
- Review SparkPayloadEthereum code for claiming all reserves
- Ensure stablecoins go to ALMProxy and everything else goes to Liquidation multisig
- Review that test decrements and increments funds from correct addresses for all reserves
- Treasury Transfer [Ethereum] - [10a]
- Check receiver address against forum post or address registry -
SPARK_FOUNDATION_MULTISIG=0x92e4629a4510AF5819d7D1601464C233599fF5ec - Check amount against forum post -
1_100_000e18 - Review that test decrements and increments funds from correct addresses -
test_ETHEREUM_sparkTreasury_transfers
- Check receiver address against forum post or address registry -
- Treasury Transfer [Ethereum] - [10b]
- Check receiver address against forum post or address registry -
SPARK_ASSET_FOUNDATION_MULTISIG=0xEabCb8C0346Ac072437362f1692706BA5768A911 - Check amount against forum post -
155_000e18 - Review that test decrements and increments funds from correct addresses -
test_ETHEREUM_sparkTreasury_transfers
- Check receiver address against forum post or address registry -
- Treasury Transfer [Ethereum] - [11]
- Check receiver address against forum post or address registry -
ALM_OPS_MULTISIG=0x2E1b01adABB8D4981863394bEa23a1263CBaeDfC - Check amount against forum post -
64_231e18 - Review that test decrements and increments funds from correct addresses -
test_ETHEREUM_sparkTreasury_transfers
- Check receiver address against forum post or address registry -
lucas-manuel
left a comment
There was a problem hiding this comment.
Approving for deployment.
- Check forum post link
- Check description for all payloads
- Check poll links
- Check spark-address-registry commit matches current HEAD
- SLL Activate SLL and Spark Savings Infra (Roles) [Robinhood] - [1a] - DONE
- SLL roles (don’t check until registry is merged)
- Check
ALM_BACKSTOP_RELAYER_MULTISIGmatches registry and forum - Check
ALM_FREEZER_MULTISIGmatches registry and forum - Check new
ALM_BACKSTOP_RELAYER_MULTISIGaddress has RELAYER role on controller - Check Old backstop relayer is revoked
- Check new
ALM_FREEZER_MULTISIGaddress has FREEZER role on controller - Check Old freezer is revoked
- Check ALMProxyFreezable ALLOCATOR and FREEZER role addresses against forum post
- Verify the test that asserts role grants and revokes
- Check
- SLL roles (don’t check until registry is merged)
- SLL Activate SLL and Spark Savings Infra (Onchain params) [Robinhood] - [1b] - DONE
- spUSDG config
- Verify deposit cap is unchanged
- Verify max rate is unchanged
- spUSDG config
- SLL Activate SLL and Spark Savings Infra (Rate Limits) [Robinhood] - [1c] - DONE
- SLL ratelimits
- Check asset address against forum post
- Check recipient address against forum post
- Check maxAmount against forum post
- Check slope against forum post
- Verify the precision of the rate limit against the underlying asset
- Check rate limit before and after state in a test
- Ensure that
_testTransferAssetIntegrationis run with new integration in spell tests
- SLL ratelimits
- SLL Enable USDG Bridging to Robinhood [Ethereum] - [2] - DONE
- SLL ratelimits - (Bridging is done via Paxos centralized bridge)
- Check asset address against forum post
- Check recipient address against forum post
- Check maxAmount against forum post
- Check slope against forum post
- Verify the precision of the rate limit against the underlying asset
- Check rate limit before and after state in a test
- Ensure that
_testTransferAssetIntegrationis run with new integration in spell tests
- SLL ratelimits - (Bridging is done via Paxos centralized bridge)
- Deploy spUSDT [XLayer] - [3]
- Review
xlayer-deploymentscripts and tests- Verify ALMProxy - DONE
- Check that contract is verified on Oklink -
- Check the release tag from which the contract is deployed -
v1.10.0 - Manually verify the bytecode of the contract
- Verify constructor arguments
- admin : (DEPLOYER, but replaced with
EXECUTORlater)
- admin : (DEPLOYER, but replaced with
- Manually check that ALMProxy has only one admin (EXECUTOR) after deploy
- Validate the test where the post deployment roles and state of ALMProxy is asserted -
test_postDeployState
- Verify RateLimits - DONE
- Check that contract is verified on Oklink -
- Check the release tag from which the contract is deployed -
v1.10.0 - Manually verify the bytecode of the contract
- Verify constructor arguments
- admin : (DEPLOYER, but replaced with
EXECUTORlater)
- admin : (DEPLOYER, but replaced with
- Manually check that RateLimits has only one admin (EXECUTOR) after deploy
- Validate the test where the post deployment roles and state of RateLimits is asserted -
test_postDeployState
- Verify Controller - DONE
- Check that contract is verified on Oklink -
- Check the release tag from which the contract is deployed -
v1.10.0 - Check constructor arguments
- Admin : (DEPLOYER, but replaced with
EXECUTORlater) - Proxy: ALM_PROXY
- RateLimits: RATE_LIIMITS
- PSM: address(0)
- USDC: address(0)
- CCTP: address(0)
- Admin : (DEPLOYER, but replaced with
- Manually verify the bytecode of the contract
- Check that all libraries are verified on Oklink
- LayerZeroLib -
- Verify bytecode of all libraries against latest production release
- LayerZeroLib
- Manually check that Controller has only one admin (EXECUTOR) after deploy
- Manually check that Controller doens’t have any additional FREEZER or RELAYER roles granted
- Check that ALMProxy, RateLimits contract addresses linked to Controller are valid
- Verify Controller has CONTROLLER_ROLE on ALMProxy and RateLimits
- Check RELAYER_ROLE holders on controller against forum post
- Relayer 1
- Relayer 2
- Check FREEZER_ROLE holders on controller
- Verify the test where post controller deployment state and roles are asserted -
test_postDeployState
- SparkVaultV2 deployment and onboarding - DONE
- Verify contract on Oklink -
- Verify bytecode against latest release -
v1.0.1 - Check that
SETTER_ROLEis set to the ALMProxyFreezable - Check that the
TAKER_ROLEis set to the ALMProxy - - Check that the VSR bounds are set to 0 and 6%
- Check that the vault is seeded, sending shares to address(1)
- Check vault initialization
- name : Spark Savings USDT
- symbol: spUSDT
- decimals: 6
- deposit cap: 750m
- Ensure that transferAsset rate limit is set:
- Check asset address is the underlying address of the vault -
- Check recipient address is the vault
- Check maxAmount
- Check slope
- Verify the precision of the rate limit data against the underlying asset
- Ensure that the take rate limit is set:
- Check vault address is used
- Check maxAmount
- Check slope
- Verify the precision of the rate limit data against the underlying asset
- Verify the test where post deploy state config and roles are tested -
test_vault_config - Verify the integration test of deployed vault -
test_e2e- SLL sets VSR
- User deposits into spUSDT
- Warp no interest
- SLL takes funds
- SLL bridges funds to mainnet
- spUSDT accrues interest
- SLL bridges funds to XLayer
- SLL transfers into spUSDT
- User withdraws from spUSDT
- Verify Governance bridge setup - DONE
- Verify Executor
- Check that Executor is deployed -
- Check that Executor contract is verified on explorer
- Manually verify that Executor is deployed from latest release
- Check constructor arguments and validate
- delay : 0
- gracePeriod: 7 days
- Manually verify the DEFAULT_ADMIN_ROLE holder - ONLY Executor
- Verify GUARDIAN_ROLE holders - None
- Verify SUBMISSION_ROLE holders - ONLY Receiver
- Verify Receiver
- Check the type of the Receiver (LZ, Arbitrum, Gnosis, etc) - Optimism
- Check that correct Receiver is deployed and verified on explorer -
- Manually verify that Receiver is deployed from latest release tag
- Check constructor arguments and validate
- L1Authority should be SPARK_PROXY
- Target should be newly deployed Executor -
- Verify Executor
- Enable USDT0 bridging to Ethereum - DONE
- Check layerZeroRecipient set in XLayer ForeignController
- Check endpoint ID against LZ docs - 30101
- Check ALMProxy address is Mainnet ALMProxy -
- Manually check events on Block explorer to check that no other addresses were set as LZ recipients
- Check LZ rate limit is set for XLayer
- Check OFT address against https://docs.usdt0.to/technical-documentation/deployments
- Check mainnet endpoint ID - 30101
- maxAmount : unlimited
- slope : 0
- Review test
- Review full e2e test
- Check layerZeroRecipient set in XLayer ForeignController
- Verify ALMProxy - DONE
- Review
- SLL Enable USDT0 Bridging to XLayer [Ethereum] - 4 - DONE
- Check layerZeroRecipient set in MainnetController
- Check endpoint ID against LZ docs https://docs.layerzero.network/v2/deployments/deployed-contracts 30274
- Check ALMProxy address is XLayer ALMProxy
- Check LZ rate limit is set for mainnet
- Check OFT address against https://docs.usdt0.to/technical-documentation/deployments
- Check endpoint ID against LZ docs https://docs.layerzero.network/v2/deployments/deployed-contracts 30274
- maxAmount : 5m
- slope : 100m / day
- Test
- Review full end to end test
- Check layerZeroRecipient set in MainnetController
- SLL Deactivate Old USDT Morpho V2 Vault [Ethereum] - 5 - DONE
- Check the address of old morpho vault v2
- Check deposit and withdraw ratelimits are set to zero
- Verify test asserting old mopho vault have zero rate limits
- Treasury Transfer (Spark Foundation Incentives) [Ethereum] - [6] DONE
- Check receiver address against forum post or address registry
- Check amount against forum post - 2m for incentives
- Review that test decrements and increments funds from correct addresses
- Treasury Transfer (SAF Anchorage Fees) [Ethereum] - [7] - DONE
- Check receiver address against forum post or address registry
- Check amount against forum post - 500k
- Review that test decrements and increments funds from correct addresses
- SLL Transfer USDS to Grove [Ethereum] - [8] DONE
- Check Grove ALMProxy address against https://github.com/grove-labs/grove-address-registry/blob/ca0351644f9ba52c7d90a6183042617ff8b75579/src/Ethereum.sol#L89
- Check syrupUSDC transfer amount
- Check the syrupUSDC is converted to USDS amount
- Check converted USDS amount is minted for spark ALMProxy
- Check that minted USDS is transferred to Grove ALMProxy
- Check temporary role (relayer, controller) grants of Payload is revoked after transfer
- Verify the test that asserts the balance changes of Proxies from this transfer
- Withdraw reserves [Ethereum] - [9] DONE
- Review SparkPayloadEthereum code for claiming all reserves
- Ensure stablecoins go to ALMProxy and everything else goes to Liquidation multisig
- Review that test decrements and increments funds from correct addresses for all reserves
- Treasury Transfer (Spark Foundation Grant) [Ethereum] - [10] DONE
- Check receiver address against forum post or address registry
- Check amount against forum post - 1.1m
- Review that test decrements and increments funds from correct addresses
- Treasury Transfer (SAF Grant) [Ethereum] - [11] DONE
- Check receiver address against forum post or address registry
- Check amount against forum post - 155k
- Review that test decrements and increments funds from correct addresses
- Treasury Transfer (SPK buybacks) [Ethereum] - [12] DONE
- Check receiver address against forum post or address registry
- Check amount against forum post - 64,231
- Review that test decrements and increments funds from correct addresses
5889042
TheMj0ln1r
left a comment
There was a problem hiding this comment.
Confirming the spell is correctly deployed on Ethereum at 0xC1090e8fEE666868622a2F1e870185F944108Ee2
~/Projects/spark-spells on feat/sc-1573-spell-20260716 ⌚ 11:42:12
$ forge verify-bytecode 0xC1090e8fEE666868622a2F1e870185F944108Ee2 SparkEthereum_20260716\
Verifying bytecode for contract SparkEthereum_20260716 at address 0xC1090e8fEE666868622a2F1e870185F944108Ee2
[⠢] Compiling...
No files changed, compilation skipped
Creation code matched with status partial
Runtime code matched with status partial |
There was a problem hiding this comment.
Confirming and approving deployment at 0xC1090e8fEE666868622a2F1e870185F944108Ee2
cast codehash 0xC1090e8fEE666868622a2F1e870185F944108Ee2
0xa7b0b6c470169f40016d354a8944f9e5f3f787159fec5192694e8f1ddbc7f26f
Review checklist: https://gist.github.com/lucas-manuel/7dd8526199fec7fabb580c012f5de192
certora-spark-review
left a comment
There was a problem hiding this comment.
Confirming and approving the spell deployment at 0xC1090e8fEE666868622a2F1e870185F944108Ee2.
Review checklist - https://gist.github.com/certora-spark-review/5edb28cc7c3fd6c67523ca146208869b
|
Confirming and approving spell deployment at Deployment checklist: https://gist.github.com/unvariant-dev/6208db73a7b62f31033355ef63d6b512 |
2026-07-16 Spark Spell
Forum Post
https://forum.skyeco.com/t/july-16-2026-proposed-changes-to-spark-for-upcoming-spell/28029
Dependencies on Sky Core spell
None
Notes for Reviewers
None
Conditions for Spell Deployment
Conditions for Spell Handoff to Sky
Conditions for Spell Merge
Summary by CodeRabbit
New Features
Bug Fixes
Tests