@hyperbridge/sdk 2.8.12 → 2.8.16

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.
@@ -1,14 +1,14 @@
1
1
  import { createConsola, LogLevels } from 'consola';
2
- import { defineChain, keccak256, toHex, createPublicClient, http, hexToBytes, toFunctionSelector, bytesToHex, encodeFunctionData, erc20Abi, bytesToBigInt, pad, toBytes, numberToBytes, decodeAbiParameters, getAddress, encodeAbiParameters, isHex, isAddress, maxUint256, parseAbiParameters, encodePacked, parseAbiItem, concat, decodeFunctionData, hexToString as hexToString$1, decodeEventLog, parseEventLogs, parseUnits, concatHex, zeroAddress, decodeFunctionResult, formatUnits } from 'viem';
2
+ import { defineChain, keccak256, toHex, parseAbi, createPublicClient, http, hexToBytes, toFunctionSelector, bytesToHex, encodeFunctionData, erc20Abi, bytesToBigInt, pad, toBytes, numberToBytes, getAddress, encodeAbiParameters, isHex, isAddress, maxUint256, parseAbiParameters, encodePacked, parseAbiItem, concat, decodeFunctionData, decodeAbiParameters, hexToString as hexToString$1, decodeEventLog, parseEventLogs, parseUnits, concatHex, formatUnits, toEventSelector } from 'viem';
3
3
  import { baseSepolia, optimismSepolia, arbitrumSepolia, soneium, gnosis, optimism, polygonAmoy, polygon, base, arbitrum, bsc, mainnet, sepolia, gnosisChiado, bscTestnet, tron, unichain } from 'viem/chains';
4
- import { TronWeb } from 'tronweb';
4
+ import { base58Decode, keccakAsU8a, decodeAddress, keccakAsHex, xxhashAsU8a, blake2AsU8a } from '@polkadot/util-crypto';
5
5
  import { flatten, zip, capitalize, maxBy, isNil } from 'lodash-es';
6
6
  import { match } from 'ts-pattern';
7
7
  import { WsProvider, ApiPromise, Keyring, HttpProvider } from '@polkadot/api';
8
8
  import { Struct, Vector, u8, Bytes, Enum, Tuple, _void, u64, u32, Option, bool, u128 } from 'scale-ts';
9
- import { xxhashAsU8a, keccakAsU8a, decodeAddress, keccakAsHex, blake2AsU8a } from '@polkadot/util-crypto';
10
- import { u8aToHex, u8aConcat, hexToU8a, stringToU8a, isHex as isHex$1, u8aToString } from '@polkadot/util';
9
+ import { hexToU8a, u8aToHex, u8aConcat, isHex as isHex$1 } from '@polkadot/util';
11
10
  import PQueue from 'p-queue';
11
+ import { TronWeb } from 'tronweb';
12
12
  import { hasWindow, isNode, env } from 'std-env';
13
13
  import mergeRace from '@async-generator/merge-race';
14
14
  import { GraphQLClient } from 'graphql-request';
@@ -319,6 +319,7 @@ var OrderStatus = /* @__PURE__ */ ((OrderStatus2) => {
319
319
  OrderStatus2["FILLED"] = "FILLED";
320
320
  OrderStatus2["REDEEMED"] = "REDEEMED";
321
321
  OrderStatus2["REFUNDED"] = "REFUNDED";
322
+ OrderStatus2["CANCELLED"] = "CANCELLED";
322
323
  return OrderStatus2;
323
324
  })(OrderStatus || {});
324
325
  var TeleportStatus = /* @__PURE__ */ ((TeleportStatus2) => {
@@ -333,6 +334,8 @@ var RequestKind = /* @__PURE__ */ ((RequestKind2) => {
333
334
  RequestKind2[RequestKind2["UpdateParams"] = 2] = "UpdateParams";
334
335
  RequestKind2[RequestKind2["SweepDust"] = 3] = "SweepDust";
335
336
  RequestKind2[RequestKind2["RefundEscrow"] = 4] = "RefundEscrow";
337
+ RequestKind2[RequestKind2["Execute"] = 5] = "Execute";
338
+ RequestKind2[RequestKind2["RedeemEscrowPartial"] = 6] = "RedeemEscrowPartial";
336
339
  return RequestKind2;
337
340
  })(RequestKind || {});
338
341
  var IntentOrderStatus = Object.freeze({
@@ -345,6 +348,7 @@ var IntentOrderStatus = Object.freeze({
345
348
  BID_SELECTED: "BID_SELECTED",
346
349
  FILLED: "FILLED",
347
350
  PARTIAL_FILL: "PARTIAL_FILL",
351
+ CANCELLED: "CANCELLED",
348
352
  EXPIRED: "EXPIRED",
349
353
  FAILED: "FAILED"
350
354
  });
@@ -2527,7 +2531,12 @@ var ABI2 = [
2527
2531
  ];
2528
2532
  var handlerV2_default = { ABI: ABI2 };
2529
2533
  function tronAddress(base58) {
2530
- return `0x${TronWeb.address.toHex(base58).slice(2)}`;
2534
+ const decoded = base58Decode(base58);
2535
+ if (decoded.length !== 25 || decoded[0] !== 65) {
2536
+ throw new Error(`Not a Tron base58 address: ${base58}`);
2537
+ }
2538
+ const hex = Array.from(decoded.slice(1, 21), (byte) => byte.toString(16).padStart(2, "0")).join("");
2539
+ return `0x${hex}`;
2531
2540
  }
2532
2541
  var Chains = /* @__PURE__ */ ((Chains2) => {
2533
2542
  Chains2["BSC_CHAPEL"] = "EVM-97";
@@ -2614,11 +2623,13 @@ var chainConfigs = {
2614
2623
  WETH: "0xae13d989dac2f0debff460ac112a837c89baa7cd",
2615
2624
  DAI: "0x1938165569a5463327fb206be06d8d9253aa06b7",
2616
2625
  USDC: "0xA801da100bF16D07F668F4A49E1f71fc54D05177",
2617
- USDT: "0xc043f483373072f7f27420d6e7d7ad269c018e18"
2626
+ USDT: "0xc043f483373072f7f27420d6e7d7ad269c018e18",
2627
+ cNGN: "0x2bbbd701cfc25d37f18127e51df0933566d5778a"
2618
2628
  },
2619
2629
  tokenDecimals: {
2620
2630
  USDC: 18,
2621
- USDT: 18
2631
+ USDT: 18,
2632
+ cNGN: 6
2622
2633
  },
2623
2634
  tokenStorageSlots: {
2624
2635
  USDC: { balanceSlot: 1, allowanceSlot: 2 },
@@ -2635,7 +2646,7 @@ var chainConfigs = {
2635
2646
  UniswapV3Quoter: "0x0000000000000000000000000000000000000000",
2636
2647
  UniswapV4Quoter: "0x0000000000000000000000000000000000000000",
2637
2648
  EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
2638
- SolverAccount: "0x110C7E1814c923127469Ca8939a12dAa70B96a17"
2649
+ SolverAccount: "0x153DB990FE3b761B54ad71D0f1A0987dF11740DB"
2639
2650
  },
2640
2651
  rpcEnvKey: "BSC_CHAPEL",
2641
2652
  defaultRpcUrl: "https://bnb-testnet.api.onfinality.io/public",
@@ -2761,7 +2772,7 @@ var chainConfigs = {
2761
2772
  },
2762
2773
  addresses: {
2763
2774
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
2764
- SolverAccount: "0x7cb55539d1144F62422099c3FA3405092022c88C",
2775
+ SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
2765
2776
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
2766
2777
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
2767
2778
  UniswapRouter02: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
@@ -2828,7 +2839,7 @@ var chainConfigs = {
2828
2839
  },
2829
2840
  addresses: {
2830
2841
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
2831
- SolverAccount: "0x7cb55539d1144F62422099c3FA3405092022c88C",
2842
+ SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
2832
2843
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
2833
2844
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
2834
2845
  UniswapRouter02: "0x10ED43C718714eb63d5aA57B78B54704E256024E",
@@ -2889,7 +2900,7 @@ var chainConfigs = {
2889
2900
  },
2890
2901
  addresses: {
2891
2902
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
2892
- SolverAccount: "0x7cb55539d1144F62422099c3FA3405092022c88C",
2903
+ SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
2893
2904
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
2894
2905
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
2895
2906
  UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
@@ -2963,7 +2974,7 @@ var chainConfigs = {
2963
2974
  },
2964
2975
  addresses: {
2965
2976
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
2966
- SolverAccount: "0x7cb55539d1144F62422099c3FA3405092022c88C",
2977
+ SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
2967
2978
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
2968
2979
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
2969
2980
  UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
@@ -2988,7 +2999,6 @@ var chainConfigs = {
2988
2999
  consensusStateId: "ETH0",
2989
3000
  coingeckoId: "base",
2990
3001
  layerZeroEid: 30184,
2991
- uniswapV4Pools: [{ tokens: ["USDC", "cNGN"], fee: 1500, tickSpacing: 30 }],
2992
3002
  erc4626Vaults: [
2993
3003
  { label: "Aave stataUSDC", address: "0xC768c589647798a6EE01A91FdE98EF2ed046DBD6", asset: "USDC" },
2994
3004
  { label: "Yield Bearing cNGN", address: "0xa82A3531021317240Fb32E67f9c7bC091F737D3b", asset: "cNGN" }
@@ -3038,7 +3048,7 @@ var chainConfigs = {
3038
3048
  },
3039
3049
  addresses: {
3040
3050
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
3041
- SolverAccount: "0x7cb55539d1144F62422099c3FA3405092022c88C",
3051
+ SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
3042
3052
  TokenGateway: "0x8b536105b6Fae2aE9199f5146D3C57Dfe53b614E",
3043
3053
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
3044
3054
  UniswapRouter02: "0xd2f9496824951D5237cC71245D659E48d0d5f9E8",
@@ -3113,11 +3123,13 @@ var chainConfigs = {
3113
3123
  //wmatic, change it to wpol
3114
3124
  DAI: "0x0000000000000000000000000000000000000000",
3115
3125
  USDC: "0xBE97E73126D66188d72fbF99029126D0340a7f18",
3116
- USDT: "0x0000000000000000000000000000000000000000"
3126
+ USDT: "0x0000000000000000000000000000000000000000",
3127
+ cNGN: "0xe4ff5d2ae65c10f530c000215029919961e8a758"
3117
3128
  },
3118
3129
  tokenDecimals: {
3119
3130
  USDC: 18,
3120
- USDT: 18
3131
+ USDT: 18,
3132
+ cNGN: 6
3121
3133
  },
3122
3134
  tokenStorageSlots: {
3123
3135
  USDT: { balanceSlot: 0, allowanceSlot: 1 },
@@ -3130,7 +3142,7 @@ var chainConfigs = {
3130
3142
  Calldispatcher: "0x876F1891982E260026630c233A4897160A281Fb8",
3131
3143
  Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
3132
3144
  EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
3133
- SolverAccount: "0x110C7E1814c923127469Ca8939a12dAa70B96a17"
3145
+ SolverAccount: "0x153DB990FE3b761B54ad71D0f1A0987dF11740DB"
3134
3146
  },
3135
3147
  rpcEnvKey: "POLYGON_AMOY",
3136
3148
  defaultRpcUrl: "https://rpc-amoy.polygon.technology",
@@ -3154,7 +3166,7 @@ var chainConfigs = {
3154
3166
  },
3155
3167
  addresses: {
3156
3168
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
3157
- SolverAccount: "0x7cb55539d1144F62422099c3FA3405092022c88C",
3169
+ SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
3158
3170
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
3159
3171
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
3160
3172
  UniswapRouter02: "0x4A7b5Da61326A6379179b40d00F57E5bbDC962c2",
@@ -3189,7 +3201,7 @@ var chainConfigs = {
3189
3201
  },
3190
3202
  addresses: {
3191
3203
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
3192
- SolverAccount: "0x7cb55539d1144F62422099c3FA3405092022c88C",
3204
+ SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
3193
3205
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
3194
3206
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
3195
3207
  UniswapRouter02: "0xB2e26652e4BAd1e56055A051f922E06760cA0BFE",
@@ -3345,7 +3357,7 @@ var chainConfigs = {
3345
3357
  },
3346
3358
  addresses: {
3347
3359
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
3348
- SolverAccount: "0x7cb55539d1144F62422099c3FA3405092022c88C",
3360
+ SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
3349
3361
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
3350
3362
  Calldispatcher: "0xE2C7e576E26E0bE7aC97c6fE925bcDAbD87c4bEd"
3351
3363
  },
@@ -3392,7 +3404,12 @@ var ABI3 = [
3392
3404
  type: "constructor",
3393
3405
  inputs: [
3394
3406
  {
3395
- name: "owner",
3407
+ name: "intrinsic",
3408
+ type: "address",
3409
+ internalType: "address"
3410
+ },
3411
+ {
3412
+ name: "extrinsic",
3396
3413
  type: "address",
3397
3414
  internalType: "address"
3398
3415
  }
@@ -3491,8 +3508,8 @@ var ABI3 = [
3491
3508
  },
3492
3509
  {
3493
3510
  name: "",
3494
- type: "address",
3495
- internalType: "address"
3511
+ type: "uint256",
3512
+ internalType: "uint256"
3496
3513
  }
3497
3514
  ],
3498
3515
  outputs: [
@@ -3506,20 +3523,31 @@ var ABI3 = [
3506
3523
  },
3507
3524
  {
3508
3525
  type: "function",
3509
- name: "_owner",
3510
- inputs: [],
3526
+ name: "_partialFills",
3527
+ inputs: [
3528
+ {
3529
+ name: "",
3530
+ type: "bytes32",
3531
+ internalType: "bytes32"
3532
+ },
3533
+ {
3534
+ name: "",
3535
+ type: "uint256",
3536
+ internalType: "uint256"
3537
+ }
3538
+ ],
3511
3539
  outputs: [
3512
3540
  {
3513
3541
  name: "",
3514
- type: "address",
3515
- internalType: "address"
3542
+ type: "uint256",
3543
+ internalType: "uint256"
3516
3544
  }
3517
3545
  ],
3518
3546
  stateMutability: "view"
3519
3547
  },
3520
3548
  {
3521
3549
  type: "function",
3522
- name: "_partialFills",
3550
+ name: "_protocolFees",
3523
3551
  inputs: [
3524
3552
  {
3525
3553
  name: "",
@@ -3528,19 +3556,31 @@ var ABI3 = [
3528
3556
  },
3529
3557
  {
3530
3558
  name: "",
3531
- type: "bytes32",
3532
- internalType: "bytes32"
3559
+ type: "uint256",
3560
+ internalType: "uint256"
3533
3561
  }
3534
3562
  ],
3535
3563
  outputs: [
3536
3564
  {
3537
- name: "",
3565
+ name: "amount",
3566
+ type: "uint256",
3567
+ internalType: "uint256"
3568
+ },
3569
+ {
3570
+ name: "committed",
3538
3571
  type: "uint256",
3539
3572
  internalType: "uint256"
3540
3573
  }
3541
3574
  ],
3542
3575
  stateMutability: "view"
3543
3576
  },
3577
+ {
3578
+ type: "function",
3579
+ name: "acceptOwnership",
3580
+ inputs: [],
3581
+ outputs: [],
3582
+ stateMutability: "nonpayable"
3583
+ },
3544
3584
  {
3545
3585
  type: "function",
3546
3586
  name: "calculateCommitmentSlotHash",
@@ -3750,6 +3790,19 @@ var ABI3 = [
3750
3790
  ],
3751
3791
  stateMutability: "view"
3752
3792
  },
3793
+ {
3794
+ type: "function",
3795
+ name: "extrinsicModule",
3796
+ inputs: [],
3797
+ outputs: [
3798
+ {
3799
+ name: "",
3800
+ type: "address",
3801
+ internalType: "address"
3802
+ }
3803
+ ],
3804
+ stateMutability: "view"
3805
+ },
3753
3806
  {
3754
3807
  type: "function",
3755
3808
  name: "fillOrder",
@@ -3912,6 +3965,23 @@ var ABI3 = [
3912
3965
  internalType: "uint256"
3913
3966
  }
3914
3967
  ]
3968
+ },
3969
+ {
3970
+ name: "inputs",
3971
+ type: "tuple[]",
3972
+ internalType: "struct TokenInfo[]",
3973
+ components: [
3974
+ {
3975
+ name: "token",
3976
+ type: "bytes32",
3977
+ internalType: "bytes32"
3978
+ },
3979
+ {
3980
+ name: "amount",
3981
+ type: "uint256",
3982
+ internalType: "uint256"
3983
+ }
3984
+ ]
3915
3985
  }
3916
3986
  ]
3917
3987
  }
@@ -3937,51 +4007,63 @@ var ABI3 = [
3937
4007
  name: "initialize",
3938
4008
  inputs: [
3939
4009
  {
3940
- name: "p",
4010
+ name: "init",
3941
4011
  type: "tuple",
3942
- internalType: "struct Params",
4012
+ internalType: "struct InitParams",
3943
4013
  components: [
3944
4014
  {
3945
- name: "host",
3946
- type: "address",
3947
- internalType: "address"
3948
- },
3949
- {
3950
- name: "dispatcher",
3951
- type: "address",
3952
- internalType: "address"
3953
- },
3954
- {
3955
- name: "solverSelection",
3956
- type: "bool",
3957
- internalType: "bool"
4015
+ name: "params",
4016
+ type: "tuple",
4017
+ internalType: "struct Params",
4018
+ components: [
4019
+ {
4020
+ name: "host",
4021
+ type: "address",
4022
+ internalType: "address"
4023
+ },
4024
+ {
4025
+ name: "dispatcher",
4026
+ type: "address",
4027
+ internalType: "address"
4028
+ },
4029
+ {
4030
+ name: "solverSelection",
4031
+ type: "bool",
4032
+ internalType: "bool"
4033
+ },
4034
+ {
4035
+ name: "surplusShareBps",
4036
+ type: "uint256",
4037
+ internalType: "uint256"
4038
+ },
4039
+ {
4040
+ name: "protocolFeeBps",
4041
+ type: "uint256",
4042
+ internalType: "uint256"
4043
+ },
4044
+ {
4045
+ name: "priceOracle",
4046
+ type: "address",
4047
+ internalType: "address"
4048
+ }
4049
+ ]
3958
4050
  },
3959
4051
  {
3960
- name: "surplusShareBps",
3961
- type: "uint256",
3962
- internalType: "uint256"
4052
+ name: "peerChains",
4053
+ type: "bytes[]",
4054
+ internalType: "bytes[]"
3963
4055
  },
3964
4056
  {
3965
- name: "protocolFeeBps",
3966
- type: "uint256",
3967
- internalType: "uint256"
4057
+ name: "relayer",
4058
+ type: "address",
4059
+ internalType: "address"
3968
4060
  },
3969
4061
  {
3970
- name: "priceOracle",
4062
+ name: "owner",
3971
4063
  type: "address",
3972
4064
  internalType: "address"
3973
4065
  }
3974
4066
  ]
3975
- },
3976
- {
3977
- name: "peerChains",
3978
- type: "bytes[]",
3979
- internalType: "bytes[]"
3980
- },
3981
- {
3982
- name: "relayer",
3983
- type: "address",
3984
- internalType: "address"
3985
4067
  }
3986
4068
  ],
3987
4069
  outputs: [],
@@ -4006,12 +4088,25 @@ var ABI3 = [
4006
4088
  ],
4007
4089
  stateMutability: "view"
4008
4090
  },
4091
+ {
4092
+ type: "function",
4093
+ name: "intrinsicModule",
4094
+ inputs: [],
4095
+ outputs: [
4096
+ {
4097
+ name: "",
4098
+ type: "address",
4099
+ internalType: "address"
4100
+ }
4101
+ ],
4102
+ stateMutability: "view"
4103
+ },
4009
4104
  {
4010
4105
  type: "function",
4011
4106
  name: "migrate",
4012
4107
  inputs: [
4013
4108
  {
4014
- name: "relayer",
4109
+ name: "owner_",
4015
4110
  type: "address",
4016
4111
  internalType: "address"
4017
4112
  }
@@ -4086,7 +4181,7 @@ var ABI3 = [
4086
4181
  name: "onGetResponse",
4087
4182
  inputs: [
4088
4183
  {
4089
- name: "incoming",
4184
+ name: "",
4090
4185
  type: "tuple",
4091
4186
  internalType: "struct IncomingGetResponse",
4092
4187
  components: [
@@ -4301,6 +4396,19 @@ var ABI3 = [
4301
4396
  outputs: [],
4302
4397
  stateMutability: "nonpayable"
4303
4398
  },
4399
+ {
4400
+ type: "function",
4401
+ name: "owner",
4402
+ inputs: [],
4403
+ outputs: [
4404
+ {
4405
+ name: "",
4406
+ type: "address",
4407
+ internalType: "address"
4408
+ }
4409
+ ],
4410
+ stateMutability: "view"
4411
+ },
4304
4412
  {
4305
4413
  type: "function",
4306
4414
  name: "params",
@@ -4346,6 +4454,39 @@ var ABI3 = [
4346
4454
  ],
4347
4455
  stateMutability: "view"
4348
4456
  },
4457
+ {
4458
+ type: "function",
4459
+ name: "pause",
4460
+ inputs: [],
4461
+ outputs: [],
4462
+ stateMutability: "nonpayable"
4463
+ },
4464
+ {
4465
+ type: "function",
4466
+ name: "paused",
4467
+ inputs: [],
4468
+ outputs: [
4469
+ {
4470
+ name: "",
4471
+ type: "bool",
4472
+ internalType: "bool"
4473
+ }
4474
+ ],
4475
+ stateMutability: "view"
4476
+ },
4477
+ {
4478
+ type: "function",
4479
+ name: "pendingOwner",
4480
+ inputs: [],
4481
+ outputs: [
4482
+ {
4483
+ name: "",
4484
+ type: "address",
4485
+ internalType: "address"
4486
+ }
4487
+ ],
4488
+ stateMutability: "view"
4489
+ },
4349
4490
  {
4350
4491
  type: "function",
4351
4492
  name: "placeOrder",
@@ -4601,6 +4742,13 @@ var ABI3 = [
4601
4742
  ],
4602
4743
  stateMutability: "view"
4603
4744
  },
4745
+ {
4746
+ type: "function",
4747
+ name: "renounceOwnership",
4748
+ inputs: [],
4749
+ outputs: [],
4750
+ stateMutability: "nonpayable"
4751
+ },
4604
4752
  {
4605
4753
  type: "function",
4606
4754
  name: "select",
@@ -4639,10 +4787,10 @@ var ABI3 = [
4639
4787
  },
4640
4788
  {
4641
4789
  type: "function",
4642
- name: "setRelayer",
4790
+ name: "transferOwnership",
4643
4791
  inputs: [
4644
4792
  {
4645
- name: "relayer",
4793
+ name: "newOwner",
4646
4794
  type: "address",
4647
4795
  internalType: "address"
4648
4796
  }
@@ -4652,19 +4800,8 @@ var ABI3 = [
4652
4800
  },
4653
4801
  {
4654
4802
  type: "function",
4655
- name: "upgradeToAndCall",
4656
- inputs: [
4657
- {
4658
- name: "newImplementation",
4659
- type: "address",
4660
- internalType: "address"
4661
- },
4662
- {
4663
- name: "data",
4664
- type: "bytes",
4665
- internalType: "bytes"
4666
- }
4667
- ],
4803
+ name: "unpause",
4804
+ inputs: [],
4668
4805
  outputs: [],
4669
4806
  stateMutability: "nonpayable"
4670
4807
  },
@@ -4810,6 +4947,12 @@ var ABI3 = [
4810
4947
  indexed: true,
4811
4948
  internalType: "bytes32"
4812
4949
  },
4950
+ {
4951
+ name: "solver",
4952
+ type: "address",
4953
+ indexed: false,
4954
+ internalType: "address"
4955
+ },
4813
4956
  {
4814
4957
  name: "tokens",
4815
4958
  type: "tuple[]",
@@ -5047,39 +5190,77 @@ var ABI3 = [
5047
5190
  },
5048
5191
  {
5049
5192
  type: "event",
5050
- name: "ParamsUpdated",
5193
+ name: "OwnershipTransferStarted",
5051
5194
  inputs: [
5052
5195
  {
5053
- name: "previous",
5054
- type: "tuple",
5055
- indexed: false,
5056
- internalType: "struct Params",
5057
- components: [
5058
- {
5059
- name: "host",
5060
- type: "address",
5061
- internalType: "address"
5062
- },
5063
- {
5064
- name: "dispatcher",
5065
- type: "address",
5066
- internalType: "address"
5067
- },
5068
- {
5069
- name: "solverSelection",
5070
- type: "bool",
5071
- internalType: "bool"
5072
- },
5073
- {
5074
- name: "surplusShareBps",
5075
- type: "uint256",
5076
- internalType: "uint256"
5077
- },
5078
- {
5079
- name: "protocolFeeBps",
5080
- type: "uint256",
5081
- internalType: "uint256"
5082
- },
5196
+ name: "previousOwner",
5197
+ type: "address",
5198
+ indexed: true,
5199
+ internalType: "address"
5200
+ },
5201
+ {
5202
+ name: "newOwner",
5203
+ type: "address",
5204
+ indexed: true,
5205
+ internalType: "address"
5206
+ }
5207
+ ],
5208
+ anonymous: false
5209
+ },
5210
+ {
5211
+ type: "event",
5212
+ name: "OwnershipTransferred",
5213
+ inputs: [
5214
+ {
5215
+ name: "previousOwner",
5216
+ type: "address",
5217
+ indexed: true,
5218
+ internalType: "address"
5219
+ },
5220
+ {
5221
+ name: "newOwner",
5222
+ type: "address",
5223
+ indexed: true,
5224
+ internalType: "address"
5225
+ }
5226
+ ],
5227
+ anonymous: false
5228
+ },
5229
+ {
5230
+ type: "event",
5231
+ name: "ParamsUpdated",
5232
+ inputs: [
5233
+ {
5234
+ name: "previous",
5235
+ type: "tuple",
5236
+ indexed: false,
5237
+ internalType: "struct Params",
5238
+ components: [
5239
+ {
5240
+ name: "host",
5241
+ type: "address",
5242
+ internalType: "address"
5243
+ },
5244
+ {
5245
+ name: "dispatcher",
5246
+ type: "address",
5247
+ internalType: "address"
5248
+ },
5249
+ {
5250
+ name: "solverSelection",
5251
+ type: "bool",
5252
+ internalType: "bool"
5253
+ },
5254
+ {
5255
+ name: "surplusShareBps",
5256
+ type: "uint256",
5257
+ internalType: "uint256"
5258
+ },
5259
+ {
5260
+ name: "protocolFeeBps",
5261
+ type: "uint256",
5262
+ internalType: "uint256"
5263
+ },
5083
5264
  {
5084
5265
  name: "priceOracle",
5085
5266
  type: "address",
@@ -5185,46 +5366,73 @@ var ABI3 = [
5185
5366
  },
5186
5367
  {
5187
5368
  type: "event",
5188
- name: "RelayerUpdated",
5369
+ name: "Paused",
5189
5370
  inputs: [
5190
5371
  {
5191
- name: "previous",
5372
+ name: "account",
5192
5373
  type: "address",
5193
5374
  indexed: false,
5194
5375
  internalType: "address"
5376
+ }
5377
+ ],
5378
+ anonymous: false
5379
+ },
5380
+ {
5381
+ type: "event",
5382
+ name: "ProtocolFeeRefunded",
5383
+ inputs: [
5384
+ {
5385
+ name: "commitment",
5386
+ type: "bytes32",
5387
+ indexed: true,
5388
+ internalType: "bytes32"
5195
5389
  },
5196
5390
  {
5197
- name: "current",
5391
+ name: "token",
5198
5392
  type: "address",
5199
- indexed: false,
5393
+ indexed: true,
5200
5394
  internalType: "address"
5395
+ },
5396
+ {
5397
+ name: "amount",
5398
+ type: "uint256",
5399
+ indexed: false,
5400
+ internalType: "uint256"
5201
5401
  }
5202
5402
  ],
5203
5403
  anonymous: false
5204
5404
  },
5205
5405
  {
5206
5406
  type: "event",
5207
- name: "Upgraded",
5407
+ name: "RelayerUpdated",
5208
5408
  inputs: [
5209
5409
  {
5210
- name: "implementation",
5410
+ name: "previous",
5411
+ type: "address",
5412
+ indexed: false,
5413
+ internalType: "address"
5414
+ },
5415
+ {
5416
+ name: "current",
5211
5417
  type: "address",
5212
- indexed: true,
5418
+ indexed: false,
5213
5419
  internalType: "address"
5214
5420
  }
5215
5421
  ],
5216
5422
  anonymous: false
5217
5423
  },
5218
5424
  {
5219
- type: "error",
5220
- name: "AddressEmptyCode",
5425
+ type: "event",
5426
+ name: "Unpaused",
5221
5427
  inputs: [
5222
5428
  {
5223
- name: "target",
5429
+ name: "account",
5224
5430
  type: "address",
5431
+ indexed: false,
5225
5432
  internalType: "address"
5226
5433
  }
5227
- ]
5434
+ ],
5435
+ anonymous: false
5228
5436
  },
5229
5437
  {
5230
5438
  type: "error",
@@ -5260,28 +5468,17 @@ var ABI3 = [
5260
5468
  },
5261
5469
  {
5262
5470
  type: "error",
5263
- name: "ERC1967InvalidImplementation",
5264
- inputs: [
5265
- {
5266
- name: "implementation",
5267
- type: "address",
5268
- internalType: "address"
5269
- }
5270
- ]
5271
- },
5272
- {
5273
- type: "error",
5274
- name: "ERC1967NonPayable",
5471
+ name: "EnforcedPause",
5275
5472
  inputs: []
5276
5473
  },
5277
5474
  {
5278
5475
  type: "error",
5279
- name: "Expired",
5476
+ name: "ExpectedPause",
5280
5477
  inputs: []
5281
5478
  },
5282
5479
  {
5283
5480
  type: "error",
5284
- name: "FailedCall",
5481
+ name: "Expired",
5285
5482
  inputs: []
5286
5483
  },
5287
5484
  {
@@ -5324,11 +5521,43 @@ var ABI3 = [
5324
5521
  name: "NotInitializing",
5325
5522
  inputs: []
5326
5523
  },
5524
+ {
5525
+ type: "error",
5526
+ name: "OwnableInvalidOwner",
5527
+ inputs: [
5528
+ {
5529
+ name: "owner",
5530
+ type: "address",
5531
+ internalType: "address"
5532
+ }
5533
+ ]
5534
+ },
5535
+ {
5536
+ type: "error",
5537
+ name: "OwnableUnauthorizedAccount",
5538
+ inputs: [
5539
+ {
5540
+ name: "account",
5541
+ type: "address",
5542
+ internalType: "address"
5543
+ }
5544
+ ]
5545
+ },
5327
5546
  {
5328
5547
  type: "error",
5329
5548
  name: "PartialFillNotAllowed",
5330
5549
  inputs: []
5331
5550
  },
5551
+ {
5552
+ type: "error",
5553
+ name: "RateBelowOrder",
5554
+ inputs: []
5555
+ },
5556
+ {
5557
+ type: "error",
5558
+ name: "RateFillTooSmall",
5559
+ inputs: []
5560
+ },
5332
5561
  {
5333
5562
  type: "error",
5334
5563
  name: "ReentrancyGuardReentrantCall",
@@ -5556,9 +5785,6 @@ var ChainConfigService = class {
5556
5785
  getUniswapV4StateViewAddress(chain) {
5557
5786
  return this.getConfig(chain)?.addresses.UniswapV4StateView ?? "0x";
5558
5787
  }
5559
- getUniswapV4PoolConfigs(chain) {
5560
- return this.getConfig(chain)?.uniswapV4Pools ?? [];
5561
- }
5562
5788
  getPermit2Address(chain) {
5563
5789
  return this.getConfig(chain)?.addresses.Permit2 ?? "0x";
5564
5790
  }
@@ -8295,9 +8521,7 @@ Failed HTTP Request: ${JSON.stringify(
8295
8521
  };
8296
8522
 
8297
8523
  // src/chains/intentsCoprocessor.ts
8298
- var SYSTEM_EVENTS_KEY = u8aToHex(u8aConcat(xxhashAsU8a("System", 128), xxhashAsU8a("Events", 128)));
8299
8524
  var OFFCHAIN_BID_PREFIX = new TextEncoder().encode("intents::bid::");
8300
- var OFFCHAIN_PHANTOM_PREFIX = new TextEncoder().encode("intents::phantom::order::");
8301
8525
  var HYPERBRIDGE_TYPES_BUNDLE = {
8302
8526
  spec: {
8303
8527
  nexus: { hasher: keccakAsU8a },
@@ -8307,11 +8531,7 @@ var HYPERBRIDGE_TYPES_BUNDLE = {
8307
8531
  var BASE_TIP = 1000000000n;
8308
8532
  var HTTP_CONNECT_TIMEOUT_MS = 2e4;
8309
8533
  var INCLUSION_TIMEOUT_MS = 2e4;
8310
- var PHANTOM_POLL_INTERVAL_MS = 15e3;
8311
- var GARGANTUA_PHANTOM_POLL_INTERVAL_MS = 6e3;
8312
8534
  var DEFAULT_RPC_MAX_RPS = 8;
8313
- var DEFAULT_MAX_BLOCKS_PER_POLL = 10;
8314
- var MAX_RATE_LIMIT_BACKOFF_TICKS = 8;
8315
8535
  var rpcLimiters = /* @__PURE__ */ new Map();
8316
8536
  function limiterFor(httpUrl) {
8317
8537
  const key = new URL(httpUrl).origin;
@@ -8327,45 +8547,6 @@ function configuredRpcMaxRps() {
8327
8547
  const parsed = raw === void 0 ? Number.NaN : Number(raw);
8328
8548
  return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_RPC_MAX_RPS;
8329
8549
  }
8330
- function isRateLimited(err) {
8331
- const message = err instanceof Error ? err.message : String(err);
8332
- return message.includes("[429]") || /too many requests/i.test(message);
8333
- }
8334
- function isMethodUnavailable(err) {
8335
- const message = err instanceof Error ? err.message : String(err);
8336
- const code = err?.code;
8337
- return code === -32601 || /method not found|unsafe to be called externally/i.test(message);
8338
- }
8339
- var EventDecodeError = class extends Error {
8340
- };
8341
- function phantomOrdersFrom(records) {
8342
- if (records == null || typeof records[Symbol.iterator] !== "function") {
8343
- throw new EventDecodeError(`Expected a decoded event vector, got ${typeof records}`);
8344
- }
8345
- const orders = [];
8346
- for (const record of records) {
8347
- if (typeof record !== "object" || record === null || !("event" in record)) {
8348
- throw new EventDecodeError(
8349
- "system.events did not decode to event records \u2014 the storage entry's metadata was probably not carried through, leaving the value as raw bytes"
8350
- );
8351
- }
8352
- const { event } = record;
8353
- if (event.section !== "intentsCoprocessor" || event.method !== "PhantomOrderRegistered") continue;
8354
- const [commitment, chain, createdAt, legs] = event.data;
8355
- orders.push({
8356
- commitment: commitment.toHex(),
8357
- chain: new TextDecoder().decode(hexToU8a(chain.toHex())),
8358
- createdAt: createdAt.toNumber(),
8359
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8360
- legs: legs.map((leg) => ({
8361
- tokenA: leg.tokenA.toHex(),
8362
- tokenB: leg.tokenB.toHex(),
8363
- standardAmount: BigInt(leg.standardAmount.toString())
8364
- }))
8365
- });
8366
- }
8367
- return orders;
8368
- }
8369
8550
  function rejectAfter(ms, message) {
8370
8551
  return new Promise((_resolve, reject) => {
8371
8552
  const timer = setTimeout(() => reject(new Error(message)), ms);
@@ -8437,19 +8618,16 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8437
8618
  ownsConnection;
8438
8619
  /** Cached result of whether the node exposes intents_* RPC methods */
8439
8620
  hasIntentsRpc = null;
8440
- /** The pallet's phantom timings, read once. Cleared on failure so the read retries. */
8441
- phantomTimingsRead = null;
8442
8621
  /** The HTTP-backed api, connected on first use. Cleared after a failed attempt so it retries. */
8443
8622
  httpApi = null;
8444
- /** Last runtime version read from the node, for {@link confirmedRuntimeVersion} to compare against. */
8445
- lastRuntimeVersion;
8446
- /** Set once the node refuses `state_queryStorage`, so the poll stops asking for it. */
8447
- rangeQueryUnavailable = false;
8448
8623
  // Serialises every extrinsic submission on this instance's substrate account. All submit/retract
8449
- // methods funnel through signAndSendExtrinsic, each using the API's auto-nonce; fired in parallel
8450
- // (bids for orders on different chains, or several phantom orders in one interval) they would grab
8451
- // the same nonce and all but one would fail. Concurrency 1 sequences them.
8624
+ // methods funnel through signAndSendExtrinsic; fired in parallel (bids for orders on different
8625
+ // chains, or several bids on one order) they would grab the same nonce and all but one would
8626
+ // fail. Concurrency 1 sequences them, and {@link nextNonce} keeps consecutive submissions off
8627
+ // each other's nonce even while the first is still in the pool.
8452
8628
  submissionQueue = new PQueue({ concurrency: 1 });
8629
+ /** The highest nonce this instance has put into the pool, so the next submission clears it. */
8630
+ lastPooledNonce;
8453
8631
  /**
8454
8632
  * Creates and connects an IntentsCoprocessor to a Hyperbridge node.
8455
8633
  * This creates and manages its own API connection.
@@ -8511,10 +8689,10 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8511
8689
  * The HTTP api is always created here, so it is always ours to close.
8512
8690
  */
8513
8691
  async disconnect() {
8514
- const http4 = this.httpApi;
8692
+ const http3 = this.httpApi;
8515
8693
  this.httpApi = null;
8516
- if (http4) {
8517
- await http4.then((api) => api.disconnect()).catch(() => {
8694
+ if (http3) {
8695
+ await http3.then((api) => api.disconnect()).catch(() => {
8518
8696
  });
8519
8697
  }
8520
8698
  if (this.ownsConnection) {
@@ -8528,9 +8706,8 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8528
8706
  *
8529
8707
  * The connection attempt is bounded on both sides. `isReadyOrError` rejects on a failed
8530
8708
  * handshake, where plain `isReady` would simply never resolve, and the timeout covers an
8531
- * endpoint that accepts the request and then goes quiet. An unbounded wait here would hang the
8532
- * poll tick awaiting it, which is precisely the silent stall that polling exists to avoid. A
8533
- * failed attempt is not cached, so the next call tries again.
8709
+ * endpoint that accepts the request and then goes quiet, so a caller awaiting it never hangs
8710
+ * silently. A failed attempt is not cached, so the next call tries again.
8534
8711
  */
8535
8712
  async http() {
8536
8713
  if (!this.httpApi) {
@@ -8539,11 +8716,9 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8539
8716
  // Response cache off (third argument, capacity 0). polkadot-js caches every request that
8540
8717
  // names a block hash — `chain_getHeader(hash)`, `state_getRuntimeVersion(hash)`, storage
8541
8718
  // reads at a hash — by storing the request promise itself, a rejected one included, for a
8542
- // 30s TTL that every hit refreshes. The phantom poll retries the block it failed on with
8543
- // identical parameters every tick, so one reset connection became the same rejection
8544
- // replayed from memory on every tick, faster than the TTL could lapse, and the node never
8545
- // saw a second request. The cache bought nothing here anyway: the poll reads each block
8546
- // once, and `api.at(hash)` reuses registries at the api layer regardless.
8719
+ // 30s TTL that every hit refreshes. A caller retrying a failed read with identical
8720
+ // parameters would get the same rejection replayed from memory for as long as it kept
8721
+ // retrying inside the TTL, and the node would never see a second request.
8547
8722
  // Concurrent calls are coalesced into one JSON-RPC batch request, and every request
8548
8723
  // to this endpoint is paced by a bucket shared with any other coprocessor in this
8549
8724
  // process pointed at the same host — the limit is the server's, and it counts
@@ -8618,7 +8793,12 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8618
8793
  return { success: false, error: err instanceof Error ? err.message : String(err) };
8619
8794
  }
8620
8795
  }
8621
- return await this.sendExtrinsicWithRetries(build(this.api), maxRetries, timeoutMs);
8796
+ return await this.sendExtrinsicWithRetries(
8797
+ build(this.api),
8798
+ maxRetries,
8799
+ timeoutMs,
8800
+ await this.nextNonce(this.api)
8801
+ );
8622
8802
  });
8623
8803
  return result ?? { success: false, error: "Submission queue returned no result" };
8624
8804
  }
@@ -8637,7 +8817,10 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8637
8817
  */
8638
8818
  async sendViaHttp(api, build) {
8639
8819
  try {
8640
- const hash = await build(api).signAndSend(this.getKeyPair(), { tip: BASE_TIP });
8820
+ const nonce = await this.nextNonce(api);
8821
+ const options = nonce === void 0 ? { tip: BASE_TIP } : { tip: BASE_TIP, nonce };
8822
+ const hash = await build(api).signAndSend(this.getKeyPair(), options);
8823
+ if (nonce !== void 0) this.lastPooledNonce = nonce;
8641
8824
  return { success: false, pending: true, extrinsicHash: hash.toHex() };
8642
8825
  } catch (err) {
8643
8826
  return this.classifySubmissionError(err instanceof Error ? err : new Error(String(err)));
@@ -8650,7 +8833,7 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8650
8833
  * Two kinds of failure are retried, and the difference is the nonce.
8651
8834
  *
8652
8835
  * An attempt that verifiably went nowhere (rejected before the pool, dropped, invalid) leaves
8653
- * the account nonce free, so the next attempt simply re-signs with the auto-nonce.
8836
+ * the account nonce free, so the next attempt simply re-signs with the pool-aware nonce.
8654
8837
  *
8655
8838
  * An attempt that reached the pool and was still there when the watch timed out (`stalled`) is
8656
8839
  * retried as a *replacement*: the same nonce it was signed with, and double the tip. Substrate's
@@ -8669,16 +8852,19 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8669
8852
  * copy is in flight and its outcome is unknown here, so the `pending` result goes back to the
8670
8853
  * caller to confirm later.
8671
8854
  */
8672
- async sendExtrinsicWithRetries(extrinsic, maxRetries, timeoutMs) {
8855
+ async sendExtrinsicWithRetries(extrinsic, maxRetries, timeoutMs, initialNonce) {
8673
8856
  const keyPair = this.getKeyPair();
8674
8857
  let attempt = 0;
8675
- let nonce;
8858
+ let nonce = initialNonce;
8676
8859
  let stalled;
8677
8860
  while (attempt < maxRetries) {
8678
8861
  const currentTip = BASE_TIP * BigInt(2 ** attempt);
8679
8862
  attempt++;
8680
8863
  try {
8681
8864
  const result = await this.sendWithTimeout(extrinsic, keyPair, currentTip, timeoutMs, nonce);
8865
+ if (nonce !== void 0 && (result.success || result.pending || result.stalled)) {
8866
+ this.lastPooledNonce = Math.max(nonce, this.lastPooledNonce ?? nonce);
8867
+ }
8682
8868
  if (result.success || result.error?.includes("Dispatch error")) {
8683
8869
  return result;
8684
8870
  }
@@ -8738,6 +8924,35 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8738
8924
  * replacement rather than a second extrinsic queued behind the first. Left undefined on the
8739
8925
  * first attempt, where the api's auto-nonce is correct.
8740
8926
  */
8927
+ /**
8928
+ * The nonce the next submission signs with, or undefined when the node cannot be asked.
8929
+ *
8930
+ * Submissions are serialised, but a watch gives up while its extrinsic is still in the pool
8931
+ * (`stalled`, reported as `pending`), and a pooled extrinsic does not advance the account's
8932
+ * on-chain nonce. An extrinsic signed against on-chain state would then take the nonce of the
8933
+ * one ahead of it and bounce off it (1013/1014) instead of queueing behind it.
8934
+ *
8935
+ * `system_accountNextIndex` is the only pool-aware source here. `signAndSend`'s own `nonce: -1`
8936
+ * is not: on a runtime carrying `AccountNonceApi`, which Hyperbridge does, polkadot-js reads the
8937
+ * nonce through that runtime call and never sees the pool.
8938
+ *
8939
+ * The RPC covers the ready queue, so anything of this instance's that has left it — retried,
8940
+ * queued as future, or simply not counted yet — is covered by `lastPooledNonce` instead, which
8941
+ * is the highest nonce this instance has put into the pool. The two are combined rather than
8942
+ * trusted separately, so a burst never reuses a nonce and a restart still picks up the chain's.
8943
+ */
8944
+ async nextNonce(api) {
8945
+ try {
8946
+ const accountNextIndex = api.rpc?.system?.accountNextIndex;
8947
+ if (!accountNextIndex) return void 0;
8948
+ const next = await accountNextIndex(this.getKeyPair().address);
8949
+ const fromPool = Number(next.toString());
8950
+ if (!Number.isFinite(fromPool)) return void 0;
8951
+ return this.lastPooledNonce === void 0 ? fromPool : Math.max(fromPool, this.lastPooledNonce + 1);
8952
+ } catch {
8953
+ return void 0;
8954
+ }
8955
+ }
8741
8956
  async sendWithTimeout(extrinsic, keyPair, tip, timeoutMs, nonce) {
8742
8957
  return new Promise((resolve) => {
8743
8958
  let resolved = false;
@@ -8780,25 +8995,10 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8780
8995
  } else if (result.status.isInBlock || result.status.isFinalized) {
8781
8996
  resolved = true;
8782
8997
  clearTimeout(timeoutId);
8783
- const interrupted = result.events.find(
8784
- ({ event }) => event.section === "utility" && event.method === "BatchInterrupted"
8785
- );
8786
- if (interrupted) {
8787
- const [indexCodec, dispatchError] = interrupted.event.data;
8788
- if (Number(indexCodec.toString()) === 0) {
8789
- resolve({
8790
- success: false,
8791
- error: `Dispatch error: ${this.describeDispatchError(dispatchError)}`
8792
- });
8793
- return;
8794
- }
8795
- }
8796
8998
  resolve({
8797
8999
  success: true,
8798
9000
  blockHash: (result.status.isInBlock ? result.status.asInBlock : result.status.asFinalized).toHex(),
8799
- extrinsicHash: extrinsic.hash.toHex(),
8800
- // Carried so a batch caller can attribute each item's outcome.
8801
- events: result.events
9001
+ extrinsicHash: extrinsic.hash.toHex()
8802
9002
  });
8803
9003
  }
8804
9004
  }).then((unsub) => {
@@ -8819,13 +9019,19 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8819
9019
  /**
8820
9020
  * Submits a bid to Hyperbridge's pallet-intents
8821
9021
  *
9022
+ * A filler can hold several bids on one order, one per price it offers, and `bid` tells them
9023
+ * apart: submitting again under an identifier the filler already holds replaces that bid alone.
9024
+ * By convention it is `keccak256` of the UserOp's `callData`, which is also what gives each bid
9025
+ * its own nonce key on the `SolverAccount` (see `CryptoUtils.bidId`).
9026
+ *
8822
9027
  * @param commitment - The order commitment hash (bytes32)
8823
9028
  * @param userOp - The encoded PackedUserOperation as hex string
9029
+ * @param bid - Identifies this bid among the filler's bids on the order (bytes32)
8824
9030
  * @returns BidSubmissionResult with success status and block/extrinsic hash
8825
9031
  */
8826
- async submitBid(commitment, userOp) {
9032
+ async submitBid(commitment, userOp, bid) {
8827
9033
  try {
8828
- return await this.signAndSendExtrinsic((api) => api.tx.intentsCoprocessor.placeBid(commitment, userOp));
9034
+ return await this.signAndSendExtrinsic((api) => api.tx.intentsCoprocessor.placeBid(commitment, bid, userOp));
8829
9035
  } catch (error) {
8830
9036
  return {
8831
9037
  success: false,
@@ -8839,46 +9045,12 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8839
9045
  * Use this to remove unused quotes and claim back deposited BRIDGE tokens.
8840
9046
  *
8841
9047
  * @param commitment - The order commitment hash (bytes32)
9048
+ * @param bid - Which of the filler's bids on the order to retract (bytes32)
8842
9049
  * @returns BidSubmissionResult with success status and block/extrinsic hash
8843
9050
  */
8844
- async retractBid(commitment) {
8845
- try {
8846
- return await this.signAndSendExtrinsic((api) => api.tx.intentsCoprocessor.retractBid(commitment));
8847
- } catch (error) {
8848
- return {
8849
- success: false,
8850
- error: error instanceof Error ? error.message : "Unknown error"
8851
- };
8852
- }
8853
- }
8854
- /**
8855
- * Places a new bid and retracts a previous one in a single transaction via utility.batch.
8856
- *
8857
- * The new bid is the primary operation, so `placeBid` MUST run first. `utility.batch` is
8858
- * non-atomic: a failing call interrupts the batch (via a BatchInterrupted event) without
8859
- * reverting the calls that already succeeded. Placing first guarantees the new bid lands even
8860
- * when the retraction then fails — which it routinely does, because a previous commitment's bid
8861
- * may already be gone (or was itself never placed), making `retractBid` return `BidNotFound`.
8862
- *
8863
- * Ordering retraction first (the previous behaviour) caused a self-sustaining cascade: a
8864
- * `BidNotFound` on the leading retract skipped the trailing `placeBid`, so the current bid never
8865
- * landed, so the *next* interval's retract of that never-placed commitment also failed, and so
8866
- * on — silently, because the batch extrinsic itself reports success. The deposit reclaim is
8867
- * best-effort; landing the bid is not.
8868
- *
8869
- * @param retractCommitment - The order commitment of the bid to retract (bytes32)
8870
- * @param bidCommitment - The order commitment of the new bid (bytes32)
8871
- * @param userOp - The encoded PackedUserOperation as hex string
8872
- * @returns BidSubmissionResult with success status and block/extrinsic hash
8873
- */
8874
- async submitBidWithRetraction(retractCommitment, bidCommitment, userOp) {
9051
+ async retractBid(commitment, bid) {
8875
9052
  try {
8876
- return await this.signAndSendExtrinsic(
8877
- (api) => api.tx.utility.batch([
8878
- api.tx.intentsCoprocessor.placeBid(bidCommitment, userOp),
8879
- api.tx.intentsCoprocessor.retractBid(retractCommitment)
8880
- ])
8881
- );
9053
+ return await this.signAndSendExtrinsic((api) => api.tx.intentsCoprocessor.retractBid(commitment, bid));
8882
9054
  } catch (error) {
8883
9055
  return {
8884
9056
  success: false,
@@ -8886,89 +9058,6 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8886
9058
  };
8887
9059
  }
8888
9060
  }
8889
- /**
8890
- * Places every phantom bid of one interval in a single extrinsic, retracting each chain's
8891
- * previous bid alongside it.
8892
- *
8893
- * The pallet registers one phantom order per configured chain in the same block, so this is the
8894
- * whole interval's set. Submitting them one at a time costs a block per chain: submissions are
8895
- * serialised on the account nonce and each waits for inclusion, so the last chain's bid is many
8896
- * blocks behind the first, against a bid window measured in tens of blocks. Batched, every bid
8897
- * lands in the same block.
8898
- *
8899
- * Uses `utility.force_batch`, not `utility.batch`. `batch` stops at the first failing call, so
8900
- * one rejected bid — a closed window, a duplicate, an insufficient deposit — would silently
8901
- * drop every bid after it. `force_batch` runs them all and reports each outcome. It needs no
8902
- * special origin: any signed account may call it, exactly like `batch`.
8903
- *
8904
- * @param bids - The bids to place; an empty list is a no-op
8905
- * @returns Per-bid outcomes, in the order given
8906
- */
8907
- async submitPhantomBids(bids) {
8908
- if (bids.length === 0) return { bids: [] };
8909
- const placeIndexByBid = [];
8910
- let callCount = 0;
8911
- for (const bid of bids) {
8912
- placeIndexByBid.push(callCount);
8913
- callCount += bid.retractCommitment ? 2 : 1;
8914
- }
8915
- const outcome = await this.signAndSendExtrinsic(
8916
- (api) => api.tx.utility.forceBatch(
8917
- bids.flatMap((bid) => {
8918
- const calls = [api.tx.intentsCoprocessor.placeBid(bid.commitment, bid.userOp)];
8919
- if (bid.retractCommitment) {
8920
- calls.push(api.tx.intentsCoprocessor.retractBid(bid.retractCommitment));
8921
- }
8922
- return calls;
8923
- })
8924
- )
8925
- );
8926
- if (!outcome.success) {
8927
- return {
8928
- bids: bids.map((bid) => ({ commitment: bid.commitment, success: false, error: outcome.error })),
8929
- pending: outcome.pending,
8930
- extrinsicHash: outcome.extrinsicHash,
8931
- error: outcome.error
8932
- };
8933
- }
8934
- const items = this.readForceBatchItems(outcome.events ?? [], callCount);
8935
- return {
8936
- bids: bids.map((bid, index) => {
8937
- const error = items.errors[placeIndexByBid[index]];
8938
- return { commitment: bid.commitment, success: !error, error };
8939
- }),
8940
- blockHash: outcome.blockHash,
8941
- extrinsicHash: outcome.extrinsicHash,
8942
- error: items.error
8943
- };
8944
- }
8945
- /**
8946
- * Reads one outcome per call out of a force_batch's events.
8947
- *
8948
- * `ItemFailed` carries no index — pallet-utility emits exactly one `ItemCompleted` or
8949
- * `ItemFailed` per call, in call order, so the k-th item event belongs to call k.
8950
- *
8951
- * A count that does not match the calls submitted means the events are not the ones assumed
8952
- * here, and every attribution after the discrepancy would be off by one. The bids are then
8953
- * reported as placed: a bid wrongly recorded as landed is retracted next interval and the
8954
- * retraction harmlessly fails with `BidNotFound`, whereas one wrongly recorded as failed is
8955
- * never retracted at all and leaves its deposit reserved.
8956
- */
8957
- readForceBatchItems(events, callCount) {
8958
- const errors = [];
8959
- for (const { event } of events) {
8960
- if (event.section !== "utility") continue;
8961
- if (event.method === "ItemCompleted") errors.push(void 0);
8962
- else if (event.method === "ItemFailed") errors.push(this.describeDispatchError(event.data[0]));
8963
- }
8964
- if (errors.length !== callCount) {
8965
- return {
8966
- errors: new Array(callCount).fill(void 0),
8967
- error: `force_batch reported ${errors.length} item events for ${callCount} calls; outcomes not attributed`
8968
- };
8969
- }
8970
- return { errors };
8971
- }
8972
9061
  /** Renders a DispatchError as `pallet::Error`, falling back to its raw form. */
8973
9062
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8974
9063
  describeDispatchError(dispatchError) {
@@ -8987,10 +9076,11 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
8987
9076
  */
8988
9077
  async getBidStorageEntries(commitment) {
8989
9078
  const api = await this.http();
8990
- const entries = await api.query.intentsCoprocessor.bids.entries(commitment);
9079
+ const entries = await api.query.intentsCoprocessor.orderBids.entries(commitment);
8991
9080
  return entries.map(([storageKey, depositValue]) => ({
8992
9081
  commitment,
8993
9082
  filler: storageKey.args[1].toString(),
9083
+ bid: storageKey.args[2].toHex(),
8994
9084
  deposit: BigInt(depositValue.toString())
8995
9085
  }));
8996
9086
  }
@@ -9022,7 +9112,7 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
9022
9112
  return result.map((entry) => {
9023
9113
  const userOp = decodeUserOpScale(entry.user_op);
9024
9114
  const filler = new Keyring({ type: "sr25519" }).encodeAddress(hexToU8a(entry.filler));
9025
- return { filler, userOp, deposit: 0n };
9115
+ return { filler, bid: entry.bid, userOp, deposit: 0n };
9026
9116
  });
9027
9117
  }
9028
9118
  /**
@@ -9031,19 +9121,20 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
9031
9121
  */
9032
9122
  async getBidsViaStorage(commitment) {
9033
9123
  const api = await this.http();
9034
- const entries = await api.query.intentsCoprocessor.bids.entries(commitment);
9124
+ const entries = await api.query.intentsCoprocessor.orderBids.entries(commitment);
9035
9125
  if (entries.length === 0) return [];
9036
9126
  const bidPromises = entries.map(async ([storageKey, depositValue]) => {
9037
9127
  try {
9038
9128
  const filler = storageKey.args[1].toString();
9129
+ const bid = storageKey.args[2].toHex();
9039
9130
  const deposit = BigInt(depositValue.toString());
9040
- const offchainKey = this.buildOffchainBidKey(commitment, filler);
9131
+ const offchainKey = this.buildOffchainBidKey(commitment, filler, bid);
9041
9132
  const offchainKeyHex = u8aToHex(offchainKey);
9042
9133
  const offchainResult = await api.rpc.offchain.localStorageGet("PERSISTENT", offchainKeyHex);
9043
9134
  if (!offchainResult || offchainResult.isNone) return null;
9044
9135
  const bidData = offchainResult.unwrap().toHex();
9045
9136
  const decoded = this.decodeBid(bidData);
9046
- return { filler: decoded.filler, userOp: decoded.userOp, deposit };
9137
+ return { filler: decoded.filler, bid, userOp: decoded.userOp, deposit };
9047
9138
  } catch {
9048
9139
  return null;
9049
9140
  }
@@ -9059,411 +9150,31 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
9059
9150
  const userOp = decodeUserOpScale(userOpHex);
9060
9151
  return { filler, userOp };
9061
9152
  }
9062
- /** Builds offchain storage key: "intents::bid::" + commitment + filler */
9063
- buildOffchainBidKey(commitment, filler) {
9064
- return u8aConcat(OFFCHAIN_BID_PREFIX, hexToU8a(commitment), decodeAddress(filler));
9153
+ /** Builds offchain storage key: "intents::bid::" + commitment + filler + bid */
9154
+ buildOffchainBidKey(commitment, filler, bid) {
9155
+ return u8aConcat(OFFCHAIN_BID_PREFIX, hexToU8a(commitment), decodeAddress(filler), hexToU8a(bid));
9065
9156
  }
9066
- /**
9067
- * Fetches the ABI-encoded phantom order from offchain storage and decodes it
9068
- * into an `Order` object. The pallet writes the order bytes under the key
9069
- * `intents::phantom::order::<commitment>` when it calls `on_initialize`.
9070
- *
9071
- * Returns `null` if the key is absent (e.g. the node is not an offchain worker
9072
- * or the commitment has expired and been cleared).
9073
- */
9074
- async fetchPhantomOrder(commitment) {
9075
- const key = u8aConcat(OFFCHAIN_PHANTOM_PREFIX, hexToU8a(commitment));
9076
- const api = await this.http();
9077
- const result = await api.rpc.offchain.localStorageGet("PERSISTENT", u8aToHex(key));
9078
- if (!result || result.isNone) return null;
9079
- const rawHex = result.unwrap().toHex();
9080
- if (rawHex === "0x" || rawHex === "0x00") return null;
9081
- const placeOrderAbi = IntentGatewayV2_default.ABI.find((item) => item.type === "function" && item.name === "placeOrder");
9082
- const orderType = placeOrderAbi?.inputs?.[0];
9083
- if (!orderType) return null;
9084
- const [decoded] = decodeAbiParameters([orderType], rawHex);
9085
- const d = decoded;
9086
- const textDecoder = new TextDecoder();
9087
- return {
9088
- id: commitment,
9089
- user: d.user,
9090
- source: textDecoder.decode(hexToBytes(d.source)),
9091
- destination: textDecoder.decode(hexToBytes(d.destination)),
9092
- deadline: d.deadline,
9093
- nonce: d.nonce,
9094
- fees: d.fees,
9095
- session: d.session,
9096
- predispatch: {
9097
- assets: d.predispatch.assets.map((a) => ({
9098
- token: a.token,
9099
- amount: a.amount
9100
- })),
9101
- call: d.predispatch.call
9102
- },
9103
- inputs: d.inputs.map((i) => ({
9104
- token: i.token,
9105
- amount: i.amount
9106
- })),
9107
- output: {
9108
- beneficiary: d.output.beneficiary,
9109
- assets: d.output.assets.map((a) => ({
9110
- token: a.token,
9111
- amount: a.amount
9112
- })),
9113
- call: d.output.call
9114
- }
9115
- };
9157
+ };
9158
+ var TronChain = class _TronChain {
9159
+ constructor(params, evm) {
9160
+ this.params = params;
9161
+ this.evm = evm;
9162
+ this.tronWebInstance = new TronWeb({ fullHost: params.rpcUrl });
9116
9163
  }
9164
+ params;
9165
+ evm;
9166
+ tronWebInstance;
9117
9167
  /**
9118
- * Reads the PhantomOrderRegistered events emitted in a single block.
9119
- *
9120
- * Costs two RPCs per block when `knownVersion` is supplied and four without it, which is why the
9121
- * poll goes to the trouble of establishing one. `api.at(hash)` has to work out which metadata to
9122
- * decode the block against, and with nothing to go on it fetches the header and then the runtime
9123
- * version at its parent — every block, forever. Its cheaper paths are a registry already pinned
9124
- * to this exact hash (only ever the previous block's) or one matching a version the caller
9125
- * names, so naming the version is the only way out. See `getBlockRegistry` in
9126
- * `@polkadot/api/base/Init`; the `getUpgradeVersion` shortcut that would otherwise skip the
9127
- * lookup only covers chains hardcoded in `@polkadot/types-known`, which Hyperbridge is not.
9168
+ * Creates a `TronChain` instance from a fully-specified config object.
9128
9169
  *
9129
- * @param knownVersion - the runtime version this block is known to run, if the caller has
9130
- * established one. Passing a version the block does not actually run decodes it against the
9131
- * wrong metadata, so this is for callers that have checked, not a place to pass a guess.
9132
- */
9133
- async getPhantomOrdersInBlock(blockNumber, knownVersion) {
9134
- const api = await this.http();
9135
- const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
9136
- return await this.getPhantomOrdersAtHash(blockHash.toHex(), knownVersion);
9137
- }
9138
- /**
9139
- * The same read, for a caller that already holds the block's hash.
9170
+ * This is the only public way to construct a `TronChain` — the constructor is private.
9140
9171
  *
9141
- * Split out so the poll can fetch a whole range's hashes in one concurrent wave — which the
9142
- * provider coalesces into a single batched request — and then read each block's events knowing
9143
- * its hash. `chain_getBlockHash` is the half of the pair that parallelises safely: it takes no
9144
- * historic block hash, so it never triggers polkadot-js's per-hash registry resolution, and
9145
- * concurrent calls cannot race each other's registry state.
9172
+ * @param params - Tron chain configuration
9173
+ * @returns A `TronChain` instance
9146
9174
  */
9147
- async getPhantomOrdersAtHash(blockHash, knownVersion) {
9148
- const api = await this.http();
9149
- const apiAt = await api.at(blockHash, knownVersion);
9150
- return phantomOrdersFrom(await apiAt.query.system.events());
9151
- }
9152
- /**
9153
- * Every block's phantom orders across a whole range, in one `state_queryStorage` call.
9154
- *
9155
- * This is the cheap path: the request cost of a scan stops depending on how many blocks it
9156
- * covers. The events key is the only key queried, and both bounds are block hashes the caller
9157
- * already holds.
9158
- *
9159
- * Two properties of the RPC shape the result.
9160
- *
9161
- * It returns *diffs*: `query_storage_unfiltered` in `sc-rpc` pushes a change set for a block only
9162
- * when the value differs from the previous block in the range (`has_changed`, and the set is
9163
- * dropped when empty), so a block whose events encode byte-for-byte identically to its
9164
- * predecessor's is simply absent. That happens on a quiet chain, where consecutive blocks carry
9165
- * nothing but the timestamp inherent's `ExtrinsicSuccess`. It is safe here because an absent
9166
- * block provably carries no phantom orders: a `PhantomOrderRegistered` commitment is derived from
9167
- * the block number (`phantom_order_commitment`), so a block that registered orders can never
9168
- * encode identically to any other block. Absent therefore means "same as the previous block",
9169
- * and the previous block having orders would contradict that.
9170
- *
9171
- * And it is gated by `--rpc-methods` (`check_if_safe` in `sc-rpc`), which answers a denied call
9172
- * with `Method not found`. The node this reads from must already run unsafe RPC to serve
9173
- * `offchain_localStorageGet` for the orders themselves, so this is normally available; the poll
9174
- * falls back to reading block by block when it is not.
9175
- *
9176
- * @returns one entry per block the node reported a change for, in ascending block order.
9177
- */
9178
- async getPhantomOrdersInRange(fromBlockHash, toBlockHash) {
9179
- const api = await this.http();
9180
- const changeSets = await api.rpc.state.queryStorage.raw(
9181
- [SYSTEM_EVENTS_KEY],
9182
- fromBlockHash,
9183
- toBlockHash
9184
- );
9185
- return changeSets.map((changeSet) => {
9186
- const value = changeSet?.changes?.find(([key]) => key === SYSTEM_EVENTS_KEY)?.[1];
9187
- if (!value) return [];
9188
- return phantomOrdersFrom(api.registry.createType("Vec<EventRecord>", value));
9189
- });
9190
- }
9191
- /**
9192
- * Polls for newly registered phantom orders, invoking the callback once per block that carries
9193
- * any, with all of that block's orders.
9194
- *
9195
- * Per block rather than per order because that is how the pallet writes them: one order per
9196
- * configured chain, all registered in the same `on_initialize`. Delivering them together lets a
9197
- * caller bid on the whole interval in one extrinsic (see {@link submitPhantomBids}) instead of
9198
- * one per chain.
9199
- *
9200
- * Each tick reads the current head and scans every block between the last one processed and that
9201
- * head, so the block cursor — not the connection — determines what has been seen. This replaced a
9202
- * system.events subscription, which was only as reliable as its socket: polkadot-js reconnects
9203
- * the transport but does not reliably re-establish storage subscriptions, and anything emitted
9204
- * while disconnected was lost silently. With a bid window measured in a handful of blocks, that
9205
- * meant silently missed bids.
9206
- *
9207
- * Scanning a block range is gap-free rather than merely self-healing: an outage delays orders but
9208
- * cannot drop them, because the cursor only advances past a block whose events were actually
9209
- * read. Recovery replays the backlog.
9210
- *
9211
- * Every read here goes over HTTP, never the websocket. Polling is a sequence of independent
9212
- * one-shot requests with no state to lose between them, which is exactly what a stateless
9213
- * transport does well: a request either answers or fails loudly on this tick, instead of a
9214
- * socket that looks alive while delivering nothing. It also means a websocket outage does not
9215
- * pause phantom bidding at all — the two transports fail independently.
9216
- *
9217
- * What the cadence does *not* describe is the request rate, which is what rate limiters police.
9218
- * A tick costs four requests whatever the range covers — the head, the runtime version, the two
9219
- * bounding block hashes as one batched request, and one `state_queryStorage` for every block's
9220
- * events — and they go out back-to-back, so an interval well under any per-second limit could
9221
- * still arrive as a burst over it. Three things keep that in bounds: the provider coalesces
9222
- * concurrent calls into one request and paces requests through the endpoint's token bucket (see
9223
- * `http`), and `maxBlocksPerPoll` bounds the range. A 429 that gets through anyway backs the
9224
- * poll off for a doubling number of ticks, so a limiter that is already shedding load is not
9225
- * handed the next window's budget in rejections too.
9226
- *
9227
- * Where the node will not serve `state_queryStorage` the poll reads block by block instead, at
9228
- * three requests plus one per block; see {@link scanRangeAtOnce}.
9229
- *
9230
- * Returns a function that stops polling.
9231
- */
9232
- pollPhantomOrders(callback, options = {}) {
9233
- const {
9234
- intervalMs,
9235
- maxBlocksPerPoll = DEFAULT_MAX_BLOCKS_PER_POLL,
9236
- onError,
9237
- onSkip
9238
- } = options;
9239
- let cursor = null;
9240
- let inFlight = false;
9241
- let stopped = false;
9242
- let backoffTicks = 0;
9243
- let backoffLength = 0;
9244
- const tick = async () => {
9245
- if (inFlight || stopped) return;
9246
- if (backoffTicks > 0) {
9247
- backoffTicks -= 1;
9248
- return;
9249
- }
9250
- inFlight = true;
9251
- try {
9252
- const api = await this.http();
9253
- const head = (await api.rpc.chain.getHeader()).number.toNumber();
9254
- if (cursor === null) {
9255
- cursor = Math.max(head - 1, -1);
9256
- } else {
9257
- const { bidWindowBlocks, intervalBlocks } = await this.phantomTimings();
9258
- if (head - cursor > bidWindowBlocks + Math.max(intervalBlocks, bidWindowBlocks)) {
9259
- const from = cursor + 1;
9260
- cursor = Math.max(head - 1 - bidWindowBlocks, -1);
9261
- onSkip?.({ from, to: cursor, head });
9262
- }
9263
- }
9264
- if (head <= cursor) return;
9265
- const knownVersion = await this.confirmedRuntimeVersion();
9266
- const to = Math.min(head, cursor + maxBlocksPerPoll);
9267
- const ranged = await this.scanRangeAtOnce(api, cursor + 1, to, knownVersion, onError);
9268
- if (ranged) {
9269
- for (const orders of ranged) {
9270
- if (stopped) return;
9271
- if (orders.length > 0) callback(orders);
9272
- }
9273
- cursor = to;
9274
- backoffLength = 0;
9275
- return;
9276
- }
9277
- const numbers = [];
9278
- for (let blockNumber = cursor + 1; blockNumber <= to; blockNumber++) numbers.push(blockNumber);
9279
- const hashes = await Promise.allSettled(
9280
- numbers.map((blockNumber) => api.rpc.chain.getBlockHash(blockNumber))
9281
- );
9282
- for (let index = 0; index < numbers.length; index++) {
9283
- if (stopped) return;
9284
- const hash = hashes[index];
9285
- if (hash.status === "rejected") throw hash.reason;
9286
- const orders = await this.getPhantomOrdersAtHash(hash.value.toHex(), knownVersion);
9287
- if (orders.length > 0) callback(orders);
9288
- cursor = numbers[index];
9289
- }
9290
- backoffLength = 0;
9291
- } catch (err) {
9292
- if (isRateLimited(err)) {
9293
- backoffLength = Math.min(backoffLength === 0 ? 1 : backoffLength * 2, MAX_RATE_LIMIT_BACKOFF_TICKS);
9294
- backoffTicks = backoffLength;
9295
- }
9296
- onError?.(err);
9297
- } finally {
9298
- inFlight = false;
9299
- }
9300
- };
9301
- void tick();
9302
- let timer = null;
9303
- const startTimer = (ms) => {
9304
- if (stopped) return;
9305
- timer = setInterval(() => void tick(), ms);
9306
- };
9307
- if (intervalMs !== void 0) startTimer(intervalMs);
9308
- else void this.phantomPollIntervalMs().then(startTimer);
9309
- return () => {
9310
- stopped = true;
9311
- if (timer) clearInterval(timer);
9312
- };
9313
- }
9314
- /**
9315
- * The Hyperbridge head, over HTTP like every other read here.
9316
- *
9317
- * Exposed for callers that have to know how old something is: a phantom order carries the block
9318
- * it was registered at, and only against the head does that become "still biddable" or "long
9319
- * expired".
9320
- */
9321
- async latestBlockNumber() {
9322
- const api = await this.http();
9323
- return (await api.rpc.chain.getHeader()).number.toNumber();
9324
- }
9325
- /**
9326
- * The pallet's phantom timings, read from chain state.
9327
- *
9328
- * Both are governance-settable and neither is derivable: on Nexus today the window is 15 while
9329
- * the runtime constant behind it is 25, so anything hard-coded is wrong in one direction or the
9330
- * other — too tight and live orders are dropped, too loose and bids are sent into a closed
9331
- * window for the pallet to reject.
9332
- *
9333
- * Read once per instance and cached, because a governance change to either is rare and a read
9334
- * per poll tick would be a request per tick forever. The cost is that a change is picked up on
9335
- * the next restart rather than immediately. A failed read is not cached, so it retries.
9336
- */
9337
- async phantomTimings() {
9338
- if (!this.phantomTimingsRead) {
9339
- this.phantomTimingsRead = this.readPhantomTimings().catch((err) => {
9340
- this.phantomTimingsRead = null;
9341
- throw err;
9342
- });
9343
- }
9344
- return this.phantomTimingsRead;
9345
- }
9346
- async readPhantomTimings() {
9347
- const api = await this.http();
9348
- const [window, interval] = await Promise.all([
9349
- api.query.intentsCoprocessor.phantomBidWindow(),
9350
- api.query.intentsCoprocessor.phantomOrderInterval()
9351
- ]);
9352
- const stored = Number(window.toString());
9353
- return {
9354
- bidWindowBlocks: stored === 0 ? Number(api.consts.intentsCoprocessor.phantomOrderBidWindowBlocks.toString()) : stored,
9355
- intervalBlocks: Number(interval.toString())
9356
- };
9357
- }
9358
- /**
9359
- * A whole range of blocks in one `state_queryStorage` call, or `null` when that is not available
9360
- * and the caller should read block by block.
9361
- *
9362
- * Two conditions have to hold, and both are about decoding rather than the range itself.
9363
- *
9364
- * The version must be confirmed for this tick — an upgrade inside the range means blocks decode
9365
- * against different metadata, and one call cannot do that.
9366
- *
9367
- * And that confirmed version must still be the one the api's own registry was built for.
9368
- * `state_queryStorage` declares no historic block hash, so rpc-core skips its registry swap and
9369
- * decodes the reply against the default registry — fixed at connect, with no
9370
- * `subscribeRuntimeVersion` on an HTTP api to refresh it. After an upgrade the two diverge, and
9371
- * the per-block path takes over for good: `api.at(hash, version)` resolves, and builds, the right
9372
- * registry. That costs a restart to get the cheap path back, which is the correct direction to
9373
- * fail in.
9374
- */
9375
- async scanRangeAtOnce(api, from, to, knownVersion, onError) {
9376
- if (this.rangeQueryUnavailable || !knownVersion) return null;
9377
- const registryVersion = api.runtimeVersion?.specVersion;
9378
- if (!registryVersion || !knownVersion.specVersion.eq(registryVersion)) return null;
9379
- const [fromHash, toHash] = from === to ? await Promise.all([api.rpc.chain.getBlockHash(from)]).then(([only]) => [only, only]) : await Promise.all([api.rpc.chain.getBlockHash(from), api.rpc.chain.getBlockHash(to)]);
9380
- try {
9381
- return await this.getPhantomOrdersInRange(fromHash.toHex(), toHash.toHex());
9382
- } catch (err) {
9383
- if (isMethodUnavailable(err)) {
9384
- this.rangeQueryUnavailable = true;
9385
- return null;
9386
- }
9387
- if (err instanceof EventDecodeError) {
9388
- this.rangeQueryUnavailable = true;
9389
- onError?.(err);
9390
- return null;
9391
- }
9392
- throw err;
9393
- }
9394
- }
9395
- /**
9396
- * The runtime version this tick's blocks may be decoded against, or `undefined` when that cannot
9397
- * be established and each block must resolve its own.
9398
- *
9399
- * Naming a version to `api.at` is what removes two of the four RPCs a block scan costs, and it
9400
- * is only sound while the version is actually the block's. Getting that wrong is not a loud
9401
- * failure: events decoded against the wrong metadata come back as a shape the scan does not
9402
- * recognise, so the block reads as carrying no phantom orders and the cursor advances past it —
9403
- * exactly the silent miss the block cursor exists to rule out.
9404
- *
9405
- * So the version is read fresh each tick and only used when it matches the previous reading.
9406
- * `specVersion` only ever increases, and this read happens *after* the head read, so two equal
9407
- * readings mean no upgrade landed anywhere in between — and therefore none in the range about to
9408
- * be scanned. A reading that differs means an upgrade landed inside the range: that tick falls
9409
- * back to per-block resolution, which is exact, and the version is used from the next tick on
9410
- * once it has been seen twice.
9411
- *
9412
- * The gap this leaves is a backlog reaching back past an upgrade, whose oldest blocks predate
9413
- * even the previous reading. Recovering from an outage that long means those bid windows closed
9414
- * many upgrades ago, so nothing is lost that was still winnable.
9415
- *
9416
- * A version that cannot be read at all yields `undefined` rather than an error: the scan is
9417
- * about to make the same request against the same endpoint and is the better place to report it.
9418
- */
9419
- async confirmedRuntimeVersion() {
9420
- let api;
9421
- let current;
9422
- try {
9423
- api = await this.http();
9424
- current = await api.rpc.state.getRuntimeVersion();
9425
- } catch {
9426
- return void 0;
9427
- }
9428
- const previous = this.lastRuntimeVersion ?? api.runtimeVersion;
9429
- this.lastRuntimeVersion = current;
9430
- if (!previous?.specVersion || !previous?.specName) return void 0;
9431
- return current.specVersion.eq(previous.specVersion) && current.specName.eq(previous.specName) ? current : void 0;
9432
- }
9433
- /**
9434
- * The poll cadence for the runtime this instance is connected to: Gargantua polls every block,
9435
- * everything else every 15s. Falls back to the slower cadence if the runtime cannot be read,
9436
- * since an unreachable node is the poll's problem to report, not the cadence lookup's.
9437
- */
9438
- async phantomPollIntervalMs() {
9439
- try {
9440
- const specName = (await this.http()).runtimeVersion.specName.toString();
9441
- return specName === "gargantua" ? GARGANTUA_PHANTOM_POLL_INTERVAL_MS : PHANTOM_POLL_INTERVAL_MS;
9442
- } catch {
9443
- return PHANTOM_POLL_INTERVAL_MS;
9444
- }
9445
- }
9446
- };
9447
- var TronChain = class _TronChain {
9448
- constructor(params, evm) {
9449
- this.params = params;
9450
- this.evm = evm;
9451
- this.tronWebInstance = new TronWeb({ fullHost: params.rpcUrl });
9452
- }
9453
- params;
9454
- evm;
9455
- tronWebInstance;
9456
- /**
9457
- * Creates a `TronChain` instance from a fully-specified config object.
9458
- *
9459
- * This is the only public way to construct a `TronChain` — the constructor is private.
9460
- *
9461
- * @param params - Tron chain configuration
9462
- * @returns A `TronChain` instance
9463
- */
9464
- static async fromParams(params) {
9465
- const evm = await EvmChain.create(params.rpcUrl, params.bundlerUrl);
9466
- return new _TronChain(params, evm);
9175
+ static async fromParams(params) {
9176
+ const evm = await EvmChain.create(params.rpcUrl, params.bundlerUrl);
9177
+ return new _TronChain(params, evm);
9467
9178
  }
9468
9179
  // -------------------------------------------------------------------------
9469
9180
  // Public accessors
@@ -10526,8 +10237,8 @@ var PharosChain = class _PharosChain {
10526
10237
  };
10527
10238
  async function generateRootWithProof(postRequest, treeSize) {
10528
10239
  const { generate_root_with_proof: generate_root_with_proof2 } = await load_ckb_mmr();
10529
- const { commitment: hash, encodePacked: encodePacked4 } = postRequestCommitment(postRequest);
10530
- const result = JSON.parse(generate_root_with_proof2(hexToBytes(encodePacked4), treeSize));
10240
+ const { commitment: hash, encodePacked: encodePacked5 } = postRequestCommitment(postRequest);
10241
+ const result = JSON.parse(generate_root_with_proof2(hexToBytes(encodePacked5), treeSize));
10531
10242
  const { root, proof, mmr_size, keccak_hash_calldata } = result;
10532
10243
  if (keccak_hash_calldata !== hash) {
10533
10244
  console.log("keccak_hash", keccak_hash_calldata);
@@ -10744,7 +10455,8 @@ async function retryPromise(operation, retryConfig) {
10744
10455
  return await operation();
10745
10456
  } catch (error) {
10746
10457
  if (shouldRetry && !shouldRetry(error)) throw error;
10747
- logger.trace(`Retrying(${i}) > ${logMessage}`);
10458
+ const detail = error instanceof Error ? error.message.split("\n")[0] : String(error);
10459
+ logger.trace(`Retrying(${i}) > ${logMessage}: ${detail.slice(0, 200)}`);
10748
10460
  lastError = error;
10749
10461
  if (i === retryConfig.maxRetries - 1) break;
10750
10462
  await new Promise((resolve) => setTimeout(resolve, retryConfig.backoffMs * 2 ** i));
@@ -12790,92 +12502,6 @@ query OrderStatus($commitment: String!) {
12790
12502
  }
12791
12503
  }
12792
12504
  }`;
12793
- var LATEST_PHANTOM_ORDER_PRICE_SNAPSHOT = `
12794
- query LatestPhantomOrderPriceSnapshot($tokenA: String!, $tokenB: String!) {
12795
- phantomOrderPriceSnapshots(
12796
- filter: {
12797
- and: [
12798
- { tokenA: { equalTo: $tokenA } }
12799
- { tokenB: { equalTo: $tokenB } }
12800
- { medianPrice: { isNull: false } }
12801
- ]
12802
- }
12803
- orderBy: BLOCK_NUMBER_DESC
12804
- first: 1
12805
- ) {
12806
- nodes {
12807
- commitment
12808
- tokenA
12809
- tokenB
12810
- standardAmount
12811
- blockNumber
12812
- medianPrice
12813
- lowestPrice
12814
- highestPrice
12815
- bidCount
12816
- snapshotTime
12817
- }
12818
- }
12819
- }`;
12820
- var AVAILABLE_LIQUIDITY = `
12821
- query AvailableLiquidity(
12822
- $poolId: String!
12823
- $sourceChain: String!
12824
- $destinationChain: String!
12825
- $direction: String!
12826
- ) {
12827
- poolChainLiquidities(
12828
- filter: {
12829
- and: [
12830
- { poolId: { equalToInsensitive: $poolId } }
12831
- { chain: { equalTo: $destinationChain } }
12832
- { direction: { equalTo: $direction } }
12833
- ]
12834
- }
12835
- first: 1
12836
- ) {
12837
- nodes {
12838
- depth
12839
- bidCount
12840
- unrestrictedDepth
12841
- unrestrictedBidCount
12842
- lastUpdatedAt
12843
- }
12844
- }
12845
- poolRoutes(
12846
- filter: {
12847
- and: [
12848
- { poolId: { equalToInsensitive: $poolId } }
12849
- { sourceChain: { equalTo: $sourceChain } }
12850
- { chain: { equalTo: $destinationChain } }
12851
- { direction: { equalTo: $direction } }
12852
- ]
12853
- }
12854
- first: 1
12855
- ) {
12856
- nodes {
12857
- depth
12858
- bidCount
12859
- lastUpdatedAt
12860
- }
12861
- }
12862
- }`;
12863
- var BUY_AND_SELL_RATES = `
12864
- query GetLiquidityPoolRate($poolId: String!) {
12865
- liquidityPools(
12866
- first: 1
12867
- filter: { id: { equalToInsensitive: $poolId } }
12868
- ) {
12869
- nodes {
12870
- id
12871
- token0Symbol
12872
- token1Symbol
12873
- sellRate
12874
- buyRate
12875
- lastUpdatedAt
12876
- }
12877
- }
12878
- }`;
12879
12505
  var TOKEN_GATEWAY_ASSET_TELEPORTED_STATUS = `
12880
12506
  query TokenGatewayAssetTeleportedStatus($commitment: String!) {
12881
12507
  tokenGatewayAssetTeleportedV2s(
@@ -12937,29 +12563,6 @@ async function queryAssetTeleported(params) {
12937
12563
  function queryGetRequest(params) {
12938
12564
  return _queryGetRequestInternal(params);
12939
12565
  }
12940
- async function _queryLatestPhantomOrderPriceSnapshot(params) {
12941
- const response = await params.queryClient.request(
12942
- LATEST_PHANTOM_ORDER_PRICE_SNAPSHOT,
12943
- {
12944
- tokenA: params.tokenA.toLowerCase(),
12945
- tokenB: params.tokenB.toLowerCase()
12946
- }
12947
- );
12948
- const snapshot = response.phantomOrderPriceSnapshots.nodes[0];
12949
- if (!snapshot?.medianPrice) return;
12950
- return {
12951
- commitment: snapshot.commitment,
12952
- tokenA: snapshot.tokenA,
12953
- tokenB: snapshot.tokenB,
12954
- standardAmount: BigInt(snapshot.standardAmount),
12955
- blockNumber: BigInt(snapshot.blockNumber),
12956
- medianPrice: BigInt(snapshot.medianPrice),
12957
- lowestPrice: snapshot.lowestPrice === null ? void 0 : BigInt(snapshot.lowestPrice),
12958
- highestPrice: snapshot.highestPrice === null ? void 0 : BigInt(snapshot.highestPrice),
12959
- bidCount: snapshot.bidCount,
12960
- snapshotTime: new Date(snapshot.snapshotTime)
12961
- };
12962
- }
12963
12566
  async function _queryTokenGatewayAssetTeleportedInternal(params) {
12964
12567
  const { commitmentHash, queryClient: client, logger = DEFAULT_LOGGER } = params;
12965
12568
  const response = await retryPromise(
@@ -16243,18 +15846,39 @@ var CryptoUtils = class _CryptoUtils {
16243
15846
  }
16244
15847
  /**
16245
15848
  * Derives the ERC-4337 nonce key that binds a bid UserOperation to its
16246
- * order and session key: the lower 192 bits of
16247
- * `keccak256(commitment ‖ sessionKey)`. `SolverAccount` rejects bid
16248
- * operations whose nonce key differs — this is what lets the solver sign
16249
- * the plain userOpHash while staying committed to the order and to the
16250
- * session key it bid against.
15849
+ * order, session key and calldata: the lower 192 bits of
15850
+ * `keccak256(commitment ‖ sessionKey ‖ keccak256(callData))`. `SolverAccount`
15851
+ * rejects bid operations whose nonce key differs — this is what lets the
15852
+ * solver sign the plain userOpHash while staying committed to the order and
15853
+ * to the session key it bid against.
15854
+ *
15855
+ * The calldata gives every bid its own key. A solver bidding several prices
15856
+ * on one order signs one op per price, and each is sequence 0 of its own key,
15857
+ * so they execute independently rather than in a sequence where one bid that
15858
+ * is never selected blocks the rest.
16251
15859
  *
16252
15860
  * @param commitment - The order commitment (`order.id`).
16253
15861
  * @param sessionKey - The order's session key address (`order.session`).
15862
+ * @param callData - The UserOperation's `callData`.
16254
15863
  * @returns The 192-bit nonce key as a bigint (pass to `EntryPoint.getNonce`).
16255
15864
  */
16256
- static bidNonceKey(commitment, sessionKey) {
16257
- return BigInt(keccak256(encodePacked(["bytes32", "address"], [commitment, sessionKey]))) & (1n << 192n) - 1n;
15865
+ static bidNonceKey(commitment, sessionKey, callData) {
15866
+ return BigInt(
15867
+ keccak256(
15868
+ encodePacked(["bytes32", "address", "bytes32"], [commitment, sessionKey, keccak256(callData)])
15869
+ )
15870
+ ) & (1n << 192n) - 1n;
15871
+ }
15872
+ /**
15873
+ * The identifier Hyperbridge files a bid under: `keccak256` of the UserOp's
15874
+ * `callData`. It is the same hash {@link bidNonceKey} takes, so a bid's
15875
+ * identifier and its nonce key both follow from the op itself, and one
15876
+ * solver's bids on one order are kept apart for the same reason on both sides.
15877
+ *
15878
+ * @param callData - The UserOperation's `callData`.
15879
+ */
15880
+ static bidId(callData) {
15881
+ return keccak256(callData);
16258
15882
  }
16259
15883
  /**
16260
15884
  * Builds the EIP-712 typed-data payload whose digest is the EntryPoint v0.8
@@ -16813,9 +16437,98 @@ var OrderPlacer = class {
16813
16437
  return { order: finalizedOrder, receipt };
16814
16438
  }
16815
16439
  };
16440
+ var TOKEN_KEYED_GATEWAY_ABI = parseAbi([
16441
+ "function _orders(bytes32 commitment, address token) view returns (uint256)",
16442
+ "function _partialFills(bytes32 commitment, bytes32 token) view returns (uint256)"
16443
+ ]);
16444
+ var keyingByClient = /* @__PURE__ */ new WeakMap();
16445
+ async function readLegEscrow(client, gateway, commitment, index, token) {
16446
+ return readKeyed(
16447
+ client,
16448
+ gateway,
16449
+ (keying) => keying === "leg" ? client.readContract({
16450
+ address: gateway,
16451
+ abi: ABI3,
16452
+ functionName: "_orders",
16453
+ args: [commitment, BigInt(index)]
16454
+ }) : client.readContract({
16455
+ address: gateway,
16456
+ abi: TOKEN_KEYED_GATEWAY_ABI,
16457
+ functionName: "_orders",
16458
+ args: [commitment, bytes32ToBytes20(token)]
16459
+ })
16460
+ );
16461
+ }
16462
+ async function readLegPartialFill(client, gateway, commitment, index, token) {
16463
+ return readKeyed(
16464
+ client,
16465
+ gateway,
16466
+ (keying) => keying === "leg" ? client.readContract({
16467
+ address: gateway,
16468
+ abi: ABI3,
16469
+ functionName: "_partialFills",
16470
+ args: [commitment, BigInt(index)]
16471
+ }) : client.readContract({
16472
+ address: gateway,
16473
+ abi: TOKEN_KEYED_GATEWAY_ABI,
16474
+ functionName: "_partialFills",
16475
+ args: [commitment, token]
16476
+ })
16477
+ );
16478
+ }
16479
+ async function readKeyed(client, gateway, read) {
16480
+ let known = keyingByClient.get(client);
16481
+ if (!known) {
16482
+ known = /* @__PURE__ */ new Map();
16483
+ keyingByClient.set(client, known);
16484
+ }
16485
+ const key = gateway.toLowerCase();
16486
+ const first = known.get(key) ?? "leg";
16487
+ try {
16488
+ const value = await read(first);
16489
+ known.set(key, first);
16490
+ return value;
16491
+ } catch (error) {
16492
+ if (!isRevert(error)) throw error;
16493
+ const second = first === "leg" ? "token" : "leg";
16494
+ try {
16495
+ const value = await read(second);
16496
+ known.set(key, second);
16497
+ return value;
16498
+ } catch (secondError) {
16499
+ throw isRevert(secondError) ? error : secondError;
16500
+ }
16501
+ }
16502
+ }
16503
+ function isRevert(error) {
16504
+ let current = error;
16505
+ while (current && typeof current === "object") {
16506
+ const item = current;
16507
+ if (item.name === "ContractFunctionZeroDataError") return true;
16508
+ if (item.code === 3) return true;
16509
+ if (!item.cause || typeof item.cause !== "object") {
16510
+ return /^(?:execution reverted\b|VM Exception while processing transaction:\s*revert\b|function selector was not recognized\b)/i.test(
16511
+ item.message ?? ""
16512
+ );
16513
+ }
16514
+ current = item.cause;
16515
+ }
16516
+ return false;
16517
+ }
16518
+ var PARTIAL_FILLS_SLOT = 11n;
16519
+ function partialFillSlot(commitment, index) {
16520
+ const inner = keccak256(encodePacked(["bytes32", "uint256"], [commitment, PARTIAL_FILLS_SLOT]));
16521
+ return keccak256(encodePacked(["uint256", "bytes32"], [BigInt(index), inner]));
16522
+ }
16816
16523
 
16817
16524
  // src/protocols/intents/OrderExecutor.ts
16818
16525
  var USED_USEROPS_STORAGE_KEY = (commitment) => `used-userops:${commitment.toLowerCase()}`;
16526
+ function remainingAfter(targets, filled) {
16527
+ return targets.map((target, index) => {
16528
+ const credited = filled[index]?.amount ?? 0n;
16529
+ return { token: target.token, amount: credited >= target.amount ? 0n : target.amount - credited };
16530
+ });
16531
+ }
16819
16532
  var OrderExecutor = class {
16820
16533
  constructor(ctx, bidManager) {
16821
16534
  this.ctx = ctx;
@@ -16865,6 +16578,38 @@ var OrderExecutor = class {
16865
16578
  JSON.stringify([...usedUserOps])
16866
16579
  );
16867
16580
  }
16581
+ /**
16582
+ * Reads the order's state on its destination chain into `totalFilledAssets`: the output credited
16583
+ * per leg from `_partialFills`, never below what is already counted, so a lagging RPC node cannot
16584
+ * take back a fill this executor has seen. Other solvers can fill the order too, so the chain, not
16585
+ * this executor's own fills, says how much is left.
16586
+ *
16587
+ * Returns the terminal update once `_filled` is set: `FILLED` when every leg is complete,
16588
+ * `CANCELLED` otherwise. `_filled` is read first because progress cannot change after it is set,
16589
+ * so a finalized order is never paired with progress from before its last fill.
16590
+ */
16591
+ async syncWithDestination(order, commitment, targetAssets, totalFilledAssets) {
16592
+ const client = this.ctx.dest.client;
16593
+ const gateway = this.ctx.dest.configService.getIntentGatewayAddress(normalizeStateMachineId(order.destination));
16594
+ const finalizer = await client.readContract({
16595
+ address: gateway,
16596
+ abi: ABI3,
16597
+ functionName: "_filled",
16598
+ args: [commitment]
16599
+ });
16600
+ const filled = await Promise.all(
16601
+ order.output.assets.map(async (asset, index) => {
16602
+ const credited = await readLegPartialFill(client, gateway, commitment, index, asset.token);
16603
+ const counted = totalFilledAssets[index]?.amount ?? 0n;
16604
+ return { token: asset.token, amount: credited > counted ? credited : counted };
16605
+ })
16606
+ );
16607
+ const remainingAssets = remainingAfter(targetAssets, filled);
16608
+ if (/^0x0{40}$/i.test(finalizer)) return { totalFilledAssets: filled, remainingAssets };
16609
+ const progress = { commitment, totalFilledAssets: filled, remainingAssets };
16610
+ const final = remainingAssets.every((asset) => asset.amount === 0n) ? { status: "FILLED", selectedSolver: finalizer, ...progress } : { status: "CANCELLED", ...progress };
16611
+ return { totalFilledAssets: filled, remainingAssets, final };
16612
+ }
16868
16613
  /**
16869
16614
  * Creates a closure that computes the deduplication hash key for a
16870
16615
  * UserOperation, pre-bound to the order's destination chain and entry point.
@@ -16923,12 +16668,12 @@ var OrderExecutor = class {
16923
16668
  }
16924
16669
  if (result.fillStatus === "partial") {
16925
16670
  const filledAssets = result.filledAssets ?? [];
16926
- totalFilledAssets = totalFilledAssets.map((a) => {
16927
- const filled = filledAssets.find((f) => f.token === a.token);
16671
+ totalFilledAssets = totalFilledAssets.map((a, index) => {
16672
+ const filled = filledAssets[index];
16928
16673
  return filled ? { token: a.token, amount: a.amount + filled.amount } : { ...a };
16929
16674
  });
16930
- remainingAssets = targetAssets.map((target) => {
16931
- const filled = totalFilledAssets.find((a) => a.token === target.token);
16675
+ remainingAssets = targetAssets.map((target, index) => {
16676
+ const filled = totalFilledAssets[index];
16932
16677
  const filledAmt = filled?.amount ?? 0n;
16933
16678
  return {
16934
16679
  token: target.token,
@@ -16994,8 +16739,27 @@ var OrderExecutor = class {
16994
16739
  const usedUserOps = await this.loadUsedUserOps(commitment);
16995
16740
  const userOpHashKey = this.createUserOpHasher(order);
16996
16741
  const targetAssets = order.output.assets.map((a) => ({ token: a.token, amount: a.amount }));
16997
- let totalFilledAssets = order.output.assets.map((a) => ({ token: a.token, amount: 0n }));
16998
- let remainingAssets = order.output.assets.map((a) => ({ token: a.token, amount: a.amount }));
16742
+ let initial;
16743
+ try {
16744
+ initial = await this.syncWithDestination(
16745
+ order,
16746
+ commitment,
16747
+ targetAssets,
16748
+ order.output.assets.map((a) => ({ token: a.token, amount: 0n }))
16749
+ );
16750
+ } catch (err) {
16751
+ yield {
16752
+ status: "FAILED",
16753
+ commitment,
16754
+ error: `Could not read the order on its destination chain: ${err instanceof Error ? err.message : String(err)}`
16755
+ };
16756
+ return;
16757
+ }
16758
+ if (initial.final) {
16759
+ yield initial.final;
16760
+ return;
16761
+ }
16762
+ const { totalFilledAssets, remainingAssets } = initial;
16999
16763
  const executionStream = this.executionStream({
17000
16764
  order,
17001
16765
  sessionPrivateKey,
@@ -17027,7 +16791,7 @@ var OrderExecutor = class {
17027
16791
  if (done) return;
17028
16792
  const fed = yield value;
17029
16793
  if (value.status === "BIDS_RECEIVED") input = fed;
17030
- if (value.status === "EXPIRED" || value.status === "FILLED") return;
16794
+ if (value.status === "EXPIRED" || value.status === "FILLED" || value.status === "CANCELLED") return;
17031
16795
  }
17032
16796
  } finally {
17033
16797
  console.log(`[OrderExecutor] Tearing down streams for commitment=${commitment}`);
@@ -17086,18 +16850,29 @@ var OrderExecutor = class {
17086
16850
  }
17087
16851
  while (true) {
17088
16852
  let freshBids;
16853
+ let final;
17089
16854
  try {
17090
- const bids2 = await this.fetchBids({ commitment, solver, solverLockStartTime });
17091
- freshBids = bids2.filter(isFreshBid);
16855
+ ;
16856
+ ({ totalFilledAssets, remainingAssets, final } = await this.syncWithDestination(
16857
+ order,
16858
+ commitment,
16859
+ targetAssets,
16860
+ totalFilledAssets
16861
+ ));
16862
+ freshBids = final ? [] : (await this.fetchBids({ commitment, solver, solverLockStartTime })).filter(isFreshBid);
17092
16863
  } catch {
17093
16864
  await sleep(pollIntervalMs);
17094
16865
  continue;
17095
16866
  }
16867
+ if (final) {
16868
+ yield final;
16869
+ return;
16870
+ }
17096
16871
  if (freshBids.length === 0) {
17097
16872
  await sleep(pollIntervalMs);
17098
16873
  continue;
17099
16874
  }
17100
- const bids = this.bidManager.buildBids(order, freshBids, sessionPrivateKey);
16875
+ const bids = this.bidManager.buildBids(order, freshBids, sessionPrivateKey).filter((bid) => servesOpenLeg(bid, remainingAssets));
17101
16876
  if (bids.length === 0) {
17102
16877
  await sleep(pollIntervalMs);
17103
16878
  continue;
@@ -17140,6 +16915,10 @@ var OrderExecutor = class {
17140
16915
  }
17141
16916
  }
17142
16917
  };
16918
+ function servesOpenLeg(bid, remainingAssets) {
16919
+ if (bid.outputs.length !== remainingAssets.length) return true;
16920
+ return bid.outputs.some((output, leg) => output.amount > 0n && remainingAssets[leg].amount > 0n);
16921
+ }
17143
16922
  var OrderCanceller = class _OrderCanceller {
17144
16923
  /**
17145
16924
  * @param ctx - Shared IntentsV2 context providing the source and destination
@@ -17178,8 +16957,9 @@ var OrderCanceller = class _OrderCanceller {
17178
16957
  /**
17179
16958
  * Quotes the native token cost of a source-initiated cross-chain cancellation.
17180
16959
  *
17181
- * Constructs a mock ISMP GET request for the destination commitment slot and
17182
- * calls `quoteNative` on the source host to obtain the dispatch fee.
16960
+ * Constructs the ISMP GET request the source gateway will dispatch, one
16961
+ * `_partialFills` key per leg, and calls `quoteNative` on the source host to
16962
+ * obtain the dispatch fee.
17183
16963
  * Returns 0 for same-chain orders (no ISMP call needed).
17184
16964
  *
17185
16965
  * @param order - The order to quote.
@@ -17193,21 +16973,16 @@ var OrderCanceller = class _OrderCanceller {
17193
16973
  }
17194
16974
  const height = order.deadline + 1n;
17195
16975
  const destIntentGateway = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachine);
17196
- const slotHash = await this.ctx.dest.client.readContract({
17197
- abi: ABI3,
17198
- address: destIntentGateway,
17199
- functionName: "calculateCommitmentSlotHash",
17200
- args: [order.id]
17201
- });
17202
- const key = concatHex([destIntentGateway, slotHash]);
17203
- const context = encodeWithdrawalRequest(order, order.user);
16976
+ const commitment = this.orderId(order);
16977
+ const keys = order.inputs.map((_, index) => concatHex([destIntentGateway, partialFillSlot(commitment, index)]));
16978
+ const context = cancelFromSourceContext(order, commitment);
17204
16979
  const getRequest = {
17205
16980
  source: sourceStateMachine,
17206
16981
  dest: destStateMachine,
17207
16982
  from: this.ctx.source.configService.getIntentGatewayAddress(destStateMachine),
17208
16983
  nonce: await this.ctx.source.getHostNonce(),
17209
16984
  height,
17210
- keys: [key],
16985
+ keys,
17211
16986
  timeoutTimestamp: 0n,
17212
16987
  context
17213
16988
  };
@@ -17232,10 +17007,13 @@ var OrderCanceller = class _OrderCanceller {
17232
17007
  *
17233
17008
  * @param order - The order to cancel.
17234
17009
  * @param indexerClient - Indexer client used to stream ISMP request status
17235
- * updates and query state-machine heights.
17236
- * @param options - Choose the initiation side. Defaults to source-side cancellation.
17010
+ * updates and query state-machine heights. The direct same-chain route does
17011
+ * not access it.
17012
+ * @param options - Choose the initiation side. Defaults to source-side
17013
+ * cancellation. Same-chain orders always use the direct local route.
17237
17014
  * @yields {@link CancelEvent} objects describing each stage of the
17238
- * cancellation lifecycle.
17015
+ * cancellation lifecycle. The caller signs or broadcasts the yielded
17016
+ * transaction, so its signer may differ from `order.user` after expiry.
17239
17017
  */
17240
17018
  async *cancelOrder(order, indexerClient, options = {}) {
17241
17019
  const sourceStateMachine = normalizeStateMachineId(order.source);
@@ -17269,9 +17047,12 @@ var OrderCanceller = class _OrderCanceller {
17269
17047
  * Async generator that cancels an order by initiating the cancel from the
17270
17048
  * source chain.
17271
17049
  *
17272
- * **Same-chain path:** encodes a direct `cancelOrder` call, yields
17273
- * `AWAITING_CANCEL_TRANSACTION`, broadcasts the signed transaction, and
17274
- * yields `CANCELLATION_COMPLETE` after confirming the `EscrowRefunded` event.
17050
+ * **Same-chain path:** encodes a direct `cancelOrder` call with zero cancel
17051
+ * options, yields `AWAITING_CANCEL_TRANSACTION`, accepts either a signed raw
17052
+ * transaction or an already-broadcast hash, and yields `CANCELLATION_COMPLETE`
17053
+ * after confirming the `EscrowRefunded` event. The contract authorizes the
17054
+ * order user through the deadline and any caller strictly after it; the SDK
17055
+ * preserves `order.user` in calldata so a third party cannot redirect escrow.
17275
17056
  *
17276
17057
  * **Cross-chain path:**
17277
17058
  * 1. Fetches (or resumes from cache) a destination finalization proof.
@@ -17581,9 +17362,9 @@ var OrderCanceller = class _OrderCanceller {
17581
17362
  }
17582
17363
  }
17583
17364
  /**
17584
- * Polls for a finalized destination-chain state proof that demonstrates
17585
- * the order commitment slot is unset (i.e. the order was not filled before
17586
- * the deadline).
17365
+ * Polls for a finalized destination-chain state proof of every leg's
17366
+ * `_partialFills` slot, i.e. how much of the order was filled before the
17367
+ * deadline.
17587
17368
  *
17588
17369
  * Waits until the latest Hyperbridge-tracked state-machine height exceeds
17589
17370
  * `order.deadline` (or the last failed probe height) before attempting to
@@ -17612,14 +17393,9 @@ var OrderCanceller = class _OrderCanceller {
17612
17393
  const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayAddress(
17613
17394
  this.ctx.dest.config.stateMachineId
17614
17395
  );
17615
- const orderId = this.orderId(order);
17616
- const slotHash = await this.ctx.dest.client.readContract({
17617
- abi: ABI3,
17618
- address: intentGatewayV2Address,
17619
- functionName: "calculateCommitmentSlotHash",
17620
- args: [orderId]
17621
- });
17622
- const proofHex = await this.ctx.dest.queryStateProof(latestHeight, [slotHash], intentGatewayV2Address);
17396
+ const commitment = this.orderId(order);
17397
+ const slots = order.inputs.map((_, index) => partialFillSlot(commitment, index));
17398
+ const proofHex = await this.ctx.dest.queryStateProof(latestHeight, slots, intentGatewayV2Address);
17623
17399
  const proof = {
17624
17400
  consensusStateId: this.ctx.dest.config.consensusStateId,
17625
17401
  height: latestHeight,
@@ -17817,118 +17593,135 @@ var OrderCanceller = class _OrderCanceller {
17817
17593
  return feeInDestFeeToken * 1005n / 1000n;
17818
17594
  }
17819
17595
  };
17820
- var FILL_ORDER_V1_ABI = [
17821
- {
17822
- type: "function",
17823
- name: "fillOrder",
17824
- stateMutability: "payable",
17825
- outputs: [],
17826
- inputs: [
17827
- ABI3.find((e) => e.type === "function" && e.name === "fillOrder").inputs[0],
17596
+ function cancelFromSourceContext(order, commitment) {
17597
+ return encodeAbiParameters(
17598
+ [
17599
+ { type: "bytes32" },
17600
+ { type: "bytes32" },
17828
17601
  {
17829
- name: "options",
17830
- type: "tuple",
17831
- internalType: "struct FillOptions",
17602
+ type: "tuple[]",
17832
17603
  components: [
17833
- { name: "relayerFee", type: "uint256", internalType: "uint256" },
17834
- { name: "nativeDispatchFee", type: "uint256", internalType: "uint256" },
17835
- {
17836
- name: "outputs",
17837
- type: "tuple[]",
17838
- internalType: "struct TokenInfo[]",
17839
- components: [
17840
- { name: "token", type: "bytes32", internalType: "bytes32" },
17841
- { name: "amount", type: "uint256", internalType: "uint256" }
17842
- ]
17843
- }
17604
+ { name: "token", type: "bytes32" },
17605
+ { name: "amount", type: "uint256" }
17844
17606
  ]
17845
- }
17607
+ },
17608
+ { type: "uint256[]" }
17609
+ ],
17610
+ [
17611
+ commitment,
17612
+ bytes20ToBytes32(order.user),
17613
+ order.inputs.map((input) => ({ token: normalizeAddressForEvmBytes32(input.token), amount: input.amount })),
17614
+ order.output.assets.map((asset) => asset.amount)
17846
17615
  ]
17616
+ );
17617
+ }
17618
+ var FILL_ORDER_SELECTOR = "0x68ddf058";
17619
+ var SUPPORTED_INTENTS_VERSION = 3n;
17620
+ var CONTRACT_VERSION_ABI = [
17621
+ {
17622
+ type: "function",
17623
+ name: "version",
17624
+ stateMutability: "view",
17625
+ inputs: [],
17626
+ outputs: [{ name: "", type: "uint64" }]
17847
17627
  }
17848
17628
  ];
17849
- var ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
17850
- var LEGACY_FILL_OPTIONS_IMPLEMENTATIONS = /* @__PURE__ */ new Set([
17851
- // The pre-validUntil IntentGatewayV2 implementation. One entry covers every chain: the
17852
- // protocol contracts are CREATE2-deployed, so this is the implementation address on all
17853
- // of them (confirmed with the maintainers).
17854
- "0x976b268b06f545c4a2bf44866aa2465bd8b3c67d"
17855
- ]);
17856
- var CHAINS_WITHOUT_VALID_UNTIL = /* @__PURE__ */ new Set([
17857
- 97,
17858
- // BNB testnet
17859
- 10200,
17860
- // Gnosis Chiado
17861
- 80002,
17862
- // Polygon Amoy
17863
- 84532,
17864
- // Base Sepolia
17865
- 421614,
17866
- // Arbitrum Sepolia
17867
- 688689,
17868
- // Pharos testnet
17869
- 11155111,
17870
- // Sepolia
17871
- 11155420,
17872
- // Optimism Sepolia
17873
- 420420417
17874
- // Polkadot Hub Paseo
17875
- ]);
17876
- var knownV2Gateways = /* @__PURE__ */ new Set();
17877
- function resetFillOptionsVersionCache() {
17878
- knownV2Gateways.clear();
17629
+ async function readContractVersion(client, address) {
17630
+ try {
17631
+ return await client.readContract({ address, abi: CONTRACT_VERSION_ABI, functionName: "version" });
17632
+ } catch (error) {
17633
+ if (isRevert(error)) return void 0;
17634
+ throw error;
17635
+ }
17879
17636
  }
17880
- async function resolveImplementation(client, gateway) {
17881
- const slot = await client.getStorageAt({ address: gateway, slot: ERC1967_IMPLEMENTATION_SLOT });
17882
- if (!slot || slot.length < 66) return gateway;
17883
- const addr = `0x${slot.slice(-40)}`;
17884
- return /^0x0{40}$/.test(addr) ? gateway : addr;
17637
+ async function supportsRateFills(client, gateway) {
17638
+ return await readContractVersion(client, gateway) === SUPPORTED_INTENTS_VERSION;
17885
17639
  }
17886
- async function getFillOptionsVersion(client, gateway) {
17887
- const chainId = client.chain?.id;
17888
- if (chainId !== void 0 && CHAINS_WITHOUT_VALID_UNTIL.has(chainId)) return 1;
17889
- const key = gateway.toLowerCase();
17890
- if (knownV2Gateways.has(key)) return 2;
17891
- const implementation = await resolveImplementation(client, gateway);
17892
- if (LEGACY_FILL_OPTIONS_IMPLEMENTATIONS.has(implementation.toLowerCase())) return 1;
17893
- knownV2Gateways.add(key);
17894
- return 2;
17640
+ async function assertGatewayRelease(client, gateway) {
17641
+ const version = await readContractVersion(client, gateway);
17642
+ if (version === SUPPORTED_INTENTS_VERSION) return;
17643
+ throw new Error(
17644
+ version === void 0 ? `IntentGateway ${gateway} reports no version(); this SDK requires release ${SUPPORTED_INTENTS_VERSION}` : `IntentGateway ${gateway} reports release ${String(version)}; this SDK requires release ${SUPPORTED_INTENTS_VERSION}`
17645
+ );
17895
17646
  }
17896
- function encodeFillOrder(order, options, version) {
17897
- if (version === 2) {
17898
- return encodeFunctionData({
17899
- abi: ABI3,
17900
- functionName: "fillOrder",
17901
- args: [order, options]
17902
- });
17647
+ var CANONICAL_EVM_TOKEN = /^0x0{24}[0-9a-fA-F]{40}$/;
17648
+ function isCanonicalEvmToken(token) {
17649
+ return CANONICAL_EVM_TOKEN.test(token);
17650
+ }
17651
+ function validateFillQuotes(order, options) {
17652
+ const count = order.output.assets.length;
17653
+ if (!count || !Array.isArray(options.inputs) || options.inputs.length !== count || options.outputs.length !== count || order.inputs.length !== count) {
17654
+ throw new Error("Fill inputs and outputs must quote every order leg");
17655
+ }
17656
+ for (let i = 0; i < count; i++) {
17657
+ const input = options.inputs[i];
17658
+ const output = options.outputs[i];
17659
+ if (input.token.toLowerCase() !== order.inputs[i].token.toLowerCase() || output.token.toLowerCase() !== order.output.assets[i].token.toLowerCase() || !isCanonicalEvmToken(input.token) || !isCanonicalEvmToken(output.token)) {
17660
+ throw new Error("Fill quote tokens must match their order legs");
17661
+ }
17662
+ if (input.amount === 0n !== (output.amount === 0n)) {
17663
+ throw new Error("Fill quote input and output must both be zero or positive");
17664
+ }
17903
17665
  }
17904
- const { relayerFee, nativeDispatchFee, outputs } = options;
17666
+ }
17667
+ function encodeFillOrder(order, options) {
17668
+ validateFillQuotes(order, options);
17905
17669
  return encodeFunctionData({
17906
- abi: FILL_ORDER_V1_ABI,
17670
+ abi: ABI3,
17907
17671
  functionName: "fillOrder",
17908
- args: [order, { relayerFee, nativeDispatchFee, outputs }]
17672
+ args: [order, options]
17909
17673
  });
17910
17674
  }
17911
17675
  function decodeFillOrder(data) {
17912
17676
  try {
17913
17677
  const decoded = decodeFunctionData({ abi: ABI3, data });
17914
- if (decoded.functionName === "fillOrder" && decoded.args && decoded.args.length >= 2) {
17915
- return { order: decoded.args[0], options: decoded.args[1] };
17916
- }
17917
- } catch {
17918
- }
17919
- try {
17920
- const decoded = decodeFunctionData({ abi: FILL_ORDER_V1_ABI, data });
17921
- if (decoded.functionName === "fillOrder" && decoded.args && decoded.args.length >= 2) {
17922
- const legacy = decoded.args[1];
17923
- return { order: decoded.args[0], options: { ...legacy, validUntil: 0n } };
17924
- }
17678
+ if (decoded.functionName !== "fillOrder" || !decoded.args || decoded.args.length < 2) return null;
17679
+ const order = decoded.args[0];
17680
+ const options = decoded.args[1];
17681
+ validateFillQuotes(order, options);
17682
+ return { order, options };
17925
17683
  } catch {
17684
+ return null;
17926
17685
  }
17927
- return null;
17928
17686
  }
17929
- var BidImpl = class {
17930
- solverAddress;
17687
+ var ENTRY_POINT_EVENT_ABI = [
17688
+ { type: "event", name: "BeforeExecution", inputs: [] },
17689
+ {
17690
+ type: "event",
17691
+ name: "UserOperationEvent",
17692
+ inputs: [
17693
+ { name: "userOpHash", type: "bytes32", indexed: true },
17694
+ { name: "sender", type: "address", indexed: true },
17695
+ { name: "paymaster", type: "address", indexed: true },
17696
+ { name: "nonce", type: "uint256", indexed: false },
17697
+ { name: "success", type: "bool", indexed: false },
17698
+ { name: "actualGasCost", type: "uint256", indexed: false },
17699
+ { name: "actualGasUsed", type: "uint256", indexed: false }
17700
+ ]
17701
+ }
17702
+ ];
17703
+ function userOperationLogs(logs, entryPoint, userOpHash) {
17704
+ const [beforeExecution, userOperationEvent] = ENTRY_POINT_EVENT_ABI.map((event) => toEventSelector(event));
17705
+ const isBoundary = (log) => log.address.toLowerCase() === entryPoint.toLowerCase() && (log.topics[0] === beforeExecution || log.topics[0] === userOperationEvent);
17706
+ const end = logs.findIndex(
17707
+ (log) => isBoundary(log) && log.topics[0] === userOperationEvent && log.topics[1]?.toLowerCase() === userOpHash.toLowerCase()
17708
+ );
17709
+ if (end === -1) throw new Error(`UserOperation ${userOpHash} is not in the transaction`);
17710
+ const { args } = decodeEventLog({
17711
+ abi: ENTRY_POINT_EVENT_ABI,
17712
+ eventName: "UserOperationEvent",
17713
+ data: logs[end].data,
17714
+ topics: logs[end].topics
17715
+ });
17716
+ if (!args.success) throw new Error(`UserOperation ${userOpHash} reverted`);
17717
+ let start = end - 1;
17718
+ while (start >= 0 && !isBoundary(logs[start])) start--;
17719
+ return logs.slice(start + 1, end);
17720
+ }
17721
+ var BidImpl = class {
17722
+ solverAddress;
17931
17723
  outputs;
17724
+ inputs;
17932
17725
  relayerFee;
17933
17726
  nativeDispatchFee;
17934
17727
  userOp;
@@ -17951,6 +17744,7 @@ var BidImpl = class {
17951
17744
  this.sessionPrivateKey = params.sessionPrivateKey;
17952
17745
  this.solverAddress = params.fillerBid.userOp.sender;
17953
17746
  this.outputs = params.fillOptions.outputs;
17747
+ this.inputs = params.fillOptions.inputs;
17954
17748
  this.relayerFee = params.fillOptions.relayerFee;
17955
17749
  this.nativeDispatchFee = params.fillOptions.nativeDispatchFee;
17956
17750
  this.userOp = params.fillerBid.userOp;
@@ -18083,31 +17877,28 @@ var BidImpl = class {
18083
17877
  { maxRetries: 5, backoffMs: 2e3, logMessage: "Fetching user operation receipt" }
18084
17878
  );
18085
17879
  txnHash = receipt.receipt.transactionHash;
18086
- try {
18087
- const chainReceipt = await this.ctx.dest.client.waitForTransactionReceipt({
18088
- hash: txnHash,
18089
- confirmations: 1
18090
- });
18091
- const events = parseEventLogs({
18092
- abi: ABI3,
18093
- logs: chainReceipt.logs,
18094
- eventName: ["OrderFilled", "PartialFill"]
18095
- });
18096
- const matched = events.find((e) => {
18097
- if (e.eventName === "OrderFilled")
18098
- return e.args.commitment.toLowerCase() === commitment.toLowerCase();
18099
- if (e.eventName === "PartialFill")
18100
- return e.args.commitment.toLowerCase() === commitment.toLowerCase();
18101
- return false;
18102
- });
18103
- if (matched?.eventName === "OrderFilled") {
18104
- fillStatus = "full";
18105
- } else if (matched?.eventName === "PartialFill") {
18106
- fillStatus = "partial";
18107
- filledAssets = matched.args.outputs ?? [];
18108
- }
18109
- } catch {
18110
- throw new Error("Failed to determine fill status from logs");
17880
+ const chainReceipt = await this.ctx.dest.client.waitForTransactionReceipt({
17881
+ hash: txnHash,
17882
+ confirmations: 1
17883
+ });
17884
+ const gateway = this.ctx.dest.configService.getIntentGatewayAddress(
17885
+ normalizeStateMachineId(this.order.destination)
17886
+ );
17887
+ const fills = parseEventLogs({
17888
+ abi: ABI3,
17889
+ logs: userOperationLogs(chainReceipt.logs, entryPointAddress, userOpHash),
17890
+ eventName: ["OrderFilled", "PartialFill"]
17891
+ }).filter(
17892
+ (event) => event.address.toLowerCase() === gateway.toLowerCase() && event.args.commitment.toLowerCase() === commitment.toLowerCase()
17893
+ );
17894
+ if (fills.some((event) => event.eventName === "OrderFilled")) {
17895
+ fillStatus = "full";
17896
+ } else if (fills.length > 0) {
17897
+ fillStatus = "partial";
17898
+ filledAssets = fills[0].args.outputs.map(({ token }, index) => ({
17899
+ token,
17900
+ amount: fills.reduce((sum, event) => sum + (event.args.outputs[index]?.amount ?? 0n), 0n)
17901
+ }));
18111
17902
  }
18112
17903
  } catch (err) {
18113
17904
  throw new Error(`Failed to execute bid: ${err instanceof Error ? err.message : String(err)}`);
@@ -18174,6 +17965,20 @@ var BidManager = class {
18174
17965
  callData,
18175
17966
  paymasterAndData = "0x"
18176
17967
  } = options;
17968
+ const fills = (this.crypto.decodeERC7821Execute(callData) ?? []).filter(
17969
+ (call) => call.data.slice(0, 10).toLowerCase() === FILL_ORDER_SELECTOR
17970
+ );
17971
+ if (fills.length === 0) throw new Error("Bid calldata carries no fillOrder call");
17972
+ for (const call of fills) {
17973
+ if (!decodeFillOrder(call.data)) {
17974
+ throw new Error("Malformed fill quote; every leg requires inputs and outputs");
17975
+ }
17976
+ }
17977
+ const chain = normalizeStateMachineId(order.destination);
17978
+ const gateway = this.ctx.dest.configService.getIntentGatewayAddress(chain);
17979
+ if (!await supportsRateFills(this.ctx.dest.client, gateway)) {
17980
+ throw new Error("Fills are not supported by the destination gateway");
17981
+ }
18177
17982
  const chainId = BigInt(
18178
17983
  this.ctx.dest.client.chain?.id ?? Number.parseInt(this.ctx.dest.config.stateMachineId.split("-")[1])
18179
17984
  );
@@ -18191,10 +17996,10 @@ var BidManager = class {
18191
17996
  signature: "0x"
18192
17997
  };
18193
17998
  const nonceKey = BigInt(nonce) >> 64n;
18194
- const expectedKey = CryptoUtils.bidNonceKey(order.id, order.session);
17999
+ const expectedKey = CryptoUtils.bidNonceKey(order.id, order.session, callData);
18195
18000
  if (nonceKey !== expectedKey) {
18196
18001
  console.warn(
18197
- `[BidManager] bid nonce key does not bind the order commitment and session key; on-chain validation will fail (order=${order.id})`
18002
+ `[BidManager] bid nonce key does not bind the order commitment, session key and calldata; on-chain validation will fail (order=${order.id})`
18198
18003
  );
18199
18004
  }
18200
18005
  const solverSignature = await solverSigner.signTypedData(
@@ -18259,7 +18064,7 @@ var BidManager = class {
18259
18064
  return this.selectAndExecuteBest(order, this.buildBids(order, bids, sessionPrivateKey));
18260
18065
  }
18261
18066
  /**
18262
- * Autopilot bid selection: sorts the given bids by output value, simulates
18067
+ * Autopilot bid selection: sorts the given bids by rate, simulates
18263
18068
  * each in order and attempts execution. Any bid that fails simulation or
18264
18069
  * execution is skipped once so the next ranked bid can be attempted in the
18265
18070
  * same round. For consumers that do not need custom selection logic.
@@ -18314,35 +18119,58 @@ var BidManager = class {
18314
18119
  throw new Error("No bids passed simulation and execution");
18315
18120
  }
18316
18121
  /**
18317
- * Sorts a list of bids for the given order by output value.
18122
+ * Sorts bids by rate, best to worst, independently of how much each one fills.
18318
18123
  *
18319
- * Delegates to one of three strategies based on the order's output token
18320
- * composition:
18321
- * - Single output token: sort by offered amount descending.
18322
- * - All stable outputs (USDC/USDT): sort by normalised USD value descending.
18323
- * - Mixed outputs: sort by DEX-quoted USD value descending, with a raw-amount
18324
- * fallback if pricing fails.
18124
+ * A leg's rate is what the bid pays out for what it takes: `output / input` for
18125
+ * that leg. Every leg of an order trades the same pair, so a bid's rate is its
18126
+ * total output over its total input across the legs it quotes. Rates are
18127
+ * compared exactly, by cross-multiplication; equal rates keep arrival order.
18325
18128
  *
18326
- * Bids that cannot satisfy the order's token set are dropped.
18129
+ * A bid is dropped when it does not quote the order's legs one for one, names
18130
+ * another token on a leg, quotes an input without an output (or the reverse),
18131
+ * quotes no leg at all, or quotes a leg below the rate the order requires.
18327
18132
  *
18328
- * @param order - The placed order whose output spec drives sorting logic.
18133
+ * @param order - The placed order the bids compete to fill.
18329
18134
  * @param bids - Executable bids to sort (from {@link buildBids}).
18330
- * @returns Sorted array of `Bid` objects ready for simulation.
18135
+ * @returns The valid bids, best rate first, ready for simulation.
18331
18136
  */
18332
18137
  async sortBids(order, bids) {
18333
- const outputs = order.output.assets;
18334
- if (outputs.length <= 1) {
18335
- console.log(`[BidManager] Using single-output sorting (1 output asset)`);
18336
- return this.sortSingleOutput(bids, outputs[0]);
18337
- }
18338
- const chainId = this.ctx.dest.config.stateMachineId;
18339
- const allStables = outputs.every((o) => this.isStableToken(bytes32ToBytes20(o.token), chainId));
18340
- if (allStables) {
18341
- console.log(`[BidManager] Using all-stables sorting (${outputs.length} stable output assets)`);
18342
- return this.sortAllStables(bids, outputs, chainId);
18138
+ const legs = order.inputs.length;
18139
+ const ranked = [];
18140
+ for (const [index, bid] of bids.entries()) {
18141
+ if (bid.inputs.length !== legs || bid.outputs.length !== legs || order.output.assets.length !== legs) {
18142
+ console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: does not quote the order's legs`);
18143
+ continue;
18144
+ }
18145
+ let input = 0n;
18146
+ let output = 0n;
18147
+ let reason = "";
18148
+ for (let leg = 0; leg < legs && !reason; leg++) {
18149
+ const take = bid.inputs[leg];
18150
+ const pay = bid.outputs[leg];
18151
+ const escrow = order.inputs[leg];
18152
+ const required = order.output.assets[leg];
18153
+ if (take.token.toLowerCase() !== escrow.token.toLowerCase()) reason = `input token mismatch on leg ${leg}`;
18154
+ else if (pay.token.toLowerCase() !== required.token.toLowerCase()) reason = `output token mismatch on leg ${leg}`;
18155
+ else if (take.amount < 0n || pay.amount < 0n || take.amount === 0n !== (pay.amount === 0n))
18156
+ reason = `no valid quote on leg ${leg}`;
18157
+ else if (pay.amount * escrow.amount < take.amount * required.amount) reason = `rate below the order on leg ${leg}`;
18158
+ input += take.amount;
18159
+ output += pay.amount;
18160
+ }
18161
+ if (!reason && input === 0n) reason = "quotes no leg";
18162
+ if (reason) {
18163
+ console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: ${reason}`);
18164
+ continue;
18165
+ }
18166
+ ranked.push({ bid, input, output, index });
18343
18167
  }
18344
- console.log(`[BidManager] Using mixed-output sorting (${outputs.length} output assets, some non-stable)`);
18345
- return this.sortMixedOutputs(bids, outputs, chainId);
18168
+ ranked.sort((a, b) => {
18169
+ const left = a.output * b.input;
18170
+ const right = b.output * a.input;
18171
+ return left === right ? a.index - b.index : left > right ? -1 : 1;
18172
+ });
18173
+ return ranked.map(({ bid }) => bid);
18346
18174
  }
18347
18175
  /**
18348
18176
  * Extracts the `FillOptions` struct from a single bid's ERC-7821
@@ -18365,150 +18193,6 @@ var BidManager = class {
18365
18193
  }
18366
18194
  return null;
18367
18195
  }
18368
- /**
18369
- * Case A: single output token.
18370
- * Filter bids by token match only, sort descending by amount.
18371
- * Partial fill bids are allowed — the contract determines fill status.
18372
- */
18373
- sortSingleOutput(bids, requiredAsset) {
18374
- const requiredAmount = new Decimal2(requiredAsset.amount.toString());
18375
- console.log(
18376
- `[BidManager] sortSingleOutput: required token=${requiredAsset.token}, amount=${requiredAmount.toString()}`
18377
- );
18378
- const validBids = [];
18379
- for (const bid of bids) {
18380
- const bidOutput = bid.outputs[0];
18381
- const bidAmount = new Decimal2(bidOutput.amount.toString());
18382
- if (bidOutput.token.toLowerCase() !== requiredAsset.token.toLowerCase()) {
18383
- console.warn(
18384
- `[BidManager] Bid from solver=${bid.solverAddress} REJECTED: token mismatch (bid=${bidOutput.token}, required=${requiredAsset.token})`
18385
- );
18386
- continue;
18387
- }
18388
- if (bidAmount.lt(requiredAmount)) {
18389
- console.log(
18390
- `[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (bid=${bidAmount.toString()}, required=${requiredAmount.toString()}, covers=${bidAmount.div(requiredAmount).mul(100).toFixed(2)}%)`
18391
- );
18392
- } else {
18393
- console.log(
18394
- `[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED: amount=${bidAmount.toString()} (surplus=${bidAmount.minus(requiredAmount).toString()})`
18395
- );
18396
- }
18397
- validBids.push({ bid, amount: bidOutput.amount });
18398
- }
18399
- validBids.sort((a, b) => {
18400
- const aAmt = new Decimal2(a.amount.toString());
18401
- const bAmt = new Decimal2(b.amount.toString());
18402
- return bAmt.comparedTo(aAmt);
18403
- });
18404
- return validBids.map(({ bid }) => bid);
18405
- }
18406
- /**
18407
- * Case B: all outputs are USDC/USDT.
18408
- * Sum normalised USD values (treating each stable as $1) and sort descending.
18409
- * Partial fill bids are allowed.
18410
- */
18411
- sortAllStables(bids, orderOutputs, chainId) {
18412
- const requiredUsd = this.computeStablesUsdValue(orderOutputs, chainId);
18413
- console.log(`[BidManager] sortAllStables: required USD value=${requiredUsd.toString()}`);
18414
- const validBids = [];
18415
- for (const bid of bids) {
18416
- const bidUsd = this.computeStablesUsdValue(bid.outputs, chainId);
18417
- if (bidUsd === null) {
18418
- console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: unable to compute USD value`);
18419
- continue;
18420
- }
18421
- if (bidUsd.lt(requiredUsd)) {
18422
- console.log(
18423
- `[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (bid=${bidUsd.toString()}, required=${requiredUsd.toString()}, covers=${bidUsd.div(requiredUsd).mul(100).toFixed(2)}%)`
18424
- );
18425
- } else {
18426
- console.log(`[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED: USD value=${bidUsd.toString()}`);
18427
- }
18428
- validBids.push({ bid, usdValue: bidUsd });
18429
- }
18430
- validBids.sort((a, b) => b.usdValue.comparedTo(a.usdValue));
18431
- return validBids.map(({ bid }) => bid);
18432
- }
18433
- /**
18434
- * Case C: mixed output tokens (at least one non-stable).
18435
- * Price every token via on-chain DEX quotes, fall back to raw amounts
18436
- * if pricing is unavailable. Partial fill bids are allowed.
18437
- */
18438
- async sortMixedOutputs(bids, orderOutputs, chainId) {
18439
- const requiredUsd = await this.computeOutputsUsdValue(orderOutputs, chainId);
18440
- if (requiredUsd === null) {
18441
- console.warn("[BidManager] sortMixedOutputs: output tokens unpriceable, falling back to raw-amount sort");
18442
- return this.sortByRawAmountFallback(bids, orderOutputs);
18443
- }
18444
- console.log(`[BidManager] sortMixedOutputs: required USD value=${requiredUsd.toString()}`);
18445
- const validBids = [];
18446
- for (const bid of bids) {
18447
- const bidUsd = await this.computeOutputsUsdValue(bid.outputs, chainId);
18448
- if (bidUsd === null) {
18449
- console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: unable to price mixed outputs`);
18450
- continue;
18451
- }
18452
- if (bidUsd.lt(requiredUsd)) {
18453
- console.log(
18454
- `[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (bid=${bidUsd.toString()}, required=${requiredUsd.toString()}, covers=${bidUsd.div(requiredUsd).mul(100).toFixed(2)}%)`
18455
- );
18456
- } else {
18457
- console.log(
18458
- `[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED: mixed USD value=${bidUsd.toString()}`
18459
- );
18460
- }
18461
- validBids.push({ bid, usdValue: bidUsd });
18462
- }
18463
- validBids.sort((a, b) => b.usdValue.comparedTo(a.usdValue));
18464
- return validBids.map(({ bid }) => bid);
18465
- }
18466
- /**
18467
- * Fallback when DEX pricing is unavailable.
18468
- * Computes total spread per bid. Bids missing a required token are rejected.
18469
- * Bids offering less than required for a token are allowed (partial fill).
18470
- * Sorted by total offered amount descending.
18471
- */
18472
- sortByRawAmountFallback(bids, orderOutputs) {
18473
- console.log(
18474
- `[BidManager] sortByRawAmountFallback: checking ${bids.length} bid(s) against ${orderOutputs.length} required output(s)`
18475
- );
18476
- const validBids = [];
18477
- for (const bid of bids) {
18478
- let valid = true;
18479
- let totalOffered = new Decimal2(0);
18480
- let rejectReason = "";
18481
- for (const required of orderOutputs) {
18482
- const matching = bid.outputs.find((o) => o.token.toLowerCase() === required.token.toLowerCase());
18483
- if (!matching) {
18484
- valid = false;
18485
- rejectReason = `missing output token=${required.token}`;
18486
- break;
18487
- }
18488
- totalOffered = totalOffered.plus(new Decimal2(matching.amount.toString()));
18489
- }
18490
- if (!valid) {
18491
- console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED (fallback): ${rejectReason}`);
18492
- continue;
18493
- }
18494
- const totalRequired = orderOutputs.reduce(
18495
- (acc, o) => acc.plus(new Decimal2(o.amount.toString())),
18496
- new Decimal2(0)
18497
- );
18498
- if (totalOffered.lt(totalRequired)) {
18499
- console.log(
18500
- `[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (fallback) (offered=${totalOffered.toString()}, required=${totalRequired.toString()}, covers=${totalOffered.div(totalRequired).mul(100).toFixed(2)}%)`
18501
- );
18502
- } else {
18503
- console.log(
18504
- `[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED (fallback): totalOffered=${totalOffered.toString()}`
18505
- );
18506
- }
18507
- validBids.push({ bid, totalOffered });
18508
- }
18509
- validBids.sort((a, b) => b.totalOffered.comparedTo(a.totalOffered));
18510
- return validBids.map(({ bid }) => bid);
18511
- }
18512
18196
  // ── Token classification helpers ──────────────────────────────────
18513
18197
  /**
18514
18198
  * Returns `true` if `tokenAddr` is either USDC or USDT on the given chain.
@@ -18539,23 +18223,6 @@ var BidManager = class {
18539
18223
  return configService.getUsdtDecimals(chainId);
18540
18224
  }
18541
18225
  // ── Basket valuation helpers ──────────────────────────────────────
18542
- /**
18543
- * Sums the USD value of a basket of stable tokens (USDC/USDT only),
18544
- * normalising each amount by its decimal count and treating each token as $1.
18545
- *
18546
- * @param outputs - List of token/amount pairs where every token is a stable.
18547
- * @param chainId - State-machine ID used to look up decimals.
18548
- * @returns Total USD value as a `Decimal`.
18549
- */
18550
- computeStablesUsdValue(outputs, chainId) {
18551
- let total = new Decimal2(0);
18552
- for (const output of outputs) {
18553
- const tokenAddr = bytes32ToBytes20(output.token);
18554
- const decimals = this.getStableDecimals(tokenAddr, chainId);
18555
- total = total.plus(new Decimal2(output.amount.toString()).div(new Decimal2(10).pow(decimals)));
18556
- }
18557
- return total;
18558
- }
18559
18226
  /**
18560
18227
  * Prices every token in the basket via on-chain DEX quotes (token → USDC).
18561
18228
  * Stables are valued at $1. Non-stables are quoted through Uniswap
@@ -18570,6 +18237,7 @@ var BidManager = class {
18570
18237
  const { asset: wethAddr } = configService.getWrappedNativeAssetWithDecimals(chainId);
18571
18238
  let totalUsd = new Decimal2(0);
18572
18239
  for (const output of outputs) {
18240
+ if (output.amount === 0n) continue;
18573
18241
  const tokenAddr = bytes32ToBytes20(output.token);
18574
18242
  if (this.isStableToken(tokenAddr, chainId)) {
18575
18243
  const decimals = this.getStableDecimals(tokenAddr, chainId);
@@ -18693,6 +18361,14 @@ var GasEstimator = class {
18693
18361
  */
18694
18362
  async estimateFillOrder(params, pricingOptions = {}) {
18695
18363
  const { order } = params;
18364
+ if (params.outputs !== void 0 && params.inputs === void 0) {
18365
+ throw new Error("Custom output quotes require explicit inputs");
18366
+ }
18367
+ const inputs = (params.inputs ?? order.inputs).map((input) => ({
18368
+ ...input,
18369
+ token: normalizeAddressForEvmBytes32(input.token)
18370
+ }));
18371
+ const quotedOutputs = params.outputs ?? order.output.assets;
18696
18372
  const orderFeeGasPriceBumpPercent = pricingOptions.orderFeeGasPriceBumpPercent ?? 0n;
18697
18373
  const solverPrivateKey = generatePrivateKey();
18698
18374
  const solverAccountAddress = privateKeyToAddress(solverPrivateKey);
@@ -18701,7 +18377,7 @@ var GasEstimator = class {
18701
18377
  const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachineId);
18702
18378
  const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(destStateMachineId);
18703
18379
  const chainId = BigInt(Number.parseInt(destStateMachineId.split("-")[1]));
18704
- const totalEthValue = order.output.assets.filter((output) => bytes32ToBytes20(output.token) === ADDRESS_ZERO2).reduce((sum, output) => sum + output.amount, 0n);
18380
+ const totalEthValue = quotedOutputs.filter((output) => bytes32ToBytes20(output.token) === ADDRESS_ZERO2).reduce((sum, output) => sum + output.amount, 0n);
18705
18381
  const [sourceFeeToken, destFeeToken, gasPrice, latestBlock] = await Promise.all([
18706
18382
  getFeeToken(this.ctx, this.ctx.source.config.stateMachineId, this.ctx.source),
18707
18383
  getFeeToken(this.ctx, this.ctx.dest.config.stateMachineId, this.ctx.dest),
@@ -18710,7 +18386,7 @@ var GasEstimator = class {
18710
18386
  ]);
18711
18387
  const baseFeePerGas = latestBlock.baseFeePerGas ?? gasPrice;
18712
18388
  const feeTokenAsBytes32 = bytes20ToBytes32(destFeeToken.address);
18713
- const assetsForOverrides = [...order.output.assets];
18389
+ const assetsForOverrides = [...quotedOutputs];
18714
18390
  if (!assetsForOverrides.some((asset) => asset.token.toLowerCase() === feeTokenAsBytes32.toLowerCase())) {
18715
18391
  assetsForOverrides.push({ token: feeTokenAsBytes32, amount: 0n });
18716
18392
  }
@@ -18733,6 +18409,7 @@ var GasEstimator = class {
18733
18409
  ]);
18734
18410
  const { bundler: bundlerStateOverrides } = stateOverridesResult;
18735
18411
  const fillOptions = {
18412
+ inputs,
18736
18413
  relayerFee: crossChainFees.postRequestFee,
18737
18414
  // Always dispatch with the fee token (see the method docs).
18738
18415
  nativeDispatchFee: 0n,
@@ -18740,7 +18417,7 @@ var GasEstimator = class {
18740
18417
  // bound here would only risk the estimate reverting on a slow bundler round trip.
18741
18418
  // The caller sets the real one on the options it actually signs.
18742
18419
  validUntil: 0n,
18743
- outputs: order.output.assets.map((asset) => ({
18420
+ outputs: quotedOutputs.map((asset) => ({
18744
18421
  ...asset,
18745
18422
  token: normalizeAddressForEvmBytes32(asset.token)
18746
18423
  }))
@@ -18752,12 +18429,8 @@ var GasEstimator = class {
18752
18429
  let maxFeePerGas = gasPrice + gasPrice * BigInt(maxFeeBumpPercent) / 100n;
18753
18430
  const orderForEstimation = { ...order, session: solverAccountAddress };
18754
18431
  const commitment = orderCommitment(orderForEstimation);
18755
- const fillOptionsVersion = await getFillOptionsVersion(this.ctx.dest.client, intentGatewayV2Address);
18756
- const fillOrderCalldata = encodeFillOrder(
18757
- transformOrderForContract(orderForEstimation),
18758
- fillOptions,
18759
- fillOptionsVersion
18760
- );
18432
+ await assertGatewayRelease(this.ctx.dest.client, intentGatewayV2Address);
18433
+ const fillOrderCalldata = encodeFillOrder(transformOrderForContract(orderForEstimation), fillOptions);
18761
18434
  let callGasLimit = 500000n;
18762
18435
  let verificationGasLimit = 100000n;
18763
18436
  let preVerificationGas = 100000n;
@@ -18904,7 +18577,8 @@ var GasEstimator = class {
18904
18577
  totalGasCostWei,
18905
18578
  totalGasInFeeToken: totalGasInSourceFeeToken,
18906
18579
  relayerFeeInSourceFeeToken: crossChainFees.relayerFeeInSourceFeeToken,
18907
- fillOptions
18580
+ fillOptions,
18581
+ inputs
18908
18582
  };
18909
18583
  }
18910
18584
  /**
@@ -19067,35 +18741,47 @@ var OrderStatusChecker = class {
19067
18741
  }
19068
18742
  ctx;
19069
18743
  /**
19070
- * Checks if a V2 order has been filled by reading the commitment storage slot on the destination chain.
19071
- *
19072
- * Reads the storage slot returned by `calculateCommitmentSlotHash` on the IntentGatewayV2 contract.
19073
- * A non-zero value at that slot means the solver has called `fillOrder` and the order is complete
19074
- * from the user's perspective (the beneficiary has received their tokens).
18744
+ * Whether the order is finalized on the destination chain, read from the gateway's `_filled`
18745
+ * getter. It is set by the completing fill, and by a cancellation, which records the refund
18746
+ * beneficiary there. A partially filled order reads false; see {@link getFillProgress}.
19075
18747
  *
19076
18748
  * @param order - The V2 order to check. `order.id` is used as the commitment; if not set it is computed.
19077
- * @returns True if the order has been filled on the destination chain, false otherwise.
19078
18749
  */
19079
18750
  async isOrderFilled(order) {
19080
18751
  const commitment = order.id ?? orderCommitment(order);
19081
- const destStateMachineId = isHex(order.destination) ? hexToString$1(order.destination) : order.destination;
19082
- const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachineId);
19083
- const filledSlot = await this.ctx.dest.client.readContract({
18752
+ const gateway = this.ctx.dest.configService.getIntentGatewayAddress(destinationStateMachine(order));
18753
+ const finalizer = await this.ctx.dest.client.readContract({
19084
18754
  abi: ABI3,
19085
- address: intentGatewayV2Address,
19086
- functionName: "calculateCommitmentSlotHash",
18755
+ address: gateway,
18756
+ functionName: "_filled",
19087
18757
  args: [commitment]
19088
18758
  });
19089
- const filledStatus = await this.ctx.dest.client.getStorageAt({
19090
- address: intentGatewayV2Address,
19091
- slot: filledSlot
19092
- });
19093
- return filledStatus !== "0x0000000000000000000000000000000000000000000000000000000000000000";
18759
+ return !/^0x0{40}$/i.test(finalizer);
18760
+ }
18761
+ /**
18762
+ * Output credited to the order so far, one entry per leg, read from `_partialFills` on the
18763
+ * destination chain. Several solvers can each fill a slice of a same-chain or cross-chain order,
18764
+ * so this, not {@link isOrderFilled}, says how far along an open order is. Surplus paid above
18765
+ * the order's rate is not counted.
18766
+ *
18767
+ * @param order - The V2 order to check. `order.id` is used as the commitment; if not set it is computed.
18768
+ */
18769
+ async getFillProgress(order) {
18770
+ const commitment = order.id ?? orderCommitment(order);
18771
+ const gateway = this.ctx.dest.configService.getIntentGatewayAddress(destinationStateMachine(order));
18772
+ return Promise.all(
18773
+ order.output.assets.map(async (asset, index) => ({
18774
+ token: asset.token,
18775
+ amount: await readLegPartialFill(this.ctx.dest.client, gateway, commitment, index, asset.token)
18776
+ }))
18777
+ );
19094
18778
  }
19095
18779
  /**
19096
18780
  * Checks if a V2 order has been refunded by reading the `_orders` mapping on the source chain.
19097
18781
  *
19098
- * Calls `_orders(commitment, tokenAddress)` for each input token. When the order is placed the
18782
+ * Calls `_orders(commitment, index)` for each input: escrow is held per leg, keyed by the input's
18783
+ * index, so inputs that repeat a token are read separately. A gateway not yet upgraded to per-leg
18784
+ * escrow is read by token instead, see {@link readLegEscrow}. When the order is placed the
19099
18785
  * escrowed amounts are stored there. After a successful refund the contract zeroes them out.
19100
18786
  * An order is considered refunded when all escrowed input amounts have been returned (i.e. are 0).
19101
18787
  *
@@ -19107,14 +18793,14 @@ var OrderStatusChecker = class {
19107
18793
  const commitment = order.id ?? orderCommitment(order);
19108
18794
  const sourceStateMachineId = isHex(order.source) ? hexToString$1(order.source) : order.source;
19109
18795
  const intentGatewayV2Address = this.ctx.source.configService.getIntentGatewayAddress(sourceStateMachineId);
19110
- for (const input of order.inputs) {
19111
- const tokenAddress = bytes32ToBytes20(input.token);
19112
- const escrowedAmount = await this.ctx.source.client.readContract({
19113
- abi: ABI3,
19114
- address: intentGatewayV2Address,
19115
- functionName: "_orders",
19116
- args: [commitment, tokenAddress]
19117
- });
18796
+ for (let index = 0; index < order.inputs.length; index++) {
18797
+ const escrowedAmount = await readLegEscrow(
18798
+ this.ctx.source.client,
18799
+ intentGatewayV2Address,
18800
+ commitment,
18801
+ index,
18802
+ order.inputs[index].token
18803
+ );
19118
18804
  if (escrowedAmount !== 0n) {
19119
18805
  return false;
19120
18806
  }
@@ -19122,727 +18808,374 @@ var OrderStatusChecker = class {
19122
18808
  return true;
19123
18809
  }
19124
18810
  };
19125
-
19126
- // src/protocols/intents/liquidity-pool.ts
19127
- function sortPoolSymbols(symbolA, symbolB) {
19128
- return symbolA.toLowerCase() <= symbolB.toLowerCase() ? [symbolA, symbolB] : [symbolB, symbolA];
18811
+ function destinationStateMachine(order) {
18812
+ return isHex(order.destination) ? hexToString$1(order.destination) : order.destination;
19129
18813
  }
19130
- function poolSlug(symbolA, symbolB) {
19131
- return sortPoolSymbols(symbolA, symbolB).join("-");
19132
- }
19133
- function resolveLiquidityPool(symbolA, symbolB) {
19134
- const [token0Symbol, token1Symbol] = sortPoolSymbols(symbolA, symbolB);
19135
- return {
19136
- poolId: `${token0Symbol}-${token1Symbol}`,
19137
- token0Symbol,
19138
- token1Symbol
19139
- };
18814
+ var ORDERBOOK_URLS = {
18815
+ mainnet: "https://orderbook.hyperfx.finance/mainnet/graphql",
18816
+ testnet: "https://orderbook.hyperfx.finance/testnet/graphql"
18817
+ };
18818
+ function orderbookUrlFor(stateMachineId) {
18819
+ return TESTNET_CHAINS.has(stateMachineId) ? ORDERBOOK_URLS.testnet : ORDERBOOK_URLS.mainnet;
19140
18820
  }
19141
-
19142
- // src/protocols/intents/LiquidityEngine.ts
19143
- var INDEXER_FIXED_POINT_DECIMALS = 18;
19144
- var POOL_RATE_SCALE = 10n ** 18n;
19145
- var SELL = "SELL";
19146
- var BUY = "BUY";
19147
- var USD_STABLE_SYMBOLS = /* @__PURE__ */ new Set(["USDC", "USDT"]);
19148
- var LiquidityEngine = class {
19149
- constructor(queryClient) {
19150
- this.queryClient = queryClient;
19151
- }
19152
- queryClient;
18821
+ var ORDERBOOK_DECIMALS = 18;
18822
+ var ORDERBOOK_SCALE = 10n ** BigInt(ORDERBOOK_DECIMALS);
18823
+ var OrderbookRequestError = class extends Error {
18824
+ constructor(message) {
18825
+ super(`HyperFX orderbook request failed: ${message}`);
18826
+ this.name = "OrderbookRequestError";
18827
+ }
18828
+ };
18829
+ var RATE_FIELDS = "side fillChain rate depthIn depthOut backingLiquidity sourceChains orderCount solverCount";
18830
+ var TOP_OF_BOOK_QUERY = `
18831
+ query TopOfBook($tokenA: String!, $tokenB: String!, $fillChain: String!, $sourceChain: String!) {
18832
+ books { id base quote }
18833
+ aToB: bestRate(tokenIn: $tokenA, tokenOut: $tokenB, fillChain: $fillChain, sourceChain: $sourceChain) { ${RATE_FIELDS} }
18834
+ bToA: bestRate(tokenIn: $tokenB, tokenOut: $tokenA, fillChain: $fillChain, sourceChain: $sourceChain) { ${RATE_FIELDS} }
18835
+ }`;
18836
+ var ROUTE_LIQUIDITY_QUERY = `
18837
+ query RouteLiquidity($route: RouteInput!) {
18838
+ books { id base quote }
18839
+ routeLiquidity(route: $route) {
18840
+ route bestRate depthIn depthOut availableLiquidity maxFillableIn orderCount solverCount
18841
+ }
18842
+ }`;
18843
+ var QUOTE_QUERY = `
18844
+ query Quote($route: RouteInput!, $amountIn: BigInt!) {
18845
+ quote(route: $route, amountIn: $amountIn) {
18846
+ route side amountIn amountOut rate fillable depth maxFillableIn
18847
+ fills { orderRate amountOut advertisedSize }
18848
+ }
18849
+ }`;
18850
+ var ORDERBOOK_QUERIES = {
18851
+ topOfBook: TOP_OF_BOOK_QUERY,
18852
+ routeLiquidity: ROUTE_LIQUIDITY_QUERY,
18853
+ quote: QUOTE_QUERY
18854
+ };
18855
+ var HyperFxOrderbook = class {
18856
+ client;
18857
+ /** @param urlOrClient - The orderbook's GraphQL URL, or a configured `graphql-request` client. */
18858
+ constructor(urlOrClient = ORDERBOOK_URLS.mainnet) {
18859
+ this.client = typeof urlOrClient === "string" ? new GraphQLClient(urlOrClient) : urlOrClient;
18860
+ }
19153
18861
  /**
19154
- * Returns liquidity reachable from one source chain on one destination.
19155
- *
19156
- * The caller resolves chain-specific token addresses through chain
19157
- * configuration; this layer only maps those configured symbols onto the
19158
- * indexer's canonical pool and route fields.
19159
- *
19160
- * Destination, unrestricted, and explicit-route capacity are returned as
19161
- * separate values so callers can apply their own source-chain policy.
19162
- *
19163
- * @returns `undefined` only when the indexer has not published a destination
19164
- * pool sample yet.
19165
- */
19166
- async getAvailableLiquidity(params) {
19167
- const pool = resolveLiquidityPool(params.source.symbol, params.destination.symbol);
19168
- const direction = params.source.symbol.toLowerCase() === pool.token0Symbol.toLowerCase() ? SELL : BUY;
19169
- const variables = {
19170
- poolId: pool.poolId,
19171
- sourceChain: params.source.chain,
19172
- destinationChain: params.destination.chain,
19173
- direction
18862
+ * The best bid and ask on `fillChain` for the pair `tokenA`/`tokenB`, counting
18863
+ * only orders a swap from `sourceChain` can use.
18864
+ */
18865
+ async topOfBook(params) {
18866
+ const data = await this.request(TOP_OF_BOOK_QUERY, params);
18867
+ const book = findBook(data.books, params.tokenA, params.tokenB);
18868
+ const rates = [data.aToB, data.bToA].filter((rate) => rate !== null).map(parseRate);
18869
+ return {
18870
+ book,
18871
+ bid: rates.find((rate) => rate.side === "BID") ?? null,
18872
+ ask: rates.find((rate) => rate.side === "ASK") ?? null
19174
18873
  };
19175
- const response = await this.queryClient.request(AVAILABLE_LIQUIDITY, variables);
19176
- if (!response?.poolChainLiquidities?.nodes || !response?.poolRoutes?.nodes) {
19177
- throw new InvalidLiquidityIndexerResponseError("liquidity connections are missing");
19178
- }
19179
- const chainLiquidity = response.poolChainLiquidities.nodes[0];
19180
- if (!chainLiquidity) return void 0;
19181
- const route = response.poolRoutes.nodes[0];
18874
+ }
18875
+ /** Total liquidity on a route, no amount required. */
18876
+ async routeLiquidity(route) {
18877
+ const { books, routeLiquidity: raw } = await this.request(ROUTE_LIQUIDITY_QUERY, { route });
18878
+ const book = findBook(books, route.tokenIn, route.tokenOut);
19182
18879
  return {
19183
- sourceChain: params.source.chain,
19184
- destinationChain: params.destination.chain,
19185
- tokenAddress: normalizeEvmAddress(params.destination.address, "destination token"),
19186
- updatedAt: readIndexerDate(chainLiquidity.lastUpdatedAt, "destination lastUpdatedAt"),
19187
- destination: readLiquiditySlice(chainLiquidity.depth, chainLiquidity.bidCount, "destination"),
19188
- unrestricted: readLiquiditySlice(
19189
- chainLiquidity.unrestrictedDepth,
19190
- chainLiquidity.unrestrictedBidCount,
19191
- "unrestricted"
19192
- ),
19193
- explicitRoute: route ? {
19194
- ...readLiquiditySlice(route.depth, route.bidCount, "explicit route"),
19195
- updatedAt: readIndexerDate(route.lastUpdatedAt, "route lastUpdatedAt")
19196
- } : null
18880
+ route: raw.route,
18881
+ book,
18882
+ side: book.base === route.tokenIn ? "BID" : "ASK",
18883
+ bestRate: raw.bestRate === null ? null : BigInt(raw.bestRate),
18884
+ depthIn: BigInt(raw.depthIn),
18885
+ depthOut: BigInt(raw.depthOut),
18886
+ availableLiquidity: BigInt(raw.availableLiquidity),
18887
+ maxFillableIn: BigInt(raw.maxFillableIn),
18888
+ orderCount: raw.orderCount,
18889
+ solverCount: raw.solverCount
19197
18890
  };
19198
18891
  }
19199
- /**
19200
- * Returns the indexed pool's aggregate buy and sell rates in less-valued
19201
- * quote-token units per one base token.
19202
- *
19203
- * The indexer depth-weights fresh per-chain samples into the pool rates. The
19204
- * source and destination chains remain part of the result because they define
19205
- * the cross-chain route whose configured token symbols were resolved.
19206
- */
19207
- async getBuyAndSellRates(params) {
19208
- const pool = resolveLiquidityPool(params.tokenInSymbol, params.tokenOutSymbol);
19209
- const response = await this.queryClient.request(BUY_AND_SELL_RATES, {
19210
- poolId: pool.poolId
18892
+ /** The clearing price for `amountIn` (1e18 tokenIn) on a route, which may combine several solvers' orders. */
18893
+ async quote(route, amountIn) {
18894
+ const { quote: raw } = await this.request(QUOTE_QUERY, {
18895
+ route,
18896
+ amountIn: amountIn.toString()
19211
18897
  });
19212
- if (!response?.liquidityPools?.nodes) {
19213
- throw new InvalidLiquidityIndexerResponseError("liquidity pool connection is missing");
19214
- }
19215
- const indexedPool = response.liquidityPools.nodes[0];
19216
- if (!indexedPool) return void 0;
19217
- validateIndexedPool(indexedPool, pool);
19218
- const sell = readIndexedRate(indexedPool.sellRate, indexedPool.lastUpdatedAt, "pool sell rate");
19219
- const buy = readIndexedRate(indexedPool.buyRate, indexedPool.lastUpdatedAt, "pool buy rate");
19220
- const inputIsToken0 = params.tokenInSymbol.toLowerCase() === pool.token0Symbol.toLowerCase();
19221
- const direct = inputIsToken0 ? sell : buy;
19222
- const reverse = inputIsToken0 ? buy : sell;
19223
- if (!direct && !reverse) return void 0;
19224
- const quoteTokenSymbol = resolveQuoteTokenSymbol(
19225
- params.tokenInSymbol,
19226
- params.tokenOutSymbol,
19227
- direct?.scaledRate,
19228
- reverse?.scaledRate
19229
- );
19230
- const quoteIsTokenOut = quoteTokenSymbol === params.tokenOutSymbol;
19231
- const orientedBuy = quoteIsTokenOut ? direct : reverse;
19232
- const orientedSell = quoteIsTokenOut ? reverse : direct;
19233
18898
  return {
19234
- baseTokenSymbol: quoteIsTokenOut ? params.tokenInSymbol : params.tokenOutSymbol,
19235
- quoteTokenSymbol,
19236
- sourceChain: params.sourceChain,
19237
- destinationChain: params.destinationChain,
19238
- buyRate: orientedBuy ? formatUnits(orientedBuy.scaledRate, INDEXER_FIXED_POINT_DECIMALS) : null,
19239
- sellRate: orientedSell ? formatUnits(reciprocalRate(orientedSell.scaledRate, "sell rate"), INDEXER_FIXED_POINT_DECIMALS) : null,
19240
- buyRateUpdatedAt: orientedBuy?.updatedAt ?? null,
19241
- sellRateUpdatedAt: orientedSell?.updatedAt ?? null
18899
+ route: raw.route,
18900
+ side: raw.side,
18901
+ amountIn: BigInt(raw.amountIn),
18902
+ amountOut: BigInt(raw.amountOut),
18903
+ rate: raw.rate === null ? null : BigInt(raw.rate),
18904
+ fillable: raw.fillable,
18905
+ depth: BigInt(raw.depth),
18906
+ maxFillableIn: BigInt(raw.maxFillableIn),
18907
+ fills: raw.fills.map((fill) => ({
18908
+ orderRate: BigInt(fill.orderRate),
18909
+ amountOut: BigInt(fill.amountOut),
18910
+ advertisedSize: BigInt(fill.advertisedSize)
18911
+ }))
19242
18912
  };
19243
18913
  }
19244
- };
19245
- var InvalidLiquidityIndexerResponseError = class extends Error {
19246
- constructor(reason) {
19247
- super(`Invalid liquidity indexer response: ${reason}`);
19248
- this.name = "InvalidLiquidityIndexerResponseError";
18914
+ async request(query, variables) {
18915
+ try {
18916
+ return await this.client.request(query, variables);
18917
+ } catch (error) {
18918
+ throw new OrderbookRequestError(describeError(error));
18919
+ }
19249
18920
  }
19250
18921
  };
18922
+ function describeError(error) {
18923
+ const graphqlErrors = error?.response?.errors;
18924
+ if (graphqlErrors?.length) return graphqlErrors.map((e) => e.message).join("; ");
18925
+ return error instanceof Error ? error.message : String(error);
18926
+ }
18927
+ function findBook(books, tokenA, tokenB) {
18928
+ const book = books.find(
18929
+ (b) => b.base === tokenA && b.quote === tokenB || b.base === tokenB && b.quote === tokenA
18930
+ );
18931
+ if (!book) throw new OrderbookRequestError(`no book trades ${tokenA} for ${tokenB}`);
18932
+ return book;
18933
+ }
18934
+ function parseRate(raw) {
18935
+ return {
18936
+ side: raw.side,
18937
+ fillChain: raw.fillChain,
18938
+ rate: BigInt(raw.rate),
18939
+ depthIn: BigInt(raw.depthIn),
18940
+ depthOut: BigInt(raw.depthOut),
18941
+ backingLiquidity: BigInt(raw.backingLiquidity),
18942
+ sourceChains: raw.sourceChains,
18943
+ orderCount: raw.orderCount,
18944
+ solverCount: raw.solverCount
18945
+ };
18946
+ }
18947
+
18948
+ // src/protocols/intents/orderbook/types.ts
19251
18949
  var UnsupportedLiquidityAssetError = class extends Error {
19252
18950
  constructor(chain, asset) {
19253
- super(`No configured liquidity asset found for ${asset} on ${chain}`);
18951
+ super(`No configured asset found for ${asset} on ${chain}`);
19254
18952
  this.name = "UnsupportedLiquidityAssetError";
19255
18953
  }
19256
18954
  };
19257
18955
  var UnsupportedLiquidityChainError = class extends Error {
19258
18956
  constructor(chainId) {
19259
- super(`No configured liquidity chain found for chain ID ${chainId}`);
18957
+ super(`No configured chain found for chain ID ${chainId}`);
19260
18958
  this.name = "UnsupportedLiquidityChainError";
19261
18959
  }
19262
18960
  };
19263
- function readLiquiditySlice(depth, providerCount, label) {
19264
- if (!Number.isSafeInteger(providerCount) || providerCount < 0) {
19265
- throw new InvalidLiquidityIndexerResponseError(`${label} provider count is invalid`);
19266
- }
19267
- return { totalLiquidity: formatIndexerAmount(depth, `${label} depth`), providerCount };
19268
- }
19269
- function formatIndexerAmount(value, label) {
19270
- try {
19271
- const amount = BigInt(value);
19272
- if (amount < 0n) throw new Error();
19273
- return formatUnits(amount, INDEXER_FIXED_POINT_DECIMALS);
19274
- } catch {
19275
- throw new InvalidLiquidityIndexerResponseError(`${label} is not a non-negative integer`);
19276
- }
19277
- }
19278
- function readIndexerDate(value, label) {
19279
- const date = new Date(dateStringtoTimestamp(value));
19280
- if (Number.isNaN(date.getTime())) throw new InvalidLiquidityIndexerResponseError(`${label} is invalid`);
19281
- return date;
19282
- }
19283
- function readIndexedRate(value, lastUpdatedAt, label) {
19284
- if (value === null) return void 0;
19285
- try {
19286
- const scaledRate = BigInt(value);
19287
- if (scaledRate <= 0n) throw new Error();
19288
- return {
19289
- scaledRate,
19290
- updatedAt: readIndexerDate(lastUpdatedAt, `${label} lastUpdatedAt`)
19291
- };
19292
- } catch (error) {
19293
- if (error instanceof InvalidLiquidityIndexerResponseError) throw error;
19294
- throw new InvalidLiquidityIndexerResponseError(`${label} is not a positive integer`);
19295
- }
19296
- }
19297
- function validateIndexedPool(indexedPool, expected) {
19298
- if (indexedPool.id.toLowerCase() !== expected.poolId.toLowerCase() || indexedPool.token0Symbol.toLowerCase() !== expected.token0Symbol.toLowerCase() || indexedPool.token1Symbol.toLowerCase() !== expected.token1Symbol.toLowerCase()) {
19299
- throw new InvalidLiquidityIndexerResponseError(`pool identity does not match ${expected.poolId}`);
19300
- }
19301
- }
19302
- function resolveQuoteTokenSymbol(tokenInSymbol, tokenOutSymbol, directRate, reverseRate) {
19303
- const inputIsUsdStable = USD_STABLE_SYMBOLS.has(tokenInSymbol);
19304
- const outputIsUsdStable = USD_STABLE_SYMBOLS.has(tokenOutSymbol);
19305
- if (inputIsUsdStable !== outputIsUsdStable) return inputIsUsdStable ? tokenOutSymbol : tokenInSymbol;
19306
- if (directRate !== void 0) return directRate >= POOL_RATE_SCALE ? tokenOutSymbol : tokenInSymbol;
19307
- if (reverseRate !== void 0) return reverseRate >= POOL_RATE_SCALE ? tokenInSymbol : tokenOutSymbol;
19308
- throw new InvalidLiquidityIndexerResponseError("cannot orient an empty rate pair");
19309
- }
19310
- function reciprocalRate(rate, label) {
19311
- const numerator = POOL_RATE_SCALE * POOL_RATE_SCALE;
19312
- const reciprocal = (numerator + rate - 1n) / rate;
19313
- if (reciprocal <= 0n) throw new InvalidLiquidityIndexerResponseError(`${label} reciprocal underflowed`);
19314
- return reciprocal;
19315
- }
19316
-
19317
- // src/protocols/intents/quote/types.ts
19318
- var UnsupportedIntentQuoteStrategyError = class extends Error {
19319
- constructor(strategy) {
19320
- super(`Unsupported intent quote strategy: ${strategy}`);
19321
- this.name = "UnsupportedIntentQuoteStrategyError";
19322
- }
19323
- };
19324
- var UnsupportedIntentQuotePairError = class extends Error {
19325
- constructor(params) {
18961
+ var OrderbookQuoteNotConvergedError = class extends Error {
18962
+ constructor(route, rounds, lastAmountIn) {
19326
18963
  super(
19327
- `No ${params.quoteSource ?? "Uniswap v4 pool config"} found for ${params.tokenIn} -> ${params.tokenOut} on ${params.source} -> ${params.destination}`
18964
+ `No input for ${route.tokenIn} -> ${route.tokenOut} on ${route.sourceChain} -> ${route.destinationChain} delivered the requested output within ${rounds} quotes; the last tried ${lastAmountIn} raw units`
19328
18965
  );
19329
- this.name = "UnsupportedIntentQuotePairError";
19330
- }
19331
- };
19332
- var PhantomSnapshotUnavailableError = class extends Error {
19333
- constructor(tokenA, tokenB) {
19334
- super(`No Phantom order price snapshot found for ${tokenA} -> ${tokenB}`);
19335
- this.name = "PhantomSnapshotUnavailableError";
19336
- }
18966
+ this.route = route;
18967
+ this.rounds = rounds;
18968
+ this.lastAmountIn = lastAmountIn;
18969
+ this.name = "OrderbookQuoteNotConvergedError";
18970
+ }
18971
+ route;
18972
+ rounds;
18973
+ lastAmountIn;
19337
18974
  };
19338
- var InvalidPhantomSnapshotError = class extends Error {
19339
- constructor(commitment, reason) {
19340
- super(`Invalid Phantom order price snapshot ${commitment}: ${reason}`);
19341
- this.name = "InvalidPhantomSnapshotError";
19342
- }
19343
- };
19344
- var IndexedRateUnavailableError = class extends Error {
19345
- constructor(params) {
19346
- const route = params.source && params.destination && params.tokenIn && params.tokenOut ? ` for ${params.tokenIn} -> ${params.tokenOut} on ${params.source} -> ${params.destination}` : "";
19347
- const side = params.side ? ` ${params.side}` : "";
19348
- super(`No indexed${side} rate available${route}`);
19349
- this.name = "IndexedRateUnavailableError";
19350
- }
19351
- };
19352
- var InvalidIndexedRateError = class extends Error {
19353
- constructor(reason) {
19354
- super(`Invalid indexed intent rate: ${reason}`);
19355
- this.name = "InvalidIndexedRateError";
18975
+ var InsufficientOrderbookLiquidityError = class extends Error {
18976
+ constructor(route, maxFillableIn) {
18977
+ super(
18978
+ `The HyperFX orderbook cannot fill ${route.tokenIn} -> ${route.tokenOut} on ${route.sourceChain} -> ${route.destinationChain}; max fillable input is ${maxFillableIn} raw units`
18979
+ );
18980
+ this.route = route;
18981
+ this.maxFillableIn = maxFillableIn;
18982
+ this.name = "InsufficientOrderbookLiquidityError";
19356
18983
  }
18984
+ route;
18985
+ maxFillableIn;
19357
18986
  };
19358
- var BPS_DENOMINATOR = 10000n;
19359
- function validateQuoteParams(params) {
19360
- const hasAmountIn = params.amountIn !== void 0;
19361
- const hasAmountOut = params.amountOut !== void 0;
19362
- if (hasAmountIn === hasAmountOut) throw new Error("Provide exactly one of amountIn or amountOut");
19363
- if (params.amountIn !== void 0 && params.amountIn <= 0n) throw new Error("amountIn must be greater than zero");
19364
- if (params.amountOut !== void 0 && params.amountOut <= 0n) throw new Error("amountOut must be greater than zero");
19365
- if (params.tokenIn.toLowerCase() === params.tokenOut.toLowerCase()) {
19366
- throw new Error("tokenIn and tokenOut cannot be the same");
19367
- }
19368
- }
19369
- async function readProtocolFeeBps(chainConfigService, source) {
19370
- const gatewayAddress = chainConfigService.getIntentGatewayAddress(source.stateMachineId);
19371
- if (!gatewayAddress || gatewayAddress === "0x" || gatewayAddress === zeroAddress) {
19372
- throw new Error(`IntentGatewayV2 is not configured for chain ${source.stateMachineId}`);
19373
- }
19374
- const gatewayParams = await source.client.readContract({
19375
- address: gatewayAddress,
19376
- abi: IntentGatewayV2_default.ABI,
19377
- functionName: "params"
19378
- });
19379
- const protocolFeeBps = Array.isArray(gatewayParams) ? BigInt(gatewayParams[4]) : BigInt(gatewayParams.protocolFeeBps ?? 0);
19380
- if (protocolFeeBps < 0n || protocolFeeBps >= BPS_DENOMINATOR) {
19381
- throw new Error(`Invalid IntentGateway protocol fee: ${protocolFeeBps} bps`);
19382
- }
19383
- return protocolFeeBps;
19384
- }
19385
- function deductProtocolFee(amount, protocolFeeBps) {
19386
- if (protocolFeeBps <= 0n) return amount;
19387
- const fee = amount * protocolFeeBps / BPS_DENOMINATOR;
19388
- return amount - fee;
19389
- }
19390
- function grossUpForProtocolFee(netAmount, protocolFeeBps) {
19391
- if (protocolFeeBps <= 0n) return netAmount;
19392
- if (protocolFeeBps >= BPS_DENOMINATOR) throw new Error("protocolFeeBps must be less than 10,000");
19393
- return divCeil(netAmount * BPS_DENOMINATOR, BPS_DENOMINATOR - protocolFeeBps);
19394
- }
19395
- function divCeil(numerator, denominator) {
19396
- if (denominator <= 0n) throw new Error("denominator must be greater than zero");
19397
- return (numerator + denominator - 1n) / denominator;
19398
- }
19399
18987
 
19400
- // src/protocols/intents/quote/uniswapV4.ts
19401
- var UNISWAP_INTENT_QUOTE_CHAIN = "EVM-8453" /* BASE_MAINNET */;
19402
- var UniswapV4IntentQuoteStrategy = class {
19403
- constructor(chainConfigService) {
19404
- this.chainConfigService = chainConfigService;
19405
- }
19406
- chainConfigService;
19407
- baseQuoteClient;
19408
- async quote(params, source, destination) {
18988
+ // src/protocols/intents/orderbook/market.ts
18989
+ var MAX_EXACT_OUTPUT_ROUNDS = 16;
18990
+ var OrderbookMarket = class {
18991
+ constructor(configService, orderbook) {
18992
+ this.configService = configService;
18993
+ this.orderbook = orderbook;
18994
+ }
18995
+ configService;
18996
+ orderbook;
18997
+ async quoteIntent(params, sourceChain, destinationChain) {
19409
18998
  validateQuoteParams(params);
19410
- const protocolFeeBps = await readProtocolFeeBps(this.chainConfigService, source);
19411
- const quoteClient = this.resolveQuoteClient(source, destination);
19412
- const poolConfig = this.resolvePoolConfig(params, source.stateMachineId, destination.stateMachineId);
19413
- return params.amountIn !== void 0 ? this.quoteExactInput({ params, client: quoteClient, protocolFeeBps, poolConfig }) : this.quoteExactOutput({ params, client: quoteClient, protocolFeeBps, poolConfig });
19414
- }
19415
- resolveQuoteClient(source, destination) {
19416
- if (source.stateMachineId === UNISWAP_INTENT_QUOTE_CHAIN) return source.client;
19417
- if (destination.stateMachineId === UNISWAP_INTENT_QUOTE_CHAIN) return destination.client;
19418
- if (this.baseQuoteClient) return this.baseQuoteClient;
19419
- const rpcUrl = this.chainConfigService.getRpcUrl(UNISWAP_INTENT_QUOTE_CHAIN);
19420
- if (!rpcUrl) throw new Error(`RPC URL is not configured for ${UNISWAP_INTENT_QUOTE_CHAIN}`);
19421
- const baseQuoteClient = createPublicClient({
19422
- chain: base,
19423
- transport: http(rpcUrl)
19424
- });
19425
- this.baseQuoteClient = baseQuoteClient;
19426
- return baseQuoteClient;
19427
- }
19428
- resolvePoolConfig(params, source, destination) {
19429
- const override = params.uniswapV4?.poolKey;
19430
- if (override) {
19431
- const poolKey = normalizePoolKey(override);
19432
- const tokenInForQuote = getAddress(override.currencyIn ?? params.tokenIn);
19433
- if (tokenInForQuote !== poolKey.currency0 && tokenInForQuote !== poolKey.currency1) {
19434
- throw new Error(
19435
- `Input currency ${tokenInForQuote} is not part of the override pool (${poolKey.currency0}, ${poolKey.currency1}). For cross-chain quotes pass uniswapV4.poolKey.currencyIn with the Base-side input currency address.`
19436
- );
19437
- }
19438
- return {
19439
- poolKey,
19440
- quoterAddress: this.resolveQuoterAddress(UNISWAP_INTENT_QUOTE_CHAIN, override.quoterAddress),
19441
- tokenInForQuote
19442
- };
19443
- }
19444
- const poolConfig = this.resolveConfiguredPool(params, source, destination, UNISWAP_INTENT_QUOTE_CHAIN);
19445
- if (poolConfig) return poolConfig;
19446
- throw new UnsupportedIntentQuotePairError({
19447
- source,
19448
- destination,
19449
- tokenIn: params.tokenIn,
19450
- tokenOut: params.tokenOut
19451
- });
19452
- }
19453
- resolveConfiguredPool(params, sourceChain, destinationChain, quoteChain) {
19454
- for (const pool of this.chainConfigService.getUniswapV4PoolConfigs(quoteChain)) {
19455
- const resolvedPool = this.resolveConfiguredPoolTokens(quoteChain, pool);
19456
- if (!resolvedPool) continue;
19457
- const tokenInForQuote = this.matchPoolToken(params.tokenIn, sourceChain, resolvedPool);
19458
- const tokenOutForQuote = this.matchPoolToken(params.tokenOut, destinationChain, resolvedPool);
19459
- if (!tokenInForQuote || !tokenOutForQuote || tokenInForQuote.symbol === tokenOutForQuote.symbol) continue;
19460
- const { currency0, currency1 } = sortCurrencies(resolvedPool[0].address, resolvedPool[1].address);
19461
- return {
19462
- poolKey: {
19463
- currency0,
19464
- currency1,
19465
- fee: pool.fee,
19466
- tickSpacing: pool.tickSpacing,
19467
- hooks: getAddress(pool.hooks ?? zeroAddress)
19468
- },
19469
- quoterAddress: this.resolveQuoterAddress(quoteChain),
19470
- tokenInForQuote: tokenInForQuote.address
19471
- };
19472
- }
19473
- return null;
19474
- }
19475
- resolveQuoterAddress(chain, override) {
19476
- const address = override ?? this.chainConfigService.getUniswapV4QuoterAddress(chain);
19477
- if (!address || address === "0x" || address === zeroAddress) {
19478
- throw new Error(`Uniswap V4 quoter is not configured for chain ${chain}`);
18999
+ const tokenIn = this.assetByAddress(sourceChain, params.tokenIn);
19000
+ const tokenOut = this.assetByAddress(destinationChain, params.tokenOut);
19001
+ const route = toRoute(tokenIn, tokenOut);
19002
+ if (params.amountIn !== void 0) {
19003
+ const quote2 = await this.orderbook().quote(route, toOrderbookAmount(params.amountIn, tokenIn.decimals));
19004
+ const amountOut2 = quote2.fillable ? fromOrderbookAmount(quote2.amountOut, tokenOut.decimals) : 0n;
19005
+ if (amountOut2 === 0n) throw this.insufficient(route, quote2.maxFillableIn, tokenIn);
19006
+ return buildQuote("EXACT_INPUT", params.amountIn, amountOut2, quote2, tokenIn, tokenOut);
19479
19007
  }
19480
- return getAddress(address);
19481
- }
19482
- resolveConfiguredPoolTokens(chain, pool) {
19483
- const first = this.resolveConfiguredPoolToken(chain, pool.tokens[0]);
19484
- const second = this.resolveConfiguredPoolToken(chain, pool.tokens[1]);
19485
- return first && second ? [first, second] : null;
19486
- }
19487
- resolveConfiguredPoolToken(chain, symbol) {
19488
- const address = this.chainConfigService.getAssetAddress(chain, symbol);
19489
- if (!address || address === "0x") return null;
19490
- return { symbol, address: getAddress(address) };
19491
- }
19492
- matchPoolToken(tokenAddress, orderChain, poolTokens) {
19493
- const addressMatch = poolTokens.find(
19494
- (poolToken) => poolToken.address.toLowerCase() === tokenAddress.toLowerCase()
19495
- );
19496
- if (addressMatch) return addressMatch;
19497
- const metadata = this.chainConfigService.getAssetMetadataByAddress(orderChain, tokenAddress);
19498
- if (!metadata) return null;
19499
- return poolTokens.find((poolToken) => poolToken.symbol === metadata.symbol) ?? null;
19500
- }
19501
- async quoteExactInput(args) {
19502
- const amountIn = args.params.amountIn;
19503
- if (amountIn === void 0) throw new Error("amountIn is required for an exact-input quote");
19504
- const swapAmountIn = deductProtocolFee(amountIn, args.protocolFeeBps);
19505
- const amountOut = await this.readV4QuoteExactInput(args.client, args.poolConfig, swapAmountIn);
19506
- return {
19507
- strategy: "uniswap_v4",
19508
- tradeType: "EXACT_INPUT",
19509
- amountIn,
19008
+ const amountOut = params.amountOut;
19009
+ const quote = await this.quoteExactOutput(route, toOrderbookAmount(amountOut, tokenOut.decimals), tokenIn);
19010
+ return buildQuote(
19011
+ "EXACT_OUTPUT",
19012
+ fromOrderbookAmount(quote.amountIn, tokenIn.decimals),
19510
19013
  amountOut,
19511
- quoteMetadata: {
19512
- quoteChain: UNISWAP_INTENT_QUOTE_CHAIN,
19513
- poolKey: args.poolConfig.poolKey,
19514
- quoterAddress: args.poolConfig.quoterAddress,
19515
- protocolFeeBps: args.protocolFeeBps
19516
- }
19517
- };
19014
+ quote,
19015
+ tokenIn,
19016
+ tokenOut
19017
+ );
19518
19018
  }
19519
- async quoteExactOutput(args) {
19520
- const amountOut = args.params.amountOut;
19521
- if (amountOut === void 0) throw new Error("amountOut is required for an exact-output quote");
19522
- const swapAmountIn = await this.readV4QuoteExactOutput(args.client, args.poolConfig, amountOut);
19523
- const amountIn = grossUpForProtocolFee(swapAmountIn, args.protocolFeeBps);
19019
+ async availableLiquidity(params, sourceChain, destinationChain) {
19020
+ const tokenIn = this.assetByAddress(sourceChain, params.tokenIn);
19021
+ const tokenOut = this.assetByAddress(destinationChain, params.tokenOut);
19022
+ const liquidity = await this.orderbook().routeLiquidity(toRoute(tokenIn, tokenOut));
19023
+ const [base3, quote] = liquidity.side === "BID" ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
19524
19024
  return {
19525
- strategy: "uniswap_v4",
19526
- tradeType: "EXACT_OUTPUT",
19527
- amountIn,
19528
- amountOut,
19529
- quoteMetadata: {
19530
- quoteChain: UNISWAP_INTENT_QUOTE_CHAIN,
19531
- poolKey: args.poolConfig.poolKey,
19532
- quoterAddress: args.poolConfig.quoterAddress,
19533
- protocolFeeBps: args.protocolFeeBps
19534
- }
19025
+ sourceChain: tokenIn.chain,
19026
+ destinationChain: tokenOut.chain,
19027
+ tokenInSymbol: tokenIn.symbol,
19028
+ tokenOutSymbol: tokenOut.symbol,
19029
+ tokenAddress: tokenOut.address,
19030
+ route: liquidity.route,
19031
+ side: liquidity.side,
19032
+ baseTokenSymbol: base3.symbol,
19033
+ quoteTokenSymbol: quote.symbol,
19034
+ bestRate: formatOptional(liquidity.bestRate),
19035
+ availableLiquidity: format(liquidity.availableLiquidity),
19036
+ depthIn: format(liquidity.depthIn),
19037
+ depthOut: format(liquidity.depthOut),
19038
+ maxFillableIn: format(liquidity.maxFillableIn),
19039
+ orderCount: liquidity.orderCount,
19040
+ solverCount: liquidity.solverCount
19535
19041
  };
19536
19042
  }
19537
- async readV4QuoteExactInput(client, poolConfig, amountIn) {
19538
- const data = encodeFunctionData({
19539
- abi: UNISWAP_V4_QUOTER_ABI,
19540
- functionName: "quoteExactInputSingle",
19541
- args: [
19542
- {
19543
- poolKey: poolConfig.poolKey,
19544
- zeroForOne: getZeroForOne(poolConfig.tokenInForQuote, poolConfig.poolKey),
19545
- exactAmount: amountIn,
19546
- hookData: "0x"
19547
- }
19548
- ]
19549
- });
19550
- const response = await client.call({ to: poolConfig.quoterAddress, data });
19551
- if (!response.data || response.data === "0x") {
19552
- throw new Error(`Uniswap V4 quoter at ${poolConfig.quoterAddress} returned no data`);
19553
- }
19554
- const [amountOut] = decodeFunctionResult({
19555
- abi: UNISWAP_V4_QUOTER_ABI,
19556
- functionName: "quoteExactInputSingle",
19557
- data: response.data
19558
- });
19559
- return amountOut;
19560
- }
19561
- async readV4QuoteExactOutput(client, poolConfig, amountOut) {
19562
- const data = encodeFunctionData({
19563
- abi: UNISWAP_V4_QUOTER_ABI,
19564
- functionName: "quoteExactOutputSingle",
19565
- args: [
19566
- {
19567
- poolKey: poolConfig.poolKey,
19568
- zeroForOne: getZeroForOne(poolConfig.tokenInForQuote, poolConfig.poolKey),
19569
- exactAmount: amountOut,
19570
- hookData: "0x"
19571
- }
19572
- ]
19043
+ async buyAndSellRates(params) {
19044
+ const tokenIn = this.assetBySymbol(params.sourceChain, params.tokenInSymbol);
19045
+ const tokenOut = this.assetBySymbol(params.destinationChain, params.tokenOutSymbol);
19046
+ const { book, bid, ask } = await this.orderbook().topOfBook({
19047
+ tokenA: tokenIn.symbol,
19048
+ tokenB: tokenOut.symbol,
19049
+ fillChain: tokenOut.chain,
19050
+ sourceChain: tokenIn.chain
19573
19051
  });
19574
- const response = await client.call({ to: poolConfig.quoterAddress, data });
19575
- if (!response.data || response.data === "0x") {
19576
- throw new Error(`Uniswap V4 quoter at ${poolConfig.quoterAddress} returned no data`);
19577
- }
19578
- const [amountIn] = decodeFunctionResult({
19579
- abi: UNISWAP_V4_QUOTER_ABI,
19580
- functionName: "quoteExactOutputSingle",
19581
- data: response.data
19582
- });
19583
- return amountIn;
19584
- }
19585
- };
19586
- function normalizePoolKey(poolKey) {
19587
- return {
19588
- currency0: getAddress(poolKey.currency0),
19589
- currency1: getAddress(poolKey.currency1),
19590
- fee: poolKey.fee,
19591
- tickSpacing: poolKey.tickSpacing,
19592
- hooks: getAddress(poolKey.hooks)
19593
- };
19594
- }
19595
- function sortCurrencies(tokenIn, tokenOut) {
19596
- const input = getAddress(tokenIn);
19597
- const output = getAddress(tokenOut);
19598
- return BigInt(input) < BigInt(output) ? { currency0: input, currency1: output } : { currency0: output, currency1: input };
19599
- }
19600
- function getZeroForOne(tokenIn, poolKey) {
19601
- return getAddress(tokenIn).toLowerCase() === getAddress(poolKey.currency0).toLowerCase();
19602
- }
19603
-
19604
- // src/protocols/intents/quote/phantomSnapshot.ts
19605
- var PHANTOM_INTENT_QUOTE_CHAIN = "EVM-8453" /* BASE_MAINNET */;
19606
- var BASE_SNAPSHOT_ASSET_BY_ORDER_ASSET = {
19607
- USDC: "USDC",
19608
- USDT: "USDC",
19609
- cNGN: "cNGN"
19610
- };
19611
- var SUPPORTED_BASE_SNAPSHOT_PAIRS = /* @__PURE__ */ new Set(["USDC:cNGN", "cNGN:USDC"]);
19612
- var PhantomSnapshotIntentQuoteStrategy = class {
19613
- constructor(chainConfigService, getQueryClient) {
19614
- this.chainConfigService = chainConfigService;
19615
- this.getQueryClient = getQueryClient;
19616
- this.pairResolver = new PhantomSnapshotPairResolver(chainConfigService);
19617
- }
19618
- chainConfigService;
19619
- getQueryClient;
19620
- pairResolver;
19621
- async quote(params, source, destination) {
19622
- validateQuoteParams(params);
19623
- const pair = this.pairResolver.resolve(params, source.stateMachineId, destination.stateMachineId);
19624
- if (!pair) {
19625
- throw new UnsupportedIntentQuotePairError({
19626
- source: source.stateMachineId,
19627
- destination: destination.stateMachineId,
19628
- tokenIn: params.tokenIn,
19629
- tokenOut: params.tokenOut,
19630
- quoteSource: "Phantom snapshot pair"
19631
- });
19632
- }
19633
- const queryClient = this.getQueryClient();
19634
- const [protocolFeeBps, snapshot] = await Promise.all([
19635
- readProtocolFeeBps(this.chainConfigService, source),
19636
- _queryLatestPhantomOrderPriceSnapshot({
19637
- tokenA: pair.tokenA,
19638
- tokenB: pair.tokenB,
19639
- queryClient
19640
- })
19641
- ]);
19642
- if (!snapshot) throw new PhantomSnapshotUnavailableError(pair.tokenA, pair.tokenB);
19643
- this.validateSnapshot(snapshot);
19644
- return this.quoteSnapshot(params, protocolFeeBps, snapshot);
19645
- }
19646
- quoteSnapshot(params, protocolFeeBps, snapshot) {
19647
- if (params.amountIn !== void 0) {
19648
- const netAmountIn2 = deductProtocolFee(params.amountIn, protocolFeeBps);
19649
- const amountOut = netAmountIn2 * snapshot.medianPrice / snapshot.standardAmount;
19650
- if (amountOut <= 0n) {
19651
- throw new InvalidPhantomSnapshotError(snapshot.commitment, "quote rounds down to zero output");
19652
- }
19653
- return this.buildResult("EXACT_INPUT", params.amountIn, amountOut, protocolFeeBps, snapshot);
19654
- }
19655
- if (params.amountOut === void 0) throw new Error("Quote amount is missing after validation");
19656
- const netAmountIn = divCeil(params.amountOut * snapshot.standardAmount, snapshot.medianPrice);
19657
- const amountIn = grossUpForProtocolFee(netAmountIn, protocolFeeBps);
19658
- return this.buildResult("EXACT_OUTPUT", amountIn, params.amountOut, protocolFeeBps, snapshot);
19659
- }
19660
- buildResult(tradeType, amountIn, amountOut, protocolFeeBps, snapshot) {
19052
+ const bidRate = bid?.rate ?? null;
19053
+ const askRate = ask?.rate ?? null;
19054
+ const mid = bidRate !== null && askRate !== null ? (bidRate + askRate) / 2n : null;
19055
+ const spread = bidRate !== null && askRate !== null && askRate >= bidRate ? askRate - bidRate : null;
19661
19056
  return {
19662
- strategy: "phantom_snapshot",
19663
- tradeType,
19664
- amountIn,
19665
- amountOut,
19666
- quoteMetadata: {
19667
- quoteChain: PHANTOM_INTENT_QUOTE_CHAIN,
19668
- commitment: snapshot.commitment,
19669
- tokenA: snapshot.tokenA,
19670
- tokenB: snapshot.tokenB,
19671
- standardAmount: snapshot.standardAmount,
19672
- medianPrice: snapshot.medianPrice,
19673
- lowestPrice: snapshot.lowestPrice,
19674
- highestPrice: snapshot.highestPrice,
19675
- blockNumber: snapshot.blockNumber,
19676
- snapshotTime: snapshot.snapshotTime,
19677
- bidCount: snapshot.bidCount,
19678
- protocolFeeBps
19679
- }
19057
+ baseTokenSymbol: book.base,
19058
+ quoteTokenSymbol: book.quote,
19059
+ sourceChain: tokenIn.chain,
19060
+ destinationChain: tokenOut.chain,
19061
+ bid: formatOptional(bidRate),
19062
+ ask: formatOptional(askRate),
19063
+ mid: formatOptional(mid),
19064
+ spread: formatOptional(spread),
19065
+ spreadBps: spread !== null && mid ? Number(spread * 1000000n / mid) / 100 : null
19680
19066
  };
19681
19067
  }
19682
- validateSnapshot(snapshot) {
19683
- if (snapshot.standardAmount <= 0n) {
19684
- throw new InvalidPhantomSnapshotError(snapshot.commitment, "standardAmount must be greater than zero");
19685
- }
19686
- if (snapshot.medianPrice <= 0n) {
19687
- throw new InvalidPhantomSnapshotError(snapshot.commitment, "medianPrice must be greater than zero");
19688
- }
19689
- if (snapshot.bidCount <= 0) {
19690
- throw new InvalidPhantomSnapshotError(snapshot.commitment, "bidCount must be greater than zero");
19691
- }
19692
- if (Number.isNaN(snapshot.snapshotTime.getTime())) {
19693
- throw new InvalidPhantomSnapshotError(snapshot.commitment, "snapshotTime is invalid");
19694
- }
19695
- }
19696
- };
19697
- var PhantomSnapshotPairResolver = class {
19698
- constructor(chainConfigService) {
19699
- this.chainConfigService = chainConfigService;
19700
- }
19701
- chainConfigService;
19702
- resolve(params, sourceStateMachineId, destinationStateMachineId) {
19703
- const tokenIn = this.resolveBaseSnapshotToken(sourceStateMachineId, params.tokenIn);
19704
- const tokenOut = this.resolveBaseSnapshotToken(destinationStateMachineId, params.tokenOut);
19705
- if (!tokenIn || !tokenOut || !isSupportedSnapshotPair(tokenIn.symbol, tokenOut.symbol)) return;
19706
- return { tokenA: tokenIn.address, tokenB: tokenOut.address };
19707
- }
19708
- resolveBaseSnapshotToken(chain, tokenAddress) {
19709
- const orderAsset = this.chainConfigService.getAssetMetadataByAddress(chain, tokenAddress)?.symbol;
19710
- if (!orderAsset) return;
19711
- const snapshotAsset = BASE_SNAPSHOT_ASSET_BY_ORDER_ASSET[orderAsset];
19712
- if (!snapshotAsset) return;
19713
- const address = this.chainConfigService.getAssetAddress(PHANTOM_INTENT_QUOTE_CHAIN, snapshotAsset);
19714
- if (!isConfiguredAddress(address)) return;
19715
- return { symbol: snapshotAsset, address };
19716
- }
19717
- };
19718
- function isSupportedSnapshotPair(tokenA, tokenB) {
19719
- return SUPPORTED_BASE_SNAPSHOT_PAIRS.has(`${tokenA}:${tokenB}`);
19720
- }
19721
- function isConfiguredAddress(address) {
19722
- return Boolean(address && address !== "0x" && !/^0x0{40}$/i.test(address));
19723
- }
19724
- var INDEXED_RATE_DECIMALS = 18;
19725
- var INDEXED_RATE_SCALE = 10n ** BigInt(INDEXED_RATE_DECIMALS);
19726
- var IndexedRateIntentQuoteStrategy = class {
19727
- constructor(chainConfigService, getQueryClient) {
19728
- this.chainConfigService = chainConfigService;
19729
- this.getQueryClient = getQueryClient;
19730
- }
19731
- chainConfigService;
19732
- getQueryClient;
19733
- async quote(params, source, destination) {
19734
- validateQuoteParams(params);
19735
- const sourceConfig = getConfigByStateMachineId(source.stateMachineId);
19736
- const destinationConfig = getConfigByStateMachineId(destination.stateMachineId);
19737
- if (!sourceConfig) throw new UnsupportedLiquidityChainError(source.stateMachineId);
19738
- if (!destinationConfig) throw new UnsupportedLiquidityChainError(destination.stateMachineId);
19739
- const tokenIn = this.resolveAsset(sourceConfig.stateMachineId, params.tokenIn);
19740
- const tokenOut = this.resolveAsset(destinationConfig.stateMachineId, params.tokenOut);
19741
- const [protocolFeeBps, rates] = await Promise.all([
19742
- readProtocolFeeBps(this.chainConfigService, source),
19743
- new LiquidityEngine(this.getQueryClient()).getBuyAndSellRates({
19744
- sourceChain: sourceConfig.stateMachineId,
19745
- destinationChain: destinationConfig.stateMachineId,
19746
- tokenInSymbol: tokenIn.symbol,
19747
- tokenOutSymbol: tokenOut.symbol
19748
- })
19749
- ]);
19750
- if (!rates) {
19751
- throw new IndexedRateUnavailableError({
19752
- source: sourceConfig.stateMachineId,
19753
- destination: destinationConfig.stateMachineId,
19754
- tokenIn: tokenIn.symbol,
19755
- tokenOut: tokenOut.symbol
19756
- });
19757
- }
19758
- const selectedRate = selectIndexedRate(rates, tokenIn.symbol, tokenOut.symbol);
19759
- return quoteWithIndexedRate(params, tokenIn, tokenOut, selectedRate, rates, protocolFeeBps);
19068
+ /**
19069
+ * The orderbook only quotes an input amount, so an output is priced by
19070
+ * guessing the input from the best rate and raising it at each clearing
19071
+ * price until the quote delivers `targetOut`.
19072
+ */
19073
+ async quoteExactOutput(route, targetOut, tokenIn) {
19074
+ const orderbook = this.orderbook();
19075
+ const liquidity = await orderbook.routeLiquidity(route);
19076
+ if (liquidity.bestRate === null) throw this.insufficient(route, 0n, tokenIn);
19077
+ const inputUnit = toOrderbookAmount(1n, tokenIn.decimals);
19078
+ let amountIn = roundUpTo(requiredInput(liquidity.side, targetOut, liquidity.bestRate), inputUnit);
19079
+ let lastAmountIn = amountIn;
19080
+ for (let round = 0; round < MAX_EXACT_OUTPUT_ROUNDS; round++) {
19081
+ if (amountIn > liquidity.maxFillableIn) throw this.insufficient(route, liquidity.maxFillableIn, tokenIn);
19082
+ const quote = await orderbook.quote(route, amountIn);
19083
+ if (quote.fillable && quote.amountOut >= targetOut) return quote;
19084
+ lastAmountIn = amountIn;
19085
+ const next = quote.rate === null ? amountIn : roundUpTo(requiredInput(quote.side, targetOut, quote.rate), inputUnit);
19086
+ amountIn = next > amountIn ? next : amountIn + inputUnit;
19087
+ }
19088
+ throw new OrderbookQuoteNotConvergedError(
19089
+ route,
19090
+ MAX_EXACT_OUTPUT_ROUNDS,
19091
+ fromOrderbookAmount(lastAmountIn, tokenIn.decimals)
19092
+ );
19760
19093
  }
19761
- resolveAsset(chain, address) {
19762
- const asset = this.chainConfigService.getAssetMetadataByAddress(chain, address);
19763
- if (!asset) throw new UnsupportedLiquidityAssetError(chain, address);
19764
- const { decimals } = asset;
19765
- if (decimals === void 0 || !Number.isSafeInteger(decimals) || decimals < 0) {
19766
- throw new InvalidIndexedRateError(`decimals are not configured for ${asset.symbol} on ${chain}`);
19767
- }
19768
- return { ...asset, decimals };
19094
+ insufficient(route, maxFillableIn, tokenIn) {
19095
+ return new InsufficientOrderbookLiquidityError(route, fromOrderbookAmount(maxFillableIn, tokenIn.decimals));
19769
19096
  }
19770
- };
19771
- function selectIndexedRate(rates, tokenInSymbol, tokenOutSymbol) {
19772
- if (tokenInSymbol === rates.baseTokenSymbol && tokenOutSymbol === rates.quoteTokenSymbol) {
19773
- return readIndexedRate2(
19774
- "buy",
19775
- rates.buyRate,
19776
- rates.buyRateUpdatedAt,
19777
- rates,
19778
- tokenInSymbol,
19779
- tokenOutSymbol
19097
+ assetByAddress(chain, address) {
19098
+ const resolvedChain = resolveChain(chain);
19099
+ return withDecimals(
19100
+ resolvedChain,
19101
+ address,
19102
+ this.configService.getAssetMetadataByAddress(resolvedChain, address)
19780
19103
  );
19781
19104
  }
19782
- if (tokenInSymbol === rates.quoteTokenSymbol && tokenOutSymbol === rates.baseTokenSymbol) {
19783
- return readIndexedRate2(
19784
- "sell",
19785
- rates.sellRate,
19786
- rates.sellRateUpdatedAt,
19787
- rates,
19788
- tokenInSymbol,
19789
- tokenOutSymbol
19790
- );
19105
+ assetBySymbol(chain, symbol) {
19106
+ const resolvedChain = resolveChain(chain);
19107
+ return withDecimals(resolvedChain, symbol, this.configService.getAssetMetadataBySymbol(resolvedChain, symbol));
19791
19108
  }
19792
- throw new InvalidIndexedRateError(
19793
- `indexed pair ${rates.baseTokenSymbol}/${rates.quoteTokenSymbol} does not match ${tokenInSymbol}/${tokenOutSymbol}`
19794
- );
19109
+ };
19110
+ function resolveChain(chain) {
19111
+ const stateMachineId = getConfigByStateMachineId(chain)?.stateMachineId;
19112
+ if (!stateMachineId) throw new UnsupportedLiquidityChainError(chain);
19113
+ return stateMachineId;
19795
19114
  }
19796
- function readIndexedRate2(side, rate, updatedAt, rates, tokenInSymbol, tokenOutSymbol) {
19797
- if (!rate || !updatedAt) {
19798
- throw new IndexedRateUnavailableError({
19799
- source: rates.sourceChain,
19800
- destination: rates.destinationChain,
19801
- tokenIn: tokenInSymbol,
19802
- tokenOut: tokenOutSymbol,
19803
- side
19804
- });
19805
- }
19806
- try {
19807
- const scaledRate = parseUnits(rate, INDEXED_RATE_DECIMALS);
19808
- if (scaledRate <= 0n || Number.isNaN(updatedAt.getTime())) throw new Error();
19809
- return { side, rate, scaledRate, updatedAt };
19810
- } catch {
19811
- throw new InvalidIndexedRateError(`${side} rate or timestamp is invalid`);
19115
+ function withDecimals(chain, asset, metadata) {
19116
+ if (!metadata) throw new UnsupportedLiquidityAssetError(chain, asset);
19117
+ const { decimals } = metadata;
19118
+ if (decimals === void 0 || !Number.isSafeInteger(decimals) || decimals < 0 || decimals > ORDERBOOK_DECIMALS) {
19119
+ throw new UnsupportedLiquidityAssetError(chain, `${metadata.symbol} (decimals are not configured)`);
19812
19120
  }
19121
+ return { chain, symbol: metadata.symbol, address: metadata.address, decimals };
19122
+ }
19123
+ function validateQuoteParams(params) {
19124
+ const hasAmountIn = params.amountIn !== void 0;
19125
+ const hasAmountOut = params.amountOut !== void 0;
19126
+ if (hasAmountIn === hasAmountOut) throw new Error("Provide exactly one of amountIn or amountOut");
19127
+ if (params.amountIn !== void 0 && params.amountIn <= 0n) throw new Error("amountIn must be greater than zero");
19128
+ if (params.amountOut !== void 0 && params.amountOut <= 0n) throw new Error("amountOut must be greater than zero");
19813
19129
  }
19814
- function quoteWithIndexedRate(params, tokenIn, tokenOut, selectedRate, rates, protocolFeeBps) {
19815
- const inputUnit = 10n ** BigInt(tokenIn.decimals);
19816
- const outputUnit = 10n ** BigInt(tokenOut.decimals);
19817
- if (params.amountIn !== void 0) {
19818
- const netAmountIn2 = deductProtocolFee(params.amountIn, protocolFeeBps);
19819
- const amountOut = selectedRate.side === "buy" ? netAmountIn2 * selectedRate.scaledRate * outputUnit / (inputUnit * INDEXED_RATE_SCALE) : netAmountIn2 * outputUnit * INDEXED_RATE_SCALE / (inputUnit * selectedRate.scaledRate);
19820
- if (amountOut <= 0n) throw new InvalidIndexedRateError("quote rounds down to zero output");
19821
- return buildResult("EXACT_INPUT", params.amountIn, amountOut, selectedRate, rates, protocolFeeBps);
19822
- }
19823
- if (params.amountOut === void 0) throw new Error("Quote amount is missing after validation");
19824
- const netAmountIn = selectedRate.side === "buy" ? divCeil(params.amountOut * inputUnit * INDEXED_RATE_SCALE, selectedRate.scaledRate * outputUnit) : divCeil(params.amountOut * inputUnit * selectedRate.scaledRate, outputUnit * INDEXED_RATE_SCALE);
19825
- const amountIn = grossUpForProtocolFee(netAmountIn, protocolFeeBps);
19826
- return buildResult("EXACT_OUTPUT", amountIn, params.amountOut, selectedRate, rates, protocolFeeBps);
19130
+ function toRoute(tokenIn, tokenOut) {
19131
+ return {
19132
+ tokenIn: tokenIn.symbol,
19133
+ tokenOut: tokenOut.symbol,
19134
+ sourceChain: tokenIn.chain,
19135
+ destinationChain: tokenOut.chain
19136
+ };
19137
+ }
19138
+ function requiredInput(side, amountOut, rate) {
19139
+ return side === "BID" ? divCeil(amountOut * ORDERBOOK_SCALE, rate) : divCeil(amountOut * rate, ORDERBOOK_SCALE);
19827
19140
  }
19828
- function buildResult(tradeType, amountIn, amountOut, selectedRate, rates, protocolFeeBps) {
19141
+ function buildQuote(tradeType, amountIn, amountOut, quote, tokenIn, tokenOut) {
19142
+ if (quote.rate === null) throw new OrderbookRequestError("the orderbook served a fillable quote with no rate");
19143
+ const [base3, quoteToken] = quote.side === "BID" ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
19829
19144
  return {
19830
- strategy: "indexed_rates",
19831
19145
  tradeType,
19832
19146
  amountIn,
19833
19147
  amountOut,
19834
19148
  quoteMetadata: {
19835
- sourceChain: rates.sourceChain,
19836
- destinationChain: rates.destinationChain,
19837
- baseTokenSymbol: rates.baseTokenSymbol,
19838
- quoteTokenSymbol: rates.quoteTokenSymbol,
19839
- rateSide: selectedRate.side,
19840
- rate: selectedRate.rate,
19841
- rateUpdatedAt: selectedRate.updatedAt,
19842
- protocolFeeBps
19149
+ sourceChain: tokenIn.chain,
19150
+ destinationChain: tokenOut.chain,
19151
+ route: quote.route,
19152
+ side: quote.side,
19153
+ baseTokenSymbol: base3.symbol,
19154
+ quoteTokenSymbol: quoteToken.symbol,
19155
+ rate: format(quote.rate),
19156
+ maxFillableIn: fromOrderbookAmount(quote.maxFillableIn, tokenIn.decimals),
19157
+ orderCount: quote.fills.length
19843
19158
  }
19844
19159
  };
19845
19160
  }
19161
+ function toOrderbookAmount(amount, decimals) {
19162
+ return amount * 10n ** BigInt(ORDERBOOK_DECIMALS - decimals);
19163
+ }
19164
+ function fromOrderbookAmount(amount, decimals) {
19165
+ return amount / 10n ** BigInt(ORDERBOOK_DECIMALS - decimals);
19166
+ }
19167
+ function roundUpTo(amount, unit) {
19168
+ return divCeil(amount, unit) * unit;
19169
+ }
19170
+ function divCeil(numerator, denominator) {
19171
+ return (numerator + denominator - 1n) / denominator;
19172
+ }
19173
+ function format(amount) {
19174
+ return formatUnits(amount, ORDERBOOK_DECIMALS);
19175
+ }
19176
+ function formatOptional(amount) {
19177
+ return amount === null ? null : format(amount);
19178
+ }
19846
19179
 
19847
19180
  // src/protocols/intents/IntentGateway.ts
19848
19181
  var ORDER_FEE_GAS_PRICE_BUMP_POLICY = {
@@ -19882,8 +19215,10 @@ var IntentGateway = class _IntentGateway {
19882
19215
  bidManager;
19883
19216
  /** Estimates gas costs for filling an order and converts them to fee-token amounts. */
19884
19217
  gasEstimator;
19885
- /** Quote strategies for pricing orders before placement, keyed by strategy name. */
19886
- quoteStrategies;
19218
+ /** The HyperFX orderbook quotes, liquidity and rates are read from. */
19219
+ orderbook;
19220
+ /** Prices intents, liquidity and rates from {@link orderbook}. */
19221
+ market;
19887
19222
  /**
19888
19223
  * Private constructor — use {@link IntentGateway.create} instead.
19889
19224
  *
@@ -19927,17 +19262,8 @@ var IntentGateway = class _IntentGateway {
19927
19262
  this.bidManager = bidManager;
19928
19263
  this.gasEstimator = gasEstimator;
19929
19264
  this._crypto = crypto;
19930
- this.quoteStrategies = {
19931
- indexed_rates: new IndexedRateIntentQuoteStrategy(
19932
- dest.configService,
19933
- () => this.requireIndexer().queryClient
19934
- ),
19935
- phantom_snapshot: new PhantomSnapshotIntentQuoteStrategy(
19936
- dest.configService,
19937
- () => this.requireIndexer().queryClient
19938
- ),
19939
- uniswap_v4: new UniswapV4IntentQuoteStrategy(dest.configService)
19940
- };
19265
+ this.orderbook = new HyperFxOrderbook(orderbookUrlFor(dest.config.stateMachineId));
19266
+ this.market = new OrderbookMarket(dest.configService, () => this.orderbook);
19941
19267
  }
19942
19268
  /**
19943
19269
  * Creates an initialized IntentGateway instance.
@@ -19983,89 +19309,66 @@ var IntentGateway = class _IntentGateway {
19983
19309
  }
19984
19310
  }
19985
19311
  /**
19986
- * Quotes an intent between this gateway's source and destination chains.
19312
+ * Points quotes, liquidity and rate reads at a HyperFX orderbook other than
19313
+ * the destination chain's network deployment ({@link ORDERBOOK_URLS}).
19314
+ * Returns `this` for chaining.
19315
+ *
19316
+ * @param orderbook - The orderbook's GraphQL URL, or a configured client.
19317
+ */
19318
+ withOrderbook(orderbook) {
19319
+ this.orderbook = typeof orderbook === "string" ? new HyperFxOrderbook(orderbook) : orderbook;
19320
+ return this;
19321
+ }
19322
+ /**
19323
+ * Quotes an intent between this gateway's source and destination chains from
19324
+ * the HyperFX orderbook. Provide exactly one of `amountIn` or `amountOut`, in
19325
+ * raw token units.
19987
19326
  *
19988
- * Uses the indexer's latest aggregate directional pool rate by default. Pass
19989
- * `strategy: "phantom_snapshot"` or `strategy: "uniswap_v4"` only when
19990
- * explicitly requesting a legacy quote source. Provide exactly one of
19991
- * `amountIn` or `amountOut`.
19327
+ * An exact-input quote is the orderbook's clearing price for `amountIn`,
19328
+ * which may combine several solvers' orders. An exact-output quote finds the
19329
+ * smallest input whose clearing price delivers `amountOut`. A cross-chain
19330
+ * route only counts orders whose solvers accept the source chain.
19992
19331
  *
19993
- * The gateway's source and destination chains resolve the configured order
19994
- * tokens; the indexer supplies the depth-weighted pool rate. Returned
19995
- * `amountIn`/`amountOut` already account for the gateway's protocol fee
19996
- * (`quoteMetadata.protocolFeeBps`), which the gateway deducts from order inputs.
19332
+ * The orderbook's rates already carry the gateway protocol fee, so the
19333
+ * returned amounts can be placed as the order's inputs and outputs directly.
19997
19334
  *
19998
- * @param params - Token pair, amount, and optional strategy/pool overrides.
19999
- * @returns The quoted amounts plus strategy-specific metadata.
20000
- * @throws {UnsupportedIntentQuoteStrategyError} For unknown strategies.
20001
- * @throws {UnsupportedIntentQuotePairError} When the selected strategy does not support the pair.
20002
- * @throws {IndexedRateUnavailableError} When the requested direction has no indexed rate.
19335
+ * @throws {InsufficientOrderbookLiquidityError} When the route cannot fill the amount.
19336
+ * @throws {OrderbookRequestError} When the orderbook is unreachable or trades no book for the pair.
20003
19337
  */
20004
19338
  async quoteIntent(params) {
20005
- const source = { stateMachineId: this.source.config.stateMachineId, client: this.source.client };
20006
- const destination = { stateMachineId: this.dest.config.stateMachineId, client: this.dest.client };
20007
- const strategy = params.strategy ?? "indexed_rates";
20008
- const handler = this.quoteStrategies[strategy];
20009
- if (!handler) throw new UnsupportedIntentQuoteStrategyError(strategy);
20010
- return handler.quote({ ...params, strategy }, source, destination);
19339
+ return this.market.quoteIntent(params, this.source.config.stateMachineId, this.dest.config.stateMachineId);
20011
19340
  }
20012
19341
  /**
20013
- * Returns indexed destination liquidity and its source-routing slices.
19342
+ * Returns the orderbook liquidity serving a swap of `tokenIn` on the source
19343
+ * chain for `tokenOut` on the destination chain: the best rate, true and
19344
+ * virtual depth, and the largest input the route can fill.
20014
19345
  *
20015
- * Destination, unrestricted, and explicit-route capacity come exclusively
20016
- * from the indexer's pair-centric liquidity entities. The SDK does not decide
20017
- * whether unrestricted bidders cover the source chain. Amounts reflect the
20018
- * latest rolling sample; they are not reservations or fill guarantees.
20019
- *
20020
- * Requires a prior call to {@link withQueryClient}.
19346
+ * Amounts reflect the live book; they are not reservations or fill guarantees.
20021
19347
  */
20022
19348
  async queryAvailableLiquidity(params) {
20023
- const { queryClient } = this.requireIndexer();
20024
- const sourceStateMachineId = getConfigByStateMachineId(this.source.config.stateMachineId)?.stateMachineId;
20025
- const destinationStateMachineId = getConfigByStateMachineId(this.dest.config.stateMachineId)?.stateMachineId;
20026
- if (!sourceStateMachineId) throw new UnsupportedLiquidityChainError(this.source.config.stateMachineId);
20027
- if (!destinationStateMachineId) throw new UnsupportedLiquidityChainError(this.dest.config.stateMachineId);
20028
- const sourceToken = this.source.configService.getAssetMetadataByAddress(sourceStateMachineId, params.tokenIn);
20029
- const destinationToken = this.dest.configService.getAssetMetadataByAddress(
20030
- destinationStateMachineId,
20031
- params.tokenOut
19349
+ return this.market.availableLiquidity(
19350
+ params,
19351
+ this.source.config.stateMachineId,
19352
+ this.dest.config.stateMachineId
20032
19353
  );
20033
- if (!sourceToken) throw new UnsupportedLiquidityAssetError(sourceStateMachineId, params.tokenIn);
20034
- if (!destinationToken) throw new UnsupportedLiquidityAssetError(destinationStateMachineId, params.tokenOut);
20035
- return new LiquidityEngine(queryClient).getAvailableLiquidity({
20036
- source: {
20037
- chain: sourceStateMachineId,
20038
- ...sourceToken
20039
- },
20040
- destination: {
20041
- chain: destinationStateMachineId,
20042
- ...destinationToken
20043
- }
20044
- });
20045
19354
  }
20046
19355
  /**
20047
- * Returns aggregate indexed pool buy and sell rates in less-valued quote-token
20048
- * units without requiring token addresses. Symbols are matched
20049
- * case-insensitively; chain IDs resolve configured token deployments.
19356
+ * Returns the orderbook's best bid and ask for a pair, with the mid and
19357
+ * spread, in quote-token units per one base token. Only orders filled on the
19358
+ * destination chain that accept swaps from the source chain are counted.
19359
+ * Symbols are matched case-insensitively; chain IDs resolve configured token
19360
+ * deployments.
20050
19361
  */
20051
19362
  async queryBuyAndSellRates(params) {
20052
- const { queryClient } = this.requireIndexer();
20053
19363
  const sourceChain = chainConfigs[params.sourceChainId]?.stateMachineId;
20054
19364
  const destinationChain = chainConfigs[params.destinationChainId]?.stateMachineId;
20055
19365
  if (!sourceChain) throw new UnsupportedLiquidityChainError(params.sourceChainId);
20056
19366
  if (!destinationChain) throw new UnsupportedLiquidityChainError(params.destinationChainId);
20057
- const sourceToken = this.source.configService.getAssetMetadataBySymbol(sourceChain, params.tokenInSymbol);
20058
- const destinationToken = this.dest.configService.getAssetMetadataBySymbol(
20059
- destinationChain,
20060
- params.tokenOutSymbol
20061
- );
20062
- if (!sourceToken) throw new UnsupportedLiquidityAssetError(sourceChain, params.tokenInSymbol);
20063
- if (!destinationToken) throw new UnsupportedLiquidityAssetError(destinationChain, params.tokenOutSymbol);
20064
- return new LiquidityEngine(queryClient).getBuyAndSellRates({
19367
+ return this.market.buyAndSellRates({
20065
19368
  sourceChain,
20066
19369
  destinationChain,
20067
- tokenInSymbol: sourceToken.symbol,
20068
- tokenOutSymbol: destinationToken.symbol
19370
+ tokenInSymbol: params.tokenInSymbol,
19371
+ tokenOutSymbol: params.tokenOutSymbol
20069
19372
  });
20070
19373
  }
20071
19374
  /**
@@ -20316,6 +19619,8 @@ var IntentGateway = class _IntentGateway {
20316
19619
  /**
20317
19620
  * Returns both the native token cost and the relayer fee for cancelling an
20318
19621
  * order. Use `relayerFee` to approve the ERC-20 spend before submitting.
19622
+ * Same-chain orders use the direct local route for either `from` option and
19623
+ * return `{ nativeValue: 0n, relayerFee: 0n }`.
20319
19624
  *
20320
19625
  * Delegates to {@link OrderCanceller.quoteCancelOrder}.
20321
19626
  *
@@ -20339,9 +19644,17 @@ var IntentGateway = class _IntentGateway {
20339
19644
  *
20340
19645
  * Delegates to {@link OrderCanceller.cancelOrder}.
20341
19646
  *
19647
+ * Same-chain orders always use the direct source-gateway route. The order
19648
+ * user may call through the deadline; any account may call strictly after
19649
+ * it, pays the transaction gas, and cannot change the refund beneficiary.
19650
+ * The SDK yields unsigned transaction fields and accepts either the caller's
19651
+ * signed raw transaction or its already-broadcast transaction hash.
19652
+ *
20342
19653
  * @param order - The order to cancel.
20343
- * @param indexerClient - Indexer client used for ISMP request status streaming.
20344
- * @param options - Choose the initiation side. Defaults to source-side cancellation.
19654
+ * @param indexerClient - Indexer client used for cross-chain ISMP request
19655
+ * status streaming; the same-chain route does not access it.
19656
+ * @param options - Choose the cross-chain initiation side. Defaults to source;
19657
+ * ignored for routing when source and destination are the same chain.
20345
19658
  * @yields {@link CancelEvent} objects describing each cancellation stage.
20346
19659
  */
20347
19660
  async *cancelOrder(order, indexerClient, options = {}) {
@@ -20471,7 +19784,7 @@ var IntentGateway = class _IntentGateway {
20471
19784
  if (estimate.totalGasCostWei === 0n || estimate.totalGasInFeeToken === 0n) {
20472
19785
  throw new Error("Gas estimation failed");
20473
19786
  }
20474
- const fees = isSameChain ? estimate.totalGasInFeeToken * 2n : (estimate.totalGasInFeeToken + estimate.relayerFeeInSourceFeeToken) * 105n / 100n;
19787
+ const fees = isSameChain ? estimate.totalGasInFeeToken * 2n : ((estimate.totalGasInFeeToken + estimate.relayerFeeInSourceFeeToken) * 105n + 99n) / 100n;
20475
19788
  const { address: feeToken } = await this.source.getFeeTokenWithDecimals();
20476
19789
  return {
20477
19790
  fees,
@@ -20504,17 +19817,27 @@ var IntentGateway = class _IntentGateway {
20504
19817
  return this._crypto.decodeERC7821Execute(callData);
20505
19818
  }
20506
19819
  /**
20507
- * Checks whether an order has been filled on the destination chain.
19820
+ * Checks whether an order is finalized on the destination chain.
20508
19821
  *
20509
19822
  * Delegates to {@link OrderStatusChecker.isOrderFilled}.
20510
19823
  *
20511
19824
  * @param order - The order to check.
20512
- * @returns `true` if the order's commitment slot on the destination chain is
20513
- * non-zero (i.e. `fillOrder` has been called successfully).
19825
+ * @returns `true` once a completing fill or a destination-side cancellation
19826
+ * has finalized the order; `false` while it is open or only partly filled.
20514
19827
  */
20515
19828
  async isOrderFilled(order) {
20516
19829
  return this.orderStatusChecker.isOrderFilled(order);
20517
19830
  }
19831
+ /**
19832
+ * Output credited to the order so far, one entry per leg.
19833
+ *
19834
+ * Delegates to {@link OrderStatusChecker.getFillProgress}.
19835
+ *
19836
+ * @param order - The order to check.
19837
+ */
19838
+ async getFillProgress(order) {
19839
+ return this.orderStatusChecker.getFillProgress(order);
19840
+ }
20518
19841
  /**
20519
19842
  * Checks whether all escrowed inputs for an order have been refunded on the
20520
19843
  * source chain.
@@ -20522,8 +19845,8 @@ var IntentGateway = class _IntentGateway {
20522
19845
  * Delegates to {@link OrderStatusChecker.isOrderRefunded}.
20523
19846
  *
20524
19847
  * @param order - The order to check.
20525
- * @returns `true` if every input token's escrowed amount has been zeroed out
20526
- * in the `_orders` mapping on the source chain.
19848
+ * @returns `true` if every input's escrowed amount has been zeroed out
19849
+ * in the per-leg `_orders` mapping on the source chain.
20527
19850
  */
20528
19851
  async isOrderRefunded(order) {
20529
19852
  return this.orderStatusChecker.isOrderRefunded(order);
@@ -20560,9 +19883,7 @@ var IntentGateway = class _IntentGateway {
20560
19883
  }
20561
19884
  requireIndexer() {
20562
19885
  if (!this.indexer) {
20563
- throw new Error(
20564
- "IntentGateway: call withQueryClient(queryClient) before using indexer-backed methods or Phantom quotes"
20565
- );
19886
+ throw new Error("IntentGateway: call withQueryClient(queryClient) before using indexer-backed methods");
20566
19887
  }
20567
19888
  return this.indexer;
20568
19889
  }
@@ -20585,78 +19906,127 @@ var IntentGateway = class _IntentGateway {
20585
19906
  const { queryClient, pollInterval, logger } = this.requireIndexer();
20586
19907
  const streamLogger = logger.withTag("[orderStatusStream]");
20587
19908
  const TERMINAL = ["FILLED", "REDEEMED", "REFUNDED"];
19909
+ const latestOrderStatus = (order2) => {
19910
+ const latest = order2.statuses[order2.statuses.length - 1];
19911
+ if (latest.status === "CANCELLED") {
19912
+ for (let i = order2.statuses.length - 1; i >= 0; i--) {
19913
+ if (TERMINAL.includes(order2.statuses[i].status)) return order2.statuses[i];
19914
+ }
19915
+ }
19916
+ return latest;
19917
+ };
20588
19918
  let order;
20589
19919
  while (!order) {
20590
19920
  await sleep(pollInterval);
20591
19921
  order = await _queryOrderInternal({ commitmentHash: commitment, queryClient, logger });
20592
19922
  }
20593
19923
  streamLogger.trace("`Order` found");
20594
- const latestStatus = order.statuses[order.statuses.length - 1];
19924
+ let latestStatus = latestOrderStatus(order);
20595
19925
  yield { status: latestStatus.status, metadata: latestStatus.metadata };
20596
19926
  if (TERMINAL.includes(latestStatus.status)) return;
20597
19927
  while (true) {
20598
19928
  await sleep(pollInterval);
20599
19929
  const updatedOrder = await _queryOrderInternal({ commitmentHash: commitment, queryClient, logger });
20600
19930
  if (!updatedOrder) continue;
20601
- const newLatestStatus = updatedOrder.statuses[updatedOrder.statuses.length - 1];
19931
+ const newLatestStatus = latestOrderStatus(updatedOrder);
20602
19932
  if (newLatestStatus.status !== latestStatus.status) {
19933
+ latestStatus = newLatestStatus;
20603
19934
  yield { status: newLatestStatus.status, metadata: newLatestStatus.metadata };
20604
19935
  if (TERMINAL.includes(newLatestStatus.status)) return;
20605
19936
  }
20606
19937
  }
20607
19938
  }
20608
19939
  };
20609
- function rpcFetch() {
20610
- const f = globalThis.fetch;
20611
- if (typeof f !== "function") {
20612
- throw new Error("No fetch available; call setAggregationFetch() before using the aggregation helpers");
20613
- }
20614
- return f;
19940
+
19941
+ // src/protocols/intents/liquidity-pool.ts
19942
+ function sortPoolSymbols(symbolA, symbolB) {
19943
+ return symbolA.toLowerCase() <= symbolB.toLowerCase() ? [symbolA, symbolB] : [symbolB, symbolA];
20615
19944
  }
20616
- var PhantomRpcError = class extends Error {
20617
- constructor(message, cause) {
20618
- super(message);
20619
- this.cause = cause;
20620
- this.name = "PhantomRpcError";
20621
- }
20622
- cause;
20623
- };
20624
- async function rpcCall(url, payload) {
20625
- let lastErr;
20626
- for (let attempt = 0; attempt < 4; attempt++) {
20627
- if (attempt > 0) await new Promise((resolve) => setTimeout(resolve, 150 * attempt));
20628
- let timer;
20629
- try {
20630
- const timeout = new Promise((_, reject) => {
20631
- timer = setTimeout(() => reject(new Error(`rpc timeout: ${url}`)), 12e3);
20632
- });
20633
- const response = await Promise.race([
20634
- rpcFetch()(url, {
20635
- method: "POST",
20636
- headers: { accept: "application/json", "content-type": "application/json" },
20637
- body: JSON.stringify(payload)
20638
- }),
20639
- timeout
20640
- ]);
20641
- const body = await response.json();
20642
- if (body?.error) {
20643
- lastErr = new Error(`rpc error: ${JSON.stringify(body.error).slice(0, 200)}`);
20644
- continue;
20645
- }
20646
- return body;
20647
- } catch (err) {
20648
- lastErr = err;
20649
- } finally {
20650
- if (timer) clearTimeout(timer);
20651
- }
20652
- }
20653
- throw new PhantomRpcError(`RPC call failed after 4 attempts: ${url}`, lastErr);
19945
+ function poolSlug(symbolA, symbolB) {
19946
+ return sortPoolSymbols(symbolA, symbolB).join("-");
19947
+ }
19948
+
19949
+ // src/protocols/intents/rateFill.ts
19950
+ function ceilDiv(numerator, denominator) {
19951
+ return numerator === 0n ? 0n : (numerator - 1n) / denominator + 1n;
19952
+ }
19953
+ function previewRateFill(escrow, required, filled, take, offered) {
19954
+ if (escrow <= 0n || required <= 0n || take <= 0n || offered <= 0n) {
19955
+ throw new Error("RateFillInvalidAmount");
19956
+ }
19957
+ if (filled < 0n || filled >= required) throw new Error("RateFillNoProgress");
19958
+ if (ceilDiv(take * required, escrow) > offered) throw new Error("RateBelowOrder");
19959
+ const uncappedCredit = take * required / escrow;
19960
+ const credit = uncappedCredit < required - filled ? uncappedCredit : required - filled;
19961
+ const release = escrow * (filled + credit) / required - escrow * filled / required;
19962
+ if (credit === 0n || release === 0n) throw new Error("RateFillNoProgress");
19963
+ const ratePayment = ceilDiv(offered * release, take);
19964
+ const delivered = ratePayment > credit ? ratePayment : credit;
19965
+ return { credit, release, delivered, surplus: delivered - credit };
20654
19966
  }
20655
- var FILL_ORDER_ABI = IntentGatewayV2_default.ABI;
20656
19967
  var DECLARATION_V1 = 1;
20657
19968
  var DECLARATION_V2 = 2;
19969
+ var PAYMASTER_ADDRESS_BYTES = 20;
19970
+ var PAYMASTER_GAS_LIMIT_BYTES = 16;
19971
+ var PAYMASTER_DATA_OFFSET = PAYMASTER_ADDRESS_BYTES + 2 * PAYMASTER_GAS_LIMIT_BYTES;
19972
+ var SIMPLEX_MODE_PERMIT2 = 2;
19973
+ var PERMIT2_DATA_BYTES = 1 + 20 + 32 + 32 + 32 + 1 + 32 + 32;
19974
+ var PERMIT2_SPONSORSHIP_BYTES = PAYMASTER_DATA_OFFSET + PERMIT2_DATA_BYTES;
20658
19975
  var MAX_DECLARED_ENTRIES = 255;
20659
19976
  var MAX_TOKEN_ID_BYTES = 32;
19977
+ function utf8Encode(text) {
19978
+ const bytes = [];
19979
+ for (const char of text) {
19980
+ const codePoint = char.codePointAt(0);
19981
+ if (codePoint < 128) bytes.push(codePoint);
19982
+ else if (codePoint < 2048) bytes.push(192 | codePoint >> 6, 128 | codePoint & 63);
19983
+ else if (codePoint < 65536) {
19984
+ bytes.push(224 | codePoint >> 12, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
19985
+ } else {
19986
+ bytes.push(
19987
+ 240 | codePoint >> 18,
19988
+ 128 | codePoint >> 12 & 63,
19989
+ 128 | codePoint >> 6 & 63,
19990
+ 128 | codePoint & 63
19991
+ );
19992
+ }
19993
+ }
19994
+ return bytes;
19995
+ }
19996
+ function utf8Decode(bytes) {
19997
+ let text = "";
19998
+ for (let offset = 0; offset < bytes.length; ) {
19999
+ const lead = bytes[offset];
20000
+ let codePoint;
20001
+ let continuations;
20002
+ if (lead < 128) {
20003
+ codePoint = lead;
20004
+ continuations = 0;
20005
+ } else if ((lead & 224) === 192) {
20006
+ codePoint = lead & 31;
20007
+ continuations = 1;
20008
+ } else if ((lead & 240) === 224) {
20009
+ codePoint = lead & 15;
20010
+ continuations = 2;
20011
+ } else if ((lead & 248) === 240) {
20012
+ codePoint = lead & 7;
20013
+ continuations = 3;
20014
+ } else {
20015
+ return null;
20016
+ }
20017
+ if (offset + continuations >= bytes.length) return null;
20018
+ for (let index = 1; index <= continuations; index++) {
20019
+ const byte = bytes[offset + index];
20020
+ if ((byte & 192) !== 128) return null;
20021
+ codePoint = codePoint << 6 | byte & 63;
20022
+ }
20023
+ const overlong = continuations === 1 && codePoint < 128 || continuations === 2 && codePoint < 2048 || continuations === 3 && codePoint < 65536;
20024
+ if (overlong || codePoint > 1114111 || codePoint >= 55296 && codePoint <= 57343) return null;
20025
+ text += String.fromCodePoint(codePoint);
20026
+ offset += continuations + 1;
20027
+ }
20028
+ return text;
20029
+ }
20660
20030
  function tokenIdToBytes(tokenId) {
20661
20031
  if (tokenId < 0n) throw new Error(`Uniswap V4 tokenId cannot be negative: ${tokenId}`);
20662
20032
  const bytes = [];
@@ -20679,7 +20049,7 @@ function encodePhantomBidDeclaration(declaration) {
20679
20049
  const version = positions.length > 0 ? DECLARATION_V2 : DECLARATION_V1;
20680
20050
  const bytes = [version, chains2.length];
20681
20051
  for (const chain of chains2) {
20682
- const encoded = stringToU8a(chain);
20052
+ const encoded = utf8Encode(chain);
20683
20053
  if (encoded.length === 0 || encoded.length > 255) {
20684
20054
  throw new Error(`Invalid state machine id in source chain declaration: ${chain}`);
20685
20055
  }
@@ -20697,82 +20067,100 @@ function encodePhantomBidDeclaration(declaration) {
20697
20067
  }
20698
20068
  return u8aToHex(new Uint8Array(bytes));
20699
20069
  }
20700
- function decodePhantomBidDeclaration(paymasterAndData) {
20701
- const absent = { acceptedSources: null, uniswapV4Positions: [] };
20702
- if (!paymasterAndData || !isHex$1(paymasterAndData)) return absent;
20703
- const bytes = hexToU8a(paymasterAndData);
20704
- if (bytes.length < 2) return absent;
20705
- const version = bytes[0];
20706
- if (version !== DECLARATION_V1 && version !== DECLARATION_V2) return absent;
20070
+ function parseDeclaration(bytes, start) {
20071
+ if (bytes.length - start < 2) return null;
20072
+ const version = bytes[start];
20073
+ if (version !== DECLARATION_V1 && version !== DECLARATION_V2) return null;
20707
20074
  const chains2 = [];
20708
- let offset = 2;
20709
- for (let entry = 0; entry < bytes[1]; entry++) {
20710
- if (offset >= bytes.length) return absent;
20075
+ let offset = start + 2;
20076
+ for (let entry = 0; entry < bytes[start + 1]; entry++) {
20077
+ if (offset >= bytes.length) return null;
20711
20078
  const length = bytes[offset];
20712
20079
  offset += 1;
20713
- if (length === 0 || offset + length > bytes.length) return absent;
20714
- chains2.push(u8aToString(bytes.subarray(offset, offset + length)));
20080
+ if (length === 0 || offset + length > bytes.length) return null;
20081
+ const chain = utf8Decode(bytes.subarray(offset, offset + length));
20082
+ if (chain === null) return null;
20083
+ chains2.push(chain);
20715
20084
  offset += length;
20716
20085
  }
20717
20086
  const positions = [];
20718
20087
  if (version === DECLARATION_V2) {
20719
- if (offset >= bytes.length) return absent;
20088
+ if (offset >= bytes.length) return null;
20720
20089
  const count = bytes[offset];
20721
20090
  offset += 1;
20722
20091
  for (let entry = 0; entry < count; entry++) {
20723
- if (offset >= bytes.length) return absent;
20092
+ if (offset >= bytes.length) return null;
20724
20093
  const length = bytes[offset];
20725
20094
  offset += 1;
20726
- if (length === 0 || length > MAX_TOKEN_ID_BYTES || offset + length > bytes.length) return absent;
20727
- let tokenId = 0n;
20728
- for (const byte of bytes.subarray(offset, offset + length)) tokenId = tokenId << 8n | BigInt(byte);
20729
- positions.push(tokenId);
20095
+ if (length === 0 || length > MAX_TOKEN_ID_BYTES || offset + length > bytes.length) return null;
20096
+ positions.push(bytesToBigInt3(bytes.subarray(offset, offset + length)));
20730
20097
  offset += length;
20731
20098
  }
20732
20099
  }
20733
- if (offset !== bytes.length) return absent;
20100
+ if (offset !== bytes.length) return null;
20734
20101
  return { acceptedSources: chains2, uniswapV4Positions: positions };
20735
20102
  }
20736
- function encodeAcceptedSourceChains(chains2) {
20737
- return encodePhantomBidDeclaration({ acceptedSourceChains: chains2 });
20103
+ function bytesToBigInt3(bytes) {
20104
+ let value = 0n;
20105
+ for (const byte of bytes) value = value << 8n | BigInt(byte);
20106
+ return value;
20738
20107
  }
20739
- function decodeAcceptedSourceChains(paymasterAndData) {
20740
- return decodePhantomBidDeclaration(paymasterAndData).acceptedSources;
20108
+ function bytesToAddress(bytes) {
20109
+ return u8aToHex(bytes);
20741
20110
  }
20742
- var UNISWAP_QUOTE_HAIRCUT_BPS = 10n;
20743
- function haircut(amount, bps) {
20744
- return amount * (10000n - bps) / 10000n;
20111
+ function hasPermit2Sponsorship(bytes) {
20112
+ return bytes.length >= PERMIT2_SPONSORSHIP_BYTES && bytes[PAYMASTER_DATA_OFFSET] === SIMPLEX_MODE_PERMIT2;
20745
20113
  }
20746
- function applyUniswapQuoteHaircut(amount) {
20747
- return haircut(amount, UNISWAP_QUOTE_HAIRCUT_BPS);
20114
+ function parseSponsorship(bytes) {
20115
+ let offset = 0;
20116
+ const take = (length) => {
20117
+ const slice = bytes.subarray(offset, offset + length);
20118
+ offset += length;
20119
+ return slice;
20120
+ };
20121
+ const paymaster = bytesToAddress(take(PAYMASTER_ADDRESS_BYTES));
20122
+ take(2 * PAYMASTER_GAS_LIMIT_BYTES);
20123
+ take(1);
20124
+ const token = bytesToAddress(take(20));
20125
+ const permitAmount = bytesToBigInt3(take(32));
20126
+ const nonce = bytesToBigInt3(take(32));
20127
+ const deadline = bytesToBigInt3(take(32));
20128
+ return { paymaster, token, permitAmount, nonce, deadline };
20748
20129
  }
20749
- var SELECTOR_GATEWAY_PARAMS = "0xcff0ab96";
20750
- var GATEWAY_PARAMS_WORDS = 6;
20751
- var GATEWAY_PARAMS_FEE_WORD = 4;
20752
- async function readProtocolFeeHaircutBps(evmRpcUrl, gatewayAddress) {
20753
- const result = await rpcCall(evmRpcUrl, {
20754
- id: 1,
20755
- jsonrpc: "2.0",
20756
- method: "eth_call",
20757
- params: [{ to: gatewayAddress, data: SELECTOR_GATEWAY_PARAMS }, "latest"]
20758
- });
20759
- const hex = result.result;
20760
- if (typeof hex !== "string" || hex.length < 2 + 64 * GATEWAY_PARAMS_WORDS) {
20761
- throw new PhantomRpcError(`IntentGateway.params() returned no usable result from ${gatewayAddress} on ${evmRpcUrl}`);
20762
- }
20763
- const start = 2 + 64 * GATEWAY_PARAMS_FEE_WORD;
20764
- const protocolFeeBps = BigInt(`0x${hex.slice(start, start + 64)}`);
20765
- if (protocolFeeBps >= 10000n) {
20766
- throw new PhantomRpcError(`IntentGateway ${gatewayAddress} reports an implausible protocol fee: ${protocolFeeBps} bps`);
20130
+ var absentDeclaration = () => ({ acceptedSources: null, uniswapV4Positions: [] });
20131
+ function decodePhantomBidPaymasterAndData(paymasterAndData) {
20132
+ const none = { mode: "none", declaration: absentDeclaration(), sponsorship: null };
20133
+ if (!paymasterAndData || !isHex$1(paymasterAndData)) return none;
20134
+ const bytes = hexToU8a(paymasterAndData);
20135
+ const bare = parseDeclaration(bytes, 0);
20136
+ if (bare) return { mode: "declaration", declaration: bare, sponsorship: null };
20137
+ if (!hasPermit2Sponsorship(bytes)) return none;
20138
+ const sponsorship = parseSponsorship(bytes);
20139
+ const tail = bytes.length > PERMIT2_SPONSORSHIP_BYTES ? parseDeclaration(bytes, PERMIT2_SPONSORSHIP_BYTES) : null;
20140
+ return { mode: "permit2", declaration: tail ?? absentDeclaration(), sponsorship };
20141
+ }
20142
+ function decodePhantomBidDeclaration(paymasterAndData) {
20143
+ return decodePhantomBidPaymasterAndData(paymasterAndData).declaration;
20144
+ }
20145
+ function encodePhantomBidPaymasterAndData(bid) {
20146
+ const declaration = encodePhantomBidDeclaration(bid);
20147
+ const sponsorship = bid.sponsorship;
20148
+ if (!sponsorship || sponsorship === "0x") return declaration;
20149
+ if (!isHex$1(sponsorship)) throw new Error("Phantom bid sponsorship is not hex");
20150
+ const bytes = hexToU8a(sponsorship);
20151
+ if (bytes.length !== PERMIT2_SPONSORSHIP_BYTES || !hasPermit2Sponsorship(bytes)) {
20152
+ throw new Error(
20153
+ `Phantom bid sponsorship must be a ${PERMIT2_SPONSORSHIP_BYTES}-byte Permit2-mode paymasterAndData, got ${bytes.length} bytes`
20154
+ );
20767
20155
  }
20768
- return protocolFeeBps;
20156
+ return `${sponsorship}${declaration.slice(2)}`;
20157
+ }
20158
+ function encodeAcceptedSourceChains(chains2) {
20159
+ return encodePhantomBidDeclaration({ acceptedSourceChains: chains2 });
20769
20160
  }
20770
- function applyProtocolFeeHaircut(amount, protocolFeeBps) {
20771
- return haircut(amount, protocolFeeBps);
20161
+ function decodeAcceptedSourceChains(paymasterAndData) {
20162
+ return decodePhantomBidDeclaration(paymasterAndData).acceptedSources;
20772
20163
  }
20773
- FILL_ORDER_ABI.find(
20774
- (item) => item?.type === "function" && item?.name === "fillOrder"
20775
- )?.inputs?.[0];
20776
20164
  var TokenGateway = class {
20777
20165
  source;
20778
20166
  dest;
@@ -24988,9 +24376,9 @@ async function teleport(teleport_param) {
24988
24376
  if (scaleEncodedAssetId === null) {
24989
24377
  throw new Error("Unknown asset id provided");
24990
24378
  }
24991
- const destinationStateMachine = normalizeStateMachineId(params.destination);
24992
- const destination = convertStateMachineIdToEnum(destinationStateMachine);
24993
- const recipient = hexToBytes(normalizeAddressForStateMachine(params.recipient, destinationStateMachine));
24379
+ const destinationStateMachine2 = normalizeStateMachineId(params.destination);
24380
+ const destination = convertStateMachineIdToEnum(destinationStateMachine2);
24381
+ const recipient = hexToBytes(normalizeAddressForStateMachine(params.recipient, destinationStateMachine2));
24994
24382
  const teleportParams = {
24995
24383
  destination,
24996
24384
  recepient: Array.from(recipient),
@@ -25243,6 +24631,6 @@ async function teleportDot(param_) {
25243
24631
  return stream;
25244
24632
  }
25245
24633
 
25246
- export { ADDRESS_ZERO2 as ADDRESS_ZERO, BundlerMethod, CHAINS_WITHOUT_VALID_UNTIL, ChainConfigService, Chains, CryptoUtils, DEFAULT_ADDRESS, DEFAULT_GRAFFITI, DOMAIN_TYPEHASH, DUMMY_PRIVATE_KEY, ERC20Method, ERC7821_BATCH_MODE, EvmChain, ABI as EvmHostABI, EvmLanguage, FILL_ORDER_V1_ABI, HyperClientStatus, HyperFungibleToken, HyperFungibleTokenABI, INCLUSION_TIMEOUT_MS, IndexedRateUnavailableError, IntentGateway, ABI3 as IntentGatewayABI, IntentOrderStatus, IntentsCoprocessor, InvalidIndexedRateError, InvalidLiquidityIndexerResponseError, InvalidPhantomSnapshotError, IsmpClient, LEGACY_FILL_OPTIONS_IMPLEMENTATIONS, MOCK_ADDRESS, ORDER_V2_PARAM_TYPE, OrderStatus, OrderStatusChecker, PACKED_USEROP_TYPEHASH, PLACE_ORDER_SELECTOR, PhantomSnapshotUnavailableError, PharosChain, PolkadotHubChain, REQUEST_COMMITMENTS_SLOT, REQUEST_RECEIPTS_SLOT, RESPONSE_COMMITMENTS_SLOT, RESPONSE_RECEIPTS_SLOT, RequestKind, RequestStatus, SELECT_SOLVER_TYPEHASH, STATE_COMMITMENTS_SLOT, SubstrateChain, Swap, TESTNET_CHAINS, TeleportStatus, TimeoutStatus, TokenGateway, TronChain, UNISWAP_QUOTE_HAIRCUT_BPS, USE_ETHERSCAN_CHAINS, UnsupportedIntentQuotePairError, UnsupportedIntentQuoteStrategyError, UnsupportedLiquidityAssetError, UnsupportedLiquidityChainError, WrappedHyperFungibleTokenABI, __test, adjustDecimals, applyProtocolFeeHaircut, applyUniswapQuoteHaircut, bytes20ToBytes32, bytes32ToBytes20, calculateAllowanceMappingLocation, calculateBalanceMappingLocation, chainConfigs, constructRedeemEscrowRequestBody, constructRefundEscrowRequestBody, convertCodecToIGetRequest, convertCodecToIProof, convertIGetRequestToCodec, convertIProofToCodec, convertStateIdToStateMachineId, convertStateMachineEnumToString, convertStateMachineIdToEnum, createEvmChain, createQueryClient, decodeAcceptedSourceChains, decodeERC7821ExecuteBatch, decodeFillOrder, decodePhantomBidDeclaration, decodeUserOpScale, deriveHttpUrl, encodeAcceptedSourceChains, encodeERC7821ExecuteBatch, encodeFillOrder, encodeISMPMessage, encodePhantomBidDeclaration, encodeStateMachineId, encodeUserOpScale, encodeWithdrawalRequest, estimateGasForPost, fetchPrice, fetchSourceProof, generateRootWithProof, getChainId, getConfigByStateMachineId, getContractCallInput, getContractCallInputs, getFillOptionsVersion, getGasPriceFromEtherscan, getOrFetchStorageSlot, getOrderPlacedFromTx, getPostRequestEventFromTx, getPostResponseEventFromTx, getRequestCommitment, getStateCommitmentFieldSlot, getStateCommitmentSlot, getStorageSlot, getViemChain, hexToString, hyperbridgeAddress, maxBigInt, normalizeAddressForEvmBytes32, normalizeAddressForStateMachine, normalizeEvmAddress, normalizeEvmChainId, normalizeStateMachineId, orderCommitment, parseStateMachineId, pharosAtlantic, pharosMainnet, polkadotAssetHubPaseo, polkadotHubMainnet, poolSlug, postRequestCommitment, queryAssetTeleported, queryGetRequest, queryPostRequest, quoteUniswap, readProtocolFeeHaircutBps, requestCommitmentKey, resetFillOptionsVersionCache, responseCommitmentKey, retryPromise, sortPoolSymbols, teleport, teleportDot, transformOrderForContract, tronChainIds, tronNile };
24634
+ export { ADDRESS_ZERO2 as ADDRESS_ZERO, BundlerMethod, CONTRACT_VERSION_ABI, ChainConfigService, Chains, CryptoUtils, DEFAULT_ADDRESS, DEFAULT_GRAFFITI, DOMAIN_TYPEHASH, DUMMY_PRIVATE_KEY, ERC20Method, ERC7821_BATCH_MODE, EvmChain, ABI as EvmHostABI, EvmLanguage, FILL_ORDER_SELECTOR, HyperClientStatus, HyperFungibleToken, HyperFungibleTokenABI, HyperFxOrderbook, INCLUSION_TIMEOUT_MS, InsufficientOrderbookLiquidityError, IntentGateway, ABI3 as IntentGatewayABI, IntentOrderStatus, IntentsCoprocessor, IsmpClient, MAX_DECLARED_ENTRIES, MOCK_ADDRESS, ORDERBOOK_DECIMALS, ORDERBOOK_QUERIES, ORDERBOOK_URLS, ORDER_V2_PARAM_TYPE, OrderStatus, OrderStatusChecker, OrderbookQuoteNotConvergedError, OrderbookRequestError, PACKED_USEROP_TYPEHASH, PERMIT2_SPONSORSHIP_BYTES, PLACE_ORDER_SELECTOR, PharosChain, PolkadotHubChain, REQUEST_COMMITMENTS_SLOT, REQUEST_RECEIPTS_SLOT, RESPONSE_COMMITMENTS_SLOT, RESPONSE_RECEIPTS_SLOT, RequestKind, RequestStatus, SELECT_SOLVER_TYPEHASH, STATE_COMMITMENTS_SLOT, SUPPORTED_INTENTS_VERSION, SubstrateChain, Swap, TESTNET_CHAINS, TeleportStatus, TimeoutStatus, TokenGateway, TronChain, USE_ETHERSCAN_CHAINS, UnsupportedLiquidityAssetError, UnsupportedLiquidityChainError, WrappedHyperFungibleTokenABI, __test, adjustDecimals, assertGatewayRelease, bytes20ToBytes32, bytes32ToBytes20, calculateAllowanceMappingLocation, calculateBalanceMappingLocation, chainConfigs, constructRedeemEscrowRequestBody, constructRefundEscrowRequestBody, convertCodecToIGetRequest, convertCodecToIProof, convertIGetRequestToCodec, convertIProofToCodec, convertStateIdToStateMachineId, convertStateMachineEnumToString, convertStateMachineIdToEnum, createEvmChain, createQueryClient, decodeAcceptedSourceChains, decodeERC7821ExecuteBatch, decodeFillOrder, decodePhantomBidDeclaration, decodePhantomBidPaymasterAndData, decodeUserOpScale, deriveHttpUrl, encodeAcceptedSourceChains, encodeERC7821ExecuteBatch, encodeFillOrder, encodeISMPMessage, encodePhantomBidDeclaration, encodePhantomBidPaymasterAndData, encodeStateMachineId, encodeUserOpScale, encodeWithdrawalRequest, estimateGasForPost, fetchPrice, fetchSourceProof, generateRootWithProof, getChainId, getConfigByStateMachineId, getContractCallInput, getContractCallInputs, getGasPriceFromEtherscan, getOrFetchStorageSlot, getOrderPlacedFromTx, getPostRequestEventFromTx, getPostResponseEventFromTx, getRequestCommitment, getStateCommitmentFieldSlot, getStateCommitmentSlot, getStorageSlot, getViemChain, hexToString, hyperbridgeAddress, isCanonicalEvmToken, maxBigInt, normalizeAddressForEvmBytes32, normalizeAddressForStateMachine, normalizeEvmAddress, normalizeEvmChainId, normalizeStateMachineId, orderCommitment, orderbookUrlFor, parseStateMachineId, pharosAtlantic, pharosMainnet, polkadotAssetHubPaseo, polkadotHubMainnet, poolSlug, postRequestCommitment, previewRateFill, queryAssetTeleported, queryGetRequest, queryPostRequest, quoteUniswap, readLegEscrow, readLegPartialFill, requestCommitmentKey, responseCommitmentKey, retryPromise, sortPoolSymbols, supportsRateFills, teleport, teleportDot, transformOrderForContract, tronChainIds, tronNile };
25247
24635
  //# sourceMappingURL=index.js.map
25248
24636
  //# sourceMappingURL=index.js.map