@hyperbridge/sdk 2.3.1 → 2.3.3

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.
@@ -1204,9 +1204,9 @@ declare class EvmChain implements IChain {
1204
1204
  quoteNative(request: IPostRequest | IGetRequest, fee: bigint): Promise<bigint>;
1205
1205
  /**
1206
1206
  * Given a desired output amount of a token, returns how much native is needed as input.
1207
- * Uses the chain's Uniswap V2 router: WETH → tokenOut path.
1207
+ * Uses the chain's Uniswap V2 router (or `router` when provided): WETH → tokenOut path.
1208
1208
  */
1209
- getAmountsIn(amountOut: bigint, tokenOutForQuote: HexString, chain?: string): Promise<bigint>;
1209
+ getAmountsIn(amountOut: bigint, tokenOutForQuote: HexString, chain?: string, router?: HexString): Promise<bigint>;
1210
1210
  /**
1211
1211
  * Given an input amount of native token, returns how much of the output token you get.
1212
1212
  * Uses the chain's Uniswap V2 router: WETH → tokenOut path.
@@ -6825,15 +6825,20 @@ var EvmChain = class _EvmChain {
6825
6825
  async quoteNative(request, fee) {
6826
6826
  const totalFee = await this.quote(request) + fee;
6827
6827
  const feeToken = await this.getFeeTokenWithDecimals();
6828
- return this.getAmountsIn(totalFee, feeToken.address, request.source);
6828
+ const hostRouter = await this.publicClient.readContract({
6829
+ address: this.params.host,
6830
+ abi: evmHost_default.ABI,
6831
+ functionName: "uniswapV2Router"
6832
+ });
6833
+ return this.getAmountsIn(totalFee, feeToken.address, request.source, hostRouter);
6829
6834
  }
6830
6835
  /**
6831
6836
  * Given a desired output amount of a token, returns how much native is needed as input.
6832
- * Uses the chain's Uniswap V2 router: WETH → tokenOut path.
6837
+ * Uses the chain's Uniswap V2 router (or `router` when provided): WETH → tokenOut path.
6833
6838
  */
6834
- async getAmountsIn(amountOut, tokenOutForQuote, chain) {
6839
+ async getAmountsIn(amountOut, tokenOutForQuote, chain, router) {
6835
6840
  const chainId = chain ?? `EVM-${this.params.chainId}`;
6836
- const v2Router = this.configService.getUniswapRouterV2Address(chainId);
6841
+ const v2Router = router ?? this.configService.getUniswapRouterV2Address(chainId);
6837
6842
  const WETH = this.configService.getWrappedNativeAssetWithDecimals(chainId).asset;
6838
6843
  const v2AmountIn = await this.publicClient.simulateContract({
6839
6844
  address: v2Router,
@@ -7078,6 +7083,11 @@ var ExpectedError = class _ExpectedError extends Error {
7078
7083
  return error instanceof _ExpectedError;
7079
7084
  }
7080
7085
  };
7086
+
7087
+ // src/configs/constants.ts
7088
+ var ISMP_PREFIX = ":child_storage:default:ISMPv2";
7089
+
7090
+ // src/chains/substrate.ts
7081
7091
  var HttpRpcClient = class {
7082
7092
  constructor(url) {
7083
7093
  this.url = url;
@@ -7201,7 +7211,7 @@ var SubstrateChain = class _SubstrateChain {
7201
7211
  * @returns {Promise<HexString | undefined>} The commitment data if found, undefined otherwise.
7202
7212
  */
7203
7213
  async queryRequestCommitment(commitment) {
7204
- const prefix = toHex(":child_storage:default:ISMP");
7214
+ const prefix = toHex(ISMP_PREFIX);
7205
7215
  const key = this.requestCommitmentKey(commitment);
7206
7216
  const item = await this.rpcClient.call("childstate_getStorage", [prefix, key]);
7207
7217
  return item;
@@ -7212,7 +7222,7 @@ var SubstrateChain = class _SubstrateChain {
7212
7222
  * @returns {Promise<HexString | undefined>} The relayer address responsible for delivering the request.
7213
7223
  */
7214
7224
  async queryRequestReceipt(commitment) {
7215
- const prefix = toHex(":child_storage:default:ISMP");
7225
+ const prefix = toHex(ISMP_PREFIX);
7216
7226
  const key = this.requestReceiptKey(commitment);
7217
7227
  const item = await this.rpcClient.call("childstate_getStorage", [prefix, key]);
7218
7228
  return item;
@@ -7236,7 +7246,7 @@ var SubstrateChain = class _SubstrateChain {
7236
7246
  * @returns {Promise<HexString | undefined>} The receipt data if present, otherwise undefined.
7237
7247
  */
7238
7248
  async queryResponseReceipt(commitment) {
7239
- const prefix = toHex(":child_storage:default:ISMP");
7249
+ const prefix = toHex(ISMP_PREFIX);
7240
7250
  const key = this.responseReceiptKey(commitment);
7241
7251
  const item = await this.rpcClient.call("childstate_getStorage", [prefix, key]);
7242
7252
  return item;
@@ -15354,7 +15364,11 @@ var OrderExecutor = class {
15354
15364
  */
15355
15365
  async fetchBids(params) {
15356
15366
  const { commitment, solver, solverLockStartTime } = params;
15357
- const fetchedBids = await this.ctx.intentsCoprocessor.getBidsForOrder(commitment);
15367
+ const intentsCoprocessor = this.ctx.intentsCoprocessor;
15368
+ if (!intentsCoprocessor) {
15369
+ throw new Error("IntentsCoprocessor required for order execution");
15370
+ }
15371
+ const fetchedBids = await intentsCoprocessor.getBidsForOrder(commitment);
15358
15372
  if (solver) {
15359
15373
  const { address, timeoutMs } = solver;
15360
15374
  const solverLockActive = Date.now() - solverLockStartTime < timeoutMs;
@@ -15443,7 +15457,7 @@ var OrderExecutor = class {
15443
15457
  * → (`FILLED` | `PARTIAL_FILL`)* → (`FILLED` | `EXPIRED`)
15444
15458
  *
15445
15459
  * **Cross-chain:** `AWAITING_BIDS` → `BIDS_RECEIVED` → `BID_SELECTED`
15446
- * (terminates — settlement is confirmed async via Hyperbridge)
15460
+ * `FILLED`
15447
15461
  */
15448
15462
  async *executeOrder(options) {
15449
15463
  const { order, sessionPrivateKey, auctionTimeMs, pollIntervalMs = DEFAULT_POLL_INTERVAL, solver } = options;
@@ -15582,7 +15596,13 @@ var OrderExecutor = class {
15582
15596
  userOp: result.userOp,
15583
15597
  transactionHash: result.txnHash
15584
15598
  };
15585
- const fill = this.processFillResult(result, commitment, targetAssets, totalFilledAssets, remainingAssets);
15599
+ const fill = this.processFillResult(
15600
+ result,
15601
+ commitment,
15602
+ targetAssets,
15603
+ totalFilledAssets,
15604
+ remainingAssets
15605
+ );
15586
15606
  totalFilledAssets = fill.totalFilledAssets;
15587
15607
  remainingAssets = fill.remainingAssets;
15588
15608
  if (fill.update) {
@@ -15608,6 +15628,10 @@ var OrderCanceller = class {
15608
15628
  this.ctx = ctx;
15609
15629
  }
15610
15630
  ctx;
15631
+ logger = createConsola({
15632
+ level: LogLevels.info,
15633
+ formatOptions: { columns: 80, colors: true, compact: true, date: false }
15634
+ }).withTag("[OrderCanceller]");
15611
15635
  /**
15612
15636
  * Returns both the native token cost and the relayer fee for cancelling an
15613
15637
  * order. Frontends can use `relayerFee` to approve the ERC-20 spend before
@@ -16023,32 +16047,55 @@ var OrderCanceller = class {
16023
16047
  }
16024
16048
  /**
16025
16049
  * Submits an unsigned GET request message to Hyperbridge and waits until
16026
- * the request receipt is confirmed on-chain.
16050
+ * the GET response receipt is confirmed on-chain.
16027
16051
  *
16028
- * If the initial submission fails, the method waits 30 seconds and then
16029
- * retries querying for the receipt up to 10 times with 5-second back-off.
16052
+ * GET handling on Hyperbridge creates a response receipt keyed by the
16053
+ * request commitment. That receipt is the durable delivery signal, so a
16054
+ * duplicate unsigned submission is considered successful only if the
16055
+ * response receipt can be observed.
16030
16056
  *
16031
16057
  * @param hyperbridge - Hyperbridge Substrate chain client.
16032
16058
  * @param commitment - The GET request commitment hash used to poll for the receipt.
16033
16059
  * @param message - The fully constructed GET request message to submit.
16034
16060
  */
16035
16061
  async submitAndConfirmReceipt(hyperbridge, commitment, message) {
16036
- let storageValue = await hyperbridge.queryRequestReceipt(commitment);
16037
- if (!storageValue) {
16038
- try {
16039
- await hyperbridge.submitUnsigned(message);
16040
- } catch {
16041
- }
16062
+ this.logger.info(`Checking GET response receipt before Hyperbridge delivery (${commitment})`);
16063
+ if (await this.queryDeliveredReceipt(hyperbridge, commitment)) {
16064
+ this.logger.info(`GET ${commitment} already delivered to Hyperbridge; skipping unsigned submission`);
16065
+ return;
16066
+ }
16067
+ try {
16068
+ this.logger.info(`Submitting unsigned GET ${commitment} to Hyperbridge`);
16069
+ await hyperbridge.submitUnsigned(message);
16070
+ this.logger.info(`Unsigned GET ${commitment} submitted; waiting for Hyperbridge response receipt`);
16042
16071
  await sleep(3e4);
16043
- storageValue = await retryPromise(
16044
- async () => {
16045
- const value = await hyperbridge.queryRequestReceipt(commitment);
16046
- if (!value) throw new Error("Receipt not found");
16047
- return value;
16048
- },
16049
- { maxRetries: 10, backoffMs: 5e3, logMessage: "Checking for receipt" }
16072
+ } catch (error) {
16073
+ this.logger.warn(
16074
+ `Unsigned GET submit failed for ${commitment}; polling response receipt before failing: ${String(error)}`
16050
16075
  );
16051
16076
  }
16077
+ try {
16078
+ await this.pollDeliveredReceipt(hyperbridge, commitment);
16079
+ this.logger.info(`Confirmed Hyperbridge GET delivery for ${commitment}`);
16080
+ } catch (error) {
16081
+ const message2 = `Failed to deliver GET request to Hyperbridge; no response receipt found for ${commitment}: ${String(error)}`;
16082
+ this.logger.error(message2);
16083
+ throw new Error(message2);
16084
+ }
16085
+ }
16086
+ async queryDeliveredReceipt(hyperbridge, commitment) {
16087
+ return hyperbridge.queryResponseReceipt(commitment);
16088
+ }
16089
+ async pollDeliveredReceipt(hyperbridge, commitment) {
16090
+ this.logger.info(`Polling Hyperbridge GET response receipt for ${commitment}`);
16091
+ return retryPromise(
16092
+ async () => {
16093
+ const value = await this.queryDeliveredReceipt(hyperbridge, commitment);
16094
+ if (!value) throw new Error(`GET response receipt not found for ${commitment}`);
16095
+ return value;
16096
+ },
16097
+ { maxRetries: 10, backoffMs: 5e3, logMessage: `Checking GET response receipt ${commitment}` }
16098
+ );
16052
16099
  }
16053
16100
  /**
16054
16101
  * Estimates the relayer fee for delivering a POST from dest to source.
@@ -16119,7 +16166,7 @@ var BidImpl = class {
16119
16166
  const sessionKeyAddress = this.order.session;
16120
16167
  const sessionKeyData = this.sessionPrivateKey ? { privateKey: this.sessionPrivateKey } : await this.ctx.sessionKeyStorage.getSessionKeyByAddress(sessionKeyAddress);
16121
16168
  if (!sessionKeyData) {
16122
- throw new Error("SessionKey not found for commitment: " + commitment);
16169
+ throw new Error(`SessionKey not found for commitment: ${commitment}`);
16123
16170
  }
16124
16171
  const signature = await CryptoUtils.signSolverSelection(
16125
16172
  commitment,
@@ -16179,8 +16226,8 @@ var BidImpl = class {
16179
16226
  /**
16180
16227
  * Signs the `SelectSolver` message with the session key, appends it to the
16181
16228
  * solver's existing UserOp signature, and submits the UserOperation to the
16182
- * bundler. For same-chain orders, waits for the receipt and reads
16183
- * `OrderFilled` / `PartialFill` logs to determine fill status.
16229
+ * bundler. Waits for the receipt and reads `OrderFilled` / `PartialFill`
16230
+ * logs to determine fill status.
16184
16231
  *
16185
16232
  * @returns A {@link SelectBidResult} with the submitted UserOperation, its hash,
16186
16233
  * the solver address, transaction hash, and fill status.
@@ -16220,33 +16267,31 @@ var BidImpl = class {
16220
16267
  { maxRetries: 5, backoffMs: 2e3, logMessage: "Fetching user operation receipt" }
16221
16268
  );
16222
16269
  txnHash = receipt.receipt.transactionHash;
16223
- if (this.order.source === this.order.destination) {
16224
- try {
16225
- const chainReceipt = await this.ctx.dest.client.waitForTransactionReceipt({
16226
- hash: txnHash,
16227
- confirmations: 1
16228
- });
16229
- const events = parseEventLogs({
16230
- abi: ABI3,
16231
- logs: chainReceipt.logs,
16232
- eventName: ["OrderFilled", "PartialFill"]
16233
- });
16234
- const matched = events.find((e) => {
16235
- if (e.eventName === "OrderFilled")
16236
- return e.args.commitment.toLowerCase() === commitment.toLowerCase();
16237
- if (e.eventName === "PartialFill")
16238
- return e.args.commitment.toLowerCase() === commitment.toLowerCase();
16239
- return false;
16240
- });
16241
- if (matched?.eventName === "OrderFilled") {
16242
- fillStatus = "full";
16243
- } else if (matched?.eventName === "PartialFill") {
16244
- fillStatus = "partial";
16245
- filledAssets = matched.args.outputs ?? [];
16246
- }
16247
- } catch {
16248
- throw new Error("Failed to determine fill status from logs");
16270
+ try {
16271
+ const chainReceipt = await this.ctx.dest.client.waitForTransactionReceipt({
16272
+ hash: txnHash,
16273
+ confirmations: 1
16274
+ });
16275
+ const events = parseEventLogs({
16276
+ abi: ABI3,
16277
+ logs: chainReceipt.logs,
16278
+ eventName: ["OrderFilled", "PartialFill"]
16279
+ });
16280
+ const matched = events.find((e) => {
16281
+ if (e.eventName === "OrderFilled")
16282
+ return e.args.commitment.toLowerCase() === commitment.toLowerCase();
16283
+ if (e.eventName === "PartialFill")
16284
+ return e.args.commitment.toLowerCase() === commitment.toLowerCase();
16285
+ return false;
16286
+ });
16287
+ if (matched?.eventName === "OrderFilled") {
16288
+ fillStatus = "full";
16289
+ } else if (matched?.eventName === "PartialFill") {
16290
+ fillStatus = "partial";
16291
+ filledAssets = matched.args.outputs ?? [];
16249
16292
  }
16293
+ } catch {
16294
+ throw new Error("Failed to determine fill status from logs");
16250
16295
  }
16251
16296
  } catch (err) {
16252
16297
  throw new Error(`Failed to execute bid: ${err instanceof Error ? err.message : String(err)}`);
@@ -17048,9 +17093,9 @@ var GasEstimator = class {
17048
17093
  from: this.ctx.source.configService.getIntentGatewayAddress(destChainId),
17049
17094
  to: this.ctx.source.configService.getIntentGatewayAddress(sourceChainId)
17050
17095
  };
17096
+ postRequestFeeInDestFeeToken = postRequestFeeInDestFeeToken * 1005n / 1000n;
17051
17097
  let protocolFeeInNativeToken = await this.ctx.dest.quoteNative(postRequest, postRequestFeeInDestFeeToken).catch(() => 0n);
17052
17098
  protocolFeeInNativeToken = protocolFeeInNativeToken * 1005n / 1000n;
17053
- postRequestFeeInDestFeeToken = postRequestFeeInDestFeeToken * 1005n / 1000n;
17054
17099
  return { postRequestFee: postRequestFeeInDestFeeToken, protocolFee: protocolFeeInNativeToken };
17055
17100
  }
17056
17101
  /**