From 0665dd136b769c68a0eeab69536b589c91d13a44 Mon Sep 17 00:00:00 2001 From: chrismaree Date: Wed, 23 Oct 2024 11:55:40 +0200 Subject: [PATCH 1/5] WIP Signed-off-by: chrismaree --- programs/svm-spoke/src/instructions/fill.rs | 4 +- .../svm-spoke/src/instructions/slow_fill.rs | 2 +- programs/svm-spoke/src/lib.rs | 9 +- scripts/svm/simpleFill.ts | 2 +- test/svm/SvmSpoke.Fill.ts | 95 ++++++++++--------- 5 files changed, 60 insertions(+), 52 deletions(-) diff --git a/programs/svm-spoke/src/instructions/fill.rs b/programs/svm-spoke/src/instructions/fill.rs index 733c9a4b5..5e461ce67 100644 --- a/programs/svm-spoke/src/instructions/fill.rs +++ b/programs/svm-spoke/src/instructions/fill.rs @@ -99,6 +99,7 @@ pub fn fill_v3_relay( relay_hash: [u8; 32], // include in props, while not using it, to enable us to access it from the #Instruction Attribute within the accounts. This enables us to pass in the relay_hash PDA. relay_data: V3RelayData, repayment_chain_id: u64, + repayment_address: Pubkey, ) -> Result<()> { let state = &mut ctx.accounts.state; let current_time = get_current_time(state)?; @@ -166,7 +167,7 @@ pub fn fill_v3_relay( fill_deadline: relay_data.fill_deadline, exclusivity_deadline: relay_data.exclusivity_deadline, exclusive_relayer: relay_data.exclusive_relayer, - relayer: *ctx.accounts.signer.key, + relayer: repayment_address, depositor: relay_data.depositor, recipient: relay_data.recipient, message: relay_data.message, @@ -225,4 +226,3 @@ pub fn close_fill_pda( Ok(()) } -// Events. diff --git a/programs/svm-spoke/src/instructions/slow_fill.rs b/programs/svm-spoke/src/instructions/slow_fill.rs index 94fb0d4bf..0068eed6b 100644 --- a/programs/svm-spoke/src/instructions/slow_fill.rs +++ b/programs/svm-spoke/src/instructions/slow_fill.rs @@ -255,7 +255,7 @@ pub fn execute_v3_slow_relay_leaf( fill_deadline: relay_data.fill_deadline, exclusivity_deadline: relay_data.exclusivity_deadline, exclusive_relayer: relay_data.exclusive_relayer, - relayer: *ctx.accounts.signer.key, + relayer: Pubkey::default(), // There is no repayment address for slow depositor: relay_data.depositor, recipient: relay_data.recipient, message: relay_data.message, diff --git a/programs/svm-spoke/src/lib.rs b/programs/svm-spoke/src/lib.rs index 53113e2b6..979779cff 100644 --- a/programs/svm-spoke/src/lib.rs +++ b/programs/svm-spoke/src/lib.rs @@ -132,8 +132,15 @@ pub mod svm_spoke { relay_hash: [u8; 32], relay_data: V3RelayData, repayment_chain_id: u64, + repayment_address: Pubkey, ) -> Result<()> { - instructions::fill_v3_relay(ctx, relay_hash, relay_data, repayment_chain_id) + instructions::fill_v3_relay( + ctx, + relay_hash, + relay_data, + repayment_chain_id, + repayment_address, + ) } pub fn close_fill_pda( diff --git a/scripts/svm/simpleFill.ts b/scripts/svm/simpleFill.ts index 30271a464..3849ef1ac 100644 --- a/scripts/svm/simpleFill.ts +++ b/scripts/svm/simpleFill.ts @@ -121,7 +121,7 @@ async function fillV3Relay(): Promise { })) ); - const tx = await (program.methods.fillV3Relay(Array.from(relayHashUint8Array), relayData, chainId) as any) + const tx = await (program.methods.fillV3Relay(Array.from(relayHashUint8Array), relayData, chainId, signer) as any) .accounts({ state: statePda, signer: signer, diff --git a/test/svm/SvmSpoke.Fill.ts b/test/svm/SvmSpoke.Fill.ts index 772e1135d..bf02e7914 100644 --- a/test/svm/SvmSpoke.Fill.ts +++ b/test/svm/SvmSpoke.Fill.ts @@ -93,7 +93,11 @@ describe("svm_spoke.fill", () => { assertSE(relayerAccount.amount, seedBalance, "Relayer's balance should be equal to seed balance before the fill"); const relayHash = Array.from(calculateRelayHashUint8Array(relayData, chainId)); - await program.methods.fillV3Relay(relayHash, relayData, new BN(1)).accounts(accounts).signers([relayer]).rpc(); + await program.methods + .fillV3Relay(relayHash, relayData, new BN(1), relayer.publicKey) + .accounts(accounts) + .signers([relayer]) + .rpc(); // Verify relayer's balance after the fill relayerAccount = await getAccount(connection, relayerTA); @@ -110,7 +114,11 @@ describe("svm_spoke.fill", () => { it("Verifies FilledV3Relay event after filling a relay", async () => { const relayHash = Array.from(calculateRelayHashUint8Array(relayData, chainId)); - await program.methods.fillV3Relay(relayHash, relayData, new BN(1)).accounts(accounts).signers([relayer]).rpc(); + await program.methods + .fillV3Relay(relayHash, relayData, new BN(420), otherRelayer.publicKey) + .accounts(accounts) + .signers([relayer]) + .rpc(); // Fetch and verify the FilledV3Relay event await new Promise((resolve) => setTimeout(resolve, 500)); @@ -122,6 +130,9 @@ describe("svm_spoke.fill", () => { Object.keys(relayData).forEach((key) => { assertSE(event[key], relayData[key], `${key.charAt(0).toUpperCase() + key.slice(1)} should match`); }); + // These props below are not part of relayData. + assertSE(event.repaymentChainId, new BN(420), "Repayment chain id should match"); + assertSE(event.relayer, otherRelayer.publicKey, "Repayment address should match"); }); it("Fails to fill a V3 relay after the fill deadline", async () => { @@ -129,7 +140,11 @@ describe("svm_spoke.fill", () => { const relayHash = Array.from(calculateRelayHashUint8Array(relayData, chainId)); try { - await program.methods.fillV3Relay(relayHash, relayData, new BN(1)).accounts(accounts).signers([relayer]).rpc(); + await program.methods + .fillV3Relay(relayHash, relayData, new BN(1), relayer.publicKey) + .accounts(accounts) + .signers([relayer]) + .rpc(); assert.fail("Fill should have failed due to fill deadline passed"); } catch (err: any) { assert.include(err.toString(), "ExpiredFillDeadline", "Expected ExpiredFillDeadline error"); @@ -144,7 +159,7 @@ describe("svm_spoke.fill", () => { const relayHash = Array.from(calculateRelayHashUint8Array(relayData, chainId)); try { await program.methods - .fillV3Relay(relayHash, relayData, new BN(1)) + .fillV3Relay(relayHash, relayData, new BN(1), relayer.publicKey) .accounts(accounts) .signers([otherRelayer]) .rpc(); @@ -165,7 +180,11 @@ describe("svm_spoke.fill", () => { const relayerAccountBefore = await getAccount(connection, otherRelayerTA); const relayHash = Array.from(calculateRelayHashUint8Array(relayData, chainId)); - await program.methods.fillV3Relay(relayHash, relayData, new BN(1)).accounts(accounts).signers([otherRelayer]).rpc(); + await program.methods + .fillV3Relay(relayHash, relayData, new BN(1), relayer.publicKey) + .accounts(accounts) + .signers([otherRelayer]) + .rpc(); // Verify relayer's balance after the fill const relayerAccountAfter = await getAccount(connection, otherRelayerTA); @@ -188,11 +207,19 @@ describe("svm_spoke.fill", () => { const relayHash = Array.from(calculateRelayHashUint8Array(relayData, chainId)); // First fill attempt - await program.methods.fillV3Relay(relayHash, relayData, new BN(1)).accounts(accounts).signers([relayer]).rpc(); + await program.methods + .fillV3Relay(relayHash, relayData, new BN(1), relayer.publicKey) + .accounts(accounts) + .signers([relayer]) + .rpc(); // Second fill attempt with the same data try { - await program.methods.fillV3Relay(relayHash, relayData, new BN(1)).accounts(accounts).signers([relayer]).rpc(); + await program.methods + .fillV3Relay(relayHash, relayData, new BN(1), relayer.publicKey) + .accounts(accounts) + .signers([relayer]) + .rpc(); assert.fail("Fill should have failed due to RelayFilled error"); } catch (err: any) { assert.include(err.toString(), "RelayFilled", "Expected RelayFilled error"); @@ -210,7 +237,11 @@ describe("svm_spoke.fill", () => { }; // Execute the fill_v3_relay call - await program.methods.fillV3Relay(relayHash, relayData, new BN(1)).accounts(accounts).signers([relayer]).rpc(); + await program.methods + .fillV3Relay(relayHash, relayData, new BN(1), relayer.publicKey) + .accounts(accounts) + .signers([relayer]) + .rpc(); // Verify the fill PDA exists before closing const fillStatusAccountBefore = await connection.getAccountInfo(accounts.fillStatus); @@ -225,7 +256,7 @@ describe("svm_spoke.fill", () => { } // Set the current time to past the fill deadline - await setCurrentTime(program, state, relayer, relayData.fillDeadline.add(new BN(1))); + await setCurrentTime(program, state, relayer, relayData.fillDeadline.add(new BN(1), relayer.publicKey)); // Close the fill PDA await program.methods.closeFillPda(relayHash, relayData).accounts(closeFillPdaAccounts).signers([relayer]).rpc(); @@ -245,7 +276,7 @@ describe("svm_spoke.fill", () => { // Fill the relay await program.methods - .fillV3Relay(Array.from(relayHash), relayData, new BN(1)) + .fillV3Relay(Array.from(relayHash), relayData, new BN(1), relayer.publicKey) .accounts(accounts) .signers([relayer]) .rpc(); @@ -267,7 +298,11 @@ describe("svm_spoke.fill", () => { // Try to fill the relay. This should fail because fills are paused. const relayHash = Array.from(calculateRelayHashUint8Array(relayData, chainId)); try { - await program.methods.fillV3Relay(relayHash, relayData, new BN(1)).accounts(accounts).signers([relayer]).rpc(); + await program.methods + .fillV3Relay(relayHash, relayData, new BN(1), relayer.publicKey) + .accounts(accounts) + .signers([relayer]) + .rpc(); assert.fail("Should not be able to fill relay when fills are paused"); } catch (err: any) { assert.include(err.toString(), "Fills are currently paused!", "Expected fills paused error"); @@ -284,7 +319,7 @@ describe("svm_spoke.fill", () => { try { await program.methods - .fillV3Relay(Array.from(relayHash), relayData, new BN(1)) + .fillV3Relay(Array.from(relayHash), relayData, new BN(1), relayer.publicKey) .accounts({ ...accounts, recipient: wrongRecipient, @@ -312,7 +347,7 @@ describe("svm_spoke.fill", () => { try { await program.methods - .fillV3Relay(Array.from(relayHash), relayData, new BN(1)) + .fillV3Relay(Array.from(relayHash), relayData, new BN(1), relayer.publicKey) .accounts({ ...accounts, mintAccount: wrongMint, @@ -327,38 +362,4 @@ describe("svm_spoke.fill", () => { assert.strictEqual(err.error.errorCode.code, "InvalidMint", "Expected error code InvalidMint"); } }); - - it("Self-relay does not invoke token transfer", async () => { - // Set recipient to be the same as relayer. - updateRelayData({ ...relayData, depositor: relayer.publicKey, recipient: relayer.publicKey }); - accounts.recipient = relayer.publicKey; - accounts.recipientTA = relayerTA; - - // Store relayer's balance before the fill - const iRelayerBalance = (await getAccount(connection, relayerTA)).amount; - - const relayHash = Array.from(calculateRelayHashUint8Array(relayData, chainId)); - const txSignature = await program.methods - .fillV3Relay(relayHash, relayData, new BN(1)) - .accounts(accounts) - .signers([relayer]) - .rpc(); - - // Verify relayer's balance after the fill is unchanged - const fRelayerBalance = (await getAccount(connection, relayerTA)).amount; - assertSE(fRelayerBalance, iRelayerBalance, "Relayer's balance should not have changed"); - - await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait for tx processing - const txResult = await connection.getTransaction(txSignature, { - commitment: "confirmed", - maxSupportedTransactionVersion: 0, - }); - if (txResult === null || txResult.meta === null) throw new Error("Transaction meta not confirmed"); - if (txResult.meta.logMessages === null || txResult.meta.logMessages === undefined) - throw new Error("Transaction logs not found"); - assert.isTrue( - txResult.meta.logMessages.every((log) => !log.includes(`Program ${TOKEN_PROGRAM_ID} invoke`)), - "Token Program should not be invoked" - ); - }); }); From 474e0e686b8c749785d08d664585003e2599d99f Mon Sep 17 00:00:00 2001 From: chrismaree Date: Wed, 23 Oct 2024 11:57:06 +0200 Subject: [PATCH 2/5] WIP Signed-off-by: chrismaree --- test/svm/SvmSpoke.Fill.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/svm/SvmSpoke.Fill.ts b/test/svm/SvmSpoke.Fill.ts index bf02e7914..10acc5556 100644 --- a/test/svm/SvmSpoke.Fill.ts +++ b/test/svm/SvmSpoke.Fill.ts @@ -362,4 +362,37 @@ describe("svm_spoke.fill", () => { assert.strictEqual(err.error.errorCode.code, "InvalidMint", "Expected error code InvalidMint"); } }); + it("Self-relay does not invoke token transfer", async () => { + // Set recipient to be the same as relayer. + updateRelayData({ ...relayData, depositor: relayer.publicKey, recipient: relayer.publicKey }); + accounts.recipient = relayer.publicKey; + accounts.recipientTA = relayerTA; + + // Store relayer's balance before the fill + const iRelayerBalance = (await getAccount(connection, relayerTA)).amount; + + const relayHash = Array.from(calculateRelayHashUint8Array(relayData, chainId)); + const txSignature = await program.methods + .fillV3Relay(relayHash, relayData, new BN(1), relayer.publicKey) + .accounts(accounts) + .signers([relayer]) + .rpc(); + + // Verify relayer's balance after the fill is unchanged + const fRelayerBalance = (await getAccount(connection, relayerTA)).amount; + assertSE(fRelayerBalance, iRelayerBalance, "Relayer's balance should not have changed"); + + await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait for tx processing + const txResult = await connection.getTransaction(txSignature, { + commitment: "confirmed", + maxSupportedTransactionVersion: 0, + }); + if (txResult === null || txResult.meta === null) throw new Error("Transaction meta not confirmed"); + if (txResult.meta.logMessages === null || txResult.meta.logMessages === undefined) + throw new Error("Transaction logs not found"); + assert.isTrue( + txResult.meta.logMessages.every((log) => !log.includes(`Program ${TOKEN_PROGRAM_ID} invoke`)), + "Token Program should not be invoked" + ); + }); }); From 68a38bdc28d7a7b4a527fe46233298ddbcacdfe4 Mon Sep 17 00:00:00 2001 From: chrismaree Date: Wed, 23 Oct 2024 11:57:24 +0200 Subject: [PATCH 3/5] WIP Signed-off-by: chrismaree --- test/svm/SvmSpoke.Fill.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/svm/SvmSpoke.Fill.ts b/test/svm/SvmSpoke.Fill.ts index 10acc5556..fd21b46c7 100644 --- a/test/svm/SvmSpoke.Fill.ts +++ b/test/svm/SvmSpoke.Fill.ts @@ -362,6 +362,7 @@ describe("svm_spoke.fill", () => { assert.strictEqual(err.error.errorCode.code, "InvalidMint", "Expected error code InvalidMint"); } }); + it("Self-relay does not invoke token transfer", async () => { // Set recipient to be the same as relayer. updateRelayData({ ...relayData, depositor: relayer.publicKey, recipient: relayer.publicKey }); From 8ab1a6d936691609bb2b40c42d6bafacc1d488c1 Mon Sep 17 00:00:00 2001 From: chrismaree Date: Fri, 25 Oct 2024 11:40:44 +0200 Subject: [PATCH 4/5] WIP Signed-off-by: chrismaree --- test/svm/SvmSpoke.SlowFill.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/svm/SvmSpoke.SlowFill.ts b/test/svm/SvmSpoke.SlowFill.ts index b8a81ad5f..24572c65b 100644 --- a/test/svm/SvmSpoke.SlowFill.ts +++ b/test/svm/SvmSpoke.SlowFill.ts @@ -221,7 +221,7 @@ describe("svm_spoke.slow_fill", () => { // Fill the relay first await program.methods - .fillV3Relay(relayHash, formatRelayData(relayData), new BN(1)) + .fillV3Relay(relayHash, formatRelayData(relayData), new BN(1), relayer.publicKey) .accounts(fillAccounts) .signers([relayer]) .rpc(); From 82dd24e7c32419817039ecf7138600bd91da9ba6 Mon Sep 17 00:00:00 2001 From: chrismaree Date: Fri, 25 Oct 2024 12:03:27 +0200 Subject: [PATCH 5/5] WIP Signed-off-by: chrismaree --- programs/svm-spoke/src/instructions/fill.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/programs/svm-spoke/src/instructions/fill.rs b/programs/svm-spoke/src/instructions/fill.rs index 5e461ce67..e72ef6955 100644 --- a/programs/svm-spoke/src/instructions/fill.rs +++ b/programs/svm-spoke/src/instructions/fill.rs @@ -225,4 +225,3 @@ pub fn close_fill_pda( Ok(()) } -