-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.js
More file actions
141 lines (117 loc) · 4.24 KB
/
Copy pathclient.js
File metadata and controls
141 lines (117 loc) · 4.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright 2026 Quantova Inc
// SPDX-License-Identifier: Apache-2.0 OR MIT
/**
* Quantova gateway client.
*
* A small, dependency light wrapper over the Quantova gateway. Every call is an
* HTTP POST to /v1/<method> with a flat JSON body, and the response is flat JSON.
* Account addresses are Q1 bech32m strings written with a capital Q. Balances and
* amounts are denominated in Quon, the base unit of QTOV, where one QTOV is one
* million Quon.
*
* For signing and key management use the QCore.js SDK, published on npm as
* @quantovainc/qcore. This file covers the read and submit surface of the gateway.
* See interacting.md for the full method list.
*/
const DEFAULT_GATEWAY = process.env.QUANTOVA_GATEWAY || "http://127.0.0.1:8080";
/** One QTOV is one million Quon. */
export const QUON_PER_QTOV = 1_000_000n;
export class Gateway {
constructor(baseUrl = DEFAULT_GATEWAY) {
this.baseUrl = baseUrl.replace(/\/+$/, "");
}
/** Low level call. POST /v1/<method> with a flat JSON body. */
async post(method, body = {}) {
const res = await fetch(`${this.baseUrl}/v1/${method}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
if (!res.ok) throw new Error(`gateway ${method} returned HTTP ${res.status}`);
const data = await res.json();
if (data && data.error) throw new Error(`gateway ${method} error ${data.error}`);
return data;
}
// read methods
/** Node identity, software version, and network name. */
nodeInfo() {
return this.post("node_info");
}
/** The current chain head, height and finalized status. */
head() {
return this.post("head");
}
/** The active QORUS committee for the current view. */
validators() {
return this.post("validators");
}
/** Chain parameters, including the chain id used when signing. */
chainParams() {
return this.post("chain_params");
}
/** Account record for a Q1 address, including balance and nonce. */
getAccount(address) {
return this.post("get_account", { address });
}
/** A transaction by its hash. */
getTransaction(hash) {
return this.post("get_transaction", { hash });
}
/** A block by height or by hash. Pass { height } or { hash }. */
getBlock(ref) {
return this.post("get_block", ref);
}
/** Total and circulating supply, denominated in Quon. */
supply() {
return this.post("supply");
}
/** The deployed container at a contract address. */
getContainer(address) {
return this.post("get_container", { address });
}
/** A storage slot of a container. */
getStorage(address, key) {
return this.post("get_storage", { address, key });
}
/** Emitted events matching a filter. */
getEvents(filter = {}) {
return this.post("get_events", filter);
}
// submit
/**
* Submit an already signed transaction produced by QCore.js. The signed
* payload carries an ML-DSA-65 signature. Returns the accepted transaction hash.
*/
submitTransaction(signedTransaction) {
return this.post("submit_transaction", { transaction: signedTransaction });
}
// convenience
/** Balance of a Q1 address in QTOV, converted from Quon. */
async balanceQTOV(address) {
const account = await this.getAccount(address);
const quon = BigInt(account.balance);
const whole = quon / QUON_PER_QTOV;
const frac = quon % QUON_PER_QTOV;
return Number(whole) + Number(frac) / Number(QUON_PER_QTOV);
}
/** Account nonce, the value to set on the next transaction you build. */
async nonce(address) {
const account = await this.getAccount(address);
return Number(account.nonce);
}
/**
* Poll get_transaction until the transaction is recorded, then return it.
* A recorded transaction is included. Confirm QORUS finality before treating
* value as settled. See interacting.md.
*/
async waitForTransaction(hash, { intervalMs = 1000, timeoutMs = 60000 } = {}) {
const start = Date.now();
for (;;) {
const tx = await this.getTransaction(hash).catch(() => null);
if (tx && tx.hash) return tx;
if (Date.now() - start > timeoutMs) throw new Error("Timed out waiting for the transaction");
await new Promise((r) => setTimeout(r, intervalMs));
}
}
}
export default Gateway;