@rialo/ts-cdk 0.4.2 → 0.8.0-alpha.0
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 +355 -294
- package/dist/index.d.mts +431 -227
- package/dist/index.d.ts +431 -227
- package/dist/index.js +1759 -173
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1747 -164
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -1,441 +1,502 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @rialo/ts-cdk
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
TypeScript library for building on the Rialo blockchain. Provides Ed25519 cryptographic
|
|
4
|
+
primitives, BIP39/SLIP-0010 HD wallet derivation, transaction construction and signing,
|
|
5
|
+
a JSON-RPC client for node communication, program deployment, and HPKE encryption for
|
|
6
|
+
TEE programs. Works in Node.js ≥ 18 and modern browsers (ESM and CJS bundles included).
|
|
6
7
|
|
|
7
8
|
## Installation
|
|
8
9
|
|
|
9
10
|
```bash
|
|
10
11
|
npm install @rialo/ts-cdk
|
|
12
|
+
# or
|
|
13
|
+
pnpm add @rialo/ts-cdk
|
|
14
|
+
# or
|
|
15
|
+
yarn add @rialo/ts-cdk
|
|
11
16
|
```
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
Requires Node.js ≥ 18. Ships both ESM (`dist/index.mjs`) and CJS (`dist/index.js`) bundles with
|
|
19
|
+
bundled TypeScript declarations. Works in modern browsers when bundled with Vite/webpack.
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
## Key public types
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
import { Keypair } from "@rialo/ts-cdk";
|
|
23
|
+
### Cryptography
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
| Export | Purpose |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `Keypair` | Ed25519 keypair; generate, derive from seed, sign, verify, dispose |
|
|
28
|
+
| `PublicKey` | 32-byte Ed25519 public key; PDA derivation, base58 encoding |
|
|
29
|
+
| `Signature` | 64-byte Ed25519 signature; base58 encoding |
|
|
30
|
+
| `Mnemonic` | BIP39 mnemonic; generate, restore, derive keypairs via SLIP-0010 |
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
const signature = keypair.sign(message);
|
|
25
|
-
const isValid = keypair.verify(message, signature);
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### Connect to the blockchain
|
|
32
|
+
### Keyring management
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
| Export | Purpose |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `RialoKeyring` | Named collection of `Keypair` instances with an active signing key |
|
|
37
|
+
| `InMemoryKeyringProvider` | Create `RialoKeyring` from a mnemonic or a list of keypairs |
|
|
38
|
+
| `DerivedKeypairInfo` | Metadata for a single derived keypair (index, pubkey, path) |
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// Query blockchain
|
|
36
|
-
const balance = await client.getBalance(keypair.publicKey);
|
|
37
|
-
const height = await client.getBlockHeight();
|
|
38
|
-
const chainId = client.getChainIdentifier();
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Build and send a transaction
|
|
40
|
+
### Transactions
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
| Export | Purpose |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `TransactionBuilder` | Fluent builder for constructing transactions |
|
|
45
|
+
| `Transaction` | Signed/unsigned transaction; serialize, deserialize, multi-sig |
|
|
46
|
+
| `Message` | Compiled transaction message with account keys and instructions |
|
|
47
|
+
| `Instruction` | Single operation: program ID, accounts, data |
|
|
48
|
+
| `AccountMeta` | Account reference with `isSigner` / `isWritable` flags |
|
|
49
|
+
| `AccountMetaTable` | Deduplication table for account references within a message |
|
|
50
|
+
| `transferInstruction` | System-program transfer helper |
|
|
51
|
+
| `createAccount` | System-program create-account helper |
|
|
45
52
|
|
|
46
|
-
|
|
47
|
-
const validFrom = BigInt(Date.now());
|
|
53
|
+
### RPC
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
| Export | Purpose |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `createRialoClient` | Factory for `RialoClient`; accepts a chain preset or custom config |
|
|
58
|
+
| `getDefaultRialoClientConfig` | Returns a `RialoClientConfig` for `"mainnet"`, `"devnet"`, `"testnet"`, or `"localnet"` |
|
|
59
|
+
| `RialoClient` | Full RPC surface for a Rialo node |
|
|
60
|
+
| `RIALO_MAINNET_CHAIN` / `…TESTNET…` / `…DEVNET…` / `…LOCALNET…` | Chain presets |
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
const tx = TransactionBuilder.create()
|
|
58
|
-
.setPayer(keypair.publicKey)
|
|
59
|
-
.setValidFrom(validFrom)
|
|
60
|
-
.addInstruction(transfer)
|
|
61
|
-
.build();
|
|
62
|
+
### Other
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
| Export | Purpose |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `Signer` / `KeypairSigner` | Abstract signing interface for hardware wallets and custom signers |
|
|
67
|
+
| `ProgramDeployment` | Deploy PolkaVM program binaries to the network |
|
|
68
|
+
| `RexValue` | Typed wrapper for plain or HPKE-encrypted byte payloads |
|
|
69
|
+
| `RialoError` / `RialoErrorType` | Structured error with discriminated type field |
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
const signature = await client.sendTransaction(signedTx.serialize());
|
|
67
|
-
```
|
|
71
|
+
## Usage
|
|
68
72
|
|
|
69
|
-
###
|
|
73
|
+
### Keypair and signing
|
|
70
74
|
|
|
71
75
|
```typescript
|
|
72
|
-
import {
|
|
76
|
+
import { Keypair, PublicKey } from "@rialo/ts-cdk";
|
|
73
77
|
|
|
74
|
-
// Generate
|
|
75
|
-
const
|
|
78
|
+
// Generate a random keypair
|
|
79
|
+
const keypair = Keypair.generate();
|
|
80
|
+
console.log("Address:", keypair.publicKey.toString());
|
|
76
81
|
|
|
77
|
-
//
|
|
78
|
-
const
|
|
82
|
+
// Restore from a known 32-byte secret key
|
|
83
|
+
const restored = Keypair.fromSecretKey(secretKeyBytes);
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
const
|
|
85
|
+
const message = new TextEncoder().encode("Hello Rialo");
|
|
86
|
+
const sig = keypair.sign(message);
|
|
87
|
+
const ok = keypair.verify(message, sig);
|
|
82
88
|
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
const restoredKeypair = await restored.toKeypair();
|
|
89
|
+
// Always dispose keypairs when finished to zero out the private key.
|
|
90
|
+
keypair.dispose();
|
|
86
91
|
```
|
|
87
92
|
|
|
88
|
-
|
|
93
|
+
### BIP39 mnemonic and HD derivation
|
|
89
94
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
Ed25519 cryptographic primitives for key management and signing.
|
|
95
|
+
Rialo uses BIP44 coin type 756 with SLIP-0010 (`m/44'/756'/{index}'/0'`).
|
|
93
96
|
|
|
94
97
|
```typescript
|
|
95
|
-
import {
|
|
98
|
+
import { Mnemonic } from "@rialo/ts-cdk";
|
|
96
99
|
|
|
97
|
-
// Generate
|
|
98
|
-
const
|
|
100
|
+
// Generate a new 12-word mnemonic (pass 256 for 24-word)
|
|
101
|
+
const mnemonic = Mnemonic.generate(); // 128-bit entropy, 12 words
|
|
102
|
+
console.log(mnemonic.toString());
|
|
103
|
+
console.log("Words:", mnemonic.getWordCount()); // 12
|
|
104
|
+
|
|
105
|
+
// Validate a phrase without constructing a Mnemonic
|
|
106
|
+
const valid = Mnemonic.isValid("word1 word2 … word12");
|
|
99
107
|
|
|
100
|
-
//
|
|
101
|
-
const
|
|
108
|
+
// Restore from an existing phrase
|
|
109
|
+
const restored = Mnemonic.fromPhrase("word1 word2 … word12");
|
|
102
110
|
|
|
103
|
-
//
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
const bytes = pubkey.toBytes();
|
|
111
|
+
// Derive account keypairs
|
|
112
|
+
const account0 = await mnemonic.toKeypair(0); // m/44'/756'/0'/0'
|
|
113
|
+
const account1 = await mnemonic.toKeypair(1); // m/44'/756'/1'/0'
|
|
107
114
|
|
|
108
|
-
//
|
|
109
|
-
const
|
|
115
|
+
// With an optional BIP39 passphrase
|
|
116
|
+
const secure = await mnemonic.toKeypair(0, { passphrase: "my-secret" });
|
|
110
117
|
|
|
111
|
-
//
|
|
112
|
-
const
|
|
118
|
+
// Derive with an explicit full path (advanced)
|
|
119
|
+
const custom = await mnemonic.toKeypairWithPath("m/44'/756'/0'/0'");
|
|
120
|
+
|
|
121
|
+
// Derive multiple at once (indices 0–4)
|
|
122
|
+
const keypairs = await mnemonic.deriveKeypairs(5);
|
|
123
|
+
|
|
124
|
+
// Convert to raw 64-byte BIP39 seed
|
|
125
|
+
const seed = await mnemonic.toSeed();
|
|
113
126
|
```
|
|
114
127
|
|
|
115
|
-
###
|
|
128
|
+
### Keyring management
|
|
116
129
|
|
|
117
|
-
|
|
130
|
+
`RialoKeyring` manages a set of derived keypairs and tracks the active signing key,
|
|
131
|
+
useful when an application needs to sign on behalf of multiple accounts.
|
|
118
132
|
|
|
119
133
|
```typescript
|
|
120
|
-
import {
|
|
121
|
-
TransactionBuilder,
|
|
122
|
-
transferInstruction,
|
|
123
|
-
type Instruction,
|
|
124
|
-
type AccountMeta
|
|
125
|
-
} from "@rialo/ts-cdk";
|
|
134
|
+
import { Mnemonic, InMemoryKeyringProvider } from "@rialo/ts-cdk";
|
|
126
135
|
|
|
127
|
-
|
|
128
|
-
const
|
|
136
|
+
const mnemonic = Mnemonic.generate();
|
|
137
|
+
const provider = new InMemoryKeyringProvider();
|
|
129
138
|
|
|
130
|
-
//
|
|
131
|
-
const
|
|
132
|
-
programId: PublicKey.fromString("YourProgramId"),
|
|
133
|
-
accounts: [
|
|
134
|
-
{ pubkey: account1, isSigner: true, isWritable: true },
|
|
135
|
-
{ pubkey: account2, isSigner: false, isWritable: true },
|
|
136
|
-
],
|
|
137
|
-
data: instructionData, // Uint8Array
|
|
138
|
-
};
|
|
139
|
+
// Derive 3 keypairs into a single keyring
|
|
140
|
+
const keyring = await provider.createFromMnemonic(mnemonic, 3);
|
|
139
141
|
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
.setValidFrom(validFrom)
|
|
144
|
-
.addInstruction(instruction)
|
|
145
|
-
.build();
|
|
142
|
+
// Switch the active keypair
|
|
143
|
+
keyring.setActiveKeypair(2);
|
|
144
|
+
console.log("Active:", keyring.pubkeyString());
|
|
146
145
|
|
|
147
|
-
//
|
|
148
|
-
const
|
|
146
|
+
// Sign with the active keypair
|
|
147
|
+
const sig = keyring.sign(messageBytes);
|
|
149
148
|
|
|
150
|
-
//
|
|
151
|
-
const
|
|
152
|
-
|
|
149
|
+
// Sign with a specific keypair without switching active
|
|
150
|
+
const sig1 = keyring.signWithKeypair(messageBytes, 1);
|
|
151
|
+
|
|
152
|
+
// Inspect all keypairs
|
|
153
|
+
for (const info of keyring.getKeypairsInfo()) {
|
|
154
|
+
console.log(`index=${info.index} pubkey=${info.pubkeyString}`);
|
|
155
|
+
}
|
|
153
156
|
|
|
154
|
-
//
|
|
155
|
-
|
|
157
|
+
// Securely zero all private keys when done
|
|
158
|
+
keyring.dispose();
|
|
156
159
|
```
|
|
157
160
|
|
|
158
|
-
###
|
|
161
|
+
### Build and send a transaction
|
|
159
162
|
|
|
160
|
-
|
|
163
|
+
`TransactionBuilder` requires a `configHashPrefix` fetched from the network. Every
|
|
164
|
+
transaction submitted to a live node must carry the current prefix or it will be
|
|
165
|
+
rejected.
|
|
161
166
|
|
|
162
167
|
```typescript
|
|
163
168
|
import {
|
|
169
|
+
TransactionBuilder,
|
|
170
|
+
transferInstruction,
|
|
164
171
|
createRialoClient,
|
|
165
172
|
getDefaultRialoClientConfig,
|
|
166
173
|
RIALO_DEVNET_CHAIN,
|
|
167
|
-
RIALO_MAINNET_CHAIN
|
|
168
174
|
} from "@rialo/ts-cdk";
|
|
169
175
|
|
|
170
|
-
// Using
|
|
176
|
+
// Using a chain preset directly
|
|
171
177
|
const client = createRialoClient({ chain: RIALO_DEVNET_CHAIN });
|
|
172
178
|
|
|
173
|
-
//
|
|
174
|
-
const
|
|
175
|
-
const mainnetClient = createRialoClient({
|
|
176
|
-
...config,
|
|
177
|
-
transport: {
|
|
178
|
-
timeout: 30000,
|
|
179
|
-
maxRetries: 3,
|
|
180
|
-
}
|
|
181
|
-
});
|
|
179
|
+
// Or by network name — useful when network comes from config/env
|
|
180
|
+
// const client = createRialoClient(getDefaultRialoClientConfig("devnet"));
|
|
182
181
|
|
|
183
|
-
//
|
|
184
|
-
const balance = await client.getBalance(publicKey);
|
|
185
|
-
const accountInfo = await client.getAccountInfo(publicKey);
|
|
186
|
-
const blockHeight = await client.getBlockHeight();
|
|
187
|
-
const chainId = client.getChainIdentifier();
|
|
188
|
-
|
|
189
|
-
// Get transaction info (returns blockHeight and optional error)
|
|
190
|
-
const txInfo = await client.getTransaction(signature);
|
|
191
|
-
if (txInfo) {
|
|
192
|
-
console.log(`Confirmed in block: ${txInfo.blockHeight}`);
|
|
193
|
-
if (txInfo.err) {
|
|
194
|
-
console.log(`Transaction failed: ${txInfo.err}`);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
182
|
+
const configHashPrefix = await client.getConfigHashPrefix(); // required
|
|
197
183
|
|
|
198
|
-
|
|
199
|
-
|
|
184
|
+
const transfer = transferInstruction(
|
|
185
|
+
keypair.publicKey,
|
|
186
|
+
recipientPubkey,
|
|
187
|
+
1_000_000n, // amount in kelvin; 1 RLO = 1_000_000_000 kelvin
|
|
188
|
+
);
|
|
200
189
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
190
|
+
const tx = TransactionBuilder.create()
|
|
191
|
+
.setPayer(keypair.publicKey)
|
|
192
|
+
.setValidFrom(BigInt(Date.now()))
|
|
193
|
+
.setConfigHashPrefix(configHashPrefix)
|
|
194
|
+
.addInstruction(transfer)
|
|
195
|
+
.build();
|
|
204
196
|
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
});
|
|
197
|
+
const signedTx = tx.sign(keypair);
|
|
198
|
+
const sig = await client.sendTransaction(signedTx.serialize());
|
|
199
|
+
console.log("Signature:", sig.toString());
|
|
200
|
+
```
|
|
210
201
|
|
|
211
|
-
|
|
212
|
-
const airdropSig = await client.requestAirdrop(publicKey, 1_000_000_000n);
|
|
202
|
+
### Multi-sig transactions
|
|
213
203
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
);
|
|
204
|
+
```typescript
|
|
205
|
+
// Each partial sign adds one signer's signature; isSigned() returns true when all
|
|
206
|
+
// required signers have contributed.
|
|
207
|
+
const partial = tx.partialSign(signer1);
|
|
208
|
+
const complete = partial.partialSign(signer2);
|
|
209
|
+
complete.ensureSigned(); // throws if any signature is missing
|
|
219
210
|
|
|
220
|
-
//
|
|
221
|
-
const
|
|
211
|
+
// Async signer interface (hardware wallets, browser extensions, etc.)
|
|
212
|
+
const signedAsync = await tx.signWith(new KeypairSigner(keypair));
|
|
213
|
+
```
|
|
222
214
|
|
|
223
|
-
|
|
224
|
-
const fee = await client.getFeeForMessage(base64Message);
|
|
215
|
+
### Deserialize a transaction
|
|
225
216
|
|
|
226
|
-
|
|
227
|
-
|
|
217
|
+
`Transaction.deserialize` reconstructs a transaction from its wire bytes — useful for
|
|
218
|
+
inspecting or re-signing transactions received from another party.
|
|
228
219
|
|
|
229
|
-
|
|
230
|
-
|
|
220
|
+
```typescript
|
|
221
|
+
import { Transaction } from "@rialo/ts-cdk";
|
|
231
222
|
|
|
232
|
-
//
|
|
233
|
-
const
|
|
234
|
-
signature: rootTxSignature,
|
|
235
|
-
maxDepth: 5,
|
|
236
|
-
});
|
|
223
|
+
// Reconstruct from wire bytes (e.g. received over a socket)
|
|
224
|
+
const tx = Transaction.deserialize(wireBytes);
|
|
237
225
|
|
|
238
|
-
//
|
|
239
|
-
const
|
|
226
|
+
// Inspect the compiled message
|
|
227
|
+
for (const ix of tx.message.instructions) {
|
|
228
|
+
console.log("program:", ix.programId.toString());
|
|
229
|
+
}
|
|
240
230
|
|
|
241
|
-
//
|
|
242
|
-
const
|
|
231
|
+
// Re-sign (e.g. when acting as co-signer)
|
|
232
|
+
const reSigned = tx.partialSign(myKeypair);
|
|
243
233
|
```
|
|
244
234
|
|
|
245
|
-
###
|
|
235
|
+
### Borsh serialization for instruction data
|
|
246
236
|
|
|
247
|
-
|
|
237
|
+
Use Borsh to encode typed parameters into the opaque `data` field of an `Instruction`.
|
|
248
238
|
|
|
249
239
|
```typescript
|
|
250
|
-
import {
|
|
240
|
+
import { field, serialize, deserialize } from "@dao-xyz/borsh";
|
|
241
|
+
import { Instruction, AccountMeta } from "@rialo/ts-cdk";
|
|
251
242
|
|
|
252
|
-
|
|
253
|
-
|
|
243
|
+
class TransferParams {
|
|
244
|
+
@field({ type: "u64" }) amount!: bigint;
|
|
245
|
+
constructor(amount: bigint) { this.amount = amount; }
|
|
246
|
+
}
|
|
254
247
|
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
const pubkey = signer.publicKey();
|
|
248
|
+
const params = new TransferParams(1_000_000n);
|
|
249
|
+
const data = Buffer.from(serialize(params));
|
|
258
250
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
publicKey(): PublicKey {
|
|
265
|
-
// return public key
|
|
266
|
-
}
|
|
267
|
-
}
|
|
251
|
+
const ix = new Instruction({
|
|
252
|
+
programId: myProgramId,
|
|
253
|
+
accounts: [new AccountMeta({ pubkey: myAccount, isSigner: false, isWritable: true })],
|
|
254
|
+
data,
|
|
255
|
+
});
|
|
268
256
|
```
|
|
269
257
|
|
|
270
|
-
## Advanced Features
|
|
271
|
-
|
|
272
258
|
### Program Derived Addresses (PDAs)
|
|
273
259
|
|
|
274
|
-
PDAs are
|
|
260
|
+
PDAs are off-curve addresses deterministically derived from seeds and a program ID.
|
|
261
|
+
No private key exists; only the program can sign on their behalf.
|
|
275
262
|
|
|
276
263
|
```typescript
|
|
277
264
|
import { PublicKey } from "@rialo/ts-cdk";
|
|
278
265
|
|
|
279
|
-
//
|
|
280
|
-
const [vaultPda,
|
|
266
|
+
// Automatic bump discovery — returns [address, bump]
|
|
267
|
+
const [vaultPda, bump] = PublicKey.findProgramAddress(
|
|
281
268
|
["vault", userPubkey.toBytes()],
|
|
282
|
-
programId
|
|
269
|
+
programId,
|
|
283
270
|
);
|
|
284
271
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
// Create PDA with known bump (more efficient for verification)
|
|
272
|
+
// With known bump (more efficient)
|
|
288
273
|
const pda = PublicKey.createProgramAddress(
|
|
289
|
-
["metadata", mintPubkey.toBytes(), new Uint8Array([
|
|
290
|
-
metadataProgramId
|
|
274
|
+
["metadata", mintPubkey.toBytes(), new Uint8Array([bump])],
|
|
275
|
+
metadataProgramId,
|
|
291
276
|
);
|
|
277
|
+
```
|
|
292
278
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
279
|
+
> **Note:** Each seed must be ≤ 32 bytes; at most 16 seeds per derivation. String seeds
|
|
280
|
+
> are UTF-8-encoded automatically.
|
|
281
|
+
|
|
282
|
+
### Deploy a program
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import { ProgramDeployment } from "@rialo/ts-cdk";
|
|
286
|
+
|
|
287
|
+
const deployment = new ProgramDeployment({
|
|
288
|
+
programData: fs.readFileSync("program.polkavm"),
|
|
289
|
+
programKeypair: programKeypair,
|
|
290
|
+
config: {
|
|
291
|
+
chunkSize: 900, // bytes per upload chunk
|
|
292
|
+
maxRetries: 5,
|
|
293
|
+
},
|
|
294
|
+
});
|
|
299
295
|
|
|
300
|
-
|
|
301
|
-
|
|
296
|
+
const programId = await deployment.deploy(client, payerKeypair);
|
|
297
|
+
console.log("Program deployed:", programId.toString());
|
|
302
298
|
```
|
|
303
299
|
|
|
304
|
-
|
|
300
|
+
### Encrypt a secret for TEE programs
|
|
305
301
|
|
|
306
|
-
-
|
|
307
|
-
|
|
308
|
-
|
|
302
|
+
`RexValue` wraps a plain or HPKE-encrypted payload. Use it to pass sensitive data to
|
|
303
|
+
programs that run inside a Trusted Execution Environment (TEE). The node's HPKE public
|
|
304
|
+
key is fetched via `getSecretSharingPubkey()`; the CDK handles the HPKE encryption.
|
|
309
305
|
|
|
310
|
-
|
|
306
|
+
```typescript
|
|
307
|
+
import { RexValue } from "@rialo/ts-cdk";
|
|
308
|
+
|
|
309
|
+
// 1. Fetch the TEE's HPKE public key from the node
|
|
310
|
+
const skPub = await client.getSecretSharingPubkey();
|
|
311
|
+
|
|
312
|
+
// 2. Encrypt your secret — RexValue.fromPlaintext performs HPKE encryption
|
|
313
|
+
const plaintext = new TextEncoder().encode("Bearer sk-…");
|
|
314
|
+
const rexValue = await RexValue.fromPlaintext(plaintext, skPub);
|
|
315
|
+
|
|
316
|
+
// 3. Serialise as Borsh bytes and embed in your instruction data
|
|
317
|
+
const borshBytes = rexValue.toBorsh();
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
To include unencrypted bytes (for non-sensitive payloads):
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
const plain = RexValue.plain(new TextEncoder().encode("public-data"));
|
|
324
|
+
const borshBytes = plain.toBorsh();
|
|
325
|
+
```
|
|
311
326
|
|
|
312
|
-
|
|
327
|
+
### Custom signer (hardware wallets)
|
|
313
328
|
|
|
314
329
|
```typescript
|
|
315
|
-
|
|
316
|
-
|
|
330
|
+
import { type Signer, PublicKey, Signature } from "@rialo/ts-cdk";
|
|
331
|
+
|
|
332
|
+
class LedgerSigner implements Signer {
|
|
333
|
+
async getPublicKey(): Promise<PublicKey> {
|
|
334
|
+
return PublicKey.fromBytes(await ledger.getPublicKey());
|
|
335
|
+
}
|
|
336
|
+
async signMessage(message: Uint8Array): Promise<Signature> {
|
|
337
|
+
const sigBytes = await ledger.sign(message);
|
|
338
|
+
return Signature.fromBytes(sigBytes);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
317
341
|
|
|
318
|
-
|
|
319
|
-
const account0 = await mnemonic.toKeypair(0);
|
|
320
|
-
const account1 = await mnemonic.toKeypair(1);
|
|
321
|
-
const account2 = await mnemonic.toKeypair(2);
|
|
342
|
+
const signedTx = await tx.signWith(new LedgerSigner());
|
|
322
343
|
```
|
|
323
344
|
|
|
324
|
-
###
|
|
345
|
+
### Subscription workflows (REX)
|
|
346
|
+
|
|
347
|
+
REX subscriptions let a program trigger downstream transactions automatically. Use
|
|
348
|
+
`getSubscription` to inspect an active subscription and `getTriggeredTransactions` to
|
|
349
|
+
audit which transactions it has fired.
|
|
325
350
|
|
|
326
351
|
```typescript
|
|
327
|
-
|
|
328
|
-
const bytes = signedTx.serialize();
|
|
352
|
+
import { createRialoClient, RIALO_DEVNET_CHAIN } from "@rialo/ts-cdk";
|
|
329
353
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
354
|
+
const client = createRialoClient({ chain: RIALO_DEVNET_CHAIN });
|
|
355
|
+
|
|
356
|
+
// Look up a subscription by subscriber address and nonce
|
|
357
|
+
const subscription = await client.getSubscription(subscriberPubkey, nonce);
|
|
358
|
+
console.log("Topic:", subscription.topic);
|
|
359
|
+
console.log("Kind:", subscription.kind);
|
|
333
360
|
|
|
334
|
-
//
|
|
335
|
-
const
|
|
336
|
-
const
|
|
361
|
+
// List the last 10 transactions triggered by this subscription account
|
|
362
|
+
const triggered = await client.getTriggeredTransactions(subscriptionAccount, 10);
|
|
363
|
+
for (const tx of triggered) {
|
|
364
|
+
console.log(`sig=${tx.signature} block=${tx.blockNumber}`);
|
|
365
|
+
}
|
|
337
366
|
```
|
|
338
367
|
|
|
339
|
-
###
|
|
368
|
+
### Workflow lineage
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
const lineage = await client.getWorkflowLineage(request);
|
|
372
|
+
// lineage.nodes contains the DAG of related transactions.
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Error handling
|
|
340
376
|
|
|
341
377
|
```typescript
|
|
342
378
|
import { RialoError, RialoErrorType } from "@rialo/ts-cdk";
|
|
343
379
|
|
|
344
380
|
try {
|
|
345
|
-
await client.sendTransaction(
|
|
346
|
-
} catch (
|
|
347
|
-
if (
|
|
348
|
-
switch (
|
|
381
|
+
await client.sendTransaction(signedTx.serialize());
|
|
382
|
+
} catch (err) {
|
|
383
|
+
if (err instanceof RialoError) {
|
|
384
|
+
switch (err.type) {
|
|
385
|
+
case RialoErrorType.RPC:
|
|
386
|
+
console.error("Node error", err.details?.code, err.details?.message);
|
|
387
|
+
break;
|
|
349
388
|
case RialoErrorType.NETWORK:
|
|
350
|
-
|
|
389
|
+
console.error("Network failure:", err.cause);
|
|
351
390
|
break;
|
|
352
391
|
case RialoErrorType.INVALID_INPUT:
|
|
353
|
-
|
|
354
|
-
break;
|
|
355
|
-
case RialoErrorType.RPC:
|
|
356
|
-
// RPC specific error
|
|
357
|
-
console.log(error.details); // RPC error details
|
|
392
|
+
console.error("Bad argument:", err.message);
|
|
358
393
|
break;
|
|
394
|
+
default:
|
|
395
|
+
throw err;
|
|
359
396
|
}
|
|
360
397
|
}
|
|
361
398
|
}
|
|
362
399
|
```
|
|
363
400
|
|
|
364
|
-
###
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
401
|
+
### Error types
|
|
402
|
+
|
|
403
|
+
| `RialoErrorType` | Condition |
|
|
404
|
+
|---|---|
|
|
405
|
+
| `RPC` | Node rejected the request |
|
|
406
|
+
| `NETWORK` | HTTP/network failure |
|
|
407
|
+
| `TRANSACTION` | Transaction build or signing error |
|
|
408
|
+
| `WALLET` | Keypair load or create failure |
|
|
409
|
+
| `ENCRYPTION` | HPKE encryption/decryption failure |
|
|
410
|
+
| `BIP32` | HD key derivation error |
|
|
411
|
+
| `INVALID_INPUT` | Invalid parameter or data |
|
|
412
|
+
| `PARSE_PUBKEY` | Public key parse failure |
|
|
413
|
+
| `INVALID_BLOCKHASH_FORMAT` | Blockhash format error |
|
|
414
|
+
| `CONFIG` | Configuration load or parse failure |
|
|
415
|
+
| `JSON` | JSON parse error |
|
|
416
|
+
| `SERIALIZATION` | Borsh/bincode serialisation error |
|
|
417
|
+
| `PASSWORD` | Password validation failure |
|
|
418
|
+
|
|
419
|
+
## RPC reference
|
|
420
|
+
|
|
421
|
+
| Method | Returns | Notes |
|
|
422
|
+
|---|---|---|
|
|
423
|
+
| `getConfigHashPrefix()` | `ConfigHashPrefix` | Required for every `TransactionBuilder` |
|
|
424
|
+
| `getBalance(pubkey)` | `Kelvin` | Balance as `bigint` |
|
|
425
|
+
| `sendTransaction(bytes, opts?)` | `Signature` | Submit signed bytes |
|
|
426
|
+
| `sendAndConfirmTransaction(bytes, opts?)` | `ConfirmedTransaction` | Submit and poll |
|
|
427
|
+
| `confirmTransaction(sig, opts?)` | `ConfirmedTransaction` | Poll by signature |
|
|
428
|
+
| `getAccountInfo(pubkey)` | `AccountInfo` | Raw account data |
|
|
429
|
+
| `getMultipleAccounts(pubkeys)` | `OptionalAccountInfo[]` | Batch query |
|
|
430
|
+
| `getAccountsByOwner(owner, filter?)` | `[OwnerAccount[], PaginationInfo?]` | Program accounts |
|
|
431
|
+
| `getBlockHeight()` | `bigint` | Finalized height |
|
|
432
|
+
| `getTransaction(sig)` | `TransactionResponse` | By signature |
|
|
433
|
+
| `getEpochInfo()` | `EpochInfo` | Current epoch |
|
|
434
|
+
| `getSignaturesForAddress(pubkey)` | `SignatureInfo[]` | Transaction history for an account |
|
|
435
|
+
| `requestAirdrop(pubkey, kelvin)` | `Signature` | Devnet/testnet only |
|
|
436
|
+
| `requestAirdropAndConfirm(pubkey, kelvin)` | `ConfirmedTransaction` | Airdrop + wait |
|
|
437
|
+
| `getFeeForMessage(base64Msg)` | `FeeResponse` | Estimate fee before sending |
|
|
438
|
+
| `getMinimumBalanceForRentExemption(size)` | `bigint` | Rent-exempt threshold |
|
|
439
|
+
| `getSecretSharingPubkey()` | `SecretSharingPubkey` | TEE HPKE public key |
|
|
440
|
+
| `getWorkflowLineage(req)` | `GetWorkflowLineageResponse` | Workflow DAG traversal |
|
|
441
|
+
| `getSubscription(subscriber, nonce)` | `Subscription` | REX subscription lookup |
|
|
442
|
+
| `getTriggeredTransactions(account, limit?)` | `TriggeredTransaction[]` | Subscription-triggered txs |
|
|
387
443
|
|
|
388
444
|
## Constants
|
|
389
445
|
|
|
390
446
|
```typescript
|
|
391
447
|
import {
|
|
392
|
-
KELVIN_PER_RLO,
|
|
393
|
-
SYSTEM_PROGRAM_ID,
|
|
394
|
-
PUBLIC_KEY_LENGTH,
|
|
395
|
-
SECRET_KEY_LENGTH,
|
|
396
|
-
SIGNATURE_LENGTH,
|
|
448
|
+
KELVIN_PER_RLO, // 1_000_000_000
|
|
449
|
+
SYSTEM_PROGRAM_ID, // "11111111111111111111111111111111"
|
|
450
|
+
PUBLIC_KEY_LENGTH, // 32
|
|
451
|
+
SECRET_KEY_LENGTH, // 32
|
|
452
|
+
SIGNATURE_LENGTH, // 64
|
|
453
|
+
URL_MAINNET, // "https://mainnet.rialo.io:4101"
|
|
454
|
+
URL_TESTNET, // "https://testnet.rialo.io:4101"
|
|
455
|
+
URL_DEVNET, // "https://devnet.rialo.io:4101"
|
|
456
|
+
URL_LOCALNET, // "http://localhost:4104"
|
|
397
457
|
} from "@rialo/ts-cdk";
|
|
458
|
+
|
|
459
|
+
// Currency conversion (KELVIN_PER_RLO is a number; use BigInt() when passing to RPC methods)
|
|
460
|
+
const kelvin = BigInt(Math.round(1.5 * KELVIN_PER_RLO)); // 1.5 RLO → 1_500_000_000n kelvin
|
|
398
461
|
```
|
|
399
462
|
|
|
400
|
-
##
|
|
463
|
+
## Caveats
|
|
401
464
|
|
|
402
|
-
|
|
465
|
+
- **`configHashPrefix`** — `TransactionBuilder.setConfigHashPrefix()` is required.
|
|
466
|
+
Omitting it or using a stale value causes the node to reject the transaction with a
|
|
467
|
+
replay-protection error.
|
|
403
468
|
|
|
404
|
-
-
|
|
405
|
-
|
|
406
|
-
- `03-transaction-operations.ts` - Transaction building and signing
|
|
407
|
-
- `05-alice-bob-transaction.ts` - Complete transfer workflow with RPC
|
|
469
|
+
- **Currency units** — all RPC amounts are in *kelvin*; 1 RLO = `KELVIN_PER_RLO`
|
|
470
|
+
(1 000 000 000) kelvin. The `transferInstruction` helper takes kelvin as `bigint`.
|
|
408
471
|
|
|
409
|
-
|
|
472
|
+
- **Derivation path** — Rialo uses BIP44 coin type 756. `Mnemonic.toKeypair(index)` uses
|
|
473
|
+
`m/44'/756'/{index}'/0'`. Keys derived on other coin types are not compatible.
|
|
410
474
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
```
|
|
475
|
+
- **Keypair disposal** — call `keypair.dispose()` (and `keyring.dispose()`) when the
|
|
476
|
+
keypair is no longer needed. After disposal, signing methods throw `CryptoError`.
|
|
414
477
|
|
|
415
|
-
|
|
478
|
+
- **PDA seeds** — strings are UTF-8-encoded; `Uint8Array` seeds are used as-is. A seed
|
|
479
|
+
exceeding 32 bytes throws `CryptoError.MAX_SEED_LENGTH_EXCEEDED`.
|
|
416
480
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
pnpm install
|
|
481
|
+
- **Node.js version** — requires Node.js ≥ 18 for the native `crypto` module and
|
|
482
|
+
`TextEncoder`/`TextDecoder` globals.
|
|
420
483
|
|
|
421
|
-
|
|
422
|
-
|
|
484
|
+
- **`AccountMetaTable`** — used internally by `TransactionBuilder` to deduplicate account
|
|
485
|
+
references in a compiled `Message`. Constructing it manually is only needed for
|
|
486
|
+
advanced multi-program transactions.
|
|
423
487
|
|
|
424
|
-
|
|
425
|
-
pnpm test
|
|
488
|
+
## Development
|
|
426
489
|
|
|
427
|
-
|
|
428
|
-
pnpm
|
|
490
|
+
```bash
|
|
491
|
+
pnpm install
|
|
492
|
+
pnpm build # compiles ESM + CJS bundles to dist/
|
|
493
|
+
pnpm test # runs vitest suite
|
|
494
|
+
pnpm lint # biome check
|
|
429
495
|
```
|
|
430
496
|
|
|
431
|
-
##
|
|
432
|
-
|
|
433
|
-
- Private keys stored as `Uint8Array` in memory
|
|
434
|
-
- Uses `@noble/curves` and `@noble/hashes` for cryptography
|
|
435
|
-
- Call `keypair.dispose()` to zero out private keys
|
|
436
|
-
- Never commit private keys or mnemonics
|
|
437
|
-
- Use environment variables for sensitive data
|
|
438
|
-
|
|
439
|
-
## License
|
|
497
|
+
## See also
|
|
440
498
|
|
|
441
|
-
|
|
499
|
+
- [`rialo-cdk`](../rialo-rs-cdk/README.md) — underlying Rust crate; source of truth for wire format and error codes
|
|
500
|
+
- [`rialo-py-cdk`](../rialo-py-cdk/README.md) — Python bindings with equivalent API surface
|
|
501
|
+
- `developer-frameworks/cdk/spec.wit` — WIT specification from which the RPC surface is derived
|
|
502
|
+
- `developer-frameworks/cdk/rialo-ts-cdk/examples/` — runnable end-to-end examples
|