@unicitylabs/sphere-sdk 0.7.2 → 0.8.0-dev.0
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/core/index.cjs +1127 -767
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +3383 -3147
- package/dist/core/index.d.ts +3383 -3147
- package/dist/core/index.js +1115 -755
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +17 -19
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +17 -19
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/nodejs/index.cjs +17 -19
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +10 -5
- package/dist/impl/nodejs/index.d.ts +10 -5
- package/dist/impl/nodejs/index.js +17 -19
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +1181 -1041
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3906 -3728
- package/dist/index.d.ts +3906 -3728
- package/dist/index.js +1159 -1019
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/core/index.cjs
CHANGED
|
@@ -1971,26 +1971,14 @@ var NostrTransportProvider = class _NostrTransportProvider {
|
|
|
1971
1971
|
}
|
|
1972
1972
|
/**
|
|
1973
1973
|
* Convert a BindingInfo (from nostr-js-sdk) to PeerInfo (sphere-sdk type).
|
|
1974
|
-
* Computes PROXY address from nametag if available.
|
|
1975
1974
|
*/
|
|
1976
1975
|
async bindingInfoToPeerInfo(binding, nametag) {
|
|
1977
|
-
const nametagValue = nametag || binding.nametag;
|
|
1978
|
-
let proxyAddress = binding.proxyAddress;
|
|
1979
|
-
if (nametagValue && !proxyAddress) {
|
|
1980
|
-
try {
|
|
1981
|
-
const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
|
|
1982
|
-
const proxyAddr = await ProxyAddress.fromNameTag(nametagValue);
|
|
1983
|
-
proxyAddress = proxyAddr.toString();
|
|
1984
|
-
} catch {
|
|
1985
|
-
}
|
|
1986
|
-
}
|
|
1987
1976
|
return {
|
|
1988
|
-
nametag:
|
|
1977
|
+
nametag: nametag || binding.nametag,
|
|
1989
1978
|
transportPubkey: binding.transportPubkey,
|
|
1990
1979
|
chainPubkey: binding.publicKey || "",
|
|
1991
1980
|
l1Address: binding.l1Address || "",
|
|
1992
1981
|
directAddress: binding.directAddress || "",
|
|
1993
|
-
proxyAddress,
|
|
1994
1982
|
timestamp: binding.timestamp
|
|
1995
1983
|
};
|
|
1996
1984
|
}
|
|
@@ -2016,7 +2004,6 @@ var NostrTransportProvider = class _NostrTransportProvider {
|
|
|
2016
2004
|
chainPubkey: content.public_key || "",
|
|
2017
2005
|
l1Address: content.l1_address || "",
|
|
2018
2006
|
directAddress: content.direct_address || "",
|
|
2019
|
-
proxyAddress: content.proxy_address || void 0,
|
|
2020
2007
|
timestamp: bindingEvent.created_at * 1e3
|
|
2021
2008
|
};
|
|
2022
2009
|
} catch {
|
|
@@ -2059,7 +2046,6 @@ var NostrTransportProvider = class _NostrTransportProvider {
|
|
|
2059
2046
|
chainPubkey: content.public_key || "",
|
|
2060
2047
|
l1Address: content.l1_address || "",
|
|
2061
2048
|
directAddress: content.direct_address || "",
|
|
2062
|
-
proxyAddress: content.proxy_address || void 0,
|
|
2063
2049
|
timestamp: event.created_at * 1e3
|
|
2064
2050
|
});
|
|
2065
2051
|
} catch {
|
|
@@ -2129,8 +2115,6 @@ var NostrTransportProvider = class _NostrTransportProvider {
|
|
|
2129
2115
|
}
|
|
2130
2116
|
const nostrPubkey = this.getNostrPubkey();
|
|
2131
2117
|
if (nametag) {
|
|
2132
|
-
const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
|
|
2133
|
-
const proxyAddr = await ProxyAddress.fromNameTag(nametag);
|
|
2134
2118
|
try {
|
|
2135
2119
|
const success2 = await this.nostrClient.publishNametagBinding(
|
|
2136
2120
|
nametag,
|
|
@@ -2138,8 +2122,7 @@ var NostrTransportProvider = class _NostrTransportProvider {
|
|
|
2138
2122
|
{
|
|
2139
2123
|
publicKey: chainPubkey,
|
|
2140
2124
|
l1Address,
|
|
2141
|
-
directAddress
|
|
2142
|
-
proxyAddress: proxyAddr.toString()
|
|
2125
|
+
directAddress
|
|
2143
2126
|
}
|
|
2144
2127
|
);
|
|
2145
2128
|
if (success2) {
|
|
@@ -6189,6 +6172,13 @@ var L1PaymentsModule = class {
|
|
|
6189
6172
|
}
|
|
6190
6173
|
};
|
|
6191
6174
|
|
|
6175
|
+
// types/v2-transfer.ts
|
|
6176
|
+
function isV2TransferPayload(obj) {
|
|
6177
|
+
if (!obj || typeof obj !== "object") return false;
|
|
6178
|
+
const p = obj;
|
|
6179
|
+
return p.type === "V2_TRANSFER" && typeof p.tokenBlob === "string" && p.tokenBlob.length > 0;
|
|
6180
|
+
}
|
|
6181
|
+
|
|
6192
6182
|
// modules/payments/TokenSplitExecutor.ts
|
|
6193
6183
|
init_logger();
|
|
6194
6184
|
init_errors();
|
|
@@ -6562,18 +6552,117 @@ var TokenReservationLedger = class {
|
|
|
6562
6552
|
// modules/payments/SpendQueue.ts
|
|
6563
6553
|
init_logger();
|
|
6564
6554
|
init_errors();
|
|
6565
|
-
var
|
|
6555
|
+
var import_Token3 = require("@unicitylabs/state-transition-sdk/lib/token/Token");
|
|
6566
6556
|
var import_CoinId2 = require("@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId");
|
|
6557
|
+
|
|
6558
|
+
// token-engine/sdk.ts
|
|
6559
|
+
var import_StateTransitionClient = require("state-transition-sdk-v2/lib/StateTransitionClient.js");
|
|
6560
|
+
var import_AggregatorClient = require("state-transition-sdk-v2/lib/api/AggregatorClient.js");
|
|
6561
|
+
var import_NetworkId = require("state-transition-sdk-v2/lib/api/NetworkId.js");
|
|
6562
|
+
var import_CertificationData = require("state-transition-sdk-v2/lib/api/CertificationData.js");
|
|
6563
|
+
var import_CertificationResponse = require("state-transition-sdk-v2/lib/api/CertificationResponse.js");
|
|
6564
|
+
var import_StateId = require("state-transition-sdk-v2/lib/api/StateId.js");
|
|
6565
|
+
var import_InclusionProof = require("state-transition-sdk-v2/lib/api/InclusionProof.js");
|
|
6566
|
+
var import_InclusionProofResponse = require("state-transition-sdk-v2/lib/api/InclusionProofResponse.js");
|
|
6567
|
+
var import_RootTrustBase = require("state-transition-sdk-v2/lib/api/bft/RootTrustBase.js");
|
|
6568
|
+
var import_InclusionProofUtils2 = require("state-transition-sdk-v2/lib/util/InclusionProofUtils.js");
|
|
6569
|
+
var import_Token2 = require("state-transition-sdk-v2/lib/transaction/Token.js");
|
|
6570
|
+
var import_MintTransaction = require("state-transition-sdk-v2/lib/transaction/MintTransaction.js");
|
|
6571
|
+
var import_TransferTransaction = require("state-transition-sdk-v2/lib/transaction/TransferTransaction.js");
|
|
6572
|
+
var import_CertifiedMintTransaction = require("state-transition-sdk-v2/lib/transaction/CertifiedMintTransaction.js");
|
|
6573
|
+
var import_CertifiedTransferTransaction = require("state-transition-sdk-v2/lib/transaction/CertifiedTransferTransaction.js");
|
|
6574
|
+
var import_TokenId2 = require("state-transition-sdk-v2/lib/transaction/TokenId.js");
|
|
6575
|
+
var import_TokenType = require("state-transition-sdk-v2/lib/transaction/TokenType.js");
|
|
6576
|
+
var import_TokenSalt = require("state-transition-sdk-v2/lib/transaction/TokenSalt.js");
|
|
6577
|
+
var import_MintJustificationVerifierService = require("state-transition-sdk-v2/lib/transaction/verification/MintJustificationVerifierService.js");
|
|
6578
|
+
var import_EncodedPredicate = require("state-transition-sdk-v2/lib/predicate/EncodedPredicate.js");
|
|
6579
|
+
var import_SignaturePredicate = require("state-transition-sdk-v2/lib/predicate/builtin/SignaturePredicate.js");
|
|
6580
|
+
var import_SignaturePredicateUnlockScript = require("state-transition-sdk-v2/lib/predicate/builtin/SignaturePredicateUnlockScript.js");
|
|
6581
|
+
var import_BurnPredicate = require("state-transition-sdk-v2/lib/predicate/builtin/BurnPredicate.js");
|
|
6582
|
+
var import_PredicateVerifierService = require("state-transition-sdk-v2/lib/predicate/verification/PredicateVerifierService.js");
|
|
6583
|
+
var import_SigningService = require("state-transition-sdk-v2/lib/crypto/secp256k1/SigningService.js");
|
|
6584
|
+
var import_Signature = require("state-transition-sdk-v2/lib/crypto/secp256k1/Signature.js");
|
|
6585
|
+
var import_MintSigningService = require("state-transition-sdk-v2/lib/crypto/MintSigningService.js");
|
|
6586
|
+
var import_HashAlgorithm2 = require("state-transition-sdk-v2/lib/crypto/hash/HashAlgorithm.js");
|
|
6587
|
+
var import_DataHash = require("state-transition-sdk-v2/lib/crypto/hash/DataHash.js");
|
|
6588
|
+
var import_DataHasher = require("state-transition-sdk-v2/lib/crypto/hash/DataHasher.js");
|
|
6589
|
+
var import_DataHasherFactory = require("state-transition-sdk-v2/lib/crypto/hash/DataHasherFactory.js");
|
|
6590
|
+
var import_CborSerializer = require("state-transition-sdk-v2/lib/serialization/cbor/CborSerializer.js");
|
|
6591
|
+
var import_CborDeserializer = require("state-transition-sdk-v2/lib/serialization/cbor/CborDeserializer.js");
|
|
6592
|
+
var import_CborError = require("state-transition-sdk-v2/lib/serialization/cbor/CborError.js");
|
|
6593
|
+
var import_Asset = require("state-transition-sdk-v2/lib/payment/asset/Asset.js");
|
|
6594
|
+
var import_AssetId = require("state-transition-sdk-v2/lib/payment/asset/AssetId.js");
|
|
6595
|
+
var import_PaymentAssetCollection = require("state-transition-sdk-v2/lib/payment/asset/PaymentAssetCollection.js");
|
|
6596
|
+
var import_TokenSplit = require("state-transition-sdk-v2/lib/payment/TokenSplit.js");
|
|
6597
|
+
var import_SplitTokenRequest = require("state-transition-sdk-v2/lib/payment/SplitTokenRequest.js");
|
|
6598
|
+
var import_SplitToken = require("state-transition-sdk-v2/lib/payment/SplitToken.js");
|
|
6599
|
+
var import_SplitAssetProof = require("state-transition-sdk-v2/lib/payment/SplitAssetProof.js");
|
|
6600
|
+
var import_SplitMintJustification = require("state-transition-sdk-v2/lib/payment/SplitMintJustification.js");
|
|
6601
|
+
var import_SplitMintJustificationVerifier = require("state-transition-sdk-v2/lib/payment/SplitMintJustificationVerifier.js");
|
|
6602
|
+
var import_VerificationStatus = require("state-transition-sdk-v2/lib/verification/VerificationStatus.js");
|
|
6603
|
+
var import_VerificationResult = require("state-transition-sdk-v2/lib/verification/VerificationResult.js");
|
|
6604
|
+
var import_HexConverter = require("state-transition-sdk-v2/lib/util/HexConverter.js");
|
|
6605
|
+
var import_BigintConverter = require("state-transition-sdk-v2/lib/util/BigintConverter.js");
|
|
6606
|
+
var import_BitString = require("state-transition-sdk-v2/lib/util/BitString.js");
|
|
6607
|
+
|
|
6608
|
+
// token-engine/token-blob.ts
|
|
6609
|
+
var TOKEN_BLOB_TAG = 39051n;
|
|
6610
|
+
var TOKEN_BLOB_VERSION = 1;
|
|
6611
|
+
function encodeTokenBlob(blob) {
|
|
6612
|
+
return import_CborSerializer.CborSerializer.encodeTag(
|
|
6613
|
+
TOKEN_BLOB_TAG,
|
|
6614
|
+
import_CborSerializer.CborSerializer.encodeArray(
|
|
6615
|
+
import_CborSerializer.CborSerializer.encodeUnsignedInteger(BigInt(blob.v)),
|
|
6616
|
+
import_CborSerializer.CborSerializer.encodeUnsignedInteger(BigInt(blob.network)),
|
|
6617
|
+
import_CborSerializer.CborSerializer.encodeTextString(blob.tokenId),
|
|
6618
|
+
import_CborSerializer.CborSerializer.encodeByteString(blob.token)
|
|
6619
|
+
)
|
|
6620
|
+
);
|
|
6621
|
+
}
|
|
6622
|
+
function decodeTokenBlob(bytes) {
|
|
6623
|
+
const tag = import_CborDeserializer.CborDeserializer.decodeTag(bytes);
|
|
6624
|
+
if (tag.tag !== TOKEN_BLOB_TAG) {
|
|
6625
|
+
throw new import_CborError.CborError(`Invalid TokenBlob tag: ${tag.tag}`);
|
|
6626
|
+
}
|
|
6627
|
+
const fields = import_CborDeserializer.CborDeserializer.decodeArray(tag.data, 4);
|
|
6628
|
+
const v = Number(import_CborDeserializer.CborDeserializer.decodeUnsignedInteger(fields[0]));
|
|
6629
|
+
if (v !== TOKEN_BLOB_VERSION) {
|
|
6630
|
+
throw new import_CborError.CborError(`Unsupported TokenBlob version: ${v}`);
|
|
6631
|
+
}
|
|
6632
|
+
return {
|
|
6633
|
+
v,
|
|
6634
|
+
network: Number(import_CborDeserializer.CborDeserializer.decodeUnsignedInteger(fields[1])),
|
|
6635
|
+
tokenId: import_CborDeserializer.CborDeserializer.decodeTextString(fields[2]),
|
|
6636
|
+
token: import_CborDeserializer.CborDeserializer.decodeByteString(fields[3])
|
|
6637
|
+
};
|
|
6638
|
+
}
|
|
6639
|
+
|
|
6640
|
+
// modules/payments/SpendQueue.ts
|
|
6567
6641
|
var QUEUE_TIMEOUT_MS = 3e4;
|
|
6568
6642
|
var QUEUE_MAX_SIZE = 100;
|
|
6569
6643
|
var TAG2 = "SpendQueue";
|
|
6570
6644
|
var SpendPlanner = class {
|
|
6645
|
+
/**
|
|
6646
|
+
* Token engine (path B). When injected, value reads go through the v2 engine
|
|
6647
|
+
* (sdkData = engine blob); otherwise the legacy v1 SdkToken path is used. The
|
|
6648
|
+
* engine is wired after construction via {@link setEngine} (it is bound to the
|
|
6649
|
+
* payments deps, which arrive after the planner is built).
|
|
6650
|
+
*/
|
|
6651
|
+
engine;
|
|
6652
|
+
constructor(engine) {
|
|
6653
|
+
this.engine = engine;
|
|
6654
|
+
}
|
|
6655
|
+
/** Inject (or clear) the token engine. */
|
|
6656
|
+
setEngine(engine) {
|
|
6657
|
+
this.engine = engine;
|
|
6658
|
+
}
|
|
6571
6659
|
/**
|
|
6572
6660
|
* Async pre-computation: parse all tokens for a given coinId.
|
|
6573
6661
|
* Called BEFORE the synchronous critical section.
|
|
6574
6662
|
*
|
|
6575
|
-
* Filters to confirmed tokens matching the coinId,
|
|
6576
|
-
*
|
|
6663
|
+
* Filters to confirmed tokens matching the coinId, decodes each token's
|
|
6664
|
+
* sdkData and extracts the bigint amount — via the v2 engine when injected,
|
|
6665
|
+
* else the legacy v1 SdkToken path.
|
|
6577
6666
|
*/
|
|
6578
6667
|
async buildParsedPool(tokens, coinId) {
|
|
6579
6668
|
const pool = /* @__PURE__ */ new Map();
|
|
@@ -6582,20 +6671,28 @@ var SpendPlanner = class {
|
|
|
6582
6671
|
if (t.status !== "confirmed") continue;
|
|
6583
6672
|
if (!t.sdkData) continue;
|
|
6584
6673
|
try {
|
|
6585
|
-
const
|
|
6586
|
-
|
|
6587
|
-
const realAmount = this.getTokenBalance(sdkToken, coinId);
|
|
6588
|
-
if (realAmount <= 0n) {
|
|
6674
|
+
const { sdkToken, amount } = this.engine ? await this.parseViaEngine(t.sdkData, coinId) : await this.parseViaSdk(t.sdkData, coinId);
|
|
6675
|
+
if (amount <= 0n) {
|
|
6589
6676
|
logger.warn(TAG2, `Token ${t.id} has 0 balance for coinId ${coinId}`);
|
|
6590
6677
|
continue;
|
|
6591
6678
|
}
|
|
6592
|
-
pool.set(t.id, { token: t, sdkToken, amount
|
|
6679
|
+
pool.set(t.id, { token: t, sdkToken, amount });
|
|
6593
6680
|
} catch (e) {
|
|
6594
6681
|
logger.warn(TAG2, "Failed to parse token", t.id, e);
|
|
6595
6682
|
}
|
|
6596
6683
|
}
|
|
6597
6684
|
return pool;
|
|
6598
6685
|
}
|
|
6686
|
+
/** Engine path (v2): sdkData is the engine blob (hex of CBOR(TokenBlob)). */
|
|
6687
|
+
async parseViaEngine(sdkData, coinId) {
|
|
6688
|
+
const token = await this.engine.decodeToken(decodeTokenBlob(hexToBytes2(sdkData)));
|
|
6689
|
+
return { sdkToken: token, amount: this.engine.balanceOf(token, coinId) };
|
|
6690
|
+
}
|
|
6691
|
+
/** Legacy v1 path: sdkData is TXF JSON. */
|
|
6692
|
+
async parseViaSdk(sdkData, coinId) {
|
|
6693
|
+
const sdkToken = await import_Token3.Token.fromJSON(JSON.parse(sdkData));
|
|
6694
|
+
return { sdkToken, amount: this.getTokenBalance(sdkToken, coinId) };
|
|
6695
|
+
}
|
|
6599
6696
|
/**
|
|
6600
6697
|
* SYNCHRONOUS critical section. NO await allowed anywhere in this method.
|
|
6601
6698
|
*
|
|
@@ -7006,174 +7103,6 @@ var SpendQueue = class {
|
|
|
7006
7103
|
}
|
|
7007
7104
|
};
|
|
7008
7105
|
|
|
7009
|
-
// modules/payments/NametagMinter.ts
|
|
7010
|
-
init_logger();
|
|
7011
|
-
var import_Token3 = require("@unicitylabs/state-transition-sdk/lib/token/Token");
|
|
7012
|
-
var import_TokenId2 = require("@unicitylabs/state-transition-sdk/lib/token/TokenId");
|
|
7013
|
-
var import_TokenType = require("@unicitylabs/state-transition-sdk/lib/token/TokenType");
|
|
7014
|
-
var import_TokenState2 = require("@unicitylabs/state-transition-sdk/lib/token/TokenState");
|
|
7015
|
-
var import_MintTransactionData = require("@unicitylabs/state-transition-sdk/lib/transaction/MintTransactionData");
|
|
7016
|
-
var import_MintCommitment = require("@unicitylabs/state-transition-sdk/lib/transaction/MintCommitment");
|
|
7017
|
-
var import_HashAlgorithm2 = require("@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm");
|
|
7018
|
-
var import_UnmaskedPredicate2 = require("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate");
|
|
7019
|
-
var import_InclusionProofUtils2 = require("@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils");
|
|
7020
|
-
var import_nostr_js_sdk3 = require("@unicitylabs/nostr-js-sdk");
|
|
7021
|
-
var UNICITY_TOKEN_TYPE_HEX = "f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509";
|
|
7022
|
-
var NametagMinter = class {
|
|
7023
|
-
client;
|
|
7024
|
-
trustBase;
|
|
7025
|
-
signingService;
|
|
7026
|
-
skipVerification;
|
|
7027
|
-
debug;
|
|
7028
|
-
constructor(config) {
|
|
7029
|
-
this.client = config.stateTransitionClient;
|
|
7030
|
-
this.trustBase = config.trustBase;
|
|
7031
|
-
this.signingService = config.signingService;
|
|
7032
|
-
this.skipVerification = config.skipVerification ?? false;
|
|
7033
|
-
this.debug = config.debug ?? false;
|
|
7034
|
-
}
|
|
7035
|
-
log(message, ...args) {
|
|
7036
|
-
logger.debug("NametagMinter", message, ...args);
|
|
7037
|
-
}
|
|
7038
|
-
/**
|
|
7039
|
-
* Check if a nametag is available (not already minted)
|
|
7040
|
-
*/
|
|
7041
|
-
async isNametagAvailable(nametag) {
|
|
7042
|
-
try {
|
|
7043
|
-
const stripped = nametag.startsWith("@") ? nametag.slice(1) : nametag;
|
|
7044
|
-
const cleanNametag = (0, import_nostr_js_sdk3.normalizeNametag)(stripped);
|
|
7045
|
-
const nametagTokenId = await import_TokenId2.TokenId.fromNameTag(cleanNametag);
|
|
7046
|
-
const isMinted = await this.client.isMinted(this.trustBase, nametagTokenId);
|
|
7047
|
-
return !isMinted;
|
|
7048
|
-
} catch (error) {
|
|
7049
|
-
this.log("Error checking nametag availability:", error);
|
|
7050
|
-
return false;
|
|
7051
|
-
}
|
|
7052
|
-
}
|
|
7053
|
-
/**
|
|
7054
|
-
* Mint a nametag token on-chain
|
|
7055
|
-
*
|
|
7056
|
-
* @param nametag - The nametag to mint (e.g., "alice" or "@alice")
|
|
7057
|
-
* @param ownerAddress - The owner's direct address
|
|
7058
|
-
* @returns MintNametagResult with token if successful
|
|
7059
|
-
*/
|
|
7060
|
-
async mintNametag(nametag, ownerAddress) {
|
|
7061
|
-
const stripped = nametag.startsWith("@") ? nametag.slice(1) : nametag;
|
|
7062
|
-
const cleanNametag = (0, import_nostr_js_sdk3.normalizeNametag)(stripped);
|
|
7063
|
-
this.log(`Starting mint for nametag: ${cleanNametag}`);
|
|
7064
|
-
try {
|
|
7065
|
-
const nametagTokenId = await import_TokenId2.TokenId.fromNameTag(cleanNametag);
|
|
7066
|
-
const nametagTokenType = new import_TokenType.TokenType(
|
|
7067
|
-
Buffer.from(UNICITY_TOKEN_TYPE_HEX, "hex")
|
|
7068
|
-
);
|
|
7069
|
-
const nametagBytes = new TextEncoder().encode(cleanNametag);
|
|
7070
|
-
const pubKey = this.signingService.publicKey;
|
|
7071
|
-
const saltInput = new Uint8Array(pubKey.length + nametagBytes.length);
|
|
7072
|
-
saltInput.set(pubKey, 0);
|
|
7073
|
-
saltInput.set(nametagBytes, pubKey.length);
|
|
7074
|
-
const saltBuffer = await crypto.subtle.digest("SHA-256", saltInput);
|
|
7075
|
-
const salt = new Uint8Array(saltBuffer);
|
|
7076
|
-
this.log("Generated deterministic salt");
|
|
7077
|
-
const mintData = await import_MintTransactionData.MintTransactionData.createFromNametag(
|
|
7078
|
-
cleanNametag,
|
|
7079
|
-
nametagTokenType,
|
|
7080
|
-
ownerAddress,
|
|
7081
|
-
salt,
|
|
7082
|
-
ownerAddress
|
|
7083
|
-
);
|
|
7084
|
-
this.log("Created MintTransactionData");
|
|
7085
|
-
const commitment = await import_MintCommitment.MintCommitment.create(mintData);
|
|
7086
|
-
this.log("Created MintCommitment");
|
|
7087
|
-
const MAX_RETRIES = 3;
|
|
7088
|
-
let submitSuccess = false;
|
|
7089
|
-
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
7090
|
-
try {
|
|
7091
|
-
this.log(`Submitting commitment (attempt ${attempt}/${MAX_RETRIES})...`);
|
|
7092
|
-
const response = await this.client.submitMintCommitment(commitment);
|
|
7093
|
-
if (response.status === "SUCCESS" || response.status === "REQUEST_ID_EXISTS") {
|
|
7094
|
-
this.log(`Commitment ${response.status === "REQUEST_ID_EXISTS" ? "already exists" : "submitted successfully"}`);
|
|
7095
|
-
submitSuccess = true;
|
|
7096
|
-
break;
|
|
7097
|
-
} else {
|
|
7098
|
-
this.log(`Commitment failed: ${response.status}`);
|
|
7099
|
-
if (attempt === MAX_RETRIES) {
|
|
7100
|
-
return {
|
|
7101
|
-
success: false,
|
|
7102
|
-
error: `Failed to submit commitment after ${MAX_RETRIES} attempts: ${response.status}`
|
|
7103
|
-
};
|
|
7104
|
-
}
|
|
7105
|
-
await new Promise((r) => setTimeout(r, 1e3 * attempt));
|
|
7106
|
-
}
|
|
7107
|
-
} catch (error) {
|
|
7108
|
-
this.log(`Attempt ${attempt} error:`, error);
|
|
7109
|
-
if (attempt === MAX_RETRIES) {
|
|
7110
|
-
return {
|
|
7111
|
-
success: false,
|
|
7112
|
-
error: `Submit failed: ${error instanceof Error ? error.message : String(error)}`
|
|
7113
|
-
};
|
|
7114
|
-
}
|
|
7115
|
-
await new Promise((r) => setTimeout(r, 1e3 * attempt));
|
|
7116
|
-
}
|
|
7117
|
-
}
|
|
7118
|
-
if (!submitSuccess) {
|
|
7119
|
-
return {
|
|
7120
|
-
success: false,
|
|
7121
|
-
error: "Failed to submit commitment after retries"
|
|
7122
|
-
};
|
|
7123
|
-
}
|
|
7124
|
-
this.log("Waiting for inclusion proof...");
|
|
7125
|
-
const inclusionProof = await (0, import_InclusionProofUtils2.waitInclusionProof)(this.trustBase, this.client, commitment);
|
|
7126
|
-
this.log("Received inclusion proof");
|
|
7127
|
-
const genesisTransaction = commitment.toTransaction(inclusionProof);
|
|
7128
|
-
const nametagPredicate = await import_UnmaskedPredicate2.UnmaskedPredicate.create(
|
|
7129
|
-
nametagTokenId,
|
|
7130
|
-
nametagTokenType,
|
|
7131
|
-
this.signingService,
|
|
7132
|
-
import_HashAlgorithm2.HashAlgorithm.SHA256,
|
|
7133
|
-
salt
|
|
7134
|
-
);
|
|
7135
|
-
const tokenState = new import_TokenState2.TokenState(nametagPredicate, null);
|
|
7136
|
-
let token;
|
|
7137
|
-
if (this.skipVerification) {
|
|
7138
|
-
this.log("Creating token WITHOUT verification (dev mode)");
|
|
7139
|
-
const tokenJson = {
|
|
7140
|
-
version: "2.0",
|
|
7141
|
-
state: tokenState.toJSON(),
|
|
7142
|
-
genesis: genesisTransaction.toJSON(),
|
|
7143
|
-
transactions: [],
|
|
7144
|
-
nametags: []
|
|
7145
|
-
};
|
|
7146
|
-
token = await import_Token3.Token.fromJSON(tokenJson);
|
|
7147
|
-
} else {
|
|
7148
|
-
token = await import_Token3.Token.mint(
|
|
7149
|
-
this.trustBase,
|
|
7150
|
-
tokenState,
|
|
7151
|
-
genesisTransaction
|
|
7152
|
-
);
|
|
7153
|
-
}
|
|
7154
|
-
this.log(`Nametag minted successfully: ${cleanNametag}`);
|
|
7155
|
-
const nametagData = {
|
|
7156
|
-
name: cleanNametag,
|
|
7157
|
-
token: token.toJSON(),
|
|
7158
|
-
timestamp: Date.now(),
|
|
7159
|
-
format: "txf",
|
|
7160
|
-
version: "2.0"
|
|
7161
|
-
};
|
|
7162
|
-
return {
|
|
7163
|
-
success: true,
|
|
7164
|
-
token,
|
|
7165
|
-
nametagData
|
|
7166
|
-
};
|
|
7167
|
-
} catch (error) {
|
|
7168
|
-
this.log("Minting failed:", error);
|
|
7169
|
-
return {
|
|
7170
|
-
success: false,
|
|
7171
|
-
error: error instanceof Error ? error.message : String(error)
|
|
7172
|
-
};
|
|
7173
|
-
}
|
|
7174
|
-
}
|
|
7175
|
-
};
|
|
7176
|
-
|
|
7177
7106
|
// modules/payments/PaymentsModule.ts
|
|
7178
7107
|
init_constants();
|
|
7179
7108
|
|
|
@@ -7756,6 +7685,15 @@ function txfToToken(tokenId, txf) {
|
|
|
7756
7685
|
sdkData: JSON.stringify(txf)
|
|
7757
7686
|
};
|
|
7758
7687
|
}
|
|
7688
|
+
function isV2TokenBlob(sdkData) {
|
|
7689
|
+
return typeof sdkData === "string" && sdkData.length >= 2 && sdkData.length % 2 === 0 && sdkData[0] !== "{" && /^[0-9a-f]+$/i.test(sdkData);
|
|
7690
|
+
}
|
|
7691
|
+
function v2TokenId(token) {
|
|
7692
|
+
return token.id.startsWith("v2_") ? token.id.slice(3) : token.id;
|
|
7693
|
+
}
|
|
7694
|
+
function isV2TokenEntry(entry) {
|
|
7695
|
+
return typeof entry === "object" && entry !== null && !("genesis" in entry) && isV2TokenBlob(entry.sdkData);
|
|
7696
|
+
}
|
|
7759
7697
|
async function buildTxfStorageData(tokens, meta, options) {
|
|
7760
7698
|
const storageData = {
|
|
7761
7699
|
_meta: {
|
|
@@ -7786,6 +7724,8 @@ async function buildTxfStorageData(tokens, meta, options) {
|
|
|
7786
7724
|
if (txf) {
|
|
7787
7725
|
const actualTokenId = txf.genesis.data.tokenId;
|
|
7788
7726
|
storageData[keyFromTokenId(actualTokenId)] = txf;
|
|
7727
|
+
} else if (isV2TokenBlob(token.sdkData)) {
|
|
7728
|
+
storageData[keyFromTokenId(v2TokenId(token))] = token;
|
|
7789
7729
|
}
|
|
7790
7730
|
}
|
|
7791
7731
|
if (options?.archivedTokens && options.archivedTokens.size > 0) {
|
|
@@ -7883,6 +7823,8 @@ function parseTxfStorageData(data) {
|
|
|
7883
7823
|
if (txfToken?.genesis?.data?.tokenId) {
|
|
7884
7824
|
const token = txfToToken(tokenId, txfToken);
|
|
7885
7825
|
result.tokens.push(token);
|
|
7826
|
+
} else if (isV2TokenEntry(storageData[key])) {
|
|
7827
|
+
result.tokens.push(storageData[key]);
|
|
7886
7828
|
}
|
|
7887
7829
|
} catch (err) {
|
|
7888
7830
|
result.validationErrors.push(`Token ${tokenId}: ${err}`);
|
|
@@ -8107,12 +8049,12 @@ init_logger();
|
|
|
8107
8049
|
init_errors();
|
|
8108
8050
|
var import_Token4 = require("@unicitylabs/state-transition-sdk/lib/token/Token");
|
|
8109
8051
|
var import_TokenId3 = require("@unicitylabs/state-transition-sdk/lib/token/TokenId");
|
|
8110
|
-
var
|
|
8052
|
+
var import_TokenState2 = require("@unicitylabs/state-transition-sdk/lib/token/TokenState");
|
|
8111
8053
|
var import_CoinId3 = require("@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId");
|
|
8112
8054
|
var import_TokenCoinData2 = require("@unicitylabs/state-transition-sdk/lib/token/fungible/TokenCoinData");
|
|
8113
8055
|
var import_TokenSplitBuilder2 = require("@unicitylabs/state-transition-sdk/lib/transaction/split/TokenSplitBuilder");
|
|
8114
8056
|
var import_HashAlgorithm3 = require("@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm");
|
|
8115
|
-
var
|
|
8057
|
+
var import_UnmaskedPredicate2 = require("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate");
|
|
8116
8058
|
var import_UnmaskedPredicateReference2 = require("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference");
|
|
8117
8059
|
var import_TransferCommitment2 = require("@unicitylabs/state-transition-sdk/lib/transaction/TransferCommitment");
|
|
8118
8060
|
var import_InclusionProofUtils3 = require("@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils");
|
|
@@ -8234,14 +8176,14 @@ var InstantSplitExecutor = class {
|
|
|
8234
8176
|
options?.message
|
|
8235
8177
|
// on-chain message (invoice memo bytes, or null)
|
|
8236
8178
|
);
|
|
8237
|
-
const mintedPredicate = await
|
|
8179
|
+
const mintedPredicate = await import_UnmaskedPredicate2.UnmaskedPredicate.create(
|
|
8238
8180
|
recipientTokenId,
|
|
8239
8181
|
tokenToSplit.type,
|
|
8240
8182
|
this.signingService,
|
|
8241
8183
|
import_HashAlgorithm3.HashAlgorithm.SHA256,
|
|
8242
8184
|
recipientSalt
|
|
8243
8185
|
);
|
|
8244
|
-
const mintedState = new
|
|
8186
|
+
const mintedState = new import_TokenState2.TokenState(mintedPredicate, null);
|
|
8245
8187
|
logger.debug("InstantSplit", "Step 5: Packaging V5 bundle...");
|
|
8246
8188
|
const senderPubkey = toHex2(this.signingService.publicKey);
|
|
8247
8189
|
let nametagTokenJson;
|
|
@@ -8356,14 +8298,14 @@ var InstantSplitExecutor = class {
|
|
|
8356
8298
|
* It does NOT need the genesis transaction or mint proof.
|
|
8357
8299
|
*/
|
|
8358
8300
|
async createTransferCommitmentFromMintData(mintData, recipientAddress, transferSalt, signingService, nametagTokens, message) {
|
|
8359
|
-
const predicate = await
|
|
8301
|
+
const predicate = await import_UnmaskedPredicate2.UnmaskedPredicate.create(
|
|
8360
8302
|
mintData.tokenId,
|
|
8361
8303
|
mintData.tokenType,
|
|
8362
8304
|
signingService,
|
|
8363
8305
|
import_HashAlgorithm3.HashAlgorithm.SHA256,
|
|
8364
8306
|
mintData.salt
|
|
8365
8307
|
);
|
|
8366
|
-
const state = new
|
|
8308
|
+
const state = new import_TokenState2.TokenState(predicate, null);
|
|
8367
8309
|
const minimalToken = {
|
|
8368
8310
|
state,
|
|
8369
8311
|
nametagTokens: nametagTokens || [],
|
|
@@ -8424,14 +8366,14 @@ var InstantSplitExecutor = class {
|
|
|
8424
8366
|
message: `Mint proof received in ${proofDuration.toFixed(0)}ms`
|
|
8425
8367
|
});
|
|
8426
8368
|
const mintTransaction = senderMintCommitment.toTransaction(senderMintProof);
|
|
8427
|
-
const predicate = await
|
|
8369
|
+
const predicate = await import_UnmaskedPredicate2.UnmaskedPredicate.create(
|
|
8428
8370
|
context.senderTokenId,
|
|
8429
8371
|
context.tokenType,
|
|
8430
8372
|
context.signingService,
|
|
8431
8373
|
import_HashAlgorithm3.HashAlgorithm.SHA256,
|
|
8432
8374
|
context.senderSalt
|
|
8433
8375
|
);
|
|
8434
|
-
const state = new
|
|
8376
|
+
const state = new import_TokenState2.TokenState(predicate, null);
|
|
8435
8377
|
const changeToken = await import_Token4.Token.mint(this.trustBase, state, mintTransaction);
|
|
8436
8378
|
if (!this.devMode) {
|
|
8437
8379
|
const verification = await changeToken.verify(this.trustBase);
|
|
@@ -8511,14 +8453,14 @@ var InstantSplitExecutor = class {
|
|
|
8511
8453
|
init_logger();
|
|
8512
8454
|
init_errors();
|
|
8513
8455
|
var import_Token5 = require("@unicitylabs/state-transition-sdk/lib/token/Token");
|
|
8514
|
-
var
|
|
8456
|
+
var import_TokenState3 = require("@unicitylabs/state-transition-sdk/lib/token/TokenState");
|
|
8515
8457
|
var import_TokenType2 = require("@unicitylabs/state-transition-sdk/lib/token/TokenType");
|
|
8516
8458
|
var import_HashAlgorithm4 = require("@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm");
|
|
8517
|
-
var
|
|
8459
|
+
var import_UnmaskedPredicate3 = require("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate");
|
|
8518
8460
|
var import_TransferCommitment3 = require("@unicitylabs/state-transition-sdk/lib/transaction/TransferCommitment");
|
|
8519
|
-
var
|
|
8520
|
-
var
|
|
8521
|
-
var
|
|
8461
|
+
var import_TransferTransaction2 = require("@unicitylabs/state-transition-sdk/lib/transaction/TransferTransaction");
|
|
8462
|
+
var import_MintCommitment = require("@unicitylabs/state-transition-sdk/lib/transaction/MintCommitment");
|
|
8463
|
+
var import_MintTransactionData = require("@unicitylabs/state-transition-sdk/lib/transaction/MintTransactionData");
|
|
8522
8464
|
var import_InclusionProofUtils4 = require("@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils");
|
|
8523
8465
|
|
|
8524
8466
|
// types/instant-split.ts
|
|
@@ -8611,11 +8553,11 @@ var InstantSplitProcessor = class {
|
|
|
8611
8553
|
logger.warn("InstantSplit", "Sender pubkey mismatch (non-fatal)");
|
|
8612
8554
|
}
|
|
8613
8555
|
const burnTxJson = JSON.parse(bundle.burnTransaction);
|
|
8614
|
-
const _burnTransaction = await
|
|
8556
|
+
const _burnTransaction = await import_TransferTransaction2.TransferTransaction.fromJSON(burnTxJson);
|
|
8615
8557
|
logger.debug("InstantSplit", "Burn transaction validated");
|
|
8616
8558
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
8617
|
-
const mintData = await
|
|
8618
|
-
const mintCommitment = await
|
|
8559
|
+
const mintData = await import_MintTransactionData.MintTransactionData.fromJSON(mintDataJson);
|
|
8560
|
+
const mintCommitment = await import_MintCommitment.MintCommitment.create(mintData);
|
|
8619
8561
|
logger.debug("InstantSplit", "Mint commitment recreated");
|
|
8620
8562
|
const mintResponse = await this.client.submitMintCommitment(mintCommitment);
|
|
8621
8563
|
if (mintResponse.status !== "SUCCESS" && mintResponse.status !== "REQUEST_ID_EXISTS") {
|
|
@@ -8647,14 +8589,14 @@ var InstantSplitProcessor = class {
|
|
|
8647
8589
|
const transferTransaction = transferCommitment.toTransaction(transferProof);
|
|
8648
8590
|
logger.debug("InstantSplit", "Transfer proof received");
|
|
8649
8591
|
const transferSalt = fromHex3(bundle.transferSaltHex);
|
|
8650
|
-
const finalRecipientPredicate = await
|
|
8592
|
+
const finalRecipientPredicate = await import_UnmaskedPredicate3.UnmaskedPredicate.create(
|
|
8651
8593
|
mintData.tokenId,
|
|
8652
8594
|
tokenType,
|
|
8653
8595
|
signingService,
|
|
8654
8596
|
import_HashAlgorithm4.HashAlgorithm.SHA256,
|
|
8655
8597
|
transferSalt
|
|
8656
8598
|
);
|
|
8657
|
-
const finalRecipientState = new
|
|
8599
|
+
const finalRecipientState = new import_TokenState3.TokenState(finalRecipientPredicate, null);
|
|
8658
8600
|
logger.debug("InstantSplit", "Final recipient state created");
|
|
8659
8601
|
let nametagTokens = [];
|
|
8660
8602
|
const recipientAddressStr = bundle.recipientAddressJson;
|
|
@@ -8761,8 +8703,8 @@ var InstantSplitProcessor = class {
|
|
|
8761
8703
|
await this.waitInclusionProofWithDevBypass(burnCommitment, options?.proofTimeoutMs);
|
|
8762
8704
|
logger.debug("InstantSplit", "V4: Burn proof received");
|
|
8763
8705
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
8764
|
-
const mintData = await
|
|
8765
|
-
const mintCommitment = await
|
|
8706
|
+
const mintData = await import_MintTransactionData.MintTransactionData.fromJSON(mintDataJson);
|
|
8707
|
+
const mintCommitment = await import_MintCommitment.MintCommitment.create(mintData);
|
|
8766
8708
|
const mintResponse = await this.client.submitMintCommitment(mintCommitment);
|
|
8767
8709
|
if (mintResponse.status !== "SUCCESS" && mintResponse.status !== "REQUEST_ID_EXISTS") {
|
|
8768
8710
|
throw new SphereError(`Mint submission failed: ${mintResponse.status}`, "TRANSFER_FAILED");
|
|
@@ -8775,14 +8717,14 @@ var InstantSplitProcessor = class {
|
|
|
8775
8717
|
logger.debug("InstantSplit", "V4: Mint proof received");
|
|
8776
8718
|
const tokenType = new import_TokenType2.TokenType(fromHex3(bundle.tokenTypeHex));
|
|
8777
8719
|
const recipientSalt = fromHex3(bundle.recipientSaltHex);
|
|
8778
|
-
const recipientPredicate = await
|
|
8720
|
+
const recipientPredicate = await import_UnmaskedPredicate3.UnmaskedPredicate.create(
|
|
8779
8721
|
mintData.tokenId,
|
|
8780
8722
|
tokenType,
|
|
8781
8723
|
signingService,
|
|
8782
8724
|
import_HashAlgorithm4.HashAlgorithm.SHA256,
|
|
8783
8725
|
recipientSalt
|
|
8784
8726
|
);
|
|
8785
|
-
const recipientState = new
|
|
8727
|
+
const recipientState = new import_TokenState3.TokenState(recipientPredicate, null);
|
|
8786
8728
|
const tokenJson = {
|
|
8787
8729
|
version: "2.0",
|
|
8788
8730
|
state: recipientState.toJSON(),
|
|
@@ -8805,14 +8747,14 @@ var InstantSplitProcessor = class {
|
|
|
8805
8747
|
const transferTransaction = transferCommitment.toTransaction(transferProof);
|
|
8806
8748
|
logger.debug("InstantSplit", "V4: Transfer proof received");
|
|
8807
8749
|
const transferSalt = fromHex3(bundle.transferSaltHex);
|
|
8808
|
-
const finalPredicate = await
|
|
8750
|
+
const finalPredicate = await import_UnmaskedPredicate3.UnmaskedPredicate.create(
|
|
8809
8751
|
mintData.tokenId,
|
|
8810
8752
|
tokenType,
|
|
8811
8753
|
signingService,
|
|
8812
8754
|
import_HashAlgorithm4.HashAlgorithm.SHA256,
|
|
8813
8755
|
transferSalt
|
|
8814
8756
|
);
|
|
8815
|
-
const finalState = new
|
|
8757
|
+
const finalState = new import_TokenState3.TokenState(finalPredicate, null);
|
|
8816
8758
|
const finalTokenJson = mintedToken.toJSON();
|
|
8817
8759
|
finalTokenJson.state = finalState.toJSON();
|
|
8818
8760
|
finalTokenJson.transactions = [transferTransaction.toJSON()];
|
|
@@ -8863,17 +8805,17 @@ var InstantSplitProcessor = class {
|
|
|
8863
8805
|
var import_Token6 = require("@unicitylabs/state-transition-sdk/lib/token/Token");
|
|
8864
8806
|
var import_CoinId4 = require("@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId");
|
|
8865
8807
|
var import_TransferCommitment4 = require("@unicitylabs/state-transition-sdk/lib/transaction/TransferCommitment");
|
|
8866
|
-
var
|
|
8867
|
-
var
|
|
8808
|
+
var import_TransferTransaction3 = require("@unicitylabs/state-transition-sdk/lib/transaction/TransferTransaction");
|
|
8809
|
+
var import_SigningService2 = require("@unicitylabs/state-transition-sdk/lib/sign/SigningService");
|
|
8868
8810
|
var import_AddressScheme = require("@unicitylabs/state-transition-sdk/lib/address/AddressScheme");
|
|
8869
|
-
var
|
|
8870
|
-
var
|
|
8811
|
+
var import_UnmaskedPredicate4 = require("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate");
|
|
8812
|
+
var import_TokenState4 = require("@unicitylabs/state-transition-sdk/lib/token/TokenState");
|
|
8871
8813
|
var import_HashAlgorithm5 = require("@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm");
|
|
8872
8814
|
var import_TokenType3 = require("@unicitylabs/state-transition-sdk/lib/token/TokenType");
|
|
8873
|
-
var
|
|
8874
|
-
var
|
|
8815
|
+
var import_MintCommitment2 = require("@unicitylabs/state-transition-sdk/lib/transaction/MintCommitment");
|
|
8816
|
+
var import_MintTransactionData2 = require("@unicitylabs/state-transition-sdk/lib/transaction/MintTransactionData");
|
|
8875
8817
|
var import_InclusionProofUtils5 = require("@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils");
|
|
8876
|
-
var
|
|
8818
|
+
var import_InclusionProof2 = require("@unicitylabs/state-transition-sdk/lib/transaction/InclusionProof");
|
|
8877
8819
|
function computeHistoryDedupKey(type, tokenId, transferId) {
|
|
8878
8820
|
if (type === "SENT" && transferId) return `${type}_transfer_${transferId}`;
|
|
8879
8821
|
if (tokenId) return `${type}_${tokenId}`;
|
|
@@ -8894,7 +8836,7 @@ function enrichWithRegistry(info) {
|
|
|
8894
8836
|
}
|
|
8895
8837
|
return info;
|
|
8896
8838
|
}
|
|
8897
|
-
async function parseTokenInfo(tokenData) {
|
|
8839
|
+
async function parseTokenInfo(tokenData, engine) {
|
|
8898
8840
|
const defaultInfo = {
|
|
8899
8841
|
coinId: "ALPHA",
|
|
8900
8842
|
symbol: "ALPHA",
|
|
@@ -8902,6 +8844,25 @@ async function parseTokenInfo(tokenData) {
|
|
|
8902
8844
|
decimals: 0,
|
|
8903
8845
|
amount: "0"
|
|
8904
8846
|
};
|
|
8847
|
+
if (engine && typeof tokenData === "string" && looksLikeTokenBlob(tokenData)) {
|
|
8848
|
+
try {
|
|
8849
|
+
const token = await engine.decodeToken(decodeTokenBlob(hexToBytes2(tokenData)));
|
|
8850
|
+
const first = engine.readValue(token)?.assets[0];
|
|
8851
|
+
if (first) {
|
|
8852
|
+
return enrichWithRegistry({
|
|
8853
|
+
coinId: first.coinId,
|
|
8854
|
+
symbol: first.coinId.slice(0, 8),
|
|
8855
|
+
name: `Token ${first.coinId.slice(0, 8)}`,
|
|
8856
|
+
decimals: 0,
|
|
8857
|
+
amount: String(first.amount),
|
|
8858
|
+
tokenId: engine.tokenId(token)
|
|
8859
|
+
});
|
|
8860
|
+
}
|
|
8861
|
+
return { ...defaultInfo, tokenId: engine.tokenId(token) };
|
|
8862
|
+
} catch (error) {
|
|
8863
|
+
logger.warn("Payments", "Failed to parse token info via engine:", error);
|
|
8864
|
+
}
|
|
8865
|
+
}
|
|
8905
8866
|
try {
|
|
8906
8867
|
const data = typeof tokenData === "string" ? JSON.parse(tokenData) : tokenData;
|
|
8907
8868
|
try {
|
|
@@ -9040,27 +9001,41 @@ async function parseTokenInfo(tokenData) {
|
|
|
9040
9001
|
}
|
|
9041
9002
|
var sdkDataCache = /* @__PURE__ */ new Map();
|
|
9042
9003
|
var SDK_DATA_CACHE_MAX = 2e3;
|
|
9004
|
+
function looksLikeTokenBlob(sdkData) {
|
|
9005
|
+
return sdkData.length >= 2 && sdkData.length % 2 === 0 && sdkData[0] !== "{" && /^[0-9a-f]+$/i.test(sdkData);
|
|
9006
|
+
}
|
|
9007
|
+
function tryParseBlobKeys(sdkData) {
|
|
9008
|
+
try {
|
|
9009
|
+
const blob = decodeTokenBlob(hexToBytes2(sdkData));
|
|
9010
|
+
return { tokenId: blob.tokenId, stateHash: sha2562(bytesToHex3(blob.token), "hex") };
|
|
9011
|
+
} catch {
|
|
9012
|
+
return null;
|
|
9013
|
+
}
|
|
9014
|
+
}
|
|
9043
9015
|
function parseSdkDataCached(sdkData) {
|
|
9044
9016
|
const cached = sdkDataCache.get(sdkData);
|
|
9045
9017
|
if (cached) return cached;
|
|
9046
|
-
let
|
|
9047
|
-
|
|
9048
|
-
|
|
9049
|
-
|
|
9050
|
-
|
|
9051
|
-
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
|
|
9018
|
+
let entry = looksLikeTokenBlob(sdkData) ? tryParseBlobKeys(sdkData) : null;
|
|
9019
|
+
if (!entry) {
|
|
9020
|
+
let tokenId = null;
|
|
9021
|
+
let stateHash = "";
|
|
9022
|
+
try {
|
|
9023
|
+
const txf = JSON.parse(sdkData);
|
|
9024
|
+
tokenId = txf.genesis?.data?.tokenId || null;
|
|
9025
|
+
stateHash = getCurrentStateHash(txf) || "";
|
|
9026
|
+
if (!stateHash) {
|
|
9027
|
+
if (txf.state?.hash) {
|
|
9028
|
+
stateHash = txf.state.hash;
|
|
9029
|
+
} else if (txf.stateHash) {
|
|
9030
|
+
stateHash = txf.stateHash;
|
|
9031
|
+
} else if (txf.currentStateHash) {
|
|
9032
|
+
stateHash = txf.currentStateHash;
|
|
9033
|
+
}
|
|
9059
9034
|
}
|
|
9035
|
+
} catch {
|
|
9060
9036
|
}
|
|
9061
|
-
|
|
9037
|
+
entry = { tokenId, stateHash };
|
|
9062
9038
|
}
|
|
9063
|
-
const entry = { tokenId, stateHash };
|
|
9064
9039
|
if (sdkDataCache.size >= SDK_DATA_CACHE_MAX) {
|
|
9065
9040
|
sdkDataCache.clear();
|
|
9066
9041
|
}
|
|
@@ -9337,6 +9312,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
9337
9312
|
);
|
|
9338
9313
|
this.deps = deps;
|
|
9339
9314
|
this.priceProvider = deps.price ?? null;
|
|
9315
|
+
this.spendPlanner.setEngine(deps.tokenEngine);
|
|
9340
9316
|
if (this.l1) {
|
|
9341
9317
|
this.l1.initialize({
|
|
9342
9318
|
identity: deps.identity,
|
|
@@ -9561,7 +9537,59 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
9561
9537
|
request.invoiceRefundAddress,
|
|
9562
9538
|
request.invoiceContact
|
|
9563
9539
|
);
|
|
9564
|
-
if (
|
|
9540
|
+
if (this.deps?.tokenEngine && peerInfo?.chainPubkey) {
|
|
9541
|
+
const engine = this.deps.tokenEngine;
|
|
9542
|
+
const recipientChainPubkey = hexToBytes2(peerInfo.chainPubkey);
|
|
9543
|
+
const memoData = onChainMessage ?? void 0;
|
|
9544
|
+
const handToRecipient = async (finished) => {
|
|
9545
|
+
const tokenBlob = bytesToHex3(encodeTokenBlob(engine.encodeToken(finished)));
|
|
9546
|
+
await this.deps.transport.sendTokenTransfer(recipientPubkey, {
|
|
9547
|
+
type: "V2_TRANSFER",
|
|
9548
|
+
version: "2.0",
|
|
9549
|
+
tokenBlob,
|
|
9550
|
+
memo: request.memo
|
|
9551
|
+
});
|
|
9552
|
+
};
|
|
9553
|
+
for (const tw of splitPlan.tokensToTransferDirectly) {
|
|
9554
|
+
const finished = await engine.transfer({
|
|
9555
|
+
token: tw.sdkToken,
|
|
9556
|
+
recipientPubkey: recipientChainPubkey,
|
|
9557
|
+
data: memoData
|
|
9558
|
+
});
|
|
9559
|
+
await handToRecipient(finished);
|
|
9560
|
+
result.tokenTransfers.push({ sourceTokenId: tw.uiToken.id, method: "direct" });
|
|
9561
|
+
await this.removeToken(tw.uiToken.id, result.id);
|
|
9562
|
+
}
|
|
9563
|
+
if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
|
|
9564
|
+
const selfChainPubkey = hexToBytes2(this.deps.identity.chainPubkey);
|
|
9565
|
+
const { outputs } = await engine.split({
|
|
9566
|
+
token: splitPlan.tokenToSplit.sdkToken,
|
|
9567
|
+
outputs: [
|
|
9568
|
+
{ recipientPubkey: recipientChainPubkey, coinId: request.coinId, amount: splitPlan.splitAmount, data: memoData },
|
|
9569
|
+
{ recipientPubkey: selfChainPubkey, coinId: request.coinId, amount: splitPlan.remainderAmount }
|
|
9570
|
+
]
|
|
9571
|
+
});
|
|
9572
|
+
await handToRecipient(outputs[0]);
|
|
9573
|
+
const changeToken = outputs[1];
|
|
9574
|
+
const changeBlob = bytesToHex3(encodeTokenBlob(engine.encodeToken(changeToken)));
|
|
9575
|
+
const changeInfo = await parseTokenInfo(changeBlob, engine);
|
|
9576
|
+
const registry = TokenRegistry.getInstance();
|
|
9577
|
+
await this.addToken({
|
|
9578
|
+
id: `v2_${engine.tokenId(changeToken)}`,
|
|
9579
|
+
coinId: changeInfo.coinId,
|
|
9580
|
+
symbol: registry.getSymbol(changeInfo.coinId) || changeInfo.symbol,
|
|
9581
|
+
name: registry.getName(changeInfo.coinId) || changeInfo.name,
|
|
9582
|
+
decimals: registry.getDecimals(changeInfo.coinId) ?? changeInfo.decimals,
|
|
9583
|
+
amount: changeInfo.amount,
|
|
9584
|
+
status: "confirmed",
|
|
9585
|
+
createdAt: Date.now(),
|
|
9586
|
+
updatedAt: Date.now(),
|
|
9587
|
+
sdkData: changeBlob
|
|
9588
|
+
});
|
|
9589
|
+
result.tokenTransfers.push({ sourceTokenId: splitPlan.tokenToSplit.uiToken.id, method: "split" });
|
|
9590
|
+
await this.removeToken(splitPlan.tokenToSplit.uiToken.id, result.id);
|
|
9591
|
+
}
|
|
9592
|
+
} else if (transferMode === "conservative") {
|
|
9565
9593
|
if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
|
|
9566
9594
|
logger.debug("Payments", "Executing conservative split...");
|
|
9567
9595
|
const splitExecutor = new TokenSplitExecutor({
|
|
@@ -10157,7 +10185,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
10157
10185
|
* because bundle-level dedup protects against replays, and split children share genesis IDs.
|
|
10158
10186
|
*/
|
|
10159
10187
|
async saveCommitmentOnlyToken(sourceTokenInput, commitmentInput, senderPubkey, deferPersistence = false, skipGenesisDedup = false) {
|
|
10160
|
-
const tokenInfo = await parseTokenInfo(sourceTokenInput);
|
|
10188
|
+
const tokenInfo = await parseTokenInfo(sourceTokenInput, this.deps?.tokenEngine);
|
|
10161
10189
|
const sdkData = typeof sourceTokenInput === "string" ? sourceTokenInput : JSON.stringify(sourceTokenInput);
|
|
10162
10190
|
const nostrTokenId = extractTokenIdFromSdkData(sdkData);
|
|
10163
10191
|
const nostrStateHash = extractStateHashFromSdkData(sdkData);
|
|
@@ -11249,8 +11277,8 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
11249
11277
|
if (pending2.stage === "RECEIVED") {
|
|
11250
11278
|
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: RECEIVED \u2192 submitting mint commitment...`);
|
|
11251
11279
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
11252
|
-
const mintData = await
|
|
11253
|
-
const mintCommitment = await
|
|
11280
|
+
const mintData = await import_MintTransactionData2.MintTransactionData.fromJSON(mintDataJson);
|
|
11281
|
+
const mintCommitment = await import_MintCommitment2.MintCommitment.create(mintData);
|
|
11254
11282
|
const mintResponse = await stClient.submitMintCommitment(mintCommitment);
|
|
11255
11283
|
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: mint response status=${mintResponse.status}`);
|
|
11256
11284
|
if (mintResponse.status !== "SUCCESS" && mintResponse.status !== "REQUEST_ID_EXISTS") {
|
|
@@ -11262,8 +11290,8 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
11262
11290
|
if (pending2.stage === "MINT_SUBMITTED") {
|
|
11263
11291
|
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: MINT_SUBMITTED \u2192 checking mint proof...`);
|
|
11264
11292
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
11265
|
-
const mintData = await
|
|
11266
|
-
const mintCommitment = await
|
|
11293
|
+
const mintData = await import_MintTransactionData2.MintTransactionData.fromJSON(mintDataJson);
|
|
11294
|
+
const mintCommitment = await import_MintCommitment2.MintCommitment.create(mintData);
|
|
11267
11295
|
const proof = await this.quickProofCheck(stClient, trustBase, mintCommitment);
|
|
11268
11296
|
if (!proof) {
|
|
11269
11297
|
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: mint proof not yet available, staying MINT_SUBMITTED`);
|
|
@@ -11360,10 +11388,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
11360
11388
|
*/
|
|
11361
11389
|
async finalizeFromV5Bundle(bundle, pending2, signingService, stClient, trustBase) {
|
|
11362
11390
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
11363
|
-
const mintData = await
|
|
11364
|
-
const mintCommitment = await
|
|
11391
|
+
const mintData = await import_MintTransactionData2.MintTransactionData.fromJSON(mintDataJson);
|
|
11392
|
+
const mintCommitment = await import_MintCommitment2.MintCommitment.create(mintData);
|
|
11365
11393
|
const mintProofJson = JSON.parse(pending2.mintProofJson);
|
|
11366
|
-
const mintProof =
|
|
11394
|
+
const mintProof = import_InclusionProof2.InclusionProof.fromJSON(mintProofJson);
|
|
11367
11395
|
const mintTransaction = mintCommitment.toTransaction(mintProof);
|
|
11368
11396
|
const tokenType = new import_TokenType3.TokenType(fromHex4(bundle.tokenTypeHex));
|
|
11369
11397
|
const senderMintedStateJson = JSON.parse(bundle.mintedTokenStateJson);
|
|
@@ -11380,14 +11408,14 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
11380
11408
|
const transferProof = await (0, import_InclusionProofUtils5.waitInclusionProof)(trustBase, stClient, transferCommitment);
|
|
11381
11409
|
const transferTransaction = transferCommitment.toTransaction(transferProof);
|
|
11382
11410
|
const transferSalt = fromHex4(bundle.transferSaltHex);
|
|
11383
|
-
const recipientPredicate = await
|
|
11411
|
+
const recipientPredicate = await import_UnmaskedPredicate4.UnmaskedPredicate.create(
|
|
11384
11412
|
mintData.tokenId,
|
|
11385
11413
|
tokenType,
|
|
11386
11414
|
signingService,
|
|
11387
11415
|
import_HashAlgorithm5.HashAlgorithm.SHA256,
|
|
11388
11416
|
transferSalt
|
|
11389
11417
|
);
|
|
11390
|
-
const recipientState = new
|
|
11418
|
+
const recipientState = new import_TokenState4.TokenState(recipientPredicate, null);
|
|
11391
11419
|
let nametagTokens = [];
|
|
11392
11420
|
const recipientAddressStr = bundle.recipientAddressJson;
|
|
11393
11421
|
if (recipientAddressStr.startsWith("PROXY://")) {
|
|
@@ -12124,68 +12152,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12124
12152
|
}
|
|
12125
12153
|
}
|
|
12126
12154
|
}
|
|
12127
|
-
/**
|
|
12128
|
-
* Mint a nametag token on-chain (like Sphere wallet and lottery)
|
|
12129
|
-
* This creates the nametag token required for receiving tokens via PROXY addresses
|
|
12130
|
-
*
|
|
12131
|
-
* @param nametag - The nametag to mint (e.g., "alice" or "@alice")
|
|
12132
|
-
* @returns MintNametagResult with success status and token if successful
|
|
12133
|
-
*/
|
|
12134
|
-
async mintNametag(nametag) {
|
|
12135
|
-
this.ensureInitialized();
|
|
12136
|
-
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
12137
|
-
if (!stClient) {
|
|
12138
|
-
return {
|
|
12139
|
-
success: false,
|
|
12140
|
-
error: "State transition client not available. Oracle provider must implement getStateTransitionClient()"
|
|
12141
|
-
};
|
|
12142
|
-
}
|
|
12143
|
-
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
12144
|
-
if (!trustBase) {
|
|
12145
|
-
return {
|
|
12146
|
-
success: false,
|
|
12147
|
-
error: "Trust base not available. Oracle provider must implement getTrustBase()"
|
|
12148
|
-
};
|
|
12149
|
-
}
|
|
12150
|
-
try {
|
|
12151
|
-
const signingService = await this.createSigningService();
|
|
12152
|
-
const { UnmaskedPredicateReference: UnmaskedPredicateReference4 } = await import("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference");
|
|
12153
|
-
const { TokenType: TokenType6 } = await import("@unicitylabs/state-transition-sdk/lib/token/TokenType");
|
|
12154
|
-
const UNICITY_TOKEN_TYPE_HEX3 = "f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509";
|
|
12155
|
-
const tokenType = new TokenType6(Buffer.from(UNICITY_TOKEN_TYPE_HEX3, "hex"));
|
|
12156
|
-
const addressRef = await UnmaskedPredicateReference4.create(
|
|
12157
|
-
tokenType,
|
|
12158
|
-
signingService.algorithm,
|
|
12159
|
-
signingService.publicKey,
|
|
12160
|
-
import_HashAlgorithm5.HashAlgorithm.SHA256
|
|
12161
|
-
);
|
|
12162
|
-
const ownerAddress = await addressRef.toAddress();
|
|
12163
|
-
const minter = new NametagMinter({
|
|
12164
|
-
stateTransitionClient: stClient,
|
|
12165
|
-
trustBase,
|
|
12166
|
-
signingService,
|
|
12167
|
-
debug: this.moduleConfig.debug
|
|
12168
|
-
});
|
|
12169
|
-
const result = await minter.mintNametag(nametag, ownerAddress);
|
|
12170
|
-
if (result.success && result.nametagData) {
|
|
12171
|
-
await this.setNametag(result.nametagData);
|
|
12172
|
-
logger.debug("Payments", `Unicity ID minted and saved: ${result.nametagData.name}`);
|
|
12173
|
-
this.deps.emitEvent("nametag:registered", {
|
|
12174
|
-
nametag: result.nametagData.name,
|
|
12175
|
-
addressIndex: 0
|
|
12176
|
-
// Primary address
|
|
12177
|
-
});
|
|
12178
|
-
}
|
|
12179
|
-
return result;
|
|
12180
|
-
} catch (error) {
|
|
12181
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
12182
|
-
logger.debug("Payments", "mintNametag failed:", errorMsg);
|
|
12183
|
-
return {
|
|
12184
|
-
success: false,
|
|
12185
|
-
error: errorMsg
|
|
12186
|
-
};
|
|
12187
|
-
}
|
|
12188
|
-
}
|
|
12189
12155
|
/**
|
|
12190
12156
|
* Mint a fungible token directly to this wallet (genesis mint).
|
|
12191
12157
|
*
|
|
@@ -12226,18 +12192,18 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12226
12192
|
}
|
|
12227
12193
|
try {
|
|
12228
12194
|
const signingService = await this.createSigningService();
|
|
12229
|
-
const { TokenId:
|
|
12195
|
+
const { TokenId: TokenId4 } = await import("@unicitylabs/state-transition-sdk/lib/token/TokenId");
|
|
12230
12196
|
const { TokenCoinData: TokenCoinData3 } = await import("@unicitylabs/state-transition-sdk/lib/token/fungible/TokenCoinData");
|
|
12231
|
-
const { UnmaskedPredicateReference:
|
|
12197
|
+
const { UnmaskedPredicateReference: UnmaskedPredicateReference3 } = await import("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference");
|
|
12232
12198
|
const tokenTypeBytes = fromHex4("f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509");
|
|
12233
12199
|
const tokenType = new import_TokenType3.TokenType(tokenTypeBytes);
|
|
12234
12200
|
const tokenIdBytes = new Uint8Array(32);
|
|
12235
12201
|
crypto.getRandomValues(tokenIdBytes);
|
|
12236
|
-
const tokenId = new
|
|
12202
|
+
const tokenId = new TokenId4(tokenIdBytes);
|
|
12237
12203
|
const coinIdBytes = fromHex4(coinIdHex);
|
|
12238
12204
|
const coinId = new import_CoinId4.CoinId(coinIdBytes);
|
|
12239
12205
|
const coinData = TokenCoinData3.create([[coinId, amount]]);
|
|
12240
|
-
const addressRef = await
|
|
12206
|
+
const addressRef = await UnmaskedPredicateReference3.create(
|
|
12241
12207
|
tokenType,
|
|
12242
12208
|
signingService.algorithm,
|
|
12243
12209
|
signingService.publicKey,
|
|
@@ -12246,7 +12212,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12246
12212
|
const ownerAddress = await addressRef.toAddress();
|
|
12247
12213
|
const salt = new Uint8Array(32);
|
|
12248
12214
|
crypto.getRandomValues(salt);
|
|
12249
|
-
const mintData = await
|
|
12215
|
+
const mintData = await import_MintTransactionData2.MintTransactionData.create(
|
|
12250
12216
|
tokenId,
|
|
12251
12217
|
tokenType,
|
|
12252
12218
|
null,
|
|
@@ -12261,7 +12227,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12261
12227
|
null
|
|
12262
12228
|
// reason: null (genesis, no burn predecessor)
|
|
12263
12229
|
);
|
|
12264
|
-
const commitment = await
|
|
12230
|
+
const commitment = await import_MintCommitment2.MintCommitment.create(mintData);
|
|
12265
12231
|
const MAX_RETRIES = 3;
|
|
12266
12232
|
let lastStatus;
|
|
12267
12233
|
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
@@ -12278,14 +12244,14 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12278
12244
|
}
|
|
12279
12245
|
const inclusionProof = await (0, import_InclusionProofUtils5.waitInclusionProof)(trustBase, stClient, commitment);
|
|
12280
12246
|
const genesisTransaction = commitment.toTransaction(inclusionProof);
|
|
12281
|
-
const predicate = await
|
|
12247
|
+
const predicate = await import_UnmaskedPredicate4.UnmaskedPredicate.create(
|
|
12282
12248
|
tokenId,
|
|
12283
12249
|
tokenType,
|
|
12284
12250
|
signingService,
|
|
12285
12251
|
import_HashAlgorithm5.HashAlgorithm.SHA256,
|
|
12286
12252
|
salt
|
|
12287
12253
|
);
|
|
12288
|
-
const tokenState = new
|
|
12254
|
+
const tokenState = new import_TokenState4.TokenState(predicate, null);
|
|
12289
12255
|
const sdkToken = await import_Token6.Token.mint(trustBase, tokenState, genesisTransaction);
|
|
12290
12256
|
const tokenIdHex = tokenId.toJSON();
|
|
12291
12257
|
const symbol = this.getCoinSymbol(coinIdHex);
|
|
@@ -12312,29 +12278,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12312
12278
|
return { success: false, error: `Local mint failed: ${msg}` };
|
|
12313
12279
|
}
|
|
12314
12280
|
}
|
|
12315
|
-
/**
|
|
12316
|
-
* Check if a nametag is available for minting
|
|
12317
|
-
* @param nametag - The nametag to check (e.g., "alice" or "@alice")
|
|
12318
|
-
*/
|
|
12319
|
-
async isNametagAvailable(nametag) {
|
|
12320
|
-
this.ensureInitialized();
|
|
12321
|
-
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
12322
|
-
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
12323
|
-
if (!stClient || !trustBase) {
|
|
12324
|
-
return false;
|
|
12325
|
-
}
|
|
12326
|
-
try {
|
|
12327
|
-
const signingService = await this.createSigningService();
|
|
12328
|
-
const minter = new NametagMinter({
|
|
12329
|
-
stateTransitionClient: stClient,
|
|
12330
|
-
trustBase,
|
|
12331
|
-
signingService
|
|
12332
|
-
});
|
|
12333
|
-
return await minter.isNametagAvailable(nametag);
|
|
12334
|
-
} catch {
|
|
12335
|
-
return false;
|
|
12336
|
-
}
|
|
12337
|
-
}
|
|
12338
12281
|
// ===========================================================================
|
|
12339
12282
|
// Public API - Sync & Validate
|
|
12340
12283
|
// ===========================================================================
|
|
@@ -12650,7 +12593,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12650
12593
|
const privateKeyBytes = new Uint8Array(
|
|
12651
12594
|
privateKeyHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
|
|
12652
12595
|
);
|
|
12653
|
-
return
|
|
12596
|
+
return import_SigningService2.SigningService.createFromSecret(privateKeyBytes);
|
|
12654
12597
|
}
|
|
12655
12598
|
/**
|
|
12656
12599
|
* Get the wallet's signing public key (used for token ownership predicates).
|
|
@@ -12665,14 +12608,14 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12665
12608
|
* Create DirectAddress from a public key using UnmaskedPredicateReference
|
|
12666
12609
|
*/
|
|
12667
12610
|
async createDirectAddressFromPubkey(pubkeyHex) {
|
|
12668
|
-
const { UnmaskedPredicateReference:
|
|
12669
|
-
const { TokenType:
|
|
12670
|
-
const
|
|
12671
|
-
const tokenType = new
|
|
12611
|
+
const { UnmaskedPredicateReference: UnmaskedPredicateReference3 } = await import("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference");
|
|
12612
|
+
const { TokenType: TokenType4 } = await import("@unicitylabs/state-transition-sdk/lib/token/TokenType");
|
|
12613
|
+
const UNICITY_TOKEN_TYPE_HEX2 = "f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509";
|
|
12614
|
+
const tokenType = new TokenType4(Buffer.from(UNICITY_TOKEN_TYPE_HEX2, "hex"));
|
|
12672
12615
|
const pubkeyBytes = new Uint8Array(
|
|
12673
12616
|
pubkeyHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
|
|
12674
12617
|
);
|
|
12675
|
-
const addressRef = await
|
|
12618
|
+
const addressRef = await UnmaskedPredicateReference3.create(
|
|
12676
12619
|
tokenType,
|
|
12677
12620
|
"secp256k1",
|
|
12678
12621
|
pubkeyBytes,
|
|
@@ -12684,10 +12627,9 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12684
12627
|
* Resolve recipient to IAddress for L3 transfers.
|
|
12685
12628
|
* Uses pre-resolved PeerInfo when available to avoid redundant network queries.
|
|
12686
12629
|
*/
|
|
12687
|
-
async resolveRecipientAddress(recipient,
|
|
12630
|
+
async resolveRecipientAddress(recipient, _addressMode = "auto", peerInfo) {
|
|
12688
12631
|
const { AddressFactory } = await import("@unicitylabs/state-transition-sdk/lib/address/AddressFactory");
|
|
12689
|
-
|
|
12690
|
-
if (recipient.startsWith("PROXY:") || recipient.startsWith("DIRECT:")) {
|
|
12632
|
+
if (recipient.startsWith("DIRECT:")) {
|
|
12691
12633
|
return AddressFactory.createAddress(recipient);
|
|
12692
12634
|
}
|
|
12693
12635
|
if (recipient.length === 66 && /^[0-9a-fA-F]+$/.test(recipient)) {
|
|
@@ -12697,28 +12639,19 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12697
12639
|
const info = peerInfo ?? await this.deps?.transport.resolve?.(recipient) ?? null;
|
|
12698
12640
|
if (!info) {
|
|
12699
12641
|
throw new SphereError(
|
|
12700
|
-
`Recipient "${recipient}" not found. Use @nametag, a
|
|
12642
|
+
`Recipient "${recipient}" not found. Use @nametag, a DIRECT: address, or a 33-byte hex pubkey.`,
|
|
12701
12643
|
"INVALID_RECIPIENT"
|
|
12702
12644
|
);
|
|
12703
12645
|
}
|
|
12704
12646
|
const nametag = recipient.startsWith("@") ? recipient.slice(1) : info.nametag || recipient;
|
|
12705
|
-
if (
|
|
12706
|
-
|
|
12707
|
-
|
|
12708
|
-
|
|
12709
|
-
|
|
12710
|
-
if (!info.directAddress) {
|
|
12711
|
-
throw new SphereError(`"${nametag}" has no DirectAddress stored. It may be a legacy registration.`, "INVALID_RECIPIENT");
|
|
12712
|
-
}
|
|
12713
|
-
logger.debug("Payments", `Using DirectAddress for "${nametag}" (forced): ${info.directAddress.slice(0, 30)}...`);
|
|
12714
|
-
return AddressFactory.createAddress(info.directAddress);
|
|
12715
|
-
}
|
|
12716
|
-
if (info.directAddress) {
|
|
12717
|
-
logger.debug("Payments", `Using DirectAddress for "${nametag}": ${info.directAddress.slice(0, 30)}...`);
|
|
12718
|
-
return AddressFactory.createAddress(info.directAddress);
|
|
12647
|
+
if (!info.directAddress) {
|
|
12648
|
+
throw new SphereError(
|
|
12649
|
+
`"${nametag}" has no DirectAddress \u2014 the recipient must publish a key-based identity binding.`,
|
|
12650
|
+
"INVALID_RECIPIENT"
|
|
12651
|
+
);
|
|
12719
12652
|
}
|
|
12720
|
-
logger.debug("Payments", `Using
|
|
12721
|
-
return
|
|
12653
|
+
logger.debug("Payments", `Using DirectAddress for "${nametag}": ${info.directAddress.slice(0, 30)}...`);
|
|
12654
|
+
return AddressFactory.createAddress(info.directAddress);
|
|
12722
12655
|
}
|
|
12723
12656
|
/**
|
|
12724
12657
|
* Handle NOSTR-FIRST commitment-only transfer (recipient side)
|
|
@@ -12773,14 +12706,14 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12773
12706
|
const addressScheme = recipientAddress.scheme;
|
|
12774
12707
|
const signingService = await this.createSigningService();
|
|
12775
12708
|
const transferSalt = transferTx.data.salt;
|
|
12776
|
-
const recipientPredicate = await
|
|
12709
|
+
const recipientPredicate = await import_UnmaskedPredicate4.UnmaskedPredicate.create(
|
|
12777
12710
|
sourceToken.id,
|
|
12778
12711
|
sourceToken.type,
|
|
12779
12712
|
signingService,
|
|
12780
12713
|
import_HashAlgorithm5.HashAlgorithm.SHA256,
|
|
12781
12714
|
transferSalt
|
|
12782
12715
|
);
|
|
12783
|
-
const recipientState = new
|
|
12716
|
+
const recipientState = new import_TokenState4.TokenState(recipientPredicate, null);
|
|
12784
12717
|
let nametagTokens = [];
|
|
12785
12718
|
if (addressScheme === import_AddressScheme.AddressScheme.PROXY) {
|
|
12786
12719
|
const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
|
|
@@ -12877,6 +12810,67 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12877
12810
|
}
|
|
12878
12811
|
}
|
|
12879
12812
|
}
|
|
12813
|
+
/**
|
|
12814
|
+
* v2 engine transfer (sender-driven): the sender handed us a FINISHED token.
|
|
12815
|
+
* Decode the blob, dedup by the genesis-stable token id, store it as a
|
|
12816
|
+
* confirmed token, and emit/record the receipt. No commitment / inclusion-proof
|
|
12817
|
+
* / finalization round-trip (contrast the v1 sourceToken+transferTx path).
|
|
12818
|
+
*/
|
|
12819
|
+
async handleV2Transfer(payload, senderPubkey) {
|
|
12820
|
+
this.ensureInitialized();
|
|
12821
|
+
if (!this.loaded && this.loadedPromise) {
|
|
12822
|
+
await this.loadedPromise;
|
|
12823
|
+
}
|
|
12824
|
+
const engine = this.deps.tokenEngine;
|
|
12825
|
+
if (!engine) return;
|
|
12826
|
+
let token;
|
|
12827
|
+
try {
|
|
12828
|
+
token = await engine.decodeToken(decodeTokenBlob(hexToBytes2(payload.tokenBlob)));
|
|
12829
|
+
} catch (err) {
|
|
12830
|
+
logger.error("Payments", "V2 transfer: failed to decode token blob:", err);
|
|
12831
|
+
return;
|
|
12832
|
+
}
|
|
12833
|
+
const id = `v2_${engine.tokenId(token)}`;
|
|
12834
|
+
if (this.tokens.has(id)) {
|
|
12835
|
+
logger.debug("Payments", `V2 transfer ${id.slice(0, 16)}... already present, skipping`);
|
|
12836
|
+
return;
|
|
12837
|
+
}
|
|
12838
|
+
const info = await parseTokenInfo(payload.tokenBlob, engine);
|
|
12839
|
+
const registry = TokenRegistry.getInstance();
|
|
12840
|
+
const uiToken = {
|
|
12841
|
+
id,
|
|
12842
|
+
coinId: info.coinId,
|
|
12843
|
+
symbol: registry.getSymbol(info.coinId) || info.symbol,
|
|
12844
|
+
name: registry.getName(info.coinId) || info.name,
|
|
12845
|
+
decimals: registry.getDecimals(info.coinId) ?? info.decimals,
|
|
12846
|
+
amount: info.amount,
|
|
12847
|
+
status: "confirmed",
|
|
12848
|
+
createdAt: Date.now(),
|
|
12849
|
+
updatedAt: Date.now(),
|
|
12850
|
+
sdkData: payload.tokenBlob
|
|
12851
|
+
};
|
|
12852
|
+
await this.addToken(uiToken);
|
|
12853
|
+
const senderInfo = await this.resolveSenderInfo(senderPubkey);
|
|
12854
|
+
this.deps.emitEvent("transfer:incoming", {
|
|
12855
|
+
id,
|
|
12856
|
+
senderPubkey,
|
|
12857
|
+
senderNametag: senderInfo.senderNametag,
|
|
12858
|
+
tokens: [uiToken],
|
|
12859
|
+
memo: payload.memo,
|
|
12860
|
+
receivedAt: Date.now()
|
|
12861
|
+
});
|
|
12862
|
+
await this.addToHistory({
|
|
12863
|
+
type: "RECEIVED",
|
|
12864
|
+
amount: info.amount,
|
|
12865
|
+
coinId: info.coinId,
|
|
12866
|
+
symbol: uiToken.symbol,
|
|
12867
|
+
timestamp: Date.now(),
|
|
12868
|
+
senderPubkey,
|
|
12869
|
+
...senderInfo,
|
|
12870
|
+
memo: payload.memo,
|
|
12871
|
+
tokenId: id
|
|
12872
|
+
});
|
|
12873
|
+
}
|
|
12880
12874
|
async handleIncomingTransfer(transfer) {
|
|
12881
12875
|
if (!this.loaded && this.loadedPromise) {
|
|
12882
12876
|
await this.loadedPromise;
|
|
@@ -12884,6 +12878,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12884
12878
|
try {
|
|
12885
12879
|
const payload = transfer.payload;
|
|
12886
12880
|
logger.debug("Payments", "handleIncomingTransfer: keys=", Object.keys(payload).join(","));
|
|
12881
|
+
if (this.deps.tokenEngine && isV2TransferPayload(transfer.payload)) {
|
|
12882
|
+
await this.handleV2Transfer(transfer.payload, transfer.senderTransportPubkey);
|
|
12883
|
+
return;
|
|
12884
|
+
}
|
|
12887
12885
|
let combinedBundle = null;
|
|
12888
12886
|
if (isCombinedTransferBundleV6(payload)) {
|
|
12889
12887
|
combinedBundle = payload;
|
|
@@ -12965,7 +12963,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12965
12963
|
const hasTransactionData = transferTxInput.transactionData !== void 0;
|
|
12966
12964
|
const hasAuthenticator = transferTxInput.authenticator !== void 0;
|
|
12967
12965
|
if (hasData && hasInclusionProof) {
|
|
12968
|
-
transferTx = await
|
|
12966
|
+
transferTx = await import_TransferTransaction3.TransferTransaction.fromJSON(transferTxInput);
|
|
12969
12967
|
} else if (hasTransactionData && hasAuthenticator) {
|
|
12970
12968
|
const commitment = await import_TransferCommitment4.TransferCommitment.fromJSON(transferTxInput);
|
|
12971
12969
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
@@ -12986,7 +12984,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
12986
12984
|
transferTx = commitment.toTransaction(inclusionProof);
|
|
12987
12985
|
} else {
|
|
12988
12986
|
try {
|
|
12989
|
-
transferTx = await
|
|
12987
|
+
transferTx = await import_TransferTransaction3.TransferTransaction.fromJSON(transferTxInput);
|
|
12990
12988
|
} catch {
|
|
12991
12989
|
const commitment = await import_TransferCommitment4.TransferCommitment.fromJSON(transferTxInput);
|
|
12992
12990
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
@@ -13028,7 +13026,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
13028
13026
|
logger.warn("Payments", "Received invalid token");
|
|
13029
13027
|
return;
|
|
13030
13028
|
}
|
|
13031
|
-
const tokenInfo = await parseTokenInfo(tokenData);
|
|
13029
|
+
const tokenInfo = await parseTokenInfo(tokenData, this.deps?.tokenEngine);
|
|
13032
13030
|
const token = {
|
|
13033
13031
|
id: tokenInfo.tokenId ?? crypto.randomUUID(),
|
|
13034
13032
|
coinId: tokenInfo.coinId,
|
|
@@ -13334,24 +13332,6 @@ function createPaymentsModule(config) {
|
|
|
13334
13332
|
return new PaymentsModule(config);
|
|
13335
13333
|
}
|
|
13336
13334
|
|
|
13337
|
-
// modules/payments/TokenSplitCalculator.ts
|
|
13338
|
-
init_logger();
|
|
13339
|
-
var import_Token7 = require("@unicitylabs/state-transition-sdk/lib/token/Token");
|
|
13340
|
-
var import_CoinId5 = require("@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId");
|
|
13341
|
-
|
|
13342
|
-
// modules/payments/BackgroundCommitmentService.ts
|
|
13343
|
-
init_logger();
|
|
13344
|
-
init_errors();
|
|
13345
|
-
|
|
13346
|
-
// modules/payments/TokenRecoveryService.ts
|
|
13347
|
-
init_logger();
|
|
13348
|
-
var import_TokenId4 = require("@unicitylabs/state-transition-sdk/lib/token/TokenId");
|
|
13349
|
-
var import_TokenState6 = require("@unicitylabs/state-transition-sdk/lib/token/TokenState");
|
|
13350
|
-
var import_TokenType4 = require("@unicitylabs/state-transition-sdk/lib/token/TokenType");
|
|
13351
|
-
var import_CoinId6 = require("@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId");
|
|
13352
|
-
var import_HashAlgorithm6 = require("@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm");
|
|
13353
|
-
var import_UnmaskedPredicate6 = require("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate");
|
|
13354
|
-
|
|
13355
13335
|
// modules/communications/CommunicationsModule.ts
|
|
13356
13336
|
init_logger();
|
|
13357
13337
|
init_errors();
|
|
@@ -14033,7 +14013,7 @@ function createCommunicationsModule(config) {
|
|
|
14033
14013
|
}
|
|
14034
14014
|
|
|
14035
14015
|
// modules/groupchat/GroupChatModule.ts
|
|
14036
|
-
var
|
|
14016
|
+
var import_nostr_js_sdk3 = require("@unicitylabs/nostr-js-sdk");
|
|
14037
14017
|
init_logger();
|
|
14038
14018
|
init_errors();
|
|
14039
14019
|
init_constants();
|
|
@@ -14051,7 +14031,7 @@ var GroupVisibility = {
|
|
|
14051
14031
|
|
|
14052
14032
|
// modules/groupchat/GroupChatModule.ts
|
|
14053
14033
|
function createNip29Filter(data) {
|
|
14054
|
-
return new
|
|
14034
|
+
return new import_nostr_js_sdk3.Filter(data);
|
|
14055
14035
|
}
|
|
14056
14036
|
var GroupChatModule = class {
|
|
14057
14037
|
config;
|
|
@@ -14100,7 +14080,7 @@ var GroupChatModule = class {
|
|
|
14100
14080
|
}
|
|
14101
14081
|
this.deps = deps;
|
|
14102
14082
|
const secretKey = Buffer.from(deps.identity.privateKey, "hex");
|
|
14103
|
-
this.keyManager =
|
|
14083
|
+
this.keyManager = import_nostr_js_sdk3.NostrKeyManager.fromPrivateKey(secretKey);
|
|
14104
14084
|
}
|
|
14105
14085
|
async load() {
|
|
14106
14086
|
this.ensureInitialized();
|
|
@@ -14241,7 +14221,7 @@ var GroupChatModule = class {
|
|
|
14241
14221
|
}
|
|
14242
14222
|
this.subscriptionIds = [];
|
|
14243
14223
|
const secretKey = Buffer.from(this.deps.identity.privateKey, "hex");
|
|
14244
|
-
this.keyManager =
|
|
14224
|
+
this.keyManager = import_nostr_js_sdk3.NostrKeyManager.fromPrivateKey(secretKey);
|
|
14245
14225
|
if (this.groups.size === 0) {
|
|
14246
14226
|
await this.restoreJoinedGroups();
|
|
14247
14227
|
} else {
|
|
@@ -14253,13 +14233,13 @@ var GroupChatModule = class {
|
|
|
14253
14233
|
this.ensureInitialized();
|
|
14254
14234
|
if (!this.keyManager) {
|
|
14255
14235
|
const secretKey = Buffer.from(this.deps.identity.privateKey, "hex");
|
|
14256
|
-
this.keyManager =
|
|
14236
|
+
this.keyManager = import_nostr_js_sdk3.NostrKeyManager.fromPrivateKey(secretKey);
|
|
14257
14237
|
}
|
|
14258
14238
|
const primaryRelay = this.config.relays[0];
|
|
14259
14239
|
if (primaryRelay) {
|
|
14260
14240
|
await this.checkAndClearOnRelayChange(primaryRelay);
|
|
14261
14241
|
}
|
|
14262
|
-
this.client = new
|
|
14242
|
+
this.client = new import_nostr_js_sdk3.NostrClient(this.keyManager);
|
|
14263
14243
|
try {
|
|
14264
14244
|
await this.client.connect(...this.config.relays);
|
|
14265
14245
|
this.connected = true;
|
|
@@ -14546,7 +14526,7 @@ var GroupChatModule = class {
|
|
|
14546
14526
|
if (!this.client) return [];
|
|
14547
14527
|
const groupsMap = /* @__PURE__ */ new Map();
|
|
14548
14528
|
await this.oneshotSubscription(
|
|
14549
|
-
new
|
|
14529
|
+
new import_nostr_js_sdk3.Filter({ kinds: [NIP29_KINDS.GROUP_METADATA] }),
|
|
14550
14530
|
{
|
|
14551
14531
|
onEvent: (event) => {
|
|
14552
14532
|
const group = this.parseGroupMetadata(event);
|
|
@@ -15046,7 +15026,7 @@ var GroupChatModule = class {
|
|
|
15046
15026
|
if (!this.client) return /* @__PURE__ */ new Set();
|
|
15047
15027
|
const adminPubkeys = /* @__PURE__ */ new Set();
|
|
15048
15028
|
return this.oneshotSubscription(
|
|
15049
|
-
new
|
|
15029
|
+
new import_nostr_js_sdk3.Filter({ kinds: [NIP29_KINDS.GROUP_ADMINS], "#d": ["", "_"] }),
|
|
15050
15030
|
{
|
|
15051
15031
|
onEvent: (event) => {
|
|
15052
15032
|
const pTags = event.tags.filter((t) => t[0] === "p");
|
|
@@ -15068,7 +15048,7 @@ var GroupChatModule = class {
|
|
|
15068
15048
|
if (!this.client) return null;
|
|
15069
15049
|
let result = null;
|
|
15070
15050
|
return this.oneshotSubscription(
|
|
15071
|
-
new
|
|
15051
|
+
new import_nostr_js_sdk3.Filter({ kinds: [NIP29_KINDS.GROUP_METADATA], "#d": [groupId] }),
|
|
15072
15052
|
{
|
|
15073
15053
|
onEvent: (event) => {
|
|
15074
15054
|
if (!result) result = this.parseGroupMetadata(event);
|
|
@@ -15105,7 +15085,7 @@ var GroupChatModule = class {
|
|
|
15105
15085
|
if (!this.client) return [];
|
|
15106
15086
|
const members = [];
|
|
15107
15087
|
return this.oneshotSubscription(
|
|
15108
|
-
new
|
|
15088
|
+
new import_nostr_js_sdk3.Filter({ kinds: [NIP29_KINDS.GROUP_MEMBERS], "#d": [groupId] }),
|
|
15109
15089
|
{
|
|
15110
15090
|
onEvent: (event) => {
|
|
15111
15091
|
const pTags = event.tags.filter((t) => t[0] === "p");
|
|
@@ -15126,7 +15106,7 @@ var GroupChatModule = class {
|
|
|
15126
15106
|
if (!this.client) return [];
|
|
15127
15107
|
const adminPubkeys = [];
|
|
15128
15108
|
return this.oneshotSubscription(
|
|
15129
|
-
new
|
|
15109
|
+
new import_nostr_js_sdk3.Filter({ kinds: [NIP29_KINDS.GROUP_ADMINS], "#d": [groupId] }),
|
|
15130
15110
|
{
|
|
15131
15111
|
onEvent: (event) => {
|
|
15132
15112
|
const pTags = event.tags.filter((t) => t[0] === "p");
|
|
@@ -16989,7 +16969,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
16989
16969
|
const sizer = format === "compact" ? size : format === "recovered" ? size + 1 : void 0;
|
|
16990
16970
|
return abytes(bytes, sizer);
|
|
16991
16971
|
}
|
|
16992
|
-
class
|
|
16972
|
+
class Signature2 {
|
|
16993
16973
|
r;
|
|
16994
16974
|
s;
|
|
16995
16975
|
recovery;
|
|
@@ -17009,7 +16989,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
17009
16989
|
let recid;
|
|
17010
16990
|
if (format === "der") {
|
|
17011
16991
|
const { r: r2, s: s2 } = DER.toSig(abytes(bytes));
|
|
17012
|
-
return new
|
|
16992
|
+
return new Signature2(r2, s2);
|
|
17013
16993
|
}
|
|
17014
16994
|
if (format === "recovered") {
|
|
17015
16995
|
recid = bytes[0];
|
|
@@ -17019,7 +16999,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
17019
16999
|
const L = lengths.signature / 2;
|
|
17020
17000
|
const r = bytes.subarray(0, L);
|
|
17021
17001
|
const s = bytes.subarray(L, L * 2);
|
|
17022
|
-
return new
|
|
17002
|
+
return new Signature2(Fn.fromBytes(r), Fn.fromBytes(s), recid);
|
|
17023
17003
|
}
|
|
17024
17004
|
static fromHex(hex, format) {
|
|
17025
17005
|
return this.fromBytes(hexToBytes(hex), format);
|
|
@@ -17031,7 +17011,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
17031
17011
|
return recovery;
|
|
17032
17012
|
}
|
|
17033
17013
|
addRecoveryBit(recovery) {
|
|
17034
|
-
return new
|
|
17014
|
+
return new Signature2(this.r, this.s, recovery);
|
|
17035
17015
|
}
|
|
17036
17016
|
recoverPublicKey(messageHash) {
|
|
17037
17017
|
const { r, s } = this;
|
|
@@ -17123,7 +17103,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
17123
17103
|
normS = Fn.neg(s);
|
|
17124
17104
|
recovery ^= 1;
|
|
17125
17105
|
}
|
|
17126
|
-
return new
|
|
17106
|
+
return new Signature2(r, normS, hasLargeCofactor ? void 0 : recovery);
|
|
17127
17107
|
}
|
|
17128
17108
|
return { seed, k2sig };
|
|
17129
17109
|
}
|
|
@@ -17138,12 +17118,12 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
17138
17118
|
publicKey = abytes(publicKey, void 0, "publicKey");
|
|
17139
17119
|
message = validateMsgAndHash(message, prehash);
|
|
17140
17120
|
if (!isBytes(signature)) {
|
|
17141
|
-
const end = signature instanceof
|
|
17121
|
+
const end = signature instanceof Signature2 ? ", use sig.toBytes()" : "";
|
|
17142
17122
|
throw new Error("verify expects Uint8Array signature" + end);
|
|
17143
17123
|
}
|
|
17144
17124
|
validateSigLength(signature, format);
|
|
17145
17125
|
try {
|
|
17146
|
-
const sig =
|
|
17126
|
+
const sig = Signature2.fromBytes(signature, format);
|
|
17147
17127
|
const P = Point.fromBytes(publicKey);
|
|
17148
17128
|
if (lowS && sig.hasHighS())
|
|
17149
17129
|
return false;
|
|
@@ -17164,7 +17144,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
17164
17144
|
function recoverPublicKey(signature, message, opts = {}) {
|
|
17165
17145
|
const { prehash } = validateSigOpts(opts, defaultSigOpts);
|
|
17166
17146
|
message = validateMsgAndHash(message, prehash);
|
|
17167
|
-
return
|
|
17147
|
+
return Signature2.fromBytes(signature, "recovered").recoverPublicKey(message).toBytes();
|
|
17168
17148
|
}
|
|
17169
17149
|
return Object.freeze({
|
|
17170
17150
|
keygen,
|
|
@@ -17176,7 +17156,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
17176
17156
|
sign,
|
|
17177
17157
|
verify,
|
|
17178
17158
|
recoverPublicKey,
|
|
17179
|
-
Signature,
|
|
17159
|
+
Signature: Signature2,
|
|
17180
17160
|
hash
|
|
17181
17161
|
});
|
|
17182
17162
|
}
|
|
@@ -18448,7 +18428,7 @@ function freezeCoinAsset(coinAsset, state, latestSender) {
|
|
|
18448
18428
|
}
|
|
18449
18429
|
|
|
18450
18430
|
// modules/accounting/AccountingModule.ts
|
|
18451
|
-
var
|
|
18431
|
+
var import_Token7 = require("@unicitylabs/state-transition-sdk/lib/token/Token.js");
|
|
18452
18432
|
var LOG_TAG2 = "Accounting";
|
|
18453
18433
|
var INV_LEDGER_PREFIX = "inv_ledger:";
|
|
18454
18434
|
var AccountingModule = class _AccountingModule {
|
|
@@ -19101,129 +19081,146 @@ var AccountingModule = class _AccountingModule {
|
|
|
19101
19081
|
);
|
|
19102
19082
|
}
|
|
19103
19083
|
try {
|
|
19104
|
-
|
|
19105
|
-
|
|
19106
|
-
const
|
|
19107
|
-
|
|
19108
|
-
|
|
19109
|
-
|
|
19110
|
-
|
|
19111
|
-
|
|
19112
|
-
|
|
19113
|
-
|
|
19114
|
-
|
|
19115
|
-
|
|
19116
|
-
|
|
19117
|
-
|
|
19118
|
-
|
|
19119
|
-
|
|
19120
|
-
|
|
19121
|
-
|
|
19122
|
-
|
|
19084
|
+
let invoiceId;
|
|
19085
|
+
let sdkData;
|
|
19086
|
+
const engine = deps.tokenEngine;
|
|
19087
|
+
if (engine) {
|
|
19088
|
+
const invoiceToken = await engine.mintDataToken({
|
|
19089
|
+
recipientPubkey: hexToBytes(deps.identity.chainPubkey),
|
|
19090
|
+
data: invoiceBytesEncoded,
|
|
19091
|
+
tokenType: hexToBytes(INVOICE_TOKEN_TYPE_HEX),
|
|
19092
|
+
salt
|
|
19093
|
+
});
|
|
19094
|
+
invoiceId = engine.tokenId(invoiceToken);
|
|
19095
|
+
if (this.invoiceTermsCache.has(invoiceId)) {
|
|
19096
|
+
throw new SphereError(`Invoice already exists locally: ${invoiceId}`, "INVOICE_ALREADY_EXISTS");
|
|
19097
|
+
}
|
|
19098
|
+
sdkData = bytesToHex(encodeTokenBlob(engine.encodeToken(invoiceToken)));
|
|
19099
|
+
} else {
|
|
19100
|
+
const { TokenId: TokenId4 } = await import("@unicitylabs/state-transition-sdk/lib/token/TokenId.js");
|
|
19101
|
+
const { TokenType: TokenType4 } = await import("@unicitylabs/state-transition-sdk/lib/token/TokenType.js");
|
|
19102
|
+
const { MintTransactionData: MintTransactionData3 } = await import("@unicitylabs/state-transition-sdk/lib/transaction/MintTransactionData.js");
|
|
19103
|
+
const { MintCommitment: MintCommitment3 } = await import("@unicitylabs/state-transition-sdk/lib/transaction/MintCommitment.js");
|
|
19104
|
+
const { SigningService: SigningService3 } = await import("@unicitylabs/state-transition-sdk/lib/sign/SigningService.js");
|
|
19105
|
+
const { HashAlgorithm: HashAlgorithm6 } = await import("@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm.js");
|
|
19106
|
+
const { DataHasher: DataHasher2 } = await import("@unicitylabs/state-transition-sdk/lib/hash/DataHasher.js");
|
|
19107
|
+
const { UnmaskedPredicate: UnmaskedPredicate5 } = await import("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate.js");
|
|
19108
|
+
const { UnmaskedPredicateReference: UnmaskedPredicateReference3 } = await import("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference.js");
|
|
19109
|
+
const { TokenState: TokenState5 } = await import("@unicitylabs/state-transition-sdk/lib/token/TokenState.js");
|
|
19110
|
+
const { Token: SdkToken4 } = await import("@unicitylabs/state-transition-sdk/lib/token/Token.js");
|
|
19111
|
+
const { waitInclusionProof: waitInclusionProof6 } = await import("@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils.js");
|
|
19112
|
+
const hash = await new DataHasher2(HashAlgorithm6.SHA256).update(invoiceBytesEncoded).digest();
|
|
19113
|
+
const invoiceTokenId = new TokenId4(hash.imprint);
|
|
19114
|
+
invoiceId = invoiceTokenId.toJSON();
|
|
19115
|
+
if (this.invoiceTermsCache.has(invoiceId)) {
|
|
19116
|
+
throw new SphereError(
|
|
19117
|
+
`Invoice already exists locally: ${invoiceId}`,
|
|
19118
|
+
"INVOICE_ALREADY_EXISTS"
|
|
19119
|
+
);
|
|
19120
|
+
}
|
|
19121
|
+
const invoiceTokenType = new TokenType4(
|
|
19122
|
+
Buffer.from(INVOICE_TOKEN_TYPE_HEX, "hex")
|
|
19123
19123
|
);
|
|
19124
|
-
|
|
19125
|
-
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
|
|
19130
|
-
|
|
19131
|
-
|
|
19132
|
-
|
|
19133
|
-
|
|
19134
|
-
|
|
19135
|
-
|
|
19136
|
-
|
|
19137
|
-
|
|
19138
|
-
|
|
19139
|
-
|
|
19140
|
-
|
|
19141
|
-
|
|
19142
|
-
|
|
19143
|
-
|
|
19144
|
-
|
|
19145
|
-
|
|
19146
|
-
|
|
19147
|
-
|
|
19148
|
-
|
|
19149
|
-
|
|
19150
|
-
|
|
19151
|
-
|
|
19152
|
-
|
|
19153
|
-
|
|
19154
|
-
|
|
19155
|
-
|
|
19156
|
-
|
|
19157
|
-
const MAX_RETRIES = 3;
|
|
19158
|
-
let submitSuccess = false;
|
|
19159
|
-
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
19160
|
-
try {
|
|
19161
|
-
if (this.config.debug) {
|
|
19162
|
-
logger.debug(
|
|
19163
|
-
LOG_TAG2,
|
|
19164
|
-
`Submitting invoice commitment (attempt ${attempt}/${MAX_RETRIES})...`
|
|
19165
|
-
);
|
|
19166
|
-
}
|
|
19167
|
-
const response = await stClient.submitMintCommitment(commitment);
|
|
19168
|
-
if (response.status === "SUCCESS" || response.status === "REQUEST_ID_EXISTS") {
|
|
19124
|
+
const signingService = await SigningService3.createFromSecret(signingKeyBytes);
|
|
19125
|
+
const addressRef = await UnmaskedPredicateReference3.create(
|
|
19126
|
+
invoiceTokenType,
|
|
19127
|
+
signingService.algorithm,
|
|
19128
|
+
signingService.publicKey,
|
|
19129
|
+
HashAlgorithm6.SHA256
|
|
19130
|
+
);
|
|
19131
|
+
const ownerAddress = await addressRef.toAddress();
|
|
19132
|
+
const mintData = await MintTransactionData3.create(
|
|
19133
|
+
invoiceTokenId,
|
|
19134
|
+
invoiceTokenType,
|
|
19135
|
+
invoiceBytesEncoded,
|
|
19136
|
+
// tokenData: serialized InvoiceTerms (UTF-8 JSON)
|
|
19137
|
+
null,
|
|
19138
|
+
// coinData: null (non-fungible invoice token)
|
|
19139
|
+
ownerAddress,
|
|
19140
|
+
salt,
|
|
19141
|
+
null,
|
|
19142
|
+
// recipientDataHash: null
|
|
19143
|
+
null
|
|
19144
|
+
// reason: null
|
|
19145
|
+
);
|
|
19146
|
+
if (this.config.debug) {
|
|
19147
|
+
logger.debug(LOG_TAG2, `Created MintTransactionData for invoice ${invoiceId}`);
|
|
19148
|
+
}
|
|
19149
|
+
const commitment = await MintCommitment3.create(mintData);
|
|
19150
|
+
if (this.config.debug) {
|
|
19151
|
+
logger.debug(LOG_TAG2, "Created MintCommitment for invoice");
|
|
19152
|
+
}
|
|
19153
|
+
const MAX_RETRIES = 3;
|
|
19154
|
+
let submitSuccess = false;
|
|
19155
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
19156
|
+
try {
|
|
19169
19157
|
if (this.config.debug) {
|
|
19170
19158
|
logger.debug(
|
|
19171
19159
|
LOG_TAG2,
|
|
19172
|
-
|
|
19160
|
+
`Submitting invoice commitment (attempt ${attempt}/${MAX_RETRIES})...`
|
|
19173
19161
|
);
|
|
19174
19162
|
}
|
|
19175
|
-
|
|
19176
|
-
|
|
19177
|
-
|
|
19178
|
-
|
|
19163
|
+
const response = await stClient.submitMintCommitment(commitment);
|
|
19164
|
+
if (response.status === "SUCCESS" || response.status === "REQUEST_ID_EXISTS") {
|
|
19165
|
+
if (this.config.debug) {
|
|
19166
|
+
logger.debug(
|
|
19167
|
+
LOG_TAG2,
|
|
19168
|
+
response.status === "REQUEST_ID_EXISTS" ? "Invoice commitment already exists (idempotent re-mint)" : "Invoice commitment submitted successfully"
|
|
19169
|
+
);
|
|
19170
|
+
}
|
|
19171
|
+
submitSuccess = true;
|
|
19172
|
+
break;
|
|
19173
|
+
} else {
|
|
19174
|
+
logger.warn(LOG_TAG2, `Invoice commitment submission failed: ${response.status}`);
|
|
19175
|
+
if (attempt === MAX_RETRIES) {
|
|
19176
|
+
throw new SphereError(
|
|
19177
|
+
`Failed to mint invoice token: commitment rejected after ${MAX_RETRIES} attempts: ${response.status}`,
|
|
19178
|
+
"INVOICE_MINT_FAILED"
|
|
19179
|
+
);
|
|
19180
|
+
}
|
|
19181
|
+
await new Promise((r) => setTimeout(r, 1e3 * attempt));
|
|
19182
|
+
}
|
|
19183
|
+
} catch (retryErr) {
|
|
19184
|
+
if (retryErr instanceof SphereError && (retryErr.code === "INVOICE_ORACLE_REQUIRED" || retryErr.code === "INVOICE_INVALID_PROOF" || retryErr.code === "INVOICE_MINT_FAILED" || retryErr.code === "NOT_INITIALIZED" || retryErr.code === "MODULE_DESTROYED")) throw retryErr;
|
|
19185
|
+
logger.warn(LOG_TAG2, `Invoice commitment attempt ${attempt} error:`, retryErr);
|
|
19179
19186
|
if (attempt === MAX_RETRIES) {
|
|
19180
19187
|
throw new SphereError(
|
|
19181
|
-
`Failed to mint invoice token:
|
|
19182
|
-
"INVOICE_MINT_FAILED"
|
|
19188
|
+
`Failed to mint invoice token: ${retryErr instanceof Error ? retryErr.message : String(retryErr)}`,
|
|
19189
|
+
"INVOICE_MINT_FAILED",
|
|
19190
|
+
retryErr
|
|
19183
19191
|
);
|
|
19184
19192
|
}
|
|
19185
19193
|
await new Promise((r) => setTimeout(r, 1e3 * attempt));
|
|
19186
19194
|
}
|
|
19187
|
-
} catch (retryErr) {
|
|
19188
|
-
if (retryErr instanceof SphereError && (retryErr.code === "INVOICE_ORACLE_REQUIRED" || retryErr.code === "INVOICE_INVALID_PROOF" || retryErr.code === "INVOICE_MINT_FAILED" || retryErr.code === "NOT_INITIALIZED" || retryErr.code === "MODULE_DESTROYED")) throw retryErr;
|
|
19189
|
-
logger.warn(LOG_TAG2, `Invoice commitment attempt ${attempt} error:`, retryErr);
|
|
19190
|
-
if (attempt === MAX_RETRIES) {
|
|
19191
|
-
throw new SphereError(
|
|
19192
|
-
`Failed to mint invoice token: ${retryErr instanceof Error ? retryErr.message : String(retryErr)}`,
|
|
19193
|
-
"INVOICE_MINT_FAILED",
|
|
19194
|
-
retryErr
|
|
19195
|
-
);
|
|
19196
|
-
}
|
|
19197
|
-
await new Promise((r) => setTimeout(r, 1e3 * attempt));
|
|
19198
19195
|
}
|
|
19199
|
-
|
|
19200
|
-
|
|
19201
|
-
|
|
19202
|
-
|
|
19203
|
-
|
|
19196
|
+
if (!submitSuccess) {
|
|
19197
|
+
throw new SphereError(
|
|
19198
|
+
"Failed to mint invoice token: commitment submission failed after retries",
|
|
19199
|
+
"INVOICE_MINT_FAILED"
|
|
19200
|
+
);
|
|
19201
|
+
}
|
|
19202
|
+
if (this.config.debug) {
|
|
19203
|
+
logger.debug(LOG_TAG2, "Waiting for invoice inclusion proof...");
|
|
19204
|
+
}
|
|
19205
|
+
const inclusionProof = await waitInclusionProof6(trustBase, stClient, commitment);
|
|
19206
|
+
if (this.config.debug) {
|
|
19207
|
+
logger.debug(LOG_TAG2, "Invoice inclusion proof received");
|
|
19208
|
+
}
|
|
19209
|
+
const genesisTransaction = commitment.toTransaction(inclusionProof);
|
|
19210
|
+
const invoicePredicate = await UnmaskedPredicate5.create(
|
|
19211
|
+
invoiceTokenId,
|
|
19212
|
+
invoiceTokenType,
|
|
19213
|
+
signingService,
|
|
19214
|
+
HashAlgorithm6.SHA256,
|
|
19215
|
+
salt
|
|
19204
19216
|
);
|
|
19217
|
+
const tokenState = new TokenState5(invoicePredicate, null);
|
|
19218
|
+
const sdkToken = await SdkToken4.mint(trustBase, tokenState, genesisTransaction);
|
|
19219
|
+
if (this.config.debug) {
|
|
19220
|
+
logger.debug(LOG_TAG2, "Invoice token minted successfully");
|
|
19221
|
+
}
|
|
19222
|
+
sdkData = JSON.stringify(sdkToken.toJSON());
|
|
19205
19223
|
}
|
|
19206
|
-
if (this.config.debug) {
|
|
19207
|
-
logger.debug(LOG_TAG2, "Waiting for invoice inclusion proof...");
|
|
19208
|
-
}
|
|
19209
|
-
const inclusionProof = await waitInclusionProof6(trustBase, stClient, commitment);
|
|
19210
|
-
if (this.config.debug) {
|
|
19211
|
-
logger.debug(LOG_TAG2, "Invoice inclusion proof received");
|
|
19212
|
-
}
|
|
19213
|
-
const genesisTransaction = commitment.toTransaction(inclusionProof);
|
|
19214
|
-
const invoicePredicate = await UnmaskedPredicate7.create(
|
|
19215
|
-
invoiceTokenId,
|
|
19216
|
-
invoiceTokenType,
|
|
19217
|
-
signingService,
|
|
19218
|
-
HashAlgorithm8.SHA256,
|
|
19219
|
-
salt
|
|
19220
|
-
);
|
|
19221
|
-
const tokenState = new TokenState7(invoicePredicate, null);
|
|
19222
|
-
const sdkToken = await SdkToken5.mint(trustBase, tokenState, genesisTransaction);
|
|
19223
|
-
if (this.config.debug) {
|
|
19224
|
-
logger.debug(LOG_TAG2, "Invoice token minted successfully");
|
|
19225
|
-
}
|
|
19226
|
-
const sdkTokenJson = sdkToken.toJSON();
|
|
19227
19224
|
const uiToken = {
|
|
19228
19225
|
id: invoiceId,
|
|
19229
19226
|
coinId: INVOICE_TOKEN_TYPE_HEX,
|
|
@@ -19234,7 +19231,7 @@ var AccountingModule = class _AccountingModule {
|
|
|
19234
19231
|
status: "confirmed",
|
|
19235
19232
|
createdAt: terms.createdAt,
|
|
19236
19233
|
updatedAt: terms.createdAt,
|
|
19237
|
-
sdkData
|
|
19234
|
+
sdkData
|
|
19238
19235
|
};
|
|
19239
19236
|
await deps.payments.addToken(uiToken);
|
|
19240
19237
|
this.invoiceTermsCache.set(invoiceId, this._normalizeInvoiceTerms(terms));
|
|
@@ -19245,17 +19242,7 @@ var AccountingModule = class _AccountingModule {
|
|
|
19245
19242
|
const allTokens = deps.payments.getTokens();
|
|
19246
19243
|
let anyScanDirty = false;
|
|
19247
19244
|
for (const token of allTokens) {
|
|
19248
|
-
if (
|
|
19249
|
-
let txf;
|
|
19250
|
-
try {
|
|
19251
|
-
txf = JSON.parse(token.sdkData);
|
|
19252
|
-
} catch {
|
|
19253
|
-
continue;
|
|
19254
|
-
}
|
|
19255
|
-
const txCount = txf.transactions?.length ?? 0;
|
|
19256
|
-
if (txCount === 0) continue;
|
|
19257
|
-
this._processTokenTransactions(token.id, txf, 0);
|
|
19258
|
-
anyScanDirty = true;
|
|
19245
|
+
if (await this._scanTokenForAttribution(token, 0)) anyScanDirty = true;
|
|
19259
19246
|
}
|
|
19260
19247
|
const archivedTokensForScan = deps.payments.getArchivedTokens();
|
|
19261
19248
|
for (const [archivedId, txf] of archivedTokensForScan) {
|
|
@@ -19271,7 +19258,7 @@ var AccountingModule = class _AccountingModule {
|
|
|
19271
19258
|
if (this.config.debug) {
|
|
19272
19259
|
logger.debug(LOG_TAG2, `Invoice created and stored: ${invoiceId}`);
|
|
19273
19260
|
}
|
|
19274
|
-
const txfToken =
|
|
19261
|
+
const txfToken = engine ? sdkData : JSON.parse(sdkData);
|
|
19275
19262
|
return {
|
|
19276
19263
|
success: true,
|
|
19277
19264
|
invoiceId,
|
|
@@ -19312,36 +19299,60 @@ var AccountingModule = class _AccountingModule {
|
|
|
19312
19299
|
this.ensureNotDestroyed();
|
|
19313
19300
|
this.ensureInitialized();
|
|
19314
19301
|
const deps = this.deps;
|
|
19315
|
-
|
|
19316
|
-
|
|
19317
|
-
|
|
19318
|
-
|
|
19319
|
-
|
|
19320
|
-
|
|
19321
|
-
|
|
19322
|
-
|
|
19323
|
-
|
|
19324
|
-
|
|
19325
|
-
|
|
19326
|
-
|
|
19327
|
-
);
|
|
19328
|
-
|
|
19329
|
-
|
|
19330
|
-
|
|
19302
|
+
let terms;
|
|
19303
|
+
let tokenId;
|
|
19304
|
+
let sdkDataForStore;
|
|
19305
|
+
const engine = deps.tokenEngine;
|
|
19306
|
+
const isV2 = !!engine && typeof token === "string";
|
|
19307
|
+
if (isV2) {
|
|
19308
|
+
const sphereToken = await engine.decodeToken(decodeTokenBlob(hexToBytes(token)));
|
|
19309
|
+
const verifyResult = await engine.verify(sphereToken);
|
|
19310
|
+
if (!verifyResult.ok) {
|
|
19311
|
+
throw new SphereError("Invoice import failed: inclusion proof is invalid.", "INVOICE_INVALID_PROOF");
|
|
19312
|
+
}
|
|
19313
|
+
tokenId = engine.tokenId(sphereToken);
|
|
19314
|
+
const data = engine.readTokenData(sphereToken);
|
|
19315
|
+
if (!data) {
|
|
19316
|
+
throw new SphereError("Invoice import failed: missing or invalid tokenData field.", "INVOICE_INVALID_DATA");
|
|
19317
|
+
}
|
|
19331
19318
|
try {
|
|
19332
|
-
|
|
19333
|
-
jsonString = new TextDecoder().decode(bytes);
|
|
19319
|
+
terms = JSON.parse(new TextDecoder().decode(data));
|
|
19334
19320
|
} catch {
|
|
19321
|
+
throw new SphereError("Invoice import failed: tokenData is not valid JSON.", "INVOICE_INVALID_DATA");
|
|
19335
19322
|
}
|
|
19336
|
-
|
|
19337
|
-
|
|
19338
|
-
|
|
19339
|
-
|
|
19340
|
-
|
|
19341
|
-
|
|
19342
|
-
|
|
19343
|
-
|
|
19344
|
-
|
|
19323
|
+
sdkDataForStore = token;
|
|
19324
|
+
} else {
|
|
19325
|
+
const tokenType = token.genesis?.data?.tokenType;
|
|
19326
|
+
if (tokenType !== INVOICE_TOKEN_TYPE_HEX) {
|
|
19327
|
+
throw new SphereError(
|
|
19328
|
+
`Invoice import failed: token type "${tokenType}" is not the expected invoice type.`,
|
|
19329
|
+
"INVOICE_WRONG_TOKEN_TYPE"
|
|
19330
|
+
);
|
|
19331
|
+
}
|
|
19332
|
+
const tokenData = token.genesis?.data?.tokenData;
|
|
19333
|
+
if (!tokenData || typeof tokenData !== "string") {
|
|
19334
|
+
throw new SphereError(
|
|
19335
|
+
"Invoice import failed: missing or invalid tokenData field.",
|
|
19336
|
+
"INVOICE_INVALID_DATA"
|
|
19337
|
+
);
|
|
19338
|
+
}
|
|
19339
|
+
let jsonString = tokenData;
|
|
19340
|
+
if (!/^\s*[[{"]/.test(tokenData)) {
|
|
19341
|
+
try {
|
|
19342
|
+
const bytes = hexToBytes(tokenData);
|
|
19343
|
+
jsonString = new TextDecoder().decode(bytes);
|
|
19344
|
+
} catch {
|
|
19345
|
+
}
|
|
19346
|
+
}
|
|
19347
|
+
try {
|
|
19348
|
+
terms = JSON.parse(jsonString);
|
|
19349
|
+
} catch {
|
|
19350
|
+
throw new SphereError(
|
|
19351
|
+
"Invoice import failed: tokenData is not valid JSON.",
|
|
19352
|
+
"INVOICE_INVALID_DATA"
|
|
19353
|
+
);
|
|
19354
|
+
}
|
|
19355
|
+
sdkDataForStore = JSON.stringify(token);
|
|
19345
19356
|
}
|
|
19346
19357
|
if (!terms || typeof terms !== "object") {
|
|
19347
19358
|
throw new SphereError(
|
|
@@ -19428,7 +19439,7 @@ var AccountingModule = class _AccountingModule {
|
|
|
19428
19439
|
}
|
|
19429
19440
|
}
|
|
19430
19441
|
}
|
|
19431
|
-
|
|
19442
|
+
if (!isV2) tokenId = token.genesis?.data?.tokenId;
|
|
19432
19443
|
if (!tokenId || typeof tokenId !== "string") {
|
|
19433
19444
|
throw new SphereError(
|
|
19434
19445
|
"Invoice import failed: missing tokenId in genesis data.",
|
|
@@ -19441,13 +19452,13 @@ var AccountingModule = class _AccountingModule {
|
|
|
19441
19452
|
"INVOICE_ALREADY_EXISTS"
|
|
19442
19453
|
);
|
|
19443
19454
|
}
|
|
19444
|
-
{
|
|
19445
|
-
const { DataHasher } = await import("@unicitylabs/state-transition-sdk/lib/hash/DataHasher.js");
|
|
19446
|
-
const { HashAlgorithm:
|
|
19447
|
-
const { TokenId:
|
|
19455
|
+
if (!isV2) {
|
|
19456
|
+
const { DataHasher: DataHasher2 } = await import("@unicitylabs/state-transition-sdk/lib/hash/DataHasher.js");
|
|
19457
|
+
const { HashAlgorithm: HashAlgorithm6 } = await import("@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm.js");
|
|
19458
|
+
const { TokenId: TokenId4 } = await import("@unicitylabs/state-transition-sdk/lib/token/TokenId.js");
|
|
19448
19459
|
const reSerializedBytes = new TextEncoder().encode(canonicalSerialize(terms));
|
|
19449
|
-
const hash = await new
|
|
19450
|
-
const reTokenId = new
|
|
19460
|
+
const hash = await new DataHasher2(HashAlgorithm6.SHA256).update(reSerializedBytes).digest();
|
|
19461
|
+
const reTokenId = new TokenId4(hash.imprint).toJSON();
|
|
19451
19462
|
if (reTokenId !== tokenId) {
|
|
19452
19463
|
throw new SphereError(
|
|
19453
19464
|
"Invoice import failed: parsed terms do not match on-chain token ID (canonical hash mismatch).",
|
|
@@ -19455,35 +19466,37 @@ var AccountingModule = class _AccountingModule {
|
|
|
19455
19466
|
);
|
|
19456
19467
|
}
|
|
19457
19468
|
}
|
|
19458
|
-
if (!
|
|
19459
|
-
|
|
19460
|
-
"Trust base unavailable \u2014 cannot verify invoice proof. Ensure oracle supports getTrustBase().",
|
|
19461
|
-
"INVOICE_INVALID_PROOF"
|
|
19462
|
-
);
|
|
19463
|
-
}
|
|
19464
|
-
try {
|
|
19465
|
-
const sdkToken = await import_Token8.Token.fromJSON(token);
|
|
19466
|
-
const verifyResult = await sdkToken.verify(deps.trustBase);
|
|
19467
|
-
const verifyOk = verifyResult.isSuccessful === true;
|
|
19468
|
-
if (!verifyOk) {
|
|
19469
|
+
if (!isV2) {
|
|
19470
|
+
if (!deps.trustBase || deps.trustBase instanceof Uint8Array && deps.trustBase.length === 0) {
|
|
19469
19471
|
throw new SphereError(
|
|
19470
|
-
"
|
|
19472
|
+
"Trust base unavailable \u2014 cannot verify invoice proof. Ensure oracle supports getTrustBase().",
|
|
19471
19473
|
"INVOICE_INVALID_PROOF"
|
|
19472
19474
|
);
|
|
19473
19475
|
}
|
|
19474
|
-
|
|
19475
|
-
|
|
19476
|
+
try {
|
|
19477
|
+
const sdkToken = await import_Token7.Token.fromJSON(token);
|
|
19478
|
+
const verifyResult = await sdkToken.verify(deps.trustBase);
|
|
19479
|
+
const verifyOk = verifyResult.isSuccessful === true;
|
|
19480
|
+
if (!verifyOk) {
|
|
19481
|
+
throw new SphereError(
|
|
19482
|
+
"Invoice import failed: inclusion proof is invalid.",
|
|
19483
|
+
"INVOICE_INVALID_PROOF"
|
|
19484
|
+
);
|
|
19485
|
+
}
|
|
19486
|
+
const canonicalTokenId = sdkToken.id?.toJSON?.() ?? null;
|
|
19487
|
+
if (!canonicalTokenId || canonicalTokenId !== tokenId) {
|
|
19488
|
+
throw new SphereError(
|
|
19489
|
+
`Invoice import failed: tokenId mismatch or unverifiable \u2014 JSON claims ${tokenId}, cryptographic identity is ${canonicalTokenId ?? "unknown"}`,
|
|
19490
|
+
"INVOICE_INVALID_DATA"
|
|
19491
|
+
);
|
|
19492
|
+
}
|
|
19493
|
+
} catch (err) {
|
|
19494
|
+
if (err instanceof SphereError) throw err;
|
|
19476
19495
|
throw new SphereError(
|
|
19477
|
-
`Invoice import failed:
|
|
19478
|
-
"
|
|
19496
|
+
`Invoice import failed: proof verification error \u2014 ${err instanceof Error ? err.message : String(err)}`,
|
|
19497
|
+
"INVOICE_INVALID_PROOF"
|
|
19479
19498
|
);
|
|
19480
19499
|
}
|
|
19481
|
-
} catch (err) {
|
|
19482
|
-
if (err instanceof SphereError) throw err;
|
|
19483
|
-
throw new SphereError(
|
|
19484
|
-
`Invoice import failed: proof verification error \u2014 ${err instanceof Error ? err.message : String(err)}`,
|
|
19485
|
-
"INVOICE_INVALID_PROOF"
|
|
19486
|
-
);
|
|
19487
19500
|
}
|
|
19488
19501
|
try {
|
|
19489
19502
|
const uiToken = {
|
|
@@ -19496,7 +19509,7 @@ var AccountingModule = class _AccountingModule {
|
|
|
19496
19509
|
status: "confirmed",
|
|
19497
19510
|
createdAt: terms.createdAt,
|
|
19498
19511
|
updatedAt: terms.createdAt,
|
|
19499
|
-
sdkData:
|
|
19512
|
+
sdkData: sdkDataForStore
|
|
19500
19513
|
};
|
|
19501
19514
|
await deps.payments.addToken(uiToken);
|
|
19502
19515
|
} catch (err) {
|
|
@@ -19551,17 +19564,8 @@ var AccountingModule = class _AccountingModule {
|
|
|
19551
19564
|
const allTokens = deps.payments.getTokens();
|
|
19552
19565
|
let anyDirty = false;
|
|
19553
19566
|
for (const existingToken of allTokens) {
|
|
19554
|
-
if (!existingToken.sdkData) continue;
|
|
19555
|
-
let txf;
|
|
19556
|
-
try {
|
|
19557
|
-
txf = JSON.parse(existingToken.sdkData);
|
|
19558
|
-
} catch {
|
|
19559
|
-
continue;
|
|
19560
|
-
}
|
|
19561
|
-
const transactions = txf.transactions ?? [];
|
|
19562
19567
|
const startIndex = this.tokenScanState.get(existingToken.id) ?? 0;
|
|
19563
|
-
if (
|
|
19564
|
-
this._processTokenTransactions(existingToken.id, txf, startIndex);
|
|
19568
|
+
if (await this._scanTokenForAttribution(existingToken, startIndex)) {
|
|
19565
19569
|
anyDirty = true;
|
|
19566
19570
|
}
|
|
19567
19571
|
}
|
|
@@ -21451,17 +21455,8 @@ var AccountingModule = class _AccountingModule {
|
|
|
21451
21455
|
const allTokens = deps.payments.getTokens();
|
|
21452
21456
|
let anyDirty = false;
|
|
21453
21457
|
for (const token of allTokens) {
|
|
21454
|
-
if (!token.sdkData) continue;
|
|
21455
|
-
let txf;
|
|
21456
|
-
try {
|
|
21457
|
-
txf = JSON.parse(token.sdkData);
|
|
21458
|
-
} catch {
|
|
21459
|
-
continue;
|
|
21460
|
-
}
|
|
21461
|
-
const transactions = txf.transactions ?? [];
|
|
21462
21458
|
const startIndex = this.tokenScanState.get(token.id) ?? 0;
|
|
21463
|
-
if (
|
|
21464
|
-
this._processTokenTransactions(token.id, txf, startIndex);
|
|
21459
|
+
if (await this._scanTokenForAttribution(token, startIndex)) {
|
|
21465
21460
|
anyDirty = true;
|
|
21466
21461
|
}
|
|
21467
21462
|
}
|
|
@@ -21516,6 +21511,53 @@ var AccountingModule = class _AccountingModule {
|
|
|
21516
21511
|
* @param txf - Parsed TxfToken.
|
|
21517
21512
|
* @param startIndex - First unprocessed transaction index.
|
|
21518
21513
|
*/
|
|
21514
|
+
/**
|
|
21515
|
+
* Attribute one payment token's invoice memo(s) to the ledger.
|
|
21516
|
+
*
|
|
21517
|
+
* v2 (engine blob): the token carries a single on-chain memo. We decode it and
|
|
21518
|
+
* shim the token into a v1-shaped `txf` (coinData ← engine.readValue, the memo
|
|
21519
|
+
* ← engine.readMemo) so the battle-hardened `_processTokenTransactions` runs
|
|
21520
|
+
* UNCHANGED — same dedup, direction, provisional/synthetic/orphan handling.
|
|
21521
|
+
* v1 (TXF JSON): parse and scan transactions directly.
|
|
21522
|
+
*
|
|
21523
|
+
* `startIndex` is the per-token watermark (0 for a full retroactive scan).
|
|
21524
|
+
* Returns true when the token was scanned. Async because engine.decodeToken is.
|
|
21525
|
+
*/
|
|
21526
|
+
async _scanTokenForAttribution(token, startIndex) {
|
|
21527
|
+
if (!token.sdkData) return false;
|
|
21528
|
+
const engine = this.deps?.tokenEngine;
|
|
21529
|
+
const isBlob = token.sdkData.length >= 2 && token.sdkData.length % 2 === 0 && token.sdkData[0] !== "{" && /^[0-9a-f]+$/i.test(token.sdkData);
|
|
21530
|
+
if (engine && isBlob) {
|
|
21531
|
+
let syntheticTxf;
|
|
21532
|
+
try {
|
|
21533
|
+
const sphereToken = await engine.decodeToken(decodeTokenBlob(hexToBytes(token.sdkData)));
|
|
21534
|
+
const memo = engine.readMemo(sphereToken);
|
|
21535
|
+
if (!memo) return false;
|
|
21536
|
+
const coinData = (engine.readValue(sphereToken)?.assets ?? []).map(
|
|
21537
|
+
(a) => [a.coinId, a.amount.toString()]
|
|
21538
|
+
);
|
|
21539
|
+
syntheticTxf = {
|
|
21540
|
+
genesis: { data: { coinData } },
|
|
21541
|
+
transactions: [{ data: { message: bytesToHex(memo) }, inclusionProof: {} }]
|
|
21542
|
+
};
|
|
21543
|
+
} catch {
|
|
21544
|
+
return false;
|
|
21545
|
+
}
|
|
21546
|
+
this._processTokenTransactions(token.id, syntheticTxf, startIndex);
|
|
21547
|
+
return true;
|
|
21548
|
+
}
|
|
21549
|
+
let txf;
|
|
21550
|
+
try {
|
|
21551
|
+
txf = JSON.parse(token.sdkData);
|
|
21552
|
+
} catch {
|
|
21553
|
+
return false;
|
|
21554
|
+
}
|
|
21555
|
+
if ((txf.transactions?.length ?? 0) > startIndex) {
|
|
21556
|
+
this._processTokenTransactions(token.id, txf, startIndex);
|
|
21557
|
+
return true;
|
|
21558
|
+
}
|
|
21559
|
+
return false;
|
|
21560
|
+
}
|
|
21519
21561
|
_processTokenTransactions(tokenId, txf, startIndex) {
|
|
21520
21562
|
const transactions = txf.transactions ?? [];
|
|
21521
21563
|
let lastSuccessIdx = startIndex;
|
|
@@ -21795,17 +21837,7 @@ var AccountingModule = class _AccountingModule {
|
|
|
21795
21837
|
async _handleIncomingTransfer(transfer) {
|
|
21796
21838
|
if (this.destroyed) return;
|
|
21797
21839
|
for (const token of transfer.tokens) {
|
|
21798
|
-
|
|
21799
|
-
let txf;
|
|
21800
|
-
try {
|
|
21801
|
-
txf = JSON.parse(token.sdkData);
|
|
21802
|
-
} catch {
|
|
21803
|
-
continue;
|
|
21804
|
-
}
|
|
21805
|
-
const startIndex = this.tokenScanState.get(token.id) ?? 0;
|
|
21806
|
-
if ((txf.transactions?.length ?? 0) > startIndex) {
|
|
21807
|
-
this._processTokenTransactions(token.id, txf, startIndex);
|
|
21808
|
-
}
|
|
21840
|
+
await this._scanTokenForAttribution(token, this.tokenScanState.get(token.id) ?? 0);
|
|
21809
21841
|
}
|
|
21810
21842
|
if (this.destroyed) return;
|
|
21811
21843
|
await this._flushDirtyLedgerEntries();
|
|
@@ -21943,16 +21975,7 @@ var AccountingModule = class _AccountingModule {
|
|
|
21943
21975
|
if (this.destroyed) return;
|
|
21944
21976
|
for (const token of result.tokens) {
|
|
21945
21977
|
if (!token.sdkData) continue;
|
|
21946
|
-
|
|
21947
|
-
try {
|
|
21948
|
-
txf = JSON.parse(token.sdkData);
|
|
21949
|
-
} catch {
|
|
21950
|
-
continue;
|
|
21951
|
-
}
|
|
21952
|
-
const startIndex = this.tokenScanState.get(token.id) ?? 0;
|
|
21953
|
-
if ((txf.transactions?.length ?? 0) > startIndex) {
|
|
21954
|
-
this._processTokenTransactions(token.id, txf, startIndex);
|
|
21955
|
-
}
|
|
21978
|
+
await this._scanTokenForAttribution(token, this.tokenScanState.get(token.id) ?? 0);
|
|
21956
21979
|
const relatedInvoices = this.tokenInvoiceMap.get(token.id);
|
|
21957
21980
|
if (relatedInvoices) {
|
|
21958
21981
|
for (const invoiceId of relatedInvoices) {
|
|
@@ -22023,15 +22046,8 @@ var AccountingModule = class _AccountingModule {
|
|
|
22023
22046
|
const tokens = this.deps.payments.getTokens();
|
|
22024
22047
|
const token = tokens.find((t) => t.id === tokenId);
|
|
22025
22048
|
if (!token?.sdkData) return;
|
|
22026
|
-
let txf;
|
|
22027
|
-
try {
|
|
22028
|
-
txf = JSON.parse(token.sdkData);
|
|
22029
|
-
} catch {
|
|
22030
|
-
return;
|
|
22031
|
-
}
|
|
22032
22049
|
const startIndex = this.tokenScanState.get(tokenId) ?? 0;
|
|
22033
|
-
if ((
|
|
22034
|
-
this._processTokenTransactions(tokenId, txf, startIndex);
|
|
22050
|
+
if (await this._scanTokenForAttribution(token, startIndex)) {
|
|
22035
22051
|
if (this.destroyed) return;
|
|
22036
22052
|
await this._flushDirtyLedgerEntries();
|
|
22037
22053
|
}
|
|
@@ -27469,29 +27485,421 @@ async function parseAndDecryptWalletDat(data, password, onProgress) {
|
|
|
27469
27485
|
};
|
|
27470
27486
|
}
|
|
27471
27487
|
|
|
27488
|
+
// token-engine/identity.ts
|
|
27489
|
+
var UNICITY_TOKEN_TYPE_HEX = "f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509";
|
|
27490
|
+
var SIGNING_ALGORITHM = "secp256k1";
|
|
27491
|
+
var EMBEDDED_PREDICATE_UNMASKED = 0;
|
|
27492
|
+
var HASH_ALGORITHM_SHA256 = 0n;
|
|
27493
|
+
var SHA256_IMPRINT_PREFIX = new Uint8Array([0, 0]);
|
|
27494
|
+
function hexToBytes4(hex) {
|
|
27495
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
27496
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
27497
|
+
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
27498
|
+
}
|
|
27499
|
+
return bytes;
|
|
27500
|
+
}
|
|
27501
|
+
function sha2565(data) {
|
|
27502
|
+
return new import_DataHasher.DataHasher(import_HashAlgorithm2.HashAlgorithm.SHA256).update(data).digest().then((h) => h.data);
|
|
27503
|
+
}
|
|
27504
|
+
async function deriveDirectAddress(publicKey) {
|
|
27505
|
+
const tokenTypeCbor = import_CborSerializer.CborSerializer.encodeByteString(hexToBytes4(UNICITY_TOKEN_TYPE_HEX));
|
|
27506
|
+
const reference = import_CborSerializer.CborSerializer.encodeArray(
|
|
27507
|
+
import_CborSerializer.CborSerializer.encodeByteString(new Uint8Array([EMBEDDED_PREDICATE_UNMASKED])),
|
|
27508
|
+
import_CborSerializer.CborSerializer.encodeByteString(tokenTypeCbor),
|
|
27509
|
+
import_CborSerializer.CborSerializer.encodeTextString(SIGNING_ALGORITHM),
|
|
27510
|
+
import_CborSerializer.CborSerializer.encodeUnsignedInteger(HASH_ALGORITHM_SHA256),
|
|
27511
|
+
import_CborSerializer.CborSerializer.encodeByteString(publicKey)
|
|
27512
|
+
);
|
|
27513
|
+
const refHash = await sha2565(reference);
|
|
27514
|
+
const imprint = new Uint8Array([...SHA256_IMPRINT_PREFIX, ...refHash]);
|
|
27515
|
+
const checksum = (await sha2565(imprint)).slice(0, 4);
|
|
27516
|
+
return `DIRECT://${import_HexConverter.HexConverter.encode(imprint)}${import_HexConverter.HexConverter.encode(checksum)}`;
|
|
27517
|
+
}
|
|
27518
|
+
|
|
27519
|
+
// token-engine/factory.ts
|
|
27520
|
+
init_errors();
|
|
27521
|
+
|
|
27522
|
+
// token-engine/SpherePaymentData.ts
|
|
27523
|
+
init_errors();
|
|
27524
|
+
var COIN_ID_PATTERN = /^([0-9a-f]{2})+$/;
|
|
27525
|
+
function assertAsset(coinId, amount) {
|
|
27526
|
+
if (!COIN_ID_PATTERN.test(coinId)) {
|
|
27527
|
+
throw new SphereError(`Invalid coin id (expected even-length lowercase hex): "${coinId}"`, "VALIDATION_ERROR");
|
|
27528
|
+
}
|
|
27529
|
+
if (amount < 0n) {
|
|
27530
|
+
throw new SphereError(`Asset amount must be non-negative: ${amount.toString()}`, "VALIDATION_ERROR");
|
|
27531
|
+
}
|
|
27532
|
+
}
|
|
27533
|
+
function sphereAssetToSdk(coinId, amount) {
|
|
27534
|
+
assertAsset(coinId, amount);
|
|
27535
|
+
return new import_Asset.Asset(new import_AssetId.AssetId(import_HexConverter.HexConverter.decode(coinId)), amount);
|
|
27536
|
+
}
|
|
27537
|
+
var SpherePaymentData = class _SpherePaymentData {
|
|
27538
|
+
constructor(assets, _memo = null) {
|
|
27539
|
+
this.assets = assets;
|
|
27540
|
+
this._memo = _memo;
|
|
27541
|
+
}
|
|
27542
|
+
/** Sphere-private CBOR tag (verified free in the v2 SDK tag space). */
|
|
27543
|
+
static CBOR_TAG = 39050n;
|
|
27544
|
+
/** Envelope version; bump when the structure changes. */
|
|
27545
|
+
static VERSION = 1n;
|
|
27546
|
+
/** Opaque, app-defined memo carried alongside the value (e.g. invoice attribution). */
|
|
27547
|
+
get memo() {
|
|
27548
|
+
return this._memo ? new Uint8Array(this._memo) : null;
|
|
27549
|
+
}
|
|
27550
|
+
/** Wrap an existing SDK asset collection (+ optional opaque memo). */
|
|
27551
|
+
static create(assets, memo = null) {
|
|
27552
|
+
return new _SpherePaymentData(assets, memo);
|
|
27553
|
+
}
|
|
27554
|
+
/** Build from a sphere-domain value (hex coin id → bigint amount) + optional opaque memo. */
|
|
27555
|
+
static fromValue(value, memo = null) {
|
|
27556
|
+
const assets = value.assets.map((a) => sphereAssetToSdk(a.coinId, a.amount));
|
|
27557
|
+
return new _SpherePaymentData(import_PaymentAssetCollection.PaymentAssetCollection.create(...assets), memo);
|
|
27558
|
+
}
|
|
27559
|
+
/** Decode from the CBOR envelope produced by {@link encode}. */
|
|
27560
|
+
static fromCBOR(bytes) {
|
|
27561
|
+
const tag = import_CborDeserializer.CborDeserializer.decodeTag(bytes);
|
|
27562
|
+
if (tag.tag !== _SpherePaymentData.CBOR_TAG) {
|
|
27563
|
+
throw new import_CborError.CborError(`Invalid SpherePaymentData tag: ${tag.tag}`);
|
|
27564
|
+
}
|
|
27565
|
+
const fields = import_CborDeserializer.CborDeserializer.decodeArray(tag.data, 3);
|
|
27566
|
+
const version = import_CborDeserializer.CborDeserializer.decodeUnsignedInteger(fields[0]);
|
|
27567
|
+
if (version !== _SpherePaymentData.VERSION) {
|
|
27568
|
+
throw new import_CborError.CborError(`Unsupported SpherePaymentData version: ${version}`);
|
|
27569
|
+
}
|
|
27570
|
+
const memo = import_CborDeserializer.CborDeserializer.decodeNullable(fields[2], import_CborDeserializer.CborDeserializer.decodeByteString);
|
|
27571
|
+
return new _SpherePaymentData(import_PaymentAssetCollection.PaymentAssetCollection.fromCBOR(fields[1]), memo);
|
|
27572
|
+
}
|
|
27573
|
+
/** Deterministic, versioned, tagged CBOR: `tag(39050)[ version, assets, memo? ]`. */
|
|
27574
|
+
encode() {
|
|
27575
|
+
return Promise.resolve(
|
|
27576
|
+
import_CborSerializer.CborSerializer.encodeTag(
|
|
27577
|
+
_SpherePaymentData.CBOR_TAG,
|
|
27578
|
+
import_CborSerializer.CborSerializer.encodeArray(
|
|
27579
|
+
import_CborSerializer.CborSerializer.encodeUnsignedInteger(_SpherePaymentData.VERSION),
|
|
27580
|
+
this.assets.toCBOR(),
|
|
27581
|
+
import_CborSerializer.CborSerializer.encodeNullable(this._memo, import_CborSerializer.CborSerializer.encodeByteString)
|
|
27582
|
+
)
|
|
27583
|
+
)
|
|
27584
|
+
);
|
|
27585
|
+
}
|
|
27586
|
+
/** Project to a sphere-domain value (hex coin id + bigint amount), preserving order. */
|
|
27587
|
+
toValue() {
|
|
27588
|
+
return {
|
|
27589
|
+
assets: this.assets.toArray().map((a) => ({
|
|
27590
|
+
coinId: import_HexConverter.HexConverter.encode(a.id.bytes),
|
|
27591
|
+
amount: a.value
|
|
27592
|
+
}))
|
|
27593
|
+
};
|
|
27594
|
+
}
|
|
27595
|
+
/** Balance of a single coin within this payload (0n when absent). */
|
|
27596
|
+
balanceOf(coinId) {
|
|
27597
|
+
if (!COIN_ID_PATTERN.test(coinId)) {
|
|
27598
|
+
throw new SphereError(`Invalid coin id (expected even-length lowercase hex): "${coinId}"`, "VALIDATION_ERROR");
|
|
27599
|
+
}
|
|
27600
|
+
const asset = this.assets.get(new import_AssetId.AssetId(import_HexConverter.HexConverter.decode(coinId)));
|
|
27601
|
+
return asset ? asset.value : 0n;
|
|
27602
|
+
}
|
|
27603
|
+
};
|
|
27604
|
+
function decodeSpherePaymentData(bytes) {
|
|
27605
|
+
return Promise.resolve(SpherePaymentData.fromCBOR(bytes));
|
|
27606
|
+
}
|
|
27607
|
+
|
|
27608
|
+
// token-engine/SphereTokenEngine.ts
|
|
27609
|
+
init_errors();
|
|
27610
|
+
var SphereTokenEngine = class {
|
|
27611
|
+
constructor(deps) {
|
|
27612
|
+
this.deps = deps;
|
|
27613
|
+
}
|
|
27614
|
+
// ── identity ────────────────────────────────────────────────────────────────
|
|
27615
|
+
getIdentity() {
|
|
27616
|
+
return { chainPubkey: new Uint8Array(this.deps.signingService.publicKey) };
|
|
27617
|
+
}
|
|
27618
|
+
/** Legacy DIRECT:// address (Path A). Async: the derivation hashes via the SDK. */
|
|
27619
|
+
deriveIdentityAddress(pubkey) {
|
|
27620
|
+
return deriveDirectAddress(pubkey ?? this.deps.signingService.publicKey);
|
|
27621
|
+
}
|
|
27622
|
+
// ── value (read) ─────────────────────────────────────────────────────────────
|
|
27623
|
+
readValue(token) {
|
|
27624
|
+
return token.value;
|
|
27625
|
+
}
|
|
27626
|
+
balanceOf(token, coinId) {
|
|
27627
|
+
let sum = 0n;
|
|
27628
|
+
for (const asset of token.value?.assets ?? []) {
|
|
27629
|
+
if (asset.coinId === coinId) sum += asset.amount;
|
|
27630
|
+
}
|
|
27631
|
+
return sum;
|
|
27632
|
+
}
|
|
27633
|
+
tokenId(token) {
|
|
27634
|
+
return token.blob.tokenId;
|
|
27635
|
+
}
|
|
27636
|
+
readMemo(token) {
|
|
27637
|
+
const sdkToken = token.sdkToken;
|
|
27638
|
+
if (sdkToken.transactions.length > 0) {
|
|
27639
|
+
return sdkToken.latestTransaction.data;
|
|
27640
|
+
}
|
|
27641
|
+
const data = sdkToken.genesis.data;
|
|
27642
|
+
if (data && this.isSpherePaymentData(data)) {
|
|
27643
|
+
return SpherePaymentData.fromCBOR(data).memo;
|
|
27644
|
+
}
|
|
27645
|
+
return null;
|
|
27646
|
+
}
|
|
27647
|
+
readTokenData(token) {
|
|
27648
|
+
const data = token.sdkToken.genesis.data;
|
|
27649
|
+
return data ? new Uint8Array(data) : null;
|
|
27650
|
+
}
|
|
27651
|
+
// ── lifecycle ────────────────────────────────────────────────────────────────
|
|
27652
|
+
async mint(params, options) {
|
|
27653
|
+
const recipient = import_SignaturePredicate.SignaturePredicate.create(params.recipientPubkey);
|
|
27654
|
+
const data = params.value ? await SpherePaymentData.fromValue(params.value).encode() : null;
|
|
27655
|
+
const mintTx = await import_MintTransaction.MintTransaction.create(this.deps.networkId, recipient, data);
|
|
27656
|
+
const certificationData = await import_CertificationData.CertificationData.fromMintTransaction(mintTx);
|
|
27657
|
+
const response = await this.deps.client.submitCertificationRequest(certificationData);
|
|
27658
|
+
if (response.status !== import_CertificationResponse.CertificationStatus.SUCCESS) {
|
|
27659
|
+
throw new SphereError(`Mint certification failed: ${response.status}`, "AGGREGATOR_ERROR");
|
|
27660
|
+
}
|
|
27661
|
+
const proof = await (0, import_InclusionProofUtils2.waitInclusionProof)(
|
|
27662
|
+
this.deps.client,
|
|
27663
|
+
this.deps.trustBase,
|
|
27664
|
+
this.deps.predicateVerifier,
|
|
27665
|
+
mintTx,
|
|
27666
|
+
options?.signal
|
|
27667
|
+
);
|
|
27668
|
+
const certified = await mintTx.toCertifiedTransaction(this.deps.trustBase, this.deps.predicateVerifier, proof);
|
|
27669
|
+
const token = await import_Token2.Token.mint(
|
|
27670
|
+
this.deps.trustBase,
|
|
27671
|
+
this.deps.predicateVerifier,
|
|
27672
|
+
this.deps.mintJustificationVerifier,
|
|
27673
|
+
certified
|
|
27674
|
+
);
|
|
27675
|
+
return this.wrapToken(token);
|
|
27676
|
+
}
|
|
27677
|
+
async mintDataToken(params, options) {
|
|
27678
|
+
const recipient = import_SignaturePredicate.SignaturePredicate.create(params.recipientPubkey);
|
|
27679
|
+
const tokenType = params.tokenType ? new import_TokenType.TokenType(params.tokenType) : import_TokenType.TokenType.generate();
|
|
27680
|
+
const salt = params.salt ? import_TokenSalt.TokenSalt.fromBytes(params.salt) : import_TokenSalt.TokenSalt.generate();
|
|
27681
|
+
const mintTx = await import_MintTransaction.MintTransaction.create(this.deps.networkId, recipient, params.data, tokenType, salt);
|
|
27682
|
+
const certificationData = await import_CertificationData.CertificationData.fromMintTransaction(mintTx);
|
|
27683
|
+
const response = await this.deps.client.submitCertificationRequest(certificationData);
|
|
27684
|
+
if (response.status !== import_CertificationResponse.CertificationStatus.SUCCESS) {
|
|
27685
|
+
throw new SphereError(`Data-token mint failed: ${response.status}`, "AGGREGATOR_ERROR");
|
|
27686
|
+
}
|
|
27687
|
+
const proof = await (0, import_InclusionProofUtils2.waitInclusionProof)(
|
|
27688
|
+
this.deps.client,
|
|
27689
|
+
this.deps.trustBase,
|
|
27690
|
+
this.deps.predicateVerifier,
|
|
27691
|
+
mintTx,
|
|
27692
|
+
options?.signal
|
|
27693
|
+
);
|
|
27694
|
+
const certified = await mintTx.toCertifiedTransaction(this.deps.trustBase, this.deps.predicateVerifier, proof);
|
|
27695
|
+
const token = await import_Token2.Token.mint(
|
|
27696
|
+
this.deps.trustBase,
|
|
27697
|
+
this.deps.predicateVerifier,
|
|
27698
|
+
this.deps.mintJustificationVerifier,
|
|
27699
|
+
certified
|
|
27700
|
+
);
|
|
27701
|
+
return this.wrapToken(token);
|
|
27702
|
+
}
|
|
27703
|
+
async transfer(params, options) {
|
|
27704
|
+
this.assertOwned(params.token);
|
|
27705
|
+
const recipient = import_SignaturePredicate.SignaturePredicate.create(params.recipientPubkey);
|
|
27706
|
+
const stateMask = crypto.getRandomValues(new Uint8Array(32));
|
|
27707
|
+
const transferTx = await import_TransferTransaction.TransferTransaction.create(params.token.sdkToken, recipient, stateMask, params.data ?? null);
|
|
27708
|
+
const unlockScript = await import_SignaturePredicateUnlockScript.SignaturePredicateUnlockScript.create(transferTx, this.deps.signingService);
|
|
27709
|
+
const certificationData = await import_CertificationData.CertificationData.fromTransaction(transferTx, unlockScript);
|
|
27710
|
+
const response = await this.deps.client.submitCertificationRequest(certificationData);
|
|
27711
|
+
if (response.status !== import_CertificationResponse.CertificationStatus.SUCCESS) {
|
|
27712
|
+
throw new SphereError(`Transfer certification failed: ${response.status}`, "TRANSFER_FAILED");
|
|
27713
|
+
}
|
|
27714
|
+
const proof = await (0, import_InclusionProofUtils2.waitInclusionProof)(
|
|
27715
|
+
this.deps.client,
|
|
27716
|
+
this.deps.trustBase,
|
|
27717
|
+
this.deps.predicateVerifier,
|
|
27718
|
+
transferTx,
|
|
27719
|
+
options?.signal
|
|
27720
|
+
);
|
|
27721
|
+
const certified = await transferTx.toCertifiedTransaction(this.deps.trustBase, this.deps.predicateVerifier, proof);
|
|
27722
|
+
const transferred = await params.token.sdkToken.transfer(this.deps.trustBase, this.deps.predicateVerifier, certified);
|
|
27723
|
+
return this.wrapToken(transferred);
|
|
27724
|
+
}
|
|
27725
|
+
async split(params, options) {
|
|
27726
|
+
this.assertOwned(params.token);
|
|
27727
|
+
if (params.outputs.length === 0) {
|
|
27728
|
+
throw new SphereError("Split requires at least one output", "VALIDATION_ERROR");
|
|
27729
|
+
}
|
|
27730
|
+
const requests = params.outputs.map(
|
|
27731
|
+
(o) => import_SplitTokenRequest.SplitTokenRequest.create(
|
|
27732
|
+
import_SignaturePredicate.SignaturePredicate.create(o.recipientPubkey),
|
|
27733
|
+
import_PaymentAssetCollection.PaymentAssetCollection.create(sphereAssetToSdk(o.coinId, o.amount))
|
|
27734
|
+
)
|
|
27735
|
+
);
|
|
27736
|
+
const split = await import_TokenSplit.TokenSplit.split(params.token.sdkToken, decodeSpherePaymentData, requests);
|
|
27737
|
+
const burnUnlock = await import_SignaturePredicateUnlockScript.SignaturePredicateUnlockScript.create(split.burn.transaction, this.deps.signingService);
|
|
27738
|
+
const burnCert = await import_CertificationData.CertificationData.fromTransaction(split.burn.transaction, burnUnlock);
|
|
27739
|
+
const burnResponse = await this.deps.client.submitCertificationRequest(burnCert);
|
|
27740
|
+
if (burnResponse.status !== import_CertificationResponse.CertificationStatus.SUCCESS) {
|
|
27741
|
+
throw new SphereError(`Split burn failed: ${burnResponse.status}`, "TRANSFER_FAILED");
|
|
27742
|
+
}
|
|
27743
|
+
const burnProof = await (0, import_InclusionProofUtils2.waitInclusionProof)(
|
|
27744
|
+
this.deps.client,
|
|
27745
|
+
this.deps.trustBase,
|
|
27746
|
+
this.deps.predicateVerifier,
|
|
27747
|
+
split.burn.transaction,
|
|
27748
|
+
options?.signal
|
|
27749
|
+
);
|
|
27750
|
+
const burnCertified = await split.burn.transaction.toCertifiedTransaction(
|
|
27751
|
+
this.deps.trustBase,
|
|
27752
|
+
this.deps.predicateVerifier,
|
|
27753
|
+
burnProof
|
|
27754
|
+
);
|
|
27755
|
+
const burntToken = await params.token.sdkToken.transfer(
|
|
27756
|
+
this.deps.trustBase,
|
|
27757
|
+
this.deps.predicateVerifier,
|
|
27758
|
+
burnCertified
|
|
27759
|
+
);
|
|
27760
|
+
const outputs = [];
|
|
27761
|
+
for (let i = 0; i < split.tokens.length; i++) {
|
|
27762
|
+
const splitToken = split.tokens[i];
|
|
27763
|
+
const data = await SpherePaymentData.create(splitToken.assets, params.outputs[i].data ?? null).encode();
|
|
27764
|
+
const justification = import_SplitMintJustification.SplitMintJustification.create(burntToken, splitToken.proofs).toCBOR();
|
|
27765
|
+
const mintTx = await import_MintTransaction.MintTransaction.create(
|
|
27766
|
+
splitToken.networkId,
|
|
27767
|
+
splitToken.recipient,
|
|
27768
|
+
data,
|
|
27769
|
+
splitToken.tokenType,
|
|
27770
|
+
splitToken.salt,
|
|
27771
|
+
justification
|
|
27772
|
+
);
|
|
27773
|
+
const certData = await import_CertificationData.CertificationData.fromMintTransaction(mintTx);
|
|
27774
|
+
const response = await this.deps.client.submitCertificationRequest(certData);
|
|
27775
|
+
if (response.status !== import_CertificationResponse.CertificationStatus.SUCCESS) {
|
|
27776
|
+
throw new SphereError(`Split mint failed: ${response.status}`, "AGGREGATOR_ERROR");
|
|
27777
|
+
}
|
|
27778
|
+
const proof = await (0, import_InclusionProofUtils2.waitInclusionProof)(
|
|
27779
|
+
this.deps.client,
|
|
27780
|
+
this.deps.trustBase,
|
|
27781
|
+
this.deps.predicateVerifier,
|
|
27782
|
+
mintTx,
|
|
27783
|
+
options?.signal
|
|
27784
|
+
);
|
|
27785
|
+
const certified = await mintTx.toCertifiedTransaction(this.deps.trustBase, this.deps.predicateVerifier, proof);
|
|
27786
|
+
const token = await import_Token2.Token.mint(
|
|
27787
|
+
this.deps.trustBase,
|
|
27788
|
+
this.deps.predicateVerifier,
|
|
27789
|
+
this.deps.mintJustificationVerifier,
|
|
27790
|
+
certified
|
|
27791
|
+
);
|
|
27792
|
+
outputs.push(this.wrapToken(token));
|
|
27793
|
+
}
|
|
27794
|
+
return { outputs };
|
|
27795
|
+
}
|
|
27796
|
+
// ── verification ─────────────────────────────────────────────────────────────
|
|
27797
|
+
async verify(token, _options) {
|
|
27798
|
+
const result = await token.sdkToken.verify(
|
|
27799
|
+
this.deps.trustBase,
|
|
27800
|
+
this.deps.predicateVerifier,
|
|
27801
|
+
this.deps.mintJustificationVerifier
|
|
27802
|
+
);
|
|
27803
|
+
return result.status === import_VerificationStatus.VerificationStatus.OK ? { ok: true } : { ok: false, reason: String(result.status) };
|
|
27804
|
+
}
|
|
27805
|
+
async isSpent(token, _options) {
|
|
27806
|
+
const probe = await import_TransferTransaction.TransferTransaction.create(
|
|
27807
|
+
token.sdkToken,
|
|
27808
|
+
import_SignaturePredicate.SignaturePredicate.create(this.deps.signingService.publicKey),
|
|
27809
|
+
new Uint8Array(32)
|
|
27810
|
+
);
|
|
27811
|
+
const stateId = await import_StateId.StateId.fromTransaction(probe);
|
|
27812
|
+
const response = await this.deps.client.getInclusionProof(stateId);
|
|
27813
|
+
return response.inclusionProof.inclusionCertificate !== null;
|
|
27814
|
+
}
|
|
27815
|
+
// ── serialization ────────────────────────────────────────────────────────────
|
|
27816
|
+
encodeToken(token) {
|
|
27817
|
+
return token.blob;
|
|
27818
|
+
}
|
|
27819
|
+
async decodeToken(blob) {
|
|
27820
|
+
const sdkToken = await import_Token2.Token.fromCBOR(blob.token);
|
|
27821
|
+
if (sdkToken.genesis.networkId.id !== this.deps.networkId.id) {
|
|
27822
|
+
throw new SphereError(
|
|
27823
|
+
`Token network mismatch: token is on network ${sdkToken.genesis.networkId.id}, engine on ${this.deps.networkId.id}`,
|
|
27824
|
+
"VALIDATION_ERROR"
|
|
27825
|
+
);
|
|
27826
|
+
}
|
|
27827
|
+
return this.wrapToken(sdkToken);
|
|
27828
|
+
}
|
|
27829
|
+
// ── internals ────────────────────────────────────────────────────────────────
|
|
27830
|
+
/** Fail fast if this engine's key does not own the token's current state. */
|
|
27831
|
+
assertOwned(token) {
|
|
27832
|
+
const owner = token.sdkToken.latestTransaction.recipient;
|
|
27833
|
+
const mine = import_EncodedPredicate.EncodedPredicate.fromPredicate(import_SignaturePredicate.SignaturePredicate.create(this.deps.signingService.publicKey));
|
|
27834
|
+
if (!import_EncodedPredicate.EncodedPredicate.equals(owner, mine)) {
|
|
27835
|
+
throw new SphereError("Cannot transfer a token not owned by this engine identity", "VALIDATION_ERROR");
|
|
27836
|
+
}
|
|
27837
|
+
}
|
|
27838
|
+
/** Wrap an SDK token into a SphereToken: cache its blob (incl. stable tokenId) + decoded value. */
|
|
27839
|
+
wrapToken(sdkToken) {
|
|
27840
|
+
const data = sdkToken.genesis.data;
|
|
27841
|
+
let value = null;
|
|
27842
|
+
if (data && this.isSpherePaymentData(data)) {
|
|
27843
|
+
try {
|
|
27844
|
+
value = SpherePaymentData.fromCBOR(data).toValue();
|
|
27845
|
+
} catch (err) {
|
|
27846
|
+
throw new SphereError(
|
|
27847
|
+
`Failed to decode token payment data: ${err instanceof Error ? err.message : String(err)}`,
|
|
27848
|
+
"VALIDATION_ERROR"
|
|
27849
|
+
);
|
|
27850
|
+
}
|
|
27851
|
+
}
|
|
27852
|
+
const blob = {
|
|
27853
|
+
v: TOKEN_BLOB_VERSION,
|
|
27854
|
+
network: sdkToken.genesis.networkId.id,
|
|
27855
|
+
tokenId: import_HexConverter.HexConverter.encode(sdkToken.id.bytes),
|
|
27856
|
+
token: sdkToken.toCBOR()
|
|
27857
|
+
};
|
|
27858
|
+
return { sdkToken, blob, value };
|
|
27859
|
+
}
|
|
27860
|
+
/** True if the bytes are a SpherePaymentData envelope (value token) vs a raw data token. */
|
|
27861
|
+
isSpherePaymentData(data) {
|
|
27862
|
+
try {
|
|
27863
|
+
return import_CborDeserializer.CborDeserializer.decodeTag(data).tag === SpherePaymentData.CBOR_TAG;
|
|
27864
|
+
} catch {
|
|
27865
|
+
return false;
|
|
27866
|
+
}
|
|
27867
|
+
}
|
|
27868
|
+
};
|
|
27869
|
+
|
|
27870
|
+
// token-engine/factory.ts
|
|
27871
|
+
async function createSphereTokenEngine(config) {
|
|
27872
|
+
if (config.trustBaseJson == null) {
|
|
27873
|
+
throw new SphereError("Engine config requires a trust base (trustBaseJson)", "INVALID_CONFIG");
|
|
27874
|
+
}
|
|
27875
|
+
const trustBase = import_RootTrustBase.RootTrustBase.fromJSON(config.trustBaseJson);
|
|
27876
|
+
const predicateVerifier = import_PredicateVerifierService.PredicateVerifierService.create();
|
|
27877
|
+
const mintJustificationVerifier = new import_MintJustificationVerifierService.MintJustificationVerifierService();
|
|
27878
|
+
mintJustificationVerifier.register(
|
|
27879
|
+
new import_SplitMintJustificationVerifier.SplitMintJustificationVerifier(trustBase, predicateVerifier, decodeSpherePaymentData)
|
|
27880
|
+
);
|
|
27881
|
+
const deps = {
|
|
27882
|
+
client: new import_StateTransitionClient.StateTransitionClient(new import_AggregatorClient.AggregatorClient(config.aggregatorUrl, config.apiKey ?? null)),
|
|
27883
|
+
trustBase,
|
|
27884
|
+
predicateVerifier,
|
|
27885
|
+
mintJustificationVerifier,
|
|
27886
|
+
signingService: new import_SigningService.SigningService(config.privateKey),
|
|
27887
|
+
// The trust base is the single source of truth for the network id (it carries
|
|
27888
|
+
// NetworkId.fromId, so any id works — e.g. testnet2 = 4 — with no enum entry).
|
|
27889
|
+
networkId: trustBase.networkId
|
|
27890
|
+
};
|
|
27891
|
+
return new SphereTokenEngine(deps);
|
|
27892
|
+
}
|
|
27893
|
+
|
|
27472
27894
|
// core/Sphere.ts
|
|
27473
|
-
var
|
|
27474
|
-
var import_TokenType5 = require("@unicitylabs/state-transition-sdk/lib/token/TokenType");
|
|
27475
|
-
var import_HashAlgorithm7 = require("@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm");
|
|
27476
|
-
var import_UnmaskedPredicateReference3 = require("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference");
|
|
27477
|
-
var import_nostr_js_sdk5 = require("@unicitylabs/nostr-js-sdk");
|
|
27895
|
+
var import_nostr_js_sdk4 = require("@unicitylabs/nostr-js-sdk");
|
|
27478
27896
|
function isValidNametag2(nametag) {
|
|
27479
|
-
if ((0,
|
|
27897
|
+
if ((0, import_nostr_js_sdk4.isPhoneNumber)(nametag)) return true;
|
|
27480
27898
|
return /^[a-z0-9_-]{3,20}$/.test(nametag);
|
|
27481
27899
|
}
|
|
27482
|
-
var UNICITY_TOKEN_TYPE_HEX2 = "f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509";
|
|
27483
27900
|
async function deriveL3PredicateAddress(privateKey) {
|
|
27484
|
-
const
|
|
27485
|
-
|
|
27486
|
-
const tokenTypeBytes = Buffer.from(UNICITY_TOKEN_TYPE_HEX2, "hex");
|
|
27487
|
-
const tokenType = new import_TokenType5.TokenType(tokenTypeBytes);
|
|
27488
|
-
const predicateRef = import_UnmaskedPredicateReference3.UnmaskedPredicateReference.create(
|
|
27489
|
-
tokenType,
|
|
27490
|
-
signingService.algorithm,
|
|
27491
|
-
signingService.publicKey,
|
|
27492
|
-
import_HashAlgorithm7.HashAlgorithm.SHA256
|
|
27493
|
-
);
|
|
27494
|
-
return (await (await predicateRef).toAddress()).toString();
|
|
27901
|
+
const prehashedPublicKey = getPublicKey(sha2562(privateKey, "hex"));
|
|
27902
|
+
return deriveDirectAddress(hexToBytes2(prehashedPublicKey));
|
|
27495
27903
|
}
|
|
27496
27904
|
var Sphere = class _Sphere {
|
|
27497
27905
|
// Singleton
|
|
@@ -27513,14 +27921,14 @@ var Sphere = class _Sphere {
|
|
|
27513
27921
|
_addressIdToIndex = /* @__PURE__ */ new Map();
|
|
27514
27922
|
/** Nametag cache: addressId -> (nametagIndex -> nametag). Separate from tracked addresses. */
|
|
27515
27923
|
_addressNametags = /* @__PURE__ */ new Map();
|
|
27516
|
-
/** Cached PROXY address (computed once when nametag is set) */
|
|
27517
|
-
_cachedProxyAddress = void 0;
|
|
27518
27924
|
// Providers
|
|
27519
27925
|
_storage;
|
|
27520
27926
|
_tokenStorageProviders = /* @__PURE__ */ new Map();
|
|
27521
27927
|
_transport;
|
|
27522
27928
|
_oracle;
|
|
27523
27929
|
_priceProvider;
|
|
27930
|
+
/** v2 token engine (built per active address from the oracle); injected into modules. */
|
|
27931
|
+
_tokenEngine;
|
|
27524
27932
|
// Modules (single-instance — backward compat, delegates to active address)
|
|
27525
27933
|
_payments;
|
|
27526
27934
|
_communications;
|
|
@@ -27861,20 +28269,6 @@ var Sphere = class _Sphere {
|
|
|
27861
28269
|
await sphere.syncIdentityWithTransport();
|
|
27862
28270
|
sphere._initialized = true;
|
|
27863
28271
|
_Sphere.instance = sphere;
|
|
27864
|
-
if (sphere._identity?.nametag && !sphere._payments.hasNametag()) {
|
|
27865
|
-
progress?.({ step: "registering_nametag", message: "Restoring nametag token..." });
|
|
27866
|
-
logger.debug("Sphere", `Unicity ID @${sphere._identity.nametag} has no token, attempting to mint...`);
|
|
27867
|
-
try {
|
|
27868
|
-
const result = await sphere.mintNametag(sphere._identity.nametag);
|
|
27869
|
-
if (result.success) {
|
|
27870
|
-
logger.debug("Sphere", `Nametag token minted successfully on load`);
|
|
27871
|
-
} else {
|
|
27872
|
-
logger.warn("Sphere", `Could not mint nametag token: ${result.error}`);
|
|
27873
|
-
}
|
|
27874
|
-
} catch (err) {
|
|
27875
|
-
logger.warn("Sphere", `Nametag token mint failed:`, err);
|
|
27876
|
-
}
|
|
27877
|
-
}
|
|
27878
28272
|
if (options.discoverAddresses !== false && sphere._transport.discoverAddresses && sphere._masterKey) {
|
|
27879
28273
|
progress?.({ step: "discovering_addresses", message: "Discovering addresses..." });
|
|
27880
28274
|
try {
|
|
@@ -28926,13 +29320,13 @@ var Sphere = class _Sphere {
|
|
|
28926
29320
|
oracle: this._oracle,
|
|
28927
29321
|
emitEvent: this.emitEvent.bind(this),
|
|
28928
29322
|
chainCode: this._masterKey?.chainCode || void 0,
|
|
28929
|
-
price: this._priceProvider ?? void 0
|
|
29323
|
+
price: this._priceProvider ?? void 0,
|
|
29324
|
+
tokenEngine: moduleSet.tokenEngine
|
|
28930
29325
|
});
|
|
28931
29326
|
}
|
|
28932
29327
|
}
|
|
28933
29328
|
this._identity = newIdentity;
|
|
28934
29329
|
this._currentAddressIndex = index;
|
|
28935
|
-
await this._updateCachedProxyAddress();
|
|
28936
29330
|
const activeModules = this._addressModules.get(index);
|
|
28937
29331
|
this._payments = activeModules.payments;
|
|
28938
29332
|
this._communications = activeModules.communications;
|
|
@@ -28970,35 +29364,10 @@ var Sphere = class _Sphere {
|
|
|
28970
29364
|
}
|
|
28971
29365
|
if (newNametag) {
|
|
28972
29366
|
await this.persistAddressNametags();
|
|
28973
|
-
if (!this._payments.hasNametag()) {
|
|
28974
|
-
logger.debug("Sphere", `Minting nametag token for @${newNametag}...`);
|
|
28975
|
-
try {
|
|
28976
|
-
const result = await this.mintNametag(newNametag);
|
|
28977
|
-
if (result.success) {
|
|
28978
|
-
logger.debug("Sphere", `Nametag token minted successfully`);
|
|
28979
|
-
} else {
|
|
28980
|
-
logger.warn("Sphere", `Could not mint nametag token: ${result.error}`);
|
|
28981
|
-
}
|
|
28982
|
-
} catch (err) {
|
|
28983
|
-
logger.warn("Sphere", `Nametag token mint failed:`, err);
|
|
28984
|
-
}
|
|
28985
|
-
}
|
|
28986
29367
|
this.emitEvent("nametag:registered", {
|
|
28987
29368
|
nametag: newNametag,
|
|
28988
29369
|
addressIndex: index
|
|
28989
29370
|
});
|
|
28990
|
-
} else if (this._identity?.nametag && !this._payments.hasNametag()) {
|
|
28991
|
-
logger.debug("Sphere", `Unicity ID @${this._identity.nametag} has no token after switch, minting...`);
|
|
28992
|
-
try {
|
|
28993
|
-
const result = await this.mintNametag(this._identity.nametag);
|
|
28994
|
-
if (result.success) {
|
|
28995
|
-
logger.debug("Sphere", `Nametag token minted successfully after switch`);
|
|
28996
|
-
} else {
|
|
28997
|
-
logger.warn("Sphere", `Could not mint nametag token after switch: ${result.error}`);
|
|
28998
|
-
}
|
|
28999
|
-
} catch (err) {
|
|
29000
|
-
logger.warn("Sphere", `Nametag token mint failed after switch:`, err);
|
|
29001
|
-
}
|
|
29002
29371
|
}
|
|
29003
29372
|
}
|
|
29004
29373
|
/**
|
|
@@ -29028,6 +29397,7 @@ var Sphere = class _Sphere {
|
|
|
29028
29397
|
const communications = createCommunicationsModule(this._communicationsConfig);
|
|
29029
29398
|
const groupChat = this._groupChatConfig ? createGroupChatModule(this._groupChatConfig) : null;
|
|
29030
29399
|
const market = this._marketConfig ? createMarketModule(this._marketConfig) : null;
|
|
29400
|
+
const tokenEngine = await this.buildTokenEngine(identity);
|
|
29031
29401
|
payments.initialize({
|
|
29032
29402
|
identity,
|
|
29033
29403
|
storage: this._storage,
|
|
@@ -29036,7 +29406,8 @@ var Sphere = class _Sphere {
|
|
|
29036
29406
|
oracle: this._oracle,
|
|
29037
29407
|
emitEvent,
|
|
29038
29408
|
chainCode: this._masterKey?.chainCode || void 0,
|
|
29039
|
-
price: this._priceProvider ?? void 0
|
|
29409
|
+
price: this._priceProvider ?? void 0,
|
|
29410
|
+
tokenEngine
|
|
29040
29411
|
});
|
|
29041
29412
|
communications.initialize({
|
|
29042
29413
|
identity,
|
|
@@ -29072,7 +29443,8 @@ var Sphere = class _Sphere {
|
|
|
29072
29443
|
emitEvent,
|
|
29073
29444
|
on: this.on.bind(this),
|
|
29074
29445
|
storage: this._storage,
|
|
29075
|
-
communications
|
|
29446
|
+
communications,
|
|
29447
|
+
tokenEngine
|
|
29076
29448
|
});
|
|
29077
29449
|
} else {
|
|
29078
29450
|
logger.warn("Sphere", "Accounting module enabled but no token storage available \u2014 disabling");
|
|
@@ -29132,6 +29504,7 @@ var Sphere = class _Sphere {
|
|
|
29132
29504
|
market,
|
|
29133
29505
|
transportAdapter: adapter,
|
|
29134
29506
|
tokenStorageProviders: new Map(tokenStorageProviders),
|
|
29507
|
+
tokenEngine,
|
|
29135
29508
|
initialized: true
|
|
29136
29509
|
};
|
|
29137
29510
|
this._addressModules.set(index, moduleSet);
|
|
@@ -29687,15 +30060,6 @@ var Sphere = class _Sphere {
|
|
|
29687
30060
|
hasNametag() {
|
|
29688
30061
|
return !!this._identity?.nametag;
|
|
29689
30062
|
}
|
|
29690
|
-
/**
|
|
29691
|
-
* Get the PROXY address for the current nametag
|
|
29692
|
-
* PROXY addresses are derived from the nametag hash and require
|
|
29693
|
-
* the nametag token to claim funds sent to them
|
|
29694
|
-
* @returns PROXY address string or undefined if no nametag
|
|
29695
|
-
*/
|
|
29696
|
-
getProxyAddress() {
|
|
29697
|
-
return this._cachedProxyAddress;
|
|
29698
|
-
}
|
|
29699
30063
|
/**
|
|
29700
30064
|
* Resolve any identifier to full peer information.
|
|
29701
30065
|
* Accepts @nametag, bare nametag, DIRECT://, PROXY://, L1 address, or transport pubkey.
|
|
@@ -29730,17 +30094,6 @@ var Sphere = class _Sphere {
|
|
|
29730
30094
|
throw new SphereError(`Cannot resolve address: ${address.slice(0, 30)}`, "INVALID_RECIPIENT");
|
|
29731
30095
|
}
|
|
29732
30096
|
}
|
|
29733
|
-
/** Compute and cache the PROXY address from the current nametag */
|
|
29734
|
-
async _updateCachedProxyAddress() {
|
|
29735
|
-
const nametag = this._identity?.nametag;
|
|
29736
|
-
if (!nametag) {
|
|
29737
|
-
this._cachedProxyAddress = void 0;
|
|
29738
|
-
return;
|
|
29739
|
-
}
|
|
29740
|
-
const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
|
|
29741
|
-
const proxyAddr = await ProxyAddress.fromNameTag(nametag);
|
|
29742
|
-
this._cachedProxyAddress = proxyAddr.toString();
|
|
29743
|
-
}
|
|
29744
30097
|
/**
|
|
29745
30098
|
* Register a nametag for the current active address
|
|
29746
30099
|
* Each address can have its own independent nametag
|
|
@@ -29768,17 +30121,6 @@ var Sphere = class _Sphere {
|
|
|
29768
30121
|
if (this._identity?.nametag) {
|
|
29769
30122
|
throw new SphereError(`Unicity ID already registered for address ${this._currentAddressIndex}: @${this._identity.nametag}`, "ALREADY_INITIALIZED");
|
|
29770
30123
|
}
|
|
29771
|
-
if (!this._payments.hasNametag()) {
|
|
29772
|
-
logger.debug("Sphere", `Minting nametag token for @${cleanNametag}...`);
|
|
29773
|
-
const result = await this.mintNametag(cleanNametag);
|
|
29774
|
-
if (!result.success) {
|
|
29775
|
-
throw new SphereError(
|
|
29776
|
-
`Failed to mint nametag token: ${result.error}`,
|
|
29777
|
-
"AGGREGATOR_ERROR"
|
|
29778
|
-
);
|
|
29779
|
-
}
|
|
29780
|
-
logger.debug("Sphere", `Nametag token minted successfully`);
|
|
29781
|
-
}
|
|
29782
30124
|
if (this._transport.publishIdentityBinding) {
|
|
29783
30125
|
const success = await this._transport.publishIdentityBinding(
|
|
29784
30126
|
this._identity.chainPubkey,
|
|
@@ -29791,7 +30133,6 @@ var Sphere = class _Sphere {
|
|
|
29791
30133
|
}
|
|
29792
30134
|
}
|
|
29793
30135
|
this._identity.nametag = cleanNametag;
|
|
29794
|
-
await this._updateCachedProxyAddress();
|
|
29795
30136
|
const currentAddressId = this._trackedAddresses.get(this._currentAddressIndex)?.addressId;
|
|
29796
30137
|
if (currentAddressId) {
|
|
29797
30138
|
let nametags = this._addressNametags.get(currentAddressId);
|
|
@@ -29824,35 +30165,19 @@ var Sphere = class _Sphere {
|
|
|
29824
30165
|
await this._storage.saveTrackedAddresses(entries);
|
|
29825
30166
|
}
|
|
29826
30167
|
/**
|
|
29827
|
-
*
|
|
29828
|
-
* This creates the nametag token required for receiving tokens via PROXY addresses (@nametag)
|
|
30168
|
+
* Check whether a nametag is available to register.
|
|
29829
30169
|
*
|
|
29830
|
-
*
|
|
29831
|
-
*
|
|
30170
|
+
* D5: nametags are Nostr bindings (name ↔ chainPubkey), not on-chain tokens. Availability is
|
|
30171
|
+
* first-seen-wins — a name is available iff no binding resolves for it.
|
|
29832
30172
|
*
|
|
29833
|
-
* @example
|
|
29834
|
-
* ```typescript
|
|
29835
|
-
* // Mint nametag token for receiving via @alice
|
|
29836
|
-
* const result = await sphere.mintNametag('alice');
|
|
29837
|
-
* if (result.success) {
|
|
29838
|
-
* console.log('Nametag minted:', result.nametagData?.name);
|
|
29839
|
-
* } else {
|
|
29840
|
-
* console.error('Mint failed:', result.error);
|
|
29841
|
-
* }
|
|
29842
|
-
* ```
|
|
29843
|
-
*/
|
|
29844
|
-
async mintNametag(nametag) {
|
|
29845
|
-
this.ensureReady();
|
|
29846
|
-
return this._payments.mintNametag(nametag);
|
|
29847
|
-
}
|
|
29848
|
-
/**
|
|
29849
|
-
* Check if a nametag is available for minting
|
|
29850
30173
|
* @param nametag - The nametag to check (e.g., "alice" or "@alice")
|
|
29851
|
-
* @returns true if available, false if taken
|
|
30174
|
+
* @returns true if available, false if already taken
|
|
29852
30175
|
*/
|
|
29853
30176
|
async isNametagAvailable(nametag) {
|
|
29854
30177
|
this.ensureReady();
|
|
29855
|
-
|
|
30178
|
+
if (!this._transport.resolveNametag) return true;
|
|
30179
|
+
const bound = await this._transport.resolveNametag(this.cleanNametag(nametag));
|
|
30180
|
+
return bound == null;
|
|
29856
30181
|
}
|
|
29857
30182
|
/**
|
|
29858
30183
|
* Load tracked addresses from storage.
|
|
@@ -30027,7 +30352,6 @@ var Sphere = class _Sphere {
|
|
|
30027
30352
|
}
|
|
30028
30353
|
if (recoveredNametag && !this._identity?.nametag) {
|
|
30029
30354
|
this._identity.nametag = recoveredNametag;
|
|
30030
|
-
await this._updateCachedProxyAddress();
|
|
30031
30355
|
const entry = await this.ensureAddressTracked(this._currentAddressIndex);
|
|
30032
30356
|
let nametags = this._addressNametags.get(entry.addressId);
|
|
30033
30357
|
if (!nametags) {
|
|
@@ -30116,7 +30440,6 @@ var Sphere = class _Sphere {
|
|
|
30116
30440
|
try {
|
|
30117
30441
|
if (this._identity) {
|
|
30118
30442
|
this._identity.nametag = recoveredNametag;
|
|
30119
|
-
await this._updateCachedProxyAddress();
|
|
30120
30443
|
}
|
|
30121
30444
|
const entry = await this.ensureAddressTracked(this._currentAddressIndex);
|
|
30122
30445
|
let nametags = this._addressNametags.get(entry.addressId);
|
|
@@ -30136,7 +30459,7 @@ var Sphere = class _Sphere {
|
|
|
30136
30459
|
*/
|
|
30137
30460
|
cleanNametag(raw) {
|
|
30138
30461
|
const stripped = raw.startsWith("@") ? raw.slice(1) : raw;
|
|
30139
|
-
return (0,
|
|
30462
|
+
return (0, import_nostr_js_sdk4.normalizeNametag)(stripped);
|
|
30140
30463
|
}
|
|
30141
30464
|
// ===========================================================================
|
|
30142
30465
|
// Public Methods - Lifecycle
|
|
@@ -30316,7 +30639,6 @@ var Sphere = class _Sphere {
|
|
|
30316
30639
|
} else if (this._identity && nametag) {
|
|
30317
30640
|
this._identity.nametag = nametag;
|
|
30318
30641
|
}
|
|
30319
|
-
await this._updateCachedProxyAddress();
|
|
30320
30642
|
}
|
|
30321
30643
|
async initializeIdentityFromMnemonic(mnemonic, derivationPath) {
|
|
30322
30644
|
const basePath = derivationPath ?? DEFAULT_BASE_PATH;
|
|
@@ -30467,10 +30789,45 @@ var Sphere = class _Sphere {
|
|
|
30467
30789
|
this._providerEventCleanups = [];
|
|
30468
30790
|
this._lastProviderConnected.clear();
|
|
30469
30791
|
}
|
|
30792
|
+
/**
|
|
30793
|
+
* Construct the v2 token engine for a given address identity (defaults to the
|
|
30794
|
+
* active one) from the oracle's gateway URL + trust base and that address's
|
|
30795
|
+
* signing key. The engine is per-address — each address signs with its own key.
|
|
30796
|
+
* The trust base is the single source of truth for the network id (so any id
|
|
30797
|
+
* works — e.g. testnet2 = 4 — with no enum entry). Returns undefined (modules
|
|
30798
|
+
* keep their legacy path) when the oracle can't supply a trust base / url, or
|
|
30799
|
+
* construction fails — a misconfigured oracle never breaks initialization.
|
|
30800
|
+
*/
|
|
30801
|
+
async buildTokenEngine(identity) {
|
|
30802
|
+
const oracle = this._oracle;
|
|
30803
|
+
const privateKey = (identity ?? this._identity)?.privateKey;
|
|
30804
|
+
const trustBaseJson = oracle.getTrustBaseJson?.() ?? null;
|
|
30805
|
+
const aggregatorUrl = oracle.getAggregatorUrl?.();
|
|
30806
|
+
if (!trustBaseJson || !aggregatorUrl || !privateKey) {
|
|
30807
|
+
logger.warn("Sphere", "v2 token engine not constructed (oracle has no trust base / url, or no identity) \u2014 legacy path");
|
|
30808
|
+
return void 0;
|
|
30809
|
+
}
|
|
30810
|
+
try {
|
|
30811
|
+
return await createSphereTokenEngine({
|
|
30812
|
+
aggregatorUrl,
|
|
30813
|
+
apiKey: oracle.getApiKey?.(),
|
|
30814
|
+
privateKey: hexToBytes2(privateKey),
|
|
30815
|
+
trustBaseJson
|
|
30816
|
+
});
|
|
30817
|
+
} catch (err) {
|
|
30818
|
+
logger.warn(
|
|
30819
|
+
"Sphere",
|
|
30820
|
+
`Failed to construct v2 token engine \u2014 modules use the legacy path: ${err instanceof Error ? err.message : String(err)}`
|
|
30821
|
+
);
|
|
30822
|
+
return void 0;
|
|
30823
|
+
}
|
|
30824
|
+
}
|
|
30470
30825
|
async initializeModules() {
|
|
30471
30826
|
const emitEvent = this.emitEvent.bind(this);
|
|
30472
30827
|
const adapter = await this.ensureTransportMux(this._currentAddressIndex, this._identity);
|
|
30473
30828
|
const moduleTransport = adapter ?? this._transport;
|
|
30829
|
+
this._tokenEngine = await this.buildTokenEngine();
|
|
30830
|
+
const tokenEngine = this._tokenEngine;
|
|
30474
30831
|
this._payments.initialize({
|
|
30475
30832
|
identity: this._identity,
|
|
30476
30833
|
storage: this._storage,
|
|
@@ -30481,7 +30838,8 @@ var Sphere = class _Sphere {
|
|
|
30481
30838
|
// Pass chain code for L1 HD derivation
|
|
30482
30839
|
chainCode: this._masterKey?.chainCode || void 0,
|
|
30483
30840
|
price: this._priceProvider ?? void 0,
|
|
30484
|
-
disabledProviderIds: this._disabledProviders
|
|
30841
|
+
disabledProviderIds: this._disabledProviders,
|
|
30842
|
+
tokenEngine
|
|
30485
30843
|
});
|
|
30486
30844
|
this._communications.initialize({
|
|
30487
30845
|
identity: this._identity,
|
|
@@ -30517,7 +30875,8 @@ var Sphere = class _Sphere {
|
|
|
30517
30875
|
emitEvent,
|
|
30518
30876
|
on: this.on.bind(this),
|
|
30519
30877
|
storage: this._storage,
|
|
30520
|
-
communications: this._communications
|
|
30878
|
+
communications: this._communications,
|
|
30879
|
+
tokenEngine
|
|
30521
30880
|
});
|
|
30522
30881
|
} else {
|
|
30523
30882
|
logger.warn("Sphere", "Accounting module enabled but no token storage available \u2014 disabling");
|
|
@@ -30579,6 +30938,7 @@ var Sphere = class _Sphere {
|
|
|
30579
30938
|
market: this._market,
|
|
30580
30939
|
transportAdapter: adapter,
|
|
30581
30940
|
tokenStorageProviders: new Map(this._tokenStorageProviders),
|
|
30941
|
+
tokenEngine: this._tokenEngine,
|
|
30582
30942
|
initialized: true
|
|
30583
30943
|
});
|
|
30584
30944
|
}
|