@unicitylabs/sphere-sdk 0.16.0 → 0.17.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.
Files changed (53) hide show
  1. package/dist/connect/index.cjs +11 -5
  2. package/dist/connect/index.cjs.map +1 -1
  3. package/dist/connect/index.d.cts +4 -1
  4. package/dist/connect/index.d.ts +4 -1
  5. package/dist/connect/index.js +11 -5
  6. package/dist/connect/index.js.map +1 -1
  7. package/dist/core/index.cjs +566 -171
  8. package/dist/core/index.cjs.map +1 -1
  9. package/dist/core/index.d.cts +67 -0
  10. package/dist/core/index.d.ts +67 -0
  11. package/dist/core/index.js +566 -171
  12. package/dist/core/index.js.map +1 -1
  13. package/dist/impl/browser/connect/index.cjs +11 -5
  14. package/dist/impl/browser/connect/index.cjs.map +1 -1
  15. package/dist/impl/browser/connect/index.d.cts +3 -1
  16. package/dist/impl/browser/connect/index.d.ts +3 -1
  17. package/dist/impl/browser/connect/index.js +11 -5
  18. package/dist/impl/browser/connect/index.js.map +1 -1
  19. package/dist/impl/nodejs/connect/index.cjs +10 -4
  20. package/dist/impl/nodejs/connect/index.cjs.map +1 -1
  21. package/dist/impl/nodejs/connect/index.d.cts +1 -1
  22. package/dist/impl/nodejs/connect/index.d.ts +1 -1
  23. package/dist/impl/nodejs/connect/index.js +10 -4
  24. package/dist/impl/nodejs/connect/index.js.map +1 -1
  25. package/dist/impl/nodejs/index.d.cts +11 -0
  26. package/dist/impl/nodejs/index.d.ts +11 -0
  27. package/dist/impl/shared/wallet-api/index.d.cts +11 -0
  28. package/dist/impl/shared/wallet-api/index.d.ts +11 -0
  29. package/dist/impl/wallet-api-v2/index.cjs +2 -0
  30. package/dist/impl/wallet-api-v2/index.cjs.map +1 -1
  31. package/dist/impl/wallet-api-v2/index.d.cts +13 -0
  32. package/dist/impl/wallet-api-v2/index.d.ts +13 -0
  33. package/dist/impl/wallet-api-v2/index.js +2 -0
  34. package/dist/impl/wallet-api-v2/index.js.map +1 -1
  35. package/dist/index.cjs +566 -171
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +61 -1
  38. package/dist/index.d.ts +61 -1
  39. package/dist/index.js +566 -171
  40. package/dist/index.js.map +1 -1
  41. package/dist/modules/payments-v2/index.cjs +609 -269
  42. package/dist/modules/payments-v2/index.cjs.map +1 -1
  43. package/dist/modules/payments-v2/index.d.cts +88 -13
  44. package/dist/modules/payments-v2/index.d.ts +88 -13
  45. package/dist/modules/payments-v2/index.js +609 -269
  46. package/dist/modules/payments-v2/index.js.map +1 -1
  47. package/dist/token-engine/index.cjs +132 -34
  48. package/dist/token-engine/index.cjs.map +1 -1
  49. package/dist/token-engine/index.d.cts +19 -0
  50. package/dist/token-engine/index.d.ts +19 -0
  51. package/dist/token-engine/index.js +132 -34
  52. package/dist/token-engine/index.js.map +1 -1
  53. package/package.json +1 -1
@@ -78,6 +78,8 @@ var import_DataHasherFactory = require("@unicitylabs/state-transition-sdk/lib/cr
78
78
  var import_CborSerializer = require("@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborSerializer.js");
79
79
  var import_CborDeserializer = require("@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborDeserializer.js");
80
80
  var import_CborError = require("@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborError.js");
81
+ var import_CborReader = require("@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborReader.js");
82
+ var import_MajorType = require("@unicitylabs/state-transition-sdk/lib/serialization/cbor/MajorType.js");
81
83
  var import_Asset = require("@unicitylabs/state-transition-sdk/lib/payment/asset/Asset.js");
82
84
  var import_AssetId = require("@unicitylabs/state-transition-sdk/lib/payment/asset/AssetId.js");
83
85
  var import_PaymentAssetCollection = require("@unicitylabs/state-transition-sdk/lib/payment/asset/PaymentAssetCollection.js");
@@ -1035,6 +1037,123 @@ async function burntTokenFromCheckpoint(deps, storedBytes, reDerivedBurnTx, sour
1035
1037
  return burntToken;
1036
1038
  }
1037
1039
 
1040
+ // token-engine/value-envelope.ts
1041
+ var SELF_DESCRIBED_CBOR_TAG = 55799n;
1042
+ var CBOR_MAJOR_TYPE_MASK = 224;
1043
+ var describe = (error) => error instanceof Error ? error.message : String(error);
1044
+ var invalid = (message) => new SphereError(message, "VALIDATION_ERROR");
1045
+ function majorTypeOf(bytes) {
1046
+ const first = bytes.at(0);
1047
+ return first === void 0 ? null : first & CBOR_MAJOR_TYPE_MASK;
1048
+ }
1049
+ function headTagNumber(bytes) {
1050
+ try {
1051
+ return new import_CborReader.CborReader(bytes).readLength(import_MajorType.MajorType.TAG);
1052
+ } catch {
1053
+ return null;
1054
+ }
1055
+ }
1056
+ function isAssetShaped(item) {
1057
+ try {
1058
+ return import_CborDeserializer.CborDeserializer.decodeArray(item, 2).every(
1059
+ (field) => majorTypeOf(field) === import_MajorType.MajorType.BYTE_STRING
1060
+ );
1061
+ } catch {
1062
+ return false;
1063
+ }
1064
+ }
1065
+ function arrayItemsOrNull(bytes) {
1066
+ try {
1067
+ return import_CborDeserializer.CborDeserializer.decodeArray(bytes);
1068
+ } catch {
1069
+ return null;
1070
+ }
1071
+ }
1072
+ function decodeSphere(genesisData) {
1073
+ try {
1074
+ return SpherePaymentData.fromCBOR(genesisData).toValue();
1075
+ } catch (error) {
1076
+ throw invalid(`Failed to decode token payment data: ${describe(error)}`);
1077
+ }
1078
+ }
1079
+ function taggedItemBody(genesisData) {
1080
+ try {
1081
+ return import_CborDeserializer.CborDeserializer.decodeTag(genesisData).data;
1082
+ } catch (error) {
1083
+ throw invalid(
1084
+ `Token value payload is a CBOR tag whose item is malformed or carries trailing bytes: ${describe(error)}`
1085
+ );
1086
+ }
1087
+ }
1088
+ function selfDescribedBodyCarriesValue(body) {
1089
+ const major = majorTypeOf(body);
1090
+ if (major === import_MajorType.MajorType.TAG) {
1091
+ const inner = headTagNumber(body);
1092
+ return inner === SpherePaymentData.CBOR_TAG || inner === SELF_DESCRIBED_CBOR_TAG;
1093
+ }
1094
+ if (major === import_MajorType.MajorType.ARRAY) {
1095
+ const items = arrayItemsOrNull(body);
1096
+ return items !== null && items.some(isAssetShaped);
1097
+ }
1098
+ return false;
1099
+ }
1100
+ function classifyTagged(genesisData) {
1101
+ const tag = headTagNumber(genesisData);
1102
+ if (tag === null) {
1103
+ throw invalid(
1104
+ "Token value payload has an unreadable or non-canonically encoded CBOR tag head \u2014 it could be a malformed SpherePaymentData envelope"
1105
+ );
1106
+ }
1107
+ if (tag === SpherePaymentData.CBOR_TAG) {
1108
+ return { envelope: "sphere", value: decodeSphere(genesisData) };
1109
+ }
1110
+ const body = taggedItemBody(genesisData);
1111
+ if (tag === SELF_DESCRIBED_CBOR_TAG && selfDescribedBodyCarriesValue(body)) {
1112
+ throw invalid(
1113
+ "Token value payload is a value envelope wrapped in the self-described CBOR tag 55799 (RFC 8949 \xA73.4.6), which no codec here unwraps \u2014 its coins would be invisible. Emit the envelope without the self-describe prefix"
1114
+ );
1115
+ }
1116
+ return { envelope: "none_tag", value: null };
1117
+ }
1118
+ function classifyArray(genesisData) {
1119
+ const items = arrayItemsOrNull(genesisData);
1120
+ if (items === null) {
1121
+ throw invalid("Token value payload is not PaymentAssetCollection: malformed CBOR array");
1122
+ }
1123
+ return items.some(isAssetShaped) ? { envelope: "bare_collection", value: null } : { envelope: "none_other", value: null };
1124
+ }
1125
+ function classifyValueEnvelope(genesisData) {
1126
+ if (genesisData === null) return { envelope: "none_absent", value: null };
1127
+ const major = majorTypeOf(genesisData);
1128
+ if (major === null) return { envelope: "none_absent", value: null };
1129
+ if (major === import_MajorType.MajorType.TAG) return classifyTagged(genesisData);
1130
+ if (major === import_MajorType.MajorType.ARRAY) return classifyArray(genesisData);
1131
+ return { envelope: "none_other", value: null };
1132
+ }
1133
+ function wrapToken(sdkToken) {
1134
+ const { envelope, value } = classifyValueEnvelope(sdkToken.genesis.data);
1135
+ const blob = {
1136
+ tokenId: import_HexConverter.HexConverter.encode(sdkToken.id.bytes),
1137
+ token: sdkToken.toCBOR()
1138
+ };
1139
+ return {
1140
+ sdkToken,
1141
+ blob,
1142
+ value,
1143
+ valueEnvelope: envelope,
1144
+ tokenType: import_HexConverter.HexConverter.encode(sdkToken.type.bytes)
1145
+ };
1146
+ }
1147
+ function assertMintableData(data) {
1148
+ try {
1149
+ classifyValueEnvelope(data);
1150
+ } catch (error) {
1151
+ throw invalid(
1152
+ `Cannot mint a data token with this payload: ${describe(error)}. Raw bytes starting in the CBOR array (0x80-0x9f) or tag (0xc0-0xdf) range must be well-formed canonical CBOR; wrap them in a CBOR byte string, map, text string, or a tag other than 39050/55799.`
1153
+ );
1154
+ }
1155
+ }
1156
+
1038
1157
  // token-engine/SphereTokenEngine.ts
1039
1158
  var DEFAULT_PROOF_POLL_INTERVAL_MS = 300;
1040
1159
  var MAX_MINT_CONCURRENCY = 8;
@@ -1091,7 +1210,7 @@ var SphereTokenEngine = class {
1091
1210
  return sdkToken.latestTransaction.data;
1092
1211
  }
1093
1212
  const data = sdkToken.genesis.data;
1094
- if (data && this.isSpherePaymentData(data)) {
1213
+ if (data && classifyValueEnvelope(data).envelope === "sphere") {
1095
1214
  return SpherePaymentData.fromCBOR(data).memo;
1096
1215
  }
1097
1216
  return null;
@@ -1121,9 +1240,10 @@ var SphereTokenEngine = class {
1121
1240
  );
1122
1241
  const certified = await mintTx.toCertifiedTransaction(this.deps.trustBase, this.deps.predicateVerifier, this.deps.unicityCertificateVerifier, proof);
1123
1242
  const token = await import_Token.Token.mint(certified, this.deps.verificationContext);
1124
- return this.wrapToken(token);
1243
+ return wrapToken(token);
1125
1244
  }
1126
1245
  async mintDataToken(params, options) {
1246
+ assertMintableData(params.data);
1127
1247
  const recipient = import_SignaturePredicate.SignaturePredicate.create(params.recipientPubkey);
1128
1248
  const tokenType = params.tokenType ? new import_TokenType.TokenType(params.tokenType) : import_TokenType.TokenType.generate();
1129
1249
  const salt = params.salt ? import_TokenSalt.TokenSalt.fromBytes(params.salt) : import_TokenSalt.TokenSalt.generate();
@@ -1138,7 +1258,7 @@ var SphereTokenEngine = class {
1138
1258
  );
1139
1259
  const certified = await mintTx.toCertifiedTransaction(this.deps.trustBase, this.deps.predicateVerifier, this.deps.unicityCertificateVerifier, proof);
1140
1260
  const token = await import_Token.Token.mint(certified, this.deps.verificationContext);
1141
- return this.wrapToken(token);
1261
+ return wrapToken(token);
1142
1262
  }
1143
1263
  async transfer(params, options) {
1144
1264
  this.assertOwned(params.token);
@@ -1161,13 +1281,19 @@ var SphereTokenEngine = class {
1161
1281
  );
1162
1282
  const certified = await transferTx.toCertifiedTransaction(this.deps.trustBase, this.deps.predicateVerifier, this.deps.unicityCertificateVerifier, proof);
1163
1283
  const transferred = await params.token.sdkToken.transfer(certified, this.deps.verificationContext);
1164
- return this.wrapToken(transferred);
1284
+ return wrapToken(transferred);
1165
1285
  }
1166
1286
  async split(params, options) {
1167
1287
  this.assertOwned(params.token);
1168
1288
  if (params.outputs.length === 0) {
1169
1289
  throw new SphereError("Split requires at least one output", "VALIDATION_ERROR");
1170
1290
  }
1291
+ if (params.token.value === null) {
1292
+ throw new SphereError(
1293
+ `Cannot split token ${params.token.blob.tokenId}: its genesis payload carries no value this SDK can read (envelope: ${params.token.valueEnvelope}). A coinless token can only be transferred whole.`,
1294
+ "VALIDATION_ERROR"
1295
+ );
1296
+ }
1171
1297
  const transferId = this.resolveTransferId(options);
1172
1298
  const requests = params.outputs.map(
1173
1299
  (o, i) => import_SplitTokenRequest.SplitTokenRequest.create(
@@ -1289,7 +1415,7 @@ var SphereTokenEngine = class {
1289
1415
  const proof = await this.submitSplitMintLeg(certData, mintTx, options);
1290
1416
  const certified = await mintTx.toCertifiedTransaction(this.deps.trustBase, this.deps.predicateVerifier, this.deps.unicityCertificateVerifier, proof);
1291
1417
  const token = await import_Token.Token.mint(certified, this.deps.verificationContext);
1292
- return this.wrapToken(token);
1418
+ return wrapToken(token);
1293
1419
  }
1294
1420
  /**
1295
1421
  * Submit one split-mint leg. A `TRANSACTION_HASH_MISMATCH` on a mint leg is NOT a foreign spend
@@ -1347,7 +1473,7 @@ var SphereTokenEngine = class {
1347
1473
  "VALIDATION_ERROR"
1348
1474
  );
1349
1475
  }
1350
- return this.wrapToken(sdkToken);
1476
+ return wrapToken(sdkToken);
1351
1477
  }
1352
1478
  // ── internals ────────────────────────────────────────────────────────────────
1353
1479
  /**
@@ -1459,34 +1585,6 @@ var SphereTokenEngine = class {
1459
1585
  throw new SphereError("Cannot transfer a token not owned by this engine identity", "VALIDATION_ERROR");
1460
1586
  }
1461
1587
  }
1462
- /** Wrap an SDK token into a SphereToken: cache its blob (incl. stable tokenId) + decoded value. */
1463
- wrapToken(sdkToken) {
1464
- const data = sdkToken.genesis.data;
1465
- let value = null;
1466
- if (data && this.isSpherePaymentData(data)) {
1467
- try {
1468
- value = SpherePaymentData.fromCBOR(data).toValue();
1469
- } catch (err) {
1470
- throw new SphereError(
1471
- `Failed to decode token payment data: ${err instanceof Error ? err.message : String(err)}`,
1472
- "VALIDATION_ERROR"
1473
- );
1474
- }
1475
- }
1476
- const blob = {
1477
- tokenId: import_HexConverter.HexConverter.encode(sdkToken.id.bytes),
1478
- token: sdkToken.toCBOR()
1479
- };
1480
- return { sdkToken, blob, value };
1481
- }
1482
- /** True if the bytes are a SpherePaymentData envelope (value token) vs a raw data token. */
1483
- isSpherePaymentData(data) {
1484
- try {
1485
- return import_CborDeserializer.CborDeserializer.decodeTag(data).tag === SpherePaymentData.CBOR_TAG;
1486
- } catch {
1487
- return false;
1488
- }
1489
- }
1490
1588
  /**
1491
1589
  * Terminate the verification worker pool, if this engine was configured with
1492
1590
  * one. Idempotent — the pool's dispose only touches workers it spawned.