@geeqdev/geeq-sdk 0.0.1 → 0.1.1
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/.idea/geeq_sdk.iml +12 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/.nvmrc +1 -0
- package/CONTRIBUTING.md +20 -0
- package/example/.env.example +4 -0
- package/example/README.md +304 -0
- package/example/USAGE.md +74 -0
- package/example/index.html +12 -0
- package/example/package-lock.json +1557 -0
- package/example/package.json +25 -0
- package/example/scripts/browser-check.mjs +1421 -0
- package/example/scripts/match-derivation.mjs +65 -0
- package/example/src/App.vue +138 -0
- package/example/src/components/AuthorityPanel.vue +277 -0
- package/example/src/components/ChainPanel.vue +267 -0
- package/example/src/components/ChainState.vue +59 -0
- package/example/src/components/CopyButton.vue +25 -0
- package/example/src/components/CreateAssetPanel.vue +313 -0
- package/example/src/components/DigitalAssetsPanel.vue +68 -0
- package/example/src/components/EvidencePanel.vue +396 -0
- package/example/src/components/ExplorerPanel.vue +119 -0
- package/example/src/components/KeypairPanel.vue +182 -0
- package/example/src/components/PhrasePanel.vue +105 -0
- package/example/src/components/SocketWarning.vue +18 -0
- package/example/src/components/StepGate.vue +24 -0
- package/example/src/components/TransferPanel.vue +416 -0
- package/example/src/components/TxDeadline.vue +19 -0
- package/example/src/components/TxFee.vue +31 -0
- package/example/src/components/TxStatus.vue +105 -0
- package/example/src/composables/useSocketConnection.ts +80 -0
- package/example/src/env.d.ts +12 -0
- package/example/src/main.ts +5 -0
- package/example/src/pennies.ts +7 -0
- package/example/src/style.css +149 -0
- package/example/tsconfig.json +19 -0
- package/example/vite.config.ts +26 -0
- package/jest.config.js +18 -0
- package/package.json +1 -5
- package/scripts/copy-wasm.mjs +21 -0
- package/scripts/smoke.mjs +382 -0
- package/src/address/record-type.ts +77 -0
- package/src/address/wallet-address.ts +105 -0
- package/src/amount.ts +143 -0
- package/src/assert.ts +30 -0
- package/src/capnp/README.md +15 -0
- package/src/capnp/adminNetTx.capnp.ts +66 -0
- package/src/capnp/appLayBlock.capnp.ts +26 -0
- package/src/capnp/appLayLedger.capnp.ts +35 -0
- package/src/capnp/appLayRec.capnp.ts +159 -0
- package/src/capnp/chainStateView.capnp.ts +49 -0
- package/src/capnp/coinAcctRec.capnp.ts +193 -0
- package/src/capnp/genesisBlock.capnp.ts +56 -0
- package/src/capnp/hubContentStmt.capnp.ts +59 -0
- package/src/capnp/misc.capnp.ts +19 -0
- package/src/capnp/netActorRec.capnp.ts +64 -0
- package/src/capnp/nodeContentStmt.capnp.ts +62 -0
- package/src/capnp/nodePayloadList.capnp.ts +28 -0
- package/src/capnp/nodeTxList.capnp.ts +37 -0
- package/src/capnp/paramAcctRec.capnp.ts +669 -0
- package/src/capnp/payload.capnp.ts +261 -0
- package/src/capnp/proxyAcctRec.capnp.ts +259 -0
- package/src/capnp/relayContentStmt.capnp.ts +85 -0
- package/src/capnp/sysAcctRec.capnp.ts +47 -0
- package/src/capnp/userAppTx.capnp.ts +269 -0
- package/src/capnp/userValTx.capnp.ts +1999 -0
- package/src/capnp/valLayBlock.capnp.ts +93 -0
- package/src/capnp/valLayLedger.capnp.ts +80 -0
- package/src/chain/geeq-chain.ts +1094 -0
- package/src/chain/geeq-node.ts +105 -0
- package/src/chain/nonce-guard.ts +73 -0
- package/src/chain/select.ts +149 -0
- package/src/crypto/account-id.ts +83 -0
- package/src/crypto/keypair.ts +221 -0
- package/src/crypto/mnemonic.ts +69 -0
- package/src/encoding/base64.ts +58 -0
- package/src/encoding/hex.ts +42 -0
- package/src/errors.ts +122 -0
- package/src/index.ts +195 -0
- package/src/ledger/coin-accounts.ts +73 -0
- package/src/ledger/decode.ts +147 -0
- package/src/ledger/geeq-ledger.ts +184 -0
- package/src/ledger/net-actors.ts +129 -0
- package/src/ledger/nft-records.ts +49 -0
- package/src/ledger/params.ts +82 -0
- package/src/ledger/proxy-accounts.ts +51 -0
- package/src/net/discovery.ts +231 -0
- package/src/net/explorer.ts +123 -0
- package/src/net/read-ledger.ts +58 -0
- package/src/net/routes.ts +79 -0
- package/src/net/transport.ts +221 -0
- package/src/net/websocket.ts +94 -0
- package/src/runtime/bindings.ts +38 -0
- package/src/runtime/init.ts +49 -0
- package/src/runtime/wasm-loader.browser.ts +22 -0
- package/src/runtime/wasm-loader.node.ts +16 -0
- package/src/socket/geeq-socket.ts +827 -0
- package/src/socket/tracked-tx.ts +319 -0
- package/src/socket/tx-status.ts +131 -0
- package/src/tx/attestation.ts +222 -0
- package/src/tx/content.ts +82 -0
- package/src/tx/encode.ts +107 -0
- package/src/tx/expiry.ts +11 -0
- package/src/tx/fee.ts +31 -0
- package/src/tx/metadata.ts +100 -0
- package/src/tx/nft.ts +108 -0
- package/src/tx/proxy.ts +156 -0
- package/src/tx/transfer.ts +162 -0
- package/src/types.ts +503 -0
- package/src/wasm/README.md +22 -0
- package/src/wasm/browser/geeq_core.d.ts +1224 -0
- package/src/wasm/browser/geeq_core.js +6014 -0
- package/src/wasm/browser/geeq_core_bg.wasm +0 -0
- package/src/wasm/browser/geeq_core_bg.wasm.d.ts +447 -0
- package/src/wasm/nodejs/geeq_core.d.ts +753 -0
- package/src/wasm/nodejs/geeq_core.js +6016 -0
- package/src/wasm/nodejs/geeq_core_bg.wasm +0 -0
- package/src/wasm/nodejs/geeq_core_bg.wasm.d.ts +447 -0
- package/src/wasm/nodejs/package.json +3 -0
- package/tsconfig.build.json +8 -0
- package/tsconfig.json +20 -0
- package/tsup.config.ts +60 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="WEB_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager">
|
|
4
|
+
<content url="file://$MODULE_DIR$">
|
|
5
|
+
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
|
6
|
+
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
|
7
|
+
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
|
8
|
+
</content>
|
|
9
|
+
<orderEntry type="inheritedJdk" />
|
|
10
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
11
|
+
</component>
|
|
12
|
+
</module>
|
package/.idea/vcs.xml
ADDED
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
22
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Working on the SDK
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
npm install
|
|
5
|
+
npm test # unit tests, no network needed
|
|
6
|
+
npm run typecheck
|
|
7
|
+
npm run build # builds browser + Node bundles, types, and the engine
|
|
8
|
+
npm run smoke # tests the built package
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Everything installs from the public npm registry. The two parts that come from Geeq's
|
|
12
|
+
private repositories are vendored: the WASM engine in [`src/wasm`](./src/wasm/README.md)
|
|
13
|
+
and the Cap'n Proto schemas in [`src/capnp`](./src/capnp/README.md).
|
|
14
|
+
|
|
15
|
+
A full Vue 3 integration example lives in [`example/`](./example). It uses the SDK from
|
|
16
|
+
this folder (`file:..`), so run `npm run build` here before starting it.
|
|
17
|
+
|
|
18
|
+
**Update the README whenever the SDK changes.** It is the package's page on npm, and
|
|
19
|
+
`tests/documented-api.test.ts` checks that its Reference section and Quick start still
|
|
20
|
+
match the code.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
# How many pennies make one Geeq. The chain counts only pennies and does not publish this,
|
|
2
|
+
# so each app sets it, as the Geeq web app sets VUE_APP_BALANCE_DIVISOR. Use the same value
|
|
3
|
+
# as your other apps and explorer, or the figures will not match theirs.
|
|
4
|
+
VITE_PENNIES_PER_GEEQ=1000000000
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Geeq SDK demo — Vue 3
|
|
2
|
+
|
|
3
|
+
A minimal Vue 3 application showing how to use
|
|
4
|
+
[`@geeqdev/geeq-sdk`](..) in a browser app. For how the SDK works and
|
|
5
|
+
how to integrate it, read its
|
|
6
|
+
**[README](../README.md)** — that is the single SDK document. This file
|
|
7
|
+
only covers the demo.
|
|
8
|
+
|
|
9
|
+
To install the demo and try it step by step, see **[USAGE.md](USAGE.md)**.
|
|
10
|
+
|
|
11
|
+
What it does: generates a BIP-39 recovery phrase, derives a Geeq keypair and
|
|
12
|
+
address, finds a node, then submits a document's hash as evidence, sends coin, delegates
|
|
13
|
+
authority to an account that digital assets are created through, creates one, lists the
|
|
14
|
+
account's digital assets and sends them on — and shows what the chain decided about each,
|
|
15
|
+
as the node reports it over its socket. Step 9 looks any transaction
|
|
16
|
+
up in a block explorer by its refHash.
|
|
17
|
+
|
|
18
|
+
The steps build on each other, so each one waits — visible but unusable — until the
|
|
19
|
+
steps before it are done, and says which to do first: the phrase (1), then the keypair
|
|
20
|
+
and its chain number (2), then a node for that chain (3). Steps 4–8 need all three; step
|
|
21
|
+
9 needs none. The chain number is set only in step 2; step 3 shows it, and moving step 2
|
|
22
|
+
to another chain lets the node go until one is found for the new chain.
|
|
23
|
+
|
|
24
|
+
Keys never leave the tab and nothing is stored — they live in memory and are gone on
|
|
25
|
+
refresh. The only network traffic is to the simulator you name in step 3 and the node it
|
|
26
|
+
points at: the SDK asks the simulator which nodes serve your chain, reads the chosen
|
|
27
|
+
node's ledger to work out what a transaction must be pinned to, opens that node's
|
|
28
|
+
WebSocket to hear verdicts, and the page posts the signed result back. Step 9 also
|
|
29
|
+
calls the block explorer you name there.
|
|
30
|
+
|
|
31
|
+
## Terminology
|
|
32
|
+
|
|
33
|
+
The demo uses the words the Geeq apps show their users. The SDK and the protocol keep
|
|
34
|
+
their own words, so the two meet wherever the demo calls the SDK:
|
|
35
|
+
|
|
36
|
+
| The demo says | The SDK and the protocol say | SDK calls |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| **Submit evidence** (step 4): evidence, evidence hash | attestation, attest hash | `createAttestation`, `attestHashOf`, `attestationSubmitBody` |
|
|
39
|
+
| **Delegate authority** (step 6): authority account, delegation | NFT mint proxy, proxy, proxy creation | `createNftMintProxy`, `findNftMintProxies` |
|
|
40
|
+
| **Create a digital asset** (step 7): digital asset | mint an NFT, NFT | `mintNft`, `findNfts`, `createTransfer({ nfts })` |
|
|
41
|
+
| **Send coin** (step 5): coin, transfer | coin asset, unchanged | `createTransfer({ amount })` |
|
|
42
|
+
|
|
43
|
+
The demo's own names use its words too: `EvidencePanel.vue`, `AuthorityPanel.vue`,
|
|
44
|
+
`CreateAssetPanel.vue` and `DigitalAssetsPanel.vue`, and the variables and test ids inside
|
|
45
|
+
them. What comes from the SDK or the chain keeps the protocol's words:
|
|
46
|
+
|
|
47
|
+
- SDK functions and types, such as `AttestationTx`, `NftMintTx` and `GeeqNftMintProxies`,
|
|
48
|
+
and the fields they return, such as `tx.nftId`, `tx.proxyAddress`, `found.proxies` and
|
|
49
|
+
`asset.attestHash`;
|
|
50
|
+
- the record types listed in step 2, such as `coin-asset`, `proxy-nft-mint` and `app-nft`;
|
|
51
|
+
- error messages from the SDK, which the panels show as they come, so one may say "NFT" or
|
|
52
|
+
"proxy";
|
|
53
|
+
- the transaction type the block explorer reports in step 9, such as `attestation`.
|
|
54
|
+
|
|
55
|
+
## Run it
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm install
|
|
59
|
+
npm run dev
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The SDK is linked from the repository root (`file:..`), so build it first if you have
|
|
63
|
+
not already:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
cd .. && npm install && npm run build
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Pointing it at a local node
|
|
70
|
+
|
|
71
|
+
Real nodes answer on port 2082 behind TLS, with the socket on the same port at `/ws/`, and
|
|
72
|
+
that is what the demo uses by default. For a local node that isn't behind TLS, open
|
|
73
|
+
**Local harness options** in step 3:
|
|
74
|
+
|
|
75
|
+
- **Node port**: the node's HTTP port, used instead of 2082.
|
|
76
|
+
- **Socket URL**: the full socket address, for a node that serves it elsewhere, such as
|
|
77
|
+
`ws://10.0.0.1:3100/ws/`. Leave it empty to derive it from the node.
|
|
78
|
+
|
|
79
|
+
The socket URL is read when the socket opens, so set it before **Find a node**, or press
|
|
80
|
+
Retry after changing it.
|
|
81
|
+
|
|
82
|
+
## What it demonstrates
|
|
83
|
+
|
|
84
|
+
| Step | SDK functions |
|
|
85
|
+
|---|---|
|
|
86
|
+
| Show engine status | `initGeeq()` |
|
|
87
|
+
| Generate a 12–24 word phrase | `generateMnemonic({ words })` |
|
|
88
|
+
| Validate a pasted phrase as you type | `validateMnemonic()` |
|
|
89
|
+
| Derive the keypair | `keypairFromMnemonic()` |
|
|
90
|
+
| Show the address | `keypair.getAddress({ chainNumber })` |
|
|
91
|
+
| Show public key and account id | `keypair.publicKey`, `keypair.accountId` |
|
|
92
|
+
| Release the engine handle | `keypair.dispose()` |
|
|
93
|
+
| Find a node for a chain number | `GeeqChain.connect({ discovery, chainNumber, penniesPerGeeq })` |
|
|
94
|
+
| Send coin to a pasted address | `chain.createTransfer({ from, to, amount })` |
|
|
95
|
+
| Read and show an amount | `chain.toPennies({ geeq })`, `chain.formatGeeq(pennies)` |
|
|
96
|
+
| Derive chain, block, node and nonce | `chain.getChainState({ account })` |
|
|
97
|
+
| Delegate authority: create an authority account to create digital assets through | `chain.createNftMintProxy({ admin, amount })` |
|
|
98
|
+
| List an account's authority accounts by index, and the next index | `chain.findNftMintProxies({ admin, maxAgeMs: 0 })` |
|
|
99
|
+
| Create a digital asset through a chosen authority account | `chain.mintNft({ admin, index, content: file, metadata })` |
|
|
100
|
+
| List the account's digital assets, with their hashes and labels | `chain.findNfts({ owner, maxAgeMs: 0 })` |
|
|
101
|
+
| Send one digital asset or several to a pasted address | `chain.createTransfer({ from, to, nfts })` |
|
|
102
|
+
| Give back the nonce of a build that was never sent | `chain.discard(tx)` |
|
|
103
|
+
| Check a build that waited is not too old to send | `chain.isExpired(tx)`, `tx.validUntilBlock` |
|
|
104
|
+
| Read a pasted evidence hash | `fromHex(text)` |
|
|
105
|
+
| Hash a chosen file | `attestHashOf(file)` |
|
|
106
|
+
| Check metadata against a chain's limits | `inspectMetadata(labels, limits)` |
|
|
107
|
+
| Build and sign evidence | `chain.createAttestation({ keypair, attestHash })` |
|
|
108
|
+
| Open the node's socket | `GeeqSocket.connect({ endpoint: chain.endpoint })` |
|
|
109
|
+
| Show its connection state | `socket.onConnectionChange(state => …)` |
|
|
110
|
+
| Show every event the node pushes | `socket.onMessage(({ event, payload }) => …)` |
|
|
111
|
+
| Subscribe the account | `socket.subscribe(keypair)` |
|
|
112
|
+
| Listen for a transaction's verdict before sending it | `socket.track(tx)` |
|
|
113
|
+
| Settle a refused submission at once | `tracked.refused({ status, message })` |
|
|
114
|
+
| Follow it to confirmed / rejected / unknown | `tracked.onChange(t => …)`, `t.status`, `t.outcome` |
|
|
115
|
+
| Look a transaction up in a block explorer | `getExplorerTransaction({ explorerUrl, refHash })` |
|
|
116
|
+
|
|
117
|
+
Details worth copying into a real application:
|
|
118
|
+
|
|
119
|
+
**1. Mnemonic generation needs no engine.** `generateMnemonic` and
|
|
120
|
+
`validateMnemonic` are pure JavaScript, so step 1 works instantly while the ~2 MB
|
|
121
|
+
WebAssembly engine is still downloading. Only key derivation waits for it.
|
|
122
|
+
|
|
123
|
+
**2. Mark keypairs raw in reactive state.** A keypair is a class instance holding
|
|
124
|
+
an engine handle and typed arrays. `KeypairPanel.vue` uses `shallowRef` + `markRaw`,
|
|
125
|
+
because deep reactivity would proxy those arrays before they reach WebAssembly and
|
|
126
|
+
buys nothing — the object is replaced wholesale, never mutated.
|
|
127
|
+
|
|
128
|
+
**3. Dispose before replacing.** `keypair.dispose()` releases the engine-side key.
|
|
129
|
+
The demo does this whenever the phrase changes, so repeated derivation does not
|
|
130
|
+
leak handles.
|
|
131
|
+
|
|
132
|
+
**4. Post to `tx.nodeUrl`, not to a URL you kept.** The transaction names the node
|
|
133
|
+
that must process it, and the node compares that number to its own with strict
|
|
134
|
+
equality. The SDK tells you where the chain state came from; submitting anywhere else
|
|
135
|
+
is a guaranteed rejection.
|
|
136
|
+
|
|
137
|
+
**5. One transaction per account per block.** Two sharing a nonce are *both* rejected by
|
|
138
|
+
the chain, so the SDK throws `nonce-collision` on the second rather than building
|
|
139
|
+
something that would destroy the first. It applies to evidence and transfers alike, since
|
|
140
|
+
they share an account's nonce — and to delegations, which spend it too. Creating a digital
|
|
141
|
+
asset spends its authority account's nonce instead, so it is held to one per authority
|
|
142
|
+
account per block. A build that was never sent can give its nonce back with
|
|
143
|
+
`chain.discard(tx)`: step 7 does that when you change the file, labels or authority
|
|
144
|
+
account, so building again is not refused.
|
|
145
|
+
|
|
146
|
+
**6. Amounts name their unit.** `{ geeq: "1.5" }` or `{ pennies }` — never a bare number,
|
|
147
|
+
because a unit mistake in money does not throw. The chain counts only pennies; how many make
|
|
148
|
+
a Geeq is this app's setting, `VITE_PENNIES_PER_GEEQ` in `.env`, passed to `connect` as
|
|
149
|
+
`penniesPerGeeq`. Set it to the divisor your other apps and explorer use. The transfer panel
|
|
150
|
+
shows the penny figure as you type.
|
|
151
|
+
|
|
152
|
+
**7. Track before you submit, and keep the socket for the page's life.** Every panel calls
|
|
153
|
+
`socket.track(tx)` before the POST, because a verdict that arrives before anyone has
|
|
154
|
+
subscribed is lost. `composables/useSocketConnection.ts` opens one socket per chain and
|
|
155
|
+
closes it only when the chain changes; closing it on an account switch would strand every
|
|
156
|
+
pending transaction. The tracked handle lives in the socket, so `TxStatus.vue` keeps
|
|
157
|
+
showing a verdict even after the panel rebuilds its transaction.
|
|
158
|
+
|
|
159
|
+
**8. No socket is not no transactions.** A socket that will not open — most often a
|
|
160
|
+
node certificate the browser has not accepted — does not stop anyone submitting.
|
|
161
|
+
`SocketWarning.vue` warns above Submit that no confirmation will follow, with the
|
|
162
|
+
socket's error and a Retry. If subscribing fails at submit time, the transaction is sent
|
|
163
|
+
anyway and the panel says no confirmation will follow.
|
|
164
|
+
|
|
165
|
+
**9. A `200` is pending, not success.** The panels show a submitted transaction as
|
|
166
|
+
pending until the node's verdict arrives. A refused POST is settled at once with
|
|
167
|
+
`tracked.refused(...)`, since the node never sends a status for a transaction it refused.
|
|
168
|
+
|
|
169
|
+
**10. Every authority account has an index, and the ledger gives the next one.** An
|
|
170
|
+
authority account's id is derived from its admin's key and an index — the first is 1 — as
|
|
171
|
+
the Geeq apps do it. `createNftMintProxy` finds the account's authority accounts and takes
|
|
172
|
+
one past the highest index, so nothing is stored. **Find in ledger** in step 6 lists them
|
|
173
|
+
by index with the balance and nonce that creating a digital asset through them will use,
|
|
174
|
+
and shows the next index. An authority account is listed only once a block has confirmed
|
|
175
|
+
it.
|
|
176
|
+
|
|
177
|
+
**11. A digital asset is sent by its authority account, not by the account.** Step 7 lists
|
|
178
|
+
the account's authority accounts to choose from. The chosen one pays the fee and the
|
|
179
|
+
chain's minimum, which goes to the account with the digital asset, and spends its own
|
|
180
|
+
nonce, so the account can send something else in the same block. The account signs, as
|
|
181
|
+
the authority account's admin. It posts like evidence: `uat`, with a payload, using
|
|
182
|
+
`attestationSubmitBody`.
|
|
183
|
+
|
|
184
|
+
**12. Digital assets are sent as a transfer, with coin.** Step 8 lists the digital assets
|
|
185
|
+
the account holds: which ones from its record in the ledger, and the hash and labels each
|
|
186
|
+
was created with from the application layer ledger. Step 5 sends them: switch it to
|
|
187
|
+
**Digital assets**, get the list, tick one or several. They go in one transfer, posted as
|
|
188
|
+
`uvt`, carrying the chain's minimum transfer, since every transfer must carry at least
|
|
189
|
+
that. A new digital asset is listed once a block has confirmed it, and one sent away is
|
|
190
|
+
gone once a block confirms that.
|
|
191
|
+
|
|
192
|
+
**13. The explorer takes the same id the socket gives you.** Paste the base64 transaction
|
|
193
|
+
id shown under a verdict into step 9. The SDK asks the explorer in hex, the form it
|
|
194
|
+
stores, so you never convert it yourself. `null` means the explorer does not have it yet:
|
|
195
|
+
it only learns of a transaction once a block has decided it.
|
|
196
|
+
|
|
197
|
+
**14. A signed transaction cannot wait long.** A node takes it only until the chain is past
|
|
198
|
+
`tx.validUntilBlock`, its target block plus 8 — about nine blocks after it was built — and
|
|
199
|
+
refuses it with a `400` after that. Every panel shows that block under Submit, and calls
|
|
200
|
+
`chain.isExpired(tx)` before posting, which reads the ledger afresh. If the chain has moved
|
|
201
|
+
past it, nothing is sent: the panel says so and turns Submit off until you build again.
|
|
202
|
+
|
|
203
|
+
## Vite configuration
|
|
204
|
+
|
|
205
|
+
One line, and it is the only SDK-specific configuration needed:
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
export default defineConfig({
|
|
209
|
+
plugins: [vue()],
|
|
210
|
+
optimizeDeps: { exclude: ['@geeqdev/geeq-sdk'] },
|
|
211
|
+
})
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Vite's dependency pre-bundling rewrites the `new URL('...wasm', import.meta.url)`
|
|
215
|
+
the SDK uses to locate its engine. Excluding the SDK keeps that pattern intact, so
|
|
216
|
+
the `.wasm` is emitted as a hashed asset. webpack 5 and Parcel need no equivalent.
|
|
217
|
+
|
|
218
|
+
## Verifying it
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
npm run typecheck # vue-tsc, strict
|
|
222
|
+
npm run build # type-checks, then builds; emits the .wasm as an asset
|
|
223
|
+
npm run browser-check # drives the production build in real Chromium
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
`browser-check` serves `dist/` and drives it with Playwright. It also stubs a Geeq
|
|
227
|
+
node — serving a synthetic validation layer ledger built with the same Cap'n Proto
|
|
228
|
+
schema the SDK decodes, and accepting the submitted transaction — so the whole path
|
|
229
|
+
runs in a real browser with no live node. The engine loads over HTTP, a phrase is
|
|
230
|
+
generated, a keypair derived and chain state read. Then evidence and a coin transfer
|
|
231
|
+
are signed, posted and decoded back, to confirm that the block, node, nonce,
|
|
232
|
+
amount and recipient they carry are the ones the ledger and the page supplied. It also
|
|
233
|
+
drives the failure paths: a nonce collision, an unfunded account, an undecodable ledger,
|
|
234
|
+
and amounts that are malformed, below the chain minimum or over the balance.
|
|
235
|
+
|
|
236
|
+
The node's socket is stubbed with Playwright's `routeWebSocket`, which swaps the page's
|
|
237
|
+
`WebSocket` for an in-page stand-in: the SDK's socket code runs unchanged against frames
|
|
238
|
+
the check sends and records, with no network handshake. The check asserts the signer is
|
|
239
|
+
subscribed *before* the POST, then pushes status events keyed by a refHash it computes
|
|
240
|
+
from the posted bytes the way the node does — so an SDK that hashed a transaction
|
|
241
|
+
differently from the node would never see it settle. It drives confirmed evidence, a
|
|
242
|
+
refused submission that settles with no socket event, a transfer that is flagged
|
|
243
|
+
`nonsane` and then found `invalid`, and an arbitrary pushed event. A delegation is posted
|
|
244
|
+
and decoded back too: its authority account must take index 1 with the id the Geeq apps
|
|
245
|
+
derive and name this account as admin, and once confirmed the ledger must list it as
|
|
246
|
+
index 1, so that the next one built takes index 2. A digital asset is then created through
|
|
247
|
+
authority account 1 and decoded back: it must be sent by the authority account on its own
|
|
248
|
+
nonce, to this account, carrying the file's hash and labels. Before it is sent, a label is
|
|
249
|
+
changed and the build redone in the same block on the same nonce; once it is sent, another
|
|
250
|
+
build in that block must be refused. The stub then puts that digital asset and one more on
|
|
251
|
+
the account's record, and serves the application layer ledger with their hashes and
|
|
252
|
+
labels: step 8 must list both, and step 5 sends them — one ticked,
|
|
253
|
+
built, then a second ticked and rebuilt in the same block — as a transfer carrying both, at
|
|
254
|
+
their places in the account's record, with the chain's minimum. Last, a transfer is built and
|
|
255
|
+
the stub's chain moved past its `validUntilBlock`: Submit must say it is too old and post
|
|
256
|
+
nothing.
|
|
257
|
+
|
|
258
|
+
Then the socket's failures:
|
|
259
|
+
- a dropped socket that reconnects and replays its subscriptions;
|
|
260
|
+
- one that cannot come back, where the transaction is sent anyway with a warning — this
|
|
261
|
+
waits out the SDK's 15 s open timeout;
|
|
262
|
+
- one that never opens, where the page warns, still submits, and Retry recovers.
|
|
263
|
+
|
|
264
|
+
Finally it stubs the block explorer's `byRefHash` route, which answers as the real one
|
|
265
|
+
does, including its HTTP 500 for a refHash it does not have. It looks up the evidence by
|
|
266
|
+
its base64 id and checks that the explorer was asked in hex. It also checks that an
|
|
267
|
+
unknown refHash shows as not found, and that a hex refHash is refused before anything is
|
|
268
|
+
sent.
|
|
269
|
+
|
|
270
|
+
It expects Chrome at `/usr/bin/google-chrome`; override with `CHROME_PATH`.
|
|
271
|
+
|
|
272
|
+
## Layout
|
|
273
|
+
|
|
274
|
+
```
|
|
275
|
+
src/
|
|
276
|
+
├── App.vue engine status + page layout
|
|
277
|
+
├── components/
|
|
278
|
+
│ ├── PhrasePanel.vue generate or restore a recovery phrase
|
|
279
|
+
│ ├── KeypairPanel.vue derive and display the keypair
|
|
280
|
+
│ ├── ChainPanel.vue name a simulator, find a node for step 2's chain; shows its socket
|
|
281
|
+
│ ├── EvidencePanel.vue paste a hash or hash a file, sign, track, submit
|
|
282
|
+
│ ├── TransferPanel.vue send coin or digital assets to a pasted address, track, submit
|
|
283
|
+
│ ├── AuthorityPanel.vue delegate authority, track, submit; list your authority accounts
|
|
284
|
+
│ ├── CreateAssetPanel.vue choose an authority account, create a digital asset through it, track, submit
|
|
285
|
+
│ ├── DigitalAssetsPanel.vue list the digital assets this account holds
|
|
286
|
+
│ ├── ExplorerPanel.vue look a transaction up in a block explorer by refHash
|
|
287
|
+
│ ├── TxStatus.vue one tracked transaction, followed to its verdict
|
|
288
|
+
│ ├── ChainState.vue the chain, block, node and nonce a built transaction is pinned to
|
|
289
|
+
│ ├── TxFee.vue the fee a built transaction will be charged
|
|
290
|
+
│ ├── TxDeadline.vue the last block a built transaction can still be sent at
|
|
291
|
+
│ ├── SocketWarning.vue what a panel says when no verdict can be heard
|
|
292
|
+
│ ├── StepGate.vue holds a step until the steps it builds on are done
|
|
293
|
+
│ └── CopyButton.vue
|
|
294
|
+
├── composables/
|
|
295
|
+
│ └── useSocketConnection.ts the chain's node socket: opened and closed with the chain
|
|
296
|
+
├── style.css light/dark, no CSS framework
|
|
297
|
+
└── main.ts
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Not for real funds
|
|
301
|
+
|
|
302
|
+
This is an SDK demo. It has no persistence, no encryption at rest, no password, and
|
|
303
|
+
it displays a private key on request — all things a real application must handle
|
|
304
|
+
properly. Read it for the SDK calls, not as a security template.
|
package/example/USAGE.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Using the demo
|
|
2
|
+
|
|
3
|
+
How to install the demo and try each step. For how the code works, see the
|
|
4
|
+
[README](README.md).
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
You need Node.js 20 or newer. The demo lives in the SDK repository's `example/` folder
|
|
9
|
+
and uses the SDK from the repository root, so build that first:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
cd .. && npm install && npm run build
|
|
13
|
+
cd example && npm install
|
|
14
|
+
cp .env.example .env
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
In `.env`, check `VITE_PENNIES_PER_GEEQ` (how many pennies make one Geeq). Use the same
|
|
18
|
+
value as your other Geeq apps and your explorer.
|
|
19
|
+
|
|
20
|
+
## Run
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm run dev
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Open the printed URL and wait for **Engine ready**.
|
|
27
|
+
|
|
28
|
+
## Steps
|
|
29
|
+
|
|
30
|
+
Steps unlock in order. Steps 1–3 set up the account and the node, steps 4–8 need them,
|
|
31
|
+
and step 9 works on its own. Nothing is saved, so a refresh clears your keys.
|
|
32
|
+
|
|
33
|
+
1. **Recovery phrase**: click **Create new**, then **Generate phrase**. Or click
|
|
34
|
+
**Restore existing** and paste your own.
|
|
35
|
+
2. **Keypair & address**: set the **Chain number** and click **Derive keypair**.
|
|
36
|
+
3. **Chain**: paste a **Simulator URL** and click **Find a node**.
|
|
37
|
+
4. **Submit evidence**: paste a hash or choose a file.
|
|
38
|
+
5. **Send coin or digital assets**: choose **Geeq** or **Digital assets** and paste the
|
|
39
|
+
recipient's address.
|
|
40
|
+
6. **Delegate authority**: create and fund an authority account. You need one before you
|
|
41
|
+
can create a digital asset.
|
|
42
|
+
7. **Create a digital asset**: click **Find my authority accounts**, pick one, and choose
|
|
43
|
+
a file.
|
|
44
|
+
8. **Your digital assets**: click **Get my digital assets**.
|
|
45
|
+
9. **Block explorer**: paste an explorer URL and a transaction id from steps 4–7.
|
|
46
|
+
|
|
47
|
+
In steps 4–7, click **Build & sign**, then **Submit to node**, and wait for the
|
|
48
|
+
**Verdict**. A new account is empty, so send it some coin before step 4.
|
|
49
|
+
|
|
50
|
+
## Terminology
|
|
51
|
+
|
|
52
|
+
The demo uses the words the Geeq apps show their users. The SDK and the protocol use
|
|
53
|
+
their own:
|
|
54
|
+
|
|
55
|
+
| In the demo | In the SDK and the protocol |
|
|
56
|
+
| ------------------------------------- | -------------------------------- |
|
|
57
|
+
| Submit evidence, evidence | attestation |
|
|
58
|
+
| Delegate authority, authority account | create an NFT mint proxy, proxy |
|
|
59
|
+
| Create a digital asset, digital asset | mint an NFT, NFT |
|
|
60
|
+
| Send coin | coin asset, unchanged |
|
|
61
|
+
|
|
62
|
+
So an error message from the SDK may say "NFT" or "proxy", the record types in step 2
|
|
63
|
+
keep their protocol names, and the block explorer in step 9 reports its own transaction
|
|
64
|
+
types, such as `attestation`. The [README](README.md#terminology) lists which names in the
|
|
65
|
+
code changed.
|
|
66
|
+
|
|
67
|
+
## If something goes wrong
|
|
68
|
+
|
|
69
|
+
| You see | Fix |
|
|
70
|
+
| ------------------------------------------------------ | ------------------------------------------------------------------------------------- |
|
|
71
|
+
| **Engine failed to load** | Rebuild the SDK and restart `npm run dev`. |
|
|
72
|
+
| `Cannot convert undefined to a BigInt` | Set `VITE_PENNIES_PER_GEEQ` in `.env` (VITE_PENNIES_PER_GEEQ=1000000000) and restart. |
|
|
73
|
+
| **Could not reach that simulator**, or socket `failed` | Open the URL in a tab, accept its certificate, then try again. |
|
|
74
|
+
| **This account has never received coins** | Send coin to the account's address first. |
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Geeq SDK Demo</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app"></div>
|
|
10
|
+
<script type="module" src="/src/main.ts"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|