dedot 0.0.1-alpha.26 → 0.0.1-alpha.27
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 +130 -18
- package/cjs/client/Dedot.js +23 -34
- package/cjs/executor/ConstantExecutor.js +1 -1
- package/cjs/executor/ErrorExecutor.js +1 -1
- package/cjs/executor/EventExecutor.js +1 -1
- package/cjs/executor/RpcExecutor.js +6 -5
- package/cjs/executor/RuntimeApiExecutor.js +9 -15
- package/cjs/executor/TxExecutor.js +8 -8
- package/cjs/extrinsic/extensions/ExtraSignedExtension.js +7 -7
- package/cjs/extrinsic/extensions/SignedExtension.js +2 -2
- package/cjs/extrinsic/extensions/known/ChargeAssetTxPayment.js +3 -3
- package/cjs/extrinsic/extensions/known/ChargeTransactionPayment.js +2 -2
- package/cjs/extrinsic/extensions/known/CheckMortality.js +1 -1
- package/cjs/index.js +1 -3
- package/cjs/packageInfo.js +1 -1
- package/cjs/storage/QueryableStorage.js +7 -7
- package/client/Dedot.d.ts +2 -2
- package/client/Dedot.js +25 -33
- package/executor/ConstantExecutor.js +1 -1
- package/executor/ErrorExecutor.js +1 -1
- package/executor/EventExecutor.js +1 -1
- package/executor/Executor.d.ts +1 -1
- package/executor/RpcExecutor.js +6 -5
- package/executor/RuntimeApiExecutor.d.ts +4 -1
- package/executor/RuntimeApiExecutor.js +9 -15
- package/executor/TxExecutor.d.ts +5 -5
- package/executor/TxExecutor.js +6 -6
- package/extrinsic/extensions/ExtraSignedExtension.js +7 -7
- package/extrinsic/extensions/SignedExtension.d.ts +3 -3
- package/extrinsic/extensions/SignedExtension.js +2 -2
- package/extrinsic/extensions/known/ChargeAssetTxPayment.js +5 -5
- package/extrinsic/extensions/known/ChargeTransactionPayment.js +2 -2
- package/extrinsic/extensions/known/CheckMortality.js +2 -2
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/package.json +11 -11
- package/packageInfo.js +1 -1
- package/storage/QueryableStorage.d.ts +3 -3
- package/storage/QueryableStorage.js +5 -5
- package/types.d.ts +10 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# dedot
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A delightful JavaScript/TypeScript client for [Polkadot](https://polkadot.network/) & [Substrate](https://substrate.io/)
|
|
4
4
|
|
|
5
5
|
<p align="left">
|
|
6
6
|
<img src="https://img.shields.io/github/license/dedotdev/dedot?style=flat-square"/>
|
|
@@ -46,8 +46,7 @@ const run = async () => {
|
|
|
46
46
|
console.log('Metadata:', metadata);
|
|
47
47
|
|
|
48
48
|
// Query on-chain storage
|
|
49
|
-
const
|
|
50
|
-
const balance = await api.query.system.account(address);
|
|
49
|
+
const balance = await api.query.system.account(<address>);
|
|
51
50
|
console.log('Balance:', balance);
|
|
52
51
|
|
|
53
52
|
|
|
@@ -58,7 +57,11 @@ const run = async () => {
|
|
|
58
57
|
|
|
59
58
|
// Get pallet constants
|
|
60
59
|
const ss58Prefix = api.consts.system.ss58Prefix;
|
|
61
|
-
console.log('Polkadot ss58Prefix:', ss58Prefix)
|
|
60
|
+
console.log('Polkadot ss58Prefix:', ss58Prefix);
|
|
61
|
+
|
|
62
|
+
// Call runtime api
|
|
63
|
+
const pendingRewards = await api.call.nominationPoolsApi.pendingRewards(<address>)
|
|
64
|
+
console.log('Pending rewards:', pendingRewards);
|
|
62
65
|
|
|
63
66
|
// await unsub();
|
|
64
67
|
// await api.disconnect();
|
|
@@ -80,8 +83,8 @@ const api = await Dedot.new('wss://rpc.polkadot.io');
|
|
|
80
83
|
- [Execute RPC Methods](#execute-rpc-methods)
|
|
81
84
|
- [Query On-chain Storage](#query-on-chain-storage)
|
|
82
85
|
- [Constants](#constants)
|
|
83
|
-
- [Runtime APIs
|
|
84
|
-
- [Submit Transactions
|
|
86
|
+
- [Runtime APIs](#runtime-apis)
|
|
87
|
+
- [Submit Transactions](#transaction-apis)
|
|
85
88
|
- [Events](#events)
|
|
86
89
|
- [Errors](#errors)
|
|
87
90
|
- [Credit](#credit)
|
|
@@ -91,10 +94,10 @@ const api = await Dedot.new('wss://rpc.polkadot.io');
|
|
|
91
94
|
| Feature | Status |
|
|
92
95
|
|-------------------------------------------------------| ----------- |
|
|
93
96
|
| Execute RPC (`api.rpc`) | ✅ |
|
|
94
|
-
| Query
|
|
97
|
+
| Query On-chain Storage (`api.query`) | ✅ |
|
|
95
98
|
| Get runtime constants (`api.consts`) | ✅ |
|
|
96
|
-
| Runtime APIs (`api.call`) |
|
|
97
|
-
| Transaction APIs (`api.tx`) |
|
|
99
|
+
| Runtime APIs (`api.call`) | ✅ |
|
|
100
|
+
| Transaction APIs (`api.tx`) | ✅ |
|
|
98
101
|
| Events (`api.events`) | ✅ |
|
|
99
102
|
| Errors (`api.errors`) | ✅ |
|
|
100
103
|
| Contract APIs | ⏳ |
|
|
@@ -139,11 +142,22 @@ const genericApi = await Dedot.new('ws://localhost:9944');
|
|
|
139
142
|
// ...
|
|
140
143
|
```
|
|
141
144
|
|
|
142
|
-
|
|
145
|
+
Supported `ChainApi` interfaces are defined [here](https://github.com/dedotdev/dedot/blob/main/packages/chaintypes/src/index.ts), you can also generate the `ChainApi` interface for the chain you want to connect with using `@dedot/cli`.
|
|
146
|
+
|
|
147
|
+
```shell
|
|
148
|
+
# Install @dedot/cli via yarn
|
|
149
|
+
yarn add -D @dedot/cli
|
|
150
|
+
|
|
151
|
+
# Or via npm
|
|
152
|
+
npm i -D @dedot/cli
|
|
153
|
+
|
|
154
|
+
# Generate ChainApi interface for Polkadot network via rpc endpoint: wss://rpc.polkadot.io
|
|
155
|
+
npx dedot chaintypes -w wss://rpc.polkadot.io
|
|
156
|
+
```
|
|
143
157
|
|
|
144
158
|
### Execute RPC Methods
|
|
145
159
|
|
|
146
|
-
RPCs can be
|
|
160
|
+
RPCs can be executed via `api.rpc` entry point. After creating a `Dedot` instance with a `ChainApi` interface of the network you want to interact with, all RPC methods of the network will be exposed in the autocompletion/suggestion with format: `api.rpc.<module>.<methodName>`. E.g: you can find all supported RPC methods for Polkadot network [here](https://github.com/dedotdev/dedot/blob/main/packages/chaintypes/src/polkadot/rpc.d.ts), similarly for other networks as well.
|
|
147
161
|
|
|
148
162
|
Examples:
|
|
149
163
|
```typescript
|
|
@@ -156,7 +170,7 @@ const result = await api.rpc.module.rpc_name('param1', 'param2');
|
|
|
156
170
|
|
|
157
171
|
### Query On-chain Storage
|
|
158
172
|
|
|
159
|
-
On-chain storage can be
|
|
173
|
+
On-chain storage can be queried via `api.query` entry point. All the available storage entries for a chain are exposed in the `ChainApi` interface for that chain and can be executed with format: `api.query.<pallet>.<storgeEntry>`. E.g: You can find all the available storage queries of Polkadot network [here](https://github.com/dedotdev/dedot/blob/main/packages/chaintypes/src/polkadot/query.d.ts), similarly for other networks as well.
|
|
160
174
|
|
|
161
175
|
Examples:
|
|
162
176
|
```typescript
|
|
@@ -168,7 +182,7 @@ const events = await api.query.system.events();
|
|
|
168
182
|
```
|
|
169
183
|
### Constants
|
|
170
184
|
|
|
171
|
-
Runtime constants (parameter types) are defined in metadata, and can be
|
|
185
|
+
Runtime constants (parameter types) are defined in metadata, and can be inspected via `api.consts` entry point with format: `api.consts.<pallet>.<constantName>`. All available constants are also exposed in the `ChainApi` interface. E.g: Available constants for Polkadot network is defined [here](https://github.com/dedotdev/dedot/blob/main/packages/chaintypes/src/polkadot/consts.d.ts), similarly for other networks.
|
|
172
186
|
|
|
173
187
|
Examples:
|
|
174
188
|
```typescript
|
|
@@ -181,15 +195,113 @@ const existentialDeposit = api.consts.balances.existentialDeposit;
|
|
|
181
195
|
|
|
182
196
|
### Runtime APIs
|
|
183
197
|
|
|
184
|
-
|
|
198
|
+
The latest stable Metadata V15 now includes all the runtime apis type information. So for chains that are supported Metadata V15, we can now execute all available runtime apis with syntax `api.call.<runtimeApi>.<methodName>`, those apis are exposed in `ChainApi` interface. E.g: Runtime Apis for Polkadot network is defined [here](https://github.com/dedotdev/dedot/blob/main/packages/chaintypes/src/polkadot/runtime.d.ts), similarly for other networks as well.
|
|
199
|
+
|
|
200
|
+
Examples:
|
|
201
|
+
```typescript
|
|
202
|
+
// Get account nonce
|
|
203
|
+
const nonce = await api.call.accountNonceApi.accountNonce(<address>);
|
|
204
|
+
|
|
205
|
+
// Query transaction payment info
|
|
206
|
+
const tx = api.tx.balances.transferKeepAlive(<address>, 2_000_000_000_000n);
|
|
207
|
+
const queryInfo = await api.call.transactionPaymentApi.queryInfo(tx.toU8a(), tx.length);
|
|
208
|
+
|
|
209
|
+
// Get runtime version
|
|
210
|
+
const runtimeVersion = await api.call.core.version();
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
For chains that only support Metadata V14, we need to bring in the Runtime Api definitions when initializing the Dedot client instance to encode & decode the calls. You can find all supported Runtime Api definitions in [`@dedot/specs`](https://github.com/dedotdev/dedot/blob/60de0fed8ba19c67a7e174c6168a127fdbf6caef/packages/specs/src/runtime/all.ts#L21-L39) package.
|
|
214
|
+
|
|
215
|
+
Examples:
|
|
216
|
+
```typescript
|
|
217
|
+
import { RuntimeApis } from '@dedot/specs';
|
|
218
|
+
const api = await Dedot.new({ endpoint: 'wss://rpc.mynetwork.com', runtimeApis: RuntimeApis });
|
|
219
|
+
|
|
220
|
+
// Or bring in only the Runtime Api definition that you want to interact with
|
|
221
|
+
import { AccountNonceApi } from '@dedot/specs';
|
|
222
|
+
const api = await Dedot.new({ endpoint: 'wss://rpc.mynetwork.com', runtimeApis: { AccountNonceApi } });
|
|
223
|
+
|
|
224
|
+
// Get account nonce
|
|
225
|
+
const nonce = await api.call.accountNonceApi.accountNonce(<address>);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
You absolutely can define your own Runtime Api definition if you don't find it in the [supported list](https://github.com/dedotdev/dedot/blob/60de0fed8ba19c67a7e174c6168a127fdbf6caef/packages/specs/src/runtime/all.ts#L21-L39).
|
|
229
|
+
|
|
230
|
+
### Transaction APIs
|
|
185
231
|
|
|
186
|
-
|
|
232
|
+
Transaction apis are designed to be compatible with [`IKeyringPair`](https://github.com/polkadot-js/api/blob/3bdf49b0428a62f16b3222b9a31bfefa43c1ca55/packages/types/src/types/interfaces.ts#L15-L21) and [`Signer`](https://github.com/polkadot-js/api/blob/3bdf49b0428a62f16b3222b9a31bfefa43c1ca55/packages/types/src/types/extrinsic.ts#L135-L150) interfaces, so you can sign the transactions with accounts created by a [`Keyring`](https://github.com/polkadot-js/common/blob/22aab4a4e62944a2cf8c885f50be2c1b842813ec/packages/keyring/src/keyring.ts#L41-L40) or from any [Polkadot{.js}-based](https://github.com/polkadot-js/extension?tab=readme-ov-file#api-interface) wallet extensions.
|
|
187
233
|
|
|
188
|
-
|
|
234
|
+
All transaction apis are exposed in `ChainApi` interface and can be access with syntax: `api.tx.<pallet>.<transactionName>`. E.g: Available transaction apis for Polkadot network are defined [here](https://github.com/dedotdev/dedot/blob/516c5dd948ac89ef53644b7fb1f62df1727adadb/packages/chaintypes/src/polkadot/tx.d.ts), similarly for other networks as well.
|
|
235
|
+
|
|
236
|
+
Example 1: Sign transaction with a Keying account
|
|
237
|
+
```typescript
|
|
238
|
+
import { cryptoWaitReady } from '@polkadot/util-crypto';
|
|
239
|
+
import { Keyring } from '@polkadot/keyring';
|
|
240
|
+
...
|
|
241
|
+
await cryptoWaitReady();
|
|
242
|
+
const keyring = new Keyring({ type: 'sr25519' });
|
|
243
|
+
const alice = keyring.addFromUri('//Alice');
|
|
244
|
+
|
|
245
|
+
const unsub = await api.tx.balances
|
|
246
|
+
.transferKeepAlive(<destAddress>, 2_000_000_000_000n)
|
|
247
|
+
.signAndSend(alice, async ({ status }) => {
|
|
248
|
+
console.log('Transaction status', status.tag);
|
|
249
|
+
if (status.tag === 'InBlock') {
|
|
250
|
+
console.log(`Transaction completed at block hash ${status.value}`);
|
|
251
|
+
await unsub();
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Example 2: Sign transaction using `Signer` from Polkadot{.js} wallet extension
|
|
257
|
+
```typescript
|
|
258
|
+
const injected = await window.injectedWeb3['polkadot-js'].enable('A cool dapp');
|
|
259
|
+
const account = (await injected.accounts.get())[0];
|
|
260
|
+
const signer = injected.signer;
|
|
261
|
+
|
|
262
|
+
const unsub = await api.tx.balances
|
|
263
|
+
.transferKeepAlive(<destAddress>, 2_000_000_000_000n)
|
|
264
|
+
.signAndSend(account.address, { signer }, async ({ status }) => {
|
|
265
|
+
console.log('Transaction status', status.tag);
|
|
266
|
+
if (status.tag === 'InBlock') {
|
|
267
|
+
console.log(`Transaction completed at block hash ${status.value}`);
|
|
268
|
+
await unsub();
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Example 3: Submit a batch transaction
|
|
274
|
+
```typescript
|
|
275
|
+
import type { PolkadotRuntimeRuntimeCallLike } from '@dedot/chaintypes/polkadot';
|
|
276
|
+
|
|
277
|
+
// Omit the detail for simplicity
|
|
278
|
+
const account = ...;
|
|
279
|
+
const signer = ...;
|
|
280
|
+
|
|
281
|
+
const transferTx = api.tx.balances.transferKeepAlive(<destAddress>, 2_000_000_000_000n);
|
|
282
|
+
const remarkCall: PolkadotRuntimeRuntimeCallLike = {
|
|
283
|
+
pallet: 'System',
|
|
284
|
+
palletCall: {
|
|
285
|
+
name: 'RemarkWithEvent',
|
|
286
|
+
params: {
|
|
287
|
+
remark: 'Hello Dedot!',
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const unsub = api.tx.utility.batch([transferTx.call, remarkCall])
|
|
293
|
+
.signAndSend(account.address, { signer }, async ({ status }) => {
|
|
294
|
+
console.log('Transaction status', status.tag);
|
|
295
|
+
if (status.tag === 'InBlock') {
|
|
296
|
+
console.log(`Transaction completed at block hash ${status.value}`);
|
|
297
|
+
await unsub();
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
```
|
|
189
301
|
|
|
190
302
|
### Events
|
|
191
303
|
|
|
192
|
-
Events for each pallet emit during runtime operations and are defined in the medata. Available events are also exposed in `ChainApi` interface so we can get information of an event through syntax `api.events.<pallet>.<eventName>`. E.g: Events for Polkadot network can be found [here](https://github.com/dedotdev/dedot/blob/main/packages/chaintypes/src/polkadot/events.ts), similarly for other network as well.
|
|
304
|
+
Events for each pallet emit during runtime operations and are defined in the medata. Available events are also exposed in `ChainApi` interface so we can get information of an event through syntax `api.events.<pallet>.<eventName>`. E.g: Events for Polkadot network can be found [here](https://github.com/dedotdev/dedot/blob/main/packages/chaintypes/src/polkadot/events.d.ts), similarly for other network as well.
|
|
193
305
|
|
|
194
306
|
This `api.events` is helpful when we want quickly check if an event matches with an event that we're expecting in a list of events, the API also comes with type narrowing for the matched event, so event name & related data of the event are fully typed.
|
|
195
307
|
|
|
@@ -213,7 +325,7 @@ await api.query.system.events(async (eventRecords) => {
|
|
|
213
325
|
|
|
214
326
|
### Errors
|
|
215
327
|
|
|
216
|
-
Pallet errors are thrown out when things go wrong in the runtime, those are defined in the metadata. Available errors for each pallet are also exposed in `ChainApi` interface, so we can get information an error through this syntax: `api.errors.<pallet>.<errorName>`. E.g: Available errors for Polkadot network can be found [here](https://github.com/dedotdev/dedot/blob/main/packages/chaintypes/src/polkadot/errors.ts).
|
|
328
|
+
Pallet errors are thrown out when things go wrong in the runtime, those are defined in the metadata. Available errors for each pallet are also exposed in `ChainApi` interface, so we can get information an error through this syntax: `api.errors.<pallet>.<errorName>`. E.g: Available errors for Polkadot network can be found [here](https://github.com/dedotdev/dedot/blob/main/packages/chaintypes/src/polkadot/errors.d.ts).
|
|
217
329
|
|
|
218
330
|
Similar to events API, this API is helpful when we want to check if an error maches with an error that we're expecting.
|
|
219
331
|
|
package/cjs/client/Dedot.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.Dedot = exports.SUPPORTED_METADATA_VERSIONS = exports.CATCH_ALL_METADATA_KEY = exports.KEEP_ALIVE_INTERVAL = void 0;
|
|
7
4
|
const rpc_provider_1 = require("@polkadot/rpc-provider");
|
|
8
5
|
const codecs_1 = require("@dedot/codecs");
|
|
9
6
|
const executor_1 = require("../executor");
|
|
10
7
|
const proxychain_1 = require("../proxychain");
|
|
11
|
-
const utils_1 = require("@dedot/utils");
|
|
12
|
-
const localforage_1 = __importDefault(require("localforage"));
|
|
13
8
|
const util_1 = require("@polkadot/util");
|
|
9
|
+
const storage_1 = require("@dedot/storage");
|
|
10
|
+
const utils_1 = require("@dedot/utils");
|
|
14
11
|
exports.KEEP_ALIVE_INTERVAL = 10_000; // in ms
|
|
15
12
|
exports.CATCH_ALL_METADATA_KEY = `RAW_META/ALL`;
|
|
16
13
|
exports.SUPPORTED_METADATA_VERSIONS = [15, 14];
|
|
@@ -54,8 +51,8 @@ exports.SUPPORTED_METADATA_VERSIONS = [15, 14];
|
|
|
54
51
|
*/
|
|
55
52
|
class Dedot {
|
|
56
53
|
#provider;
|
|
57
|
-
#registry;
|
|
58
54
|
#options;
|
|
55
|
+
#registry;
|
|
59
56
|
#metadata;
|
|
60
57
|
#metadataLatest;
|
|
61
58
|
#genesisHash;
|
|
@@ -74,7 +71,6 @@ class Dedot {
|
|
|
74
71
|
constructor(options) {
|
|
75
72
|
this.#options = this.#normalizeOptions(options);
|
|
76
73
|
this.#provider = this.#getProvider();
|
|
77
|
-
this.#registry = new codecs_1.CodecRegistry();
|
|
78
74
|
}
|
|
79
75
|
/**
|
|
80
76
|
* Factory method to create a new Dedot instance
|
|
@@ -117,24 +113,18 @@ class Dedot {
|
|
|
117
113
|
this.#subscribeUpdates();
|
|
118
114
|
}
|
|
119
115
|
async #initializeLocalCache() {
|
|
116
|
+
if (!this.#options.cacheMetadata)
|
|
117
|
+
return;
|
|
120
118
|
// Initialize local cache
|
|
121
|
-
if (this.#options.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
await this.#localCache.setItem('testKey', 'testValue');
|
|
131
|
-
await this.#localCache.removeItem('testKey');
|
|
132
|
-
}
|
|
133
|
-
catch (e) {
|
|
134
|
-
this.#localCache = undefined;
|
|
135
|
-
this.#options.cacheMetadata = false;
|
|
136
|
-
console.error('Cannot initialize local cache in this environment, disable metadata caching');
|
|
137
|
-
}
|
|
119
|
+
if (this.#options.cacheStorage) {
|
|
120
|
+
this.#localCache = this.#options.cacheStorage;
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
this.#localCache = new storage_1.LocalStorage();
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
throw new Error('localStorage is not available for caching, please provide a cacheStorage option');
|
|
138
128
|
}
|
|
139
129
|
}
|
|
140
130
|
async #setupMetadata(preloadMetadata) {
|
|
@@ -152,7 +142,7 @@ class Dedot {
|
|
|
152
142
|
if (this.#localCache && this.#options.cacheMetadata) {
|
|
153
143
|
if (!metadata) {
|
|
154
144
|
try {
|
|
155
|
-
const cachedRawMetadata = await this.#localCache.
|
|
145
|
+
const cachedRawMetadata = await this.#localCache.get(metadataKey);
|
|
156
146
|
if (cachedRawMetadata) {
|
|
157
147
|
metadata = codecs_1.$Metadata.tryDecode(cachedRawMetadata);
|
|
158
148
|
}
|
|
@@ -171,7 +161,7 @@ class Dedot {
|
|
|
171
161
|
}
|
|
172
162
|
}
|
|
173
163
|
if (shouldUpdateCache && this.#localCache) {
|
|
174
|
-
await this.#localCache.
|
|
164
|
+
await this.#localCache.set(metadataKey, (0, util_1.u8aToHex)(codecs_1.$Metadata.tryEncode(metadata)));
|
|
175
165
|
}
|
|
176
166
|
if (!metadata) {
|
|
177
167
|
throw new Error('Cannot load metadata');
|
|
@@ -270,17 +260,16 @@ class Dedot {
|
|
|
270
260
|
}
|
|
271
261
|
#getProvider() {
|
|
272
262
|
const { provider, endpoint } = this.#options;
|
|
273
|
-
if (provider)
|
|
263
|
+
if (provider) {
|
|
264
|
+
(0, utils_1.assert)(provider.hasSubscriptions, 'Only supports RPC Provider can make subscription requests');
|
|
274
265
|
return provider;
|
|
266
|
+
}
|
|
275
267
|
if (endpoint) {
|
|
276
268
|
if (endpoint.startsWith('ws://') || endpoint.startsWith('wss://')) {
|
|
277
269
|
return new rpc_provider_1.WsProvider(endpoint);
|
|
278
270
|
}
|
|
279
|
-
else if (endpoint.startsWith('http://') || endpoint.startsWith('https://')) {
|
|
280
|
-
return new rpc_provider_1.HttpProvider(endpoint);
|
|
281
|
-
}
|
|
282
271
|
else {
|
|
283
|
-
throw new Error('Invalid network endpoint, a valid endpoint should start with `wss://`, `ws
|
|
272
|
+
throw new Error('Invalid RPC network endpoint, a valid endpoint should start with `wss://`, `ws://`');
|
|
284
273
|
}
|
|
285
274
|
}
|
|
286
275
|
// TODO support light-client
|
|
@@ -368,10 +357,10 @@ class Dedot {
|
|
|
368
357
|
return !!this.#metadata && !!this.#metadataLatest;
|
|
369
358
|
}
|
|
370
359
|
get metadata() {
|
|
371
|
-
return
|
|
360
|
+
return this.#metadata;
|
|
372
361
|
}
|
|
373
362
|
get metadataLatest() {
|
|
374
|
-
return
|
|
363
|
+
return this.#metadataLatest;
|
|
375
364
|
}
|
|
376
365
|
/**
|
|
377
366
|
* Setup metadata for
|
|
@@ -380,7 +369,7 @@ class Dedot {
|
|
|
380
369
|
setMetadata(metadata) {
|
|
381
370
|
this.#metadata = metadata;
|
|
382
371
|
this.#metadataLatest = metadata.latest;
|
|
383
|
-
this
|
|
372
|
+
this.#registry = new codecs_1.PortableRegistry(this.#metadataLatest);
|
|
384
373
|
}
|
|
385
374
|
/**
|
|
386
375
|
* @description Disconnect to blockchain node
|
|
@@ -15,7 +15,7 @@ class ConstantExecutor extends Executor_1.Executor {
|
|
|
15
15
|
if (!constantDef) {
|
|
16
16
|
throw new Error(`Constant ${constantName} not found in pallet ${pallet}`);
|
|
17
17
|
}
|
|
18
|
-
const $codec = this.registry.
|
|
18
|
+
const $codec = this.registry.findCodec(constantDef.typeId);
|
|
19
19
|
return $codec.tryDecode(constantDef.value);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -40,7 +40,7 @@ class ErrorExecutor extends Executor_1.Executor {
|
|
|
40
40
|
(0, utils_1.assert)(errorDef, `Error def not found for ${errorName}`);
|
|
41
41
|
return {
|
|
42
42
|
...errorDef,
|
|
43
|
-
fieldCodecs: errorDef.fields.map(({ typeId }) => this.registry.
|
|
43
|
+
fieldCodecs: errorDef.fields.map(({ typeId }) => this.registry.findCodec(typeId)),
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -46,7 +46,7 @@ class EventExecutor extends Executor_1.Executor {
|
|
|
46
46
|
(0, utils_1.assert)(eventDef, `Event def not found for ${errorName}`);
|
|
47
47
|
return {
|
|
48
48
|
...eventDef,
|
|
49
|
-
fieldCodecs: eventDef.fields.map(({ typeId }) => this.registry.
|
|
49
|
+
fieldCodecs: eventDef.fields.map(({ typeId }) => this.registry.findCodec(typeId)),
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -68,9 +68,10 @@ class RpcExecutor extends Executor_1.Executor {
|
|
|
68
68
|
// We use `undefined` to represent Option::None in the client
|
|
69
69
|
return undefined;
|
|
70
70
|
}
|
|
71
|
-
const { type, isScale } = callSpec;
|
|
71
|
+
const { type, isScale, codec } = callSpec;
|
|
72
72
|
if (isScale) {
|
|
73
|
-
|
|
73
|
+
(0, utils_1.assert)(codec, 'Codec not found to decode response');
|
|
74
|
+
return codec.tryDecode(raw);
|
|
74
75
|
}
|
|
75
76
|
if ((0, utils_1.isNativeType)(type)) {
|
|
76
77
|
return raw;
|
|
@@ -78,13 +79,13 @@ class RpcExecutor extends Executor_1.Executor {
|
|
|
78
79
|
return raw;
|
|
79
80
|
}
|
|
80
81
|
tryEncode(paramSpec, value) {
|
|
81
|
-
const {
|
|
82
|
+
const { isScale, codec, isOptional } = paramSpec;
|
|
82
83
|
if (isScale) {
|
|
83
84
|
if (isOptional && (value === undefined || value === null)) {
|
|
84
85
|
return null;
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
-
return (0, util_1.u8aToHex)(
|
|
87
|
+
(0, utils_1.assert)(codec, 'Codec not found to encode params');
|
|
88
|
+
return (0, util_1.u8aToHex)(codec.tryEncode(value));
|
|
88
89
|
}
|
|
89
90
|
// TODO generalize this!
|
|
90
91
|
if (value && value['toJSON']) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RuntimeApiExecutor = exports.FallbackRuntimeApis = void 0;
|
|
3
|
+
exports.RuntimeApiExecutor = exports.FallbackRuntimeApiSpecs = exports.FallbackRuntimeApis = void 0;
|
|
4
4
|
const Executor_1 = require("./Executor");
|
|
5
5
|
const utils_1 = require("@dedot/utils");
|
|
6
6
|
const util_1 = require("@polkadot/util");
|
|
@@ -8,13 +8,14 @@ const specs_1 = require("@dedot/specs");
|
|
|
8
8
|
exports.FallbackRuntimeApis = [
|
|
9
9
|
['0x37e397fc7c91f5e4', 2], // Metadata Api v2
|
|
10
10
|
];
|
|
11
|
+
exports.FallbackRuntimeApiSpecs = { Metadata: specs_1.Metadata };
|
|
11
12
|
class RuntimeApiExecutor extends Executor_1.Executor {
|
|
12
13
|
execute(runtimeApi, method) {
|
|
13
14
|
const runtimeApiName = (0, util_1.stringPascalCase)(runtimeApi);
|
|
14
15
|
const methodName = (0, utils_1.stringSnakeCase)(method);
|
|
15
16
|
const callName = this.#callName({ runtimeApiName, methodName });
|
|
16
17
|
const callSpec = this.#findRuntimeApiMethodSpec(runtimeApiName, methodName);
|
|
17
|
-
(0, utils_1.assert)(callSpec, `Runtime
|
|
18
|
+
(0, utils_1.assert)(callSpec, `Runtime api spec not found for ${callName}`);
|
|
18
19
|
const callFn = async (...args) => {
|
|
19
20
|
const { params } = callSpec;
|
|
20
21
|
const formattedInputs = params.map((param, index) => this.tryEncode(param, args[index]));
|
|
@@ -42,10 +43,7 @@ class RuntimeApiExecutor extends Executor_1.Executor {
|
|
|
42
43
|
if (codec)
|
|
43
44
|
return codec;
|
|
44
45
|
if ((0, util_1.isNumber)(typeId)) {
|
|
45
|
-
return this.registry.
|
|
46
|
-
}
|
|
47
|
-
if (type) {
|
|
48
|
-
return this.registry.findCodec(type);
|
|
46
|
+
return this.registry.findCodec(typeId);
|
|
49
47
|
}
|
|
50
48
|
throw new Error(error || 'Codec not found');
|
|
51
49
|
}
|
|
@@ -56,14 +54,14 @@ class RuntimeApiExecutor extends Executor_1.Executor {
|
|
|
56
54
|
const targetVersion = this.#findTargetRuntimeApiVersion(runtimeApi);
|
|
57
55
|
if (!(0, util_1.isNumber)(targetVersion))
|
|
58
56
|
return undefined;
|
|
59
|
-
const userDefinedSpec = this.#
|
|
57
|
+
const userDefinedSpec = this.#findDefinedSpec(this.api.options.runtimeApis, runtimeApi, method, targetVersion);
|
|
60
58
|
if (userDefinedSpec)
|
|
61
59
|
return userDefinedSpec;
|
|
62
60
|
const methodDef = this.#findRuntimeApiMethodDef(runtimeApi, method);
|
|
63
61
|
if (methodDef) {
|
|
64
62
|
return this.#toMethodSpec(runtimeApi, methodDef);
|
|
65
63
|
}
|
|
66
|
-
return this.#
|
|
64
|
+
return this.#findDefinedSpec(exports.FallbackRuntimeApiSpecs, runtimeApi, method, targetVersion);
|
|
67
65
|
}
|
|
68
66
|
#findRuntimeApiMethodDef(runtimeApi, method) {
|
|
69
67
|
try {
|
|
@@ -99,14 +97,10 @@ class RuntimeApiExecutor extends Executor_1.Executor {
|
|
|
99
97
|
?.at(1);
|
|
100
98
|
return foundVersion;
|
|
101
99
|
}
|
|
102
|
-
#
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
#findUserDefinedSpec(runtimeApi, method, runtimeApiVersion) {
|
|
106
|
-
const userDefinedSpecs = this.api.options.runtime;
|
|
107
|
-
if (!userDefinedSpecs)
|
|
100
|
+
#findDefinedSpec(specs, runtimeApi, method, runtimeApiVersion) {
|
|
101
|
+
if (!specs)
|
|
108
102
|
return undefined;
|
|
109
|
-
const methodSpecs = (0, specs_1.
|
|
103
|
+
const methodSpecs = (0, specs_1.toRuntimeApiSpecs)(specs).map(specs_1.toRuntimeApiMethods).flat();
|
|
110
104
|
return methodSpecs.find(({ runtimeApiName, methodName, version }) => `${(0, util_1.stringPascalCase)(runtimeApiName)}_${(0, utils_1.stringSnakeCase)(methodName)}` === `${runtimeApi}_${method}` &&
|
|
111
105
|
runtimeApiVersion === version);
|
|
112
106
|
}
|
|
@@ -6,7 +6,7 @@ const utils_1 = require("@dedot/utils");
|
|
|
6
6
|
const util_1 = require("@polkadot/util");
|
|
7
7
|
const codecs_1 = require("@dedot/codecs");
|
|
8
8
|
const extrinsic_1 = require("../extrinsic");
|
|
9
|
-
const
|
|
9
|
+
const utils_2 = require("@dedot/utils");
|
|
10
10
|
function isKeyringPair(account) {
|
|
11
11
|
return (0, util_1.isFunction)(account.sign);
|
|
12
12
|
}
|
|
@@ -20,7 +20,7 @@ exports.isKeyringPair = isKeyringPair;
|
|
|
20
20
|
function signRaw(signerPair, raw, options) {
|
|
21
21
|
const u8a = (0, util_1.hexToU8a)(raw);
|
|
22
22
|
// Ref: https://github.com/paritytech/polkadot-sdk/blob/943697fa693a4da6ef481ef93df522accb7d0583/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs#L234-L238
|
|
23
|
-
const toSignRaw = u8a.length > 256 ? (0,
|
|
23
|
+
const toSignRaw = u8a.length > 256 ? (0, utils_2.blake2AsU8a)(u8a, 256) : u8a;
|
|
24
24
|
return signerPair.sign(toSignRaw, options);
|
|
25
25
|
}
|
|
26
26
|
exports.signRaw = signRaw;
|
|
@@ -31,12 +31,12 @@ exports.signRaw = signRaw;
|
|
|
31
31
|
class TxExecutor extends Executor_1.Executor {
|
|
32
32
|
execute(pallet, functionName) {
|
|
33
33
|
const targetPallet = this.getPallet(pallet);
|
|
34
|
-
(0, utils_1.assert)(targetPallet.calls,
|
|
34
|
+
(0, utils_1.assert)(targetPallet.calls, `Tx calls are not available for pallet ${targetPallet.name}`);
|
|
35
35
|
const txType = this.metadata.types[targetPallet.calls];
|
|
36
|
-
(0, utils_1.assert)(txType.type.tag === 'Enum', 'Tx type should be enum');
|
|
36
|
+
(0, utils_1.assert)(txType.type.tag === 'Enum', 'Tx type defs should be enum');
|
|
37
37
|
const isFlatEnum = txType.type.value.members.every((m) => m.fields.length === 0);
|
|
38
38
|
const txCallDef = txType.type.value.members.find((m) => (0, util_1.stringCamelCase)(m.name) === functionName);
|
|
39
|
-
(0, utils_1.assert)(txCallDef,
|
|
39
|
+
(0, utils_1.assert)(txCallDef, `Tx call spec not found for ${pallet}.${functionName}`);
|
|
40
40
|
const txCallFn = (...args) => {
|
|
41
41
|
let call;
|
|
42
42
|
if (isFlatEnum) {
|
|
@@ -62,7 +62,7 @@ class TxExecutor extends Executor_1.Executor {
|
|
|
62
62
|
};
|
|
63
63
|
txCallFn.meta = {
|
|
64
64
|
...txCallDef,
|
|
65
|
-
fieldCodecs: txCallDef.fields.map(({ typeId }) => this.registry.
|
|
65
|
+
fieldCodecs: txCallDef.fields.map(({ typeId }) => this.registry.findCodec(typeId)),
|
|
66
66
|
pallet: targetPallet.name,
|
|
67
67
|
palletIndex: targetPallet.index,
|
|
68
68
|
};
|
|
@@ -91,7 +91,7 @@ class TxExecutor extends Executor_1.Executor {
|
|
|
91
91
|
throw new Error('Signer not found. Cannot sign the extrinsic!');
|
|
92
92
|
}
|
|
93
93
|
const { signatureTypeId } = this.registry.metadata.extrinsic;
|
|
94
|
-
const $Signature = this.registry.
|
|
94
|
+
const $Signature = this.registry.findCodec(signatureTypeId);
|
|
95
95
|
this.attachSignature({
|
|
96
96
|
address: address,
|
|
97
97
|
signature: $Signature.tryDecode(signature),
|
|
@@ -132,7 +132,7 @@ class TxExecutor extends Executor_1.Executor {
|
|
|
132
132
|
api.rpc.chain.getBlock(blockHash),
|
|
133
133
|
api.queryAt(blockHash).system.events(),
|
|
134
134
|
]);
|
|
135
|
-
const txIndex = signedBlock.block.extrinsics.findIndex((tx) => (0,
|
|
135
|
+
const txIndex = signedBlock.block.extrinsics.findIndex((tx) => (0, utils_2.blake2AsHex)((0, util_1.hexToU8a)(tx)) === txHash);
|
|
136
136
|
(0, utils_1.assert)(txIndex >= 0, 'Extrinsic not found!');
|
|
137
137
|
const events = blockEvents.filter(({ phase }) => phase.tag === 'ApplyExtrinsic' && phase.value === txIndex);
|
|
138
138
|
return callback(new extrinsic_1.SubmittableResult({ status, txHash, events, txIndex }));
|
|
@@ -41,20 +41,20 @@ class ExtraSignedExtension extends SignedExtension_1.SignedExtension {
|
|
|
41
41
|
return 'ExtraSignedExtension';
|
|
42
42
|
}
|
|
43
43
|
get dataCodec() {
|
|
44
|
-
const { extraTypeId } = this.
|
|
45
|
-
return (0, utils_1.ensurePresence)(this.registry.
|
|
44
|
+
const { extraTypeId } = this.registry.metadata.extrinsic;
|
|
45
|
+
return (0, utils_1.ensurePresence)(this.registry.findCodec(extraTypeId));
|
|
46
46
|
}
|
|
47
47
|
get additionalSignedCodec() {
|
|
48
|
-
const $AdditionalSignedCodecs = this.#signedExtensionDefs.map((se) => this.registry.
|
|
48
|
+
const $AdditionalSignedCodecs = this.#signedExtensionDefs.map((se) => this.registry.findCodec(se.additionalSigned));
|
|
49
49
|
return $.Tuple(...$AdditionalSignedCodecs);
|
|
50
50
|
}
|
|
51
51
|
get payloadCodec() {
|
|
52
|
-
const { callTypeId } = this.
|
|
53
|
-
const $Call = this.registry.
|
|
52
|
+
const { callTypeId } = this.registry.metadata.extrinsic;
|
|
53
|
+
const $Call = this.registry.findCodec(callTypeId);
|
|
54
54
|
return $.Tuple($Call, this.dataCodec, this.additionalSignedCodec);
|
|
55
55
|
}
|
|
56
56
|
get #signedExtensionDefs() {
|
|
57
|
-
return this.
|
|
57
|
+
return this.registry.metadata.extrinsic.signedExtensions;
|
|
58
58
|
}
|
|
59
59
|
#getSignedExtensions() {
|
|
60
60
|
return this.#signedExtensionDefs.map((extDef) => {
|
|
@@ -70,7 +70,7 @@ class ExtraSignedExtension extends SignedExtension_1.SignedExtension {
|
|
|
70
70
|
}
|
|
71
71
|
toPayload(call = '0x') {
|
|
72
72
|
const signedExtensions = this.#signedExtensions.map((se) => se.identifier);
|
|
73
|
-
const { version } = this.
|
|
73
|
+
const { version } = this.registry.metadata.extrinsic;
|
|
74
74
|
return (0, util_1.objectSpread)({ address: this.options.signerAddress, signedExtensions, version, method: call }, ...this.#signedExtensions.map((se) => se.toPayload()));
|
|
75
75
|
}
|
|
76
76
|
toRawPayload(call = '0x') {
|
|
@@ -20,10 +20,10 @@ class SignedExtension {
|
|
|
20
20
|
return this.signedExtensionDef.ident;
|
|
21
21
|
}
|
|
22
22
|
get dataCodec() {
|
|
23
|
-
return (0, utils_1.ensurePresence)(this.
|
|
23
|
+
return (0, utils_1.ensurePresence)(this.registry.findCodec(this.signedExtensionDef.typeId));
|
|
24
24
|
}
|
|
25
25
|
get additionalSignedCodec() {
|
|
26
|
-
return (0, utils_1.ensurePresence)(this.
|
|
26
|
+
return (0, utils_1.ensurePresence)(this.registry.findCodec(this.signedExtensionDef.additionalSigned));
|
|
27
27
|
}
|
|
28
28
|
get registry() {
|
|
29
29
|
return this.api.registry;
|
|
@@ -18,7 +18,7 @@ class ChargeAssetTxPayment extends SignedExtension_1.SignedExtension {
|
|
|
18
18
|
toPayload() {
|
|
19
19
|
const { tip, assetId } = this.data;
|
|
20
20
|
return {
|
|
21
|
-
tip: (0,
|
|
21
|
+
tip: (0, utils_1.bnToHex)(tip),
|
|
22
22
|
// @ts-ignore
|
|
23
23
|
assetId: this.#encodeAssetId(assetId),
|
|
24
24
|
};
|
|
@@ -30,10 +30,10 @@ class ChargeAssetTxPayment extends SignedExtension_1.SignedExtension {
|
|
|
30
30
|
return (0, util_1.u8aToHex)(this.$AssetId().tryEncode(assetId));
|
|
31
31
|
}
|
|
32
32
|
$AssetId() {
|
|
33
|
-
const extensionTypeDef = this.registry.
|
|
33
|
+
const extensionTypeDef = this.registry.findType(this.signedExtensionDef.typeId);
|
|
34
34
|
(0, utils_1.assert)(extensionTypeDef.type.tag === 'Struct');
|
|
35
35
|
const assetIdTypeDef = extensionTypeDef.type.value.fields.find((f) => f.name === 'asset_id');
|
|
36
|
-
const $codec = this.registry.
|
|
36
|
+
const $codec = this.registry.findCodec(assetIdTypeDef.typeId);
|
|
37
37
|
const codecMetadata = $codec.metadata[0];
|
|
38
38
|
if (codecMetadata.name === '$.option') {
|
|
39
39
|
return codecMetadata.args[0]; // inner shape
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ChargeTransactionPayment = void 0;
|
|
4
4
|
const SignedExtension_1 = require("../SignedExtension");
|
|
5
|
-
const
|
|
5
|
+
const utils_1 = require("@dedot/utils");
|
|
6
6
|
class ChargeTransactionPayment extends SignedExtension_1.SignedExtension {
|
|
7
7
|
async init() {
|
|
8
8
|
this.data = this.payloadOptions.tip || 0n;
|
|
9
9
|
}
|
|
10
10
|
toPayload() {
|
|
11
11
|
return {
|
|
12
|
-
tip: (0,
|
|
12
|
+
tip: (0, utils_1.bnToHex)(this.data),
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
15
|
}
|