@quantovainc/qcore 0.1.31 → 0.1.33
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/browser.mjs +2 -2
- package/index.d.ts +21 -3
- package/index.js +2 -2
- package/package.json +3 -2
- package/pkg/package.json +1 -1
- package/pkg/qcore_js.d.ts +7 -7
- package/pkg/qcore_js_bg.js +34 -46
- package/pkg/qcore_js_bg.wasm +0 -0
- package/pkg/qcore_js_bg.wasm.d.ts +7 -7
- package/pkg-node/package.json +1 -1
- package/pkg-node/qcore_js.d.ts +7 -7
- package/pkg-node/qcore_js.js +34 -46
- package/pkg-node/qcore_js_bg.wasm +0 -0
- package/shared.js +159 -70
- package/shared.mjs +557 -0
package/shared.js
CHANGED
|
@@ -28,7 +28,15 @@ function checkAmount(amount) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function accountIndex(index) {
|
|
31
|
-
|
|
31
|
+
if (typeof index === 'number' && !Number.isSafeInteger(index)) {
|
|
32
|
+
throw new Error('the account index must be a whole number in the safe integer range, a number that large silently rounds and would sign with a different account key');
|
|
33
|
+
}
|
|
34
|
+
let i;
|
|
35
|
+
try {
|
|
36
|
+
i = BigInt(index);
|
|
37
|
+
} catch {
|
|
38
|
+
throw new Error('the account index must be a whole number');
|
|
39
|
+
}
|
|
32
40
|
if (i < 0n || i > 0xffffffffffffffffn) {
|
|
33
41
|
throw new Error('the account index must fit in an unsigned 64 bit integer');
|
|
34
42
|
}
|
|
@@ -51,6 +59,53 @@ function accountNonce(nonce) {
|
|
|
51
59
|
return n;
|
|
52
60
|
}
|
|
53
61
|
|
|
62
|
+
const VALIDITY_BLOCKS = 300n;
|
|
63
|
+
const MAX_PLAUSIBLE_HEAD = 1n << 40n;
|
|
64
|
+
const HEAD_BLOCKS_PER_SEC = 4n;
|
|
65
|
+
const HEAD_SLACK_SECS = 60n;
|
|
66
|
+
const TRANSFER_METER = 1210n;
|
|
67
|
+
|
|
68
|
+
function meterLimitOf(meterLimit) {
|
|
69
|
+
if (typeof meterLimit === 'number' && !Number.isSafeInteger(meterLimit)) {
|
|
70
|
+
throw new Error('the meter limit must be a whole number in the safe integer range');
|
|
71
|
+
}
|
|
72
|
+
let meter;
|
|
73
|
+
try {
|
|
74
|
+
meter = BigInt(meterLimit);
|
|
75
|
+
} catch {
|
|
76
|
+
throw new Error('the meter limit must be a whole number');
|
|
77
|
+
}
|
|
78
|
+
if (meter < 0n || meter > 0xffffffffffffffffn) {
|
|
79
|
+
throw new Error('the meter limit must fit in an unsigned 64 bit integer');
|
|
80
|
+
}
|
|
81
|
+
return meter;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function vmCallFee(transferFee, meterLimit) {
|
|
85
|
+
const meter = meterLimitOf(meterLimit);
|
|
86
|
+
let units = (meter + TRANSFER_METER - 1n) / TRANSFER_METER;
|
|
87
|
+
if (units < 1n) units = 1n;
|
|
88
|
+
return BigInt(transferFee) * units;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function validUntil(info) {
|
|
92
|
+
const head = info && info.head_height;
|
|
93
|
+
if (head == null) throw new Error('the gateway did not report a head height to bound the transaction to');
|
|
94
|
+
if (typeof head === 'number' && !Number.isSafeInteger(head)) {
|
|
95
|
+
throw new Error('the gateway reported a head height outside the safe integer range');
|
|
96
|
+
}
|
|
97
|
+
let h;
|
|
98
|
+
try {
|
|
99
|
+
h = BigInt(head);
|
|
100
|
+
} catch {
|
|
101
|
+
throw new Error('the gateway reported a head height that is not a whole number');
|
|
102
|
+
}
|
|
103
|
+
if (h < 0n || h > MAX_PLAUSIBLE_HEAD) {
|
|
104
|
+
throw new Error('the gateway reported a head height past any height this chain can have reached');
|
|
105
|
+
}
|
|
106
|
+
return h + VALIDITY_BLOCKS;
|
|
107
|
+
}
|
|
108
|
+
|
|
54
109
|
function gatewayFee(fee) {
|
|
55
110
|
if (typeof fee === 'number' && !Number.isSafeInteger(fee)) {
|
|
56
111
|
throw new Error('the gateway reported a fee outside the safe integer range, a number that large silently rounds and would sign a different fee');
|
|
@@ -83,7 +138,7 @@ async function readBounded(res) {
|
|
|
83
138
|
if (done) break;
|
|
84
139
|
total += value.byteLength;
|
|
85
140
|
if (total > MAX_RESPONSE) {
|
|
86
|
-
try { await reader.cancel(); } catch {
|
|
141
|
+
try { await reader.cancel(); } catch {}
|
|
87
142
|
throw new Error('the response is too large');
|
|
88
143
|
}
|
|
89
144
|
chunks.push(value);
|
|
@@ -198,12 +253,6 @@ function makeClient(core) {
|
|
|
198
253
|
this.network = opts.network instanceof Network ? opts.network : Network.forUrl(base);
|
|
199
254
|
}
|
|
200
255
|
this.base = requireSafeTransport(base).replace(/\/$/, '');
|
|
201
|
-
// The chain name the gateway reports is hashed into the signature preimage of
|
|
202
|
-
// every signing path, so whoever names it decides which network a signature is
|
|
203
|
-
// valid on. `Network.forUrl` leaves chainId null, which is the default for
|
|
204
|
-
// `new Client(url)`, and the configured check is skipped when it is null, so by
|
|
205
|
-
// default the endpoint chose. Bind it with expectedChainId, or rely on the pin,
|
|
206
|
-
// which at least refuses a gateway that changes its mind mid session.
|
|
207
256
|
this.expectedChainId =
|
|
208
257
|
typeof opts.expectedChainId === 'string' && opts.expectedChainId.length > 0
|
|
209
258
|
? opts.expectedChainId
|
|
@@ -231,12 +280,6 @@ function makeClient(core) {
|
|
|
231
280
|
if (!this.acknowledgeMainnet && this._isMainnetId(id)) {
|
|
232
281
|
throw new Error(`the gateway reports the mainnet chain ${name}; refusing to sign a mainnet transaction without acknowledgeMainnet`);
|
|
233
282
|
}
|
|
234
|
-
// Pin on first ACCEPTED use, after every refusal above. With nothing configured
|
|
235
|
-
// the endpoint names the chain, and the least this can do is refuse one that
|
|
236
|
-
// answers differently later in the same session, which is how a signature ends
|
|
237
|
-
// up bound to a network the caller never chose while every earlier call looked
|
|
238
|
-
// entirely normal. Pinning a name we refused to sign for would be wrong: it was
|
|
239
|
-
// never a chain this client accepted.
|
|
240
283
|
if (this._pinnedChainName === null) {
|
|
241
284
|
this._pinnedChainName = name;
|
|
242
285
|
} else if (this._pinnedChainName !== name) {
|
|
@@ -277,19 +320,43 @@ function makeClient(core) {
|
|
|
277
320
|
head() { return this._call('head', '{}'); }
|
|
278
321
|
async account(address) {
|
|
279
322
|
const acct = await this._call('get_account', core.account_body(address));
|
|
280
|
-
if (acct
|
|
323
|
+
if (!acct || typeof acct.address !== 'string') {
|
|
324
|
+
throw new Error(`the gateway answered about ${address} without naming the account, refusing to trust it`);
|
|
325
|
+
}
|
|
326
|
+
if (acct.address !== address) {
|
|
281
327
|
throw new Error(`the gateway answered for ${acct.address} when asked about ${address}, refusing to trust it`);
|
|
282
328
|
}
|
|
283
329
|
return acct;
|
|
284
330
|
}
|
|
285
|
-
_checkedNonce(reported, expected) {
|
|
331
|
+
_checkedNonce(reported, expected, key) {
|
|
286
332
|
const n = accountNonce(reported);
|
|
287
|
-
if (
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
333
|
+
if (!this._nextNonces) this._nextNonces = new Map();
|
|
334
|
+
const local = key != null ? this._nextNonces.get(key) : undefined;
|
|
335
|
+
const e = expected != null ? BigInt(expected) : local;
|
|
336
|
+
if (e == null) return n;
|
|
337
|
+
if (n > e) throw new Error(`the gateway reported nonce ${n} above the expected ${e}; refusing so a signature cannot be banked for a nonce the account has not reached`);
|
|
338
|
+
return expected != null ? e : n;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
_remember(key, used, outcome) {
|
|
342
|
+
if (!this._nextNonces) this._nextNonces = new Map();
|
|
343
|
+
if (outcome && outcome.verdict === 'accepted') this._nextNonces.set(key, BigInt(used) + 1n);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
_validity(info) {
|
|
347
|
+
const until = validUntil(info);
|
|
348
|
+
const head = until - VALIDITY_BLOCKS;
|
|
349
|
+
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
350
|
+
if (this._headFloor) {
|
|
351
|
+
const { height, at } = this._headFloor;
|
|
352
|
+
if (head < height) throw new Error(`the gateway reports head ${head} below the ${height} it reported earlier, refusing to sign`);
|
|
353
|
+
const elapsed = now > at ? now - at : 0n;
|
|
354
|
+
const allowed = (elapsed + HEAD_SLACK_SECS) * HEAD_BLOCKS_PER_SEC;
|
|
355
|
+
if (head > height + allowed) throw new Error(`the gateway head leapt from ${height} to ${head} faster than blocks are made, refusing to sign`);
|
|
356
|
+
} else {
|
|
357
|
+
this._headFloor = { height: head, at: now };
|
|
291
358
|
}
|
|
292
|
-
return
|
|
359
|
+
return until;
|
|
293
360
|
}
|
|
294
361
|
transaction(txId) { return this._call('get_transaction', core.transaction_body(txId)); }
|
|
295
362
|
block(height) { return this._call('get_block', core.block_by_height_body(BigInt(height))); }
|
|
@@ -307,62 +374,70 @@ function makeClient(core) {
|
|
|
307
374
|
const info = await this.nodeInfo();
|
|
308
375
|
this._guardMainnet();
|
|
309
376
|
const chainId = this._signingChainId(info);
|
|
310
|
-
const
|
|
311
|
-
if (
|
|
312
|
-
|
|
377
|
+
const reported = info && info.fee && info.fee.transfer_quon;
|
|
378
|
+
if (reported == null) throw new Error('the gateway did not report a transfer fee');
|
|
379
|
+
const fee = gatewayFee(reported);
|
|
380
|
+
if (fee > ceiling) {
|
|
313
381
|
throw new Error(`the gateway fee ${fee} is above the maximum you allowed ${maxFeeQuon}, refusing to sign`);
|
|
314
382
|
}
|
|
315
383
|
const from = core.address(seedHex, accountIndex(index));
|
|
316
384
|
const acct = await this.account(from);
|
|
317
385
|
if (!acct || acct.nonce == null) throw new Error('the gateway did not report a nonce');
|
|
318
|
-
const nonce = this._checkedNonce(acct.nonce, expectedNonce);
|
|
386
|
+
const nonce = this._checkedNonce(acct.nonce, expectedNonce, from);
|
|
319
387
|
const signed = JSON.parse(
|
|
320
|
-
core.sign_transfer(seedHex, accountIndex(index), to, String(amount), nonce, String(fee), chainId)
|
|
388
|
+
core.sign_transfer(seedHex, accountIndex(index), to, String(amount), nonce, String(fee), chainId, this._validity(info))
|
|
321
389
|
);
|
|
322
390
|
const outcome = await this.submit(signed.tx_hex);
|
|
391
|
+
this._remember(from, nonce, outcome);
|
|
323
392
|
return { signed, outcome };
|
|
324
393
|
}
|
|
325
394
|
|
|
326
|
-
async register(seedHex, index, maxFeeQuon) {
|
|
395
|
+
async register(seedHex, index, maxFeeQuon, expectedNonce) {
|
|
327
396
|
const ceiling = feeCeiling(maxFeeQuon);
|
|
328
397
|
const info = await this.nodeInfo();
|
|
329
398
|
this._guardMainnet();
|
|
330
399
|
const chainId = this._signingChainId(info);
|
|
331
|
-
const
|
|
332
|
-
if (
|
|
333
|
-
|
|
400
|
+
const reported = info && info.fee && info.fee.transfer_quon;
|
|
401
|
+
if (reported == null) throw new Error('the gateway did not report a transfer fee');
|
|
402
|
+
const fee = gatewayFee(reported);
|
|
403
|
+
if (fee > ceiling) {
|
|
334
404
|
throw new Error(`the gateway fee ${fee} is above the maximum you allowed ${maxFeeQuon}, refusing to sign`);
|
|
335
405
|
}
|
|
336
406
|
const from = core.address(seedHex, accountIndex(index));
|
|
337
407
|
const acct = await this.account(from);
|
|
338
408
|
if (!acct || acct.nonce == null) throw new Error('the gateway did not report a nonce');
|
|
339
|
-
const
|
|
409
|
+
const nonce = this._checkedNonce(acct.nonce, expectedNonce, from);
|
|
410
|
+
const signed = JSON.parse(core.signRegister(seedHex, accountIndex(index), nonce, String(fee), chainId, this._validity(info)));
|
|
340
411
|
const outcome = await this.submit(signed.tx_hex);
|
|
412
|
+
this._remember(from, nonce, outcome);
|
|
341
413
|
return { signed, outcome };
|
|
342
414
|
}
|
|
343
415
|
|
|
344
|
-
async call(seedHex, index, target, argsHex, meterLimit, maxFeeQuon) {
|
|
416
|
+
async call(seedHex, index, target, argsHex, meterLimit, maxFeeQuon, expectedNonce) {
|
|
345
417
|
if (!core.valid_address(target)) throw new Error('the target is not a q1 address');
|
|
346
418
|
const ceiling = feeCeiling(maxFeeQuon);
|
|
347
419
|
const info = await this.nodeInfo();
|
|
348
420
|
this._guardMainnet();
|
|
349
421
|
const chainId = this._signingChainId(info);
|
|
350
|
-
const
|
|
351
|
-
if (
|
|
352
|
-
|
|
353
|
-
|
|
422
|
+
const reported = info && info.fee && info.fee.transfer_quon;
|
|
423
|
+
if (reported == null) throw new Error('the gateway did not report a transfer fee');
|
|
424
|
+
const fee = vmCallFee(gatewayFee(reported), meterLimit);
|
|
425
|
+
if (fee > ceiling) {
|
|
426
|
+
throw new Error(`the fee ${fee} is above the maximum you allowed ${maxFeeQuon}, refusing to sign`);
|
|
354
427
|
}
|
|
355
428
|
const from = core.address(seedHex, accountIndex(index));
|
|
356
429
|
const acct = await this.account(from);
|
|
357
430
|
if (!acct || acct.nonce == null) throw new Error('the gateway did not report a nonce');
|
|
431
|
+
const nonce = this._checkedNonce(acct.nonce, expectedNonce, from);
|
|
358
432
|
const signed = JSON.parse(
|
|
359
|
-
core.sign_call(seedHex, accountIndex(index), target, argsHex,
|
|
433
|
+
core.sign_call(seedHex, accountIndex(index), target, argsHex, nonce, meterLimitOf(meterLimit), String(fee), chainId, this._validity(info))
|
|
360
434
|
);
|
|
361
435
|
const outcome = await this.submit(signed.tx_hex);
|
|
436
|
+
this._remember(from, nonce, outcome);
|
|
362
437
|
return { signed, outcome };
|
|
363
438
|
}
|
|
364
439
|
|
|
365
|
-
async assetCall(seedHex, index, target, argsHex, assetIssuer, amount, meterLimit, maxFeeQuon) {
|
|
440
|
+
async assetCall(seedHex, index, target, argsHex, assetIssuer, amount, meterLimit, maxFeeQuon, expectedNonce) {
|
|
366
441
|
if (!core.valid_address(target)) throw new Error('the target is not a q1 address');
|
|
367
442
|
if (!core.valid_address(assetIssuer)) throw new Error('the asset issuer is not a q1 address');
|
|
368
443
|
checkAmount(amount);
|
|
@@ -370,77 +445,83 @@ function makeClient(core) {
|
|
|
370
445
|
const info = await this.nodeInfo();
|
|
371
446
|
this._guardMainnet();
|
|
372
447
|
const chainId = this._signingChainId(info);
|
|
373
|
-
const
|
|
374
|
-
if (
|
|
375
|
-
|
|
376
|
-
|
|
448
|
+
const reported = info && info.fee && info.fee.transfer_quon;
|
|
449
|
+
if (reported == null) throw new Error('the gateway did not report a transfer fee');
|
|
450
|
+
const fee = vmCallFee(gatewayFee(reported), meterLimit);
|
|
451
|
+
if (fee > ceiling) {
|
|
452
|
+
throw new Error(`the fee ${fee} is above the maximum you allowed ${maxFeeQuon}, refusing to sign`);
|
|
377
453
|
}
|
|
378
454
|
const from = core.address(seedHex, accountIndex(index));
|
|
379
455
|
const acct = await this.account(from);
|
|
380
456
|
if (!acct || acct.nonce == null) throw new Error('the gateway did not report a nonce');
|
|
457
|
+
const nonce = this._checkedNonce(acct.nonce, expectedNonce, from);
|
|
381
458
|
const signed = JSON.parse(
|
|
382
|
-
core.signAssetCall(seedHex, accountIndex(index), target, argsHex, assetIssuer, String(amount),
|
|
459
|
+
core.signAssetCall(seedHex, accountIndex(index), target, argsHex, assetIssuer, String(amount), nonce, meterLimitOf(meterLimit), String(fee), chainId, this._validity(info))
|
|
383
460
|
);
|
|
384
461
|
const outcome = await this.submit(signed.tx_hex);
|
|
462
|
+
this._remember(from, nonce, outcome);
|
|
385
463
|
return { signed, outcome };
|
|
386
464
|
}
|
|
387
465
|
|
|
388
|
-
async payableCall(seedHex, index, target, argsHex, value, meterLimit, maxFeeQuon) {
|
|
466
|
+
async payableCall(seedHex, index, target, argsHex, value, meterLimit, maxFeeQuon, expectedNonce) {
|
|
389
467
|
if (!core.valid_address(target)) throw new Error('the target is not a q1 address');
|
|
390
468
|
checkAmount(value);
|
|
391
469
|
const ceiling = feeCeiling(maxFeeQuon);
|
|
392
470
|
const info = await this.nodeInfo();
|
|
393
471
|
this._guardMainnet();
|
|
394
472
|
const chainId = this._signingChainId(info);
|
|
395
|
-
const
|
|
396
|
-
if (
|
|
397
|
-
|
|
398
|
-
|
|
473
|
+
const reported = info && info.fee && info.fee.transfer_quon;
|
|
474
|
+
if (reported == null) throw new Error('the gateway did not report a transfer fee');
|
|
475
|
+
const fee = vmCallFee(gatewayFee(reported), meterLimit);
|
|
476
|
+
if (fee > ceiling) {
|
|
477
|
+
throw new Error(`the fee ${fee} is above the maximum you allowed ${maxFeeQuon}, refusing to sign`);
|
|
399
478
|
}
|
|
400
479
|
const from = core.address(seedHex, accountIndex(index));
|
|
401
480
|
const acct = await this.account(from);
|
|
402
481
|
if (!acct || acct.nonce == null) throw new Error('the gateway did not report a nonce');
|
|
482
|
+
const nonce = this._checkedNonce(acct.nonce, expectedNonce, from);
|
|
403
483
|
const signed = JSON.parse(
|
|
404
|
-
core.signPayableCall(seedHex, accountIndex(index), target, argsHex,
|
|
484
|
+
core.signPayableCall(seedHex, accountIndex(index), target, argsHex, nonce, meterLimitOf(meterLimit), String(fee), String(value), chainId, this._validity(info))
|
|
405
485
|
);
|
|
406
486
|
const outcome = await this.submit(signed.tx_hex);
|
|
487
|
+
this._remember(from, nonce, outcome);
|
|
407
488
|
return { signed, outcome };
|
|
408
489
|
}
|
|
409
490
|
|
|
491
|
+
async _slotValue(contract, key) {
|
|
492
|
+
const resp = await this._call('get_storage_at', JSON.stringify({ address: contract, keys: [key] }));
|
|
493
|
+
return BigInt(core.storageValue(JSON.stringify(resp), key));
|
|
494
|
+
}
|
|
495
|
+
|
|
410
496
|
async contractNonce(contract, signerHex) {
|
|
411
|
-
|
|
412
|
-
return BigInt(core.storageValue(JSON.stringify(resp), core.nonceSlotKey(signerHex)));
|
|
497
|
+
return this._slotValue(contract, core.nonceSlotKey(signerHex));
|
|
413
498
|
}
|
|
414
499
|
|
|
415
500
|
async contractScalar(contract, slot) {
|
|
416
|
-
|
|
417
|
-
return BigInt(core.storageValue(JSON.stringify(resp), core.scalarSlotKey(BigInt(slot))));
|
|
501
|
+
return this._slotValue(contract, core.scalarSlotKey(BigInt(slot)));
|
|
418
502
|
}
|
|
419
503
|
|
|
420
|
-
async callSignedOrder(callerSeedHex, callerIndex, contract, selectorHex, orderSpec, ownerSeedHex, ownerIndex, meterLimit, maxFeeQuon, expectedOrderNonce) {
|
|
504
|
+
async callSignedOrder(callerSeedHex, callerIndex, contract, selectorHex, orderSpec, ownerSeedHex, ownerIndex, meterLimit, maxFeeQuon, expectedOrderNonce, expectedNonce) {
|
|
421
505
|
if (!core.valid_address(contract)) throw new Error('the contract is not a q1 address');
|
|
422
506
|
const ceiling = feeCeiling(maxFeeQuon);
|
|
423
507
|
const info = await this.nodeInfo();
|
|
424
508
|
this._guardMainnet();
|
|
425
509
|
const chainId = this._signingChainId(info);
|
|
426
|
-
const
|
|
427
|
-
if (
|
|
428
|
-
|
|
429
|
-
|
|
510
|
+
const reported = info && info.fee && info.fee.transfer_quon;
|
|
511
|
+
if (reported == null) throw new Error('the gateway did not report a transfer fee');
|
|
512
|
+
const fee = vmCallFee(gatewayFee(reported), meterLimit);
|
|
513
|
+
if (fee > ceiling) {
|
|
514
|
+
throw new Error(`the fee ${fee} is above the maximum you allowed ${maxFeeQuon}, refusing to sign`);
|
|
430
515
|
}
|
|
431
516
|
const signer = core.orderSigner(ownerSeedHex, accountIndex(ownerIndex));
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
// nonce and the reply is a valid order banked until the contract counter reaches
|
|
436
|
-
// it. Pass expectedOrderNonce to bind what you meant to sign; without it you are
|
|
437
|
-
// trusting the endpoint with the owner key.
|
|
438
|
-
const nonce = await this.contractNonce(contract, signer);
|
|
439
|
-
if (expectedOrderNonce != null && BigInt(expectedOrderNonce) !== nonce) {
|
|
517
|
+
const orderKey = contract + '/' + signer;
|
|
518
|
+
const reportedOrder = await this.contractNonce(contract, signer);
|
|
519
|
+
if (expectedOrderNonce != null && BigInt(expectedOrderNonce) !== reportedOrder) {
|
|
440
520
|
throw new Error(
|
|
441
|
-
`the gateway reported order nonce ${
|
|
521
|
+
`the gateway reported order nonce ${reportedOrder} but you expected ${expectedOrderNonce}, refusing to sign`
|
|
442
522
|
);
|
|
443
523
|
}
|
|
524
|
+
const nonce = this._checkedNonce(reportedOrder, expectedOrderNonce, orderKey);
|
|
444
525
|
const order = JSON.parse(core.buildTypedOrderCall(
|
|
445
526
|
chainId,
|
|
446
527
|
contract,
|
|
@@ -448,7 +529,12 @@ function makeClient(core) {
|
|
|
448
529
|
BigInt(orderSpec.schemeOff),
|
|
449
530
|
BigInt(orderSpec.ptrOff),
|
|
450
531
|
BigInt(orderSpec.regionOff || 0),
|
|
451
|
-
JSON.stringify(orderSpec.fields || [])
|
|
532
|
+
JSON.stringify(orderSpec.fields || [], (k, v) => {
|
|
533
|
+
if (typeof v !== 'bigint') return v;
|
|
534
|
+
if (k === 'value') return v.toString();
|
|
535
|
+
if (v > BigInt(Number.MAX_SAFE_INTEGER)) throw new Error(`the order field ${k} ${v} is too large to carry`);
|
|
536
|
+
return Number(v);
|
|
537
|
+
}),
|
|
452
538
|
ownerSeedHex,
|
|
453
539
|
accountIndex(ownerIndex),
|
|
454
540
|
nonce,
|
|
@@ -456,13 +542,16 @@ function makeClient(core) {
|
|
|
456
542
|
const from = core.address(callerSeedHex, accountIndex(callerIndex));
|
|
457
543
|
const acct = await this.account(from);
|
|
458
544
|
if (!acct || acct.nonce == null) throw new Error('the gateway did not report a nonce');
|
|
545
|
+
const accountNonceUsed = this._checkedNonce(acct.nonce, expectedNonce, from);
|
|
459
546
|
const signed = JSON.parse(
|
|
460
|
-
core.sign_call(callerSeedHex, accountIndex(callerIndex), contract, order.call_args,
|
|
547
|
+
core.sign_call(callerSeedHex, accountIndex(callerIndex), contract, order.call_args, accountNonceUsed, meterLimitOf(meterLimit), String(fee), chainId, this._validity(info))
|
|
461
548
|
);
|
|
462
549
|
const outcome = await this.submit(signed.tx_hex);
|
|
550
|
+
this._remember(from, accountNonceUsed, outcome);
|
|
551
|
+
this._remember(orderKey, nonce, outcome);
|
|
463
552
|
return { order, signed, outcome, orderNonce: nonce };
|
|
464
553
|
}
|
|
465
554
|
};
|
|
466
555
|
}
|
|
467
556
|
|
|
468
|
-
module.exports = { makeClient, feeCeiling, checkAmount, generateSeed, readBounded, requireSafeTransport, Network };
|
|
557
|
+
module.exports = { makeClient, feeCeiling, checkAmount, generateSeed, readBounded, requireSafeTransport, validUntil, vmCallFee, VALIDITY_BLOCKS, Network };
|