@unicitylabs/sphere-sdk 0.14.5 → 0.14.6-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/connect/index.cjs +1 -1
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +1 -1
- package/dist/connect/index.js.map +1 -1
- package/dist/core/index.cjs +94 -61
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +94 -61
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/connect/index.cjs +1 -1
- package/dist/impl/browser/connect/index.cjs.map +1 -1
- package/dist/impl/browser/connect/index.js +1 -1
- package/dist/impl/browser/connect/index.js.map +1 -1
- package/dist/impl/wallet-api-v2/index.cjs.map +1 -1
- package/dist/impl/wallet-api-v2/index.js.map +1 -1
- package/dist/index.cjs +94 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +94 -61
- package/dist/index.js.map +1 -1
- package/dist/modules/payments-v2/index.cjs +20 -14
- package/dist/modules/payments-v2/index.cjs.map +1 -1
- package/dist/modules/payments-v2/index.js +20 -14
- package/dist/modules/payments-v2/index.js.map +1 -1
- package/dist/token-engine/index.cjs +86 -59
- package/dist/token-engine/index.cjs.map +1 -1
- package/dist/token-engine/index.js +86 -59
- package/dist/token-engine/index.js.map +1 -1
- package/package.json +1 -1
package/dist/core/index.js
CHANGED
|
@@ -9397,7 +9397,18 @@ function pause(ms, signal) {
|
|
|
9397
9397
|
);
|
|
9398
9398
|
});
|
|
9399
9399
|
}
|
|
9400
|
-
async function
|
|
9400
|
+
async function retryTransient(attempt, signal, intervalMs) {
|
|
9401
|
+
for (; ; ) {
|
|
9402
|
+
try {
|
|
9403
|
+
return await attempt();
|
|
9404
|
+
} catch (err) {
|
|
9405
|
+
if (signal.aborted) throw err;
|
|
9406
|
+
if (!isTransientGatewayError(err)) throw err;
|
|
9407
|
+
await pause(intervalMs, signal);
|
|
9408
|
+
}
|
|
9409
|
+
}
|
|
9410
|
+
}
|
|
9411
|
+
function certificationDeadline(timeoutMs, external, label) {
|
|
9401
9412
|
const controller = new AbortController();
|
|
9402
9413
|
const relayAbort = () => {
|
|
9403
9414
|
controller.abort(external?.reason);
|
|
@@ -9407,34 +9418,29 @@ async function awaitProofBounded(deps, transaction, external) {
|
|
|
9407
9418
|
else external.addEventListener("abort", relayAbort, { once: true });
|
|
9408
9419
|
}
|
|
9409
9420
|
const timer = setTimeout(() => {
|
|
9410
|
-
controller.abort(
|
|
9411
|
-
|
|
9412
|
-
|
|
9413
|
-
|
|
9414
|
-
|
|
9415
|
-
|
|
9416
|
-
|
|
9417
|
-
try {
|
|
9418
|
-
for (; ; ) {
|
|
9419
|
-
try {
|
|
9420
|
-
return await waitInclusionProof(
|
|
9421
|
-
deps.client,
|
|
9422
|
-
deps.trustBase,
|
|
9423
|
-
deps.predicateVerifier,
|
|
9424
|
-
transaction,
|
|
9425
|
-
controller.signal,
|
|
9426
|
-
deps.intervalMs
|
|
9427
|
-
);
|
|
9428
|
-
} catch (err) {
|
|
9429
|
-
if (controller.signal.aborted) throw err;
|
|
9430
|
-
if (!isTransientGatewayError(err)) throw err;
|
|
9431
|
-
await pause(deps.intervalMs, controller.signal);
|
|
9432
|
-
}
|
|
9421
|
+
controller.abort(new SphereError(`${label} within ${String(timeoutMs)} ms`, "AGGREGATOR_ERROR"));
|
|
9422
|
+
}, timeoutMs);
|
|
9423
|
+
return {
|
|
9424
|
+
signal: controller.signal,
|
|
9425
|
+
dispose: () => {
|
|
9426
|
+
clearTimeout(timer);
|
|
9427
|
+
external?.removeEventListener("abort", relayAbort);
|
|
9433
9428
|
}
|
|
9434
|
-
}
|
|
9435
|
-
|
|
9436
|
-
|
|
9437
|
-
|
|
9429
|
+
};
|
|
9430
|
+
}
|
|
9431
|
+
async function awaitProofBounded(deps, transaction, signal) {
|
|
9432
|
+
return retryTransient(
|
|
9433
|
+
() => waitInclusionProof(
|
|
9434
|
+
deps.client,
|
|
9435
|
+
deps.trustBase,
|
|
9436
|
+
deps.predicateVerifier,
|
|
9437
|
+
transaction,
|
|
9438
|
+
signal,
|
|
9439
|
+
deps.intervalMs
|
|
9440
|
+
),
|
|
9441
|
+
signal,
|
|
9442
|
+
deps.intervalMs
|
|
9443
|
+
);
|
|
9438
9444
|
}
|
|
9439
9445
|
|
|
9440
9446
|
// token-engine/errors.ts
|
|
@@ -9476,6 +9482,21 @@ var CheckpointTrustbaseMismatchError = class extends SphereError {
|
|
|
9476
9482
|
}
|
|
9477
9483
|
};
|
|
9478
9484
|
|
|
9485
|
+
// token-engine/certification-outcome.ts
|
|
9486
|
+
function certificationFailure(err, failLabel, submitError, submitRejectedCleanly) {
|
|
9487
|
+
if (err instanceof Error && err.message === `Invalid inclusion proof status: ${InclusionProofVerificationStatus.TRANSACTION_HASH_MISMATCH}`) {
|
|
9488
|
+
return new TransferConflictError(
|
|
9489
|
+
`${failLabel}: the source state was already consumed by a different transaction (lost race \u2014 abort this intent and re-plan under a new transferId)`,
|
|
9490
|
+
err
|
|
9491
|
+
);
|
|
9492
|
+
}
|
|
9493
|
+
if (submitRejectedCleanly) return submitError;
|
|
9494
|
+
return new ProofUnconfirmedError(
|
|
9495
|
+
`${failLabel}: certification unconfirmed \u2014 the source spend may be on-chain; keep the intent open and resume under the same transferId`,
|
|
9496
|
+
submitError ?? err
|
|
9497
|
+
);
|
|
9498
|
+
}
|
|
9499
|
+
|
|
9479
9500
|
// token-engine/token-blob.ts
|
|
9480
9501
|
var TOKEN_BLOB_TAG = 39051n;
|
|
9481
9502
|
var TOKEN_BLOB_VERSION = 1;
|
|
@@ -9998,10 +10019,28 @@ var SphereTokenEngine = class {
|
|
|
9998
10019
|
* failure, not a resume case).
|
|
9999
10020
|
*/
|
|
10000
10021
|
async submitAndAwaitProof(certificationData, transaction, failLabel, failCode, options) {
|
|
10022
|
+
const deadline = certificationDeadline(
|
|
10023
|
+
this.proofTimeoutMs,
|
|
10024
|
+
options?.signal,
|
|
10025
|
+
`${failLabel}: not certified`
|
|
10026
|
+
);
|
|
10027
|
+
try {
|
|
10028
|
+
return await this.submitThenProve(certificationData, transaction, failLabel, failCode, deadline.signal);
|
|
10029
|
+
} finally {
|
|
10030
|
+
deadline.dispose();
|
|
10031
|
+
}
|
|
10032
|
+
}
|
|
10033
|
+
/** One certification attempt under one deadline: the metered submit retries
|
|
10034
|
+
* transient answers instead of falling through to a proof that cannot exist. */
|
|
10035
|
+
async submitThenProve(certificationData, transaction, failLabel, failCode, signal) {
|
|
10001
10036
|
let submitError = null;
|
|
10002
10037
|
let submitRejectedCleanly = false;
|
|
10003
10038
|
try {
|
|
10004
|
-
const response = await
|
|
10039
|
+
const response = await retryTransient(
|
|
10040
|
+
() => this.deps.client.submitCertificationRequest(certificationData),
|
|
10041
|
+
signal,
|
|
10042
|
+
this.deps.proofPollIntervalMs ?? DEFAULT_PROOF_POLL_INTERVAL_MS
|
|
10043
|
+
);
|
|
10005
10044
|
if (response.status !== CertificationStatus.SUCCESS) {
|
|
10006
10045
|
submitError = new SphereError(`${failLabel}: ${response.status}`, failCode);
|
|
10007
10046
|
submitRejectedCleanly = CLEAN_REJECT_STATUSES.has(response.status);
|
|
@@ -10015,33 +10054,21 @@ var SphereTokenEngine = class {
|
|
|
10015
10054
|
client: this.deps.client,
|
|
10016
10055
|
trustBase: this.deps.trustBase,
|
|
10017
10056
|
predicateVerifier: this.deps.predicateVerifier,
|
|
10018
|
-
timeoutMs: this.proofTimeoutMs,
|
|
10019
10057
|
intervalMs: this.deps.proofPollIntervalMs ?? DEFAULT_PROOF_POLL_INTERVAL_MS
|
|
10020
10058
|
// #683
|
|
10021
10059
|
},
|
|
10022
10060
|
transaction,
|
|
10023
|
-
|
|
10061
|
+
signal
|
|
10024
10062
|
);
|
|
10025
10063
|
} catch (err) {
|
|
10026
|
-
|
|
10027
|
-
throw new TransferConflictError(
|
|
10028
|
-
`${failLabel}: the source state was already consumed by a different transaction (lost race \u2014 abort this intent and re-plan under a new transferId)`,
|
|
10029
|
-
err
|
|
10030
|
-
);
|
|
10031
|
-
}
|
|
10032
|
-
if (submitRejectedCleanly) throw submitError;
|
|
10033
|
-
throw new ProofUnconfirmedError(
|
|
10034
|
-
`${failLabel}: certification unconfirmed \u2014 the source spend may be on-chain; keep the intent open and resume under the same transferId`,
|
|
10035
|
-
submitError ?? err
|
|
10036
|
-
);
|
|
10064
|
+
throw certificationFailure(err, failLabel, submitError, submitRejectedCleanly);
|
|
10037
10065
|
}
|
|
10038
10066
|
}
|
|
10039
10067
|
/**
|
|
10040
|
-
* One inclusion-proof wait, with the deadline OWNED here (#739)
|
|
10041
|
-
*
|
|
10042
|
-
*
|
|
10043
|
-
*
|
|
10044
|
-
* (keep-open), which is the correct posture: the spend may be on-chain.
|
|
10068
|
+
* One inclusion-proof wait, with the deadline OWNED here (#739) so it is bounded
|
|
10069
|
+
* and configurable rather than the SDK's fixed default. A hit throws, and the
|
|
10070
|
+
* caller maps it to ProofUnconfirmedError (keep-open) — the correct posture,
|
|
10071
|
+
* since the spend may be on-chain.
|
|
10045
10072
|
*/
|
|
10046
10073
|
/** Fail fast if this engine's key does not own the token's current state. */
|
|
10047
10074
|
assertOwned(token) {
|
|
@@ -11376,7 +11403,7 @@ function createMachineStores(kv) {
|
|
|
11376
11403
|
}
|
|
11377
11404
|
|
|
11378
11405
|
// modules/payments-v2/machine/TransferMachine.ts
|
|
11379
|
-
var CERTIFY_WIDTH =
|
|
11406
|
+
var CERTIFY_WIDTH = 20;
|
|
11380
11407
|
var KEEP_OPEN_CODES = /* @__PURE__ */ new Set([
|
|
11381
11408
|
"CERTIFICATION_UNCONFIRMED",
|
|
11382
11409
|
"CHECKPOINT_PERSIST_FAILED",
|
|
@@ -11472,12 +11499,15 @@ var TransferMachine = class {
|
|
|
11472
11499
|
payload: r.payload,
|
|
11473
11500
|
...r.payload.memo !== void 0 ? { memo: r.payload.memo } : {}
|
|
11474
11501
|
};
|
|
11475
|
-
const
|
|
11502
|
+
const outcomes = await this.resumeOps(ctx, engine, r);
|
|
11503
|
+
const { committed, cls, firstError } = summarize(outcomes);
|
|
11504
|
+
const conflicts = this.toConflicts(engine, r, outcomes);
|
|
11476
11505
|
if (committed.length === 0 && conflicts.length > 0) throw conflicts[0].error;
|
|
11477
11506
|
let deliveryPending = false;
|
|
11478
11507
|
if (committed.length > 0) {
|
|
11479
11508
|
deliveryPending = await this.deliverSet(r.transferId, r.payload.recipient, r.payload.memo, committed);
|
|
11480
11509
|
}
|
|
11510
|
+
if (cls !== null && cls !== "conflict") throw firstError;
|
|
11481
11511
|
await this.applyCommitted(engine, r.transferId, committed);
|
|
11482
11512
|
if (conflicts.length > 0) {
|
|
11483
11513
|
return { deliveryPending, partial: await this.settlePartial(engine, r, committed, conflicts) };
|
|
@@ -11562,25 +11592,28 @@ var TransferMachine = class {
|
|
|
11562
11592
|
);
|
|
11563
11593
|
return { recipientBlob: outputs[0].blob.token, changeBlob: outputs[1].blob.token };
|
|
11564
11594
|
}
|
|
11595
|
+
/** Raw outcomes; `summarize` alone decides what they mean — same as the send path. */
|
|
11565
11596
|
async resumeOps(ctx, engine, r) {
|
|
11566
|
-
const
|
|
11567
|
-
const conflicts = [];
|
|
11597
|
+
const outcomes = [];
|
|
11568
11598
|
for (const op of buildOps(r.payload)) {
|
|
11569
11599
|
const journaled = op.kind === "direct" ? r.journaled.get(op.opIndex) : void 0;
|
|
11570
11600
|
if (journaled !== void 0) {
|
|
11571
|
-
|
|
11601
|
+
outcomes.push({ op, certified: true, recipientBlob: hexToBytes4(journaled.blobHex) });
|
|
11572
11602
|
continue;
|
|
11573
11603
|
}
|
|
11574
|
-
|
|
11575
|
-
const
|
|
11576
|
-
if (
|
|
11577
|
-
committed.push(outcome);
|
|
11578
|
-
continue;
|
|
11579
|
-
}
|
|
11580
|
-
if (classifyError(outcome.error) !== "conflict") throw outcome.error;
|
|
11581
|
-
conflicts.push({ op, error: outcome.error, amount: conflictAmount(engine, r.payload, op, source) });
|
|
11604
|
+
outcomes.push(await this.certifyOne(ctx, engine, op, r.sources.get(op.sourceTokenId)));
|
|
11605
|
+
const last = outcomes[outcomes.length - 1];
|
|
11606
|
+
if (last.error !== void 0 && classifyError(last.error) !== "conflict") break;
|
|
11582
11607
|
}
|
|
11583
|
-
return
|
|
11608
|
+
return outcomes;
|
|
11609
|
+
}
|
|
11610
|
+
/** Conflicted ops with the amount each leaves undelivered (#690 shortfall math). */
|
|
11611
|
+
toConflicts(engine, r, outcomes) {
|
|
11612
|
+
return outcomes.filter((o) => !o.certified && classifyError(o.error) === "conflict").map((o) => ({
|
|
11613
|
+
op: o.op,
|
|
11614
|
+
error: o.error,
|
|
11615
|
+
amount: conflictAmount(engine, r.payload, o.op, r.sources.get(o.op.sourceTokenId))
|
|
11616
|
+
}));
|
|
11584
11617
|
}
|
|
11585
11618
|
async deliverSet(transferId, recipientPubkey, memo, committed) {
|
|
11586
11619
|
const journaled = committed.filter((o) => o.error === void 0 && o.recipientBlob !== void 0);
|