@across-protocol/contracts 4.0.11 → 4.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/scripts/svm/{enableRoute.js → createVault.js} +13 -35
  2. package/dist/scripts/svm/fakeFillWithRandomDistribution.js +9 -8
  3. package/dist/scripts/svm/nativeDeposit.js +138 -0
  4. package/dist/scripts/svm/queryEventsV2.js +3 -3
  5. package/dist/scripts/svm/{queryRoute.js → queryVault.js} +10 -25
  6. package/dist/scripts/svm/remoteHubPoolPauseDeposits.js +2 -2
  7. package/dist/scripts/svm/simpleDeposit.js +3 -12
  8. package/dist/scripts/svm/simpleFakeRelayerRepayment.js +2 -9
  9. package/dist/scripts/svm/simpleFill.js +3 -2
  10. package/dist/src/svm/assets/idl/svm_spoke.json +43 -369
  11. package/dist/src/svm/assets/svm_spoke.d.ts +40 -366
  12. package/dist/src/svm/clients/SvmSpoke/accounts/index.d.ts +0 -1
  13. package/dist/src/svm/clients/SvmSpoke/accounts/index.js +0 -1
  14. package/dist/src/svm/clients/SvmSpoke/errors/svmSpoke.d.ts +3 -1
  15. package/dist/src/svm/clients/SvmSpoke/errors/svmSpoke.js +4 -1
  16. package/dist/src/svm/clients/SvmSpoke/instructions/deposit.d.ts +21 -13
  17. package/dist/src/svm/clients/SvmSpoke/instructions/deposit.js +38 -6
  18. package/dist/src/svm/clients/SvmSpoke/instructions/depositNow.d.ts +21 -13
  19. package/dist/src/svm/clients/SvmSpoke/instructions/depositNow.js +38 -6
  20. package/dist/src/svm/clients/SvmSpoke/instructions/fillRelay.d.ts +20 -16
  21. package/dist/src/svm/clients/SvmSpoke/instructions/fillRelay.js +6 -1
  22. package/dist/src/svm/clients/SvmSpoke/instructions/index.d.ts +0 -1
  23. package/dist/src/svm/clients/SvmSpoke/instructions/index.js +0 -1
  24. package/dist/src/svm/clients/SvmSpoke/instructions/unsafeDeposit.d.ts +21 -13
  25. package/dist/src/svm/clients/SvmSpoke/instructions/unsafeDeposit.js +38 -6
  26. package/dist/src/svm/clients/SvmSpoke/programs/svmSpoke.d.ts +6 -10
  27. package/dist/src/svm/clients/SvmSpoke/programs/svmSpoke.js +5 -13
  28. package/dist/src/svm/clients/SvmSpoke/types/index.d.ts +0 -1
  29. package/dist/src/svm/clients/SvmSpoke/types/index.js +0 -1
  30. package/dist/src/svm/web3-v1/helpers.d.ts +114 -1
  31. package/dist/src/svm/web3-v1/helpers.js +179 -1
  32. package/dist/target/types/svm_spoke.d.ts +40 -366
  33. package/dist/test/svm/SvmSpoke.Deposit.js +143 -176
  34. package/dist/test/svm/SvmSpoke.Fill.AcrossPlus.js +20 -17
  35. package/dist/test/svm/SvmSpoke.Fill.js +52 -38
  36. package/dist/test/svm/SvmSpoke.HandleReceiveMessage.js +2 -114
  37. package/dist/test/svm/SvmSpoke.SlowFill.AcrossPlus.js +2 -2
  38. package/dist/test/svm/SvmSpoke.SlowFill.js +37 -34
  39. package/dist/test/svm/SvmSpoke.common.d.ts +2 -3
  40. package/dist/test/svm/SvmSpoke.common.js +3 -12
  41. package/package.json +1 -1
  42. package/dist/scripts/svm/remoteHubPoolSetDepositRoute.d.ts +0 -1
  43. package/dist/scripts/svm/remoteHubPoolSetDepositRoute.js +0 -252
  44. package/dist/src/svm/clients/SvmSpoke/accounts/route.d.ts +0 -27
  45. package/dist/src/svm/clients/SvmSpoke/accounts/route.js +0 -66
  46. package/dist/src/svm/clients/SvmSpoke/instructions/setEnableRoute.d.ts +0 -95
  47. package/dist/src/svm/clients/SvmSpoke/instructions/setEnableRoute.js +0 -213
  48. package/dist/src/svm/clients/SvmSpoke/types/enabledDepositRoute.d.ts +0 -21
  49. package/dist/src/svm/clients/SvmSpoke/types/enabledDepositRoute.js +0 -30
  50. package/dist/test/svm/SvmSpoke.Routes.js +0 -167
  51. /package/dist/scripts/svm/{enableRoute.d.ts → createVault.d.ts} +0 -0
  52. /package/dist/scripts/svm/{queryRoute.d.ts → nativeDeposit.d.ts} +0 -0
  53. /package/dist/{test/svm/SvmSpoke.Routes.d.ts → scripts/svm/queryVault.d.ts} +0 -0
@@ -35,44 +35,29 @@ const web3_v1_1 = require("../../src/svm/web3-v1");
35
35
  const test_utils_1 = require("../../test-utils");
36
36
  const SvmSpoke_common_1 = require("./SvmSpoke.common");
37
37
  const utils_1 = require("./utils");
38
- const { provider, connection, program, owner, seedBalance, initializeState, depositData, createRoutePda, getVaultAta, assertSE, assert, getCurrentTime, depositQuoteTimeBuffer, fillDeadlineBuffer, } = SvmSpoke_common_1.common;
38
+ const { provider, connection, program, owner, seedBalance, initializeState, depositData, assertSE, assert, getCurrentTime, depositQuoteTimeBuffer, fillDeadlineBuffer, getOrCreateVaultAta, } = SvmSpoke_common_1.common;
39
39
  const maxExclusivityOffsetSeconds = new anchor_1.BN(test_utils_1.MAX_EXCLUSIVITY_OFFSET_SECONDS); // 1 year in seconds
40
40
  describe("svm_spoke.deposit", () => {
41
41
  anchor.setProvider(provider);
42
42
  const depositor = web3_js_1.Keypair.generate();
43
- const payer = anchor.AnchorProvider.env().wallet.payer;
43
+ const { payer } = anchor.AnchorProvider.env().wallet;
44
44
  const tokenDecimals = 6;
45
45
  let state, inputToken, depositorTA, vault, tokenProgram;
46
46
  let seed;
47
47
  let depositAccounts;
48
- let setEnableRouteAccounts; // Common variable for setEnableRoute accounts
49
48
  const setupInputToken = async () => {
50
49
  inputToken = await (0, spl_token_1.createMint)(connection, payer, owner, owner, tokenDecimals, undefined, undefined, tokenProgram);
51
50
  depositorTA = (await (0, spl_token_1.getOrCreateAssociatedTokenAccount)(connection, payer, inputToken, depositor.publicKey, undefined, undefined, undefined, tokenProgram)).address;
52
51
  await (0, spl_token_1.mintTo)(connection, payer, inputToken, depositorTA, owner, seedBalance, undefined, undefined, tokenProgram);
53
52
  };
54
- const enableRoute = async () => {
55
- const routeChainId = new anchor_1.BN(1);
56
- const route = createRoutePda(inputToken, seed, routeChainId);
57
- vault = await getVaultAta(inputToken, state);
58
- setEnableRouteAccounts = {
59
- signer: owner,
60
- payer: owner,
61
- state,
62
- route,
63
- vault,
64
- originTokenMint: inputToken, // Note the Sol expects this to be named originTokenMint.
65
- tokenProgram: tokenProgram ?? spl_token_1.TOKEN_PROGRAM_ID,
66
- associatedTokenProgram: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
67
- systemProgram: anchor.web3.SystemProgram.programId,
68
- };
69
- await program.methods.setEnableRoute(inputToken, routeChainId, true).accounts(setEnableRouteAccounts).rpc();
53
+ const createVault = async () => {
54
+ vault = await getOrCreateVaultAta(payer, inputToken, state);
70
55
  // Set known fields in the depositData.
71
56
  depositData.depositor = depositor.publicKey;
72
57
  depositData.inputToken = inputToken;
73
58
  depositAccounts = {
74
59
  state,
75
- route,
60
+ delegate: (0, web3_v1_1.getDepositPda)(depositData, program.programId),
76
61
  signer: depositor.publicKey,
77
62
  depositorTokenAccount: depositorTA,
78
63
  vault,
@@ -81,30 +66,33 @@ describe("svm_spoke.deposit", () => {
81
66
  program: program.programId,
82
67
  };
83
68
  };
84
- const approvedDeposit = async (depositDataValues, calledDepositAccounts = depositAccounts) => {
85
- // Delegate state PDA to pull depositor tokens.
86
- const approveIx = await (0, spl_token_1.createApproveCheckedInstruction)(calledDepositAccounts.depositorTokenAccount, calledDepositAccounts.mint, calledDepositAccounts.state, depositor.publicKey, BigInt(depositData.inputAmount.toString()), tokenDecimals, undefined, tokenProgram);
69
+ const approvedDeposit = async (depositData, calledDepositAccounts = depositAccounts) => {
70
+ const delegatePda = (0, web3_v1_1.getDepositPda)(depositData, program.programId);
71
+ calledDepositAccounts.delegate = delegatePda;
72
+ // Delegate delegate PDA to pull depositor tokens.
73
+ const approveIx = await (0, spl_token_1.createApproveCheckedInstruction)(calledDepositAccounts.depositorTokenAccount, calledDepositAccounts.mint, delegatePda, depositor.publicKey, BigInt(depositData.inputAmount.toString()), tokenDecimals, undefined, tokenProgram);
87
74
  const depositIx = await program.methods
88
- .deposit(...depositDataValues)
75
+ .deposit(depositData.depositor, depositData.recipient, depositData.inputToken, depositData.outputToken, depositData.inputAmount, depositData.outputAmount, depositData.destinationChainId, depositData.exclusiveRelayer, depositData.quoteTimestamp.toNumber(), depositData.fillDeadline.toNumber(), depositData.exclusivityParameter.toNumber(), depositData.message)
89
76
  .accounts(calledDepositAccounts)
90
77
  .instruction();
91
78
  const depositTx = new web3_js_1.Transaction().add(approveIx, depositIx);
92
- const tx = await (0, web3_js_1.sendAndConfirmTransaction)(connection, depositTx, [payer, depositor]);
93
- return tx;
79
+ return (0, web3_js_1.sendAndConfirmTransaction)(connection, depositTx, [depositor]);
94
80
  };
81
+ before(async () => {
82
+ await connection.requestAirdrop(depositor.publicKey, 10_000_000_000); // 10 SOL
83
+ });
95
84
  beforeEach(async () => {
96
85
  ({ state, seed } = await initializeState());
97
86
  tokenProgram = spl_token_1.TOKEN_PROGRAM_ID; // Some tests might override this.
98
87
  await setupInputToken();
99
- await enableRoute();
88
+ await createVault();
100
89
  });
101
90
  it("Deposits tokens via deposit function and checks balances", async () => {
102
91
  // Verify vault balance is zero before the deposit
103
92
  let vaultAccount = await (0, spl_token_1.getAccount)(connection, vault);
104
93
  assertSE(vaultAccount.amount, "0", "Vault balance should be zero before the deposit");
105
94
  // Execute the deposit call
106
- let depositDataValues = Object.values(depositData);
107
- await approvedDeposit(depositDataValues);
95
+ await approvedDeposit(depositData);
108
96
  // Verify tokens leave the depositor's account
109
97
  let depositorAccount = await (0, spl_token_1.getAccount)(connection, depositorTA);
110
98
  assertSE(depositorAccount.amount, seedBalance - depositData.inputAmount.toNumber(), "Depositor's balance should be reduced by the deposited amount");
@@ -114,8 +102,7 @@ describe("svm_spoke.deposit", () => {
114
102
  // Modify depositData for the second deposit
115
103
  const secondInputAmount = new anchor_1.BN(300000);
116
104
  // Execute the second deposit call
117
- depositDataValues = Object.values({ ...depositData, inputAmount: secondInputAmount });
118
- await approvedDeposit(depositDataValues);
105
+ await approvedDeposit({ ...depositData, inputAmount: secondInputAmount });
119
106
  // Verify tokens leave the depositor's account again
120
107
  depositorAccount = await (0, spl_token_1.getAccount)(connection, depositorTA);
121
108
  assertSE(depositorAccount.amount, seedBalance - depositData.inputAmount.toNumber() - secondInputAmount.toNumber(), "Depositor's balance should be reduced by the total deposited amount");
@@ -126,8 +113,7 @@ describe("svm_spoke.deposit", () => {
126
113
  it("Verifies FundsDeposited after deposits", async () => {
127
114
  depositData.inputAmount = depositData.inputAmount.add(new anchor_1.BN(69));
128
115
  // Execute the first deposit call
129
- let depositDataValues = Object.values(depositData);
130
- const tx = await approvedDeposit(depositDataValues);
116
+ const tx = await approvedDeposit(depositData);
131
117
  let events = await (0, web3_v1_1.readEventsUntilFound)(connection, tx, [program]);
132
118
  let event = events[0].data; // 0th event is the latest event
133
119
  const expectedValues1 = { ...depositData, depositId: (0, web3_v1_1.intToU8Array32)(1) }; // Verify the event props emitted match the depositData.
@@ -139,8 +125,8 @@ describe("svm_spoke.deposit", () => {
139
125
  // Test the id recovery with the conversion utils
140
126
  assertSE((0, web3_v1_1.u8Array32ToInt)(event.depositId), 1, `depositId should recover to 1`);
141
127
  assertSE((0, web3_v1_1.u8Array32ToBigNumber)(event.depositId), ethers_1.BigNumber.from(1), `depositId should recover to 1`);
142
- // Execute the second deposit_v3 call
143
- const tx2 = await approvedDeposit(depositDataValues);
128
+ // Execute the second deposit call
129
+ const tx2 = await approvedDeposit(depositData);
144
130
  events = await (0, web3_v1_1.readEventsUntilFound)(connection, tx2, [program]);
145
131
  event = events[0].data; // 0th event is the latest event.
146
132
  const expectedValues2 = { ...expectedValues1, depositId: (0, web3_v1_1.intToU8Array32)(2) }; // Verify the event props emitted match the depositData.
@@ -159,46 +145,11 @@ describe("svm_spoke.deposit", () => {
159
145
  let fillDeadline = currentTime - 1; // 1 second before current time on the contract.
160
146
  depositData.fillDeadline = new anchor_1.BN(fillDeadline);
161
147
  depositData.quoteTimestamp = new anchor_1.BN(currentTime - 1); // 1 second before current time on the contract to reset.
162
- const depositDataValues = Object.values(depositData);
163
- const tx = await approvedDeposit(depositDataValues);
148
+ const tx = await approvedDeposit(depositData);
164
149
  const events = await (0, web3_v1_1.readEventsUntilFound)(connection, tx, [program]);
165
150
  const event = events[0].data; // 0th event is the latest event.
166
151
  assertSE(event.fillDeadline, fillDeadline, "Fill deadline should match");
167
152
  });
168
- it("Fails to deposit tokens to a route that is uninitalized", async () => {
169
- const differentChainId = new anchor_1.BN(2); // Different chain ID
170
- if (!depositData.inputToken) {
171
- throw new Error("Input token is null");
172
- }
173
- const differentRoutePda = createRoutePda(depositData.inputToken, seed, differentChainId);
174
- depositAccounts.route = differentRoutePda;
175
- try {
176
- const depositDataValues = Object.values({
177
- ...depositData,
178
- destinationChainId: differentChainId,
179
- });
180
- await approvedDeposit(depositDataValues);
181
- assert.fail("Deposit should have failed for a route that is not initialized");
182
- }
183
- catch (err) {
184
- assert.include(err.toString(), "AccountNotInitialized", "Expected AccountNotInitialized error");
185
- }
186
- });
187
- it("Fails to deposit tokens to a route that is explicitly disabled", async () => {
188
- // Disable the route
189
- await program.methods
190
- .setEnableRoute(depositData.inputToken, depositData.destinationChainId, false)
191
- .accounts(setEnableRouteAccounts)
192
- .rpc();
193
- try {
194
- const depositDataValues = Object.values(depositData);
195
- await approvedDeposit(depositDataValues);
196
- assert.fail("Deposit should have failed for a route that is explicitly disabled");
197
- }
198
- catch (err) {
199
- assert.include(err.toString(), "DisabledRoute", "Expected DisabledRoute error");
200
- }
201
- });
202
153
  it("Fails to process deposit when deposits are paused", async () => {
203
154
  // Pause deposits
204
155
  const pauseDepositsAccounts = { state, signer: owner, program: program.programId };
@@ -207,8 +158,7 @@ describe("svm_spoke.deposit", () => {
207
158
  assert.isTrue(stateAccountData.pausedDeposits, "Deposits should be paused");
208
159
  // Try to deposit. This should fail because deposits are paused.
209
160
  try {
210
- const depositDataValues = Object.values(depositData);
211
- await approvedDeposit(depositDataValues);
161
+ await approvedDeposit(depositData);
212
162
  assert.fail("Should not be able to process deposit when deposits are paused");
213
163
  }
214
164
  catch (err) {
@@ -220,8 +170,7 @@ describe("svm_spoke.deposit", () => {
220
170
  const futureQuoteTimestamp = new anchor_1.BN(currentTime + 10); // 10 seconds in the future
221
171
  depositData.quoteTimestamp = futureQuoteTimestamp;
222
172
  try {
223
- const depositDataValues = Object.values(depositData);
224
- await approvedDeposit(depositDataValues);
173
+ await approvedDeposit(depositData);
225
174
  assert.fail("Deposit should have failed due to InvalidQuoteTimestamp");
226
175
  }
227
176
  catch (err) {
@@ -233,8 +182,7 @@ describe("svm_spoke.deposit", () => {
233
182
  const futureQuoteTimestamp = new anchor_1.BN(currentTime - depositQuoteTimeBuffer.toNumber() - 1); // older than buffer.
234
183
  depositData.quoteTimestamp = futureQuoteTimestamp;
235
184
  try {
236
- const depositDataValues = Object.values(depositData);
237
- await approvedDeposit(depositDataValues);
185
+ await approvedDeposit(depositData);
238
186
  assert.fail("Deposit should have failed due to InvalidQuoteTimestamp");
239
187
  }
240
188
  catch (err) {
@@ -248,8 +196,7 @@ describe("svm_spoke.deposit", () => {
248
196
  depositData.fillDeadline = new anchor_1.BN(invalidFillDeadline);
249
197
  depositData.quoteTimestamp = new anchor_1.BN(currentTime);
250
198
  try {
251
- const depositDataValues = Object.values(depositData);
252
- await approvedDeposit(depositDataValues);
199
+ await approvedDeposit(depositData);
253
200
  assert.fail("Deposit should have failed due to InvalidFillDeadline (future deadline)");
254
201
  }
255
202
  catch (err) {
@@ -257,101 +204,41 @@ describe("svm_spoke.deposit", () => {
257
204
  }
258
205
  });
259
206
  it("Fails to process deposit for mint inconsistent input_token", async () => {
260
- // Save the correct data and accounts from global scope before changing it when creating a new input token.
207
+ // Save the correct data from global scope before changing it when creating a new input token.
261
208
  const firstInputToken = inputToken;
262
- const firstDepositAccounts = depositAccounts;
263
- // Create a new input token and enable the route (this updates global scope variables).
209
+ // Create a new input token and the vault.
264
210
  await setupInputToken();
265
- await enableRoute();
266
- // Try to execute the deposit call with malformed inputs where the first input token and its derived route is
267
- // passed combined with mint, vault and user token account from the second input token.
211
+ await createVault();
212
+ // Try to execute the deposit call with malformed inputs where the first input token is passed combined with mint,
213
+ // vault and user token account from the second input token.
268
214
  const malformedDepositData = { ...depositData, inputToken: firstInputToken };
269
- const malformedDepositAccounts = { ...depositAccounts, route: firstDepositAccounts.route };
215
+ const malformedDepositAccounts = { ...depositAccounts };
270
216
  try {
271
- const depositDataValues = Object.values(malformedDepositData);
272
- await approvedDeposit(depositDataValues, malformedDepositAccounts);
217
+ await approvedDeposit(malformedDepositData, malformedDepositAccounts);
273
218
  assert.fail("Should not be able to process deposit for inconsistent mint");
274
219
  }
275
220
  catch (err) {
276
221
  assert.include(err.toString(), "Error Code: InvalidMint", "Expected InvalidMint error");
277
222
  }
278
223
  });
279
- it("Tests deposit with a fake route PDA", async () => {
280
- // Create fake program state
281
- const fakeState = await initializeState();
282
- const fakeVault = await getVaultAta(inputToken, fakeState.state);
283
- const fakeRouteChainId = new anchor_1.BN(3);
284
- const fakeRoutePda = createRoutePda(inputToken, fakeState.seed, fakeRouteChainId);
285
- // A seeds constraint was violated.
286
- const fakeSetEnableRouteAccounts = {
287
- signer: owner,
288
- payer: owner,
289
- state: fakeState.state,
290
- route: fakeRoutePda,
291
- vault: fakeVault,
292
- originTokenMint: inputToken,
293
- tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
294
- associatedTokenProgram: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
295
- systemProgram: anchor.web3.SystemProgram.programId,
296
- program: program.programId,
297
- };
298
- await program.methods.setEnableRoute(inputToken, fakeRouteChainId, true).accounts(fakeSetEnableRouteAccounts).rpc();
299
- const fakeDepositAccounts = {
300
- state: fakeState.state,
301
- route: fakeRoutePda,
302
- signer: depositor.publicKey,
303
- depositorTokenAccount: depositorTA,
304
- vault: fakeVault,
305
- mint: inputToken,
306
- tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
307
- program: program.programId,
308
- };
309
- // Deposit with the fake state and route PDA should succeed.
310
- const depositDataValues = Object.values({
311
- ...depositData,
312
- destinationChainId: fakeRouteChainId,
313
- });
314
- const tx = await approvedDeposit(depositDataValues, fakeDepositAccounts);
315
- let events = await (0, web3_v1_1.readEventsUntilFound)(connection, tx, [program]);
316
- let event = events[0].data; // 0th event is the latest event.
317
- const expectedValues = {
318
- ...{ ...depositData, destinationChainId: fakeRouteChainId },
319
- depositId: (0, web3_v1_1.intToU8Array32)(1),
320
- }; // Verify the event props emitted match the depositData.
321
- for (let [key, value] of Object.entries(expectedValues)) {
322
- if (key === "exclusivityParameter")
323
- key = "exclusivityDeadline"; // the prop and the event names differ on this key.
324
- assertSE(event[key], value, `${key} should match`);
325
- }
326
- // Check fake vault acount balance
327
- const fakeVaultAccount = await (0, spl_token_1.getAccount)(connection, fakeVault);
328
- assertSE(fakeVaultAccount.amount, depositData.inputAmount.toNumber(), "Fake vault balance should be increased by the deposited amount");
329
- // Deposit with the fake route in the original program state should fail.
330
- try {
331
- const depositDataValues = Object.values({
332
- ...{ ...depositData, destinationChainId: fakeRouteChainId },
333
- });
334
- await approvedDeposit(depositDataValues, { ...depositAccounts, route: fakeRoutePda });
335
- assert.fail("Deposit should have failed for a fake route PDA");
336
- }
337
- catch (err) {
338
- assert.include(err.toString(), "A seeds constraint was violated");
339
- }
340
- const vaultAccount = await (0, spl_token_1.getAccount)(connection, vault);
341
- assertSE(vaultAccount.amount, 0, "Vault balance should not be changed by the fake route deposit");
342
- });
343
- it("depositV3Now behaves as deposit but forces the quote timestamp as expected", async () => {
224
+ it("depositNow behaves as deposit but forces the quote timestamp as expected", async () => {
344
225
  // Set up initial deposit data. Note that this method has a slightly different interface to deposit, using
345
226
  // fillDeadlineOffset rather than fillDeadline. current chain time is added to fillDeadlineOffset to set the
346
227
  // fillDeadline for the deposit. exclusivityPeriod operates the same as in standard deposit.
347
- // Equally, depositV3Now does not have `quoteTimestamp`. this is set to the current time from the program.
228
+ // Equally, depositNow does not have `quoteTimestamp`. this is set to the current time from the program.
348
229
  const fillDeadlineOffset = 60; // 60 seconds offset
230
+ const depositNowData = {
231
+ ...depositData,
232
+ fillDeadlineOffset: new anchor_1.BN(fillDeadlineOffset),
233
+ exclusivityPeriod: new anchor_1.BN(0),
234
+ };
235
+ const delegatePda = (0, web3_v1_1.getDepositNowPda)(depositNowData, program.programId);
349
236
  // Delegate state PDA to pull depositor tokens.
350
- const approveIx = await (0, spl_token_1.createApproveCheckedInstruction)(depositAccounts.depositorTokenAccount, depositAccounts.mint, depositAccounts.state, depositor.publicKey, BigInt(depositData.inputAmount.toString()), tokenDecimals, undefined, tokenProgram);
237
+ const approveIx = await (0, spl_token_1.createApproveCheckedInstruction)(depositAccounts.depositorTokenAccount, depositAccounts.mint, delegatePda, depositor.publicKey, BigInt(depositData.inputAmount.toString()), tokenDecimals, undefined, tokenProgram);
351
238
  // Execute the deposit_now call. Remove the quoteTimestamp from the depositData as not needed for this method.
352
239
  const depositIx = await program.methods
353
- .depositNow(depositData.depositor, depositData.recipient, depositData.inputToken, depositData.outputToken, depositData.inputAmount, depositData.outputAmount, depositData.destinationChainId, depositData.exclusiveRelayer, fillDeadlineOffset, 0, depositData.message)
354
- .accounts(depositAccounts)
240
+ .depositNow(depositNowData.depositor, depositNowData.recipient, depositNowData.inputToken, depositNowData.outputToken, depositNowData.inputAmount, depositNowData.outputAmount, depositNowData.destinationChainId, depositNowData.exclusiveRelayer, fillDeadlineOffset, 0, depositNowData.message)
241
+ .accounts({ ...depositAccounts, delegate: delegatePda })
355
242
  .instruction();
356
243
  const depositTx = new web3_js_1.Transaction().add(approveIx, depositIx);
357
244
  const tx = await (0, web3_js_1.sendAndConfirmTransaction)(connection, depositTx, [payer, depositor]);
@@ -378,8 +265,7 @@ describe("svm_spoke.deposit", () => {
378
265
  depositData.exclusiveRelayer = new web3_js_1.PublicKey("11111111111111111111111111111111");
379
266
  depositData.exclusivityParameter = new anchor_1.BN(1);
380
267
  try {
381
- const depositDataValues = Object.values(depositData);
382
- await approvedDeposit(depositDataValues);
268
+ await approvedDeposit(depositData);
383
269
  assert.fail("Should have failed due to InvalidExclusiveRelayer");
384
270
  }
385
271
  catch (err) {
@@ -395,8 +281,7 @@ describe("svm_spoke.deposit", () => {
395
281
  for (const exclusivityDeadline of invalidExclusivityDeadlines) {
396
282
  depositData.exclusivityParameter = exclusivityDeadline;
397
283
  try {
398
- const depositDataValues = Object.values(depositData);
399
- await approvedDeposit(depositDataValues);
284
+ await approvedDeposit(depositData);
400
285
  assert.fail("Should have failed due to InvalidExclusiveRelayer");
401
286
  }
402
287
  catch (err) {
@@ -405,16 +290,14 @@ describe("svm_spoke.deposit", () => {
405
290
  }
406
291
  // Test with exclusivityDeadline set to 0
407
292
  depositData.exclusivityParameter = new anchor_1.BN(0);
408
- const depositDataValues = Object.values(depositData);
409
- await approvedDeposit(depositDataValues);
293
+ await approvedDeposit(depositData);
410
294
  });
411
295
  it("Exclusivity param is used as an offset", async () => {
412
296
  const currentTime = new anchor_1.BN(await getCurrentTime(program, state));
413
297
  depositData.quoteTimestamp = currentTime;
414
298
  depositData.exclusiveRelayer = depositor.publicKey;
415
299
  depositData.exclusivityParameter = maxExclusivityOffsetSeconds;
416
- const depositDataValues = Object.values(depositData);
417
- const tx = await approvedDeposit(depositDataValues);
300
+ const tx = await approvedDeposit(depositData);
418
301
  const events = await (0, web3_v1_1.readEventsUntilFound)(connection, tx, [program]);
419
302
  const event = events[0].data; // 0th event is the latest event
420
303
  assertSE(event.exclusivityDeadline, currentTime.add(maxExclusivityOffsetSeconds), "exclusivityDeadline should be current time + offset");
@@ -425,8 +308,7 @@ describe("svm_spoke.deposit", () => {
425
308
  const exclusivityDeadlineTimestamp = maxExclusivityOffsetSeconds.add(new anchor_1.BN(1)); // 1 year + 1 second
426
309
  depositData.exclusiveRelayer = depositor.publicKey;
427
310
  depositData.exclusivityParameter = exclusivityDeadlineTimestamp;
428
- const depositDataValues = Object.values(depositData);
429
- const tx = await approvedDeposit(depositDataValues);
311
+ const tx = await approvedDeposit(depositData);
430
312
  const events = await (0, web3_v1_1.readEventsUntilFound)(connection, tx, [program]);
431
313
  const event = events[0].data; // 0th event is the latest event;
432
314
  assertSE(event.exclusivityDeadline, exclusivityDeadlineTimestamp, "exclusivityDeadline should be passed in time");
@@ -437,8 +319,7 @@ describe("svm_spoke.deposit", () => {
437
319
  const zeroExclusivity = new anchor_1.BN(0);
438
320
  depositData.exclusiveRelayer = depositor.publicKey;
439
321
  depositData.exclusivityParameter = zeroExclusivity;
440
- const depositDataValues = Object.values(depositData);
441
- const tx = await approvedDeposit(depositDataValues);
322
+ const tx = await approvedDeposit(depositData);
442
323
  const events = await (0, web3_v1_1.readEventsUntilFound)(connection, tx, [program]);
443
324
  const event = events[0].data; // 0th event is the latest event;
444
325
  assertSE(event.exclusivityDeadline, zeroExclusivity, "Exclusivity deadline should always be 0");
@@ -458,8 +339,8 @@ describe("svm_spoke.deposit", () => {
458
339
  .view();
459
340
  assert.strictEqual(expectedDepositIdArray.toString(), unsafeDepositIdTx.toString(), "Deposit ID should match the expected hash");
460
341
  // Delegate state PDA to pull depositor tokens.
461
- const approveIx = await (0, spl_token_1.createApproveCheckedInstruction)(depositAccounts.depositorTokenAccount, depositAccounts.mint, depositAccounts.state, depositor.publicKey, BigInt(depositData.inputAmount.toString()), tokenDecimals, undefined, tokenProgram);
462
- // Create the transaction for unsafeDepositV3
342
+ const approveIx = await (0, spl_token_1.createApproveCheckedInstruction)(depositAccounts.depositorTokenAccount, depositAccounts.mint, (0, web3_v1_1.getDepositPda)(depositData, program.programId), depositor.publicKey, BigInt(depositData.inputAmount.toString()), tokenDecimals, undefined, tokenProgram);
343
+ // Create the transaction for unsafeDeposit
463
344
  const unsafeDepositIx = await program.methods
464
345
  .unsafeDeposit(depositData.depositor, depositData.recipient, depositData.inputToken, depositData.outputToken, depositData.inputAmount, depositData.outputAmount, depositData.destinationChainId, depositData.exclusiveRelayer, forcedDepositId, // deposit nonce
465
346
  depositData.quoteTimestamp.toNumber(), depositData.fillDeadline.toNumber(), depositData.exclusivityParameter.toNumber(), depositData.message)
@@ -482,7 +363,7 @@ describe("svm_spoke.deposit", () => {
482
363
  // CPI-guard is available only for the 2022 token program.
483
364
  tokenProgram = spl_token_1.TOKEN_2022_PROGRAM_ID;
484
365
  await setupInputToken();
485
- await enableRoute();
366
+ await createVault();
486
367
  // Enable CPI-guard for the depositor (requires TA reallocation).
487
368
  const enableCpiGuardTx = new web3_js_1.Transaction().add((0, spl_token_1.createReallocateInstruction)(depositorTA, payer.publicKey, [spl_token_1.ExtensionType.CpiGuard], depositor.publicKey), (0, spl_token_1.createEnableCpiGuardInstruction)(depositorTA, depositor.publicKey));
488
369
  await (0, web3_js_1.sendAndConfirmTransaction)(connection, enableCpiGuardTx, [payer, depositor]);
@@ -490,8 +371,7 @@ describe("svm_spoke.deposit", () => {
490
371
  let vaultAccount = await (0, spl_token_1.getAccount)(connection, vault, undefined, tokenProgram);
491
372
  assertSE(vaultAccount.amount, "0", "Vault balance should be zero before the deposit");
492
373
  // Execute the deposit call
493
- const depositDataValues = Object.values(depositData);
494
- await approvedDeposit(depositDataValues);
374
+ await approvedDeposit(depositData);
495
375
  // Verify tokens leave the depositor's account
496
376
  const depositorAccount = await (0, spl_token_1.getAccount)(connection, depositorTA, undefined, tokenProgram);
497
377
  assertSE(depositorAccount.amount, seedBalance - depositData.inputAmount.toNumber(), "Depositor's balance should be reduced by the deposited amount");
@@ -513,6 +393,93 @@ describe("svm_spoke.deposit", () => {
513
393
  assert.include(err.toString(), "owner does not match");
514
394
  }
515
395
  });
396
+ it("Deposit native token, new token account", async () => {
397
+ // Fund depositor account with SOL.
398
+ const nativeAmount = 1_000_000_000; // 1 SOL
399
+ await connection.requestAirdrop(depositor.publicKey, nativeAmount * 2); // Add buffer for transaction fees.
400
+ // Setup wSOL as the input token.
401
+ inputToken = spl_token_1.NATIVE_MINT;
402
+ const nativeDecimals = 9;
403
+ depositorTA = (0, spl_token_1.getAssociatedTokenAddressSync)(inputToken, depositor.publicKey);
404
+ await createVault();
405
+ // Will need to add rent exemption to the deposit amount, will recover it at the end of the transaction.
406
+ const rentExempt = await (0, spl_token_1.getMinimumBalanceForRentExemptAccount)(connection);
407
+ const transferIx = web3_js_1.SystemProgram.transfer({
408
+ fromPubkey: depositor.publicKey,
409
+ toPubkey: depositorTA,
410
+ lamports: BigInt(nativeAmount) + BigInt(rentExempt),
411
+ });
412
+ // Create wSOL user account.
413
+ const createIx = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(depositor.publicKey, depositorTA, depositor.publicKey, inputToken);
414
+ const nativeDepositData = { ...depositData, inputAmount: new anchor_1.BN(nativeAmount), outputAmount: new anchor_1.BN(nativeAmount) };
415
+ const depositDataValues = Object.values(nativeDepositData);
416
+ const delegate = (0, web3_v1_1.getDepositPda)(nativeDepositData, program.programId);
417
+ const approveIx = await (0, spl_token_1.createApproveCheckedInstruction)(depositAccounts.depositorTokenAccount, depositAccounts.mint, delegate, depositor.publicKey, BigInt(nativeAmount), nativeDecimals, undefined, tokenProgram);
418
+ const depositIx = await program.methods
419
+ .deposit(...depositDataValues)
420
+ .accounts({ ...depositAccounts, delegate })
421
+ .instruction();
422
+ const closeIx = (0, spl_token_1.createCloseAccountInstruction)(depositorTA, depositor.publicKey, depositor.publicKey);
423
+ const iVaultAmount = (await (0, spl_token_1.getAccount)(connection, vault, undefined, tokenProgram)).amount;
424
+ const depositTx = new web3_js_1.Transaction().add(transferIx, createIx, approveIx, depositIx, closeIx);
425
+ const tx = await (0, web3_js_1.sendAndConfirmTransaction)(connection, depositTx, [depositor]);
426
+ const fVaultAmount = (await (0, spl_token_1.getAccount)(connection, vault, undefined, tokenProgram)).amount;
427
+ assertSE(fVaultAmount, iVaultAmount + BigInt(nativeAmount), "Vault balance should be increased by the deposited amount");
428
+ });
429
+ it("Deposit native token, existing token account", async () => {
430
+ // Fund depositor account with SOL.
431
+ const nativeAmount = 1_000_000_000; // 1 SOL
432
+ await connection.requestAirdrop(depositor.publicKey, nativeAmount * 2); // Add buffer for transaction fees.
433
+ // Setup wSOL as the input token, creating the associated token account for the user.
434
+ inputToken = spl_token_1.NATIVE_MINT;
435
+ const nativeDecimals = 9;
436
+ depositorTA = (await (0, spl_token_1.getOrCreateAssociatedTokenAccount)(connection, payer, inputToken, depositor.publicKey)).address;
437
+ await createVault();
438
+ // Transfer SOL to the user token account.
439
+ const transferIx = web3_js_1.SystemProgram.transfer({
440
+ fromPubkey: depositor.publicKey,
441
+ toPubkey: depositorTA,
442
+ lamports: nativeAmount,
443
+ });
444
+ // Sync the user token account with the native balance.
445
+ const syncIx = (0, spl_token_1.createSyncNativeInstruction)(depositorTA);
446
+ const nativeDepositData = { ...depositData, inputAmount: new anchor_1.BN(nativeAmount), outputAmount: new anchor_1.BN(nativeAmount) };
447
+ const depositDataValues = Object.values(nativeDepositData);
448
+ const delegate = (0, web3_v1_1.getDepositPda)(nativeDepositData, program.programId);
449
+ const approveIx = await (0, spl_token_1.createApproveCheckedInstruction)(depositAccounts.depositorTokenAccount, depositAccounts.mint, delegate, depositor.publicKey, BigInt(nativeAmount), nativeDecimals, undefined, tokenProgram);
450
+ const depositIx = await program.methods
451
+ .deposit(...depositDataValues)
452
+ .accounts({ ...depositAccounts, delegate })
453
+ .instruction();
454
+ const iVaultAmount = (await (0, spl_token_1.getAccount)(connection, vault, undefined, tokenProgram)).amount;
455
+ const depositTx = new web3_js_1.Transaction().add(transferIx, syncIx, approveIx, depositIx);
456
+ const tx = await (0, web3_js_1.sendAndConfirmTransaction)(connection, depositTx, [depositor]);
457
+ const fVaultAmount = (await (0, spl_token_1.getAccount)(connection, vault, undefined, tokenProgram)).amount;
458
+ assertSE(fVaultAmount, iVaultAmount + BigInt(nativeAmount), "Vault balance should be increased by the deposited amount");
459
+ });
460
+ it("Deposits tokens to a new vault", async () => {
461
+ // Create new input token without creating a new vault for it.
462
+ await setupInputToken();
463
+ const inputTokenAccount = await provider.connection.getAccountInfo(inputToken);
464
+ if (inputTokenAccount === null)
465
+ throw new Error("Input mint account not found");
466
+ vault = (0, spl_token_1.getAssociatedTokenAddressSync)(inputToken, state, true, inputTokenAccount.owner, spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID);
467
+ // Update global variables using the new input token.
468
+ depositData.inputToken = inputToken;
469
+ depositAccounts.depositorTokenAccount = depositorTA;
470
+ depositAccounts.vault = vault;
471
+ depositAccounts.mint = inputToken;
472
+ // Verify there is no vault account before the deposit.
473
+ assert.isNull(await provider.connection.getAccountInfo(vault), "Vault should not exist before the deposit");
474
+ // Execute the deposit call
475
+ await approvedDeposit(depositData);
476
+ // Verify tokens leave the depositor's account
477
+ const depositorAccount = await (0, spl_token_1.getAccount)(connection, depositorTA);
478
+ assertSE(depositorAccount.amount, seedBalance - depositData.inputAmount.toNumber(), "Depositor's balance should be reduced by the deposited amount");
479
+ // Verify tokens are credited into the new vault
480
+ const vaultAccount = await (0, spl_token_1.getAccount)(connection, vault);
481
+ assertSE(vaultAccount.amount, depositData.inputAmount, "Vault balance should equal the deposited amount");
482
+ });
516
483
  describe("codama client and solana kit", () => {
517
484
  it("Deposit with with solana kit and codama client", async () => {
518
485
  // typescript is not happy with the depositData object
@@ -534,7 +501,7 @@ describe("svm_spoke.deposit", () => {
534
501
  const approveIx = (0, token_1.getApproveCheckedInstruction)({
535
502
  source: (0, kit_1.address)(depositAccounts.depositorTokenAccount.toString()),
536
503
  mint: (0, kit_1.address)(depositAccounts.mint.toString()),
537
- delegate: (0, kit_1.address)(depositAccounts.state.toString()),
504
+ delegate: (0, kit_1.address)((0, web3_v1_1.getDepositPda)(depositData, program.programId).toString()),
538
505
  owner: (0, kit_1.address)(depositor.publicKey.toString()),
539
506
  amount: BigInt(depositData.inputAmount.toString()),
540
507
  decimals: tokenDecimals,
@@ -555,7 +522,7 @@ describe("svm_spoke.deposit", () => {
555
522
  };
556
523
  const formattedAccounts = {
557
524
  state: (0, kit_1.address)(depositAccounts.state.toString()),
558
- route: (0, kit_1.address)(depositAccounts.route.toString()),
525
+ delegate: (0, kit_1.address)((0, web3_v1_1.getDepositPda)(depositData, program.programId).toString()),
559
526
  depositorTokenAccount: (0, kit_1.address)(depositAccounts.depositorTokenAccount.toString()),
560
527
  mint: (0, kit_1.address)(depositAccounts.mint.toString()),
561
528
  tokenProgram: (0, kit_1.address)(tokenProgram.toString()),
@@ -36,20 +36,21 @@ const utils_1 = require("./utils");
36
36
  const { provider, connection, program, owner, chainId, seedBalance, initializeState, assertSE } = SvmSpoke_common_1.common;
37
37
  describe("svm_spoke.fill.across_plus", () => {
38
38
  anchor.setProvider(provider);
39
- const payer = anchor.AnchorProvider.env().wallet.payer;
39
+ const { payer } = anchor.AnchorProvider.env().wallet;
40
40
  const relayer = web3_js_1.Keypair.generate();
41
41
  const handlerProgram = anchor.workspace.MulticallHandler;
42
- let handlerSigner, handlerATA, finalRecipient, finalRecipientATA, state, mint, relayerATA;
42
+ let handlerSigner, handlerATA, finalRecipient, finalRecipientATA, state, mint, relayerATA, seed;
43
43
  const relayAmount = 500000;
44
44
  const mintDecimals = 6;
45
45
  let relayData; // reused relay data for all tests.
46
46
  let accounts; // Store accounts to simplify contract interactions.
47
- function updateRelayData(newRelayData) {
47
+ const updateRelayData = (newRelayData) => {
48
48
  relayData = newRelayData;
49
49
  const relayHashUint8Array = (0, web3_v1_1.calculateRelayHashUint8Array)(relayData, chainId);
50
50
  const [fillStatusPDA] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("fills"), relayHashUint8Array], program.programId);
51
51
  accounts = {
52
52
  state,
53
+ delegate: (0, web3_v1_1.getFillRelayDelegatePda)(relayHashUint8Array, new anchor_1.BN(1), relayer.publicKey, program.programId).pda,
53
54
  signer: relayer.publicKey,
54
55
  instructionParams: program.programId,
55
56
  mint: mint,
@@ -60,31 +61,30 @@ describe("svm_spoke.fill.across_plus", () => {
60
61
  associatedTokenProgram: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
61
62
  systemProgram: anchor.web3.SystemProgram.programId,
62
63
  };
63
- }
64
- async function createApproveAndFillIx(multicallHandlerCoder, bufferParams = false) {
64
+ };
65
+ const createApproveAndFillIx = async (multicallHandlerCoder, bufferParams = false) => {
66
+ const relayHashUint8Array = (0, web3_v1_1.calculateRelayHashUint8Array)(relayData, chainId);
67
+ const relayHash = Array.from(relayHashUint8Array);
65
68
  // Delegate state PDA to pull relayer tokens.
66
- const approveIx = await (0, spl_token_1.createApproveCheckedInstruction)(accounts.relayerTokenAccount, accounts.mint, accounts.state, accounts.signer, BigInt(relayAmount), mintDecimals);
69
+ const approveIx = await (0, spl_token_1.createApproveCheckedInstruction)(accounts.relayerTokenAccount, accounts.mint, (0, web3_v1_1.getFillRelayDelegatePda)(relayHashUint8Array, new anchor_1.BN(1), relayer.publicKey, program.programId).pda, accounts.signer, BigInt(relayAmount), mintDecimals);
67
70
  const remainingAccounts = [
68
71
  { pubkey: handlerProgram.programId, isSigner: false, isWritable: false },
69
72
  ...multicallHandlerCoder.compiledKeyMetas,
70
73
  ];
71
- const relayHash = Array.from((0, web3_v1_1.calculateRelayHashUint8Array)(relayData, chainId));
72
74
  // Prepare fill instruction.
73
- const fillV3RelayValues = [relayHash, relayData, new anchor_1.BN(1), relayer.publicKey];
75
+ const fillRelayValues = [relayHash, relayData, new anchor_1.BN(1), relayer.publicKey];
74
76
  if (bufferParams) {
75
- await (0, web3_v1_1.loadFillRelayParams)(program, relayer, fillV3RelayValues[1], fillV3RelayValues[2], fillV3RelayValues[3]);
77
+ await (0, web3_v1_1.loadFillRelayParams)(program, relayer, fillRelayValues[1], fillRelayValues[2], fillRelayValues[3]);
76
78
  [accounts.instructionParams] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("instruction_params"), relayer.publicKey.toBuffer()], program.programId);
77
79
  }
78
- const fillV3RelayParams = bufferParams
79
- ? [fillV3RelayValues[0], null, null, null]
80
- : fillV3RelayValues;
80
+ const fillRelayParams = bufferParams ? [fillRelayValues[0], null, null, null] : fillRelayValues;
81
81
  const fillIx = await program.methods
82
- .fillRelay(...fillV3RelayParams)
82
+ .fillRelay(...fillRelayParams)
83
83
  .accounts(accounts)
84
84
  .remainingAccounts(remainingAccounts)
85
85
  .instruction();
86
86
  return { approveIx, fillIx };
87
- }
87
+ };
88
88
  before("Creates token mint and associated token accounts", async () => {
89
89
  mint = await (0, spl_token_1.createMint)(connection, payer, owner, owner, mintDecimals);
90
90
  relayerATA = (await (0, spl_token_1.getOrCreateAssociatedTokenAccount)(connection, payer, mint, relayer.publicKey)).address;
@@ -96,7 +96,7 @@ describe("svm_spoke.fill.across_plus", () => {
96
96
  beforeEach(async () => {
97
97
  finalRecipient = web3_js_1.Keypair.generate().publicKey;
98
98
  finalRecipientATA = (await (0, spl_token_1.getOrCreateAssociatedTokenAccount)(connection, payer, mint, finalRecipient)).address;
99
- ({ state } = await initializeState());
99
+ ({ state, seed } = await initializeState());
100
100
  const initialRelayData = {
101
101
  depositor: finalRecipient,
102
102
  recipient: handlerSigner, // Handler PDA that can forward tokens as needed within the message call.
@@ -279,9 +279,12 @@ describe("svm_spoke.fill.across_plus", () => {
279
279
  programAddress: (0, kit_1.address)(program.programId.toString()),
280
280
  seeds: ["__event_authority"],
281
281
  });
282
- const relayHash = Array.from((0, web3_v1_1.calculateRelayHashUint8Array)(relayData, chainId));
282
+ const relayHashUint8Array = (0, web3_v1_1.calculateRelayHashUint8Array)(relayData, chainId);
283
+ const relayHash = Array.from(relayHashUint8Array);
284
+ const delegate = (0, kit_1.address)((0, web3_v1_1.getFillRelayDelegatePda)(relayHashUint8Array, new anchor_1.BN(1), relayer.publicKey, program.programId).pda.toString());
283
285
  const formattedAccounts = {
284
286
  state: (0, kit_1.address)(accounts.state.toString()),
287
+ delegate,
285
288
  instructionParams: (0, kit_1.address)(program.programId.toString()),
286
289
  mint: (0, kit_1.address)(mint.toString()),
287
290
  relayerTokenAccount: (0, kit_1.address)(relayerATA.toString()),
@@ -316,7 +319,7 @@ describe("svm_spoke.fill.across_plus", () => {
316
319
  const approveIx = (0, token_1.getApproveCheckedInstruction)({
317
320
  source: (0, kit_1.address)(accounts.relayerTokenAccount.toString()),
318
321
  mint: (0, kit_1.address)(accounts.mint.toString()),
319
- delegate: (0, kit_1.address)(accounts.state.toString()),
322
+ delegate,
320
323
  owner: (0, kit_1.address)(accounts.signer.toString()),
321
324
  amount: BigInt(relayData.outputAmount.toString()),
322
325
  decimals: mintDecimals,