@hyperbridge/sdk 2.4.0 → 2.4.2

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.
@@ -2490,30 +2490,30 @@ var handlerV2_default = { ABI: ABI2 };
2490
2490
  function tronAddress(base58) {
2491
2491
  return `0x${tronweb.TronWeb.address.toHex(base58).slice(2)}`;
2492
2492
  }
2493
- var Chains = /* @__PURE__ */ ((Chains3) => {
2494
- Chains3["BSC_CHAPEL"] = "EVM-97";
2495
- Chains3["GNOSIS_CHIADO"] = "EVM-10200";
2496
- Chains3["HYPERBRIDGE_GARGANTUA"] = "KUSAMA-4009";
2497
- Chains3["SEPOLIA"] = "EVM-11155111";
2498
- Chains3["MAINNET"] = "EVM-1";
2499
- Chains3["BSC_MAINNET"] = "EVM-56";
2500
- Chains3["ARBITRUM_MAINNET"] = "EVM-42161";
2501
- Chains3["ARBITRUM_SEPOLIA"] = "EVM-421614";
2502
- Chains3["BASE_MAINNET"] = "EVM-8453";
2503
- Chains3["BASE_SEPOLIA"] = "EVM-84532";
2504
- Chains3["OPTIMISM_MAINNET"] = "EVM-10";
2505
- Chains3["OPTIMISM_SEPOLIA"] = "EVM-11155420";
2506
- Chains3["GNOSIS_MAINNET"] = "EVM-100";
2507
- Chains3["SONEIUM_MAINNET"] = "EVM-1868";
2508
- Chains3["POLYGON_MAINNET"] = "EVM-137";
2509
- Chains3["POLKADOT_HUB_MAINNET"] = "EVM-420420419";
2510
- Chains3["POLYGON_AMOY"] = "EVM-80002";
2511
- Chains3["POLKADOT_ASSET_HUB_PASEO"] = "EVM-420420417";
2512
- Chains3["TRON_MAINNET"] = "EVM-728126428";
2513
- Chains3["TRON_NILE"] = "EVM-3448148188";
2514
- Chains3["PHAROS_MAINNET"] = "EVM-688600";
2515
- Chains3["PHAROS_ATLANTIC"] = "EVM-688689";
2516
- return Chains3;
2493
+ var Chains = /* @__PURE__ */ ((Chains2) => {
2494
+ Chains2["BSC_CHAPEL"] = "EVM-97";
2495
+ Chains2["GNOSIS_CHIADO"] = "EVM-10200";
2496
+ Chains2["HYPERBRIDGE_GARGANTUA"] = "KUSAMA-4009";
2497
+ Chains2["SEPOLIA"] = "EVM-11155111";
2498
+ Chains2["MAINNET"] = "EVM-1";
2499
+ Chains2["BSC_MAINNET"] = "EVM-56";
2500
+ Chains2["ARBITRUM_MAINNET"] = "EVM-42161";
2501
+ Chains2["ARBITRUM_SEPOLIA"] = "EVM-421614";
2502
+ Chains2["BASE_MAINNET"] = "EVM-8453";
2503
+ Chains2["BASE_SEPOLIA"] = "EVM-84532";
2504
+ Chains2["OPTIMISM_MAINNET"] = "EVM-10";
2505
+ Chains2["OPTIMISM_SEPOLIA"] = "EVM-11155420";
2506
+ Chains2["GNOSIS_MAINNET"] = "EVM-100";
2507
+ Chains2["SONEIUM_MAINNET"] = "EVM-1868";
2508
+ Chains2["POLYGON_MAINNET"] = "EVM-137";
2509
+ Chains2["POLKADOT_HUB_MAINNET"] = "EVM-420420419";
2510
+ Chains2["POLYGON_AMOY"] = "EVM-80002";
2511
+ Chains2["POLKADOT_ASSET_HUB_PASEO"] = "EVM-420420417";
2512
+ Chains2["TRON_MAINNET"] = "EVM-728126428";
2513
+ Chains2["TRON_NILE"] = "EVM-3448148188";
2514
+ Chains2["PHAROS_MAINNET"] = "EVM-688600";
2515
+ Chains2["PHAROS_ATLANTIC"] = "EVM-688689";
2516
+ return Chains2;
2517
2517
  })(Chains || {});
2518
2518
  var polkadotAssetHubPaseo = viem.defineChain({
2519
2519
  id: 420420417,
@@ -2704,7 +2704,7 @@ var chainConfigs = {
2704
2704
  },
2705
2705
  addresses: {
2706
2706
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
2707
- SolverAccount: "0x3bdB532d91F165BeFad5542700205f5BB5152a82",
2707
+ SolverAccount: "0xfCd233b937D7622AAc63ced3C9A1A12F4a6B64E3",
2708
2708
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
2709
2709
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
2710
2710
  UniswapRouter02: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
@@ -2759,7 +2759,7 @@ var chainConfigs = {
2759
2759
  },
2760
2760
  addresses: {
2761
2761
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
2762
- SolverAccount: "0x3bdB532d91F165BeFad5542700205f5BB5152a82",
2762
+ SolverAccount: "0xfCd233b937D7622AAc63ced3C9A1A12F4a6B64E3",
2763
2763
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
2764
2764
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
2765
2765
  UniswapRouter02: "0x10ED43C718714eb63d5aA57B78B54704E256024E",
@@ -2815,7 +2815,7 @@ var chainConfigs = {
2815
2815
  },
2816
2816
  addresses: {
2817
2817
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
2818
- SolverAccount: "0x3bdB532d91F165BeFad5542700205f5BB5152a82",
2818
+ SolverAccount: "0xfCd233b937D7622AAc63ced3C9A1A12F4a6B64E3",
2819
2819
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
2820
2820
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
2821
2821
  UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
@@ -2872,7 +2872,7 @@ var chainConfigs = {
2872
2872
  },
2873
2873
  addresses: {
2874
2874
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
2875
- SolverAccount: "0x3bdB532d91F165BeFad5542700205f5BB5152a82",
2875
+ SolverAccount: "0xfCd233b937D7622AAc63ced3C9A1A12F4a6B64E3",
2876
2876
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
2877
2877
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
2878
2878
  UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
@@ -2931,7 +2931,7 @@ var chainConfigs = {
2931
2931
  },
2932
2932
  addresses: {
2933
2933
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
2934
- SolverAccount: "0x3bdB532d91F165BeFad5542700205f5BB5152a82",
2934
+ SolverAccount: "0xfCd233b937D7622AAc63ced3C9A1A12F4a6B64E3",
2935
2935
  TokenGateway: "0x8b536105b6Fae2aE9199f5146D3C57Dfe53b614E",
2936
2936
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
2937
2937
  UniswapRouter02: "0xd2f9496824951D5237cC71245D659E48d0d5f9E8",
@@ -3042,7 +3042,7 @@ var chainConfigs = {
3042
3042
  },
3043
3043
  addresses: {
3044
3044
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
3045
- SolverAccount: "0x3bdB532d91F165BeFad5542700205f5BB5152a82",
3045
+ SolverAccount: "0xfCd233b937D7622AAc63ced3C9A1A12F4a6B64E3",
3046
3046
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
3047
3047
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
3048
3048
  UniswapRouter02: "0x4A7b5Da61326A6379179b40d00F57E5bbDC962c2",
@@ -3077,7 +3077,7 @@ var chainConfigs = {
3077
3077
  },
3078
3078
  addresses: {
3079
3079
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
3080
- SolverAccount: "0x3bdB532d91F165BeFad5542700205f5BB5152a82",
3080
+ SolverAccount: "0xfCd233b937D7622AAc63ced3C9A1A12F4a6B64E3",
3081
3081
  TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
3082
3082
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
3083
3083
  UniswapRouter02: "0xB2e26652e4BAd1e56055A051f922E06760cA0BFE",
@@ -3232,7 +3232,7 @@ var chainConfigs = {
3232
3232
  },
3233
3233
  addresses: {
3234
3234
  IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
3235
- SolverAccount: "0x3bdB532d91F165BeFad5542700205f5BB5152a82",
3235
+ SolverAccount: "0xfCd233b937D7622AAc63ced3C9A1A12F4a6B64E3",
3236
3236
  Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
3237
3237
  Calldispatcher: "0xE2C7e576E26E0bE7aC97c6fE925bcDAbD87c4bEd"
3238
3238
  },
@@ -5118,6 +5118,24 @@ var ChainConfigService = class {
5118
5118
  getAssetAddress(chain, symbol) {
5119
5119
  return this.getConfig(chain)?.assets?.[symbol];
5120
5120
  }
5121
+ /**
5122
+ * Resolves configured token metadata from an address on a specific chain.
5123
+ * This is used by SDK helpers that accept token addresses rather than caller-
5124
+ * supplied symbols or decimals.
5125
+ */
5126
+ getAssetMetadataByAddress(chain, address) {
5127
+ const config = this.getConfig(chain);
5128
+ if (!config?.assets) return;
5129
+ const normalizedAddress = address.toLowerCase();
5130
+ for (const [symbol, configuredAddress] of Object.entries(config.assets)) {
5131
+ if (configuredAddress.toLowerCase() !== normalizedAddress) continue;
5132
+ return {
5133
+ symbol,
5134
+ address: configuredAddress,
5135
+ decimals: config.tokenDecimals?.[symbol]
5136
+ };
5137
+ }
5138
+ }
5121
5139
  getUsdtAsset(chain) {
5122
5140
  return this.getConfig(chain)?.assets?.USDT ?? "0x";
5123
5141
  }
@@ -7791,7 +7809,7 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
7791
7809
  */
7792
7810
  async sendExtrinsicWithRetries(extrinsic, maxRetries, timeoutMs) {
7793
7811
  const keyPair = this.getKeyPair();
7794
- let baseTip = 500000000000n;
7812
+ const baseTip = 1000000000n;
7795
7813
  let attempt = 0;
7796
7814
  while (attempt < maxRetries) {
7797
7815
  const currentTip = baseTip * BigInt(2 ** attempt);
@@ -11461,6 +11479,33 @@ query OrderStatus($commitment: String!) {
11461
11479
  }
11462
11480
  }
11463
11481
  }`;
11482
+ var LATEST_PHANTOM_ORDER_PRICE_SNAPSHOT = `
11483
+ query LatestPhantomOrderPriceSnapshot($tokenA: String!, $tokenB: String!) {
11484
+ phantomOrderPriceSnapshots(
11485
+ filter: {
11486
+ and: [
11487
+ { tokenA: { equalTo: $tokenA } }
11488
+ { tokenB: { equalTo: $tokenB } }
11489
+ { medianPrice: { isNull: false } }
11490
+ ]
11491
+ }
11492
+ orderBy: BLOCK_NUMBER_DESC
11493
+ first: 1
11494
+ ) {
11495
+ nodes {
11496
+ commitment
11497
+ tokenA
11498
+ tokenB
11499
+ standardAmount
11500
+ blockNumber
11501
+ medianPrice
11502
+ lowestPrice
11503
+ highestPrice
11504
+ bidCount
11505
+ snapshotTime
11506
+ }
11507
+ }
11508
+ }`;
11464
11509
  var TOKEN_GATEWAY_ASSET_TELEPORTED_STATUS = `
11465
11510
  query TokenGatewayAssetTeleportedStatus($commitment: String!) {
11466
11511
  tokenGatewayAssetTeleportedV2s(
@@ -11522,6 +11567,29 @@ async function queryAssetTeleported(params) {
11522
11567
  function queryGetRequest(params) {
11523
11568
  return _queryGetRequestInternal(params);
11524
11569
  }
11570
+ async function _queryLatestPhantomOrderPriceSnapshot(params) {
11571
+ const response = await params.queryClient.request(
11572
+ LATEST_PHANTOM_ORDER_PRICE_SNAPSHOT,
11573
+ {
11574
+ tokenA: params.tokenA.toLowerCase(),
11575
+ tokenB: params.tokenB.toLowerCase()
11576
+ }
11577
+ );
11578
+ const snapshot = response.phantomOrderPriceSnapshots.nodes[0];
11579
+ if (!snapshot?.medianPrice) return;
11580
+ return {
11581
+ commitment: snapshot.commitment,
11582
+ tokenA: snapshot.tokenA,
11583
+ tokenB: snapshot.tokenB,
11584
+ standardAmount: BigInt(snapshot.standardAmount),
11585
+ blockNumber: BigInt(snapshot.blockNumber),
11586
+ medianPrice: BigInt(snapshot.medianPrice),
11587
+ lowestPrice: snapshot.lowestPrice === null ? void 0 : BigInt(snapshot.lowestPrice),
11588
+ highestPrice: snapshot.highestPrice === null ? void 0 : BigInt(snapshot.highestPrice),
11589
+ bidCount: snapshot.bidCount,
11590
+ snapshotTime: new Date(snapshot.snapshotTime)
11591
+ };
11592
+ }
11525
11593
  async function _queryTokenGatewayAssetTeleportedInternal(params) {
11526
11594
  const { commitmentHash, queryClient: client, logger = DEFAULT_LOGGER } = params;
11527
11595
  const response = await retryPromise(
@@ -17321,15 +17389,67 @@ var UnsupportedIntentQuoteStrategyError = class extends Error {
17321
17389
  var UnsupportedIntentQuotePairError = class extends Error {
17322
17390
  constructor(params) {
17323
17391
  super(
17324
- `No Uniswap v4 pool config found for ${params.tokenIn.symbol ?? params.tokenIn.address} -> ${params.tokenOut.symbol ?? params.tokenOut.address} on ${params.source} -> ${params.destination}`
17392
+ `No ${params.quoteSource ?? "Uniswap v4 pool config"} found for ${params.tokenIn} -> ${params.tokenOut} on ${params.source} -> ${params.destination}`
17325
17393
  );
17326
17394
  this.name = "UnsupportedIntentQuotePairError";
17327
17395
  }
17328
17396
  };
17397
+ var PhantomSnapshotUnavailableError = class extends Error {
17398
+ constructor(tokenA, tokenB) {
17399
+ super(`No Phantom order price snapshot found for ${tokenA} -> ${tokenB}`);
17400
+ this.name = "PhantomSnapshotUnavailableError";
17401
+ }
17402
+ };
17403
+ var InvalidPhantomSnapshotError = class extends Error {
17404
+ constructor(commitment, reason) {
17405
+ super(`Invalid Phantom order price snapshot ${commitment}: ${reason}`);
17406
+ this.name = "InvalidPhantomSnapshotError";
17407
+ }
17408
+ };
17409
+ var BPS_DENOMINATOR = 10000n;
17410
+ function validateQuoteParams(params) {
17411
+ const hasAmountIn = params.amountIn !== void 0;
17412
+ const hasAmountOut = params.amountOut !== void 0;
17413
+ if (hasAmountIn === hasAmountOut) throw new Error("Provide exactly one of amountIn or amountOut");
17414
+ if (params.amountIn !== void 0 && params.amountIn <= 0n) throw new Error("amountIn must be greater than zero");
17415
+ if (params.amountOut !== void 0 && params.amountOut <= 0n) throw new Error("amountOut must be greater than zero");
17416
+ if (params.tokenIn.toLowerCase() === params.tokenOut.toLowerCase()) {
17417
+ throw new Error("tokenIn and tokenOut cannot be the same");
17418
+ }
17419
+ }
17420
+ async function readProtocolFeeBps(chainConfigService, source) {
17421
+ const gatewayAddress = chainConfigService.getIntentGatewayAddress(source.stateMachineId);
17422
+ if (!gatewayAddress || gatewayAddress === "0x" || gatewayAddress === viem.zeroAddress) {
17423
+ throw new Error(`IntentGatewayV2 is not configured for chain ${source.stateMachineId}`);
17424
+ }
17425
+ const gatewayParams = await source.client.readContract({
17426
+ address: gatewayAddress,
17427
+ abi: IntentGatewayV2_default.ABI,
17428
+ functionName: "params"
17429
+ });
17430
+ const protocolFeeBps = Array.isArray(gatewayParams) ? BigInt(gatewayParams[4]) : BigInt(gatewayParams.protocolFeeBps ?? 0);
17431
+ if (protocolFeeBps < 0n || protocolFeeBps >= BPS_DENOMINATOR) {
17432
+ throw new Error(`Invalid IntentGateway protocol fee: ${protocolFeeBps} bps`);
17433
+ }
17434
+ return protocolFeeBps;
17435
+ }
17436
+ function deductProtocolFee(amount, protocolFeeBps) {
17437
+ if (protocolFeeBps <= 0n) return amount;
17438
+ const fee = amount * protocolFeeBps / BPS_DENOMINATOR;
17439
+ return amount - fee;
17440
+ }
17441
+ function grossUpForProtocolFee(netAmount, protocolFeeBps) {
17442
+ if (protocolFeeBps <= 0n) return netAmount;
17443
+ if (protocolFeeBps >= BPS_DENOMINATOR) throw new Error("protocolFeeBps must be less than 10,000");
17444
+ return divCeil(netAmount * BPS_DENOMINATOR, BPS_DENOMINATOR - protocolFeeBps);
17445
+ }
17446
+ function divCeil(numerator, denominator) {
17447
+ if (denominator <= 0n) throw new Error("denominator must be greater than zero");
17448
+ return (numerator + denominator - 1n) / denominator;
17449
+ }
17329
17450
 
17330
17451
  // src/protocols/intents/quote/uniswapV4.ts
17331
17452
  var UNISWAP_INTENT_QUOTE_CHAIN = "EVM-8453" /* BASE_MAINNET */;
17332
- var BPS_DENOMINATOR = 10000n;
17333
17453
  var UniswapV4IntentQuoteStrategy = class {
17334
17454
  constructor(chainConfigService) {
17335
17455
  this.chainConfigService = chainConfigService;
@@ -17337,10 +17457,10 @@ var UniswapV4IntentQuoteStrategy = class {
17337
17457
  chainConfigService;
17338
17458
  baseQuoteClient;
17339
17459
  async quote(params, source, destination) {
17340
- this.validateQuoteParams(params);
17341
- const protocolFeeBps = await this.readProtocolFeeBps(source.client, source.stateMachineId);
17460
+ validateQuoteParams(params);
17461
+ const protocolFeeBps = await readProtocolFeeBps(this.chainConfigService, source);
17342
17462
  const quoteClient = this.resolveQuoteClient(source, destination);
17343
- const poolConfig = this.resolvePoolConfig(params, source.stateMachineId, UNISWAP_INTENT_QUOTE_CHAIN);
17463
+ const poolConfig = this.resolvePoolConfig(params, source.stateMachineId, destination.stateMachineId);
17344
17464
  return params.amountIn !== void 0 ? this.quoteExactInput({ params, client: quoteClient, protocolFeeBps, poolConfig }) : this.quoteExactOutput({ params, client: quoteClient, protocolFeeBps, poolConfig });
17345
17465
  }
17346
17466
  resolveQuoteClient(source, destination) {
@@ -17356,34 +17476,11 @@ var UniswapV4IntentQuoteStrategy = class {
17356
17476
  this.baseQuoteClient = baseQuoteClient;
17357
17477
  return baseQuoteClient;
17358
17478
  }
17359
- validateQuoteParams(params) {
17360
- const hasAmountIn = params.amountIn !== void 0;
17361
- const hasAmountOut = params.amountOut !== void 0;
17362
- if (hasAmountIn === hasAmountOut) throw new Error("Provide exactly one of amountIn or amountOut");
17363
- if (hasAmountIn && params.amountIn <= 0n) throw new Error("amountIn must be greater than zero");
17364
- if (hasAmountOut && params.amountOut <= 0n) throw new Error("amountOut must be greater than zero");
17365
- if (params.tokenIn.address.toLowerCase() === params.tokenOut.address.toLowerCase()) {
17366
- throw new Error("tokenIn and tokenOut cannot be the same");
17367
- }
17368
- }
17369
- async readProtocolFeeBps(client, chain) {
17370
- const gatewayAddress = this.chainConfigService.getIntentGatewayAddress(chain);
17371
- if (!gatewayAddress || gatewayAddress === "0x" || gatewayAddress === viem.zeroAddress) {
17372
- throw new Error(`IntentGatewayV2 is not configured for chain ${chain}`);
17373
- }
17374
- const gatewayParams = await client.readContract({
17375
- address: gatewayAddress,
17376
- abi: IntentGatewayV2_default.ABI,
17377
- functionName: "params"
17378
- });
17379
- if (isGatewayParamsTuple(gatewayParams)) return BigInt(gatewayParams[4]);
17380
- return BigInt(gatewayParams.protocolFeeBps ?? 0);
17381
- }
17382
17479
  resolvePoolConfig(params, source, destination) {
17383
17480
  const override = params.uniswapV4?.poolKey;
17384
17481
  if (override) {
17385
17482
  const poolKey = normalizePoolKey(override);
17386
- const tokenInForQuote = viem.getAddress(override.currencyIn ?? params.tokenIn.address);
17483
+ const tokenInForQuote = viem.getAddress(override.currencyIn ?? params.tokenIn);
17387
17484
  if (tokenInForQuote !== poolKey.currency0 && tokenInForQuote !== poolKey.currency1) {
17388
17485
  throw new Error(
17389
17486
  `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.`
@@ -17391,11 +17488,11 @@ var UniswapV4IntentQuoteStrategy = class {
17391
17488
  }
17392
17489
  return {
17393
17490
  poolKey,
17394
- quoterAddress: this.resolveQuoterAddress(destination, override.quoterAddress),
17491
+ quoterAddress: this.resolveQuoterAddress(UNISWAP_INTENT_QUOTE_CHAIN, override.quoterAddress),
17395
17492
  tokenInForQuote
17396
17493
  };
17397
17494
  }
17398
- const poolConfig = this.resolveConfiguredPool(params, destination);
17495
+ const poolConfig = this.resolveConfiguredPool(params, source, destination, UNISWAP_INTENT_QUOTE_CHAIN);
17399
17496
  if (poolConfig) return poolConfig;
17400
17497
  throw new UnsupportedIntentQuotePairError({
17401
17498
  source,
@@ -17404,12 +17501,12 @@ var UniswapV4IntentQuoteStrategy = class {
17404
17501
  tokenOut: params.tokenOut
17405
17502
  });
17406
17503
  }
17407
- resolveConfiguredPool(params, chain) {
17408
- for (const pool of this.chainConfigService.getUniswapV4PoolConfigs(chain)) {
17409
- const resolvedPool = this.resolveConfiguredPoolTokens(chain, pool);
17504
+ resolveConfiguredPool(params, sourceChain, destinationChain, quoteChain) {
17505
+ for (const pool of this.chainConfigService.getUniswapV4PoolConfigs(quoteChain)) {
17506
+ const resolvedPool = this.resolveConfiguredPoolTokens(quoteChain, pool);
17410
17507
  if (!resolvedPool) continue;
17411
- const tokenInForQuote = matchPoolToken(params.tokenIn, resolvedPool);
17412
- const tokenOutForQuote = matchPoolToken(params.tokenOut, resolvedPool);
17508
+ const tokenInForQuote = this.matchPoolToken(params.tokenIn, sourceChain, resolvedPool);
17509
+ const tokenOutForQuote = this.matchPoolToken(params.tokenOut, destinationChain, resolvedPool);
17413
17510
  if (!tokenInForQuote || !tokenOutForQuote || tokenInForQuote.symbol === tokenOutForQuote.symbol) continue;
17414
17511
  const { currency0, currency1 } = sortCurrencies(resolvedPool[0].address, resolvedPool[1].address);
17415
17512
  return {
@@ -17420,7 +17517,7 @@ var UniswapV4IntentQuoteStrategy = class {
17420
17517
  tickSpacing: pool.tickSpacing,
17421
17518
  hooks: viem.getAddress(pool.hooks ?? viem.zeroAddress)
17422
17519
  },
17423
- quoterAddress: this.resolveQuoterAddress(chain),
17520
+ quoterAddress: this.resolveQuoterAddress(quoteChain),
17424
17521
  tokenInForQuote: tokenInForQuote.address
17425
17522
  };
17426
17523
  }
@@ -17443,8 +17540,18 @@ var UniswapV4IntentQuoteStrategy = class {
17443
17540
  if (!address || address === "0x") return null;
17444
17541
  return { symbol, address: viem.getAddress(address) };
17445
17542
  }
17543
+ matchPoolToken(tokenAddress, orderChain, poolTokens) {
17544
+ const addressMatch = poolTokens.find(
17545
+ (poolToken) => poolToken.address.toLowerCase() === tokenAddress.toLowerCase()
17546
+ );
17547
+ if (addressMatch) return addressMatch;
17548
+ const metadata = this.chainConfigService.getAssetMetadataByAddress(orderChain, tokenAddress);
17549
+ if (!metadata) return null;
17550
+ return poolTokens.find((poolToken) => poolToken.symbol === metadata.symbol) ?? null;
17551
+ }
17446
17552
  async quoteExactInput(args) {
17447
17553
  const amountIn = args.params.amountIn;
17554
+ if (amountIn === void 0) throw new Error("amountIn is required for an exact-input quote");
17448
17555
  const swapAmountIn = deductProtocolFee(amountIn, args.protocolFeeBps);
17449
17556
  const amountOut = await this.readV4QuoteExactInput(args.client, args.poolConfig, swapAmountIn);
17450
17557
  return {
@@ -17462,6 +17569,7 @@ var UniswapV4IntentQuoteStrategy = class {
17462
17569
  }
17463
17570
  async quoteExactOutput(args) {
17464
17571
  const amountOut = args.params.amountOut;
17572
+ if (amountOut === void 0) throw new Error("amountOut is required for an exact-output quote");
17465
17573
  const swapAmountIn = await this.readV4QuoteExactOutput(args.client, args.poolConfig, amountOut);
17466
17574
  const amountIn = grossUpForProtocolFee(swapAmountIn, args.protocolFeeBps);
17467
17575
  return {
@@ -17540,34 +17648,125 @@ function sortCurrencies(tokenIn, tokenOut) {
17540
17648
  const output = viem.getAddress(tokenOut);
17541
17649
  return BigInt(input) < BigInt(output) ? { currency0: input, currency1: output } : { currency0: output, currency1: input };
17542
17650
  }
17543
- function matchPoolToken(token, poolTokens) {
17544
- const tokenAddress = token.address.toLowerCase();
17545
- const addressMatch = poolTokens.find((poolToken) => poolToken.address.toLowerCase() === tokenAddress);
17546
- if (addressMatch) return addressMatch;
17547
- const tokenSymbol = token.symbol?.toUpperCase();
17548
- if (!tokenSymbol) return null;
17549
- return poolTokens.find((poolToken) => poolToken.symbol.toUpperCase() === tokenSymbol) ?? null;
17550
- }
17551
17651
  function getZeroForOne(tokenIn, poolKey) {
17552
17652
  return viem.getAddress(tokenIn).toLowerCase() === viem.getAddress(poolKey.currency0).toLowerCase();
17553
17653
  }
17554
- function isGatewayParamsTuple(value) {
17555
- return Array.isArray(value);
17556
- }
17557
- function deductProtocolFee(amount, protocolFeeBps) {
17558
- if (protocolFeeBps <= 0n) return amount;
17559
- const fee = amount * protocolFeeBps / BPS_DENOMINATOR;
17560
- return amount - fee;
17561
- }
17562
- function grossUpForProtocolFee(netAmount, protocolFeeBps) {
17563
- if (protocolFeeBps <= 0n) return netAmount;
17564
- return divCeil(netAmount * BPS_DENOMINATOR, BPS_DENOMINATOR - protocolFeeBps);
17654
+
17655
+ // src/protocols/intents/quote/phantomSnapshot.ts
17656
+ var PHANTOM_INTENT_QUOTE_CHAIN = "EVM-8453" /* BASE_MAINNET */;
17657
+ var BASE_SNAPSHOT_ASSET_BY_ORDER_ASSET = {
17658
+ USDC: "USDC",
17659
+ USDT: "USDC",
17660
+ cNGN: "cNGN"
17661
+ };
17662
+ var SUPPORTED_BASE_SNAPSHOT_PAIRS = /* @__PURE__ */ new Set(["USDC:cNGN", "cNGN:USDC"]);
17663
+ var PhantomSnapshotIntentQuoteStrategy = class {
17664
+ constructor(chainConfigService, getQueryClient) {
17665
+ this.chainConfigService = chainConfigService;
17666
+ this.getQueryClient = getQueryClient;
17667
+ }
17668
+ chainConfigService;
17669
+ getQueryClient;
17670
+ async quote(params, source, destination) {
17671
+ validateQuoteParams(params);
17672
+ const pair = this.resolveBaseSnapshotPair(params, source.stateMachineId, destination.stateMachineId);
17673
+ if (!pair) {
17674
+ throw new UnsupportedIntentQuotePairError({
17675
+ source: source.stateMachineId,
17676
+ destination: destination.stateMachineId,
17677
+ tokenIn: params.tokenIn,
17678
+ tokenOut: params.tokenOut,
17679
+ quoteSource: "Phantom snapshot pair"
17680
+ });
17681
+ }
17682
+ const queryClient = this.getQueryClient();
17683
+ const [protocolFeeBps, snapshot] = await Promise.all([
17684
+ readProtocolFeeBps(this.chainConfigService, source),
17685
+ _queryLatestPhantomOrderPriceSnapshot({
17686
+ tokenA: pair.tokenA,
17687
+ tokenB: pair.tokenB,
17688
+ queryClient
17689
+ })
17690
+ ]);
17691
+ if (!snapshot) throw new PhantomSnapshotUnavailableError(pair.tokenA, pair.tokenB);
17692
+ this.validateSnapshot(snapshot);
17693
+ return this.quoteSnapshot(params, protocolFeeBps, snapshot);
17694
+ }
17695
+ quoteSnapshot(params, protocolFeeBps, snapshot) {
17696
+ if (params.amountIn !== void 0) {
17697
+ const netAmountIn2 = deductProtocolFee(params.amountIn, protocolFeeBps);
17698
+ const amountOut = netAmountIn2 * snapshot.medianPrice / snapshot.standardAmount;
17699
+ if (amountOut <= 0n) {
17700
+ throw new InvalidPhantomSnapshotError(snapshot.commitment, "quote rounds down to zero output");
17701
+ }
17702
+ return this.buildResult("EXACT_INPUT", params.amountIn, amountOut, protocolFeeBps, snapshot);
17703
+ }
17704
+ if (params.amountOut === void 0) throw new Error("Quote amount is missing after validation");
17705
+ const netAmountIn = divCeil(params.amountOut * snapshot.standardAmount, snapshot.medianPrice);
17706
+ const amountIn = grossUpForProtocolFee(netAmountIn, protocolFeeBps);
17707
+ return this.buildResult("EXACT_OUTPUT", amountIn, params.amountOut, protocolFeeBps, snapshot);
17708
+ }
17709
+ buildResult(tradeType, amountIn, amountOut, protocolFeeBps, snapshot) {
17710
+ return {
17711
+ strategy: "phantom_snapshot",
17712
+ tradeType,
17713
+ amountIn,
17714
+ amountOut,
17715
+ quoteMetadata: {
17716
+ quoteChain: PHANTOM_INTENT_QUOTE_CHAIN,
17717
+ commitment: snapshot.commitment,
17718
+ tokenA: snapshot.tokenA,
17719
+ tokenB: snapshot.tokenB,
17720
+ standardAmount: snapshot.standardAmount,
17721
+ medianPrice: snapshot.medianPrice,
17722
+ lowestPrice: snapshot.lowestPrice,
17723
+ highestPrice: snapshot.highestPrice,
17724
+ blockNumber: snapshot.blockNumber,
17725
+ snapshotTime: snapshot.snapshotTime,
17726
+ bidCount: snapshot.bidCount,
17727
+ protocolFeeBps
17728
+ }
17729
+ };
17730
+ }
17731
+ validateSnapshot(snapshot) {
17732
+ if (snapshot.standardAmount <= 0n) {
17733
+ throw new InvalidPhantomSnapshotError(snapshot.commitment, "standardAmount must be greater than zero");
17734
+ }
17735
+ if (snapshot.medianPrice <= 0n) {
17736
+ throw new InvalidPhantomSnapshotError(snapshot.commitment, "medianPrice must be greater than zero");
17737
+ }
17738
+ if (snapshot.bidCount <= 0) {
17739
+ throw new InvalidPhantomSnapshotError(snapshot.commitment, "bidCount must be greater than zero");
17740
+ }
17741
+ if (Number.isNaN(snapshot.snapshotTime.getTime())) {
17742
+ throw new InvalidPhantomSnapshotError(snapshot.commitment, "snapshotTime is invalid");
17743
+ }
17744
+ }
17745
+ resolveBaseSnapshotPair(params, sourceStateMachineId, destinationStateMachineId) {
17746
+ const tokenIn = this.resolveBaseSnapshotToken(sourceStateMachineId, params.tokenIn);
17747
+ const tokenOut = this.resolveBaseSnapshotToken(destinationStateMachineId, params.tokenOut);
17748
+ if (!tokenIn || !tokenOut || !isSupportedSnapshotPair(tokenIn.symbol, tokenOut.symbol)) return;
17749
+ return { tokenA: tokenIn.address, tokenB: tokenOut.address };
17750
+ }
17751
+ resolveBaseSnapshotToken(chain, tokenAddress) {
17752
+ const orderAsset = this.chainConfigService.getAssetMetadataByAddress(chain, tokenAddress)?.symbol;
17753
+ if (!orderAsset) return;
17754
+ const snapshotAsset = BASE_SNAPSHOT_ASSET_BY_ORDER_ASSET[orderAsset];
17755
+ if (!snapshotAsset) return;
17756
+ const address = this.chainConfigService.getAssetAddress(PHANTOM_INTENT_QUOTE_CHAIN, snapshotAsset);
17757
+ if (!isConfiguredAddress(address)) return;
17758
+ return { symbol: snapshotAsset, address };
17759
+ }
17760
+ };
17761
+ function isSupportedSnapshotPair(tokenA, tokenB) {
17762
+ return SUPPORTED_BASE_SNAPSHOT_PAIRS.has(`${tokenA}:${tokenB}`);
17565
17763
  }
17566
- function divCeil(numerator, denominator) {
17567
- return (numerator + denominator - 1n) / denominator;
17764
+ function isConfiguredAddress(address) {
17765
+ return Boolean(address && address !== "0x" && !/^0x0{40}$/i.test(address));
17568
17766
  }
17569
17767
 
17570
17768
  // src/protocols/intents/IntentGateway.ts
17769
+ var CROSS_CHAIN_ORDER_FEE_GAS_BUMP = 600000n;
17571
17770
  var IntentGateway = class _IntentGateway {
17572
17771
  /** EVM chain on which orders are placed and escrowed. */
17573
17772
  source;
@@ -17639,6 +17838,10 @@ var IntentGateway = class _IntentGateway {
17639
17838
  this.gasEstimator = gasEstimator;
17640
17839
  this._crypto = crypto;
17641
17840
  this.quoteStrategies = {
17841
+ phantom_snapshot: new PhantomSnapshotIntentQuoteStrategy(
17842
+ dest.configService,
17843
+ () => this.requireIndexer().queryClient
17844
+ ),
17642
17845
  uniswap_v4: new UniswapV4IntentQuoteStrategy(dest.configService)
17643
17846
  };
17644
17847
  }
@@ -17688,37 +17891,39 @@ var IntentGateway = class _IntentGateway {
17688
17891
  /**
17689
17892
  * Quotes an intent between this gateway's source and destination chains.
17690
17893
  *
17691
- * `strategy` defaults to `uniswap_v4`, currently the only supported
17692
- * strategy. Provide exactly one of `amountIn` or `amountOut`.
17894
+ * Uses the latest directional Phantom order price snapshot from the attached
17895
+ * indexer by default. Pass `strategy: "uniswap_v4"` only when explicitly
17896
+ * requesting a Uniswap quote. Provide exactly one of `amountIn` or `amountOut`.
17693
17897
  *
17694
- * The Uniswap quote strategy always prices against the configured Base
17695
- * pool, regardless of this gateway's destination chain. Returned
17898
+ * Both built-in strategies resolve their canonical market on Base,
17899
+ * regardless of this gateway's destination chain. Returned
17696
17900
  * `amountIn`/`amountOut` already account for the gateway's protocol fee
17697
17901
  * (`quoteMetadata.protocolFeeBps`), which the gateway deducts from order
17698
- * inputs; apply only your own slippage tolerance before placing the order.
17902
+ * inputs; use the returned amounts directly when placing the order.
17699
17903
  *
17700
17904
  * @param params - Token pair, amount, and optional strategy/pool overrides.
17701
17905
  * @returns The quoted amounts plus strategy-specific metadata.
17702
17906
  * @throws {UnsupportedIntentQuoteStrategyError} For unknown strategies.
17703
- * @throws {UnsupportedIntentQuotePairError} When no pool is configured for the pair.
17907
+ * @throws {UnsupportedIntentQuotePairError} When the selected strategy does not support the pair.
17908
+ * @throws {PhantomSnapshotUnavailableError} When an eligible cNGN pair has no snapshot.
17704
17909
  */
17705
17910
  async quoteIntent(params) {
17706
- const strategy = params.strategy ?? "uniswap_v4";
17911
+ const source = { stateMachineId: this.source.config.stateMachineId, client: this.source.client };
17912
+ const destination = { stateMachineId: this.dest.config.stateMachineId, client: this.dest.client };
17913
+ const strategy = params.strategy ?? "phantom_snapshot";
17707
17914
  const handler = this.quoteStrategies[strategy];
17708
17915
  if (!handler) throw new UnsupportedIntentQuoteStrategyError(strategy);
17709
- return handler.quote(
17710
- { ...params, strategy },
17711
- { stateMachineId: this.source.config.stateMachineId, client: this.source.client },
17712
- { stateMachineId: this.dest.config.stateMachineId, client: this.dest.client }
17713
- );
17916
+ return handler.quote({ ...params, strategy }, source, destination);
17714
17917
  }
17715
17918
  /**
17716
17919
  * Bidirectional async generator that orchestrates the full order lifecycle:
17717
17920
  * placement, fee estimation, bid collection, and execution.
17718
17921
  *
17719
17922
  * **Yield/receive protocol:**
17720
- * 1. If `order.fees` is unset or zero, estimates gas and sets `order.fees`
17721
- * with a 1% buffer and the wei cost with a 2% buffer for the `value` field.
17923
+ * 1. If `order.fees` is unset or zero, estimates gas and sets same-chain
17924
+ * `order.fees` to twice the estimate. Cross-chain orders retain a 1% buffer
17925
+ * and include an additional 600k-gas fee uplift, while the wei cost used for
17926
+ * the `value` field receives a 2% buffer.
17722
17927
  * 2. Yields `AWAITING_PLACE_ORDER` with `{ to, data, value, sessionPrivateKey }`.
17723
17928
  * The caller must sign the transaction and pass it back via `gen.next(signedTx)`.
17724
17929
  * 3. Yields `ORDER_PLACED` with the finalised order and transaction hash once
@@ -17750,8 +17955,15 @@ var IntentGateway = class _IntentGateway {
17750
17955
  if (estimate.totalGasCostWei === 0n || estimate.totalGasInFeeToken === 0n) {
17751
17956
  throw new Error("Gas estimation failed");
17752
17957
  }
17958
+ const isSameChain = this.source.config.stateMachineId === this.dest.config.stateMachineId;
17753
17959
  value = estimate.totalGasCostWei + estimate.totalGasCostWei * 2n / 100n;
17754
- order.fees = estimate.totalGasInFeeToken + estimate.totalGasInFeeToken * 1n / 100n;
17960
+ const crossChainFeeBump = isSameChain ? 0n : await convertGasToFeeToken(
17961
+ this.ctx,
17962
+ CROSS_CHAIN_ORDER_FEE_GAS_BUMP,
17963
+ "source",
17964
+ this.source.config.stateMachineId
17965
+ );
17966
+ order.fees = isSameChain ? estimate.totalGasInFeeToken * 2n : estimate.totalGasInFeeToken + (crossChainFeeBump + estimate.totalGasInFeeToken * 1n / 100n);
17755
17967
  }
17756
17968
  const placeOrderGen = this.orderPlacer.placeOrder(order, graffiti);
17757
17969
  const placeOrderFirst = await placeOrderGen.next();
@@ -18132,7 +18344,9 @@ var IntentGateway = class _IntentGateway {
18132
18344
  }
18133
18345
  requireIndexer() {
18134
18346
  if (!this.indexer) {
18135
- throw new Error("IntentGateway: call withQueryClient(queryClient) before using indexer-backed methods");
18347
+ throw new Error(
18348
+ "IntentGateway: call withQueryClient(queryClient) before using indexer-backed methods or Phantom quotes"
18349
+ );
18136
18350
  }
18137
18351
  return this.indexer;
18138
18352
  }
@@ -22667,6 +22881,7 @@ exports.IntentGateway = IntentGateway;
22667
22881
  exports.IntentGatewayABI = ABI3;
22668
22882
  exports.IntentOrderStatus = IntentOrderStatus;
22669
22883
  exports.IntentsCoprocessor = IntentsCoprocessor;
22884
+ exports.InvalidPhantomSnapshotError = InvalidPhantomSnapshotError;
22670
22885
  exports.IsmpClient = IsmpClient;
22671
22886
  exports.MOCK_ADDRESS = MOCK_ADDRESS;
22672
22887
  exports.ORDER_V2_PARAM_TYPE = ORDER_V2_PARAM_TYPE;
@@ -22674,6 +22889,7 @@ exports.OrderStatus = OrderStatus;
22674
22889
  exports.OrderStatusChecker = OrderStatusChecker;
22675
22890
  exports.PACKED_USEROP_TYPEHASH = PACKED_USEROP_TYPEHASH;
22676
22891
  exports.PLACE_ORDER_SELECTOR = PLACE_ORDER_SELECTOR;
22892
+ exports.PhantomSnapshotUnavailableError = PhantomSnapshotUnavailableError;
22677
22893
  exports.PharosChain = PharosChain;
22678
22894
  exports.PolkadotHubChain = PolkadotHubChain;
22679
22895
  exports.REQUEST_COMMITMENTS_SLOT = REQUEST_COMMITMENTS_SLOT;