@buildonspark/spark-sdk 0.1.44 → 0.1.45
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/CHANGELOG.md +9 -0
- package/dist/{RequestLightningSendInput-RGel43ks.d.ts → RequestLightningSendInput-DEPd_fPO.d.ts} +1 -1
- package/dist/{RequestLightningSendInput-BxbCtwpV.d.cts → RequestLightningSendInput-Du0z7Om7.d.cts} +1 -1
- package/dist/address/index.cjs +2 -2
- package/dist/address/index.d.cts +2 -2
- package/dist/address/index.d.ts +2 -2
- package/dist/address/index.js +2 -2
- package/dist/{chunk-XX4RRWOX.js → chunk-5FUB65LX.js} +5 -7
- package/dist/{chunk-DAXGVPVM.js → chunk-6264CGDM.js} +4 -4
- package/dist/{chunk-UBT6EDVJ.js → chunk-7V6N75CC.js} +1 -1
- package/dist/{chunk-4Q2ZDYYU.js → chunk-BGGEVUJK.js} +1157 -208
- package/dist/{chunk-CIZNCBKE.js → chunk-C2S227QR.js} +648 -45
- package/dist/{chunk-NBCNYDWJ.js → chunk-GZ5IPPJ2.js} +2 -2
- package/dist/{chunk-6AFUC5M2.js → chunk-HWJWKEIU.js} +8 -2
- package/dist/{chunk-A2ZLMH6I.js → chunk-J2IE4Z7Y.js} +231 -299
- package/dist/{chunk-KEKGSH7B.js → chunk-KMUMFYFX.js} +3 -3
- package/dist/chunk-LHRD2WT6.js +2374 -0
- package/dist/{chunk-SQKXGAIR.js → chunk-NTFKFRQ2.js} +1 -1
- package/dist/{chunk-K4BJARWM.js → chunk-OBFKIEMP.js} +1 -1
- package/dist/{chunk-WPTRVD2V.js → chunk-PQN3C2MF.js} +15 -15
- package/dist/{chunk-EKFD62HN.js → chunk-R5PXJZQS.js} +1 -0
- package/dist/{chunk-HTMXTJRK.js → chunk-YUPMXTCJ.js} +4 -4
- package/dist/graphql/objects/index.d.cts +5 -4
- package/dist/graphql/objects/index.d.ts +5 -4
- package/dist/index-B2AwKW5J.d.cts +214 -0
- package/dist/index-CJDi1HWc.d.ts +214 -0
- package/dist/index.cjs +4025 -1314
- package/dist/index.d.cts +764 -19
- package/dist/index.d.ts +764 -19
- package/dist/index.js +16 -20
- package/dist/index.node.cjs +4025 -1318
- package/dist/index.node.d.cts +10 -8
- package/dist/index.node.d.ts +10 -8
- package/dist/index.node.js +16 -24
- package/dist/native/index.cjs +4026 -1315
- package/dist/native/index.d.cts +281 -85
- package/dist/native/index.d.ts +281 -85
- package/dist/native/index.js +4017 -1306
- package/dist/{network-CroCOQ0B.d.ts → network-BTJl-Sul.d.ts} +1 -1
- package/dist/{network-CfxLnaot.d.cts → network-CqgsdUF2.d.cts} +1 -1
- package/dist/proto/lrc20.cjs +222 -19
- package/dist/proto/lrc20.d.cts +1 -1
- package/dist/proto/lrc20.d.ts +1 -1
- package/dist/proto/lrc20.js +2 -2
- package/dist/proto/spark.cjs +1154 -205
- package/dist/proto/spark.d.cts +1 -1
- package/dist/proto/spark.d.ts +1 -1
- package/dist/proto/spark.js +3 -1
- package/dist/proto/spark_token.cjs +1377 -58
- package/dist/proto/spark_token.d.cts +153 -15
- package/dist/proto/spark_token.d.ts +153 -15
- package/dist/proto/spark_token.js +40 -4
- package/dist/{sdk-types-BeCBoozO.d.cts → sdk-types-B0SwjolI.d.cts} +1 -1
- package/dist/{sdk-types-CTbTdDbE.d.ts → sdk-types-Cc4l4kb1.d.ts} +1 -1
- package/dist/services/config.cjs +1 -1
- package/dist/services/config.d.cts +5 -4
- package/dist/services/config.d.ts +5 -4
- package/dist/services/config.js +6 -6
- package/dist/services/connection.cjs +2438 -262
- package/dist/services/connection.d.cts +5 -4
- package/dist/services/connection.d.ts +5 -4
- package/dist/services/connection.js +4 -4
- package/dist/services/index.cjs +5936 -3153
- package/dist/services/index.d.cts +7 -6
- package/dist/services/index.d.ts +7 -6
- package/dist/services/index.js +15 -13
- package/dist/services/lrc-connection.cjs +223 -20
- package/dist/services/lrc-connection.d.cts +5 -4
- package/dist/services/lrc-connection.d.ts +5 -4
- package/dist/services/lrc-connection.js +4 -4
- package/dist/services/token-transactions.cjs +840 -236
- package/dist/services/token-transactions.d.cts +25 -7
- package/dist/services/token-transactions.d.ts +25 -7
- package/dist/services/token-transactions.js +5 -4
- package/dist/services/wallet-config.cjs +2 -0
- package/dist/services/wallet-config.d.cts +7 -5
- package/dist/services/wallet-config.d.ts +7 -5
- package/dist/services/wallet-config.js +3 -1
- package/dist/signer/signer.cjs +1 -1
- package/dist/signer/signer.d.cts +3 -2
- package/dist/signer/signer.d.ts +3 -2
- package/dist/signer/signer.js +2 -2
- package/dist/{signer-D7vfYik9.d.ts → signer-BocS_J6B.d.ts} +2 -6
- package/dist/{signer-DaY8c60s.d.cts → signer-DKS0AJkw.d.cts} +2 -6
- package/dist/{spark-C4ZrsgjC.d.cts → spark-dM7EYXYQ.d.cts} +93 -15
- package/dist/{spark-C4ZrsgjC.d.ts → spark-dM7EYXYQ.d.ts} +93 -15
- package/dist/spark_bindings/native/index.cjs +183 -0
- package/dist/spark_bindings/native/index.d.cts +14 -0
- package/dist/spark_bindings/native/index.d.ts +14 -0
- package/dist/spark_bindings/native/index.js +141 -0
- package/dist/spark_bindings/wasm/index.cjs +1093 -0
- package/dist/spark_bindings/wasm/index.d.cts +47 -0
- package/dist/spark_bindings/wasm/index.d.ts +47 -0
- package/dist/{chunk-K4C4W5FC.js → spark_bindings/wasm/index.js} +7 -6
- package/dist/types/index.cjs +1156 -208
- package/dist/types/index.d.cts +5 -4
- package/dist/types/index.d.ts +5 -4
- package/dist/types/index.js +2 -2
- package/dist/types-C-Rp0Oo7.d.cts +46 -0
- package/dist/types-C-Rp0Oo7.d.ts +46 -0
- package/dist/utils/index.cjs +64 -12
- package/dist/utils/index.d.cts +14 -134
- package/dist/utils/index.d.ts +14 -134
- package/dist/utils/index.js +7 -7
- package/package.json +21 -1
- package/src/index.node.ts +0 -1
- package/src/index.ts +0 -1
- package/src/native/index.ts +1 -2
- package/src/proto/common.ts +5 -5
- package/src/proto/google/protobuf/descriptor.ts +34 -34
- package/src/proto/google/protobuf/duration.ts +2 -2
- package/src/proto/google/protobuf/empty.ts +2 -2
- package/src/proto/google/protobuf/timestamp.ts +2 -2
- package/src/proto/mock.ts +4 -4
- package/src/proto/spark.ts +1452 -185
- package/src/proto/spark_authn.ts +7 -7
- package/src/proto/spark_token.ts +1668 -105
- package/src/proto/validate/validate.ts +24 -24
- package/src/services/bolt11-spark.ts +62 -187
- package/src/services/coop-exit.ts +3 -0
- package/src/services/lrc20.ts +1 -1
- package/src/services/token-transactions.ts +197 -9
- package/src/services/transfer.ts +22 -0
- package/src/services/tree-creation.ts +13 -0
- package/src/services/wallet-config.ts +1 -1
- package/src/spark-wallet/spark-wallet.node.ts +0 -4
- package/src/spark-wallet/spark-wallet.ts +76 -108
- package/src/spark-wallet/types.ts +39 -3
- package/src/tests/bolt11-spark.test.ts +7 -15
- package/src/tests/integration/ssp/coop-exit.test.ts +7 -7
- package/src/tests/integration/swap.test.ts +453 -433
- package/src/tests/integration/transfer.test.ts +261 -248
- package/src/tests/token-identifier.test.ts +54 -0
- package/src/tests/tokens.test.ts +218 -23
- package/src/utils/token-hashing.ts +320 -44
- package/src/utils/token-identifier.ts +88 -0
- package/src/utils/token-transaction-validation.ts +350 -5
- package/src/utils/token-transactions.ts +12 -8
- package/src/utils/transaction.ts +0 -6
- package/dist/chunk-B3AMIGJG.js +0 -1073
- package/dist/index-CZmDdSts.d.cts +0 -829
- package/dist/index-ClIRO_3y.d.ts +0 -829
- package/dist/wasm-7OWFHDMS.js +0 -21
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
calculateAvailableTokenAmount,
|
|
3
3
|
checkIfSelectedOutputsAreAvailable,
|
|
4
4
|
collectResponses
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-HWJWKEIU.js";
|
|
6
6
|
import {
|
|
7
7
|
decodeSparkAddress
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KMUMFYFX.js";
|
|
9
9
|
import {
|
|
10
10
|
bigIntToPrivateKey,
|
|
11
11
|
recoverSecret
|
|
@@ -110,13 +110,21 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
|
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
hashObj2.update(issuerPubKey);
|
|
113
|
-
|
|
113
|
+
let timestampValue = 0;
|
|
114
|
+
const mintInput = tokenTransaction.tokenInputs.mintInput;
|
|
115
|
+
if ("issuerProvidedTimestamp" in mintInput) {
|
|
116
|
+
const v0MintInput = mintInput;
|
|
117
|
+
if (v0MintInput.issuerProvidedTimestamp != 0) {
|
|
118
|
+
timestampValue = v0MintInput.issuerProvidedTimestamp;
|
|
119
|
+
}
|
|
120
|
+
} else if ("clientCreatedTimestamp" in tokenTransaction && tokenTransaction.clientCreatedTimestamp) {
|
|
121
|
+
timestampValue = tokenTransaction.clientCreatedTimestamp.getTime();
|
|
122
|
+
}
|
|
123
|
+
if (timestampValue != 0) {
|
|
114
124
|
const timestampBytes = new Uint8Array(8);
|
|
115
125
|
new DataView(timestampBytes.buffer).setBigUint64(
|
|
116
126
|
0,
|
|
117
|
-
BigInt(
|
|
118
|
-
tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp
|
|
119
|
-
),
|
|
127
|
+
BigInt(timestampValue),
|
|
120
128
|
true
|
|
121
129
|
// true for little-endian to match Go implementation
|
|
122
130
|
);
|
|
@@ -125,12 +133,95 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
|
|
|
125
133
|
allHashes.push(hashObj2.digest());
|
|
126
134
|
}
|
|
127
135
|
}
|
|
136
|
+
if (tokenTransaction.tokenInputs?.$case === "createInput") {
|
|
137
|
+
const issuerPubKeyHashObj = sha256.create();
|
|
138
|
+
const createInput = tokenTransaction.tokenInputs.createInput;
|
|
139
|
+
if (!createInput.issuerPublicKey || createInput.issuerPublicKey.length === 0) {
|
|
140
|
+
throw new ValidationError("issuer public key cannot be nil or empty", {
|
|
141
|
+
field: "tokenInputs.createInput.issuerPublicKey"
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
issuerPubKeyHashObj.update(createInput.issuerPublicKey);
|
|
145
|
+
allHashes.push(issuerPubKeyHashObj.digest());
|
|
146
|
+
const tokenNameHashObj = sha256.create();
|
|
147
|
+
if (!createInput.tokenName || createInput.tokenName.length === 0) {
|
|
148
|
+
throw new ValidationError("token name cannot be empty", {
|
|
149
|
+
field: "tokenInputs.createInput.tokenName"
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
if (createInput.tokenName.length > 20) {
|
|
153
|
+
throw new ValidationError("token name cannot be longer than 20 bytes", {
|
|
154
|
+
field: "tokenInputs.createInput.tokenName",
|
|
155
|
+
value: createInput.tokenName,
|
|
156
|
+
expectedLength: 20,
|
|
157
|
+
actualLength: createInput.tokenName.length
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const tokenNameBytes = new Uint8Array(20);
|
|
161
|
+
const tokenNameEncoder = new TextEncoder();
|
|
162
|
+
tokenNameBytes.set(tokenNameEncoder.encode(createInput.tokenName));
|
|
163
|
+
tokenNameHashObj.update(tokenNameBytes);
|
|
164
|
+
allHashes.push(tokenNameHashObj.digest());
|
|
165
|
+
const tokenTickerHashObj = sha256.create();
|
|
166
|
+
if (!createInput.tokenTicker || createInput.tokenTicker.length === 0) {
|
|
167
|
+
throw new ValidationError("token ticker cannot be empty", {
|
|
168
|
+
field: "tokenInputs.createInput.tokenTicker"
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (createInput.tokenTicker.length > 6) {
|
|
172
|
+
throw new ValidationError("token ticker cannot be longer than 6 bytes", {
|
|
173
|
+
field: "tokenInputs.createInput.tokenTicker",
|
|
174
|
+
value: createInput.tokenTicker,
|
|
175
|
+
expectedLength: 6,
|
|
176
|
+
actualLength: createInput.tokenTicker.length
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
const tokenTickerBytes = new Uint8Array(6);
|
|
180
|
+
const tokenTickerEncoder = new TextEncoder();
|
|
181
|
+
tokenTickerBytes.set(tokenTickerEncoder.encode(createInput.tokenTicker));
|
|
182
|
+
tokenTickerHashObj.update(tokenTickerBytes);
|
|
183
|
+
allHashes.push(tokenTickerHashObj.digest());
|
|
184
|
+
const decimalsHashObj = sha256.create();
|
|
185
|
+
const decimalsBytes = new Uint8Array(4);
|
|
186
|
+
new DataView(decimalsBytes.buffer).setUint32(
|
|
187
|
+
0,
|
|
188
|
+
createInput.decimals,
|
|
189
|
+
false
|
|
190
|
+
);
|
|
191
|
+
decimalsHashObj.update(decimalsBytes);
|
|
192
|
+
allHashes.push(decimalsHashObj.digest());
|
|
193
|
+
const maxSupplyHashObj = sha256.create();
|
|
194
|
+
if (!createInput.maxSupply) {
|
|
195
|
+
throw new ValidationError("max supply cannot be nil", {
|
|
196
|
+
field: "tokenInputs.createInput.maxSupply"
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (createInput.maxSupply.length !== 16) {
|
|
200
|
+
throw new ValidationError("max supply must be exactly 16 bytes", {
|
|
201
|
+
field: "tokenInputs.createInput.maxSupply",
|
|
202
|
+
value: createInput.maxSupply,
|
|
203
|
+
expectedLength: 16,
|
|
204
|
+
actualLength: createInput.maxSupply.length
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
maxSupplyHashObj.update(createInput.maxSupply);
|
|
208
|
+
allHashes.push(maxSupplyHashObj.digest());
|
|
209
|
+
const isFreezableHashObj = sha256.create();
|
|
210
|
+
const isFreezableByte = new Uint8Array([createInput.isFreezable ? 1 : 0]);
|
|
211
|
+
isFreezableHashObj.update(isFreezableByte);
|
|
212
|
+
allHashes.push(isFreezableHashObj.digest());
|
|
213
|
+
const creationEntityHashObj = sha256.create();
|
|
214
|
+
if (!partialHash && createInput.creationEntityPublicKey) {
|
|
215
|
+
creationEntityHashObj.update(createInput.creationEntityPublicKey);
|
|
216
|
+
}
|
|
217
|
+
allHashes.push(creationEntityHashObj.digest());
|
|
218
|
+
}
|
|
128
219
|
if (!tokenTransaction.tokenOutputs) {
|
|
129
220
|
throw new ValidationError("token outputs cannot be null", {
|
|
130
221
|
field: "tokenOutputs"
|
|
131
222
|
});
|
|
132
223
|
}
|
|
133
|
-
if (tokenTransaction.tokenOutputs.length === 0) {
|
|
224
|
+
if (tokenTransaction.tokenOutputs.length === 0 && tokenTransaction.tokenInputs?.$case !== "createInput") {
|
|
134
225
|
throw new ValidationError("token outputs cannot be empty", {
|
|
135
226
|
field: "tokenOutputs"
|
|
136
227
|
});
|
|
@@ -307,6 +398,26 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
307
398
|
);
|
|
308
399
|
versionHashObj.update(versionBytes);
|
|
309
400
|
allHashes.push(versionHashObj.digest());
|
|
401
|
+
const typeHashObj = sha256.create();
|
|
402
|
+
const typeBytes = new Uint8Array(4);
|
|
403
|
+
let transactionType = 0;
|
|
404
|
+
if (tokenTransaction.tokenInputs?.$case === "mintInput") {
|
|
405
|
+
transactionType = 2 /* TOKEN_TRANSACTION_TYPE_MINT */;
|
|
406
|
+
} else if (tokenTransaction.tokenInputs?.$case === "transferInput") {
|
|
407
|
+
transactionType = 3 /* TOKEN_TRANSACTION_TYPE_TRANSFER */;
|
|
408
|
+
} else if (tokenTransaction.tokenInputs?.$case === "createInput") {
|
|
409
|
+
transactionType = 1 /* TOKEN_TRANSACTION_TYPE_CREATE */;
|
|
410
|
+
} else {
|
|
411
|
+
throw new ValidationError(
|
|
412
|
+
"token transaction must have exactly one input type",
|
|
413
|
+
{
|
|
414
|
+
field: "tokenInputs"
|
|
415
|
+
}
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
new DataView(typeBytes.buffer).setUint32(0, transactionType, false);
|
|
419
|
+
typeHashObj.update(typeBytes);
|
|
420
|
+
allHashes.push(typeHashObj.digest());
|
|
310
421
|
if (tokenTransaction.tokenInputs?.$case === "transferInput") {
|
|
311
422
|
if (!tokenTransaction.tokenInputs.transferInput.outputsToSpend) {
|
|
312
423
|
throw new ValidationError("outputs to spend cannot be null", {
|
|
@@ -318,6 +429,15 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
318
429
|
field: "tokenInputs.transferInput.outputsToSpend"
|
|
319
430
|
});
|
|
320
431
|
}
|
|
432
|
+
const outputsLenHashObj2 = sha256.create();
|
|
433
|
+
const outputsLenBytes2 = new Uint8Array(4);
|
|
434
|
+
new DataView(outputsLenBytes2.buffer).setUint32(
|
|
435
|
+
0,
|
|
436
|
+
tokenTransaction.tokenInputs.transferInput.outputsToSpend.length,
|
|
437
|
+
false
|
|
438
|
+
);
|
|
439
|
+
outputsLenHashObj2.update(outputsLenBytes2);
|
|
440
|
+
allHashes.push(outputsLenHashObj2.digest());
|
|
321
441
|
for (const [
|
|
322
442
|
i,
|
|
323
443
|
output
|
|
@@ -354,8 +474,7 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
354
474
|
hashObj2.update(voutBytes);
|
|
355
475
|
allHashes.push(hashObj2.digest());
|
|
356
476
|
}
|
|
357
|
-
}
|
|
358
|
-
if (tokenTransaction.tokenInputs?.$case === "mintInput") {
|
|
477
|
+
} else if (tokenTransaction.tokenInputs?.$case === "mintInput") {
|
|
359
478
|
const hashObj2 = sha256.create();
|
|
360
479
|
if (tokenTransaction.tokenInputs.mintInput.issuerPublicKey) {
|
|
361
480
|
const issuerPubKey = tokenTransaction.tokenInputs.mintInput.issuerPublicKey;
|
|
@@ -368,31 +487,113 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
368
487
|
});
|
|
369
488
|
}
|
|
370
489
|
hashObj2.update(issuerPubKey);
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp
|
|
377
|
-
),
|
|
378
|
-
true
|
|
379
|
-
// true for little-endian to match Go implementation
|
|
490
|
+
allHashes.push(hashObj2.digest());
|
|
491
|
+
const tokenIdentifierHashObj = sha256.create();
|
|
492
|
+
if (tokenTransaction.tokenInputs.mintInput.tokenIdentifier) {
|
|
493
|
+
tokenIdentifierHashObj.update(
|
|
494
|
+
tokenTransaction.tokenInputs.mintInput.tokenIdentifier
|
|
380
495
|
);
|
|
381
|
-
|
|
496
|
+
} else {
|
|
497
|
+
tokenIdentifierHashObj.update(new Uint8Array(32));
|
|
382
498
|
}
|
|
383
|
-
allHashes.push(
|
|
499
|
+
allHashes.push(tokenIdentifierHashObj.digest());
|
|
500
|
+
}
|
|
501
|
+
} else if (tokenTransaction.tokenInputs?.$case === "createInput") {
|
|
502
|
+
const createInput = tokenTransaction.tokenInputs.createInput;
|
|
503
|
+
const issuerPubKeyHashObj = sha256.create();
|
|
504
|
+
if (!createInput.issuerPublicKey || createInput.issuerPublicKey.length === 0) {
|
|
505
|
+
throw new ValidationError("issuer public key cannot be nil or empty", {
|
|
506
|
+
field: "tokenInputs.createInput.issuerPublicKey"
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
issuerPubKeyHashObj.update(createInput.issuerPublicKey);
|
|
510
|
+
allHashes.push(issuerPubKeyHashObj.digest());
|
|
511
|
+
const tokenNameHashObj = sha256.create();
|
|
512
|
+
if (!createInput.tokenName || createInput.tokenName.length === 0) {
|
|
513
|
+
throw new ValidationError("token name cannot be empty", {
|
|
514
|
+
field: "tokenInputs.createInput.tokenName"
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
if (createInput.tokenName.length > 20) {
|
|
518
|
+
throw new ValidationError("token name cannot be longer than 20 bytes", {
|
|
519
|
+
field: "tokenInputs.createInput.tokenName",
|
|
520
|
+
value: createInput.tokenName,
|
|
521
|
+
expectedLength: 20,
|
|
522
|
+
actualLength: createInput.tokenName.length
|
|
523
|
+
});
|
|
384
524
|
}
|
|
525
|
+
const tokenNameEncoder = new TextEncoder();
|
|
526
|
+
tokenNameHashObj.update(tokenNameEncoder.encode(createInput.tokenName));
|
|
527
|
+
allHashes.push(tokenNameHashObj.digest());
|
|
528
|
+
const tokenTickerHashObj = sha256.create();
|
|
529
|
+
if (!createInput.tokenTicker || createInput.tokenTicker.length === 0) {
|
|
530
|
+
throw new ValidationError("token ticker cannot be empty", {
|
|
531
|
+
field: "tokenInputs.createInput.tokenTicker"
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
if (createInput.tokenTicker.length > 6) {
|
|
535
|
+
throw new ValidationError("token ticker cannot be longer than 6 bytes", {
|
|
536
|
+
field: "tokenInputs.createInput.tokenTicker",
|
|
537
|
+
value: createInput.tokenTicker,
|
|
538
|
+
expectedLength: 6,
|
|
539
|
+
actualLength: createInput.tokenTicker.length
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
const tokenTickerEncoder = new TextEncoder();
|
|
543
|
+
tokenTickerHashObj.update(
|
|
544
|
+
tokenTickerEncoder.encode(createInput.tokenTicker)
|
|
545
|
+
);
|
|
546
|
+
allHashes.push(tokenTickerHashObj.digest());
|
|
547
|
+
const decimalsHashObj = sha256.create();
|
|
548
|
+
const decimalsBytes = new Uint8Array(4);
|
|
549
|
+
new DataView(decimalsBytes.buffer).setUint32(
|
|
550
|
+
0,
|
|
551
|
+
createInput.decimals,
|
|
552
|
+
false
|
|
553
|
+
);
|
|
554
|
+
decimalsHashObj.update(decimalsBytes);
|
|
555
|
+
allHashes.push(decimalsHashObj.digest());
|
|
556
|
+
const maxSupplyHashObj = sha256.create();
|
|
557
|
+
if (!createInput.maxSupply) {
|
|
558
|
+
throw new ValidationError("max supply cannot be nil", {
|
|
559
|
+
field: "tokenInputs.createInput.maxSupply"
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
if (createInput.maxSupply.length !== 16) {
|
|
563
|
+
throw new ValidationError("max supply must be exactly 16 bytes", {
|
|
564
|
+
field: "tokenInputs.createInput.maxSupply",
|
|
565
|
+
value: createInput.maxSupply,
|
|
566
|
+
expectedLength: 16,
|
|
567
|
+
actualLength: createInput.maxSupply.length
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
maxSupplyHashObj.update(createInput.maxSupply);
|
|
571
|
+
allHashes.push(maxSupplyHashObj.digest());
|
|
572
|
+
const isFreezableHashObj = sha256.create();
|
|
573
|
+
isFreezableHashObj.update(
|
|
574
|
+
new Uint8Array([createInput.isFreezable ? 1 : 0])
|
|
575
|
+
);
|
|
576
|
+
allHashes.push(isFreezableHashObj.digest());
|
|
577
|
+
const creationEntityHashObj = sha256.create();
|
|
578
|
+
if (!partialHash && createInput.creationEntityPublicKey) {
|
|
579
|
+
creationEntityHashObj.update(createInput.creationEntityPublicKey);
|
|
580
|
+
}
|
|
581
|
+
allHashes.push(creationEntityHashObj.digest());
|
|
385
582
|
}
|
|
386
583
|
if (!tokenTransaction.tokenOutputs) {
|
|
387
584
|
throw new ValidationError("token outputs cannot be null", {
|
|
388
585
|
field: "tokenOutputs"
|
|
389
586
|
});
|
|
390
587
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
588
|
+
const outputsLenHashObj = sha256.create();
|
|
589
|
+
const outputsLenBytes = new Uint8Array(4);
|
|
590
|
+
new DataView(outputsLenBytes.buffer).setUint32(
|
|
591
|
+
0,
|
|
592
|
+
tokenTransaction.tokenOutputs.length,
|
|
593
|
+
false
|
|
594
|
+
);
|
|
595
|
+
outputsLenHashObj.update(outputsLenBytes);
|
|
596
|
+
allHashes.push(outputsLenHashObj.digest());
|
|
396
597
|
for (const [i, output] of tokenTransaction.tokenOutputs.entries()) {
|
|
397
598
|
if (!output) {
|
|
398
599
|
throw new ValidationError(`output cannot be null at index ${i}`, {
|
|
@@ -451,18 +652,16 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
451
652
|
);
|
|
452
653
|
hashObj2.update(locktimeBytes);
|
|
453
654
|
}
|
|
454
|
-
if (output.tokenPublicKey) {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
`token public key at index ${i} cannot be empty`,
|
|
458
|
-
{
|
|
459
|
-
field: `tokenOutputs[${i}].tokenPublicKey`,
|
|
460
|
-
index: i
|
|
461
|
-
}
|
|
462
|
-
);
|
|
463
|
-
}
|
|
655
|
+
if (!output.tokenPublicKey || output.tokenPublicKey.length === 0) {
|
|
656
|
+
hashObj2.update(new Uint8Array(33));
|
|
657
|
+
} else {
|
|
464
658
|
hashObj2.update(output.tokenPublicKey);
|
|
465
659
|
}
|
|
660
|
+
if (!output.tokenIdentifier || output.tokenIdentifier.length === 0) {
|
|
661
|
+
hashObj2.update(new Uint8Array(32));
|
|
662
|
+
} else {
|
|
663
|
+
hashObj2.update(output.tokenIdentifier);
|
|
664
|
+
}
|
|
466
665
|
if (output.tokenAmount) {
|
|
467
666
|
if (output.tokenAmount.length === 0) {
|
|
468
667
|
throw new ValidationError(
|
|
@@ -503,6 +702,15 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
503
702
|
}
|
|
504
703
|
return a.length - b.length;
|
|
505
704
|
});
|
|
705
|
+
const operatorLenHashObj = sha256.create();
|
|
706
|
+
const operatorLenBytes = new Uint8Array(4);
|
|
707
|
+
new DataView(operatorLenBytes.buffer).setUint32(
|
|
708
|
+
0,
|
|
709
|
+
sortedPubKeys.length,
|
|
710
|
+
false
|
|
711
|
+
);
|
|
712
|
+
operatorLenHashObj.update(operatorLenBytes);
|
|
713
|
+
allHashes.push(operatorLenHashObj.digest());
|
|
506
714
|
for (const [i, pubKey] of sortedPubKeys.entries()) {
|
|
507
715
|
if (!pubKey) {
|
|
508
716
|
throw new ValidationError(
|
|
@@ -538,7 +746,15 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
538
746
|
allHashes.push(hashObj.digest());
|
|
539
747
|
const clientTimestampHashObj = sha256.create();
|
|
540
748
|
const clientCreatedTs = tokenTransaction.clientCreatedTimestamp;
|
|
541
|
-
|
|
749
|
+
if (!clientCreatedTs) {
|
|
750
|
+
throw new ValidationError(
|
|
751
|
+
"client created timestamp cannot be null for V1 token transactions",
|
|
752
|
+
{
|
|
753
|
+
field: "clientCreatedTimestamp"
|
|
754
|
+
}
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
const clientUnixTime = clientCreatedTs.getTime();
|
|
542
758
|
const clientTimestampBytes = new Uint8Array(8);
|
|
543
759
|
new DataView(clientTimestampBytes.buffer).setBigUint64(
|
|
544
760
|
0,
|
|
@@ -631,7 +847,7 @@ function areByteArraysEqual(a, b) {
|
|
|
631
847
|
function hasDuplicates(array) {
|
|
632
848
|
return new Set(array).size !== array.length;
|
|
633
849
|
}
|
|
634
|
-
function
|
|
850
|
+
function validateTokenTransactionV0(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
|
|
635
851
|
if (finalTokenTransaction.network !== partialTokenTransaction.network) {
|
|
636
852
|
throw new InternalValidationError(
|
|
637
853
|
"Network mismatch in response token transaction",
|
|
@@ -788,7 +1004,251 @@ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction
|
|
|
788
1004
|
}
|
|
789
1005
|
);
|
|
790
1006
|
}
|
|
1007
|
+
if (finalOutput.tokenPublicKey !== void 0 && partialOutput.tokenPublicKey !== void 0 && !areByteArraysEqual(
|
|
1008
|
+
finalOutput.tokenPublicKey,
|
|
1009
|
+
partialOutput.tokenPublicKey
|
|
1010
|
+
)) {
|
|
1011
|
+
throw new InternalValidationError(
|
|
1012
|
+
"Token public key mismatch in token output",
|
|
1013
|
+
{
|
|
1014
|
+
outputIndex: i,
|
|
1015
|
+
value: finalOutput.tokenPublicKey?.toString(),
|
|
1016
|
+
expected: partialOutput.tokenPublicKey?.toString()
|
|
1017
|
+
}
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
if (!areByteArraysEqual(finalOutput.tokenAmount, partialOutput.tokenAmount)) {
|
|
1021
|
+
throw new InternalValidationError(
|
|
1022
|
+
"Token amount mismatch in token output",
|
|
1023
|
+
{
|
|
1024
|
+
outputIndex: i,
|
|
1025
|
+
value: finalOutput.tokenAmount.toString(),
|
|
1026
|
+
expected: partialOutput.tokenAmount.toString()
|
|
1027
|
+
}
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
1030
|
+
if (finalOutput.withdrawBondSats !== void 0) {
|
|
1031
|
+
if (finalOutput.withdrawBondSats !== expectedWithdrawBondSats) {
|
|
1032
|
+
throw new InternalValidationError(
|
|
1033
|
+
"Withdraw bond sats mismatch in token output",
|
|
1034
|
+
{
|
|
1035
|
+
outputIndex: i,
|
|
1036
|
+
value: finalOutput.withdrawBondSats,
|
|
1037
|
+
expected: expectedWithdrawBondSats
|
|
1038
|
+
}
|
|
1039
|
+
);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
if (finalOutput.withdrawRelativeBlockLocktime !== void 0) {
|
|
1043
|
+
if (finalOutput.withdrawRelativeBlockLocktime !== expectedWithdrawRelativeBlockLocktime) {
|
|
1044
|
+
throw new InternalValidationError(
|
|
1045
|
+
"Withdraw relative block locktime mismatch in token output",
|
|
1046
|
+
{
|
|
1047
|
+
outputIndex: i,
|
|
1048
|
+
value: finalOutput.withdrawRelativeBlockLocktime,
|
|
1049
|
+
expected: expectedWithdrawRelativeBlockLocktime
|
|
1050
|
+
}
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
if (keyshareInfo.threshold !== expectedThreshold) {
|
|
1055
|
+
throw new InternalValidationError(
|
|
1056
|
+
"Threshold mismatch: expected " + expectedThreshold + " but got " + keyshareInfo.threshold,
|
|
1057
|
+
{
|
|
1058
|
+
field: "threshold",
|
|
1059
|
+
value: keyshareInfo.threshold,
|
|
1060
|
+
expected: expectedThreshold
|
|
1061
|
+
}
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
if (keyshareInfo.ownerIdentifiers.length !== Object.keys(signingOperators).length) {
|
|
1066
|
+
throw new InternalValidationError(
|
|
1067
|
+
`Keyshare operator count (${keyshareInfo.ownerIdentifiers.length}) does not match signing operator count (${Object.keys(signingOperators).length})`,
|
|
1068
|
+
{
|
|
1069
|
+
keyshareInfo: keyshareInfo.ownerIdentifiers.length,
|
|
1070
|
+
signingOperators: Object.keys(signingOperators).length
|
|
1071
|
+
}
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
if (hasDuplicates(keyshareInfo.ownerIdentifiers)) {
|
|
1075
|
+
throw new InternalValidationError(
|
|
1076
|
+
"Duplicate ownerIdentifiers found in keyshareInfo",
|
|
1077
|
+
{
|
|
1078
|
+
keyshareInfo: keyshareInfo.ownerIdentifiers
|
|
1079
|
+
}
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
for (const identifier of keyshareInfo.ownerIdentifiers) {
|
|
1083
|
+
if (!signingOperators[identifier]) {
|
|
1084
|
+
throw new InternalValidationError(
|
|
1085
|
+
`Keyshare operator ${identifier} not found in signing operator list`,
|
|
1086
|
+
{
|
|
1087
|
+
keyshareInfo: identifier,
|
|
1088
|
+
signingOperators: Object.keys(signingOperators)
|
|
1089
|
+
}
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
|
|
1095
|
+
if (finalTokenTransaction.network !== partialTokenTransaction.network) {
|
|
1096
|
+
throw new InternalValidationError(
|
|
1097
|
+
"Network mismatch in response token transaction",
|
|
1098
|
+
{
|
|
1099
|
+
value: finalTokenTransaction.network,
|
|
1100
|
+
expected: partialTokenTransaction.network
|
|
1101
|
+
}
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
1104
|
+
if (!finalTokenTransaction.tokenInputs) {
|
|
1105
|
+
throw new InternalValidationError(
|
|
1106
|
+
"Token inputs missing in final transaction",
|
|
1107
|
+
{
|
|
1108
|
+
value: finalTokenTransaction
|
|
1109
|
+
}
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
if (!partialTokenTransaction.tokenInputs) {
|
|
1113
|
+
throw new InternalValidationError(
|
|
1114
|
+
"Token inputs missing in partial transaction",
|
|
1115
|
+
{
|
|
1116
|
+
value: partialTokenTransaction
|
|
1117
|
+
}
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
if (finalTokenTransaction.tokenInputs.$case !== partialTokenTransaction.tokenInputs.$case) {
|
|
1121
|
+
throw new InternalValidationError(
|
|
1122
|
+
`Transaction type mismatch: final transaction has ${finalTokenTransaction.tokenInputs.$case}, partial transaction has ${partialTokenTransaction.tokenInputs.$case}`,
|
|
1123
|
+
{
|
|
1124
|
+
value: finalTokenTransaction.tokenInputs.$case,
|
|
1125
|
+
expected: partialTokenTransaction.tokenInputs.$case
|
|
1126
|
+
}
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
if (finalTokenTransaction.sparkOperatorIdentityPublicKeys.length !== partialTokenTransaction.sparkOperatorIdentityPublicKeys.length) {
|
|
1130
|
+
throw new InternalValidationError(
|
|
1131
|
+
"Spark operator identity public keys count mismatch",
|
|
1132
|
+
{
|
|
1133
|
+
value: finalTokenTransaction.sparkOperatorIdentityPublicKeys.length,
|
|
1134
|
+
expected: partialTokenTransaction.sparkOperatorIdentityPublicKeys.length
|
|
1135
|
+
}
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1138
|
+
if (partialTokenTransaction.tokenInputs.$case === "mintInput" && finalTokenTransaction.tokenInputs.$case === "mintInput") {
|
|
1139
|
+
const finalMintInput = finalTokenTransaction.tokenInputs.mintInput;
|
|
1140
|
+
const partialMintInput = partialTokenTransaction.tokenInputs.mintInput;
|
|
1141
|
+
if (!areByteArraysEqual(
|
|
1142
|
+
finalMintInput.issuerPublicKey,
|
|
1143
|
+
partialMintInput.issuerPublicKey
|
|
1144
|
+
)) {
|
|
1145
|
+
throw new InternalValidationError(
|
|
1146
|
+
"Issuer public key mismatch in mint input",
|
|
1147
|
+
{
|
|
1148
|
+
value: finalMintInput.issuerPublicKey.toString(),
|
|
1149
|
+
expected: partialMintInput.issuerPublicKey.toString()
|
|
1150
|
+
}
|
|
1151
|
+
);
|
|
1152
|
+
}
|
|
1153
|
+
} else if (partialTokenTransaction.tokenInputs.$case === "transferInput" && finalTokenTransaction.tokenInputs.$case === "transferInput") {
|
|
1154
|
+
const finalTransferInput = finalTokenTransaction.tokenInputs.transferInput;
|
|
1155
|
+
const partialTransferInput = partialTokenTransaction.tokenInputs.transferInput;
|
|
1156
|
+
if (finalTransferInput.outputsToSpend.length !== partialTransferInput.outputsToSpend.length) {
|
|
1157
|
+
throw new InternalValidationError(
|
|
1158
|
+
"Outputs to spend count mismatch in transfer input",
|
|
1159
|
+
{
|
|
1160
|
+
value: finalTransferInput.outputsToSpend.length,
|
|
1161
|
+
expected: partialTransferInput.outputsToSpend.length
|
|
1162
|
+
}
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
for (let i = 0; i < finalTransferInput.outputsToSpend.length; i++) {
|
|
1166
|
+
const finalOutput = finalTransferInput.outputsToSpend[i];
|
|
1167
|
+
const partialOutput = partialTransferInput.outputsToSpend[i];
|
|
1168
|
+
if (!finalOutput) {
|
|
1169
|
+
throw new InternalValidationError(
|
|
1170
|
+
"Token output to spend missing in final transaction",
|
|
1171
|
+
{
|
|
1172
|
+
outputIndex: i,
|
|
1173
|
+
value: finalOutput
|
|
1174
|
+
}
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
if (!partialOutput) {
|
|
1178
|
+
throw new InternalValidationError(
|
|
1179
|
+
"Token output to spend missing in partial transaction",
|
|
1180
|
+
{
|
|
1181
|
+
outputIndex: i,
|
|
1182
|
+
value: partialOutput
|
|
1183
|
+
}
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
if (!areByteArraysEqual(
|
|
1187
|
+
finalOutput.prevTokenTransactionHash,
|
|
1188
|
+
partialOutput.prevTokenTransactionHash
|
|
1189
|
+
)) {
|
|
1190
|
+
throw new InternalValidationError(
|
|
1191
|
+
"Previous token transaction hash mismatch in transfer input",
|
|
1192
|
+
{
|
|
1193
|
+
outputIndex: i,
|
|
1194
|
+
value: finalOutput.prevTokenTransactionHash.toString(),
|
|
1195
|
+
expected: partialOutput.prevTokenTransactionHash.toString()
|
|
1196
|
+
}
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
if (finalOutput.prevTokenTransactionVout !== partialOutput.prevTokenTransactionVout) {
|
|
1200
|
+
throw new InternalValidationError(
|
|
1201
|
+
"Previous token transaction vout mismatch in transfer input",
|
|
1202
|
+
{
|
|
1203
|
+
outputIndex: i,
|
|
1204
|
+
value: finalOutput.prevTokenTransactionVout,
|
|
1205
|
+
expected: partialOutput.prevTokenTransactionVout
|
|
1206
|
+
}
|
|
1207
|
+
);
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
if (finalTokenTransaction.tokenOutputs.length !== partialTokenTransaction.tokenOutputs.length) {
|
|
1212
|
+
throw new InternalValidationError("Token outputs count mismatch", {
|
|
1213
|
+
value: finalTokenTransaction.tokenOutputs.length,
|
|
1214
|
+
expected: partialTokenTransaction.tokenOutputs.length
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
for (let i = 0; i < finalTokenTransaction.tokenOutputs.length; i++) {
|
|
1218
|
+
const finalOutput = finalTokenTransaction.tokenOutputs[i];
|
|
1219
|
+
const partialOutput = partialTokenTransaction.tokenOutputs[i];
|
|
1220
|
+
if (!finalOutput) {
|
|
1221
|
+
throw new InternalValidationError(
|
|
1222
|
+
"Token output missing in final transaction",
|
|
1223
|
+
{
|
|
1224
|
+
outputIndex: i,
|
|
1225
|
+
value: finalOutput
|
|
1226
|
+
}
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1229
|
+
if (!partialOutput) {
|
|
1230
|
+
throw new InternalValidationError(
|
|
1231
|
+
"Token output missing in partial transaction",
|
|
1232
|
+
{
|
|
1233
|
+
outputIndex: i,
|
|
1234
|
+
value: partialOutput
|
|
1235
|
+
}
|
|
1236
|
+
);
|
|
1237
|
+
}
|
|
791
1238
|
if (!areByteArraysEqual(
|
|
1239
|
+
finalOutput.ownerPublicKey,
|
|
1240
|
+
partialOutput.ownerPublicKey
|
|
1241
|
+
)) {
|
|
1242
|
+
throw new InternalValidationError(
|
|
1243
|
+
"Owner public key mismatch in token output",
|
|
1244
|
+
{
|
|
1245
|
+
outputIndex: i,
|
|
1246
|
+
value: finalOutput.ownerPublicKey.toString(),
|
|
1247
|
+
expected: partialOutput.ownerPublicKey.toString()
|
|
1248
|
+
}
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
if (finalOutput.tokenPublicKey !== void 0 && partialOutput.tokenPublicKey !== void 0 && !areByteArraysEqual(
|
|
792
1252
|
finalOutput.tokenPublicKey,
|
|
793
1253
|
partialOutput.tokenPublicKey
|
|
794
1254
|
)) {
|
|
@@ -874,6 +1334,12 @@ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction
|
|
|
874
1334
|
);
|
|
875
1335
|
}
|
|
876
1336
|
}
|
|
1337
|
+
if (finalTokenTransaction.clientCreatedTimestamp.getTime() !== partialTokenTransaction.clientCreatedTimestamp.getTime()) {
|
|
1338
|
+
throw new InternalValidationError("Client created timestamp mismatch", {
|
|
1339
|
+
value: finalTokenTransaction.clientCreatedTimestamp,
|
|
1340
|
+
expected: partialTokenTransaction.clientCreatedTimestamp
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
877
1343
|
}
|
|
878
1344
|
|
|
879
1345
|
// src/services/token-transactions.ts
|
|
@@ -1063,7 +1529,8 @@ var TokenTransactionService = class {
|
|
|
1063
1529
|
},
|
|
1064
1530
|
tokenOutputs,
|
|
1065
1531
|
sparkOperatorIdentityPublicKeys: this.collectOperatorIdentityPublicKeys(),
|
|
1066
|
-
expiryTime: void 0
|
|
1532
|
+
expiryTime: void 0,
|
|
1533
|
+
clientCreatedTimestamp: /* @__PURE__ */ new Date()
|
|
1067
1534
|
};
|
|
1068
1535
|
}
|
|
1069
1536
|
collectOperatorIdentityPublicKeys() {
|
|
@@ -1272,7 +1739,7 @@ var TokenTransactionService = class {
|
|
|
1272
1739
|
if (!startResponse.keyshareInfo) {
|
|
1273
1740
|
throw new Error("Keyshare info missing in start response");
|
|
1274
1741
|
}
|
|
1275
|
-
|
|
1742
|
+
validateTokenTransactionV0(
|
|
1276
1743
|
startResponse.finalTokenTransaction,
|
|
1277
1744
|
tokenTransaction,
|
|
1278
1745
|
signingOperators,
|
|
@@ -1523,7 +1990,26 @@ var TokenTransactionService = class {
|
|
|
1523
1990
|
);
|
|
1524
1991
|
}
|
|
1525
1992
|
}
|
|
1526
|
-
async fetchOwnedTokenOutputs(
|
|
1993
|
+
async fetchOwnedTokenOutputs(params) {
|
|
1994
|
+
if (this.config.getTokenTransactionVersion() === "V0") {
|
|
1995
|
+
return this.fetchOwnedTokenOutputsV0(params);
|
|
1996
|
+
} else {
|
|
1997
|
+
return this.fetchOwnedTokenOutputsV1(params);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
async queryTokenTransactions(params) {
|
|
2001
|
+
if (this.config.getTokenTransactionVersion() === "V0") {
|
|
2002
|
+
return this.queryTokenTransactionsV0(params);
|
|
2003
|
+
} else {
|
|
2004
|
+
return this.queryTokenTransactionsV1(params);
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
async fetchOwnedTokenOutputsV0(params) {
|
|
2008
|
+
const {
|
|
2009
|
+
ownerPublicKeys,
|
|
2010
|
+
issuerPublicKeys: tokenPublicKeys = [],
|
|
2011
|
+
tokenIdentifiers = []
|
|
2012
|
+
} = params;
|
|
1527
2013
|
const sparkClient = await this.connectionManager.createSparkClient(
|
|
1528
2014
|
this.config.getCoordinatorAddress()
|
|
1529
2015
|
);
|
|
@@ -1531,6 +2017,7 @@ var TokenTransactionService = class {
|
|
|
1531
2017
|
const result = await sparkClient.query_token_outputs({
|
|
1532
2018
|
ownerPublicKeys,
|
|
1533
2019
|
tokenPublicKeys,
|
|
2020
|
+
tokenIdentifiers,
|
|
1534
2021
|
network: this.config.getNetworkProto()
|
|
1535
2022
|
});
|
|
1536
2023
|
return result.outputsWithPreviousTransactionData;
|
|
@@ -1538,7 +2025,7 @@ var TokenTransactionService = class {
|
|
|
1538
2025
|
throw new NetworkError(
|
|
1539
2026
|
"Failed to fetch owned token outputs",
|
|
1540
2027
|
{
|
|
1541
|
-
operation: "query_token_outputs",
|
|
2028
|
+
operation: "spark.query_token_outputs",
|
|
1542
2029
|
errorCount: 1,
|
|
1543
2030
|
errors: error instanceof Error ? error.message : String(error)
|
|
1544
2031
|
},
|
|
@@ -1546,11 +2033,127 @@ var TokenTransactionService = class {
|
|
|
1546
2033
|
);
|
|
1547
2034
|
}
|
|
1548
2035
|
}
|
|
1549
|
-
async
|
|
1550
|
-
const
|
|
1551
|
-
|
|
1552
|
-
[]
|
|
2036
|
+
async fetchOwnedTokenOutputsV1(params) {
|
|
2037
|
+
const {
|
|
2038
|
+
ownerPublicKeys,
|
|
2039
|
+
issuerPublicKeys = [],
|
|
2040
|
+
tokenIdentifiers = []
|
|
2041
|
+
} = params;
|
|
2042
|
+
const tokenClient = await this.connectionManager.createSparkTokenClient(
|
|
2043
|
+
this.config.getCoordinatorAddress()
|
|
2044
|
+
);
|
|
2045
|
+
try {
|
|
2046
|
+
const result = await tokenClient.query_token_outputs({
|
|
2047
|
+
ownerPublicKeys,
|
|
2048
|
+
issuerPublicKeys,
|
|
2049
|
+
tokenIdentifiers,
|
|
2050
|
+
network: this.config.getNetworkProto()
|
|
2051
|
+
});
|
|
2052
|
+
return result.outputsWithPreviousTransactionData;
|
|
2053
|
+
} catch (error) {
|
|
2054
|
+
throw new NetworkError(
|
|
2055
|
+
"Failed to fetch owned token outputs",
|
|
2056
|
+
{
|
|
2057
|
+
operation: "spark_token.query_token_outputs",
|
|
2058
|
+
errorCount: 1,
|
|
2059
|
+
errors: error instanceof Error ? error.message : String(error)
|
|
2060
|
+
},
|
|
2061
|
+
error
|
|
2062
|
+
);
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
async queryTokenTransactionsV0(params) {
|
|
2066
|
+
const {
|
|
2067
|
+
ownerPublicKeys,
|
|
2068
|
+
issuerPublicKeys,
|
|
2069
|
+
tokenTransactionHashes,
|
|
2070
|
+
tokenIdentifiers,
|
|
2071
|
+
outputIds
|
|
2072
|
+
} = params;
|
|
2073
|
+
const sparkClient = await this.connectionManager.createSparkClient(
|
|
2074
|
+
this.config.getCoordinatorAddress()
|
|
1553
2075
|
);
|
|
2076
|
+
let queryParams = {
|
|
2077
|
+
tokenPublicKeys: issuerPublicKeys?.map(hexToBytes),
|
|
2078
|
+
ownerPublicKeys: ownerPublicKeys?.map(hexToBytes),
|
|
2079
|
+
tokenIdentifiers: tokenIdentifiers?.map(hexToBytes),
|
|
2080
|
+
tokenTransactionHashes: tokenTransactionHashes?.map(hexToBytes),
|
|
2081
|
+
outputIds: outputIds || [],
|
|
2082
|
+
limit: 100,
|
|
2083
|
+
offset: 0
|
|
2084
|
+
};
|
|
2085
|
+
try {
|
|
2086
|
+
const response = await sparkClient.query_token_transactions(queryParams);
|
|
2087
|
+
return response.tokenTransactionsWithStatus.map((tx) => {
|
|
2088
|
+
const v1TokenTransaction = {
|
|
2089
|
+
version: 1,
|
|
2090
|
+
network: tx.tokenTransaction.network,
|
|
2091
|
+
tokenInputs: tx.tokenTransaction.tokenInputs,
|
|
2092
|
+
tokenOutputs: tx.tokenTransaction.tokenOutputs,
|
|
2093
|
+
sparkOperatorIdentityPublicKeys: tx.tokenTransaction.sparkOperatorIdentityPublicKeys,
|
|
2094
|
+
expiryTime: void 0,
|
|
2095
|
+
// V0 doesn't have expiry time
|
|
2096
|
+
clientCreatedTimestamp: tx.tokenTransaction?.tokenInputs?.$case === "mintInput" ? new Date(
|
|
2097
|
+
tx.tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp * 1e3
|
|
2098
|
+
) : /* @__PURE__ */ new Date()
|
|
2099
|
+
};
|
|
2100
|
+
return {
|
|
2101
|
+
tokenTransaction: v1TokenTransaction,
|
|
2102
|
+
status: tx.status,
|
|
2103
|
+
confirmationMetadata: tx.confirmationMetadata
|
|
2104
|
+
};
|
|
2105
|
+
});
|
|
2106
|
+
} catch (error) {
|
|
2107
|
+
throw new NetworkError(
|
|
2108
|
+
"Failed to query token transactions",
|
|
2109
|
+
{
|
|
2110
|
+
operation: "spark.query_token_transactions",
|
|
2111
|
+
errorCount: 1,
|
|
2112
|
+
errors: error instanceof Error ? error.message : String(error)
|
|
2113
|
+
},
|
|
2114
|
+
error
|
|
2115
|
+
);
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
async queryTokenTransactionsV1(params) {
|
|
2119
|
+
const {
|
|
2120
|
+
ownerPublicKeys,
|
|
2121
|
+
issuerPublicKeys,
|
|
2122
|
+
tokenTransactionHashes,
|
|
2123
|
+
tokenIdentifiers,
|
|
2124
|
+
outputIds
|
|
2125
|
+
} = params;
|
|
2126
|
+
const tokenClient = await this.connectionManager.createSparkTokenClient(
|
|
2127
|
+
this.config.getCoordinatorAddress()
|
|
2128
|
+
);
|
|
2129
|
+
let queryParams = {
|
|
2130
|
+
issuerPublicKeys: issuerPublicKeys?.map(hexToBytes),
|
|
2131
|
+
ownerPublicKeys: ownerPublicKeys?.map(hexToBytes),
|
|
2132
|
+
tokenIdentifiers: tokenIdentifiers?.map(hexToBytes),
|
|
2133
|
+
tokenTransactionHashes: tokenTransactionHashes?.map(hexToBytes),
|
|
2134
|
+
outputIds: outputIds || [],
|
|
2135
|
+
limit: 100,
|
|
2136
|
+
offset: 0
|
|
2137
|
+
};
|
|
2138
|
+
try {
|
|
2139
|
+
const response = await tokenClient.query_token_transactions(queryParams);
|
|
2140
|
+
return response.tokenTransactionsWithStatus;
|
|
2141
|
+
} catch (error) {
|
|
2142
|
+
throw new NetworkError(
|
|
2143
|
+
"Failed to query token transactions",
|
|
2144
|
+
{
|
|
2145
|
+
operation: "spark_token.query_token_transactions",
|
|
2146
|
+
errorCount: 1,
|
|
2147
|
+
errors: error instanceof Error ? error.message : String(error)
|
|
2148
|
+
},
|
|
2149
|
+
error
|
|
2150
|
+
);
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
async syncTokenOutputs(tokenOutputs) {
|
|
2154
|
+
const unsortedTokenOutputs = await this.fetchOwnedTokenOutputs({
|
|
2155
|
+
ownerPublicKeys: await this.config.signer.getTrackedPublicKeys()
|
|
2156
|
+
});
|
|
1554
2157
|
unsortedTokenOutputs.forEach((output) => {
|
|
1555
2158
|
const tokenKey = bytesToHex(output.output.tokenPublicKey);
|
|
1556
2159
|
const index = output.previousTransactionVout;
|