@quantovainc/qcore 0.5.4 → 0.5.6

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/README.md CHANGED
@@ -134,6 +134,13 @@ Pass `addressBook`, a list of Q1 addresses you trust, in the Client options, and
134
134
  a target that shares two or more leading and trailing characters with a known address, eight in all, but is a
135
135
  different address. The sending accounts and every target signed for in the session are known as well.
136
136
 
137
+ Pass `fetch`, a function with the fetch signature, in the Client options to route every gateway request
138
+ through your own transport, for example one that enforces an address allow list. Without it the Client
139
+ uses the platform fetch, which on Node follows HTTPS_PROXY only when NODE_USE_ENV_PROXY is set. The
140
+ Client refuses to start when NODE_TLS_REJECT_UNAUTHORIZED is 0. Signing calls for one account run one at a
141
+ time across every Client in the process, and each Client keeps its own record of signed nonces, so keep
142
+ one Client per account to have every nonce tracked in one place.
143
+
137
144
  The last argument to a Client signing call, transfer, register, call, or callSignedOrder, is a fee
138
145
  ceiling, the most you are ever willing to pay in fees for one transaction. You choose it yourself, as a
139
146
  fixed number your app decides on its own, before you sign. The Client reads the gateway's reported fee,
package/index.d.ts CHANGED
@@ -237,6 +237,7 @@ export interface ClientOptions {
237
237
  network?: Network;
238
238
  expectedChainId?: string;
239
239
  addressBook?: ReadonlyArray<string>;
240
+ fetch?: (url: string, init: { method: string; headers: Record<string, string>; body: string; signal: AbortSignal; redirect: 'error' }) => Promise<Response>;
240
241
  }
241
242
 
242
243
  export class Client {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantovainc/qcore",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "Quantova's post quantum client core for JavaScript. Signs with ML-DSA-65 and builds Q1 addresses.",
5
5
  "scripts": {
6
6
  "build": "bash scripts/build.sh",
package/pkg/README.md CHANGED
@@ -134,6 +134,13 @@ Pass `addressBook`, a list of Q1 addresses you trust, in the Client options, and
134
134
  a target that shares two or more leading and trailing characters with a known address, eight in all, but is a
135
135
  different address. The sending accounts and every target signed for in the session are known as well.
136
136
 
137
+ Pass `fetch`, a function with the fetch signature, in the Client options to route every gateway request
138
+ through your own transport, for example one that enforces an address allow list. Without it the Client
139
+ uses the platform fetch, which on Node follows HTTPS_PROXY only when NODE_USE_ENV_PROXY is set. The
140
+ Client refuses to start when NODE_TLS_REJECT_UNAUTHORIZED is 0. Signing calls for one account run one at a
141
+ time across every Client in the process, and each Client keeps its own record of signed nonces, so keep
142
+ one Client per account to have every nonce tracked in one place.
143
+
137
144
  The last argument to a Client signing call, transfer, register, call, or callSignedOrder, is a fee
138
145
  ceiling, the most you are ever willing to pay in fees for one transaction. You choose it yourself, as a
139
146
  fixed number your app decides on its own, before you sign. The Client reads the gateway's reported fee,
package/pkg/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "qcore-js",
3
3
  "type": "module",
4
4
  "description": "The JavaScript binding for the Quantova client core, generated over QCore with wasm-bindgen. The core does the key derivation, the post quantum signing, and the wire, the page does the fetch.",
5
- "version": "0.5.4",
5
+ "version": "0.5.6",
6
6
  "license": "Apache-2.0 OR MIT",
7
7
  "repository": {
8
8
  "type": "git",
@@ -323,7 +323,10 @@ export function chainIdFromName(name) {
323
323
  const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
324
324
  const len0 = WASM_VECTOR_LEN;
325
325
  const ret = wasm.chainIdFromName(ptr0, len0);
326
- return BigInt.asUintN(64, ret);
326
+ if (ret[2]) {
327
+ throw takeFromExternrefTable0(ret[1]);
328
+ }
329
+ return BigInt.asUintN(64, ret[0]);
327
330
  }
328
331
 
329
332
  /**
Binary file
@@ -10,7 +10,7 @@ export const block_by_height_body: (a: bigint) => [number, number];
10
10
  export const boundedValidUntil: (a: number, b: number, c: bigint, d: bigint, e: number, f: bigint, g: bigint) => [bigint, number, number];
11
11
  export const buildSignedOrderCall: (a: bigint, b: number, c: number, d: number, e: number, f: number, g: number, h: bigint, i: bigint, j: bigint, k: number, l: number, m: number, n: number, o: bigint, p: number, q: number, r: bigint, s: bigint, t: bigint) => [number, number, number, number];
12
12
  export const buildTypedOrderCall: (a: bigint, b: number, c: number, d: number, e: number, f: number, g: number, h: bigint, i: bigint, j: bigint, k: bigint, l: number, m: number, n: number, o: number, p: bigint, q: bigint, r: bigint) => [number, number, number, number];
13
- export const chainIdFromName: (a: number, b: number) => bigint;
13
+ export const chainIdFromName: (a: number, b: number) => [bigint, number, number];
14
14
  export const checkGatewayJson: (a: number, b: number) => [number, number];
15
15
  export const checkOrderExpiry: (a: bigint, b: bigint) => [number, number];
16
16
  export const checkValidUntil: (a: bigint, b: bigint) => [number, number];
@@ -134,6 +134,13 @@ Pass `addressBook`, a list of Q1 addresses you trust, in the Client options, and
134
134
  a target that shares two or more leading and trailing characters with a known address, eight in all, but is a
135
135
  different address. The sending accounts and every target signed for in the session are known as well.
136
136
 
137
+ Pass `fetch`, a function with the fetch signature, in the Client options to route every gateway request
138
+ through your own transport, for example one that enforces an address allow list. Without it the Client
139
+ uses the platform fetch, which on Node follows HTTPS_PROXY only when NODE_USE_ENV_PROXY is set. The
140
+ Client refuses to start when NODE_TLS_REJECT_UNAUTHORIZED is 0. Signing calls for one account run one at a
141
+ time across every Client in the process, and each Client keeps its own record of signed nonces, so keep
142
+ one Client per account to have every nonce tracked in one place.
143
+
137
144
  The last argument to a Client signing call, transfer, register, call, or callSignedOrder, is a fee
138
145
  ceiling, the most you are ever willing to pay in fees for one transaction. You choose it yourself, as a
139
146
  fixed number your app decides on its own, before you sign. The Client reads the gateway's reported fee,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "qcore-js",
3
3
  "description": "The JavaScript binding for the Quantova client core, generated over QCore with wasm-bindgen. The core does the key derivation, the post quantum signing, and the wire, the page does the fetch.",
4
- "version": "0.5.4",
4
+ "version": "0.5.6",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -334,7 +334,10 @@ function chainIdFromName(name) {
334
334
  const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
335
335
  const len0 = WASM_VECTOR_LEN;
336
336
  const ret = wasm.chainIdFromName(ptr0, len0);
337
- return BigInt.asUintN(64, ret);
337
+ if (ret[2]) {
338
+ throw takeFromExternrefTable0(ret[1]);
339
+ }
340
+ return BigInt.asUintN(64, ret[0]);
338
341
  }
339
342
  exports.chainIdFromName = chainIdFromName;
340
343
 
Binary file
package/shared.js CHANGED
@@ -59,6 +59,20 @@ function wholeNumber(value, label, max) {
59
59
  return n;
60
60
  }
61
61
 
62
+ const ACCOUNT_LOCKS = new Map();
63
+
64
+ function requireVerifiedTls() {
65
+ const env = typeof process !== 'undefined' && process && process.env ? process.env : null;
66
+ if (env && env.NODE_TLS_REJECT_UNAUTHORIZED === '0') {
67
+ throw new Error('this process has TLS certificate checks turned off with NODE_TLS_REJECT_UNAUTHORIZED=0, refusing to talk to a gateway');
68
+ }
69
+ }
70
+
71
+ function shown(value) {
72
+ const text = String(value).replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, '');
73
+ return text.length > 96 ? text.slice(0, 96) + '...' : text;
74
+ }
75
+
62
76
  function coreArg(kind, label, value) {
63
77
  if (kind === 'text') {
64
78
  if (typeof value !== 'string') throw new Error(`the ${label} must be a string`);
@@ -343,7 +357,10 @@ function makeClient(core) {
343
357
  this._session = new core.SigningSession(book);
344
358
  this._pinnedChainName = null;
345
359
  this._headFloor = null;
346
- this._locks = new Map();
360
+ if (opts.fetch != null && typeof opts.fetch !== 'function') throw new Error('the fetch option must be a function with the fetch signature');
361
+ this._fetch = opts.fetch || ((url, init) => fetch(url, init));
362
+ requireVerifiedTls();
363
+ this._locks = ACCOUNT_LOCKS;
347
364
  for (const name of ['transfer', 'register', 'call', 'assetCall', 'payableCall']) {
348
365
  const inner = this[name].bind(this);
349
366
  this[name] = (seed, index, ...rest) => {
@@ -392,18 +409,18 @@ function makeClient(core) {
392
409
  const mainnet = isMainnetChain(name);
393
410
  if (configured) {
394
411
  if (name !== configured) {
395
- throw new Error(`the gateway reports chain ${name} but this client is configured for ${configured}; refusing to sign a transaction that would be valid on a network you did not choose`);
412
+ throw new Error(`the gateway reports chain ${shown(name)} but this client is configured for ${configured}; refusing to sign a transaction that would be valid on a network you did not choose`);
396
413
  }
397
414
  } else if (isPublicChain(name) && !(mainnet && this.acknowledgeMainnet)) {
398
- throw new Error(`the gateway reports the public chain ${name} but this client was opened for an unnamed network; configure the testnet or mainnet network before signing for it`);
415
+ throw new Error(`the gateway reports the public chain ${shown(name)} but this client was opened for an unnamed network; configure the testnet or mainnet network before signing for it`);
399
416
  }
400
417
  if (mainnet && !this.acknowledgeMainnet) {
401
- throw new Error(`the gateway reports the mainnet chain ${name}; refusing to sign a mainnet transaction without acknowledgeMainnet`);
418
+ throw new Error(`the gateway reports the mainnet chain ${shown(name)}; refusing to sign a mainnet transaction without acknowledgeMainnet`);
402
419
  }
403
420
  if (this._pinnedChainName === null) {
404
421
  this._pinnedChainName = name;
405
422
  } else if (this._pinnedChainName !== name) {
406
- throw new Error(`the gateway reported chain ${this._pinnedChainName} earlier and now reports ${name}; refusing to sign, the endpoint is not naming one network`);
423
+ throw new Error(`the gateway reported chain ${shown(this._pinnedChainName)} earlier and now reports ${shown(name)}; refusing to sign, the endpoint is not naming one network`);
407
424
  }
408
425
  return BigInt(core.chainIdFromName(name));
409
426
  }
@@ -412,7 +429,7 @@ function makeClient(core) {
412
429
  const controller = new AbortController();
413
430
  const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
414
431
  try {
415
- const res = await fetch(this.base + '/v1/' + method, {
432
+ const res = await this._fetch(this.base + '/v1/' + method, {
416
433
  method: 'POST',
417
434
  headers: { 'Content-Type': 'application/json' },
418
435
  body: body || '{}',
@@ -425,7 +442,7 @@ function makeClient(core) {
425
442
  try { data = JSON.parse(text); } catch { throw new Error('the node returned a non JSON response'); }
426
443
  if (res.status !== 200) {
427
444
  const detail = data && typeof data === 'object' ? (data.message || data.error) : null;
428
- throw new Error(detail || ('status ' + res.status));
445
+ throw new Error(detail ? shown(detail) : ('status ' + res.status));
429
446
  }
430
447
  return data;
431
448
  } finally {
@@ -441,7 +458,7 @@ function makeClient(core) {
441
458
  throw new Error(`the gateway answered about ${address} without naming the account, refusing to trust it`);
442
459
  }
443
460
  if (acct.address !== address) {
444
- throw new Error(`the gateway answered for ${acct.address} when asked about ${address}, refusing to trust it`);
461
+ throw new Error(`the gateway answered for ${shown(acct.address)} when asked about ${address}, refusing to trust it`);
445
462
  }
446
463
  return acct;
447
464
  }
@@ -469,7 +486,7 @@ function makeClient(core) {
469
486
  for (const [key, slot] of slots) this._session.signed(key, slot);
470
487
  const outcome = await this.submit(txHex);
471
488
  const verdict = outcome && outcome.verdict;
472
- if (verdict !== 'accepted' && verdict !== 'rejected') throw new Error(`unknown verdict ${verdict}`);
489
+ if (verdict !== 'accepted' && verdict !== 'rejected') throw new Error(`unknown verdict ${shown(verdict)}`);
473
490
  for (const [key, slot] of slots) this._session.outcome(key, slot, verdict === 'accepted');
474
491
  return outcome;
475
492
  }
package/shared.mjs CHANGED
@@ -59,6 +59,20 @@ function wholeNumber(value, label, max) {
59
59
  return n;
60
60
  }
61
61
 
62
+ const ACCOUNT_LOCKS = new Map();
63
+
64
+ function requireVerifiedTls() {
65
+ const env = typeof process !== 'undefined' && process && process.env ? process.env : null;
66
+ if (env && env.NODE_TLS_REJECT_UNAUTHORIZED === '0') {
67
+ throw new Error('this process has TLS certificate checks turned off with NODE_TLS_REJECT_UNAUTHORIZED=0, refusing to talk to a gateway');
68
+ }
69
+ }
70
+
71
+ function shown(value) {
72
+ const text = String(value).replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, '');
73
+ return text.length > 96 ? text.slice(0, 96) + '...' : text;
74
+ }
75
+
62
76
  function coreArg(kind, label, value) {
63
77
  if (kind === 'text') {
64
78
  if (typeof value !== 'string') throw new Error(`the ${label} must be a string`);
@@ -343,7 +357,10 @@ function makeClient(core) {
343
357
  this._session = new core.SigningSession(book);
344
358
  this._pinnedChainName = null;
345
359
  this._headFloor = null;
346
- this._locks = new Map();
360
+ if (opts.fetch != null && typeof opts.fetch !== 'function') throw new Error('the fetch option must be a function with the fetch signature');
361
+ this._fetch = opts.fetch || ((url, init) => fetch(url, init));
362
+ requireVerifiedTls();
363
+ this._locks = ACCOUNT_LOCKS;
347
364
  for (const name of ['transfer', 'register', 'call', 'assetCall', 'payableCall']) {
348
365
  const inner = this[name].bind(this);
349
366
  this[name] = (seed, index, ...rest) => {
@@ -392,18 +409,18 @@ function makeClient(core) {
392
409
  const mainnet = isMainnetChain(name);
393
410
  if (configured) {
394
411
  if (name !== configured) {
395
- throw new Error(`the gateway reports chain ${name} but this client is configured for ${configured}; refusing to sign a transaction that would be valid on a network you did not choose`);
412
+ throw new Error(`the gateway reports chain ${shown(name)} but this client is configured for ${configured}; refusing to sign a transaction that would be valid on a network you did not choose`);
396
413
  }
397
414
  } else if (isPublicChain(name) && !(mainnet && this.acknowledgeMainnet)) {
398
- throw new Error(`the gateway reports the public chain ${name} but this client was opened for an unnamed network; configure the testnet or mainnet network before signing for it`);
415
+ throw new Error(`the gateway reports the public chain ${shown(name)} but this client was opened for an unnamed network; configure the testnet or mainnet network before signing for it`);
399
416
  }
400
417
  if (mainnet && !this.acknowledgeMainnet) {
401
- throw new Error(`the gateway reports the mainnet chain ${name}; refusing to sign a mainnet transaction without acknowledgeMainnet`);
418
+ throw new Error(`the gateway reports the mainnet chain ${shown(name)}; refusing to sign a mainnet transaction without acknowledgeMainnet`);
402
419
  }
403
420
  if (this._pinnedChainName === null) {
404
421
  this._pinnedChainName = name;
405
422
  } else if (this._pinnedChainName !== name) {
406
- throw new Error(`the gateway reported chain ${this._pinnedChainName} earlier and now reports ${name}; refusing to sign, the endpoint is not naming one network`);
423
+ throw new Error(`the gateway reported chain ${shown(this._pinnedChainName)} earlier and now reports ${shown(name)}; refusing to sign, the endpoint is not naming one network`);
407
424
  }
408
425
  return BigInt(core.chainIdFromName(name));
409
426
  }
@@ -412,7 +429,7 @@ function makeClient(core) {
412
429
  const controller = new AbortController();
413
430
  const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
414
431
  try {
415
- const res = await fetch(this.base + '/v1/' + method, {
432
+ const res = await this._fetch(this.base + '/v1/' + method, {
416
433
  method: 'POST',
417
434
  headers: { 'Content-Type': 'application/json' },
418
435
  body: body || '{}',
@@ -425,7 +442,7 @@ function makeClient(core) {
425
442
  try { data = JSON.parse(text); } catch { throw new Error('the node returned a non JSON response'); }
426
443
  if (res.status !== 200) {
427
444
  const detail = data && typeof data === 'object' ? (data.message || data.error) : null;
428
- throw new Error(detail || ('status ' + res.status));
445
+ throw new Error(detail ? shown(detail) : ('status ' + res.status));
429
446
  }
430
447
  return data;
431
448
  } finally {
@@ -441,7 +458,7 @@ function makeClient(core) {
441
458
  throw new Error(`the gateway answered about ${address} without naming the account, refusing to trust it`);
442
459
  }
443
460
  if (acct.address !== address) {
444
- throw new Error(`the gateway answered for ${acct.address} when asked about ${address}, refusing to trust it`);
461
+ throw new Error(`the gateway answered for ${shown(acct.address)} when asked about ${address}, refusing to trust it`);
445
462
  }
446
463
  return acct;
447
464
  }
@@ -469,7 +486,7 @@ function makeClient(core) {
469
486
  for (const [key, slot] of slots) this._session.signed(key, slot);
470
487
  const outcome = await this.submit(txHex);
471
488
  const verdict = outcome && outcome.verdict;
472
- if (verdict !== 'accepted' && verdict !== 'rejected') throw new Error(`unknown verdict ${verdict}`);
489
+ if (verdict !== 'accepted' && verdict !== 'rejected') throw new Error(`unknown verdict ${shown(verdict)}`);
473
490
  for (const [key, slot] of slots) this._session.outcome(key, slot, verdict === 'accepted');
474
491
  return outcome;
475
492
  }