@unicitylabs/sphere-sdk 0.17.6 → 0.18.0-dev.2
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/chunks/{chunk-T4DZCXWS.js → chunk-FGQ6CKKK.js} +2 -2
- package/dist/connect/chunks/{chunk-T4DZCXWS.js.map → chunk-FGQ6CKKK.js.map} +1 -1
- package/dist/connect/chunks/{chunk-BRYRG2TL.js → chunk-JYBI36GK.js} +2 -2
- package/dist/connect/chunks/{chunk-MA32MTCD.js → chunk-OAAY2JEA.js} +2 -2
- package/dist/connect/index.cjs +1 -1
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +3 -3
- package/dist/connect/internal/host.js +2 -2
- package/dist/core/index.cjs +304 -47
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +392 -320
- package/dist/core/index.d.ts +392 -320
- package/dist/core/index.js +304 -47
- 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 +2 -2
- package/dist/impl/wallet-api-v2/index.cjs +2 -0
- package/dist/impl/wallet-api-v2/index.cjs.map +1 -1
- package/dist/impl/wallet-api-v2/index.d.cts +30 -30
- package/dist/impl/wallet-api-v2/index.d.ts +30 -30
- package/dist/impl/wallet-api-v2/index.js +2 -0
- package/dist/impl/wallet-api-v2/index.js.map +1 -1
- package/dist/index.cjs +304 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +279 -154
- package/dist/index.d.ts +279 -154
- package/dist/index.js +304 -47
- package/dist/index.js.map +1 -1
- package/dist/modules/payments-v2/index.cjs +249 -28
- package/dist/modules/payments-v2/index.cjs.map +1 -1
- package/dist/modules/payments-v2/index.d.cts +252 -166
- package/dist/modules/payments-v2/index.d.ts +252 -166
- package/dist/modules/payments-v2/index.js +249 -28
- package/dist/modules/payments-v2/index.js.map +1 -1
- package/dist/token-engine/index.cjs +455 -427
- package/dist/token-engine/index.cjs.map +1 -1
- package/dist/token-engine/index.d.cts +26 -1
- package/dist/token-engine/index.d.ts +26 -1
- package/dist/token-engine/index.js +455 -427
- package/dist/token-engine/index.js.map +1 -1
- package/package.json +1 -1
- /package/dist/connect/chunks/{chunk-BRYRG2TL.js.map → chunk-JYBI36GK.js.map} +0 -0
- /package/dist/connect/chunks/{chunk-MA32MTCD.js.map → chunk-OAAY2JEA.js.map} +0 -0
package/dist/connect/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ConnectHost
|
|
3
|
-
} from "./chunks/chunk-
|
|
3
|
+
} from "./chunks/chunk-OAAY2JEA.js";
|
|
4
4
|
import {
|
|
5
5
|
nftContentFromWire,
|
|
6
6
|
nftContentToWire
|
|
@@ -9,7 +9,7 @@ import "./chunks/chunk-3CYK5SIU.js";
|
|
|
9
9
|
import {
|
|
10
10
|
ConnectClient,
|
|
11
11
|
ConnectError
|
|
12
|
-
} from "./chunks/chunk-
|
|
12
|
+
} from "./chunks/chunk-JYBI36GK.js";
|
|
13
13
|
import {
|
|
14
14
|
ALL_PERMISSIONS,
|
|
15
15
|
DEFAULT_PERMISSIONS,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
hasIntentPermission,
|
|
20
20
|
hasMethodPermission,
|
|
21
21
|
validatePermissions
|
|
22
|
-
} from "./chunks/chunk-
|
|
22
|
+
} from "./chunks/chunk-FGQ6CKKK.js";
|
|
23
23
|
import {
|
|
24
24
|
AUTO_PUSHED_EVENTS,
|
|
25
25
|
ERROR_CODES,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ConnectHost
|
|
3
|
-
} from "../chunks/chunk-
|
|
3
|
+
} from "../chunks/chunk-OAAY2JEA.js";
|
|
4
4
|
import "../chunks/chunk-3CYK5SIU.js";
|
|
5
|
-
import "../chunks/chunk-
|
|
5
|
+
import "../chunks/chunk-FGQ6CKKK.js";
|
|
6
6
|
import "../chunks/chunk-NPYX4JAI.js";
|
|
7
7
|
export {
|
|
8
8
|
ConnectHost
|
package/dist/core/index.cjs
CHANGED
|
@@ -10373,6 +10373,19 @@ async function readTokenNft(token) {
|
|
|
10373
10373
|
}
|
|
10374
10374
|
}
|
|
10375
10375
|
|
|
10376
|
+
// token-engine/plugin-ops.ts
|
|
10377
|
+
function contextWithMintVerifiers(base, verifiers) {
|
|
10378
|
+
const registry = new import_MintJustificationVerifierService.MintJustificationVerifierService();
|
|
10379
|
+
for (const verifier of verifiers) registry.register(verifier);
|
|
10380
|
+
return new import_VerificationContext.VerificationContext(
|
|
10381
|
+
base.trustBase,
|
|
10382
|
+
base.predicateVerifier,
|
|
10383
|
+
base.unicityCertificateVerifier,
|
|
10384
|
+
registry,
|
|
10385
|
+
new import_TokenIssuanceVerifierService.TokenIssuanceVerifierService(false)
|
|
10386
|
+
);
|
|
10387
|
+
}
|
|
10388
|
+
|
|
10376
10389
|
// token-engine/split-checkpoint.ts
|
|
10377
10390
|
var CHECKPOINT_VERSION = 2;
|
|
10378
10391
|
var CHECKPOINT_SDK_VERSION = "@unicitylabs/state-transition-sdk@3.0.1";
|
|
@@ -10519,6 +10532,10 @@ var SphereTokenEngine = class {
|
|
|
10519
10532
|
const data = token.sdkToken.genesis.data;
|
|
10520
10533
|
return data ? new Uint8Array(data) : null;
|
|
10521
10534
|
}
|
|
10535
|
+
readTokenJustification(token) {
|
|
10536
|
+
const justification = token.sdkToken.genesis.justification;
|
|
10537
|
+
return justification ? new Uint8Array(justification) : null;
|
|
10538
|
+
}
|
|
10522
10539
|
readNft(token) {
|
|
10523
10540
|
return readTokenNft(token);
|
|
10524
10541
|
}
|
|
@@ -10550,7 +10567,7 @@ var SphereTokenEngine = class {
|
|
|
10550
10567
|
const recipient = import_SignaturePredicate.SignaturePredicate.create(params.recipientPubkey);
|
|
10551
10568
|
const tokenType = params.tokenType ? new import_TokenType.TokenType(params.tokenType) : import_TokenType.TokenType.generate();
|
|
10552
10569
|
const salt = params.salt ? import_TokenSalt.TokenSalt.fromBytes(params.salt) : import_TokenSalt.TokenSalt.generate();
|
|
10553
|
-
const mintTx = await import_MintTransaction.MintTransaction.create(this.deps.networkId, recipient, { data: params.data, tokenType, salt });
|
|
10570
|
+
const mintTx = await import_MintTransaction.MintTransaction.create(this.deps.networkId, recipient, { data: params.data, tokenType, salt, justification: params.justification ?? null });
|
|
10554
10571
|
const certificationData = await import_CertificationData.CertificationData.fromMintTransaction(mintTx);
|
|
10555
10572
|
const proof = await this.submitAndAwaitProof(
|
|
10556
10573
|
certificationData,
|
|
@@ -10560,34 +10577,30 @@ var SphereTokenEngine = class {
|
|
|
10560
10577
|
options
|
|
10561
10578
|
);
|
|
10562
10579
|
const certified = await mintTx.toCertifiedTransaction(this.deps.trustBase, this.deps.predicateVerifier, this.deps.unicityCertificateVerifier, proof);
|
|
10563
|
-
const
|
|
10564
|
-
return wrapToken(
|
|
10580
|
+
const verifiers = params.mintJustificationVerifiers;
|
|
10581
|
+
return wrapToken(await import_Token.Token.mint(certified, verifiers ? contextWithMintVerifiers(this.deps, verifiers) : this.deps.verificationContext));
|
|
10565
10582
|
}
|
|
10566
10583
|
buildNftMint(params) {
|
|
10567
10584
|
return planNftMint(this.deps, params);
|
|
10568
10585
|
}
|
|
10569
10586
|
async transfer(params, options) {
|
|
10570
10587
|
this.assertOwned(params.token);
|
|
10571
|
-
|
|
10572
|
-
|
|
10588
|
+
return this.spend(params.token, import_SignaturePredicate.SignaturePredicate.create(params.recipientPubkey), params.data ?? null, options, "Transfer certification failed");
|
|
10589
|
+
}
|
|
10590
|
+
async burn(params, options) {
|
|
10591
|
+
this.assertOwned(params.token);
|
|
10592
|
+
return this.spend(params.token, import_BurnPredicate.BurnPredicate.create(sha256(params.reasonBytes)), params.reasonBytes, options, "Burn certification failed");
|
|
10593
|
+
}
|
|
10594
|
+
async spend(token, recipient, data, options, failLabel) {
|
|
10573
10595
|
const stateMask = import_StateMask.StateMask.fromBytes(
|
|
10574
|
-
deriveRealization(this.privateKeyHex,
|
|
10596
|
+
deriveRealization(this.privateKeyHex, this.resolveTransferId(options), this.resolveOpIndex(options), "stateMask")
|
|
10575
10597
|
);
|
|
10576
|
-
const transferTx = await import_TransferTransaction.TransferTransaction.create(
|
|
10577
|
-
data: params.data ?? null
|
|
10578
|
-
});
|
|
10598
|
+
const transferTx = await import_TransferTransaction.TransferTransaction.create(token.sdkToken, recipient, stateMask, { data });
|
|
10579
10599
|
const unlockScript = await import_SignaturePredicateUnlockScript.SignaturePredicateUnlockScript.create(transferTx, this.deps.signingService);
|
|
10580
10600
|
const certificationData = await import_CertificationData.CertificationData.fromTransaction(transferTx, unlockScript);
|
|
10581
|
-
const proof = await this.submitAndAwaitProof(
|
|
10582
|
-
certificationData,
|
|
10583
|
-
transferTx,
|
|
10584
|
-
"Transfer certification failed",
|
|
10585
|
-
"TRANSFER_FAILED",
|
|
10586
|
-
options
|
|
10587
|
-
);
|
|
10601
|
+
const proof = await this.submitAndAwaitProof(certificationData, transferTx, failLabel, "TRANSFER_FAILED", options);
|
|
10588
10602
|
const certified = await transferTx.toCertifiedTransaction(this.deps.trustBase, this.deps.predicateVerifier, this.deps.unicityCertificateVerifier, proof);
|
|
10589
|
-
|
|
10590
|
-
return wrapToken(transferred);
|
|
10603
|
+
return wrapToken(await token.sdkToken.transfer(certified, this.deps.verificationContext));
|
|
10591
10604
|
}
|
|
10592
10605
|
async split(params, options) {
|
|
10593
10606
|
this.assertOwned(params.token);
|
|
@@ -10902,6 +10915,20 @@ var SphereTokenEngine = class {
|
|
|
10902
10915
|
|
|
10903
10916
|
// token-engine/factory.ts
|
|
10904
10917
|
var DEFAULT_VERIFICATION_POOL_SIZE = 4;
|
|
10918
|
+
function registerPluginVerifiers(registry, plugins) {
|
|
10919
|
+
for (const plugin of plugins ?? []) {
|
|
10920
|
+
for (const verifier of plugin.mintJustificationVerifiers ?? []) {
|
|
10921
|
+
try {
|
|
10922
|
+
registry.register(verifier);
|
|
10923
|
+
} catch (err) {
|
|
10924
|
+
throw new SphereError(
|
|
10925
|
+
`Token plugin '${plugin.id}' registers mint-reason tag ${verifier.tag} twice or over another plugin's: ` + (err instanceof Error ? err.message : String(err)),
|
|
10926
|
+
"INVALID_CONFIG"
|
|
10927
|
+
);
|
|
10928
|
+
}
|
|
10929
|
+
}
|
|
10930
|
+
}
|
|
10931
|
+
}
|
|
10905
10932
|
function disposedError() {
|
|
10906
10933
|
return new SphereError(
|
|
10907
10934
|
"Verification worker pool disposed \u2014 the in-flight verification was cancelled",
|
|
@@ -10983,6 +11010,7 @@ async function createSphereTokenEngine(config) {
|
|
|
10983
11010
|
mintJustificationVerifier.register(
|
|
10984
11011
|
new import_SplitMintJustificationVerifier.SplitMintJustificationVerifier(decodeSpherePaymentData)
|
|
10985
11012
|
);
|
|
11013
|
+
registerPluginVerifiers(mintJustificationVerifier, config.plugins);
|
|
10986
11014
|
const deps = {
|
|
10987
11015
|
client: new import_StateTransitionClient.StateTransitionClient(new import_AggregatorClient.AggregatorClient(config.aggregatorUrl, config.apiKey ?? null)),
|
|
10988
11016
|
trustBase,
|
|
@@ -12100,6 +12128,8 @@ var STORE_KEYS = {
|
|
|
12100
12128
|
deliveryJournal: "delivery-journal",
|
|
12101
12129
|
mintJournal: "mint-journal",
|
|
12102
12130
|
nftMintJournal: "nft-mint-journal",
|
|
12131
|
+
customMintJournal: "custom-mint-journal",
|
|
12132
|
+
burnJournal: "burn-journal",
|
|
12103
12133
|
shortfalls: "shortfalls",
|
|
12104
12134
|
settlingLinks: "settling",
|
|
12105
12135
|
streamCursor: (s) => `cursor:${s}`,
|
|
@@ -12284,6 +12314,8 @@ function createMachineStores(kv) {
|
|
|
12284
12314
|
deliveryJournal: new DeliveryJournal(kv),
|
|
12285
12315
|
mintJournal: new ListStore(kv, STORE_KEYS.mintJournal, (e) => e.mintId),
|
|
12286
12316
|
nftMintJournal: new ListStore(kv, STORE_KEYS.nftMintJournal, (e) => e.mintId),
|
|
12317
|
+
customMintJournal: new ListStore(kv, STORE_KEYS.customMintJournal, (e) => e.mintId),
|
|
12318
|
+
burnJournal: new ListStore(kv, STORE_KEYS.burnJournal, (e) => e.burnId),
|
|
12287
12319
|
shortfalls: new ListStore(kv, STORE_KEYS.shortfalls, (e) => e.transferId)
|
|
12288
12320
|
};
|
|
12289
12321
|
}
|
|
@@ -12991,7 +13023,12 @@ var Converger = class {
|
|
|
12991
13023
|
} catch (err) {
|
|
12992
13024
|
retryAfterMs ??= retryAfterMsOf(err);
|
|
12993
13025
|
}
|
|
12994
|
-
for (const replay of [
|
|
13026
|
+
for (const replay of [
|
|
13027
|
+
() => this.deps.replayMints(),
|
|
13028
|
+
() => this.deps.replayNftMints(),
|
|
13029
|
+
() => this.deps.replayCustomMints(),
|
|
13030
|
+
() => this.deps.replayBurns()
|
|
13031
|
+
]) {
|
|
12995
13032
|
try {
|
|
12996
13033
|
progress = await replay() > 0 || progress;
|
|
12997
13034
|
} catch (err) {
|
|
@@ -13002,14 +13039,17 @@ var Converger = class {
|
|
|
13002
13039
|
}
|
|
13003
13040
|
/** §4 heartbeat predicate — read fresh from the §6 stores, never cached. */
|
|
13004
13041
|
async pendingWork() {
|
|
13005
|
-
const [backstop, journal, mints, nftMints] = await Promise.all([
|
|
13042
|
+
const [backstop, journal, mints, nftMints, customMints, burns] = await Promise.all([
|
|
13006
13043
|
this.deps.stores.backstop.list(),
|
|
13007
13044
|
this.deps.stores.deliveryJournal.list(),
|
|
13008
13045
|
this.deps.stores.mintJournal.list(),
|
|
13009
|
-
this.deps.stores.nftMintJournal.list()
|
|
13046
|
+
this.deps.stores.nftMintJournal.list(),
|
|
13047
|
+
this.deps.stores.customMintJournal.list(),
|
|
13048
|
+
this.deps.stores.burnJournal.list()
|
|
13010
13049
|
]);
|
|
13011
|
-
const mintsOpen = mints.length > 0 || nftMints.length > 0;
|
|
13012
|
-
|
|
13050
|
+
const mintsOpen = mints.length > 0 || nftMints.length > 0 || customMints.length > 0;
|
|
13051
|
+
const burnsOpen = burns.some((e) => !e.settled);
|
|
13052
|
+
return backstop.length > 0 || journal.some((e) => e.undeliverable !== true) || mintsOpen || burnsOpen;
|
|
13013
13053
|
}
|
|
13014
13054
|
async resumePass() {
|
|
13015
13055
|
const report = await resumeAll(this.filteredMachineDeps(), {
|
|
@@ -13241,6 +13281,12 @@ async function decodeView(deps, tokenId, bytes) {
|
|
|
13241
13281
|
|
|
13242
13282
|
// modules/payments-v2/inventory/token-data.ts
|
|
13243
13283
|
async function readTokenData(deps, tokenId) {
|
|
13284
|
+
return deps.engine.readTokenData(await heldToken(deps, tokenId));
|
|
13285
|
+
}
|
|
13286
|
+
async function readTokenJustification(deps, tokenId) {
|
|
13287
|
+
return deps.engine.readTokenJustification(await heldToken(deps, tokenId));
|
|
13288
|
+
}
|
|
13289
|
+
async function heldToken(deps, tokenId) {
|
|
13244
13290
|
if (deps.view.stateHashOf(tokenId) === void 0) {
|
|
13245
13291
|
throw new SphereError(`Token ${tokenId} is not in inventory`, "VALIDATION_ERROR");
|
|
13246
13292
|
}
|
|
@@ -13248,7 +13294,7 @@ async function readTokenData(deps, tokenId) {
|
|
|
13248
13294
|
if (bytes === void 0) {
|
|
13249
13295
|
throw new SphereError(`Token ${tokenId} has no blob in storage`, "STORAGE_ERROR");
|
|
13250
13296
|
}
|
|
13251
|
-
return deps.engine.
|
|
13297
|
+
return deps.engine.decodeToken({ tokenId, token: bytes });
|
|
13252
13298
|
}
|
|
13253
13299
|
|
|
13254
13300
|
// modules/payments-v2/history/History.ts
|
|
@@ -15084,6 +15130,7 @@ function mintParams(recipientPubkey, coinId, amount) {
|
|
|
15084
15130
|
|
|
15085
15131
|
// modules/payments-v2/mint.ts
|
|
15086
15132
|
var ATTENTION_MINT_UNRESOLVED = "mint:unresolved";
|
|
15133
|
+
var INVENTORY_SCAN_PAGE_LIMIT = 50;
|
|
15087
15134
|
function runMintUnderJournal(deps, input) {
|
|
15088
15135
|
return mintUnderJournal(deps, input);
|
|
15089
15136
|
}
|
|
@@ -15136,6 +15183,15 @@ async function finalizeMint(deps, input) {
|
|
|
15136
15183
|
deps.noteHeldState(token.blob.tokenId, (await deps.engine.deliveryKeys(bytes)).stateHash);
|
|
15137
15184
|
deps.refreshView();
|
|
15138
15185
|
}
|
|
15186
|
+
async function tokenInServerInventory(storagePort, tokenId) {
|
|
15187
|
+
let page = await storagePort.listInventory();
|
|
15188
|
+
for (let i = 0; i < INVENTORY_SCAN_PAGE_LIMIT; i++) {
|
|
15189
|
+
if (page.items.some((item) => item.tokenId === tokenId && item.status === "active")) return true;
|
|
15190
|
+
if (!page.more) return false;
|
|
15191
|
+
page = await storagePort.listInventory(page.cursor);
|
|
15192
|
+
}
|
|
15193
|
+
return false;
|
|
15194
|
+
}
|
|
15139
15195
|
async function replayCoinMints(deps) {
|
|
15140
15196
|
let resolved = 0;
|
|
15141
15197
|
for (const entry of await deps.mintJournal.list()) {
|
|
@@ -15239,6 +15295,199 @@ async function mintJournaled(deps, entry) {
|
|
|
15239
15295
|
await finalizeMint(deps, { mintId: entry.mintId, token, assets: [], journal: deps.nftMintJournal });
|
|
15240
15296
|
}
|
|
15241
15297
|
|
|
15298
|
+
// modules/payments-v2/mint-custom.ts
|
|
15299
|
+
var HEX32 = /^[0-9a-f]{64}$/;
|
|
15300
|
+
function assertRequest(request) {
|
|
15301
|
+
if (request.tokenType.length !== 32) {
|
|
15302
|
+
throw new SphereError("mintCustom: tokenType must be 32 bytes", "VALIDATION_ERROR");
|
|
15303
|
+
}
|
|
15304
|
+
if (request.salt.length < 16 || request.salt.length > 64) {
|
|
15305
|
+
throw new SphereError("mintCustom: salt must be 16 to 64 bytes", "VALIDATION_ERROR");
|
|
15306
|
+
}
|
|
15307
|
+
if (request.data.length === 0) {
|
|
15308
|
+
throw new SphereError("mintCustom: data must not be empty", "VALIDATION_ERROR");
|
|
15309
|
+
}
|
|
15310
|
+
for (const asset of request.assets) {
|
|
15311
|
+
if (!HEX32.test(asset.coinId) || asset.amount <= 0n) {
|
|
15312
|
+
throw new SphereError("mintCustom: assets need a 64-hex coinId and a positive amount", "VALIDATION_ERROR");
|
|
15313
|
+
}
|
|
15314
|
+
}
|
|
15315
|
+
}
|
|
15316
|
+
async function runCustomMintUnderJournal(deps, input) {
|
|
15317
|
+
try {
|
|
15318
|
+
assertRequest(input.request);
|
|
15319
|
+
} catch (err) {
|
|
15320
|
+
return { success: false, error: messageOf(err) };
|
|
15321
|
+
}
|
|
15322
|
+
const entry = journalEntryOf2(input.mintId, input.request, deps.now());
|
|
15323
|
+
await deps.customMintJournal.upsert(entry);
|
|
15324
|
+
let tokenId;
|
|
15325
|
+
try {
|
|
15326
|
+
tokenId = await mintJournaled2(deps, entry, input.request.mintJustificationVerifiers);
|
|
15327
|
+
} catch (err) {
|
|
15328
|
+
deps.armHeartbeat();
|
|
15329
|
+
return { success: false, error: messageOf(err) };
|
|
15330
|
+
}
|
|
15331
|
+
return { success: true, tokenId };
|
|
15332
|
+
}
|
|
15333
|
+
async function replayCustomMints(deps) {
|
|
15334
|
+
let resolved = 0;
|
|
15335
|
+
for (const entry of await deps.customMintJournal.list()) {
|
|
15336
|
+
if (deps.isActiveOp(entry.mintId)) continue;
|
|
15337
|
+
try {
|
|
15338
|
+
if (entry.tokenId !== "" && await deps.tokenInServerInventory(entry.tokenId)) {
|
|
15339
|
+
await deps.customMintJournal.removeByKey(entry.mintId);
|
|
15340
|
+
} else {
|
|
15341
|
+
await mintJournaled2(deps, entry, void 0);
|
|
15342
|
+
}
|
|
15343
|
+
resolved += 1;
|
|
15344
|
+
} catch {
|
|
15345
|
+
continue;
|
|
15346
|
+
}
|
|
15347
|
+
}
|
|
15348
|
+
return resolved;
|
|
15349
|
+
}
|
|
15350
|
+
function journalEntryOf2(mintId, request, createdAt) {
|
|
15351
|
+
return {
|
|
15352
|
+
mintId,
|
|
15353
|
+
tokenId: "",
|
|
15354
|
+
dataHex: bytesToHex3(request.data),
|
|
15355
|
+
saltHex: bytesToHex3(request.salt),
|
|
15356
|
+
tokenTypeHex: bytesToHex3(request.tokenType),
|
|
15357
|
+
justificationHex: request.justification ? bytesToHex3(request.justification) : null,
|
|
15358
|
+
assets: request.assets.map((a) => ({ coinId: a.coinId, amount: a.amount.toString() })),
|
|
15359
|
+
createdAt
|
|
15360
|
+
};
|
|
15361
|
+
}
|
|
15362
|
+
async function mintJournaled2(deps, entry, mintJustificationVerifiers) {
|
|
15363
|
+
const token = await deps.engine.mintDataToken(
|
|
15364
|
+
{
|
|
15365
|
+
recipientPubkey: deps.ownPubkeyBytes,
|
|
15366
|
+
data: hexToBytes4(entry.dataHex),
|
|
15367
|
+
tokenType: hexToBytes4(entry.tokenTypeHex),
|
|
15368
|
+
salt: hexToBytes4(entry.saltHex),
|
|
15369
|
+
...entry.justificationHex !== null ? { justification: hexToBytes4(entry.justificationHex) } : {},
|
|
15370
|
+
...mintJustificationVerifiers ? { mintJustificationVerifiers } : {}
|
|
15371
|
+
},
|
|
15372
|
+
{ transferId: entry.mintId }
|
|
15373
|
+
);
|
|
15374
|
+
if (entry.tokenId !== "" && token.blob.tokenId !== entry.tokenId) {
|
|
15375
|
+
throw new SphereError(`minted token ${token.blob.tokenId}, but the journal names ${entry.tokenId}`, "VALIDATION_ERROR");
|
|
15376
|
+
}
|
|
15377
|
+
if (entry.tokenId === "") {
|
|
15378
|
+
await deps.customMintJournal.upsert({ ...entry, tokenId: token.blob.tokenId });
|
|
15379
|
+
}
|
|
15380
|
+
await finalizeMint(deps, {
|
|
15381
|
+
mintId: entry.mintId,
|
|
15382
|
+
token,
|
|
15383
|
+
assets: entry.assets,
|
|
15384
|
+
journal: deps.customMintJournal
|
|
15385
|
+
});
|
|
15386
|
+
return token.blob.tokenId;
|
|
15387
|
+
}
|
|
15388
|
+
|
|
15389
|
+
// modules/payments-v2/burn.ts
|
|
15390
|
+
var HEX322 = /^[0-9a-f]{64}$/;
|
|
15391
|
+
async function heldToken2(deps, tokenId) {
|
|
15392
|
+
const bytes = (await deps.storagePort.getBlobs([tokenId])).get(tokenId);
|
|
15393
|
+
if (bytes === void 0) {
|
|
15394
|
+
throw new SphereError(`Token ${tokenId} has no blob in storage; it is not held here`, "STORAGE_ERROR");
|
|
15395
|
+
}
|
|
15396
|
+
return deps.engine.decodeToken({ tokenId, token: bytes });
|
|
15397
|
+
}
|
|
15398
|
+
function assetsOf(token) {
|
|
15399
|
+
return (token.value?.assets ?? []).map((a) => ({ coinId: a.coinId, amount: a.amount.toString() }));
|
|
15400
|
+
}
|
|
15401
|
+
async function runBurnUnderJournal(deps, input) {
|
|
15402
|
+
const { burnId } = input;
|
|
15403
|
+
const { tokenId, reasonBytes } = input.request;
|
|
15404
|
+
if (!HEX322.test(tokenId) || reasonBytes.length === 0) {
|
|
15405
|
+
return { success: false, burnId, tokenId, error: "burn: tokenId must be 64 hex and reasonBytes non-empty" };
|
|
15406
|
+
}
|
|
15407
|
+
let token;
|
|
15408
|
+
try {
|
|
15409
|
+
token = await heldToken2(deps, tokenId);
|
|
15410
|
+
if (!deps.engine.isOwnedBy(token, deps.engine.getIdentity().chainPubkey)) {
|
|
15411
|
+
throw new SphereError(`Token ${tokenId} is not owned by this wallet`, "VALIDATION_ERROR");
|
|
15412
|
+
}
|
|
15413
|
+
} catch (err) {
|
|
15414
|
+
return { success: false, burnId, tokenId, error: messageOf(err) };
|
|
15415
|
+
}
|
|
15416
|
+
const entry = {
|
|
15417
|
+
burnId,
|
|
15418
|
+
tokenId,
|
|
15419
|
+
reasonHex: bytesToHex3(reasonBytes),
|
|
15420
|
+
burnedTokenHex: null,
|
|
15421
|
+
settled: false,
|
|
15422
|
+
assets: assetsOf(token),
|
|
15423
|
+
createdAt: deps.now()
|
|
15424
|
+
};
|
|
15425
|
+
await deps.burnJournal.upsert(entry);
|
|
15426
|
+
try {
|
|
15427
|
+
const settled = await burnJournaled(deps, entry, token, { applied: false });
|
|
15428
|
+
return { success: true, burnId, tokenId, burnedToken: hexToBytes4(settled.burnedTokenHex ?? "") };
|
|
15429
|
+
} catch (err) {
|
|
15430
|
+
deps.armHeartbeat();
|
|
15431
|
+
return { success: false, burnId, tokenId, error: messageOf(err) };
|
|
15432
|
+
}
|
|
15433
|
+
}
|
|
15434
|
+
async function replayBurns(deps) {
|
|
15435
|
+
let progressed = 0;
|
|
15436
|
+
for (const entry of await deps.burnJournal.list()) {
|
|
15437
|
+
if (entry.settled || deps.isActiveOp(entry.burnId)) continue;
|
|
15438
|
+
try {
|
|
15439
|
+
const token = entry.burnedTokenHex === null ? await heldToken2(deps, entry.tokenId) : null;
|
|
15440
|
+
const applied = entry.burnedTokenHex !== null && !await deps.tokenInServerInventory(entry.tokenId);
|
|
15441
|
+
await burnJournaled(deps, entry, token, { applied });
|
|
15442
|
+
progressed += 1;
|
|
15443
|
+
} catch {
|
|
15444
|
+
continue;
|
|
15445
|
+
}
|
|
15446
|
+
}
|
|
15447
|
+
return progressed;
|
|
15448
|
+
}
|
|
15449
|
+
async function pendingBurns(deps) {
|
|
15450
|
+
return (await deps.burnJournal.list()).map((entry) => ({
|
|
15451
|
+
burnId: entry.burnId,
|
|
15452
|
+
tokenId: entry.tokenId,
|
|
15453
|
+
reasonBytes: hexToBytes4(entry.reasonHex),
|
|
15454
|
+
burnedToken: entry.burnedTokenHex === null ? null : hexToBytes4(entry.burnedTokenHex),
|
|
15455
|
+
settled: entry.settled,
|
|
15456
|
+
createdAt: entry.createdAt
|
|
15457
|
+
}));
|
|
15458
|
+
}
|
|
15459
|
+
async function acknowledgeBurn(deps, burnId) {
|
|
15460
|
+
const entry = await deps.burnJournal.getByKey(burnId);
|
|
15461
|
+
if (entry === void 0) return;
|
|
15462
|
+
if (!entry.settled) {
|
|
15463
|
+
throw new SphereError(`Burn ${burnId} is not settled yet; it cannot be acknowledged`, "VALIDATION_ERROR");
|
|
15464
|
+
}
|
|
15465
|
+
await deps.burnJournal.removeByKey(burnId);
|
|
15466
|
+
}
|
|
15467
|
+
async function burnJournaled(deps, entry, token, state) {
|
|
15468
|
+
let current = entry;
|
|
15469
|
+
if (current.burnedTokenHex === null) {
|
|
15470
|
+
if (token === null) throw new SphereError("burn replay needs the held token to certify", "VALIDATION_ERROR");
|
|
15471
|
+
const burned = await deps.engine.burn(
|
|
15472
|
+
{ token, reasonBytes: hexToBytes4(current.reasonHex) },
|
|
15473
|
+
{ transferId: current.burnId }
|
|
15474
|
+
);
|
|
15475
|
+
if (burned.blob.tokenId !== current.tokenId) {
|
|
15476
|
+
throw new SphereError(`burned token ${burned.blob.tokenId}, but the journal names ${current.tokenId}`, "VALIDATION_ERROR");
|
|
15477
|
+
}
|
|
15478
|
+
current = { ...current, burnedTokenHex: bytesToHex3(burned.blob.token) };
|
|
15479
|
+
await deps.burnJournal.upsert(current);
|
|
15480
|
+
}
|
|
15481
|
+
if (!state.applied) {
|
|
15482
|
+
await deps.storagePort.applyDelta({ transferId: current.burnId, spent: [current.tokenId], added: [] });
|
|
15483
|
+
}
|
|
15484
|
+
await deps.recordSent({ transferId: current.burnId, assets: current.assets, tokenId: current.tokenId });
|
|
15485
|
+
current = { ...current, settled: true };
|
|
15486
|
+
await deps.burnJournal.upsert(current);
|
|
15487
|
+
deps.refreshView();
|
|
15488
|
+
return current;
|
|
15489
|
+
}
|
|
15490
|
+
|
|
15242
15491
|
// modules/payments-v2/send-whole.ts
|
|
15243
15492
|
async function materializeWholeSpend(deps, input) {
|
|
15244
15493
|
const { engine } = deps;
|
|
@@ -15424,7 +15673,6 @@ async function takeSourceBlobs(deps, sourceIds) {
|
|
|
15424
15673
|
|
|
15425
15674
|
// modules/payments-v2/PaymentsFacade.ts
|
|
15426
15675
|
var MAX_RESELECT = 8;
|
|
15427
|
-
var INVENTORY_SCAN_PAGE_LIMIT = 50;
|
|
15428
15676
|
var PaymentsFacade = class {
|
|
15429
15677
|
constructor(deps) {
|
|
15430
15678
|
this.deps = deps;
|
|
@@ -15461,6 +15709,8 @@ var PaymentsFacade = class {
|
|
|
15461
15709
|
refreshView: () => this.view.delta(),
|
|
15462
15710
|
replayMints: () => replayCoinMints(this.mintDeps()),
|
|
15463
15711
|
replayNftMints: () => replayNftMints(this.mintDeps()),
|
|
15712
|
+
replayCustomMints: () => replayCustomMints(this.mintDeps()),
|
|
15713
|
+
replayBurns: () => replayBurns(this.mintDeps()),
|
|
15464
15714
|
isActiveOp: (id) => this.activeMoneyOps.has(id),
|
|
15465
15715
|
emit: deps.emit,
|
|
15466
15716
|
now: () => this.nowMs()
|
|
@@ -15556,6 +15806,9 @@ var PaymentsFacade = class {
|
|
|
15556
15806
|
tokenData(tokenId) {
|
|
15557
15807
|
return readTokenData(this.readDeps(), tokenId);
|
|
15558
15808
|
}
|
|
15809
|
+
tokenJustification(tokenId) {
|
|
15810
|
+
return readTokenJustification(this.readDeps(), tokenId);
|
|
15811
|
+
}
|
|
15559
15812
|
nft(tokenId) {
|
|
15560
15813
|
return readNft(this.readDeps(), tokenId);
|
|
15561
15814
|
}
|
|
@@ -15604,8 +15857,12 @@ var PaymentsFacade = class {
|
|
|
15604
15857
|
return this.track(this.mintInner(coinId, amount));
|
|
15605
15858
|
}
|
|
15606
15859
|
mintNft(request) {
|
|
15607
|
-
return this.track(this.
|
|
15860
|
+
return this.track(this.ownedOp((mintId) => runNftMintUnderJournal(this.mintDeps(), { mintId, request })));
|
|
15608
15861
|
}
|
|
15862
|
+
mintCustom = (request) => this.track(this.ownedOp((mintId) => runCustomMintUnderJournal(this.mintDeps(), { mintId, request })));
|
|
15863
|
+
burn = (request) => this.track(this.ownedOp((burnId) => runBurnUnderJournal(this.mintDeps(), { burnId, request })));
|
|
15864
|
+
pendingBurns = () => this.track(pendingBurns(this.mintDeps()));
|
|
15865
|
+
acknowledgeBurn = (burnId) => this.track(acknowledgeBurn(this.mintDeps(), burnId));
|
|
15609
15866
|
// §4 retry verb: coalesces onto the running pass — NEVER re-issue send() (#631/#676).
|
|
15610
15867
|
async resumeNow() {
|
|
15611
15868
|
if (!this.started) return;
|
|
@@ -15629,12 +15886,15 @@ var PaymentsFacade = class {
|
|
|
15629
15886
|
nowMs() {
|
|
15630
15887
|
return (this.deps.now ?? Date.now)();
|
|
15631
15888
|
}
|
|
15632
|
-
/** One snapshot serves the coin and the
|
|
15889
|
+
/** One snapshot serves the coin, NFT and custom mints and the burn, live and replayed. */
|
|
15633
15890
|
mintDeps() {
|
|
15634
15891
|
return {
|
|
15635
15892
|
engine: this.engine(),
|
|
15636
15893
|
mintJournal: this.machineStores.mintJournal,
|
|
15637
15894
|
nftMintJournal: this.machineStores.nftMintJournal,
|
|
15895
|
+
customMintJournal: this.machineStores.customMintJournal,
|
|
15896
|
+
burnJournal: this.machineStores.burnJournal,
|
|
15897
|
+
recordSent: (input) => this.historyStore.recordSent(input),
|
|
15638
15898
|
storagePort: this.deps.storagePort,
|
|
15639
15899
|
recordMint: (input) => this.historyStore.recordMint(input),
|
|
15640
15900
|
armHeartbeat: () => this.heartbeat.arm(),
|
|
@@ -15643,7 +15903,7 @@ var PaymentsFacade = class {
|
|
|
15643
15903
|
ownPubkeyBytes: this.ownPubkeyBytes,
|
|
15644
15904
|
nftTokenType: this.deps.nftTokenType,
|
|
15645
15905
|
isActiveOp: (mintId) => this.activeMoneyOps.has(mintId),
|
|
15646
|
-
tokenInServerInventory: (tokenId) => this.
|
|
15906
|
+
tokenInServerInventory: (tokenId) => tokenInServerInventory(this.deps.storagePort, tokenId),
|
|
15647
15907
|
emit: this.deps.emit,
|
|
15648
15908
|
now: () => this.nowMs()
|
|
15649
15909
|
};
|
|
@@ -15964,28 +16224,17 @@ var PaymentsFacade = class {
|
|
|
15964
16224
|
if (!/^(?:[0-9a-f]{2})+$/.test(coinId) || amount <= 0n) {
|
|
15965
16225
|
return { success: false, error: "coinId must be even-length lowercase hex and amount positive" };
|
|
15966
16226
|
}
|
|
15967
|
-
return this.
|
|
16227
|
+
return this.ownedOp((mintId) => runMintUnderJournal(this.mintDeps(), { mintId, coinId, amount }));
|
|
15968
16228
|
}
|
|
15969
|
-
/** A live
|
|
15970
|
-
async
|
|
15971
|
-
const
|
|
15972
|
-
this.activeMoneyOps.add(
|
|
16229
|
+
/** A live money op under a fresh id — its replay stays hands-off while this attempt runs (§7). */
|
|
16230
|
+
async ownedOp(run) {
|
|
16231
|
+
const id = this.newId();
|
|
16232
|
+
this.activeMoneyOps.add(id);
|
|
15973
16233
|
try {
|
|
15974
|
-
return await run(
|
|
16234
|
+
return await run(id);
|
|
15975
16235
|
} finally {
|
|
15976
|
-
this.activeMoneyOps.delete(
|
|
15977
|
-
}
|
|
15978
|
-
}
|
|
15979
|
-
async tokenInServerInventory(tokenId) {
|
|
15980
|
-
let page = await this.deps.storagePort.listInventory();
|
|
15981
|
-
for (let i = 0; i < INVENTORY_SCAN_PAGE_LIMIT; i++) {
|
|
15982
|
-
if (page.items.some((item) => item.tokenId === tokenId && item.status === "active")) {
|
|
15983
|
-
return true;
|
|
15984
|
-
}
|
|
15985
|
-
if (!page.more) return false;
|
|
15986
|
-
page = await this.deps.storagePort.listInventory(page.cursor);
|
|
16236
|
+
this.activeMoneyOps.delete(id);
|
|
15987
16237
|
}
|
|
15988
|
-
return false;
|
|
15989
16238
|
}
|
|
15990
16239
|
// ── wiring internals ───────────────────────────────────────────────────────
|
|
15991
16240
|
engine() {
|
|
@@ -17377,6 +17626,8 @@ var Sphere = class _Sphere {
|
|
|
17377
17626
|
* the rebuild after an api-key change share one pool configuration.
|
|
17378
17627
|
*/
|
|
17379
17628
|
_verification;
|
|
17629
|
+
/** Token plugins (SphereInitOptions.plugins), applied to every engine like _verification. */
|
|
17630
|
+
_plugins;
|
|
17380
17631
|
/** This Sphere's OWN token registry. Disposed by destroy(); never the process global. */
|
|
17381
17632
|
_registry = null;
|
|
17382
17633
|
// Events
|
|
@@ -17490,6 +17741,7 @@ var Sphere = class _Sphere {
|
|
|
17490
17741
|
communications: options.communications,
|
|
17491
17742
|
password: options.password,
|
|
17492
17743
|
verification: options.verification,
|
|
17744
|
+
plugins: options.plugins,
|
|
17493
17745
|
discoverAddresses: options.discoverAddresses,
|
|
17494
17746
|
onProgress: options.onProgress
|
|
17495
17747
|
});
|
|
@@ -17527,6 +17779,7 @@ var Sphere = class _Sphere {
|
|
|
17527
17779
|
communications: options.communications,
|
|
17528
17780
|
password: options.password,
|
|
17529
17781
|
verification: options.verification,
|
|
17782
|
+
plugins: options.plugins,
|
|
17530
17783
|
discoverAddresses: options.discoverAddresses,
|
|
17531
17784
|
onProgress: options.onProgress
|
|
17532
17785
|
});
|
|
@@ -17705,6 +17958,7 @@ var Sphere = class _Sphere {
|
|
|
17705
17958
|
options.communications
|
|
17706
17959
|
);
|
|
17707
17960
|
sphere._verification = options.verification;
|
|
17961
|
+
sphere._plugins = options.plugins;
|
|
17708
17962
|
sphere._paymentsV2Composition = composition;
|
|
17709
17963
|
sphere._password = options.password ?? null;
|
|
17710
17964
|
sphere._passwordProtected = sphere._password !== null;
|
|
@@ -17769,6 +18023,7 @@ var Sphere = class _Sphere {
|
|
|
17769
18023
|
options.communications
|
|
17770
18024
|
);
|
|
17771
18025
|
sphere._verification = options.verification;
|
|
18026
|
+
sphere._plugins = options.plugins;
|
|
17772
18027
|
sphere._paymentsV2Composition = composition;
|
|
17773
18028
|
sphere._password = options.password ?? null;
|
|
17774
18029
|
sphere._passwordProtected = sphere._password !== null;
|
|
@@ -17855,6 +18110,7 @@ var Sphere = class _Sphere {
|
|
|
17855
18110
|
options.communications
|
|
17856
18111
|
);
|
|
17857
18112
|
sphere._verification = options.verification;
|
|
18113
|
+
sphere._plugins = options.plugins;
|
|
17858
18114
|
sphere._paymentsV2Composition = composition;
|
|
17859
18115
|
sphere._password = options.password ?? null;
|
|
17860
18116
|
sphere._passwordProtected = sphere._password !== null;
|
|
@@ -20165,7 +20421,8 @@ var Sphere = class _Sphere {
|
|
|
20165
20421
|
apiKey: oracle.getApiKey?.(),
|
|
20166
20422
|
privateKey: hexToBytes4(privateKey),
|
|
20167
20423
|
trustBaseJson,
|
|
20168
|
-
...this._verification ? { verification: this._verification } : {}
|
|
20424
|
+
...this._verification ? { verification: this._verification } : {},
|
|
20425
|
+
...this._plugins ? { plugins: this._plugins } : {}
|
|
20169
20426
|
});
|
|
20170
20427
|
} catch (err) {
|
|
20171
20428
|
logger.warn(
|