@unicitylabs/sphere-sdk 0.13.2 → 0.13.3-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -10351,17 +10351,9 @@ function decryptDeliveryBundle(key, envelope) {
10351
10351
  }
10352
10352
 
10353
10353
  // types/txf.ts
10354
- var ARCHIVED_PREFIX = "archived-";
10355
- var FORKED_PREFIX = "_forked_";
10356
10354
  var RESERVED_KEYS = ["_meta", "_nametag", "_nametags", "_tombstones", "_invalidatedNametags", "_outbox", "_mintOutbox", "_sent", "_invalid", "_integrity", "_history"];
10357
10355
  function isTokenKey(key) {
10358
- return key.startsWith("_") && !key.startsWith(ARCHIVED_PREFIX) && !key.startsWith(FORKED_PREFIX) && !RESERVED_KEYS.includes(key);
10359
- }
10360
- function isArchivedKey(key) {
10361
- return key.startsWith(ARCHIVED_PREFIX);
10362
- }
10363
- function isForkedKey(key) {
10364
- return key.startsWith(FORKED_PREFIX);
10356
+ return key.startsWith("_") && !RESERVED_KEYS.includes(key);
10365
10357
  }
10366
10358
  function tokenIdFromKey(key) {
10367
10359
  return key.startsWith("_") ? key.substring(1) : key;
@@ -10369,27 +10361,112 @@ function tokenIdFromKey(key) {
10369
10361
  function keyFromTokenId(tokenId) {
10370
10362
  return `_${tokenId}`;
10371
10363
  }
10372
- function tokenIdFromArchivedKey(key) {
10373
- return key.startsWith(ARCHIVED_PREFIX) ? key.substring(ARCHIVED_PREFIX.length) : key;
10364
+ function isValidTokenId(tokenId) {
10365
+ return /^[0-9a-fA-F]{64}$/.test(tokenId);
10374
10366
  }
10375
- function archivedKeyFromTokenId(tokenId) {
10376
- return `${ARCHIVED_PREFIX}${tokenId}`;
10367
+
10368
+ // serialization/txf-serializer.ts
10369
+ function isV2TokenBlob(sdkData) {
10370
+ return typeof sdkData === "string" && sdkData.length >= 2 && sdkData.length % 2 === 0 && sdkData[0] !== "{" && /^[0-9a-f]+$/i.test(sdkData);
10377
10371
  }
10378
- function forkedKeyFromTokenIdAndState(tokenId, stateHash) {
10379
- return `${FORKED_PREFIX}${tokenId}_${stateHash}`;
10372
+ function v2TokenId(token) {
10373
+ return token.id.startsWith("v2_") ? token.id.slice(3) : token.id;
10380
10374
  }
10381
- function parseForkedKey(key) {
10382
- if (!key.startsWith(FORKED_PREFIX)) return null;
10383
- const remainder = key.substring(FORKED_PREFIX.length);
10384
- const underscoreIndex = remainder.indexOf("_");
10385
- if (underscoreIndex === -1 || underscoreIndex < 64) return null;
10386
- return {
10387
- tokenId: remainder.substring(0, underscoreIndex),
10388
- stateHash: remainder.substring(underscoreIndex + 1)
10375
+ function isV2TokenEntry(entry) {
10376
+ return typeof entry === "object" && entry !== null && !("genesis" in entry) && isV2TokenBlob(entry.sdkData);
10377
+ }
10378
+ async function buildTxfStorageData(tokens, meta, options) {
10379
+ const storageData = {
10380
+ _meta: {
10381
+ ...meta,
10382
+ formatVersion: "2.0"
10383
+ }
10389
10384
  };
10385
+ if (options?.nametags && options.nametags.length > 0) {
10386
+ storageData._nametags = options.nametags;
10387
+ }
10388
+ if (options?.tombstones && options.tombstones.length > 0) {
10389
+ storageData._tombstones = options.tombstones;
10390
+ }
10391
+ if (options?.historyEntries && options.historyEntries.length > 0) {
10392
+ storageData._history = options.historyEntries;
10393
+ }
10394
+ for (const token of tokens) {
10395
+ if (isV2TokenBlob(token.sdkData)) {
10396
+ storageData[keyFromTokenId(v2TokenId(token))] = token;
10397
+ } else {
10398
+ logger.warn(
10399
+ "TXF",
10400
+ `Refusing to persist token ${token.id.slice(0, 16)}...: sdkData is not a v2 token blob \u2014 entry skipped`
10401
+ );
10402
+ }
10403
+ }
10404
+ return storageData;
10390
10405
  }
10391
- function isValidTokenId(tokenId) {
10392
- return /^[0-9a-fA-F]{64}$/.test(tokenId);
10406
+ function parseTxfStorageData(data) {
10407
+ const result = {
10408
+ tokens: [],
10409
+ meta: null,
10410
+ nametags: [],
10411
+ tombstones: [],
10412
+ historyEntries: [],
10413
+ validationErrors: []
10414
+ };
10415
+ if (!data || typeof data !== "object") {
10416
+ result.validationErrors.push("Storage data is not an object");
10417
+ return result;
10418
+ }
10419
+ const storageData = data;
10420
+ if (storageData._meta && typeof storageData._meta === "object") {
10421
+ result.meta = storageData._meta;
10422
+ }
10423
+ const seenNames = /* @__PURE__ */ new Set();
10424
+ if (Array.isArray(storageData._nametags)) {
10425
+ for (const entry of storageData._nametags) {
10426
+ if (entry && typeof entry === "object" && typeof entry.name === "string") {
10427
+ result.nametags.push(entry);
10428
+ seenNames.add(entry.name);
10429
+ }
10430
+ }
10431
+ }
10432
+ if (storageData._nametag && typeof storageData._nametag === "object") {
10433
+ const legacy = storageData._nametag;
10434
+ if (typeof legacy.name === "string" && !seenNames.has(legacy.name)) {
10435
+ result.nametags.push(legacy);
10436
+ }
10437
+ }
10438
+ if (storageData._tombstones && Array.isArray(storageData._tombstones)) {
10439
+ for (const entry of storageData._tombstones) {
10440
+ if (typeof entry === "object" && entry !== null && typeof entry.tokenId === "string" && typeof entry.stateHash === "string" && typeof entry.timestamp === "number") {
10441
+ result.tombstones.push(entry);
10442
+ }
10443
+ }
10444
+ }
10445
+ if (Array.isArray(storageData._history)) {
10446
+ for (const entry of storageData._history) {
10447
+ if (typeof entry === "object" && entry !== null && typeof entry.dedupKey === "string" && typeof entry.type === "string") {
10448
+ result.historyEntries.push(entry);
10449
+ }
10450
+ }
10451
+ }
10452
+ for (const key of Object.keys(storageData)) {
10453
+ if (isTokenKey(key)) {
10454
+ const tokenId = tokenIdFromKey(key);
10455
+ const entry = storageData[key];
10456
+ if (isV2TokenEntry(entry)) {
10457
+ result.tokens.push(entry);
10458
+ } else {
10459
+ const msg = `Token ${tokenId}: unrecognized storage entry (not a v2 token blob) \u2014 entry skipped`;
10460
+ logger.warn("TXF", msg);
10461
+ result.validationErrors.push(msg);
10462
+ }
10463
+ } else if (key.startsWith("token-")) {
10464
+ const msg = `Token ${key}: sdkData is not a v2 token blob \u2014 entry skipped`;
10465
+ logger.warn("TXF", msg);
10466
+ result.validationErrors.push(msg);
10467
+ }
10468
+ }
10469
+ return result;
10393
10470
  }
10394
10471
 
10395
10472
  // registry/TokenRegistry.ts
@@ -10830,403 +10907,14 @@ function getCoinIdByName(name) {
10830
10907
  }
10831
10908
  function normalizeCoinId(coinId) {
10832
10909
  if (coinId.length <= 20 && /^[A-Za-z0-9]+$/.test(coinId)) {
10833
- const resolved = getCoinIdBySymbol(coinId);
10834
- if (resolved) return resolved;
10835
- }
10836
- return coinId;
10837
- }
10838
- function coinIdsMatch(a, b) {
10839
- if (a === b) return true;
10840
- return normalizeCoinId(a) === normalizeCoinId(b);
10841
- }
10842
-
10843
- // serialization/txf-serializer.ts
10844
- function bytesToHex5(bytes) {
10845
- const arr = Array.isArray(bytes) ? bytes : Array.from(bytes);
10846
- return arr.map((b) => b.toString(16).padStart(2, "0")).join("");
10847
- }
10848
- function normalizeToHex(value) {
10849
- if (typeof value === "string") {
10850
- return value;
10851
- }
10852
- if (value && typeof value === "object") {
10853
- const obj = value;
10854
- if ("bytes" in obj && (Array.isArray(obj.bytes) || obj.bytes instanceof Uint8Array)) {
10855
- return bytesToHex5(obj.bytes);
10856
- }
10857
- if (obj.type === "Buffer" && Array.isArray(obj.data)) {
10858
- return bytesToHex5(obj.data);
10859
- }
10860
- }
10861
- return String(value);
10862
- }
10863
- function normalizeSdkTokenToStorage(sdkTokenJson) {
10864
- const txf = structuredClone(sdkTokenJson);
10865
- if (txf.genesis?.data) {
10866
- const data = txf.genesis.data;
10867
- if (data.tokenId !== void 0) {
10868
- data.tokenId = normalizeToHex(data.tokenId);
10869
- }
10870
- if (data.tokenType !== void 0) {
10871
- data.tokenType = normalizeToHex(data.tokenType);
10872
- }
10873
- if (data.salt !== void 0) {
10874
- data.salt = normalizeToHex(data.salt);
10875
- }
10876
- }
10877
- if (txf.genesis?.inclusionProof?.authenticator) {
10878
- const auth = txf.genesis.inclusionProof.authenticator;
10879
- if (auth.publicKey !== void 0) {
10880
- auth.publicKey = normalizeToHex(auth.publicKey);
10881
- }
10882
- if (auth.signature !== void 0) {
10883
- auth.signature = normalizeToHex(auth.signature);
10884
- }
10885
- }
10886
- if (Array.isArray(txf.transactions)) {
10887
- for (const tx of txf.transactions) {
10888
- if (tx.inclusionProof?.authenticator) {
10889
- const auth = tx.inclusionProof.authenticator;
10890
- if (auth.publicKey !== void 0) {
10891
- auth.publicKey = normalizeToHex(auth.publicKey);
10892
- }
10893
- if (auth.signature !== void 0) {
10894
- auth.signature = normalizeToHex(auth.signature);
10895
- }
10896
- }
10897
- }
10898
- }
10899
- return txf;
10900
- }
10901
- function tokenToTxf(token) {
10902
- const jsonData = token.sdkData;
10903
- if (!jsonData) {
10904
- return null;
10905
- }
10906
- try {
10907
- const txfData = normalizeSdkTokenToStorage(JSON.parse(jsonData));
10908
- if (!txfData.genesis || !txfData.state) {
10909
- return null;
10910
- }
10911
- if (!txfData.version) {
10912
- txfData.version = "2.0";
10913
- }
10914
- if (!txfData.transactions) {
10915
- txfData.transactions = [];
10916
- }
10917
- if (!txfData.nametags) {
10918
- txfData.nametags = [];
10919
- }
10920
- if (!txfData._integrity) {
10921
- txfData._integrity = {
10922
- genesisDataJSONHash: "0000" + "0".repeat(60)
10923
- };
10924
- }
10925
- return txfData;
10926
- } catch {
10927
- return null;
10928
- }
10929
- }
10930
- function objectToTxf(obj) {
10931
- if (!obj.sdkData) return null;
10932
- try {
10933
- const txfData = normalizeSdkTokenToStorage(JSON.parse(obj.sdkData));
10934
- if (!txfData.genesis || !txfData.state) return null;
10935
- return txfData;
10936
- } catch {
10937
- return null;
10938
- }
10939
- }
10940
- function determineTokenStatus(txf) {
10941
- if (txf.transactions.length > 0) {
10942
- const lastTx = txf.transactions[txf.transactions.length - 1];
10943
- if (lastTx.inclusionProof === null) {
10944
- return "pending";
10945
- }
10946
- }
10947
- return "confirmed";
10948
- }
10949
- function txfToToken(tokenId, txf) {
10950
- const coinData = txf.genesis.data.coinData;
10951
- const totalAmount = coinData.reduce((sum, [, amt]) => {
10952
- return sum + BigInt(amt || "0");
10953
- }, BigInt(0));
10954
- let coinId = coinData[0]?.[0] || "";
10955
- for (const [cid, amt] of coinData) {
10956
- if (BigInt(amt || "0") > 0) {
10957
- coinId = cid;
10958
- break;
10959
- }
10960
- }
10961
- const tokenType = txf.genesis.data.tokenType;
10962
- const isNft = tokenType === "455ad8720656b08e8dbd5bac1f3c73eeea5431565f6c1c3af742b1aa12d41d89";
10963
- const now = Date.now();
10964
- const registry = TokenRegistry.getInstance();
10965
- const def = registry.getDefinition(coinId);
10966
- return {
10967
- id: tokenId,
10968
- coinId,
10969
- symbol: isNft ? "NFT" : def?.symbol || coinId.slice(0, 8),
10970
- name: isNft ? "NFT" : def?.name ? def.name.charAt(0).toUpperCase() + def.name.slice(1) : "Token",
10971
- decimals: isNft ? 0 : def?.decimals ?? 8,
10972
- amount: totalAmount.toString(),
10973
- status: determineTokenStatus(txf),
10974
- createdAt: now,
10975
- updatedAt: now,
10976
- sdkData: JSON.stringify(txf)
10977
- };
10978
- }
10979
- function isV2TokenBlob(sdkData) {
10980
- return typeof sdkData === "string" && sdkData.length >= 2 && sdkData.length % 2 === 0 && sdkData[0] !== "{" && /^[0-9a-f]+$/i.test(sdkData);
10981
- }
10982
- function v2TokenId(token) {
10983
- return token.id.startsWith("v2_") ? token.id.slice(3) : token.id;
10984
- }
10985
- function isV2TokenEntry(entry) {
10986
- return typeof entry === "object" && entry !== null && !("genesis" in entry) && isV2TokenBlob(entry.sdkData);
10987
- }
10988
- async function buildTxfStorageData(tokens, meta, options) {
10989
- const storageData = {
10990
- _meta: {
10991
- ...meta,
10992
- formatVersion: "2.0"
10993
- }
10994
- };
10995
- if (options?.nametags && options.nametags.length > 0) {
10996
- storageData._nametags = options.nametags;
10997
- }
10998
- if (options?.tombstones && options.tombstones.length > 0) {
10999
- storageData._tombstones = options.tombstones;
11000
- }
11001
- if (options?.outboxEntries && options.outboxEntries.length > 0) {
11002
- storageData._outbox = options.outboxEntries;
11003
- }
11004
- if (options?.mintOutboxEntries && options.mintOutboxEntries.length > 0) {
11005
- storageData._mintOutbox = options.mintOutboxEntries;
11006
- }
11007
- if (options?.invalidatedNametags && options.invalidatedNametags.length > 0) {
11008
- storageData._invalidatedNametags = options.invalidatedNametags;
11009
- }
11010
- if (options?.historyEntries && options.historyEntries.length > 0) {
11011
- storageData._history = options.historyEntries;
11012
- }
11013
- for (const token of tokens) {
11014
- const txf = tokenToTxf(token);
11015
- if (txf) {
11016
- const actualTokenId = txf.genesis.data.tokenId;
11017
- storageData[keyFromTokenId(actualTokenId)] = txf;
11018
- } else if (isV2TokenBlob(token.sdkData)) {
11019
- storageData[keyFromTokenId(v2TokenId(token))] = token;
11020
- }
11021
- }
11022
- if (options?.archivedTokens && options.archivedTokens.size > 0) {
11023
- for (const [tokenId, txf] of options.archivedTokens) {
11024
- storageData[archivedKeyFromTokenId(tokenId)] = txf;
11025
- }
11026
- }
11027
- if (options?.forkedTokens && options.forkedTokens.size > 0) {
11028
- for (const [key, txf] of options.forkedTokens) {
11029
- const [tokenId, stateHash] = key.split("_");
11030
- if (tokenId && stateHash) {
11031
- storageData[forkedKeyFromTokenIdAndState(tokenId, stateHash)] = txf;
11032
- }
11033
- }
11034
- }
11035
- return storageData;
11036
- }
11037
- function parseTxfStorageData(data) {
11038
- const result = {
11039
- tokens: [],
11040
- meta: null,
11041
- nametags: [],
11042
- tombstones: [],
11043
- archivedTokens: /* @__PURE__ */ new Map(),
11044
- forkedTokens: /* @__PURE__ */ new Map(),
11045
- outboxEntries: [],
11046
- mintOutboxEntries: [],
11047
- invalidatedNametags: [],
11048
- historyEntries: [],
11049
- validationErrors: []
11050
- };
11051
- if (!data || typeof data !== "object") {
11052
- result.validationErrors.push("Storage data is not an object");
11053
- return result;
11054
- }
11055
- const storageData = data;
11056
- if (storageData._meta && typeof storageData._meta === "object") {
11057
- result.meta = storageData._meta;
11058
- }
11059
- const seenNames = /* @__PURE__ */ new Set();
11060
- if (Array.isArray(storageData._nametags)) {
11061
- for (const entry of storageData._nametags) {
11062
- if (entry && typeof entry === "object" && typeof entry.name === "string") {
11063
- result.nametags.push(entry);
11064
- seenNames.add(entry.name);
11065
- }
11066
- }
11067
- }
11068
- if (storageData._nametag && typeof storageData._nametag === "object") {
11069
- const legacy = storageData._nametag;
11070
- if (typeof legacy.name === "string" && !seenNames.has(legacy.name)) {
11071
- result.nametags.push(legacy);
11072
- }
11073
- }
11074
- if (storageData._tombstones && Array.isArray(storageData._tombstones)) {
11075
- for (const entry of storageData._tombstones) {
11076
- if (typeof entry === "object" && entry !== null && typeof entry.tokenId === "string" && typeof entry.stateHash === "string" && typeof entry.timestamp === "number") {
11077
- result.tombstones.push(entry);
11078
- }
11079
- }
11080
- }
11081
- if (storageData._outbox && Array.isArray(storageData._outbox)) {
11082
- for (const entry of storageData._outbox) {
11083
- if (typeof entry === "object" && entry !== null && typeof entry.id === "string" && typeof entry.status === "string") {
11084
- result.outboxEntries.push(entry);
11085
- }
11086
- }
11087
- }
11088
- if (storageData._mintOutbox && Array.isArray(storageData._mintOutbox)) {
11089
- for (const entry of storageData._mintOutbox) {
11090
- if (typeof entry === "object" && entry !== null && typeof entry.id === "string" && typeof entry.status === "string") {
11091
- result.mintOutboxEntries.push(entry);
11092
- }
11093
- }
11094
- }
11095
- if (storageData._invalidatedNametags && Array.isArray(storageData._invalidatedNametags)) {
11096
- for (const entry of storageData._invalidatedNametags) {
11097
- if (typeof entry === "object" && entry !== null && typeof entry.name === "string") {
11098
- result.invalidatedNametags.push(entry);
11099
- }
11100
- }
11101
- }
11102
- if (Array.isArray(storageData._history)) {
11103
- for (const entry of storageData._history) {
11104
- if (typeof entry === "object" && entry !== null && typeof entry.dedupKey === "string" && typeof entry.type === "string") {
11105
- result.historyEntries.push(entry);
11106
- }
11107
- }
11108
- }
11109
- for (const key of Object.keys(storageData)) {
11110
- if (isTokenKey(key)) {
11111
- const tokenId = tokenIdFromKey(key);
11112
- try {
11113
- const txfToken = storageData[key];
11114
- if (txfToken?.genesis?.data?.tokenId) {
11115
- const token = txfToToken(tokenId, txfToken);
11116
- result.tokens.push(token);
11117
- } else if (isV2TokenEntry(storageData[key])) {
11118
- result.tokens.push(storageData[key]);
11119
- }
11120
- } catch (err) {
11121
- result.validationErrors.push(`Token ${tokenId}: ${err}`);
11122
- }
11123
- } else if (isArchivedKey(key)) {
11124
- const tokenId = tokenIdFromArchivedKey(key);
11125
- try {
11126
- const txfToken = storageData[key];
11127
- if (txfToken?.genesis?.data?.tokenId) {
11128
- result.archivedTokens.set(tokenId, txfToken);
11129
- }
11130
- } catch {
11131
- result.validationErrors.push(`Archived token ${tokenId}: invalid structure`);
11132
- }
11133
- } else if (isForkedKey(key)) {
11134
- const parsed = parseForkedKey(key);
11135
- if (parsed) {
11136
- try {
11137
- const txfToken = storageData[key];
11138
- if (txfToken?.genesis?.data?.tokenId) {
11139
- const mapKey = `${parsed.tokenId}_${parsed.stateHash}`;
11140
- result.forkedTokens.set(mapKey, txfToken);
11141
- }
11142
- } catch {
11143
- result.validationErrors.push(`Forked token ${parsed.tokenId}: invalid structure`);
11144
- }
11145
- }
11146
- } else if (key.startsWith("token-")) {
11147
- try {
11148
- const entry = storageData[key];
11149
- const txfToken = entry?.token;
11150
- if (txfToken?.genesis?.data?.tokenId) {
11151
- const tokenId = txfToken.genesis.data.tokenId;
11152
- const token = txfToToken(tokenId, txfToken);
11153
- result.tokens.push(token);
11154
- }
11155
- } catch (err) {
11156
- result.validationErrors.push(`Token ${key}: ${err}`);
11157
- }
11158
- }
11159
- }
11160
- return result;
11161
- }
11162
- function getTokenId(token) {
11163
- if (token.sdkData) {
11164
- try {
11165
- const txf = JSON.parse(token.sdkData);
11166
- if (txf.genesis?.data?.tokenId) {
11167
- return txf.genesis.data.tokenId;
11168
- }
11169
- } catch {
11170
- }
11171
- }
11172
- return token.id;
11173
- }
11174
- function getCurrentStateHash(txf) {
11175
- if (txf.transactions && txf.transactions.length > 0) {
11176
- const lastTx = txf.transactions[txf.transactions.length - 1];
11177
- if (lastTx?.newStateHash) {
11178
- return lastTx.newStateHash;
11179
- }
11180
- if (lastTx?.inclusionProof?.authenticator?.stateHash) {
11181
- return lastTx.inclusionProof.authenticator.stateHash;
11182
- }
11183
- }
11184
- if (txf._integrity?.currentStateHash) {
11185
- return txf._integrity.currentStateHash;
11186
- }
11187
- if (txf.genesis?.inclusionProof?.authenticator?.stateHash) {
11188
- return txf.genesis.inclusionProof.authenticator.stateHash;
11189
- }
11190
- return void 0;
11191
- }
11192
- function hasValidTxfData(token) {
11193
- if (!token.sdkData) return false;
11194
- try {
11195
- const txf = JSON.parse(token.sdkData);
11196
- return !!(txf.genesis && txf.genesis.data && txf.genesis.data.tokenId && txf.state && txf.genesis.inclusionProof);
11197
- } catch {
11198
- return false;
11199
- }
11200
- }
11201
- function hasUncommittedTransactions(token) {
11202
- if (!token.sdkData) return false;
11203
- try {
11204
- const txf = JSON.parse(token.sdkData);
11205
- if (!txf.transactions || txf.transactions.length === 0) return false;
11206
- return txf.transactions.some(
11207
- (tx) => tx.inclusionProof === null
11208
- );
11209
- } catch {
11210
- return false;
11211
- }
11212
- }
11213
- function hasMissingNewStateHash(txf) {
11214
- if (!txf.transactions || txf.transactions.length === 0) {
11215
- return false;
10910
+ const resolved = getCoinIdBySymbol(coinId);
10911
+ if (resolved) return resolved;
11216
10912
  }
11217
- return txf.transactions.some((tx) => !tx.newStateHash);
10913
+ return coinId;
11218
10914
  }
11219
- function countCommittedTransactions(token) {
11220
- if (!token.sdkData) return 0;
11221
- try {
11222
- const txf = JSON.parse(token.sdkData);
11223
- if (!txf.transactions) return 0;
11224
- return txf.transactions.filter(
11225
- (tx) => tx.inclusionProof !== null
11226
- ).length;
11227
- } catch {
11228
- return 0;
11229
- }
10915
+ function coinIdsMatch(a, b) {
10916
+ if (a === b) return true;
10917
+ return normalizeCoinId(a) === normalizeCoinId(b);
11230
10918
  }
11231
10919
 
11232
10920
  // core/utils.ts
@@ -11394,6 +11082,10 @@ function surfacedSendFailure(summary) {
11394
11082
  }
11395
11083
  return primaryError;
11396
11084
  }
11085
+ function currentStateHashOfTxf(txf) {
11086
+ const last = txf.transactions?.[txf.transactions.length - 1];
11087
+ return last?.newStateHash ?? last?.inclusionProof?.authenticator?.stateHash ?? txf._integrity?.currentStateHash ?? txf.genesis?.inclusionProof?.authenticator?.stateHash ?? "";
11088
+ }
11397
11089
  function genesisIdOf(token) {
11398
11090
  return extractTokenIdFromSdkData(token.sdkData) ?? token.id.replace(/^v2_/, "");
11399
11091
  }
@@ -11505,7 +11197,7 @@ function parseSdkDataCached(sdkData) {
11505
11197
  try {
11506
11198
  const txf = JSON.parse(sdkData);
11507
11199
  tokenId = txf.genesis?.data?.tokenId || null;
11508
- stateHash = getCurrentStateHash(txf) || "";
11200
+ stateHash = currentStateHashOfTxf(txf);
11509
11201
  if (!stateHash) {
11510
11202
  if (txf.state?.hash) {
11511
11203
  stateHash = txf.state.hash;
@@ -12251,7 +11943,6 @@ var PaymentsModule = class _PaymentsModule {
12251
11943
  if (op.kind === "direct") {
12252
11944
  finished = await ctx.engine.transfer({ token: op.sdkToken, recipientPubkey: ctx.recipientChainPubkey }, opts);
12253
11945
  } else {
12254
- const checkpointStore = this.getCheckpointStore();
12255
11946
  const { outputs } = await ctx.engine.split(
12256
11947
  {
12257
11948
  token: op.sdkToken,
@@ -12260,7 +11951,7 @@ var PaymentsModule = class _PaymentsModule {
12260
11951
  { recipientPubkey: ctx.selfChainPubkey, coinId: ctx.coinId, amount: op.remainderAmount }
12261
11952
  ]
12262
11953
  },
12263
- { ...opts, ...checkpointStore ? { checkpointStore } : {} }
11954
+ { ...opts, ...ctx.checkpointStore ? { checkpointStore: ctx.checkpointStore } : {} }
12264
11955
  );
12265
11956
  finished = outputs[0];
12266
11957
  changeOutput = outputs[1];
@@ -12447,7 +12138,8 @@ var PaymentsModule = class _PaymentsModule {
12447
12138
  recipientChainPubkeyHex,
12448
12139
  selfChainPubkey: hexToBytes4(this.deps.identity.chainPubkey),
12449
12140
  coinId: request.coinId,
12450
- ...request.memo !== void 0 ? { memo: request.memo } : {}
12141
+ ...request.memo !== void 0 ? { memo: request.memo } : {},
12142
+ ...this.getCheckpointStore() ? { checkpointStore: this.getCheckpointStore() } : {}
12451
12143
  })
12452
12144
  );
12453
12145
  attempt.summary = summary;
@@ -14964,8 +14656,11 @@ var PaymentsModule = class _PaymentsModule {
14964
14656
  try {
14965
14657
  const plain = decryptField(this.getFieldEncryptionKey(), intent.payload);
14966
14658
  payload = JSON.parse(plain);
14967
- if (payload.v !== 1 && payload.v !== 2 || !Array.isArray(payload.direct)) {
14968
- throw new SphereError("Unknown intent payload shape", "VALIDATION_ERROR");
14659
+ if (payload.v !== 2 || !Array.isArray(payload.direct)) {
14660
+ throw new SphereError(
14661
+ `Unsupported intent payload shape (v=${String(payload.v)}) \u2014 not resumable by this wallet version`,
14662
+ "VALIDATION_ERROR"
14663
+ );
14969
14664
  }
14970
14665
  } catch (err) {
14971
14666
  logger.warn("Payments", `Intent ${intent.transferId.slice(0, 8)}\u2026 payload undecodable \u2014 skipped:`, err);
@@ -15104,31 +14799,22 @@ var PaymentsModule = class _PaymentsModule {
15104
14799
  async resumeIntent(transferId, payload) {
15105
14800
  const engine = this.deps.tokenEngine;
15106
14801
  const walletApi = this.deps.walletApi;
15107
- const delivery = this.delivery;
15108
14802
  const provider = this.getActiveTokenStorageProvider();
15109
14803
  if (!provider) throw new SphereError("No token storage provider for intent resume", "STORAGE_ERROR");
15110
- const serverApply = delivery.custody === "inventory";
15111
- const recipientChainPubkey = hexToBytes4(payload.recipient);
15112
- const deliverBlob = async (tokenBlobHex, opIndex) => {
15113
- await this.savePendingV2Delivery({
15114
- transferId,
15115
- recipientPubkey: payload.recipient,
15116
- tokenBlob: tokenBlobHex,
15117
- memo: payload.memo,
15118
- opIndex,
15119
- createdAt: Date.now()
15120
- });
15121
- const nm = this.currentNametagName();
15122
- await this.tryDeliver(
15123
- () => delivery.deliver(payload.recipient, hexToBytes4(tokenBlobHex), {
15124
- transferId,
15125
- memo: payload.memo,
15126
- ...nm !== void 0 ? { senderNametag: nm } : {}
15127
- }),
15128
- tokenBlobHex
15129
- );
14804
+ const serverApply = this.delivery.custody === "inventory";
14805
+ const checkpointStore = this.getCheckpointStore();
14806
+ const ctx = {
14807
+ engine,
14808
+ transferId,
14809
+ recipientChainPubkey: hexToBytes4(payload.recipient),
14810
+ recipientChainPubkeyHex: payload.recipient,
14811
+ selfChainPubkey: hexToBytes4(this.deps.identity.chainPubkey),
14812
+ coinId: payload.coinId,
14813
+ ...payload.memo !== void 0 ? { memo: payload.memo } : {},
14814
+ ...checkpointStore ? { checkpointStore } : {}
15130
14815
  };
15131
14816
  const journaled = await this.journaledByOp(transferId);
14817
+ const blobs = [];
15132
14818
  const spent = [];
15133
14819
  let conflicted = false;
15134
14820
  let firstConflict;
@@ -15136,91 +14822,71 @@ var PaymentsModule = class _PaymentsModule {
15136
14822
  for (const [opIndex, genesisId] of payload.direct.entries()) {
15137
14823
  const existing = journaled.get(opIndex);
15138
14824
  if (existing) {
15139
- await deliverBlob(existing.tokenBlob, opIndex);
14825
+ blobs.push(existing.tokenBlob);
15140
14826
  spent.push(genesisId);
15141
- } else {
15142
- const source = await engine.decodeToken(await provider.getToken(genesisId));
15143
- try {
15144
- const finished = await engine.transfer(
15145
- { token: source, recipientPubkey: recipientChainPubkey },
15146
- // (transferId, opIndex) pairing replayed from the intent's persisted order (§8.1)
15147
- { signal: timeoutSignal(SEND_ENGINE_OP_TIMEOUT_MS), transferId, opIndex }
15148
- );
15149
- await deliverBlob(bytesToHex4(encodeTokenBlob(engine.encodeToken(finished))), opIndex);
15150
- spent.push(genesisId);
15151
- } catch (err) {
15152
- if (!(err instanceof TransferConflictError)) throw err;
15153
- conflicted = true;
15154
- firstConflict ??= err;
15155
- undeliveredAmount += engine.balanceOf(source, payload.coinId);
15156
- logger.warn("Payments", `Resume op ${opIndex} lost its source to a concurrent transfer \u2014 not delivered (\xA78.1/#4):`, err);
15157
- }
14827
+ continue;
14828
+ }
14829
+ const source = await engine.decodeToken(await provider.getToken(genesisId));
14830
+ const outcome = await this.certifyOperation(
14831
+ {
14832
+ kind: "direct",
14833
+ opIndex,
14834
+ uiTokenId: `v2_${genesisId}`,
14835
+ genesisId,
14836
+ sourceSdkData: "",
14837
+ sdkToken: source,
14838
+ deliveredAmount: engine.balanceOf(source, payload.coinId)
14839
+ },
14840
+ ctx
14841
+ );
14842
+ if (outcome.error !== void 0) {
14843
+ if (!(outcome.error instanceof TransferConflictError)) throw outcome.error;
14844
+ conflicted = true;
14845
+ firstConflict ??= outcome.error;
14846
+ undeliveredAmount += engine.balanceOf(source, payload.coinId);
14847
+ logger.warn("Payments", `Resume op ${opIndex} lost its source to a concurrent transfer \u2014 not delivered (\xA78.1/#4):`, outcome.error);
14848
+ continue;
15158
14849
  }
14850
+ blobs.push(outcome.tokenBlob);
14851
+ spent.push(genesisId);
15159
14852
  }
15160
14853
  let changeOutput = null;
15161
14854
  if (payload.split) {
15162
14855
  const splitOpIndex = payload.direct.length;
15163
- const existingSplit = journaled.get(splitOpIndex);
15164
- const checkpointStore = payload.v === 2 ? this.getCheckpointStore() : void 0;
15165
14856
  let splitDelivered = false;
15166
- if (checkpointStore === void 0 && existingSplit) {
15167
- await deliverBlob(existingSplit.tokenBlob, splitOpIndex);
15168
- splitDelivered = true;
15169
- } else {
15170
- try {
15171
- const blob = await provider.getToken(payload.split.tokenId);
15172
- const source = await engine.decodeToken(blob);
15173
- const selfChainPubkey = hexToBytes4(this.deps.identity.chainPubkey);
15174
- const { outputs } = await engine.split(
15175
- {
15176
- token: source,
15177
- outputs: [
15178
- {
15179
- recipientPubkey: recipientChainPubkey,
15180
- coinId: payload.coinId,
15181
- amount: BigInt(payload.split.splitAmount)
15182
- },
15183
- {
15184
- recipientPubkey: selfChainPubkey,
15185
- coinId: payload.coinId,
15186
- amount: BigInt(payload.split.remainderAmount)
15187
- }
15188
- ]
15189
- },
15190
- {
15191
- signal: timeoutSignal(SEND_ENGINE_OP_TIMEOUT_MS),
15192
- transferId,
15193
- opIndex: splitOpIndex,
15194
- ...checkpointStore ? { checkpointStore } : {}
15195
- }
15196
- );
15197
- changeOutput = outputs[1];
15198
- if (!serverApply) await this.storeEngineToken(engine, changeOutput, { criticalSave: true });
15199
- await deliverBlob(bytesToHex4(encodeTokenBlob(engine.encodeToken(outputs[0]))), splitOpIndex);
15200
- splitDelivered = true;
15201
- } catch (err) {
15202
- if (err instanceof ProofUnconfirmedError) throw err;
15203
- if (checkpointStore !== void 0 && (err instanceof CheckpointPersistFailedError || err instanceof SplitCheckpointLostError || err instanceof CheckpointTrustbaseMismatchError)) {
15204
- throw err;
14857
+ {
14858
+ const source = await engine.decodeToken(await provider.getToken(payload.split.tokenId));
14859
+ const outcome = await this.certifyOperation(
14860
+ {
14861
+ kind: "split",
14862
+ opIndex: splitOpIndex,
14863
+ uiTokenId: `v2_${payload.split.tokenId}`,
14864
+ genesisId: payload.split.tokenId,
14865
+ sourceSdkData: "",
14866
+ sdkToken: source,
14867
+ deliveredAmount: BigInt(payload.split.splitAmount),
14868
+ remainderAmount: BigInt(payload.split.remainderAmount)
14869
+ },
14870
+ ctx
14871
+ );
14872
+ if (outcome.error === void 0) {
14873
+ changeOutput = outcome.changeOutput ?? null;
14874
+ if (!serverApply && changeOutput) {
14875
+ await this.storeEngineToken(engine, changeOutput, { criticalSave: true });
15205
14876
  }
15206
- if (err instanceof TransferConflictError) {
14877
+ blobs.push(outcome.tokenBlob);
14878
+ splitDelivered = true;
14879
+ } else {
14880
+ splitDelivered = this.classifyResumeSplitFailure(outcome.error, (err) => {
15207
14881
  conflicted = true;
15208
14882
  firstConflict ??= err;
15209
14883
  undeliveredAmount += BigInt(payload.split.splitAmount);
15210
- logger.warn("Payments", `Resume split: source lost to a concurrent transfer \u2014 not delivered (\xA78.1/#4):`, err);
15211
- } else if (err instanceof SplitCheckpointLostError) {
15212
- logger.warn("Payments", `Resume split (legacy no-checkpoint): recording the spend; change recovers on the next inventory resync (\xA73.1):`, err);
15213
- this.deps.emitEvent("inventory:conflict", { transferId, coinId: payload.coinId, error: err.message });
15214
- splitDelivered = true;
15215
- } else {
15216
- throw err;
15217
- }
14884
+ });
15218
14885
  }
15219
14886
  }
15220
- if (splitDelivered) {
15221
- spent.push(payload.split.tokenId);
15222
- }
14887
+ if (splitDelivered) spent.push(payload.split.tokenId);
15223
14888
  }
14889
+ await this.deliverCommittedBlobs(blobs, payload.recipient, transferId, payload.memo);
15224
14890
  if (conflicted && spent.length === 0) throw firstConflict;
15225
14891
  if (serverApply) {
15226
14892
  await this.applyInventoryDelta(
@@ -15232,6 +14898,55 @@ var PaymentsModule = class _PaymentsModule {
15232
14898
  // the one the sources were read from, captured for the whole resume
15233
14899
  );
15234
14900
  }
14901
+ await this.dropResumedSources(spent, transferId, payload);
14902
+ if (conflicted) {
14903
+ const remaining = undeliveredAmount > 0n ? undeliveredAmount : 0n;
14904
+ const delivered = BigInt(payload.amount) - remaining;
14905
+ await walletApi.completeIntent(transferId);
14906
+ await this.recordResumedSentHistory(payload, transferId, delivered > 0n ? delivered.toString() : "0", spent[0]);
14907
+ this.deps.emitEvent("send:partial-remainder", {
14908
+ transferId,
14909
+ remainingAmount: remaining.toString(),
14910
+ coinId: payload.coinId,
14911
+ recipientPubkey: payload.recipient
14912
+ });
14913
+ throw new PartialSendConflictError(
14914
+ "Resume: part of the payment was delivered before a source was consumed by a concurrent transfer \u2014 the delivered legs are final; re-plan ONLY the remainder.",
14915
+ transferId,
14916
+ spent,
14917
+ // the DELIVERED genesisIds — never the conflicted leg
14918
+ remaining.toString(),
14919
+ firstConflict
14920
+ );
14921
+ }
14922
+ await walletApi.completeIntent(transferId);
14923
+ await this.recordResumedSentHistory(payload, transferId, payload.amount, payload.direct[0]);
14924
+ }
14925
+ /**
14926
+ * A resumed split that produced no output: a lost source means the leg delivered
14927
+ * nothing (returns false), and every checkpoint failure keeps the intent open by
14928
+ * throwing. There is no path here that records the spend.
14929
+ */
14930
+ classifyResumeSplitFailure(error, onConflict) {
14931
+ if (error instanceof ProofUnconfirmedError) throw error;
14932
+ if (error instanceof CheckpointPersistFailedError || error instanceof SplitCheckpointLostError || error instanceof CheckpointTrustbaseMismatchError) {
14933
+ throw error;
14934
+ }
14935
+ if (error instanceof TransferConflictError) {
14936
+ onConflict(error);
14937
+ logger.warn("Payments", "Resume split: source lost to a concurrent transfer \u2014 not delivered (\xA78.1/#4):", error);
14938
+ return false;
14939
+ }
14940
+ throw error;
14941
+ }
14942
+ /**
14943
+ * Drop the local records of the sources a resume consumed (present when
14944
+ * resuming on the originating device). M7: each removal carries the LOCAL state
14945
+ * we spent, so a source a concurrent claim reactivated to a NEW state (a
14946
+ * self-send round-trip) is KEPT, not destroyed.
14947
+ */
14948
+ async dropResumedSources(spent, transferId, payload) {
14949
+ const engine = this.deps.tokenEngine;
15235
14950
  for (const genesisId of spent) {
15236
14951
  const local = this.tokens.get(`v2_${genesisId}`);
15237
14952
  if (!local) continue;
@@ -15243,8 +14958,7 @@ var PaymentsModule = class _PaymentsModule {
15243
14958
  let spentOnChain = false;
15244
14959
  try {
15245
14960
  if (local.sdkData) {
15246
- const decoded = await engine.decodeToken(decodeTokenBlob(hexToBytes4(local.sdkData)));
15247
- spentOnChain = await engine.isSpent(decoded);
14961
+ spentOnChain = await engine.isSpent(await engine.decodeToken(decodeTokenBlob(hexToBytes4(local.sdkData))));
15248
14962
  }
15249
14963
  } catch {
15250
14964
  spentOnChain = false;
@@ -15258,47 +14972,19 @@ var PaymentsModule = class _PaymentsModule {
15258
14972
  );
15259
14973
  }
15260
14974
  }
15261
- if (conflicted) {
15262
- const remaining = undeliveredAmount;
15263
- const delivered = BigInt(payload.amount) - remaining;
15264
- await walletApi.completeIntent(transferId);
15265
- await this.addToHistory({
15266
- type: "SENT",
15267
- amount: (delivered > 0n ? delivered : 0n).toString(),
15268
- coinId: payload.coinId,
15269
- symbol: this.getCoinSymbol(payload.coinId),
15270
- timestamp: Date.now(),
15271
- recipientPubkey: payload.recipient,
15272
- memo: payload.memo,
15273
- transferId,
15274
- tokenId: spent[0] ? `v2_${spent[0]}` : void 0
15275
- });
15276
- this.deps.emitEvent("send:partial-remainder", {
15277
- transferId,
15278
- remainingAmount: (remaining > 0n ? remaining : 0n).toString(),
15279
- coinId: payload.coinId,
15280
- recipientPubkey: payload.recipient
15281
- });
15282
- throw new PartialSendConflictError(
15283
- "Resume: part of the payment was delivered before a source was consumed by a concurrent transfer \u2014 the delivered legs are final; re-plan ONLY the remainder.",
15284
- transferId,
15285
- spent,
15286
- // the DELIVERED genesisIds — never the conflicted leg
15287
- (remaining > 0n ? remaining : 0n).toString(),
15288
- firstConflict
15289
- );
15290
- }
15291
- await walletApi.completeIntent(transferId);
14975
+ }
14976
+ /** §10: the SENT record — same dedupKey as the original attempt, so a resume after the history POST is a server-side no-op. */
14977
+ async recordResumedSentHistory(payload, transferId, amount, tokenGenesisId) {
15292
14978
  await this.addToHistory({
15293
14979
  type: "SENT",
15294
- amount: payload.amount,
14980
+ amount,
15295
14981
  coinId: payload.coinId,
15296
14982
  symbol: this.getCoinSymbol(payload.coinId),
15297
14983
  timestamp: Date.now(),
15298
14984
  recipientPubkey: payload.recipient,
15299
14985
  memo: payload.memo,
15300
14986
  transferId,
15301
- tokenId: payload.direct[0] ? `v2_${payload.direct[0]}` : void 0
14987
+ tokenId: tokenGenesisId ? `v2_${tokenGenesisId}` : void 0
15302
14988
  });
15303
14989
  }
15304
14990
  // ===========================================================================
@@ -15320,11 +15006,7 @@ var PaymentsModule = class _PaymentsModule {
15320
15006
  */
15321
15007
  async save(opts = {}) {
15322
15008
  const providers = this.getTokenStorageProviders();
15323
- const tokenStats = Array.from(this.tokens.values()).map((t) => {
15324
- const txf = tokenToTxf(t);
15325
- return `${t.id.slice(0, 12)}(${t.status},txf=${!!txf})`;
15326
- });
15327
- logger.debug("Payments", `save(): providers=${providers.size}, tokens=[${tokenStats.join(", ")}]`);
15009
+ logger.debug("Payments", `save(): providers=${providers.size}, tokens=${this.tokens.size}`);
15328
15010
  if (providers.size === 0) {
15329
15011
  logger.debug("Payments", "save(): No token storage providers - TXF not persisted");
15330
15012
  return;
@@ -23998,7 +23680,6 @@ import canonicalize from "canonicalize";
23998
23680
 
23999
23681
  // core/address.ts
24000
23682
  var DIRECT_PREFIX = "DIRECT://";
24001
- var PROXY_PREFIX = "PROXY://";
24002
23683
  var NAMETAG_PREFIX = "@";
24003
23684
  function parseAddress(address) {
24004
23685
  if (!address || typeof address !== "string") return null;
@@ -24010,9 +23691,6 @@ function parseAddress(address) {
24010
23691
  }
24011
23692
  return null;
24012
23693
  }
24013
- if (trimmed.startsWith(PROXY_PREFIX) && trimmed.length > PROXY_PREFIX.length) {
24014
- return { type: "PROXY", raw: trimmed, value: trimmed.slice(PROXY_PREFIX.length) };
24015
- }
24016
23694
  if (trimmed.startsWith(NAMETAG_PREFIX)) {
24017
23695
  const value = trimmed.slice(NAMETAG_PREFIX.length);
24018
23696
  if (value.length > 0) {
@@ -24035,8 +23713,6 @@ function normalizeAddress(address) {
24035
23713
  switch (parsed.type) {
24036
23714
  case "DIRECT":
24037
23715
  return `DIRECT://${parsed.value.toLowerCase()}`;
24038
- case "PROXY":
24039
- return `PROXY://${parsed.value.toLowerCase()}`;
24040
23716
  case "NAMETAG":
24041
23717
  return `@${parsed.value.toLowerCase()}`;
24042
23718
  }
@@ -27257,444 +26933,94 @@ function parseWalletText(content) {
27257
26933
  return {
27258
26934
  success: false,
27259
26935
  error: "Could not find encrypted master key in backup file"
27260
- };
27261
- }
27262
- return {
27263
- success: false,
27264
- needsPassword: true,
27265
- error: "Password required for encrypted wallet"
27266
- };
27267
- }
27268
- const masterKey = extractFromText(
27269
- content,
27270
- /MASTER PRIVATE KEY \(keep secret!\):\s*([^\n]+)/
27271
- );
27272
- if (!masterKey) {
27273
- return {
27274
- success: false,
27275
- error: "Could not find master private key in backup file"
27276
- };
27277
- }
27278
- const chainCode = extractFromText(
27279
- content,
27280
- /MASTER CHAIN CODE \(for (?:BIP32 HD|Alpha) wallet compatibility\):\s*([^\n]+)/
27281
- );
27282
- const descriptorPath = extractFromText(content, /DESCRIPTOR PATH:\s*([^\n]+)/);
27283
- const isBIP32 = content.includes("WALLET TYPE: BIP32 hierarchical deterministic wallet") || content.includes("WALLET TYPE: Alpha descriptor wallet") || !!chainCode;
27284
- const effectiveDescriptorPath = descriptorPath ?? (isBIP32 ? "84'/1'/0'" : void 0);
27285
- const data = {
27286
- masterKey,
27287
- chainCode: chainCode ?? void 0,
27288
- descriptorPath: effectiveDescriptorPath,
27289
- derivationMode: isBIP32 ? "bip32" : "wif_hmac"
27290
- };
27291
- return {
27292
- success: true,
27293
- data
27294
- };
27295
- } catch (e) {
27296
- return {
27297
- success: false,
27298
- error: `Failed to parse wallet text: ${e instanceof Error ? e.message : String(e)}`
27299
- };
27300
- }
27301
- }
27302
- function parseAndDecryptWalletText(content, password) {
27303
- try {
27304
- const isEncrypted = isTextWalletEncrypted(content);
27305
- if (!isEncrypted) {
27306
- return parseWalletText(content);
27307
- }
27308
- const encryptedKey = extractFromText(
27309
- content,
27310
- /ENCRYPTED MASTER KEY \(password protected\):\s*([^\n]+)/
27311
- );
27312
- if (!encryptedKey) {
27313
- return {
27314
- success: false,
27315
- error: "Could not find encrypted master key in backup file"
27316
- };
27317
- }
27318
- const masterKey = decryptTextFormatKey(encryptedKey, password);
27319
- if (!masterKey) {
27320
- return {
27321
- success: false,
27322
- error: "Failed to decrypt - incorrect password?"
27323
- };
27324
- }
27325
- const chainCode = extractFromText(
27326
- content,
27327
- /MASTER CHAIN CODE \(for (?:BIP32 HD|Alpha) wallet compatibility\):\s*([^\n]+)/
27328
- );
27329
- const descriptorPath = extractFromText(content, /DESCRIPTOR PATH:\s*([^\n]+)/);
27330
- const isBIP32 = content.includes("WALLET TYPE: BIP32 hierarchical deterministic wallet") || content.includes("WALLET TYPE: Alpha descriptor wallet") || !!chainCode;
27331
- const effectiveDescriptorPath = descriptorPath ?? (isBIP32 ? "84'/1'/0'" : void 0);
27332
- const data = {
27333
- masterKey,
27334
- chainCode: chainCode ?? void 0,
27335
- descriptorPath: effectiveDescriptorPath,
27336
- derivationMode: isBIP32 ? "bip32" : "wif_hmac"
27337
- };
27338
- return {
27339
- success: true,
27340
- data
27341
- };
27342
- } catch (e) {
27343
- return {
27344
- success: false,
27345
- error: `Failed to parse/decrypt wallet text: ${e instanceof Error ? e.message : String(e)}`
27346
- };
27347
- }
27348
- }
27349
-
27350
- // serialization/wallet-dat.ts
27351
- import CryptoJS4 from "crypto-js";
27352
- function uint8ArrayToWordArray(u8arr) {
27353
- const hex = bytesToHex4(u8arr);
27354
- return CryptoJS4.enc.Hex.parse(hex);
27355
- }
27356
- function isSQLiteDatabase(data) {
27357
- if (data.length < 16) return false;
27358
- const header = new TextDecoder().decode(data.slice(0, 16));
27359
- return header.startsWith("SQLite format 3");
27360
- }
27361
- function isWalletDatEncrypted(data) {
27362
- const mkeyPattern = new TextEncoder().encode("mkey");
27363
- return findPattern(data, mkeyPattern, 0) !== -1;
27364
- }
27365
- function findAllCMasterKeys(data) {
27366
- const results = [];
27367
- for (let pos = 0; pos < data.length - 70; pos++) {
27368
- if (data[pos] === 48) {
27369
- const saltLenPos = pos + 1 + 48;
27370
- if (saltLenPos < data.length && data[saltLenPos] === 8) {
27371
- const iterPos = saltLenPos + 1 + 8 + 4;
27372
- if (iterPos + 4 <= data.length) {
27373
- const iterations = data[iterPos] | data[iterPos + 1] << 8 | data[iterPos + 2] << 16 | data[iterPos + 3] << 24;
27374
- if (iterations >= 1e3 && iterations <= 1e7) {
27375
- const encryptedKey = data.slice(pos + 1, pos + 1 + 48);
27376
- const salt = data.slice(saltLenPos + 1, saltLenPos + 1 + 8);
27377
- const derivationMethod = data[saltLenPos + 1 + 8] | data[saltLenPos + 1 + 8 + 1] << 8 | data[saltLenPos + 1 + 8 + 2] << 16 | data[saltLenPos + 1 + 8 + 3] << 24;
27378
- results.push({ encryptedKey, salt, derivationMethod, iterations, position: pos });
27379
- }
27380
- }
27381
- }
27382
- }
27383
- }
27384
- return results;
27385
- }
27386
- function findWpkhDescriptor(data) {
27387
- const descriptorPattern = new TextEncoder().encode("walletdescriptor");
27388
- let descriptorIndex = 0;
27389
- while ((descriptorIndex = findPattern(data, descriptorPattern, descriptorIndex)) !== -1) {
27390
- let scanPos = descriptorIndex + descriptorPattern.length + 32;
27391
- const descLen = data[scanPos];
27392
- scanPos++;
27393
- const descBytes = data.slice(scanPos, scanPos + Math.min(descLen, 200));
27394
- let descStr = "";
27395
- for (let i = 0; i < descBytes.length && descBytes[i] >= 32 && descBytes[i] <= 126; i++) {
27396
- descStr += String.fromCharCode(descBytes[i]);
27397
- }
27398
- if (descStr.startsWith("wpkh(xpub") && descStr.includes("/0/*)")) {
27399
- const xpubMatch = descStr.match(/xpub[1-9A-HJ-NP-Za-km-z]{100,}/);
27400
- if (xpubMatch) {
27401
- const descIdStart = descriptorIndex + descriptorPattern.length;
27402
- const descriptorId = data.slice(descIdStart, descIdStart + 32);
27403
- const pathMatch = descStr.match(/\[[\da-f]+\/(\d+'\/\d+'\/\d+')\]/);
27404
- const descriptorPath = pathMatch ? pathMatch[1] : "84'/1'/0'";
27405
- return {
27406
- descriptorId,
27407
- xpubString: xpubMatch[0],
27408
- descriptorPath
27409
- };
27410
- }
27411
- }
27412
- descriptorIndex++;
27413
- }
27414
- return { descriptorId: null, xpubString: null, descriptorPath: null };
27415
- }
27416
- function extractChainCodeFromXpub(xpubString) {
27417
- const decoded = base58Decode(xpubString);
27418
- return bytesToHex4(decoded.slice(13, 45));
27419
- }
27420
- function findMasterChainCode(data) {
27421
- const xpubPattern = new TextEncoder().encode("xpub");
27422
- const base58Chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
27423
- let searchPos = 0;
27424
- while (searchPos < data.length) {
27425
- const xpubIndex = findPattern(data, xpubPattern, searchPos);
27426
- if (xpubIndex === -1) break;
27427
- let xpubStr = "xpub";
27428
- let pos = xpubIndex + 4;
27429
- while (pos < data.length && xpubStr.length < 120) {
27430
- const char = String.fromCharCode(data[pos]);
27431
- if (base58Chars.includes(char)) {
27432
- xpubStr += char;
27433
- pos++;
27434
- } else {
27435
- break;
27436
- }
27437
- }
27438
- if (xpubStr.length > 100) {
27439
- try {
27440
- const decoded = base58Decode(xpubStr);
27441
- const depth = decoded[4];
27442
- if (depth === 0) {
27443
- return bytesToHex4(decoded.slice(13, 45));
27444
- }
27445
- } catch {
27446
- }
27447
- }
27448
- searchPos = xpubIndex + 4;
27449
- }
27450
- return null;
27451
- }
27452
- function extractDescriptorKeys(data) {
27453
- const keys = [];
27454
- const descriptorKeyPattern = new TextEncoder().encode("walletdescriptorkey");
27455
- let index = 0;
27456
- while ((index = findPattern(data, descriptorKeyPattern, index)) !== -1) {
27457
- for (let checkPos = index + descriptorKeyPattern.length; checkPos < Math.min(index + descriptorKeyPattern.length + 200, data.length - 40); checkPos++) {
27458
- if (data[checkPos] === 211 && data[checkPos + 1] === 2 && data[checkPos + 2] === 1 && data[checkPos + 3] === 1 && data[checkPos + 4] === 4 && data[checkPos + 5] === 32) {
27459
- const privKey = data.slice(checkPos + 6, checkPos + 38);
27460
- const privKeyHex = bytesToHex4(privKey);
27461
- if (isValidPrivateKey(privKeyHex)) {
27462
- keys.push(privKeyHex);
27463
- break;
27464
- }
27465
- }
27466
- }
27467
- index++;
27468
- }
27469
- return keys;
27470
- }
27471
- function extractLegacyKeys(data) {
27472
- const keys = [];
27473
- const keyPattern = new TextEncoder().encode("key");
27474
- let index = 0;
27475
- while ((index = findPattern(data, keyPattern, index)) !== -1) {
27476
- const searchPattern = new Uint8Array([4, 32]);
27477
- for (let i = index; i < Math.min(index + 200, data.length - 34); i++) {
27478
- if (data[i] === searchPattern[0] && data[i + 1] === searchPattern[1]) {
27479
- const privKey = data.slice(i + 2, i + 34);
27480
- const privKeyHex = bytesToHex4(privKey);
27481
- if (isValidPrivateKey(privKeyHex)) {
27482
- keys.push(privKeyHex);
27483
- break;
27484
- }
27485
- }
27486
- }
27487
- index++;
27488
- }
27489
- return keys;
27490
- }
27491
- function findEncryptedKeyForDescriptor(data, descriptorId) {
27492
- const ckeyPattern = new TextEncoder().encode("walletdescriptorckey");
27493
- let ckeyIndex = findPattern(data, ckeyPattern, 0);
27494
- while (ckeyIndex !== -1) {
27495
- const recordDescId = data.slice(ckeyIndex + ckeyPattern.length, ckeyIndex + ckeyPattern.length + 32);
27496
- if (Array.from(recordDescId).every((b, i) => b === descriptorId[i])) {
27497
- let keyPos = ckeyIndex + ckeyPattern.length + 32;
27498
- const pubkeyLen = data[keyPos];
27499
- keyPos++;
27500
- const pubkey = data.slice(keyPos, keyPos + pubkeyLen);
27501
- for (let searchPos = keyPos + pubkeyLen; searchPos < Math.min(keyPos + pubkeyLen + 100, data.length - 50); searchPos++) {
27502
- const valueLen = data[searchPos];
27503
- if (valueLen >= 32 && valueLen <= 64) {
27504
- const encryptedKey = data.slice(searchPos + 1, searchPos + 1 + valueLen);
27505
- return { pubkey, encryptedKey };
27506
- }
27507
- }
27508
- }
27509
- ckeyIndex = findPattern(data, ckeyPattern, ckeyIndex + 1);
27510
- }
27511
- return null;
27512
- }
27513
- async function decryptCMasterKey(cmk, password, onProgress) {
27514
- const { encryptedKey, salt, iterations } = cmk;
27515
- const passwordHex = bytesToHex4(new TextEncoder().encode(password));
27516
- const saltHex = bytesToHex4(salt);
27517
- const inputHex = passwordHex + saltHex;
27518
- let hash = CryptoJS4.SHA512(CryptoJS4.enc.Hex.parse(inputHex));
27519
- const BATCH_SIZE = 1e3;
27520
- for (let i = 0; i < iterations - 1; i++) {
27521
- hash = CryptoJS4.SHA512(hash);
27522
- if (onProgress && i % BATCH_SIZE === 0) {
27523
- await onProgress(i, iterations);
27524
- }
27525
- }
27526
- const derivedKey = CryptoJS4.lib.WordArray.create(hash.words.slice(0, 8));
27527
- const derivedIv = CryptoJS4.lib.WordArray.create(hash.words.slice(8, 12));
27528
- const encryptedWords = uint8ArrayToWordArray(encryptedKey);
27529
- const decrypted = CryptoJS4.AES.decrypt(
27530
- { ciphertext: encryptedWords },
27531
- derivedKey,
27532
- { iv: derivedIv, padding: CryptoJS4.pad.Pkcs7, mode: CryptoJS4.mode.CBC }
27533
- );
27534
- const result = CryptoJS4.enc.Hex.stringify(decrypted);
27535
- if (!result || result.length !== 64) {
27536
- throw new SphereError("Master key decryption failed - incorrect password", "DECRYPTION_ERROR");
27537
- }
27538
- return result;
27539
- }
27540
- function decryptPrivateKey(encryptedKey, pubkey, masterKeyHex) {
27541
- const pubkeyWords = uint8ArrayToWordArray(pubkey);
27542
- const pubkeyHashWords = CryptoJS4.SHA256(CryptoJS4.SHA256(pubkeyWords));
27543
- const ivWords = CryptoJS4.lib.WordArray.create(pubkeyHashWords.words.slice(0, 4));
27544
- const masterKeyWords = CryptoJS4.enc.Hex.parse(masterKeyHex);
27545
- const encryptedWords = uint8ArrayToWordArray(encryptedKey);
27546
- const decrypted = CryptoJS4.AES.decrypt(
27547
- { ciphertext: encryptedWords },
27548
- masterKeyWords,
27549
- { iv: ivWords, padding: CryptoJS4.pad.Pkcs7, mode: CryptoJS4.mode.CBC }
27550
- );
27551
- return CryptoJS4.enc.Hex.stringify(decrypted);
27552
- }
27553
- function parseWalletDat(data) {
27554
- if (!isSQLiteDatabase(data)) {
27555
- return {
27556
- success: false,
27557
- error: "Invalid wallet.dat file - not an SQLite database"
27558
- };
27559
- }
27560
- const isEncrypted = isWalletDatEncrypted(data);
27561
- const cmasterKeys = isEncrypted ? findAllCMasterKeys(data) : [];
27562
- const descriptorKeys = isEncrypted ? [] : extractDescriptorKeys(data);
27563
- const legacyKeys = isEncrypted ? [] : extractLegacyKeys(data);
27564
- const { descriptorId: _descriptorId, xpubString, descriptorPath } = findWpkhDescriptor(data);
27565
- void _descriptorId;
27566
- let chainCode = null;
27567
- if (xpubString) {
27568
- try {
27569
- chainCode = extractChainCodeFromXpub(xpubString);
27570
- } catch {
27571
- chainCode = findMasterChainCode(data);
27572
- }
27573
- } else {
27574
- chainCode = findMasterChainCode(data);
27575
- }
27576
- if (!isEncrypted) {
27577
- let masterKey = null;
27578
- if (descriptorKeys.length > 0) {
27579
- masterKey = descriptorKeys[0];
27580
- } else if (legacyKeys.length > 0) {
27581
- masterKey = legacyKeys[0];
27582
- }
27583
- if (masterKey) {
27584
- const parsedData = {
27585
- masterKey,
27586
- chainCode: chainCode ?? void 0,
27587
- descriptorPath: descriptorPath ?? "84'/1'/0'",
27588
- derivationMode: chainCode ? "bip32" : "wif_hmac"
26936
+ };
26937
+ }
26938
+ return {
26939
+ success: false,
26940
+ needsPassword: true,
26941
+ error: "Password required for encrypted wallet"
27589
26942
  };
26943
+ }
26944
+ const masterKey = extractFromText(
26945
+ content,
26946
+ /MASTER PRIVATE KEY \(keep secret!\):\s*([^\n]+)/
26947
+ );
26948
+ if (!masterKey) {
27590
26949
  return {
27591
- success: true,
27592
- data: parsedData
26950
+ success: false,
26951
+ error: "Could not find master private key in backup file"
27593
26952
  };
27594
26953
  }
27595
- return {
27596
- success: false,
27597
- error: "No valid private keys found in wallet.dat file"
27598
- };
27599
- }
27600
- if (cmasterKeys.length === 0) {
27601
- return {
27602
- success: false,
27603
- error: "Encrypted wallet but no CMasterKey structures found"
26954
+ const chainCode = extractFromText(
26955
+ content,
26956
+ /MASTER CHAIN CODE \(for (?:BIP32 HD|Alpha) wallet compatibility\):\s*([^\n]+)/
26957
+ );
26958
+ const descriptorPath = extractFromText(content, /DESCRIPTOR PATH:\s*([^\n]+)/);
26959
+ const isBIP32 = content.includes("WALLET TYPE: BIP32 hierarchical deterministic wallet") || content.includes("WALLET TYPE: Alpha descriptor wallet") || !!chainCode;
26960
+ const effectiveDescriptorPath = descriptorPath ?? (isBIP32 ? "84'/1'/0'" : void 0);
26961
+ const data = {
26962
+ masterKey,
26963
+ chainCode: chainCode ?? void 0,
26964
+ descriptorPath: effectiveDescriptorPath,
26965
+ derivationMode: isBIP32 ? "bip32" : "wif_hmac"
27604
26966
  };
27605
- }
27606
- const firstCmk = cmasterKeys[0];
27607
- return {
27608
- success: false,
27609
- needsPassword: true,
27610
- encryptionInfo: {
27611
- iterations: firstCmk.iterations,
27612
- salt: firstCmk.salt,
27613
- encryptedKey: firstCmk.encryptedKey
27614
- },
27615
- error: "Password required for encrypted wallet"
27616
- };
27617
- }
27618
- async function parseAndDecryptWalletDat(data, password, onProgress) {
27619
- if (!isSQLiteDatabase(data)) {
27620
26967
  return {
27621
- success: false,
27622
- error: "Invalid wallet.dat file - not an SQLite database"
26968
+ success: true,
26969
+ data
27623
26970
  };
27624
- }
27625
- const isEncrypted = isWalletDatEncrypted(data);
27626
- if (!isEncrypted) {
27627
- return parseWalletDat(data);
27628
- }
27629
- const cmasterKeys = findAllCMasterKeys(data);
27630
- if (cmasterKeys.length === 0) {
26971
+ } catch (e) {
27631
26972
  return {
27632
26973
  success: false,
27633
- error: "Encrypted wallet but no CMasterKey structures found"
26974
+ error: `Failed to parse wallet text: ${e instanceof Error ? e.message : String(e)}`
27634
26975
  };
27635
26976
  }
27636
- let masterKeyHex = null;
27637
- for (const cmk of cmasterKeys) {
27638
- try {
27639
- masterKeyHex = await decryptCMasterKey(cmk, password, onProgress);
27640
- if (masterKeyHex && masterKeyHex.length === 64) {
27641
- break;
27642
- }
27643
- } catch {
27644
- continue;
26977
+ }
26978
+ function parseAndDecryptWalletText(content, password) {
26979
+ try {
26980
+ const isEncrypted = isTextWalletEncrypted(content);
26981
+ if (!isEncrypted) {
26982
+ return parseWalletText(content);
27645
26983
  }
27646
- }
27647
- if (!masterKeyHex || masterKeyHex.length !== 64) {
27648
- return {
27649
- success: false,
27650
- error: "Master key decryption failed - incorrect password"
27651
- };
27652
- }
27653
- const { descriptorId, xpubString, descriptorPath } = findWpkhDescriptor(data);
27654
- let chainCode = null;
27655
- if (xpubString) {
27656
- try {
27657
- chainCode = extractChainCodeFromXpub(xpubString);
27658
- } catch {
27659
- chainCode = findMasterChainCode(data);
26984
+ const encryptedKey = extractFromText(
26985
+ content,
26986
+ /ENCRYPTED MASTER KEY \(password protected\):\s*([^\n]+)/
26987
+ );
26988
+ if (!encryptedKey) {
26989
+ return {
26990
+ success: false,
26991
+ error: "Could not find encrypted master key in backup file"
26992
+ };
27660
26993
  }
27661
- } else {
27662
- chainCode = findMasterChainCode(data);
27663
- }
27664
- if (!descriptorId) {
27665
- return {
27666
- success: false,
27667
- error: "Could not find native SegWit receive descriptor"
26994
+ const masterKey = decryptTextFormatKey(encryptedKey, password);
26995
+ if (!masterKey) {
26996
+ return {
26997
+ success: false,
26998
+ error: "Failed to decrypt - incorrect password?"
26999
+ };
27000
+ }
27001
+ const chainCode = extractFromText(
27002
+ content,
27003
+ /MASTER CHAIN CODE \(for (?:BIP32 HD|Alpha) wallet compatibility\):\s*([^\n]+)/
27004
+ );
27005
+ const descriptorPath = extractFromText(content, /DESCRIPTOR PATH:\s*([^\n]+)/);
27006
+ const isBIP32 = content.includes("WALLET TYPE: BIP32 hierarchical deterministic wallet") || content.includes("WALLET TYPE: Alpha descriptor wallet") || !!chainCode;
27007
+ const effectiveDescriptorPath = descriptorPath ?? (isBIP32 ? "84'/1'/0'" : void 0);
27008
+ const data = {
27009
+ masterKey,
27010
+ chainCode: chainCode ?? void 0,
27011
+ descriptorPath: effectiveDescriptorPath,
27012
+ derivationMode: isBIP32 ? "bip32" : "wif_hmac"
27668
27013
  };
27669
- }
27670
- const encryptedKeyData = findEncryptedKeyForDescriptor(data, descriptorId);
27671
- if (!encryptedKeyData) {
27672
27014
  return {
27673
- success: false,
27674
- error: "Could not find encrypted private key for descriptor"
27015
+ success: true,
27016
+ data
27675
27017
  };
27676
- }
27677
- const bip32MasterKey = decryptPrivateKey(
27678
- encryptedKeyData.encryptedKey,
27679
- encryptedKeyData.pubkey,
27680
- masterKeyHex
27681
- );
27682
- if (!bip32MasterKey || bip32MasterKey.length !== 64) {
27018
+ } catch (e) {
27683
27019
  return {
27684
27020
  success: false,
27685
- error: "Could not decrypt BIP32 master private key"
27021
+ error: `Failed to parse/decrypt wallet text: ${e instanceof Error ? e.message : String(e)}`
27686
27022
  };
27687
27023
  }
27688
- const parsedData = {
27689
- masterKey: bip32MasterKey,
27690
- chainCode: chainCode ?? void 0,
27691
- descriptorPath: descriptorPath ?? "84'/1'/0'",
27692
- derivationMode: "bip32"
27693
- };
27694
- return {
27695
- success: true,
27696
- data: parsedData
27697
- };
27698
27024
  }
27699
27025
 
27700
27026
  // core/Sphere.ts
@@ -28527,32 +27853,196 @@ var Sphere = class _Sphere {
28527
27853
  if (this._transport.isConnected() && this._transport.fetchPendingEvents) {
28528
27854
  await this._transport.fetchPendingEvents();
28529
27855
  }
28530
- }
28531
- getAggregator() {
28532
- return this._oracle;
27856
+ }
27857
+ getAggregator() {
27858
+ return this._oracle;
27859
+ }
27860
+ /**
27861
+ * Apply a new gateway API key to the LIVE oracle + token engine WITHOUT a full
27862
+ * Sphere rebuild (transport / realtime socket / discovery stay up). Use this to
27863
+ * inject a per-wallet subscription key provisioned AFTER init, or a per-address
27864
+ * key on an address switch, so the next money operation authenticates with it.
27865
+ *
27866
+ * Money-safety: the running token engine is snapshotted per-operation (the
27867
+ * payments module reads `deps.tokenEngine` into a local at op start), so an
27868
+ * in-flight send/mint completes on the OLD key (submit + proof stay paired on
27869
+ * one client) and only operations started AFTER this call use the new key.
27870
+ * Only the ACTIVE address's engine is rebuilt — other tracked addresses re-key
27871
+ * on their next switch/build. No-op-safe if the engine can't be built (the
27872
+ * modules fall back to their legacy path, same as init).
27873
+ */
27874
+ async setOracleApiKey(apiKey) {
27875
+ this._oracle.setApiKey?.(apiKey);
27876
+ const active = this._addressModules.get(this._currentAddressIndex);
27877
+ const replaced = active?.tokenEngine ?? this._tokenEngine;
27878
+ this._tokenEngine = await this.buildTokenEngine();
27879
+ if (active) active.tokenEngine = this._tokenEngine;
27880
+ this._payments.setTokenEngine(this._tokenEngine);
27881
+ if (replaced && replaced !== this._tokenEngine) replaced.dispose?.();
27882
+ }
27883
+ /**
27884
+ * Import a wallet from a backup file: a `UNICITY WALLET DETAILS` text backup
27885
+ * (the format `exportToTxt` writes, optionally password-encrypted), a legacy
27886
+ * flat-JSON webwallet export, or a bare mnemonic in a text file.
27887
+ *
27888
+ * @example
27889
+ * const result = await Sphere.importFromLegacyFile({
27890
+ * fileContent: await file.text(),
27891
+ * fileName: file.name,
27892
+ * password, // when the backup is encrypted
27893
+ * ...providers,
27894
+ * });
27895
+ */
27896
+ static async importFromLegacyFile(options) {
27897
+ const { fileContent, fileName, password, onDecryptProgress, ...baseOptions } = options;
27898
+ const fileType = _Sphere.detectLegacyFileType(fileName, fileContent);
27899
+ if (fileType === "unknown") {
27900
+ return { success: false, error: "Unknown file format" };
27901
+ }
27902
+ if (fileType === "mnemonic") {
27903
+ const mnemonic = fileContent.trim().toLowerCase().split(/\s+/).join(" ");
27904
+ if (!_Sphere.validateMnemonic(mnemonic)) {
27905
+ return { success: false, error: "Invalid mnemonic phrase" };
27906
+ }
27907
+ const sphere = await _Sphere.import({ ...baseOptions, mnemonic });
27908
+ return { success: true, sphere, mnemonic };
27909
+ }
27910
+ if (fileType === "txt") {
27911
+ const content = fileContent;
27912
+ let parseResult;
27913
+ if (password) {
27914
+ parseResult = parseAndDecryptWalletText(content, password);
27915
+ } else if (isTextWalletEncrypted(content)) {
27916
+ return { success: false, needsPassword: true, error: "Password required for encrypted wallet" };
27917
+ } else {
27918
+ parseResult = parseWalletText(content);
27919
+ }
27920
+ if (parseResult.needsPassword && !password) {
27921
+ return { success: false, needsPassword: true, error: "Password required for encrypted wallet" };
27922
+ }
27923
+ if (!parseResult.success || !parseResult.data) {
27924
+ return { success: false, error: parseResult.error };
27925
+ }
27926
+ const { masterKey, chainCode, descriptorPath, derivationMode } = parseResult.data;
27927
+ const basePath = descriptorPath ? `m/${descriptorPath}` : DEFAULT_BASE_PATH;
27928
+ const sphere = await _Sphere.import({
27929
+ ...baseOptions,
27930
+ masterKey,
27931
+ chainCode,
27932
+ basePath,
27933
+ derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac")
27934
+ });
27935
+ return { success: true, sphere };
27936
+ }
27937
+ if (fileType === "json") {
27938
+ const content = fileContent;
27939
+ let parsed;
27940
+ try {
27941
+ parsed = JSON.parse(content);
27942
+ } catch {
27943
+ return { success: false, error: "Invalid JSON file" };
27944
+ }
27945
+ if (parsed.type === "sphere-wallet") {
27946
+ const result = await _Sphere.importFromJSON({
27947
+ ...baseOptions,
27948
+ jsonContent: content,
27949
+ password
27950
+ });
27951
+ if (result.success) {
27952
+ const sphere2 = _Sphere.getInstance();
27953
+ return { success: true, sphere: sphere2, mnemonic: result.mnemonic };
27954
+ }
27955
+ if (!password && result.error?.includes("Password required")) {
27956
+ return { success: false, needsPassword: true, error: result.error };
27957
+ }
27958
+ return { success: false, error: result.error };
27959
+ }
27960
+ let masterKey;
27961
+ let mnemonic;
27962
+ if (parsed.encrypted && typeof parsed.encrypted === "object") {
27963
+ if (!password) {
27964
+ return { success: false, needsPassword: true, error: "Password required for encrypted wallet" };
27965
+ }
27966
+ const enc = parsed.encrypted;
27967
+ if (!enc.salt || !enc.masterPrivateKey) {
27968
+ return { success: false, error: "Invalid encrypted wallet format" };
27969
+ }
27970
+ const decryptedKey = decryptWithSalt(enc.masterPrivateKey, password, enc.salt);
27971
+ if (!decryptedKey) {
27972
+ return { success: false, error: "Failed to decrypt - incorrect password?" };
27973
+ }
27974
+ masterKey = decryptedKey;
27975
+ if (enc.mnemonic) {
27976
+ mnemonic = decryptWithSalt(enc.mnemonic, password, enc.salt) ?? void 0;
27977
+ }
27978
+ } else {
27979
+ masterKey = parsed.masterPrivateKey;
27980
+ mnemonic = parsed.mnemonic;
27981
+ }
27982
+ if (!masterKey) {
27983
+ return { success: false, error: "No master key found in wallet JSON" };
27984
+ }
27985
+ const chainCode = parsed.chainCode;
27986
+ const descriptorPath = parsed.descriptorPath;
27987
+ const derivationMode = parsed.derivationMode;
27988
+ const isBIP32 = derivationMode === "bip32" || !!chainCode;
27989
+ const basePath = descriptorPath ? `m/${descriptorPath}` : isBIP32 ? "m/84'/1'/0'" : DEFAULT_BASE_PATH;
27990
+ if (mnemonic) {
27991
+ const sphere2 = await _Sphere.import({ ...baseOptions, mnemonic, basePath });
27992
+ return { success: true, sphere: sphere2, mnemonic };
27993
+ }
27994
+ const sphere = await _Sphere.import({
27995
+ ...baseOptions,
27996
+ masterKey,
27997
+ chainCode,
27998
+ basePath,
27999
+ derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac")
28000
+ });
28001
+ return { success: true, sphere };
28002
+ }
28003
+ return { success: false, error: "Unsupported file type" };
28004
+ }
28005
+ /**
28006
+ * Detect legacy file type from filename and content
28007
+ */
28008
+ static detectLegacyFileType(fileName, content) {
28009
+ if (fileName.endsWith(".json")) {
28010
+ return "json";
28011
+ }
28012
+ try {
28013
+ const trimmed = content.trim();
28014
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
28015
+ JSON.parse(trimmed);
28016
+ return "json";
28017
+ }
28018
+ } catch {
28019
+ }
28020
+ const words = content.trim().split(/\s+/);
28021
+ if ((words.length === 12 || words.length === 24) && words.every((w) => /^[a-z]+$/.test(w.toLowerCase()))) {
28022
+ return "mnemonic";
28023
+ }
28024
+ if (isWalletTextFormat(content)) {
28025
+ return "txt";
28026
+ }
28027
+ return "unknown";
28533
28028
  }
28534
28029
  /**
28535
- * Apply a new gateway API key to the LIVE oracle + token engine WITHOUT a full
28536
- * Sphere rebuild (transport / realtime socket / discovery stay up). Use this to
28537
- * inject a per-wallet subscription key provisioned AFTER init, or a per-address
28538
- * key on an address switch, so the next money operation authenticates with it.
28539
- *
28540
- * Money-safety: the running token engine is snapshotted per-operation (the
28541
- * payments module reads `deps.tokenEngine` into a local at op start), so an
28542
- * in-flight send/mint completes on the OLD key (submit + proof stay paired on
28543
- * one client) and only operations started AFTER this call use the new key.
28544
- * Only the ACTIVE address's engine is rebuilt — other tracked addresses re-key
28545
- * on their next switch/build. No-op-safe if the engine can't be built (the
28546
- * modules fall back to their legacy path, same as init).
28030
+ * Check if a legacy file is encrypted
28547
28031
  */
28548
- async setOracleApiKey(apiKey) {
28549
- this._oracle.setApiKey?.(apiKey);
28550
- const active = this._addressModules.get(this._currentAddressIndex);
28551
- const replaced = active?.tokenEngine ?? this._tokenEngine;
28552
- this._tokenEngine = await this.buildTokenEngine();
28553
- if (active) active.tokenEngine = this._tokenEngine;
28554
- this._payments.setTokenEngine(this._tokenEngine);
28555
- if (replaced && replaced !== this._tokenEngine) replaced.dispose?.();
28032
+ static isLegacyFileEncrypted(fileName, content) {
28033
+ const fileType = _Sphere.detectLegacyFileType(fileName, content);
28034
+ if (fileType === "txt") {
28035
+ return isTextWalletEncrypted(content);
28036
+ }
28037
+ if (fileType === "json") {
28038
+ try {
28039
+ const data = JSON.parse(content);
28040
+ return !!data.encrypted;
28041
+ } catch {
28042
+ return false;
28043
+ }
28044
+ }
28045
+ return false;
28556
28046
  }
28557
28047
  /**
28558
28048
  * Check if wallet has BIP32 master key for HD derivation
@@ -28824,224 +28314,6 @@ var Sphere = class _Sphere {
28824
28314
  };
28825
28315
  }
28826
28316
  }
28827
- /**
28828
- * Import wallet from legacy file (.dat, .txt, or mnemonic text)
28829
- *
28830
- * Supports:
28831
- * - Bitcoin Core wallet.dat files (SQLite format, encrypted or unencrypted)
28832
- * - Text backup files (UNICITY WALLET DETAILS format)
28833
- * - Plain mnemonic text (12 or 24 words)
28834
- *
28835
- * @returns Object with success status, created Sphere instance, and optionally recovered mnemonic
28836
- *
28837
- * @example
28838
- * ```ts
28839
- * // Import from .dat file
28840
- * const fileBuffer = await file.arrayBuffer();
28841
- * const result = await Sphere.importFromLegacyFile({
28842
- * fileContent: new Uint8Array(fileBuffer),
28843
- * fileName: 'wallet.dat',
28844
- * password: 'wallet-password', // if encrypted
28845
- * storage, transport, oracle,
28846
- * });
28847
- *
28848
- * // Import from .txt file
28849
- * const textContent = await file.text();
28850
- * const result = await Sphere.importFromLegacyFile({
28851
- * fileContent: textContent,
28852
- * fileName: 'backup.txt',
28853
- * storage, transport, oracle,
28854
- * });
28855
- * ```
28856
- */
28857
- static async importFromLegacyFile(options) {
28858
- const { fileContent, fileName, password, onDecryptProgress, ...baseOptions } = options;
28859
- const fileType = _Sphere.detectLegacyFileType(fileName, fileContent);
28860
- if (fileType === "unknown") {
28861
- return { success: false, error: "Unknown file format" };
28862
- }
28863
- if (fileType === "mnemonic") {
28864
- const mnemonic = fileContent.trim().toLowerCase().split(/\s+/).join(" ");
28865
- if (!_Sphere.validateMnemonic(mnemonic)) {
28866
- return { success: false, error: "Invalid mnemonic phrase" };
28867
- }
28868
- const sphere = await _Sphere.import({ ...baseOptions, mnemonic });
28869
- return { success: true, sphere, mnemonic };
28870
- }
28871
- if (fileType === "dat") {
28872
- const data = fileContent instanceof Uint8Array ? fileContent : new TextEncoder().encode(fileContent);
28873
- let parseResult;
28874
- if (password) {
28875
- parseResult = await parseAndDecryptWalletDat(data, password, onDecryptProgress);
28876
- } else {
28877
- parseResult = parseWalletDat(data);
28878
- }
28879
- if (parseResult.needsPassword && !password) {
28880
- return { success: false, needsPassword: true, error: "Password required for encrypted wallet" };
28881
- }
28882
- if (!parseResult.success || !parseResult.data) {
28883
- return { success: false, error: parseResult.error };
28884
- }
28885
- const { masterKey, chainCode, descriptorPath, derivationMode } = parseResult.data;
28886
- const basePath = descriptorPath ? `m/${descriptorPath}` : DEFAULT_BASE_PATH;
28887
- const sphere = await _Sphere.import({
28888
- ...baseOptions,
28889
- masterKey,
28890
- chainCode,
28891
- basePath,
28892
- derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac")
28893
- });
28894
- return { success: true, sphere };
28895
- }
28896
- if (fileType === "txt") {
28897
- const content = typeof fileContent === "string" ? fileContent : new TextDecoder().decode(fileContent);
28898
- let parseResult;
28899
- if (password) {
28900
- parseResult = parseAndDecryptWalletText(content, password);
28901
- } else if (isTextWalletEncrypted(content)) {
28902
- return { success: false, needsPassword: true, error: "Password required for encrypted wallet" };
28903
- } else {
28904
- parseResult = parseWalletText(content);
28905
- }
28906
- if (parseResult.needsPassword && !password) {
28907
- return { success: false, needsPassword: true, error: "Password required for encrypted wallet" };
28908
- }
28909
- if (!parseResult.success || !parseResult.data) {
28910
- return { success: false, error: parseResult.error };
28911
- }
28912
- const { masterKey, chainCode, descriptorPath, derivationMode } = parseResult.data;
28913
- const basePath = descriptorPath ? `m/${descriptorPath}` : DEFAULT_BASE_PATH;
28914
- const sphere = await _Sphere.import({
28915
- ...baseOptions,
28916
- masterKey,
28917
- chainCode,
28918
- basePath,
28919
- derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac")
28920
- });
28921
- return { success: true, sphere };
28922
- }
28923
- if (fileType === "json") {
28924
- const content = typeof fileContent === "string" ? fileContent : new TextDecoder().decode(fileContent);
28925
- let parsed;
28926
- try {
28927
- parsed = JSON.parse(content);
28928
- } catch {
28929
- return { success: false, error: "Invalid JSON file" };
28930
- }
28931
- if (parsed.type === "sphere-wallet") {
28932
- const result = await _Sphere.importFromJSON({
28933
- ...baseOptions,
28934
- jsonContent: content,
28935
- password
28936
- });
28937
- if (result.success) {
28938
- const sphere2 = _Sphere.getInstance();
28939
- return { success: true, sphere: sphere2, mnemonic: result.mnemonic };
28940
- }
28941
- if (!password && result.error?.includes("Password required")) {
28942
- return { success: false, needsPassword: true, error: result.error };
28943
- }
28944
- return { success: false, error: result.error };
28945
- }
28946
- let masterKey;
28947
- let mnemonic;
28948
- if (parsed.encrypted && typeof parsed.encrypted === "object") {
28949
- if (!password) {
28950
- return { success: false, needsPassword: true, error: "Password required for encrypted wallet" };
28951
- }
28952
- const enc = parsed.encrypted;
28953
- if (!enc.salt || !enc.masterPrivateKey) {
28954
- return { success: false, error: "Invalid encrypted wallet format" };
28955
- }
28956
- const decryptedKey = decryptWithSalt(enc.masterPrivateKey, password, enc.salt);
28957
- if (!decryptedKey) {
28958
- return { success: false, error: "Failed to decrypt - incorrect password?" };
28959
- }
28960
- masterKey = decryptedKey;
28961
- if (enc.mnemonic) {
28962
- mnemonic = decryptWithSalt(enc.mnemonic, password, enc.salt) ?? void 0;
28963
- }
28964
- } else {
28965
- masterKey = parsed.masterPrivateKey;
28966
- mnemonic = parsed.mnemonic;
28967
- }
28968
- if (!masterKey) {
28969
- return { success: false, error: "No master key found in wallet JSON" };
28970
- }
28971
- const chainCode = parsed.chainCode;
28972
- const descriptorPath = parsed.descriptorPath;
28973
- const derivationMode = parsed.derivationMode;
28974
- const isBIP32 = derivationMode === "bip32" || !!chainCode;
28975
- const basePath = descriptorPath ? `m/${descriptorPath}` : isBIP32 ? "m/84'/1'/0'" : DEFAULT_BASE_PATH;
28976
- if (mnemonic) {
28977
- const sphere2 = await _Sphere.import({ ...baseOptions, mnemonic, basePath });
28978
- return { success: true, sphere: sphere2, mnemonic };
28979
- }
28980
- const sphere = await _Sphere.import({
28981
- ...baseOptions,
28982
- masterKey,
28983
- chainCode,
28984
- basePath,
28985
- derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac")
28986
- });
28987
- return { success: true, sphere };
28988
- }
28989
- return { success: false, error: "Unsupported file type" };
28990
- }
28991
- /**
28992
- * Detect legacy file type from filename and content
28993
- */
28994
- static detectLegacyFileType(fileName, content) {
28995
- if (fileName.endsWith(".dat")) {
28996
- return "dat";
28997
- }
28998
- const textContent = typeof content === "string" ? content : content.length < 1e3 ? new TextDecoder().decode(content) : "";
28999
- if (fileName.endsWith(".json")) {
29000
- return "json";
29001
- }
29002
- try {
29003
- const trimmed = textContent.trim();
29004
- if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
29005
- JSON.parse(trimmed);
29006
- return "json";
29007
- }
29008
- } catch {
29009
- }
29010
- const words = textContent.trim().split(/\s+/);
29011
- if ((words.length === 12 || words.length === 24) && words.every((w) => /^[a-z]+$/.test(w.toLowerCase()))) {
29012
- return "mnemonic";
29013
- }
29014
- if (isWalletTextFormat(textContent)) {
29015
- return "txt";
29016
- }
29017
- if (content instanceof Uint8Array && isSQLiteDatabase(content)) {
29018
- return "dat";
29019
- }
29020
- return "unknown";
29021
- }
29022
- /**
29023
- * Check if a legacy file is encrypted
29024
- */
29025
- static isLegacyFileEncrypted(fileName, content) {
29026
- const fileType = _Sphere.detectLegacyFileType(fileName, content);
29027
- if (fileType === "dat" && content instanceof Uint8Array) {
29028
- return isWalletDatEncrypted(content);
29029
- }
29030
- if (fileType === "txt") {
29031
- const textContent = typeof content === "string" ? content : new TextDecoder().decode(content);
29032
- return isTextWalletEncrypted(textContent);
29033
- }
29034
- if (fileType === "json") {
29035
- try {
29036
- const textContent = typeof content === "string" ? content : new TextDecoder().decode(content);
29037
- const data = JSON.parse(textContent);
29038
- return !!data.encrypted;
29039
- } catch {
29040
- return false;
29041
- }
29042
- }
29043
- return false;
29044
- }
29045
28317
  /**
29046
28318
  * Get the current active address index
29047
28319
  *
@@ -30946,116 +30218,6 @@ function formatAmount(amount, options = {}) {
30946
30218
  return symbol ? `${readable} ${symbol}` : readable;
30947
30219
  }
30948
30220
 
30949
- // core/bech32.ts
30950
- var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
30951
- var GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
30952
- function convertBits(data, fromBits, toBits, pad) {
30953
- let acc = 0;
30954
- let bits = 0;
30955
- const ret = [];
30956
- const maxv = (1 << toBits) - 1;
30957
- for (let i = 0; i < data.length; i++) {
30958
- const value = data[i];
30959
- if (value < 0 || value >> fromBits !== 0) return null;
30960
- acc = acc << fromBits | value;
30961
- bits += fromBits;
30962
- while (bits >= toBits) {
30963
- bits -= toBits;
30964
- ret.push(acc >> bits & maxv);
30965
- }
30966
- }
30967
- if (pad) {
30968
- if (bits > 0) {
30969
- ret.push(acc << toBits - bits & maxv);
30970
- }
30971
- } else if (bits >= fromBits || acc << toBits - bits & maxv) {
30972
- return null;
30973
- }
30974
- return ret;
30975
- }
30976
- function hrpExpand(hrp) {
30977
- const ret = [];
30978
- for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) >> 5);
30979
- ret.push(0);
30980
- for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) & 31);
30981
- return ret;
30982
- }
30983
- function bech32Polymod(values) {
30984
- let chk = 1;
30985
- for (let p = 0; p < values.length; p++) {
30986
- const top = chk >> 25;
30987
- chk = (chk & 33554431) << 5 ^ values[p];
30988
- for (let i = 0; i < 5; i++) {
30989
- if (top >> i & 1) chk ^= GENERATOR[i];
30990
- }
30991
- }
30992
- return chk;
30993
- }
30994
- function bech32Checksum(hrp, data) {
30995
- const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
30996
- const mod2 = bech32Polymod(values) ^ 1;
30997
- const ret = [];
30998
- for (let p = 0; p < 6; p++) {
30999
- ret.push(mod2 >> 5 * (5 - p) & 31);
31000
- }
31001
- return ret;
31002
- }
31003
- function encodeBech32(hrp, version, program) {
31004
- if (version < 0 || version > 16) {
31005
- throw new SphereError("Invalid witness version", "VALIDATION_ERROR");
31006
- }
31007
- const converted = convertBits(Array.from(program), 8, 5, true);
31008
- if (!converted) {
31009
- throw new SphereError("Failed to convert bits", "VALIDATION_ERROR");
31010
- }
31011
- const data = [version].concat(converted);
31012
- const checksum = bech32Checksum(hrp, data);
31013
- const combined = data.concat(checksum);
31014
- let out = hrp + "1";
31015
- for (let i = 0; i < combined.length; i++) {
31016
- out += CHARSET[combined[i]];
31017
- }
31018
- return out;
31019
- }
31020
- function decodeBech32(addr) {
31021
- addr = addr.toLowerCase();
31022
- const pos = addr.lastIndexOf("1");
31023
- if (pos < 1) return null;
31024
- const hrp = addr.substring(0, pos);
31025
- const dataStr = addr.substring(pos + 1);
31026
- const data = [];
31027
- for (let i = 0; i < dataStr.length; i++) {
31028
- const val = CHARSET.indexOf(dataStr[i]);
31029
- if (val === -1) return null;
31030
- data.push(val);
31031
- }
31032
- const checksum = bech32Checksum(hrp, data.slice(0, -6));
31033
- for (let i = 0; i < 6; i++) {
31034
- if (checksum[i] !== data[data.length - 6 + i]) {
31035
- return null;
31036
- }
31037
- }
31038
- const version = data[0];
31039
- const program = convertBits(data.slice(1, -6), 5, 8, false);
31040
- if (!program) return null;
31041
- return {
31042
- hrp,
31043
- witnessVersion: version,
31044
- data: Uint8Array.from(program)
31045
- };
31046
- }
31047
- function createAddress(hrp, pubkeyHash) {
31048
- const hashBytes = typeof pubkeyHash === "string" ? Uint8Array.from(Buffer.from(pubkeyHash, "hex")) : pubkeyHash;
31049
- return encodeBech32(hrp, 1, hashBytes);
31050
- }
31051
- function isValidBech32(addr) {
31052
- return decodeBech32(addr) !== null;
31053
- }
31054
- function getAddressHrp(addr) {
31055
- const result = decodeBech32(addr);
31056
- return result?.hrp ?? null;
31057
- }
31058
-
31059
30221
  // core/network-health.ts
31060
30222
  var DEFAULT_TIMEOUT_MS = 5e3;
31061
30223
  async function checkNetworkHealth(network = "testnet", options) {
@@ -31240,7 +30402,7 @@ async function runCustomCheck(name, checkFn, timeoutMs) {
31240
30402
 
31241
30403
  // storage/whole-blob-inventory-adapter.ts
31242
30404
  var TOKEN_KEY_RE = /^_[0-9a-f]{4,}$/i;
31243
- function bytesToHex6(bytes) {
30405
+ function bytesToHex5(bytes) {
31244
30406
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
31245
30407
  }
31246
30408
  function hexToBytes6(hex) {
@@ -31350,7 +30512,7 @@ var WholeBlobInventoryAdapter = class {
31350
30512
  if (isV2TokenEntry2(entry)) {
31351
30513
  try {
31352
30514
  const blob = decodeTokenBlob(hexToBytes6(entry.sdkData));
31353
- stateHash = bytesToHex6(sha256(blob.token));
30515
+ stateHash = bytesToHex5(sha256(blob.token));
31354
30516
  } catch {
31355
30517
  }
31356
30518
  }
@@ -31375,7 +30537,7 @@ function hexToBytes7(hex) {
31375
30537
  for (let i = 0; i < out.length; i++) out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
31376
30538
  return out;
31377
30539
  }
31378
- function bytesToHex7(bytes) {
30540
+ function bytesToHex6(bytes) {
31379
30541
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
31380
30542
  }
31381
30543
  function computeDeliveryId(tokenIdHex, stateHashHex) {
@@ -31384,7 +30546,7 @@ function computeDeliveryId(tokenIdHex, stateHashHex) {
31384
30546
  const joined = new Uint8Array(tokenId.length + stateHash.length);
31385
30547
  joined.set(tokenId, 0);
31386
30548
  joined.set(stateHash, tokenId.length);
31387
- return bytesToHex7(sha256(joined));
30549
+ return bytesToHex6(sha256(joined));
31388
30550
  }
31389
30551
  function composeDeliveryKeys(keys) {
31390
30552
  return { ...keys, deliveryId: computeDeliveryId(keys.tokenId, keys.stateHash) };
@@ -31794,7 +30956,6 @@ export {
31794
30956
  WalletApiError,
31795
30957
  WholeBlobInventoryAdapter,
31796
30958
  addressesMatch,
31797
- archivedKeyFromTokenId,
31798
30959
  areSameNametag,
31799
30960
  assertFieldEnvelopeShape,
31800
30961
  base58Decode,
@@ -31807,8 +30968,6 @@ export {
31807
30968
  composeDeliveryKeys,
31808
30969
  computeDeliveryId,
31809
30970
  computeSwapId,
31810
- countCommittedTransactions,
31811
- createAddress,
31812
30971
  createCommunicationsModule,
31813
30972
  createGroupChatModule,
31814
30973
  createKeyPair,
@@ -31819,15 +30978,12 @@ export {
31819
30978
  createSphere,
31820
30979
  createSwapModule,
31821
30980
  createTokenValidator,
31822
- decodeBech32,
31823
30981
  decrypt,
31824
- decryptCMasterKey,
31825
30982
  decryptField,
31826
30983
  decryptFieldBytes,
31827
30984
  decryptJson,
31828
30985
  decryptMnemonic,
31829
30986
  decryptNametag2 as decryptNametag,
31830
- decryptPrivateKey,
31831
30987
  decryptSimple,
31832
30988
  decryptTextFormatKey,
31833
30989
  decryptWithSalt,
@@ -31836,7 +30992,6 @@ export {
31836
30992
  deriveFieldEncryptionKey,
31837
30993
  deriveKeyAtPath,
31838
30994
  doubleSha256,
31839
- encodeBech32,
31840
30995
  encrypt,
31841
30996
  encryptField,
31842
30997
  encryptFieldBytes,
@@ -31845,28 +31000,21 @@ export {
31845
31000
  encryptSimple,
31846
31001
  extractFromText,
31847
31002
  findPattern,
31848
- forkedKeyFromTokenIdAndState,
31849
31003
  formatAmount,
31850
31004
  generateAddressFromMasterKey,
31851
31005
  generateMasterKey,
31852
31006
  generateMnemonic2 as generateMnemonic,
31853
- getAddressHrp,
31854
31007
  getAddressId,
31855
31008
  getAddressStorageKey,
31856
31009
  getCoinIdByName,
31857
31010
  getCoinIdBySymbol,
31858
- getCurrentStateHash,
31859
31011
  getPublicKey,
31860
31012
  getSphere,
31861
31013
  getTokenDecimals,
31862
31014
  getTokenDefinition,
31863
31015
  getTokenIconUrl,
31864
- getTokenId,
31865
31016
  getTokenName,
31866
31017
  getTokenSymbol,
31867
- hasMissingNewStateHash,
31868
- hasUncommittedTransactions,
31869
- hasValidTxfData,
31870
31018
  hash160,
31871
31019
  hashAddressForTag,
31872
31020
  hashNametag,
@@ -31874,22 +31022,17 @@ export {
31874
31022
  hexToBytes4 as hexToBytes,
31875
31023
  identityFromMnemonicSync,
31876
31024
  initSphere,
31877
- isArchivedKey,
31878
- isForkedKey,
31879
31025
  isKnownToken,
31880
31026
  isPhoneNumber2 as isPhoneNumber,
31881
31027
  isPossiblyCommittedSendOutcome,
31882
- isSQLiteDatabase,
31883
31028
  isSphereError,
31884
31029
  isTextWalletEncrypted,
31885
31030
  isTokenKey,
31886
31031
  isValidAddress,
31887
- isValidBech32,
31888
31032
  isValidDirectAddress,
31889
31033
  isValidNametag2 as isValidNametag,
31890
31034
  isValidPrivateKey,
31891
31035
  isValidTokenId,
31892
- isWalletDatEncrypted,
31893
31036
  isWalletTextFormat,
31894
31037
  keyFromTokenId,
31895
31038
  loadSphere,
@@ -31898,15 +31041,10 @@ export {
31898
31041
  normalizeAddress,
31899
31042
  normalizeCoinId,
31900
31043
  normalizeNametag2 as normalizeNametag,
31901
- normalizeSdkTokenToStorage,
31902
- objectToTxf,
31903
31044
  parseAddress,
31904
- parseAndDecryptWalletDat,
31905
31045
  parseAndDecryptWalletText,
31906
- parseForkedKey,
31907
31046
  parseTokenAmount,
31908
31047
  parseTxfStorageData,
31909
- parseWalletDat,
31910
31048
  parseWalletText,
31911
31049
  randomBytes4 as randomBytes,
31912
31050
  randomHex,
@@ -31920,10 +31058,7 @@ export {
31920
31058
  sleep,
31921
31059
  sphereExists,
31922
31060
  toHumanReadable,
31923
- tokenIdFromArchivedKey,
31924
31061
  tokenIdFromKey,
31925
- tokenToTxf,
31926
- txfToToken,
31927
31062
  validateManifest,
31928
31063
  validateMnemonic2 as validateMnemonic,
31929
31064
  verifyChallengeTemplate,