@buildonspark/spark-sdk 0.1.43 → 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 +16 -0
- package/dist/{RequestLightningSendInput-D7fZdT4A.d.ts → RequestLightningSendInput-DEPd_fPO.d.ts} +43 -4
- package/dist/{RequestLightningSendInput-Na1mHdWg.d.cts → RequestLightningSendInput-Du0z7Om7.d.cts} +43 -4
- 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-IRW5TWMH.js → chunk-5FUB65LX.js} +7 -9
- package/dist/{chunk-BUTZWYBW.js → chunk-6264CGDM.js} +4 -4
- package/dist/{chunk-VFJQNBFX.js → chunk-7V6N75CC.js} +5 -2
- package/dist/{chunk-M6A4KFIG.js → chunk-BGGEVUJK.js} +1505 -445
- package/dist/{chunk-DQYKQJRZ.js → chunk-C2S227QR.js} +675 -52
- package/dist/{chunk-GYQR4B4P.js → chunk-GZ5IPPJ2.js} +2 -2
- package/dist/{chunk-6AFUC5M2.js → chunk-HWJWKEIU.js} +8 -2
- package/dist/{chunk-TOSP3INR.js → chunk-I54FARY2.js} +4 -2
- package/dist/{chunk-WWOTVNPP.js → chunk-J2IE4Z7Y.js} +544 -431
- package/dist/{chunk-O4RYNJNB.js → chunk-KMUMFYFX.js} +3 -3
- package/dist/chunk-LHRD2WT6.js +2374 -0
- package/dist/{chunk-ABZA6R5S.js → chunk-NTFKFRQ2.js} +1 -1
- package/dist/{chunk-MIVX3GHD.js → chunk-OBFKIEMP.js} +1 -1
- package/dist/{chunk-HRQRRDSS.js → chunk-PQN3C2MF.js} +15 -15
- package/dist/{chunk-DOA6QXYQ.js → chunk-R5PXJZQS.js} +3 -1
- package/dist/{chunk-TIUBYNN5.js → chunk-YUPMXTCJ.js} +4 -4
- package/dist/graphql/objects/index.d.cts +6 -43
- package/dist/graphql/objects/index.d.ts +6 -43
- package/dist/graphql/objects/index.js +1 -1
- package/dist/index-B2AwKW5J.d.cts +214 -0
- package/dist/index-CJDi1HWc.d.ts +214 -0
- package/dist/index.cjs +4150 -1026
- package/dist/index.d.cts +764 -19
- package/dist/index.d.ts +764 -19
- package/dist/index.js +17 -21
- package/dist/index.node.cjs +4153 -1033
- package/dist/index.node.d.cts +10 -8
- package/dist/index.node.d.ts +10 -8
- package/dist/index.node.js +20 -28
- package/dist/native/index.cjs +4166 -1042
- package/dist/native/index.d.cts +369 -108
- package/dist/native/index.d.ts +369 -108
- package/dist/native/index.js +4138 -1015
- package/dist/{network-xkBSpaTn.d.ts → network-BTJl-Sul.d.ts} +1 -1
- package/dist/{network-D5lKssVl.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 +1502 -442
- package/dist/proto/spark.d.cts +1 -1
- package/dist/proto/spark.d.ts +1 -1
- package/dist/proto/spark.js +5 -5
- package/dist/proto/spark_token.cjs +1515 -56
- 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-B-q9py_P.d.cts → sdk-types-B0SwjolI.d.cts} +1 -1
- package/dist/{sdk-types-BPoPgzda.d.ts → sdk-types-Cc4l4kb1.d.ts} +1 -1
- package/dist/services/config.cjs +7 -3
- 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 +2938 -646
- 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 +6381 -3461
- 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 +227 -21
- 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 +868 -244
- 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 +4 -1
- 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 +5 -2
- 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-wqesWifN.d.ts → signer-BocS_J6B.d.ts} +2 -6
- package/dist/{signer-IO3oMRNj.d.cts → signer-DKS0AJkw.d.cts} +2 -6
- package/dist/{spark-CDm4gqS6.d.cts → spark-dM7EYXYQ.d.cts} +138 -42
- package/dist/{spark-CDm4gqS6.d.ts → spark-dM7EYXYQ.d.ts} +138 -42
- 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 +1503 -443
- package/dist/types/index.d.cts +6 -5
- package/dist/types/index.d.ts +6 -5
- package/dist/types/index.js +3 -3
- package/dist/types-C-Rp0Oo7.d.cts +46 -0
- package/dist/types-C-Rp0Oo7.d.ts +46 -0
- package/dist/utils/index.cjs +358 -36
- package/dist/utils/index.d.cts +14 -134
- package/dist/utils/index.d.ts +14 -134
- package/dist/utils/index.js +8 -8
- package/package.json +21 -1
- package/src/constants.ts +5 -1
- package/src/graphql/client.ts +28 -0
- package/src/graphql/mutations/RequestCoopExit.ts +6 -0
- package/src/graphql/mutations/RequestSwapLeaves.ts +2 -0
- package/src/graphql/queries/GetCoopExitFeeQuote.ts +20 -0
- 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 +1924 -525
- 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 +209 -9
- package/src/services/transfer.ts +22 -3
- package/src/services/tree-creation.ts +13 -0
- package/src/services/wallet-config.ts +2 -1
- package/src/spark-wallet/spark-wallet.node.ts +3 -7
- package/src/spark-wallet/spark-wallet.ts +376 -232
- package/src/spark-wallet/types.ts +39 -3
- package/src/tests/bolt11-spark.test.ts +7 -15
- package/src/tests/integration/deposit.test.ts +16 -0
- package/src/tests/integration/ssp/coop-exit.test.ts +85 -21
- package/src/tests/integration/ssp/swap.test.ts +47 -0
- 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 -22
- package/src/utils/token-hashing.ts +346 -52
- 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 +2 -8
- package/dist/chunk-VA7MV4MZ.js +0 -1073
- package/dist/index-7RYRH5wc.d.ts +0 -815
- package/dist/index-BJOc8Ur-.d.cts +0 -815
- package/dist/wasm-7OWFHDMS.js +0 -21
- package/src/logger.ts +0 -3
|
@@ -142,6 +142,215 @@ var InternalValidationError = class extends SparkSDKError {
|
|
|
142
142
|
}
|
|
143
143
|
};
|
|
144
144
|
|
|
145
|
+
// src/proto/spark_token.ts
|
|
146
|
+
var import_wire5 = require("@bufbuild/protobuf/wire");
|
|
147
|
+
|
|
148
|
+
// src/proto/google/protobuf/timestamp.ts
|
|
149
|
+
var import_wire = require("@bufbuild/protobuf/wire");
|
|
150
|
+
|
|
151
|
+
// src/proto/spark.ts
|
|
152
|
+
var import_wire4 = require("@bufbuild/protobuf/wire");
|
|
153
|
+
|
|
154
|
+
// src/proto/common.ts
|
|
155
|
+
var import_wire2 = require("@bufbuild/protobuf/wire");
|
|
156
|
+
|
|
157
|
+
// src/proto/google/protobuf/empty.ts
|
|
158
|
+
var import_wire3 = require("@bufbuild/protobuf/wire");
|
|
159
|
+
|
|
160
|
+
// src/proto/spark.ts
|
|
161
|
+
function createBaseSparkAddress() {
|
|
162
|
+
return { identityPublicKey: new Uint8Array(0), paymentIntentFields: void 0 };
|
|
163
|
+
}
|
|
164
|
+
var SparkAddress = {
|
|
165
|
+
encode(message, writer = new import_wire4.BinaryWriter()) {
|
|
166
|
+
if (message.identityPublicKey.length !== 0) {
|
|
167
|
+
writer.uint32(10).bytes(message.identityPublicKey);
|
|
168
|
+
}
|
|
169
|
+
if (message.paymentIntentFields !== void 0) {
|
|
170
|
+
PaymentIntentFields.encode(message.paymentIntentFields, writer.uint32(18).fork()).join();
|
|
171
|
+
}
|
|
172
|
+
return writer;
|
|
173
|
+
},
|
|
174
|
+
decode(input, length) {
|
|
175
|
+
const reader = input instanceof import_wire4.BinaryReader ? input : new import_wire4.BinaryReader(input);
|
|
176
|
+
const end = length === void 0 ? reader.len : reader.pos + length;
|
|
177
|
+
const message = createBaseSparkAddress();
|
|
178
|
+
while (reader.pos < end) {
|
|
179
|
+
const tag = reader.uint32();
|
|
180
|
+
switch (tag >>> 3) {
|
|
181
|
+
case 1: {
|
|
182
|
+
if (tag !== 10) {
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
message.identityPublicKey = reader.bytes();
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
case 2: {
|
|
189
|
+
if (tag !== 18) {
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
message.paymentIntentFields = PaymentIntentFields.decode(reader, reader.uint32());
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
reader.skip(tag & 7);
|
|
200
|
+
}
|
|
201
|
+
return message;
|
|
202
|
+
},
|
|
203
|
+
fromJSON(object) {
|
|
204
|
+
return {
|
|
205
|
+
identityPublicKey: isSet(object.identityPublicKey) ? bytesFromBase64(object.identityPublicKey) : new Uint8Array(0),
|
|
206
|
+
paymentIntentFields: isSet(object.paymentIntentFields) ? PaymentIntentFields.fromJSON(object.paymentIntentFields) : void 0
|
|
207
|
+
};
|
|
208
|
+
},
|
|
209
|
+
toJSON(message) {
|
|
210
|
+
const obj = {};
|
|
211
|
+
if (message.identityPublicKey.length !== 0) {
|
|
212
|
+
obj.identityPublicKey = base64FromBytes(message.identityPublicKey);
|
|
213
|
+
}
|
|
214
|
+
if (message.paymentIntentFields !== void 0) {
|
|
215
|
+
obj.paymentIntentFields = PaymentIntentFields.toJSON(message.paymentIntentFields);
|
|
216
|
+
}
|
|
217
|
+
return obj;
|
|
218
|
+
},
|
|
219
|
+
create(base) {
|
|
220
|
+
return SparkAddress.fromPartial(base ?? {});
|
|
221
|
+
},
|
|
222
|
+
fromPartial(object) {
|
|
223
|
+
const message = createBaseSparkAddress();
|
|
224
|
+
message.identityPublicKey = object.identityPublicKey ?? new Uint8Array(0);
|
|
225
|
+
message.paymentIntentFields = object.paymentIntentFields !== void 0 && object.paymentIntentFields !== null ? PaymentIntentFields.fromPartial(object.paymentIntentFields) : void 0;
|
|
226
|
+
return message;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
function createBasePaymentIntentFields() {
|
|
230
|
+
return { id: new Uint8Array(0), assetIdentifier: void 0, assetAmount: new Uint8Array(0), memo: void 0 };
|
|
231
|
+
}
|
|
232
|
+
var PaymentIntentFields = {
|
|
233
|
+
encode(message, writer = new import_wire4.BinaryWriter()) {
|
|
234
|
+
if (message.id.length !== 0) {
|
|
235
|
+
writer.uint32(10).bytes(message.id);
|
|
236
|
+
}
|
|
237
|
+
if (message.assetIdentifier !== void 0) {
|
|
238
|
+
writer.uint32(18).bytes(message.assetIdentifier);
|
|
239
|
+
}
|
|
240
|
+
if (message.assetAmount.length !== 0) {
|
|
241
|
+
writer.uint32(26).bytes(message.assetAmount);
|
|
242
|
+
}
|
|
243
|
+
if (message.memo !== void 0) {
|
|
244
|
+
writer.uint32(34).string(message.memo);
|
|
245
|
+
}
|
|
246
|
+
return writer;
|
|
247
|
+
},
|
|
248
|
+
decode(input, length) {
|
|
249
|
+
const reader = input instanceof import_wire4.BinaryReader ? input : new import_wire4.BinaryReader(input);
|
|
250
|
+
const end = length === void 0 ? reader.len : reader.pos + length;
|
|
251
|
+
const message = createBasePaymentIntentFields();
|
|
252
|
+
while (reader.pos < end) {
|
|
253
|
+
const tag = reader.uint32();
|
|
254
|
+
switch (tag >>> 3) {
|
|
255
|
+
case 1: {
|
|
256
|
+
if (tag !== 10) {
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
message.id = reader.bytes();
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
case 2: {
|
|
263
|
+
if (tag !== 18) {
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
message.assetIdentifier = reader.bytes();
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
case 3: {
|
|
270
|
+
if (tag !== 26) {
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
message.assetAmount = reader.bytes();
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
case 4: {
|
|
277
|
+
if (tag !== 34) {
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
message.memo = reader.string();
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
reader.skip(tag & 7);
|
|
288
|
+
}
|
|
289
|
+
return message;
|
|
290
|
+
},
|
|
291
|
+
fromJSON(object) {
|
|
292
|
+
return {
|
|
293
|
+
id: isSet(object.id) ? bytesFromBase64(object.id) : new Uint8Array(0),
|
|
294
|
+
assetIdentifier: isSet(object.assetIdentifier) ? bytesFromBase64(object.assetIdentifier) : void 0,
|
|
295
|
+
assetAmount: isSet(object.assetAmount) ? bytesFromBase64(object.assetAmount) : new Uint8Array(0),
|
|
296
|
+
memo: isSet(object.memo) ? globalThis.String(object.memo) : void 0
|
|
297
|
+
};
|
|
298
|
+
},
|
|
299
|
+
toJSON(message) {
|
|
300
|
+
const obj = {};
|
|
301
|
+
if (message.id.length !== 0) {
|
|
302
|
+
obj.id = base64FromBytes(message.id);
|
|
303
|
+
}
|
|
304
|
+
if (message.assetIdentifier !== void 0) {
|
|
305
|
+
obj.assetIdentifier = base64FromBytes(message.assetIdentifier);
|
|
306
|
+
}
|
|
307
|
+
if (message.assetAmount.length !== 0) {
|
|
308
|
+
obj.assetAmount = base64FromBytes(message.assetAmount);
|
|
309
|
+
}
|
|
310
|
+
if (message.memo !== void 0) {
|
|
311
|
+
obj.memo = message.memo;
|
|
312
|
+
}
|
|
313
|
+
return obj;
|
|
314
|
+
},
|
|
315
|
+
create(base) {
|
|
316
|
+
return PaymentIntentFields.fromPartial(base ?? {});
|
|
317
|
+
},
|
|
318
|
+
fromPartial(object) {
|
|
319
|
+
const message = createBasePaymentIntentFields();
|
|
320
|
+
message.id = object.id ?? new Uint8Array(0);
|
|
321
|
+
message.assetIdentifier = object.assetIdentifier ?? void 0;
|
|
322
|
+
message.assetAmount = object.assetAmount ?? new Uint8Array(0);
|
|
323
|
+
message.memo = object.memo ?? void 0;
|
|
324
|
+
return message;
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
function bytesFromBase64(b64) {
|
|
328
|
+
if (globalThis.Buffer) {
|
|
329
|
+
return Uint8Array.from(globalThis.Buffer.from(b64, "base64"));
|
|
330
|
+
} else {
|
|
331
|
+
const bin = globalThis.atob(b64);
|
|
332
|
+
const arr = new Uint8Array(bin.length);
|
|
333
|
+
for (let i = 0; i < bin.length; ++i) {
|
|
334
|
+
arr[i] = bin.charCodeAt(i);
|
|
335
|
+
}
|
|
336
|
+
return arr;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function base64FromBytes(arr) {
|
|
340
|
+
if (globalThis.Buffer) {
|
|
341
|
+
return globalThis.Buffer.from(arr).toString("base64");
|
|
342
|
+
} else {
|
|
343
|
+
const bin = [];
|
|
344
|
+
arr.forEach((byte) => {
|
|
345
|
+
bin.push(globalThis.String.fromCharCode(byte));
|
|
346
|
+
});
|
|
347
|
+
return globalThis.btoa(bin.join(""));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
function isSet(value) {
|
|
351
|
+
return value !== null && value !== void 0;
|
|
352
|
+
}
|
|
353
|
+
|
|
145
354
|
// src/utils/token-hashing.ts
|
|
146
355
|
function hashTokenTransaction(tokenTransaction, partialHash = false) {
|
|
147
356
|
switch (tokenTransaction.version) {
|
|
@@ -224,13 +433,21 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
|
|
|
224
433
|
});
|
|
225
434
|
}
|
|
226
435
|
hashObj2.update(issuerPubKey);
|
|
227
|
-
|
|
436
|
+
let timestampValue = 0;
|
|
437
|
+
const mintInput = tokenTransaction.tokenInputs.mintInput;
|
|
438
|
+
if ("issuerProvidedTimestamp" in mintInput) {
|
|
439
|
+
const v0MintInput = mintInput;
|
|
440
|
+
if (v0MintInput.issuerProvidedTimestamp != 0) {
|
|
441
|
+
timestampValue = v0MintInput.issuerProvidedTimestamp;
|
|
442
|
+
}
|
|
443
|
+
} else if ("clientCreatedTimestamp" in tokenTransaction && tokenTransaction.clientCreatedTimestamp) {
|
|
444
|
+
timestampValue = tokenTransaction.clientCreatedTimestamp.getTime();
|
|
445
|
+
}
|
|
446
|
+
if (timestampValue != 0) {
|
|
228
447
|
const timestampBytes = new Uint8Array(8);
|
|
229
448
|
new DataView(timestampBytes.buffer).setBigUint64(
|
|
230
449
|
0,
|
|
231
|
-
BigInt(
|
|
232
|
-
tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp
|
|
233
|
-
),
|
|
450
|
+
BigInt(timestampValue),
|
|
234
451
|
true
|
|
235
452
|
// true for little-endian to match Go implementation
|
|
236
453
|
);
|
|
@@ -239,12 +456,95 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
|
|
|
239
456
|
allHashes.push(hashObj2.digest());
|
|
240
457
|
}
|
|
241
458
|
}
|
|
459
|
+
if (tokenTransaction.tokenInputs?.$case === "createInput") {
|
|
460
|
+
const issuerPubKeyHashObj = import_sha2.sha256.create();
|
|
461
|
+
const createInput = tokenTransaction.tokenInputs.createInput;
|
|
462
|
+
if (!createInput.issuerPublicKey || createInput.issuerPublicKey.length === 0) {
|
|
463
|
+
throw new ValidationError("issuer public key cannot be nil or empty", {
|
|
464
|
+
field: "tokenInputs.createInput.issuerPublicKey"
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
issuerPubKeyHashObj.update(createInput.issuerPublicKey);
|
|
468
|
+
allHashes.push(issuerPubKeyHashObj.digest());
|
|
469
|
+
const tokenNameHashObj = import_sha2.sha256.create();
|
|
470
|
+
if (!createInput.tokenName || createInput.tokenName.length === 0) {
|
|
471
|
+
throw new ValidationError("token name cannot be empty", {
|
|
472
|
+
field: "tokenInputs.createInput.tokenName"
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
if (createInput.tokenName.length > 20) {
|
|
476
|
+
throw new ValidationError("token name cannot be longer than 20 bytes", {
|
|
477
|
+
field: "tokenInputs.createInput.tokenName",
|
|
478
|
+
value: createInput.tokenName,
|
|
479
|
+
expectedLength: 20,
|
|
480
|
+
actualLength: createInput.tokenName.length
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
const tokenNameBytes = new Uint8Array(20);
|
|
484
|
+
const tokenNameEncoder = new TextEncoder();
|
|
485
|
+
tokenNameBytes.set(tokenNameEncoder.encode(createInput.tokenName));
|
|
486
|
+
tokenNameHashObj.update(tokenNameBytes);
|
|
487
|
+
allHashes.push(tokenNameHashObj.digest());
|
|
488
|
+
const tokenTickerHashObj = import_sha2.sha256.create();
|
|
489
|
+
if (!createInput.tokenTicker || createInput.tokenTicker.length === 0) {
|
|
490
|
+
throw new ValidationError("token ticker cannot be empty", {
|
|
491
|
+
field: "tokenInputs.createInput.tokenTicker"
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
if (createInput.tokenTicker.length > 6) {
|
|
495
|
+
throw new ValidationError("token ticker cannot be longer than 6 bytes", {
|
|
496
|
+
field: "tokenInputs.createInput.tokenTicker",
|
|
497
|
+
value: createInput.tokenTicker,
|
|
498
|
+
expectedLength: 6,
|
|
499
|
+
actualLength: createInput.tokenTicker.length
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
const tokenTickerBytes = new Uint8Array(6);
|
|
503
|
+
const tokenTickerEncoder = new TextEncoder();
|
|
504
|
+
tokenTickerBytes.set(tokenTickerEncoder.encode(createInput.tokenTicker));
|
|
505
|
+
tokenTickerHashObj.update(tokenTickerBytes);
|
|
506
|
+
allHashes.push(tokenTickerHashObj.digest());
|
|
507
|
+
const decimalsHashObj = import_sha2.sha256.create();
|
|
508
|
+
const decimalsBytes = new Uint8Array(4);
|
|
509
|
+
new DataView(decimalsBytes.buffer).setUint32(
|
|
510
|
+
0,
|
|
511
|
+
createInput.decimals,
|
|
512
|
+
false
|
|
513
|
+
);
|
|
514
|
+
decimalsHashObj.update(decimalsBytes);
|
|
515
|
+
allHashes.push(decimalsHashObj.digest());
|
|
516
|
+
const maxSupplyHashObj = import_sha2.sha256.create();
|
|
517
|
+
if (!createInput.maxSupply) {
|
|
518
|
+
throw new ValidationError("max supply cannot be nil", {
|
|
519
|
+
field: "tokenInputs.createInput.maxSupply"
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
if (createInput.maxSupply.length !== 16) {
|
|
523
|
+
throw new ValidationError("max supply must be exactly 16 bytes", {
|
|
524
|
+
field: "tokenInputs.createInput.maxSupply",
|
|
525
|
+
value: createInput.maxSupply,
|
|
526
|
+
expectedLength: 16,
|
|
527
|
+
actualLength: createInput.maxSupply.length
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
maxSupplyHashObj.update(createInput.maxSupply);
|
|
531
|
+
allHashes.push(maxSupplyHashObj.digest());
|
|
532
|
+
const isFreezableHashObj = import_sha2.sha256.create();
|
|
533
|
+
const isFreezableByte = new Uint8Array([createInput.isFreezable ? 1 : 0]);
|
|
534
|
+
isFreezableHashObj.update(isFreezableByte);
|
|
535
|
+
allHashes.push(isFreezableHashObj.digest());
|
|
536
|
+
const creationEntityHashObj = import_sha2.sha256.create();
|
|
537
|
+
if (!partialHash && createInput.creationEntityPublicKey) {
|
|
538
|
+
creationEntityHashObj.update(createInput.creationEntityPublicKey);
|
|
539
|
+
}
|
|
540
|
+
allHashes.push(creationEntityHashObj.digest());
|
|
541
|
+
}
|
|
242
542
|
if (!tokenTransaction.tokenOutputs) {
|
|
243
543
|
throw new ValidationError("token outputs cannot be null", {
|
|
244
544
|
field: "tokenOutputs"
|
|
245
545
|
});
|
|
246
546
|
}
|
|
247
|
-
if (tokenTransaction.tokenOutputs.length === 0) {
|
|
547
|
+
if (tokenTransaction.tokenOutputs.length === 0 && tokenTransaction.tokenInputs?.$case !== "createInput") {
|
|
248
548
|
throw new ValidationError("token outputs cannot be empty", {
|
|
249
549
|
field: "tokenOutputs"
|
|
250
550
|
});
|
|
@@ -421,6 +721,26 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
421
721
|
);
|
|
422
722
|
versionHashObj.update(versionBytes);
|
|
423
723
|
allHashes.push(versionHashObj.digest());
|
|
724
|
+
const typeHashObj = import_sha2.sha256.create();
|
|
725
|
+
const typeBytes = new Uint8Array(4);
|
|
726
|
+
let transactionType = 0;
|
|
727
|
+
if (tokenTransaction.tokenInputs?.$case === "mintInput") {
|
|
728
|
+
transactionType = 2 /* TOKEN_TRANSACTION_TYPE_MINT */;
|
|
729
|
+
} else if (tokenTransaction.tokenInputs?.$case === "transferInput") {
|
|
730
|
+
transactionType = 3 /* TOKEN_TRANSACTION_TYPE_TRANSFER */;
|
|
731
|
+
} else if (tokenTransaction.tokenInputs?.$case === "createInput") {
|
|
732
|
+
transactionType = 1 /* TOKEN_TRANSACTION_TYPE_CREATE */;
|
|
733
|
+
} else {
|
|
734
|
+
throw new ValidationError(
|
|
735
|
+
"token transaction must have exactly one input type",
|
|
736
|
+
{
|
|
737
|
+
field: "tokenInputs"
|
|
738
|
+
}
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
new DataView(typeBytes.buffer).setUint32(0, transactionType, false);
|
|
742
|
+
typeHashObj.update(typeBytes);
|
|
743
|
+
allHashes.push(typeHashObj.digest());
|
|
424
744
|
if (tokenTransaction.tokenInputs?.$case === "transferInput") {
|
|
425
745
|
if (!tokenTransaction.tokenInputs.transferInput.outputsToSpend) {
|
|
426
746
|
throw new ValidationError("outputs to spend cannot be null", {
|
|
@@ -432,6 +752,15 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
432
752
|
field: "tokenInputs.transferInput.outputsToSpend"
|
|
433
753
|
});
|
|
434
754
|
}
|
|
755
|
+
const outputsLenHashObj2 = import_sha2.sha256.create();
|
|
756
|
+
const outputsLenBytes2 = new Uint8Array(4);
|
|
757
|
+
new DataView(outputsLenBytes2.buffer).setUint32(
|
|
758
|
+
0,
|
|
759
|
+
tokenTransaction.tokenInputs.transferInput.outputsToSpend.length,
|
|
760
|
+
false
|
|
761
|
+
);
|
|
762
|
+
outputsLenHashObj2.update(outputsLenBytes2);
|
|
763
|
+
allHashes.push(outputsLenHashObj2.digest());
|
|
435
764
|
for (const [
|
|
436
765
|
i,
|
|
437
766
|
output
|
|
@@ -468,8 +797,7 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
468
797
|
hashObj2.update(voutBytes);
|
|
469
798
|
allHashes.push(hashObj2.digest());
|
|
470
799
|
}
|
|
471
|
-
}
|
|
472
|
-
if (tokenTransaction.tokenInputs?.$case === "mintInput") {
|
|
800
|
+
} else if (tokenTransaction.tokenInputs?.$case === "mintInput") {
|
|
473
801
|
const hashObj2 = import_sha2.sha256.create();
|
|
474
802
|
if (tokenTransaction.tokenInputs.mintInput.issuerPublicKey) {
|
|
475
803
|
const issuerPubKey = tokenTransaction.tokenInputs.mintInput.issuerPublicKey;
|
|
@@ -482,31 +810,113 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
482
810
|
});
|
|
483
811
|
}
|
|
484
812
|
hashObj2.update(issuerPubKey);
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp
|
|
491
|
-
),
|
|
492
|
-
true
|
|
493
|
-
// true for little-endian to match Go implementation
|
|
813
|
+
allHashes.push(hashObj2.digest());
|
|
814
|
+
const tokenIdentifierHashObj = import_sha2.sha256.create();
|
|
815
|
+
if (tokenTransaction.tokenInputs.mintInput.tokenIdentifier) {
|
|
816
|
+
tokenIdentifierHashObj.update(
|
|
817
|
+
tokenTransaction.tokenInputs.mintInput.tokenIdentifier
|
|
494
818
|
);
|
|
495
|
-
|
|
819
|
+
} else {
|
|
820
|
+
tokenIdentifierHashObj.update(new Uint8Array(32));
|
|
496
821
|
}
|
|
497
|
-
allHashes.push(
|
|
822
|
+
allHashes.push(tokenIdentifierHashObj.digest());
|
|
823
|
+
}
|
|
824
|
+
} else if (tokenTransaction.tokenInputs?.$case === "createInput") {
|
|
825
|
+
const createInput = tokenTransaction.tokenInputs.createInput;
|
|
826
|
+
const issuerPubKeyHashObj = import_sha2.sha256.create();
|
|
827
|
+
if (!createInput.issuerPublicKey || createInput.issuerPublicKey.length === 0) {
|
|
828
|
+
throw new ValidationError("issuer public key cannot be nil or empty", {
|
|
829
|
+
field: "tokenInputs.createInput.issuerPublicKey"
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
issuerPubKeyHashObj.update(createInput.issuerPublicKey);
|
|
833
|
+
allHashes.push(issuerPubKeyHashObj.digest());
|
|
834
|
+
const tokenNameHashObj = import_sha2.sha256.create();
|
|
835
|
+
if (!createInput.tokenName || createInput.tokenName.length === 0) {
|
|
836
|
+
throw new ValidationError("token name cannot be empty", {
|
|
837
|
+
field: "tokenInputs.createInput.tokenName"
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
if (createInput.tokenName.length > 20) {
|
|
841
|
+
throw new ValidationError("token name cannot be longer than 20 bytes", {
|
|
842
|
+
field: "tokenInputs.createInput.tokenName",
|
|
843
|
+
value: createInput.tokenName,
|
|
844
|
+
expectedLength: 20,
|
|
845
|
+
actualLength: createInput.tokenName.length
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
const tokenNameEncoder = new TextEncoder();
|
|
849
|
+
tokenNameHashObj.update(tokenNameEncoder.encode(createInput.tokenName));
|
|
850
|
+
allHashes.push(tokenNameHashObj.digest());
|
|
851
|
+
const tokenTickerHashObj = import_sha2.sha256.create();
|
|
852
|
+
if (!createInput.tokenTicker || createInput.tokenTicker.length === 0) {
|
|
853
|
+
throw new ValidationError("token ticker cannot be empty", {
|
|
854
|
+
field: "tokenInputs.createInput.tokenTicker"
|
|
855
|
+
});
|
|
498
856
|
}
|
|
857
|
+
if (createInput.tokenTicker.length > 6) {
|
|
858
|
+
throw new ValidationError("token ticker cannot be longer than 6 bytes", {
|
|
859
|
+
field: "tokenInputs.createInput.tokenTicker",
|
|
860
|
+
value: createInput.tokenTicker,
|
|
861
|
+
expectedLength: 6,
|
|
862
|
+
actualLength: createInput.tokenTicker.length
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
const tokenTickerEncoder = new TextEncoder();
|
|
866
|
+
tokenTickerHashObj.update(
|
|
867
|
+
tokenTickerEncoder.encode(createInput.tokenTicker)
|
|
868
|
+
);
|
|
869
|
+
allHashes.push(tokenTickerHashObj.digest());
|
|
870
|
+
const decimalsHashObj = import_sha2.sha256.create();
|
|
871
|
+
const decimalsBytes = new Uint8Array(4);
|
|
872
|
+
new DataView(decimalsBytes.buffer).setUint32(
|
|
873
|
+
0,
|
|
874
|
+
createInput.decimals,
|
|
875
|
+
false
|
|
876
|
+
);
|
|
877
|
+
decimalsHashObj.update(decimalsBytes);
|
|
878
|
+
allHashes.push(decimalsHashObj.digest());
|
|
879
|
+
const maxSupplyHashObj = import_sha2.sha256.create();
|
|
880
|
+
if (!createInput.maxSupply) {
|
|
881
|
+
throw new ValidationError("max supply cannot be nil", {
|
|
882
|
+
field: "tokenInputs.createInput.maxSupply"
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
if (createInput.maxSupply.length !== 16) {
|
|
886
|
+
throw new ValidationError("max supply must be exactly 16 bytes", {
|
|
887
|
+
field: "tokenInputs.createInput.maxSupply",
|
|
888
|
+
value: createInput.maxSupply,
|
|
889
|
+
expectedLength: 16,
|
|
890
|
+
actualLength: createInput.maxSupply.length
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
maxSupplyHashObj.update(createInput.maxSupply);
|
|
894
|
+
allHashes.push(maxSupplyHashObj.digest());
|
|
895
|
+
const isFreezableHashObj = import_sha2.sha256.create();
|
|
896
|
+
isFreezableHashObj.update(
|
|
897
|
+
new Uint8Array([createInput.isFreezable ? 1 : 0])
|
|
898
|
+
);
|
|
899
|
+
allHashes.push(isFreezableHashObj.digest());
|
|
900
|
+
const creationEntityHashObj = import_sha2.sha256.create();
|
|
901
|
+
if (!partialHash && createInput.creationEntityPublicKey) {
|
|
902
|
+
creationEntityHashObj.update(createInput.creationEntityPublicKey);
|
|
903
|
+
}
|
|
904
|
+
allHashes.push(creationEntityHashObj.digest());
|
|
499
905
|
}
|
|
500
906
|
if (!tokenTransaction.tokenOutputs) {
|
|
501
907
|
throw new ValidationError("token outputs cannot be null", {
|
|
502
908
|
field: "tokenOutputs"
|
|
503
909
|
});
|
|
504
910
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
911
|
+
const outputsLenHashObj = import_sha2.sha256.create();
|
|
912
|
+
const outputsLenBytes = new Uint8Array(4);
|
|
913
|
+
new DataView(outputsLenBytes.buffer).setUint32(
|
|
914
|
+
0,
|
|
915
|
+
tokenTransaction.tokenOutputs.length,
|
|
916
|
+
false
|
|
917
|
+
);
|
|
918
|
+
outputsLenHashObj.update(outputsLenBytes);
|
|
919
|
+
allHashes.push(outputsLenHashObj.digest());
|
|
510
920
|
for (const [i, output] of tokenTransaction.tokenOutputs.entries()) {
|
|
511
921
|
if (!output) {
|
|
512
922
|
throw new ValidationError(`output cannot be null at index ${i}`, {
|
|
@@ -565,18 +975,16 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
565
975
|
);
|
|
566
976
|
hashObj2.update(locktimeBytes);
|
|
567
977
|
}
|
|
568
|
-
if (output.tokenPublicKey) {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
`token public key at index ${i} cannot be empty`,
|
|
572
|
-
{
|
|
573
|
-
field: `tokenOutputs[${i}].tokenPublicKey`,
|
|
574
|
-
index: i
|
|
575
|
-
}
|
|
576
|
-
);
|
|
577
|
-
}
|
|
978
|
+
if (!output.tokenPublicKey || output.tokenPublicKey.length === 0) {
|
|
979
|
+
hashObj2.update(new Uint8Array(33));
|
|
980
|
+
} else {
|
|
578
981
|
hashObj2.update(output.tokenPublicKey);
|
|
579
982
|
}
|
|
983
|
+
if (!output.tokenIdentifier || output.tokenIdentifier.length === 0) {
|
|
984
|
+
hashObj2.update(new Uint8Array(32));
|
|
985
|
+
} else {
|
|
986
|
+
hashObj2.update(output.tokenIdentifier);
|
|
987
|
+
}
|
|
580
988
|
if (output.tokenAmount) {
|
|
581
989
|
if (output.tokenAmount.length === 0) {
|
|
582
990
|
throw new ValidationError(
|
|
@@ -617,6 +1025,15 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
617
1025
|
}
|
|
618
1026
|
return a.length - b.length;
|
|
619
1027
|
});
|
|
1028
|
+
const operatorLenHashObj = import_sha2.sha256.create();
|
|
1029
|
+
const operatorLenBytes = new Uint8Array(4);
|
|
1030
|
+
new DataView(operatorLenBytes.buffer).setUint32(
|
|
1031
|
+
0,
|
|
1032
|
+
sortedPubKeys.length,
|
|
1033
|
+
false
|
|
1034
|
+
);
|
|
1035
|
+
operatorLenHashObj.update(operatorLenBytes);
|
|
1036
|
+
allHashes.push(operatorLenHashObj.digest());
|
|
620
1037
|
for (const [i, pubKey] of sortedPubKeys.entries()) {
|
|
621
1038
|
if (!pubKey) {
|
|
622
1039
|
throw new ValidationError(
|
|
@@ -650,17 +1067,38 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
|
|
|
650
1067
|
);
|
|
651
1068
|
hashObj.update(networkBytes);
|
|
652
1069
|
allHashes.push(hashObj.digest());
|
|
653
|
-
const
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
|
|
1070
|
+
const clientTimestampHashObj = import_sha2.sha256.create();
|
|
1071
|
+
const clientCreatedTs = tokenTransaction.clientCreatedTimestamp;
|
|
1072
|
+
if (!clientCreatedTs) {
|
|
1073
|
+
throw new ValidationError(
|
|
1074
|
+
"client created timestamp cannot be null for V1 token transactions",
|
|
1075
|
+
{
|
|
1076
|
+
field: "clientCreatedTimestamp"
|
|
1077
|
+
}
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
const clientUnixTime = clientCreatedTs.getTime();
|
|
1081
|
+
const clientTimestampBytes = new Uint8Array(8);
|
|
1082
|
+
new DataView(clientTimestampBytes.buffer).setBigUint64(
|
|
657
1083
|
0,
|
|
658
|
-
BigInt(
|
|
1084
|
+
BigInt(clientUnixTime),
|
|
659
1085
|
false
|
|
660
|
-
// false for big-endian
|
|
661
1086
|
);
|
|
662
|
-
|
|
663
|
-
allHashes.push(
|
|
1087
|
+
clientTimestampHashObj.update(clientTimestampBytes);
|
|
1088
|
+
allHashes.push(clientTimestampHashObj.digest());
|
|
1089
|
+
if (!partialHash) {
|
|
1090
|
+
const expiryHashObj = import_sha2.sha256.create();
|
|
1091
|
+
const expiryTimeBytes = new Uint8Array(8);
|
|
1092
|
+
const expiryUnixTime = tokenTransaction.expiryTime ? Math.floor(tokenTransaction.expiryTime.getTime() / 1e3) : 0;
|
|
1093
|
+
new DataView(expiryTimeBytes.buffer).setBigUint64(
|
|
1094
|
+
0,
|
|
1095
|
+
BigInt(expiryUnixTime),
|
|
1096
|
+
false
|
|
1097
|
+
// false for big-endian
|
|
1098
|
+
);
|
|
1099
|
+
expiryHashObj.update(expiryTimeBytes);
|
|
1100
|
+
allHashes.push(expiryHashObj.digest());
|
|
1101
|
+
}
|
|
664
1102
|
const finalHashObj = import_sha2.sha256.create();
|
|
665
1103
|
const concatenatedHashes = new Uint8Array(
|
|
666
1104
|
allHashes.reduce((sum, hash) => sum + hash.length, 0)
|
|
@@ -760,7 +1198,7 @@ function areByteArraysEqual(a, b) {
|
|
|
760
1198
|
function hasDuplicates(array) {
|
|
761
1199
|
return new Set(array).size !== array.length;
|
|
762
1200
|
}
|
|
763
|
-
function
|
|
1201
|
+
function validateTokenTransactionV0(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
|
|
764
1202
|
if (finalTokenTransaction.network !== partialTokenTransaction.network) {
|
|
765
1203
|
throw new InternalValidationError(
|
|
766
1204
|
"Network mismatch in response token transaction",
|
|
@@ -917,7 +1355,7 @@ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction
|
|
|
917
1355
|
}
|
|
918
1356
|
);
|
|
919
1357
|
}
|
|
920
|
-
if (!areByteArraysEqual(
|
|
1358
|
+
if (finalOutput.tokenPublicKey !== void 0 && partialOutput.tokenPublicKey !== void 0 && !areByteArraysEqual(
|
|
921
1359
|
finalOutput.tokenPublicKey,
|
|
922
1360
|
partialOutput.tokenPublicKey
|
|
923
1361
|
)) {
|
|
@@ -925,8 +1363,8 @@ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction
|
|
|
925
1363
|
"Token public key mismatch in token output",
|
|
926
1364
|
{
|
|
927
1365
|
outputIndex: i,
|
|
928
|
-
value: finalOutput.tokenPublicKey
|
|
929
|
-
expected: partialOutput.tokenPublicKey
|
|
1366
|
+
value: finalOutput.tokenPublicKey?.toString(),
|
|
1367
|
+
expected: partialOutput.tokenPublicKey?.toString()
|
|
930
1368
|
}
|
|
931
1369
|
);
|
|
932
1370
|
}
|
|
@@ -1004,222 +1442,264 @@ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction
|
|
|
1004
1442
|
}
|
|
1005
1443
|
}
|
|
1006
1444
|
}
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1445
|
+
function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
|
|
1446
|
+
if (finalTokenTransaction.network !== partialTokenTransaction.network) {
|
|
1447
|
+
throw new InternalValidationError(
|
|
1448
|
+
"Network mismatch in response token transaction",
|
|
1449
|
+
{
|
|
1450
|
+
value: finalTokenTransaction.network,
|
|
1451
|
+
expected: partialTokenTransaction.network
|
|
1452
|
+
}
|
|
1453
|
+
);
|
|
1454
|
+
}
|
|
1455
|
+
if (!finalTokenTransaction.tokenInputs) {
|
|
1456
|
+
throw new InternalValidationError(
|
|
1457
|
+
"Token inputs missing in final transaction",
|
|
1458
|
+
{
|
|
1459
|
+
value: finalTokenTransaction
|
|
1460
|
+
}
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1463
|
+
if (!partialTokenTransaction.tokenInputs) {
|
|
1464
|
+
throw new InternalValidationError(
|
|
1465
|
+
"Token inputs missing in partial transaction",
|
|
1466
|
+
{
|
|
1467
|
+
value: partialTokenTransaction
|
|
1468
|
+
}
|
|
1469
|
+
);
|
|
1470
|
+
}
|
|
1471
|
+
if (finalTokenTransaction.tokenInputs.$case !== partialTokenTransaction.tokenInputs.$case) {
|
|
1472
|
+
throw new InternalValidationError(
|
|
1473
|
+
`Transaction type mismatch: final transaction has ${finalTokenTransaction.tokenInputs.$case}, partial transaction has ${partialTokenTransaction.tokenInputs.$case}`,
|
|
1474
|
+
{
|
|
1475
|
+
value: finalTokenTransaction.tokenInputs.$case,
|
|
1476
|
+
expected: partialTokenTransaction.tokenInputs.$case
|
|
1477
|
+
}
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
if (finalTokenTransaction.sparkOperatorIdentityPublicKeys.length !== partialTokenTransaction.sparkOperatorIdentityPublicKeys.length) {
|
|
1481
|
+
throw new InternalValidationError(
|
|
1482
|
+
"Spark operator identity public keys count mismatch",
|
|
1483
|
+
{
|
|
1484
|
+
value: finalTokenTransaction.sparkOperatorIdentityPublicKeys.length,
|
|
1485
|
+
expected: partialTokenTransaction.sparkOperatorIdentityPublicKeys.length
|
|
1486
|
+
}
|
|
1487
|
+
);
|
|
1488
|
+
}
|
|
1489
|
+
if (partialTokenTransaction.tokenInputs.$case === "mintInput" && finalTokenTransaction.tokenInputs.$case === "mintInput") {
|
|
1490
|
+
const finalMintInput = finalTokenTransaction.tokenInputs.mintInput;
|
|
1491
|
+
const partialMintInput = partialTokenTransaction.tokenInputs.mintInput;
|
|
1492
|
+
if (!areByteArraysEqual(
|
|
1493
|
+
finalMintInput.issuerPublicKey,
|
|
1494
|
+
partialMintInput.issuerPublicKey
|
|
1495
|
+
)) {
|
|
1496
|
+
throw new InternalValidationError(
|
|
1497
|
+
"Issuer public key mismatch in mint input",
|
|
1498
|
+
{
|
|
1499
|
+
value: finalMintInput.issuerPublicKey.toString(),
|
|
1500
|
+
expected: partialMintInput.issuerPublicKey.toString()
|
|
1501
|
+
}
|
|
1502
|
+
);
|
|
1036
1503
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1504
|
+
} else if (partialTokenTransaction.tokenInputs.$case === "transferInput" && finalTokenTransaction.tokenInputs.$case === "transferInput") {
|
|
1505
|
+
const finalTransferInput = finalTokenTransaction.tokenInputs.transferInput;
|
|
1506
|
+
const partialTransferInput = partialTokenTransaction.tokenInputs.transferInput;
|
|
1507
|
+
if (finalTransferInput.outputsToSpend.length !== partialTransferInput.outputsToSpend.length) {
|
|
1508
|
+
throw new InternalValidationError(
|
|
1509
|
+
"Outputs to spend count mismatch in transfer input",
|
|
1510
|
+
{
|
|
1511
|
+
value: finalTransferInput.outputsToSpend.length,
|
|
1512
|
+
expected: partialTransferInput.outputsToSpend.length
|
|
1513
|
+
}
|
|
1514
|
+
);
|
|
1039
1515
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
case 1: {
|
|
1050
|
-
if (tag !== 10) {
|
|
1051
|
-
break;
|
|
1516
|
+
for (let i = 0; i < finalTransferInput.outputsToSpend.length; i++) {
|
|
1517
|
+
const finalOutput = finalTransferInput.outputsToSpend[i];
|
|
1518
|
+
const partialOutput = partialTransferInput.outputsToSpend[i];
|
|
1519
|
+
if (!finalOutput) {
|
|
1520
|
+
throw new InternalValidationError(
|
|
1521
|
+
"Token output to spend missing in final transaction",
|
|
1522
|
+
{
|
|
1523
|
+
outputIndex: i,
|
|
1524
|
+
value: finalOutput
|
|
1052
1525
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1526
|
+
);
|
|
1527
|
+
}
|
|
1528
|
+
if (!partialOutput) {
|
|
1529
|
+
throw new InternalValidationError(
|
|
1530
|
+
"Token output to spend missing in partial transaction",
|
|
1531
|
+
{
|
|
1532
|
+
outputIndex: i,
|
|
1533
|
+
value: partialOutput
|
|
1059
1534
|
}
|
|
1060
|
-
|
|
1061
|
-
continue;
|
|
1062
|
-
}
|
|
1535
|
+
);
|
|
1063
1536
|
}
|
|
1064
|
-
if ((
|
|
1065
|
-
|
|
1537
|
+
if (!areByteArraysEqual(
|
|
1538
|
+
finalOutput.prevTokenTransactionHash,
|
|
1539
|
+
partialOutput.prevTokenTransactionHash
|
|
1540
|
+
)) {
|
|
1541
|
+
throw new InternalValidationError(
|
|
1542
|
+
"Previous token transaction hash mismatch in transfer input",
|
|
1543
|
+
{
|
|
1544
|
+
outputIndex: i,
|
|
1545
|
+
value: finalOutput.prevTokenTransactionHash.toString(),
|
|
1546
|
+
expected: partialOutput.prevTokenTransactionHash.toString()
|
|
1547
|
+
}
|
|
1548
|
+
);
|
|
1549
|
+
}
|
|
1550
|
+
if (finalOutput.prevTokenTransactionVout !== partialOutput.prevTokenTransactionVout) {
|
|
1551
|
+
throw new InternalValidationError(
|
|
1552
|
+
"Previous token transaction vout mismatch in transfer input",
|
|
1553
|
+
{
|
|
1554
|
+
outputIndex: i,
|
|
1555
|
+
value: finalOutput.prevTokenTransactionVout,
|
|
1556
|
+
expected: partialOutput.prevTokenTransactionVout
|
|
1557
|
+
}
|
|
1558
|
+
);
|
|
1066
1559
|
}
|
|
1067
|
-
reader.skip(tag & 7);
|
|
1068
|
-
}
|
|
1069
|
-
return message;
|
|
1070
|
-
},
|
|
1071
|
-
fromJSON(object) {
|
|
1072
|
-
return {
|
|
1073
|
-
identityPublicKey: isSet(object.identityPublicKey) ? bytesFromBase64(object.identityPublicKey) : new Uint8Array(0),
|
|
1074
|
-
paymentIntentFields: isSet(object.paymentIntentFields) ? PaymentIntentFields.fromJSON(object.paymentIntentFields) : void 0
|
|
1075
|
-
};
|
|
1076
|
-
},
|
|
1077
|
-
toJSON(message) {
|
|
1078
|
-
const obj = {};
|
|
1079
|
-
if (message.identityPublicKey.length !== 0) {
|
|
1080
|
-
obj.identityPublicKey = base64FromBytes(message.identityPublicKey);
|
|
1081
|
-
}
|
|
1082
|
-
if (message.paymentIntentFields !== void 0) {
|
|
1083
|
-
obj.paymentIntentFields = PaymentIntentFields.toJSON(message.paymentIntentFields);
|
|
1084
1560
|
}
|
|
1085
|
-
return obj;
|
|
1086
|
-
},
|
|
1087
|
-
create(base) {
|
|
1088
|
-
return SparkAddress.fromPartial(base ?? {});
|
|
1089
|
-
},
|
|
1090
|
-
fromPartial(object) {
|
|
1091
|
-
const message = createBaseSparkAddress();
|
|
1092
|
-
message.identityPublicKey = object.identityPublicKey ?? new Uint8Array(0);
|
|
1093
|
-
message.paymentIntentFields = object.paymentIntentFields !== void 0 && object.paymentIntentFields !== null ? PaymentIntentFields.fromPartial(object.paymentIntentFields) : void 0;
|
|
1094
|
-
return message;
|
|
1095
1561
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
if (
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
if (message.memo !== void 0) {
|
|
1112
|
-
writer.uint32(34).string(message.memo);
|
|
1113
|
-
}
|
|
1114
|
-
return writer;
|
|
1115
|
-
},
|
|
1116
|
-
decode(input, length) {
|
|
1117
|
-
const reader = input instanceof import_wire4.BinaryReader ? input : new import_wire4.BinaryReader(input);
|
|
1118
|
-
let end = length === void 0 ? reader.len : reader.pos + length;
|
|
1119
|
-
const message = createBasePaymentIntentFields();
|
|
1120
|
-
while (reader.pos < end) {
|
|
1121
|
-
const tag = reader.uint32();
|
|
1122
|
-
switch (tag >>> 3) {
|
|
1123
|
-
case 1: {
|
|
1124
|
-
if (tag !== 10) {
|
|
1125
|
-
break;
|
|
1126
|
-
}
|
|
1127
|
-
message.id = reader.bytes();
|
|
1128
|
-
continue;
|
|
1562
|
+
if (finalTokenTransaction.tokenOutputs.length !== partialTokenTransaction.tokenOutputs.length) {
|
|
1563
|
+
throw new InternalValidationError("Token outputs count mismatch", {
|
|
1564
|
+
value: finalTokenTransaction.tokenOutputs.length,
|
|
1565
|
+
expected: partialTokenTransaction.tokenOutputs.length
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
for (let i = 0; i < finalTokenTransaction.tokenOutputs.length; i++) {
|
|
1569
|
+
const finalOutput = finalTokenTransaction.tokenOutputs[i];
|
|
1570
|
+
const partialOutput = partialTokenTransaction.tokenOutputs[i];
|
|
1571
|
+
if (!finalOutput) {
|
|
1572
|
+
throw new InternalValidationError(
|
|
1573
|
+
"Token output missing in final transaction",
|
|
1574
|
+
{
|
|
1575
|
+
outputIndex: i,
|
|
1576
|
+
value: finalOutput
|
|
1129
1577
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1578
|
+
);
|
|
1579
|
+
}
|
|
1580
|
+
if (!partialOutput) {
|
|
1581
|
+
throw new InternalValidationError(
|
|
1582
|
+
"Token output missing in partial transaction",
|
|
1583
|
+
{
|
|
1584
|
+
outputIndex: i,
|
|
1585
|
+
value: partialOutput
|
|
1136
1586
|
}
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1587
|
+
);
|
|
1588
|
+
}
|
|
1589
|
+
if (!areByteArraysEqual(
|
|
1590
|
+
finalOutput.ownerPublicKey,
|
|
1591
|
+
partialOutput.ownerPublicKey
|
|
1592
|
+
)) {
|
|
1593
|
+
throw new InternalValidationError(
|
|
1594
|
+
"Owner public key mismatch in token output",
|
|
1595
|
+
{
|
|
1596
|
+
outputIndex: i,
|
|
1597
|
+
value: finalOutput.ownerPublicKey.toString(),
|
|
1598
|
+
expected: partialOutput.ownerPublicKey.toString()
|
|
1143
1599
|
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1600
|
+
);
|
|
1601
|
+
}
|
|
1602
|
+
if (finalOutput.tokenPublicKey !== void 0 && partialOutput.tokenPublicKey !== void 0 && !areByteArraysEqual(
|
|
1603
|
+
finalOutput.tokenPublicKey,
|
|
1604
|
+
partialOutput.tokenPublicKey
|
|
1605
|
+
)) {
|
|
1606
|
+
throw new InternalValidationError(
|
|
1607
|
+
"Token public key mismatch in token output",
|
|
1608
|
+
{
|
|
1609
|
+
outputIndex: i,
|
|
1610
|
+
value: finalOutput.tokenPublicKey.toString(),
|
|
1611
|
+
expected: partialOutput.tokenPublicKey.toString()
|
|
1150
1612
|
}
|
|
1151
|
-
|
|
1152
|
-
if ((tag & 7) === 4 || tag === 0) {
|
|
1153
|
-
break;
|
|
1154
|
-
}
|
|
1155
|
-
reader.skip(tag & 7);
|
|
1613
|
+
);
|
|
1156
1614
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
},
|
|
1167
|
-
toJSON(message) {
|
|
1168
|
-
const obj = {};
|
|
1169
|
-
if (message.id.length !== 0) {
|
|
1170
|
-
obj.id = base64FromBytes(message.id);
|
|
1615
|
+
if (!areByteArraysEqual(finalOutput.tokenAmount, partialOutput.tokenAmount)) {
|
|
1616
|
+
throw new InternalValidationError(
|
|
1617
|
+
"Token amount mismatch in token output",
|
|
1618
|
+
{
|
|
1619
|
+
outputIndex: i,
|
|
1620
|
+
value: finalOutput.tokenAmount.toString(),
|
|
1621
|
+
expected: partialOutput.tokenAmount.toString()
|
|
1622
|
+
}
|
|
1623
|
+
);
|
|
1171
1624
|
}
|
|
1172
|
-
if (
|
|
1173
|
-
|
|
1625
|
+
if (finalOutput.withdrawBondSats !== void 0) {
|
|
1626
|
+
if (finalOutput.withdrawBondSats !== expectedWithdrawBondSats) {
|
|
1627
|
+
throw new InternalValidationError(
|
|
1628
|
+
"Withdraw bond sats mismatch in token output",
|
|
1629
|
+
{
|
|
1630
|
+
outputIndex: i,
|
|
1631
|
+
value: finalOutput.withdrawBondSats,
|
|
1632
|
+
expected: expectedWithdrawBondSats
|
|
1633
|
+
}
|
|
1634
|
+
);
|
|
1635
|
+
}
|
|
1174
1636
|
}
|
|
1175
|
-
if (
|
|
1176
|
-
|
|
1637
|
+
if (finalOutput.withdrawRelativeBlockLocktime !== void 0) {
|
|
1638
|
+
if (finalOutput.withdrawRelativeBlockLocktime !== expectedWithdrawRelativeBlockLocktime) {
|
|
1639
|
+
throw new InternalValidationError(
|
|
1640
|
+
"Withdraw relative block locktime mismatch in token output",
|
|
1641
|
+
{
|
|
1642
|
+
outputIndex: i,
|
|
1643
|
+
value: finalOutput.withdrawRelativeBlockLocktime,
|
|
1644
|
+
expected: expectedWithdrawRelativeBlockLocktime
|
|
1645
|
+
}
|
|
1646
|
+
);
|
|
1647
|
+
}
|
|
1177
1648
|
}
|
|
1178
|
-
if (
|
|
1179
|
-
|
|
1649
|
+
if (keyshareInfo.threshold !== expectedThreshold) {
|
|
1650
|
+
throw new InternalValidationError(
|
|
1651
|
+
"Threshold mismatch: expected " + expectedThreshold + " but got " + keyshareInfo.threshold,
|
|
1652
|
+
{
|
|
1653
|
+
field: "threshold",
|
|
1654
|
+
value: keyshareInfo.threshold,
|
|
1655
|
+
expected: expectedThreshold
|
|
1656
|
+
}
|
|
1657
|
+
);
|
|
1180
1658
|
}
|
|
1181
|
-
return obj;
|
|
1182
|
-
},
|
|
1183
|
-
create(base) {
|
|
1184
|
-
return PaymentIntentFields.fromPartial(base ?? {});
|
|
1185
|
-
},
|
|
1186
|
-
fromPartial(object) {
|
|
1187
|
-
const message = createBasePaymentIntentFields();
|
|
1188
|
-
message.id = object.id ?? new Uint8Array(0);
|
|
1189
|
-
message.assetIdentifier = object.assetIdentifier ?? void 0;
|
|
1190
|
-
message.assetAmount = object.assetAmount ?? new Uint8Array(0);
|
|
1191
|
-
message.memo = object.memo ?? void 0;
|
|
1192
|
-
return message;
|
|
1193
1659
|
}
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1660
|
+
if (keyshareInfo.ownerIdentifiers.length !== Object.keys(signingOperators).length) {
|
|
1661
|
+
throw new InternalValidationError(
|
|
1662
|
+
`Keyshare operator count (${keyshareInfo.ownerIdentifiers.length}) does not match signing operator count (${Object.keys(signingOperators).length})`,
|
|
1663
|
+
{
|
|
1664
|
+
keyshareInfo: keyshareInfo.ownerIdentifiers.length,
|
|
1665
|
+
signingOperators: Object.keys(signingOperators).length
|
|
1666
|
+
}
|
|
1667
|
+
);
|
|
1668
|
+
}
|
|
1669
|
+
if (hasDuplicates(keyshareInfo.ownerIdentifiers)) {
|
|
1670
|
+
throw new InternalValidationError(
|
|
1671
|
+
"Duplicate ownerIdentifiers found in keyshareInfo",
|
|
1672
|
+
{
|
|
1673
|
+
keyshareInfo: keyshareInfo.ownerIdentifiers
|
|
1674
|
+
}
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1677
|
+
for (const identifier of keyshareInfo.ownerIdentifiers) {
|
|
1678
|
+
if (!signingOperators[identifier]) {
|
|
1679
|
+
throw new InternalValidationError(
|
|
1680
|
+
`Keyshare operator ${identifier} not found in signing operator list`,
|
|
1681
|
+
{
|
|
1682
|
+
keyshareInfo: identifier,
|
|
1683
|
+
signingOperators: Object.keys(signingOperators)
|
|
1684
|
+
}
|
|
1685
|
+
);
|
|
1203
1686
|
}
|
|
1204
|
-
return arr;
|
|
1205
1687
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
} else {
|
|
1211
|
-
const bin = [];
|
|
1212
|
-
arr.forEach((byte) => {
|
|
1213
|
-
bin.push(globalThis.String.fromCharCode(byte));
|
|
1688
|
+
if (finalTokenTransaction.clientCreatedTimestamp.getTime() !== partialTokenTransaction.clientCreatedTimestamp.getTime()) {
|
|
1689
|
+
throw new InternalValidationError("Client created timestamp mismatch", {
|
|
1690
|
+
value: finalTokenTransaction.clientCreatedTimestamp,
|
|
1691
|
+
expected: partialTokenTransaction.clientCreatedTimestamp
|
|
1214
1692
|
});
|
|
1215
|
-
return globalThis.btoa(bin.join(""));
|
|
1216
1693
|
}
|
|
1217
1694
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1695
|
+
|
|
1696
|
+
// src/services/token-transactions.ts
|
|
1697
|
+
var import_utils7 = require("@noble/hashes/utils");
|
|
1221
1698
|
|
|
1222
1699
|
// src/address/address.ts
|
|
1700
|
+
var import_secp256k1 = require("@noble/curves/secp256k1");
|
|
1701
|
+
var import_utils3 = require("@noble/hashes/utils");
|
|
1702
|
+
var import_base2 = require("@scure/base");
|
|
1223
1703
|
var import_uuidv7 = require("uuidv7");
|
|
1224
1704
|
var import_utils4 = require("@noble/curves/abstract/utils");
|
|
1225
1705
|
var AddressNetwork = {
|
|
@@ -1516,6 +1996,9 @@ var TokenTransactionService = class {
|
|
|
1516
1996
|
return txId;
|
|
1517
1997
|
}
|
|
1518
1998
|
async constructTransferTokenTransactionV0(selectedOutputs, tokenOutputData) {
|
|
1999
|
+
selectedOutputs.sort(
|
|
2000
|
+
(a, b) => a.previousTransactionVout - b.previousTransactionVout
|
|
2001
|
+
);
|
|
1519
2002
|
const availableTokenAmount = calculateAvailableTokenAmount(selectedOutputs);
|
|
1520
2003
|
const totalRequestedAmount = tokenOutputData.reduce(
|
|
1521
2004
|
(sum, output) => sum + output.tokenAmount,
|
|
@@ -1551,6 +2034,9 @@ var TokenTransactionService = class {
|
|
|
1551
2034
|
};
|
|
1552
2035
|
}
|
|
1553
2036
|
async constructTransferTokenTransaction(selectedOutputs, tokenOutputData) {
|
|
2037
|
+
selectedOutputs.sort(
|
|
2038
|
+
(a, b) => a.previousTransactionVout - b.previousTransactionVout
|
|
2039
|
+
);
|
|
1554
2040
|
const availableTokenAmount = calculateAvailableTokenAmount(selectedOutputs);
|
|
1555
2041
|
const totalRequestedAmount = tokenOutputData.reduce(
|
|
1556
2042
|
(sum, output) => sum + output.tokenAmount,
|
|
@@ -1584,7 +2070,8 @@ var TokenTransactionService = class {
|
|
|
1584
2070
|
},
|
|
1585
2071
|
tokenOutputs,
|
|
1586
2072
|
sparkOperatorIdentityPublicKeys: this.collectOperatorIdentityPublicKeys(),
|
|
1587
|
-
expiryTime: void 0
|
|
2073
|
+
expiryTime: void 0,
|
|
2074
|
+
clientCreatedTimestamp: /* @__PURE__ */ new Date()
|
|
1588
2075
|
};
|
|
1589
2076
|
}
|
|
1590
2077
|
collectOperatorIdentityPublicKeys() {
|
|
@@ -1793,7 +2280,7 @@ var TokenTransactionService = class {
|
|
|
1793
2280
|
if (!startResponse.keyshareInfo) {
|
|
1794
2281
|
throw new Error("Keyshare info missing in start response");
|
|
1795
2282
|
}
|
|
1796
|
-
|
|
2283
|
+
validateTokenTransactionV0(
|
|
1797
2284
|
startResponse.finalTokenTransaction,
|
|
1798
2285
|
tokenTransaction,
|
|
1799
2286
|
signingOperators,
|
|
@@ -2017,6 +2504,7 @@ var TokenTransactionService = class {
|
|
|
2017
2504
|
await coordinatorClient.commit_transaction(
|
|
2018
2505
|
{
|
|
2019
2506
|
finalTokenTransaction,
|
|
2507
|
+
finalTokenTransactionHash,
|
|
2020
2508
|
inputTtxoSignaturesPerOperator,
|
|
2021
2509
|
ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey()
|
|
2022
2510
|
},
|
|
@@ -2043,7 +2531,26 @@ var TokenTransactionService = class {
|
|
|
2043
2531
|
);
|
|
2044
2532
|
}
|
|
2045
2533
|
}
|
|
2046
|
-
async fetchOwnedTokenOutputs(
|
|
2534
|
+
async fetchOwnedTokenOutputs(params) {
|
|
2535
|
+
if (this.config.getTokenTransactionVersion() === "V0") {
|
|
2536
|
+
return this.fetchOwnedTokenOutputsV0(params);
|
|
2537
|
+
} else {
|
|
2538
|
+
return this.fetchOwnedTokenOutputsV1(params);
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
async queryTokenTransactions(params) {
|
|
2542
|
+
if (this.config.getTokenTransactionVersion() === "V0") {
|
|
2543
|
+
return this.queryTokenTransactionsV0(params);
|
|
2544
|
+
} else {
|
|
2545
|
+
return this.queryTokenTransactionsV1(params);
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
async fetchOwnedTokenOutputsV0(params) {
|
|
2549
|
+
const {
|
|
2550
|
+
ownerPublicKeys,
|
|
2551
|
+
issuerPublicKeys: tokenPublicKeys = [],
|
|
2552
|
+
tokenIdentifiers = []
|
|
2553
|
+
} = params;
|
|
2047
2554
|
const sparkClient = await this.connectionManager.createSparkClient(
|
|
2048
2555
|
this.config.getCoordinatorAddress()
|
|
2049
2556
|
);
|
|
@@ -2051,6 +2558,7 @@ var TokenTransactionService = class {
|
|
|
2051
2558
|
const result = await sparkClient.query_token_outputs({
|
|
2052
2559
|
ownerPublicKeys,
|
|
2053
2560
|
tokenPublicKeys,
|
|
2561
|
+
tokenIdentifiers,
|
|
2054
2562
|
network: this.config.getNetworkProto()
|
|
2055
2563
|
});
|
|
2056
2564
|
return result.outputsWithPreviousTransactionData;
|
|
@@ -2058,7 +2566,7 @@ var TokenTransactionService = class {
|
|
|
2058
2566
|
throw new NetworkError(
|
|
2059
2567
|
"Failed to fetch owned token outputs",
|
|
2060
2568
|
{
|
|
2061
|
-
operation: "query_token_outputs",
|
|
2569
|
+
operation: "spark.query_token_outputs",
|
|
2062
2570
|
errorCount: 1,
|
|
2063
2571
|
errors: error instanceof Error ? error.message : String(error)
|
|
2064
2572
|
},
|
|
@@ -2066,11 +2574,127 @@ var TokenTransactionService = class {
|
|
|
2066
2574
|
);
|
|
2067
2575
|
}
|
|
2068
2576
|
}
|
|
2069
|
-
async
|
|
2070
|
-
const
|
|
2071
|
-
|
|
2072
|
-
[]
|
|
2577
|
+
async fetchOwnedTokenOutputsV1(params) {
|
|
2578
|
+
const {
|
|
2579
|
+
ownerPublicKeys,
|
|
2580
|
+
issuerPublicKeys = [],
|
|
2581
|
+
tokenIdentifiers = []
|
|
2582
|
+
} = params;
|
|
2583
|
+
const tokenClient = await this.connectionManager.createSparkTokenClient(
|
|
2584
|
+
this.config.getCoordinatorAddress()
|
|
2585
|
+
);
|
|
2586
|
+
try {
|
|
2587
|
+
const result = await tokenClient.query_token_outputs({
|
|
2588
|
+
ownerPublicKeys,
|
|
2589
|
+
issuerPublicKeys,
|
|
2590
|
+
tokenIdentifiers,
|
|
2591
|
+
network: this.config.getNetworkProto()
|
|
2592
|
+
});
|
|
2593
|
+
return result.outputsWithPreviousTransactionData;
|
|
2594
|
+
} catch (error) {
|
|
2595
|
+
throw new NetworkError(
|
|
2596
|
+
"Failed to fetch owned token outputs",
|
|
2597
|
+
{
|
|
2598
|
+
operation: "spark_token.query_token_outputs",
|
|
2599
|
+
errorCount: 1,
|
|
2600
|
+
errors: error instanceof Error ? error.message : String(error)
|
|
2601
|
+
},
|
|
2602
|
+
error
|
|
2603
|
+
);
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
async queryTokenTransactionsV0(params) {
|
|
2607
|
+
const {
|
|
2608
|
+
ownerPublicKeys,
|
|
2609
|
+
issuerPublicKeys,
|
|
2610
|
+
tokenTransactionHashes,
|
|
2611
|
+
tokenIdentifiers,
|
|
2612
|
+
outputIds
|
|
2613
|
+
} = params;
|
|
2614
|
+
const sparkClient = await this.connectionManager.createSparkClient(
|
|
2615
|
+
this.config.getCoordinatorAddress()
|
|
2616
|
+
);
|
|
2617
|
+
let queryParams = {
|
|
2618
|
+
tokenPublicKeys: issuerPublicKeys?.map(import_utils7.hexToBytes),
|
|
2619
|
+
ownerPublicKeys: ownerPublicKeys?.map(import_utils7.hexToBytes),
|
|
2620
|
+
tokenIdentifiers: tokenIdentifiers?.map(import_utils7.hexToBytes),
|
|
2621
|
+
tokenTransactionHashes: tokenTransactionHashes?.map(import_utils7.hexToBytes),
|
|
2622
|
+
outputIds: outputIds || [],
|
|
2623
|
+
limit: 100,
|
|
2624
|
+
offset: 0
|
|
2625
|
+
};
|
|
2626
|
+
try {
|
|
2627
|
+
const response = await sparkClient.query_token_transactions(queryParams);
|
|
2628
|
+
return response.tokenTransactionsWithStatus.map((tx) => {
|
|
2629
|
+
const v1TokenTransaction = {
|
|
2630
|
+
version: 1,
|
|
2631
|
+
network: tx.tokenTransaction.network,
|
|
2632
|
+
tokenInputs: tx.tokenTransaction.tokenInputs,
|
|
2633
|
+
tokenOutputs: tx.tokenTransaction.tokenOutputs,
|
|
2634
|
+
sparkOperatorIdentityPublicKeys: tx.tokenTransaction.sparkOperatorIdentityPublicKeys,
|
|
2635
|
+
expiryTime: void 0,
|
|
2636
|
+
// V0 doesn't have expiry time
|
|
2637
|
+
clientCreatedTimestamp: tx.tokenTransaction?.tokenInputs?.$case === "mintInput" ? new Date(
|
|
2638
|
+
tx.tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp * 1e3
|
|
2639
|
+
) : /* @__PURE__ */ new Date()
|
|
2640
|
+
};
|
|
2641
|
+
return {
|
|
2642
|
+
tokenTransaction: v1TokenTransaction,
|
|
2643
|
+
status: tx.status,
|
|
2644
|
+
confirmationMetadata: tx.confirmationMetadata
|
|
2645
|
+
};
|
|
2646
|
+
});
|
|
2647
|
+
} catch (error) {
|
|
2648
|
+
throw new NetworkError(
|
|
2649
|
+
"Failed to query token transactions",
|
|
2650
|
+
{
|
|
2651
|
+
operation: "spark.query_token_transactions",
|
|
2652
|
+
errorCount: 1,
|
|
2653
|
+
errors: error instanceof Error ? error.message : String(error)
|
|
2654
|
+
},
|
|
2655
|
+
error
|
|
2656
|
+
);
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
async queryTokenTransactionsV1(params) {
|
|
2660
|
+
const {
|
|
2661
|
+
ownerPublicKeys,
|
|
2662
|
+
issuerPublicKeys,
|
|
2663
|
+
tokenTransactionHashes,
|
|
2664
|
+
tokenIdentifiers,
|
|
2665
|
+
outputIds
|
|
2666
|
+
} = params;
|
|
2667
|
+
const tokenClient = await this.connectionManager.createSparkTokenClient(
|
|
2668
|
+
this.config.getCoordinatorAddress()
|
|
2073
2669
|
);
|
|
2670
|
+
let queryParams = {
|
|
2671
|
+
issuerPublicKeys: issuerPublicKeys?.map(import_utils7.hexToBytes),
|
|
2672
|
+
ownerPublicKeys: ownerPublicKeys?.map(import_utils7.hexToBytes),
|
|
2673
|
+
tokenIdentifiers: tokenIdentifiers?.map(import_utils7.hexToBytes),
|
|
2674
|
+
tokenTransactionHashes: tokenTransactionHashes?.map(import_utils7.hexToBytes),
|
|
2675
|
+
outputIds: outputIds || [],
|
|
2676
|
+
limit: 100,
|
|
2677
|
+
offset: 0
|
|
2678
|
+
};
|
|
2679
|
+
try {
|
|
2680
|
+
const response = await tokenClient.query_token_transactions(queryParams);
|
|
2681
|
+
return response.tokenTransactionsWithStatus;
|
|
2682
|
+
} catch (error) {
|
|
2683
|
+
throw new NetworkError(
|
|
2684
|
+
"Failed to query token transactions",
|
|
2685
|
+
{
|
|
2686
|
+
operation: "spark_token.query_token_transactions",
|
|
2687
|
+
errorCount: 1,
|
|
2688
|
+
errors: error instanceof Error ? error.message : String(error)
|
|
2689
|
+
},
|
|
2690
|
+
error
|
|
2691
|
+
);
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
async syncTokenOutputs(tokenOutputs) {
|
|
2695
|
+
const unsortedTokenOutputs = await this.fetchOwnedTokenOutputs({
|
|
2696
|
+
ownerPublicKeys: await this.config.signer.getTrackedPublicKeys()
|
|
2697
|
+
});
|
|
2074
2698
|
unsortedTokenOutputs.forEach((output) => {
|
|
2075
2699
|
const tokenKey = (0, import_utils6.bytesToHex)(output.output.tokenPublicKey);
|
|
2076
2700
|
const index = output.previousTransactionVout;
|