@invisible-labs/sdk 0.6.0-devnet.4 → 0.6.0-devnet.5
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 +70 -13
- package/dist/.invisible-sdk-build-target.json +2 -2
- package/dist/{chunk-UADJCUPK.js → chunk-3MDHAS4D.js} +6 -5
- package/dist/chunk-3MDHAS4D.js.map +1 -0
- package/dist/{chunk-E4DCEDAG.js → chunk-3TGQ4CZ3.js} +178 -2
- package/dist/chunk-3TGQ4CZ3.js.map +1 -0
- package/dist/chunk-DCTYBUY3.js +258 -0
- package/dist/chunk-DCTYBUY3.js.map +1 -0
- package/dist/{chunk-NHEHCUS5.js → chunk-EBWTAXNT.js} +3 -3
- package/dist/{chunk-NHEHCUS5.js.map → chunk-EBWTAXNT.js.map} +1 -1
- package/dist/{chunk-V5HXJRBW.js → chunk-HJFMDMPY.js} +3 -3
- package/dist/chunk-HJFMDMPY.js.map +1 -0
- package/dist/{chunk-GHBQF3A7.js → chunk-QRN46R3F.js} +5 -2
- package/dist/chunk-QRN46R3F.js.map +1 -0
- package/dist/chunk-Y7AK6RBV.js +4189 -0
- package/dist/chunk-Y7AK6RBV.js.map +1 -0
- package/dist/{coordinator-ZNLGAYXD.js → coordinator-PEWHNZ7I.js} +3 -3
- package/dist/{coordinator-ZNLGAYXD.js.map → coordinator-PEWHNZ7I.js.map} +1 -1
- package/dist/events.js +3 -3
- package/dist/index.d.ts +14 -4
- package/dist/index.js +74 -11
- package/dist/index.js.map +1 -1
- package/dist/lp.d.ts +33 -9
- package/dist/lp.js +305 -45
- package/dist/lp.js.map +1 -1
- package/dist/presets.d.ts +6 -2
- package/dist/presets.js +8 -8
- package/dist/presets.js.map +1 -1
- package/dist/stats.js +1 -1
- package/dist/storage.js +2 -243
- package/dist/storage.js.map +1 -1
- package/dist/{types.generated-DJBTjLpP.d.ts → types.generated-YhFu9ZBR.d.ts} +29 -4
- package/dist/user.d.ts +31 -4
- package/dist/user.js +409 -57
- package/dist/user.js.map +1 -1
- package/package.json +4 -1
- package/dist/chunk-5NNEO7IK.js +0 -1150
- package/dist/chunk-5NNEO7IK.js.map +0 -1
- package/dist/chunk-BRDLLGCZ.js +0 -59
- package/dist/chunk-BRDLLGCZ.js.map +0 -1
- package/dist/chunk-DIA6U2CV.js +0 -1927
- package/dist/chunk-DIA6U2CV.js.map +0 -1
- package/dist/chunk-E4DCEDAG.js.map +0 -1
- package/dist/chunk-GHBQF3A7.js.map +0 -1
- package/dist/chunk-UADJCUPK.js.map +0 -1
- package/dist/chunk-V5HXJRBW.js.map +0 -1
package/dist/user.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { scheduledPayoutWindowSeconds } from './chunk-
|
|
2
|
-
import { validatePayoutPolicyShape, formatAjvErrors, createSession, createExponentialBackoff } from './chunk-
|
|
1
|
+
import { scheduledPayoutWindowSeconds } from './chunk-3TGQ4CZ3.js';
|
|
2
|
+
import { validatePayoutPolicyShape, formatAjvErrors, persistTransferStatus, createSession, disabledClientPersistence, readPersistedTransferForResume, persistTransferReady, createExponentialBackoff, persistTransferTerminal, persistTransferRecoveryCode, persistTransferAllocation, persistTransferDkgMetadata } from './chunk-Y7AK6RBV.js';
|
|
3
|
+
export { getPersistedTransfer, listPersistedTransfers, purgePersistedTransfers, removePersistedTransfer } from './chunk-Y7AK6RBV.js';
|
|
3
4
|
import { PRODUCT_MAX_ENTRY_LAMPORTS, PRODUCT_MIN_ENTRY_LAMPORTS } from './chunk-4X5OCCQW.js';
|
|
4
|
-
import { assertAttested, publicKey, solanaAddressFromPublicKeyBytes } from './chunk-
|
|
5
|
-
import { requestEnvelope, CoordinatorMessageType, onEnvelope, closeProtocolRuntime, EnvelopeKind } from './chunk-
|
|
6
|
-
import { getSessionState } from './chunk-
|
|
7
|
-
import './chunk-
|
|
8
|
-
import { PolicyValidationError, CommandError,
|
|
9
|
-
export { InvalidDepositAmountError } from './chunk-
|
|
5
|
+
import { assertAttested, publicKey, solanaAddressFromPublicKeyBytes } from './chunk-EBWTAXNT.js';
|
|
6
|
+
import { requestEnvelope, CoordinatorMessageType, onEnvelope, closeProtocolRuntime, EnvelopeKind } from './chunk-3MDHAS4D.js';
|
|
7
|
+
import { getSessionState } from './chunk-HJFMDMPY.js';
|
|
8
|
+
import './chunk-DCTYBUY3.js';
|
|
9
|
+
import { PolicyValidationError, CommandError, StorageError, TransportError, normalizeError, InvalidDepositAmountError, AttestationError, RoutingError } from './chunk-QRN46R3F.js';
|
|
10
|
+
export { InvalidDepositAmountError } from './chunk-QRN46R3F.js';
|
|
10
11
|
import './chunk-VR6T6OJS.js';
|
|
11
12
|
|
|
12
13
|
// src/validation/payoutPolicy.ts
|
|
@@ -171,7 +172,7 @@ function recoveryCodeFromUserInput(input) {
|
|
|
171
172
|
var protocolPromise = null;
|
|
172
173
|
var frostRuntimePromise = null;
|
|
173
174
|
function loadProtocol() {
|
|
174
|
-
protocolPromise ??= import('./coordinator-
|
|
175
|
+
protocolPromise ??= import('./coordinator-PEWHNZ7I.js');
|
|
175
176
|
return protocolPromise;
|
|
176
177
|
}
|
|
177
178
|
function loadFrostRuntime() {
|
|
@@ -212,6 +213,16 @@ function readDkgComplete(protocol, envelope) {
|
|
|
212
213
|
coordinatorTimestampMs: envelope.timestamp_ms
|
|
213
214
|
};
|
|
214
215
|
}
|
|
216
|
+
function assertDepositConfirmedAmount(protocol, envelope, expectedAmountLamports) {
|
|
217
|
+
const payload = protocol.asDepositConfirmedPayload(envelope);
|
|
218
|
+
if (payload.amount_lamports !== expectedAmountLamports) {
|
|
219
|
+
throw new InvalidDepositAmountError(
|
|
220
|
+
BigInt(payload.amount_lamports),
|
|
221
|
+
BigInt(expectedAmountLamports)
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
return payload;
|
|
225
|
+
}
|
|
215
226
|
function tagBenignTransportDrop(err) {
|
|
216
227
|
err[BENIGN_TRANSPORT_DROP] = true;
|
|
217
228
|
return err;
|
|
@@ -241,9 +252,12 @@ var UserCoordinatorSession = class {
|
|
|
241
252
|
this.refundExecutedListeners = /* @__PURE__ */ new Set();
|
|
242
253
|
this.normalUserActorSyncListeners = /* @__PURE__ */ new Set();
|
|
243
254
|
this.coordinatorErrorListeners = /* @__PURE__ */ new Set();
|
|
255
|
+
this.storageErrorListeners = /* @__PURE__ */ new Set();
|
|
244
256
|
this.emittedPayoutKeys = /* @__PURE__ */ new Set();
|
|
245
257
|
this.emittedRefundKeys = /* @__PURE__ */ new Set();
|
|
246
258
|
this.statusReconciliationStops = /* @__PURE__ */ new Map();
|
|
259
|
+
this.pushProcessing = /* @__PURE__ */ new Map();
|
|
260
|
+
this.terminalOutcomes = /* @__PURE__ */ new Map();
|
|
247
261
|
this.coordinator = options.coordinator;
|
|
248
262
|
this.createSessionImpl = options.createSession ?? createSession;
|
|
249
263
|
this.closeSessionAfterOperationFailure = closeSessionAfterRefund;
|
|
@@ -272,6 +286,10 @@ var UserCoordinatorSession = class {
|
|
|
272
286
|
this.coordinatorErrorListeners.add(listener);
|
|
273
287
|
return () => this.coordinatorErrorListeners.delete(listener);
|
|
274
288
|
}
|
|
289
|
+
onStorageError(listener) {
|
|
290
|
+
this.storageErrorListeners.add(listener);
|
|
291
|
+
return () => this.storageErrorListeners.delete(listener);
|
|
292
|
+
}
|
|
275
293
|
get currentSwapState() {
|
|
276
294
|
return this.swapState;
|
|
277
295
|
}
|
|
@@ -282,6 +300,9 @@ var UserCoordinatorSession = class {
|
|
|
282
300
|
get currentSwapId() {
|
|
283
301
|
return this.swapId;
|
|
284
302
|
}
|
|
303
|
+
clientPersistenceState() {
|
|
304
|
+
return this.session ? getSessionState(this.session).clientPersistence : disabledClientPersistence();
|
|
305
|
+
}
|
|
285
306
|
beginOperation() {
|
|
286
307
|
this.activeOperations += 1;
|
|
287
308
|
if (this.activeOperations === 1) this.setSessionStatus("connecting");
|
|
@@ -297,6 +318,7 @@ var UserCoordinatorSession = class {
|
|
|
297
318
|
if (!context) {
|
|
298
319
|
context = {
|
|
299
320
|
swapId,
|
|
321
|
+
requestedAmountLamports: null,
|
|
300
322
|
swapState: this.swapId === swapId ? this.swapState : "new",
|
|
301
323
|
syncSecret: this.swapId === swapId && this.syncSecret ? new Uint8Array(this.syncSecret) : null,
|
|
302
324
|
resumeSecret: this.swapId === swapId && this.resumeSecret ? new Uint8Array(this.resumeSecret) : null,
|
|
@@ -321,16 +343,19 @@ var UserCoordinatorSession = class {
|
|
|
321
343
|
if (this.swapId === context.swapId) {
|
|
322
344
|
this.swapState = state;
|
|
323
345
|
}
|
|
324
|
-
this.emitStateChange(context.swapId, state);
|
|
325
346
|
if (TERMINAL_SWAP_STATES.has(state)) {
|
|
326
347
|
this.evictSwapContext(context.swapId);
|
|
327
348
|
}
|
|
349
|
+
this.emitStateChange(context.swapId, state);
|
|
328
350
|
}
|
|
329
351
|
evictSwapContext(swapId) {
|
|
330
352
|
this.statusReconciliationStops.get(swapId)?.();
|
|
331
353
|
this.statusReconciliationStops.delete(swapId);
|
|
332
354
|
const context = this.swapContexts.get(swapId);
|
|
333
355
|
if (context) {
|
|
356
|
+
if (isTerminalSwapState(context.swapState)) {
|
|
357
|
+
this.rememberTerminalOutcome(swapId, context.swapState);
|
|
358
|
+
}
|
|
334
359
|
context.syncSecret?.fill(0);
|
|
335
360
|
context.resumeSecret?.fill(0);
|
|
336
361
|
context.bufferedDepositConfirmed = null;
|
|
@@ -347,9 +372,26 @@ var UserCoordinatorSession = class {
|
|
|
347
372
|
clearSwapContexts() {
|
|
348
373
|
for (const swapId of this.swapContexts.keys()) this.evictSwapContext(swapId);
|
|
349
374
|
this.swapContexts.clear();
|
|
375
|
+
this.pushProcessing.clear();
|
|
376
|
+
this.terminalOutcomes.clear();
|
|
350
377
|
this.emittedPayoutKeys.clear();
|
|
351
378
|
this.emittedRefundKeys.clear();
|
|
352
379
|
}
|
|
380
|
+
isActiveSwapContext(context) {
|
|
381
|
+
return this.swapContexts.get(context.swapId) === context;
|
|
382
|
+
}
|
|
383
|
+
rememberTerminalOutcome(swapId, state, refund, storageError) {
|
|
384
|
+
const previous = this.terminalOutcomes.get(swapId);
|
|
385
|
+
this.terminalOutcomes.set(swapId, {
|
|
386
|
+
state,
|
|
387
|
+
...refund !== void 0 && refund !== null ? { refund } : previous?.refund !== void 0 ? { refund: previous.refund } : {},
|
|
388
|
+
...storageError !== void 0 ? { storageError } : previous?.storageError !== void 0 ? { storageError: previous.storageError } : {}
|
|
389
|
+
});
|
|
390
|
+
if (this.terminalOutcomes.size > MAX_EVENT_DEDUP_ENTRIES_PER_KIND) {
|
|
391
|
+
const oldest = this.terminalOutcomes.keys().next().value;
|
|
392
|
+
if (oldest !== void 0) this.terminalOutcomes.delete(oldest);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
353
395
|
async runSwap(params) {
|
|
354
396
|
assertCurrentUserPayoutSpecRuntimeLimits(params.payoutSpec);
|
|
355
397
|
this.beginOperation();
|
|
@@ -433,14 +475,38 @@ var UserCoordinatorSession = class {
|
|
|
433
475
|
this.setSessionStatus("running");
|
|
434
476
|
const context = this.ensureSwapContext(params.swapId);
|
|
435
477
|
context.swapState = params.delegateShare ? "awaiting_deposit" : "awaiting_dkg";
|
|
478
|
+
context.bufferDepositConfirmedUntilDelegateAck = true;
|
|
436
479
|
this.setCurrentContext(context);
|
|
437
480
|
let jointPublicKey;
|
|
481
|
+
let depositAddress;
|
|
438
482
|
let depositExpiresAtMs;
|
|
439
483
|
let coordinatorTimestampMs;
|
|
440
484
|
let delegateShare = params.delegateShare ? new Uint8Array(params.delegateShare) : void 0;
|
|
485
|
+
const persistence = this.clientPersistenceState();
|
|
486
|
+
const persistedResumeRecord = await readPersistedTransferForResume(
|
|
487
|
+
persistence,
|
|
488
|
+
context.swapId
|
|
489
|
+
);
|
|
490
|
+
if (params.delegateShare !== void 0 && persistedResumeRecord !== null) {
|
|
491
|
+
if (persistedResumeRecord.depositAddress === void 0 || persistedResumeRecord.depositExpiresAtMs === void 0 || persistedResumeRecord.coordinatorTimestampMs === void 0) {
|
|
492
|
+
throw new StorageError(
|
|
493
|
+
"STORAGE_KEY_MISSING",
|
|
494
|
+
"persisted DKG metadata is missing for saved delegate share",
|
|
495
|
+
{ phase: "ready", swapId: context.swapId, remoteAccepted: false }
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
depositAddress = persistedResumeRecord.depositAddress;
|
|
499
|
+
depositExpiresAtMs = persistedResumeRecord.depositExpiresAtMs;
|
|
500
|
+
coordinatorTimestampMs = persistedResumeRecord.coordinatorTimestampMs;
|
|
501
|
+
}
|
|
441
502
|
if (!delegateShare) {
|
|
442
|
-
const dkg = await this.runDkg(
|
|
503
|
+
const dkg = await this.runDkg(
|
|
504
|
+
context,
|
|
505
|
+
params.onDelegateShareReady,
|
|
506
|
+
persistedResumeRecord !== null
|
|
507
|
+
);
|
|
443
508
|
jointPublicKey = dkg.jointPublicKey;
|
|
509
|
+
depositAddress = solanaAddressFromPublicKeyBytes(jointPublicKey);
|
|
444
510
|
depositExpiresAtMs = dkg.depositExpiresAtMs;
|
|
445
511
|
coordinatorTimestampMs = dkg.coordinatorTimestampMs;
|
|
446
512
|
delegateShare = dkg.keyHandle.secretShareBytes();
|
|
@@ -476,8 +542,35 @@ var UserCoordinatorSession = class {
|
|
|
476
542
|
"DelegateAck spending_policy does not match persisted policy_snapshot"
|
|
477
543
|
);
|
|
478
544
|
}
|
|
479
|
-
context.
|
|
480
|
-
|
|
545
|
+
context.requestedAmountLamports = delegateAck.spending_policy.entry_amount_lamports;
|
|
546
|
+
if (context.bufferedDepositConfirmed) {
|
|
547
|
+
assertDepositConfirmedAmount(
|
|
548
|
+
this.requireProtocol(),
|
|
549
|
+
context.bufferedDepositConfirmed,
|
|
550
|
+
delegateAck.spending_policy.entry_amount_lamports
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
if (persistedResumeRecord !== null) {
|
|
554
|
+
if (depositAddress === void 0 || depositExpiresAtMs === void 0 || coordinatorTimestampMs === void 0) {
|
|
555
|
+
throw new StorageError(
|
|
556
|
+
"STORAGE_KEY_MISSING",
|
|
557
|
+
"persisted DKG metadata is missing for saved delegate share",
|
|
558
|
+
{ phase: "ready", swapId: context.swapId, remoteAccepted: true }
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
await persistTransferReady(persistence, {
|
|
562
|
+
swapId: context.swapId,
|
|
563
|
+
depositAddress,
|
|
564
|
+
depositExpiresAtMs,
|
|
565
|
+
delegatedAtMs,
|
|
566
|
+
coordinatorTimestampMs
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
const hadBufferedDeposit = context.bufferedDepositConfirmed !== null;
|
|
570
|
+
await this.releaseDepositConfirmedGate(context);
|
|
571
|
+
if (!hadBufferedDeposit && this.isActiveSwapContext(context)) {
|
|
572
|
+
this.updateContextState(context, "awaiting_deposit");
|
|
573
|
+
}
|
|
481
574
|
completed = true;
|
|
482
575
|
terminalStatus = "done";
|
|
483
576
|
return {
|
|
@@ -518,6 +611,7 @@ var UserCoordinatorSession = class {
|
|
|
518
611
|
this.statusReconciliationStops.clear();
|
|
519
612
|
}
|
|
520
613
|
restoreSwapContext(params) {
|
|
614
|
+
if (this.terminalOutcomes.has(params.swapId)) return;
|
|
521
615
|
if (params.syncSecret !== void 0) {
|
|
522
616
|
if (params.syncSecret.length !== SYNC_SECRET_BYTE_LENGTH) {
|
|
523
617
|
throw new CommandError(
|
|
@@ -558,7 +652,13 @@ var UserCoordinatorSession = class {
|
|
|
558
652
|
}
|
|
559
653
|
);
|
|
560
654
|
const status = this.requireProtocol().asSyncUserResponsePayload(env);
|
|
561
|
-
this.
|
|
655
|
+
const persistence = this.clientPersistenceState();
|
|
656
|
+
await this.enqueueSwapProcessing(context.swapId, async () => {
|
|
657
|
+
if (!this.isActiveSwapContext(context)) return;
|
|
658
|
+
await persistTransferStatus(persistence, context.swapId, status, env.timestamp_ms);
|
|
659
|
+
if (!this.isActiveSwapContext(context)) return;
|
|
660
|
+
this.applySwapStatus(context, status, env.timestamp_ms);
|
|
661
|
+
});
|
|
562
662
|
return status;
|
|
563
663
|
}
|
|
564
664
|
startSwapStatusReconciliation(intervalMs = DEFAULT_SWAP_STATUS_RECONCILE_INTERVAL_MS) {
|
|
@@ -675,10 +775,12 @@ var UserCoordinatorSession = class {
|
|
|
675
775
|
throw new CommandError("REJECTED_STATE", "syncSecret requires swapId");
|
|
676
776
|
}
|
|
677
777
|
this.restoreSwapContext({ swapId, syncSecret: params.syncSecret });
|
|
778
|
+
this.ensureRefundContext(swapId);
|
|
678
779
|
requestSwapId = swapId;
|
|
679
780
|
} else if (params.swapId) {
|
|
680
781
|
const swapId = params.swapId;
|
|
681
782
|
this.restoreSwapContext({ swapId });
|
|
783
|
+
this.ensureRefundContext(swapId);
|
|
682
784
|
requestSwapId = swapId;
|
|
683
785
|
}
|
|
684
786
|
openedForRefund = !this.hasUsableSession();
|
|
@@ -703,9 +805,21 @@ var UserCoordinatorSession = class {
|
|
|
703
805
|
}
|
|
704
806
|
if (env.type === CoordinatorMessageType.WithdrawExecuted) {
|
|
705
807
|
const resolvedSwapId2 = env.swap_id ?? requestSwapId;
|
|
706
|
-
|
|
707
|
-
if (
|
|
708
|
-
|
|
808
|
+
if (resolvedSwapId2) requestSwapId = resolvedSwapId2;
|
|
809
|
+
if (resolvedSwapId2) await this.waitForPushProcessing(resolvedSwapId2);
|
|
810
|
+
const terminalOutcome2 = resolvedSwapId2 ? this.terminalOutcomes.get(resolvedSwapId2) : void 0;
|
|
811
|
+
if (terminalOutcome2?.storageError) throw terminalOutcome2.storageError;
|
|
812
|
+
if (!terminalOutcome2) this.ensureRefundContext(resolvedSwapId2);
|
|
813
|
+
const refund = this.requireProtocol().asWithdrawExecutedPayload(env);
|
|
814
|
+
if (resolvedSwapId2 && terminalOutcome2?.refund === void 0) {
|
|
815
|
+
await persistTransferTerminal(
|
|
816
|
+
this.clientPersistenceState(),
|
|
817
|
+
resolvedSwapId2,
|
|
818
|
+
"refunded",
|
|
819
|
+
env.timestamp_ms
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
return { kind: "executed", refund };
|
|
709
823
|
}
|
|
710
824
|
if (env.type !== CoordinatorMessageType.WithdrawAccepted) {
|
|
711
825
|
throw new CommandError(
|
|
@@ -715,10 +829,28 @@ var UserCoordinatorSession = class {
|
|
|
715
829
|
}
|
|
716
830
|
const accepted = this.requireProtocol().asWithdrawAcceptedPayload(env);
|
|
717
831
|
const resolvedSwapId = env.swap_id ?? requestSwapId;
|
|
718
|
-
|
|
832
|
+
if (resolvedSwapId) requestSwapId = resolvedSwapId;
|
|
833
|
+
if (resolvedSwapId) await this.waitForPushProcessing(resolvedSwapId);
|
|
834
|
+
let terminalOutcome = resolvedSwapId ? this.terminalOutcomes.get(resolvedSwapId) : void 0;
|
|
835
|
+
if (terminalOutcome?.storageError) throw terminalOutcome.storageError;
|
|
836
|
+
let resolvedContext = terminalOutcome ? null : this.ensureRefundContext(resolvedSwapId);
|
|
837
|
+
if (resolvedSwapId && !terminalOutcome) {
|
|
838
|
+
await persistTransferRecoveryCode(
|
|
839
|
+
this.clientPersistenceState(),
|
|
840
|
+
resolvedSwapId,
|
|
841
|
+
recoveryCode
|
|
842
|
+
);
|
|
843
|
+
await this.waitForPushProcessing(resolvedSwapId);
|
|
844
|
+
terminalOutcome = this.terminalOutcomes.get(resolvedSwapId);
|
|
845
|
+
if (terminalOutcome?.storageError) throw terminalOutcome.storageError;
|
|
846
|
+
if (terminalOutcome) resolvedContext = null;
|
|
847
|
+
}
|
|
719
848
|
if (!options.waitForFinality) {
|
|
720
849
|
return { kind: "accepted", accepted };
|
|
721
850
|
}
|
|
851
|
+
if (terminalOutcome?.refund !== void 0) {
|
|
852
|
+
return { kind: "executed", refund: terminalOutcome.refund };
|
|
853
|
+
}
|
|
722
854
|
if (!resolvedContext) {
|
|
723
855
|
throw new CommandError("REJECTED_STALE_JOB", REFUND_PENDING_FINALIZATION_MESSAGE);
|
|
724
856
|
}
|
|
@@ -734,10 +866,21 @@ var UserCoordinatorSession = class {
|
|
|
734
866
|
recoveryCode.fill(0);
|
|
735
867
|
this.endOperation();
|
|
736
868
|
if (openedForRefund && this.closeSessionAfterOperationFailure && this.activeOperations === 0) {
|
|
869
|
+
await this.waitForPushProcessing(requestSwapId);
|
|
737
870
|
this.close();
|
|
738
871
|
}
|
|
739
872
|
}
|
|
740
873
|
}
|
|
874
|
+
ensureRefundContext(swapId) {
|
|
875
|
+
if (swapId === null) return null;
|
|
876
|
+
if (this.terminalOutcomes.has(swapId)) return null;
|
|
877
|
+
const context = this.ensureSwapContext(swapId);
|
|
878
|
+
if (context.swapState === "new") {
|
|
879
|
+
context.swapState = "awaiting_deposit";
|
|
880
|
+
this.setCurrentContext(context);
|
|
881
|
+
}
|
|
882
|
+
return context;
|
|
883
|
+
}
|
|
741
884
|
async awaitRefundOutcomeFromSwapStatus(context) {
|
|
742
885
|
const deadline = Date.now() + DEFAULT_REFUND_OUTCOME_POLL_BUDGET_MS;
|
|
743
886
|
for (; ; ) {
|
|
@@ -765,13 +908,11 @@ var UserCoordinatorSession = class {
|
|
|
765
908
|
const protocol = this.requireProtocol();
|
|
766
909
|
const prepared = await this.prepareContract(params);
|
|
767
910
|
const depositEnv = await prepared.depositConfirmedPromise;
|
|
768
|
-
const depositPayload =
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
);
|
|
774
|
-
}
|
|
911
|
+
const depositPayload = assertDepositConfirmedAmount(
|
|
912
|
+
protocol,
|
|
913
|
+
depositEnv,
|
|
914
|
+
params.amountLamports
|
|
915
|
+
);
|
|
775
916
|
this.log(
|
|
776
917
|
`deposit confirmed tx=${depositPayload.tx_signature} amount=${depositPayload.amount_lamports}`,
|
|
777
918
|
"in"
|
|
@@ -849,6 +990,7 @@ var UserCoordinatorSession = class {
|
|
|
849
990
|
const swapId = swapPayload.swap_id;
|
|
850
991
|
const context = {
|
|
851
992
|
swapId,
|
|
993
|
+
requestedAmountLamports: params.amountLamports,
|
|
852
994
|
swapState: "awaiting_dkg",
|
|
853
995
|
syncSecret: new Uint8Array(syncSecret),
|
|
854
996
|
resumeSecret: new Uint8Array(resumeSecret),
|
|
@@ -857,6 +999,14 @@ var UserCoordinatorSession = class {
|
|
|
857
999
|
};
|
|
858
1000
|
this.swapContexts.set(swapId, context);
|
|
859
1001
|
this.setCurrentContext(context);
|
|
1002
|
+
await persistTransferAllocation(this.clientPersistenceState(), {
|
|
1003
|
+
swapId,
|
|
1004
|
+
amountLamports: params.amountLamports,
|
|
1005
|
+
payoutSpec: params.payoutSpec,
|
|
1006
|
+
policySnapshot: swapPayload.policy_snapshot,
|
|
1007
|
+
syncSecret,
|
|
1008
|
+
coordinatorTimestampMs: swapResp.timestamp_ms
|
|
1009
|
+
});
|
|
860
1010
|
await params.onSwapAllocated?.({
|
|
861
1011
|
swapId,
|
|
862
1012
|
syncSecretHex,
|
|
@@ -881,6 +1031,11 @@ var UserCoordinatorSession = class {
|
|
|
881
1031
|
recoveryCommitment = generated.commitment;
|
|
882
1032
|
try {
|
|
883
1033
|
recoveryCodeHex = recoveryCodeToHex(generated.code);
|
|
1034
|
+
await persistTransferRecoveryCode(
|
|
1035
|
+
this.clientPersistenceState(),
|
|
1036
|
+
context.swapId,
|
|
1037
|
+
generated.code
|
|
1038
|
+
);
|
|
884
1039
|
await params.onRecoveryCodeReady?.({ codeHex: recoveryCodeHex });
|
|
885
1040
|
} finally {
|
|
886
1041
|
generated.code.fill(0);
|
|
@@ -917,8 +1072,22 @@ var UserCoordinatorSession = class {
|
|
|
917
1072
|
"DelegateAck spending_policy does not match ContractRequest policy_snapshot"
|
|
918
1073
|
);
|
|
919
1074
|
}
|
|
1075
|
+
if (context.bufferedDepositConfirmed) {
|
|
1076
|
+
assertDepositConfirmedAmount(
|
|
1077
|
+
this.requireProtocol(),
|
|
1078
|
+
context.bufferedDepositConfirmed,
|
|
1079
|
+
params.amountLamports
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
await persistTransferReady(this.clientPersistenceState(), {
|
|
1083
|
+
swapId,
|
|
1084
|
+
depositAddress: solanaAddressFromPublicKeyBytes(jointPublicKey),
|
|
1085
|
+
depositExpiresAtMs,
|
|
1086
|
+
delegatedAtMs: delegateAck.delegated_at_ms,
|
|
1087
|
+
coordinatorTimestampMs
|
|
1088
|
+
});
|
|
920
1089
|
this.log(`delegated at ${delegateAck.delegated_at_ms}`, "in");
|
|
921
|
-
this.releaseDepositConfirmedGate(context);
|
|
1090
|
+
await this.releaseDepositConfirmedGate(context);
|
|
922
1091
|
await params.onDepositAddressReady?.({
|
|
923
1092
|
swapId,
|
|
924
1093
|
jointPublicKey,
|
|
@@ -950,7 +1119,7 @@ var UserCoordinatorSession = class {
|
|
|
950
1119
|
}
|
|
951
1120
|
}
|
|
952
1121
|
}
|
|
953
|
-
async runDkg(context, onDelegateShareReady) {
|
|
1122
|
+
async runDkg(context, onDelegateShareReady, persistDkgMetadata = true) {
|
|
954
1123
|
await ensureFrostWasm();
|
|
955
1124
|
const protocol = this.requireProtocol();
|
|
956
1125
|
const { dkgRound1 } = await loadFrost();
|
|
@@ -1007,6 +1176,14 @@ var UserCoordinatorSession = class {
|
|
|
1007
1176
|
"DKG joint public key mismatch between Alice and coordinator"
|
|
1008
1177
|
);
|
|
1009
1178
|
}
|
|
1179
|
+
if (persistDkgMetadata) {
|
|
1180
|
+
await persistTransferDkgMetadata(this.clientPersistenceState(), {
|
|
1181
|
+
swapId: context.swapId,
|
|
1182
|
+
depositAddress: solanaAddressFromPublicKeyBytes(alicePubkey),
|
|
1183
|
+
depositExpiresAtMs: complete.depositExpiresAtMs,
|
|
1184
|
+
coordinatorTimestampMs: complete.coordinatorTimestampMs
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1010
1187
|
const pubkeyHexPrefix = Array.from(alicePubkey.slice(0, 8)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1011
1188
|
this.log(`DKG complete - joint pubkey ${pubkeyHexPrefix}`, "info");
|
|
1012
1189
|
return {
|
|
@@ -1081,6 +1258,18 @@ var UserCoordinatorSession = class {
|
|
|
1081
1258
|
handleEnvelope(env) {
|
|
1082
1259
|
const protocol = this.requireProtocol();
|
|
1083
1260
|
this.log(`<- ${env.type} kind=${env.kind}`, "in");
|
|
1261
|
+
if (env.kind === EnvelopeKind.PUSH) {
|
|
1262
|
+
if (env.swap_id === null) {
|
|
1263
|
+
this.log(`ignored ${env.type} without an explicit swap_id`, "info");
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
if (!this.swapContexts.has(env.swap_id)) {
|
|
1267
|
+
this.log(`ignored ${env.type} for unknown swap ${env.swap_id}`, "info");
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
this.enqueuePush(env);
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1084
1273
|
const context = env.swap_id ? this.swapContexts.get(env.swap_id) ?? null : null;
|
|
1085
1274
|
if (env.swap_id === null && env.kind !== EnvelopeKind.ERROR) {
|
|
1086
1275
|
this.log(`ignored ${env.type} without an explicit swap_id`, "info");
|
|
@@ -1090,27 +1279,8 @@ var UserCoordinatorSession = class {
|
|
|
1090
1279
|
this.log(`ignored ${env.type} for unknown swap ${env.swap_id}`, "info");
|
|
1091
1280
|
return;
|
|
1092
1281
|
}
|
|
1093
|
-
const payoutExecuted = env.kind === EnvelopeKind.PUSH && env.type === CoordinatorMessageType.PayoutExecuted ? protocol.asPayoutExecutedPayload(env) : null;
|
|
1094
|
-
const payoutMatchesCurrentSwap = payoutExecuted !== null && context !== null;
|
|
1095
|
-
const refundExecuted = env.kind === EnvelopeKind.PUSH && env.type === CoordinatorMessageType.WithdrawExecuted ? protocol.asWithdrawExecutedPayload(env) : null;
|
|
1096
|
-
if (this.shouldBufferDepositConfirmed(env)) {
|
|
1097
|
-
this.bufferDepositConfirmed(env);
|
|
1098
|
-
return;
|
|
1099
|
-
}
|
|
1100
1282
|
const stateForEnvelope = context?.swapState ?? this.swapState;
|
|
1101
|
-
const next =
|
|
1102
|
-
stateForEnvelope,
|
|
1103
|
-
env.kind,
|
|
1104
|
-
env.type,
|
|
1105
|
-
payoutExecuted ? { payoutFinal: payoutExecuted.final } : void 0
|
|
1106
|
-
);
|
|
1107
|
-
if (env.kind === EnvelopeKind.PUSH && next === null) {
|
|
1108
|
-
this.log(
|
|
1109
|
-
`ignored ${env.type} for swap ${env.swap_id ?? "null"} while client context is ${context?.swapId ?? "none"} in state ${stateForEnvelope}`,
|
|
1110
|
-
"info"
|
|
1111
|
-
);
|
|
1112
|
-
return;
|
|
1113
|
-
}
|
|
1283
|
+
const next = protocol.nextState(stateForEnvelope, env.kind, env.type);
|
|
1114
1284
|
if (next !== null) {
|
|
1115
1285
|
if (context) {
|
|
1116
1286
|
this.updateContextState(context, next);
|
|
@@ -1128,18 +1298,165 @@ var UserCoordinatorSession = class {
|
|
|
1128
1298
|
}
|
|
1129
1299
|
return;
|
|
1130
1300
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1301
|
+
}
|
|
1302
|
+
enqueuePush(env) {
|
|
1303
|
+
const swapId = env.swap_id;
|
|
1304
|
+
if (swapId === null) return;
|
|
1305
|
+
const context = this.swapContexts.get(swapId);
|
|
1306
|
+
if (context === void 0) return;
|
|
1307
|
+
const persistence = this.clientPersistenceState();
|
|
1308
|
+
void this.enqueueSwapProcessing(
|
|
1309
|
+
swapId,
|
|
1310
|
+
() => this.processPushEnvelope(env, context, persistence)
|
|
1311
|
+
).catch(() => void 0);
|
|
1312
|
+
}
|
|
1313
|
+
enqueueSwapProcessing(swapId, process) {
|
|
1314
|
+
const previous = this.pushProcessing.get(swapId) ?? Promise.resolve();
|
|
1315
|
+
const processing = previous.catch(() => void 0).then(process);
|
|
1316
|
+
this.pushProcessing.set(swapId, processing);
|
|
1317
|
+
void processing.finally(() => {
|
|
1318
|
+
if (this.pushProcessing.get(swapId) === processing) {
|
|
1319
|
+
this.pushProcessing.delete(swapId);
|
|
1320
|
+
}
|
|
1321
|
+
}).catch(() => void 0);
|
|
1322
|
+
return processing;
|
|
1323
|
+
}
|
|
1324
|
+
async waitForPushProcessing(swapId) {
|
|
1325
|
+
if (swapId === null) return;
|
|
1326
|
+
await (this.pushProcessing.get(swapId)?.catch(() => void 0) ?? Promise.resolve());
|
|
1327
|
+
}
|
|
1328
|
+
async processPushEnvelope(env, context, persistence) {
|
|
1329
|
+
const protocol = this.requireProtocol();
|
|
1330
|
+
const payoutExecuted = env.type === CoordinatorMessageType.PayoutExecuted ? protocol.asPayoutExecutedPayload(env) : null;
|
|
1331
|
+
const refundExecuted = env.type === CoordinatorMessageType.WithdrawExecuted ? protocol.asWithdrawExecutedPayload(env) : null;
|
|
1332
|
+
if (this.shouldBufferDepositConfirmed(env)) {
|
|
1333
|
+
this.bufferDepositConfirmed(env);
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
if (env.type === CoordinatorMessageType.DkgComplete) {
|
|
1337
|
+
this.settlePushListener(env);
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
if (env.type === CoordinatorMessageType.DepositConfirmed) {
|
|
1341
|
+
if (context.requestedAmountLamports === null) {
|
|
1342
|
+
this.log(
|
|
1343
|
+
`ignored DepositConfirmed for swap ${context.swapId} without requested amount`,
|
|
1344
|
+
"info"
|
|
1345
|
+
);
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
try {
|
|
1349
|
+
assertDepositConfirmedAmount(protocol, env, context.requestedAmountLamports);
|
|
1350
|
+
} catch (error) {
|
|
1351
|
+
this.settlePushListener(env, error instanceof Error ? error : new Error(String(error)));
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
const next = protocol.nextState(
|
|
1356
|
+
context.swapState,
|
|
1357
|
+
env.kind,
|
|
1358
|
+
env.type,
|
|
1359
|
+
payoutExecuted ? { payoutFinal: payoutExecuted.final } : void 0
|
|
1360
|
+
);
|
|
1361
|
+
if (next === null) {
|
|
1362
|
+
this.log(
|
|
1363
|
+
`ignored ${env.type} for swap ${env.swap_id ?? "null"} while client context is ${context.swapId} in state ${context.swapState}`,
|
|
1364
|
+
"info"
|
|
1365
|
+
);
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
if (env.type === CoordinatorMessageType.DelegateAck) {
|
|
1369
|
+
if (!this.isActiveSwapContext(context)) {
|
|
1370
|
+
context.swapState = next;
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
this.updateContextState(context, next);
|
|
1374
|
+
this.settlePushListener(env);
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
if (isTerminalSwapState(next)) {
|
|
1378
|
+
await this.handleTerminalPush(
|
|
1379
|
+
env,
|
|
1380
|
+
context,
|
|
1381
|
+
next,
|
|
1382
|
+
payoutExecuted,
|
|
1383
|
+
refundExecuted,
|
|
1384
|
+
persistence
|
|
1385
|
+
);
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
await this.handleNonTerminalPush(env, context, next, payoutExecuted, persistence);
|
|
1389
|
+
}
|
|
1390
|
+
async handleNonTerminalPush(env, context, next, payoutExecuted, persistence) {
|
|
1391
|
+
if (!this.isActiveSwapContext(context)) {
|
|
1392
|
+
context.swapState = next;
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
let storageError = null;
|
|
1396
|
+
try {
|
|
1397
|
+
await persistTransferStatus(persistence, context.swapId, { state: next }, env.timestamp_ms);
|
|
1398
|
+
} catch (error) {
|
|
1399
|
+
storageError = storageErrorFromPush(error, context.swapId, null);
|
|
1400
|
+
}
|
|
1401
|
+
if (!this.isActiveSwapContext(context)) {
|
|
1402
|
+
context.swapState = next;
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
try {
|
|
1406
|
+
this.updateContextState(context, next);
|
|
1407
|
+
if (payoutExecuted) this.emitPayoutExecuted(payoutExecuted, context.swapId);
|
|
1408
|
+
} finally {
|
|
1409
|
+
try {
|
|
1410
|
+
if (storageError) this.emitStorageError(storageError);
|
|
1411
|
+
} finally {
|
|
1412
|
+
this.settlePushListener(env);
|
|
1134
1413
|
}
|
|
1135
|
-
|
|
1136
|
-
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
async handleTerminalPush(env, context, next, payoutExecuted, refundExecuted, persistence) {
|
|
1417
|
+
this.rememberTerminalOutcome(context.swapId, next, refundExecuted);
|
|
1418
|
+
let storageError = null;
|
|
1419
|
+
if (persistence.enabled) {
|
|
1420
|
+
try {
|
|
1421
|
+
await persistTransferTerminal(
|
|
1422
|
+
persistence,
|
|
1423
|
+
context.swapId,
|
|
1424
|
+
next,
|
|
1425
|
+
env.timestamp_ms,
|
|
1426
|
+
refundExecuted ? "refund" : "sync"
|
|
1427
|
+
);
|
|
1428
|
+
} catch (error) {
|
|
1429
|
+
storageError = storageErrorFromPush(error, context.swapId, refundExecuted);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
if (storageError) {
|
|
1433
|
+
this.rememberTerminalOutcome(context.swapId, next, refundExecuted, storageError);
|
|
1434
|
+
}
|
|
1435
|
+
if (!this.isActiveSwapContext(context)) {
|
|
1436
|
+
context.swapState = next;
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
try {
|
|
1440
|
+
this.updateContextState(context, next);
|
|
1441
|
+
if (payoutExecuted) this.emitPayoutExecuted(payoutExecuted, context.swapId);
|
|
1442
|
+
if (refundExecuted) this.emitRefundExecuted(refundExecuted, context.swapId);
|
|
1443
|
+
} finally {
|
|
1444
|
+
try {
|
|
1445
|
+
if (storageError) this.emitStorageError(storageError);
|
|
1446
|
+
} finally {
|
|
1447
|
+
this.settlePushListener(env);
|
|
1137
1448
|
}
|
|
1138
|
-
this.resolvePushListener(env);
|
|
1139
1449
|
}
|
|
1140
1450
|
}
|
|
1451
|
+
emitStorageError(error) {
|
|
1452
|
+
for (const listener of this.storageErrorListeners) listener(error);
|
|
1453
|
+
this.log(`client persistence failed: ${normalizeError(error)}`, "info");
|
|
1454
|
+
}
|
|
1141
1455
|
applySwapStatus(context, status, coordinatorTimestampMs) {
|
|
1142
1456
|
const keepTerminalState = TERMINAL_SWAP_STATES.has(context.swapState) && status.state !== context.swapState;
|
|
1457
|
+
if (!keepTerminalState && isTerminalSwapState(status.state)) {
|
|
1458
|
+
this.rememberTerminalOutcome(context.swapId, status.state, status.withdraw_execution);
|
|
1459
|
+
}
|
|
1143
1460
|
if (!keepTerminalState && context.swapState !== status.state) {
|
|
1144
1461
|
this.updateContextState(context, status.state);
|
|
1145
1462
|
}
|
|
@@ -1237,7 +1554,7 @@ var UserCoordinatorSession = class {
|
|
|
1237
1554
|
}
|
|
1238
1555
|
this.log("ignored duplicate DepositConfirmed while waiting for DelegateAck", "info");
|
|
1239
1556
|
}
|
|
1240
|
-
releaseDepositConfirmedGate(context) {
|
|
1557
|
+
async releaseDepositConfirmedGate(context) {
|
|
1241
1558
|
const protocol = this.requireProtocol();
|
|
1242
1559
|
context.bufferDepositConfirmedUntilDelegateAck = false;
|
|
1243
1560
|
const buffered = context.bufferedDepositConfirmed;
|
|
@@ -1248,10 +1565,26 @@ var UserCoordinatorSession = class {
|
|
|
1248
1565
|
this.log(`ignored buffered DepositConfirmed in state ${context.swapState}`, "info");
|
|
1249
1566
|
return;
|
|
1250
1567
|
}
|
|
1568
|
+
let storageError = null;
|
|
1569
|
+
try {
|
|
1570
|
+
await persistTransferStatus(
|
|
1571
|
+
this.clientPersistenceState(),
|
|
1572
|
+
context.swapId,
|
|
1573
|
+
{ state: next },
|
|
1574
|
+
buffered.timestamp_ms
|
|
1575
|
+
);
|
|
1576
|
+
} catch (error) {
|
|
1577
|
+
storageError = storageErrorFromPush(error, context.swapId, null);
|
|
1578
|
+
}
|
|
1579
|
+
if (storageError) {
|
|
1580
|
+
this.emitStorageError(storageError);
|
|
1581
|
+
throw storageError;
|
|
1582
|
+
}
|
|
1583
|
+
if (!this.isActiveSwapContext(context)) return;
|
|
1251
1584
|
this.updateContextState(context, next);
|
|
1252
|
-
this.
|
|
1585
|
+
this.settlePushListener(buffered);
|
|
1253
1586
|
}
|
|
1254
|
-
|
|
1587
|
+
settlePushListener(env, error) {
|
|
1255
1588
|
const listeners = this.pushListeners.get(env.type);
|
|
1256
1589
|
if (!listeners) return;
|
|
1257
1590
|
const index = listeners.findIndex(
|
|
@@ -1261,7 +1594,8 @@ var UserCoordinatorSession = class {
|
|
|
1261
1594
|
const listener = listeners.splice(index, 1)[0];
|
|
1262
1595
|
if (listeners.length === 0) this.pushListeners.delete(env.type);
|
|
1263
1596
|
if (listener.timer) clearTimeout(listener.timer);
|
|
1264
|
-
listener.
|
|
1597
|
+
if (error) listener.reject(error);
|
|
1598
|
+
else listener.resolve(env);
|
|
1265
1599
|
}
|
|
1266
1600
|
clearPushListenerTimer(type, swapId) {
|
|
1267
1601
|
const listener = this.pushListeners.get(type)?.find((candidate) => candidate.swapId === void 0 || candidate.swapId === swapId);
|
|
@@ -1420,6 +1754,12 @@ async function requestUserSync(session, swapId, syncSecret, timeoutMs) {
|
|
|
1420
1754
|
);
|
|
1421
1755
|
const payload = (await loadProtocol()).asSyncUserResponsePayload(env);
|
|
1422
1756
|
assertSyncResponseContractId(env, payload, swapId);
|
|
1757
|
+
await persistTransferStatus(
|
|
1758
|
+
getSessionState(session).clientPersistence,
|
|
1759
|
+
swapId,
|
|
1760
|
+
payload,
|
|
1761
|
+
env.timestamp_ms
|
|
1762
|
+
);
|
|
1423
1763
|
return {
|
|
1424
1764
|
...payload,
|
|
1425
1765
|
coordinatorTimestampMs: env.timestamp_ms
|
|
@@ -1503,6 +1843,18 @@ function isRetryableSwapStatusReconciliationError(err) {
|
|
|
1503
1843
|
if (err instanceof AttestationError) return false;
|
|
1504
1844
|
return err instanceof CommandError && err.code === "REJECTED_STALE_JOB";
|
|
1505
1845
|
}
|
|
1846
|
+
function isTerminalSwapState(state) {
|
|
1847
|
+
return state === "completed" || state === "refunded" || state === "failed";
|
|
1848
|
+
}
|
|
1849
|
+
function storageErrorFromPush(error, swapId, refundExecuted) {
|
|
1850
|
+
if (error instanceof StorageError) return error;
|
|
1851
|
+
return new StorageError("STORAGE_NOT_AVAILABLE", "client persistence update failed", {
|
|
1852
|
+
cause: error,
|
|
1853
|
+
swapId,
|
|
1854
|
+
phase: refundExecuted ? "refund" : "sync",
|
|
1855
|
+
remoteAccepted: true
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1506
1858
|
function coordinatorErrorFromEnvelope(protocol, env) {
|
|
1507
1859
|
try {
|
|
1508
1860
|
const payload = protocol.asErrorPayload(env);
|