@hyperbridge/sdk 2.5.0 → 2.6.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.
@@ -910,6 +910,10 @@ interface ChainConfigData {
910
910
  USDT: string;
911
911
  cNGN?: string;
912
912
  EXT?: string;
913
+ ZARP?: string;
914
+ EURC?: string;
915
+ XSGD?: string;
916
+ TRYB?: string;
913
917
  };
914
918
  tokenDecimals?: {
915
919
  USDC: number;
@@ -1010,6 +1014,13 @@ declare class ChainConfigService {
1010
1014
  getUsdcDecimals(chain: string): number;
1011
1015
  getUsdtDecimals(chain: string): number;
1012
1016
  getCNgnAsset(chain: string): HexString | undefined;
1017
+ /**
1018
+ * Address of `symbol` on `chain` from the per-chain asset table, matched
1019
+ * case-insensitively ("cNGN" ≡ "CNGN"). This table is the single source of
1020
+ * truth for token addresses — the simplex asset registry resolves through
1021
+ * it, so a new asset is added once in `chain.ts` and nowhere else.
1022
+ */
1023
+ getAssetBySymbol(chain: string, symbol: string): HexString | undefined;
1013
1024
  getCNgnDecimals(chain: string): number | undefined;
1014
1025
  getExtAsset(chain: string): HexString | undefined;
1015
1026
  getExtDecimals(chain: string): number | undefined;
@@ -1725,7 +1736,10 @@ declare class SubstrateChain implements IChain {
1725
1736
  */
1726
1737
  latestStateMachineHeight(stateMachineId: StateMachineIdParams): Promise<bigint>;
1727
1738
  /**
1728
- * Get the state machine update time for a given state machine height.
1739
+ * Get the state machine update time for a given state machine height. Reads the
1740
+ * `BoundedStateMachineUpdateTime` map in pallet-ismp directly, so the height is either
1741
+ * still retained on-chain or it has been evicted — there's no intermediate RPC to
1742
+ * reinterpret the absence.
1729
1743
  * @param {StateMachineHeight} stateMachineHeight - The state machine height.
1730
1744
  * @returns {Promise<bigint>} The statemachine update time in seconds.
1731
1745
  */
@@ -3588,6 +3602,13 @@ interface FillOrderEstimate {
3588
3602
  maxPriorityFeePerGas: bigint;
3589
3603
  totalGasCostWei: bigint;
3590
3604
  totalGasInFeeToken: bigint;
3605
+ /**
3606
+ * Relayer fee for the cross-chain settlement message, denominated in the
3607
+ * SOURCE fee token (same unit as `Order.fees`). This is `RELAYER_MESSAGE_GAS`
3608
+ * priced on the source chain; it is 0 for same-chain fills. A filler's
3609
+ * `order.fees` must cover `totalGasInFeeToken + relayerFeeInSourceFeeToken`.
3610
+ */
3611
+ relayerFeeInSourceFeeToken: bigint;
3591
3612
  }
3592
3613
  /**
3593
3614
  * Result of submitting a bid to Hyperbridge
@@ -4967,10 +4988,12 @@ declare class IntentGateway {
4967
4988
  * placement, fee estimation, bid collection, and execution.
4968
4989
  *
4969
4990
  * **Yield/receive protocol:**
4970
- * 1. If `order.fees` is unset or zero, estimates gas on an internal copy and sets
4971
- * same-chain fees to twice the estimate. Cross-chain orders retain a 1% buffer
4972
- * and include an additional 600k-gas fee uplift, while the wei cost used for
4973
- * the `value` field receives a 2% buffer.
4991
+ * 1. If `order.fees` is unset or zero, estimates gas on an internal copy and
4992
+ * sets same-chain fees to twice the estimate. Cross-chain orders attach
4993
+ * (fill gas + a settlement-message uplift of `RELAYER_MESSAGE_GAS`, the
4994
+ * same gas budget the solver's relayer fee uses) with a 5% buffer over
4995
+ * the whole sum — strictly above the solver's unpadded requirement. The
4996
+ * wei cost used for the `value` field receives a 2% buffer.
4974
4997
  * 2. Yields `AWAITING_PLACE_ORDER` with `{ to, data, value, sessionPrivateKey }`.
4975
4998
  * The caller must sign the transaction and pass it back via `gen.next(signedTx)`.
4976
4999
  * 3. Yields `ORDER_PLACED` with the finalised order and transaction hash once
@@ -2728,7 +2728,11 @@ var chainConfigs = {
2728
2728
  DAI: "0x6b175474e89094c44da98b954eedeac495271d0f",
2729
2729
  USDC: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
2730
2730
  USDT: "0xdac17f958d2ee523a2206206994597c13d831ec7",
2731
- cNGN: "0x17CDB2a01e7a34CbB3DD4b83260B05d0274C8dab"
2731
+ cNGN: "0x17CDB2a01e7a34CbB3DD4b83260B05d0274C8dab",
2732
+ ZARP: "0xb755506531786C8aC63B756BaB1ac387bACB0C04",
2733
+ EURC: "0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
2734
+ XSGD: "0x70e8dE73cE538DA2bEEd35d14187F6959a8ecA96",
2735
+ TRYB: "0x2C537E5624e4af88A7ae4060C022609376C8D0EB"
2732
2736
  },
2733
2737
  tokenDecimals: {
2734
2738
  USDC: 6,
@@ -2898,7 +2902,9 @@ var chainConfigs = {
2898
2902
  USDC: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
2899
2903
  USDT: "0xfde4c96c8593536e31f229ea8f37b2ada2699bb2",
2900
2904
  EXT: "0x0e668E5127087e236578893a0e01E41837A28469",
2901
- cNGN: "0x46C85152bFe9f96829aA94755D9f915F9B10EF5F"
2905
+ cNGN: "0x46C85152bFe9f96829aA94755D9f915F9B10EF5F",
2906
+ ZARP: "0xb755506531786C8aC63B756BaB1ac387bACB0C04",
2907
+ EURC: "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
2902
2908
  },
2903
2909
  tokenDecimals: {
2904
2910
  USDC: 6,
@@ -2958,7 +2964,9 @@ var chainConfigs = {
2958
2964
  USDC: "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
2959
2965
  USDT: "0xc2132d05d31c914a87c6611c10748aeb04b58e8f",
2960
2966
  EXT: "0x7C8c11ADb8EF7cd3CFa718008Ea048445C6E7209",
2961
- cNGN: "0x52828daa48C1a9A06F37500882b42daf0bE04C3B"
2967
+ cNGN: "0x52828daa48C1a9A06F37500882b42daf0bE04C3B",
2968
+ ZARP: "0xb755506531786C8aC63B756BaB1ac387bACB0C04",
2969
+ XSGD: "0xDC3326e71D45186F113a2F448984CA0e8D201995"
2962
2970
  },
2963
2971
  tokenDecimals: {
2964
2972
  USDC: 6,
@@ -5195,6 +5203,21 @@ var ChainConfigService = class {
5195
5203
  getCNgnAsset(chain) {
5196
5204
  return this.getConfig(chain)?.assets?.cNGN;
5197
5205
  }
5206
+ /**
5207
+ * Address of `symbol` on `chain` from the per-chain asset table, matched
5208
+ * case-insensitively ("cNGN" ≡ "CNGN"). This table is the single source of
5209
+ * truth for token addresses — the simplex asset registry resolves through
5210
+ * it, so a new asset is added once in `chain.ts` and nowhere else.
5211
+ */
5212
+ getAssetBySymbol(chain, symbol) {
5213
+ const assets = this.getConfig(chain)?.assets;
5214
+ if (!assets) return void 0;
5215
+ const target = symbol.trim().toUpperCase();
5216
+ for (const [key, address] of Object.entries(assets)) {
5217
+ if (key.toUpperCase() === target) return address;
5218
+ }
5219
+ return void 0;
5220
+ }
5198
5221
  getCNgnDecimals(chain) {
5199
5222
  return this.getConfig(chain)?.tokenDecimals?.cNGN;
5200
5223
  }
@@ -7418,29 +7441,28 @@ var SubstrateChain = class _SubstrateChain {
7418
7441
  return BigInt(latestHeight);
7419
7442
  }
7420
7443
  /**
7421
- * Get the state machine update time for a given state machine height.
7444
+ * Get the state machine update time for a given state machine height. Reads the
7445
+ * `BoundedStateMachineUpdateTime` map in pallet-ismp directly, so the height is either
7446
+ * still retained on-chain or it has been evicted — there's no intermediate RPC to
7447
+ * reinterpret the absence.
7422
7448
  * @param {StateMachineHeight} stateMachineHeight - The state machine height.
7423
7449
  * @returns {Promise<bigint>} The statemachine update time in seconds.
7424
7450
  */
7425
7451
  async stateMachineUpdateTime(stateMachineHeight) {
7426
- const state_id = convertStateIdToStateMachineId(stateMachineHeight.id.stateId);
7427
- const stateMachineId = {
7428
- state_id,
7429
- consensus_state_id: stateMachineHeight.id.consensusStateId
7430
- };
7431
- const payload = {
7432
- id: stateMachineId,
7433
- height: Number(stateMachineHeight.height)
7452
+ if (!this.api) throw new Error("API not initialized");
7453
+ const id = {
7454
+ stateId: stateMachineHeight.id.stateId,
7455
+ // on-chain StateMachineId encodes consensusStateId as [u8; 4]
7456
+ consensusStateId: toHex(toBytes(stateMachineHeight.id.consensusStateId))
7434
7457
  };
7435
- try {
7436
- const updateTime = await this.rpcClient.call("ismp_queryStateMachineUpdateTime", [payload]);
7437
- return BigInt(updateTime);
7438
- } catch (error) {
7439
- if (MissingConsensusUpdateTimeError.isError(error)) {
7440
- throw new MissingConsensusUpdateTimeError(MISSING_CONSENSUS_UPDATE_TIME_MESSAGE, { cause: error });
7441
- }
7442
- throw error;
7458
+ const updateTime = await this.api.query.ismp.boundedStateMachineUpdateTime(
7459
+ id,
7460
+ Number(stateMachineHeight.height)
7461
+ );
7462
+ if (updateTime.isNone) {
7463
+ throw new MissingConsensusUpdateTimeError(MISSING_CONSENSUS_UPDATE_TIME_MESSAGE);
7443
7464
  }
7465
+ return BigInt(updateTime.unwrap().toString());
7444
7466
  }
7445
7467
  /**
7446
7468
  * Get the challenge period for a given state machine id.
@@ -17301,6 +17323,7 @@ var BidManager = class {
17301
17323
  }
17302
17324
  }
17303
17325
  };
17326
+ var RELAYER_MESSAGE_GAS = 1000000n;
17304
17327
  var GasEstimator = class {
17305
17328
  /**
17306
17329
  * @param ctx - Shared IntentsV2 context providing the source and destination
@@ -17321,7 +17344,12 @@ var GasEstimator = class {
17321
17344
  *
17322
17345
  * **Cross-chain orders:** also estimates the ISMP POST request fee required
17323
17346
  * for the solver to trigger source-chain escrow redemption after filling, and
17324
- * includes it in `fillOptions.relayerFee` and `fillOptions.nativeDispatchFee`.
17347
+ * includes it in `fillOptions.relayerFee`. The dispatch is always paid in the
17348
+ * fee token — `nativeDispatchFee` is fixed at 0. The native rail would draw
17349
+ * from the solver account's native balance, which nothing guarantees, and a
17350
+ * shortfall is invisible to estimation (the account balance is overridden
17351
+ * during simulation) — it would only surface as a reverted execution that
17352
+ * still bills the paymaster.
17325
17353
  *
17326
17354
  * **Bundler path:** constructs a mock `PackedUserOperation` signed by an
17327
17355
  * ephemeral keypair, applies state overrides, and calls
@@ -17370,24 +17398,19 @@ var GasEstimator = class {
17370
17398
  intentGatewayV2Address,
17371
17399
  entryPointAddress
17372
17400
  }),
17373
- isSameChain ? Promise.resolve({ postRequestFee: 0n, protocolFee: 0n }) : this.estimateCrossChainFees(
17374
- sourceFeeToken,
17375
- destFeeToken,
17376
- souceStateMachineId,
17377
- destStateMachineId,
17378
- order
17379
- )
17401
+ isSameChain ? Promise.resolve({ postRequestFee: 0n, relayerFeeInSourceFeeToken: 0n }) : this.estimateCrossChainFees(sourceFeeToken, destFeeToken, souceStateMachineId)
17380
17402
  ]);
17381
17403
  const { viem: stateOverrides, bundler: bundlerStateOverrides } = stateOverridesResult;
17382
17404
  const fillOptions = {
17383
17405
  relayerFee: crossChainFees.postRequestFee,
17384
- nativeDispatchFee: crossChainFees.protocolFee,
17406
+ // Always dispatch with the fee token (see the method docs).
17407
+ nativeDispatchFee: 0n,
17385
17408
  outputs: order.output.assets.map((asset) => ({
17386
17409
  ...asset,
17387
17410
  token: normalizeAddressForEvmBytes32(asset.token)
17388
17411
  }))
17389
17412
  };
17390
- const totalNativeValue = totalEthValue + fillOptions.nativeDispatchFee;
17413
+ const totalNativeValue = totalEthValue;
17391
17414
  const priorityFeeBumpPercent = params.maxPriorityFeePerGasBumpPercent ?? 8;
17392
17415
  const maxFeeBumpPercent = params.maxFeePerGasBumpPercent ?? 10;
17393
17416
  let maxPriorityFeePerGas = gasPrice + gasPrice * BigInt(priorityFeeBumpPercent) / 100n;
@@ -17554,37 +17577,32 @@ var GasEstimator = class {
17554
17577
  maxPriorityFeePerGas,
17555
17578
  totalGasCostWei,
17556
17579
  totalGasInFeeToken: totalGasInSourceFeeToken,
17580
+ relayerFeeInSourceFeeToken: crossChainFees.relayerFeeInSourceFeeToken,
17557
17581
  fillOptions
17558
17582
  };
17559
17583
  }
17560
17584
  /**
17561
- * Estimates cross-chain ISMP POST request fees by running the gas-to-fee-token
17562
- * conversion and host nonce fetch in parallel, then quoting the native dispatch cost.
17563
- */
17564
- async estimateCrossChainFees(sourceFeeToken, destFeeToken, sourceChainId, destChainId, order) {
17565
- const postRequestGas = 400000n;
17566
- const [postRequestFeeInSourceFeeToken, nonce] = await Promise.all([
17567
- convertGasToFeeToken(this.ctx, postRequestGas, "source", sourceChainId),
17568
- this.ctx.dest.getHostNonce()
17569
- ]);
17570
- let postRequestFeeInDestFeeToken = adjustDecimals(
17585
+ * Estimates the cross-chain ISMP POST request fee (the relayer fee for the
17586
+ * RedeemEscrow message), in both the source and destination fee tokens.
17587
+ * The dispatch is always paid in the fee token — the native rail was
17588
+ * removed because it silently drew on a native balance nothing guarantees.
17589
+ */
17590
+ async estimateCrossChainFees(sourceFeeToken, destFeeToken, sourceChainId) {
17591
+ const postRequestFeeInSourceFeeToken = await convertGasToFeeToken(
17592
+ this.ctx,
17593
+ RELAYER_MESSAGE_GAS,
17594
+ "source",
17595
+ sourceChainId
17596
+ );
17597
+ const postRequestFeeInDestFeeToken = adjustDecimals(
17571
17598
  postRequestFeeInSourceFeeToken,
17572
17599
  sourceFeeToken.decimals,
17573
17600
  destFeeToken.decimals
17574
17601
  );
17575
- const postRequest = {
17576
- source: destChainId,
17577
- dest: sourceChainId,
17578
- body: constructRedeemEscrowRequestBody({ ...order, id: orderCommitment(order) }, MOCK_ADDRESS),
17579
- timeoutTimestamp: 0n,
17580
- nonce,
17581
- from: this.ctx.source.configService.getIntentGatewayAddress(destChainId),
17582
- to: this.ctx.source.configService.getIntentGatewayAddress(sourceChainId)
17602
+ return {
17603
+ postRequestFee: postRequestFeeInDestFeeToken,
17604
+ relayerFeeInSourceFeeToken: postRequestFeeInSourceFeeToken
17583
17605
  };
17584
- postRequestFeeInDestFeeToken = postRequestFeeInDestFeeToken * 1005n / 1000n;
17585
- let protocolFeeInNativeToken = await this.ctx.dest.quoteNative(postRequest, postRequestFeeInDestFeeToken).catch(() => 0n);
17586
- protocolFeeInNativeToken = protocolFeeInNativeToken * 1005n / 1000n;
17587
- return { postRequestFee: postRequestFeeInDestFeeToken, protocolFee: protocolFeeInNativeToken };
17588
17606
  }
17589
17607
  /**
17590
17608
  * Builds EVM state override objects for gas estimation of the `fillOrder`
@@ -18344,7 +18362,6 @@ function isConfiguredAddress(address) {
18344
18362
  }
18345
18363
 
18346
18364
  // src/protocols/intents/IntentGateway.ts
18347
- var CROSS_CHAIN_ORDER_FEE_GAS_BUMP = 600000n;
18348
18365
  var IntentGateway = class _IntentGateway {
18349
18366
  /** EVM chain on which orders are placed and escrowed. */
18350
18367
  source;
@@ -18531,10 +18548,12 @@ var IntentGateway = class _IntentGateway {
18531
18548
  * placement, fee estimation, bid collection, and execution.
18532
18549
  *
18533
18550
  * **Yield/receive protocol:**
18534
- * 1. If `order.fees` is unset or zero, estimates gas on an internal copy and sets
18535
- * same-chain fees to twice the estimate. Cross-chain orders retain a 1% buffer
18536
- * and include an additional 600k-gas fee uplift, while the wei cost used for
18537
- * the `value` field receives a 2% buffer.
18551
+ * 1. If `order.fees` is unset or zero, estimates gas on an internal copy and
18552
+ * sets same-chain fees to twice the estimate. Cross-chain orders attach
18553
+ * (fill gas + a settlement-message uplift of `RELAYER_MESSAGE_GAS`, the
18554
+ * same gas budget the solver's relayer fee uses) with a 5% buffer over
18555
+ * the whole sum — strictly above the solver's unpadded requirement. The
18556
+ * wei cost used for the `value` field receives a 2% buffer.
18538
18557
  * 2. Yields `AWAITING_PLACE_ORDER` with `{ to, data, value, sessionPrivateKey }`.
18539
18558
  * The caller must sign the transaction and pass it back via `gen.next(signedTx)`.
18540
18559
  * 3. Yields `ORDER_PLACED` with the finalised order and transaction hash once
@@ -18571,11 +18590,11 @@ var IntentGateway = class _IntentGateway {
18571
18590
  value = estimate.totalGasCostWei + estimate.totalGasCostWei * 2n / 100n;
18572
18591
  const crossChainFeeBump = isSameChain ? 0n : await convertGasToFeeToken(
18573
18592
  this.ctx,
18574
- CROSS_CHAIN_ORDER_FEE_GAS_BUMP,
18593
+ RELAYER_MESSAGE_GAS,
18575
18594
  "source",
18576
18595
  this.source.config.stateMachineId
18577
18596
  );
18578
- executionOrder.fees = isSameChain ? estimate.totalGasInFeeToken * 2n : estimate.totalGasInFeeToken + (crossChainFeeBump + estimate.totalGasInFeeToken * 1n / 100n);
18597
+ executionOrder.fees = isSameChain ? estimate.totalGasInFeeToken * 2n : (estimate.totalGasInFeeToken + crossChainFeeBump) * 105n / 100n;
18579
18598
  }
18580
18599
  const placeOrderGen = this.orderPlacer.placeOrder(executionOrder, graffiti);
18581
18600
  const placeOrderFirst = await placeOrderGen.next();