@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.cjs
CHANGED
|
@@ -9483,7 +9483,18 @@ function pause(ms, signal) {
|
|
|
9483
9483
|
);
|
|
9484
9484
|
});
|
|
9485
9485
|
}
|
|
9486
|
-
async function
|
|
9486
|
+
async function retryTransient(attempt, signal, intervalMs) {
|
|
9487
|
+
for (; ; ) {
|
|
9488
|
+
try {
|
|
9489
|
+
return await attempt();
|
|
9490
|
+
} catch (err) {
|
|
9491
|
+
if (signal.aborted) throw err;
|
|
9492
|
+
if (!isTransientGatewayError(err)) throw err;
|
|
9493
|
+
await pause(intervalMs, signal);
|
|
9494
|
+
}
|
|
9495
|
+
}
|
|
9496
|
+
}
|
|
9497
|
+
function certificationDeadline(timeoutMs, external, label) {
|
|
9487
9498
|
const controller = new AbortController();
|
|
9488
9499
|
const relayAbort = () => {
|
|
9489
9500
|
controller.abort(external?.reason);
|
|
@@ -9493,34 +9504,29 @@ async function awaitProofBounded(deps, transaction, external) {
|
|
|
9493
9504
|
else external.addEventListener("abort", relayAbort, { once: true });
|
|
9494
9505
|
}
|
|
9495
9506
|
const timer = setTimeout(() => {
|
|
9496
|
-
controller.abort(
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9501
|
-
|
|
9502
|
-
|
|
9503
|
-
try {
|
|
9504
|
-
for (; ; ) {
|
|
9505
|
-
try {
|
|
9506
|
-
return await (0, import_InclusionProofUtils.waitInclusionProof)(
|
|
9507
|
-
deps.client,
|
|
9508
|
-
deps.trustBase,
|
|
9509
|
-
deps.predicateVerifier,
|
|
9510
|
-
transaction,
|
|
9511
|
-
controller.signal,
|
|
9512
|
-
deps.intervalMs
|
|
9513
|
-
);
|
|
9514
|
-
} catch (err) {
|
|
9515
|
-
if (controller.signal.aborted) throw err;
|
|
9516
|
-
if (!isTransientGatewayError(err)) throw err;
|
|
9517
|
-
await pause(deps.intervalMs, controller.signal);
|
|
9518
|
-
}
|
|
9507
|
+
controller.abort(new SphereError(`${label} within ${String(timeoutMs)} ms`, "AGGREGATOR_ERROR"));
|
|
9508
|
+
}, timeoutMs);
|
|
9509
|
+
return {
|
|
9510
|
+
signal: controller.signal,
|
|
9511
|
+
dispose: () => {
|
|
9512
|
+
clearTimeout(timer);
|
|
9513
|
+
external?.removeEventListener("abort", relayAbort);
|
|
9519
9514
|
}
|
|
9520
|
-
}
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9515
|
+
};
|
|
9516
|
+
}
|
|
9517
|
+
async function awaitProofBounded(deps, transaction, signal) {
|
|
9518
|
+
return retryTransient(
|
|
9519
|
+
() => (0, import_InclusionProofUtils.waitInclusionProof)(
|
|
9520
|
+
deps.client,
|
|
9521
|
+
deps.trustBase,
|
|
9522
|
+
deps.predicateVerifier,
|
|
9523
|
+
transaction,
|
|
9524
|
+
signal,
|
|
9525
|
+
deps.intervalMs
|
|
9526
|
+
),
|
|
9527
|
+
signal,
|
|
9528
|
+
deps.intervalMs
|
|
9529
|
+
);
|
|
9524
9530
|
}
|
|
9525
9531
|
|
|
9526
9532
|
// token-engine/errors.ts
|
|
@@ -9562,6 +9568,21 @@ var CheckpointTrustbaseMismatchError = class extends SphereError {
|
|
|
9562
9568
|
}
|
|
9563
9569
|
};
|
|
9564
9570
|
|
|
9571
|
+
// token-engine/certification-outcome.ts
|
|
9572
|
+
function certificationFailure(err, failLabel, submitError, submitRejectedCleanly) {
|
|
9573
|
+
if (err instanceof Error && err.message === `Invalid inclusion proof status: ${import_InclusionProofVerificationRule.InclusionProofVerificationStatus.TRANSACTION_HASH_MISMATCH}`) {
|
|
9574
|
+
return new TransferConflictError(
|
|
9575
|
+
`${failLabel}: the source state was already consumed by a different transaction (lost race \u2014 abort this intent and re-plan under a new transferId)`,
|
|
9576
|
+
err
|
|
9577
|
+
);
|
|
9578
|
+
}
|
|
9579
|
+
if (submitRejectedCleanly) return submitError;
|
|
9580
|
+
return new ProofUnconfirmedError(
|
|
9581
|
+
`${failLabel}: certification unconfirmed \u2014 the source spend may be on-chain; keep the intent open and resume under the same transferId`,
|
|
9582
|
+
submitError ?? err
|
|
9583
|
+
);
|
|
9584
|
+
}
|
|
9585
|
+
|
|
9565
9586
|
// token-engine/token-blob.ts
|
|
9566
9587
|
var TOKEN_BLOB_TAG = 39051n;
|
|
9567
9588
|
var TOKEN_BLOB_VERSION = 1;
|
|
@@ -10084,10 +10105,28 @@ var SphereTokenEngine = class {
|
|
|
10084
10105
|
* failure, not a resume case).
|
|
10085
10106
|
*/
|
|
10086
10107
|
async submitAndAwaitProof(certificationData, transaction, failLabel, failCode, options) {
|
|
10108
|
+
const deadline = certificationDeadline(
|
|
10109
|
+
this.proofTimeoutMs,
|
|
10110
|
+
options?.signal,
|
|
10111
|
+
`${failLabel}: not certified`
|
|
10112
|
+
);
|
|
10113
|
+
try {
|
|
10114
|
+
return await this.submitThenProve(certificationData, transaction, failLabel, failCode, deadline.signal);
|
|
10115
|
+
} finally {
|
|
10116
|
+
deadline.dispose();
|
|
10117
|
+
}
|
|
10118
|
+
}
|
|
10119
|
+
/** One certification attempt under one deadline: the metered submit retries
|
|
10120
|
+
* transient answers instead of falling through to a proof that cannot exist. */
|
|
10121
|
+
async submitThenProve(certificationData, transaction, failLabel, failCode, signal) {
|
|
10087
10122
|
let submitError = null;
|
|
10088
10123
|
let submitRejectedCleanly = false;
|
|
10089
10124
|
try {
|
|
10090
|
-
const response = await
|
|
10125
|
+
const response = await retryTransient(
|
|
10126
|
+
() => this.deps.client.submitCertificationRequest(certificationData),
|
|
10127
|
+
signal,
|
|
10128
|
+
this.deps.proofPollIntervalMs ?? DEFAULT_PROOF_POLL_INTERVAL_MS
|
|
10129
|
+
);
|
|
10091
10130
|
if (response.status !== import_CertificationResponse.CertificationStatus.SUCCESS) {
|
|
10092
10131
|
submitError = new SphereError(`${failLabel}: ${response.status}`, failCode);
|
|
10093
10132
|
submitRejectedCleanly = CLEAN_REJECT_STATUSES.has(response.status);
|
|
@@ -10101,33 +10140,21 @@ var SphereTokenEngine = class {
|
|
|
10101
10140
|
client: this.deps.client,
|
|
10102
10141
|
trustBase: this.deps.trustBase,
|
|
10103
10142
|
predicateVerifier: this.deps.predicateVerifier,
|
|
10104
|
-
timeoutMs: this.proofTimeoutMs,
|
|
10105
10143
|
intervalMs: this.deps.proofPollIntervalMs ?? DEFAULT_PROOF_POLL_INTERVAL_MS
|
|
10106
10144
|
// #683
|
|
10107
10145
|
},
|
|
10108
10146
|
transaction,
|
|
10109
|
-
|
|
10147
|
+
signal
|
|
10110
10148
|
);
|
|
10111
10149
|
} catch (err) {
|
|
10112
|
-
|
|
10113
|
-
throw new TransferConflictError(
|
|
10114
|
-
`${failLabel}: the source state was already consumed by a different transaction (lost race \u2014 abort this intent and re-plan under a new transferId)`,
|
|
10115
|
-
err
|
|
10116
|
-
);
|
|
10117
|
-
}
|
|
10118
|
-
if (submitRejectedCleanly) throw submitError;
|
|
10119
|
-
throw new ProofUnconfirmedError(
|
|
10120
|
-
`${failLabel}: certification unconfirmed \u2014 the source spend may be on-chain; keep the intent open and resume under the same transferId`,
|
|
10121
|
-
submitError ?? err
|
|
10122
|
-
);
|
|
10150
|
+
throw certificationFailure(err, failLabel, submitError, submitRejectedCleanly);
|
|
10123
10151
|
}
|
|
10124
10152
|
}
|
|
10125
10153
|
/**
|
|
10126
|
-
* One inclusion-proof wait, with the deadline OWNED here (#739)
|
|
10127
|
-
*
|
|
10128
|
-
*
|
|
10129
|
-
*
|
|
10130
|
-
* (keep-open), which is the correct posture: the spend may be on-chain.
|
|
10154
|
+
* One inclusion-proof wait, with the deadline OWNED here (#739) so it is bounded
|
|
10155
|
+
* and configurable rather than the SDK's fixed default. A hit throws, and the
|
|
10156
|
+
* caller maps it to ProofUnconfirmedError (keep-open) — the correct posture,
|
|
10157
|
+
* since the spend may be on-chain.
|
|
10131
10158
|
*/
|
|
10132
10159
|
/** Fail fast if this engine's key does not own the token's current state. */
|
|
10133
10160
|
assertOwned(token) {
|
|
@@ -11462,7 +11489,7 @@ function createMachineStores(kv) {
|
|
|
11462
11489
|
}
|
|
11463
11490
|
|
|
11464
11491
|
// modules/payments-v2/machine/TransferMachine.ts
|
|
11465
|
-
var CERTIFY_WIDTH =
|
|
11492
|
+
var CERTIFY_WIDTH = 20;
|
|
11466
11493
|
var KEEP_OPEN_CODES = /* @__PURE__ */ new Set([
|
|
11467
11494
|
"CERTIFICATION_UNCONFIRMED",
|
|
11468
11495
|
"CHECKPOINT_PERSIST_FAILED",
|
|
@@ -11558,12 +11585,15 @@ var TransferMachine = class {
|
|
|
11558
11585
|
payload: r.payload,
|
|
11559
11586
|
...r.payload.memo !== void 0 ? { memo: r.payload.memo } : {}
|
|
11560
11587
|
};
|
|
11561
|
-
const
|
|
11588
|
+
const outcomes = await this.resumeOps(ctx, engine, r);
|
|
11589
|
+
const { committed, cls, firstError } = summarize(outcomes);
|
|
11590
|
+
const conflicts = this.toConflicts(engine, r, outcomes);
|
|
11562
11591
|
if (committed.length === 0 && conflicts.length > 0) throw conflicts[0].error;
|
|
11563
11592
|
let deliveryPending = false;
|
|
11564
11593
|
if (committed.length > 0) {
|
|
11565
11594
|
deliveryPending = await this.deliverSet(r.transferId, r.payload.recipient, r.payload.memo, committed);
|
|
11566
11595
|
}
|
|
11596
|
+
if (cls !== null && cls !== "conflict") throw firstError;
|
|
11567
11597
|
await this.applyCommitted(engine, r.transferId, committed);
|
|
11568
11598
|
if (conflicts.length > 0) {
|
|
11569
11599
|
return { deliveryPending, partial: await this.settlePartial(engine, r, committed, conflicts) };
|
|
@@ -11648,25 +11678,28 @@ var TransferMachine = class {
|
|
|
11648
11678
|
);
|
|
11649
11679
|
return { recipientBlob: outputs[0].blob.token, changeBlob: outputs[1].blob.token };
|
|
11650
11680
|
}
|
|
11681
|
+
/** Raw outcomes; `summarize` alone decides what they mean — same as the send path. */
|
|
11651
11682
|
async resumeOps(ctx, engine, r) {
|
|
11652
|
-
const
|
|
11653
|
-
const conflicts = [];
|
|
11683
|
+
const outcomes = [];
|
|
11654
11684
|
for (const op of buildOps(r.payload)) {
|
|
11655
11685
|
const journaled = op.kind === "direct" ? r.journaled.get(op.opIndex) : void 0;
|
|
11656
11686
|
if (journaled !== void 0) {
|
|
11657
|
-
|
|
11687
|
+
outcomes.push({ op, certified: true, recipientBlob: hexToBytes4(journaled.blobHex) });
|
|
11658
11688
|
continue;
|
|
11659
11689
|
}
|
|
11660
|
-
|
|
11661
|
-
const
|
|
11662
|
-
if (
|
|
11663
|
-
committed.push(outcome);
|
|
11664
|
-
continue;
|
|
11665
|
-
}
|
|
11666
|
-
if (classifyError(outcome.error) !== "conflict") throw outcome.error;
|
|
11667
|
-
conflicts.push({ op, error: outcome.error, amount: conflictAmount(engine, r.payload, op, source) });
|
|
11690
|
+
outcomes.push(await this.certifyOne(ctx, engine, op, r.sources.get(op.sourceTokenId)));
|
|
11691
|
+
const last = outcomes[outcomes.length - 1];
|
|
11692
|
+
if (last.error !== void 0 && classifyError(last.error) !== "conflict") break;
|
|
11668
11693
|
}
|
|
11669
|
-
return
|
|
11694
|
+
return outcomes;
|
|
11695
|
+
}
|
|
11696
|
+
/** Conflicted ops with the amount each leaves undelivered (#690 shortfall math). */
|
|
11697
|
+
toConflicts(engine, r, outcomes) {
|
|
11698
|
+
return outcomes.filter((o) => !o.certified && classifyError(o.error) === "conflict").map((o) => ({
|
|
11699
|
+
op: o.op,
|
|
11700
|
+
error: o.error,
|
|
11701
|
+
amount: conflictAmount(engine, r.payload, o.op, r.sources.get(o.op.sourceTokenId))
|
|
11702
|
+
}));
|
|
11670
11703
|
}
|
|
11671
11704
|
async deliverSet(transferId, recipientPubkey, memo, committed) {
|
|
11672
11705
|
const journaled = committed.filter((o) => o.error === void 0 && o.recipientBlob !== void 0);
|