@invisible-labs/sdk 0.6.0-devnet.3 → 0.6.0-devnet.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/README.md +67 -10
- package/dist/.invisible-sdk-build-target.json +7 -0
- package/dist/{chunk-BWCGNTN5.js → chunk-5NNEO7IK.js} +31 -34
- package/dist/chunk-5NNEO7IK.js.map +1 -0
- package/dist/chunk-BRDLLGCZ.js +59 -0
- package/dist/chunk-BRDLLGCZ.js.map +1 -0
- package/dist/{chunk-NKRVQXRP.js → chunk-E4DCEDAG.js} +121 -11
- package/dist/chunk-E4DCEDAG.js.map +1 -0
- package/dist/{chunk-QQSI3ZD7.js → chunk-UADJCUPK.js} +106 -15
- package/dist/chunk-UADJCUPK.js.map +1 -0
- package/dist/{coordinator-VVJ33WF2.js → coordinator-ZNLGAYXD.js} +3 -3
- package/dist/{coordinator-VVJ33WF2.js.map → coordinator-ZNLGAYXD.js.map} +1 -1
- package/dist/events.js +1 -1
- package/dist/index.d.ts +59 -353
- package/dist/index.js +94 -39
- package/dist/index.js.map +1 -1
- package/dist/lp.d.ts +44 -10
- package/dist/lp.js +211 -71
- package/dist/lp.js.map +1 -1
- package/dist/presets.d.ts +5 -42
- package/dist/presets.js +10 -68
- package/dist/presets.js.map +1 -1
- package/dist/{errors-N2touVm4.d.ts → types.generated-DJBTjLpP.d.ts} +37 -1
- package/dist/user.d.ts +107 -8
- package/dist/user.js +613 -224
- package/dist/user.js.map +1 -1
- package/package.json +2 -31
- package/dist/chunk-BWCGNTN5.js.map +0 -1
- package/dist/chunk-NKRVQXRP.js.map +0 -1
- package/dist/chunk-QQSI3ZD7.js.map +0 -1
- package/dist/types.generated-BSEBz4jR.d.ts +0 -68
package/dist/user.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { scheduledPayoutWindowSeconds } from './chunk-
|
|
2
|
-
import { validatePayoutPolicyShape, formatAjvErrors, createSession, createExponentialBackoff } from './chunk-
|
|
1
|
+
import { scheduledPayoutWindowSeconds } from './chunk-E4DCEDAG.js';
|
|
2
|
+
import { validatePayoutPolicyShape, formatAjvErrors, createSession, createExponentialBackoff } from './chunk-5NNEO7IK.js';
|
|
3
3
|
import { PRODUCT_MAX_ENTRY_LAMPORTS, PRODUCT_MIN_ENTRY_LAMPORTS } from './chunk-4X5OCCQW.js';
|
|
4
4
|
import { assertAttested, publicKey, solanaAddressFromPublicKeyBytes } from './chunk-NHEHCUS5.js';
|
|
5
|
-
import { requestEnvelope, CoordinatorMessageType, onEnvelope, closeProtocolRuntime, EnvelopeKind } from './chunk-
|
|
5
|
+
import { requestEnvelope, CoordinatorMessageType, onEnvelope, closeProtocolRuntime, EnvelopeKind } from './chunk-UADJCUPK.js';
|
|
6
6
|
import { getSessionState } from './chunk-V5HXJRBW.js';
|
|
7
7
|
import './chunk-DIA6U2CV.js';
|
|
8
|
-
import { PolicyValidationError, CommandError, TransportError, InvalidDepositAmountError, normalizeError,
|
|
8
|
+
import { PolicyValidationError, CommandError, TransportError, InvalidDepositAmountError, normalizeError, AttestationError, RoutingError } from './chunk-GHBQF3A7.js';
|
|
9
9
|
export { InvalidDepositAmountError } from './chunk-GHBQF3A7.js';
|
|
10
10
|
import './chunk-VR6T6OJS.js';
|
|
11
11
|
|
|
@@ -171,7 +171,7 @@ function recoveryCodeFromUserInput(input) {
|
|
|
171
171
|
var protocolPromise = null;
|
|
172
172
|
var frostRuntimePromise = null;
|
|
173
173
|
function loadProtocol() {
|
|
174
|
-
protocolPromise ??= import('./coordinator-
|
|
174
|
+
protocolPromise ??= import('./coordinator-ZNLGAYXD.js');
|
|
175
175
|
return protocolPromise;
|
|
176
176
|
}
|
|
177
177
|
function loadFrostRuntime() {
|
|
@@ -185,20 +185,22 @@ var BENIGN_TRANSPORT_DROP = /* @__PURE__ */ Symbol("benignTransportDrop");
|
|
|
185
185
|
var ALICE_ID = 1;
|
|
186
186
|
var COORDINATOR_ID = 2;
|
|
187
187
|
var SYNC_SECRET_BYTE_LENGTH = 32;
|
|
188
|
+
var RESUME_SECRET_BYTE_LENGTH = SYNC_SECRET_BYTE_LENGTH;
|
|
188
189
|
var SYNC_CONTRACT_ID_MISMATCH_MESSAGE = "sync response contract id does not match requested contract";
|
|
189
|
-
var ACTIVE_CONTRACT_REQUEST_MESSAGE = "coordinator session already has an active contract";
|
|
190
190
|
var DEFAULT_SWAP_STATUS_RECONCILE_INTERVAL_MS = 5e3;
|
|
191
191
|
var MAX_SWAP_STATUS_RETRY_DELAY_MS = 3e4;
|
|
192
192
|
var SWAP_STATUS_RETRY_MULTIPLIER = 2;
|
|
193
|
+
var MAX_EVENT_DEDUP_ENTRIES_PER_KIND = 1024;
|
|
193
194
|
var SWAP_STATUS_RETRY_JITTER_RATIO = 0.2;
|
|
194
195
|
var DEFAULT_REFUND_OUTCOME_POLL_BUDGET_MS = 5 * 60 * 1e3;
|
|
195
196
|
var REFUND_OUTCOME_POLL_INTERVAL_MS = 3e3;
|
|
196
197
|
var REFUND_OUTCOME_PER_POLL_TIMEOUT_MS = 5e3;
|
|
198
|
+
var UNBOUND_RECONCILIATION_KEY = "__unbound__";
|
|
197
199
|
var REQUEST_TIMEOUT_MESSAGE = "coordinator request timed out";
|
|
200
|
+
var REFUND_PENDING_FINALIZATION_MESSAGE = "refund accepted and pending finalization; check status again shortly";
|
|
198
201
|
var CURRENT_SCHEDULED_PAYOUT_WINDOW_SECONDS = new Set(scheduledPayoutWindowSeconds());
|
|
199
202
|
var CURRENT_SCHEDULED_PAYOUT_WINDOW_MESSAGE = `scheduled payout_spec.window_seconds must be one of [${scheduledPayoutWindowSeconds().join(", ")}]`;
|
|
200
203
|
var TERMINAL_SWAP_STATES = /* @__PURE__ */ new Set(["completed", "refunded", "failed"]);
|
|
201
|
-
var activeFunctionalContractRequests = /* @__PURE__ */ new WeakSet();
|
|
202
204
|
function isBenignTransportDrop(err) {
|
|
203
205
|
return typeof err === "object" && err !== null && err[BENIGN_TRANSPORT_DROP] === true;
|
|
204
206
|
}
|
|
@@ -227,8 +229,12 @@ var UserCoordinatorSession = class {
|
|
|
227
229
|
this.sessionStatus = "idle";
|
|
228
230
|
this.swapId = null;
|
|
229
231
|
this.syncSecret = null;
|
|
232
|
+
this.resumeSecret = null;
|
|
230
233
|
this.attested = false;
|
|
231
234
|
this.pushListeners = /* @__PURE__ */ new Map();
|
|
235
|
+
this.swapContexts = /* @__PURE__ */ new Map();
|
|
236
|
+
this.openingSession = null;
|
|
237
|
+
this.activeOperations = 0;
|
|
232
238
|
this.stateListeners = /* @__PURE__ */ new Set();
|
|
233
239
|
this.logListeners = /* @__PURE__ */ new Set();
|
|
234
240
|
this.payoutExecutedListeners = /* @__PURE__ */ new Set();
|
|
@@ -237,12 +243,10 @@ var UserCoordinatorSession = class {
|
|
|
237
243
|
this.coordinatorErrorListeners = /* @__PURE__ */ new Set();
|
|
238
244
|
this.emittedPayoutKeys = /* @__PURE__ */ new Set();
|
|
239
245
|
this.emittedRefundKeys = /* @__PURE__ */ new Set();
|
|
240
|
-
this.
|
|
241
|
-
this.bufferDepositConfirmedUntilDelegateAck = false;
|
|
242
|
-
this.bufferedDepositConfirmed = null;
|
|
246
|
+
this.statusReconciliationStops = /* @__PURE__ */ new Map();
|
|
243
247
|
this.coordinator = options.coordinator;
|
|
244
248
|
this.createSessionImpl = options.createSession ?? createSession;
|
|
245
|
-
this.
|
|
249
|
+
this.closeSessionAfterOperationFailure = closeSessionAfterRefund;
|
|
246
250
|
}
|
|
247
251
|
onStateChange(listener) {
|
|
248
252
|
this.stateListeners.add(listener);
|
|
@@ -278,51 +282,226 @@ var UserCoordinatorSession = class {
|
|
|
278
282
|
get currentSwapId() {
|
|
279
283
|
return this.swapId;
|
|
280
284
|
}
|
|
285
|
+
beginOperation() {
|
|
286
|
+
this.activeOperations += 1;
|
|
287
|
+
if (this.activeOperations === 1) this.setSessionStatus("connecting");
|
|
288
|
+
}
|
|
289
|
+
endOperation() {
|
|
290
|
+
this.activeOperations = Math.max(0, this.activeOperations - 1);
|
|
291
|
+
if (this.activeOperations === 0 && this.sessionStatus === "connecting") {
|
|
292
|
+
this.setSessionStatus("idle");
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
ensureSwapContext(swapId, syncSecret, resumeSecret) {
|
|
296
|
+
let context = this.swapContexts.get(swapId);
|
|
297
|
+
if (!context) {
|
|
298
|
+
context = {
|
|
299
|
+
swapId,
|
|
300
|
+
swapState: this.swapId === swapId ? this.swapState : "new",
|
|
301
|
+
syncSecret: this.swapId === swapId && this.syncSecret ? new Uint8Array(this.syncSecret) : null,
|
|
302
|
+
resumeSecret: this.swapId === swapId && this.resumeSecret ? new Uint8Array(this.resumeSecret) : null,
|
|
303
|
+
bufferDepositConfirmedUntilDelegateAck: false,
|
|
304
|
+
bufferedDepositConfirmed: null
|
|
305
|
+
};
|
|
306
|
+
this.swapContexts.set(swapId, context);
|
|
307
|
+
}
|
|
308
|
+
if (syncSecret !== void 0) context.syncSecret = new Uint8Array(syncSecret);
|
|
309
|
+
if (resumeSecret !== void 0) context.resumeSecret = new Uint8Array(resumeSecret);
|
|
310
|
+
this.setCurrentContext(context);
|
|
311
|
+
return context;
|
|
312
|
+
}
|
|
313
|
+
setCurrentContext(context) {
|
|
314
|
+
this.swapId = context.swapId;
|
|
315
|
+
this.swapState = context.swapState;
|
|
316
|
+
this.syncSecret = context.syncSecret ? new Uint8Array(context.syncSecret) : null;
|
|
317
|
+
this.resumeSecret = context.resumeSecret ? new Uint8Array(context.resumeSecret) : null;
|
|
318
|
+
}
|
|
319
|
+
updateContextState(context, state) {
|
|
320
|
+
context.swapState = state;
|
|
321
|
+
if (this.swapId === context.swapId) {
|
|
322
|
+
this.swapState = state;
|
|
323
|
+
}
|
|
324
|
+
this.emitStateChange(context.swapId, state);
|
|
325
|
+
if (TERMINAL_SWAP_STATES.has(state)) {
|
|
326
|
+
this.evictSwapContext(context.swapId);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
evictSwapContext(swapId) {
|
|
330
|
+
this.statusReconciliationStops.get(swapId)?.();
|
|
331
|
+
this.statusReconciliationStops.delete(swapId);
|
|
332
|
+
const context = this.swapContexts.get(swapId);
|
|
333
|
+
if (context) {
|
|
334
|
+
context.syncSecret?.fill(0);
|
|
335
|
+
context.resumeSecret?.fill(0);
|
|
336
|
+
context.bufferedDepositConfirmed = null;
|
|
337
|
+
context.bufferDepositConfirmedUntilDelegateAck = false;
|
|
338
|
+
this.swapContexts.delete(swapId);
|
|
339
|
+
}
|
|
340
|
+
if (this.swapId === swapId) {
|
|
341
|
+
this.syncSecret?.fill(0);
|
|
342
|
+
this.resumeSecret?.fill(0);
|
|
343
|
+
this.syncSecret = null;
|
|
344
|
+
this.resumeSecret = null;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
clearSwapContexts() {
|
|
348
|
+
for (const swapId of this.swapContexts.keys()) this.evictSwapContext(swapId);
|
|
349
|
+
this.swapContexts.clear();
|
|
350
|
+
this.emittedPayoutKeys.clear();
|
|
351
|
+
this.emittedRefundKeys.clear();
|
|
352
|
+
}
|
|
281
353
|
async runSwap(params) {
|
|
282
354
|
assertCurrentUserPayoutSpecRuntimeLimits(params.payoutSpec);
|
|
283
|
-
this.
|
|
284
|
-
this.setSessionStatus("connecting");
|
|
355
|
+
this.beginOperation();
|
|
285
356
|
let completed = false;
|
|
357
|
+
let terminalStatus = null;
|
|
286
358
|
try {
|
|
287
359
|
await ensureFrostWasm();
|
|
288
360
|
await this.openSession();
|
|
289
361
|
this.setSessionStatus("running");
|
|
290
362
|
const result = await this.runProtocol(params);
|
|
291
363
|
completed = true;
|
|
292
|
-
|
|
364
|
+
terminalStatus = "done";
|
|
293
365
|
return result;
|
|
294
366
|
} catch (err) {
|
|
295
367
|
const error = this.normalizeSessionError(err);
|
|
296
368
|
if (!isBenignTransportDrop(error)) {
|
|
297
|
-
|
|
369
|
+
terminalStatus = "failed";
|
|
298
370
|
}
|
|
299
371
|
throw error;
|
|
300
372
|
} finally {
|
|
301
|
-
|
|
373
|
+
this.endOperation();
|
|
374
|
+
if (this.activeOperations === 0 && terminalStatus !== null) {
|
|
375
|
+
this.setSessionStatus(terminalStatus);
|
|
376
|
+
}
|
|
377
|
+
if (!completed && this.activeOperations === 0 && this.closeSessionAfterOperationFailure) {
|
|
302
378
|
this.close();
|
|
303
379
|
}
|
|
304
380
|
}
|
|
305
381
|
}
|
|
306
382
|
async contractRequest(params) {
|
|
307
383
|
assertCurrentUserPayoutSpecRuntimeLimits(params.payoutSpec);
|
|
308
|
-
this.
|
|
309
|
-
|
|
384
|
+
this.beginOperation();
|
|
385
|
+
let completed = false;
|
|
386
|
+
let terminalStatus = null;
|
|
310
387
|
try {
|
|
311
388
|
await ensureFrostWasm();
|
|
312
389
|
await this.openSession();
|
|
313
390
|
this.setSessionStatus("running");
|
|
314
391
|
const prepared = await this.prepareContract(params);
|
|
392
|
+
completed = true;
|
|
393
|
+
terminalStatus = "done";
|
|
315
394
|
return toContractRequestResult(prepared);
|
|
316
395
|
} catch (err) {
|
|
317
396
|
const error = this.normalizeSessionError(err);
|
|
318
|
-
|
|
397
|
+
terminalStatus = "failed";
|
|
319
398
|
throw error;
|
|
399
|
+
} finally {
|
|
400
|
+
this.endOperation();
|
|
401
|
+
if (this.activeOperations === 0 && terminalStatus !== null) {
|
|
402
|
+
this.setSessionStatus(terminalStatus);
|
|
403
|
+
}
|
|
404
|
+
if (!completed && this.activeOperations === 0 && this.closeSessionAfterOperationFailure) {
|
|
405
|
+
this.close();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
async resumePreDelegation(params) {
|
|
410
|
+
if (!params.policySnapshot) {
|
|
411
|
+
throw new CommandError(
|
|
412
|
+
"REJECTED_GUARD",
|
|
413
|
+
"policySnapshot is required to resume pre-delegation"
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
if (params.recoveryCommitment.length !== SYNC_SECRET_BYTE_LENGTH) {
|
|
417
|
+
throw new CommandError(
|
|
418
|
+
"REJECTED_GUARD",
|
|
419
|
+
`recoveryCommitment must be ${SYNC_SECRET_BYTE_LENGTH} bytes`
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
this.beginOperation();
|
|
423
|
+
let completed = false;
|
|
424
|
+
let terminalStatus = null;
|
|
425
|
+
try {
|
|
426
|
+
await ensureFrostWasm();
|
|
427
|
+
this.restoreSwapContext({
|
|
428
|
+
swapId: params.swapId,
|
|
429
|
+
syncSecret: params.syncSecret,
|
|
430
|
+
resumeSecret: params.resumeSecret
|
|
431
|
+
});
|
|
432
|
+
await this.openSession();
|
|
433
|
+
this.setSessionStatus("running");
|
|
434
|
+
const context = this.ensureSwapContext(params.swapId);
|
|
435
|
+
context.swapState = params.delegateShare ? "awaiting_deposit" : "awaiting_dkg";
|
|
436
|
+
this.setCurrentContext(context);
|
|
437
|
+
let jointPublicKey;
|
|
438
|
+
let depositExpiresAtMs;
|
|
439
|
+
let coordinatorTimestampMs;
|
|
440
|
+
let delegateShare = params.delegateShare ? new Uint8Array(params.delegateShare) : void 0;
|
|
441
|
+
if (!delegateShare) {
|
|
442
|
+
const dkg = await this.runDkg(context, params.onDelegateShareReady);
|
|
443
|
+
jointPublicKey = dkg.jointPublicKey;
|
|
444
|
+
depositExpiresAtMs = dkg.depositExpiresAtMs;
|
|
445
|
+
coordinatorTimestampMs = dkg.coordinatorTimestampMs;
|
|
446
|
+
delegateShare = dkg.keyHandle.secretShareBytes();
|
|
447
|
+
this.updateContextState(context, "awaiting_deposit");
|
|
448
|
+
}
|
|
449
|
+
const delegateAckPromise = this.awaitPush(CoordinatorMessageType.DelegateAck, context.swapId);
|
|
450
|
+
let delegateResp;
|
|
451
|
+
try {
|
|
452
|
+
delegateResp = await this.request(
|
|
453
|
+
CoordinatorMessageType.DelegateShare,
|
|
454
|
+
{
|
|
455
|
+
share: delegateShare,
|
|
456
|
+
recovery_commitment: new Uint8Array(params.recoveryCommitment),
|
|
457
|
+
resume_secret: context.resumeSecret
|
|
458
|
+
},
|
|
459
|
+
{ swapId: context.swapId }
|
|
460
|
+
);
|
|
461
|
+
} catch (err) {
|
|
462
|
+
void delegateAckPromise.catch(() => void 0);
|
|
463
|
+
throw err;
|
|
464
|
+
}
|
|
465
|
+
const delegatedAtMs = this.requireProtocol().asDelegateShareResponsePayload(delegateResp).delegated_at_ms;
|
|
466
|
+
const delegateAck = this.requireProtocol().asDelegateAckPayload(await delegateAckPromise);
|
|
467
|
+
if (delegateAck.delegated_at_ms !== delegatedAtMs) {
|
|
468
|
+
throw new CommandError(
|
|
469
|
+
"REJECTED_GUARD",
|
|
470
|
+
"DelegateAck delegated_at_ms does not match DelegateShare response"
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
if (!spendingPoliciesEqual(delegateAck.spending_policy, params.policySnapshot)) {
|
|
474
|
+
throw new CommandError(
|
|
475
|
+
"REJECTED_GUARD",
|
|
476
|
+
"DelegateAck spending_policy does not match persisted policy_snapshot"
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
context.bufferDepositConfirmedUntilDelegateAck = false;
|
|
480
|
+
this.updateContextState(context, "awaiting_deposit");
|
|
481
|
+
completed = true;
|
|
482
|
+
terminalStatus = "done";
|
|
483
|
+
return {
|
|
484
|
+
swapId: context.swapId,
|
|
485
|
+
jointPublicKey,
|
|
486
|
+
depositExpiresAtMs,
|
|
487
|
+
coordinatorTimestampMs,
|
|
488
|
+
delegatedAtMs
|
|
489
|
+
};
|
|
490
|
+
} catch (err) {
|
|
491
|
+
terminalStatus = "failed";
|
|
492
|
+
throw this.normalizeSessionError(err);
|
|
493
|
+
} finally {
|
|
494
|
+
if (!completed) this.cancelPushWaitersForSwap(params.swapId);
|
|
495
|
+
this.endOperation();
|
|
496
|
+
if (this.activeOperations === 0 && terminalStatus !== null) {
|
|
497
|
+
this.setSessionStatus(terminalStatus);
|
|
498
|
+
}
|
|
320
499
|
}
|
|
321
500
|
}
|
|
322
501
|
/** @internal Used by the functional Session API without closing its caller-owned session. */
|
|
323
502
|
releaseWithoutClosing() {
|
|
324
|
-
this.
|
|
325
|
-
this.
|
|
503
|
+
this.stopAllStatusReconciliations();
|
|
504
|
+
this.clearSwapContexts();
|
|
326
505
|
this.detachSession(
|
|
327
506
|
new TransportError("CONNECTION_LOST", "coordinator session operation released"),
|
|
328
507
|
false,
|
|
@@ -330,12 +509,15 @@ var UserCoordinatorSession = class {
|
|
|
330
509
|
);
|
|
331
510
|
}
|
|
332
511
|
close() {
|
|
333
|
-
this.
|
|
334
|
-
this.
|
|
512
|
+
this.stopAllStatusReconciliations();
|
|
513
|
+
this.clearSwapContexts();
|
|
335
514
|
this.detachSession(new TransportError("CONNECTION_LOST", "coordinator session closed"), true);
|
|
336
515
|
}
|
|
516
|
+
stopAllStatusReconciliations() {
|
|
517
|
+
for (const stop of [...this.statusReconciliationStops.values()]) stop();
|
|
518
|
+
this.statusReconciliationStops.clear();
|
|
519
|
+
}
|
|
337
520
|
restoreSwapContext(params) {
|
|
338
|
-
this.swapId = params.swapId;
|
|
339
521
|
if (params.syncSecret !== void 0) {
|
|
340
522
|
if (params.syncSecret.length !== SYNC_SECRET_BYTE_LENGTH) {
|
|
341
523
|
throw new CommandError(
|
|
@@ -343,28 +525,46 @@ var UserCoordinatorSession = class {
|
|
|
343
525
|
`syncSecret must be ${SYNC_SECRET_BYTE_LENGTH} bytes`
|
|
344
526
|
);
|
|
345
527
|
}
|
|
346
|
-
this.syncSecret = new Uint8Array(params.syncSecret);
|
|
347
528
|
}
|
|
529
|
+
if (params.resumeSecret !== void 0) {
|
|
530
|
+
if (params.resumeSecret.length !== RESUME_SECRET_BYTE_LENGTH) {
|
|
531
|
+
throw new CommandError(
|
|
532
|
+
"REJECTED_GUARD",
|
|
533
|
+
`resumeSecret must be ${RESUME_SECRET_BYTE_LENGTH} bytes`
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
this.ensureSwapContext(params.swapId, params.syncSecret, params.resumeSecret);
|
|
348
538
|
}
|
|
349
539
|
async requestSwapStatus(timeoutMs) {
|
|
350
540
|
if (!this.swapId) {
|
|
351
541
|
throw new CommandError("REJECTED_STATE", "Sync requires swapId");
|
|
352
542
|
}
|
|
543
|
+
const context = this.ensureSwapContext(this.swapId, this.syncSecret ?? void 0);
|
|
544
|
+
return this.requestSwapStatusForContext(context, timeoutMs);
|
|
545
|
+
}
|
|
546
|
+
async requestSwapStatusForContext(context, timeoutMs) {
|
|
353
547
|
await this.openSession();
|
|
354
548
|
const env = await this.request(
|
|
355
549
|
CoordinatorMessageType.Sync,
|
|
356
550
|
{
|
|
357
551
|
actor: "user",
|
|
358
|
-
...
|
|
552
|
+
...context.syncSecret ? { sync_secret: context.syncSecret } : {}
|
|
359
553
|
},
|
|
360
|
-
|
|
554
|
+
{
|
|
555
|
+
swapId: context.swapId,
|
|
556
|
+
timeoutMs,
|
|
557
|
+
rejectMatchingOutOfBandErrors: true
|
|
558
|
+
}
|
|
361
559
|
);
|
|
362
560
|
const status = this.requireProtocol().asSyncUserResponsePayload(env);
|
|
363
|
-
this.applySwapStatus(status, env.timestamp_ms);
|
|
561
|
+
this.applySwapStatus(context, status, env.timestamp_ms);
|
|
364
562
|
return status;
|
|
365
563
|
}
|
|
366
564
|
startSwapStatusReconciliation(intervalMs = DEFAULT_SWAP_STATUS_RECONCILE_INTERVAL_MS) {
|
|
367
|
-
this.
|
|
565
|
+
const reconciliationContext = this.swapId ? this.ensureSwapContext(this.swapId, this.syncSecret ?? void 0) : null;
|
|
566
|
+
const reconciliationKey = reconciliationContext?.swapId ?? UNBOUND_RECONCILIATION_KEY;
|
|
567
|
+
this.statusReconciliationStops.get(reconciliationKey)?.();
|
|
368
568
|
let stopped = false;
|
|
369
569
|
let reconciling = false;
|
|
370
570
|
let timer = null;
|
|
@@ -389,20 +589,18 @@ var UserCoordinatorSession = class {
|
|
|
389
589
|
if (stopped || reconciling || !isVisible()) return;
|
|
390
590
|
reconciling = true;
|
|
391
591
|
try {
|
|
392
|
-
const status = await this.requestSwapStatus();
|
|
592
|
+
const status = reconciliationContext ? await this.requestSwapStatusForContext(reconciliationContext) : await this.requestSwapStatus();
|
|
393
593
|
retryBackoff.reset();
|
|
394
594
|
if (status.state === "completed" || status.state === "refunded" || status.state === "failed") {
|
|
395
|
-
|
|
396
|
-
if (timer) clearTimeout(timer);
|
|
595
|
+
stopReconciliation();
|
|
397
596
|
} else {
|
|
398
597
|
schedule(intervalMs);
|
|
399
598
|
}
|
|
400
599
|
} catch (err) {
|
|
401
600
|
this.log(`SwapStatus reconcile failed: ${normalizeError(err)}`, "info");
|
|
402
601
|
if (!isRetryableSwapStatusReconciliationError(err)) {
|
|
403
|
-
|
|
404
|
-
if (
|
|
405
|
-
this.close();
|
|
602
|
+
stopReconciliation();
|
|
603
|
+
if (err instanceof AttestationError) this.close();
|
|
406
604
|
return;
|
|
407
605
|
}
|
|
408
606
|
schedule(retryBackoff.nextDelayMs());
|
|
@@ -438,7 +636,8 @@ var UserCoordinatorSession = class {
|
|
|
438
636
|
browserDocument?.addEventListener("freeze", handleFreeze);
|
|
439
637
|
browserDocument?.addEventListener("resume", reconcileWhenVisible);
|
|
440
638
|
reconcileWhenVisible();
|
|
441
|
-
|
|
639
|
+
const stopReconciliation = () => {
|
|
640
|
+
if (stopped) return;
|
|
442
641
|
stopped = true;
|
|
443
642
|
if (timer) clearTimeout(timer);
|
|
444
643
|
browserWindow?.removeEventListener("focus", reconcileWhenVisible);
|
|
@@ -447,8 +646,12 @@ var UserCoordinatorSession = class {
|
|
|
447
646
|
browserDocument?.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
448
647
|
browserDocument?.removeEventListener("freeze", handleFreeze);
|
|
449
648
|
browserDocument?.removeEventListener("resume", reconcileWhenVisible);
|
|
649
|
+
if (this.statusReconciliationStops.get(reconciliationKey) === stopReconciliation) {
|
|
650
|
+
this.statusReconciliationStops.delete(reconciliationKey);
|
|
651
|
+
}
|
|
450
652
|
};
|
|
451
|
-
|
|
653
|
+
this.statusReconciliationStops.set(reconciliationKey, stopReconciliation);
|
|
654
|
+
return stopReconciliation;
|
|
452
655
|
}
|
|
453
656
|
async requestRefund(params) {
|
|
454
657
|
const result = await this.requestRefundIntentInternal(params, { waitForFinality: true });
|
|
@@ -460,9 +663,10 @@ var UserCoordinatorSession = class {
|
|
|
460
663
|
}
|
|
461
664
|
async requestRefundIntentInternal(params, options) {
|
|
462
665
|
assertRecoveryCode(params.recoveryCode);
|
|
666
|
+
this.beginOperation();
|
|
463
667
|
const recoveryCode = new Uint8Array(params.recoveryCode);
|
|
464
668
|
const ackTimeout = params.timeoutMs ?? 3e4;
|
|
465
|
-
let
|
|
669
|
+
let requestSwapId = params.swapId ?? null;
|
|
466
670
|
let openedForRefund = false;
|
|
467
671
|
try {
|
|
468
672
|
if (params.syncSecret !== void 0) {
|
|
@@ -471,33 +675,36 @@ var UserCoordinatorSession = class {
|
|
|
471
675
|
throw new CommandError("REJECTED_STATE", "syncSecret requires swapId");
|
|
472
676
|
}
|
|
473
677
|
this.restoreSwapContext({ swapId, syncSecret: params.syncSecret });
|
|
678
|
+
requestSwapId = swapId;
|
|
474
679
|
} else if (params.swapId) {
|
|
475
680
|
const swapId = params.swapId;
|
|
476
681
|
this.restoreSwapContext({ swapId });
|
|
682
|
+
requestSwapId = swapId;
|
|
477
683
|
}
|
|
478
684
|
openedForRefund = !this.hasUsableSession();
|
|
479
685
|
await this.openSession();
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
686
|
+
let env;
|
|
687
|
+
try {
|
|
688
|
+
env = await this.request(
|
|
689
|
+
CoordinatorMessageType.WithdrawRequest,
|
|
690
|
+
{
|
|
691
|
+
recovery_code: recoveryCode
|
|
692
|
+
},
|
|
693
|
+
{ swapId: requestSwapId, timeoutMs: ackTimeout }
|
|
694
|
+
);
|
|
695
|
+
} catch (err) {
|
|
696
|
+
if (isRequestTimeoutError(err)) {
|
|
697
|
+
throw new CommandError(
|
|
698
|
+
"REJECTED_STALE_JOB",
|
|
699
|
+
`WithdrawRequest acknowledgement timed out after ${ackTimeout}ms`
|
|
493
700
|
);
|
|
494
|
-
})
|
|
495
|
-
]);
|
|
496
|
-
if (ackTimer) clearTimeout(ackTimer);
|
|
497
|
-
if (env.type === CoordinatorMessageType.WithdrawExecuted) {
|
|
498
|
-
if (env.swap_id && !this.swapId) {
|
|
499
|
-
this.swapId = env.swap_id;
|
|
500
701
|
}
|
|
702
|
+
throw err;
|
|
703
|
+
}
|
|
704
|
+
if (env.type === CoordinatorMessageType.WithdrawExecuted) {
|
|
705
|
+
const resolvedSwapId2 = env.swap_id ?? requestSwapId;
|
|
706
|
+
const resolvedContext2 = resolvedSwapId2 ? this.ensureSwapContext(resolvedSwapId2) : null;
|
|
707
|
+
if (resolvedContext2) this.setCurrentContext(resolvedContext2);
|
|
501
708
|
return { kind: "executed", refund: this.requireProtocol().asWithdrawExecutedPayload(env) };
|
|
502
709
|
}
|
|
503
710
|
if (env.type !== CoordinatorMessageType.WithdrawAccepted) {
|
|
@@ -506,29 +713,32 @@ var UserCoordinatorSession = class {
|
|
|
506
713
|
`Expected WithdrawAccepted or WithdrawExecuted response, got ${env.type}`
|
|
507
714
|
);
|
|
508
715
|
}
|
|
509
|
-
if (env.swap_id && !this.swapId) {
|
|
510
|
-
this.swapId = env.swap_id;
|
|
511
|
-
}
|
|
512
716
|
const accepted = this.requireProtocol().asWithdrawAcceptedPayload(env);
|
|
717
|
+
const resolvedSwapId = env.swap_id ?? requestSwapId;
|
|
718
|
+
const resolvedContext = resolvedSwapId ? this.ensureSwapContext(resolvedSwapId) : null;
|
|
513
719
|
if (!options.waitForFinality) {
|
|
514
720
|
return { kind: "accepted", accepted };
|
|
515
721
|
}
|
|
516
|
-
if (!
|
|
517
|
-
throw new CommandError(
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
);
|
|
722
|
+
if (!resolvedContext) {
|
|
723
|
+
throw new CommandError("REJECTED_STALE_JOB", REFUND_PENDING_FINALIZATION_MESSAGE);
|
|
724
|
+
}
|
|
725
|
+
if (!resolvedContext.syncSecret) {
|
|
726
|
+
throw new CommandError("REJECTED_STALE_JOB", REFUND_PENDING_FINALIZATION_MESSAGE);
|
|
521
727
|
}
|
|
522
|
-
|
|
728
|
+
this.setCurrentContext(resolvedContext);
|
|
729
|
+
return {
|
|
730
|
+
kind: "executed",
|
|
731
|
+
refund: await this.awaitRefundOutcomeFromSwapStatus(resolvedContext)
|
|
732
|
+
};
|
|
523
733
|
} finally {
|
|
524
|
-
if (ackTimer) clearTimeout(ackTimer);
|
|
525
734
|
recoveryCode.fill(0);
|
|
526
|
-
|
|
735
|
+
this.endOperation();
|
|
736
|
+
if (openedForRefund && this.closeSessionAfterOperationFailure && this.activeOperations === 0) {
|
|
527
737
|
this.close();
|
|
528
738
|
}
|
|
529
739
|
}
|
|
530
740
|
}
|
|
531
|
-
async awaitRefundOutcomeFromSwapStatus() {
|
|
741
|
+
async awaitRefundOutcomeFromSwapStatus(context) {
|
|
532
742
|
const deadline = Date.now() + DEFAULT_REFUND_OUTCOME_POLL_BUDGET_MS;
|
|
533
743
|
for (; ; ) {
|
|
534
744
|
const perPollTimeout = Math.min(
|
|
@@ -536,7 +746,7 @@ var UserCoordinatorSession = class {
|
|
|
536
746
|
Math.max(0, deadline - Date.now())
|
|
537
747
|
);
|
|
538
748
|
try {
|
|
539
|
-
const status = await this.
|
|
749
|
+
const status = await this.requestSwapStatusForContext(context, perPollTimeout);
|
|
540
750
|
if (status.withdraw_execution) {
|
|
541
751
|
return status.withdraw_execution;
|
|
542
752
|
}
|
|
@@ -546,10 +756,7 @@ var UserCoordinatorSession = class {
|
|
|
546
756
|
}
|
|
547
757
|
}
|
|
548
758
|
if (Date.now() >= deadline) {
|
|
549
|
-
throw new CommandError(
|
|
550
|
-
"REJECTED_STALE_JOB",
|
|
551
|
-
"refund accepted and pending finalization; check status again shortly"
|
|
552
|
-
);
|
|
759
|
+
throw new CommandError("REJECTED_STALE_JOB", REFUND_PENDING_FINALIZATION_MESSAGE);
|
|
553
760
|
}
|
|
554
761
|
await delay(REFUND_OUTCOME_POLL_INTERVAL_MS);
|
|
555
762
|
}
|
|
@@ -570,13 +777,19 @@ var UserCoordinatorSession = class {
|
|
|
570
777
|
"in"
|
|
571
778
|
);
|
|
572
779
|
await params.onDepositConfirmed?.({ originAddress: depositPayload.origin_address });
|
|
573
|
-
|
|
780
|
+
const context = this.swapContexts.get(prepared.swapId);
|
|
781
|
+
if (!context) {
|
|
782
|
+
throw new CommandError("REJECTED_STATE", `missing client context for ${prepared.swapId}`);
|
|
783
|
+
}
|
|
784
|
+
await this.requestSwapStatusForContext(context);
|
|
574
785
|
return {
|
|
575
786
|
swapId: prepared.swapId,
|
|
576
787
|
jointPublicKey: prepared.jointPublicKey,
|
|
577
788
|
depositTxSignature: depositPayload.tx_signature,
|
|
578
789
|
depositObservedAtMs: depositPayload.observed_at_ms,
|
|
579
790
|
delegatedAtMs: prepared.delegatedAtMs,
|
|
791
|
+
resumeSecret: new Uint8Array(prepared.resumeSecret),
|
|
792
|
+
resumeSecretHex: prepared.resumeSecretHex,
|
|
580
793
|
recoveryCodeHex: prepared.recoveryCodeHex,
|
|
581
794
|
policySnapshot: prepared.policySnapshot,
|
|
582
795
|
delegatePolicySnapshot: prepared.delegatePolicySnapshot
|
|
@@ -587,6 +800,7 @@ var UserCoordinatorSession = class {
|
|
|
587
800
|
const requestedPayoutWindowMs = params.payoutWindowMs ?? payoutWindowMsFromSpec(params.payoutSpec);
|
|
588
801
|
const payoutDeadlineMs = requestedPayoutWindowMs !== void 0 ? Date.now() + requestedPayoutWindowMs : void 0;
|
|
589
802
|
let generatedSyncSecret = null;
|
|
803
|
+
let generatedResumeSecret = null;
|
|
590
804
|
const syncSecret = params.syncSecret ? new Uint8Array(params.syncSecret) : (() => {
|
|
591
805
|
generatedSyncSecret = randomSecret32();
|
|
592
806
|
return generatedSyncSecret;
|
|
@@ -597,105 +811,165 @@ var UserCoordinatorSession = class {
|
|
|
597
811
|
`syncSecret must be ${SYNC_SECRET_BYTE_LENGTH} bytes`
|
|
598
812
|
);
|
|
599
813
|
}
|
|
600
|
-
this.syncSecret = new Uint8Array(syncSecret);
|
|
601
814
|
const syncSecretHex = bytesToHex(syncSecret);
|
|
602
815
|
const syncCommitment = await sha256Commitment(syncSecret);
|
|
603
816
|
if (generatedSyncSecret) {
|
|
604
817
|
await params.onSyncSecretReady?.({ secretHex: syncSecretHex });
|
|
605
818
|
}
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
...(params.payoutDeadlineMs !== void 0 || payoutDeadlineMs !== void 0) && {
|
|
612
|
-
payout_deadline_ms: params.payoutDeadlineMs ?? payoutDeadlineMs
|
|
613
|
-
}
|
|
614
|
-
});
|
|
615
|
-
const swapPayload = protocol.asSwapRequestResponsePayload(swapResp);
|
|
616
|
-
const swapId = swapPayload.swap_id;
|
|
617
|
-
this.swapId = swapId;
|
|
618
|
-
params.onPolicySnapshot?.(swapPayload.policy_snapshot);
|
|
619
|
-
this.log(`swap accepted - id=${swapId}`, "in");
|
|
620
|
-
this.bufferDepositConfirmedUntilDelegateAck = true;
|
|
621
|
-
this.bufferedDepositConfirmed = null;
|
|
622
|
-
const depositConfirmedPromise = this.awaitPush(CoordinatorMessageType.DepositConfirmed, null);
|
|
623
|
-
void depositConfirmedPromise.catch(() => void 0);
|
|
624
|
-
const { jointPublicKey, keyHandle, depositExpiresAtMs, coordinatorTimestampMs } = await this.runDkg();
|
|
625
|
-
let recoveryCommitment = params.recoveryCommitment;
|
|
626
|
-
let recoveryCodeHex;
|
|
627
|
-
if (!recoveryCommitment) {
|
|
628
|
-
const generated = await generateRecoveryCode();
|
|
629
|
-
recoveryCommitment = generated.commitment;
|
|
630
|
-
try {
|
|
631
|
-
recoveryCodeHex = recoveryCodeToHex(generated.code);
|
|
632
|
-
await params.onRecoveryCodeReady?.({ codeHex: recoveryCodeHex });
|
|
633
|
-
} finally {
|
|
634
|
-
generated.code.fill(0);
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
const delegateAckPromise = this.awaitPush(CoordinatorMessageType.DelegateAck);
|
|
638
|
-
const share = params.delegateShare ?? keyHandle.secretShareBytes();
|
|
639
|
-
let delegateResp;
|
|
640
|
-
try {
|
|
641
|
-
delegateResp = await this.request(CoordinatorMessageType.DelegateShare, {
|
|
642
|
-
share,
|
|
643
|
-
recovery_commitment: recoveryCommitment
|
|
644
|
-
});
|
|
645
|
-
} catch (err) {
|
|
646
|
-
void delegateAckPromise.catch(() => void 0);
|
|
647
|
-
throw err;
|
|
648
|
-
}
|
|
649
|
-
const delegatePayload = protocol.asDelegateShareResponsePayload(delegateResp);
|
|
650
|
-
const delegateAck = protocol.asDelegateAckPayload(await delegateAckPromise);
|
|
651
|
-
if (delegateAck.delegated_at_ms !== delegatePayload.delegated_at_ms) {
|
|
819
|
+
const resumeSecret = params.resumeSecret ? new Uint8Array(params.resumeSecret) : (() => {
|
|
820
|
+
generatedResumeSecret = randomSecret32();
|
|
821
|
+
return generatedResumeSecret;
|
|
822
|
+
})();
|
|
823
|
+
if (resumeSecret.length !== RESUME_SECRET_BYTE_LENGTH) {
|
|
652
824
|
throw new CommandError(
|
|
653
825
|
"REJECTED_GUARD",
|
|
654
|
-
|
|
826
|
+
`resumeSecret must be ${RESUME_SECRET_BYTE_LENGTH} bytes`
|
|
655
827
|
);
|
|
656
828
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
);
|
|
829
|
+
const resumeSecretHex = bytesToHex(resumeSecret);
|
|
830
|
+
const resumeCommitment = await sha256Commitment(resumeSecret);
|
|
831
|
+
if (generatedResumeSecret) {
|
|
832
|
+
await params.onResumeSecretReady?.({ secretHex: resumeSecretHex });
|
|
662
833
|
}
|
|
663
|
-
this.
|
|
664
|
-
|
|
665
|
-
|
|
834
|
+
const swapResp = await this.request(
|
|
835
|
+
CoordinatorMessageType.ContractRequest,
|
|
836
|
+
{
|
|
837
|
+
actor: "user",
|
|
838
|
+
amount_lamports: params.amountLamports,
|
|
839
|
+
payout_spec: params.payoutSpec,
|
|
840
|
+
sync_commitment: syncCommitment,
|
|
841
|
+
resume_commitment: resumeCommitment,
|
|
842
|
+
...(params.payoutDeadlineMs !== void 0 || payoutDeadlineMs !== void 0) && {
|
|
843
|
+
payout_deadline_ms: params.payoutDeadlineMs ?? payoutDeadlineMs
|
|
844
|
+
}
|
|
845
|
+
},
|
|
846
|
+
{ swapId: null, requireNonNullResponseSwapId: true }
|
|
847
|
+
);
|
|
848
|
+
const swapPayload = protocol.asSwapRequestResponsePayload(swapResp);
|
|
849
|
+
const swapId = swapPayload.swap_id;
|
|
850
|
+
const context = {
|
|
666
851
|
swapId,
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
852
|
+
swapState: "awaiting_dkg",
|
|
853
|
+
syncSecret: new Uint8Array(syncSecret),
|
|
854
|
+
resumeSecret: new Uint8Array(resumeSecret),
|
|
855
|
+
bufferDepositConfirmedUntilDelegateAck: true,
|
|
856
|
+
bufferedDepositConfirmed: null
|
|
857
|
+
};
|
|
858
|
+
this.swapContexts.set(swapId, context);
|
|
859
|
+
this.setCurrentContext(context);
|
|
860
|
+
await params.onSwapAllocated?.({
|
|
674
861
|
swapId,
|
|
675
|
-
amountLamports: params.amountLamports,
|
|
676
|
-
jointPublicKey,
|
|
677
|
-
depositExpiresAtMs,
|
|
678
|
-
coordinatorTimestampMs,
|
|
679
|
-
delegatedAtMs: delegateAck.delegated_at_ms,
|
|
680
|
-
syncSecret,
|
|
681
862
|
syncSecretHex,
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
863
|
+
resumeSecretHex
|
|
864
|
+
});
|
|
865
|
+
params.onPolicySnapshot?.(swapPayload.policy_snapshot);
|
|
866
|
+
this.log(`swap accepted - id=${swapId}`, "in");
|
|
867
|
+
let preparedSuccessfully = false;
|
|
868
|
+
try {
|
|
869
|
+
const depositConfirmedPromise = this.awaitPush(
|
|
870
|
+
CoordinatorMessageType.DepositConfirmed,
|
|
871
|
+
context.swapId,
|
|
872
|
+
null
|
|
873
|
+
);
|
|
874
|
+
void depositConfirmedPromise.catch(() => void 0);
|
|
875
|
+
const { jointPublicKey, keyHandle, depositExpiresAtMs, coordinatorTimestampMs } = await this.runDkg(context, params.delegateShare ? void 0 : params.onDelegateShareReady);
|
|
876
|
+
this.updateContextState(context, "awaiting_deposit");
|
|
877
|
+
let recoveryCommitment = params.recoveryCommitment;
|
|
878
|
+
let recoveryCodeHex;
|
|
879
|
+
if (!recoveryCommitment) {
|
|
880
|
+
const generated = await generateRecoveryCode();
|
|
881
|
+
recoveryCommitment = generated.commitment;
|
|
882
|
+
try {
|
|
883
|
+
recoveryCodeHex = recoveryCodeToHex(generated.code);
|
|
884
|
+
await params.onRecoveryCodeReady?.({ codeHex: recoveryCodeHex });
|
|
885
|
+
} finally {
|
|
886
|
+
generated.code.fill(0);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
const delegateAckPromise = this.awaitPush(CoordinatorMessageType.DelegateAck, context.swapId);
|
|
890
|
+
const share = params.delegateShare ?? keyHandle.secretShareBytes();
|
|
891
|
+
let delegateResp;
|
|
892
|
+
try {
|
|
893
|
+
delegateResp = await this.request(
|
|
894
|
+
CoordinatorMessageType.DelegateShare,
|
|
895
|
+
{
|
|
896
|
+
share,
|
|
897
|
+
recovery_commitment: recoveryCommitment,
|
|
898
|
+
resume_secret: context.resumeSecret
|
|
899
|
+
},
|
|
900
|
+
{ swapId: context.swapId }
|
|
901
|
+
);
|
|
902
|
+
} catch (err) {
|
|
903
|
+
void delegateAckPromise.catch(() => void 0);
|
|
904
|
+
throw err;
|
|
905
|
+
}
|
|
906
|
+
const delegatePayload = protocol.asDelegateShareResponsePayload(delegateResp);
|
|
907
|
+
const delegateAck = protocol.asDelegateAckPayload(await delegateAckPromise);
|
|
908
|
+
if (delegateAck.delegated_at_ms !== delegatePayload.delegated_at_ms) {
|
|
909
|
+
throw new CommandError(
|
|
910
|
+
"REJECTED_GUARD",
|
|
911
|
+
"DelegateAck delegated_at_ms does not match DelegateShare response"
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
if (!spendingPoliciesEqual(delegateAck.spending_policy, swapPayload.policy_snapshot)) {
|
|
915
|
+
throw new CommandError(
|
|
916
|
+
"REJECTED_GUARD",
|
|
917
|
+
"DelegateAck spending_policy does not match ContractRequest policy_snapshot"
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
this.log(`delegated at ${delegateAck.delegated_at_ms}`, "in");
|
|
921
|
+
this.releaseDepositConfirmedGate(context);
|
|
922
|
+
await params.onDepositAddressReady?.({
|
|
923
|
+
swapId,
|
|
924
|
+
jointPublicKey,
|
|
925
|
+
amountLamports: params.amountLamports,
|
|
926
|
+
depositExpiresAtMs,
|
|
927
|
+
coordinatorTimestampMs
|
|
928
|
+
});
|
|
929
|
+
preparedSuccessfully = true;
|
|
930
|
+
return {
|
|
931
|
+
requestId: swapId,
|
|
932
|
+
swapId,
|
|
933
|
+
amountLamports: params.amountLamports,
|
|
934
|
+
jointPublicKey,
|
|
935
|
+
depositExpiresAtMs,
|
|
936
|
+
coordinatorTimestampMs,
|
|
937
|
+
delegatedAtMs: delegateAck.delegated_at_ms,
|
|
938
|
+
syncSecret,
|
|
939
|
+
syncSecretHex,
|
|
940
|
+
resumeSecret,
|
|
941
|
+
resumeSecretHex,
|
|
942
|
+
recoveryCodeHex,
|
|
943
|
+
policySnapshot: swapPayload.policy_snapshot,
|
|
944
|
+
delegatePolicySnapshot: delegateAck.spending_policy,
|
|
945
|
+
depositConfirmedPromise
|
|
946
|
+
};
|
|
947
|
+
} finally {
|
|
948
|
+
if (!preparedSuccessfully) {
|
|
949
|
+
this.cancelPushWaitersForSwap(context.swapId);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
687
952
|
}
|
|
688
|
-
async runDkg() {
|
|
953
|
+
async runDkg(context, onDelegateShareReady) {
|
|
689
954
|
await ensureFrostWasm();
|
|
690
955
|
const protocol = this.requireProtocol();
|
|
691
956
|
const { dkgRound1 } = await loadFrost();
|
|
692
|
-
await this.request(
|
|
957
|
+
await this.request(
|
|
958
|
+
CoordinatorMessageType.DkgInit,
|
|
959
|
+
{ resume_secret: context.resumeSecret },
|
|
960
|
+
{ swapId: context.swapId }
|
|
961
|
+
);
|
|
693
962
|
this.log("DKG initialised", "info");
|
|
694
963
|
const aliceRound1State = dkgRound1(ALICE_ID);
|
|
695
964
|
const aliceRound1Bytes = aliceRound1State.round1PackageBytes();
|
|
696
|
-
const round1Resp = await this.request(
|
|
697
|
-
|
|
698
|
-
|
|
965
|
+
const round1Resp = await this.request(
|
|
966
|
+
CoordinatorMessageType.DkgRound1,
|
|
967
|
+
{
|
|
968
|
+
package: aliceRound1Bytes,
|
|
969
|
+
resume_secret: context.resumeSecret
|
|
970
|
+
},
|
|
971
|
+
{ swapId: context.swapId }
|
|
972
|
+
);
|
|
699
973
|
const round1Payload = protocol.asDkgRound1ResponsePayload(round1Resp);
|
|
700
974
|
this.log(`DKG round1 complete - coord pkg ${round1Payload.package.byteLength}B`, "in");
|
|
701
975
|
const aliceRound2State = aliceRound1State.intoRound2(COORDINATOR_ID, round1Payload.package);
|
|
@@ -710,10 +984,20 @@ var UserCoordinatorSession = class {
|
|
|
710
984
|
} catch (err) {
|
|
711
985
|
throw new CommandError("REJECTED_GUARD", `Alice DKG finalize failed: ${normalizeError(err)}`);
|
|
712
986
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
987
|
+
await onDelegateShareReady?.({
|
|
988
|
+
swapId: context.swapId,
|
|
989
|
+
delegateShare: new Uint8Array(aliceKeyHandle.secretShareBytes())
|
|
716
990
|
});
|
|
991
|
+
const dkgCompletePromise = this.awaitPush(CoordinatorMessageType.DkgComplete, context.swapId);
|
|
992
|
+
void dkgCompletePromise.catch(() => void 0);
|
|
993
|
+
await this.request(
|
|
994
|
+
CoordinatorMessageType.DkgRound2,
|
|
995
|
+
{
|
|
996
|
+
package: aliceRound2Bytes,
|
|
997
|
+
resume_secret: context.resumeSecret
|
|
998
|
+
},
|
|
999
|
+
{ swapId: context.swapId }
|
|
1000
|
+
);
|
|
717
1001
|
const completeEnvelope = await dkgCompletePromise;
|
|
718
1002
|
const complete = readDkgComplete(protocol, completeEnvelope);
|
|
719
1003
|
const alicePubkey = aliceKeyHandle.groupPublicKeyBytes();
|
|
@@ -733,6 +1017,20 @@ var UserCoordinatorSession = class {
|
|
|
733
1017
|
};
|
|
734
1018
|
}
|
|
735
1019
|
async openSession() {
|
|
1020
|
+
if (this.hasUsableSession()) return;
|
|
1021
|
+
if (this.openingSession !== null) {
|
|
1022
|
+
await this.openingSession;
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
const opening = this.openSessionOnce();
|
|
1026
|
+
this.openingSession = opening;
|
|
1027
|
+
try {
|
|
1028
|
+
await opening;
|
|
1029
|
+
} finally {
|
|
1030
|
+
if (this.openingSession === opening) this.openingSession = null;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
async openSessionOnce() {
|
|
736
1034
|
if (this.hasUsableSession()) return;
|
|
737
1035
|
if (this.session !== null) {
|
|
738
1036
|
this.detachSession(
|
|
@@ -758,11 +1056,6 @@ var UserCoordinatorSession = class {
|
|
|
758
1056
|
this.log(`connected to ${this.coordinator.endpoints[0]?.wsUrl ?? "coordinator"}`, "info");
|
|
759
1057
|
this.log("attestation verified", "info");
|
|
760
1058
|
}
|
|
761
|
-
assertNoActiveContract() {
|
|
762
|
-
if (this.swapId !== null || this.sessionStatus === "connecting" || this.sessionStatus === "running") {
|
|
763
|
-
throw new CommandError("REJECTED_STATE", ACTIVE_CONTRACT_REQUEST_MESSAGE);
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
1059
|
hasUsableSession() {
|
|
767
1060
|
if (this.session === null) return false;
|
|
768
1061
|
const state = getSessionState(this.session);
|
|
@@ -788,30 +1081,43 @@ var UserCoordinatorSession = class {
|
|
|
788
1081
|
handleEnvelope(env) {
|
|
789
1082
|
const protocol = this.requireProtocol();
|
|
790
1083
|
this.log(`<- ${env.type} kind=${env.kind}`, "in");
|
|
1084
|
+
const context = env.swap_id ? this.swapContexts.get(env.swap_id) ?? null : null;
|
|
1085
|
+
if (env.swap_id === null && env.kind !== EnvelopeKind.ERROR) {
|
|
1086
|
+
this.log(`ignored ${env.type} without an explicit swap_id`, "info");
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
if (env.swap_id !== null && context === null) {
|
|
1090
|
+
this.log(`ignored ${env.type} for unknown swap ${env.swap_id}`, "info");
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
791
1093
|
const payoutExecuted = env.kind === EnvelopeKind.PUSH && env.type === CoordinatorMessageType.PayoutExecuted ? protocol.asPayoutExecutedPayload(env) : null;
|
|
792
|
-
const payoutMatchesCurrentSwap = payoutExecuted !== null &&
|
|
1094
|
+
const payoutMatchesCurrentSwap = payoutExecuted !== null && context !== null;
|
|
793
1095
|
const refundExecuted = env.kind === EnvelopeKind.PUSH && env.type === CoordinatorMessageType.WithdrawExecuted ? protocol.asWithdrawExecutedPayload(env) : null;
|
|
794
1096
|
if (this.shouldBufferDepositConfirmed(env)) {
|
|
795
1097
|
this.bufferDepositConfirmed(env);
|
|
796
1098
|
return;
|
|
797
1099
|
}
|
|
798
|
-
const
|
|
799
|
-
const next =
|
|
800
|
-
|
|
1100
|
+
const stateForEnvelope = context?.swapState ?? this.swapState;
|
|
1101
|
+
const next = payoutExecuted !== null && !payoutMatchesCurrentSwap ? null : protocol.nextState(
|
|
1102
|
+
stateForEnvelope,
|
|
801
1103
|
env.kind,
|
|
802
1104
|
env.type,
|
|
803
1105
|
payoutExecuted ? { payoutFinal: payoutExecuted.final } : void 0
|
|
804
1106
|
);
|
|
805
1107
|
if (env.kind === EnvelopeKind.PUSH && next === null) {
|
|
806
1108
|
this.log(
|
|
807
|
-
|
|
1109
|
+
`ignored ${env.type} for swap ${env.swap_id ?? "null"} while client context is ${context?.swapId ?? "none"} in state ${stateForEnvelope}`,
|
|
808
1110
|
"info"
|
|
809
1111
|
);
|
|
810
1112
|
return;
|
|
811
1113
|
}
|
|
812
1114
|
if (next !== null) {
|
|
813
|
-
|
|
814
|
-
|
|
1115
|
+
if (context) {
|
|
1116
|
+
this.updateContextState(context, next);
|
|
1117
|
+
} else {
|
|
1118
|
+
this.swapState = next;
|
|
1119
|
+
this.emitStateChange(this.swapId, next);
|
|
1120
|
+
}
|
|
815
1121
|
}
|
|
816
1122
|
if (env.kind === EnvelopeKind.ERROR) {
|
|
817
1123
|
const coordinatorError = coordinatorErrorFromEnvelope(protocol, env);
|
|
@@ -823,26 +1129,25 @@ var UserCoordinatorSession = class {
|
|
|
823
1129
|
return;
|
|
824
1130
|
}
|
|
825
1131
|
if (env.kind === EnvelopeKind.PUSH) {
|
|
826
|
-
if (payoutExecuted && payoutMatchesCurrentSwap) {
|
|
827
|
-
this.emitPayoutExecuted(payoutExecuted,
|
|
1132
|
+
if (payoutExecuted && payoutMatchesCurrentSwap && context) {
|
|
1133
|
+
this.emitPayoutExecuted(payoutExecuted, context.swapId);
|
|
828
1134
|
}
|
|
829
|
-
if (refundExecuted) {
|
|
830
|
-
this.emitRefundExecuted(refundExecuted,
|
|
1135
|
+
if (refundExecuted && context) {
|
|
1136
|
+
this.emitRefundExecuted(refundExecuted, context.swapId);
|
|
831
1137
|
}
|
|
832
1138
|
this.resolvePushListener(env);
|
|
833
1139
|
}
|
|
834
1140
|
}
|
|
835
|
-
applySwapStatus(status, coordinatorTimestampMs) {
|
|
836
|
-
const keepTerminalState = TERMINAL_SWAP_STATES.has(
|
|
837
|
-
if (!keepTerminalState &&
|
|
838
|
-
this.
|
|
839
|
-
this.emitStateChange();
|
|
1141
|
+
applySwapStatus(context, status, coordinatorTimestampMs) {
|
|
1142
|
+
const keepTerminalState = TERMINAL_SWAP_STATES.has(context.swapState) && status.state !== context.swapState;
|
|
1143
|
+
if (!keepTerminalState && context.swapState !== status.state) {
|
|
1144
|
+
this.updateContextState(context, status.state);
|
|
840
1145
|
}
|
|
841
1146
|
for (const fragment of status.fragments_executed) {
|
|
842
|
-
this.emitPayoutExecuted(fragment,
|
|
1147
|
+
this.emitPayoutExecuted(fragment, context.swapId);
|
|
843
1148
|
}
|
|
844
1149
|
if (status.withdraw_execution) {
|
|
845
|
-
this.emitRefundExecuted(status.withdraw_execution,
|
|
1150
|
+
this.emitRefundExecuted(status.withdraw_execution, context.swapId);
|
|
846
1151
|
}
|
|
847
1152
|
if (status.actor_sync !== void 0) {
|
|
848
1153
|
for (const listener of this.normalUserActorSyncListeners) {
|
|
@@ -853,8 +1158,7 @@ var UserCoordinatorSession = class {
|
|
|
853
1158
|
emitPayoutExecuted(payload, swapId) {
|
|
854
1159
|
if (!swapId) return;
|
|
855
1160
|
const key = `${swapId}:${payload.index}:${payload.tx_signature}`;
|
|
856
|
-
if (this.emittedPayoutKeys
|
|
857
|
-
this.emittedPayoutKeys.add(key);
|
|
1161
|
+
if (!this.rememberEventKey(this.emittedPayoutKeys, key)) return;
|
|
858
1162
|
this.log(
|
|
859
1163
|
`payout executed tx=${payload.tx_signature} amount=${payload.amount_lamports} final=${payload.final}`,
|
|
860
1164
|
"in"
|
|
@@ -866,88 +1170,133 @@ var UserCoordinatorSession = class {
|
|
|
866
1170
|
emitRefundExecuted(payload, swapId) {
|
|
867
1171
|
if (!swapId) return;
|
|
868
1172
|
const key = `${swapId}:${payload.tx_signature}`;
|
|
869
|
-
if (this.emittedRefundKeys
|
|
870
|
-
this.emittedRefundKeys.add(key);
|
|
1173
|
+
if (!this.rememberEventKey(this.emittedRefundKeys, key)) return;
|
|
871
1174
|
this.log(`refund executed tx=${payload.tx_signature} amount=${payload.amount_lamports}`, "in");
|
|
872
1175
|
for (const listener of this.refundExecutedListeners) {
|
|
873
1176
|
listener(payload, swapId);
|
|
874
1177
|
}
|
|
875
1178
|
}
|
|
876
|
-
|
|
1179
|
+
rememberEventKey(keys, key) {
|
|
1180
|
+
if (keys.has(key)) return false;
|
|
1181
|
+
keys.add(key);
|
|
1182
|
+
if (keys.size > MAX_EVENT_DEDUP_ENTRIES_PER_KIND) {
|
|
1183
|
+
const oldest = keys.values().next().value;
|
|
1184
|
+
if (oldest !== void 0) keys.delete(oldest);
|
|
1185
|
+
}
|
|
1186
|
+
return true;
|
|
1187
|
+
}
|
|
1188
|
+
request(type, payload, options = {}) {
|
|
877
1189
|
if (this.session === null) {
|
|
878
1190
|
throw new TransportError("CONNECTION_LOST", "coordinator session is not connected");
|
|
879
1191
|
}
|
|
880
1192
|
return requestEnvelope(this.session, type, payload, {
|
|
881
|
-
swapId: this.swapId,
|
|
882
|
-
timeoutMs,
|
|
1193
|
+
swapId: options.swapId === void 0 ? this.swapId : options.swapId,
|
|
1194
|
+
timeoutMs: options.timeoutMs,
|
|
1195
|
+
rejectMatchingOutOfBandErrors: options.rejectMatchingOutOfBandErrors,
|
|
1196
|
+
requireNonNullResponseSwapId: options.requireNonNullResponseSwapId,
|
|
883
1197
|
onLog: (message, direction) => this.log(message, direction)
|
|
884
1198
|
});
|
|
885
1199
|
}
|
|
886
|
-
awaitPush(type, timeoutMs = 3e4) {
|
|
1200
|
+
awaitPush(type, swapId, timeoutMs = 3e4) {
|
|
887
1201
|
return new Promise((resolve, reject) => {
|
|
888
1202
|
const timer = timeoutMs === null ? null : setTimeout(() => {
|
|
889
|
-
this.
|
|
1203
|
+
this.removePushListener(type, listener);
|
|
890
1204
|
reject(new CommandError("REJECTED_STALE_JOB", `timed out waiting for ${type} push`));
|
|
891
1205
|
}, timeoutMs);
|
|
892
|
-
|
|
1206
|
+
const listener = { swapId, resolve, reject, timer };
|
|
1207
|
+
const listeners = this.pushListeners.get(type) ?? [];
|
|
1208
|
+
listeners.push(listener);
|
|
1209
|
+
this.pushListeners.set(type, listeners);
|
|
893
1210
|
});
|
|
894
1211
|
}
|
|
895
1212
|
rejectAllPushListeners(err) {
|
|
896
|
-
for (const
|
|
897
|
-
|
|
898
|
-
|
|
1213
|
+
for (const listeners of this.pushListeners.values()) {
|
|
1214
|
+
for (const listener of listeners) {
|
|
1215
|
+
if (listener.timer) clearTimeout(listener.timer);
|
|
1216
|
+
listener.reject(err);
|
|
1217
|
+
}
|
|
899
1218
|
}
|
|
900
1219
|
this.pushListeners.clear();
|
|
901
|
-
this.
|
|
902
|
-
|
|
1220
|
+
for (const context of this.swapContexts.values()) {
|
|
1221
|
+
context.bufferDepositConfirmedUntilDelegateAck = false;
|
|
1222
|
+
context.bufferedDepositConfirmed = null;
|
|
1223
|
+
}
|
|
903
1224
|
}
|
|
904
1225
|
shouldBufferDepositConfirmed(env) {
|
|
905
|
-
|
|
1226
|
+
const context = env.swap_id ? this.swapContexts.get(env.swap_id) : null;
|
|
1227
|
+
return env.kind === EnvelopeKind.PUSH && env.type === CoordinatorMessageType.DepositConfirmed && context?.bufferDepositConfirmedUntilDelegateAck === true;
|
|
906
1228
|
}
|
|
907
1229
|
bufferDepositConfirmed(env) {
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
1230
|
+
const context = env.swap_id ? this.swapContexts.get(env.swap_id) : null;
|
|
1231
|
+
if (!context) return;
|
|
1232
|
+
if (!context.bufferedDepositConfirmed) {
|
|
1233
|
+
context.bufferedDepositConfirmed = env;
|
|
1234
|
+
this.clearPushListenerTimer(CoordinatorMessageType.DepositConfirmed, context.swapId);
|
|
911
1235
|
this.log("buffered DepositConfirmed until DelegateAck is verified", "info");
|
|
912
1236
|
return;
|
|
913
1237
|
}
|
|
914
1238
|
this.log("ignored duplicate DepositConfirmed while waiting for DelegateAck", "info");
|
|
915
1239
|
}
|
|
916
|
-
releaseDepositConfirmedGate() {
|
|
1240
|
+
releaseDepositConfirmedGate(context) {
|
|
917
1241
|
const protocol = this.requireProtocol();
|
|
918
|
-
|
|
919
|
-
const buffered =
|
|
1242
|
+
context.bufferDepositConfirmedUntilDelegateAck = false;
|
|
1243
|
+
const buffered = context.bufferedDepositConfirmed;
|
|
920
1244
|
if (!buffered) return;
|
|
921
|
-
|
|
922
|
-
const next = protocol.nextState(
|
|
1245
|
+
context.bufferedDepositConfirmed = null;
|
|
1246
|
+
const next = protocol.nextState(context.swapState, buffered.kind, buffered.type);
|
|
923
1247
|
if (next === null) {
|
|
924
|
-
this.log(`ignored buffered DepositConfirmed in state ${
|
|
1248
|
+
this.log(`ignored buffered DepositConfirmed in state ${context.swapState}`, "info");
|
|
925
1249
|
return;
|
|
926
1250
|
}
|
|
927
|
-
this.
|
|
928
|
-
this.emitStateChange();
|
|
1251
|
+
this.updateContextState(context, next);
|
|
929
1252
|
this.resolvePushListener(buffered);
|
|
930
1253
|
}
|
|
931
1254
|
resolvePushListener(env) {
|
|
932
|
-
const
|
|
933
|
-
if (!
|
|
934
|
-
|
|
1255
|
+
const listeners = this.pushListeners.get(env.type);
|
|
1256
|
+
if (!listeners) return;
|
|
1257
|
+
const index = listeners.findIndex(
|
|
1258
|
+
(candidate) => candidate.swapId === void 0 || candidate.swapId === env.swap_id
|
|
1259
|
+
);
|
|
1260
|
+
if (index < 0) return;
|
|
1261
|
+
const listener = listeners.splice(index, 1)[0];
|
|
1262
|
+
if (listeners.length === 0) this.pushListeners.delete(env.type);
|
|
935
1263
|
if (listener.timer) clearTimeout(listener.timer);
|
|
936
1264
|
listener.resolve(env);
|
|
937
1265
|
}
|
|
938
|
-
clearPushListenerTimer(type) {
|
|
939
|
-
const listener = this.pushListeners.get(type);
|
|
1266
|
+
clearPushListenerTimer(type, swapId) {
|
|
1267
|
+
const listener = this.pushListeners.get(type)?.find((candidate) => candidate.swapId === void 0 || candidate.swapId === swapId);
|
|
940
1268
|
if (!listener?.timer) return;
|
|
941
1269
|
clearTimeout(listener.timer);
|
|
942
1270
|
listener.timer = null;
|
|
943
1271
|
}
|
|
1272
|
+
removePushListener(type, listener) {
|
|
1273
|
+
const listeners = this.pushListeners.get(type);
|
|
1274
|
+
if (!listeners) return;
|
|
1275
|
+
const index = listeners.indexOf(listener);
|
|
1276
|
+
if (index >= 0) listeners.splice(index, 1);
|
|
1277
|
+
if (listeners.length === 0) this.pushListeners.delete(type);
|
|
1278
|
+
}
|
|
1279
|
+
cancelPushWaitersForSwap(swapId) {
|
|
1280
|
+
for (const [type, listeners] of this.pushListeners.entries()) {
|
|
1281
|
+
const remaining = listeners.filter((listener) => {
|
|
1282
|
+
if (listener.swapId !== swapId) return true;
|
|
1283
|
+
if (listener.timer) clearTimeout(listener.timer);
|
|
1284
|
+
return false;
|
|
1285
|
+
});
|
|
1286
|
+
if (remaining.length === 0) {
|
|
1287
|
+
this.pushListeners.delete(type);
|
|
1288
|
+
} else if (remaining.length !== listeners.length) {
|
|
1289
|
+
this.pushListeners.set(type, remaining);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
944
1293
|
setSessionStatus(status) {
|
|
945
1294
|
this.sessionStatus = status;
|
|
946
1295
|
this.emitStateChange();
|
|
947
1296
|
}
|
|
948
|
-
emitStateChange() {
|
|
1297
|
+
emitStateChange(swapId = this.swapId, swapState = this.swapState) {
|
|
949
1298
|
for (const listener of this.stateListeners) {
|
|
950
|
-
listener(
|
|
1299
|
+
listener(swapState, this.sessionStatus, swapId);
|
|
951
1300
|
}
|
|
952
1301
|
}
|
|
953
1302
|
log(msg, direction) {
|
|
@@ -983,28 +1332,42 @@ function toContractRequestResult(prepared) {
|
|
|
983
1332
|
delegatedAtMs: prepared.delegatedAtMs,
|
|
984
1333
|
syncSecret: new Uint8Array(prepared.syncSecret),
|
|
985
1334
|
syncSecretHex: prepared.syncSecretHex,
|
|
1335
|
+
resumeSecret: new Uint8Array(prepared.resumeSecret),
|
|
1336
|
+
resumeSecretHex: prepared.resumeSecretHex,
|
|
986
1337
|
recoveryCodeHex: prepared.recoveryCodeHex,
|
|
987
1338
|
policySnapshot: prepared.policySnapshot,
|
|
988
1339
|
delegatePolicySnapshot: prepared.delegatePolicySnapshot
|
|
989
1340
|
};
|
|
990
1341
|
}
|
|
991
1342
|
async function contractRequestOnSession(session, params) {
|
|
992
|
-
if (activeFunctionalContractRequests.has(session)) {
|
|
993
|
-
throw new CommandError("REJECTED_STATE", ACTIVE_CONTRACT_REQUEST_MESSAGE);
|
|
994
|
-
}
|
|
995
|
-
activeFunctionalContractRequests.add(session);
|
|
996
1343
|
let client = null;
|
|
997
1344
|
try {
|
|
998
|
-
client = new UserCoordinatorSession(
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1345
|
+
client = new UserCoordinatorSession(
|
|
1346
|
+
{
|
|
1347
|
+
coordinator: getSessionState(session).pool,
|
|
1348
|
+
createSession: async () => session
|
|
1349
|
+
},
|
|
1350
|
+
false
|
|
1351
|
+
);
|
|
1002
1352
|
return await client.contractRequest(params);
|
|
1003
1353
|
} finally {
|
|
1004
|
-
activeFunctionalContractRequests.delete(session);
|
|
1005
1354
|
client?.releaseWithoutClosing();
|
|
1006
1355
|
}
|
|
1007
1356
|
}
|
|
1357
|
+
async function resumePreDelegationOnSession(session, params) {
|
|
1358
|
+
const client = new UserCoordinatorSession(
|
|
1359
|
+
{
|
|
1360
|
+
coordinator: getSessionState(session).pool,
|
|
1361
|
+
createSession: async () => session
|
|
1362
|
+
},
|
|
1363
|
+
false
|
|
1364
|
+
);
|
|
1365
|
+
try {
|
|
1366
|
+
return await client.resumePreDelegation(params);
|
|
1367
|
+
} finally {
|
|
1368
|
+
client.releaseWithoutClosing();
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1008
1371
|
async function requestRefundOnSession(session, params) {
|
|
1009
1372
|
const client = new UserCoordinatorSession(
|
|
1010
1373
|
{
|
|
@@ -1182,11 +1545,35 @@ async function contractRequest(session, args) {
|
|
|
1182
1545
|
...args.onSyncSecretReady !== void 0 && {
|
|
1183
1546
|
onSyncSecretReady: args.onSyncSecretReady
|
|
1184
1547
|
},
|
|
1548
|
+
...args.resumeSecret !== void 0 && { resumeSecret: args.resumeSecret },
|
|
1549
|
+
...args.onResumeSecretReady !== void 0 && {
|
|
1550
|
+
onResumeSecretReady: args.onResumeSecretReady
|
|
1551
|
+
},
|
|
1552
|
+
...args.onSwapAllocated !== void 0 && {
|
|
1553
|
+
onSwapAllocated: args.onSwapAllocated
|
|
1554
|
+
},
|
|
1185
1555
|
...args.onRecoveryCodeReady !== void 0 && {
|
|
1186
1556
|
onRecoveryCodeReady: args.onRecoveryCodeReady
|
|
1557
|
+
},
|
|
1558
|
+
...args.onDelegateShareReady !== void 0 && {
|
|
1559
|
+
onDelegateShareReady: args.onDelegateShareReady
|
|
1187
1560
|
}
|
|
1188
1561
|
});
|
|
1189
1562
|
}
|
|
1563
|
+
async function resumePreDelegation(session, args) {
|
|
1564
|
+
assertAttested(session);
|
|
1565
|
+
return resumePreDelegationOnSession(session, {
|
|
1566
|
+
swapId: args.swapId,
|
|
1567
|
+
resumeSecret: new Uint8Array(args.resumeSecret),
|
|
1568
|
+
...args.syncSecret !== void 0 && { syncSecret: new Uint8Array(args.syncSecret) },
|
|
1569
|
+
recoveryCommitment: new Uint8Array(args.recoveryCommitment),
|
|
1570
|
+
policySnapshot: args.policySnapshot,
|
|
1571
|
+
...args.onDelegateShareReady !== void 0 && {
|
|
1572
|
+
onDelegateShareReady: args.onDelegateShareReady
|
|
1573
|
+
},
|
|
1574
|
+
...args.delegateShare !== void 0 && { delegateShare: new Uint8Array(args.delegateShare) }
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1190
1577
|
async function sync(session, contractId, syncSecret, timeoutMs) {
|
|
1191
1578
|
assertAttested(session);
|
|
1192
1579
|
return requestUserSync(session, contractId, syncSecret, timeoutMs);
|
|
@@ -1228,10 +1615,12 @@ async function requestRefund(session, args) {
|
|
|
1228
1615
|
assertAttested(session);
|
|
1229
1616
|
assertRecoveryCode(args.recoveryCode);
|
|
1230
1617
|
return requestRefundOnSession(session, {
|
|
1618
|
+
...args.swapId !== void 0 && { swapId: args.swapId },
|
|
1619
|
+
...args.syncSecret !== void 0 && { syncSecret: new Uint8Array(args.syncSecret) },
|
|
1231
1620
|
recoveryCode: new Uint8Array(args.recoveryCode)
|
|
1232
1621
|
});
|
|
1233
1622
|
}
|
|
1234
1623
|
|
|
1235
|
-
export { INSTANT_PAYOUT_WINDOW_MS, MAX_ENTRY_AMOUNT_LAMPORTS, MIN_ENTRY_AMOUNT_LAMPORTS, PAYOUT_WINDOW_MILLISECONDS_PER_SECOND, RECOVERY_CODE_BYTE_LENGTH, SUPPORTED_TOTAL_DEADLINE_MS, commitmentFromCode, contractRequest, generateRecoveryCode, recoveryCodeFromHex, recoveryCodeFromUserInput, recoveryCodeToHex, requestRefund, sync };
|
|
1624
|
+
export { INSTANT_PAYOUT_WINDOW_MS, MAX_ENTRY_AMOUNT_LAMPORTS, MIN_ENTRY_AMOUNT_LAMPORTS, PAYOUT_WINDOW_MILLISECONDS_PER_SECOND, RECOVERY_CODE_BYTE_LENGTH, SUPPORTED_TOTAL_DEADLINE_MS, commitmentFromCode, contractRequest, generateRecoveryCode, recoveryCodeFromHex, recoveryCodeFromUserInput, recoveryCodeToHex, requestRefund, resumePreDelegation, sync };
|
|
1236
1625
|
//# sourceMappingURL=user.js.map
|
|
1237
1626
|
//# sourceMappingURL=user.js.map
|