@geeqdev/geeq-sdk 0.2.0 → 0.2.2
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 +12 -2
- package/dist/browser/geeq_core_bg.wasm +0 -0
- package/dist/browser/index.js +12468 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/node/geeq_core_bg.wasm +0 -0
- package/dist/node/index.cjs +12559 -0
- package/dist/node/index.cjs.map +1 -0
- package/dist/node/index.js +12469 -0
- package/dist/node/index.js.map +1 -0
- package/dist/types/index.d.cts +2224 -0
- package/dist/types/index.d.ts +2224 -0
- package/package.json +8 -3
- package/.idea/geeq_sdk.iml +0 -12
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
- package/.nvmrc +0 -1
- package/CONTRIBUTING.md +0 -20
- package/example/.env.example +0 -4
- package/example/README.md +0 -304
- package/example/USAGE.md +0 -74
- package/example/index.html +0 -12
- package/example/package-lock.json +0 -1557
- package/example/package.json +0 -25
- package/example/scripts/browser-check.mjs +0 -1421
- package/example/scripts/match-derivation.mjs +0 -65
- package/example/src/App.vue +0 -138
- package/example/src/components/AuthorityPanel.vue +0 -277
- package/example/src/components/ChainPanel.vue +0 -267
- package/example/src/components/ChainState.vue +0 -59
- package/example/src/components/CopyButton.vue +0 -25
- package/example/src/components/CreateAssetPanel.vue +0 -313
- package/example/src/components/DigitalAssetsPanel.vue +0 -68
- package/example/src/components/EvidencePanel.vue +0 -396
- package/example/src/components/ExplorerPanel.vue +0 -119
- package/example/src/components/KeypairPanel.vue +0 -182
- package/example/src/components/PhrasePanel.vue +0 -105
- package/example/src/components/SocketWarning.vue +0 -18
- package/example/src/components/StepGate.vue +0 -24
- package/example/src/components/TransferPanel.vue +0 -416
- package/example/src/components/TxDeadline.vue +0 -19
- package/example/src/components/TxFee.vue +0 -31
- package/example/src/components/TxStatus.vue +0 -105
- package/example/src/composables/useSocketConnection.ts +0 -80
- package/example/src/env.d.ts +0 -12
- package/example/src/main.ts +0 -5
- package/example/src/pennies.ts +0 -7
- package/example/src/style.css +0 -149
- package/example/tsconfig.json +0 -19
- package/example/vite.config.ts +0 -26
- package/jest.config.js +0 -18
- package/scripts/copy-wasm.mjs +0 -21
- package/scripts/smoke.mjs +0 -382
- package/tsconfig.build.json +0 -8
- package/tsconfig.json +0 -21
- package/tsup.config.ts +0 -60
|
@@ -0,0 +1,2224 @@
|
|
|
1
|
+
/** Account ids and public keys are both 32 bytes. */
|
|
2
|
+
declare const ACCOUNT_ID_BYTES = 32;
|
|
3
|
+
declare const PUBLIC_KEY_BYTES = 32;
|
|
4
|
+
/**
|
|
5
|
+
* Any way of naming an account that does not need the engine.
|
|
6
|
+
*
|
|
7
|
+
* Structural on purpose: a {@link GeeqKeypair} already carries `accountId`, so it
|
|
8
|
+
* satisfies this without the crypto layer importing the keypair type and without the
|
|
9
|
+
* caller unwrapping anything.
|
|
10
|
+
*/
|
|
11
|
+
type AccountRef = Uint8Array | {
|
|
12
|
+
readonly accountId: Uint8Array;
|
|
13
|
+
} | {
|
|
14
|
+
readonly publicKey: Uint8Array;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Derive the 32-byte account id for a public key.
|
|
18
|
+
*
|
|
19
|
+
* This is a pure hash — it needs no engine and no network, so it works before
|
|
20
|
+
* {@link initGeeq} has resolved.
|
|
21
|
+
*/
|
|
22
|
+
declare function accountIdFromPublicKey(publicKey: Uint8Array): Uint8Array;
|
|
23
|
+
|
|
24
|
+
/** Which coin record subtype an account is. Only `'asset'` may sign an attestation. */
|
|
25
|
+
type GeeqCoinRecordKind = 'asset' | 'hl' | 'micro' | 'unknown';
|
|
26
|
+
/** One coin account record, as plain values. */
|
|
27
|
+
interface GeeqCoinAccount {
|
|
28
|
+
readonly accountId: Uint8Array;
|
|
29
|
+
readonly kind: GeeqCoinRecordKind;
|
|
30
|
+
/**
|
|
31
|
+
* `undefined` for a hash-lock record, which carries no nonce field at all, and for a
|
|
32
|
+
* record whose subtype could not be read.
|
|
33
|
+
*/
|
|
34
|
+
readonly nonce: number | undefined;
|
|
35
|
+
/** Balance in pennies. Use `formatGeeq` to show it. */
|
|
36
|
+
readonly balance: bigint;
|
|
37
|
+
/** The NFTs it holds, in the order its record lists them. Read for coin-asset records only. */
|
|
38
|
+
readonly nfts: readonly GeeqHeldNft[];
|
|
39
|
+
}
|
|
40
|
+
/** One NFT an account holds, as its record lists it. */
|
|
41
|
+
interface GeeqHeldNft {
|
|
42
|
+
/** The NFT's 32-byte id. */
|
|
43
|
+
readonly id: Uint8Array;
|
|
44
|
+
/** A counterparty NFT moves only with a counterparty transaction, never a plain transfer. */
|
|
45
|
+
readonly counterparty: boolean;
|
|
46
|
+
}
|
|
47
|
+
/** What we keep per account. The id is the map key, so it is not repeated here. */
|
|
48
|
+
interface CoinAccountFacts {
|
|
49
|
+
readonly kind: GeeqCoinRecordKind;
|
|
50
|
+
readonly nonce: number | undefined;
|
|
51
|
+
readonly balance: bigint;
|
|
52
|
+
readonly nfts: readonly GeeqHeldNft[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Which kind of proxy a record is. Only `'nft-mint'` is read further. */
|
|
56
|
+
type GeeqProxyKind = 'nft-mint' | 'token-mint' | 'funding' | 'multisig' | 'dce' | 'unknown';
|
|
57
|
+
/** One proxy account record, as plain values. */
|
|
58
|
+
interface GeeqProxyAccount {
|
|
59
|
+
readonly accountId: Uint8Array;
|
|
60
|
+
readonly kind: GeeqProxyKind;
|
|
61
|
+
/**
|
|
62
|
+
* The proxy's own nonce. A mint through it spends this one, not the admin's — a proxy
|
|
63
|
+
* carries its nonce on the record itself.
|
|
64
|
+
*/
|
|
65
|
+
readonly nonce: number;
|
|
66
|
+
/** Balance in pennies. Use `formatGeeq` to show it. */
|
|
67
|
+
readonly balance: bigint;
|
|
68
|
+
/** The account id of the only key that can sign for it. Read for NFT mint proxies only. */
|
|
69
|
+
readonly admin: Uint8Array | undefined;
|
|
70
|
+
}
|
|
71
|
+
/** What we keep per proxy. The id is the map key, so it is not repeated here. */
|
|
72
|
+
type ProxyAccountFacts = Omit<GeeqProxyAccount, 'accountId'>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Where the WebAssembly engine should be loaded from. Leave it unset and the SDK
|
|
76
|
+
* uses the copy shipped beside its own bundle, which every common bundler emits
|
|
77
|
+
* as a hashed asset automatically.
|
|
78
|
+
*/
|
|
79
|
+
type WasmSource = string | URL | Request | Response | ArrayBuffer | Uint8Array | WebAssembly.Module;
|
|
80
|
+
interface InitOptions {
|
|
81
|
+
/** Override where `geeq_core_bg.wasm` is fetched from. */
|
|
82
|
+
readonly wasm?: WasmSource;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The kind of ledger record an address points at. Most applications only ever
|
|
86
|
+
* need `'coin-asset'`, which is the default and is what a normal user account is.
|
|
87
|
+
*/
|
|
88
|
+
type GeeqRecordType = 'coin-asset' | 'coin-hl' | 'coin-micro' | 'app-counterparty' | 'app-dce' | 'app-nft' | 'app-stackable' | 'proxy-nft-mint' | 'proxy-funding' | 'proxy-multisig' | 'proxy-dce' | 'proxy-token-mint' | 'gt-nwa' | 'param-boolean' | 'param-count-2' | 'param-count-8' | 'sys';
|
|
89
|
+
/** Which coin family a derivation path belongs to. */
|
|
90
|
+
type GeeqCoinType = 'mainnet' | 'testnet';
|
|
91
|
+
interface WalletAddressOptions {
|
|
92
|
+
/** The chain this address belongs to. Addresses are not portable across chains. */
|
|
93
|
+
readonly chainNumber: number;
|
|
94
|
+
/** Defaults to `'coin-asset'` — an ordinary user account. */
|
|
95
|
+
readonly recordType?: GeeqRecordType;
|
|
96
|
+
}
|
|
97
|
+
interface DecodedWalletAddress {
|
|
98
|
+
/** The address that was decoded, unchanged. */
|
|
99
|
+
readonly address: string;
|
|
100
|
+
readonly chainNumber: number;
|
|
101
|
+
readonly recordType: GeeqRecordType;
|
|
102
|
+
/** The 32-byte account id this address points at. */
|
|
103
|
+
readonly accountId: Uint8Array;
|
|
104
|
+
}
|
|
105
|
+
/** Options for deriving a keypair from a BIP-39 mnemonic along the Geeq path. */
|
|
106
|
+
interface MnemonicOptions {
|
|
107
|
+
/** Optional BIP-39 passphrase. Defaults to an empty string. */
|
|
108
|
+
readonly passphrase?: string;
|
|
109
|
+
/** Defaults to `'coin-asset'`. */
|
|
110
|
+
readonly recordType?: GeeqRecordType;
|
|
111
|
+
/** Defaults to `'mainnet'`. */
|
|
112
|
+
readonly coinType?: GeeqCoinType;
|
|
113
|
+
/** Defaults to 0. */
|
|
114
|
+
readonly account?: number;
|
|
115
|
+
/** Defaults to 0. */
|
|
116
|
+
readonly addressIndex?: number;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* An Ed25519 keypair plus the identifiers derived from it.
|
|
120
|
+
*
|
|
121
|
+
* `privateKey` is raw secret material. Never log it, never put it in an error
|
|
122
|
+
* message, and never send it anywhere. Call {@link GeeqKeypair.dispose} when done
|
|
123
|
+
* to release the engine-side copy.
|
|
124
|
+
*/
|
|
125
|
+
interface GeeqKeypair {
|
|
126
|
+
/** 32-byte Ed25519 public key. */
|
|
127
|
+
readonly publicKey: Uint8Array;
|
|
128
|
+
/** 32-byte Ed25519 secret key. Secret material. */
|
|
129
|
+
readonly privateKey: Uint8Array;
|
|
130
|
+
/** 32-byte account id derived from the public key. */
|
|
131
|
+
readonly accountId: Uint8Array;
|
|
132
|
+
/** The base58 wallet address for this keypair on a given chain. */
|
|
133
|
+
getAddress(options: WalletAddressOptions): string;
|
|
134
|
+
/** Sign a message. Throws once {@link GeeqKeypair.dispose} has been called. */
|
|
135
|
+
sign(message: Uint8Array): Uint8Array;
|
|
136
|
+
/** Release the engine-side keypair. The byte fields stay readable afterwards. */
|
|
137
|
+
dispose(): void;
|
|
138
|
+
}
|
|
139
|
+
/** The metadata limits this chain publishes in its own ledger. */
|
|
140
|
+
interface GeeqMetadataLimits {
|
|
141
|
+
/** Maximum NUMBER of metadata entries. From the `metadataVarNum` parameter. */
|
|
142
|
+
readonly maxEntries: number;
|
|
143
|
+
/** Maximum bytes in ONE entry. There is no aggregate cap. From `metadataVarBytes`. */
|
|
144
|
+
readonly maxBytesPerEntry: number;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The live chain values a transaction is pinned to.
|
|
148
|
+
*
|
|
149
|
+
* `blockNumber` is the block being *asked for*, which is the ledger's last committed
|
|
150
|
+
* block plus one. Read it from a node with {@link GeeqChain}, or supply it yourself for
|
|
151
|
+
* replay and offline signing.
|
|
152
|
+
*/
|
|
153
|
+
interface ChainStateInput {
|
|
154
|
+
/** The chain this transaction targets — the ledger's own chain number. */
|
|
155
|
+
readonly chainNumber: number;
|
|
156
|
+
/** The block it asks to be included in: the ledger's block **+ 1**. */
|
|
157
|
+
readonly blockNumber: number;
|
|
158
|
+
/** The receiving node's own number, from the net actor list in the ledger. */
|
|
159
|
+
readonly nodeNumber: number;
|
|
160
|
+
/** The signing account's current nonce, from its coin account record. */
|
|
161
|
+
readonly nonce: number;
|
|
162
|
+
/** When present, metadata is checked against it before anything is signed. */
|
|
163
|
+
readonly metadataLimits?: GeeqMetadataLimits | undefined;
|
|
164
|
+
/**
|
|
165
|
+
* The chain's `geeqNorm` parameter, which every fee is a multiple of. When present, the
|
|
166
|
+
* built transaction carries its {@link GeeqFee}.
|
|
167
|
+
*/
|
|
168
|
+
readonly geeqNorm?: bigint | undefined;
|
|
169
|
+
/**
|
|
170
|
+
* The node this state describes, and therefore the only node that will accept a
|
|
171
|
+
* transaction built from it — `nodeNumber` is checked with strict equality.
|
|
172
|
+
*/
|
|
173
|
+
readonly nodeUrl?: string | undefined;
|
|
174
|
+
/**
|
|
175
|
+
* N, the ledger block this was read from. Present only when a chain produced it —
|
|
176
|
+
* there is nothing to report when the caller supplied the numbers.
|
|
177
|
+
*/
|
|
178
|
+
readonly ledgerBlockNumber?: number | undefined;
|
|
179
|
+
/** `Date.now()` at the read. Present only when a chain produced it. */
|
|
180
|
+
readonly readAt?: number | undefined;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Chain state read from a node, carrying where and when it came from.
|
|
184
|
+
*
|
|
185
|
+
* The same fields as {@link ChainStateInput}, with the provenance ones narrowed from
|
|
186
|
+
* optional to always present — a chain can always say which ledger block and which node
|
|
187
|
+
* it read.
|
|
188
|
+
*/
|
|
189
|
+
interface GeeqChainState extends ChainStateInput {
|
|
190
|
+
/** N — the ledger's last committed block. {@link blockNumber} is this plus one. */
|
|
191
|
+
readonly ledgerBlockNumber: number;
|
|
192
|
+
/** `Date.now()` when the ledger was read, so callers can see how stale this is. */
|
|
193
|
+
readonly readAt: number;
|
|
194
|
+
/** The node it was read from, and therefore the node it must be submitted to. */
|
|
195
|
+
readonly nodeUrl: string;
|
|
196
|
+
/** The signing account's balance, in pennies, as at this read. */
|
|
197
|
+
readonly balance: bigint;
|
|
198
|
+
/** The smallest transfer this chain accepts, in pennies, if it publishes one. */
|
|
199
|
+
readonly minimumTransfer: bigint | undefined;
|
|
200
|
+
/** The chain's `geeqNorm` parameter, if it publishes one. */
|
|
201
|
+
readonly geeqNorm: bigint | undefined;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* What the chain charges for a transaction, in pennies, on top of any amount it sends.
|
|
205
|
+
*
|
|
206
|
+
* Worked out by the SDK the way the node works it out, from the signed bytes, so it is
|
|
207
|
+
* the exact figure rather than an estimate.
|
|
208
|
+
*/
|
|
209
|
+
interface GeeqFee {
|
|
210
|
+
/** The whole fee: {@link data} plus {@link coin}. */
|
|
211
|
+
readonly total: bigint;
|
|
212
|
+
/** `geeqNorm` per byte of the signed transaction, and of its payload when it has one. */
|
|
213
|
+
readonly data: bigint;
|
|
214
|
+
/**
|
|
215
|
+
* A quarter of a percent of the amount sent, rounded down and capped at
|
|
216
|
+
* `geeqNorm × 10⁷`. Zero for an attestation, which sends no amount.
|
|
217
|
+
*/
|
|
218
|
+
readonly coin: bigint;
|
|
219
|
+
/** How many bytes {@link data} charges for. */
|
|
220
|
+
readonly bytes: number;
|
|
221
|
+
}
|
|
222
|
+
/** What is being attested, independent of any chain state. */
|
|
223
|
+
interface AttestationContent {
|
|
224
|
+
/** The account that signs both the attestation and the transaction. */
|
|
225
|
+
readonly keypair: GeeqKeypair;
|
|
226
|
+
/** 32-byte hash of the content. The content itself never leaves the device. */
|
|
227
|
+
readonly attestHash: Uint8Array;
|
|
228
|
+
/**
|
|
229
|
+
* Optional labels stored alongside the hash, in the order given. Strings are encoded
|
|
230
|
+
* as UTF-8. Anything here is public once submitted.
|
|
231
|
+
*/
|
|
232
|
+
readonly metadata?: readonly (string | Uint8Array)[];
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* The four chain values supplied explicitly.
|
|
236
|
+
*
|
|
237
|
+
* Kept for replay, deterministic tests and air-gapped signing, where there is no node
|
|
238
|
+
* to ask. Most callers should let {@link GeeqChain} read them instead — none of them can
|
|
239
|
+
* be derived offline, and a wrong one is rejected by the chain.
|
|
240
|
+
*/
|
|
241
|
+
type AttestationTxFlatInput = AttestationContent & {
|
|
242
|
+
readonly chainNumber: number;
|
|
243
|
+
readonly blockNumber: number;
|
|
244
|
+
readonly nodeNumber: number;
|
|
245
|
+
readonly nonce: number;
|
|
246
|
+
readonly chainState?: never;
|
|
247
|
+
};
|
|
248
|
+
/** The same four values as one object, which is what a chain read produces. */
|
|
249
|
+
type AttestationTxStateInput = AttestationContent & {
|
|
250
|
+
readonly chainState: ChainStateInput;
|
|
251
|
+
readonly chainNumber?: never;
|
|
252
|
+
readonly blockNumber?: never;
|
|
253
|
+
readonly nodeNumber?: never;
|
|
254
|
+
readonly nonce?: never;
|
|
255
|
+
};
|
|
256
|
+
type AttestationTxInput = AttestationTxFlatInput | AttestationTxStateInput;
|
|
257
|
+
/**
|
|
258
|
+
* A signed attestation transaction, ready to submit. The SDK does not submit it — post
|
|
259
|
+
* {@link AttestationTx.transaction} and {@link AttestationTx.payload} to the node named
|
|
260
|
+
* by {@link AttestationTx.nodeUrl}, after handing it to `GeeqSocket.track` to hear the
|
|
261
|
+
* verdict.
|
|
262
|
+
*/
|
|
263
|
+
interface AttestationTx {
|
|
264
|
+
/** base64 packed `UserAppTx`. Submit as the `transaction` field. */
|
|
265
|
+
readonly transaction: string;
|
|
266
|
+
/** base64 packed `Payload`. Submit as the `payload` field. */
|
|
267
|
+
readonly payload: string;
|
|
268
|
+
/** 32-byte BLAKE3 of the flattened payload, as embedded in the transaction. */
|
|
269
|
+
readonly refHashPayload: Uint8Array;
|
|
270
|
+
/**
|
|
271
|
+
* 32-byte BLAKE3 of the signed, flattened transaction — how a node identifies it, and
|
|
272
|
+
* the `refHash` its status events carry. `transactionIdOf(tx)` gives it as the base64
|
|
273
|
+
* string a {@link GeeqSocket} matches on.
|
|
274
|
+
*/
|
|
275
|
+
readonly transactionHash: Uint8Array;
|
|
276
|
+
/** The signer's 32-byte public key — whose status events to subscribe to. */
|
|
277
|
+
readonly publicKey: Uint8Array;
|
|
278
|
+
/**
|
|
279
|
+
* What the chain charges the signing account for it. Undefined when the chain state
|
|
280
|
+
* carried no `geeqNorm`.
|
|
281
|
+
*/
|
|
282
|
+
readonly fee: GeeqFee | undefined;
|
|
283
|
+
/** Exactly what this transaction is pinned to. Frozen. */
|
|
284
|
+
readonly chainState: ChainStateInput;
|
|
285
|
+
/**
|
|
286
|
+
* The last block a node takes it at: its target block plus 8. Once the chain's latest
|
|
287
|
+
* block is past this, every node refuses it as too old, and it has to be built and
|
|
288
|
+
* signed again. `GeeqChain.isExpired` checks.
|
|
289
|
+
*/
|
|
290
|
+
readonly validUntilBlock: number;
|
|
291
|
+
/**
|
|
292
|
+
* Where this must be submitted, when a chain read chose the node.
|
|
293
|
+
*
|
|
294
|
+
* Not a convenience: the node checks that `nodeNumber` is its own, with strict
|
|
295
|
+
* equality, so posting to any other node is a guaranteed rejection. Undefined only
|
|
296
|
+
* when the caller supplied the four values themselves and the SDK never saw a node.
|
|
297
|
+
*/
|
|
298
|
+
readonly nodeUrl?: string | undefined;
|
|
299
|
+
}
|
|
300
|
+
/** What is being transferred, independent of any chain state. */
|
|
301
|
+
interface CoinTransferContent {
|
|
302
|
+
/** The account paying. Must be a coin-asset account on this chain. */
|
|
303
|
+
readonly keypair: GeeqKeypair;
|
|
304
|
+
/** Who receives it. Resolved to a 32-byte account id. */
|
|
305
|
+
readonly to: AccountRef;
|
|
306
|
+
/**
|
|
307
|
+
* How much, in pennies. Use `toPennies` to get here from a figure. Never
|
|
308
|
+
* zero: the node reads a zero amount as the sender's whole balance.
|
|
309
|
+
*/
|
|
310
|
+
readonly amount: bigint;
|
|
311
|
+
/** NFTs sent with it. Each must be one the sender holds, named once. */
|
|
312
|
+
readonly nfts?: readonly NftTransferEntry[];
|
|
313
|
+
}
|
|
314
|
+
/** One NFT a transfer moves. */
|
|
315
|
+
interface NftTransferEntry {
|
|
316
|
+
/** The NFT's 32-byte id. */
|
|
317
|
+
readonly id: Uint8Array;
|
|
318
|
+
/** Where it sits in the sender's list of NFTs, from 0 — as `GeeqCoinAccount.nfts` orders them. */
|
|
319
|
+
readonly position: number;
|
|
320
|
+
}
|
|
321
|
+
/** The four chain values supplied explicitly. For replay and air-gapped signing. */
|
|
322
|
+
type CoinTransferTxFlatInput = CoinTransferContent & {
|
|
323
|
+
readonly chainNumber: number;
|
|
324
|
+
readonly blockNumber: number;
|
|
325
|
+
readonly nodeNumber: number;
|
|
326
|
+
readonly nonce: number;
|
|
327
|
+
readonly chainState?: never;
|
|
328
|
+
};
|
|
329
|
+
/** The same four as one object, which is what a chain read produces. */
|
|
330
|
+
type CoinTransferTxStateInput = CoinTransferContent & {
|
|
331
|
+
readonly chainState: ChainStateInput;
|
|
332
|
+
readonly chainNumber?: never;
|
|
333
|
+
readonly blockNumber?: never;
|
|
334
|
+
readonly nodeNumber?: never;
|
|
335
|
+
readonly nonce?: never;
|
|
336
|
+
};
|
|
337
|
+
type CoinTransferTxInput = CoinTransferTxFlatInput | CoinTransferTxStateInput;
|
|
338
|
+
/**
|
|
339
|
+
* A signed coin transfer, ready to submit.
|
|
340
|
+
*
|
|
341
|
+
* Note there is no `payload`: a validation-layer transaction is self-contained, unlike an
|
|
342
|
+
* attestation. Post it with `coinTransferSubmitBody`, which sends it as type `uvt`, after
|
|
343
|
+
* handing it to `GeeqSocket.track` to hear the verdict.
|
|
344
|
+
*/
|
|
345
|
+
interface CoinTransferTx {
|
|
346
|
+
/** base64 packed `UserValTx`. Submit as the `transaction` field. */
|
|
347
|
+
readonly transaction: string;
|
|
348
|
+
/**
|
|
349
|
+
* 32-byte BLAKE3 of the flattened transaction **without** its signature — how the chain
|
|
350
|
+
* identifies a validation-layer transaction, and the `refHash` its status events carry.
|
|
351
|
+
* Note this is the opposite of an attestation, whose hash includes the signature.
|
|
352
|
+
*/
|
|
353
|
+
readonly transactionHash: Uint8Array;
|
|
354
|
+
/** The sender's 32-byte public key — whose status events to subscribe to. */
|
|
355
|
+
readonly publicKey: Uint8Array;
|
|
356
|
+
/** What was sent, in pennies. */
|
|
357
|
+
readonly amount: bigint;
|
|
358
|
+
/** The ids of the NFTs sent with it, if any. */
|
|
359
|
+
readonly nfts: readonly Uint8Array[];
|
|
360
|
+
/**
|
|
361
|
+
* What the chain charges the sender, on top of {@link amount}. Undefined when the chain
|
|
362
|
+
* state carried no `geeqNorm`.
|
|
363
|
+
*/
|
|
364
|
+
readonly fee: GeeqFee | undefined;
|
|
365
|
+
/** The 32-byte account id it was sent to. */
|
|
366
|
+
readonly to: Uint8Array;
|
|
367
|
+
/** Exactly what this transaction is pinned to. Frozen. */
|
|
368
|
+
readonly chainState: ChainStateInput;
|
|
369
|
+
/**
|
|
370
|
+
* The last block a node takes it at: its target block plus 8. Once the chain's latest
|
|
371
|
+
* block is past this, every node refuses it as too old, and it has to be built and
|
|
372
|
+
* signed again. `GeeqChain.isExpired` checks.
|
|
373
|
+
*/
|
|
374
|
+
readonly validUntilBlock: number;
|
|
375
|
+
/** Where it must be submitted, when a chain read chose the node. */
|
|
376
|
+
readonly nodeUrl?: string | undefined;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* What a proxy creation needs. The chain values come as one object only — there is no
|
|
380
|
+
* flat form, since a proxy is always built against a ledger read.
|
|
381
|
+
*/
|
|
382
|
+
interface NftMintProxyTxInput {
|
|
383
|
+
/**
|
|
384
|
+
* The account paying for the proxy, which also becomes its admin: the only key that
|
|
385
|
+
* can later mint through it. Must be a coin-asset account on this chain.
|
|
386
|
+
*/
|
|
387
|
+
readonly keypair: GeeqKeypair;
|
|
388
|
+
/**
|
|
389
|
+
* Which of the admin's proxies this is, from 1. The proxy's id is derived from the
|
|
390
|
+
* admin's public key and this index, as the Geeq wallet derives it, so it must be one
|
|
391
|
+
* the admin has not used — `GeeqChain.findNftMintProxies` gives the next one.
|
|
392
|
+
*/
|
|
393
|
+
readonly index: number;
|
|
394
|
+
/** Coin moved onto the proxy, in pennies. It pays for the mints made through it. */
|
|
395
|
+
readonly amount: bigint;
|
|
396
|
+
readonly chainState: ChainStateInput;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* A signed transaction creating an NFT mint proxy, ready to submit.
|
|
400
|
+
*
|
|
401
|
+
* A validation-layer transaction, like a transfer: post it with `coinTransferSubmitBody`,
|
|
402
|
+
* after handing it to `GeeqSocket.track` to hear the verdict.
|
|
403
|
+
*/
|
|
404
|
+
interface NftMintProxyTx {
|
|
405
|
+
/** base64 packed `UserValTx`. Submit as the `transaction` field. */
|
|
406
|
+
readonly transaction: string;
|
|
407
|
+
/** 32-byte BLAKE3 of the signature-excluded flatten — the `refHash` its status events carry. */
|
|
408
|
+
readonly transactionHash: Uint8Array;
|
|
409
|
+
/** The admin's 32-byte public key — whose status events to subscribe to. */
|
|
410
|
+
readonly publicKey: Uint8Array;
|
|
411
|
+
/** The coin moved onto the proxy, in pennies. */
|
|
412
|
+
readonly amount: bigint;
|
|
413
|
+
/** Which of the admin's proxies this is, from 1. */
|
|
414
|
+
readonly index: number;
|
|
415
|
+
/** The new proxy's 32-byte account id, derived from the admin's key and {@link index}. */
|
|
416
|
+
readonly proxyAccountId: Uint8Array;
|
|
417
|
+
/** The new proxy's wallet address on this chain, record type `proxy-nft-mint`. */
|
|
418
|
+
readonly proxyAddress: string;
|
|
419
|
+
/**
|
|
420
|
+
* What the chain charges the admin, on top of {@link amount}. Undefined when the chain
|
|
421
|
+
* state carried no `geeqNorm`.
|
|
422
|
+
*/
|
|
423
|
+
readonly fee: GeeqFee | undefined;
|
|
424
|
+
/** Exactly what this transaction is pinned to. Frozen. */
|
|
425
|
+
readonly chainState: ChainStateInput;
|
|
426
|
+
/**
|
|
427
|
+
* The last block a node takes it at: its target block plus 8. Once the chain's latest
|
|
428
|
+
* block is past this, every node refuses it as too old, and it has to be built and
|
|
429
|
+
* signed again. `GeeqChain.isExpired` checks.
|
|
430
|
+
*/
|
|
431
|
+
readonly validUntilBlock: number;
|
|
432
|
+
/** Where it must be submitted, when a chain read chose the node. */
|
|
433
|
+
readonly nodeUrl?: string | undefined;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* What an NFT mint needs. The chain values come as one object only, as for a proxy.
|
|
437
|
+
*/
|
|
438
|
+
interface NftMintTxInput {
|
|
439
|
+
/** The proxy's admin. It signs both the NFT and the transaction. */
|
|
440
|
+
readonly keypair: GeeqKeypair;
|
|
441
|
+
/** The 32-byte account id of the proxy minting it, which pays for it. */
|
|
442
|
+
readonly proxyAccountId: Uint8Array;
|
|
443
|
+
/** 32-byte hash of what the NFT stands for. The content itself never leaves the device. */
|
|
444
|
+
readonly attestHash: Uint8Array;
|
|
445
|
+
/** Optional public labels stored with the NFT, in the order given. */
|
|
446
|
+
readonly metadata?: readonly (string | Uint8Array)[];
|
|
447
|
+
/** Who receives the NFT. Resolved to a 32-byte account id. */
|
|
448
|
+
readonly to: AccountRef;
|
|
449
|
+
/** Coin the proxy sends to the receiver along with the NFT, in pennies. */
|
|
450
|
+
readonly amount: bigint;
|
|
451
|
+
/** Its `nonce` is the proxy's own, not the admin's. */
|
|
452
|
+
readonly chainState: ChainStateInput;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* A signed NFT mint, ready to submit.
|
|
456
|
+
*
|
|
457
|
+
* An application-layer transaction, like an attestation: post `transaction` and `payload`
|
|
458
|
+
* with `attestationSubmitBody`, after handing it to `GeeqSocket.track` to hear the verdict.
|
|
459
|
+
*/
|
|
460
|
+
interface NftMintTx {
|
|
461
|
+
/** base64 packed `UserAppTx`. Submit as the `transaction` field. */
|
|
462
|
+
readonly transaction: string;
|
|
463
|
+
/** base64 packed `Payload`. Submit as the `payload` field. */
|
|
464
|
+
readonly payload: string;
|
|
465
|
+
/** 32-byte BLAKE3 of the flattened payload, as embedded in the transaction. */
|
|
466
|
+
readonly refHashPayload: Uint8Array;
|
|
467
|
+
/** 32-byte BLAKE3 of the signed, flattened transaction — the `refHash` its status events carry. */
|
|
468
|
+
readonly transactionHash: Uint8Array;
|
|
469
|
+
/** The admin's 32-byte public key — whose status events to subscribe to. */
|
|
470
|
+
readonly publicKey: Uint8Array;
|
|
471
|
+
/** The new NFT's 32-byte id: the hash of its attestation subgroup, as the wallet derives it. */
|
|
472
|
+
readonly nftId: Uint8Array;
|
|
473
|
+
/** The proxy minting it. */
|
|
474
|
+
readonly proxyAccountId: Uint8Array;
|
|
475
|
+
/** The 32-byte account id receiving it. */
|
|
476
|
+
readonly to: Uint8Array;
|
|
477
|
+
/** The coin sent along with it, in pennies. */
|
|
478
|
+
readonly amount: bigint;
|
|
479
|
+
/**
|
|
480
|
+
* What the chain charges the proxy — not the admin — on top of {@link amount}. Undefined
|
|
481
|
+
* when the chain state carried no `geeqNorm`.
|
|
482
|
+
*/
|
|
483
|
+
readonly fee: GeeqFee | undefined;
|
|
484
|
+
/** Exactly what this transaction is pinned to. Frozen. */
|
|
485
|
+
readonly chainState: ChainStateInput;
|
|
486
|
+
/**
|
|
487
|
+
* The last block a node takes it at: its target block plus 8. Once the chain's latest
|
|
488
|
+
* block is past this, every node refuses it as too old, and it has to be built and
|
|
489
|
+
* signed again. `GeeqChain.isExpired` checks.
|
|
490
|
+
*/
|
|
491
|
+
readonly validUntilBlock: number;
|
|
492
|
+
/** Where it must be submitted, when a chain read chose the node. */
|
|
493
|
+
readonly nodeUrl?: string | undefined;
|
|
494
|
+
}
|
|
495
|
+
/** One of an admin's NFT mint proxies, as the ledger holds it. */
|
|
496
|
+
interface GeeqNftMintProxy extends GeeqProxyAccount {
|
|
497
|
+
/**
|
|
498
|
+
* Which of the admin's proxies it is, from 1. Undefined for a proxy whose id was not
|
|
499
|
+
* derived from the admin's key — one made with an id of its own.
|
|
500
|
+
*/
|
|
501
|
+
readonly index: number | undefined;
|
|
502
|
+
/** Its wallet address on this chain, record type `proxy-nft-mint`. */
|
|
503
|
+
readonly address: string;
|
|
504
|
+
}
|
|
505
|
+
/** The NFT mint proxies one admin has, and the index its next one takes. */
|
|
506
|
+
interface GeeqNftMintProxies {
|
|
507
|
+
/** In index order; any without an index come last. */
|
|
508
|
+
readonly proxies: readonly GeeqNftMintProxy[];
|
|
509
|
+
/** One past the highest index in use, or 1 when there is none. */
|
|
510
|
+
readonly nextIndex: number;
|
|
511
|
+
}
|
|
512
|
+
/** An NFT an account holds, with the hash and labels it was minted with. */
|
|
513
|
+
interface GeeqNft extends GeeqHeldNft {
|
|
514
|
+
/** The hash of what it stands for. Undefined when the application layer ledger has no record of it. */
|
|
515
|
+
readonly attestHash: Uint8Array | undefined;
|
|
516
|
+
/** Its public labels as text, in order. */
|
|
517
|
+
readonly metadata: readonly string[];
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Load the Geeq engine. Idempotent and single-flight: concurrent callers share one
|
|
522
|
+
* load, and repeat calls after success resolve immediately.
|
|
523
|
+
*
|
|
524
|
+
* You rarely need to call this yourself — every async entry point in the SDK awaits
|
|
525
|
+
* it first. Call it at startup if you would rather pay the cost up front.
|
|
526
|
+
*/
|
|
527
|
+
declare function initGeeq(options?: InitOptions): Promise<void>;
|
|
528
|
+
/** True once the engine is loaded and the synchronous APIs are usable. */
|
|
529
|
+
declare function isGeeqReady(): boolean;
|
|
530
|
+
|
|
531
|
+
/** Create a brand new random keypair. Synchronous; requires a loaded engine. */
|
|
532
|
+
declare function generateKeypairSync(): GeeqKeypair;
|
|
533
|
+
/** Create a brand new random keypair, loading the engine if needed. */
|
|
534
|
+
declare function generateKeypair(): Promise<GeeqKeypair>;
|
|
535
|
+
/** Re-create a keypair from stored public and private key bytes. */
|
|
536
|
+
declare function importKeypairSync(publicKey: Uint8Array, privateKey: Uint8Array): GeeqKeypair;
|
|
537
|
+
/** Re-create a keypair from stored key bytes, loading the engine if needed. */
|
|
538
|
+
declare function importKeypair(publicKey: Uint8Array, privateKey: Uint8Array): Promise<GeeqKeypair>;
|
|
539
|
+
/** Recover a keypair from its 32-byte secret key alone. */
|
|
540
|
+
declare function keypairFromSecretKeySync(privateKey: Uint8Array): GeeqKeypair;
|
|
541
|
+
/** Recover a keypair from its secret key, loading the engine if needed. */
|
|
542
|
+
declare function keypairFromSecretKey(privateKey: Uint8Array): Promise<GeeqKeypair>;
|
|
543
|
+
/**
|
|
544
|
+
* Derive a keypair from a BIP-39 mnemonic along Geeq's standard derivation path.
|
|
545
|
+
*
|
|
546
|
+
* The same mnemonic and options always produce the same keypair, so this is how a
|
|
547
|
+
* wallet is restored on another device.
|
|
548
|
+
*/
|
|
549
|
+
declare function keypairFromMnemonicSync(mnemonic: string, options?: MnemonicOptions): GeeqKeypair;
|
|
550
|
+
/** Derive a keypair from a mnemonic, loading the engine if needed. */
|
|
551
|
+
declare function keypairFromMnemonic(mnemonic: string, options?: MnemonicOptions): Promise<GeeqKeypair>;
|
|
552
|
+
/** Verify an Ed25519 signature. Requires a loaded engine. */
|
|
553
|
+
declare function verifySignature(publicKey: Uint8Array, signature: Uint8Array, message: Uint8Array): boolean;
|
|
554
|
+
|
|
555
|
+
/** Supported mnemonic lengths. 12 words is the common default; 24 is the strongest. */
|
|
556
|
+
type MnemonicWordCount = 12 | 15 | 18 | 21 | 24;
|
|
557
|
+
declare const MNEMONIC_WORD_COUNTS: readonly [12, 15, 18, 21, 24];
|
|
558
|
+
interface GenerateMnemonicOptions {
|
|
559
|
+
/** How many words to generate. Defaults to 12. */
|
|
560
|
+
readonly words?: MnemonicWordCount;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Generate a fresh BIP-39 recovery phrase, using the platform's cryptographically
|
|
564
|
+
* secure random source.
|
|
565
|
+
*
|
|
566
|
+
* Pure JavaScript — no engine needed, so this works before {@link initGeeq}
|
|
567
|
+
* resolves. Phrases are generated from the English wordlist, which is what
|
|
568
|
+
* {@link keypairFromMnemonic} expects.
|
|
569
|
+
*
|
|
570
|
+
* The phrase is the *only* way to recover the wallet. Show it to the user once,
|
|
571
|
+
* let them write it down, and never transmit or persist it in plaintext.
|
|
572
|
+
*
|
|
573
|
+
* ```ts
|
|
574
|
+
* const mnemonic = generateMnemonic() // 12 words
|
|
575
|
+
* const long = generateMnemonic({ words: 24 }) // 24 words
|
|
576
|
+
* ```
|
|
577
|
+
*/
|
|
578
|
+
declare function generateMnemonic(options?: GenerateMnemonicOptions): string;
|
|
579
|
+
/**
|
|
580
|
+
* Check a recovery phrase for the right word count, known words, and a valid
|
|
581
|
+
* checksum. Use it to give immediate feedback on a restore form rather than
|
|
582
|
+
* waiting for {@link keypairFromMnemonic} to throw.
|
|
583
|
+
*
|
|
584
|
+
* Pure JavaScript — no engine needed.
|
|
585
|
+
*/
|
|
586
|
+
declare function validateMnemonic(mnemonic: string): boolean;
|
|
587
|
+
/** Trim and collapse whitespace so pasted phrases validate as typed ones do. */
|
|
588
|
+
declare function normalizeMnemonic(mnemonic: string): string;
|
|
589
|
+
|
|
590
|
+
/** Identify the account either by its public key or by its account id. */
|
|
591
|
+
type AccountIdentifier = {
|
|
592
|
+
readonly publicKey: Uint8Array;
|
|
593
|
+
readonly accountId?: never;
|
|
594
|
+
} | {
|
|
595
|
+
readonly accountId: Uint8Array;
|
|
596
|
+
readonly publicKey?: never;
|
|
597
|
+
};
|
|
598
|
+
type CreateWalletAddressInput = AccountIdentifier & WalletAddressOptions;
|
|
599
|
+
/**
|
|
600
|
+
* Build the base58 wallet address for an account. Synchronous; requires the engine
|
|
601
|
+
* to be loaded already. Most callers want {@link createWalletAddress} instead.
|
|
602
|
+
*/
|
|
603
|
+
declare function createWalletAddressSync(input: CreateWalletAddressInput): string;
|
|
604
|
+
/**
|
|
605
|
+
* Build the base58 wallet address for an account, loading the engine if needed.
|
|
606
|
+
*
|
|
607
|
+
* ```ts
|
|
608
|
+
* const address = await createWalletAddress({ publicKey, chainNumber: 1 })
|
|
609
|
+
* ```
|
|
610
|
+
*/
|
|
611
|
+
declare function createWalletAddress(input: CreateWalletAddressInput): Promise<string>;
|
|
612
|
+
/** Decode a base58 wallet address. Synchronous; requires the engine to be loaded. */
|
|
613
|
+
declare function decodeWalletAddressSync(address: string): DecodedWalletAddress;
|
|
614
|
+
/** Decode a base58 wallet address, loading the engine if needed. */
|
|
615
|
+
declare function decodeWalletAddress(address: string): Promise<DecodedWalletAddress>;
|
|
616
|
+
/**
|
|
617
|
+
* True when `address` decodes as a Geeq wallet address. Requires a loaded engine.
|
|
618
|
+
*
|
|
619
|
+
* Throws `not-initialized` rather than answering before the engine has loaded: `false`
|
|
620
|
+
* would call every address invalid, including good ones.
|
|
621
|
+
*/
|
|
622
|
+
declare function isValidWalletAddress(address: string): boolean;
|
|
623
|
+
|
|
624
|
+
/** Every record type this SDK understands, for validation and tooling. */
|
|
625
|
+
declare const GEEQ_RECORD_TYPES: readonly GeeqRecordType[];
|
|
626
|
+
declare const DEFAULT_RECORD_TYPE: GeeqRecordType;
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* An amount of coin, with its unit stated.
|
|
630
|
+
*
|
|
631
|
+
* The protocol counts only **pennies**, as geeq_node_core calls them. A Geeq is a display
|
|
632
|
+
* unit, and how many pennies make one is not on the chain: the app says, as
|
|
633
|
+
* `penniesPerGeeq` when it connects, and every conversion takes it from there.
|
|
634
|
+
*
|
|
635
|
+
* Every amount crossing this SDK's surface names its unit, because the alternative is a
|
|
636
|
+
* bare number that means one thing to the caller and another to the chain. That mistake
|
|
637
|
+
* does not throw — it just moves the wrong amount.
|
|
638
|
+
*
|
|
639
|
+
* ```ts
|
|
640
|
+
* { geeq: "12.34" } // human-facing: what someone typed
|
|
641
|
+
* { pennies: balance } // protocol-facing: as the chain counts it
|
|
642
|
+
* ```
|
|
643
|
+
*/
|
|
644
|
+
type GeeqAmount = {
|
|
645
|
+
readonly geeq: string | number;
|
|
646
|
+
} | {
|
|
647
|
+
readonly pennies: bigint | number;
|
|
648
|
+
};
|
|
649
|
+
/**
|
|
650
|
+
* Resolve any {@link GeeqAmount} to pennies, the unit the protocol uses. A `{ geeq }`
|
|
651
|
+
* figure is read at `penniesPerGeeq` to the Geeq; `{ pennies }` is taken as it is.
|
|
652
|
+
*/
|
|
653
|
+
declare function toPennies(amount: GeeqAmount, penniesPerGeeq: bigint): bigint;
|
|
654
|
+
/**
|
|
655
|
+
* Format pennies as a decimal Geeq string at `penniesPerGeeq` to the Geeq, the way the Geeq
|
|
656
|
+
* wallet shows amounts: every place the unit has, trailing zeros dropped.
|
|
657
|
+
*
|
|
658
|
+
* A negative figure — a shortfall, say — keeps its sign: `-1.5`, not `-1.-5`.
|
|
659
|
+
*/
|
|
660
|
+
declare function formatGeeq(pennies: bigint, penniesPerGeeq: bigint): string;
|
|
661
|
+
|
|
662
|
+
/** A response, narrowed to what this SDK reads. A WHATWG `Response` satisfies it. */
|
|
663
|
+
interface GeeqHttpResponse {
|
|
664
|
+
readonly ok: boolean;
|
|
665
|
+
readonly status: number;
|
|
666
|
+
text(): Promise<string>;
|
|
667
|
+
}
|
|
668
|
+
/** A request, narrowed to what this SDK sends. Assignable to `RequestInit`. */
|
|
669
|
+
interface GeeqRequestInit {
|
|
670
|
+
readonly method?: string;
|
|
671
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
672
|
+
readonly body?: string;
|
|
673
|
+
readonly signal?: AbortSignal;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* How the SDK reaches a node.
|
|
677
|
+
*
|
|
678
|
+
* Deliberately a structural subset of WHATWG `fetch`, so `{ transport: fetch }`
|
|
679
|
+
* typechecks with no adapter, and so does undici with a custom dispatcher, a relative
|
|
680
|
+
* URL through a dev proxy, or a scripted array of responses in a test.
|
|
681
|
+
*/
|
|
682
|
+
type GeeqTransport = (url: string, init?: GeeqRequestInit) => Promise<GeeqHttpResponse>;
|
|
683
|
+
/**
|
|
684
|
+
* `globalThis.fetch`, resolved at call time.
|
|
685
|
+
*
|
|
686
|
+
* Never a stored reference: an unbound `fetch` throws `Illegal invocation` in a
|
|
687
|
+
* browser, and capturing it would defeat any test that swaps `globalThis.fetch` after
|
|
688
|
+
* this module is imported.
|
|
689
|
+
*/
|
|
690
|
+
declare const defaultTransport: GeeqTransport;
|
|
691
|
+
interface RequestOptions {
|
|
692
|
+
readonly transport: GeeqTransport;
|
|
693
|
+
readonly timeoutMs: number;
|
|
694
|
+
readonly retries: number;
|
|
695
|
+
readonly headers?: Readonly<Record<string, string>> | undefined;
|
|
696
|
+
readonly signal?: AbortSignal | undefined;
|
|
697
|
+
readonly method?: string | undefined;
|
|
698
|
+
readonly body?: string | undefined;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/** How the directory classifies a node. Only `'active'` processes transactions. */
|
|
702
|
+
type GeeqNodeKind = 'active' | 'relay' | 'listener' | 'chain-admin' | 'none' | 'unknown';
|
|
703
|
+
/** One chain the directory knows about. */
|
|
704
|
+
interface GeeqDiscoveredChain {
|
|
705
|
+
/** The directory's own row id, which every other directory route calls `systemId`. */
|
|
706
|
+
readonly systemId: number;
|
|
707
|
+
/** The protocol chain number — what a transaction carries and a node checks. */
|
|
708
|
+
readonly chainNumber: number;
|
|
709
|
+
readonly name: string | undefined;
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* One node the directory knows about.
|
|
713
|
+
*
|
|
714
|
+
* Note what is **missing**: a node number. The directory can say where a node is but
|
|
715
|
+
* not who it is in the chain's own net actor list, so the ledger read is still the only
|
|
716
|
+
* way to learn the number a transaction must carry.
|
|
717
|
+
*/
|
|
718
|
+
interface GeeqDiscoveredNode {
|
|
719
|
+
readonly host: string;
|
|
720
|
+
readonly kind: GeeqNodeKind;
|
|
721
|
+
/** The directory's own lifecycle state — `new`, `ready`, `stopped`. */
|
|
722
|
+
readonly status: string;
|
|
723
|
+
/** Where to reach it. Always the client port; the directory's own port is internal. */
|
|
724
|
+
readonly url: string;
|
|
725
|
+
}
|
|
726
|
+
/** Every chain the directory knows about. */
|
|
727
|
+
declare function listChains(origin: string, request: RequestOptions): Promise<GeeqDiscoveredChain[]>;
|
|
728
|
+
interface NodeAddressing {
|
|
729
|
+
/** Scheme for the node URLs. Defaults to the directory's own. */
|
|
730
|
+
readonly protocol?: string | undefined;
|
|
731
|
+
/** Client port. Defaults to {@link GEEQ_NODE_PORT}; override only for local setups. */
|
|
732
|
+
readonly port?: number | undefined;
|
|
733
|
+
}
|
|
734
|
+
/** Every node the directory lists for one chain. */
|
|
735
|
+
declare function listNodes(origin: string, systemId: number, request: RequestOptions, addressing?: NodeAddressing): Promise<GeeqDiscoveredNode[]>;
|
|
736
|
+
interface DiscoverOptions extends NodeAddressing {
|
|
737
|
+
readonly origin: string;
|
|
738
|
+
/** Select the chain by the name the directory gives it. Matched case-insensitively. */
|
|
739
|
+
readonly chainName?: string | undefined;
|
|
740
|
+
/** Select by protocol chain number, or — alongside `chainName` — assert it. */
|
|
741
|
+
readonly chainNumber?: number | undefined;
|
|
742
|
+
readonly request: RequestOptions;
|
|
743
|
+
}
|
|
744
|
+
interface Discovery {
|
|
745
|
+
readonly chain: GeeqDiscoveredChain;
|
|
746
|
+
/** Every node listed for the chain, in directory order. */
|
|
747
|
+
readonly nodes: readonly GeeqDiscoveredNode[];
|
|
748
|
+
/** Those that will actually take a transaction. */
|
|
749
|
+
readonly usable: readonly GeeqDiscoveredNode[];
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Find a chain in the directory and list its nodes.
|
|
753
|
+
*
|
|
754
|
+
* This reads two routes and nothing else. The directory is a deployment control plane:
|
|
755
|
+
* it has no authentication, and its other routes create and destroy machines and serve
|
|
756
|
+
* private keys. Treat every value it returns as a hint about *where* to look, never as
|
|
757
|
+
* authority about the chain itself — that comes from the ledger.
|
|
758
|
+
*/
|
|
759
|
+
declare function discover(options: DiscoverOptions): Promise<Discovery>;
|
|
760
|
+
|
|
761
|
+
/** What kind of actor a net actor record describes. */
|
|
762
|
+
type GeeqNodeRole = 'anchor-node' | 'anon-node' | 'cert-node' | 'cert-authority' | 'chain-admin' | 'relay' | 'treasury-agent' | 'unknown';
|
|
763
|
+
/** What that actor is currently doing. */
|
|
764
|
+
type GeeqNodeStatus = 'chain-admin' | 'hub' | 'leaving' | 'listening' | 'node' | 'ready' | 'relay' | 'suspended' | 'unknown';
|
|
765
|
+
/** One net actor record, as plain values. */
|
|
766
|
+
interface GeeqLedgerNode {
|
|
767
|
+
/** `nodeNumSelf` — what a transaction must name, checked with strict equality. */
|
|
768
|
+
readonly nodeNumber: number;
|
|
769
|
+
/** The bare IP the ledger records. Nodes are matched on this and nothing else. */
|
|
770
|
+
readonly host: string;
|
|
771
|
+
/**
|
|
772
|
+
* The port recorded against this node in the ledger.
|
|
773
|
+
*
|
|
774
|
+
* **Not the port you connect to.** Clients always reach a node on 2082, where TLS is
|
|
775
|
+
* terminated; every first-party client ignores this field and rebuilds the URL from
|
|
776
|
+
* its own configuration. Exposed for diagnostics, and used only to break a tie when
|
|
777
|
+
* one address carries several records.
|
|
778
|
+
*/
|
|
779
|
+
readonly port: number;
|
|
780
|
+
readonly role: GeeqNodeRole;
|
|
781
|
+
readonly status: GeeqNodeStatus;
|
|
782
|
+
/**
|
|
783
|
+
* True when the protocol permits this node to accept transactions.
|
|
784
|
+
*
|
|
785
|
+
* **Not a liveness signal.** Nothing in the protocol evicts a crashed node from the
|
|
786
|
+
* net actor list, and `blockNumLiveness` is rewritten for every actor on every commit
|
|
787
|
+
* rather than per node, so it carries no health information at all. A node that died
|
|
788
|
+
* an hour ago still reads as processing here. The only way to learn a node is up is
|
|
789
|
+
* to talk to it.
|
|
790
|
+
*/
|
|
791
|
+
readonly processing: boolean;
|
|
792
|
+
/**
|
|
793
|
+
* `blockNumRemove` — the block at which this node's turn in the active set ends.
|
|
794
|
+
*
|
|
795
|
+
* Reset 100–355 blocks ahead each time the node is promoted, so it is a rotation
|
|
796
|
+
* deadline rather than a departure flag.
|
|
797
|
+
*/
|
|
798
|
+
readonly retiresAtBlock: number;
|
|
799
|
+
/**
|
|
800
|
+
* True when this node is inside its own shutdown window and will refuse work.
|
|
801
|
+
*
|
|
802
|
+
* The node's submit handler answers HTTP 503 `'Block chain is stopped'` once its
|
|
803
|
+
* `blockNumRemove` is less than its current block plus two, so this is knowable from
|
|
804
|
+
* the ledger before a transaction is ever built.
|
|
805
|
+
*/
|
|
806
|
+
readonly retiring: boolean;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/** @internal — built by {@link decodeValidationLedger}, never by hand. */
|
|
810
|
+
interface GeeqLedgerInit {
|
|
811
|
+
readonly chainNumber: number;
|
|
812
|
+
readonly blockNumber: number;
|
|
813
|
+
readonly nodes: readonly GeeqLedgerNode[];
|
|
814
|
+
readonly metadataLimits: GeeqMetadataLimits | undefined;
|
|
815
|
+
readonly minimumTransfer: bigint | undefined;
|
|
816
|
+
readonly geeqNorm: bigint | undefined;
|
|
817
|
+
readonly accounts: ReadonlyMap<string, CoinAccountFacts>;
|
|
818
|
+
readonly proxies: ReadonlyMap<string, ProxyAccountFacts>;
|
|
819
|
+
readonly readAt: number;
|
|
820
|
+
readonly nodeUrl: string | undefined;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* One validation layer ledger, decoded into plain values.
|
|
824
|
+
*
|
|
825
|
+
* This is a snapshot, not a view: the Cap'n Proto `Message` it came from is released
|
|
826
|
+
* the moment decoding finishes. That is deliberate and load-bearing. capnp-ts counts a
|
|
827
|
+
* traversal budget per `Message` and never resets it, so a retained handle rescanned on
|
|
828
|
+
* every transaction eventually throws `PTR_TRAVERSAL_LIMIT_EXCEEDED`; and reading a
|
|
829
|
+
* malformed union arm mutates the message in place. Neither can happen to a snapshot.
|
|
830
|
+
*
|
|
831
|
+
* It holds no WebAssembly handle, so unlike a keypair it needs no `dispose()`.
|
|
832
|
+
*/
|
|
833
|
+
declare class GeeqLedger {
|
|
834
|
+
/** The ledger's own chain number. A transaction must name exactly this. */
|
|
835
|
+
readonly chainNumber: number;
|
|
836
|
+
/** N — the last block committed to this ledger. */
|
|
837
|
+
readonly blockNumber: number;
|
|
838
|
+
/** N + 1 — the block a transaction built now should ask for. */
|
|
839
|
+
readonly targetBlockNumber: number;
|
|
840
|
+
/** Every net actor, in ledger order. */
|
|
841
|
+
readonly nodes: readonly GeeqLedgerNode[];
|
|
842
|
+
/** Undefined when this chain publishes no metadata parameters. */
|
|
843
|
+
readonly metadataLimits: GeeqMetadataLimits | undefined;
|
|
844
|
+
/**
|
|
845
|
+
* The smallest transfer this chain accepts, in pennies.
|
|
846
|
+
*
|
|
847
|
+
* Undefined when the chain does not publish the parameters it is derived from.
|
|
848
|
+
*/
|
|
849
|
+
readonly minimumTransfer: bigint | undefined;
|
|
850
|
+
/**
|
|
851
|
+
* The chain's `geeqNorm` parameter, which the minimum transfer and every fee are
|
|
852
|
+
* multiples of. Undefined when the chain does not publish it.
|
|
853
|
+
*/
|
|
854
|
+
readonly geeqNorm: bigint | undefined;
|
|
855
|
+
/** `Date.now()` when this was read, so callers can judge staleness. */
|
|
856
|
+
readonly readAt: number;
|
|
857
|
+
/** The node it was read from, when it came from one. */
|
|
858
|
+
readonly nodeUrl: string | undefined;
|
|
859
|
+
private readonly accounts;
|
|
860
|
+
private readonly proxies;
|
|
861
|
+
/** @internal */
|
|
862
|
+
constructor(init: GeeqLedgerInit);
|
|
863
|
+
/** The nodes that will actually accept a transaction. */
|
|
864
|
+
get processingNodes(): readonly GeeqLedgerNode[];
|
|
865
|
+
/**
|
|
866
|
+
* Find a net actor record.
|
|
867
|
+
*
|
|
868
|
+
* By `host` this matches the bare IP and nothing else — every first-party client does
|
|
869
|
+
* the same, because a record's `port` is the node's internal listen port while clients
|
|
870
|
+
* connect through a proxy on another one. Matching on both finds nothing.
|
|
871
|
+
*/
|
|
872
|
+
findNode(match: {
|
|
873
|
+
readonly host: string;
|
|
874
|
+
} | {
|
|
875
|
+
readonly nodeNumber: number;
|
|
876
|
+
}): GeeqLedgerNode | undefined;
|
|
877
|
+
/** Every net actor record at one host. More than one is possible, and ambiguous. */
|
|
878
|
+
findNodes(host: string): readonly GeeqLedgerNode[];
|
|
879
|
+
/**
|
|
880
|
+
* The signing account's coin record, or `undefined` when this chain has none for it.
|
|
881
|
+
*
|
|
882
|
+
* Absence is the ordinary state of a freshly generated keypair: an account appears in
|
|
883
|
+
* the ledger only once it has been funded.
|
|
884
|
+
*/
|
|
885
|
+
findCoinAccount(account: AccountRef): GeeqCoinAccount | undefined;
|
|
886
|
+
/** A proxy record, or `undefined` when this chain has none with that id. */
|
|
887
|
+
findProxyAccount(account: AccountRef): GeeqProxyAccount | undefined;
|
|
888
|
+
/**
|
|
889
|
+
* Every NFT mint proxy an account administers — the ones it can mint through.
|
|
890
|
+
*
|
|
891
|
+
* Found by the admin each record names, so it needs nothing remembered from when they
|
|
892
|
+
* were created.
|
|
893
|
+
*/
|
|
894
|
+
findProxyAccounts(match: {
|
|
895
|
+
readonly admin: AccountRef;
|
|
896
|
+
}): readonly GeeqProxyAccount[];
|
|
897
|
+
/** How many coin accounts this ledger carries. Mostly useful for diagnostics. */
|
|
898
|
+
get coinAccountCount(): number;
|
|
899
|
+
/** Summary only — the account table is far too large to serialise. */
|
|
900
|
+
toJSON(): Record<string, unknown>;
|
|
901
|
+
toString(): string;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/** The protocol attests a 32-byte BLAKE3 digest and rejects any other length. */
|
|
905
|
+
declare const ATTEST_HASH_BYTES = 32;
|
|
906
|
+
/**
|
|
907
|
+
* Anything that can be attested.
|
|
908
|
+
*
|
|
909
|
+
* A `File` from an `<input type="file">` is a `Blob`, so it can be passed straight in —
|
|
910
|
+
* there is no need to read it into a buffer first. A string is encoded as UTF-8.
|
|
911
|
+
*/
|
|
912
|
+
type GeeqContent = Uint8Array | ArrayBuffer | Blob | string;
|
|
913
|
+
/** Read any accepted content into bytes. Async only because a `Blob` requires it. */
|
|
914
|
+
declare function readContent(content: GeeqContent): Promise<Uint8Array>;
|
|
915
|
+
/**
|
|
916
|
+
* The digest that goes on chain.
|
|
917
|
+
*
|
|
918
|
+
* The content itself never leaves the device; only this does. Pure BLAKE3, so it needs
|
|
919
|
+
* no engine and no network and works before {@link initGeeq} has resolved — which is
|
|
920
|
+
* what lets a UI show the digest as someone types.
|
|
921
|
+
*
|
|
922
|
+
* Use this rather than calling a hash library directly: the length and the algorithm are
|
|
923
|
+
* both fixed by the protocol, and a digest of any other width is rejected when the
|
|
924
|
+
* transaction is built.
|
|
925
|
+
*/
|
|
926
|
+
declare function attestHashOfSync(content: Uint8Array | ArrayBuffer | string): Uint8Array;
|
|
927
|
+
/** {@link attestHashOfSync}, also accepting a `Blob` or a `File`. */
|
|
928
|
+
declare function attestHashOf(content: GeeqContent): Promise<Uint8Array>;
|
|
929
|
+
/** Reject a digest the chain would refuse, naming what was wrong. */
|
|
930
|
+
declare function assertAttestHash(attestHash: unknown): Uint8Array;
|
|
931
|
+
|
|
932
|
+
/** @internal */
|
|
933
|
+
interface NodeRequestConfig {
|
|
934
|
+
readonly transport: GeeqTransport;
|
|
935
|
+
readonly timeoutMs: number;
|
|
936
|
+
readonly retries: number;
|
|
937
|
+
readonly headers: Readonly<Record<string, string>> | undefined;
|
|
938
|
+
}
|
|
939
|
+
/** @internal */
|
|
940
|
+
interface GeeqNodeInit extends NodeRequestConfig {
|
|
941
|
+
readonly url: string;
|
|
942
|
+
readonly nodeNumber: number;
|
|
943
|
+
readonly host: string;
|
|
944
|
+
readonly port: number;
|
|
945
|
+
readonly role: GeeqNodeRole;
|
|
946
|
+
readonly status: GeeqNodeStatus;
|
|
947
|
+
readonly processing: boolean;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* One node, identified in its own chain's ledger.
|
|
951
|
+
*
|
|
952
|
+
* A node is only meaningful once a ledger has confirmed which actor it is: the number a
|
|
953
|
+
* transaction must carry is the node's own `nodeNumSelf`, checked with strict equality,
|
|
954
|
+
* and nothing outside the ledger reports it.
|
|
955
|
+
*/
|
|
956
|
+
declare class GeeqNode {
|
|
957
|
+
/** Absolute origin, no trailing slash. */
|
|
958
|
+
readonly url: string;
|
|
959
|
+
/** `nodeNumSelf` — what a transaction targeting this node must name. */
|
|
960
|
+
readonly nodeNumber: number;
|
|
961
|
+
/** The bare IP the ledger records for it. */
|
|
962
|
+
readonly host: string;
|
|
963
|
+
/** Its own listen port from the ledger, which is not necessarily {@link url}'s. */
|
|
964
|
+
readonly port: number;
|
|
965
|
+
readonly role: GeeqNodeRole;
|
|
966
|
+
readonly status: GeeqNodeStatus;
|
|
967
|
+
/** Whether it accepts transactions at all. */
|
|
968
|
+
readonly processing: boolean;
|
|
969
|
+
private readonly request;
|
|
970
|
+
/** @internal */
|
|
971
|
+
constructor(init: GeeqNodeInit);
|
|
972
|
+
/**
|
|
973
|
+
* Where a transaction built for this node must be POSTed.
|
|
974
|
+
*
|
|
975
|
+
* The SDK does not submit. This exists so an application posts to the node the SDK
|
|
976
|
+
* actually read from, instead of keeping a second copy of the URL that can drift.
|
|
977
|
+
*/
|
|
978
|
+
get submitUrl(): string;
|
|
979
|
+
/** Read this node's current ledger. No caching — {@link GeeqChain} owns that. */
|
|
980
|
+
readLedger(options?: {
|
|
981
|
+
readonly signal?: AbortSignal;
|
|
982
|
+
}): Promise<GeeqLedger>;
|
|
983
|
+
toJSON(): Record<string, unknown>;
|
|
984
|
+
toString(): string;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
interface GeeqChainOptions {
|
|
988
|
+
/**
|
|
989
|
+
* How many pennies make one Geeq: a power of ten, as a bigint.
|
|
990
|
+
*
|
|
991
|
+
* The chain counts only pennies and does not publish this, so the app says — use the
|
|
992
|
+
* divisor its wallet and explorer show amounts with. {@link GeeqChain.toPennies} reads
|
|
993
|
+
* `{ geeq }` figures with it, and {@link GeeqChain.formatGeeq} and the chain's own
|
|
994
|
+
* messages show amounts with it.
|
|
995
|
+
*/
|
|
996
|
+
readonly penniesPerGeeq: bigint;
|
|
997
|
+
/**
|
|
998
|
+
* The chain's node directory — the simulator URL for your environment — which the SDK
|
|
999
|
+
* asks for an active node. Works for every chain and environment.
|
|
1000
|
+
*
|
|
1001
|
+
* Supply this or {@link endpoint}, not both. The directory is the only thing that
|
|
1002
|
+
* knows which nodes exist and which are running; the ledger then says which actor the
|
|
1003
|
+
* chosen one is. Note the directory is a deployment control plane with no
|
|
1004
|
+
* authentication — the SDK reads two of its routes and never touches the rest.
|
|
1005
|
+
*/
|
|
1006
|
+
readonly discovery?: string | URL;
|
|
1007
|
+
/**
|
|
1008
|
+
* A specific node, when you already know one.
|
|
1009
|
+
*
|
|
1010
|
+
* Supply this or {@link discovery}, not both.
|
|
1011
|
+
*/
|
|
1012
|
+
readonly endpoint?: string | URL;
|
|
1013
|
+
/**
|
|
1014
|
+
* Which chain to use, by the name its directory gives it.
|
|
1015
|
+
*
|
|
1016
|
+
* Only meaningful with {@link discovery} — a name exists nowhere but the directory.
|
|
1017
|
+
* Matched case-insensitively.
|
|
1018
|
+
*/
|
|
1019
|
+
readonly chainName?: string;
|
|
1020
|
+
/**
|
|
1021
|
+
* Which chain to use, by protocol number.
|
|
1022
|
+
*
|
|
1023
|
+
* With {@link discovery} this selects the chain when no {@link chainName} is given,
|
|
1024
|
+
* and asserts it when one is. With {@link endpoint} it asserts the node serves the
|
|
1025
|
+
* chain you expect, and a mismatch throws `chain-mismatch` on the first ledger read.
|
|
1026
|
+
*/
|
|
1027
|
+
readonly chainNumber?: number;
|
|
1028
|
+
/** Defaults to a call through `globalThis.fetch`. */
|
|
1029
|
+
readonly transport?: GeeqTransport;
|
|
1030
|
+
/** Per request. Defaults to 10000. */
|
|
1031
|
+
readonly timeoutMs?: number;
|
|
1032
|
+
/** Extra headers on every request — a proxy token, a trace id. */
|
|
1033
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
1034
|
+
/** How long a read ledger may be reused. Defaults to 5000. 0 disables the cache. */
|
|
1035
|
+
readonly ledgerMaxAgeMs?: number;
|
|
1036
|
+
/** Skip host matching. Required behind a gateway or when using a DNS name. */
|
|
1037
|
+
readonly nodeNumber?: number;
|
|
1038
|
+
/**
|
|
1039
|
+
* The port discovered nodes are reached on. Defaults to 2082.
|
|
1040
|
+
*
|
|
1041
|
+
* Deployment configuration, not node selection — override it only when running
|
|
1042
|
+
* against nodes that are not behind the standard TLS front door, such as a local
|
|
1043
|
+
* test harness.
|
|
1044
|
+
*/
|
|
1045
|
+
readonly nodePort?: number;
|
|
1046
|
+
/** Retries on transport failure only, never on a response. Defaults to 1. */
|
|
1047
|
+
readonly retries?: number;
|
|
1048
|
+
readonly signal?: AbortSignal;
|
|
1049
|
+
}
|
|
1050
|
+
interface AttestationRequest {
|
|
1051
|
+
/** The account that signs. Must be a coin-asset account on this chain. */
|
|
1052
|
+
readonly keypair: GeeqKeypair;
|
|
1053
|
+
/**
|
|
1054
|
+
* What to attest. Hashed here with BLAKE3-32; the content never leaves the device.
|
|
1055
|
+
*
|
|
1056
|
+
* A `File` straight from a file input works, as does a string or raw bytes.
|
|
1057
|
+
*/
|
|
1058
|
+
readonly content?: GeeqContent;
|
|
1059
|
+
/** Or supply the digest yourself. Exactly one of `content` and `attestHash`. */
|
|
1060
|
+
readonly attestHash?: Uint8Array;
|
|
1061
|
+
/** Public labels, checked against this chain's limits before anything is signed. */
|
|
1062
|
+
readonly metadata?: readonly (string | Uint8Array)[];
|
|
1063
|
+
/** Override the derived nonce. See {@link NonceGuard} for when that is needed. */
|
|
1064
|
+
readonly nonce?: number;
|
|
1065
|
+
readonly signal?: AbortSignal;
|
|
1066
|
+
}
|
|
1067
|
+
interface CoinTransferRequest {
|
|
1068
|
+
/** The account paying. Must be a coin-asset account on this chain. */
|
|
1069
|
+
readonly from: GeeqKeypair;
|
|
1070
|
+
/**
|
|
1071
|
+
* Who receives it.
|
|
1072
|
+
*
|
|
1073
|
+
* A base58 wallet address is the usual thing — it is what a person pastes — and the
|
|
1074
|
+
* chain it encodes is checked against this one. A raw account id or public key works
|
|
1075
|
+
* too, but carries no chain to check.
|
|
1076
|
+
*/
|
|
1077
|
+
readonly to: string | AccountRef;
|
|
1078
|
+
/**
|
|
1079
|
+
* How much. State the unit: `{ geeq: "1.5" }`, read at {@link GeeqChainOptions.penniesPerGeeq},
|
|
1080
|
+
* or `{ pennies }` as the chain counts them. May be left out
|
|
1081
|
+
* when sending NFTs, which then go with the chain's minimum transfer.
|
|
1082
|
+
*/
|
|
1083
|
+
readonly amount?: GeeqAmount;
|
|
1084
|
+
/** NFTs to send, by id — see {@link GeeqChain.findNfts}. The sender must hold each one. */
|
|
1085
|
+
readonly nfts?: readonly Uint8Array[];
|
|
1086
|
+
/** Override the derived nonce. See {@link NonceGuard}. */
|
|
1087
|
+
readonly nonce?: number;
|
|
1088
|
+
readonly signal?: AbortSignal;
|
|
1089
|
+
}
|
|
1090
|
+
interface ChainStateRequest {
|
|
1091
|
+
readonly account: AccountRef;
|
|
1092
|
+
readonly maxAgeMs?: number;
|
|
1093
|
+
readonly signal?: AbortSignal;
|
|
1094
|
+
}
|
|
1095
|
+
interface NftMintProxyRequest {
|
|
1096
|
+
/**
|
|
1097
|
+
* The account paying for the proxy, which also becomes its admin: the only key that
|
|
1098
|
+
* can later mint NFTs through it. Must be a coin-asset account on this chain.
|
|
1099
|
+
*/
|
|
1100
|
+
readonly admin: GeeqKeypair;
|
|
1101
|
+
/**
|
|
1102
|
+
* Coin moved onto the proxy, `{ geeq }` or `{ pennies }` like any amount. It pays for the
|
|
1103
|
+
* mints made through it, so fund it for more than one.
|
|
1104
|
+
*/
|
|
1105
|
+
readonly amount: GeeqAmount;
|
|
1106
|
+
/**
|
|
1107
|
+
* Which of the admin's proxies this is, from 1. Leave it out to take the next one —
|
|
1108
|
+
* one past the highest the ledger holds for this admin, see
|
|
1109
|
+
* {@link GeeqChain.findNftMintProxies}. An index already in use is refused.
|
|
1110
|
+
*/
|
|
1111
|
+
readonly index?: number;
|
|
1112
|
+
/** Override the derived nonce. See {@link NonceGuard}. */
|
|
1113
|
+
readonly nonce?: number;
|
|
1114
|
+
readonly signal?: AbortSignal;
|
|
1115
|
+
}
|
|
1116
|
+
interface NftMintProxiesRequest {
|
|
1117
|
+
/**
|
|
1118
|
+
* The admin whose proxies to find. A keypair will do; so will a bare public key, since
|
|
1119
|
+
* listing needs no signature. Not an account id: an index is derived from the key.
|
|
1120
|
+
*/
|
|
1121
|
+
readonly admin: {
|
|
1122
|
+
readonly publicKey: Uint8Array;
|
|
1123
|
+
};
|
|
1124
|
+
/** How old a cached ledger may be. 0 reads afresh — a new proxy shows only once confirmed. */
|
|
1125
|
+
readonly maxAgeMs?: number;
|
|
1126
|
+
readonly signal?: AbortSignal;
|
|
1127
|
+
}
|
|
1128
|
+
interface NftsRequest {
|
|
1129
|
+
/** Whose NFTs. A keypair will do, as will an account id or a public key. */
|
|
1130
|
+
readonly owner: AccountRef;
|
|
1131
|
+
/** How old a cached ledger may be. 0 reads afresh — a new NFT shows only once confirmed. */
|
|
1132
|
+
readonly maxAgeMs?: number;
|
|
1133
|
+
readonly signal?: AbortSignal;
|
|
1134
|
+
}
|
|
1135
|
+
interface NftMintRequest {
|
|
1136
|
+
/** The proxy's admin: the only key that can mint through it. It signs the mint. */
|
|
1137
|
+
readonly admin: GeeqKeypair;
|
|
1138
|
+
/**
|
|
1139
|
+
* Which of the admin's proxies mints it, by index — see
|
|
1140
|
+
* {@link GeeqChain.findNftMintProxies}. The proxy pays the fee and {@link amount}, and
|
|
1141
|
+
* spends its own nonce, not the admin's.
|
|
1142
|
+
*/
|
|
1143
|
+
readonly index: number;
|
|
1144
|
+
/**
|
|
1145
|
+
* What the NFT stands for. Hashed here with BLAKE3-32; the content never leaves the
|
|
1146
|
+
* device. A `File` straight from a file input works, as does a string or raw bytes.
|
|
1147
|
+
*/
|
|
1148
|
+
readonly content?: GeeqContent;
|
|
1149
|
+
/** Or supply the digest yourself. Exactly one of `content` and `attestHash`. */
|
|
1150
|
+
readonly attestHash?: Uint8Array;
|
|
1151
|
+
/** Public labels stored with the NFT, checked against this chain's limits before signing. */
|
|
1152
|
+
readonly metadata?: readonly (string | Uint8Array)[];
|
|
1153
|
+
/** Who receives the NFT. Defaults to the admin. An address is checked against this chain. */
|
|
1154
|
+
readonly to?: string | AccountRef;
|
|
1155
|
+
/** Coin the proxy sends to the receiver with it. Defaults to the chain's minimum transfer. */
|
|
1156
|
+
readonly amount?: GeeqAmount;
|
|
1157
|
+
/** Override the proxy's derived nonce. See {@link NonceGuard}. */
|
|
1158
|
+
readonly nonce?: number;
|
|
1159
|
+
readonly signal?: AbortSignal;
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* A chain, reached through one node.
|
|
1163
|
+
*
|
|
1164
|
+
* Holds the node directory, the metadata limits and a short-lived ledger cache, so an
|
|
1165
|
+
* attestation needs only a keypair and something to attest. Everything a transaction is
|
|
1166
|
+
* pinned to — chain number, target block, node number, nonce — is read from the ledger
|
|
1167
|
+
* rather than asked of the caller, because none of it can be known offline and a wrong
|
|
1168
|
+
* value is rejected by the chain.
|
|
1169
|
+
*
|
|
1170
|
+
* A chain is bound to the endpoint it was connected to. To use a different node, connect
|
|
1171
|
+
* another one: a different node means a different address, certificate and CORS origin,
|
|
1172
|
+
* which is not something to switch silently.
|
|
1173
|
+
*
|
|
1174
|
+
* In a reactive framework, mark an instance raw (Vue's `markRaw`) rather than letting it
|
|
1175
|
+
* be proxied.
|
|
1176
|
+
*/
|
|
1177
|
+
declare class GeeqChain {
|
|
1178
|
+
/** The node this chain reads from and builds transactions for. */
|
|
1179
|
+
readonly endpoint: string;
|
|
1180
|
+
/** What the directory said about the nodes on this chain, when one was used. */
|
|
1181
|
+
readonly candidates: readonly GeeqDiscoveredNode[];
|
|
1182
|
+
/** The chain's name, when a directory supplied one. Display only — chains are numbered. */
|
|
1183
|
+
readonly chainName: string | undefined;
|
|
1184
|
+
/** How many pennies make one Geeq, as given to {@link GeeqChain.connect}. */
|
|
1185
|
+
readonly penniesPerGeeq: bigint;
|
|
1186
|
+
private readonly request;
|
|
1187
|
+
private readonly ledgerMaxAgeMs;
|
|
1188
|
+
private readonly nonces;
|
|
1189
|
+
private readonly declaredChainNumber;
|
|
1190
|
+
private readonly nodeNumberOverride;
|
|
1191
|
+
private cached;
|
|
1192
|
+
private resolved;
|
|
1193
|
+
private inflight;
|
|
1194
|
+
/** @internal */
|
|
1195
|
+
constructor(init: {
|
|
1196
|
+
endpoint: string;
|
|
1197
|
+
candidates: readonly GeeqDiscoveredNode[];
|
|
1198
|
+
chainName: string | undefined;
|
|
1199
|
+
chainNumber: number | undefined;
|
|
1200
|
+
nodeNumber: number | undefined;
|
|
1201
|
+
penniesPerGeeq: bigint;
|
|
1202
|
+
request: NodeRequestConfig;
|
|
1203
|
+
ledgerMaxAgeMs: number;
|
|
1204
|
+
});
|
|
1205
|
+
/**
|
|
1206
|
+
* Choose a chain and a node, without reading anything from the chain itself.
|
|
1207
|
+
*
|
|
1208
|
+
* With `discovery`, the directory is asked which nodes exist and one of the active
|
|
1209
|
+
* ones is taken. With `endpoint`, that node is used as given. Either way **no ledger
|
|
1210
|
+
* is fetched here** — a ledger read is only valid for a few blocks, so it happens when
|
|
1211
|
+
* a transaction is actually being built rather than when the app starts.
|
|
1212
|
+
*/
|
|
1213
|
+
static connect(options: GeeqChainOptions): Promise<GeeqChain>;
|
|
1214
|
+
/** {@link GeeqChain.connect}, and install the result as the process-wide default. */
|
|
1215
|
+
static init(options: GeeqChainOptions): Promise<GeeqChain>;
|
|
1216
|
+
/** The default chain. Throws `not-initialized` when there is none. */
|
|
1217
|
+
static current(): GeeqChain;
|
|
1218
|
+
/** Whether a default chain has been installed. */
|
|
1219
|
+
static get initialized(): boolean;
|
|
1220
|
+
/** Clear the default. Call this from `afterEach` so tests do not leak into each other. */
|
|
1221
|
+
static reset(): void;
|
|
1222
|
+
/** Resolve an amount to pennies, reading a `{ geeq }` figure at {@link penniesPerGeeq}. */
|
|
1223
|
+
toPennies(amount: GeeqAmount): bigint;
|
|
1224
|
+
/** Show pennies as a Geeq figure at {@link penniesPerGeeq}, as the Geeq wallet does. */
|
|
1225
|
+
formatGeeq(pennies: bigint): string;
|
|
1226
|
+
/**
|
|
1227
|
+
* This chain's number.
|
|
1228
|
+
*
|
|
1229
|
+
* Known immediately when a directory named the chain, or once a ledger has been read.
|
|
1230
|
+
* `undefined` in between — with a bare endpoint and no declared number, only the node
|
|
1231
|
+
* can say.
|
|
1232
|
+
*/
|
|
1233
|
+
get chainNumber(): number | undefined;
|
|
1234
|
+
/**
|
|
1235
|
+
* The node, once a ledger read has identified it in the net actor list.
|
|
1236
|
+
*
|
|
1237
|
+
* `undefined` until then: a node's number is the one thing the directory cannot say,
|
|
1238
|
+
* so it is not known before the first read.
|
|
1239
|
+
*/
|
|
1240
|
+
get node(): GeeqNode | undefined;
|
|
1241
|
+
/** The net actor directory from the last ledger read, if there has been one. */
|
|
1242
|
+
get nodes(): readonly GeeqLedgerNode[];
|
|
1243
|
+
/** Those of them that accept transactions. */
|
|
1244
|
+
get processingNodes(): readonly GeeqLedgerNode[];
|
|
1245
|
+
/** The ledger from the last read, if it is still cached. */
|
|
1246
|
+
get ledger(): GeeqLedger | undefined;
|
|
1247
|
+
/**
|
|
1248
|
+
* A URL for another node in this chain.
|
|
1249
|
+
*
|
|
1250
|
+
* Every node answers client traffic on {@link GEEQ_NODE_PORT}, so only the scheme is
|
|
1251
|
+
* carried over from the endpoint in use. The port recorded against a node in the
|
|
1252
|
+
* ledger is its own internal listener and is never what you connect to.
|
|
1253
|
+
*/
|
|
1254
|
+
endpointFor(host: string): string;
|
|
1255
|
+
/**
|
|
1256
|
+
* The current ledger, from cache when it is fresh enough.
|
|
1257
|
+
*
|
|
1258
|
+
* Staleness is safe in exactly one direction. The node accepts a target block within
|
|
1259
|
+
* `[N-8, N+1]` of its own head, and a cached ledger can only be *behind*, so the
|
|
1260
|
+
* target it yields is never in the future — the only rejected direction. The default
|
|
1261
|
+
* five seconds is set by the node list and metadata limits, which have no such
|
|
1262
|
+
* tolerance, not by the block window.
|
|
1263
|
+
*/
|
|
1264
|
+
getLedger(options?: {
|
|
1265
|
+
readonly maxAgeMs?: number;
|
|
1266
|
+
readonly signal?: AbortSignal;
|
|
1267
|
+
}): Promise<GeeqLedger>;
|
|
1268
|
+
/** Discard the cached ledger and read again. */
|
|
1269
|
+
refresh(options?: {
|
|
1270
|
+
readonly signal?: AbortSignal;
|
|
1271
|
+
}): Promise<GeeqLedger>;
|
|
1272
|
+
/**
|
|
1273
|
+
* One read at a time.
|
|
1274
|
+
*
|
|
1275
|
+
* Same single-flight shape as `initGeeq`, including clearing the promise on failure so
|
|
1276
|
+
* a later call can retry rather than being stuck with the first error. Without it, a
|
|
1277
|
+
* page that builds several transactions at once pulls the whole ledger several times
|
|
1278
|
+
* from an endpoint with no rate limiting of any kind.
|
|
1279
|
+
*
|
|
1280
|
+
* The read is shared, so it carries no caller's signal: one caller aborting must not
|
|
1281
|
+
* fail the others waiting on it. Each caller stops waiting on its own signal instead,
|
|
1282
|
+
* and the read runs on, bounded by `timeoutMs`, to fill the cache for whoever is next.
|
|
1283
|
+
*/
|
|
1284
|
+
private read;
|
|
1285
|
+
/**
|
|
1286
|
+
* Everything a transaction must be pinned to, read from this chain.
|
|
1287
|
+
*
|
|
1288
|
+
* Throws rather than guessing when the account cannot sign: absent from the ledger
|
|
1289
|
+
* (the ordinary state of an unfunded keypair), or present as a record type the
|
|
1290
|
+
* protocol will not accept.
|
|
1291
|
+
*/
|
|
1292
|
+
getChainState(request: ChainStateRequest): Promise<GeeqChainState>;
|
|
1293
|
+
/**
|
|
1294
|
+
* What every transaction built from `ledger` is pinned to, bar the signer's nonce: the
|
|
1295
|
+
* same for a signer's own transaction and for a proxy's.
|
|
1296
|
+
*/
|
|
1297
|
+
private pinnedTo;
|
|
1298
|
+
/** {@link getChainState} against a ledger already in hand, so a build reads only one. */
|
|
1299
|
+
private stateIn;
|
|
1300
|
+
/**
|
|
1301
|
+
* The ledger a build is made from, and the state of `signer` in it.
|
|
1302
|
+
*
|
|
1303
|
+
* A cached ledger is up to a few seconds old, so "this account already built against
|
|
1304
|
+
* this block" may only mean "we are looking at an old block". Look again once before
|
|
1305
|
+
* letting the nonce guard refuse — otherwise a caller who waited out the block interval
|
|
1306
|
+
* is told to wait for a block that has already passed. An explicit nonce is the caller
|
|
1307
|
+
* taking responsibility, so it skips the check.
|
|
1308
|
+
*
|
|
1309
|
+
* Everything the build then needs — what the sender holds, which proxies exist — comes
|
|
1310
|
+
* from this same ledger, so it all describes one block.
|
|
1311
|
+
*/
|
|
1312
|
+
private readForBuild;
|
|
1313
|
+
/** Read afresh if `guardKey` already built against `ledger`'s block. See {@link readForBuild}. */
|
|
1314
|
+
private recheckIfClaimed;
|
|
1315
|
+
/**
|
|
1316
|
+
* Build and sign an attestation, deriving everything the chain decides.
|
|
1317
|
+
*
|
|
1318
|
+
* This is where the ledger is read, because this is the first moment the values it
|
|
1319
|
+
* carries are actually needed — and they go stale within a handful of blocks, so
|
|
1320
|
+
* reading them any earlier would only mean reading them twice.
|
|
1321
|
+
*
|
|
1322
|
+
* The result is **not submitted**. Hand it to {@link GeeqSocket.track} first, so its
|
|
1323
|
+
* verdict has somewhere to arrive, then POST `transaction` and `payload` to
|
|
1324
|
+
* {@link AttestationTx.nodeUrl}; any other node rejects it, because the node number is
|
|
1325
|
+
* checked with strict equality.
|
|
1326
|
+
*/
|
|
1327
|
+
createAttestation(input: AttestationRequest): Promise<AttestationTx>;
|
|
1328
|
+
/**
|
|
1329
|
+
* Record the nonce a finished build took, so a second build against the same block is
|
|
1330
|
+
* refused rather than sent to share it.
|
|
1331
|
+
*
|
|
1332
|
+
* Claimed only once a transaction really exists, so a build that failed validation does
|
|
1333
|
+
* not consume the account's one nonce for this block. An explicit nonce is the caller
|
|
1334
|
+
* taking responsibility, so it bypasses the guard entirely.
|
|
1335
|
+
*/
|
|
1336
|
+
private claimNonce;
|
|
1337
|
+
/**
|
|
1338
|
+
* Resolve a recipient, checking the chain it belongs to when one is stated.
|
|
1339
|
+
*
|
|
1340
|
+
* An address carries a chain number, and an address from another chain is almost
|
|
1341
|
+
* always a paste from the wrong place. The account id inside it would still be
|
|
1342
|
+
* technically usable here, which is exactly why this is worth refusing rather than
|
|
1343
|
+
* quietly sending.
|
|
1344
|
+
*/
|
|
1345
|
+
private resolveRecipient;
|
|
1346
|
+
/**
|
|
1347
|
+
* Send coin to another account, and NFTs with it if you name them.
|
|
1348
|
+
*
|
|
1349
|
+
* Reads the ledger, so it also knows what the sender holds and what the chain's minimum
|
|
1350
|
+
* transfer is. The amount is checked against the minimum, and the sender's NFTs against
|
|
1351
|
+
* the ones named, before anything is signed; the balance against the amount plus the
|
|
1352
|
+
* fee once the signed transaction gives the fee. NFTs always travel with coin: leave
|
|
1353
|
+
* `amount` out and they go with the chain's minimum transfer.
|
|
1354
|
+
*
|
|
1355
|
+
* The result is **not submitted**. Hand it to {@link GeeqSocket.track} first, then POST
|
|
1356
|
+
* `transaction` to {@link CoinTransferTx.nodeUrl} using `coinTransferSubmitBody`, which
|
|
1357
|
+
* sends it as type `uvt` — a different shape from an attestation, and with no separate
|
|
1358
|
+
* payload.
|
|
1359
|
+
*/
|
|
1360
|
+
createTransfer(input: CoinTransferRequest): Promise<CoinTransferTx>;
|
|
1361
|
+
/**
|
|
1362
|
+
* The NFTs an account holds on this chain, in the order its record lists them, each with
|
|
1363
|
+
* the hash and labels it was minted with.
|
|
1364
|
+
*
|
|
1365
|
+
* Which NFTs it holds comes from the validation layer ledger; what each stands for, from
|
|
1366
|
+
* the application layer ledger, which is read afresh every time. An account the chain
|
|
1367
|
+
* does not know holds none. A new NFT shows once a block has confirmed it, so pass
|
|
1368
|
+
* `maxAgeMs: 0` to look straight after one was minted or sent.
|
|
1369
|
+
*/
|
|
1370
|
+
findNfts(request: NftsRequest): Promise<readonly GeeqNft[]>;
|
|
1371
|
+
/**
|
|
1372
|
+
* The NFT mint proxies an admin has on this chain, each with its index, and the index
|
|
1373
|
+
* its next proxy takes: one past the highest in use, or 1 for an admin with none.
|
|
1374
|
+
*
|
|
1375
|
+
* A proxy appears once a block has confirmed it, so pass `maxAgeMs: 0` to look
|
|
1376
|
+
* straight after one was submitted.
|
|
1377
|
+
*/
|
|
1378
|
+
findNftMintProxies(request: NftMintProxiesRequest): Promise<GeeqNftMintProxies>;
|
|
1379
|
+
/**
|
|
1380
|
+
* Create a proxy to mint NFTs through.
|
|
1381
|
+
*
|
|
1382
|
+
* A proxy is a record of its own: it holds coin, carries its own nonce, and names one
|
|
1383
|
+
* admin — `admin` here — who signs every mint made through it. Its id is derived from
|
|
1384
|
+
* the admin's key and an index, as the Geeq wallet derives it: by default the next
|
|
1385
|
+
* index {@link findNftMintProxies} reports, so it is found again from the key alone.
|
|
1386
|
+
*
|
|
1387
|
+
* Checks the funding against the chain's minimum, and the admin's balance against the
|
|
1388
|
+
* funding plus the fee. The result is **not submitted** — track it, then post it with
|
|
1389
|
+
* `coinTransferSubmitBody`, exactly as a transfer. The proxy exists once a block
|
|
1390
|
+
* confirms it.
|
|
1391
|
+
*/
|
|
1392
|
+
createNftMintProxy(input: NftMintProxyRequest): Promise<NftMintProxyTx>;
|
|
1393
|
+
/**
|
|
1394
|
+
* Mint an NFT through one of the admin's proxies.
|
|
1395
|
+
*
|
|
1396
|
+
* The proxy is the sender: it pays the fee and the coin sent with the NFT, and spends
|
|
1397
|
+
* its own nonce, not the admin's. The admin signs. The NFT itself is the content's hash
|
|
1398
|
+
* and labels, as an attestation is, and its id is derived from them — so the same
|
|
1399
|
+
* content with the same labels through the same proxy cannot be minted twice.
|
|
1400
|
+
*
|
|
1401
|
+
* Reads the ledger to find the proxy and check what it holds. The result is **not
|
|
1402
|
+
* submitted** — track it, then post it with `attestationSubmitBody`, exactly as an
|
|
1403
|
+
* attestation: two fields, as `uat`.
|
|
1404
|
+
*/
|
|
1405
|
+
mintNft(input: NftMintRequest): Promise<NftMintTx>;
|
|
1406
|
+
/**
|
|
1407
|
+
* Whether a built transaction is now too old to send: the chain is past its
|
|
1408
|
+
* `validUntilBlock`, and a node would refuse it with an HTTP 400.
|
|
1409
|
+
*
|
|
1410
|
+
* Reads the ledger afresh, because a cached one can only be behind the chain and would
|
|
1411
|
+
* say "not yet" when it already is. Call it before submitting a transaction that may
|
|
1412
|
+
* have waited.
|
|
1413
|
+
*/
|
|
1414
|
+
isExpired(tx: {
|
|
1415
|
+
readonly validUntilBlock: number;
|
|
1416
|
+
}): Promise<boolean>;
|
|
1417
|
+
/**
|
|
1418
|
+
* Give back the nonce a built transaction took, because it will never be sent — the
|
|
1419
|
+
* user changed something and is building again. The next build may then take the same
|
|
1420
|
+
* nonce in the same block instead of being refused with `nonce-collision`.
|
|
1421
|
+
*
|
|
1422
|
+
* Only for a transaction that was not submitted: if it reaches the node as well as its
|
|
1423
|
+
* rebuild, the two share a nonce and the node rejects both.
|
|
1424
|
+
*/
|
|
1425
|
+
discard(tx: {
|
|
1426
|
+
readonly transactionHash: Uint8Array;
|
|
1427
|
+
}): void;
|
|
1428
|
+
/** Forget which accounts have built a transaction against the current block. */
|
|
1429
|
+
forgetNonces(): void;
|
|
1430
|
+
/** Drop cached state, and step down as the default if this chain holds that slot. */
|
|
1431
|
+
dispose(): void;
|
|
1432
|
+
toJSON(): Record<string, unknown>;
|
|
1433
|
+
toString(): string;
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* Connect to a chain and make it the default.
|
|
1437
|
+
*
|
|
1438
|
+
* Thin alias for {@link GeeqChain.init} — the name most applications reach for, and one
|
|
1439
|
+
* line so there is no second implementation to keep in step.
|
|
1440
|
+
*
|
|
1441
|
+
* ```ts
|
|
1442
|
+
* await initChain({ endpoint: 'https://1.2.3.4:2082' })
|
|
1443
|
+
* const tx = await attest({ keypair, content: fileBytes })
|
|
1444
|
+
* ```
|
|
1445
|
+
*/
|
|
1446
|
+
declare function initChain(options: GeeqChainOptions): Promise<GeeqChain>;
|
|
1447
|
+
/** Build an attestation on the default chain. See {@link GeeqChain.createAttestation}. */
|
|
1448
|
+
declare function attest(input: AttestationRequest): Promise<AttestationTx>;
|
|
1449
|
+
/** Send coin on the default chain. See {@link GeeqChain.createTransfer}. */
|
|
1450
|
+
declare function transfer(input: CoinTransferRequest): Promise<CoinTransferTx>;
|
|
1451
|
+
|
|
1452
|
+
/**
|
|
1453
|
+
* The port every Geeq node answers client traffic on.
|
|
1454
|
+
*
|
|
1455
|
+
* Nodes terminate TLS on 2082 and that is the only client-facing port; an endpoint
|
|
1456
|
+
* given without one is resolved to it rather than to the scheme's default, because a
|
|
1457
|
+
* request to 443 would fail opaquely in a browser with no way to tell why.
|
|
1458
|
+
*/
|
|
1459
|
+
declare const GEEQ_NODE_PORT = 2082;
|
|
1460
|
+
interface SelectNodeOptions {
|
|
1461
|
+
/** Skip host matching entirely. Required behind a gateway or a DNS name. */
|
|
1462
|
+
readonly nodeNumber?: number | undefined;
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* Choose the net actor record that a transaction should name.
|
|
1466
|
+
*
|
|
1467
|
+
* Matching is on **host only**. A record's `port` is the node's own listen port, while
|
|
1468
|
+
* a client reaches it through a proxy on another one, so requiring both to agree finds
|
|
1469
|
+
* nothing on a correctly deployed chain. Port is used solely to disambiguate when one
|
|
1470
|
+
* address carries several records.
|
|
1471
|
+
*
|
|
1472
|
+
* This never silently retargets. A different node means a different address, a
|
|
1473
|
+
* different certificate, a different CORS origin and a different operator seeing the
|
|
1474
|
+
* transaction, so an unusable node is reported with its alternatives and the caller
|
|
1475
|
+
* decides.
|
|
1476
|
+
*/
|
|
1477
|
+
declare function selectNode(ledger: GeeqLedger, endpoint: string | URL, options?: SelectNodeOptions): GeeqLedgerNode;
|
|
1478
|
+
|
|
1479
|
+
/**
|
|
1480
|
+
* Every node route the SDK knows, in one place.
|
|
1481
|
+
*
|
|
1482
|
+
* `origin` is an absolute node URL with no trailing slash — see `originOf`.
|
|
1483
|
+
*/
|
|
1484
|
+
/** `GET` the current validation layer ledger, base64 packed capnp under `result`. */
|
|
1485
|
+
declare function ledgerRoute(origin: string): string;
|
|
1486
|
+
/**
|
|
1487
|
+
* Where a signed transaction is POSTed.
|
|
1488
|
+
*
|
|
1489
|
+
* The SDK does not submit — this is exported so an application builds the same URL the
|
|
1490
|
+
* SDK read from, rather than keeping its own copy of the path.
|
|
1491
|
+
*/
|
|
1492
|
+
declare function submitRoute(origin: string): string;
|
|
1493
|
+
/**
|
|
1494
|
+
* The node's client WebSocket, where transaction status events arrive.
|
|
1495
|
+
*
|
|
1496
|
+
* Same host and port as the HTTP API — the node's TLS front door routes `/ws/` to the
|
|
1497
|
+
* socket server and `/api/` to the HTTP one — so the only change is the scheme. The
|
|
1498
|
+
* trailing slash is part of the route: the proxy answers `/ws` with a redirect, and a
|
|
1499
|
+
* WebSocket handshake treats a redirect as failure.
|
|
1500
|
+
*/
|
|
1501
|
+
declare function socketRoute(origin: string): string;
|
|
1502
|
+
/**
|
|
1503
|
+
* The body a node expects for an application-layer transaction: an attestation or an NFT
|
|
1504
|
+
* mint, each a transaction and its payload.
|
|
1505
|
+
*/
|
|
1506
|
+
declare function attestationSubmitBody(transaction: string, payload: string): string;
|
|
1507
|
+
/**
|
|
1508
|
+
* The body a node expects for a coin transfer.
|
|
1509
|
+
*
|
|
1510
|
+
* A different type and a different shape from an attestation: a validation-layer
|
|
1511
|
+
* transaction carries no separate payload, so there is one blob rather than two.
|
|
1512
|
+
*/
|
|
1513
|
+
declare function coinTransferSubmitBody(transaction: string): string;
|
|
1514
|
+
|
|
1515
|
+
/** A transaction as a block explorer reports it, field for field. */
|
|
1516
|
+
interface GeeqExplorerTransaction {
|
|
1517
|
+
/** Hex — the form the explorer files transactions under. */
|
|
1518
|
+
readonly refHash: string;
|
|
1519
|
+
/** The transaction's kind, such as `coin`. */
|
|
1520
|
+
readonly type: string;
|
|
1521
|
+
/** The explorer's verdict on it. */
|
|
1522
|
+
readonly status: string;
|
|
1523
|
+
readonly block: number;
|
|
1524
|
+
readonly chainName: string;
|
|
1525
|
+
readonly chainNumber: number;
|
|
1526
|
+
/** The sender's wallet address. */
|
|
1527
|
+
readonly from: string;
|
|
1528
|
+
readonly senderType: string;
|
|
1529
|
+
/** The receiver's wallet address, or empty when it has none. */
|
|
1530
|
+
readonly to: string;
|
|
1531
|
+
readonly receiverType: string;
|
|
1532
|
+
readonly publicKey: string;
|
|
1533
|
+
readonly signature: string;
|
|
1534
|
+
readonly createdAt: string;
|
|
1535
|
+
readonly fee: string;
|
|
1536
|
+
readonly acctNumApp?: string;
|
|
1537
|
+
/** What it moved — coin, tokens, NFTs — with amounts as decimal strings. */
|
|
1538
|
+
readonly values: readonly {
|
|
1539
|
+
readonly type: string;
|
|
1540
|
+
readonly value: string;
|
|
1541
|
+
readonly name?: string;
|
|
1542
|
+
}[];
|
|
1543
|
+
/** An attestation's hash and metadata. */
|
|
1544
|
+
readonly payload?: {
|
|
1545
|
+
readonly attestationHash: string;
|
|
1546
|
+
readonly metadata: readonly string[];
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
interface ExplorerTransactionRequest {
|
|
1550
|
+
/** The explorer's base URL, such as `https://blkexp.geeq-test.io`. */
|
|
1551
|
+
readonly explorerUrl: string | URL;
|
|
1552
|
+
/**
|
|
1553
|
+
* The transaction's refHash in base64 — what `transactionIdOf(tx)` returns and socket
|
|
1554
|
+
* status events carry. It is sent to the explorer as hex.
|
|
1555
|
+
*/
|
|
1556
|
+
readonly refHash: string;
|
|
1557
|
+
/** Defaults to `globalThis.fetch`. */
|
|
1558
|
+
readonly transport?: GeeqTransport;
|
|
1559
|
+
/** Defaults to 10000. */
|
|
1560
|
+
readonly timeoutMs?: number;
|
|
1561
|
+
readonly signal?: AbortSignal;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Look a transaction up in a block explorer by its refHash.
|
|
1565
|
+
*
|
|
1566
|
+
* Resolves `null` when the explorer does not have it — not indexed yet, or never put in a
|
|
1567
|
+
* block. The explorer only knows a transaction once a block has decided it, so for one
|
|
1568
|
+
* you have just sent, the node socket answers first.
|
|
1569
|
+
*/
|
|
1570
|
+
declare function getExplorerTransaction(request: ExplorerTransactionRequest): Promise<GeeqExplorerTransaction | null>;
|
|
1571
|
+
|
|
1572
|
+
/** What a WebSocket hands its `message` listeners, narrowed to the one field read. */
|
|
1573
|
+
interface GeeqWebSocketMessageEvent {
|
|
1574
|
+
readonly data: unknown;
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* A WebSocket, narrowed to what this SDK uses.
|
|
1578
|
+
*
|
|
1579
|
+
* Deliberately structural, like {@link GeeqTransport}: a browser `WebSocket`, Node 22's
|
|
1580
|
+
* global one and the `ws` package's class all satisfy it with no adapter, and so does a
|
|
1581
|
+
* scripted fake in a test. Listeners are attached with `addEventListener` rather than
|
|
1582
|
+
* `onmessage` and friends because a method is compared bivariantly, which is what lets
|
|
1583
|
+
* each implementation's own event types through.
|
|
1584
|
+
*/
|
|
1585
|
+
interface GeeqWebSocketLike {
|
|
1586
|
+
readonly readyState: number;
|
|
1587
|
+
send(data: string): void;
|
|
1588
|
+
close(code?: number, reason?: string): void;
|
|
1589
|
+
addEventListener(type: 'open', listener: (event: unknown) => void): void;
|
|
1590
|
+
addEventListener(type: 'message', listener: (event: GeeqWebSocketMessageEvent) => void): void;
|
|
1591
|
+
addEventListener(type: 'close', listener: (event: unknown) => void): void;
|
|
1592
|
+
addEventListener(type: 'error', listener: (event: unknown) => void): void;
|
|
1593
|
+
}
|
|
1594
|
+
/**
|
|
1595
|
+
* How the SDK opens a socket.
|
|
1596
|
+
*
|
|
1597
|
+
* `(url) => new WebSocket(url)` is the whole contract. Pass one to use the `ws` package on
|
|
1598
|
+
* Node 20, to add headers or a TLS agent there, or to script a connection in a test.
|
|
1599
|
+
*/
|
|
1600
|
+
type GeeqWebSocketFactory = (url: string) => GeeqWebSocketLike;
|
|
1601
|
+
/**
|
|
1602
|
+
* `new globalThis.WebSocket(url)`, resolved at call time.
|
|
1603
|
+
*
|
|
1604
|
+
* Never a stored reference, for the same reason as `defaultTransport`: a test that swaps
|
|
1605
|
+
* the global after import must still be honoured. Node 20 has no global WebSocket at all,
|
|
1606
|
+
* and a library that supports Node 20 cannot assume one, so its absence is reported with
|
|
1607
|
+
* the one-line fix rather than as a `TypeError`.
|
|
1608
|
+
*/
|
|
1609
|
+
declare const defaultWebSocketFactory: GeeqWebSocketFactory;
|
|
1610
|
+
|
|
1611
|
+
/**
|
|
1612
|
+
* The four verdicts a node reports for a transaction, by their protocol names.
|
|
1613
|
+
*
|
|
1614
|
+
* - `valid` — committed in a block. Final.
|
|
1615
|
+
* - `invalid` — placed in a block's invalid list, typically a nonce or solvency failure
|
|
1616
|
+
* found at commit. Final, and **the sender is still charged the fee**.
|
|
1617
|
+
* - `incorrectlyIncluded` — carried by a node the chain judged dishonest. Final; not the
|
|
1618
|
+
* sender's fault.
|
|
1619
|
+
* - `nonsane` — refused by the receiving node, at intake (alongside an HTTP 400) or at block
|
|
1620
|
+
* selection (after a 200). The node drops it, so it is final in practice — but a node
|
|
1621
|
+
* restarting can carry its buffer forward, and then a later verdict follows.
|
|
1622
|
+
*
|
|
1623
|
+
* From geeq_node_core `UutStatuses` (actors/interfaces.ts).
|
|
1624
|
+
*/
|
|
1625
|
+
type GeeqTxVerdict = 'nonsane' | 'incorrectlyIncluded' | 'invalid' | 'valid';
|
|
1626
|
+
/**
|
|
1627
|
+
* One `uut_status` event, normalised.
|
|
1628
|
+
*
|
|
1629
|
+
* Every field is what the node sent, renamed only where the wire name misleads. Nothing
|
|
1630
|
+
* is inferred: in particular `vlbBlock` is passed through as reported and not treated as
|
|
1631
|
+
* the inclusion block, because on current nodes it is one ahead of it for `valid` and
|
|
1632
|
+
* `invalid` events.
|
|
1633
|
+
*/
|
|
1634
|
+
interface GeeqTxStatusEvent {
|
|
1635
|
+
/**
|
|
1636
|
+
* The transaction's refHash, standard base64 — compare it with `transactionIdOf(tx)`.
|
|
1637
|
+
* Always the transaction hash, never the payload hash.
|
|
1638
|
+
*/
|
|
1639
|
+
readonly id: string;
|
|
1640
|
+
readonly verdict: GeeqTxVerdict;
|
|
1641
|
+
/** The node's own boolean: true exactly when `verdict` is `valid`. */
|
|
1642
|
+
readonly isValid: boolean;
|
|
1643
|
+
/** The node's reason, verbatim. Empty when valid. Show it; never parse it. */
|
|
1644
|
+
readonly error: string | undefined;
|
|
1645
|
+
/** The transaction's own target block, as the node reports it. */
|
|
1646
|
+
readonly blockNumber: number | undefined;
|
|
1647
|
+
/** The node's `vlbBlock`, as reported. See the note above before relying on it. */
|
|
1648
|
+
readonly vlbBlock: number | undefined;
|
|
1649
|
+
/**
|
|
1650
|
+
* `outgoing` on the sender's copy, `incoming` on the receiver's, when the node says —
|
|
1651
|
+
* older nodes do not. Do not use it to tell your own transactions apart: match on
|
|
1652
|
+
* {@link id} instead.
|
|
1653
|
+
*/
|
|
1654
|
+
readonly direction: 'incoming' | 'outgoing' | undefined;
|
|
1655
|
+
/** The signer's base64 public key. */
|
|
1656
|
+
readonly signer: string | undefined;
|
|
1657
|
+
/** When the node stamped it. Second precision. */
|
|
1658
|
+
readonly createdAt: Date | undefined;
|
|
1659
|
+
/** The event's payload exactly as it arrived, for logging and support. */
|
|
1660
|
+
readonly raw: unknown;
|
|
1661
|
+
}
|
|
1662
|
+
/**
|
|
1663
|
+
* A transaction's id as status events name it: its `transactionHash`, in base64.
|
|
1664
|
+
*
|
|
1665
|
+
* Works on anything the SDK builds — an attestation or a transfer — because each already
|
|
1666
|
+
* carries the hash its kind is identified by, and the two kinds are hashed differently.
|
|
1667
|
+
*/
|
|
1668
|
+
declare function transactionIdOf(tx: {
|
|
1669
|
+
readonly transactionHash: Uint8Array;
|
|
1670
|
+
}): string;
|
|
1671
|
+
|
|
1672
|
+
/** The node committed it. */
|
|
1673
|
+
interface GeeqTxConfirmed {
|
|
1674
|
+
readonly status: 'confirmed';
|
|
1675
|
+
readonly id: string;
|
|
1676
|
+
/** The `valid` event that settled it. */
|
|
1677
|
+
readonly event: GeeqTxStatusEvent;
|
|
1678
|
+
readonly at: Date;
|
|
1679
|
+
}
|
|
1680
|
+
/**
|
|
1681
|
+
* Why a transaction was rejected. Branch on this, never on {@link GeeqTxRejected.message}.
|
|
1682
|
+
*
|
|
1683
|
+
* - `invalid` — found wrong at commit, usually the nonce or the balance. The fee is still
|
|
1684
|
+
* charged.
|
|
1685
|
+
* - `incorrectly-included` — carried by a node the chain judged dishonest. Not your fault.
|
|
1686
|
+
* - `nonsane` — the receiving node refused it and dropped it.
|
|
1687
|
+
* - `refused` — the node answered the submission with an error status. It never entered
|
|
1688
|
+
* a block and will produce no status event.
|
|
1689
|
+
*/
|
|
1690
|
+
type GeeqTxRejectionReason = 'invalid' | 'incorrectly-included' | 'nonsane' | 'refused';
|
|
1691
|
+
interface GeeqTxRejected {
|
|
1692
|
+
readonly status: 'rejected';
|
|
1693
|
+
readonly id: string;
|
|
1694
|
+
readonly reason: GeeqTxRejectionReason;
|
|
1695
|
+
/** The node's own words when it gave any. For display and support — never parse it. */
|
|
1696
|
+
readonly message: string;
|
|
1697
|
+
/** The event that settled it. Undefined for a `refused` submission the socket never saw. */
|
|
1698
|
+
readonly event: GeeqTxStatusEvent | undefined;
|
|
1699
|
+
/** The HTTP status of a `refused` submission, when the caller reported one. */
|
|
1700
|
+
readonly httpStatus: number | undefined;
|
|
1701
|
+
readonly at: Date;
|
|
1702
|
+
}
|
|
1703
|
+
/**
|
|
1704
|
+
* No verdict, and none is coming to this handle.
|
|
1705
|
+
*
|
|
1706
|
+
* - `timeout` — nothing final arrived in time. **This is not a rejection**: statuses sent
|
|
1707
|
+
* while the socket was reconnecting are lost, so it may well have settled. Read the
|
|
1708
|
+
* ledger (has the account's nonce moved on?) before sending it again.
|
|
1709
|
+
* - `closed` — the socket was disposed while it was pending.
|
|
1710
|
+
* - `released` — the caller stopped tracking it.
|
|
1711
|
+
*/
|
|
1712
|
+
type GeeqTxUnknownReason = 'timeout' | 'closed' | 'released';
|
|
1713
|
+
interface GeeqTxUnknown {
|
|
1714
|
+
readonly status: 'unknown';
|
|
1715
|
+
readonly id: string;
|
|
1716
|
+
readonly reason: GeeqTxUnknownReason;
|
|
1717
|
+
readonly message: string;
|
|
1718
|
+
readonly at: Date;
|
|
1719
|
+
}
|
|
1720
|
+
type GeeqTxOutcome = GeeqTxConfirmed | GeeqTxRejected | GeeqTxUnknown;
|
|
1721
|
+
/** `pending` until an outcome, then the outcome's own status. Never goes back. */
|
|
1722
|
+
type GeeqTxState = 'pending' | GeeqTxOutcome['status'];
|
|
1723
|
+
/** What a submission refusal looked like, for {@link GeeqTrackedTx.refused}. */
|
|
1724
|
+
interface GeeqTxRefusal {
|
|
1725
|
+
/** The HTTP status the node answered with. */
|
|
1726
|
+
readonly status?: number;
|
|
1727
|
+
/** The node's `details`, or the body — whatever it said. */
|
|
1728
|
+
readonly message?: string;
|
|
1729
|
+
}
|
|
1730
|
+
/** @internal */
|
|
1731
|
+
interface TrackedTxInit {
|
|
1732
|
+
readonly id: string;
|
|
1733
|
+
readonly timeoutMs: number;
|
|
1734
|
+
readonly nonsaneGraceMs: number;
|
|
1735
|
+
/** Called once, when it settles — the socket drops it from its table. */
|
|
1736
|
+
readonly detach: () => void;
|
|
1737
|
+
}
|
|
1738
|
+
/**
|
|
1739
|
+
* One submitted transaction, followed to its verdict.
|
|
1740
|
+
*
|
|
1741
|
+
* Returned by {@link GeeqSocket.track}. It collapses the node's four verdicts, some of
|
|
1742
|
+
* which arrive more than once and one of which is only usually final, into one of three
|
|
1743
|
+
* outcomes an application can branch on — and it never rejects, because a rejected
|
|
1744
|
+
* transaction is an answer, not a failure:
|
|
1745
|
+
*
|
|
1746
|
+
* ```ts
|
|
1747
|
+
* const outcome = await tracked.settled()
|
|
1748
|
+
* if (outcome.status === 'confirmed') …
|
|
1749
|
+
* else if (outcome.status === 'rejected') show(outcome.reason, outcome.message)
|
|
1750
|
+
* else checkLedgerBeforeRetrying() // 'unknown'
|
|
1751
|
+
* ```
|
|
1752
|
+
*
|
|
1753
|
+
* In a reactive framework, keep it raw (Vue's `markRaw`) and re-read `status` and
|
|
1754
|
+
* `events` from {@link onChange}.
|
|
1755
|
+
*/
|
|
1756
|
+
declare class GeeqTrackedTx {
|
|
1757
|
+
/** The transaction's refHash, base64 — the same string status events carry. */
|
|
1758
|
+
readonly id: string;
|
|
1759
|
+
private readonly received;
|
|
1760
|
+
private readonly listeners;
|
|
1761
|
+
private readonly nonsaneGraceMs;
|
|
1762
|
+
private readonly detach;
|
|
1763
|
+
private readonly promise;
|
|
1764
|
+
private readonly resolve;
|
|
1765
|
+
private current;
|
|
1766
|
+
private deadline;
|
|
1767
|
+
private grace;
|
|
1768
|
+
/** @internal */
|
|
1769
|
+
constructor(init: TrackedTxInit);
|
|
1770
|
+
/** `pending`, then `confirmed`, `rejected` or `unknown` — once, and for good. */
|
|
1771
|
+
get status(): GeeqTxState;
|
|
1772
|
+
/** The outcome, once there is one. */
|
|
1773
|
+
get outcome(): GeeqTxOutcome | undefined;
|
|
1774
|
+
/** Every status event received for this transaction, oldest first. */
|
|
1775
|
+
get events(): readonly GeeqTxStatusEvent[];
|
|
1776
|
+
/** Resolves with the outcome. Never rejects — see the class notes. */
|
|
1777
|
+
settled(): Promise<GeeqTxOutcome>;
|
|
1778
|
+
/**
|
|
1779
|
+
* Call `listener` whenever an event arrives for this transaction or it settles.
|
|
1780
|
+
*
|
|
1781
|
+
* Returns the function that removes it. Read {@link status}, {@link events} and
|
|
1782
|
+
* {@link outcome} inside; they are already up to date.
|
|
1783
|
+
*/
|
|
1784
|
+
onChange(listener: (tx: GeeqTrackedTx) => void): () => void;
|
|
1785
|
+
/**
|
|
1786
|
+
* Report that the node refused the submission — answered it with an error status.
|
|
1787
|
+
*
|
|
1788
|
+
* Settles it `rejected` at once. A refused transaction never reaches a block, so no
|
|
1789
|
+
* status event would ever arrive to settle it, and waiting would only turn a clear
|
|
1790
|
+
* answer into a timeout. Do **not** call this when the POST failed to arrive at all
|
|
1791
|
+
* (a network error): the node may have it, so leave it tracked.
|
|
1792
|
+
*/
|
|
1793
|
+
refused(refusal?: GeeqTxRefusal): void;
|
|
1794
|
+
/** Stop tracking. Settles `unknown` with reason `released` if it was still pending. */
|
|
1795
|
+
release(): void;
|
|
1796
|
+
/** @internal Settle as unknown because the socket is going away, or on release. */
|
|
1797
|
+
abandon(reason: 'closed' | 'released', message: string): void;
|
|
1798
|
+
/**
|
|
1799
|
+
* @internal Take one status event for this transaction.
|
|
1800
|
+
*
|
|
1801
|
+
* The only place the protocol's rules live. First-event-wins would report false
|
|
1802
|
+
* failures: a `nonsane` can be followed by a real verdict when a node carries its buffer
|
|
1803
|
+
* over a restart, so it only settles if nothing final follows within the grace window.
|
|
1804
|
+
* Everything after the outcome — a second node's copy, a duplicate — is ignored.
|
|
1805
|
+
*/
|
|
1806
|
+
receive(event: GeeqTxStatusEvent): void;
|
|
1807
|
+
private finish;
|
|
1808
|
+
private notify;
|
|
1809
|
+
toJSON(): Record<string, unknown>;
|
|
1810
|
+
toString(): string;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
/**
|
|
1814
|
+
* - `connecting` — the first handshake, inside {@link GeeqSocket.connect}.
|
|
1815
|
+
* - `open` — subscribed and receiving.
|
|
1816
|
+
* - `reconnecting` — dropped after being open; retrying with backoff. Anything the node
|
|
1817
|
+
* sends meanwhile is lost.
|
|
1818
|
+
* - `closed` — disposed. Final.
|
|
1819
|
+
*/
|
|
1820
|
+
type GeeqSocketState = 'connecting' | 'open' | 'reconnecting' | 'closed';
|
|
1821
|
+
/** One JSON frame from the node, as `{ event, payload }`. */
|
|
1822
|
+
interface GeeqSocketMessage {
|
|
1823
|
+
readonly event: string;
|
|
1824
|
+
readonly payload: unknown;
|
|
1825
|
+
}
|
|
1826
|
+
interface GeeqSocketOptions {
|
|
1827
|
+
/**
|
|
1828
|
+
* The node the socket belongs to — normally `chain.endpoint`, which is also where the
|
|
1829
|
+
* transactions go. Its socket is derived: `https://ip:2082` becomes
|
|
1830
|
+
* `wss://ip:2082/ws/`.
|
|
1831
|
+
*
|
|
1832
|
+
* Supply this or {@link url}, not both. Use the node you submit to: only that node
|
|
1833
|
+
* reports a `nonsane` refusal, though every node reports the final verdicts.
|
|
1834
|
+
*/
|
|
1835
|
+
readonly endpoint?: string | URL;
|
|
1836
|
+
/**
|
|
1837
|
+
* The socket URL itself, when it is not the one derived from the node — a local
|
|
1838
|
+
* harness reaching the socket server directly on its own port, for instance.
|
|
1839
|
+
*/
|
|
1840
|
+
readonly url?: string | URL;
|
|
1841
|
+
/** Defaults to `new globalThis.WebSocket(url)`. Supply one on Node 20 — see README. */
|
|
1842
|
+
readonly webSocket?: GeeqWebSocketFactory;
|
|
1843
|
+
/**
|
|
1844
|
+
* How long a handshake, or a send waiting on one, may take. Defaults to 15000. 0 waits
|
|
1845
|
+
* for ever — including a first handshake that neither opens nor fails.
|
|
1846
|
+
*/
|
|
1847
|
+
readonly openTimeoutMs?: number;
|
|
1848
|
+
/** How often to send the keepalive `'ping'`. Defaults to 25000; 0 disables it. */
|
|
1849
|
+
readonly heartbeatMs?: number;
|
|
1850
|
+
/** Reconnect after a drop. Defaults to true. */
|
|
1851
|
+
readonly reconnect?: boolean;
|
|
1852
|
+
/** The first reconnect delay, doubled on each failure. Defaults to 1000. */
|
|
1853
|
+
readonly reconnectDelayMs?: number;
|
|
1854
|
+
/** The ceiling on that delay. Defaults to 30000. */
|
|
1855
|
+
readonly maxReconnectDelayMs?: number;
|
|
1856
|
+
/** Abandons the first handshake. Once connected, use {@link GeeqSocket.dispose}. */
|
|
1857
|
+
readonly signal?: AbortSignal;
|
|
1858
|
+
}
|
|
1859
|
+
interface GeeqSendOptions {
|
|
1860
|
+
/**
|
|
1861
|
+
* Re-send the frame on every reconnect. A node forgets a connection's subscriptions
|
|
1862
|
+
* when it drops, so anything that subscribes should set this. Only the latest frame for
|
|
1863
|
+
* each event name is kept.
|
|
1864
|
+
*/
|
|
1865
|
+
readonly replay?: boolean;
|
|
1866
|
+
}
|
|
1867
|
+
interface GeeqListenOptions {
|
|
1868
|
+
readonly blockNumber?: number;
|
|
1869
|
+
/** Defaults to true. */
|
|
1870
|
+
readonly now?: boolean;
|
|
1871
|
+
}
|
|
1872
|
+
interface GeeqTrackOptions {
|
|
1873
|
+
/** How long to wait for a final status. Defaults to 300000. 0 waits for ever. */
|
|
1874
|
+
readonly timeoutMs?: number;
|
|
1875
|
+
/** How long a `nonsane` may be overturned by a real verdict. Defaults to 30000. */
|
|
1876
|
+
readonly nonsaneGraceMs?: number;
|
|
1877
|
+
/** More accounts to subscribe alongside the signer. */
|
|
1878
|
+
readonly accounts?: readonly (AccountRef | string)[];
|
|
1879
|
+
}
|
|
1880
|
+
/**
|
|
1881
|
+
* Anything with the hash a status event names. Every transaction this SDK builds fits,
|
|
1882
|
+
* and brings its signer's `publicKey` for the subscription.
|
|
1883
|
+
*/
|
|
1884
|
+
interface GeeqTrackable {
|
|
1885
|
+
readonly transactionHash: Uint8Array;
|
|
1886
|
+
readonly publicKey?: Uint8Array;
|
|
1887
|
+
}
|
|
1888
|
+
/**
|
|
1889
|
+
* A node's WebSocket: the channel through which it reports what happened to the
|
|
1890
|
+
* transactions you sent, and pushes account and chain updates.
|
|
1891
|
+
*
|
|
1892
|
+
* One class for every use an application has for the socket:
|
|
1893
|
+
*
|
|
1894
|
+
* - {@link track} a transaction you are about to submit, and get its verdict;
|
|
1895
|
+
* - {@link subscribe} to accounts and read their events with {@link on};
|
|
1896
|
+
* - {@link send} any frame the node understands, and receive any it sends.
|
|
1897
|
+
*
|
|
1898
|
+
* The protocol's hazards are handled here, once: subscriptions replace rather than add,
|
|
1899
|
+
* so the full set of keys is always sent; the node forgets a connection's subscriptions
|
|
1900
|
+
* when it drops, so they are replayed on every reconnect before anything is announced;
|
|
1901
|
+
* the edge proxy drops an idle socket, so it is kept alive; a transaction's first status
|
|
1902
|
+
* is not always its last, so {@link GeeqTrackedTx} decides when it is final.
|
|
1903
|
+
*
|
|
1904
|
+
* ```ts
|
|
1905
|
+
* const socket = await GeeqSocket.connect({ endpoint: chain.endpoint })
|
|
1906
|
+
* const tx = await chain.createTransfer({ from, to, amount })
|
|
1907
|
+
* const tracked = await socket.track(tx) // before submitting — always
|
|
1908
|
+
* const response = await fetch(submitRoute(tx.nodeUrl), { … })
|
|
1909
|
+
* if (!response.ok) tracked.refused({ status: response.status })
|
|
1910
|
+
* const outcome = await tracked.settled()
|
|
1911
|
+
* ```
|
|
1912
|
+
*
|
|
1913
|
+
* In a reactive framework, mark an instance raw (Vue's `markRaw`) rather than letting it
|
|
1914
|
+
* be proxied — a proxied native WebSocket throws on every call.
|
|
1915
|
+
*/
|
|
1916
|
+
declare class GeeqSocket {
|
|
1917
|
+
/** The socket URL, normalised. */
|
|
1918
|
+
readonly url: string;
|
|
1919
|
+
private readonly factory;
|
|
1920
|
+
private readonly openTimeoutMs;
|
|
1921
|
+
private readonly heartbeatMs;
|
|
1922
|
+
private readonly reconnects;
|
|
1923
|
+
private readonly reconnectDelayMs;
|
|
1924
|
+
private readonly maxReconnectDelayMs;
|
|
1925
|
+
/** The frames in force, by event name, replayed on every connection. */
|
|
1926
|
+
private readonly persisted;
|
|
1927
|
+
/** What this connection has already been told, so a repeat is not sent twice. */
|
|
1928
|
+
private readonly told;
|
|
1929
|
+
private readonly keys;
|
|
1930
|
+
private readonly tracked;
|
|
1931
|
+
private readonly eventListeners;
|
|
1932
|
+
private readonly messageListeners;
|
|
1933
|
+
private readonly statusListeners;
|
|
1934
|
+
private readonly stateListeners;
|
|
1935
|
+
private readonly waiters;
|
|
1936
|
+
private socket;
|
|
1937
|
+
private current;
|
|
1938
|
+
private everOpened;
|
|
1939
|
+
private attempts;
|
|
1940
|
+
private openTimer;
|
|
1941
|
+
private reconnectTimer;
|
|
1942
|
+
private heartbeatTimer;
|
|
1943
|
+
/** @internal */
|
|
1944
|
+
constructor(init: {
|
|
1945
|
+
url: string;
|
|
1946
|
+
factory: GeeqWebSocketFactory;
|
|
1947
|
+
openTimeoutMs: number;
|
|
1948
|
+
heartbeatMs: number;
|
|
1949
|
+
reconnect: boolean;
|
|
1950
|
+
reconnectDelayMs: number;
|
|
1951
|
+
maxReconnectDelayMs: number;
|
|
1952
|
+
});
|
|
1953
|
+
/**
|
|
1954
|
+
* Open a node's socket and resolve once it is open.
|
|
1955
|
+
*
|
|
1956
|
+
* Throws `socket-unreachable` if the first handshake fails, rather than retrying
|
|
1957
|
+
* quietly: a socket that never opened is almost always a certificate, a mixed-content
|
|
1958
|
+
* page or a wrong URL, and retrying hides which. After that first open, a drop is
|
|
1959
|
+
* retried automatically and reported through {@link onConnectionChange}.
|
|
1960
|
+
*/
|
|
1961
|
+
static connect(options: GeeqSocketOptions): Promise<GeeqSocket>;
|
|
1962
|
+
/** Where the connection stands. See {@link GeeqSocketState}. */
|
|
1963
|
+
get state(): GeeqSocketState;
|
|
1964
|
+
/** Every account key subscribed so far, base64. The set only grows. */
|
|
1965
|
+
get subscriptions(): readonly string[];
|
|
1966
|
+
/**
|
|
1967
|
+
* Subscribe to accounts' events: their transactions' statuses and record updates.
|
|
1968
|
+
*
|
|
1969
|
+
* Takes a keypair, a `{ publicKey }`, a 32-byte account id, a base64 key, or a list of
|
|
1970
|
+
* them. The node has no unsubscribe and treats every subscription as a replacement, so
|
|
1971
|
+
* this adds to the set this socket holds and sends all of it — calling it for one
|
|
1972
|
+
* account never silences another. Resolves once the node has been told.
|
|
1973
|
+
*/
|
|
1974
|
+
subscribe(accounts: AccountRef | string | readonly (AccountRef | string)[]): Promise<void>;
|
|
1975
|
+
/** Ask for events from now, or from a block. Replayed on reconnect. */
|
|
1976
|
+
listen(options?: GeeqListenOptions): Promise<void>;
|
|
1977
|
+
/**
|
|
1978
|
+
* Subscribe to the whole chain's record feed — every account, fee and parameter update.
|
|
1979
|
+
* What a block explorer or an indexer wants; an ordinary application does not.
|
|
1980
|
+
*/
|
|
1981
|
+
subscribeBlockExplorer(): Promise<void>;
|
|
1982
|
+
/**
|
|
1983
|
+
* Send a frame, `{ event, payload }`, waiting for the connection if it is down.
|
|
1984
|
+
*
|
|
1985
|
+
* The escape hatch for anything the node understands that this class has no method
|
|
1986
|
+
* for. Rejects with `socket-unreachable` if the socket does not reopen within
|
|
1987
|
+
* `openTimeoutMs` — a replayed frame is still kept, and goes out when it does.
|
|
1988
|
+
*/
|
|
1989
|
+
send(event: string, payload?: unknown, options?: GeeqSendOptions): Promise<void>;
|
|
1990
|
+
/**
|
|
1991
|
+
* Follow a transaction to its verdict. Call it **before** submitting.
|
|
1992
|
+
*
|
|
1993
|
+
* Subscribes the signer — the node pushes a transaction's statuses only to connections
|
|
1994
|
+
* subscribed to its account — and resolves once the node has been told, so a status
|
|
1995
|
+
* cannot arrive before anyone is listening for it. If this throws, do not submit: a
|
|
1996
|
+
* transaction sent with no way to hear its verdict leaves the user guessing.
|
|
1997
|
+
*
|
|
1998
|
+
* Tracking the same transaction twice returns the same handle.
|
|
1999
|
+
*/
|
|
2000
|
+
track(tx: GeeqTrackable, options?: GeeqTrackOptions): Promise<GeeqTrackedTx>;
|
|
2001
|
+
/**
|
|
2002
|
+
* Call `listener` with the payload of every frame named `event`, whatever it is —
|
|
2003
|
+
* `'uut_status'`, `'coin-account-update'`, `'fee-update'`, or one this SDK has never
|
|
2004
|
+
* heard of. Returns the function that removes it.
|
|
2005
|
+
*/
|
|
2006
|
+
on(event: string, listener: (payload: unknown) => void): () => void;
|
|
2007
|
+
/** Call `listener` with every JSON frame the node sends. */
|
|
2008
|
+
onMessage(listener: (message: GeeqSocketMessage) => void): () => void;
|
|
2009
|
+
/** Call `listener` with every transaction status, tracked or not, already parsed. */
|
|
2010
|
+
onTxStatus(listener: (event: GeeqTxStatusEvent) => void): () => void;
|
|
2011
|
+
/** Call `listener` whenever {@link state} changes. */
|
|
2012
|
+
onConnectionChange(listener: (state: GeeqSocketState) => void): () => void;
|
|
2013
|
+
/**
|
|
2014
|
+
* Close for good. Pending sends reject with `socket-closed`, and every transaction still
|
|
2015
|
+
* being tracked settles `unknown` with reason `closed` — it may yet be decided, just
|
|
2016
|
+
* not heard about here.
|
|
2017
|
+
*/
|
|
2018
|
+
dispose(): void;
|
|
2019
|
+
toJSON(): Record<string, unknown>;
|
|
2020
|
+
toString(): string;
|
|
2021
|
+
private assertOpenable;
|
|
2022
|
+
private setState;
|
|
2023
|
+
/** Resolves when the socket is open, or rejects after `openTimeoutMs` or on dispose. */
|
|
2024
|
+
private whenOpen;
|
|
2025
|
+
private dial;
|
|
2026
|
+
private opened;
|
|
2027
|
+
/** A handshake failed, or an open socket dropped. */
|
|
2028
|
+
private attemptFailed;
|
|
2029
|
+
/**
|
|
2030
|
+
* Put one frame on the current connection. True once it is there — or already was.
|
|
2031
|
+
*
|
|
2032
|
+
* False means the connection is gone. If our books still said it was open, it is
|
|
2033
|
+
* treated as the drop it is, here and now, so the caller waits for the next connection
|
|
2034
|
+
* instead of spinning on this one.
|
|
2035
|
+
*/
|
|
2036
|
+
private transmit;
|
|
2037
|
+
private receive;
|
|
2038
|
+
private startHeartbeat;
|
|
2039
|
+
private stopHeartbeat;
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
/** What one metadata entry costs, and whether the chain would take it. */
|
|
2043
|
+
interface MetadataEntryReport {
|
|
2044
|
+
readonly index: number;
|
|
2045
|
+
/** Length once encoded as UTF-8, which is what the limit is measured in. */
|
|
2046
|
+
readonly bytes: number;
|
|
2047
|
+
readonly overLimit: boolean;
|
|
2048
|
+
}
|
|
2049
|
+
interface MetadataReport {
|
|
2050
|
+
readonly entries: readonly MetadataEntryReport[];
|
|
2051
|
+
readonly count: number;
|
|
2052
|
+
readonly tooManyEntries: boolean;
|
|
2053
|
+
readonly withinLimits: boolean;
|
|
2054
|
+
/** Undefined when the chain publishes no limits, in which case nothing is checked. */
|
|
2055
|
+
readonly limits: GeeqMetadataLimits | undefined;
|
|
2056
|
+
}
|
|
2057
|
+
/**
|
|
2058
|
+
* Measure metadata against a chain's limits without throwing.
|
|
2059
|
+
*
|
|
2060
|
+
* The same rules {@link assertMetadataWithinLimits} enforces, reported rather than
|
|
2061
|
+
* raised, so a UI can colour a field as someone types instead of waiting for a failed
|
|
2062
|
+
* build. Byte lengths are UTF-8, which is the only measure that matters here — a label
|
|
2063
|
+
* of ten emoji is forty bytes, and counting characters would call it short.
|
|
2064
|
+
*/
|
|
2065
|
+
declare function inspectMetadata(metadata: readonly (string | Uint8Array)[] | undefined, limits: GeeqMetadataLimits | undefined): MetadataReport;
|
|
2066
|
+
|
|
2067
|
+
declare function toBase64(bytes: Uint8Array): string;
|
|
2068
|
+
/**
|
|
2069
|
+
* Decode base64, rejecting anything the alphabet does not cover.
|
|
2070
|
+
*
|
|
2071
|
+
* `label` names the thing being decoded so the message points at the caller's data
|
|
2072
|
+
* rather than at this function.
|
|
2073
|
+
*/
|
|
2074
|
+
declare function fromBase64(value: string, label?: string): Uint8Array;
|
|
2075
|
+
|
|
2076
|
+
declare function toHex(bytes: Uint8Array): string;
|
|
2077
|
+
declare function fromHex(value: string, label?: string): Uint8Array;
|
|
2078
|
+
|
|
2079
|
+
interface DecodeLedgerOptions {
|
|
2080
|
+
/** The node this came from, carried through onto the snapshot. */
|
|
2081
|
+
readonly nodeUrl?: string | undefined;
|
|
2082
|
+
/** Overrides the read timestamp. For deterministic tests. */
|
|
2083
|
+
readonly readAt?: number | undefined;
|
|
2084
|
+
}
|
|
2085
|
+
/**
|
|
2086
|
+
* Decode a validation layer ledger.
|
|
2087
|
+
*
|
|
2088
|
+
* `source` is what a node's `result` field holds: base64, or the bytes behind it. The
|
|
2089
|
+
* message is Cap'n Proto **packed**, which is what the node writes with
|
|
2090
|
+
* `toPackedArrayBuffer()` — not the flattened form used for signing.
|
|
2091
|
+
*
|
|
2092
|
+
* Everything is read in this one pass and the message is then dropped, so the caller
|
|
2093
|
+
* gets plain values with no traversal budget attached. See {@link GeeqLedger}.
|
|
2094
|
+
*/
|
|
2095
|
+
declare function decodeValidationLedger(source: Uint8Array | ArrayBuffer | string, options?: DecodeLedgerOptions): GeeqLedger;
|
|
2096
|
+
|
|
2097
|
+
/**
|
|
2098
|
+
* Build and sign an attestation transaction. Synchronous; requires a loaded engine.
|
|
2099
|
+
*
|
|
2100
|
+
* This function is offline: it opens no sockets and reads no ledger. It needs chain
|
|
2101
|
+
* state that only a node can supply, so either pass the four values yourself or let
|
|
2102
|
+
* {@link GeeqChain} read them and hand you a `chainState`.
|
|
2103
|
+
*
|
|
2104
|
+
* The transaction is signed but **not submitted**. Post
|
|
2105
|
+
* {@link AttestationTx.transaction} and {@link AttestationTx.payload} to the node named
|
|
2106
|
+
* by {@link AttestationTx.nodeUrl}.
|
|
2107
|
+
*/
|
|
2108
|
+
declare function createAttestationTxSync(input: AttestationTxInput): AttestationTx;
|
|
2109
|
+
/** Build and sign an attestation transaction, loading the engine if needed. */
|
|
2110
|
+
declare function createAttestationTx(input: AttestationTxInput): Promise<AttestationTx>;
|
|
2111
|
+
|
|
2112
|
+
/**
|
|
2113
|
+
* Build and sign a coin transfer. Synchronous; requires a loaded engine.
|
|
2114
|
+
*
|
|
2115
|
+
* Unlike an attestation this is a **validation layer** transaction: it carries no
|
|
2116
|
+
* separate payload, so there is one base64 blob to submit rather than two, and it is
|
|
2117
|
+
* posted as type `uvt`.
|
|
2118
|
+
*
|
|
2119
|
+
* NFTs ride along in the same transaction, with coin: the chain's minimum transfer
|
|
2120
|
+
* applies even when the point is the NFTs.
|
|
2121
|
+
*
|
|
2122
|
+
* Offline — it opens no sockets and reads no ledger. It cannot check that the sender can
|
|
2123
|
+
* afford the transfer, that the amount clears the chain's minimum, or that it holds the
|
|
2124
|
+
* NFTs; all three need a ledger. {@link GeeqChain.createTransfer} does check them.
|
|
2125
|
+
*/
|
|
2126
|
+
declare function createCoinTransferTxSync(input: CoinTransferTxInput): CoinTransferTx;
|
|
2127
|
+
/** Build and sign a coin transfer, loading the engine if needed. */
|
|
2128
|
+
declare function createCoinTransferTx(input: CoinTransferTxInput): Promise<CoinTransferTx>;
|
|
2129
|
+
|
|
2130
|
+
/**
|
|
2131
|
+
* Build and sign a transaction that creates an NFT mint proxy. Synchronous; requires a
|
|
2132
|
+
* loaded engine.
|
|
2133
|
+
*
|
|
2134
|
+
* A proxy is a record of its own on the chain. It holds coin, carries its own nonce, and
|
|
2135
|
+
* names one admin — the signer here — who is the only key that can mint NFTs through it.
|
|
2136
|
+
* The signer pays `amount` onto it, plus the fee.
|
|
2137
|
+
*
|
|
2138
|
+
* Offline: it cannot check that the index is unused or that the signer can afford it.
|
|
2139
|
+
* {@link GeeqChain.createNftMintProxy} does both.
|
|
2140
|
+
*/
|
|
2141
|
+
declare function createNftMintProxyTxSync(input: NftMintProxyTxInput): NftMintProxyTx;
|
|
2142
|
+
/** Build and sign a proxy creation, loading the engine if needed. */
|
|
2143
|
+
declare function createNftMintProxyTx(input: NftMintProxyTxInput): Promise<NftMintProxyTx>;
|
|
2144
|
+
|
|
2145
|
+
/**
|
|
2146
|
+
* Build and sign an NFT mint. Synchronous; requires a loaded engine.
|
|
2147
|
+
*
|
|
2148
|
+
* An NFT is minted through a proxy, and the proxy is the sender: it pays the fee and
|
|
2149
|
+
* `amount`, which goes to the receiver with the NFT, and it spends its own nonce. Its
|
|
2150
|
+
* admin — the signer here — is the only key the chain accepts for it. The NFT itself is an
|
|
2151
|
+
* attestation subgroup, as an attestation carries: the content's hash and its labels,
|
|
2152
|
+
* signed by the admin and naming the proxy.
|
|
2153
|
+
*
|
|
2154
|
+
* Offline: it cannot check that the proxy exists, is the signer's, or can pay.
|
|
2155
|
+
* {@link GeeqChain.mintNft} does all three.
|
|
2156
|
+
*/
|
|
2157
|
+
declare function createNftMintTxSync(input: NftMintTxInput): NftMintTx;
|
|
2158
|
+
/** Build and sign an NFT mint, loading the engine if needed. */
|
|
2159
|
+
declare function createNftMintTx(input: NftMintTxInput): Promise<NftMintTx>;
|
|
2160
|
+
|
|
2161
|
+
/**
|
|
2162
|
+
* Every error thrown by this SDK is a {@link GeeqError} carrying a stable
|
|
2163
|
+
* {@link GeeqErrorCode}. Branch on `code`, never on the message text.
|
|
2164
|
+
*/
|
|
2165
|
+
type GeeqErrorCode =
|
|
2166
|
+
/** An SDK function was called before the engine finished loading. */
|
|
2167
|
+
'not-initialized'
|
|
2168
|
+
/** The WebAssembly engine could not be loaded. */
|
|
2169
|
+
| 'init-failed'
|
|
2170
|
+
/** A public or private key was the wrong length, or the pair did not match. */
|
|
2171
|
+
| 'invalid-key'
|
|
2172
|
+
/** A wallet address was malformed, or encoded a record type we do not know. */
|
|
2173
|
+
| 'invalid-address'
|
|
2174
|
+
/** A caller-supplied argument was outside its allowed range. */
|
|
2175
|
+
| 'invalid-argument'
|
|
2176
|
+
/** A node could not be reached at all — no HTTP response arrived. */
|
|
2177
|
+
| 'network-unreachable'
|
|
2178
|
+
/** A node, simulator or explorer answered with an error status. See `status` and `nodeDetails`. */
|
|
2179
|
+
| 'node-error'
|
|
2180
|
+
/** A node answered, but its ledger could not be decoded. */
|
|
2181
|
+
| 'ledger-unreadable'
|
|
2182
|
+
/** The node's chain is not the one the caller said to expect. */
|
|
2183
|
+
| 'chain-mismatch'
|
|
2184
|
+
/** The signing account has no record on this chain yet — it needs funding. */
|
|
2185
|
+
| 'account-not-found'
|
|
2186
|
+
/** The account exists but its record type cannot sign this transaction. */
|
|
2187
|
+
| 'account-not-attestable'
|
|
2188
|
+
/**
|
|
2189
|
+
* The node being targeted cannot be identified, or cannot process transactions. Also
|
|
2190
|
+
* thrown when a simulator or explorer answers with something it should not serve.
|
|
2191
|
+
*/
|
|
2192
|
+
| 'node-unusable'
|
|
2193
|
+
/** Metadata exceeds a limit this chain publishes in its ledger. */
|
|
2194
|
+
| 'metadata-too-large'
|
|
2195
|
+
/** A second transaction was built for one account against one block. */
|
|
2196
|
+
| 'nonce-collision'
|
|
2197
|
+
/** The sending account does not hold enough coin. */
|
|
2198
|
+
| 'insufficient-funds'
|
|
2199
|
+
/** The amount is below the smallest transfer this chain accepts. */
|
|
2200
|
+
| 'amount-below-minimum'
|
|
2201
|
+
/** The sending account does not hold an NFT it was asked to send. */
|
|
2202
|
+
| 'nft-not-owned'
|
|
2203
|
+
/** A node's WebSocket could not be opened, or this runtime has no WebSocket at all. */
|
|
2204
|
+
| 'socket-unreachable'
|
|
2205
|
+
/** The {@link GeeqSocket} was disposed, so it will not send or receive again. */
|
|
2206
|
+
| 'socket-closed';
|
|
2207
|
+
interface GeeqErrorOptions {
|
|
2208
|
+
readonly cause?: unknown;
|
|
2209
|
+
/** HTTP status, when a server answered. */
|
|
2210
|
+
readonly status?: number;
|
|
2211
|
+
/**
|
|
2212
|
+
* The server's own `details`, verbatim; a list of them is joined with `; `. Never parse
|
|
2213
|
+
* it — branch on `code`.
|
|
2214
|
+
*/
|
|
2215
|
+
readonly nodeDetails?: string;
|
|
2216
|
+
}
|
|
2217
|
+
declare class GeeqError extends Error {
|
|
2218
|
+
readonly code: GeeqErrorCode;
|
|
2219
|
+
readonly status?: number | undefined;
|
|
2220
|
+
readonly nodeDetails?: string | undefined;
|
|
2221
|
+
constructor(code: GeeqErrorCode, message: string, options?: GeeqErrorOptions);
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
export { ACCOUNT_ID_BYTES, ATTEST_HASH_BYTES, type AccountIdentifier, type AccountRef, type AttestationContent, type AttestationRequest, type AttestationTx, type AttestationTxFlatInput, type AttestationTxInput, type AttestationTxStateInput, type ChainStateInput, type ChainStateRequest, type CoinTransferContent, type CoinTransferRequest, type CoinTransferTx, type CoinTransferTxFlatInput, type CoinTransferTxInput, type CoinTransferTxStateInput, type CreateWalletAddressInput, DEFAULT_RECORD_TYPE, type DecodeLedgerOptions, type DecodedWalletAddress, type Discovery, type ExplorerTransactionRequest, GEEQ_NODE_PORT, GEEQ_RECORD_TYPES, type GeeqAmount, GeeqChain, type GeeqChainOptions, type GeeqChainState, type GeeqCoinAccount, type GeeqCoinRecordKind, type GeeqCoinType, type GeeqContent, type GeeqDiscoveredChain, type GeeqDiscoveredNode, GeeqError, type GeeqErrorCode, type GeeqExplorerTransaction, type GeeqFee, type GeeqHeldNft, type GeeqHttpResponse, type GeeqKeypair, GeeqLedger, type GeeqLedgerNode, type GeeqListenOptions, type GeeqMetadataLimits, type GeeqNft, type GeeqNftMintProxies, type GeeqNftMintProxy, GeeqNode, type GeeqNodeKind, type GeeqNodeRole, type GeeqNodeStatus, type GeeqProxyAccount, type GeeqProxyKind, type GeeqRecordType, type GeeqRequestInit, type GeeqSendOptions, GeeqSocket, type GeeqSocketMessage, type GeeqSocketOptions, type GeeqSocketState, type GeeqTrackOptions, type GeeqTrackable, GeeqTrackedTx, type GeeqTransport, type GeeqTxConfirmed, type GeeqTxOutcome, type GeeqTxRefusal, type GeeqTxRejected, type GeeqTxRejectionReason, type GeeqTxState, type GeeqTxStatusEvent, type GeeqTxUnknown, type GeeqTxUnknownReason, type GeeqTxVerdict, type GeeqWebSocketFactory, type GeeqWebSocketLike, type GeeqWebSocketMessageEvent, type GenerateMnemonicOptions, type InitOptions, MNEMONIC_WORD_COUNTS, type MetadataEntryReport, type MetadataReport, type MnemonicOptions, type MnemonicWordCount, type NftMintProxiesRequest, type NftMintProxyRequest, type NftMintProxyTx, type NftMintProxyTxInput, type NftMintRequest, type NftMintTx, type NftMintTxInput, type NftTransferEntry, type NftsRequest, PUBLIC_KEY_BYTES, type WalletAddressOptions, type WasmSource, accountIdFromPublicKey, assertAttestHash, attest, attestHashOf, attestHashOfSync, attestationSubmitBody, coinTransferSubmitBody, createAttestationTx, createAttestationTxSync, createCoinTransferTx, createCoinTransferTxSync, createNftMintProxyTx, createNftMintProxyTxSync, createNftMintTx, createNftMintTxSync, createWalletAddress, createWalletAddressSync, decodeValidationLedger, decodeWalletAddress, decodeWalletAddressSync, defaultTransport, defaultWebSocketFactory, discover, formatGeeq, fromBase64, fromHex, generateKeypair, generateKeypairSync, generateMnemonic, getExplorerTransaction, importKeypair, importKeypairSync, initChain, initGeeq, inspectMetadata, isGeeqReady, isValidWalletAddress, keypairFromMnemonic, keypairFromMnemonicSync, keypairFromSecretKey, keypairFromSecretKeySync, ledgerRoute, listChains, listNodes, normalizeMnemonic, readContent, selectNode, socketRoute, submitRoute, toBase64, toHex, toPennies, transactionIdOf, transfer, validateMnemonic, verifySignature };
|