@hyperbridge/sdk 2.8.2 → 2.8.4
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.
- package/dist/browser/index.d.ts +365 -51
- package/dist/browser/index.js +732 -291
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +739 -289
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +69 -16
- package/dist/node/index.d.ts +69 -16
- package/dist/node/index.js +732 -291
- package/dist/node/index.js.map +1 -1
- package/dist/node/{intents-helpers-D_km9I2f.d.cts → intents-helpers-CkPAsLHB.d.cts} +332 -40
- package/dist/node/{intents-helpers-D_km9I2f.d.ts → intents-helpers-CkPAsLHB.d.ts} +332 -40
- package/dist/node/intents-helpers.cjs +394 -39
- package/dist/node/intents-helpers.cjs.map +1 -1
- package/dist/node/intents-helpers.d.cts +1 -1
- package/dist/node/intents-helpers.d.ts +1 -1
- package/dist/node/intents-helpers.js +391 -40
- package/dist/node/intents-helpers.js.map +1 -1
- package/package.json +155 -153
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { bE as AggregationLogger, bF as BidNonceKeyFn, bG as BidSignature, bH as ENTRY_POINT_V08_ADDRESS, bI as FILL_ORDER_ABI, bJ as FetchLike, bK as FillData, bL as HexString, bM as IntentGatewayV2, bN as LpBalance, bO as OrderCommitmentFn, bP as PhantomAggregation, bQ as PhantomLegAggregation, bR as PhantomLegBidder, bS as RecoverBidSigner, bT as RpcBidInfo, bU as SolverBalanceReader, bV as YieldVaultMap, bW as aggregatePhantomBids, bi as decodeAcceptedSourceChains, bj as decodeERC7821ExecuteBatch, bk as decodePhantomBidDeclaration, bl as decodeUserOpScale, bn as encodeAcceptedSourceChains, bo as encodeERC7821ExecuteBatch, bq as encodePhantomBidDeclaration, br as encodeUserOpScale, bX as extractFillData, bY as fetchBidsForOrder, bZ as memoizedSolverBalance, b_ as orderCommitmentFromDecoded, bA as poolSlug, b$ as recoverBidSignerViem, c0 as setAggregationFetch, bB as sortPoolSymbols, c1 as splitBidSignature, c2 as weightedMedian, c3 as zipFillLegs } from './intents-helpers-CkPAsLHB.cjs';
|
|
2
2
|
import 'consola';
|
|
3
3
|
import 'decimal.js';
|
|
4
4
|
import 'graphql-request';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { bE as AggregationLogger, bF as BidNonceKeyFn, bG as BidSignature, bH as ENTRY_POINT_V08_ADDRESS, bI as FILL_ORDER_ABI, bJ as FetchLike, bK as FillData, bL as HexString, bM as IntentGatewayV2, bN as LpBalance, bO as OrderCommitmentFn, bP as PhantomAggregation, bQ as PhantomLegAggregation, bR as PhantomLegBidder, bS as RecoverBidSigner, bT as RpcBidInfo, bU as SolverBalanceReader, bV as YieldVaultMap, bW as aggregatePhantomBids, bi as decodeAcceptedSourceChains, bj as decodeERC7821ExecuteBatch, bk as decodePhantomBidDeclaration, bl as decodeUserOpScale, bn as encodeAcceptedSourceChains, bo as encodeERC7821ExecuteBatch, bq as encodePhantomBidDeclaration, br as encodeUserOpScale, bX as extractFillData, bY as fetchBidsForOrder, bZ as memoizedSolverBalance, b_ as orderCommitmentFromDecoded, bA as poolSlug, b$ as recoverBidSignerViem, c0 as setAggregationFetch, bB as sortPoolSymbols, c1 as splitBidSignature, c2 as weightedMedian, c3 as zipFillLegs } from './intents-helpers-CkPAsLHB.js';
|
|
2
2
|
import 'consola';
|
|
3
3
|
import 'decimal.js';
|
|
4
4
|
import 'graphql-request';
|
|
@@ -1937,6 +1937,14 @@ function decodeUserOpScale(hex) {
|
|
|
1937
1937
|
signature: u8aToHex(new Uint8Array(decoded.signature))
|
|
1938
1938
|
};
|
|
1939
1939
|
}
|
|
1940
|
+
|
|
1941
|
+
// src/protocols/intents/liquidity-pool.ts
|
|
1942
|
+
function sortPoolSymbols(symbolA, symbolB) {
|
|
1943
|
+
return symbolA.toLowerCase() <= symbolB.toLowerCase() ? [symbolA, symbolB] : [symbolB, symbolA];
|
|
1944
|
+
}
|
|
1945
|
+
function poolSlug(symbolA, symbolB) {
|
|
1946
|
+
return sortPoolSymbols(symbolA, symbolB).join("-");
|
|
1947
|
+
}
|
|
1940
1948
|
var SELECT_SOLVER_TYPEHASH = keccak256(toHex("SelectSolver(bytes32 commitment,address solver)"));
|
|
1941
1949
|
var PACKED_USEROP_TYPEHASH = keccak256(
|
|
1942
1950
|
toHex(
|
|
@@ -2039,6 +2047,12 @@ var CryptoUtils = class _CryptoUtils {
|
|
|
2039
2047
|
* signing infrastructure (hardware wallets, MPC/TEE policy engines) instead
|
|
2040
2048
|
* of an opaque 32-byte digest.
|
|
2041
2049
|
*
|
|
2050
|
+
* The payload must be a standard self-describing `eth_signTypedData_v4`
|
|
2051
|
+
* payload — `EIP712Domain` listed in `types`, `chainId` as a JSON number —
|
|
2052
|
+
* because some signing backends (e.g. MPC Vault) hash it server-side from
|
|
2053
|
+
* the JSON rather than locally via viem. viem ignores both details when
|
|
2054
|
+
* hashing, so the digest is unchanged for local signers.
|
|
2055
|
+
*
|
|
2042
2056
|
* @param userOp - The packed UserOperation to sign (signature field ignored).
|
|
2043
2057
|
* @param entryPoint - Address of the EntryPoint v0.8 contract.
|
|
2044
2058
|
* @param chainId - Chain ID of the network on which the operation will execute.
|
|
@@ -2049,10 +2063,22 @@ var CryptoUtils = class _CryptoUtils {
|
|
|
2049
2063
|
domain: {
|
|
2050
2064
|
name: "ERC4337",
|
|
2051
2065
|
version: "1",
|
|
2052
|
-
chainId
|
|
2066
|
+
// Runtime number so JSON.stringify emits a canonical v4 numeric chainId for
|
|
2067
|
+
// server-side hashers; viem's uint256 type mapping wants bigint but its
|
|
2068
|
+
// runtime accepts numbers, hence the cast.
|
|
2069
|
+
chainId: Number(chainId),
|
|
2053
2070
|
verifyingContract: entryPoint
|
|
2054
2071
|
},
|
|
2072
|
+
// `as const`: viem derives the domain's TYPE from `types.EIP712Domain`, so the
|
|
2073
|
+
// entries must stay string literals — widened `string` fields make viem's
|
|
2074
|
+
// typed-data generics reject the payload at every call site.
|
|
2055
2075
|
types: {
|
|
2076
|
+
EIP712Domain: [
|
|
2077
|
+
{ name: "name", type: "string" },
|
|
2078
|
+
{ name: "version", type: "string" },
|
|
2079
|
+
{ name: "chainId", type: "uint256" },
|
|
2080
|
+
{ name: "verifyingContract", type: "address" }
|
|
2081
|
+
],
|
|
2056
2082
|
PackedUserOperation: [
|
|
2057
2083
|
{ name: "sender", type: "address" },
|
|
2058
2084
|
{ name: "nonce", type: "uint256" },
|
|
@@ -2316,6 +2342,107 @@ var CryptoUtils = class _CryptoUtils {
|
|
|
2316
2342
|
}
|
|
2317
2343
|
};
|
|
2318
2344
|
|
|
2345
|
+
// src/protocols/intents/uniswap-v4-position.ts
|
|
2346
|
+
var Q96 = 1n << 96n;
|
|
2347
|
+
var MIN_TICK = -887272;
|
|
2348
|
+
var MAX_TICK = 887272;
|
|
2349
|
+
function word(data, index) {
|
|
2350
|
+
const hex = data.startsWith("0x") ? data.slice(2) : data;
|
|
2351
|
+
const start = index * 64;
|
|
2352
|
+
if (hex.length < start + 64) throw new Error(`return data too short for word ${index}`);
|
|
2353
|
+
return BigInt(`0x${hex.slice(start, start + 64)}`);
|
|
2354
|
+
}
|
|
2355
|
+
function asSigned(value, bits) {
|
|
2356
|
+
const width = 1n << BigInt(bits);
|
|
2357
|
+
const masked = value & width - 1n;
|
|
2358
|
+
return masked >= width >> 1n ? masked - width : masked;
|
|
2359
|
+
}
|
|
2360
|
+
function addressFromWord(data, index) {
|
|
2361
|
+
const hex = data.startsWith("0x") ? data.slice(2) : data;
|
|
2362
|
+
return `0x${hex.slice(index * 64 + 24, (index + 1) * 64)}`.toLowerCase();
|
|
2363
|
+
}
|
|
2364
|
+
function getSqrtRatioAtTick(tick) {
|
|
2365
|
+
if (!Number.isInteger(tick) || tick < MIN_TICK || tick > MAX_TICK) {
|
|
2366
|
+
throw new Error(`tick out of range: ${tick}`);
|
|
2367
|
+
}
|
|
2368
|
+
const absTick = BigInt(Math.abs(tick));
|
|
2369
|
+
let ratio = (absTick & 0x1n) !== 0n ? 0xfffcb933bd6fad37aa2d162d1a594001n : 0x100000000000000000000000000000000n;
|
|
2370
|
+
const factors = [
|
|
2371
|
+
[0x2n, 0xfff97272373d413259a46990580e213an],
|
|
2372
|
+
[0x4n, 0xfff2e50f5f656932ef12357cf3c7fdccn],
|
|
2373
|
+
[0x8n, 0xffe5caca7e10e4e61c3624eaa0941cd0n],
|
|
2374
|
+
[0x10n, 0xffcb9843d60f6159c9db58835c926644n],
|
|
2375
|
+
[0x20n, 0xff973b41fa98c081472e6896dfb254c0n],
|
|
2376
|
+
[0x40n, 0xff2ea16466c96a3843ec78b326b52861n],
|
|
2377
|
+
[0x80n, 0xfe5dee046a99a2a811c461f1969c3053n],
|
|
2378
|
+
[0x100n, 0xfcbe86c7900a88aedcffc83b479aa3a4n],
|
|
2379
|
+
[0x200n, 0xf987a7253ac413176f2b074cf7815e54n],
|
|
2380
|
+
[0x400n, 0xf3392b0822b70005940c7a398e4b70f3n],
|
|
2381
|
+
[0x800n, 0xe7159475a2c29b7443b29c7fa6e889d9n],
|
|
2382
|
+
[0x1000n, 0xd097f3bdfd2022b8845ad8f792aa5825n],
|
|
2383
|
+
[0x2000n, 0xa9f746462d870fdf8a65dc1f90e061e5n],
|
|
2384
|
+
[0x4000n, 0x70d869a156d2a1b890bb3df62baf32f7n],
|
|
2385
|
+
[0x8000n, 0x31be135f97d08fd981231505542fcfa6n],
|
|
2386
|
+
[0x10000n, 0x9aa508b5b7a84e1c677de54f3e99bc9n],
|
|
2387
|
+
[0x20000n, 0x5d6af8dedb81196699c329225ee604n],
|
|
2388
|
+
[0x40000n, 0x2216e584f5fa1ea926041bedfe98n],
|
|
2389
|
+
[0x80000n, 0x48a170391f7dc42444e8fa2n]
|
|
2390
|
+
];
|
|
2391
|
+
for (const [bit, factor] of factors) {
|
|
2392
|
+
if ((absTick & bit) !== 0n) ratio = ratio * factor >> 128n;
|
|
2393
|
+
}
|
|
2394
|
+
if (tick > 0) ratio = (1n << 256n) / ratio;
|
|
2395
|
+
return (ratio >> 32n) + (ratio % (1n << 32n) === 0n ? 0n : 1n);
|
|
2396
|
+
}
|
|
2397
|
+
function positionTicks(info) {
|
|
2398
|
+
return {
|
|
2399
|
+
tickLower: Number(asSigned(info >> 8n, 24)),
|
|
2400
|
+
tickUpper: Number(asSigned(info >> 32n, 24))
|
|
2401
|
+
};
|
|
2402
|
+
}
|
|
2403
|
+
function getAmountsForLiquidity(params) {
|
|
2404
|
+
let { sqrtRatioAX96, sqrtRatioBX96 } = params;
|
|
2405
|
+
const { sqrtPriceX96, liquidity } = params;
|
|
2406
|
+
if (sqrtRatioAX96 > sqrtRatioBX96) [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96];
|
|
2407
|
+
const amount0For = (from, to) => liquidity * Q96 * (to - from) / to / from;
|
|
2408
|
+
const amount1For = (from, to) => liquidity * (to - from) / Q96;
|
|
2409
|
+
if (sqrtPriceX96 <= sqrtRatioAX96) {
|
|
2410
|
+
return { amount0: amount0For(sqrtRatioAX96, sqrtRatioBX96), amount1: 0n };
|
|
2411
|
+
}
|
|
2412
|
+
if (sqrtPriceX96 < sqrtRatioBX96) {
|
|
2413
|
+
return {
|
|
2414
|
+
amount0: amount0For(sqrtPriceX96, sqrtRatioBX96),
|
|
2415
|
+
amount1: amount1For(sqrtRatioAX96, sqrtPriceX96)
|
|
2416
|
+
};
|
|
2417
|
+
}
|
|
2418
|
+
return { amount0: 0n, amount1: amount1For(sqrtRatioAX96, sqrtRatioBX96) };
|
|
2419
|
+
}
|
|
2420
|
+
function decodePoolAndPositionInfo(data) {
|
|
2421
|
+
const hex = data.startsWith("0x") ? data.slice(2) : data;
|
|
2422
|
+
if (hex.length < 6 * 64) throw new Error("getPoolAndPositionInfo returned too little data");
|
|
2423
|
+
const { tickLower, tickUpper } = positionTicks(word(data, 5));
|
|
2424
|
+
return {
|
|
2425
|
+
currency0: addressFromWord(data, 0),
|
|
2426
|
+
currency1: addressFromWord(data, 1),
|
|
2427
|
+
poolKeyEncoded: `0x${hex.slice(0, 5 * 64)}`,
|
|
2428
|
+
tickLower,
|
|
2429
|
+
tickUpper
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
2432
|
+
function positionAmountOfToken(params) {
|
|
2433
|
+
const { info, liquidity, sqrtPriceX96 } = params;
|
|
2434
|
+
const outputToken = params.outputToken.toLowerCase();
|
|
2435
|
+
if (outputToken !== info.currency0 && outputToken !== info.currency1) return 0n;
|
|
2436
|
+
if (liquidity <= 0n || sqrtPriceX96 <= 0n) return 0n;
|
|
2437
|
+
const { amount0, amount1 } = getAmountsForLiquidity({
|
|
2438
|
+
sqrtPriceX96,
|
|
2439
|
+
sqrtRatioAX96: getSqrtRatioAtTick(info.tickLower),
|
|
2440
|
+
sqrtRatioBX96: getSqrtRatioAtTick(info.tickUpper),
|
|
2441
|
+
liquidity
|
|
2442
|
+
});
|
|
2443
|
+
return outputToken === info.currency0 ? amount0 : amount1;
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2319
2446
|
// src/protocols/intents/phantom-aggregation.ts
|
|
2320
2447
|
var ENTRY_POINT_V08_ADDRESS = "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108";
|
|
2321
2448
|
var injectedFetch;
|
|
@@ -2329,6 +2456,14 @@ function rpcFetch() {
|
|
|
2329
2456
|
}
|
|
2330
2457
|
return f;
|
|
2331
2458
|
}
|
|
2459
|
+
var PhantomRpcError = class extends Error {
|
|
2460
|
+
constructor(message, cause) {
|
|
2461
|
+
super(message);
|
|
2462
|
+
this.cause = cause;
|
|
2463
|
+
this.name = "PhantomRpcError";
|
|
2464
|
+
}
|
|
2465
|
+
cause;
|
|
2466
|
+
};
|
|
2332
2467
|
async function rpcCall(url, payload) {
|
|
2333
2468
|
let lastErr;
|
|
2334
2469
|
for (let attempt = 0; attempt < 4; attempt++) {
|
|
@@ -2346,23 +2481,46 @@ async function rpcCall(url, payload) {
|
|
|
2346
2481
|
}),
|
|
2347
2482
|
timeout
|
|
2348
2483
|
]);
|
|
2349
|
-
|
|
2484
|
+
const body = await response.json();
|
|
2485
|
+
if (body?.error) {
|
|
2486
|
+
lastErr = new Error(`rpc error: ${JSON.stringify(body.error).slice(0, 200)}`);
|
|
2487
|
+
continue;
|
|
2488
|
+
}
|
|
2489
|
+
return body;
|
|
2350
2490
|
} catch (err) {
|
|
2351
2491
|
lastErr = err;
|
|
2352
2492
|
} finally {
|
|
2353
2493
|
if (timer) clearTimeout(timer);
|
|
2354
2494
|
}
|
|
2355
2495
|
}
|
|
2356
|
-
throw lastErr;
|
|
2496
|
+
throw new PhantomRpcError(`RPC call failed after 4 attempts: ${url}`, lastErr);
|
|
2357
2497
|
}
|
|
2358
2498
|
var FILL_ORDER_ABI = IntentGatewayV2_default.ABI;
|
|
2359
|
-
var
|
|
2360
|
-
var
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2499
|
+
var DECLARATION_V1 = 1;
|
|
2500
|
+
var DECLARATION_V2 = 2;
|
|
2501
|
+
var MAX_DECLARED_ENTRIES = 255;
|
|
2502
|
+
var MAX_TOKEN_ID_BYTES = 32;
|
|
2503
|
+
function tokenIdToBytes(tokenId) {
|
|
2504
|
+
if (tokenId < 0n) throw new Error(`Uniswap V4 tokenId cannot be negative: ${tokenId}`);
|
|
2505
|
+
const bytes = [];
|
|
2506
|
+
let rest = tokenId;
|
|
2507
|
+
while (rest > 0n) {
|
|
2508
|
+
bytes.unshift(Number(rest & 0xffn));
|
|
2509
|
+
rest >>= 8n;
|
|
2510
|
+
}
|
|
2511
|
+
return bytes.length > 0 ? bytes : [0];
|
|
2512
|
+
}
|
|
2513
|
+
function encodePhantomBidDeclaration(declaration) {
|
|
2514
|
+
const chains = declaration.acceptedSourceChains ?? [];
|
|
2515
|
+
const positions = declaration.uniswapV4Positions ?? [];
|
|
2516
|
+
if (chains.length > MAX_DECLARED_ENTRIES) {
|
|
2517
|
+
throw new Error(`Cannot declare more than ${MAX_DECLARED_ENTRIES} source chains`);
|
|
2518
|
+
}
|
|
2519
|
+
if (positions.length > MAX_DECLARED_ENTRIES) {
|
|
2520
|
+
throw new Error(`Cannot declare more than ${MAX_DECLARED_ENTRIES} Uniswap V4 positions`);
|
|
2364
2521
|
}
|
|
2365
|
-
const
|
|
2522
|
+
const version = positions.length > 0 ? DECLARATION_V2 : DECLARATION_V1;
|
|
2523
|
+
const bytes = [version, chains.length];
|
|
2366
2524
|
for (const chain of chains) {
|
|
2367
2525
|
const encoded = stringToU8a(chain);
|
|
2368
2526
|
if (encoded.length === 0 || encoded.length > 255) {
|
|
@@ -2370,25 +2528,59 @@ function encodeAcceptedSourceChains(chains) {
|
|
|
2370
2528
|
}
|
|
2371
2529
|
bytes.push(encoded.length, ...encoded);
|
|
2372
2530
|
}
|
|
2531
|
+
if (version === DECLARATION_V2) {
|
|
2532
|
+
bytes.push(positions.length);
|
|
2533
|
+
for (const tokenId of positions) {
|
|
2534
|
+
const encoded = tokenIdToBytes(tokenId);
|
|
2535
|
+
if (encoded.length > MAX_TOKEN_ID_BYTES) {
|
|
2536
|
+
throw new Error(`Uniswap V4 tokenId exceeds uint256: ${tokenId}`);
|
|
2537
|
+
}
|
|
2538
|
+
bytes.push(encoded.length, ...encoded);
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2373
2541
|
return u8aToHex(new Uint8Array(bytes));
|
|
2374
2542
|
}
|
|
2375
|
-
function
|
|
2376
|
-
|
|
2543
|
+
function decodePhantomBidDeclaration(paymasterAndData) {
|
|
2544
|
+
const absent = { acceptedSources: null, uniswapV4Positions: [] };
|
|
2545
|
+
if (!paymasterAndData || !isHex(paymasterAndData)) return absent;
|
|
2377
2546
|
const bytes = hexToU8a(paymasterAndData);
|
|
2378
|
-
if (bytes.length < 2
|
|
2379
|
-
const
|
|
2547
|
+
if (bytes.length < 2) return absent;
|
|
2548
|
+
const version = bytes[0];
|
|
2549
|
+
if (version !== DECLARATION_V1 && version !== DECLARATION_V2) return absent;
|
|
2380
2550
|
const chains = [];
|
|
2381
2551
|
let offset = 2;
|
|
2382
|
-
for (let entry = 0; entry <
|
|
2383
|
-
if (offset >= bytes.length) return
|
|
2552
|
+
for (let entry = 0; entry < bytes[1]; entry++) {
|
|
2553
|
+
if (offset >= bytes.length) return absent;
|
|
2384
2554
|
const length = bytes[offset];
|
|
2385
2555
|
offset += 1;
|
|
2386
|
-
if (length === 0 || offset + length > bytes.length) return
|
|
2556
|
+
if (length === 0 || offset + length > bytes.length) return absent;
|
|
2387
2557
|
chains.push(u8aToString(bytes.subarray(offset, offset + length)));
|
|
2388
2558
|
offset += length;
|
|
2389
2559
|
}
|
|
2390
|
-
|
|
2391
|
-
|
|
2560
|
+
const positions = [];
|
|
2561
|
+
if (version === DECLARATION_V2) {
|
|
2562
|
+
if (offset >= bytes.length) return absent;
|
|
2563
|
+
const count = bytes[offset];
|
|
2564
|
+
offset += 1;
|
|
2565
|
+
for (let entry = 0; entry < count; entry++) {
|
|
2566
|
+
if (offset >= bytes.length) return absent;
|
|
2567
|
+
const length = bytes[offset];
|
|
2568
|
+
offset += 1;
|
|
2569
|
+
if (length === 0 || length > MAX_TOKEN_ID_BYTES || offset + length > bytes.length) return absent;
|
|
2570
|
+
let tokenId = 0n;
|
|
2571
|
+
for (const byte of bytes.subarray(offset, offset + length)) tokenId = tokenId << 8n | BigInt(byte);
|
|
2572
|
+
positions.push(tokenId);
|
|
2573
|
+
offset += length;
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
if (offset !== bytes.length) return absent;
|
|
2577
|
+
return { acceptedSources: chains, uniswapV4Positions: positions };
|
|
2578
|
+
}
|
|
2579
|
+
function encodeAcceptedSourceChains(chains) {
|
|
2580
|
+
return encodePhantomBidDeclaration({ acceptedSourceChains: chains });
|
|
2581
|
+
}
|
|
2582
|
+
function decodeAcceptedSourceChains(paymasterAndData) {
|
|
2583
|
+
return decodePhantomBidDeclaration(paymasterAndData).acceptedSources;
|
|
2392
2584
|
}
|
|
2393
2585
|
function zipFillLegs(assets, outputs) {
|
|
2394
2586
|
return assets.map((asset, index) => {
|
|
@@ -2473,17 +2665,46 @@ async function isDelegatedToSolverAccount(evmRpcUrl, account, solverAccount) {
|
|
|
2473
2665
|
method: "eth_getCode",
|
|
2474
2666
|
params: [account, "latest"]
|
|
2475
2667
|
});
|
|
2476
|
-
|
|
2668
|
+
if (typeof response.result !== "string") {
|
|
2669
|
+
throw new PhantomRpcError(`eth_getCode returned no code for ${account} on ${evmRpcUrl}`);
|
|
2670
|
+
}
|
|
2671
|
+
const code = response.result.toLowerCase();
|
|
2477
2672
|
if (!code.startsWith(DELEGATION_INDICATOR_PREFIX)) return false;
|
|
2478
2673
|
return `0x${code.slice(DELEGATION_INDICATOR_PREFIX.length)}` === solverAccount.toLowerCase();
|
|
2479
2674
|
}
|
|
2675
|
+
function memoizedDelegationCheck() {
|
|
2676
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2677
|
+
return (evmRpcUrl, account, solverAccount) => {
|
|
2678
|
+
const key = `${evmRpcUrl}|${account.toLowerCase()}|${solverAccount.toLowerCase()}`;
|
|
2679
|
+
let pending = cache.get(key);
|
|
2680
|
+
if (!pending) {
|
|
2681
|
+
pending = isDelegatedToSolverAccount(evmRpcUrl, account, solverAccount).catch((err) => {
|
|
2682
|
+
cache.delete(key);
|
|
2683
|
+
throw err;
|
|
2684
|
+
});
|
|
2685
|
+
cache.set(key, pending);
|
|
2686
|
+
}
|
|
2687
|
+
return pending;
|
|
2688
|
+
};
|
|
2689
|
+
}
|
|
2480
2690
|
function evmChainId(chain) {
|
|
2481
2691
|
const [prefix, id] = chain.split("-");
|
|
2482
2692
|
if (prefix !== "EVM" || !id || !/^\d+$/.test(id)) return null;
|
|
2483
2693
|
return BigInt(id);
|
|
2484
2694
|
}
|
|
2485
2695
|
async function isVerifiedSolverBid(params) {
|
|
2486
|
-
const {
|
|
2696
|
+
const {
|
|
2697
|
+
userOp,
|
|
2698
|
+
commitment,
|
|
2699
|
+
sessionKey,
|
|
2700
|
+
chainId,
|
|
2701
|
+
solverAccount,
|
|
2702
|
+
evmRpcUrl,
|
|
2703
|
+
recoverSigner,
|
|
2704
|
+
bidNonceKey,
|
|
2705
|
+
isDelegated,
|
|
2706
|
+
logger
|
|
2707
|
+
} = params;
|
|
2487
2708
|
const solver = userOp.sender;
|
|
2488
2709
|
const parsed = splitBidSignature(userOp.signature);
|
|
2489
2710
|
if (!parsed) {
|
|
@@ -2506,7 +2727,7 @@ async function isVerifiedSolverBid(params) {
|
|
|
2506
2727
|
logger?.warn({ solver, commitment, signer }, "Rejecting phantom bid: signature does not recover to the sender");
|
|
2507
2728
|
return false;
|
|
2508
2729
|
}
|
|
2509
|
-
if (!await
|
|
2730
|
+
if (!await isDelegated(evmRpcUrl, solver, solverAccount)) {
|
|
2510
2731
|
logger?.warn({ solver, commitment, solverAccount }, "Rejecting phantom bid: sender is not a delegated solver");
|
|
2511
2732
|
return false;
|
|
2512
2733
|
}
|
|
@@ -2522,18 +2743,17 @@ async function fetchBidsForOrder(nodeUrl, commitment) {
|
|
|
2522
2743
|
return Array.isArray(data.result) ? data.result : [];
|
|
2523
2744
|
}
|
|
2524
2745
|
async function ethCallUint(evmRpcUrl, to, data) {
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
} catch {
|
|
2535
|
-
return 0n;
|
|
2746
|
+
const result = await rpcCall(evmRpcUrl, {
|
|
2747
|
+
id: 1,
|
|
2748
|
+
jsonrpc: "2.0",
|
|
2749
|
+
method: "eth_call",
|
|
2750
|
+
params: [{ to, data }, "latest"]
|
|
2751
|
+
});
|
|
2752
|
+
if (result.result === "0x") return 0n;
|
|
2753
|
+
if (typeof result.result !== "string") {
|
|
2754
|
+
throw new PhantomRpcError(`eth_call returned no result for ${to} on ${evmRpcUrl}`);
|
|
2536
2755
|
}
|
|
2756
|
+
return BigInt(result.result);
|
|
2537
2757
|
}
|
|
2538
2758
|
async function getTotalSolverBalance(evmRpcUrl, chain, token, solver, yieldVaults) {
|
|
2539
2759
|
const padded = solver.replace("0x", "").padStart(64, "0");
|
|
@@ -2545,27 +2765,104 @@ async function getTotalSolverBalance(evmRpcUrl, chain, token, solver, yieldVault
|
|
|
2545
2765
|
);
|
|
2546
2766
|
return vaultBalances.reduce((acc, b) => acc + b, raw);
|
|
2547
2767
|
}
|
|
2768
|
+
var SELECTOR_OWNER_OF = "0x6352211e";
|
|
2769
|
+
var SELECTOR_POSITION_LIQUIDITY = "0x1efeed33";
|
|
2770
|
+
var SELECTOR_POOL_AND_POSITION_INFO = "0x7ba03aad";
|
|
2771
|
+
var SELECTOR_GET_SLOT0 = "0xc815641c";
|
|
2772
|
+
var uint256Arg = (value) => value.toString(16).padStart(64, "0");
|
|
2773
|
+
async function readV4Position(evmRpcUrl, contracts, tokenId, keccak, logger) {
|
|
2774
|
+
const call = async (to, data) => {
|
|
2775
|
+
const result = await rpcCall(evmRpcUrl, {
|
|
2776
|
+
id: 1,
|
|
2777
|
+
jsonrpc: "2.0",
|
|
2778
|
+
method: "eth_call",
|
|
2779
|
+
params: [{ to, data }, "latest"]
|
|
2780
|
+
});
|
|
2781
|
+
if (result.result === "0x") return null;
|
|
2782
|
+
if (typeof result.result !== "string") {
|
|
2783
|
+
throw new PhantomRpcError(`eth_call returned no result for ${to} on ${evmRpcUrl}`);
|
|
2784
|
+
}
|
|
2785
|
+
return result.result;
|
|
2786
|
+
};
|
|
2787
|
+
const arg = uint256Arg(tokenId);
|
|
2788
|
+
const [ownerData, infoData, liquidityData] = await Promise.all([
|
|
2789
|
+
call(contracts.positionManager, `${SELECTOR_OWNER_OF}${arg}`),
|
|
2790
|
+
call(contracts.positionManager, `${SELECTOR_POOL_AND_POSITION_INFO}${arg}`),
|
|
2791
|
+
call(contracts.positionManager, `${SELECTOR_POSITION_LIQUIDITY}${arg}`)
|
|
2792
|
+
]);
|
|
2793
|
+
if (!ownerData) return null;
|
|
2794
|
+
if (!infoData || !liquidityData) {
|
|
2795
|
+
logger?.warn(
|
|
2796
|
+
{ tokenId: tokenId.toString(), positionManager: contracts.positionManager },
|
|
2797
|
+
"Uniswap V4 position exists but its pool info or liquidity did not read back \u2014 check the configured PositionManager"
|
|
2798
|
+
);
|
|
2799
|
+
return null;
|
|
2800
|
+
}
|
|
2801
|
+
const info = decodePoolAndPositionInfo(infoData);
|
|
2802
|
+
const slot0Data = await call(contracts.stateView, `${SELECTOR_GET_SLOT0}${keccak(info.poolKeyEncoded).slice(2)}`);
|
|
2803
|
+
if (!slot0Data) {
|
|
2804
|
+
logger?.warn(
|
|
2805
|
+
{ tokenId: tokenId.toString(), stateView: contracts.stateView, evmRpcUrl },
|
|
2806
|
+
"Uniswap V4 slot0 read returned nothing for a live position \u2014 the configured StateView address is wrong"
|
|
2807
|
+
);
|
|
2808
|
+
return null;
|
|
2809
|
+
}
|
|
2810
|
+
return {
|
|
2811
|
+
owner: `0x${ownerData.slice(-40)}`.toLowerCase(),
|
|
2812
|
+
info,
|
|
2813
|
+
liquidity: word(liquidityData, 0),
|
|
2814
|
+
sqrtPriceX96: word(slot0Data, 0)
|
|
2815
|
+
};
|
|
2816
|
+
}
|
|
2817
|
+
function memoizedV4Position(keccak, logger) {
|
|
2818
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2819
|
+
return (evmRpcUrl, chain, contracts, tokenId) => {
|
|
2820
|
+
const key = `${chain}|${tokenId}`;
|
|
2821
|
+
let pending = cache.get(key);
|
|
2822
|
+
if (!pending) {
|
|
2823
|
+
pending = readV4Position(evmRpcUrl, contracts, tokenId, keccak, logger).catch((err) => {
|
|
2824
|
+
cache.delete(key);
|
|
2825
|
+
throw err;
|
|
2826
|
+
});
|
|
2827
|
+
cache.set(key, pending);
|
|
2828
|
+
}
|
|
2829
|
+
return pending;
|
|
2830
|
+
};
|
|
2831
|
+
}
|
|
2548
2832
|
function memoizedSolverBalance(yieldVaults) {
|
|
2549
2833
|
const cache = /* @__PURE__ */ new Map();
|
|
2550
2834
|
return (evmRpcUrl, chain, token, solver) => {
|
|
2551
2835
|
const key = `${chain}|${token.toLowerCase()}|${solver.toLowerCase()}`;
|
|
2552
2836
|
let pending = cache.get(key);
|
|
2553
2837
|
if (!pending) {
|
|
2554
|
-
pending = getTotalSolverBalance(evmRpcUrl, chain, token, solver, yieldVaults)
|
|
2838
|
+
pending = getTotalSolverBalance(evmRpcUrl, chain, token, solver, yieldVaults).catch((err) => {
|
|
2839
|
+
cache.delete(key);
|
|
2840
|
+
throw err;
|
|
2841
|
+
});
|
|
2555
2842
|
cache.set(key, pending);
|
|
2556
2843
|
}
|
|
2557
2844
|
return pending;
|
|
2558
2845
|
};
|
|
2559
2846
|
}
|
|
2560
|
-
async function sweepSolverLiquidity(evmRpcUrls, yieldVaults, solver, getBalance) {
|
|
2847
|
+
async function sweepSolverLiquidity(evmRpcUrls, yieldVaults, solver, getBalance, positions) {
|
|
2561
2848
|
const balances = [];
|
|
2562
2849
|
for (const [chain, tokens] of Object.entries(yieldVaults)) {
|
|
2563
2850
|
const url = evmRpcUrls[chain];
|
|
2564
2851
|
if (!url) continue;
|
|
2565
2852
|
for (const token of Object.keys(tokens)) {
|
|
2566
2853
|
const balance = await getBalance(url, chain, token, solver);
|
|
2567
|
-
|
|
2568
|
-
|
|
2854
|
+
const uniswapV4Balance = chain === positions.chain ? positions.states.reduce(
|
|
2855
|
+
(total2, state) => total2 + positionAmountOfToken({
|
|
2856
|
+
info: state.info,
|
|
2857
|
+
liquidity: state.liquidity,
|
|
2858
|
+
sqrtPriceX96: state.sqrtPriceX96,
|
|
2859
|
+
outputToken: token
|
|
2860
|
+
}),
|
|
2861
|
+
0n
|
|
2862
|
+
) : 0n;
|
|
2863
|
+
const total = balance + uniswapV4Balance;
|
|
2864
|
+
if (total === 0n) continue;
|
|
2865
|
+
balances.push({ solver, chain, tokenAddress: token, balance: total });
|
|
2569
2866
|
}
|
|
2570
2867
|
}
|
|
2571
2868
|
return balances;
|
|
@@ -2576,6 +2873,24 @@ function toAddress(token) {
|
|
|
2576
2873
|
return `0x${addr}`;
|
|
2577
2874
|
}
|
|
2578
2875
|
async function aggregatePhantomBids(params) {
|
|
2876
|
+
const isDelegated = memoizedDelegationCheck();
|
|
2877
|
+
let lastErr;
|
|
2878
|
+
for (let attempt = 1; attempt <= AGGREGATION_ATTEMPTS; attempt++) {
|
|
2879
|
+
try {
|
|
2880
|
+
return await runAggregation(params, isDelegated);
|
|
2881
|
+
} catch (err) {
|
|
2882
|
+
lastErr = err;
|
|
2883
|
+
params.logger?.warn(
|
|
2884
|
+
{ err, commitment: params.commitment, chain: params.chain, attempt, of: AGGREGATION_ATTEMPTS },
|
|
2885
|
+
"Phantom aggregation attempt failed"
|
|
2886
|
+
);
|
|
2887
|
+
if (attempt < AGGREGATION_ATTEMPTS) await new Promise((resolve) => setTimeout(resolve, 250 * attempt));
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
throw lastErr;
|
|
2891
|
+
}
|
|
2892
|
+
var AGGREGATION_ATTEMPTS = 5;
|
|
2893
|
+
async function runAggregation(params, isDelegated) {
|
|
2579
2894
|
const { nodeUrl, evmRpcUrls, chain, gatewayAddress, commitment, yieldVaults, solverAccount, logger } = params;
|
|
2580
2895
|
const extractFill = params.extractFill ?? extractFillData;
|
|
2581
2896
|
const recoverSigner = params.recoverSigner ?? recoverBidSignerViem;
|
|
@@ -2590,6 +2905,8 @@ async function aggregatePhantomBids(params) {
|
|
|
2590
2905
|
}
|
|
2591
2906
|
const bids = await fetchBidsForOrder(nodeUrl, commitment);
|
|
2592
2907
|
if (bids.length === 0) return null;
|
|
2908
|
+
const v4Contracts = params.uniswapV4?.[chain];
|
|
2909
|
+
const readPosition = memoizedV4Position(params.keccak ?? keccak256, logger);
|
|
2593
2910
|
const getBalance = params.getBalance ?? memoizedSolverBalance(yieldVaults);
|
|
2594
2911
|
const quotesByLeg = /* @__PURE__ */ new Map();
|
|
2595
2912
|
const lpBalances = [];
|
|
@@ -2620,6 +2937,7 @@ async function aggregatePhantomBids(params) {
|
|
|
2620
2937
|
evmRpcUrl: destUrl,
|
|
2621
2938
|
recoverSigner,
|
|
2622
2939
|
bidNonceKey,
|
|
2940
|
+
isDelegated,
|
|
2623
2941
|
logger
|
|
2624
2942
|
});
|
|
2625
2943
|
if (!verified) continue;
|
|
@@ -2629,12 +2947,39 @@ async function aggregatePhantomBids(params) {
|
|
|
2629
2947
|
continue;
|
|
2630
2948
|
}
|
|
2631
2949
|
countedSolvers.add(normalizedSolver);
|
|
2632
|
-
const
|
|
2950
|
+
const declaration = decodePhantomBidDeclaration(decoded.paymasterAndData);
|
|
2951
|
+
const acceptedSources = declaration.acceptedSources;
|
|
2633
2952
|
const quotedLegs = [...fillData.legs.entries()].filter(([, leg]) => leg.solverAmount !== 0n);
|
|
2953
|
+
const declaredPositions = v4Contracts ? declaration.uniswapV4Positions : [];
|
|
2954
|
+
const positions = (await Promise.all(
|
|
2955
|
+
declaredPositions.map((tokenId) => readPosition(destUrl, chain, v4Contracts, tokenId))
|
|
2956
|
+
)).filter((state, index) => {
|
|
2957
|
+
if (!state) return false;
|
|
2958
|
+
if (state.owner !== normalizedSolver) {
|
|
2959
|
+
logger?.warn(
|
|
2960
|
+
{ solver, commitment, tokenId: declaredPositions[index].toString(), owner: state.owner },
|
|
2961
|
+
"Ignoring declared Uniswap V4 position: not owned by the bidding solver"
|
|
2962
|
+
);
|
|
2963
|
+
return false;
|
|
2964
|
+
}
|
|
2965
|
+
return true;
|
|
2966
|
+
});
|
|
2634
2967
|
const weights = await Promise.all(
|
|
2635
2968
|
// Price influence: the solver's liquidity in THIS leg's output token on the destination
|
|
2636
2969
|
// chain, so a leg is weighted by the inventory that actually backs it.
|
|
2637
|
-
quotedLegs.map(([, leg]) =>
|
|
2970
|
+
quotedLegs.map(async ([, leg]) => {
|
|
2971
|
+
const outputToken = toAddress(leg.outputToken);
|
|
2972
|
+
const balance = await getBalance(destUrl, chain, outputToken, solver);
|
|
2973
|
+
return positions.reduce(
|
|
2974
|
+
(total, state) => total + positionAmountOfToken({
|
|
2975
|
+
info: state.info,
|
|
2976
|
+
liquidity: state.liquidity,
|
|
2977
|
+
sqrtPriceX96: state.sqrtPriceX96,
|
|
2978
|
+
outputToken
|
|
2979
|
+
}),
|
|
2980
|
+
balance
|
|
2981
|
+
);
|
|
2982
|
+
})
|
|
2638
2983
|
);
|
|
2639
2984
|
for (const [position, [legIndex, leg]] of quotedLegs.entries()) {
|
|
2640
2985
|
const weight = weights[position];
|
|
@@ -2643,8 +2988,14 @@ async function aggregatePhantomBids(params) {
|
|
|
2643
2988
|
entry.bidders.push({ solver: normalizedSolver, weight, acceptedSources });
|
|
2644
2989
|
quotesByLeg.set(legIndex, entry);
|
|
2645
2990
|
}
|
|
2646
|
-
lpBalances.push(
|
|
2991
|
+
lpBalances.push(
|
|
2992
|
+
...await sweepSolverLiquidity(evmRpcUrls, yieldVaults, solver, getBalance, {
|
|
2993
|
+
chain,
|
|
2994
|
+
states: positions
|
|
2995
|
+
})
|
|
2996
|
+
);
|
|
2647
2997
|
} catch (err) {
|
|
2998
|
+
if (err instanceof PhantomRpcError) throw err;
|
|
2648
2999
|
logger?.warn({ err, filler: bid.filler }, "Failed to process bid for price snapshot");
|
|
2649
3000
|
}
|
|
2650
3001
|
}
|
|
@@ -2675,6 +3026,6 @@ async function aggregatePhantomBids(params) {
|
|
|
2675
3026
|
return { legs, lpBalances };
|
|
2676
3027
|
}
|
|
2677
3028
|
|
|
2678
|
-
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 };
|
|
3029
|
+
export { ENTRY_POINT_V08_ADDRESS, FILL_ORDER_ABI, IntentGatewayV2_default as IntentGatewayV2, aggregatePhantomBids, decodeAcceptedSourceChains, decodeERC7821ExecuteBatch, decodePhantomBidDeclaration, decodeUserOpScale, encodeAcceptedSourceChains, encodeERC7821ExecuteBatch, encodePhantomBidDeclaration, encodeUserOpScale, extractFillData, fetchBidsForOrder, memoizedSolverBalance, orderCommitmentFromDecoded, poolSlug, recoverBidSignerViem, setAggregationFetch, sortPoolSymbols, splitBidSignature, weightedMedian, zipFillLegs };
|
|
2679
3030
|
//# sourceMappingURL=intents-helpers.js.map
|
|
2680
3031
|
//# sourceMappingURL=intents-helpers.js.map
|