@across-protocol/sdk 4.1.44 → 4.1.45-beta.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 (109) hide show
  1. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +23 -14
  2. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  3. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js +10 -1
  4. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
  5. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.d.ts +7 -7
  6. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +47 -36
  7. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  8. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
  9. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js +2 -2
  10. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  11. package/dist/cjs/clients/HubPoolClient.d.ts +3 -2
  12. package/dist/cjs/clients/HubPoolClient.js +27 -15
  13. package/dist/cjs/clients/HubPoolClient.js.map +1 -1
  14. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.d.ts +1 -0
  15. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js +19 -5
  16. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
  17. package/dist/cjs/clients/mocks/MockHubPoolClient.d.ts +2 -0
  18. package/dist/cjs/clients/mocks/MockHubPoolClient.js +18 -0
  19. package/dist/cjs/clients/mocks/MockHubPoolClient.js.map +1 -1
  20. package/dist/cjs/svm/eventsClient.js +5 -12
  21. package/dist/cjs/svm/eventsClient.js.map +1 -1
  22. package/dist/cjs/svm/index.d.ts +2 -0
  23. package/dist/cjs/svm/index.js +3 -0
  24. package/dist/cjs/svm/index.js.map +1 -1
  25. package/dist/cjs/svm/utils/events.d.ts +6 -1
  26. package/dist/cjs/svm/utils/events.js +13 -4
  27. package/dist/cjs/svm/utils/events.js.map +1 -1
  28. package/dist/cjs/svm/utils/index.d.ts +1 -0
  29. package/dist/cjs/svm/utils/index.js +5 -0
  30. package/dist/cjs/svm/utils/index.js.map +1 -0
  31. package/dist/cjs/utils/DepositUtils.d.ts +1 -0
  32. package/dist/cjs/utils/DepositUtils.js +5 -1
  33. package/dist/cjs/utils/DepositUtils.js.map +1 -1
  34. package/dist/cjs/utils/common.d.ts +2 -0
  35. package/dist/cjs/utils/common.js +3 -1
  36. package/dist/cjs/utils/common.js.map +1 -1
  37. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +24 -15
  38. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  39. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js +16 -1
  40. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
  41. package/dist/esm/clients/BundleDataClient/utils/FillUtils.d.ts +28 -7
  42. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +83 -50
  43. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  44. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
  45. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js +2 -2
  46. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  47. package/dist/esm/clients/HubPoolClient.d.ts +3 -16
  48. package/dist/esm/clients/HubPoolClient.js +31 -33
  49. package/dist/esm/clients/HubPoolClient.js.map +1 -1
  50. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.d.ts +1 -0
  51. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js +28 -14
  52. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
  53. package/dist/esm/clients/mocks/MockHubPoolClient.d.ts +2 -0
  54. package/dist/esm/clients/mocks/MockHubPoolClient.js +18 -0
  55. package/dist/esm/clients/mocks/MockHubPoolClient.js.map +1 -1
  56. package/dist/esm/svm/eventsClient.js +6 -13
  57. package/dist/esm/svm/eventsClient.js.map +1 -1
  58. package/dist/esm/svm/index.d.ts +2 -0
  59. package/dist/esm/svm/index.js +3 -0
  60. package/dist/esm/svm/index.js.map +1 -1
  61. package/dist/esm/svm/utils/events.d.ts +9 -1
  62. package/dist/esm/svm/utils/events.js +15 -3
  63. package/dist/esm/svm/utils/events.js.map +1 -1
  64. package/dist/esm/svm/utils/index.d.ts +1 -0
  65. package/dist/esm/svm/utils/index.js +2 -0
  66. package/dist/esm/svm/utils/index.js.map +1 -0
  67. package/dist/esm/utils/DepositUtils.d.ts +1 -0
  68. package/dist/esm/utils/DepositUtils.js +5 -1
  69. package/dist/esm/utils/DepositUtils.js.map +1 -1
  70. package/dist/esm/utils/common.d.ts +2 -0
  71. package/dist/esm/utils/common.js +2 -0
  72. package/dist/esm/utils/common.js.map +1 -1
  73. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
  74. package/dist/types/clients/BundleDataClient/utils/DataworkerUtils.d.ts.map +1 -1
  75. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts +28 -7
  76. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -1
  77. package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
  78. package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts.map +1 -1
  79. package/dist/types/clients/HubPoolClient.d.ts +3 -16
  80. package/dist/types/clients/HubPoolClient.d.ts.map +1 -1
  81. package/dist/types/clients/SpokePoolClient/SpokePoolClient.d.ts +1 -0
  82. package/dist/types/clients/SpokePoolClient/SpokePoolClient.d.ts.map +1 -1
  83. package/dist/types/clients/mocks/MockHubPoolClient.d.ts +2 -0
  84. package/dist/types/clients/mocks/MockHubPoolClient.d.ts.map +1 -1
  85. package/dist/types/svm/eventsClient.d.ts.map +1 -1
  86. package/dist/types/svm/index.d.ts +2 -0
  87. package/dist/types/svm/index.d.ts.map +1 -1
  88. package/dist/types/svm/utils/events.d.ts +9 -1
  89. package/dist/types/svm/utils/events.d.ts.map +1 -1
  90. package/dist/types/svm/utils/index.d.ts +2 -0
  91. package/dist/types/svm/utils/index.d.ts.map +1 -0
  92. package/dist/types/utils/DepositUtils.d.ts +1 -0
  93. package/dist/types/utils/DepositUtils.d.ts.map +1 -1
  94. package/dist/types/utils/common.d.ts +2 -0
  95. package/dist/types/utils/common.d.ts.map +1 -1
  96. package/package.json +1 -1
  97. package/src/clients/BundleDataClient/BundleDataClient.ts +38 -21
  98. package/src/clients/BundleDataClient/utils/DataworkerUtils.ts +36 -1
  99. package/src/clients/BundleDataClient/utils/FillUtils.ts +133 -71
  100. package/src/clients/BundleDataClient/utils/PoolRebalanceUtils.ts +3 -2
  101. package/src/clients/HubPoolClient.ts +41 -38
  102. package/src/clients/SpokePoolClient/SpokePoolClient.ts +54 -16
  103. package/src/clients/mocks/MockHubPoolClient.ts +16 -0
  104. package/src/svm/eventsClient.ts +6 -12
  105. package/src/svm/index.ts +2 -0
  106. package/src/svm/utils/events.ts +16 -4
  107. package/src/svm/utils/index.ts +1 -0
  108. package/src/utils/DepositUtils.ts +6 -1
  109. package/src/utils/common.ts +2 -0
@@ -163,12 +163,13 @@ export function updateRunningBalanceForDeposit(
163
163
  runningBalances: RunningBalances,
164
164
  hubPoolClient: HubPoolClient,
165
165
  deposit: V3DepositWithBlock,
166
- updateAmount: BigNumber
166
+ updateAmount: BigNumber,
167
+ mainnetBundleEndBlock: number
167
168
  ): void {
168
169
  const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
169
170
  deposit.inputToken,
170
171
  deposit.originChainId,
171
- deposit.quoteBlockNumber
172
+ mainnetBundleEndBlock
172
173
  );
173
174
  updateRunningBalance(runningBalances, deposit.originChainId, l1TokenCounterpart, updateAmount);
174
175
  }
@@ -231,40 +231,41 @@ export class HubPoolClient extends BaseAbstractClient {
231
231
  return sortEventsDescending(l2Tokens)[0].l1Token;
232
232
  }
233
233
 
234
- /**
235
- * Returns the L1 token that should be used for an L2 Bridge event. This function is
236
- * designed to be used by the caller to associate the L2 token with its mapped L1 token
237
- * at the HubPool equivalent block number of the L2 event.
238
- * @param deposit Deposit event
239
- * @param returns string L1 token counterpart for Deposit
240
- */
241
- getL1TokenForDeposit(deposit: Pick<DepositWithBlock, "originChainId" | "inputToken" | "quoteBlockNumber">): string {
234
+ protected getL1TokenForDeposit(
235
+ deposit: Pick<DepositWithBlock, "originChainId" | "inputToken" | "quoteBlockNumber">
236
+ ): string {
242
237
  // L1-->L2 token mappings are set via PoolRebalanceRoutes which occur on mainnet,
243
238
  // so we use the latest token mapping. This way if a very old deposit is filled, the relayer can use the
244
239
  // latest L2 token mapping to find the L1 token counterpart.
245
240
  return this.getL1TokenForL2TokenAtBlock(deposit.inputToken, deposit.originChainId, deposit.quoteBlockNumber);
246
241
  }
247
242
 
248
- /**
249
- * Returns the L2 token that should be used as a counterpart to a deposit event. For example, the caller
250
- * might want to know what the refund token will be on l2ChainId for the deposit event.
251
- * @param l2ChainId Chain where caller wants to get L2 token counterpart for
252
- * @param event Deposit event
253
- * @returns string L2 token counterpart on l2ChainId
254
- */
255
- getL2TokenForDeposit(
256
- deposit: Pick<DepositWithBlock, "originChainId" | "destinationChainId" | "inputToken" | "quoteBlockNumber">,
257
- l2ChainId = deposit.destinationChainId
258
- ): string {
259
- const l1Token = this.getL1TokenForDeposit(deposit);
260
- // Use the latest hub block number to find the L2 token counterpart.
261
- return this.getL2TokenForL1TokenAtBlock(l1Token, l2ChainId, deposit.quoteBlockNumber);
262
- }
263
-
264
243
  l2TokenEnabledForL1Token(l1Token: string, destinationChainId: number): boolean {
265
244
  return this.l1TokensToDestinationTokens?.[l1Token]?.[destinationChainId] != undefined;
266
245
  }
267
246
 
247
+ l2TokenEnabledForL1TokenAtBlock(l1Token: string, destinationChainId: number, hubBlockNumber: number): boolean {
248
+ // Find the last mapping published before the target block.
249
+ const l2Token: DestinationTokenWithBlock | undefined = sortEventsDescending(
250
+ this.l1TokensToDestinationTokensWithBlock?.[l1Token]?.[destinationChainId] ?? []
251
+ ).find((mapping: DestinationTokenWithBlock) => mapping.blockNumber <= hubBlockNumber);
252
+ return l2Token !== undefined;
253
+ }
254
+
255
+ l2TokenHasPoolRebalanceRoute(l2Token: string, l2ChainId: number, hubPoolBlock = this.latestBlockSearched): boolean {
256
+ return Object.values(this.l1TokensToDestinationTokensWithBlock).some((destinationTokenMapping) => {
257
+ return Object.entries(destinationTokenMapping).some(([_l2ChainId, setPoolRebalanceRouteEvents]) => {
258
+ return setPoolRebalanceRouteEvents.some((e) => {
259
+ return (
260
+ e.blockNumber <= hubPoolBlock &&
261
+ compareAddressesSimple(e.l2Token, l2Token) &&
262
+ Number(_l2ChainId) === l2ChainId
263
+ );
264
+ });
265
+ });
266
+ });
267
+ }
268
+
268
269
  /**
269
270
  * @dev If tokenAddress + chain do not exist in TOKEN_SYMBOLS_MAP then this will throw.
270
271
  * @param tokenAddress Token address on `chain`
@@ -529,21 +530,23 @@ export class HubPoolClient extends BaseAbstractClient {
529
530
  chainIdB: number,
530
531
  hubPoolBlock = this.latestBlockSearched
531
532
  ): boolean {
532
- try {
533
- // Resolve both SpokePool tokens back to their respective HubPool tokens and verify that they match.
534
- const l1TokenA = this.getL1TokenForL2TokenAtBlock(tokenA, chainIdA, hubPoolBlock);
535
- const l1TokenB = this.getL1TokenForL2TokenAtBlock(tokenB, chainIdB, hubPoolBlock);
536
- if (l1TokenA !== l1TokenB) {
537
- return false;
538
- }
539
-
540
- // Resolve both HubPool tokens back to a current SpokePool token and verify that they match.
541
- const _tokenA = this.getL2TokenForL1TokenAtBlock(l1TokenA, chainIdA, hubPoolBlock);
542
- const _tokenB = this.getL2TokenForL1TokenAtBlock(l1TokenB, chainIdB, hubPoolBlock);
543
- return tokenA === _tokenA && tokenB === _tokenB;
544
- } catch {
545
- return false; // One or both input tokens were not recognised.
533
+ if (
534
+ !this.l2TokenHasPoolRebalanceRoute(tokenA, chainIdA, hubPoolBlock) ||
535
+ !this.l2TokenHasPoolRebalanceRoute(tokenB, chainIdB, hubPoolBlock)
536
+ ) {
537
+ return false;
546
538
  }
539
+ // Resolve both SpokePool tokens back to their respective HubPool tokens and verify that they match.
540
+ const l1TokenA = this.getL1TokenForL2TokenAtBlock(tokenA, chainIdA, hubPoolBlock);
541
+ const l1TokenB = this.getL1TokenForL2TokenAtBlock(tokenB, chainIdB, hubPoolBlock);
542
+ if (l1TokenA !== l1TokenB) {
543
+ return false;
544
+ }
545
+
546
+ // Resolve both HubPool tokens back to a current SpokePool token and verify that they match.
547
+ const _tokenA = this.getL2TokenForL1TokenAtBlock(l1TokenA, chainIdA, hubPoolBlock);
548
+ const _tokenB = this.getL2TokenForL1TokenAtBlock(l1TokenB, chainIdB, hubPoolBlock);
549
+ return tokenA === _tokenA && tokenB === _tokenB;
547
550
  }
548
551
 
549
552
  getSpokeActivationBlockForChain(chainId: number): number {
@@ -17,6 +17,7 @@ import {
17
17
  isZeroAddress,
18
18
  toAddress,
19
19
  validateFillForDeposit,
20
+ chainIsEvm,
20
21
  } from "../../utils";
21
22
  import {
22
23
  duplicateEvent,
@@ -41,7 +42,7 @@ import {
41
42
  } from "../../interfaces";
42
43
  import { BaseAbstractClient, UpdateFailureReason } from "../BaseAbstractClient";
43
44
  import { AcrossConfigStoreClient } from "../AcrossConfigStoreClient";
44
- import { getRepaymentChainId, forceDestinationRepayment } from "../BundleDataClient";
45
+ import { getRefundInformationFromFill } from "../BundleDataClient";
45
46
  import { HubPoolClient } from "../HubPoolClient";
46
47
 
47
48
  export type SpokePoolUpdateSuccess = {
@@ -365,22 +366,25 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
365
366
  fill: FillWithBlock
366
367
  ) => {
367
368
  if (validateFillForDeposit(fill, deposit).valid) {
368
- const repaymentChainId = getRepaymentChainId(fill, deposit);
369
- // In order to keep this function sync, we can't call verifyFillRepayment so we'll log any fills that
370
- // we'll have to overwrite repayment information for. This includes fills for lite chains where the
371
- // repayment address is invalid, and fills for non-lite chains where the repayment address is valid or
372
- // the repayment chain is invalid. We don't check that the origin chain is a valid EVM chain for
373
- // lite chain deposits yet because only EVM chains are supported on Across...for now. This means
374
- // this logic will have to be revisited when we add SVM to log properly.
369
+ const fillRepaymentData = {
370
+ ...fill,
371
+ fromLiteChain: deposit.fromLiteChain,
372
+ };
373
+ const { chainToSendRefundTo: repaymentChainId } = getRefundInformationFromFill(
374
+ fillRepaymentData,
375
+ this.hubPoolClient!,
376
+ this.hubPoolClient!.latestBlockSearched
377
+ );
378
+ // In order to keep this function sync, we can't call verifyFillRepayment so we'll log any fills where
379
+ // the filler-specified repayment chain and repayment address is not a valid repayment upon
380
+ // first glance. In other words, the repayment address is not a valid EVM address or the repayment chain
381
+ // is not a valid EVM chain. In the case where the repayment address is not a valid EVM address, the dataworker
382
+ // might be able to overwrite the repayment address to the msg.sender on the fill txn, but to keep this
383
+ // functioon synchronous, we can't make that decision now. So this function might log some false positives.
375
384
  if (
376
385
  this.hubPoolClient &&
377
386
  !isSlowFill(fill) &&
378
- (!isValidEvmAddress(fill.relayer) ||
379
- forceDestinationRepayment(
380
- repaymentChainId,
381
- { ...deposit, quoteBlockNumber: this.hubPoolClient!.latestBlockSearched },
382
- this.hubPoolClient
383
- ))
387
+ (!chainIsEvm(repaymentChainId) || !isValidEvmAddress(fill.relayer))
384
388
  ) {
385
389
  groupedFills.unrepayableFills.push(fill);
386
390
  }
@@ -450,6 +454,29 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
450
454
  return `${event.depositId.toString()}-${event.originChainId}`;
451
455
  }
452
456
 
457
+ protected canResolveZeroAddressOutputToken(deposit: DepositWithBlock): boolean {
458
+ if (
459
+ !this.hubPoolClient?.l2TokenHasPoolRebalanceRoute(
460
+ deposit.inputToken,
461
+ deposit.originChainId,
462
+ deposit.quoteBlockNumber
463
+ )
464
+ ) {
465
+ return false;
466
+ } else {
467
+ const l1Token = this.hubPoolClient?.getL1TokenForL2TokenAtBlock(
468
+ deposit.inputToken,
469
+ deposit.originChainId,
470
+ deposit.quoteBlockNumber
471
+ );
472
+ return this.hubPoolClient.l2TokenEnabledForL1TokenAtBlock(
473
+ l1Token,
474
+ deposit.destinationChainId,
475
+ deposit.quoteBlockNumber
476
+ );
477
+ }
478
+ }
479
+
453
480
  /**
454
481
  * A wrapper over the `_update` method that handles errors and logs. This method additionally calls into the
455
482
  * HubPoolClient to update the state of this client with data from the HubPool contract.
@@ -709,8 +736,19 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
709
736
  * @returns The destination token.
710
737
  */
711
738
  protected getDestinationTokenForDeposit(deposit: DepositWithBlock): string {
712
- // If there is no rate model client return address(0).
713
- return this.hubPoolClient?.getL2TokenForDeposit(deposit) ?? ZERO_ADDRESS;
739
+ if (!this.canResolveZeroAddressOutputToken(deposit)) {
740
+ return ZERO_ADDRESS;
741
+ }
742
+ // L1 token should be resolved if we get here:
743
+ const l1Token = this.hubPoolClient!.getL1TokenForL2TokenAtBlock(
744
+ deposit.inputToken,
745
+ deposit.originChainId,
746
+ deposit.quoteBlockNumber
747
+ )!;
748
+ return (
749
+ this.hubPoolClient!.getL2TokenForL1TokenAtBlock(l1Token, deposit.destinationChainId, deposit.quoteBlockNumber) ??
750
+ ZERO_ADDRESS
751
+ );
714
752
  }
715
753
 
716
754
  /**
@@ -100,6 +100,22 @@ export class MockHubPoolClient extends HubPoolClient {
100
100
  this.spokePoolTokens[l1Token][chainId] = l2Token;
101
101
  }
102
102
 
103
+ l2TokenEnabledForL1TokenAtBlock(l1Token: string, destinationChainId: number, hubBlockNumber: number): boolean {
104
+ if (this.spokePoolTokens[l1Token]?.[destinationChainId]) {
105
+ return true;
106
+ } else {
107
+ return super.l2TokenEnabledForL1TokenAtBlock(l1Token, destinationChainId, hubBlockNumber);
108
+ }
109
+ }
110
+ l2TokenHasPoolRebalanceRoute(l2Token: string, chainId: number, hubPoolBlock: number): boolean {
111
+ const l1Token = Object.keys(this.spokePoolTokens).find(
112
+ (l1Token) => this.spokePoolTokens[l1Token]?.[chainId] === l2Token
113
+ );
114
+ if (!l1Token) {
115
+ return super.l2TokenHasPoolRebalanceRoute(l2Token, chainId, hubPoolBlock);
116
+ } else return true;
117
+ }
118
+
103
119
  deleteTokenMapping(l1Token: string, chainId: number) {
104
120
  delete this.spokePoolTokens[l1Token]?.[chainId];
105
121
  }
@@ -1,6 +1,5 @@
1
1
  import { getDeployedAddress, SvmSpokeIdl } from "@across-protocol/contracts";
2
2
  import { getSolanaChainId } from "@across-protocol/contracts/dist/src/svm/web3-v1";
3
- import { BorshEventCoder, utils } from "@coral-xyz/anchor";
4
3
  import web3, {
5
4
  Address,
6
5
  Commitment,
@@ -9,8 +8,9 @@ import web3, {
9
8
  RpcTransport,
10
9
  Signature,
11
10
  } from "@solana/kit";
11
+ import { bs58 } from "../utils";
12
12
  import { EventData, EventName, EventWithData } from "./types";
13
- import { getEventName, parseEventData } from "./utils/events";
13
+ import { decodeEvent } from "./utils/events";
14
14
  import { isDevnet } from "./utils/helpers";
15
15
 
16
16
  // Utility type to extract the return type for the JSON encoding overload. We only care about the overload where the
@@ -185,17 +185,11 @@ export class SvmSpokeEventsClient {
185
185
  this.svmSpokeAddress === ixProgramId &&
186
186
  this.svmSpokeEventAuthority === singleIxAccount
187
187
  ) {
188
- const ixData = utils.bytes.bs58.decode(ix.data);
188
+ const ixData = bs58.decode(ix.data);
189
189
  // Skip the first 8 bytes (assumed header) and encode the rest.
190
- const eventData = utils.bytes.base64.encode(Buffer.from(new Uint8Array(ixData).slice(8)));
191
- const event = new BorshEventCoder(SvmSpokeIdl).decode(eventData);
192
- if (!event?.name) throw new Error("Event name is undefined");
193
- const name = getEventName(event.name);
194
- events.push({
195
- program: this.svmSpokeAddress,
196
- data: parseEventData(event?.data),
197
- name,
198
- });
190
+ const eventData = Buffer.from(ixData.slice(8)).toString("base64");
191
+ const { name, data } = decodeEvent(SvmSpokeIdl, eventData);
192
+ events.push({ program: this.svmSpokeAddress, name, data });
199
193
  }
200
194
  }
201
195
  }
package/src/svm/index.ts CHANGED
@@ -1 +1,3 @@
1
1
  export * from "./eventsClient";
2
+ export * from "./types";
3
+ export * as utils from "./utils";
@@ -1,6 +1,6 @@
1
- import { BN } from "@coral-xyz/anchor";
2
- import web3 from "@solana/kit";
3
- import { EventName, SVMEventNames } from "../types";
1
+ import { BN, BorshEventCoder, Idl } from "@coral-xyz/anchor";
2
+ import { address } from "@solana/kit";
3
+ import { EventName, EventData, SVMEventNames } from "../types";
4
4
 
5
5
  /**
6
6
  * Parses event data from a transaction.
@@ -15,7 +15,7 @@ export function parseEventData(eventData: any): any {
15
15
 
16
16
  if (typeof eventData === "object") {
17
17
  if (eventData.constructor.name === "PublicKey") {
18
- return web3.address(eventData.toString());
18
+ return address(eventData.toString());
19
19
  }
20
20
  if (BN.isBN(eventData)) {
21
21
  return BigInt(eventData.toString());
@@ -30,6 +30,18 @@ export function parseEventData(eventData: any): any {
30
30
  return eventData;
31
31
  }
32
32
 
33
+ /**
34
+ * Decodes a raw event according to a supplied IDL.
35
+ */
36
+ export function decodeEvent(idl: Idl, rawEvent: string): { data: EventData; name: EventName } {
37
+ const event = new BorshEventCoder(idl).decode(rawEvent);
38
+ if (!event) throw new Error(`Malformed rawEvent for IDL ${idl.address}: ${rawEvent}`);
39
+ return {
40
+ name: getEventName(event.name),
41
+ data: parseEventData(event.data),
42
+ };
43
+ }
44
+
33
45
  /**
34
46
  * Converts a snake_case string to camelCase.
35
47
  */
@@ -0,0 +1 @@
1
+ export * from "./events";
@@ -2,7 +2,7 @@ import assert from "assert";
2
2
  import { SpokePoolClient } from "../clients";
3
3
  import { DEFAULT_CACHING_TTL, EMPTY_MESSAGE, UNDEFINED_MESSAGE_HASH, ZERO_BYTES } from "../constants";
4
4
  import { CachingMechanismInterface, Deposit, DepositWithBlock, Fill, RelayData, SlowFillRequest } from "../interfaces";
5
- import { getMessageHash, isUnsafeDepositId } from "./SpokeUtils";
5
+ import { getMessageHash, isUnsafeDepositId, isZeroAddress } from "./SpokeUtils";
6
6
  import { getNetworkName } from "./NetworkUtils";
7
7
  import { bnZero } from "./BigNumberUtils";
8
8
  import { getDepositInCache, getDepositKey, setDepositInCache } from "./CachingUtils";
@@ -208,6 +208,11 @@ export function isZeroValueDeposit(deposit: Pick<Deposit, "inputAmount" | "messa
208
208
  return deposit.inputAmount.eq(0) && isMessageEmpty(deposit.message);
209
209
  }
210
210
 
211
+ export function invalidOutputToken(deposit: Pick<DepositWithBlock, "outputToken">): boolean {
212
+ // If the output token is zero address, then it is invalid.
213
+ return isZeroAddress(deposit.outputToken);
214
+ }
215
+
211
216
  export function isZeroValueFillOrSlowFillRequest(
212
217
  e: Pick<Fill | SlowFillRequest, "inputAmount" | "messageHash">
213
218
  ): boolean {
@@ -1,4 +1,5 @@
1
1
  import Decimal from "decimal.js";
2
+ import bs58 from "bs58";
2
3
  import { ethers } from "ethers";
3
4
  import { BigNumber, BigNumberish, BN, formatUnits, parseUnits, toBN } from "./BigNumberUtils";
4
5
  import { ConvertDecimals } from "./FormattingUtils";
@@ -8,6 +9,7 @@ export const AddressZero = ethers.constants.AddressZero;
8
9
  export const MAX_BIG_INT = BigNumber.from(Number.MAX_SAFE_INTEGER.toString());
9
10
 
10
11
  export const { keccak256 } = ethers.utils;
12
+ export { bs58 };
11
13
 
12
14
  /**
13
15
  * toBNWei.