@hyperbridge/sdk 1.8.8 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.d.ts +46 -15
- package/dist/browser/index.js +300 -178
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.d.ts +46 -15
- package/dist/node/index.js +300 -178
- package/dist/node/index.js.map +1 -1
- package/package.json +1 -1
package/dist/node/index.js
CHANGED
|
@@ -556,7 +556,6 @@ var IntentOrderStatus = Object.freeze({
|
|
|
556
556
|
AWAITING_BIDS: "AWAITING_BIDS",
|
|
557
557
|
BIDS_RECEIVED: "BIDS_RECEIVED",
|
|
558
558
|
BID_SELECTED: "BID_SELECTED",
|
|
559
|
-
USEROP_SUBMITTED: "USEROP_SUBMITTED",
|
|
560
559
|
FILLED: "FILLED",
|
|
561
560
|
PARTIAL_FILL: "PARTIAL_FILL",
|
|
562
561
|
EXPIRED: "EXPIRED",
|
|
@@ -5533,6 +5532,7 @@ var EvmChain = class _EvmChain {
|
|
|
5533
5532
|
});
|
|
5534
5533
|
this.chainConfigService = new ChainConfigService();
|
|
5535
5534
|
}
|
|
5535
|
+
params;
|
|
5536
5536
|
publicClient;
|
|
5537
5537
|
chainConfigService;
|
|
5538
5538
|
/**
|
|
@@ -6133,6 +6133,7 @@ var HttpRpcClient = class {
|
|
|
6133
6133
|
constructor(url) {
|
|
6134
6134
|
this.url = url;
|
|
6135
6135
|
}
|
|
6136
|
+
url;
|
|
6136
6137
|
/**
|
|
6137
6138
|
* Make an RPC call over HTTP
|
|
6138
6139
|
* @param method - The RPC method name
|
|
@@ -6170,6 +6171,7 @@ var SubstrateChain = class _SubstrateChain {
|
|
|
6170
6171
|
const httpUrl = replaceWebsocketWithHttp(url);
|
|
6171
6172
|
this.rpcClient = new HttpRpcClient(httpUrl);
|
|
6172
6173
|
}
|
|
6174
|
+
params;
|
|
6173
6175
|
/*
|
|
6174
6176
|
* api: The Polkadot API instance for the Substrate chain.
|
|
6175
6177
|
*/
|
|
@@ -6687,6 +6689,9 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
6687
6689
|
this.substratePrivateKey = substratePrivateKey;
|
|
6688
6690
|
this.ownsConnection = ownsConnection;
|
|
6689
6691
|
}
|
|
6692
|
+
api;
|
|
6693
|
+
substratePrivateKey;
|
|
6694
|
+
ownsConnection;
|
|
6690
6695
|
/** Cached result of whether the node exposes intents_* RPC methods */
|
|
6691
6696
|
hasIntentsRpc = null;
|
|
6692
6697
|
/**
|
|
@@ -6964,6 +6969,7 @@ var TronChain = class _TronChain {
|
|
|
6964
6969
|
this.evm = evm;
|
|
6965
6970
|
this.tronWebInstance = new TronWeb({ fullHost: params.rpcUrl });
|
|
6966
6971
|
}
|
|
6972
|
+
params;
|
|
6967
6973
|
evm;
|
|
6968
6974
|
tronWebInstance;
|
|
6969
6975
|
/**
|
|
@@ -7504,6 +7510,7 @@ var SubstrateHttpRpc = class {
|
|
|
7504
7510
|
constructor(url) {
|
|
7505
7511
|
this.url = url;
|
|
7506
7512
|
}
|
|
7513
|
+
url;
|
|
7507
7514
|
async call(method, params = []) {
|
|
7508
7515
|
const body = JSON.stringify({
|
|
7509
7516
|
jsonrpc: "2.0",
|
|
@@ -7548,6 +7555,7 @@ var PolkadotHubChain = class _PolkadotHubChain {
|
|
|
7548
7555
|
this.evm = evm;
|
|
7549
7556
|
this.substrateRpc = new SubstrateHttpRpc(replaceWebsocketWithHttp(params.substrateRpcUrl));
|
|
7550
7557
|
}
|
|
7558
|
+
params;
|
|
7551
7559
|
evm;
|
|
7552
7560
|
substrateRpc;
|
|
7553
7561
|
static fromParams(params) {
|
|
@@ -12629,6 +12637,7 @@ var CryptoUtils = class {
|
|
|
12629
12637
|
constructor(ctx) {
|
|
12630
12638
|
this.ctx = ctx;
|
|
12631
12639
|
}
|
|
12640
|
+
ctx;
|
|
12632
12641
|
/**
|
|
12633
12642
|
* Computes an EIP-712 domain separator for a given contract.
|
|
12634
12643
|
*
|
|
@@ -15164,6 +15173,7 @@ var OrderPlacer = class {
|
|
|
15164
15173
|
constructor(ctx) {
|
|
15165
15174
|
this.ctx = ctx;
|
|
15166
15175
|
}
|
|
15176
|
+
ctx;
|
|
15167
15177
|
/**
|
|
15168
15178
|
* Bidirectional async generator that orchestrates order placement.
|
|
15169
15179
|
*
|
|
@@ -15241,67 +15251,40 @@ var OrderPlacer = class {
|
|
|
15241
15251
|
return { order, receipt };
|
|
15242
15252
|
}
|
|
15243
15253
|
};
|
|
15244
|
-
|
|
15245
|
-
// src/protocols/intents/OrderExecutor.ts
|
|
15246
15254
|
var USED_USEROPS_STORAGE_KEY = (commitment) => `used-userops:${commitment.toLowerCase()}`;
|
|
15247
15255
|
var OrderExecutor = class {
|
|
15248
|
-
/**
|
|
15249
|
-
* @param ctx - Shared IntentsV2 context providing the destination chain
|
|
15250
|
-
* client, coprocessor, bundler URL, and storage adapters.
|
|
15251
|
-
* @param bidManager - Handles bid validation, sorting, simulation, and
|
|
15252
|
-
* UserOperation submission.
|
|
15253
|
-
* @param crypto - Crypto utilities used to compute UserOperation hashes for
|
|
15254
|
-
* deduplication.
|
|
15255
|
-
*/
|
|
15256
15256
|
constructor(ctx, bidManager, crypto) {
|
|
15257
15257
|
this.ctx = ctx;
|
|
15258
15258
|
this.bidManager = bidManager;
|
|
15259
15259
|
this.crypto = crypto;
|
|
15260
15260
|
}
|
|
15261
|
+
ctx;
|
|
15262
|
+
bidManager;
|
|
15263
|
+
crypto;
|
|
15261
15264
|
/**
|
|
15262
|
-
*
|
|
15263
|
-
*
|
|
15264
|
-
* or an unrecoverable error occurs.
|
|
15265
|
-
*
|
|
15266
|
-
* **Status progression (cross-chain orders):**
|
|
15267
|
-
* `AWAITING_BIDS` → `BIDS_RECEIVED` → `BID_SELECTED` → `USEROP_SUBMITTED`
|
|
15268
|
-
* then terminates (settlement is confirmed off-chain via Hyperbridge).
|
|
15269
|
-
*
|
|
15270
|
-
* **Status progression (same-chain orders):**
|
|
15271
|
-
* `AWAITING_BIDS` → `BIDS_RECEIVED` → `BID_SELECTED` → `USEROP_SUBMITTED`
|
|
15272
|
-
* → (`FILLED` | `PARTIAL_FILL`)* → (`FILLED` | `EXPIRED`)
|
|
15273
|
-
*
|
|
15274
|
-
* **Error statuses:** `FAILED` (retryable error during bid selection/submission,
|
|
15275
|
-
* triggers automatic retry) or `EXPIRED` (deadline reached or no new bids —
|
|
15276
|
-
* terminal, no further retries).
|
|
15277
|
-
*
|
|
15278
|
-
* @param options - Execution parameters including the placed order, its
|
|
15279
|
-
* session private key, bid collection settings, and poll interval.
|
|
15280
|
-
* @yields {@link IntentOrderStatusUpdate} objects describing each stage.
|
|
15281
|
-
* @throws Never throws directly; all errors are reported as `FAILED` yields.
|
|
15265
|
+
* Sleeps until the order's block deadline is reached, then yields EXPIRED.
|
|
15266
|
+
* Uses the chain's block time to calculate the sleep duration.
|
|
15282
15267
|
*/
|
|
15283
|
-
async *
|
|
15284
|
-
const
|
|
15285
|
-
|
|
15286
|
-
|
|
15287
|
-
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15292
|
-
const commitment = order.id;
|
|
15293
|
-
const isSameChain = order.source === order.destination;
|
|
15294
|
-
if (!this.ctx.intentsCoprocessor) {
|
|
15295
|
-
yield { status: "FAILED", error: "IntentsCoprocessor required for order execution" };
|
|
15296
|
-
return;
|
|
15297
|
-
}
|
|
15298
|
-
if (!this.ctx.bundlerUrl) {
|
|
15299
|
-
yield { status: "FAILED", error: "Bundler URL not configured" };
|
|
15300
|
-
return;
|
|
15268
|
+
async *deadlineStream(deadline, commitment) {
|
|
15269
|
+
const client = this.ctx.dest.client;
|
|
15270
|
+
const blockTimeMs = client.chain?.blockTime ?? 2e3;
|
|
15271
|
+
while (true) {
|
|
15272
|
+
const currentBlock = await client.getBlockNumber();
|
|
15273
|
+
if (currentBlock >= deadline) break;
|
|
15274
|
+
const blocksRemaining = Number(deadline - currentBlock);
|
|
15275
|
+
const sleepMs = blocksRemaining * blockTimeMs;
|
|
15276
|
+
await sleep(sleepMs);
|
|
15301
15277
|
}
|
|
15278
|
+
yield {
|
|
15279
|
+
status: "EXPIRED",
|
|
15280
|
+
commitment,
|
|
15281
|
+
error: "Order deadline reached"
|
|
15282
|
+
};
|
|
15283
|
+
}
|
|
15284
|
+
/** Loads the persisted deduplication set of already-submitted UserOp hashes for a given order commitment. */
|
|
15285
|
+
async loadUsedUserOps(commitment) {
|
|
15302
15286
|
const usedUserOps = /* @__PURE__ */ new Set();
|
|
15303
|
-
const
|
|
15304
|
-
const persisted = await this.ctx.usedUserOpsStorage.getItem(storageKey);
|
|
15287
|
+
const persisted = await this.ctx.usedUserOpsStorage.getItem(USED_USEROPS_STORAGE_KEY(commitment));
|
|
15305
15288
|
if (persisted) {
|
|
15306
15289
|
try {
|
|
15307
15290
|
const parsed = JSON.parse(persisted);
|
|
@@ -15311,74 +15294,214 @@ var OrderExecutor = class {
|
|
|
15311
15294
|
} catch {
|
|
15312
15295
|
}
|
|
15313
15296
|
}
|
|
15314
|
-
|
|
15315
|
-
|
|
15316
|
-
|
|
15297
|
+
return usedUserOps;
|
|
15298
|
+
}
|
|
15299
|
+
/** Persists the deduplication set of UserOp hashes to storage. */
|
|
15300
|
+
async persistUsedUserOps(commitment, usedUserOps) {
|
|
15301
|
+
await this.ctx.usedUserOpsStorage.setItem(
|
|
15302
|
+
USED_USEROPS_STORAGE_KEY(commitment),
|
|
15303
|
+
JSON.stringify([...usedUserOps])
|
|
15304
|
+
);
|
|
15305
|
+
}
|
|
15306
|
+
/**
|
|
15307
|
+
* Creates a closure that computes the deduplication hash key for a
|
|
15308
|
+
* UserOperation, pre-bound to the order's destination chain and entry point.
|
|
15309
|
+
*/
|
|
15310
|
+
createUserOpHasher(order) {
|
|
15317
15311
|
const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(hexToString(order.destination));
|
|
15318
15312
|
const chainId = BigInt(
|
|
15319
15313
|
this.ctx.dest.client.chain?.id ?? Number.parseInt(this.ctx.dest.config.stateMachineId.split("-")[1])
|
|
15320
15314
|
);
|
|
15321
|
-
|
|
15315
|
+
return (userOp) => this.crypto.computeUserOpHash(userOp, entryPointAddress, chainId);
|
|
15316
|
+
}
|
|
15317
|
+
/**
|
|
15318
|
+
* Fetches bids from the coprocessor for a given order commitment.
|
|
15319
|
+
* If a preferred solver is configured and the solver lock has not expired,
|
|
15320
|
+
* only bids from that solver are returned.
|
|
15321
|
+
*/
|
|
15322
|
+
async fetchBids(params) {
|
|
15323
|
+
const { commitment, solver, solverLockStartTime } = params;
|
|
15324
|
+
const fetchedBids = await this.ctx.intentsCoprocessor.getBidsForOrder(commitment);
|
|
15325
|
+
if (solver) {
|
|
15326
|
+
const { address, timeoutMs } = solver;
|
|
15327
|
+
const solverLockActive = Date.now() - solverLockStartTime < timeoutMs;
|
|
15328
|
+
return solverLockActive ? fetchedBids.filter((bid) => bid.userOp.sender.toLowerCase() === address.toLowerCase()) : fetchedBids;
|
|
15329
|
+
}
|
|
15330
|
+
return fetchedBids;
|
|
15331
|
+
}
|
|
15332
|
+
/**
|
|
15333
|
+
* Selects the best bid from the provided candidates, submits the
|
|
15334
|
+
* UserOperation, and persists the dedup entry to prevent resubmission.
|
|
15335
|
+
*/
|
|
15336
|
+
async submitBid(params) {
|
|
15337
|
+
const { order, freshBids, sessionPrivateKey, commitment, usedUserOps, userOpHashKey } = params;
|
|
15338
|
+
const result = await this.bidManager.selectBid(order, freshBids, sessionPrivateKey);
|
|
15339
|
+
usedUserOps.add(userOpHashKey(result.userOp));
|
|
15340
|
+
await this.persistUsedUserOps(commitment, usedUserOps);
|
|
15341
|
+
return result;
|
|
15342
|
+
}
|
|
15343
|
+
/**
|
|
15344
|
+
* Processes a fill result and returns updated fill accumulators,
|
|
15345
|
+
* the status update to yield (if any), and whether the order is
|
|
15346
|
+
* fully satisfied.
|
|
15347
|
+
*/
|
|
15348
|
+
processFillResult(result, commitment, targetAssets, totalFilledAssets, remainingAssets) {
|
|
15349
|
+
if (result.fillStatus === "full") {
|
|
15350
|
+
totalFilledAssets = targetAssets.map((a) => ({ token: a.token, amount: a.amount }));
|
|
15351
|
+
remainingAssets = targetAssets.map((a) => ({ token: a.token, amount: 0n }));
|
|
15352
|
+
return {
|
|
15353
|
+
update: {
|
|
15354
|
+
status: "FILLED",
|
|
15355
|
+
commitment,
|
|
15356
|
+
userOpHash: result.userOpHash,
|
|
15357
|
+
selectedSolver: result.solverAddress,
|
|
15358
|
+
transactionHash: result.txnHash,
|
|
15359
|
+
totalFilledAssets,
|
|
15360
|
+
remainingAssets
|
|
15361
|
+
},
|
|
15362
|
+
done: true,
|
|
15363
|
+
totalFilledAssets,
|
|
15364
|
+
remainingAssets
|
|
15365
|
+
};
|
|
15366
|
+
}
|
|
15367
|
+
if (result.fillStatus === "partial") {
|
|
15368
|
+
const filledAssets = result.filledAssets ?? [];
|
|
15369
|
+
totalFilledAssets = totalFilledAssets.map((a) => {
|
|
15370
|
+
const filled = filledAssets.find((f) => f.token === a.token);
|
|
15371
|
+
return filled ? { token: a.token, amount: a.amount + filled.amount } : { ...a };
|
|
15372
|
+
});
|
|
15373
|
+
remainingAssets = targetAssets.map((target) => {
|
|
15374
|
+
const filled = totalFilledAssets.find((a) => a.token === target.token);
|
|
15375
|
+
const filledAmt = filled?.amount ?? 0n;
|
|
15376
|
+
return {
|
|
15377
|
+
token: target.token,
|
|
15378
|
+
amount: filledAmt >= target.amount ? 0n : target.amount - filledAmt
|
|
15379
|
+
};
|
|
15380
|
+
});
|
|
15381
|
+
const fullyFilled = remainingAssets.every((a) => a.amount === 0n);
|
|
15382
|
+
return {
|
|
15383
|
+
update: fullyFilled ? {
|
|
15384
|
+
status: "FILLED",
|
|
15385
|
+
commitment,
|
|
15386
|
+
userOpHash: result.userOpHash,
|
|
15387
|
+
selectedSolver: result.solverAddress,
|
|
15388
|
+
transactionHash: result.txnHash,
|
|
15389
|
+
totalFilledAssets,
|
|
15390
|
+
remainingAssets
|
|
15391
|
+
} : {
|
|
15392
|
+
status: "PARTIAL_FILL",
|
|
15393
|
+
commitment,
|
|
15394
|
+
userOpHash: result.userOpHash,
|
|
15395
|
+
selectedSolver: result.solverAddress,
|
|
15396
|
+
transactionHash: result.txnHash,
|
|
15397
|
+
filledAssets,
|
|
15398
|
+
totalFilledAssets,
|
|
15399
|
+
remainingAssets
|
|
15400
|
+
},
|
|
15401
|
+
done: fullyFilled,
|
|
15402
|
+
totalFilledAssets,
|
|
15403
|
+
remainingAssets
|
|
15404
|
+
};
|
|
15405
|
+
}
|
|
15406
|
+
return { update: null, done: false, totalFilledAssets, remainingAssets };
|
|
15407
|
+
}
|
|
15408
|
+
/**
|
|
15409
|
+
* Executes an intent order by racing bid polling against the order's
|
|
15410
|
+
* block deadline. Yields status updates at each lifecycle stage.
|
|
15411
|
+
*
|
|
15412
|
+
* **Same-chain:** `AWAITING_BIDS` → `BIDS_RECEIVED` → `BID_SELECTED`
|
|
15413
|
+
* → (`FILLED` | `PARTIAL_FILL`)* → (`FILLED` | `EXPIRED`)
|
|
15414
|
+
*
|
|
15415
|
+
* **Cross-chain:** `AWAITING_BIDS` → `BIDS_RECEIVED` → `BID_SELECTED`
|
|
15416
|
+
* (terminates — settlement is confirmed async via Hyperbridge)
|
|
15417
|
+
*/
|
|
15418
|
+
async *executeOrder(options) {
|
|
15419
|
+
const { order, sessionPrivateKey, auctionTimeMs, pollIntervalMs = DEFAULT_POLL_INTERVAL, solver } = options;
|
|
15420
|
+
const commitment = order.id;
|
|
15421
|
+
const isSameChain = order.source === order.destination;
|
|
15422
|
+
if (!this.ctx.intentsCoprocessor) {
|
|
15423
|
+
yield { status: "FAILED", error: "IntentsCoprocessor required for order execution" };
|
|
15424
|
+
return;
|
|
15425
|
+
}
|
|
15426
|
+
if (!this.ctx.bundlerUrl) {
|
|
15427
|
+
yield { status: "FAILED", error: "Bundler URL not configured" };
|
|
15428
|
+
return;
|
|
15429
|
+
}
|
|
15430
|
+
const usedUserOps = await this.loadUsedUserOps(commitment);
|
|
15431
|
+
const userOpHashKey = this.createUserOpHasher(order);
|
|
15322
15432
|
const targetAssets = order.output.assets.map((a) => ({ token: a.token, amount: a.amount }));
|
|
15323
15433
|
let totalFilledAssets = order.output.assets.map((a) => ({ token: a.token, amount: 0n }));
|
|
15324
15434
|
let remainingAssets = order.output.assets.map((a) => ({ token: a.token, amount: a.amount }));
|
|
15435
|
+
const executionStream = this.executionStream({
|
|
15436
|
+
order,
|
|
15437
|
+
sessionPrivateKey,
|
|
15438
|
+
commitment,
|
|
15439
|
+
auctionTimeMs,
|
|
15440
|
+
pollIntervalMs,
|
|
15441
|
+
solver,
|
|
15442
|
+
usedUserOps,
|
|
15443
|
+
userOpHashKey,
|
|
15444
|
+
targetAssets,
|
|
15445
|
+
totalFilledAssets,
|
|
15446
|
+
remainingAssets
|
|
15447
|
+
});
|
|
15448
|
+
const deadlineTimeout = this.deadlineStream(order.deadline, commitment);
|
|
15449
|
+
const combined = mergeRace(deadlineTimeout, executionStream);
|
|
15450
|
+
for await (const update of combined) {
|
|
15451
|
+
yield update;
|
|
15452
|
+
if (update.status === "EXPIRED" || update.status === "FILLED") return;
|
|
15453
|
+
if (update.status === "BID_SELECTED" && !isSameChain) return;
|
|
15454
|
+
}
|
|
15455
|
+
}
|
|
15456
|
+
/**
|
|
15457
|
+
* Core execution loop that polls for bids, submits UserOperations,
|
|
15458
|
+
* and tracks fill progress. Yields between each poll iteration so
|
|
15459
|
+
* that `mergeRace` can interleave the deadline stream.
|
|
15460
|
+
*/
|
|
15461
|
+
async *executionStream(params) {
|
|
15462
|
+
const {
|
|
15463
|
+
order,
|
|
15464
|
+
sessionPrivateKey,
|
|
15465
|
+
commitment,
|
|
15466
|
+
auctionTimeMs,
|
|
15467
|
+
pollIntervalMs,
|
|
15468
|
+
solver,
|
|
15469
|
+
usedUserOps,
|
|
15470
|
+
userOpHashKey,
|
|
15471
|
+
targetAssets
|
|
15472
|
+
} = params;
|
|
15473
|
+
let { totalFilledAssets, remainingAssets } = params;
|
|
15474
|
+
const solverLockStartTime = Date.now();
|
|
15475
|
+
yield { status: "AWAITING_BIDS", commitment, totalFilledAssets, remainingAssets };
|
|
15325
15476
|
try {
|
|
15477
|
+
const auctionEnd = Date.now() + auctionTimeMs;
|
|
15478
|
+
while (Date.now() < auctionEnd) {
|
|
15479
|
+
await sleep(Math.min(pollIntervalMs, auctionEnd - Date.now()));
|
|
15480
|
+
}
|
|
15326
15481
|
while (true) {
|
|
15327
|
-
|
|
15328
|
-
|
|
15329
|
-
const
|
|
15330
|
-
|
|
15331
|
-
|
|
15332
|
-
commitment,
|
|
15333
|
-
totalFilledAssets,
|
|
15334
|
-
remainingAssets,
|
|
15335
|
-
error: deadlineError
|
|
15336
|
-
};
|
|
15337
|
-
return;
|
|
15338
|
-
}
|
|
15339
|
-
yield { status: "AWAITING_BIDS", commitment, totalFilledAssets, remainingAssets };
|
|
15340
|
-
const startTime = Date.now();
|
|
15341
|
-
let bids = [];
|
|
15342
|
-
let solverLockExpired = false;
|
|
15343
|
-
while (Date.now() - startTime < bidTimeoutMs) {
|
|
15344
|
-
try {
|
|
15345
|
-
const fetchedBids = await this.ctx.intentsCoprocessor.getBidsForOrder(commitment);
|
|
15346
|
-
if (solver) {
|
|
15347
|
-
const { address, timeoutMs } = solver;
|
|
15348
|
-
const solverLockActive = Date.now() - startTime < timeoutMs;
|
|
15349
|
-
if (!solverLockActive) solverLockExpired = true;
|
|
15350
|
-
bids = solverLockActive ? fetchedBids.filter((bid) => bid.userOp.sender.toLowerCase() === address.toLowerCase()) : fetchedBids;
|
|
15351
|
-
} else {
|
|
15352
|
-
bids = fetchedBids;
|
|
15353
|
-
}
|
|
15354
|
-
if (bids.length >= minBids) {
|
|
15355
|
-
break;
|
|
15356
|
-
}
|
|
15357
|
-
} catch {
|
|
15358
|
-
}
|
|
15482
|
+
let freshBids;
|
|
15483
|
+
try {
|
|
15484
|
+
const bids = await this.fetchBids({ commitment, solver, solverLockStartTime });
|
|
15485
|
+
freshBids = bids.filter((bid) => !usedUserOps.has(userOpHashKey(bid.userOp)));
|
|
15486
|
+
} catch {
|
|
15359
15487
|
await sleep(pollIntervalMs);
|
|
15488
|
+
continue;
|
|
15360
15489
|
}
|
|
15361
|
-
const freshBids = bids.filter((bid) => {
|
|
15362
|
-
const key = userOpHashKey(bid.userOp);
|
|
15363
|
-
return !usedUserOps.has(key);
|
|
15364
|
-
});
|
|
15365
15490
|
if (freshBids.length === 0) {
|
|
15366
|
-
|
|
15367
|
-
|
|
15368
|
-
const noBidsError = isPartiallyFilled ? `No new bids${solverClause} after partial fill` : `No new bids${solverClause} available within ${bidTimeoutMs}ms timeout`;
|
|
15369
|
-
yield {
|
|
15370
|
-
status: "EXPIRED",
|
|
15371
|
-
commitment,
|
|
15372
|
-
totalFilledAssets,
|
|
15373
|
-
remainingAssets,
|
|
15374
|
-
error: noBidsError
|
|
15375
|
-
};
|
|
15376
|
-
return;
|
|
15491
|
+
await sleep(pollIntervalMs);
|
|
15492
|
+
continue;
|
|
15377
15493
|
}
|
|
15378
15494
|
yield { status: "BIDS_RECEIVED", commitment, bidCount: freshBids.length, bids: freshBids };
|
|
15379
|
-
let
|
|
15495
|
+
let submitResult;
|
|
15380
15496
|
try {
|
|
15381
|
-
|
|
15497
|
+
submitResult = await this.submitBid({
|
|
15498
|
+
order,
|
|
15499
|
+
freshBids,
|
|
15500
|
+
sessionPrivateKey,
|
|
15501
|
+
commitment,
|
|
15502
|
+
usedUserOps,
|
|
15503
|
+
userOpHashKey
|
|
15504
|
+
});
|
|
15382
15505
|
} catch (err) {
|
|
15383
15506
|
yield {
|
|
15384
15507
|
status: "FAILED",
|
|
@@ -15390,77 +15513,26 @@ var OrderExecutor = class {
|
|
|
15390
15513
|
await sleep(pollIntervalMs);
|
|
15391
15514
|
continue;
|
|
15392
15515
|
}
|
|
15393
|
-
const usedKey = userOpHashKey(result.userOp);
|
|
15394
|
-
usedUserOps.add(usedKey);
|
|
15395
|
-
await persistUsedUserOps();
|
|
15396
15516
|
yield {
|
|
15397
15517
|
status: "BID_SELECTED",
|
|
15398
15518
|
commitment,
|
|
15399
|
-
selectedSolver:
|
|
15400
|
-
userOpHash:
|
|
15401
|
-
userOp:
|
|
15519
|
+
selectedSolver: submitResult.solverAddress,
|
|
15520
|
+
userOpHash: submitResult.userOpHash,
|
|
15521
|
+
userOp: submitResult.userOp,
|
|
15522
|
+
transactionHash: submitResult.txnHash
|
|
15402
15523
|
};
|
|
15403
|
-
|
|
15404
|
-
|
|
15524
|
+
const fill = this.processFillResult(
|
|
15525
|
+
submitResult,
|
|
15405
15526
|
commitment,
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
|
|
15410
|
-
|
|
15411
|
-
|
|
15412
|
-
|
|
15413
|
-
|
|
15414
|
-
|
|
15415
|
-
remainingAssets = targetAssets.map((a) => ({ token: a.token, amount: 0n }));
|
|
15416
|
-
yield {
|
|
15417
|
-
status: "FILLED",
|
|
15418
|
-
commitment,
|
|
15419
|
-
userOpHash: result.userOpHash,
|
|
15420
|
-
selectedSolver: result.solverAddress,
|
|
15421
|
-
transactionHash: result.txnHash,
|
|
15422
|
-
totalFilledAssets,
|
|
15423
|
-
remainingAssets
|
|
15424
|
-
};
|
|
15425
|
-
return;
|
|
15426
|
-
}
|
|
15427
|
-
if (result.fillStatus === "partial") {
|
|
15428
|
-
const filledAssets = result.filledAssets ?? [];
|
|
15429
|
-
for (const filled of filledAssets) {
|
|
15430
|
-
const entry = totalFilledAssets.find((a) => a.token === filled.token);
|
|
15431
|
-
if (entry) entry.amount += filled.amount;
|
|
15432
|
-
}
|
|
15433
|
-
remainingAssets = targetAssets.map((target) => {
|
|
15434
|
-
const filled = totalFilledAssets.find((a) => a.token === target.token);
|
|
15435
|
-
const filledAmt = filled?.amount ?? 0n;
|
|
15436
|
-
return {
|
|
15437
|
-
token: target.token,
|
|
15438
|
-
amount: filledAmt >= target.amount ? 0n : target.amount - filledAmt
|
|
15439
|
-
};
|
|
15440
|
-
});
|
|
15441
|
-
const fullyFilled = remainingAssets.every((a) => a.amount === 0n);
|
|
15442
|
-
if (fullyFilled) {
|
|
15443
|
-
yield {
|
|
15444
|
-
status: "FILLED",
|
|
15445
|
-
commitment,
|
|
15446
|
-
userOpHash: result.userOpHash,
|
|
15447
|
-
selectedSolver: result.solverAddress,
|
|
15448
|
-
transactionHash: result.txnHash,
|
|
15449
|
-
totalFilledAssets,
|
|
15450
|
-
remainingAssets
|
|
15451
|
-
};
|
|
15452
|
-
return;
|
|
15453
|
-
}
|
|
15454
|
-
yield {
|
|
15455
|
-
status: "PARTIAL_FILL",
|
|
15456
|
-
commitment,
|
|
15457
|
-
userOpHash: result.userOpHash,
|
|
15458
|
-
selectedSolver: result.solverAddress,
|
|
15459
|
-
transactionHash: result.txnHash,
|
|
15460
|
-
filledAssets,
|
|
15461
|
-
totalFilledAssets,
|
|
15462
|
-
remainingAssets
|
|
15463
|
-
};
|
|
15527
|
+
targetAssets,
|
|
15528
|
+
totalFilledAssets,
|
|
15529
|
+
remainingAssets
|
|
15530
|
+
);
|
|
15531
|
+
totalFilledAssets = fill.totalFilledAssets;
|
|
15532
|
+
remainingAssets = fill.remainingAssets;
|
|
15533
|
+
if (fill.update) {
|
|
15534
|
+
yield fill.update;
|
|
15535
|
+
if (fill.done) return;
|
|
15464
15536
|
}
|
|
15465
15537
|
}
|
|
15466
15538
|
} catch (err) {
|
|
@@ -15480,6 +15552,7 @@ var OrderCanceller = class {
|
|
|
15480
15552
|
constructor(ctx) {
|
|
15481
15553
|
this.ctx = ctx;
|
|
15482
15554
|
}
|
|
15555
|
+
ctx;
|
|
15483
15556
|
/**
|
|
15484
15557
|
* Returns both the native token cost and the relayer fee for cancelling an
|
|
15485
15558
|
* order. Frontends can use `relayerFee` to approve the ERC-20 spend before
|
|
@@ -15949,6 +16022,8 @@ var BidManager = class {
|
|
|
15949
16022
|
this.ctx = ctx;
|
|
15950
16023
|
this.crypto = crypto;
|
|
15951
16024
|
}
|
|
16025
|
+
ctx;
|
|
16026
|
+
crypto;
|
|
15952
16027
|
/**
|
|
15953
16028
|
* Constructs a signed `PackedUserOperation` that a solver can submit to the
|
|
15954
16029
|
* Hyperbridge coprocessor as a bid to fill an order.
|
|
@@ -18028,6 +18103,8 @@ var GasEstimator = class {
|
|
|
18028
18103
|
this.ctx = ctx;
|
|
18029
18104
|
this.crypto = crypto;
|
|
18030
18105
|
}
|
|
18106
|
+
ctx;
|
|
18107
|
+
crypto;
|
|
18031
18108
|
/**
|
|
18032
18109
|
* Estimates the gas cost for a solver to fill the given order and returns
|
|
18033
18110
|
* a structured estimate with individual gas components and total costs in
|
|
@@ -18449,6 +18526,7 @@ var OrderStatusChecker = class {
|
|
|
18449
18526
|
constructor(ctx) {
|
|
18450
18527
|
this.ctx = ctx;
|
|
18451
18528
|
}
|
|
18529
|
+
ctx;
|
|
18452
18530
|
/**
|
|
18453
18531
|
* Checks if a V2 order has been filled by reading the commitment storage slot on the destination chain.
|
|
18454
18532
|
*
|
|
@@ -18630,7 +18708,7 @@ var IntentGateway = class _IntentGateway {
|
|
|
18630
18708
|
* The caller must sign the transaction and pass it back via `gen.next(signedTx)`.
|
|
18631
18709
|
* 3. Yields `ORDER_PLACED` with the finalised order and transaction hash once
|
|
18632
18710
|
* the `OrderPlaced` event is confirmed.
|
|
18633
|
-
* 4. Delegates to {@link OrderExecutor.
|
|
18711
|
+
* 4. Delegates to {@link OrderExecutor.executeOrder} and forwards all
|
|
18634
18712
|
* subsequent status updates until the order is filled, exhausted, or fails.
|
|
18635
18713
|
*
|
|
18636
18714
|
* @param order - The order to place and execute. `order.fees` may be 0; it
|
|
@@ -18640,8 +18718,7 @@ var IntentGateway = class _IntentGateway {
|
|
|
18640
18718
|
* @param options - Optional tuning parameters:
|
|
18641
18719
|
* - `maxPriorityFeePerGasBumpPercent` — bump % for the priority fee estimate (default 8).
|
|
18642
18720
|
* - `maxFeePerGasBumpPercent` — bump % for the max fee estimate (default 10).
|
|
18643
|
-
* - `
|
|
18644
|
-
* - `bidTimeoutMs` — how long to poll for bids before giving up (default 60 000 ms).
|
|
18721
|
+
* - `auctionTimeMs` — duration in ms to collect bids before selecting the best one.
|
|
18645
18722
|
* - `pollIntervalMs` — interval between bid-polling attempts.
|
|
18646
18723
|
* @yields {@link IntentOrderStatusUpdate} at each lifecycle stage.
|
|
18647
18724
|
* @throws If the `placeOrder` generator behaves unexpectedly, or if gas
|
|
@@ -18674,18 +18751,63 @@ var IntentGateway = class _IntentGateway {
|
|
|
18674
18751
|
}
|
|
18675
18752
|
const { order: finalizedOrder, receipt: placementReceipt } = placeOrderSecond.value;
|
|
18676
18753
|
yield { status: "ORDER_PLACED", order: finalizedOrder, receipt: placementReceipt };
|
|
18677
|
-
for await (const status of this.orderExecutor.
|
|
18754
|
+
for await (const status of this.orderExecutor.executeOrder({
|
|
18678
18755
|
order: finalizedOrder,
|
|
18679
18756
|
sessionPrivateKey,
|
|
18680
|
-
|
|
18681
|
-
|
|
18682
|
-
|
|
18683
|
-
solver: options?.solver
|
|
18757
|
+
auctionTimeMs: options.auctionTimeMs,
|
|
18758
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
18759
|
+
solver: options.solver
|
|
18684
18760
|
})) {
|
|
18685
18761
|
yield status;
|
|
18686
18762
|
}
|
|
18687
18763
|
return;
|
|
18688
18764
|
}
|
|
18765
|
+
/**
|
|
18766
|
+
* Validates that an order has the minimum fields required for post-placement
|
|
18767
|
+
* resume (i.e. it was previously placed and has an on-chain identity).
|
|
18768
|
+
*
|
|
18769
|
+
* @throws If `order.id` or `order.session` is missing or zero-valued.
|
|
18770
|
+
*/
|
|
18771
|
+
assertOrderCanResume(order) {
|
|
18772
|
+
if (!order.id) {
|
|
18773
|
+
throw new Error("Cannot resume execution without order.id");
|
|
18774
|
+
}
|
|
18775
|
+
if (!order.session || order.session === ADDRESS_ZERO2) {
|
|
18776
|
+
throw new Error("Cannot resume execution without order.session");
|
|
18777
|
+
}
|
|
18778
|
+
}
|
|
18779
|
+
/**
|
|
18780
|
+
* Resumes execution of a previously placed order.
|
|
18781
|
+
*
|
|
18782
|
+
* Use this method after an app restart or crash to pick up where
|
|
18783
|
+
* {@link execute} left off. The order must already be placed on-chain
|
|
18784
|
+
* (i.e. it must have a valid `id` and `session`).
|
|
18785
|
+
*
|
|
18786
|
+
* Internally delegates to {@link OrderExecutor.executeOrder} and
|
|
18787
|
+
* yields the same status updates as the execution phase of {@link execute}:
|
|
18788
|
+
* `AWAITING_BIDS`, `BIDS_RECEIVED`, `BID_SELECTED`,
|
|
18789
|
+
* `FILLED`, `PARTIAL_FILL`, `EXPIRED`, or `FAILED`.
|
|
18790
|
+
*
|
|
18791
|
+
* Callers may check {@link isOrderFilled} or {@link isOrderRefunded} before
|
|
18792
|
+
* calling this method to avoid resuming an already-terminal order.
|
|
18793
|
+
*
|
|
18794
|
+
* @param order - A previously placed order with a valid `id` and `session`.
|
|
18795
|
+
* @param options - Optional tuning parameters for bid collection and execution.
|
|
18796
|
+
* @yields {@link IntentOrderStatusUpdate} at each execution stage.
|
|
18797
|
+
* @throws If the order is missing required fields for resumption.
|
|
18798
|
+
*/
|
|
18799
|
+
async *resume(order, options) {
|
|
18800
|
+
this.assertOrderCanResume(order);
|
|
18801
|
+
for await (const status of this.orderExecutor.executeOrder({
|
|
18802
|
+
order,
|
|
18803
|
+
sessionPrivateKey: options.sessionPrivateKey,
|
|
18804
|
+
auctionTimeMs: options.auctionTimeMs,
|
|
18805
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
18806
|
+
solver: options.solver
|
|
18807
|
+
})) {
|
|
18808
|
+
yield status;
|
|
18809
|
+
}
|
|
18810
|
+
}
|
|
18689
18811
|
/**
|
|
18690
18812
|
* Returns both the native token cost and the relayer fee for cancelling an
|
|
18691
18813
|
* order. Use `relayerFee` to approve the ERC-20 spend before submitting.
|