@across-protocol/sdk 4.3.20 → 4.3.23

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 (76) hide show
  1. package/dist/cjs/arch/svm/SpokeUtils.d.ts +4 -2
  2. package/dist/cjs/arch/svm/SpokeUtils.js +68 -26
  3. package/dist/cjs/arch/svm/SpokeUtils.js.map +1 -1
  4. package/dist/cjs/arch/svm/utils.d.ts +4 -1
  5. package/dist/cjs/arch/svm/utils.js +31 -8
  6. package/dist/cjs/arch/svm/utils.js.map +1 -1
  7. package/dist/cjs/caching/Arweave/ArweaveClient.d.ts +4 -1
  8. package/dist/cjs/caching/Arweave/ArweaveClient.js +66 -17
  9. package/dist/cjs/caching/Arweave/ArweaveClient.js.map +1 -1
  10. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.d.ts +24 -24
  11. package/dist/cjs/gasPriceOracle/adapters/ethereum.js +1 -5
  12. package/dist/cjs/gasPriceOracle/adapters/ethereum.js.map +1 -1
  13. package/dist/cjs/gasPriceOracle/adapters/solana.js +1 -5
  14. package/dist/cjs/gasPriceOracle/adapters/solana.js.map +1 -1
  15. package/dist/cjs/providers/utils.js +2 -0
  16. package/dist/cjs/providers/utils.js.map +1 -1
  17. package/dist/cjs/utils/BigNumberUtils.d.ts +2 -0
  18. package/dist/cjs/utils/BigNumberUtils.js +5 -1
  19. package/dist/cjs/utils/BigNumberUtils.js.map +1 -1
  20. package/dist/cjs/utils/DepositUtils.d.ts +2 -0
  21. package/dist/cjs/utils/DepositUtils.js +9 -1
  22. package/dist/cjs/utils/DepositUtils.js.map +1 -1
  23. package/dist/cjs/utils/TokenUtils.d.ts +1 -1
  24. package/dist/cjs/utils/TokenUtils.js +1 -1
  25. package/dist/cjs/utils/TokenUtils.js.map +1 -1
  26. package/dist/esm/arch/svm/SpokeUtils.d.ts +4 -2
  27. package/dist/esm/arch/svm/SpokeUtils.js +70 -29
  28. package/dist/esm/arch/svm/SpokeUtils.js.map +1 -1
  29. package/dist/esm/arch/svm/utils.d.ts +15 -1
  30. package/dist/esm/arch/svm/utils.js +40 -9
  31. package/dist/esm/arch/svm/utils.js.map +1 -1
  32. package/dist/esm/caching/Arweave/ArweaveClient.d.ts +4 -1
  33. package/dist/esm/caching/Arweave/ArweaveClient.js +72 -20
  34. package/dist/esm/caching/Arweave/ArweaveClient.js.map +1 -1
  35. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.d.ts +24 -24
  36. package/dist/esm/gasPriceOracle/adapters/ethereum.js +2 -6
  37. package/dist/esm/gasPriceOracle/adapters/ethereum.js.map +1 -1
  38. package/dist/esm/gasPriceOracle/adapters/solana.js +2 -6
  39. package/dist/esm/gasPriceOracle/adapters/solana.js.map +1 -1
  40. package/dist/esm/providers/utils.js +4 -1
  41. package/dist/esm/providers/utils.js.map +1 -1
  42. package/dist/esm/utils/BigNumberUtils.d.ts +5 -0
  43. package/dist/esm/utils/BigNumberUtils.js +5 -0
  44. package/dist/esm/utils/BigNumberUtils.js.map +1 -1
  45. package/dist/esm/utils/DepositUtils.d.ts +16 -2
  46. package/dist/esm/utils/DepositUtils.js +20 -2
  47. package/dist/esm/utils/DepositUtils.js.map +1 -1
  48. package/dist/esm/utils/TokenUtils.d.ts +3 -23
  49. package/dist/esm/utils/TokenUtils.js +1 -1
  50. package/dist/esm/utils/TokenUtils.js.map +1 -1
  51. package/dist/types/arch/svm/SpokeUtils.d.ts +4 -2
  52. package/dist/types/arch/svm/SpokeUtils.d.ts.map +1 -1
  53. package/dist/types/arch/svm/utils.d.ts +15 -1
  54. package/dist/types/arch/svm/utils.d.ts.map +1 -1
  55. package/dist/types/caching/Arweave/ArweaveClient.d.ts +4 -1
  56. package/dist/types/caching/Arweave/ArweaveClient.d.ts.map +1 -1
  57. package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts +24 -24
  58. package/dist/types/gasPriceOracle/adapters/ethereum.d.ts.map +1 -1
  59. package/dist/types/gasPriceOracle/adapters/solana.d.ts.map +1 -1
  60. package/dist/types/providers/utils.d.ts.map +1 -1
  61. package/dist/types/utils/BigNumberUtils.d.ts +5 -0
  62. package/dist/types/utils/BigNumberUtils.d.ts.map +1 -1
  63. package/dist/types/utils/DepositUtils.d.ts +16 -2
  64. package/dist/types/utils/DepositUtils.d.ts.map +1 -1
  65. package/dist/types/utils/TokenUtils.d.ts +3 -23
  66. package/dist/types/utils/TokenUtils.d.ts.map +1 -1
  67. package/package.json +1 -1
  68. package/src/arch/svm/SpokeUtils.ts +75 -14
  69. package/src/arch/svm/utils.ts +43 -8
  70. package/src/caching/Arweave/ArweaveClient.ts +47 -12
  71. package/src/gasPriceOracle/adapters/ethereum.ts +2 -6
  72. package/src/gasPriceOracle/adapters/solana.ts +2 -7
  73. package/src/providers/utils.ts +3 -0
  74. package/src/utils/BigNumberUtils.ts +6 -0
  75. package/src/utils/DepositUtils.ts +41 -2
  76. package/src/utils/TokenUtils.ts +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"TokenUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/TokenUtils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TokenUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/TokenUtils.ts"],"names":[],"mappings":"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"}
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.20",
4
+ "version": "4.3.23",
5
5
  "license": "AGPL-3.0",
6
6
  "homepage": "https://docs.across.to/reference/sdk",
7
7
  "files": [
@@ -1,18 +1,21 @@
1
1
  import { MessageTransmitterClient, SvmSpokeClient, TokenMessengerMinterClient } from "@across-protocol/contracts";
2
2
  import { decodeFillStatusAccount, fetchState } from "@across-protocol/contracts/dist/src/svm/clients/SvmSpoke";
3
- import { hashNonEmptyMessage } from "@across-protocol/contracts/dist/src/svm/web3-v1";
3
+ import { decodeMessageHeader, hashNonEmptyMessage } from "@across-protocol/contracts/dist/src/svm/web3-v1";
4
4
  import { intToU8Array32 } from "@across-protocol/contracts/dist/src/svm/web3-v1/conversionUtils";
5
5
  import { SYSTEM_PROGRAM_ADDRESS } from "@solana-program/system";
6
6
  import {
7
7
  ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
8
+ Mint,
8
9
  TOKEN_PROGRAM_ADDRESS,
9
10
  fetchMint,
10
11
  getApproveCheckedInstruction,
11
12
  getCreateAssociatedTokenIdempotentInstruction,
12
13
  } from "@solana-program/token";
13
14
  import {
15
+ Account,
14
16
  AccountRole,
15
17
  Address,
18
+ FetchAccountConfig,
16
19
  IAccountMeta,
17
20
  KeyPairSigner,
18
21
  ReadonlyUint8Array,
@@ -61,11 +64,17 @@ import {
61
64
  simulateAndDecode,
62
65
  toAddress,
63
66
  unwrapEventData,
67
+ getRootBundlePda,
64
68
  } from "./";
65
69
  import { SvmCpiEventsClient } from "./eventsClient";
66
70
  import { SVM_NO_BLOCK_AT_SLOT, isSolanaError } from "./provider";
67
71
  import { AttestedCCTPMessage, SVMEventNames, SVMProvider } from "./types";
68
- import { getNearestSlotTime } from "./utils";
72
+ import {
73
+ getEmergencyDeleteRootBundleRootBundleId,
74
+ getNearestSlotTime,
75
+ isEmergencyDeleteRootBundleMessageBody,
76
+ isRelayRootBundleMessageBody,
77
+ } from "./utils";
69
78
 
70
79
  /**
71
80
  * @note: Average Solana slot duration is about 400-500ms. We can be conservative
@@ -555,7 +564,7 @@ export async function getFillRelayTx(
555
564
  ]);
556
565
 
557
566
  const mint = toAddress(outputToken);
558
- const mintInfo = await fetchMint(solanaClient, mint);
567
+ const mintInfo = await getMintInfo(solanaClient, mint);
559
568
 
560
569
  const [recipientAta, relayerAta, fillStatus, eventAuthority] = await Promise.all([
561
570
  getAssociatedTokenAddress(recipient, outputToken, mintInfo.programAddress),
@@ -618,7 +627,7 @@ export const createFillInstruction = async (
618
627
  tokenDecimals: number,
619
628
  createRecipientAtaIfNeeded: boolean = true
620
629
  ) => {
621
- const mintInfo = await fetchMint(solanaClient, fillInput.mint);
630
+ const mintInfo = await getMintInfo(solanaClient, fillInput.mint);
622
631
  const approveIx = getApproveCheckedInstruction(
623
632
  {
624
633
  source: fillInput.relayerTokenAccount,
@@ -679,7 +688,7 @@ export const createDepositInstruction = async (
679
688
  systemProgram: depositInput.systemProgram,
680
689
  tokenProgram: depositInput.tokenProgram,
681
690
  });
682
- const mintInfo = await fetchMint(solanaClient, depositInput.mint);
691
+ const mintInfo = await getMintInfo(solanaClient, depositInput.mint);
683
692
  const approveIx = getApproveCheckedInstruction(
684
693
  {
685
694
  source: depositInput.depositorTokenAccount,
@@ -1112,15 +1121,59 @@ export const hasCCTPV1MessageBeenProcessed = async (
1112
1121
  * Returns the account metas for a tokenless message.
1113
1122
  * @returns The account metas for a tokenless message.
1114
1123
  */
1115
- export async function getAccountMetasForTokenlessMessage(): Promise<IAccountMeta<string>[]> {
1116
- const statePda = await getStatePda(SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS);
1117
- return [
1124
+ export async function getAccountMetasForTokenlessMessage(
1125
+ solanaClient: SVMProvider,
1126
+ signer: KeyPairSigner,
1127
+ messageBytes: string
1128
+ ): Promise<IAccountMeta<string>[]> {
1129
+ const messageHeader = decodeMessageHeader(Buffer.from(messageBytes, "hex"));
1130
+ const programAddress = SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS;
1131
+ const statePda = await getStatePda(programAddress);
1132
+ const selfAuthority = await getSelfAuthority();
1133
+ const eventAuthority = await getEventAuthority(programAddress);
1134
+
1135
+ const base: IAccountMeta<string>[] = [
1118
1136
  { address: statePda, role: AccountRole.READONLY },
1119
- { address: await getSelfAuthority(), role: AccountRole.READONLY },
1120
- { address: SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS, role: AccountRole.READONLY },
1137
+ { address: selfAuthority, role: AccountRole.READONLY },
1138
+ { address: programAddress, role: AccountRole.READONLY },
1139
+ ];
1140
+
1141
+ if (isRelayRootBundleMessageBody(messageHeader.messageBody)) {
1142
+ const {
1143
+ data: { rootBundleId },
1144
+ } = await SvmSpokeClient.fetchState(solanaClient, statePda);
1145
+ const rootBundle = await getRootBundlePda(programAddress, rootBundleId);
1146
+
1147
+ return [
1148
+ ...base,
1149
+ { address: signer.address, role: AccountRole.WRITABLE },
1150
+ { address: statePda, role: AccountRole.WRITABLE },
1151
+ { address: rootBundle, role: AccountRole.WRITABLE },
1152
+ { address: SYSTEM_PROGRAM_ADDRESS, role: AccountRole.READONLY },
1153
+ { address: eventAuthority, role: AccountRole.READONLY },
1154
+ { address: programAddress, role: AccountRole.READONLY },
1155
+ ];
1156
+ }
1157
+
1158
+ if (isEmergencyDeleteRootBundleMessageBody(messageHeader.messageBody)) {
1159
+ const rootBundleId = getEmergencyDeleteRootBundleRootBundleId(messageHeader.messageBody);
1160
+ const rootBundle = await getRootBundlePda(programAddress, rootBundleId);
1161
+
1162
+ return [
1163
+ ...base,
1164
+ { address: signer.address, role: AccountRole.READONLY },
1165
+ { address: statePda, role: AccountRole.READONLY },
1166
+ { address: rootBundle, role: AccountRole.WRITABLE },
1167
+ { address: eventAuthority, role: AccountRole.READONLY },
1168
+ { address: programAddress, role: AccountRole.READONLY },
1169
+ ];
1170
+ }
1171
+
1172
+ return [
1173
+ ...base,
1121
1174
  { address: statePda, role: AccountRole.WRITABLE },
1122
- { address: await getEventAuthority(SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS), role: AccountRole.READONLY },
1123
- { address: SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS, role: AccountRole.READONLY },
1175
+ { address: eventAuthority, role: AccountRole.READONLY },
1176
+ { address: programAddress, role: AccountRole.READONLY },
1124
1177
  ];
1125
1178
  }
1126
1179
 
@@ -1246,7 +1299,7 @@ export async function getCCTPV1ReceiveMessageTx(
1246
1299
  hubChainId,
1247
1300
  TokenMessengerMinterClient.TOKEN_MESSENGER_MINTER_PROGRAM_ADDRESS
1248
1301
  )
1249
- : await getAccountMetasForTokenlessMessage();
1302
+ : await getAccountMetasForTokenlessMessage(solanaClient, signer, message.messageBytes);
1250
1303
 
1251
1304
  const messageBytes = message.messageBytes.startsWith("0x")
1252
1305
  ? Buffer.from(message.messageBytes.slice(2), "hex")
@@ -1260,7 +1313,7 @@ export async function getCCTPV1ReceiveMessageTx(
1260
1313
  messageTransmitter: messageTransmitterPda,
1261
1314
  eventAuthority: eventAuthorityPda,
1262
1315
  usedNonces,
1263
- receiver: SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS,
1316
+ receiver: cctpMessageReceiver,
1264
1317
  systemProgram: SYSTEM_PROGRAM_ADDRESS,
1265
1318
  message: messageBytes,
1266
1319
  attestation: Buffer.from(message.attestation.slice(2), "hex"),
@@ -1315,3 +1368,11 @@ export function finalizeCCTPV1Messages(
1315
1368
  return signature;
1316
1369
  });
1317
1370
  }
1371
+
1372
+ export async function getMintInfo(
1373
+ solanaClient: SVMProvider,
1374
+ mint: Address<string>,
1375
+ config?: FetchAccountConfig
1376
+ ): Promise<Account<Mint, string>> {
1377
+ return await fetchMint(solanaClient, mint, config);
1378
+ }
@@ -1,9 +1,7 @@
1
- import assert from "assert";
2
- import { MessageTransmitterClient, SvmSpokeClient } from "@across-protocol/contracts";
1
+ import { MessageTransmitterClient, SpokePool__factory, SvmSpokeClient } from "@across-protocol/contracts";
3
2
  import { BN, BorshEventCoder, Idl } from "@coral-xyz/anchor";
4
3
  import {
5
4
  Address,
6
- type Commitment,
7
5
  IInstruction,
8
6
  KeyPairSigner,
9
7
  address,
@@ -19,14 +17,16 @@ import {
19
17
  setTransactionMessageFeePayerSigner,
20
18
  setTransactionMessageLifetimeUsingBlockhash,
21
19
  signTransactionMessageWithSigners,
20
+ type Commitment,
22
21
  type TransactionSigner,
23
22
  } from "@solana/kit";
23
+ import assert from "assert";
24
24
  import bs58 from "bs58";
25
25
  import { ethers } from "ethers";
26
26
  import { FillType, RelayData } from "../../interfaces";
27
- import { BigNumber, Address as SdkAddress, getRelayDataHash, isDefined, isUint8Array } from "../../utils";
28
- import { AttestedCCTPMessage, EventName, SVMEventNames, SVMProvider } from "./types";
27
+ import { BigNumber, Address as SdkAddress, biMin, getRelayDataHash, isDefined, isUint8Array } from "../../utils";
29
28
  import { getTimestampForSlot } from "./SpokeUtils";
29
+ import { AttestedCCTPMessage, EventName, SVMEventNames, SVMProvider } from "./types";
30
30
 
31
31
  export { isSolanaError } from "@solana/kit";
32
32
 
@@ -90,11 +90,11 @@ export async function getLatestFinalizedSlotWithBlock(
90
90
  maxSlot: bigint,
91
91
  maxLookback = 1000
92
92
  ): Promise<number> {
93
- const { slot: finalizedSlot } = await getNearestSlotTime(provider, { commitment: "finalized" });
94
- const endSlot = Math.min(Number(maxSlot), Number(finalizedSlot));
95
93
  const opts = { maxSupportedTransactionVersion: 0, transactionDetails: "none", rewards: false } as const;
94
+ const { slot: finalizedSlot } = await getNearestSlotTime(provider, { commitment: "finalized" });
95
+ const endSlot = biMin(maxSlot, finalizedSlot);
96
96
 
97
- let slot = BigInt(endSlot);
97
+ let slot = endSlot;
98
98
  do {
99
99
  const block = await provider.getBlock(slot, opts).send();
100
100
  if (isDefined(block) && [block.blockHeight, block.blockTime].every(isDefined)) {
@@ -472,6 +472,41 @@ export function isDepositForBurnEvent(event: AttestedCCTPMessage): boolean {
472
472
  return event.type === "transfer";
473
473
  }
474
474
 
475
+ /**
476
+ * True if `body` encodes a `relayRootBundle(bytes32,bytes32)` call.
477
+ */
478
+ export const isRelayRootBundleMessageBody = (body: Buffer): boolean => {
479
+ if (body.length < 4) return false;
480
+
481
+ const spokePoolInterface = new ethers.utils.Interface(SpokePool__factory.abi);
482
+ const relayRootBundleSelector = spokePoolInterface.getSighash("relayRootBundle");
483
+
484
+ return body.slice(0, 4).equals(Buffer.from(relayRootBundleSelector.slice(2), "hex"));
485
+ };
486
+
487
+ /**
488
+ * True if `body` encodes a `emergencyDeleteRootBundle(uint32)` call.
489
+ */
490
+ export const isEmergencyDeleteRootBundleMessageBody = (body: Buffer): boolean => {
491
+ if (body.length < 4) return false;
492
+
493
+ const spokePoolInterface = new ethers.utils.Interface(SpokePool__factory.abi);
494
+ const emergencyDeleteRootBundleSelector = spokePoolInterface.getSighash("emergencyDeleteRootBundle");
495
+
496
+ return body.slice(0, 4).equals(Buffer.from(emergencyDeleteRootBundleSelector.slice(2), "hex"));
497
+ };
498
+
499
+ /**
500
+ * Decodes the root bundle ID from an emergency delete root bundle message body.
501
+ * @param body The message body.
502
+ * @returns The root bundle ID.
503
+ */
504
+ export const getEmergencyDeleteRootBundleRootBundleId = (body: Buffer): number => {
505
+ const spokePoolInterface = new ethers.utils.Interface(SpokePool__factory.abi);
506
+ const result = spokePoolInterface.decodeFunctionData("emergencyDeleteRootBundle", body);
507
+ return result.rootBundleId.toNumber();
508
+ };
509
+
475
510
  /**
476
511
  * Convert a bigint (0 ≤ n < 2^256) to a 32-byte Uint8Array (big-endian).
477
512
  * @param n The bigint to convert.
@@ -4,7 +4,7 @@ import axios from "axios";
4
4
  import { Struct, create } from "superstruct";
5
5
  import winston from "winston";
6
6
  import { ARWEAVE_TAG_APP_NAME, ARWEAVE_TAG_APP_VERSION, DEFAULT_ARWEAVE_STORAGE_ADDRESS } from "../../constants";
7
- import { BigNumber, isDefined, jsonReplacerWithBigNumbers, toBN } from "../../utils";
7
+ import { BigNumber, delay, isDefined, jsonReplacerWithBigNumbers, toBN } from "../../utils";
8
8
 
9
9
  export class ArweaveClient {
10
10
  private client: Arweave;
@@ -15,7 +15,9 @@ export class ArweaveClient {
15
15
  private logger: winston.Logger,
16
16
  gatewayURL = "arweave.net",
17
17
  protocol = "https",
18
- port = 443
18
+ port = 443,
19
+ private readonly retries = 2,
20
+ private readonly retryDelaySeconds = 1
19
21
  ) {
20
22
  this.gatewayUrl = `${protocol}://${gatewayURL}:${port}`;
21
23
  this.client = new Arweave({
@@ -30,6 +32,12 @@ export class ArweaveClient {
30
32
  message: "Arweave client initialized",
31
33
  gateway: this.gatewayUrl,
32
34
  });
35
+ if (this.retries < 0) {
36
+ throw new Error(`retries cannot be < 0 and must be an integer. Currently set to ${this.retries}`);
37
+ }
38
+ if (this.retryDelaySeconds < 0) {
39
+ throw new Error(`delay cannot be < 0. Currently set to ${this.retryDelaySeconds}`);
40
+ }
33
41
  }
34
42
 
35
43
  /**
@@ -225,21 +233,48 @@ export class ArweaveClient {
225
233
  return this.client.wallets.jwkToAddress(this.arweaveJWT);
226
234
  }
227
235
 
236
+ private async _retryRequest<T>(request: () => Promise<T>, retryCount: number): Promise<T> {
237
+ try {
238
+ return request();
239
+ } catch (e) {
240
+ if (retryCount < this.retries) {
241
+ // Implement a slightly aggressive exponential backoff to account for fierce parallelism.
242
+ const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount); // ms; attempt = [0, 1, 2, ...]
243
+ const delayS = baseDelay + baseDelay * Math.random();
244
+ this.logger.debug({
245
+ at: "ArweaveClient:getBalance",
246
+ message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
247
+ retryCount,
248
+ });
249
+ await delay(delayS);
250
+ return this._retryRequest(request, retryCount + 1);
251
+ } else {
252
+ throw e;
253
+ }
254
+ }
255
+ }
256
+
228
257
  /**
229
258
  * The balance of the signer
230
259
  * @returns The balance of the signer in winston units
231
260
  */
232
261
  async getBalance(): Promise<BigNumber> {
233
262
  const address = await this.getAddress();
234
- const balanceInFloat = await this.client.wallets.getBalance(address);
235
- // Sometimes the balance is returned in scientific notation, so we need to
236
- // convert it to a BigNumber
237
- if (balanceInFloat.includes("e")) {
238
- const [balance, exponent] = balanceInFloat.split("e");
239
- const resultingBN = BigNumber.from(balance).mul(toBN(10).pow(exponent.replace("+", "")));
240
- return BigNumber.from(resultingBN.toString());
241
- } else {
242
- return BigNumber.from(balanceInFloat);
243
- }
263
+ const request = async () => {
264
+ const balanceInFloat = await this.client.wallets.getBalance(address);
265
+ // @dev The reason we add in the BN.from into this retry loop is because the client.getBalance call
266
+ // does not correctly throw an error if the request fails, instead it will return the error string as the
267
+ // balanceInFloat.
268
+ // Sometimes the balance is returned in scientific notation, so we need to
269
+ // convert it to a BigNumber
270
+ if (balanceInFloat.includes("e")) {
271
+ const [balance, exponent] = balanceInFloat.split("e");
272
+ const resultingBN = BigNumber.from(balance).mul(toBN(10).pow(exponent.replace("+", "")));
273
+ return BigNumber.from(resultingBN.toString());
274
+ } else {
275
+ return BigNumber.from(balanceInFloat);
276
+ }
277
+ };
278
+ return await this._retryRequest(request, 0);
244
279
  }
245
280
  }
@@ -1,6 +1,6 @@
1
1
  import assert from "assert";
2
2
  import { providers } from "ethers";
3
- import { BigNumber, bnZero, fixedPointAdjustment, getNetworkName, parseUnits } from "../../utils";
3
+ import { BigNumber, bnZero, fixedPointAdjustment, getNetworkName } from "../../utils";
4
4
  import { EvmGasPriceEstimate } from "../types";
5
5
  import { gasPriceError } from "../util";
6
6
  import { GasPriceEstimateOptions } from "../oracle";
@@ -37,11 +37,7 @@ export async function eip1559Raw(
37
37
  const maxPriorityFeePerGas = BigNumber.from(_maxPriorityFeePerGas);
38
38
  assert(BigNumber.isBigNumber(baseFeePerGas), `No baseFeePerGas received on ${getNetworkName(chainId)}`);
39
39
 
40
- let scaledPriorityFee = maxPriorityFeePerGas.mul(priorityFeeMultiplier).div(fixedPointAdjustment);
41
- const flooredPriorityFeePerGas = parseUnits(process.env[`MIN_PRIORITY_FEE_PER_GAS_${chainId}`] || "0", 9);
42
- if (scaledPriorityFee.lt(flooredPriorityFeePerGas)) {
43
- scaledPriorityFee = BigNumber.from(flooredPriorityFeePerGas);
44
- }
40
+ const scaledPriorityFee = maxPriorityFeePerGas.mul(priorityFeeMultiplier).div(fixedPointAdjustment);
45
41
  const scaledBaseFee = baseFeePerGas.mul(baseFeeMultiplier).div(fixedPointAdjustment);
46
42
  return {
47
43
  maxFeePerGas: scaledPriorityFee.add(scaledBaseFee),
@@ -1,5 +1,5 @@
1
1
  import { SVMProvider } from "../../arch/svm";
2
- import { toBN, dedupArray, parseUnits } from "../../utils";
2
+ import { toBN, dedupArray } from "../../utils";
3
3
  import { SvmGasPriceEstimate } from "../types";
4
4
  import { GasPriceEstimateOptions } from "../oracle";
5
5
  import { CompilableTransactionMessage, TransactionMessageBytesBase64, compileTransaction } from "@solana/kit";
@@ -32,14 +32,9 @@ export async function messageFee(provider: SVMProvider, opts: GasPriceEstimateOp
32
32
  .filter((fee) => fee > 0);
33
33
  const totalPrioritizationFees = nonzeroPrioritizationFees.reduce((acc, fee) => acc + fee, BigInt(0));
34
34
 
35
- // Optionally impose a minimum priority fee, denoted in microLamports/computeUnit.
36
- const flooredPriorityFeePerGas = parseUnits(process.env[`MIN_PRIORITY_FEE_PER_GAS_${opts.chainId}`] || "0", 6);
37
- let microLamportsPerComputeUnit = toBN(
35
+ const microLamportsPerComputeUnit = toBN(
38
36
  totalPrioritizationFees / BigInt(Math.max(nonzeroPrioritizationFees.length, 1))
39
37
  );
40
- if (microLamportsPerComputeUnit.lt(flooredPriorityFeePerGas)) {
41
- microLamportsPerComputeUnit = flooredPriorityFeePerGas;
42
- }
43
38
  return {
44
39
  baseFee: toBN(baseFeeResponse!.value!),
45
40
  microLamportsPerComputeUnit,
@@ -96,14 +96,17 @@ const IGNORED_FIELDS = {
96
96
  // 2023-08-31 Added blockHash because of upstream zkSync provider disagreements. Consider removing later.
97
97
  // 2024-05-07 Added l1BatchNumber and logType due to Alchemy. Consider removing later.
98
98
  // 2024-07-11 Added blockTimestamp after zkSync rolled out a new node release.
99
+ // 2025-07-24 Added additional fields returned by Chainstack on (at least) Polygon.
99
100
  eth_getBlockByNumber: [
100
101
  "miner", // polygon (sometimes)
101
102
  "l1BatchNumber", // zkSync
102
103
  "l1BatchTimestamp", // zkSync
104
+ "requestsHash", // Chainstack (Polygon)
103
105
  "size", // Alchemy/Arbitrum (temporary)
104
106
  "totalDifficulty", // Quicknode/Alchemy (sometimes)
105
107
  "logsBloom", // zkSync (third-party providers return 0x0..0)
106
108
  "transactions", // Polygon yParity field in transactions[]
109
+ "withdrawals", // Chainstack (Polygon)
107
110
  ],
108
111
  eth_getLogs: ["blockTimestamp", "transactionLogIndex", "l1BatchNumber", "logType"],
109
112
  };
@@ -19,6 +19,12 @@ export const bnOne = BigNumber.from("1");
19
19
  export const bnUint32Max = BigNumber.from("0xffffffff");
20
20
  export const bnUint256Max = BigNumber.from("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
21
21
 
22
+ /**
23
+ * BigInt min/max helpers.
24
+ */
25
+ export const biMin = (a: bigint, b: bigint) => (a > b ? b : a);
26
+ export const biMax = (a: bigint, b: bigint) => (a > b ? a : b);
27
+
22
28
  /**
23
29
  * Converts a stringified number into a BigNumber with 18 decimal places.
24
30
  * @param num The number to parse.
@@ -265,7 +265,7 @@ export function resolveDepositMessage(deposit: Deposit): string {
265
265
  * Converts a RelayData object with `Address` types as address fields to a `RelayData`-like object with
266
266
  * strings as address fields.
267
267
  * @param relayData RelayData type.
268
- * @returns a RelayData-like type which has strings as fields.
268
+ * @returns a RelayData-like type which has hex 32 byte strings as fields.
269
269
  */
270
270
  export function convertRelayDataParamsToBytes32(relayData: RelayData): ConvertedRelayData {
271
271
  return {
@@ -282,7 +282,7 @@ export function convertRelayDataParamsToBytes32(relayData: RelayData): Converted
282
282
  * Converts a Fill object with `Address` types as address fields to a `RelayData`-like object with
283
283
  * strings as address fields.
284
284
  * @param relayData RelayData type.
285
- * @returns a RelayData-like type which has strings as fields.
285
+ * @returns a RelayData-like type which has hex 32 byte strings as fields.
286
286
  */
287
287
  export function convertFillParamsToBytes32(fill: Fill): ConvertedFill {
288
288
  return {
@@ -299,3 +299,42 @@ export function convertFillParamsToBytes32(fill: Fill): ConvertedFill {
299
299
  },
300
300
  };
301
301
  }
302
+
303
+ /**
304
+ * Converts a RelayData object with `Address` types as address fields to a `RelayData`-like object with
305
+ * strings as address fields.
306
+ * @param relayData RelayData type.
307
+ * @returns a RelayData-like type which has native address representation strings as fields.
308
+ */
309
+ export function convertRelayDataParamsToNative(relayData: RelayData): ConvertedRelayData {
310
+ return {
311
+ ...relayData,
312
+ depositor: relayData.depositor.toNative(),
313
+ recipient: relayData.recipient.toNative(),
314
+ inputToken: relayData.inputToken.toNative(),
315
+ outputToken: relayData.outputToken.toNative(),
316
+ exclusiveRelayer: relayData.exclusiveRelayer.toNative(),
317
+ };
318
+ }
319
+
320
+ /**
321
+ * Converts a Fill object with `Address` types as address fields to a `RelayData`-like object with
322
+ * strings as address fields.
323
+ * @param relayData RelayData type.
324
+ * @returns a RelayData-like type which has native address representation strings as fields.
325
+ */
326
+ export function convertFillParamsToNative(fill: Fill): ConvertedFill {
327
+ return {
328
+ ...fill,
329
+ depositor: fill.depositor.toNative(),
330
+ recipient: fill.recipient.toNative(),
331
+ inputToken: fill.inputToken.toNative(),
332
+ outputToken: fill.outputToken.toNative(),
333
+ exclusiveRelayer: fill.exclusiveRelayer.toNative(),
334
+ relayer: fill.relayer.toNative(),
335
+ relayExecutionInfo: {
336
+ ...fill.relayExecutionInfo,
337
+ updatedRecipient: fill.relayExecutionInfo.updatedRecipient.toNative(),
338
+ },
339
+ };
340
+ }
@@ -58,12 +58,12 @@ export function resolveSymbolOnChain(chainId: number, symbol: string): TokenInfo
58
58
  */
59
59
  export const resolveContractFromSymbol = (
60
60
  symbol: string,
61
- chainId: string,
61
+ chainId: number,
62
62
  tokenMapping = TOKEN_SYMBOLS_MAP
63
63
  ): string | undefined => {
64
64
  return Object.values(tokenMapping).find((details) => {
65
65
  return details.symbol.toLowerCase() === symbol.toLowerCase();
66
- })?.addresses[Number(chainId)];
66
+ })?.addresses[chainId];
67
67
  };
68
68
 
69
69
  export function getCoingeckoTokenIdByAddress(address: string, chainId: number): string {