@across-protocol/contracts 3.0.18 → 3.0.19

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 (74) hide show
  1. package/README.md +2 -0
  2. package/artifacts/build-info/9cb910e5bb5dd730cd01af84a0fb0466.json +1 -0
  3. package/artifacts/contracts/Ink_SpokePool.sol/Ink_SpokePool.dbg.json +4 -0
  4. package/artifacts/contracts/Ink_SpokePool.sol/Ink_SpokePool.json +2316 -0
  5. package/contracts/Ink_SpokePool.sol +72 -0
  6. package/dist/deploy/consts.js +8 -2
  7. package/dist/deployments/deployments.json +7 -1
  8. package/dist/hardhat.config.js +17 -0
  9. package/dist/scripts/svm/addressToPublicKey.js +2 -2
  10. package/dist/scripts/svm/bridgeLiabilityToHubPool.d.ts +1 -4
  11. package/dist/scripts/svm/bridgeLiabilityToHubPool.js +5 -15
  12. package/dist/scripts/svm/closeRelayerPdas.js +3 -3
  13. package/dist/scripts/svm/executeRebalanceToHubPool.d.ts +1 -4
  14. package/dist/scripts/svm/executeRebalanceToHubPool.js +6 -16
  15. package/dist/scripts/svm/executeRebalanceToSpokePool.js +14 -27
  16. package/dist/scripts/svm/fakeFillWithRandomDistribution.js +6 -7
  17. package/dist/scripts/svm/initialize.js +2 -2
  18. package/dist/scripts/svm/proposeRebalanceToSpokePool.js +11 -15
  19. package/dist/scripts/svm/publicKeyToAddress.js +2 -2
  20. package/dist/scripts/svm/queryDeposits.js +2 -2
  21. package/dist/scripts/svm/queryFills.js +10 -11
  22. package/dist/scripts/svm/remoteHubPoolPauseDeposits.js +10 -24
  23. package/dist/scripts/svm/remoteHubPoolSetDepositRoute.js +16 -29
  24. package/dist/scripts/svm/remotePauseDeposits.js +21 -27
  25. package/dist/scripts/svm/simpleFakeRelayerRepayment.js +3 -3
  26. package/dist/scripts/svm/simpleFill.js +3 -4
  27. package/dist/scripts/svm/utils/helpers.d.ts +3 -1
  28. package/dist/scripts/svm/utils/helpers.js +13 -3
  29. package/dist/src/svm/coders.d.ts +37 -0
  30. package/dist/src/svm/coders.js +250 -0
  31. package/dist/src/svm/conversionUtils.d.ts +22 -0
  32. package/dist/src/svm/conversionUtils.js +73 -0
  33. package/dist/src/svm/index.d.ts +6 -0
  34. package/dist/src/svm/index.js +22 -0
  35. package/dist/src/svm/instructionParamsUtils.d.ts +31 -0
  36. package/dist/src/svm/instructionParamsUtils.js +128 -0
  37. package/dist/src/svm/relayHashUtils.d.ts +30 -0
  38. package/dist/src/svm/relayHashUtils.js +209 -0
  39. package/dist/src/svm/solanaProgramUtils.d.ts +38 -0
  40. package/dist/src/svm/solanaProgramUtils.js +147 -0
  41. package/dist/src/svm/transactionUtils.d.ts +8 -0
  42. package/dist/src/svm/transactionUtils.js +55 -0
  43. package/dist/src/types/svm.d.ts +118 -0
  44. package/dist/src/types/svm.js +2 -0
  45. package/dist/test/svm/MulticallHandler.js +2 -2
  46. package/dist/test/svm/SvmSpoke.Bundle.js +48 -48
  47. package/dist/test/svm/SvmSpoke.Deposit.js +13 -13
  48. package/dist/test/svm/SvmSpoke.Fill.AcrossPlus.js +15 -17
  49. package/dist/test/svm/SvmSpoke.Fill.js +29 -30
  50. package/dist/test/svm/SvmSpoke.HandleReceiveMessage.js +2 -2
  51. package/dist/test/svm/SvmSpoke.Ownership.js +6 -6
  52. package/dist/test/svm/SvmSpoke.RefundClaims.js +5 -5
  53. package/dist/test/svm/SvmSpoke.Routes.js +3 -3
  54. package/dist/test/svm/SvmSpoke.SlowFill.AcrossPlus.js +19 -20
  55. package/dist/test/svm/SvmSpoke.SlowFill.js +18 -18
  56. package/dist/test/svm/SvmSpoke.TokenBridge.js +13 -13
  57. package/dist/test/svm/SvmSpoke.common.d.ts +1 -49
  58. package/dist/test/svm/SvmSpoke.common.js +4 -4
  59. package/dist/test/svm/cctpHelpers.js +2 -2
  60. package/dist/test/svm/utils.d.ts +5 -66
  61. package/dist/test/svm/utils.js +10 -226
  62. package/dist/typechain/contracts/Ink_SpokePool.d.ts +1251 -0
  63. package/dist/typechain/contracts/Ink_SpokePool.js +2 -0
  64. package/dist/typechain/contracts/index.d.ts +1 -0
  65. package/dist/typechain/factories/contracts/Ink_SpokePool__factory.d.ts +1833 -0
  66. package/dist/typechain/factories/contracts/Ink_SpokePool__factory.js +2347 -0
  67. package/dist/typechain/factories/contracts/index.d.ts +1 -0
  68. package/dist/typechain/factories/contracts/index.js +3 -1
  69. package/dist/typechain/hardhat.d.ts +9 -0
  70. package/dist/typechain/index.d.ts +2 -0
  71. package/dist/typechain/index.js +5 -3
  72. package/package.json +2 -2
  73. package/dist/src/SvmUtils.d.ts +0 -72
  74. package/dist/src/SvmUtils.js +0 -496
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.relayerRefundHashFn = exports.readUInt256BE = void 0;
4
+ exports.calculateRelayHashUint8Array = calculateRelayHashUint8Array;
5
+ exports.calculateRelayEventHashUint8Array = calculateRelayEventHashUint8Array;
6
+ exports.hashNonEmptyMessage = hashNonEmptyMessage;
7
+ exports.calculateRelayerRefundLeafHashUint8Array = calculateRelayerRefundLeafHashUint8Array;
8
+ exports.slowFillHashFn = slowFillHashFn;
9
+ const anchor_1 = require("@coral-xyz/anchor");
10
+ const ethers_1 = require("ethers");
11
+ const borsh_1 = require("borsh");
12
+ /**
13
+ * Calculates the relay hash from relay data and chain ID.
14
+ */
15
+ function calculateRelayHashUint8Array(relayData, chainId) {
16
+ const contentToHash = Buffer.concat([
17
+ relayData.depositor.toBuffer(),
18
+ relayData.recipient.toBuffer(),
19
+ relayData.exclusiveRelayer.toBuffer(),
20
+ relayData.inputToken.toBuffer(),
21
+ relayData.outputToken.toBuffer(),
22
+ relayData.inputAmount.toArrayLike(Buffer, "le", 8),
23
+ relayData.outputAmount.toArrayLike(Buffer, "le", 8),
24
+ relayData.originChainId.toArrayLike(Buffer, "le", 8),
25
+ Buffer.from(relayData.depositId),
26
+ new anchor_1.BN(relayData.fillDeadline).toArrayLike(Buffer, "le", 4),
27
+ new anchor_1.BN(relayData.exclusivityDeadline).toArrayLike(Buffer, "le", 4),
28
+ hashNonEmptyMessage(relayData.message), // Replace with hash of message, so that relay hash can be recovered from event.
29
+ chainId.toArrayLike(Buffer, "le", 8),
30
+ ]);
31
+ const relayHash = ethers_1.ethers.utils.keccak256(contentToHash);
32
+ const relayHashBuffer = Buffer.from(relayHash.slice(2), "hex");
33
+ return new Uint8Array(relayHashBuffer);
34
+ }
35
+ /**
36
+ * Calculates the relay event hash from relay event data and chain ID.
37
+ */
38
+ function calculateRelayEventHashUint8Array(relayEventData, chainId) {
39
+ const contentToHash = Buffer.concat([
40
+ relayEventData.depositor.toBuffer(),
41
+ relayEventData.recipient.toBuffer(),
42
+ relayEventData.exclusiveRelayer.toBuffer(),
43
+ relayEventData.inputToken.toBuffer(),
44
+ relayEventData.outputToken.toBuffer(),
45
+ relayEventData.inputAmount.toArrayLike(Buffer, "le", 8),
46
+ relayEventData.outputAmount.toArrayLike(Buffer, "le", 8),
47
+ relayEventData.originChainId.toArrayLike(Buffer, "le", 8),
48
+ Buffer.from(relayEventData.depositId),
49
+ new anchor_1.BN(relayEventData.fillDeadline).toArrayLike(Buffer, "le", 4),
50
+ new anchor_1.BN(relayEventData.exclusivityDeadline).toArrayLike(Buffer, "le", 4),
51
+ Buffer.from(relayEventData.messageHash), // Renamed to messageHash in the event data.
52
+ chainId.toArrayLike(Buffer, "le", 8),
53
+ ]);
54
+ const relayHash = ethers_1.ethers.utils.keccak256(contentToHash);
55
+ const relayHashBuffer = Buffer.from(relayHash.slice(2), "hex");
56
+ return new Uint8Array(relayHashBuffer);
57
+ }
58
+ /**
59
+ * Reads a 256-bit unsigned integer from a buffer.
60
+ */
61
+ const readUInt256BE = (buffer) => {
62
+ let result = BigInt(0);
63
+ for (let i = 0; i < buffer.length; i++) {
64
+ result = (result << BigInt(8)) + BigInt(buffer[i]);
65
+ }
66
+ return result;
67
+ };
68
+ exports.readUInt256BE = readUInt256BE;
69
+ /**
70
+ * Hashes a non-empty message using Keccak256.
71
+ */
72
+ function hashNonEmptyMessage(message) {
73
+ if (message.length > 0) {
74
+ const hash = ethers_1.ethers.utils.keccak256(message);
75
+ return Uint8Array.from(Buffer.from(hash.slice(2), "hex"));
76
+ }
77
+ // else return zeroed bytes32
78
+ return new Uint8Array(32);
79
+ }
80
+ /**
81
+ * Class for relay data.
82
+ */
83
+ class RelayData {
84
+ constructor(properties) {
85
+ Object.assign(this, properties);
86
+ }
87
+ }
88
+ /**
89
+ * Schema for relay data.
90
+ */
91
+ const relayDataSchema = new Map([
92
+ [
93
+ RelayData,
94
+ {
95
+ kind: "struct",
96
+ fields: [
97
+ ["amountToReturn", "u64"],
98
+ ["chainId", "u64"],
99
+ ["refundAmounts", ["u64"]],
100
+ ["leafId", "u32"],
101
+ ["mintPublicKey", [32]],
102
+ ["refundAddresses", [[32]]],
103
+ ],
104
+ },
105
+ ],
106
+ ]);
107
+ /**
108
+ * Calculates the relayer refund leaf hash for Solana.
109
+ */
110
+ function calculateRelayerRefundLeafHashUint8Array(relayData) {
111
+ const refundAddresses = relayData.refundAddresses.map((address) => address.toBuffer());
112
+ const data = new RelayData({
113
+ amountToReturn: relayData.amountToReturn,
114
+ chainId: relayData.chainId,
115
+ refundAmounts: relayData.refundAmounts,
116
+ leafId: relayData.leafId,
117
+ mintPublicKey: relayData.mintPublicKey.toBuffer(),
118
+ refundAddresses: refundAddresses,
119
+ });
120
+ const serializedData = (0, borsh_1.serialize)(relayDataSchema, data);
121
+ // SVM leaves require the first 64 bytes to be 0 to ensure EVM leaves can never be played on SVM and vice versa.
122
+ const contentToHash = Buffer.concat([Buffer.alloc(64, 0), serializedData]);
123
+ return ethers_1.ethers.utils.keccak256(contentToHash);
124
+ }
125
+ /**
126
+ * Hash function for relayer refund leaves.
127
+ */
128
+ const relayerRefundHashFn = (input) => {
129
+ if (!input.isSolana) {
130
+ const abiCoder = new ethers_1.ethers.utils.AbiCoder();
131
+ const encodedData = abiCoder.encode([
132
+ "tuple( uint256 amountToReturn, uint256 chainId, uint256[] refundAmounts, uint256 leafId, address l2TokenAddress, address[] refundAddresses)",
133
+ ], [
134
+ {
135
+ leafId: input.leafId,
136
+ chainId: input.chainId,
137
+ amountToReturn: input.amountToReturn,
138
+ l2TokenAddress: input.l2TokenAddress, // Type assertion
139
+ refundAddresses: input.refundAddresses, // Type assertion
140
+ refundAmounts: input.refundAmounts, // Type assertion
141
+ },
142
+ ]);
143
+ return ethers_1.ethers.utils.keccak256(encodedData);
144
+ }
145
+ else {
146
+ return calculateRelayerRefundLeafHashUint8Array(input);
147
+ }
148
+ };
149
+ exports.relayerRefundHashFn = relayerRefundHashFn;
150
+ /**
151
+ * Class for slow fill data.
152
+ */
153
+ class SlowFillData {
154
+ constructor(properties) {
155
+ Object.assign(this, properties);
156
+ }
157
+ }
158
+ /**
159
+ * Schema for slow fill data.
160
+ */
161
+ const slowFillDataSchema = new Map([
162
+ [
163
+ SlowFillData,
164
+ {
165
+ kind: "struct",
166
+ fields: [
167
+ ["depositor", [32]],
168
+ ["recipient", [32]],
169
+ ["exclusiveRelayer", [32]],
170
+ ["inputToken", [32]],
171
+ ["outputToken", [32]],
172
+ ["inputAmount", "u64"],
173
+ ["outputAmount", "u64"],
174
+ ["originChainId", "u64"],
175
+ ["depositId", [32]],
176
+ ["fillDeadline", "u32"],
177
+ ["exclusivityDeadline", "u32"],
178
+ ["message", ["u8"]],
179
+ ["chainId", "u64"],
180
+ ["updatedOutputAmount", "u64"],
181
+ ],
182
+ },
183
+ ],
184
+ ]);
185
+ /**
186
+ * Hash function for slow fill leaves.
187
+ */
188
+ function slowFillHashFn(slowFillLeaf) {
189
+ const data = new SlowFillData({
190
+ depositor: Uint8Array.from(slowFillLeaf.relayData.depositor.toBuffer()),
191
+ recipient: Uint8Array.from(slowFillLeaf.relayData.recipient.toBuffer()),
192
+ exclusiveRelayer: Uint8Array.from(slowFillLeaf.relayData.exclusiveRelayer.toBuffer()),
193
+ inputToken: Uint8Array.from(slowFillLeaf.relayData.inputToken.toBuffer()),
194
+ outputToken: Uint8Array.from(slowFillLeaf.relayData.outputToken.toBuffer()),
195
+ inputAmount: slowFillLeaf.relayData.inputAmount,
196
+ outputAmount: slowFillLeaf.relayData.outputAmount,
197
+ originChainId: slowFillLeaf.relayData.originChainId,
198
+ depositId: Uint8Array.from(Buffer.from(slowFillLeaf.relayData.depositId)),
199
+ fillDeadline: slowFillLeaf.relayData.fillDeadline,
200
+ exclusivityDeadline: slowFillLeaf.relayData.exclusivityDeadline,
201
+ message: Uint8Array.from(slowFillLeaf.relayData.message),
202
+ chainId: slowFillLeaf.chainId,
203
+ updatedOutputAmount: slowFillLeaf.updatedOutputAmount,
204
+ });
205
+ const serializedData = (0, borsh_1.serialize)(slowFillDataSchema, data);
206
+ // SVM leaves require the first 64 bytes to be 0 to ensure EVM leaves cannot be played on SVM and vice versa
207
+ const contentToHash = Buffer.concat([Buffer.alloc(64, 0), serializedData]);
208
+ return ethers_1.ethers.utils.keccak256(contentToHash);
209
+ }
@@ -0,0 +1,38 @@
1
+ import { Idl, Program, web3 } from "@coral-xyz/anchor";
2
+ import { Connection, Finality, PublicKey, SignaturesForAddressOptions } from "@solana/web3.js";
3
+ import { EventType } from "../types/svm";
4
+ /**
5
+ * Finds a program address with a given label and optional extra seeds.
6
+ */
7
+ export declare function findProgramAddress(label: string, program: PublicKey, extraSeeds?: string[]): {
8
+ publicKey: web3.PublicKey;
9
+ bump: number;
10
+ };
11
+ /**
12
+ * Reads events from a transaction.
13
+ */
14
+ export declare function readEvents<IDL extends Idl = Idl>(connection: Connection, txSignature: string, programs: Program<IDL>[], commitment?: Finality): Promise<{
15
+ program: web3.PublicKey;
16
+ data: any;
17
+ name: string | undefined;
18
+ }[]>;
19
+ /**
20
+ * Helper function to wait for an event to be emitted. Should only be used in tests where txSignature is known to emit.
21
+ */
22
+ export declare function readEventsUntilFound<IDL extends Idl = Idl>(connection: Connection, txSignature: string, programs: Program<IDL>[]): Promise<{
23
+ program: web3.PublicKey;
24
+ data: any;
25
+ name: string | undefined;
26
+ }[]>;
27
+ /**
28
+ * Retrieves a specific event by name from a list of events.
29
+ */
30
+ export declare function getEvent(events: any[], program: PublicKey, eventName: string): any;
31
+ /**
32
+ * Reads all events for a specific program.
33
+ */
34
+ export declare function readProgramEvents(connection: Connection, program: Program<any>, finality?: Finality, options?: SignaturesForAddressOptions): Promise<EventType[]>;
35
+ /**
36
+ * Subscribes to CPI events for a program.
37
+ */
38
+ export declare function subscribeToCpiEventsForProgram(connection: Connection, program: Program<any>, callback: (events: any[]) => void): Promise<number>;
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findProgramAddress = findProgramAddress;
4
+ exports.readEvents = readEvents;
5
+ exports.readEventsUntilFound = readEventsUntilFound;
6
+ exports.getEvent = getEvent;
7
+ exports.readProgramEvents = readProgramEvents;
8
+ exports.subscribeToCpiEventsForProgram = subscribeToCpiEventsForProgram;
9
+ const anchor_1 = require("@coral-xyz/anchor");
10
+ const web3_js_1 = require("@solana/web3.js");
11
+ /**
12
+ * Finds a program address with a given label and optional extra seeds.
13
+ */
14
+ function findProgramAddress(label, program, extraSeeds) {
15
+ const seeds = [Buffer.from(anchor_1.utils.bytes.utf8.encode(label))];
16
+ if (extraSeeds) {
17
+ for (const extraSeed of extraSeeds) {
18
+ if (typeof extraSeed === "string") {
19
+ seeds.push(Buffer.from(anchor_1.utils.bytes.utf8.encode(extraSeed)));
20
+ }
21
+ else if (Array.isArray(extraSeed)) {
22
+ seeds.push(Buffer.from(extraSeed));
23
+ }
24
+ else if (Buffer.isBuffer(extraSeed)) {
25
+ seeds.push(extraSeed);
26
+ }
27
+ else {
28
+ seeds.push(extraSeed.toBuffer());
29
+ }
30
+ }
31
+ }
32
+ const res = web3_js_1.PublicKey.findProgramAddressSync(seeds, program);
33
+ return { publicKey: res[0], bump: res[1] };
34
+ }
35
+ /**
36
+ * Reads events from a transaction.
37
+ */
38
+ async function readEvents(connection, txSignature, programs, commitment = "confirmed") {
39
+ const txResult = await connection.getTransaction(txSignature, { commitment, maxSupportedTransactionVersion: 0 });
40
+ if (txResult === null)
41
+ return [];
42
+ return processEventFromTx(txResult, programs);
43
+ }
44
+ /**
45
+ * Processes events from a transaction.
46
+ */
47
+ function processEventFromTx(txResult, programs) {
48
+ const eventAuthorities = new Map();
49
+ for (const program of programs) {
50
+ eventAuthorities.set(program.programId.toString(), findProgramAddress("__event_authority", program.programId).publicKey);
51
+ }
52
+ const events = [];
53
+ // Resolve any potential addresses that were passed from address lookup tables.
54
+ const messageAccountKeys = txResult.transaction.message.getAccountKeys({
55
+ accountKeysFromLookups: txResult.meta?.loadedAddresses,
56
+ });
57
+ for (const ixBlock of txResult.meta?.innerInstructions ?? []) {
58
+ for (const ix of ixBlock.instructions) {
59
+ for (const program of programs) {
60
+ const ixProgramId = messageAccountKeys.get(ix.programIdIndex);
61
+ const singleIxAccount = ix.accounts.length === 1 ? messageAccountKeys.get(ix.accounts[0]) : undefined;
62
+ if (ixProgramId !== undefined &&
63
+ singleIxAccount !== undefined &&
64
+ program.programId.equals(ixProgramId) &&
65
+ eventAuthorities.get(ixProgramId.toString())?.equals(singleIxAccount)) {
66
+ const ixData = anchor_1.utils.bytes.bs58.decode(ix.data);
67
+ const eventData = anchor_1.utils.bytes.base64.encode(Buffer.from(new Uint8Array(ixData).slice(8)));
68
+ const event = program.coder.events.decode(eventData);
69
+ events.push({
70
+ program: program.programId,
71
+ data: event?.data,
72
+ name: event?.name,
73
+ });
74
+ }
75
+ }
76
+ }
77
+ }
78
+ return events;
79
+ }
80
+ /**
81
+ * Helper function to wait for an event to be emitted. Should only be used in tests where txSignature is known to emit.
82
+ */
83
+ async function readEventsUntilFound(connection, txSignature, programs) {
84
+ const startTime = Date.now();
85
+ let txResult = null;
86
+ while (Date.now() - startTime < 5000) {
87
+ // 5 seconds timeout to wait to find the event.
88
+ txResult = await connection.getTransaction(txSignature, {
89
+ commitment: "confirmed",
90
+ maxSupportedTransactionVersion: 0,
91
+ });
92
+ if (txResult !== null)
93
+ return processEventFromTx(txResult, programs);
94
+ await new Promise((resolve) => setTimeout(resolve, 50)); // 50 ms delay between retries.
95
+ }
96
+ throw new Error("No event found within 5 seconds");
97
+ }
98
+ /**
99
+ * Retrieves a specific event by name from a list of events.
100
+ */
101
+ function getEvent(events, program, eventName) {
102
+ for (const event of events) {
103
+ if (event.name === eventName && program.toString() === event.program.toString()) {
104
+ return event.data;
105
+ }
106
+ }
107
+ throw new Error("Event " + eventName + " not found");
108
+ }
109
+ /**
110
+ * Reads all events for a specific program.
111
+ */
112
+ async function readProgramEvents(connection, program, finality = "confirmed", options = { limit: 1000 }) {
113
+ const allSignatures = [];
114
+ // Fetch all signatures in sequential batches
115
+ while (true) {
116
+ const signatures = await connection.getSignaturesForAddress(program.programId, options, finality);
117
+ allSignatures.push(...signatures);
118
+ // Update options for the next batch. Set before to the last fetched signature.
119
+ if (signatures.length > 0) {
120
+ options = { ...options, before: signatures[signatures.length - 1].signature };
121
+ }
122
+ if (options.limit && signatures.length < options.limit)
123
+ break; // Exit early if the number of signatures < limit
124
+ }
125
+ // Fetch events for all signatures in parallel
126
+ const eventsWithSlots = await Promise.all(allSignatures.map(async (signature) => {
127
+ const events = await readEvents(connection, signature.signature, [program], finality);
128
+ return events.map((event) => ({
129
+ ...event,
130
+ confirmationStatus: signature.confirmationStatus || "Unknown",
131
+ blockTime: signature.blockTime || 0,
132
+ signature: signature.signature,
133
+ slot: signature.slot,
134
+ name: event.name || "Unknown",
135
+ }));
136
+ }));
137
+ return eventsWithSlots.flat(); // Flatten the array of events & return.
138
+ }
139
+ /**
140
+ * Subscribes to CPI events for a program.
141
+ */
142
+ async function subscribeToCpiEventsForProgram(connection, program, callback) {
143
+ const subscriptionId = connection.onLogs(new web3_js_1.PublicKey(findProgramAddress("__event_authority", program.programId).publicKey.toString()), async (logs) => {
144
+ callback(await readEvents(connection, logs.signature, [program], "confirmed"));
145
+ }, "confirmed");
146
+ return subscriptionId;
147
+ }
@@ -0,0 +1,8 @@
1
+ import { Connection, Keypair, PublicKey, TransactionInstruction } from "@solana/web3.js";
2
+ /**
3
+ * Sends a transaction using an Address Lookup Table for large numbers of accounts.
4
+ */
5
+ export declare function sendTransactionWithLookupTable(connection: Connection, instructions: TransactionInstruction[], sender: Keypair): Promise<{
6
+ txSignature: string;
7
+ lookupTableAddress: PublicKey;
8
+ }>;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendTransactionWithLookupTable = sendTransactionWithLookupTable;
4
+ const anchor_1 = require("@coral-xyz/anchor");
5
+ const web3_js_1 = require("@solana/web3.js");
6
+ /**
7
+ * Sends a transaction using an Address Lookup Table for large numbers of accounts.
8
+ */
9
+ async function sendTransactionWithLookupTable(connection, instructions, sender) {
10
+ // Maximum number of accounts that can be added to Address Lookup Table (ALT) in a single transaction.
11
+ const maxExtendedAccounts = 30;
12
+ // Consolidate addresses from all instructions into a single array for the ALT.
13
+ const lookupAddresses = Array.from(new Set(instructions.flatMap((instruction) => [
14
+ instruction.programId,
15
+ ...instruction.keys.map((accountMeta) => accountMeta.pubkey),
16
+ ])));
17
+ // Create instructions for creating and extending the ALT.
18
+ const [lookupTableInstruction, lookupTableAddress] = await web3_js_1.AddressLookupTableProgram.createLookupTable({
19
+ authority: sender.publicKey,
20
+ payer: sender.publicKey,
21
+ recentSlot: await connection.getSlot(),
22
+ });
23
+ // Submit the ALT creation transaction
24
+ await anchor_1.web3.sendAndConfirmTransaction(connection, new anchor_1.web3.Transaction().add(lookupTableInstruction), [sender], {
25
+ skipPreflight: true, // Avoids recent slot mismatch in simulation.
26
+ });
27
+ // Extend the ALT with all accounts making sure not to exceed the maximum number of accounts per transaction.
28
+ for (let i = 0; i < lookupAddresses.length; i += maxExtendedAccounts) {
29
+ const extendInstruction = web3_js_1.AddressLookupTableProgram.extendLookupTable({
30
+ lookupTable: lookupTableAddress,
31
+ authority: sender.publicKey,
32
+ payer: sender.publicKey,
33
+ addresses: lookupAddresses.slice(i, i + maxExtendedAccounts),
34
+ });
35
+ await anchor_1.web3.sendAndConfirmTransaction(connection, new anchor_1.web3.Transaction().add(extendInstruction), [sender], {
36
+ skipPreflight: true, // Avoids recent slot mismatch in simulation.
37
+ });
38
+ }
39
+ // Avoids invalid ALT index as ALT might not be active yet on the following tx.
40
+ await new Promise((resolve) => setTimeout(resolve, 1000));
41
+ // Fetch the AddressLookupTableAccount
42
+ const lookupTableAccount = (await connection.getAddressLookupTable(lookupTableAddress)).value;
43
+ if (lookupTableAccount === null)
44
+ throw new Error("AddressLookupTableAccount not fetched");
45
+ // Create the versioned transaction
46
+ const versionedTx = new web3_js_1.VersionedTransaction(new web3_js_1.TransactionMessage({
47
+ payerKey: sender.publicKey,
48
+ recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
49
+ instructions,
50
+ }).compileToV0Message([lookupTableAccount]));
51
+ // Sign and submit the versioned transaction.
52
+ versionedTx.sign([sender]);
53
+ const txSignature = await connection.sendTransaction(versionedTx);
54
+ return { txSignature, lookupTableAddress };
55
+ }
@@ -0,0 +1,118 @@
1
+ import { BN } from "@coral-xyz/anchor";
2
+ import { PublicKey } from "@solana/web3.js";
3
+ import { BigNumber } from "ethers";
4
+ /**
5
+ * Relayer Refund Interfaces
6
+ */
7
+ export interface RelayerRefundLeaf {
8
+ isSolana: boolean;
9
+ amountToReturn: BigNumber;
10
+ chainId: BigNumber;
11
+ refundAmounts: BigNumber[];
12
+ leafId: BigNumber;
13
+ l2TokenAddress: string;
14
+ refundAddresses: string[];
15
+ }
16
+ export interface RelayerRefundLeafSolana {
17
+ isSolana: boolean;
18
+ amountToReturn: BN;
19
+ chainId: BN;
20
+ refundAmounts: BN[];
21
+ leafId: BN;
22
+ mintPublicKey: PublicKey;
23
+ refundAddresses: PublicKey[];
24
+ }
25
+ export type RelayerRefundLeafType = RelayerRefundLeaf | RelayerRefundLeafSolana;
26
+ /**
27
+ * Slow Fill Leaf Interface
28
+ */
29
+ export interface SlowFillLeaf {
30
+ relayData: RelayData;
31
+ chainId: BN;
32
+ updatedOutputAmount: BN;
33
+ }
34
+ /**
35
+ * Relay Data Interface
36
+ */
37
+ export type RelayData = {
38
+ depositor: PublicKey;
39
+ recipient: PublicKey;
40
+ exclusiveRelayer: PublicKey;
41
+ inputToken: PublicKey;
42
+ outputToken: PublicKey;
43
+ inputAmount: BN;
44
+ outputAmount: BN;
45
+ originChainId: BN;
46
+ depositId: number[];
47
+ fillDeadline: number;
48
+ exclusivityDeadline: number;
49
+ message: Buffer;
50
+ };
51
+ /**
52
+ * Deposit Data Interfaces
53
+ */
54
+ export interface DepositData {
55
+ depositor: PublicKey | null;
56
+ recipient: PublicKey;
57
+ inputToken: PublicKey | null;
58
+ outputToken: PublicKey;
59
+ inputAmount: BN;
60
+ outputAmount: BN;
61
+ destinationChainId: BN;
62
+ exclusiveRelayer: PublicKey;
63
+ quoteTimestamp: BN;
64
+ fillDeadline: BN;
65
+ exclusivityParameter: BN;
66
+ message: Buffer;
67
+ }
68
+ export type DepositDataValues = [
69
+ PublicKey,
70
+ PublicKey,
71
+ PublicKey,
72
+ PublicKey,
73
+ BN,
74
+ BN,
75
+ BN,
76
+ PublicKey,
77
+ number,
78
+ number,
79
+ number,
80
+ Buffer
81
+ ];
82
+ /**
83
+ * Fill Data Interfaces
84
+ */
85
+ export type FillDataValues = [number[], RelayData, BN, PublicKey];
86
+ export type FillDataParams = [number[], RelayData | null, BN | null, PublicKey | null];
87
+ /**
88
+ * Request V3 Slow Fill Data Interfaces
89
+ */
90
+ export type RequestV3SlowFillDataValues = [number[], RelayData];
91
+ export type RequestV3SlowFillDataParams = [number[], RelayData | null];
92
+ /**
93
+ * Execute V3 Slow Relay Leaf Data Interfaces
94
+ */
95
+ export type ExecuteV3SlowRelayLeafDataValues = [number[], SlowFillLeaf, number, number[][]];
96
+ export type ExecuteV3SlowRelayLeafDataParams = [number[], SlowFillLeaf | null, number | null, number[][] | null];
97
+ /**
98
+ * Across+ Message Interface
99
+ */
100
+ export type AcrossPlusMessage = {
101
+ handler: PublicKey;
102
+ readOnlyLen: number;
103
+ valueAmount: BN;
104
+ accounts: PublicKey[];
105
+ handlerMessage: Buffer;
106
+ };
107
+ /**
108
+ * Event Type Interface
109
+ */
110
+ export interface EventType {
111
+ program: PublicKey;
112
+ data: any;
113
+ name: string;
114
+ slot: number;
115
+ confirmationStatus: string;
116
+ blockTime: number;
117
+ signature: string;
118
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -27,7 +27,7 @@ const anchor = __importStar(require("@coral-xyz/anchor"));
27
27
  const anchor_1 = require("@coral-xyz/anchor");
28
28
  const web3_js_1 = require("@solana/web3.js");
29
29
  const spl_token_1 = require("@solana/spl-token");
30
- const SvmUtils_1 = require("../../src/SvmUtils");
30
+ const svm_1 = require("../../src/svm");
31
31
  const SvmSpoke_common_1 = require("./SvmSpoke.common");
32
32
  const { provider, owner, connection, assertSE } = SvmSpoke_common_1.common;
33
33
  describe("multicall_handler", () => {
@@ -47,7 +47,7 @@ describe("multicall_handler", () => {
47
47
  const recipient = web3_js_1.Keypair.generate().publicKey;
48
48
  const recipientATA = (await (0, spl_token_1.getOrCreateAssociatedTokenAccount)(connection, payer, mint, recipient)).address;
49
49
  const transferIx = (0, spl_token_1.createTransferCheckedInstruction)(handlerATA, mint, recipientATA, handlerSigner, tokenAmount, mintDecimals);
50
- const multicallHandlerCoder = new SvmUtils_1.MulticallHandlerCoder([transferIx]);
50
+ const multicallHandlerCoder = new svm_1.MulticallHandlerCoder([transferIx]);
51
51
  const handlerMessage = multicallHandlerCoder.encode();
52
52
  await program.methods
53
53
  .handleV3AcrossMessage(handlerMessage)