From 227bb48e03b03bac980ed1d7994cda21f7088e78 Mon Sep 17 00:00:00 2001 From: Reinis Martinsons Date: Fri, 20 Sep 2024 10:28:44 +0000 Subject: [PATCH] fix: override chain id in executing slow fill Signed-off-by: Reinis Martinsons --- .../svm-spoke/src/instructions/slow_fill.rs | 10 ++++- test/svm/SvmSpoke.SlowFill.ts | 41 ++++++++++++++++++- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/programs/svm-spoke/src/instructions/slow_fill.rs b/programs/svm-spoke/src/instructions/slow_fill.rs index 1348c5518..5bf72c23c 100644 --- a/programs/svm-spoke/src/instructions/slow_fill.rs +++ b/programs/svm-spoke/src/instructions/slow_fill.rs @@ -188,10 +188,16 @@ pub fn execute_v3_slow_relay_leaf( root_bundle_id: u32, proof: Vec<[u8; 32]>, ) -> Result<()> { - let relay_data = slow_fill_leaf.relay_data.clone(); // Clone relay_data to avoid move + let relay_data = slow_fill_leaf.relay_data; + + let slow_fill = V3SlowFill { + relay_data: relay_data.clone(), // Clone relay_data to avoid move + chain_id: ctx.accounts.state.chain_id, // This overrides caller provided chain_id, same as in EVM SpokePool. + updated_output_amount: slow_fill_leaf.updated_output_amount, + }; let root = ctx.accounts.root_bundle.slow_relay_root; - let leaf = slow_fill_leaf.to_keccak_hash(); + let leaf = slow_fill.to_keccak_hash(); verify_merkle_proof(root, leaf, proof)?; // Check if the fill status is unfilled diff --git a/test/svm/SvmSpoke.SlowFill.ts b/test/svm/SvmSpoke.SlowFill.ts index 06e5e104b..74030b03d 100644 --- a/test/svm/SvmSpoke.SlowFill.ts +++ b/test/svm/SvmSpoke.SlowFill.ts @@ -68,7 +68,7 @@ describe("svm_spoke.slow_fill", () => { }; } - const relaySlowFillRootBundle = async () => { + const relaySlowFillRootBundle = async (slowRelayLeafRecipient = recipient, slowRelayLeafChainId = chainId) => { //TODO: verify that the leaf structure created here is equivalent to the one created by the EVM logic. I think // I've gotten the concatenation, endianness, etc correct but want to be sure. const slowRelayLeafs: SlowFillLeaf[] = []; @@ -87,7 +87,7 @@ describe("svm_spoke.slow_fill", () => { exclusivityDeadline: new BN(Math.floor(Date.now() / 1000) - 60), message: Buffer.from("Test message"), }, - chainId, + chainId: slowRelayLeafChainId, updatedOutputAmount: new BN(relayAmount), }; updateRelayData(slowRelayLeaf.relayData); @@ -381,4 +381,41 @@ describe("svm_spoke.slow_fill", () => { assert.strictEqual(err.error.errorCode.code, "InvalidFillRecipient", "Expected error code InvalidFillRecipient"); } }); + + it("Cannot execute V3 slow relay leaf targeted at another chain", async () => { + // Request V3 slow fill for another chain. + const anotherChainId = new BN(Math.floor(Math.random() * 1000000)); + const { relayHash, leaf, rootBundleId, proofAsNumbers, rootBundle } = await relaySlowFillRootBundle( + undefined, + anotherChainId + ); + await program.methods + .requestV3SlowFill(relayHash, leaf.relayData) + .accounts(requestAccounts) + .signers([relayer]) + .rpc(); + + // Trying to execute V3 slow relay leaf for another chain should fail as the program overrides chain_id that should + // invalidate the proofs. + try { + await program.methods + .executeV3SlowRelayLeaf(relayHash, leaf, rootBundleId, proofAsNumbers) + .accounts({ + state, + rootBundle, + signer: owner, + fillStatus: requestAccounts.fillStatus, + vault, + tokenProgram: TOKEN_PROGRAM_ID, + mint, + recipient, + recipientTokenAccount: recipientTA, + }) + .rpc(); + assert.fail("Execution should have failed for another chain"); + } catch (err) { + assert.instanceOf(err, anchor.AnchorError); + assert.strictEqual(err.error.errorCode.code, "InvalidProof", "Expected error code InvalidProof"); + } + }); });