@hyperbridge/sdk 2.6.1 → 2.8.0

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,6 +1,6 @@
1
1
  import { keccak256, toHex, encodeAbiParameters, encodeFunctionData, decodeFunctionData, decodeAbiParameters, numberToBytes, bytesToBigInt, recoverAddress, parseAbiParameters, concat, encodePacked, pad } from 'viem';
2
2
  import '@polkadot/api';
3
- import { hexToU8a, u8aToHex } from '@polkadot/util';
3
+ import { hexToU8a, u8aToHex, stringToU8a, isHex, u8aToString } from '@polkadot/util';
4
4
  import '@polkadot/util-crypto';
5
5
  import { Struct, Vector, u8, Bytes } from 'scale-ts';
6
6
  import 'p-queue';
@@ -1608,6 +1608,24 @@ var ABI2 = [
1608
1608
  internalType: "uint256"
1609
1609
  }
1610
1610
  ]
1611
+ },
1612
+ {
1613
+ name: "predispatchCall",
1614
+ type: "bytes",
1615
+ indexed: false,
1616
+ internalType: "bytes"
1617
+ },
1618
+ {
1619
+ name: "outputCall",
1620
+ type: "bytes",
1621
+ indexed: false,
1622
+ internalType: "bytes"
1623
+ },
1624
+ {
1625
+ name: "graffiti",
1626
+ type: "bytes32",
1627
+ indexed: false,
1628
+ internalType: "bytes32"
1611
1629
  }
1612
1630
  ],
1613
1631
  anonymous: false
@@ -2338,6 +2356,49 @@ async function rpcCall(url, payload) {
2338
2356
  throw lastErr;
2339
2357
  }
2340
2358
  var FILL_ORDER_ABI = IntentGatewayV2_default.ABI;
2359
+ var DECLARATION_VERSION = 1;
2360
+ var MAX_DECLARED_CHAINS = 255;
2361
+ function encodeAcceptedSourceChains(chains) {
2362
+ if (chains.length > MAX_DECLARED_CHAINS) {
2363
+ throw new Error(`Cannot declare more than ${MAX_DECLARED_CHAINS} source chains`);
2364
+ }
2365
+ const bytes = [DECLARATION_VERSION, chains.length];
2366
+ for (const chain of chains) {
2367
+ const encoded = stringToU8a(chain);
2368
+ if (encoded.length === 0 || encoded.length > 255) {
2369
+ throw new Error(`Invalid state machine id in source chain declaration: ${chain}`);
2370
+ }
2371
+ bytes.push(encoded.length, ...encoded);
2372
+ }
2373
+ return u8aToHex(new Uint8Array(bytes));
2374
+ }
2375
+ function decodeAcceptedSourceChains(paymasterAndData) {
2376
+ if (!paymasterAndData || !isHex(paymasterAndData)) return null;
2377
+ const bytes = hexToU8a(paymasterAndData);
2378
+ if (bytes.length < 2 || bytes[0] !== DECLARATION_VERSION) return null;
2379
+ const count = bytes[1];
2380
+ const chains = [];
2381
+ let offset = 2;
2382
+ for (let entry = 0; entry < count; entry++) {
2383
+ if (offset >= bytes.length) return null;
2384
+ const length = bytes[offset];
2385
+ offset += 1;
2386
+ if (length === 0 || offset + length > bytes.length) return null;
2387
+ chains.push(u8aToString(bytes.subarray(offset, offset + length)));
2388
+ offset += length;
2389
+ }
2390
+ if (offset !== bytes.length) return null;
2391
+ return chains;
2392
+ }
2393
+ function zipFillLegs(assets, outputs) {
2394
+ return assets.map((asset, index) => {
2395
+ const rawAmount = outputs[index]?.amount;
2396
+ return {
2397
+ outputToken: asset.token,
2398
+ solverAmount: rawAmount === void 0 || rawAmount === null ? 0n : BigInt(rawAmount.toString())
2399
+ };
2400
+ });
2401
+ }
2341
2402
  function weightedMedian(entries) {
2342
2403
  const sorted = [...entries].sort((a, b) => a.price < b.price ? -1 : a.price > b.price ? 1 : 0);
2343
2404
  const totalWeight = sorted.reduce((acc, e) => e.weight > 0n ? acc + e.weight : acc, 0n);
@@ -2363,10 +2424,10 @@ function extractFillData(callData, gatewayAddress) {
2363
2424
  if (decoded.functionName !== "fillOrder" || !decoded.args || decoded.args.length < 2) continue;
2364
2425
  const order = decoded.args[0];
2365
2426
  const options = decoded.args[1];
2366
- const outputToken = order?.output?.assets?.[0]?.token;
2427
+ const assets = order?.output?.assets;
2367
2428
  const outputs = options?.outputs;
2368
- if (!outputToken || !outputs?.length) continue;
2369
- return { order, options, outputToken, solverAmount: outputs[0].amount };
2429
+ if (!assets?.length || !outputs?.length) continue;
2430
+ return { order, options, legs: zipFillLegs(assets, outputs) };
2370
2431
  } catch {
2371
2432
  continue;
2372
2433
  }
@@ -2484,13 +2545,25 @@ async function getTotalSolverBalance(evmRpcUrl, chain, token, solver, yieldVault
2484
2545
  );
2485
2546
  return vaultBalances.reduce((acc, b) => acc + b, raw);
2486
2547
  }
2487
- async function sweepSolverLiquidity(evmRpcUrls, yieldVaults, solver) {
2548
+ function memoizedSolverBalance(yieldVaults) {
2549
+ const cache = /* @__PURE__ */ new Map();
2550
+ return (evmRpcUrl, chain, token, solver) => {
2551
+ const key = `${chain}|${token.toLowerCase()}|${solver.toLowerCase()}`;
2552
+ let pending = cache.get(key);
2553
+ if (!pending) {
2554
+ pending = getTotalSolverBalance(evmRpcUrl, chain, token, solver, yieldVaults);
2555
+ cache.set(key, pending);
2556
+ }
2557
+ return pending;
2558
+ };
2559
+ }
2560
+ async function sweepSolverLiquidity(evmRpcUrls, yieldVaults, solver, getBalance) {
2488
2561
  const balances = [];
2489
2562
  for (const [chain, tokens] of Object.entries(yieldVaults)) {
2490
2563
  const url = evmRpcUrls[chain];
2491
2564
  if (!url) continue;
2492
2565
  for (const token of Object.keys(tokens)) {
2493
- const balance = await getTotalSolverBalance(url, chain, token, solver, yieldVaults);
2566
+ const balance = await getBalance(url, chain, token, solver);
2494
2567
  if (balance === 0n) continue;
2495
2568
  balances.push({ solver, chain, tokenAddress: token, balance });
2496
2569
  }
@@ -2517,7 +2590,8 @@ async function aggregatePhantomBids(params) {
2517
2590
  }
2518
2591
  const bids = await fetchBidsForOrder(nodeUrl, commitment);
2519
2592
  if (bids.length === 0) return null;
2520
- const quotes = [];
2593
+ const getBalance = params.getBalance ?? memoizedSolverBalance(yieldVaults);
2594
+ const quotesByLeg = /* @__PURE__ */ new Map();
2521
2595
  const lpBalances = [];
2522
2596
  const countedSolvers = /* @__PURE__ */ new Set();
2523
2597
  for (const bid of bids) {
@@ -2555,25 +2629,41 @@ async function aggregatePhantomBids(params) {
2555
2629
  continue;
2556
2630
  }
2557
2631
  countedSolvers.add(normalizedSolver);
2558
- const outputTokenAddress = toAddress(fillData.outputToken);
2559
- const weight = await getTotalSolverBalance(destUrl, chain, outputTokenAddress, solver, yieldVaults);
2560
- quotes.push({ price: fillData.solverAmount, weight });
2561
- lpBalances.push(...await sweepSolverLiquidity(evmRpcUrls, yieldVaults, solver));
2632
+ const acceptedSources = decodeAcceptedSourceChains(decoded.paymasterAndData);
2633
+ const quotedLegs = [...fillData.legs.entries()].filter(([, leg]) => leg.solverAmount !== 0n);
2634
+ const weights = await Promise.all(
2635
+ // Price influence: the solver's liquidity in THIS leg's output token on the destination
2636
+ // chain, so a leg is weighted by the inventory that actually backs it.
2637
+ quotedLegs.map(([, leg]) => getBalance(destUrl, chain, toAddress(leg.outputToken), solver))
2638
+ );
2639
+ for (const [position, [legIndex, leg]] of quotedLegs.entries()) {
2640
+ const weight = weights[position];
2641
+ const entry = quotesByLeg.get(legIndex) ?? { outputToken: leg.outputToken, quotes: [], bidders: [] };
2642
+ entry.quotes.push({ price: leg.solverAmount, weight });
2643
+ entry.bidders.push({ solver: normalizedSolver, weight, acceptedSources });
2644
+ quotesByLeg.set(legIndex, entry);
2645
+ }
2646
+ lpBalances.push(...await sweepSolverLiquidity(evmRpcUrls, yieldVaults, solver, getBalance));
2562
2647
  } catch (err) {
2563
2648
  logger?.warn({ err, filler: bid.filler }, "Failed to process bid for price snapshot");
2564
2649
  }
2565
2650
  }
2566
- if (quotes.length === 0) return null;
2567
- const medianPrice = weightedMedian(quotes);
2568
- return {
2569
- lowestPrice: medianPrice,
2570
- highestPrice: medianPrice,
2571
- medianPrice,
2572
- bidCount: quotes.length,
2573
- lpBalances
2574
- };
2651
+ if (quotesByLeg.size === 0) return null;
2652
+ const legs = [...quotesByLeg.entries()].sort(([a], [b]) => a - b).map(([legIndex, { outputToken, quotes, bidders }]) => {
2653
+ const medianPrice = weightedMedian(quotes);
2654
+ return {
2655
+ legIndex,
2656
+ outputToken,
2657
+ lowestPrice: medianPrice,
2658
+ highestPrice: medianPrice,
2659
+ medianPrice,
2660
+ bidCount: quotes.length,
2661
+ bidders
2662
+ };
2663
+ });
2664
+ return { legs, lpBalances };
2575
2665
  }
2576
2666
 
2577
- export { ENTRY_POINT_V08_ADDRESS, FILL_ORDER_ABI, IntentGatewayV2_default as IntentGatewayV2, aggregatePhantomBids, decodeERC7821ExecuteBatch, decodeUserOpScale, encodeERC7821ExecuteBatch, encodeUserOpScale, extractFillData, fetchBidsForOrder, orderCommitmentFromDecoded, recoverBidSignerViem, setAggregationFetch, splitBidSignature, weightedMedian };
2667
+ export { ENTRY_POINT_V08_ADDRESS, FILL_ORDER_ABI, IntentGatewayV2_default as IntentGatewayV2, aggregatePhantomBids, decodeAcceptedSourceChains, decodeERC7821ExecuteBatch, decodeUserOpScale, encodeAcceptedSourceChains, encodeERC7821ExecuteBatch, encodeUserOpScale, extractFillData, fetchBidsForOrder, memoizedSolverBalance, orderCommitmentFromDecoded, recoverBidSignerViem, setAggregationFetch, splitBidSignature, weightedMedian, zipFillLegs };
2578
2668
  //# sourceMappingURL=intents-helpers.js.map
2579
2669
  //# sourceMappingURL=intents-helpers.js.map