@across-protocol/sdk 4.3.33 → 4.3.34-alpha.1

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 (37) hide show
  1. package/dist/cjs/arch/svm/SpokeUtils.d.ts +21 -10
  2. package/dist/cjs/arch/svm/SpokeUtils.js +134 -27
  3. package/dist/cjs/arch/svm/SpokeUtils.js.map +1 -1
  4. package/dist/cjs/arch/svm/encoders.d.ts +19 -0
  5. package/dist/cjs/arch/svm/encoders.js +52 -0
  6. package/dist/cjs/arch/svm/encoders.js.map +1 -0
  7. package/dist/cjs/arch/svm/index.d.ts +1 -0
  8. package/dist/cjs/arch/svm/index.js +1 -0
  9. package/dist/cjs/arch/svm/index.js.map +1 -1
  10. package/dist/cjs/arch/svm/utils.d.ts +2 -0
  11. package/dist/cjs/arch/svm/utils.js +18 -1
  12. package/dist/cjs/arch/svm/utils.js.map +1 -1
  13. package/dist/esm/arch/svm/SpokeUtils.d.ts +38 -10
  14. package/dist/esm/arch/svm/SpokeUtils.js +160 -28
  15. package/dist/esm/arch/svm/SpokeUtils.js.map +1 -1
  16. package/dist/esm/arch/svm/encoders.d.ts +19 -0
  17. package/dist/esm/arch/svm/encoders.js +43 -0
  18. package/dist/esm/arch/svm/encoders.js.map +1 -0
  19. package/dist/esm/arch/svm/index.d.ts +1 -0
  20. package/dist/esm/arch/svm/index.js +1 -0
  21. package/dist/esm/arch/svm/index.js.map +1 -1
  22. package/dist/esm/arch/svm/utils.d.ts +8 -0
  23. package/dist/esm/arch/svm/utils.js +22 -0
  24. package/dist/esm/arch/svm/utils.js.map +1 -1
  25. package/dist/types/arch/svm/SpokeUtils.d.ts +38 -10
  26. package/dist/types/arch/svm/SpokeUtils.d.ts.map +1 -1
  27. package/dist/types/arch/svm/encoders.d.ts +20 -0
  28. package/dist/types/arch/svm/encoders.d.ts.map +1 -0
  29. package/dist/types/arch/svm/index.d.ts +1 -0
  30. package/dist/types/arch/svm/index.d.ts.map +1 -1
  31. package/dist/types/arch/svm/utils.d.ts +8 -0
  32. package/dist/types/arch/svm/utils.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/src/arch/svm/SpokeUtils.ts +193 -22
  35. package/src/arch/svm/encoders.ts +86 -0
  36. package/src/arch/svm/index.ts +1 -0
  37. package/src/arch/svm/utils.ts +23 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@across-protocol/sdk",
3
3
  "author": "UMA Team",
4
- "version": "4.3.33",
4
+ "version": "4.3.34-alpha.1",
5
5
  "license": "AGPL-3.0",
6
6
  "homepage": "https://docs.across.to/reference/sdk",
7
7
  "files": [
@@ -17,6 +17,7 @@ import {
17
17
  Address,
18
18
  FetchAccountConfig,
19
19
  IAccountMeta,
20
+ IInstruction,
20
21
  KeyPairSigner,
21
22
  ReadonlyUint8Array,
22
23
  appendTransactionMessageInstruction,
@@ -32,9 +33,11 @@ import {
32
33
  signTransactionMessageWithSigners,
33
34
  some,
34
35
  type TransactionSigner,
36
+ type WritableAccount,
37
+ type ReadonlyAccount,
35
38
  } from "@solana/kit";
36
39
  import assert from "assert";
37
- import { arrayify, hexZeroPad, hexlify } from "ethers/lib/utils";
40
+ import { arrayify } from "ethers/lib/utils";
38
41
  import { Logger } from "winston";
39
42
  import { CHAIN_IDs, TOKEN_SYMBOLS_MAP } from "../../constants";
40
43
  import { DepositWithBlock, FillStatus, FillWithBlock, RelayData, RelayExecutionEventInfo } from "../../interfaces";
@@ -66,6 +69,11 @@ import {
66
69
  toAddress,
67
70
  unwrapEventData,
68
71
  getRootBundlePda,
72
+ getAcrossPlusMessageDecoder,
73
+ getAccountMeta,
74
+ toSvmRelayData,
75
+ getInstructionParamsPda,
76
+ type AcrossPlusMessage,
69
77
  } from "./";
70
78
  import { SvmCpiEventsClient } from "./eventsClient";
71
79
  import { SVM_BLOCK_NOT_AVAILABLE, SVM_SLOT_SKIPPED, isSolanaError } from "./provider";
@@ -601,6 +609,7 @@ export async function getFillRelayTx(
601
609
  getEventAuthority(program),
602
610
  ]);
603
611
 
612
+ const message = new Uint8Array(Buffer.from(relayData.message.slice(2), "hex"));
604
613
  const svmRelayData: SvmSpokeClient.FillRelayInput["relayData"] = {
605
614
  depositor: toAddress(depositor),
606
615
  recipient: toAddress(recipient),
@@ -613,9 +622,24 @@ export async function getFillRelayTx(
613
622
  depositId: new Uint8Array(intToU8Array32(relayData.depositId.toNumber())),
614
623
  fillDeadline: relayData.fillDeadline,
615
624
  exclusivityDeadline: relayData.exclusivityDeadline,
616
- message: new Uint8Array(Buffer.from(relayData.message, "hex")),
625
+ message,
617
626
  };
618
627
 
628
+ // Add remaining accounts if the relayData has a non-empty message.
629
+ // @dev ! since in the context of creating a `fillRelayTx`, `relayData` must be defined.
630
+ const remainingAccounts: (WritableAccount | ReadonlyAccount)[] = [];
631
+ if (relayData.message !== "0x") {
632
+ const acrossPlusMessage = deserializeMessage(relayData.message);
633
+ // The first `remainingAccount` _must_ be the handler address.
634
+ // https://github.com/across-protocol/contracts/blob/3310f8dc716407a5f97ef5fd2eae63df83251f2f/programs/svm-spoke/src/utils/message_utils.rs#L36.
635
+ remainingAccounts.push(getAccountMeta(acrossPlusMessage.handler, true));
636
+ remainingAccounts.push(
637
+ ...acrossPlusMessage.accounts.map((account, idx) =>
638
+ getAccountMeta(account, idx < acrossPlusMessage.accounts.length - acrossPlusMessage.read_only_len)
639
+ )
640
+ );
641
+ }
642
+
619
643
  const fillInput: SvmSpokeClient.FillRelayInput = {
620
644
  signer: signer,
621
645
  state,
@@ -636,7 +660,105 @@ export async function getFillRelayTx(
636
660
  };
637
661
  // Pass createRecipientAtaIfNeeded =true to the createFillInstruction function to create the recipient token account
638
662
  // if it doesn't exist.
639
- return createFillInstruction(signer, solanaClient, fillInput, mintInfo.data.decimals, true);
663
+ return createFillInstruction(
664
+ signer,
665
+ solanaClient,
666
+ fillInput,
667
+ svmRelayData,
668
+ mintInfo.data.decimals,
669
+ true,
670
+ remainingAccounts
671
+ );
672
+ }
673
+
674
+ /**
675
+ * Creates a fill instruction with an instruction params PDA as the relayData input.
676
+ * @param spokePoolAddr Address of the spoke pool we're trying to fill through
677
+ * @param solanaClient RPC client to interact with Solana chain
678
+ * @param relayData RelayData instance, supplemented with destinationChainId
679
+ * @param signer signer associated with the relayer creating a Fill. Can be VoidSigner for gas estimation
680
+ * @param repaymentChainId Chain id where relayer repayment is desired
681
+ * @param repaymentAddress Address to which repayment will go to on repaymentChainId
682
+ * @returns FillRelay transaction
683
+ */
684
+ export async function getIPFillRelayTx(
685
+ spokePoolAddr: SvmAddress,
686
+ solanaClient: SVMProvider,
687
+ relayData: Omit<RelayData, "recipient" | "outputToken"> & {
688
+ destinationChainId: number;
689
+ recipient: SvmAddress;
690
+ outputToken: SvmAddress;
691
+ },
692
+ signer: TransactionSigner,
693
+ repaymentChainId: number,
694
+ repaymentAddress: SdkAddress
695
+ ) {
696
+ const program = toAddress(spokePoolAddr);
697
+ const _relayDataHash = getRelayDataHash(relayData, relayData.destinationChainId);
698
+ const relayDataHash = new Uint8Array(Buffer.from(_relayDataHash.slice(2), "hex"));
699
+
700
+ const [state, delegate, instructionParams] = await Promise.all([
701
+ getStatePda(program),
702
+ getFillRelayDelegatePda(relayDataHash, BigInt(repaymentChainId), toAddress(repaymentAddress), program),
703
+ getInstructionParamsPda(program, signer.address),
704
+ ]);
705
+
706
+ const mint = toAddress(relayData.outputToken);
707
+ const mintInfo = await getMintInfo(solanaClient, mint);
708
+
709
+ const [recipientAta, relayerAta, fillStatus, eventAuthority] = await Promise.all([
710
+ getAssociatedTokenAddress(relayData.recipient, relayData.outputToken, mintInfo.programAddress),
711
+ getAssociatedTokenAddress(SvmAddress.from(signer.address), relayData.outputToken, mintInfo.programAddress),
712
+ getFillStatusPda(program, relayData, relayData.destinationChainId),
713
+ getEventAuthority(program),
714
+ ]);
715
+
716
+ // Add remaining accounts if the relayData has a non-empty message.
717
+ // @dev ! since in the context of creating a `fillRelayTx`, `relayData` must be defined.
718
+ const remainingAccounts: (WritableAccount | ReadonlyAccount)[] = [];
719
+ if (relayData.message !== "0x") {
720
+ const acrossPlusMessage = deserializeMessage(relayData.message);
721
+ // The first `remainingAccount` _must_ be the handler address.
722
+ // https://github.com/across-protocol/contracts/blob/3310f8dc716407a5f97ef5fd2eae63df83251f2f/programs/svm-spoke/src/utils/message_utils.rs#L36.
723
+ remainingAccounts.push(getAccountMeta(acrossPlusMessage.handler, true));
724
+ remainingAccounts.push(
725
+ ...acrossPlusMessage.accounts.map((account, idx) =>
726
+ getAccountMeta(account, idx < acrossPlusMessage.accounts.length - acrossPlusMessage.read_only_len)
727
+ )
728
+ );
729
+ }
730
+
731
+ const fillInput: SvmSpokeClient.FillRelayInput = {
732
+ signer: signer,
733
+ state,
734
+ delegate,
735
+ mint,
736
+ relayerTokenAccount: relayerAta,
737
+ recipientTokenAccount: recipientAta,
738
+ fillStatus,
739
+ tokenProgram: mintInfo.programAddress,
740
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
741
+ systemProgram: SYSTEM_PROGRAM_ADDRESS,
742
+ eventAuthority,
743
+ program,
744
+ instructionParams,
745
+ relayHash: relayDataHash,
746
+ relayData: null,
747
+ repaymentChainId: null,
748
+ repaymentAddress: null,
749
+ };
750
+
751
+ // Pass createRecipientAtaIfNeeded =true to the createFillInstruction function to create the recipient token account
752
+ // if it doesn't exist.
753
+ return createFillInstruction(
754
+ signer,
755
+ solanaClient,
756
+ fillInput,
757
+ { outputAmount: relayData.outputAmount.toBigInt(), recipient: toAddress(relayData.recipient) },
758
+ mintInfo.data.decimals,
759
+ true,
760
+ remainingAccounts
761
+ );
640
762
  }
641
763
 
642
764
  /**
@@ -652,8 +774,10 @@ export const createFillInstruction = async (
652
774
  signer: TransactionSigner,
653
775
  solanaClient: SVMProvider,
654
776
  fillInput: SvmSpokeClient.FillRelayInput,
777
+ relayData: Pick<SvmSpokeClient.RelayDataArgs, "outputAmount" | "recipient">,
655
778
  tokenDecimals: number,
656
- createRecipientAtaIfNeeded: boolean = true
779
+ createRecipientAtaIfNeeded: boolean = true,
780
+ remainingAccounts: (WritableAccount | ReadonlyAccount)[] = []
657
781
  ) => {
658
782
  const mintInfo = await getMintInfo(solanaClient, fillInput.mint);
659
783
  const approveIx = getApproveCheckedInstruction(
@@ -662,7 +786,7 @@ export const createFillInstruction = async (
662
786
  mint: fillInput.mint,
663
787
  delegate: fillInput.delegate,
664
788
  owner: fillInput.signer,
665
- amount: (fillInput.relayData as SvmSpokeClient.RelayDataArgs).outputAmount,
789
+ amount: relayData.outputAmount,
666
790
  decimals: tokenDecimals,
667
791
  },
668
792
  {
@@ -673,7 +797,7 @@ export const createFillInstruction = async (
673
797
  const getCreateAssociatedTokenIdempotentIx = () =>
674
798
  getCreateAssociatedTokenIdempotentInstruction({
675
799
  payer: signer,
676
- owner: (fillInput.relayData as SvmSpokeClient.RelayDataArgs).recipient,
800
+ owner: relayData.recipient,
677
801
  mint: fillInput.mint,
678
802
  ata: fillInput.recipientTokenAccount,
679
803
  systemProgram: SYSTEM_PROGRAM_ADDRESS,
@@ -682,6 +806,9 @@ export const createFillInstruction = async (
682
806
 
683
807
  const createFillIx = SvmSpokeClient.getFillRelayInstruction(fillInput);
684
808
 
809
+ // Add remaining accounts.
810
+ createFillIx.accounts.push(...remainingAccounts);
811
+
685
812
  return pipe(
686
813
  await createDefaultTransaction(solanaClient, signer),
687
814
  (tx) =>
@@ -691,6 +818,14 @@ export const createFillInstruction = async (
691
818
  );
692
819
  };
693
820
 
821
+ export function deserializeMessage(_message: string): AcrossPlusMessage {
822
+ const message = new Uint8Array(Buffer.from(_message.slice(2), "hex"));
823
+ // Add remaining accounts if the relayData has a non-empty message.
824
+ // @dev ! since in the context of creating a `fillRelayTx`, `relayData` must be defined.
825
+ const acrossPlusMessageDecoder = getAcrossPlusMessageDecoder();
826
+ return acrossPlusMessageDecoder.decode(message);
827
+ }
828
+
694
829
  /**
695
830
  * Creates a deposit instruction.
696
831
  * @param signer - The signer of the transaction.
@@ -882,28 +1017,23 @@ export async function getAssociatedTokenAddress(
882
1017
  }
883
1018
 
884
1019
  export function getRelayDataHash(relayData: RelayData, destinationChainId: number): string {
885
- const addressEncoder = getAddressEncoder();
1020
+ assert(relayData.message.startsWith("0x"), "Message must be a hex string");
886
1021
  const uint64Encoder = getU64Encoder();
887
- const uint32Encoder = getU32Encoder();
888
1022
 
889
- assert(relayData.message.startsWith("0x"), "Message must be a hex string");
890
- const encodeAddress = (data: SdkAddress) => Uint8Array.from(addressEncoder.encode(toAddress(data)));
1023
+ const svmRelayData = toSvmRelayData(relayData);
1024
+ const relayDataEncoder = SvmSpokeClient.getRelayDataEncoder();
1025
+ const encodedRelayData = relayDataEncoder.encode(svmRelayData);
1026
+ const encodedMessage = Buffer.from(relayData.message.slice(2), "hex");
891
1027
 
1028
+ // Reformat the encoded relay data the same way it is done in the SvmSpoke:
1029
+ // https://github.com/across-protocol/contracts/blob/3310f8dc716407a5f97ef5fd2eae63df83251f2f/programs/svm-spoke/src/utils/merkle_proof_utils.rs#L5
1030
+ const messageOffset = encodedRelayData.length - 4 - encodedMessage.length;
892
1031
  const contentToHash = Buffer.concat([
893
- encodeAddress(relayData.depositor),
894
- encodeAddress(relayData.recipient),
895
- encodeAddress(relayData.exclusiveRelayer),
896
- encodeAddress(relayData.inputToken),
897
- encodeAddress(relayData.outputToken),
898
- arrayify(hexZeroPad(hexlify(relayData.inputAmount), 32)),
899
- Uint8Array.from(uint64Encoder.encode(BigInt(relayData.outputAmount.toString()))),
900
- Uint8Array.from(uint64Encoder.encode(BigInt(relayData.originChainId.toString()))),
901
- arrayify(hexZeroPad(hexlify(relayData.depositId), 32)),
902
- Uint8Array.from(uint32Encoder.encode(relayData.fillDeadline)),
903
- Uint8Array.from(uint32Encoder.encode(relayData.exclusivityDeadline)),
904
- hashNonEmptyMessage(Buffer.from(arrayify(relayData.message))),
1032
+ encodedRelayData.slice(0, messageOffset),
1033
+ hashNonEmptyMessage(encodedMessage),
905
1034
  Uint8Array.from(uint64Encoder.encode(BigInt(destinationChainId))),
906
1035
  ]);
1036
+
907
1037
  return keccak256(contentToHash);
908
1038
  }
909
1039
 
@@ -991,6 +1121,47 @@ async function fetchBatchFillStatusFromPdaAccounts(
991
1121
  return fillStatuses;
992
1122
  }
993
1123
 
1124
+ /**
1125
+ * Returns a set of instructions to execute to fill a relay via instruction params.
1126
+ * @param spokePool The program ID of the Solana spoke pool.
1127
+ * @param relayData The relay data to write to the instruction params PDA.
1128
+ * @param signer The transaction signer and authority of the instruction params PDA.
1129
+ * @param maxWriteSize The maximum fragment size to write to instruction params.
1130
+ */
1131
+ export async function getFillRelayViaInstructionParamsInstructions(
1132
+ spokePool: Address<string>,
1133
+ relayData: RelayData,
1134
+ signer: TransactionSigner<string>,
1135
+ maxWriteSize = 450
1136
+ ): Promise<IInstruction[]> {
1137
+ const instructionParams = await getInstructionParamsPda(spokePool, signer.address);
1138
+
1139
+ const relayDataEncoder = SvmSpokeClient.getRelayDataEncoder();
1140
+ const svmRelayData = toSvmRelayData(relayData);
1141
+ const encodedRelayData = relayDataEncoder.encode(svmRelayData);
1142
+
1143
+ const initInstructionParamsIx = SvmSpokeClient.getInitializeInstructionParamsInstruction({
1144
+ signer,
1145
+ instructionParams,
1146
+ totalSize: encodedRelayData.length,
1147
+ });
1148
+ const instructions: IInstruction[] = [initInstructionParamsIx];
1149
+
1150
+ for (let i = 0; i <= encodedRelayData.length / maxWriteSize; ++i) {
1151
+ const offset = i * maxWriteSize;
1152
+ const offsetEnd = Math.min(offset + maxWriteSize, encodedRelayData.length);
1153
+ const fragment = encodedRelayData.slice(offset, offsetEnd);
1154
+ const writeInstructionParamsIx = SvmSpokeClient.getWriteInstructionParamsFragmentInstruction({
1155
+ signer,
1156
+ instructionParams,
1157
+ offset,
1158
+ fragment,
1159
+ });
1160
+ instructions.push(writeInstructionParamsIx);
1161
+ }
1162
+ return instructions;
1163
+ }
1164
+
994
1165
  /**
995
1166
  * Returns the delegate PDA for deposit.
996
1167
  */
@@ -0,0 +1,86 @@
1
+ import {
2
+ AccountRole,
3
+ addDecoderSizePrefix,
4
+ addEncoderSizePrefix,
5
+ getAddressDecoder,
6
+ getAddressEncoder,
7
+ getArrayEncoder,
8
+ getArrayDecoder,
9
+ getBytesDecoder,
10
+ getBytesEncoder,
11
+ getStructDecoder,
12
+ getStructEncoder,
13
+ getU8Decoder,
14
+ getU8Encoder,
15
+ getU32Decoder,
16
+ getU32Encoder,
17
+ getU64Decoder,
18
+ getU64Encoder,
19
+ type Address,
20
+ type Decoder,
21
+ type Encoder,
22
+ type ReadonlyUint8Array,
23
+ type WritableAccount,
24
+ type ReadonlyAccount,
25
+ } from "@solana/kit";
26
+
27
+ export type AcrossPlusMessage = {
28
+ handler: Address;
29
+ read_only_len: number;
30
+ value_amount: bigint;
31
+ accounts: Array<Address>;
32
+ handler_message: ReadonlyUint8Array;
33
+ };
34
+
35
+ export type CompiledIx = {
36
+ program_id_index: number;
37
+ account_key_indexes: Array<number>;
38
+ data: ReadonlyUint8Array;
39
+ };
40
+
41
+ export function getAcrossPlusMessageEncoder(): Encoder<AcrossPlusMessage> {
42
+ return getStructEncoder([
43
+ ["handler", getAddressEncoder()],
44
+ ["read_only_len", getU8Encoder()],
45
+ ["value_amount", getU64Encoder()],
46
+ ["accounts", getArrayEncoder(getAddressEncoder())],
47
+ ["handler_message", addEncoderSizePrefix(getBytesEncoder(), getU32Encoder())],
48
+ ]);
49
+ }
50
+
51
+ export function getAcrossPlusMessageDecoder(): Decoder<AcrossPlusMessage> {
52
+ return getStructDecoder([
53
+ ["handler", getAddressDecoder()],
54
+ ["read_only_len", getU8Decoder()],
55
+ ["value_amount", getU64Decoder()],
56
+ ["accounts", getArrayDecoder(getAddressDecoder())],
57
+ ["handler_message", addDecoderSizePrefix(getBytesDecoder(), getU32Decoder())],
58
+ ]);
59
+ }
60
+
61
+ export function getHandlerMessageEncoder(): Encoder<Array<CompiledIx>> {
62
+ return getArrayEncoder(getCompiledIxEncoder());
63
+ }
64
+
65
+ export function getCompiledIxEncoder(): Encoder<CompiledIx> {
66
+ return getStructEncoder([
67
+ ["program_id_index", getU8Encoder()],
68
+ ["account_key_indexes", getArrayEncoder(getU8Encoder())],
69
+ ["data", addEncoderSizePrefix(getBytesEncoder(), getU32Encoder())],
70
+ ]);
71
+ }
72
+
73
+ export function getCompiledIxDecoder(): Decoder<CompiledIx> {
74
+ return getStructDecoder([
75
+ ["program_id_index", getU8Decoder()],
76
+ ["account_key_indexes", getArrayDecoder(getU8Decoder())],
77
+ ["data", addDecoderSizePrefix(getBytesDecoder(), getU32Decoder())],
78
+ ]);
79
+ }
80
+
81
+ export function getAccountMeta(value: Address, isWritable: boolean): WritableAccount | ReadonlyAccount {
82
+ return Object.freeze({
83
+ address: value,
84
+ role: isWritable ? AccountRole.WRITABLE : AccountRole.READONLY,
85
+ });
86
+ }
@@ -5,3 +5,4 @@ export * from "./utils";
5
5
  export * from "./constants";
6
6
  export * from "./BlockUtils";
7
7
  export * from "./provider";
8
+ export * from "./encoders";
@@ -507,6 +507,29 @@ export const getEmergencyDeleteRootBundleRootBundleId = (body: Buffer): number =
507
507
  return result.rootBundleId.toNumber();
508
508
  };
509
509
 
510
+ /**
511
+ * Converts a common `RelayData` type to an SvmSpokeClient.RelayData` type. This is useful for when we need
512
+ * to interface directly with the SvmSpoke.
513
+ * @param relayData The common RelayData TS type.
514
+ * @returns RelayData which conforms to the typing of the SvmSpoke.
515
+ */
516
+ export function toSvmRelayData(relayData: RelayData): SvmSpokeClient.RelayData {
517
+ return {
518
+ originChainId: BigInt(relayData.originChainId),
519
+ depositor: address(relayData.depositor.toBase58()),
520
+ recipient: address(relayData.recipient.toBase58()),
521
+ depositId: ethers.utils.arrayify(ethers.utils.hexZeroPad(relayData.depositId.toHexString(), 32)),
522
+ inputToken: address(relayData.inputToken.toBase58()),
523
+ outputToken: address(relayData.outputToken.toBase58()),
524
+ inputAmount: ethers.utils.arrayify(ethers.utils.hexZeroPad(relayData.inputAmount.toHexString(), 32)),
525
+ outputAmount: relayData.outputAmount.toBigInt(),
526
+ message: Uint8Array.from(Buffer.from(relayData.message.slice(2), "hex")),
527
+ fillDeadline: relayData.fillDeadline,
528
+ exclusiveRelayer: address(relayData.exclusiveRelayer.toBase58()),
529
+ exclusivityDeadline: relayData.exclusivityDeadline,
530
+ };
531
+ }
532
+
510
533
  /**
511
534
  * Convert a bigint (0 ≤ n < 2^256) to a 32-byte Uint8Array (big-endian).
512
535
  * @param n The bigint to convert.