Compare commits

..
85 Commits
Author SHA1 Message Date
Github Actions 27871135a0 [CI Skip] 0.95.2 2019-10-25 15:01:08 +00:00
Jaco Greeff 26be5e0cc5 0.95 nextIndex patch 2019-10-25 16:54:54 +02:00
Github Actions 66142c0137 [CI Skip] 0.96.0-beta.0 2019-10-25 14:28:45 +00:00
Jaco Greeff de395c7053 Skip nextIndex (#1513)
* Skip nextIndex

* Remove from derive
2019-10-25 16:22:06 +02:00
Github Actions ab78245576 [CI Skip] 0.95.1 2019-10-25 10:46:56 +00:00
Jaco Greeff 6ff0efca25 0.95 (#1512) 2019-10-25 12:40:21 +02:00
Github Actions fa0fd7140c [CI Skip] 0.95.0-beta.36 2019-10-25 06:57:58 +00:00
Jaco Greeff 0b71291cf1 Update latest extrinsic version (#1511)
* Update latest extrinsic version

* Don't export const with types
2019-10-25 08:51:03 +02:00
Github Actions 44d0ced5af [CI Skip] 0.95.0-beta.35 2019-10-24 14:34:28 +00:00
Jaco Greeff a8bfa90b87 Update signing comment (#1509)
* Update signing comment

* Extrinsic V4 CHANGELOG
2019-10-24 16:20:40 +02:00
Github Actions 835361d3c5 [CI Skip] 0.95.0-beta.34 2019-10-24 13:19:53 +00:00
Jaco Greeff 3bb719fcfc Extrinsic v4 (#1498)
* Extrinsic v4

* Comments

* V4 with MultiSignature

* Bump keyring with signature type indicator

* Return actual Signature type

* Update with MultiSignature enum

* Bump to stable common

* De-dup definitions somewhat
2019-10-24 15:13:03 +02:00
Github Actions 00a3001df9 [CI Skip] 0.95.0-beta.33 2019-10-23 15:49:30 +00:00
Jaco Greeff cac0056fc4 Allow user-define RPC interfaces (#1504)
* Allow user-define RPC interfaces

* Add user-decorated tests

* Pacify CC

* Typos

* Just push.
2019-10-23 17:36:27 +02:00
Github Actions a9e55e66d6 [CI Skip] 0.95.0-beta.32 2019-10-23 11:29:09 +00:00
Jaco Greeff c10f0e47b2 FAQ entry for tuple call (#1505)
* FAQ entry for tuple call

* Add default moral length
2019-10-23 13:22:13 +02:00
Github Actions 0b45bc6ab9 [CI Skip] 0.95.0-beta.31 2019-10-22 13:30:24 +00:00
Jaco Greeff 30f62f4024 Exclude build folders (#1503) 2019-10-22 15:23:47 +02:00
Github Actions 262f01b54e [CI Skip] 0.95.0-beta.30 2019-10-22 09:41:41 +00:00
Jaco Greeff 26c2774992 Bump dev deps (#1502) 2019-10-22 11:35:09 +02:00
Github Actions 58ff26cc78 [CI Skip] 0.95.0-beta.29 2019-10-21 15:36:21 +00:00
Jaco Greeff 62eab2d661 Fix returned accountId for derived staking.info (#1501) 2019-10-21 17:26:34 +02:00
Github Actions d4ab4f8293 [CI Skip] 0.95.0-beta.28 2019-10-21 14:25:19 +00:00
Jaco Greeff aed4b3ee6a Cleanup contracts type registry (#1497)
* Cleanup contracts type registry

* Remove some ! compiler overrides

* More mappy lookups

* Empty check
2019-10-21 16:18:41 +02:00
Github Actions 4c90c6158f [CI Skip] 0.95.0-beta.27 2019-10-20 10:04:04 +00:00
kwingram25 b911bdbd2d Add dynamic Vec ABI support (#1499) 2019-10-20 11:57:19 +02:00
Github Actions b5edcb8529 [CI Skip] 0.95.0-beta.26 2019-10-19 14:46:26 +00:00
Jaco Greeff 9086592252 Flatten encodeTypes, add missing BTreeMap (#1495)
* Flatten encodeTypes, add missing BTreeMap

* Fix param encoding
2019-10-19 16:39:53 +02:00
Github Actions c0b428dfbc [CI Skip] 0.95.0-beta.25 2019-10-18 12:51:38 +00:00
Jaco Greeff e49427ac61 Retrieve account.nextIndex via derive.balances.all (#1487)
* Retrieva account.nextIndex via derive.balances.all

* Remove unneeded cast

* Cast system.accountNonce

* Option -> null

* No undefined nonce
2019-10-18 14:45:25 +02:00
Github Actions 64149de2d4 [CI Skip] 0.95.0-beta.24 2019-10-17 13:29:23 +00:00
Jaco Greeff fe3de4379f Support TransactionPayment.{TransactionBaseFee, TransactionByteFee} (#1493)
* Support TransactionPayment.{TransactionBaseFee, TransactionByteFee}

* Dedup

* Ordering
2019-10-17 15:22:39 +02:00
Github Actions 5532daf640 [CI Skip] 0.95.0-beta.23 2019-10-16 13:11:35 +00:00
Jaco Greeff e197c6f114 Update shared-vec WASM (#1492) 2019-10-16 15:04:53 +02:00
Github Actions f3b71b21b5 [CI Skip] 0.95.0-beta.22 2019-10-16 08:20:10 +00:00
Jaco Greeff db3cb47d05 Firm up on derive typings & results (#1489)
* Firm up on derive typings & results

* Move assertion (eslint vs ts, round 1, fight!)
2019-10-16 10:13:13 +02:00
Github Actions 3f135f2da2 [CI Skip] 0.95.0-beta.21 2019-10-15 10:13:51 +00:00
Jaco Greeff 4ec6a0f9b8 Align doc headers & links (incl. api interface) (#1486) 2019-10-15 12:07:43 +02:00
Github Actions eca0d8d81a [CI Skip] 0.95.0-beta.20 2019-10-15 08:42:24 +00:00
Jaco Greeff e056675b3a Add raw RPC endpoints (#1485) 2019-10-15 10:36:15 +02:00
Github Actions 71a4b39698 [CI Skip] 0.95.0-beta.19 2019-10-14 11:23:40 +00:00
Jaco Greeff d194a6e4c9 Allow BTreeMap.with('u32', 'Text') (not only classes) (#1483) 2019-10-14 13:17:45 +02:00
Github Actions 4a7d8677a3 [CI Skip] 0.95.0-beta.18 2019-10-14 09:48:07 +00:00
Jaco Greeff 21ac0ac2fb Add TypeDefInfo handling for BTreeMap (#1481)
* Add TypeDefInfo handling for BTreeMap

* Update getTypeClass.ts

* Fixup BTreeMap result (will be active once class support is merged)

* Merge master, update with BTreeMap classes
2019-10-14 11:42:31 +02:00
Paul M FoxandJaco Greeff acfd856b25 Basic BTreeMaps codec support (#1474)
* BTreeMap codec type

* used proper, relative path

* Register class types by default

* reduced cognitive complexity

* Update packages/types/src/codec/BTreeMap.ts

Co-Authored-By: Jaco Greeff <jacogr@gmail.com>

* Update packages/types/src/codec/BTreeMap.ts

Co-Authored-By: Jaco Greeff <jacogr@gmail.com>

* Update packages/types/src/codec/BTreeMap.spec.ts

Co-Authored-By: Jaco Greeff <jacogr@gmail.com>

* added copyright; logic fixes

* added BTreeMap in alphabetical order

* better unit tests

multiple value examples taken from scale codec repo

* lint fix
2019-10-14 11:10:04 +02:00
Github Actions d5d8b59f8b [CI Skip] 0.95.0-beta.17 2019-10-12 14:06:12 +00:00
Jaco Greeff b24fe30a40 Split merge docs gen into sep process (#1482)
* Split merge docs gen into sep process

* Update doc refs
2019-10-12 16:00:22 +02:00
Github Actions 207e2982d7 [CI Skip] 0.95.0-beta.16 2019-10-12 09:34:53 +00:00
Jaco Greeff 6fab577e23 Expose hasSubscriptions on api rx interface (#1479) 2019-10-12 11:16:57 +02:00
扩散性百万甜面包 f7ca638a1a Minor class Events (#1478)
* Fix the return value as boolean on Event

* Minor class Events
2019-10-12 11:16:27 +02:00
Github Actions 0c96ba7a02 [CI Skip] 0.95.0-beta.15 2019-10-11 14:43:06 +00:00
Jaco Greeff 7143f5e643 Add new parathreads types (#1477)
* Add new parathreads types

* Fix dangling comma
2019-10-11 16:25:44 +02:00
Github Actions 910fa20b78 [CI Skip] 0.95.0-beta.14 2019-10-11 11:03:11 +00:00
Jaco Greeff 4855e631b5 Remove secret token from test step (#1475) 2019-10-11 12:44:52 +02:00
Jaco Greeff 698f2725c9 [CI Skip] 0.95.0-beta.13 2019-10-11 08:15:30 +00:00
Jaco Greeff 492fce1af7 Bump deps (#1472) 2019-10-11 09:58:00 +02:00
Jaco Greeff 397e9494eb [CI Skip] 0.95.0-beta.12 2019-10-11 07:50:34 +00:00
Jaco Greeff b8d7f4803b CHANGELOG (#1471) 2019-10-11 09:30:30 +02:00
Jaco Greeff 89f0d452f4 [CI Skip] 0.95.0-beta.11 2019-10-10 18:58:12 +00:00
Jaco Greeff bf8bed36ef Update drr equality (#1469)
* Update drr equality

* null === null

* Array length compare

* isFunction(next.eq)

* Just JSON.stringify on compare

* Add distinctUntilChanged in  rpc-core

* prev/next -> a/b
2019-10-10 20:41:57 +02:00
Jaco Greeff 38529ad13c [CI Skip] 0.95.0-beta.10 2019-10-10 16:49:38 +00:00
Jaco Greeff 8a6d23d461 Allow limited (non-sub operation) with Http provider (#1465)
* Allow limited (non-sub operation) with Http provider

* Throw-away typo
2019-10-10 18:28:15 +02:00
Jaco Greeff d80cc717e2 [CI Skip] 0.95.0-beta.9 2019-10-10 15:57:14 +00:00
Jaco Greeff a207348c13 Remove generated types from docs (#1468) 2019-10-10 17:35:21 +02:00
Jaco Greeff 4a795b4c50 [CI Skip] 0.95.0-beta.8 2019-10-10 15:22:27 +00:00
Jaco Greeff e54cee1fad Cleanup codec .skip tests (#1467) 2019-10-10 17:01:31 +02:00
Jaco Greeff 4e4108abfa [CI Skip] 0.95.0-beta.7 2019-10-10 14:52:30 +00:00
Jaco Greeff 3196e66efb Remove depcrecated addSignature (#1466) 2019-10-10 16:34:20 +02:00
Jaco Greeff 7e0f20908c [CI Skip] 0.95.0-beta.6 2019-10-10 11:18:34 +00:00
Jaco Greeff 985749ade1 Small typos (#1464) 2019-10-10 13:01:05 +02:00
Jaco Greeff ec8deb8be3 [CI Skip] 0.95.0-beta.5 2019-10-10 09:22:18 +00:00
Jaco Greeff b8d4bc5c6a Call.injectMetadata (align with Events) (#1462)
* Call.injectMetadata (align with Events)

* Fix interface builds

* Fix md builds

* Fixup tests with injection
2019-10-10 11:05:01 +02:00
Jaco Greeff 2870513453 [CI Skip] 0.95.0-beta.4 2019-10-09 13:38:10 +00:00
Jaco Greeff e27b35cd9f Merge branch 'master' of github.com:polkadot-js/api 2019-10-09 15:17:09 +02:00
Jaco Greeff bc86dbb31e Bump dev, gh-pages deploy 2019-10-09 15:17:06 +02:00
Jaco Greeff d1b047f675 [CI Skip] 0.95.0-beta.3 2019-10-09 12:49:13 +00:00
Jaco Greeff 8b43ee6ca1 Alias GH_TOKEN 2019-10-09 14:28:21 +02:00
Jaco Greeff f6e5068dae Swap CI to GH actions (#1460) 2019-10-09 14:22:00 +02:00
Jaco Greeff fe40e2378a Skip CI in actions (#1459) 2019-10-09 14:07:27 +02:00
Travis CI 2e9192ca02 [CI Skip] 0.95.0-beta.2 2019-10-08 14:51:58 +00:00
kwingram25 05ec4964fe Generate types from new contract ABI JSON (#1320)
* generate types from registry

* cleanup

* merge, rearrange

* lint

* built out

* abi v2 creation

* throw on unions

* linting

* version handling

* split functions

* cleanup

* drop v1 support

* special types

* changes

* requested changes

* formatTYpe

* rv outdated test

* rv union test

* codeclimate

* codeclimate

* codeclimate

* codeclimate

* codeclimate

* review

* cleanup encodeTypes

* fix option sub

* TypeDefInfo.Result
2019-10-08 16:31:48 +02:00
Travis CI 64f8444d47 [CI Skip] 0.95.0-beta.1 2019-10-08 13:24:45 +00:00
Jaco Greeff c0f9b45dca Bump deps (#1458) 2019-10-08 15:05:25 +02:00
Travis CI ffadc335d5 [CI Skip] 0.95.0-beta.0 2019-10-08 09:51:15 +00:00
Jaco Greeff 9c09386600 Support Metadata V8 (#1441)
* Support Metadata V8

* Update V7 references, introduce *Latest (as applicable)

* Add v8 static metadata

* Bump to latest metadata
2019-10-08 11:30:54 +02:00
167 changed files with 17059 additions and 1841 deletions
-24
View File
@@ -1,24 +0,0 @@
version: 2
jobs:
build:
branches:
ignore:
- gh-pages
working_directory: ~/polkadot-js
docker:
- image: circleci/node:10
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ checksum "yarn.lock" }}
- run:
name: install-deps
command: yarn install --frozen-lockfile
- save_cache:
key: dependency-cache-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
- ~/.cache/yarn
- run:
name: build
command: yarn polkadot-dev-circleci-build
+1 -1
View File
@@ -5,7 +5,7 @@ module.exports = {
parserOptions: {
...base.parserOptions,
project: [
'./tsconfig.eslint.json'
'./tsconfig.json'
]
},
rules: {
@@ -1,4 +1,4 @@
name: CI
name: PR
on: [pull_request]
jobs:
@@ -51,7 +51,7 @@ jobs:
- name: build
run: |
yarn install --frozen-lockfile
yarn build:split:code
yarn build
build_docs:
name: Build Docs
@@ -68,4 +68,4 @@ jobs:
- name: build
run: |
yarn install --frozen-lockfile
yarn build:split:docs
yarn docs
+53
View File
@@ -0,0 +1,53 @@
name: Master
on:
push:
branches:
- master
jobs:
build_code:
name: Build Code
if: "! contains(github.event.head_commit.message, '[CI Skip]')"
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: build
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
GH_PAT: ${{ secrets.GH_PAT }}
GH_TOKEN: ${{ secrets.GH_PAT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
yarn install --frozen-lockfile
CI_NO_BETA=true yarn polkadot-dev-ghact-build
build_docs:
name: Build Docs
if: "! contains(github.event.head_commit.message, '[CI Skip]')"
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: build
env:
GH_PAT: ${{ secrets.GH_PAT }}
GH_TOKEN: ${{ secrets.GH_PAT }}
GH_PAGES_SRC: build-docs
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
yarn install --frozen-lockfile
yarn polkadot-dev-ghact-docs
-28
View File
@@ -1,28 +0,0 @@
language: node_js
node_js:
- "10"
env:
global:
- CC_TEST_REPORTER_ID=b8983d04997f43ff9b9df9aa92904967547680e2a229af812b3cf14985713e84
- GH_PAGES_SRC="build-docs"
cache:
yarn: true
directories:
- node_modules
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- chmod +x ./cc-test-reporter
- export PATH=$HOME/.yarn/bin::$(yarn global bin):$PATH
before_script:
- ./cc-test-reporter before-build
script:
- yarn polkadot-dev-travis-build
after_script:
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
deploy:
skip_cleanup: true
provider: script
script: yarn polkadot-dev-travis-deploy
on:
branch: master
+10
View File
@@ -1,3 +1,13 @@
# 0.95.1
- Support Extrinsic V4 with additional signature indicator (Latest Polkadot/Substrate/Kusama)
- Adjust subscription update checks to avoid duplicated data updates
- Support Metadata V8 (exposes per-module `decl_error` definitions)
- Support next generation contracts ABI (with additional type definitions)
- Support for `BTreeMap<K, V>` types and definitions
- All latest Polkadot & Substrate types (as per master branches)
- **Breaking change** `Call.injectMethods` is moved to `Call.injectMetadata` to align with `Events` (This _should_ not be used externally, however mentioned as breaking here)
# 0.94.1
- Add handling of `Result<Ok, Error>` definitions
+1 -1
View File
@@ -46,7 +46,7 @@
- [Unsubscribe from listening](examples/promise/04_unsubscribe/README.md)
- [Read chain state](examples/promise/05_read_storage/README.md)
- [Make a transfer](examples/promise/06_make_transfer/README.md)
- [Display system events](examples/promise/08_system_events/README.md)(
- [Display system events](examples/promise/08_system_events/README.md)
- [Transaction with events](examples/promise/09_transfer_events/README.md)
- [Upgrade via sudo](examples/promise/10_upgrade_chain/README.md)
- [ApiRx](examples/rx/README.md)
@@ -2,4 +2,4 @@
In addition to querying the latest storage, you can make storage queries at a specific blockhash. Be aware that the node applies a pruning strategy and typically only keeps the last 256 blocks, unless run in archive mode.
<<< @/docs/examples/promise/07_read_storage_at/index.js
<<< @/docs/examples/promise/05_read_storage_at/index.js
@@ -2,4 +2,4 @@
This example shows how to instantiate a Polkadot API object and use it to connect to a node and retrieve balance updates.
<<< @/docs/examples/rx/03_listent_to_balance_change/index.js
<<< @/docs/examples/rx/03_listen_to_balance_change/index.js
+10
View File
@@ -23,3 +23,13 @@ As of this writing we don't have an explicit example of implementing the signer
Some calls in Polkadot/Substrate can only be submitted as root, these are indicated by `ensure_root(origin)` in the Rust codebase. Root here does not refer to the actual account, i.e. `//Alice` on a `--dev` chain, but rather that it cannot be submitted as a bare user transaction. This restriction applies to chain upgrades, changing balances or anything that modifies the state and/or chain operation.
To submit these transactions, it needs to be send as a [wrapped transaction](api.tx.wrap.md#sudo-use) via either `sudo.sudo` (assuming you have access on your chain) or `democracy.proposal` (which would allow users of the chain to vote on it).
## How do I call a function with a Tuple input
Tuples, as defined in the Polkadot/Substrate types appear as `(TypeA, TypeB)`. For instance we may have an `(AccountId, u64)` input as defined in the metadata or as part of the user types. To specify a Tuple as an input, wrap it is an array format, for instance to call `query.module.get((u32, u64))` where a `(u32, u64)` Tuple input is expected, you would do `query.module.get([123, 456])`
## How long do transactions live
Polkadot/Substrate supports both immortal and mortal transactions. For immortal, this means that the transaction has an infinite lifetime, for mortals, the transactions expire after a defined period. By default the API sends mortal transactions when no explicit extrinsic era has been specified. This means that all transaction has a limited lifetime and will expire if not included in the period set.
The length for this transaction validity is set to 50 blocks, which translates to 5 minutes assuming a default of 6 second blocktimes. (10 blocks per minute in this default configuration).
+1 -1
View File
@@ -295,4 +295,4 @@ ___
### utility
▸ **BatchExecuted**(`Vec<Result<Null,DispatchError>>`)
▸ **BatchExecuted**(`Vec<DispatchResult>`)
+1 -1
View File
@@ -9,5 +9,5 @@
"packages": [
"packages/*"
],
"version": "0.94.1"
"version": "0.95.2"
}
+8 -13
View File
@@ -1,5 +1,5 @@
{
"version": "0.94.1",
"version": "0.95.2",
"private": true,
"engines": {
"yarn": "^1.10.1"
@@ -9,17 +9,13 @@
],
"resolutions": {
"babel-core": "^7.0.0-bridge.0",
"typescript": "^3.6.3"
"typescript": "^3.6.4"
},
"scripts": {
"build": "yarn build:split:code && yarn build:split:docs",
"build:split:code": "yarn build:interfaces && polkadot-dev-build-ts",
"build:split:docs": "yarn run build:methodsdoc && polkadot-dev-build-docs",
"build:htmldoc": "yarn clean && typedoc --theme default --out docs/html",
"build": "yarn build:interfaces && polkadot-dev-build-ts",
"build:interfaces": "node packages/types/src/scripts/interfacesTsWrapper.js",
"build:methodsdoc": "node packages/types/src/scripts/MetadataMdWrapper.js",
"docs": "node packages/types/src/scripts/MetadataMdWrapper.js && polkadot-dev-build-docs",
"chain:info": "node packages/types/src/scripts/extractChainWrapper.js",
"check": "yarn lint",
"lint": "eslint --ext .js,.jsx,.ts,.tsx . && tsc --noEmit --pretty",
"clean": "polkadot-dev-clean-build",
"postinstall": "polkadot-dev-yarn-only",
@@ -32,11 +28,10 @@
"test:watch": "jest --coverage --watch"
},
"devDependencies": {
"@babel/core": "^7.6.2",
"@babel/core": "^7.6.4",
"@babel/register": "^7.6.2",
"@babel/runtime": "^7.6.2",
"@polkadot/dev": "^0.31.1",
"@polkadot/ts": "^0.1.73",
"gh-pages": "^2.1.1"
"@babel/runtime": "^7.6.3",
"@polkadot/dev": "^0.32.0-beta.11",
"@polkadot/ts": "^0.1.82"
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-contract",
"version": "0.94.1",
"version": "0.95.2",
"description": "Interfaces for interacting with contracts and contract ABIs",
"main": "index.js",
"keywords": [
@@ -26,7 +26,7 @@
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api-contract#readme",
"dependencies": {
"@babel/runtime": "^7.6.2",
"@polkadot/types": "^0.94.1"
"@babel/runtime": "^7.6.3",
"@polkadot/types": "^0.95.2"
}
}
-97
View File
@@ -2,108 +2,11 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ContractABIArg } from './types';
import typesAbi from '../test/abi/types.json';
import erc20Abi from '../test/contracts/Erc20.json';
import { Abi } from '.';
describe('Abi', (): void => {
describe('types encoding', (): void => {
let abi: Abi;
beforeAll((): void => {
abi = new Abi(typesAbi);
});
function check (method: string, args: ContractABIArg[], type: string | null): void {
const fn = abi.messages[method];
expect(fn.args).toEqual(args);
expect(fn.type).toEqual(type);
}
it('has the primitive method with args & return', (): void => {
check(
'primitive',
[
{ name: 'bool', type: 'bool' },
{ name: 'u32', type: 'u32' }
],
'bool'
);
});
it('has the vector method with args & return', (): void => {
check(
'vector',
[
{ name: 'vecU8', type: 'Vec<u8>' },
{ name: 'vecU32', type: 'Vec<u32>' }
],
'Vec<bool>'
);
});
it('has the vector_fixed method with args & return', (): void => {
check(
'vectorFixed',
[
{ name: 'vecU8Length32', type: '[u8;32]' }
],
'[u32;8]'
);
});
it('has the option method with args & return', (): void => {
check(
'option',
[
{ name: 'optionU32', type: 'Option<u32>' }
],
'Option<bool>'
);
});
it('has the result method with return (empty)', (): void => {
check(
'result',
[],
'()'
);
});
it('allows for nested args', (): void => {
check(
'nested',
[
{ name: 'optionVec', type: 'Option<Vec<u32>>' }
],
'Vec<(u32,u64)>'
);
});
describe('messages', (): void => {
it('fails when invalid args are supplied', (): void => {
expect(
(): Uint8Array => abi.messages.primitive(false)
).toThrow(/Expected 2 arguments to contract messages.primitive, found 1/);
});
it('encodes primitives correctly', (): void => {
expect(
abi.messages.primitive(true, 0x12345678)
).toEqual(new Uint8Array([
9 << 2, // total length (4 + 1 + 4)
0x67, 0x2b, 0, 0, // 11111 -> hex (LE)
1, // true
0x78, 0x56, 0x34, 0x12 // u32
]));
});
});
});
describe('erc20', (): void => {
let abi: Abi;
+22 -12
View File
@@ -2,30 +2,40 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ContractABI, ContractABIFn, InterfaceAbi, AbiMessages } from './types';
import { ContractABI, ContractABIPre, ContractABIFn, InterfaceAbi, AbiMessages } from './types';
import { stringCamelCase } from '@polkadot/util';
import { createMethod } from './method';
import { validateAbi } from './validation';
import ContractRegistry from './ContractRegistry';
export default class ContractAbi implements InterfaceAbi {
export default class ContractAbi extends ContractRegistry implements InterfaceAbi {
public readonly abi: ContractABI;
public readonly deploy: ContractABIFn;
public readonly constructors: ContractABIFn[];
public readonly messages: AbiMessages = {};
public constructor (abi: ContractABI) {
validateAbi(abi);
public constructor (abi: ContractABIPre) {
super(abi);
[this.abi, this.constructors, this.messages] = this.decodeAbi(abi);
}
this.abi = abi;
this.deploy = createMethod('deploy', abi.deploy);
private decodeAbi (abiPre: ContractABIPre): [ContractABI, ContractABIFn[], AbiMessages] {
this.validateAbi(abiPre);
abi.messages.forEach((method): void => {
const abi = this.convertAbi(abiPre);
const constructors = abi.contract.constructors.map(
(constructor, index): ContractABIFn => {
return this.createMethod(`constructor ${index}`, constructor);
}
);
const messages: AbiMessages = {};
abi.contract.messages.forEach((method): void => {
const name = stringCamelCase(method.name);
this.messages[name] = createMethod(`messages.${name}`, method);
messages[name] = this.createMethod(`messages.${name}`, method);
});
return [abi, constructors, messages];
}
}
@@ -0,0 +1,175 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { CodecArg, TypeDef } from '@polkadot/types/types';
import { ContractABIArgBasePre, ContractABIContract, ContractABIContractPre, ContractABIEvent, ContractABIEventPre, ContractABIFn, ContractABIFnArg, ContractABIMethod, ContractABIMethodBase, ContractABIMethodPre, ContractABI, ContractABIPre, ContractABIRange, ContractABIRangePre, ContractABIStorage, ContractABIStorageLayout, ContractABIStorageLayoutPre, ContractABIStoragePre, ContractABIStorageStruct, ContractABIStorageStructPre, ContractABITypePre } from './types';
import { Compact } from '@polkadot/types';
import { assert, isNumber, isString, isNull, isObject, isUndefined, stringCamelCase } from '@polkadot/util';
import MetaRegistry from './MetaRegistry';
import { createArgClass } from './method';
export default class ContractRegistry extends MetaRegistry {
// Contract ABI helpers
public validateArgs (name: string, args: ContractABIArgBasePre[]): void {
assert(Array.isArray(args), `Expected 'args' to exist on ${name}`);
args.forEach((arg): void => {
const unknownKeys = Object.keys(arg).filter((key): boolean => !['name', 'type'].includes(key));
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for ${name}`);
assert(isNumber(arg.name) && isString(this.stringAt(arg.name)), `${name} args should have valid name `);
assert(isNumber(arg.type.ty) && isObject(this.typeDefAt(arg.type.ty)), `${name} args should have valid type`);
});
}
public validateConstructors ({ contract: { constructors } }: ContractABIPre): void {
constructors.forEach((constructor: ContractABIMethodPre, index): void => {
const unknownKeys = Object.keys(constructor).filter((key): boolean => !['args', 'docs', 'name', 'selector'].includes(key));
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI constructor`);
this.validateArgs(`constructor ${index}`, constructor.args);
});
}
public validateMethods ({ contract: { messages } }: ContractABIPre): void {
messages.forEach((method): void => {
const unknownKeys = Object.keys(method).filter((key): boolean => !['args', 'docs', 'mutates', 'name', 'selector', 'return_type'].includes(key));
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for messages.${method.name}`);
const { name, selector, return_type: returnType } = method;
assert(isNumber(name) && isString(this.stringAt(name)), `Expected name for messages.${method.name}`);
assert(isNumber(selector), `Expected selector for messages.${method.name}`);
assert(isNull(returnType) || (isNumber(returnType.ty) && isObject(this.typeDefAt(returnType.ty))), `Expected return_type for messages.${method.name}`);
this.validateArgs(`messages.${method.name}`, method.args);
});
}
public validateAbi (abi: ContractABIPre): void {
const unknownKeys = Object.keys(abi.contract).filter((key): boolean => !['constructors', 'docs', 'events', 'messages', 'name'].includes(key));
assert(unknownKeys.length === 0, `Unknown fields ${unknownKeys.join(', ')} found in ABI`);
const { contract: { constructors, messages, name } } = abi;
assert(constructors && messages && isString(this.stringAt(name)), 'ABI should have constructors, messages & name sections');
this.validateConstructors(abi);
this.validateMethods(abi);
}
public createMethod (name: string, method: Partial<ContractABIMethod> & ContractABIMethodBase): ContractABIFn {
const args = method.args.map(({ name, type }): ContractABIFnArg => {
assert(isObject(type), `Invalid type at index ${type}`);
return {
name: stringCamelCase(name),
type
};
});
const Clazz = createArgClass(args, isUndefined(method.selector) ? {} : { __selector: 'u32' });
const baseStruct: { [index: string]: any } = { __selector: method.selector };
const encoder = (...params: CodecArg[]): Uint8Array => {
assert(params.length === args.length, `Expected ${args.length} arguments to contract ${name}, found ${params.length}`);
const u8a = new Clazz(
args.reduce((mapped, { name }, index): Record<string, CodecArg> => {
mapped[name] = params[index];
return mapped;
}, { ...baseStruct })
).toU8a();
return Compact.addLengthPrefix(u8a);
};
const fn = (encoder as ContractABIFn);
fn.args = args;
fn.isConstant = !(method.mutates || false);
fn.type = method.returnType || null;
return fn;
}
public convertAbi ({ contract, storage }: ContractABIPre): ContractABI {
return {
contract: this.convertContract(contract),
storage: this.convertStorage(storage)
};
}
public convertArgs (args: ContractABIArgBasePre[]): any[] {
return args.map(({ name, type, ...arg }) => ({ ...arg, name: this.stringAt(name), type: this.convertType(type) }));
}
public convertType ({ ty, display_name: displayNameIndices }: ContractABITypePre): TypeDef {
const displayName = this.stringsAt(displayNameIndices).join('::');
return this.typeDefAt(ty, { displayName });
}
public convertContract ({ constructors, messages, name, events, ...contract }: ContractABIContractPre): ContractABIContract {
return {
constructors: this.convertConstructors(constructors),
messages: messages.map(method => this.convertMethod(method)),
name: this.stringAt(name),
...(events
? { events: events.map(event => this.convertEvent(event)) }
: {}),
...contract
};
}
public convertConstructors (constructors: ContractABIMethodPre[]): ContractABIMethod[] {
return constructors.map(
(constructor: ContractABIMethodPre): ContractABIMethod => {
return this.convertMethod(constructor);
}
);
}
public convertMethod ({ args, name, return_type: returnType, ...method }: ContractABIMethodPre): ContractABIMethod {
return {
...method,
args: this.convertArgs(args),
name: this.stringAt(name),
returnType: returnType ? this.convertType(returnType) : null
};
}
public convertEvent ({ args }: ContractABIEventPre): ContractABIEvent {
return {
args: this.convertArgs(args)
};
}
public convertStorage (storage: ContractABIStoragePre): ContractABIStorage {
return this.convertStorageStruct(storage);
}
public convertStorageLayout (storageLayout: ContractABIStorageLayoutPre): ContractABIStorageLayout {
if ((storageLayout as ContractABIStorageStructPre)['struct.type']) {
return this.convertStorageStruct(storageLayout as ContractABIStorageStructPre);
} else {
return this.convertStorageRange(storageLayout as ContractABIRangePre);
}
}
public convertStorageStruct ({ 'struct.type': structType, 'struct.fields': structFields }: ContractABIStorageStructPre): ContractABIStorageStruct {
return {
'struct.type': this.typeDefAt(structType),
'struct.fields': structFields.map(({ name, layout }) => ({
name: this.stringAt(name),
layout: this.convertStorageLayout(layout)
}))
};
}
public convertStorageRange ({ 'range.elem_type': type, ...range }: ContractABIRangePre): ContractABIRange {
return {
...range,
'range.elem_type': this.typeDefAt(type)
};
}
}
@@ -0,0 +1,33 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import fs from 'fs';
import path from 'path';
import MetaRegistry from './MetaRegistry';
import erc20Abi from '../test/contracts/Erc20.json';
import sharedVecAbi from '../test/contracts/SharedVecV2.json';
describe('MetaRegistry', (): void => {
describe('construction', (): void => {
it('initializes from a contract ABI (ERC20)', (): void => {
const metaRegistry = new MetaRegistry(erc20Abi);
fs.writeFile(path.join(__dirname, '../test/compare/erc20.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void {
if (err) throw err;
});
expect(true).toBe(true);
});
it('initializes from a contract ABI (SharedVec)', (): void => {
const metaRegistry = new MetaRegistry(sharedVecAbi);
fs.writeFile(path.join(__dirname, '../test/compare/shared-vec.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void {
if (err) throw err;
});
expect(true).toBe(true);
});
});
});
+348
View File
@@ -0,0 +1,348 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { MetaRegistryItem, MetaRegistryJson, MetaTypeDefClikeEnum, MetaType, MetaTypeDefEnum, MetaTypeDefEnumVariant, MetaTypeDefEnumVariantStruct, MetaTypeDefEnumVariantTupleStruct, MetaTypeDefEnumVariantUnit, MetaTypeDefStruct, MetaTypeDefStructField, MetaTypeDefTupleStruct, MetaTypeDefUnion, MetaTypeIdCustom, MetaTypeIdVec, MetaTypeIdVecFixed, MetaTypeInfo, StringIndex, TypeDef, TypeDefInfo, TypeIndex } from '@polkadot/types/types';
import { assert } from '@polkadot/util';
import { displayType, withTypeString } from '@polkadot/types';
const builtinMap: [(id: any) => boolean, MetaTypeInfo][] = [
[(id: any): boolean => typeof id === 'string', MetaTypeInfo.BuiltinPlain],
[(id: any): boolean => Array.isArray(id), MetaTypeInfo.BuiltinTuple],
[(id: any): boolean => !!(id['array.type']), MetaTypeInfo.BuiltinVecFixed],
[(id: any): boolean => !!(id['slice.type']), MetaTypeInfo.BuiltinVec]
];
const typeMap: [string, MetaTypeInfo][] = [
['enum.variants', MetaTypeInfo.Enum],
['clike_enum.variants', MetaTypeInfo.ClikeEnum],
['struct.fields', MetaTypeInfo.Struct],
['tuple_struct.types', MetaTypeInfo.TupleStruct]
];
function detectedType ({ def, id }: MetaType): MetaTypeInfo {
assert(!(def as MetaTypeDefUnion)['union.fields'], 'Invalid union type definition found');
const lookup = def === 'builtin'
? builtinMap.find(([test]): boolean => test(id))
: typeMap.find(([test]): boolean => !!(def as any)[test]);
return lookup
? lookup[1]
: MetaTypeInfo.Null;
}
class MetadataRegistryLookup {
protected _strings: string[] = [];
protected _types: MetaType[] = [];
public typeDefs: TypeDef[] = [];
public constructor ({ registry: { strings, types } }: MetaRegistryJson) {
this._strings = strings;
this._types = types;
}
protected hasItemAt (index: number, variant: MetaRegistryItem): boolean {
switch (variant) {
case MetaRegistryItem.String:
return this._strings && !!this._strings[index - 1];
case MetaRegistryItem.Type:
return this._types && !!this._types[index - 1];
case MetaRegistryItem.TypeDef:
return this.typeDefs && !!this.typeDefs[index - 1];
}
}
protected itemAt (index: number, variant: MetaRegistryItem): any {
assert(this.hasItemAt(index, variant), `MetaRegistry: Invalid ${variant} index ${index} found in metadata`);
switch (variant) {
case MetaRegistryItem.String:
return this._strings[index - 1];
case MetaRegistryItem.Type:
return this._types[index - 1];
case MetaRegistryItem.TypeDef:
return this.typeDefs[index - 1];
}
}
protected itemsAt (indices: number[], variant: MetaRegistryItem): any[] {
return indices.map((index: number): string => this.itemAt(index, variant));
}
protected stringAt (index: StringIndex): string {
return this.itemAt(index, MetaRegistryItem.String);
}
public stringsAt (indices: StringIndex[]): string[] {
return this.itemsAt(indices, MetaRegistryItem.String);
}
public typeAt (index: TypeIndex): MetaType {
return this.itemAt(index, MetaRegistryItem.Type);
}
public typesAt (indices: TypeIndex[]): MetaType[] {
return this.itemsAt(indices, MetaRegistryItem.Type);
}
public hasTypeDefAt (index: TypeIndex): boolean {
return this.hasItemAt(index, MetaRegistryItem.TypeDef);
}
public typeDefAt (index: TypeIndex, extra: Pick<TypeDef, never> = {}): TypeDef {
return {
...this.itemAt(index, MetaRegistryItem.TypeDef),
...extra
};
}
}
export default class MetaRegistry extends MetadataRegistryLookup {
public constructor (json: MetaRegistryJson) {
super(json);
// Generate TypeDefs for each provided registry type
this._types.forEach((_, index: number): void => this.setTypeDefAtIndex(index + 1));
}
public setTypeDefAtIndex (typeIndex: TypeIndex): void {
this.typeDefs[typeIndex - 1] = this.typeDefFromMetaType(this.typeAt(typeIndex), typeIndex);
}
private typeDefIdFields ({ id }: MetaType): Pick<TypeDef, never> {
const { 'custom.name': nameIndex, 'custom.namespace': namespaceIndices, 'custom.params': paramsIndices } = id as MetaTypeIdCustom;
if (!nameIndex) {
return {};
}
return {
name: this.stringAt(nameIndex),
...(namespaceIndices && namespaceIndices.length
? { namespace: this.stringsAt(namespaceIndices).join('::') }
: {}
),
...(paramsIndices && paramsIndices.length
? { params: this.typesAt(paramsIndices).map((type): TypeDef => this.typeDefFromMetaType(type)) }
: {}
)
};
}
private typeDefDefFields (metaType: MetaType, typeIndex?: TypeIndex): Pick<TypeDef, never> {
let typeDef;
switch (detectedType(metaType)) {
case MetaTypeInfo.BuiltinPlain:
typeDef = this.typeDefForBuiltinPlain(metaType.id as string);
break;
case MetaTypeInfo.BuiltinTuple:
typeDef = this.typeDefForBuiltinTuple(metaType.id as TypeIndex[]);
break;
case MetaTypeInfo.BuiltinVec:
typeDef = this.typeDefForBuiltinVec(metaType.id as MetaTypeIdVec, typeIndex);
break;
case MetaTypeInfo.BuiltinVecFixed:
typeDef = this.typeDefForBuiltinVecFixed(metaType.id as MetaTypeIdVecFixed, typeIndex);
break;
case MetaTypeInfo.Enum:
typeDef = this.typeDefForEnum(metaType.def as MetaTypeDefEnum, metaType.id as MetaTypeIdCustom, typeIndex);
break;
case MetaTypeInfo.ClikeEnum:
typeDef = this.typeDefForClikeEnum(metaType.def as MetaTypeDefClikeEnum);
break;
case MetaTypeInfo.Struct:
typeDef = this.typeDefForStruct(metaType.def as MetaTypeDefStruct);
break;
case MetaTypeInfo.TupleStruct:
typeDef = this.typeDefForTupleStruct(metaType.def as MetaTypeDefTupleStruct);
break;
case MetaTypeInfo.Null:
default:
throw new Error(`Invalid type detected at index ${typeIndex}`);
}
return typeDef;
}
public typeDefFromMetaType (metaType: MetaType, typeIndex?: TypeIndex): TypeDef {
return withTypeString({
info: TypeDefInfo.Null,
type: '',
...this.typeDefDefFields(metaType, typeIndex),
...this.typeDefIdFields(metaType)
}) as TypeDef;
}
public typeDefFromMetaTypeAt (typeIndex: TypeIndex): TypeDef {
if (!this.hasTypeDefAt(typeIndex)) {
this.setTypeDefAtIndex(typeIndex);
}
return this.typeDefAt(typeIndex);
}
private typeDefForEnumVariant (variant: MetaTypeDefEnumVariant): Pick<TypeDef, any> {
const { 'unit_variant.name': unitNameIndex } = variant as MetaTypeDefEnumVariantUnit;
if (unitNameIndex) {
return {
info: TypeDefInfo.Plain,
name: this.stringAt(unitNameIndex),
type: 'Null'
};
}
const { 'tuple_struct_variant.name': tupleStructVariantNameIndex } = variant as MetaTypeDefEnumVariantTupleStruct;
if (tupleStructVariantNameIndex) {
return this.typeDefForTupleStruct(variant as MetaTypeDefEnumVariantTupleStruct);
}
const { 'struct_variant.name': structVariantNameIndex } = variant as MetaTypeDefEnumVariantStruct;
if (structVariantNameIndex) {
return this.typeDefForStruct(variant as MetaTypeDefEnumVariantStruct);
}
return {
info: TypeDefInfo.Null,
type: 'Null'
};
}
private typeDefForBuiltinPlain (id: string): Pick<TypeDef, never> {
return {
info: TypeDefInfo.Plain,
type: id
};
}
private typeDefForBuiltinTuple (id: TypeIndex[]): Pick<TypeDef, never> {
const sub = id.map((tupleTypeIndex: number): TypeDef => this.typeDefFromMetaTypeAt(tupleTypeIndex));
return {
info: TypeDefInfo.Tuple,
sub
};
}
private typeDefForBuiltinVec (id: MetaTypeIdVec, typeIndex?: TypeIndex): Pick<TypeDef, never> {
const { 'slice.type': vecTypeIndex } = id;
assert(!typeIndex || vecTypeIndex !== typeIndex, `MetaRegistry: self-referencing registry type at index ${typeIndex}`);
const type = displayType(this.typeDefFromMetaTypeAt(vecTypeIndex));
assert(type && type.length > 0, `MetaRegistry: Invalid builtin Vec type found at index ${typeIndex}`);
return {
info: TypeDefInfo.Vec,
type: `Vec<${type}>`,
sub: this.typeDefFromMetaTypeAt(vecTypeIndex)
};
}
private typeDefForBuiltinVecFixed (id: MetaTypeIdVecFixed, typeIndex?: TypeIndex): Pick<TypeDef, never> {
const { 'array.type': vecTypeIndex, 'array.len': vecLength } = id;
assert(!vecLength || vecLength <= 256, 'MetaRegistry: Only support for [Type; <length>], where length <= 256');
assert(!typeIndex || vecTypeIndex !== typeIndex, `MetaRegistry: self-referencing registry type at index ${typeIndex}`);
const type = displayType(this.typeDefFromMetaTypeAt(vecTypeIndex));
assert(type && type.length > 0, `MetaRegistry: Invalid vector type found at index ${typeIndex}`);
return {
info: TypeDefInfo.VecFixed,
ext: { length: vecLength, type },
type: `[${type};${vecLength}]`,
sub: this.typeDefFromMetaTypeAt(vecTypeIndex)
};
}
private typeDefForEnum (def: MetaTypeDefEnum, id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick<TypeDef, any> {
const name = id && this.stringAt(id['custom.name']);
switch (name) {
case 'Option':
return this.typeDefForOption(id, typeIndex);
case 'Result':
return this.typeDefForResult(id, typeIndex);
default: {
const sub = def['enum.variants'].map(variant => this.typeDefForEnumVariant(variant));
return {
info: TypeDefInfo.Enum,
sub
};
}
}
}
private typeDefForClikeEnum (def: MetaTypeDefClikeEnum): Pick<TypeDef, never> {
return {
info: TypeDefInfo.Enum,
sub: def['clike_enum.variants'].map(({ name: nameIndex, discriminant }): TypeDef => ({
ext: { discriminant },
info: TypeDefInfo.Plain,
name: this.stringAt(nameIndex),
type: 'Null'
}))
};
}
public typeDefForOption (id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick<TypeDef, any> {
assert(id['custom.params'] && id['custom.params'][0], `Invalid Option type defined at index ${typeIndex}`);
return {
info: TypeDefInfo.Option,
sub: this.typeDefFromMetaTypeAt(id['custom.params']![0])
};
}
public typeDefForResult (id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick<TypeDef, any> {
assert(id['custom.params'] && id['custom.params'][0] && id['custom.params'][1], `Invalid Result type defined at index ${typeIndex}`);
return {
info: TypeDefInfo.Result,
sub: id['custom.params']!.map((typeIndex): TypeDef => this.typeDefFromMetaTypeAt(typeIndex))
};
}
public typeDefForStruct (def: MetaTypeDefStruct | MetaTypeDefEnumVariantStruct): Pick<TypeDef, any> {
const structFields = (def as MetaTypeDefStruct)['struct.fields'] || (def as MetaTypeDefEnumVariantStruct)['struct_variant.fields'];
const structNameIndex = (def as MetaTypeDefEnumVariantStruct)['struct_variant.name'];
return withTypeString({
info: TypeDefInfo.Struct,
...(structNameIndex
? { name: this.stringAt(structNameIndex) }
: {}
),
sub: structFields.map((field: MetaTypeDefStructField): TypeDef => ({
...this.typeDefFromMetaTypeAt(field.type),
name: this.stringAt(field.name)
}))
});
}
private typeDefForTupleStruct (def: MetaTypeDefTupleStruct | MetaTypeDefEnumVariantTupleStruct): Pick<TypeDef, any> {
const tupleStructTypes = (def as MetaTypeDefTupleStruct)['tuple_struct.types'] || (def as MetaTypeDefEnumVariantTupleStruct)['tuple_struct_variant.types'];
const tupleStructNameIndex = (def as MetaTypeDefEnumVariantTupleStruct)['tuple_struct_variant.name'];
return withTypeString({
info: TypeDefInfo.Tuple,
...(tupleStructNameIndex
? { name: this.stringAt(tupleStructNameIndex) }
: {}
),
sub: tupleStructTypes.map((fieldIndex: number, index: number): TypeDef => ({
...this.typeDefFromMetaTypeAt(fieldIndex),
index
}))
});
}
}
+2 -2
View File
@@ -3,7 +3,7 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { SubmittableModuleExtrinsics } from '@polkadot/api/types';
import { ApiObject, ContractABI, ContractBase } from './types';
import { ApiObject, ContractABIPre, ContractBase } from './types';
import { assert } from '@polkadot/util';
@@ -17,7 +17,7 @@ export default abstract class RxBase implements ContractBase<'rxjs'> {
public readonly apiContracts: SubmittableModuleExtrinsics<'rxjs'>;
public constructor (api: ApiObject<'rxjs'>, abi: ContractABI | Abi) {
public constructor (api: ApiObject<'rxjs'>, abi: ContractABIPre | Abi) {
this.abi = abi instanceof Abi
? abi
: new Abi(abi);
+6 -4
View File
@@ -5,13 +5,14 @@
import { SubmittableResultImpl } from '@polkadot/api/types';
import { AccountId, Address, Hash } from '@polkadot/types/interfaces';
import { IKeyringPair } from '@polkadot/types/types';
import { ContractABI } from './types';
import { ContractABIPre } from './types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiRx, SubmittableResult } from '@polkadot/api';
import { createType } from '@polkadot/types';
import { assert } from '@polkadot/util';
import Abi from './Abi';
import RxBase from './RxBase';
@@ -37,16 +38,17 @@ class BlueprintCreateResult extends SubmittableResult {
export default class Blueprint extends RxBase {
public readonly codeHash: Hash;
public constructor (api: ApiRx, abi: ContractABI | Abi, codeHash: string | Hash) {
public constructor (api: ApiRx, abi: ContractABIPre | Abi, codeHash: string | Hash) {
super(api, abi);
this.codeHash = createType('Hash', codeHash);
}
public deployContract (endowment: number | BN, maxGas: number | BN, ...params: any[]): BlueprintCreate {
public deployContract (constructorIndex = 0, endowment: number | BN, maxGas: number | BN, ...params: any[]): BlueprintCreate {
assert(!!this.abi.constructors[constructorIndex], `Specified constructor index ${constructorIndex} does not exist`);
const signAndSend = (account: IKeyringPair | string | AccountId | Address): BlueprintCreateResultSubscription => {
return this.apiContracts
.create(endowment, maxGas, this.codeHash, this.abi.deploy(...params))
.create(endowment, maxGas, this.codeHash, this.abi.constructors[constructorIndex](...params))
.signAndSend(account)
.pipe(map(this.createResult));
};
+2 -2
View File
@@ -5,7 +5,7 @@
import { SubmittableResultImpl } from '@polkadot/api/types';
import { AccountId, Address, Hash } from '@polkadot/types/interfaces';
import { IKeyringPair } from '@polkadot/types/types';
import { ContractABI } from './types';
import { ContractABIPre } from './types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
@@ -50,7 +50,7 @@ class CodePutCodeResult extends SubmittableResult {
export default class RxCode extends RxBase {
public readonly code: Uint8Array;
public constructor (api: ApiRx, abi: ContractABI | Abi, wasm: string | Uint8Array) {
public constructor (api: ApiRx, abi: ContractABIPre | Abi, wasm: string | Uint8Array) {
super(api, abi);
this.code = u8aToU8a(wasm);
+3 -3
View File
@@ -4,7 +4,7 @@
import { AccountId, Address } from '@polkadot/types/interfaces';
import { IKeyringPair } from '@polkadot/types/types';
import { ContractABI, ContractABIFn, InterfaceContract, InterfaceContractCalls } from './types';
import { ContractABIPre, ContractABIFn, InterfaceContract, InterfaceContractCalls } from './types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
@@ -27,12 +27,12 @@ export default class RxContract extends RxBase implements InterfaceContract {
public readonly calls: InterfaceContractCalls = {};
public constructor (api: ApiRx, abi: ContractABI | Abi, address: string | AccountId | Address) {
public constructor (api: ApiRx, abi: ContractABIPre | Abi, address: string | AccountId | Address) {
super(api, abi);
this.address = createType('Address', address);
Object.entries(abi.messages).forEach(([name]): void => {
Object.entries(this.abi.messages).forEach(([name]): void => {
this.calls[name] = (fn: ContractABIFn): CallResult =>
(value: BN | number, maxGas: BN | number, ...params: any[]): ContractCall =>
this.apiContracts.call(this.address, value, maxGas, fn(...params));
+4 -53
View File
@@ -2,68 +2,19 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { CodecArg, Constructor } from '@polkadot/types/types';
import { ContractABIFn, ContractABIFnArg, ContractABIMethod, ContractABIMethodBase, ContractABITypes } from './types';
import { Constructor } from '@polkadot/types/types';
import { ContractABIFnArg } from './types';
import { Compact, createClass } from '@polkadot/types';
import { assert, isString, isUndefined, stringCamelCase } from '@polkadot/util';
export function typeToString (type: ContractABITypes): string {
if (isString(type)) {
return type;
} else if (Array.isArray(type)) {
return `(${type.map((type): string => typeToString(type)).join(',')})`;
} else if (type['Option<T>']) {
return `Option<${typeToString(type['Option<T>'].T)}>`;
} else if (type['Result<T,E>']) {
return '()'; // Result is not supported, but only applicable for returns
} else if (type['Vec<T>']) {
return `Vec<${typeToString(type['Vec<T>'].T)}>`;
} else if (type['[T;n]']) {
return `[${typeToString(type['[T;n]'].T)};${type['[T;n]'].n}]`;
}
throw new Error(`Unknown type specified ${JSON.stringify(type)}`);
}
import { createClass, encodeType } from '@polkadot/types';
export function createArgClass (args: ContractABIFnArg[], baseDef: Record<string, string>): Constructor {
return createClass(
JSON.stringify(
args.reduce((base: Record<string, any>, { name, type }): Record<string, any> => {
base[name] = type;
base[name] = encodeType(type);
return base;
}, baseDef)
)
);
}
export function createMethod (name: string, method: Partial<ContractABIMethod> & ContractABIMethodBase): ContractABIFn {
const args: ContractABIFnArg[] = method.args.map(({ name, type }): ContractABIFnArg => ({
name: stringCamelCase(name),
type: typeToString(type)
}));
const Clazz = createArgClass(args, isUndefined(method.selector) ? {} : { __selector: 'u32' });
const baseStruct: { [index: string]: any } = { __selector: method.selector };
const encoder = (...params: CodecArg[]): Uint8Array => {
assert(params.length === args.length, `Expected ${args.length} arguments to contract ${name}, found ${params.length}`);
const u8a = new Clazz(
args.reduce((mapped, { name }, index): Record<string, CodecArg> => {
mapped[name] = params[index];
return mapped;
}, { ...baseStruct })
).toU8a();
return Compact.addLengthPrefix(u8a);
};
const fn = (encoder as ContractABIFn);
fn.args = args;
fn.isConstant = !(method.mutates || false);
fn.type = method.return_type ? typeToString(method.return_type) : null;
return fn;
}
+121 -28
View File
@@ -5,6 +5,7 @@
import { SubmittableModuleExtrinsics } from '@polkadot/api/types';
import { Address } from '@polkadot/types/interfaces';
import { CodecArg } from '@polkadot/types/types';
import { MetaRegistryJson, StringIndex, TypeIndex, TypeDef } from '@polkadot/types/codec/create/types';
import { ApiPromise, ApiRx } from '@polkadot/api';
@@ -12,67 +13,159 @@ export type ApiObject<ApiType> = ApiType extends 'rxjs'
? ApiRx
: ApiPromise;
export interface ContractABITypesStruct {
'Option<T>'?: {
T: ContractABITypes;
};
'Result<T,E>'?: {
T: ContractABITypes;
E: ContractABITypes;
};
'Vec<T>'?: {
T: ContractABITypes;
};
'[T;n]'?: {
T: ContractABITypes;
n: number;
};
export interface ContractABITypePre {
ty: TypeIndex;
display_name: StringIndex[];
}
export type ContractABITypes = string | ContractABITypesStruct | (string | ContractABITypesStruct)[];
export interface ContractABIArgBasePre {
name: StringIndex;
type: ContractABITypePre;
}
export interface ContractABIArg {
export interface ContractABIArgBase {
name: string;
type: ContractABITypes;
type: TypeDef;
}
export type ContractABIMethodArgPre = ContractABIArgBasePre;
export type ContractABIMethodArg = ContractABIArgBase;
export interface ContractABIMethodBase {
args: ContractABIArg[];
args: ContractABIMethodArg[];
}
export interface ContractABIMethod extends ContractABIMethodBase {
export interface ContractABIMethodBasePre {
args: ContractABIMethodArgPre[];
}
export interface ContractABIMethodCommon {
docs?: ContractABIDocs;
mutates?: boolean;
name: string;
selector: number;
return_type: ContractABITypes | null;
}
export interface ContractABIMethodPre extends ContractABIMethodCommon, ContractABIMethodBasePre {
name: StringIndex;
return_type: ContractABITypePre | null;
}
export interface ContractABIMethod extends ContractABIMethodCommon {
args: ContractABIMethodArg[];
name: string;
returnType: TypeDef | null;
}
export interface ContractABIContractCommon {
docs?: ContractABIDocs;
}
export interface ContractABIContractPre extends ContractABIContractCommon {
constructors: ContractABIMethodPre[];
messages: ContractABIMethodPre[];
name: StringIndex;
events?: ContractABIEventPre[];
docs?: ContractABIDocs;
}
export interface ContractABIContract extends ContractABIContractCommon {
constructors: ContractABIMethod[];
messages: ContractABIMethod[];
name: string;
events?: ContractABIEvent[];
docs?: ContractABIDocs;
}
export interface ContractABIPre extends MetaRegistryJson {
storage: ContractABIStoragePre;
contract: ContractABIContractPre;
}
export interface ContractABI {
deploy: ContractABIMethodBase;
messages: ContractABIMethod[];
name: string;
storage: ContractABIStorage;
contract: ContractABIContract;
}
export interface ContractABIFnArg {
name: string;
type: string;
type: TypeDef;
}
export interface ContractABIMeta {
args: ContractABIFnArg[];
isConstant: boolean;
type: string | null;
type: TypeDef | null;
}
export interface ContractABIFn extends ContractABIMeta {
(...args: CodecArg[]): Uint8Array;
}
export interface ContractABIEventArgBase {
indexed: boolean;
}
export interface ContractABIEventArgPre extends ContractABIArgBasePre, ContractABIEventArgBase {}
export interface ContractABIEventArg extends ContractABIArgBase, ContractABIEventArgBase {}
export type ContractABIDocs = string[];
export interface ContractABIEventPre {
args: ContractABIEventArgPre[];
}
export interface ContractABIEvent {
args: ContractABIEventArg[];
}
export interface ContractABIRangeBase {
'range.offset': number[];
'range.len': number;
}
export interface ContractABIRangePre extends ContractABIRangeBase {
'range.elem_type': TypeIndex;
}
export interface ContractABIRange extends ContractABIRangeBase {
'range.elem_type': TypeDef;
}
export type ContractABIStorageLayoutPre = ContractABIStorageStructPre | ContractABIRangePre;
export type ContractABIStorageLayout = ContractABIStorageStruct | ContractABIRange;
export interface ContractABIStorageStructFieldPre {
name: StringIndex;
layout: ContractABIStorageLayoutPre;
}
export interface ContractABIStorageStructField {
name: string;
layout: ContractABIStorageLayout;
}
export interface ContractABIStorageStructPre {
'struct.type': TypeIndex;
'struct.fields': ContractABIStorageStructFieldPre[];
}
export interface ContractABIStorageStruct {
'struct.type': TypeDef;
'struct.fields': ContractABIStorageStructField[];
}
export type ContractABIStoragePre = ContractABIStorageStructPre;
export type ContractABIStorage = ContractABIStorageStruct;
export type AbiMessages = Record<string, ContractABIFn>;
export interface InterfaceAbi {
readonly abi: ContractABI;
readonly deploy: ContractABIFn;
readonly constructors: ContractABIFn[];
readonly messages: AbiMessages;
}
File diff suppressed because it is too large Load Diff
-50
View File
@@ -1,50 +0,0 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ContractABI, ContractABIArg } from './types';
import { assert, isNumber, isNull, isString, isObject } from '@polkadot/util';
export function validateArgs (name: string, args: ContractABIArg[]): void {
assert(Array.isArray(args), `Expected 'args' to exist on ${name}`);
args.forEach((arg): void => {
const unknownKeys = Object.keys(arg).filter((key): boolean => !['name', 'type'].includes(key));
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for ${name}`);
assert(isString(arg.name), `${name} args should have valid name `);
assert(isString(arg.type) || isObject(arg.type), `${name} args should have valid type`);
});
}
export function validateDeploy ({ deploy }: ContractABI): void {
const unknownKeys = Object.keys(deploy).filter((key): boolean => !['args'].includes(key));
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI deploy`);
validateArgs('deploy', deploy.args);
}
export function validateMethods ({ messages }: ContractABI): void {
messages.forEach((method): void => {
const unknownKeys = Object.keys(method).filter((key): boolean => !['args', 'mutates', 'name', 'selector', 'return_type'].includes(key));
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for messages.${method.name}`);
assert(isString(method.name), `Expected name for messages.${method.name}`);
assert(isNumber(method.selector), `Expected selector for messages.${method.name}`);
assert(isNull(method.return_type) || isString(method.return_type) || isObject(method.return_type), `Expected return_type for messages.${method.name}`);
validateArgs(`messages.${method.name}`, method.args);
});
}
export function validateAbi (abi: ContractABI): void {
const unknownKeys = Object.keys(abi).filter((key): boolean => !['deploy', 'messages', 'name'].includes(key));
assert(unknownKeys.length === 0, `Unknown fields ${unknownKeys.join(', ')} found in ABI`);
assert(abi.deploy && abi.messages && isString(abi.name), 'ABI should have deploy, messages & name sections');
validateDeploy(abi);
validateMethods(abi);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,184 @@
[
{
"info": 7,
"type": "{\"value\": {\"cell\": {\"cell\": ([u8;32])}}}",
"name": "Flipper",
"namespace": "flipper::normal",
"sub": [
{
"info": 7,
"type": "{\"cell\": {\"cell\": ([u8;32])}}",
"name": "value",
"namespace": "ink_core::storage::value",
"params": [
{
"info": 5,
"type": "bool"
}
],
"sub": [
{
"info": 7,
"type": "{\"cell\": ([u8;32])}",
"name": "cell",
"namespace": "ink_core::storage::cell::sync_cell",
"params": [
{
"info": 5,
"type": "bool"
}
],
"sub": [
{
"info": 8,
"type": "([u8;32])",
"name": "cell",
"namespace": "ink_core::storage::key",
"sub": [
{
"info": 10,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": ""
},
"sub": {
"info": 5,
"type": "u8"
},
"index": 0
}
]
}
]
}
]
}
]
},
{
"info": 7,
"type": "{\"cell\": {\"cell\": ([u8;32])}}",
"name": "Value",
"namespace": "ink_core::storage::value",
"params": [
{
"info": 5,
"type": "bool"
}
],
"sub": [
{
"info": 7,
"type": "{\"cell\": ([u8;32])}",
"name": "cell",
"namespace": "ink_core::storage::cell::sync_cell",
"params": [
{
"info": 5,
"type": "bool"
}
],
"sub": [
{
"info": 8,
"type": "([u8;32])",
"name": "cell",
"namespace": "ink_core::storage::key",
"sub": [
{
"info": 10,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": ""
},
"sub": {
"info": 5,
"type": "u8"
},
"index": 0
}
]
}
]
}
]
},
{
"info": 5,
"type": "bool"
},
{
"info": 7,
"type": "{\"cell\": ([u8;32])}",
"name": "SyncCell",
"namespace": "ink_core::storage::cell::sync_cell",
"params": [
{
"info": 5,
"type": "bool"
}
],
"sub": [
{
"info": 8,
"type": "([u8;32])",
"name": "cell",
"namespace": "ink_core::storage::key",
"sub": [
{
"info": 10,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": ""
},
"sub": {
"info": 5,
"type": "u8"
},
"index": 0
}
]
}
]
},
{
"info": 8,
"type": "([u8;32])",
"name": "Key",
"namespace": "ink_core::storage::key",
"sub": [
{
"info": 10,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": ""
},
"sub": {
"info": 5,
"type": "u8"
},
"index": 0
}
]
},
{
"info": 10,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": ""
},
"sub": {
"info": 5,
"type": "u8"
}
},
{
"info": 5,
"type": "u8"
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,201 @@
{
"registry": {
"strings": [
"Flipper",
"flipper",
"normal",
"value",
"Value",
"ink_core",
"storage",
"cell",
"SyncCell",
"sync_cell",
"Key",
"key",
"flip",
"get"
],
"types": [
{
"id": {
"custom.name": 1,
"custom.namespace": [
2,
3
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 4,
"type": 2
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
4
],
"custom.params": [
3
]
},
"def": {
"struct.fields": [
{
"name": 8,
"type": 4
}
]
}
},
{
"id": "bool",
"def": "builtin"
},
{
"id": {
"custom.name": 9,
"custom.namespace": [
6,
7,
8,
10
],
"custom.params": [
3
]
},
"def": {
"struct.fields": [
{
"name": 8,
"type": 5
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
12
],
"custom.params": []
},
"def": {
"tuple_struct.types": [
6
]
}
},
{
"id": {
"array.len": 32,
"array.type": 7
},
"def": "builtin"
},
{
"id": "u8",
"def": "builtin"
}
]
},
"storage": {
"struct.type": 1,
"struct.fields": [
{
"name": 4,
"layout": {
"struct.type": 2,
"struct.fields": [
{
"name": 8,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"range.len": 1,
"range.elem_type": 3
}
}
]
}
}
]
},
"contract": {
"name": 1,
"deploy": {
"args": [],
"docs": [
"Initializes our state to `false` upon deploying our smart contract."
]
},
"messages": [
{
"name": 13,
"selector": 970692492,
"mutates": true,
"args": [],
"return_type": null,
"docs": [
"Flips the current state of our smart contract."
]
},
{
"name": 14,
"selector": 4266279973,
"mutates": false,
"args": [],
"return_type": 3,
"docs": [
"Returns the current state."
]
}
],
"events": [],
"docs": []
}
}
@@ -0,0 +1,935 @@
{
"registry": {
"strings": [
"SharedVec",
"shared_vec",
"normal",
"mutators",
"HashMap",
"ink_core",
"storage",
"collections",
"hash_map",
"impls",
"AccountId",
"env",
"srml",
"types",
"Access",
"begin",
"Option",
"None",
"Some",
"end",
"len",
"Value",
"value",
"cell",
"SyncCell",
"sync_cell",
"Key",
"key",
"entries",
"SyncChunk",
"chunk",
"sync_chunk",
"Entry",
"Occupied",
"OccupiedEntry",
"val",
"Removed",
"cells_key",
"vec",
"Vec",
"cells",
"on_deploy",
"push",
"i32",
"Result",
"Ok",
"Err",
"register",
"mutator",
"set",
"at",
"u32",
"to",
"get",
"Mutate",
"Push",
"Register"
],
"types": [
{
"id": {
"custom.name": 1,
"custom.namespace": [
2,
3
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 4,
"type": 2
},
{
"name": 39,
"type": 15
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8,
9,
10
],
"custom.params": [
3,
6
]
},
"def": {
"struct.fields": [
{
"name": 21,
"type": 9
},
{
"name": 29,
"type": 12
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
12,
13,
14
],
"custom.params": []
},
"def": {
"tuple_struct.types": [
4
]
}
},
{
"id": {
"array.len": 32,
"array.type": 5
},
"def": "builtin"
},
{
"id": "u8",
"def": "builtin"
},
{
"id": {
"custom.name": 15,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 16,
"type": 7
},
{
"name": 20,
"type": 7
}
]
}
},
{
"id": {
"custom.name": 17,
"custom.namespace": [],
"custom.params": [
8
]
},
"def": {
"enum.variants": [
{
"unit_variant.name": 18
},
{
"tuple_struct_variant.name": 19,
"tuple_struct_variant.types": [
8
]
}
]
}
},
{
"id": "u32",
"def": "builtin"
},
{
"id": {
"custom.name": 22,
"custom.namespace": [
6,
7,
23
],
"custom.params": [
8
]
},
"def": {
"struct.fields": [
{
"name": 24,
"type": 10
}
]
}
},
{
"id": {
"custom.name": 25,
"custom.namespace": [
6,
7,
24,
26
],
"custom.params": [
8
]
},
"def": {
"struct.fields": [
{
"name": 24,
"type": 11
}
]
}
},
{
"id": {
"custom.name": 27,
"custom.namespace": [
6,
7,
28
],
"custom.params": []
},
"def": {
"tuple_struct.types": [
4
]
}
},
{
"id": {
"custom.name": 30,
"custom.namespace": [
6,
7,
31,
32,
31
],
"custom.params": [
13
]
},
"def": {
"struct.fields": [
{
"name": 38,
"type": 11
}
]
}
},
{
"id": {
"custom.name": 33,
"custom.namespace": [
6,
7,
8,
9,
10
],
"custom.params": [
3,
6
]
},
"def": {
"enum.variants": [
{
"tuple_struct_variant.name": 34,
"tuple_struct_variant.types": [
14
]
},
{
"unit_variant.name": 37
}
]
}
},
{
"id": {
"custom.name": 35,
"custom.namespace": [
6,
7,
8,
9,
10
],
"custom.params": [
3,
6
]
},
"def": {
"struct.fields": [
{
"name": 28,
"type": 3
},
{
"name": 36,
"type": 6
}
]
}
},
{
"id": {
"custom.name": 40,
"custom.namespace": [
6,
7,
8,
39,
10
],
"custom.params": [
16
]
},
"def": {
"struct.fields": [
{
"name": 21,
"type": 9
},
{
"name": 41,
"type": 17
}
]
}
},
{
"id": "i32",
"def": "builtin"
},
{
"id": {
"custom.name": 30,
"custom.namespace": [
6,
7,
31,
32,
31
],
"custom.params": [
16
]
},
"def": {
"struct.fields": [
{
"name": 38,
"type": 11
}
]
}
},
{
"id": {
"custom.name": 45,
"custom.namespace": [],
"custom.params": [
19,
8
]
},
"def": {
"enum.variants": [
{
"tuple_struct_variant.name": 46,
"tuple_struct_variant.types": [
19
]
},
{
"tuple_struct_variant.name": 47,
"tuple_struct_variant.types": [
8
]
}
]
}
},
{
"id": [],
"def": "builtin"
},
{
"id": {
"custom.name": 45,
"custom.namespace": [],
"custom.params": [
16,
8
]
},
"def": {
"enum.variants": [
{
"tuple_struct_variant.name": 46,
"tuple_struct_variant.types": [
16
]
},
{
"tuple_struct_variant.name": 47,
"tuple_struct_variant.types": [
8
]
}
]
}
},
{
"id": {
"custom.name": 17,
"custom.namespace": [],
"custom.params": [
16
]
},
"def": {
"enum.variants": [
{
"unit_variant.name": 18
},
{
"tuple_struct_variant.name": 19,
"tuple_struct_variant.types": [
16
]
}
]
}
}
]
},
"storage": {
"struct.type": 1,
"struct.fields": [
{
"name": 4,
"layout": {
"struct.type": 2,
"struct.fields": [
{
"name": 21,
"layout": {
"struct.type": 9,
"struct.fields": [
{
"name": 24,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"range.len": 1,
"range.elem_type": 8
}
}
]
}
},
{
"name": 29,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1
],
"range.len": 4294967295,
"range.elem_type": 13
}
}
]
}
},
{
"name": 39,
"layout": {
"struct.type": 15,
"struct.fields": [
{
"name": 21,
"layout": {
"struct.type": 9,
"struct.fields": [
{
"name": 24,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0
],
"range.len": 1,
"range.elem_type": 8
}
}
]
}
},
{
"name": 41,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
1
],
"range.len": 4294967295,
"range.elem_type": 16
}
}
]
}
}
]
},
"contract": {
"name": 1,
"constructors": [
{
"name": 42,
"selector": 0,
"args": [],
"docs": [
"Initializes the value to the initial value."
]
}
],
"messages": [
{
"name": 43,
"selector": 865577567,
"mutates": true,
"args": [
{
"name": 23,
"type": {
"ty": 16,
"display_name": [
44
]
}
}
],
"return_type": {
"ty": 18,
"display_name": [
45
]
},
"docs": [
"Pushes a new value to the shared vector.",
"",
"# Errors",
"",
"- If the caller does not have unlimited access rights."
]
},
{
"name": 48,
"selector": 572030971,
"mutates": true,
"args": [
{
"name": 49,
"type": {
"ty": 3,
"display_name": [
11
]
}
},
{
"name": 16,
"type": {
"ty": 7,
"display_name": [
17
]
}
},
{
"name": 20,
"type": {
"ty": 7,
"display_name": [
17
]
}
}
],
"return_type": {
"ty": 18,
"display_name": [
45
]
},
"docs": [
"Registers a new user with the given access rights.",
"",
"Can also be used to change access rights of an already existing user.",
"",
"# Errors",
"",
"- If the caller does not have unlimited access rights."
]
},
{
"name": 50,
"selector": 2028185770,
"mutates": true,
"args": [
{
"name": 51,
"type": {
"ty": 8,
"display_name": [
52
]
}
},
{
"name": 53,
"type": {
"ty": 16,
"display_name": [
44
]
}
}
],
"return_type": {
"ty": 20,
"display_name": [
45
]
},
"docs": [
"Sets the value at the given position to the given value.",
"",
"Returns the previous value.",
"",
"# Errors",
"",
"- If the given position is out of bounds.",
"- If the caller does not have the required access rights."
]
},
{
"name": 54,
"selector": 4266279973,
"mutates": false,
"args": [
{
"name": 51,
"type": {
"ty": 8,
"display_name": [
52
]
}
}
],
"return_type": {
"ty": 21,
"display_name": [
17
]
},
"docs": [
"Returns the value of the shared vector at the given position",
"or `None` if the access is out of bounds."
]
},
{
"name": 21,
"selector": 1403873684,
"mutates": false,
"args": [],
"return_type": {
"ty": 8,
"display_name": [
52
]
},
"docs": [
"Returns the length of the shared vector."
]
}
],
"events": [
{
"name": 55,
"args": [
{
"name": 51,
"indexed": false,
"type": {
"ty": 8,
"display_name": [
52
]
}
},
{
"name": 23,
"indexed": false,
"type": {
"ty": 16,
"display_name": [
44
]
}
}
],
"docs": [
"Fires whenever a mutator changes the vector."
]
},
{
"name": 56,
"args": [
{
"name": 49,
"indexed": false,
"type": {
"ty": 3,
"display_name": [
11
]
}
},
{
"name": 23,
"indexed": false,
"type": {
"ty": 16,
"display_name": [
44
]
}
}
],
"docs": [
"Fires whenever a mutator pushes the vector successfully."
]
},
{
"name": 57,
"args": [
{
"name": 49,
"indexed": false,
"type": {
"ty": 3,
"display_name": [
11
]
}
},
{
"name": 16,
"indexed": false,
"type": {
"ty": 7,
"display_name": [
17
]
}
},
{
"name": 20,
"indexed": false,
"type": {
"ty": 7,
"display_name": [
17
]
}
}
],
"docs": [
"Fires whenever a new mutator is registered",
"or when a mutators access rights are changed."
]
}
],
"docs": []
}
}
@@ -0,0 +1,697 @@
{
"registry": {
"strings": [
"RustStructures",
"structures",
"normal",
"my_tuple_struct",
"Value",
"ink_core",
"storage",
"value",
"TupleStruct",
"cell",
"SyncCell",
"sync_cell",
"Key",
"key",
"my_struct",
"Struct",
"first",
"seconds",
"my_clike_enum",
"ClikeEnum",
"FirstVariant",
"SecondVariant",
"ThirdVariant",
"my_enum",
"RustEnum",
"NoData",
"TupleVariant",
"StructVariant",
"second",
"my_union",
"Union"
],
"types": [
{
"id": {
"custom.name": 1,
"custom.namespace": [
2,
3
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 4,
"type": 2
},
{
"name": 15,
"type": 9
},
{
"name": 19,
"type": 12
},
{
"name": 24,
"type": 15
},
{
"name": 30,
"type": 18
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8
],
"custom.params": [
3
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 6
}
]
}
},
{
"id": {
"custom.name": 9,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"tuple_struct.types": [
4,
5
]
}
},
{
"id": "u8",
"def": "builtin"
},
{
"id": "u16",
"def": "builtin"
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
10,
12
],
"custom.params": [
3
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 7
}
]
}
},
{
"id": {
"custom.name": 13,
"custom.namespace": [
6,
7,
14
],
"custom.params": []
},
"def": {
"tuple_struct.types": [
8
]
}
},
{
"id": {
"array.len": 32,
"array.type": 4
},
"def": "builtin"
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8
],
"custom.params": [
10
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 11
}
]
}
},
{
"id": {
"custom.name": 16,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 17,
"type": 4
},
{
"name": 18,
"type": 5
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
10,
12
],
"custom.params": [
10
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 7
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8
],
"custom.params": [
13
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 14
}
]
}
},
{
"id": {
"custom.name": 20,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"clike_enum.variants": [
{
"name": 21,
"discriminant": 0
},
{
"name": 22,
"discriminant": 1
},
{
"name": 23,
"discriminant": 42
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
10,
12
],
"custom.params": [
13
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 7
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8
],
"custom.params": [
16
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 17
}
]
}
},
{
"id": {
"custom.name": 25,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"enum.variants": [
{
"unit_variant.name": 26
},
{
"tuple_struct_variant.name": 27,
"tuple_struct_variant.types": [
4,
5
]
},
{
"struct_variant.name": 28,
"struct_variant.fields": [
{
"name": 17,
"type": 4
},
{
"name": 29,
"type": 5
}
]
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
10,
12
],
"custom.params": [
16
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 7
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8
],
"custom.params": [
19
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 20
}
]
}
},
{
"id": {
"custom.name": 31,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"union.fields": [
{
"name": 17,
"type": 4
},
{
"name": 29,
"type": 5
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
10,
12
],
"custom.params": [
19
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 7
}
]
}
}
]
},
"storage": {
"struct.type": 1,
"struct.fields": [
{
"name": 4,
"layout": {
"struct.type": 2,
"struct.fields": [
{
"name": 10,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"range.len": 1,
"range.elem_type": 3
}
}
]
}
},
{
"name": 15,
"layout": {
"struct.type": 9,
"struct.fields": [
{
"name": 10,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1
],
"range.len": 1,
"range.elem_type": 10
}
}
]
}
},
{
"name": 19,
"layout": {
"struct.type": 12,
"struct.fields": [
{
"name": 10,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
"range.len": 1,
"range.elem_type": 13
}
}
]
}
},
{
"name": 24,
"layout": {
"struct.type": 15,
"struct.fields": [
{
"name": 10,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
3
],
"range.len": 1,
"range.elem_type": 16
}
}
]
}
},
{
"name": 30,
"layout": {
"struct.type": 18,
"struct.fields": [
{
"name": 10,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
4
],
"range.len": 1,
"range.elem_type": 19
}
}
]
}
}
]
},
"contract": {
"name": 1,
"deploy": {
"args": [],
"docs": []
},
"messages": [],
"events": [],
"docs": []
}
}
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-derive",
"version": "0.94.1",
"version": "0.95.2",
"description": "Common functions used across Polkadot, derived from RPC calls and storage queries.",
"main": "index.js",
"keywords": [
@@ -27,11 +27,11 @@
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api-derive#readme",
"dependencies": {
"@babel/runtime": "^7.6.2",
"@polkadot/api": "^0.94.1",
"@polkadot/types": "^0.94.1"
"@babel/runtime": "^7.6.3",
"@polkadot/api": "^0.95.2",
"@polkadot/types": "^0.95.2"
},
"devDependencies": {
"@polkadot/keyring": "^1.5.1"
"@polkadot/keyring": "^1.6.1"
}
}
+32 -22
View File
@@ -8,7 +8,7 @@ import BN from 'bn.js';
import { combineLatest, of, Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { ClassOf, Option, createType } from '@polkadot/types';
import { Option, Vec, createType } from '@polkadot/types';
import { bnMax } from '@polkadot/util';
import { idAndIndex } from '../accounts/idAndIndex';
@@ -16,33 +16,35 @@ import { bestNumber } from '../chain/bestNumber';
import { DerivedBalances } from '../types';
import { drr } from '../util/drr';
type Result = [AccountId | undefined, BlockNumber | undefined, [Balance?, Balance?, BalanceLock[]?, Option<VestingSchedule>?, Index?]];
type ResultBalance = [Balance, Balance, BalanceLock[], Option<VestingSchedule>];
type Result = [AccountId, BlockNumber, ResultBalance, Index];
function calcBalances ([accountId = createType('AccountId'), bestNumber = createType('Balance'), [freeBalance = createType('Balance'), reservedBalance = createType('Balance'), locks = [], vesting = new Option<VestingSchedule>(ClassOf('VestingSchedule'), null), accountNonce = createType('Balance')]]: Result): DerivedBalances {
function calcBalances ([accountId, bestNumber, [freeBalance, reservedBalance, locks, vesting], accountNonce]: Result): DerivedBalances {
let lockedBalance = createType('Balance');
if (Array.isArray(locks)) {
// only get the locks that are valid until passed the current block
const totals = locks.filter((value): boolean => bestNumber && value.until.gt(bestNumber));
// get the maximum of the locks according to https://github.com/paritytech/substrate/blob/master/srml/balances/src/lib.rs#L699
lockedBalance = totals[0]
? bnMax(...totals.map(({ amount }): Balance => amount)) as Balance
? createType('Balance', bnMax(...totals.map(({ amount }): Balance => amount)))
: createType('Balance');
}
// offset = balance locked at genesis, perBlock is the unlock amount
const { offset, perBlock } = vesting.unwrapOr(createType('VestingSchedule'));
const vestedNow: BN = perBlock.mul(bestNumber);
const vestedBalance: BN = vestedNow.gt(offset)
const vestedNow = createType('Balance', perBlock.mul(bestNumber));
const vestedBalance = vestedNow.gt(offset)
? freeBalance
: freeBalance.sub(offset).add(vestedNow);
: createType('Balance', freeBalance.sub(offset).add(vestedNow));
// NOTE Workaround for this account on Alex (one of a couple reported) -
// 5F7BJL6Z4m8RLtK7nXEqqpEqhBbd535Z3CZeYF6ccvaQAY6N
// The locked is > the vested and ended up with the locked > free,
// i.e. related to https://github.com/paritytech/polkadot/issues/225
// (most probably due to movements from stash -> controller -> free)
const availableBalance: BN = bnMax(createType('Balance'), vestedBalance.sub(lockedBalance));
const availableBalance = createType('Balance', bnMax(new BN(0), vestedBalance.sub(lockedBalance)));
return {
accountId,
@@ -52,22 +54,30 @@ function calcBalances ([accountId = createType('AccountId'), bestNumber = create
lockedBalance,
reservedBalance,
vestedBalance,
votingBalance: freeBalance.add(reservedBalance)
} as DerivedBalances;
votingBalance: createType('Balance', freeBalance.add(reservedBalance))
};
}
function queryBalances (api: ApiInterfaceRx, accountId: AccountId): Observable<ResultBalance> {
return api.queryMulti<[Balance, Balance, Vec<BalanceLock>, Option<VestingSchedule>]>([
[api.query.balances.freeBalance, accountId],
[api.query.balances.reservedBalance, accountId],
[api.query.balances.locks, accountId],
[api.query.balances.vesting, accountId]
]);
}
/**
* @name all
* @param {( AccountIndex | AccountId | Address | string )} address - An accounts Id in different formats.
* @returns An object containing the combined results of the storage queries for
* all relevant fees as declared in the substrate chain spec.
* @returns An object containing the results of various balance queries
* @example
* <BR>
*
* ```javascript
* const ALICE = 'F7Hs';
*
* api.derive.balances.all(ALICE, ([accountId, lockedBalance]) => {
* api.derive.balances.all(ALICE, ({ accountId, lockedBalance }) => {
* console.log(`The account ${accountId} has a locked balance ${lockedBalance} units.`);
* });
* ```
@@ -80,16 +90,16 @@ export function all (api: ApiInterfaceRx): (address: AccountIndex | AccountId |
? combineLatest([
of(accountId),
bestNumber(api)(),
api.queryMulti([
[api.query.balances.freeBalance, accountId],
[api.query.balances.reservedBalance, accountId],
[api.query.balances.locks, accountId],
[api.query.balances.vesting, accountId],
[api.query.system.accountNonce, accountId]
])
queryBalances(api, accountId),
// FIXME This is having issues with Kusama, only use accountNonce atm
// api.rpc.account && api.rpc.account.nextIndex
// ? api.rpc.account.nextIndex(accountId)
// // otherwise we end up with this: type 'Codec | Index' is not assignable to type 'Index'.
// : api.query.system.accountNonce<Index>(accountId)
api.query.system.accountNonce<Index>(accountId)
])
: of([undefined, undefined, [undefined, undefined, undefined, undefined, undefined]])
) as Observable<Result>
: of([createType('AccountId'), createType('BlockNumber'), [createType('Balance'), createType('Balance'), createType('Vec<BalanceLock>'), createType('Option<VestingSchedule>', null)], createType('Index')])
)
),
map(calcBalances),
drr()
+20 -18
View File
@@ -3,37 +3,39 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Balance } from '@polkadot/types/interfaces';
import { DerivedFees } from '../types';
import BN from 'bn.js';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { drr } from '../util/drr';
type Result = [BN, BN, BN, BN, BN];
type Result = [Balance, Balance, Balance, Balance, Balance];
function queryV2 (api: ApiInterfaceRx): Observable<Result> {
const paymentBase = api.consts.transactionPayment || api.consts.balances;
function querySubtrateV2 (api: ApiInterfaceRx): Observable<Result> {
return of([
// get values from api.const for substrate versions post spec_version: 101
// https://github.com/paritytech/substrate/pull/2883/files#diff-5e5e1c3aec9ddfde0a9054d062ab3db9R131
api.consts.balances.creationFee,
api.consts.balances.existentialDeposit,
api.consts.balances.transactionBaseFee,
api.consts.balances.transactionByteFee,
api.consts.balances.transferFee
]) as any as Observable<Result>;
api.consts.balances.creationFee as Balance,
api.consts.balances.existentialDeposit as Balance,
api.consts.balances.transferFee as Balance,
paymentBase.transactionBaseFee as Balance,
paymentBase.transactionByteFee as Balance
]);
}
function querySubtrateV1 (api: ApiInterfaceRx): Observable<Result> {
return api.queryMulti([
function queryV1 (api: ApiInterfaceRx): Observable<Result> {
return api.queryMulti<Result>([
// Support older versions and get values from storage
api.query.balances.creationFee,
api.query.balances.existentialDeposit,
api.query.balances.transferFee,
api.query.balances.transactionBaseFee,
api.query.balances.transactionByteFee,
api.query.balances.transferFee
]) as any as Observable<Result>;
api.query.balances.transactionByteFee
]);
}
/**
@@ -44,7 +46,7 @@ function querySubtrateV1 (api: ApiInterfaceRx): Observable<Result> {
* <BR>
*
* ```javascript
* api.derive.balances.fees(([creationFee, transferFee]) => {
* api.derive.balances.fees(({ creationFee, transferFee }) => {
* console.log(`The fee for creating a new account on this chain is ${creationFee} units. The fee required for making a transfer is ${transferFee} units.`);
* });
* ```
@@ -53,10 +55,10 @@ export function fees (api: ApiInterfaceRx): () => Observable<DerivedFees> {
return (): Observable<DerivedFees> => {
return (
api.consts.balances
? querySubtrateV2(api)
: querySubtrateV1(api)
? queryV2(api)
: queryV1(api)
).pipe(
map(([creationFee, existentialDeposit, transactionBaseFee, transactionByteFee, transferFee]): DerivedFees => ({
map(([creationFee, existentialDeposit, transferFee, transactionBaseFee, transactionByteFee]): DerivedFees => ({
creationFee,
existentialDeposit,
transactionBaseFee,
+9 -6
View File
@@ -3,17 +3,20 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, BlockNumber, SetIndex, VoteIndex } from '@polkadot/types/interfaces';
import { Codec } from '@polkadot/types/types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Vec, u32 } from '@polkadot/types';
import { DerivedElectionsInfo } from '../types';
import { drr } from '../util/drr';
function query (api: ApiInterfaceRx): Observable<[[AccountId, BlockNumber][], AccountId[], BN, BN, SetIndex, BlockNumber, VoteIndex, SetIndex]> {
return api.queryMulti([
type Result = [Vec<[AccountId, BlockNumber] & Codec>, Vec<AccountId>, u32, u32, SetIndex, BlockNumber, VoteIndex, SetIndex];
function query (api: ApiInterfaceRx): Observable<Result> {
return api.queryMulti<Result>([
api.query.elections.members,
api.query.elections.candidates,
api.query.elections.candidateCount,
@@ -22,7 +25,7 @@ function query (api: ApiInterfaceRx): Observable<[[AccountId, BlockNumber][], Ac
api.query.elections.termDuration,
api.query.elections.voteCount,
api.query.elections.voterCount
]) as any;
]);
}
/**
@@ -33,7 +36,7 @@ function query (api: ApiInterfaceRx): Observable<[[AccountId, BlockNumber][], Ac
* <BR>
*
* ```javascript
* api.derive.elections.info(([members, candidates]) => {
* api.derive.elections.info(({ members, candidates }) => {
* console.log(`There are currently ${members.length} council members and ${candidates.length} prospective council candidates.`);
* });
* ```
@@ -56,7 +59,7 @@ export function info (api: ApiInterfaceRx): () => Observable<DerivedElectionsInf
termDuration,
voteCount,
voterCount
} as unknown as DerivedElectionsInfo)),
})),
drr()
);
};
+74 -73
View File
@@ -5,51 +5,51 @@
import { BlockNumber, EraIndex, SessionIndex } from '@polkadot/types/interfaces';
import { DerivedSessionInfo } from '../types';
import BN from 'bn.js';
import { Observable, combineLatest, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option, u64 } from '@polkadot/types';
import { Option, u64, createType } from '@polkadot/types';
import { drr } from '../util/drr';
import { bestNumber } from '../chain';
type Result0to94 = [BlockNumber, [SessionIndex, Option<BlockNumber>, BN, BN, SessionIndex]];
type Result = [[boolean, boolean, u64, SessionIndex], [u64, u64, u64], [SessionIndex, EraIndex]];
type Result94Session = [SessionIndex, Option<BlockNumber>, BlockNumber, BlockNumber, SessionIndex];
type Result94 = [BlockNumber, Result94Session];
const ZERO = new BN(0);
const ONE = new BN(1);
type ResultIndex = [SessionIndex, EraIndex];
type ResultSlots = [u64, u64, u64];
type ResultType = [boolean, boolean, u64, SessionIndex];
type Result = [ResultType, ResultSlots, ResultIndex];
// internal helper to just split the logic - take all inputs, do the calculations and combine
function createDerived0to94 ([bestNumber, [currentIndex, _lastLengthChange, sessionLength, lastEraLengthChange, sessionsPerEra]]: Result0to94): DerivedSessionInfo {
const lastLengthChange = _lastLengthChange
? _lastLengthChange.unwrapOr(ZERO)
: ZERO;
function createDerived94 ([bestNumber, [currentIndex, _lastLengthChange, sessionLength, lastEraLengthChange, sessionsPerEra]]: Result94): DerivedSessionInfo {
const lastLengthChange = (_lastLengthChange && _lastLengthChange.unwrapOr(null)) || createType('BlockNumber');
const sessionProgress = bestNumber
.sub(lastLengthChange)
.add(sessionLength)
.mod(sessionLength);
const currentEra = (currentIndex)
const currentEra = currentIndex
.sub(lastEraLengthChange)
.mod(sessionsPerEra);
const eraProgress = currentEra
.mul(sessionLength)
.add(sessionProgress);
return {
currentEra,
currentEra: createType('EraIndex', currentEra),
currentIndex,
eraLength: sessionLength.mul(sessionsPerEra),
eraProgress: currentEra
.mul(sessionLength)
.add(sessionProgress),
eraLength: createType('BlockNumber', sessionLength.mul(sessionsPerEra)),
eraProgress: createType('BlockNumber', eraProgress),
isEpoch: false,
lastEraLengthChange,
lastLengthChange,
sessionLength,
sessionsPerEra,
sessionProgress
} as unknown as DerivedSessionInfo;
sessionProgress: createType('BlockNumber', sessionProgress)
};
}
function createDerived ([[hasBabe, isGenesisSlot, epochDuration, sessionsPerEra], [currentSlot, epochIndex, epochOrGenesisStartSlot], [currentIndex, currentEra]]: Result): DerivedSessionInfo {
function createDerivedLatest ([[hasBabe, isGenesisSlot, epochDuration, sessionsPerEra], [currentSlot, epochIndex, epochOrGenesisStartSlot], [currentIndex, currentEra]]: Result): DerivedSessionInfo {
const epochStartSlot = isGenesisSlot
? epochIndex
.mul(epochDuration)
@@ -64,73 +64,74 @@ function createDerived ([[hasBabe, isGenesisSlot, epochDuration, sessionsPerEra]
return {
currentEra,
currentIndex,
eraLength: sessionsPerEra.mul(epochDuration),
eraProgress,
eraLength: createType('BlockNumber', sessionsPerEra.mul(epochDuration)),
eraProgress: createType('BlockNumber', eraProgress),
isEpoch: hasBabe,
lastEraLengthChange: ZERO,
lastLengthChange: epochStartSlot,
lastEraLengthChange: createType('BlockNumber'),
lastLengthChange: createType('BlockNumber', epochStartSlot),
sessionLength: epochDuration,
sessionsPerEra,
sessionProgress: sessionProgress
} as unknown as DerivedSessionInfo;
sessionProgress: createType('BlockNumber', sessionProgress)
};
}
function info94 (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
return combineLatest([
bestNumber(api)(),
api.queryMulti<Result94Session>([
api.query.session.currentIndex,
api.query.session.lastLengthChange,
api.query.session.sessionLength,
api.query.staking.lastEraLengthChange,
api.query.staking.sessionsPerEra
])
]).pipe(
map(createDerived94),
drr()
);
}
function infoLatest (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
const hasBabe = !!api.consts.babe;
return combineLatest([
of([
hasBabe,
hasBabe && !!api.query.babe.genesisSlot,
hasBabe
? api.consts.babe.epochDuration as u64
: createType('u64', 1),
api.consts.staking.sessionsPerEra as SessionIndex
] as ResultType),
hasBabe
? api.queryMulti<ResultSlots>([
api.query.babe.currentSlot,
api.query.babe.epochIndex,
api.query.babe.genesisSlot
? api.query.babe.genesisSlot
: api.query.babe.epochStartSlot
])
: of([createType('u64', 1), createType('u64', 1), createType('u64', 1)] as ResultSlots),
api.queryMulti<ResultIndex>([
api.query.session.currentIndex,
api.query.staking.currentEra
])
]).pipe(
map(createDerivedLatest),
drr()
);
}
/**
* @description Retrieves all the session and era info and calculates specific values on it as the length of the session and eras
*/
export function info (api: ApiInterfaceRx): () => Observable<DerivedSessionInfo> {
const hasBabe = !!api.consts.babe;
return (): Observable<DerivedSessionInfo> => {
// With substrate `spec_version 94`, the era and session has been explicitly exposed as `parameter_types`.
// pre-94 we had more info and needed to calculate (handle old/Alex first)
// https://github.com/paritytech/substrate/commit/dbf322620948935d2bbae214504e6c668c3073ed#diff-c29f42d6b931fa93ba038dbbbfec3055
return api.query.session.lastLengthChange
? (
combineLatest([
bestNumber(api)(),
api.queryMulti([
api.query.session.currentIndex,
api.query.session.lastLengthChange,
api.query.session.sessionLength,
api.query.staking.lastEraLengthChange,
api.query.staking.sessionsPerEra
])
]) as any as Observable<Result0to94>
).pipe(
map(createDerived0to94),
drr()
)
: (
combineLatest([
// sessionsPerEra:
// substrate spec_version >= 94 : get from parameter_types exposed as api.consts
// https://github.com/paritytech/substrate/pull/2802/files#diff-5e5e1c3aec9ddfde0a9054d062ab3db9R156
of([
hasBabe,
hasBabe && !!api.query.babe.genesisSlot,
hasBabe
? api.consts.babe.epochDuration
: ONE,
api.consts.staking.sessionsPerEra
]),
hasBabe
? api.queryMulti([
api.query.babe.currentSlot,
api.query.babe.epochIndex,
api.query.babe.genesisSlot
? api.query.babe.genesisSlot
: api.query.babe.epochStartSlot
])
: of([ONE, ONE, ONE]),
api.queryMulti([
api.query.session.currentIndex,
api.query.staking.currentEra
])
]) as unknown as Observable<Result>
).pipe(
map(createDerived),
drr()
);
? info94(api) // 1.x
: infoLatest(api); // 2.x
};
}
+16 -15
View File
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, BlockNumber } from '@polkadot/types/interfaces/runtime';
import { AccountId, Balance, BlockNumber } from '@polkadot/types/interfaces/runtime';
import { Keys } from '@polkadot/types/interfaces/session';
import { Exposure, RewardDestination, StakingLedger, UnlockChunk, ValidatorPrefs } from '@polkadot/types/interfaces/staking';
import { Codec } from '@polkadot/types/types';
@@ -40,15 +40,16 @@ function groupByEra (list: UnlockChunk[]): Record<string, BN> {
}
// calculate the remining blocks in a specific unlock era
function remainingBlocks (era: BN, eraLength: BN, bestNumber: BlockNumber): BN {
function remainingBlocks (era: BN, eraLength: BN, bestNumber: BlockNumber): BlockNumber {
const remaining = eraLength.mul(era).sub(bestNumber);
return remaining.lten(0)
return createType('BlockNumber', remaining.lten(0)
? new BN(0)
: remaining;
: remaining
);
}
function calculateUnlocking (stakingLedger: StakingLedger | undefined, eraLength: BN, bestNumber: BlockNumber): DerivedUnlocking | undefined {
function calculateUnlocking (stakingLedger: StakingLedger | undefined, eraLength: BN, bestNumber: BlockNumber): DerivedUnlocking[] | undefined {
if (isUndefined(stakingLedger)) {
return undefined;
}
@@ -63,24 +64,24 @@ function calculateUnlocking (stakingLedger: StakingLedger | undefined, eraLength
// group the Unlockchunks that have the same era and sum their values
const groupedResult = groupByEra(unlockingChunks);
const results = Object.entries(groupedResult).map(([eraString, value]): { value: BN; remainingBlocks: BN } => ({
value,
const results = Object.entries(groupedResult).map(([eraString, value]): DerivedUnlocking => ({
value: createType('Balance', value),
remainingBlocks: remainingBlocks(createType('BlockNumber', eraString), eraLength, bestNumber)
}));
return results.length ? results : undefined;
}
function redeemableSum (stakingLedger: StakingLedger | undefined, eraLength: BN, bestNumber: BlockNumber): BN {
function redeemableSum (stakingLedger: StakingLedger | undefined, eraLength: BN, bestNumber: BlockNumber): Balance {
if (isUndefined(stakingLedger)) {
return new BN(0);
return createType('Balance');
}
return stakingLedger.unlocking.reduce((total, { era, value }): BN => {
return createType('Balance', stakingLedger.unlocking.reduce((total, { era, value }): BN => {
return remainingBlocks(era.unwrap(), eraLength, bestNumber).eqn(0)
? total.add(value.unwrap())
: total;
}, new BN(0));
}, new BN(0)));
}
function unwrapSessionIds (stashId: AccountId, queuedKeys: Option<AccountId> | Vec<[AccountId, Keys] & Codec>, nextKeys: Option<Keys>): { nextSessionIds: AccountId[]; nextSessionId?: AccountId; sessionIds: AccountId[]; sessionId?: AccountId } {
@@ -132,7 +133,7 @@ function retrieveMulti (api: ApiInterfaceRx, stashId: AccountId, controllerId: A
]) as Observable<MultiResult>;
}
function retrieveInfo (api: ApiInterfaceRx, stashId: AccountId, controllerId: AccountId): Observable<DerivedStaking> {
function retrieveInfo (api: ApiInterfaceRx, accountId: AccountId, stashId: AccountId, controllerId: AccountId): Observable<DerivedStaking> {
return combineLatest([
eraLength(api)(),
bestNumber(api)(),
@@ -143,7 +144,7 @@ function retrieveInfo (api: ApiInterfaceRx, stashId: AccountId, controllerId: Ac
const stakingLedger = _stakingLedger.unwrapOr(undefined);
return {
accountId: stashId,
accountId,
controllerId,
nominators,
offline: recentlyOffline[stashId.toString()],
@@ -178,9 +179,9 @@ export function info (api: ApiInterfaceRx): (_accountId: Uint8Array | string) =>
).pipe(
switchMap(([controllerId, stakingLedger]): Observable<DerivedStaking> =>
controllerId.isSome
? retrieveInfo(api, accountId, controllerId.unwrap())
? retrieveInfo(api, accountId, accountId, controllerId.unwrap())
: stakingLedger.isSome
? retrieveInfo(api, stakingLedger.unwrap().stash, accountId)
? retrieveInfo(api, accountId, stakingLedger.unwrap().stash, accountId)
: of({ accountId, nextSessionIds: [], sessionIds: [] })
),
drr()
+27 -26
View File
@@ -2,19 +2,20 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, Balance, BlockNumber, Exposure, Index, RewardDestination, SetIndex, StakingLedger, ValidatorPrefs, Vote, VoteIndex } from '@polkadot/types/interfaces';
import { AccountId, Balance, BlockNumber, EraIndex, Exposure, Index, RewardDestination, SessionIndex, SetIndex, StakingLedger, ValidatorPrefs, Vote, VoteIndex } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import { u32 } from '@polkadot/types';
export interface DerivedBalances {
accountId: AccountId;
accountNonce: Index;
freeBalance: BN;
lockedBalance: BN;
availableBalance: BN;
reservedBalance: BN;
votingBalance: BN;
vestedBalance: BN;
freeBalance: Balance;
lockedBalance: Balance;
availableBalance: Balance;
reservedBalance: Balance;
votingBalance: Balance;
vestedBalance: Balance;
}
export type DerivedBalancesMap = Record<string, DerivedBalances>;
@@ -35,8 +36,8 @@ export interface DerivedContractFees {
export interface DerivedElectionsInfo {
members: Record<string, BlockNumber>;
candidates: AccountId[];
candidateCount: BN;
desiredSeats: BN;
candidateCount: u32;
desiredSeats: u32;
nextVoterSet: SetIndex;
termDuration: BlockNumber;
voteCount: VoteIndex;
@@ -44,11 +45,11 @@ export interface DerivedElectionsInfo {
}
export interface DerivedFees {
creationFee: BN;
existentialDeposit: BN;
transactionBaseFee: BN;
transactionByteFee: BN;
transferFee: BN;
creationFee: Balance;
existentialDeposit: Balance;
transactionBaseFee: Balance;
transactionByteFee: Balance;
transferFee: Balance;
}
export interface RecentlyOffline {
@@ -65,16 +66,16 @@ export interface DerivedReferendumVote {
}
export interface DerivedSessionInfo {
currentEra: BN;
currentIndex: BN;
eraLength: BN;
eraProgress: BN;
currentEra: EraIndex;
currentIndex: SessionIndex;
eraLength: BlockNumber;
eraProgress: BlockNumber;
isEpoch: boolean;
lastEraLengthChange: BN;
lastLengthChange: BN;
sessionLength: BN;
sessionsPerEra: BN;
sessionProgress: BN;
lastEraLengthChange: BlockNumber;
lastLengthChange: BlockNumber;
sessionLength: BlockNumber;
sessionsPerEra: SessionIndex;
sessionProgress: BlockNumber;
}
export type DerivedStakingAccount = [AccountId, DerivedStakingOnlineStatus];
@@ -99,7 +100,7 @@ export interface DerivedStaking extends DerivedStakingOnlineStatus {
nextSessionId?: AccountId;
nextSessionIds: AccountId[];
nominators?: AccountId[];
redeemable?: BN;
redeemable?: Balance;
rewardDestination?: RewardDestination;
// @deprecated Use sessionIds instead
sessionId?: AccountId;
@@ -107,11 +108,11 @@ export interface DerivedStaking extends DerivedStakingOnlineStatus {
stakers?: Exposure;
stakingLedger?: StakingLedger;
stashId?: AccountId;
unlocking?: DerivedUnlocking;
unlocking?: DerivedUnlocking[];
validatorPrefs?: ValidatorPrefs;
}
export type DerivedUnlocking = { remainingBlocks: BN; value: BN }[];
export type DerivedUnlocking = { remainingBlocks: BlockNumber; value: Balance };
export interface VoterPosition {
globalIndex: BN;
+3 -1
View File
@@ -22,7 +22,9 @@ export const drr = (): DrrResult => <T> (source$: Observable<T>): Observable<T>
throw error;
}),
distinctUntilChanged(),
distinctUntilChanged((a: any, b: any): boolean =>
JSON.stringify({ value: a }) === JSON.stringify({ value: b })
),
publishReplay(1),
refCount()
);
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-metadata",
"version": "0.94.1",
"version": "0.95.2",
"description": "Helpers to extract information from runtime metadata",
"main": "index.js",
"publishConfig": {
@@ -26,12 +26,12 @@
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/type-metadata#readme",
"dependencies": {
"@babel/runtime": "^7.6.2",
"@polkadot/types": "^0.94.1",
"@polkadot/util": "^1.5.1",
"@polkadot/util-crypto": "^1.5.1"
"@babel/runtime": "^7.6.3",
"@polkadot/types": "^0.95.2",
"@polkadot/util": "^1.6.1",
"@polkadot/util-crypto": "^1.6.1"
},
"devDependencies": {
"@polkadot/keyring": "^1.5.1"
"@polkadot/keyring": "^1.6.1"
}
}
@@ -14,7 +14,7 @@ import { stringCamelCase } from '@polkadot/util';
* @param metadata - The metadata
*/
export default function fromMetadata (metadata: Metadata): Constants {
return metadata.asLatest.modules.reduce((result, moduleMetadata): Constants => {
return metadata.asLatest.modules.reduce((result: Constants, moduleMetadata): Constants => {
if (moduleMetadata.constants.isEmpty) {
return result;
}
@@ -22,7 +22,7 @@ export default function fromMetadata (metadata: Metadata): Constants {
const { name } = moduleMetadata;
// For access, we change the index names, i.e. Democracy.EnactmentPeriod -> democracy.enactmentPeriod
result[stringCamelCase(name.toString())] = moduleMetadata.constants.reduce((newModule, meta): ModuleConstants => {
result[stringCamelCase(name.toString())] = moduleMetadata.constants.reduce((newModule: ModuleConstants, meta): ModuleConstants => {
const codec = createTypeUnsafe(meta.type.toString(), [meta.value]);
// This is not a perfect idea, however as it stands with number-only constants on the metadata
@@ -33,8 +33,8 @@ export default function fromMetadata (metadata: Metadata): Constants {
newModule[stringCamelCase(meta.name.toString())] = codec;
return newModule;
}, {} as unknown as ModuleConstants);
}, {});
return result;
}, {} as unknown as Constants);
}, {});
}
+2 -2
View File
@@ -3,10 +3,10 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { Codec } from '@polkadot/types/types';
import { ModuleConstantMetadataV7 } from '@polkadot/types/interfaces';
import { ModuleConstantMetadataLatest } from '@polkadot/types/interfaces';
export interface ConstantCodec extends Codec {
meta: ModuleConstantMetadataV7;
meta: ModuleConstantMetadataLatest;
}
export type ModuleConstants = Record<string, Codec>;
@@ -2,10 +2,10 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Call, FunctionMetadataV7 } from '@polkadot/types/interfaces';
import { Call, FunctionMetadataLatest } from '@polkadot/types/interfaces';
import { CallFunction } from '@polkadot/types/types';
import { createType } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
import { assert, stringCamelCase } from '@polkadot/util';
/**
@@ -21,7 +21,7 @@ export default function createDescriptor (
section: string,
sectionIndex: number,
methodIndex: number,
callMetadata: FunctionMetadataV7
callMetadata: FunctionMetadataLatest
): CallFunction {
const callIndex = new Uint8Array([sectionIndex, methodIndex]);
const expectedArgs = callMetadata.args;
@@ -5,7 +5,7 @@
import '@polkadot/types/injector';
import { createType, Metadata } from '@polkadot/types';
import json from '@polkadot/types/Metadata/v7/static';
import json from '@polkadot/types/Metadata/static';
import fromMetadata from '.';
@@ -4,7 +4,7 @@
import { Calls, ModulesWithCalls } from '@polkadot/types/types';
import { ModuleMetadataV7 } from '@polkadot/types/Metadata/v7/Metadata';
import { ModuleMetadataV8 } from '@polkadot/types/Metadata/v8/Metadata';
import Metadata from '@polkadot/types/Metadata';
import { stringCamelCase } from '@polkadot/util';
@@ -19,16 +19,16 @@ import createUnchecked from './createUnchecked';
export default function fromMetadata (metadata: Metadata): ModulesWithCalls {
return metadata.asLatest.modules
.filter(({ calls }): boolean => calls.isSome)
.reduce((result, modul: ModuleMetadataV7, sectionIndex): ModulesWithCalls => {
const section = stringCamelCase(modul.name.toString());
.reduce((result, { calls, name }: ModuleMetadataV8, sectionIndex): ModulesWithCalls => {
const section = stringCamelCase(name.toString());
result[section] = modul.calls.unwrap().reduce((newModule, callMetadata, methodIndex): Calls => {
result[section] = calls.unwrap().reduce((newModule: Calls, callMetadata, methodIndex): Calls => {
const method = stringCamelCase(callMetadata.name.toString());
newModule[method] = createUnchecked(section, sectionIndex, methodIndex, callMetadata);
return newModule;
}, {} as unknown as Calls);
}, {});
return result;
}, { ...extrinsics });
@@ -2,17 +2,26 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ModulesWithCalls } from '@polkadot/types/types';
import '@polkadot/types/injector';
import BN from 'bn.js';
import testingPairs from '@polkadot/keyring/testingPairs';
import { createType } from '@polkadot/types';
import { createType, Metadata } from '@polkadot/types';
import metadataStatic from '@polkadot/types/Metadata/static';
import extrinsics from './static';
import fromMetadata from './fromMetadata';
const keyring = testingPairs({ type: 'ed25519' }, false);
describe('extrinsics', (): void => {
let extrinsics: ModulesWithCalls;
beforeEach((): void => {
extrinsics = fromMetadata(new Metadata(metadataStatic));
});
it('encodes an actual transfer (actual data)', (): void => {
expect(
createType('Extrinsic',
@@ -4,7 +4,7 @@
import { ModulesWithCalls } from '@polkadot/types/types';
import { Metadata } from '@polkadot/types';
import Metadata from '@polkadot/types/Metadata';
import metadataRpc from '@polkadot/types/Metadata/static';
import fromMetadata from './fromMetadata';
@@ -5,9 +5,8 @@
import { Codec } from '@polkadot/types/types';
import BN from 'bn.js';
import { Bytes, Compact, StorageKey, U8a } from '@polkadot/types';
import { createType, createTypeUnsafe } from '@polkadot/types/codec';
import { StorageEntryMetadata, StorageEntryType } from '@polkadot/types/Metadata/v7/Storage';
import { Compact, U8a, createType, createTypeUnsafe } from '@polkadot/types/codec';
import { StorageEntryMetadata, StorageEntryType } from '@polkadot/types/Metadata/v8/Storage';
import { StorageEntry } from '@polkadot/types/primitive/StorageKey';
import { assert, isNull, isUndefined, stringLowerFirst, stringToU8a, u8aConcat } from '@polkadot/util';
@@ -121,15 +120,15 @@ function extendLinkedMap ({ meta: { documentation, name, type } }: CreateItemFn,
// meta fallback only applies to actual entry values, create one for head
headFn.meta = new StorageEntryMetadata({
name,
modifier: createType('StorageEntryModifierV7', 1), // required
type: new StorageEntryType(createType('PlainTypeV7', type.asMap.key), 0),
fallback: new Bytes(createTypeUnsafe(type.asMap.key.toString()).toHex()),
modifier: createType('StorageEntryModifierLatest', 1), // required
type: new StorageEntryType(createType('PlainTypeLatest', type.asMap.key), 0),
fallback: createType('Bytes', createTypeUnsafe(type.asMap.key.toString()).toHex()),
documentation
});
// here we pass the section/method through as well - these are not on
// the function itself, so specify these explicitly to the constructor
storageFn.headKey = new StorageKey(headFn, {
storageFn.headKey = createType('StorageKey', headFn, {
method: storageFn.method,
section: `head of ${storageFn.section}`
});
@@ -5,18 +5,12 @@
import '@polkadot/types/injector';
import testingPairs from '@polkadot/keyring/testingPairs';
import { Metadata } from '@polkadot/types';
import json from '@polkadot/types/Metadata/static';
import { u8aToHex } from '@polkadot/util';
import fromMetadata from '../fromMetadata';
import storage from '../static';
const keyring = testingPairs({ type: 'ed25519' });
// Use the pre-generated metadata
const metadata = new Metadata(json);
const storage = fromMetadata(metadata);
describe('fromMetadata', (): void => {
it('should throw if the storage function expects an argument', (): void => {
expect((): any => storage.balances.freeBalance()).toThrowError(/requires one argument/);
@@ -2,9 +2,9 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { StorageEntryMetadata, StorageEntryType } from '@polkadot/types/Metadata/v7/Storage';
import { StorageEntryMetadata, StorageEntryType } from '@polkadot/types/Metadata/v8/Storage';
import { StorageEntry } from '@polkadot/types/primitive/StorageKey';
import { createType, Text, Vec } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
import createFunction from './createFunction';
@@ -18,8 +18,8 @@ const createRuntimeFunction = (method: string, key: string, { documentation, typ
createFunction(
{
meta: {
documentation: new Vec(Text, [documentation]),
modifier: createType('StorageEntryModifierV7', 1), // required
documentation: createType('Vec<Text>', [documentation]),
modifier: createType('StorageEntryModifierLatest', 1), // required
type: new StorageEntryType(type, 0),
toJSON: (): any => key
} as unknown as StorageEntryMetadata,
+10 -10
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api",
"version": "0.94.1",
"version": "0.95.2",
"description": "Promise and RxJS wrappers around the Polkadot JS RPC",
"main": "index.js",
"keywords": [
@@ -26,16 +26,16 @@
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api#readme",
"dependencies": {
"@babel/runtime": "^7.6.2",
"@polkadot/api-derive": "^0.94.1",
"@polkadot/api-metadata": "^0.94.1",
"@polkadot/keyring": "^1.5.1",
"@polkadot/rpc-core": "^0.94.1",
"@polkadot/rpc-provider": "^0.94.1",
"@polkadot/types": "^0.94.1",
"@polkadot/util-crypto": "^1.5.1"
"@babel/runtime": "^7.6.3",
"@polkadot/api-derive": "^0.95.2",
"@polkadot/api-metadata": "^0.95.2",
"@polkadot/keyring": "^1.6.1",
"@polkadot/rpc-core": "^0.95.2",
"@polkadot/rpc-provider": "^0.95.2",
"@polkadot/types": "^0.95.2",
"@polkadot/util-crypto": "^1.6.1"
},
"devDependencies": {
"@polkadot/keyring": "^1.5.1"
"@polkadot/keyring": "^1.6.1"
}
}
+34 -24
View File
@@ -2,7 +2,6 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { RpcMethod } from '@polkadot/jsonrpc/types';
import { RpcInterface } from '@polkadot/rpc-core/jsonrpc.types';
import { Call, Hash, RuntimeVersion } from '@polkadot/types/interfaces';
import { AnyFunction, CallFunction, Codec, CodecArg as Arg, ModulesWithCalls } from '@polkadot/types/types';
@@ -20,7 +19,6 @@ import { map, switchMap } from 'rxjs/operators';
import decorateDerive, { ExactDerive } from '@polkadot/api-derive';
import { Constants } from '@polkadot/api-metadata/consts/types';
import { Storage } from '@polkadot/api-metadata/storage/types';
import jsonrpc from '@polkadot/jsonrpc';
import RpcCore from '@polkadot/rpc-core';
import { WsProvider } from '@polkadot/rpc-provider';
import { Metadata, Null, u64 } from '@polkadot/types';
@@ -69,8 +67,6 @@ export default abstract class Decorate<ApiType> extends Events {
protected _rpcCore: RpcCore;
private _rpcMap: Map<string, RpcMethod> = new Map();
protected _runtimeMetadata?: Metadata;
protected _runtimeVersion?: RuntimeVersion;
@@ -125,8 +121,16 @@ export default abstract class Decorate<ApiType> extends Events {
this.decorateMethod = decorateMethod;
this._options = options;
this._type = type;
this._rpcCore = new RpcCore(thisProvider);
this._rpcCore = new RpcCore(thisProvider, this._options.rpc);
this._isConnected = new BehaviorSubject(this._rpcCore.provider.isConnected());
this._rx.hasSubscriptions = this._rpcCore.provider.hasSubscriptions;
}
/**
* @returns `true` if the API operates with subscriptions
*/
get hasSubscriptions (): boolean {
return this._rpcCore.provider.hasSubscriptions;
}
private decorateFunctionMeta (input: MetaDecoration, output: MetaDecoration): MetaDecoration {
@@ -165,7 +169,7 @@ export default abstract class Decorate<ApiType> extends Events {
const hasResults = methods.length !== 0;
// loop through all entries we have (populated in decorate) and filter as required
[...this._rpcMap.entries()]
[...this._rpcCore.mapping.entries()]
.filter(([key, { isOptional }]): boolean =>
// only remove when we have results and method missing, or with no results if optional
hasResults
@@ -180,15 +184,15 @@ export default abstract class Decorate<ApiType> extends Events {
}
protected decorateRpc<ApiType> (rpc: RpcCore, decorateMethod: DecorateMethod<ApiType>): DecoratedRpc<ApiType, RpcInterface> {
return Object.keys(jsonrpc).reduce((out, _sectionName): DecoratedRpc<ApiType, RpcInterface> => {
return rpc.sections.reduce((out, _sectionName): DecoratedRpc<ApiType, RpcInterface> => {
const sectionName = _sectionName as keyof DecoratedRpc<ApiType, RpcInterface>;
// out and section here are horrors to get right from a typing perspective :()
// out and section here are horrors to get right from a typing perspective :(
(out as any)[sectionName] = Object.entries(rpc[sectionName]).reduce((section, [methodName, method]): DecoratedRpcSection<ApiType, RpcInterface[typeof sectionName]> => {
(section as any)[methodName] = decorateMethod(method, { methodName });
// add this endpoint mapping to our internal map - we use this for filters
this._rpcMap.set(`${sectionName}_${methodName}`, jsonrpc[sectionName].methods[methodName]);
// skip subscriptions where we have a non-subscribe interface
if (this.hasSubscriptions || !(methodName.startsWith('subscribe') || methodName.startsWith('unsubscribe'))) {
(section as any)[methodName] = decorateMethod(method, { methodName });
}
return section;
}, {} as unknown as DecoratedRpcSection<ApiType, RpcInterface[typeof sectionName]>);
@@ -246,15 +250,19 @@ export default abstract class Decorate<ApiType> extends Events {
? [creator, args]
: [creator, ...args];
const decorated = creator.headKey
// FIXME We probably want to be able to query the full list with non-subs as well
const decorated = this.hasSubscriptions && creator.headKey
? this.decorateStorageEntryLinked(creator, decorateMethod)
: decorateMethod((...args: any[]): Observable<Codec> =>
this._rpcCore.state
// Unfortunately for one-shot calls we also use .subscribeStorage here
.subscribeStorage<[Codec]>([getArgs(...args)])
// state_storage returns an array of values, since we have just subscribed to
// a single entry, we pull that from the array and return it as-is
.pipe(map(([data]): Codec => data)), { methodName: creator.method });
: decorateMethod((...args: any[]): Observable<Codec> => (
this.hasSubscriptions
? this._rpcCore.state
// Unfortunately for one-shot calls we also use .subscribeStorage here
.subscribeStorage<[Codec]>([getArgs(...args)])
// state_storage returns an array of values, since we have just subscribed to
// a single entry, we pull that from the array and return it as-is
.pipe(map(([data]): Codec => data))
: this._rpcCore.state.getStorage(getArgs(...args))
), { methodName: creator.method });
decorated.creator = creator;
@@ -267,10 +275,12 @@ export default abstract class Decorate<ApiType> extends Events {
decorated.key = (arg1?: Arg, arg2?: Arg): string =>
u8aToHex(compactStripLength(creator(creator.meta.type.isDoubleMap ? [arg1, arg2] : arg1))[1]);
// When using double map storage function, user need to pass double map key as an array
decorated.multi = decorateMethod((args: (Arg | Arg[])[]): Observable<Codec[]> =>
this._rpcCore.state.subscribeStorage(
args.map((arg: Arg[] | Arg): [StorageEntry, Arg | Arg[]] => [creator, arg])));
if (this.hasSubscriptions) {
// When using double map storage function, user need to pass double map key as an array
decorated.multi = decorateMethod((args: (Arg | Arg[])[]): Observable<Codec[]> =>
this._rpcCore.state.subscribeStorage(
args.map((arg: Arg[] | Arg): [StorageEntry, Arg | Arg[]] => [creator, arg])));
}
decorated.size = decorateMethod((arg1?: Arg, arg2?: Arg): Observable<u64> =>
this._rpcCore.state.getStorageSize(getArgs(arg1, arg2)));
+3 -7
View File
@@ -7,14 +7,10 @@ import { ApiInterfaceEvents } from '../types';
import EventEmitter from 'eventemitter3';
export default class Events {
private _eventemitter: EventEmitter;
private _eventemitter = new EventEmitter();
protected constructor () {
this._eventemitter = new EventEmitter();
}
protected emit (type: ApiInterfaceEvents, ...args: any[]): void {
this._eventemitter.emit(type, ...args);
protected emit (type: ApiInterfaceEvents, ...args: any[]): boolean {
return this._eventemitter.emit(type, ...args);
}
/**
+7 -5
View File
@@ -10,8 +10,8 @@ import constantsFromMeta from '@polkadot/api-metadata/consts/fromMetadata';
import extrinsicsFromMeta from '@polkadot/api-metadata/extrinsics/fromMetadata';
import storageFromMeta from '@polkadot/api-metadata/storage/fromMetadata';
import { GenericCall, GenericEvent, Metadata, u32 as U32 } from '@polkadot/types';
import { LATEST_VERSION as EXTRINSIC_LATEST_VERSION } from '@polkadot/types/primitive/Extrinsic/constants';
import { assert, logger } from '@polkadot/util';
import { LATEST_EXTRINSIC_VERSION } from '@polkadot/types/primitive/Extrinsic/Extrinsic';
import { logger } from '@polkadot/util';
import { cryptoWaitReady, setSS58Format } from '@polkadot/util-crypto';
import addressDefaults from '@polkadot/util-crypto/address/defaults';
@@ -59,7 +59,9 @@ export default abstract class Init<ApiType> extends Decorate<ApiType> {
public constructor (options: ApiOptions, type: ApiTypes, decorateMethod: DecorateMethod<ApiType>) {
super(options, type, decorateMethod);
assert(this._rpcCore.provider.hasSubscriptions, 'Api can only be used with a provider supporting subscriptions');
if (!this.hasSubscriptions) {
console.warn('Api will be available in a limited mode since the provider does not support subscriptions');
}
// We only register the types (global) if this is not a cloned instance.
// Do right up-front, so we get in the user types before we are actually
@@ -172,13 +174,13 @@ export default abstract class Init<ApiType> extends Decorate<ApiType> {
// only inject if we are not a clone (global init)
if (!this._options.source) {
GenericEvent.injectMetadata(metadata);
GenericCall.injectMethods(extrinsics);
GenericCall.injectMetadata(metadata);
// detect the extrinsic version in-use based on the last block
const { block: { extrinsics: [firstTx] } }: SignedBlock = await this._rpcCore.chain.getBlock().toPromise();
// If we haven't sync-ed to 1 yes, this won't have any values
this._extrinsicType = firstTx ? firstTx.type : EXTRINSIC_LATEST_VERSION;
this._extrinsicType = firstTx ? firstTx.type : LATEST_EXTRINSIC_VERSION;
}
this._extrinsics = this.decorateExtrinsics(extrinsics, this.decorateMethod);
+3 -3
View File
@@ -28,7 +28,7 @@ try {
}
function assertResult<T> (value: T | undefined): T {
assert(!isUndefined(value), 'Api needs to be initialised before using, listen on \'ready\'');
assert(!isUndefined(value), 'Api needs to be initialized before using, listen on \'ready\'');
return value as T;
}
@@ -163,7 +163,7 @@ export default abstract class ApiBase<ApiType> extends Init<ApiType> {
/**
* @description Contains all the raw rpc sections and their subsequent methods in the API as defined by the jsonrpc interface definitions. Unlike the dynamic `api.query` and `api.tx` sections, these methods are fixed (although extensible with node upgrades) and not determined by the runtime.
*
* RPC endpoints available here allow for the query of chain, node and system information, in addition to providing interfaces for the raw queries of state (usine known keys) and the submission of transactions.
* RPC endpoints available here allow for the query of chain, node and system information, in addition to providing interfaces for the raw queries of state (using known keys) and the submission of transactions.
*
* @example
* <BR>
@@ -225,7 +225,7 @@ export default abstract class ApiBase<ApiType> extends Init<ApiType> {
}
/**
* @description Disconnect from the underlying provider, halting all comms
* @description Disconnect from the underlying provider, halting all network traffic
*/
public disconnect (): void {
this._rpcCore.disconnect();
+8 -5
View File
@@ -72,7 +72,7 @@ export default class Submittable<ApiType> extends _Extrinsic implements Submitta
// signAndSend implementation for all 3 cases above
public signAndSend (account: IKeyringPair | string | AccountId | Address, optionsOrStatus?: Partial<SignerOptions> | Callback<SubmittableResultImpl>, optionalStatusCb?: Callback<SubmittableResultImpl>): SubmitableResultResult<ApiType> | SubmitableResultSubscription<ApiType> {
const [options, statusCb] = this._makeSignAndSendOptions(optionsOrStatus, optionalStatusCb);
const isSubscription = this._ignoreStatusCb || !!statusCb;
const isSubscription = this._api.hasSubscriptions && (this._ignoreStatusCb || !!statusCb);
const address = isKeyringPair(account) ? account.address : account.toString();
let updateId: number | undefined;
@@ -106,7 +106,7 @@ export default class Submittable<ApiType> extends _Extrinsic implements Submitta
// send implementation for both immediate Hash and statusCb variants
public send (statusCb?: Callback<SubmittableResultImpl>): SubmitableResultResult<ApiType> | SubmitableResultSubscription<ApiType> {
const isSubscription = this._ignoreStatusCb || !!statusCb;
const isSubscription = this._api.hasSubscriptions && (this._ignoreStatusCb || !!statusCb);
return this._decorateMethod(
isSubscription
@@ -193,9 +193,12 @@ export default class Submittable<ApiType> extends _Extrinsic implements Submitta
return combineLatest([
// if we have a nonce already, don't retrieve the latest, use what is there
isUndefined(options.nonce)
? this._api.rpc.account.nextIndex
? this._api.rpc.account.nextIndex(address)
: this._api.query.system.accountNonce(address)
// FIXME This apparently is having issues on latest Kusama for nonce retrieval,
// hence we are using the accountNonce only
// ? this._api.rpc.account.nextIndex
// ? this._api.rpc.account.nextIndex(address)
// : this._api.query.system.accountNonce(address)
? this._api.query.system.accountNonce(address)
: of(createType('Index', options.nonce)),
// if we have an era provided already or eraLength is <= 0 (immortal)
// don't get the latest block, just pass null, handle in mergeMap
+5
View File
@@ -2,6 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { UserRpc } from '@polkadot/rpc-core/types';
import { Hash, RuntimeVersion } from '@polkadot/types/interfaces';
import { AnyFunction, Callback, CallFunction, Codec, CodecArg, RegistryTypes, SignatureOptions, SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types';
import { SubmittableResultImpl, SubmittableExtrinsic } from './submittable/types';
@@ -185,6 +186,10 @@ export interface ApiOptions {
* connecting to a WsProvider connecting localhost with the default port, i.e. `ws://127.0.0.1:9944`
*/
provider?: ProviderInterface;
/**
* @description User-defined RPC methods
*/
rpc?: UserRpc;
/**
* @description An external signer which will be used to sign extrinsic when account passed in is not KeyringPair
*/
@@ -79,7 +79,7 @@ describeE2E({
return (
api.tx.contracts
.create(CREATION_FEE, MAX_GAS, codeHash, abi.deploy(randomStart))
.create(CREATION_FEE, MAX_GAS, codeHash, abi.constructors[0](randomStart))
.signAndSend(keyring.dave, (result: SubmittableResult): void => {
// console.error('create', JSON.stringify(result));
@@ -84,7 +84,7 @@ describeE2E({
return (
api.tx.contracts
.create(CREATION_FEE, MAX_GAS, codeHash, abi.deploy(randomStart))
.create(CREATION_FEE, MAX_GAS, codeHash, abi.constructors[0](randomStart))
.signAndSend(keyring.dave, (result: SubmittableResult): void => {
if (result.status.isFinalized) {
const record = result.findRecord('contracts', 'Instantiated');
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/rpc-core",
"version": "0.94.1",
"version": "0.95.2",
"description": "A JavaScript wrapper for the Polkadot JsonRPC interface",
"main": "index.js",
"keywords": [
@@ -26,11 +26,11 @@
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-core#readme",
"dependencies": {
"@babel/runtime": "^7.6.2",
"@polkadot/jsonrpc": "^0.94.1",
"@polkadot/rpc-provider": "^0.94.1",
"@polkadot/types": "^0.94.1",
"@polkadot/util": "^1.5.1",
"@babel/runtime": "^7.6.3",
"@polkadot/jsonrpc": "^0.95.2",
"@polkadot/rpc-provider": "^0.95.2",
"@polkadot/types": "^0.95.2",
"@polkadot/util": "^1.6.1",
"rxjs": "^6.5.3"
}
}
+7
View File
@@ -15,6 +15,7 @@ import rpcMetadataV4 from '@polkadot/types/Metadata/v4/static';
import rpcMetadataV5 from '@polkadot/types/Metadata/v5/static';
import rpcMetadataV6 from '@polkadot/types/Metadata/v6/static';
import rpcMetadataV7 from '@polkadot/types/Metadata/v7/static';
import rpcMetadataV8 from '@polkadot/types/Metadata/v8/static';
import Api from '.';
@@ -212,3 +213,9 @@ formattingTests('v7', fromMetadata(new Metadata(rpcMetadataV7)), [
'0x1dbb0224910f42a14e7f1406b24c6fe8157296691b02a78756e01946038fffab',
'0xc7879f4faa637a90d782070a3cb6be99a9fb0316e19a0454ce93c4f0a34712f1'
]);
formattingTests('v8', fromMetadata(new Metadata(rpcMetadataV8)), [
'0xec8f96437274a883afcac82d01a9defeb68209cd4f2c084632813692aa5e65ad',
'0x1dbb0224910f42a14e7f1406b24c6fe8157296691b02a78756e01946038fffab',
'0xc7879f4faa637a90d782070a3cb6be99a9fb0316e19a0454ce93c4f0a34712f1'
]);
+34 -1
View File
@@ -3,6 +3,7 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import MockProvider from '@polkadot/rpc-provider/mock';
import { isFunction } from '@polkadot/util';
import Rpc from '.';
@@ -19,8 +20,40 @@ describe('Api', (): void => {
expect(
Object.keys(rpc).filter((key): boolean => !key.startsWith('_'))
).toEqual([
'provider',
'provider', 'mapping', 'sections',
'account', 'author', 'chain', 'contracts', 'rpc', 'state', 'system'
]);
});
it('allows for the definition of user RPCs', (): void => {
const rpc = new Rpc(new MockProvider(), {
testing: [
{
name: 'foo',
params: [{ name: 'bar', type: 'u32' }],
type: 'Balance'
}
]
});
expect(isFunction((rpc as any).testing.foo)).toBe(true);
expect(rpc.sections.includes('testing')).toBe(true);
expect(rpc.mapping.get('testing_foo')).toEqual({
description: 'User defined',
isDeprecated: false,
isHidden: false,
isOptional: false,
isSigned: false,
isSubscription: false,
method: 'foo',
params: [{
isOptional: false,
name: 'bar',
type: 'u32'
}],
pubsub: ['', '', ''],
section: 'testing',
type: 'Balance'
});
});
});
+71 -31
View File
@@ -3,19 +3,23 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { ProviderInterface } from '@polkadot/rpc-provider/types';
import { RpcMethod } from '@polkadot/jsonrpc/types';
import { RpcMethod, RpcSection, RpcParam } from '@polkadot/jsonrpc/types';
import { AnyJson, Codec } from '@polkadot/types/types';
import { RpcInterface } from './jsonrpc.types';
import { RpcInterfaceMethod } from './types';
import { RpcInterfaceMethod, UserRpc } from './types';
import memoizee from 'memoizee';
import { combineLatest, from, Observable, Observer, of, throwError } from 'rxjs';
import { catchError, map, publishReplay, refCount, switchMap } from 'rxjs/operators';
import interfaces from '@polkadot/jsonrpc';
import { catchError, distinctUntilChanged, map, publishReplay, refCount, switchMap } from 'rxjs/operators';
import jsonrpc from '@polkadot/jsonrpc';
import jsonrpcMethod from '@polkadot/jsonrpc/create/method';
import jsonrpcParam from '@polkadot/jsonrpc/create/param';
import { Option, StorageKey, Vec, createClass } from '@polkadot/types';
import { createTypeUnsafe } from '@polkadot/types/codec';
import { assert, isFunction, isNull, isNumber, logger, u8aToU8a } from '@polkadot/util';
type UserRpcConverted = Record<string, Record<string, RpcMethod>>;
const l = logger('rpc-core');
const EMPTY_META = {
@@ -55,38 +59,40 @@ export default class Rpc implements RpcInterface {
public readonly provider: ProviderInterface;
public readonly account: RpcInterface['account'];
public readonly mapping: Map<string, RpcMethod> = new Map();
public readonly author: RpcInterface['author'];
public readonly sections: string[] = [];
public readonly chain: RpcInterface['chain'];
// Ok, this is quite horrible - we really should not be using the ! here, but we are actually assigning
// these via the createInterfaces inside the constructor. However... this is not quite visible. The reason
// why we don't do for individual assignments is to allow user-defined RPCs to also be defined
public readonly contracts: RpcInterface['contracts'];
public readonly account!: RpcInterface['account'];
public readonly rpc: RpcInterface['rpc'];
public readonly author!: RpcInterface['author'];
public readonly state: RpcInterface['state'];
public readonly chain!: RpcInterface['chain'];
public readonly system: RpcInterface['system'];
public readonly contracts!: RpcInterface['contracts'];
public readonly rpc!: RpcInterface['rpc'];
public readonly state!: RpcInterface['state'];
public readonly system!: RpcInterface['system'];
/**
* @constructor
* Default constructor for the Api Object
* @param {ProviderInterface} provider An API provider using HTTP or WebSocket
*/
public constructor (provider: ProviderInterface) {
public constructor (provider: ProviderInterface, userRpc: UserRpc = {}) {
// eslint-disable-next-line @typescript-eslint/unbound-method
assert(provider && isFunction(provider.send), 'Expected Provider to API create');
this.provider = provider;
this.account = this.createInterface('account');
this.author = this.createInterface('author');
this.contracts = this.createInterface('contracts');
this.chain = this.createInterface('chain');
this.rpc = this.createInterface('rpc');
this.state = this.createInterface('state');
this.system = this.createInterface('system');
this.createInterfaces(jsonrpc, userRpc);
}
/**
@@ -105,9 +111,7 @@ export default class Rpc implements RpcInterface {
* ```
*/
public static signature ({ method, params, type }: RpcMethod): string {
const inputs = params.map(({ name, type }): string =>
`${name}: ${type}`
).join(', ');
const inputs = params.map(({ name, type }): string => `${name}: ${type}`).join(', ');
return `${method} (${inputs}): ${type}`;
}
@@ -123,13 +127,47 @@ export default class Rpc implements RpcInterface {
return `${Rpc.signature(method)}:: ${error.message}`;
}
private createInterface<Section extends keyof RpcInterface> (section: Section): RpcInterface[Section] {
const { methods } = interfaces[section];
private createInterfaces<Section extends keyof RpcInterface> (interfaces: Record<string, RpcSection>, userBare: UserRpc): void {
// these are the base keys (i.e. part of jsonrpc)
this.sections.push(...Object.keys(interfaces));
// add any extra user-defined sections
this.sections.push(...Object.keys(userBare).filter((key): boolean => !this.sections.includes(key)));
// convert the user inputs into the same format as used in jsonrpc
const user = Object.entries(userBare).reduce((user: UserRpcConverted, [sectionName, methods]): UserRpcConverted => {
user[sectionName] = methods.reduce((section: Record<string, RpcMethod>, def): Record<string, RpcMethod> => {
const { description = 'User defined', name, params, type } = def;
section[name] = jsonrpcMethod(sectionName, name, {
description,
params: params.map(({ isOptional, name, type }): RpcParam =>
jsonrpcParam(name, type as any, { isOptional })),
type: type as any
});
return section;
}, {});
return user;
}, {});
// decorate the sections with base and user methods
this.sections.forEach((sectionName): void => {
(this as any)[sectionName as Section] = {
...this.createInterface(sectionName, interfaces[sectionName] ? interfaces[sectionName].methods : {}),
...this.createInterface(sectionName, user[sectionName] || {})
};
});
}
private createInterface<Section extends keyof RpcInterface> (section: string, methods: Record<string, RpcMethod>): RpcInterface[Section] {
return Object
.keys(methods)
.reduce((exposed, methodName): RpcInterface[Section] => {
const def = methods[methodName];
.reduce((exposed, method): RpcInterface[Section] => {
const def = methods[method];
this.mapping.set(`${section}_${method}`, def);
// FIXME Remove any here
// To do so, remove `RpcInterfaceMethod` from './types.ts', and refactor
@@ -137,7 +175,7 @@ export default class Rpc implements RpcInterface {
// `<S extends keyof RpcInterface, M extends keyof RpcInterface[S]>`
// Not doing so, because it makes this class a little bit less readable,
// and leaving it as-is doesn't harm much
(exposed as any)[methodName] = def.isSubscription
(exposed as any)[method] = def.isSubscription
? this.createMethodSubscribe(def)
: this.createMethodSend(def);
@@ -170,14 +208,12 @@ export default class Rpc implements RpcInterface {
const message = this.createErrorMessage(method, error);
// don't scare with old nodes, this is handled transparently
if (rpcName !== 'rpc_methods') {
l.error(message);
}
rpcName !== 'rpc_methods' && l.error(message);
return throwError(new Error(message));
}),
publishReplay(1), // create a Replay(1)
refCount() // Unsubcribe WS when there are no more subscribers
refCount() // Unsubscribe WS when there are no more subscribers
);
};
@@ -250,6 +286,10 @@ export default class Rpc implements RpcInterface {
);
};
}).pipe(
// Duplicated in api-derive/util/drr
distinctUntilChanged((a: any, b: any): boolean =>
JSON.stringify({ value: a }) === JSON.stringify({ value: b })
),
publishReplay(1),
refCount()
);
+9
View File
@@ -7,3 +7,12 @@ import { Observable } from 'rxjs';
export interface RpcInterfaceMethod {
(...params: any[]): Observable<any>;
}
export interface UserRpcMethod {
description?: string;
name: string;
params: { isOptional?: boolean; name: string; type: string }[];
type: string;
}
export type UserRpc = Record<string, UserRpcMethod[]>;
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/rpc-provider",
"version": "0.94.1",
"version": "0.95.2",
"description": "Transport providers for the API",
"main": "index.js",
"keywords": [
@@ -26,18 +26,18 @@
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-provider#readme",
"dependencies": {
"@babel/runtime": "^7.6.2",
"@polkadot/api-metadata": "^0.94.1",
"@polkadot/util": "^1.5.1",
"@polkadot/util-crypto": "^1.5.1",
"@babel/runtime": "^7.6.3",
"@polkadot/api-metadata": "^0.95.2",
"@polkadot/util": "^1.6.1",
"@polkadot/util-crypto": "^1.6.1",
"@types/nock": "^11.1.0",
"eventemitter3": "^4.0.0",
"isomorphic-fetch": "^2.2.1",
"websocket": "^1.0.30"
},
"devDependencies": {
"@polkadot/keyring": "^1.5.1",
"mock-socket": "^9.0.0",
"nock": "^11.3.5"
"@polkadot/keyring": "^1.6.1",
"mock-socket": "^9.0.2",
"nock": "^11.4.0"
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/jsonrpc",
"version": "0.94.1",
"version": "0.95.2",
"description": "Method definitions for the Polkadot RPC layer",
"main": "index.js",
"publishConfig": {
@@ -26,6 +26,6 @@
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/type-jsonrpc#readme",
"dependencies": {
"@babel/runtime": "^7.6.2"
"@babel/runtime": "^7.6.3"
}
}
+1 -135
View File
@@ -10,15 +10,12 @@ These are the base types of the codec. They are typically not used directly, but
| **Types** | |
| --- | --- |
| [[AbstractArray]] | Manages codec arrays. It is an extension to Array |
| [[Base]] | A type extends the Base class, when it holds a value |
| [[Compact]] | A compact length-encoding codec wrapper. Mostly used by other types to add length-prefixed encoding |
| [[Enum]] | A codec wrapper for an enum. Enums are encoded as a single byte, where the byte is a zero-indexed value |
| [[Int]] | A generic signed integer codec |
| [[Option]] | An Option is an optional field. The first byte indicates that there is is value to follow |
| [[Set]] | An Set is an array of string values, represented an an encoded type by a bitwise representation of the values |
| [[Struct]] | A Struct defines an Object with key-value pairs - where the values are Codec values. |
| [[StructAny]] | Wraps the a JSON structure retrieve via RPC. It extends the standard JS Map |
| [[Tuple]] | A Tuple defines an anonymous fixed-length array, where each element has its own type |
| [[U8a]] | A basic wrapper around Uint8Array. It will consume the full Uint8Array as passed to it |
| [[U8aFixed]] | A U8a that manages a a sequence of bytes up to the specified bitLength |
@@ -35,7 +32,6 @@ These primitive types are available:
| --- | --- |
| [[AccountId]] | A wrapper around an AccountId/PublicKey representation |
| [[AccountIndex]] | A wrapper around an AccountIndex, which is a shortened, variable-length encoding for an Account |
| [[AccountInfo]] | An Account information structure for contracts |
| [[Address]] | A wrapper around an AccountId and/or AccountIndex that is encoded with a prefix |
| [[bool]] | Representation for a boolean value in the system |
| [[Bytes]] | A Bytes wrapper for `Vec<u8>` |
@@ -45,7 +41,7 @@ These primitive types are available:
| [[EventRecord]] | A record for an [[Event]] (as specified by [[Metadata]]) with the specific [[Phase]] of application |
| [[Extrinsic]] | Representation of an Extrinsic in the system |
| [[ExtrinsicEra]] | The era for an extrinsic, indicating either a mortal or immortal extrinsic |
| [[ExtrinsicSignature]] | A container for the [[Signature]] associated with a specific [[Extrinsic]] |
| [[ExtrinsicPayload]] | A signing payload for an [[Extrinsic]]. For the final encoding, it is variable length based on the contents included |
| [[H160]] | Hash containing 160 bits (20 bytes), typically used in blocks, extrinsics and as a sane default |
| [[H256]] | Hash containing 256 bits (32 bytes), typically used in blocks, extrinsics and as a sane default |
| [[H512]] | Hash containing 512 bits (64 bytes), typically used for signatures |
@@ -58,9 +54,7 @@ These primitive types are available:
| [[i256]] | A 256-bit signed integer |
| [[Moment]] | A wrapper around seconds/timestamps. Internally the representation only has second precicion (aligning with Rust) |
| [[Null]] | Implements a type that does not contain anything (apart from `null`) |
| [[Origin]] | Where Origin occurs, it should be ignored as an internal-only value |
| [[Signature]] | The default signature that is used accross the system |
| [[ExtrinsicPayload]] | A signing payload for an [[Extrinsic]]. For the final encoding, it is variable length based on the contents included |
| [[StorageData]] | Data retrieved via Storage queries and data for key-value pairs |
| [[StorageKey]] | A representation of a storage key (typically hashed) in the system |
| [[Text]] | This is a string wrapper, along with the length. |
@@ -71,131 +65,3 @@ These primitive types are available:
| [[u64]] | A 64-bit unsigned integer |
| [[u128]] | A 128-bit unsigned integer |
| [[u256]] | A 256-bit unsigned integer |
| [[uSize]] | A System default unsigned number, typically used in RPC to report non-consensus data |
| [[Weight]] | Numeric range of a transaction weight. |
| [[WeightMultiplier]] | Representation of a weight multiplier. This represents how a fee value can be computed from a weighted transaction. |
## Substrate types
These custom types implement specific types that are found as part of the Substrate core. They're all extensions of one of the codec types:
| **Types** | |
| --- | --- |
| [[AccountNonce]] | The Nonce or number of transactions sent by a specific account |
| [[Amount]] | The Substrate Amount representation as a [[Balance]] |
| [[ApprovalFlag]] | Approval flag, implemented as a [[U32]] |
| [[AssetOf]] | The Substrate AssetOf representation as a [[Balance]] |
| [[AuthorityId]] | Wrapper for a AuthorityId. Same as an normal AccountId |
| [[AuthoritiesChange]] | Log for Authories changed |
| [[AuthorityWeight]] | The weight of an authority |
| [[Balance]] | The Substrate Balance representation as a [[U128]] |
| [[BalanceLock]] | The Substrate BalanceLock for staking |
| [[BalanceOf]] | The Substrate BalanceOf representation as a [[Balance]] |
| [[BlockNumber]] | A representation of a Substrate BlockNumber, implemented as a [[U64]] |
| [[CodeHash]] | The default contract code hash that is used accross the system |
| [[Conviction]] | A value denoting the strength of conviction of a vote. |
| [[Consensus]] | Log item indicating consensus |
| [[ContractInfo]] | The contract information for a given contract |
| [[ContractStorageKey]] | A representation of a storage key for contracts |
| [[EraIndex]] | A representation for the era count |
| [[Exposure]] | A snapshot of the stake backing a single validator in the system |
| [[Gas]] | A gas number type for Substrate, extending [[U64]] |
| [[Heartbeat]] | Heartbeat which is send/received. |
| [[IndividualExposure]] | The Substrate IndividualExposure for staking |
| [[InherentOfflineReport]] | Describes the offline-reporting extrinsic |
| [[Justification]] | A generic justification as a stream of [[Bytes]], this is specific per consensus implementation |
| [[Key]] | The Substrate Key representation as a [[Bytes]] (`vec<u8>`) |
| [[Keys]] | The session keys for both Grandpa (ed25519) and Babe (sr25519) |
| [[KeyValue]] | KeyValue structure. Since most of the keys and resultant values in Subtrate are hashed and/or encoded, keys and values are reprsented as [[Bytes]] |
| [[KeyValueOption]] | A key/value change. Similar to the [[KeyValue]] structure, but the value can be optional |
| [[LockIdentifier]] | The Substrate LockIdentifier for staking |
| [[LockPeriods]] | A number of lock periods |
| [[MemberCount]] | A number of council members |
| [[NewAccountOutcome]] | Enum to track the outcome for creation of an [[AccountId]] |
| [[NextAuthority]] | The next authority available as [[SessionKey]] |
| [[OpaqueKey]] | A key represented as a [[Bytes]] |
| [[Perbill]] | Parts per billion (see also [[Permill]]) |
| [[Permill]] | Parts per million (See also [[Perbill]]) |
| [[PrefabWasmModule]] | Struct to encode the vesting schedule of an individual account |
| [[PropIndex]] | An increasing number that represents a specific council proposal index in the system |
| [[Proposal]] | A proposal in the system. It just extends [[Call]] (Proposal = Call in Rust) |
| [[ProposalIndex]] | An increasing number that represents a specific council proposal index in the system |
| [[ReferendumIndex]] | An increasing number that represents a specific referendum in the system |
| [[ReferendumInfo]] | Info regarding an ongoing referendum |
| [[RewardDestination]] | A destination account for payment |
| [[Schedule]] | Definition of the cost schedule and other parameterizations for wasm vm |
| [[Seal]] | Log item indicating a sealing event |
| [[SeedOf]] | The Substrate SeedOf representation as a [[Hash]] |
| [[SessionIndex]] | Simple index type with which we can count sessions as [[U32]] |
| [[SessionKey]] | Wrapper for a SessionKey. Same as an normal [[AuthorityId]], i.e. a wrapper around publicKey |
| [[SetIndex]] | Set index, implemented as a [[U32]] |
| [[StakingLedger]] | The ledger of a (bonded) stash |
| [[StoredPendingChange]] | Stored pending change for a Grandpa events |
| [[StoredState]] | Current state of the GRANDPA authority set. State transitions must happen in the same order of states defined below, e.g. `Paused` implies a prior `PendingPause` |
| [[TreasuryProposal]] | A Proposal made for Treasury |
| [[UncleEntryItem]] | Information about an uncle to include |
| [[UnlockChunk]] | Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked |
| [[ValidatorId]] | Validator in the system, maps to an AccountId |
| [[ValidatorPrefs]] | Validator preferences |
| [[VestingSchedule]] | Struct to encode the vesting schedule of an individual account |
| [[Vote]] | A number of lock periods, plus a vote, one way or the other |
| [[Votes]] | Info for keeping track of a council motion being voted on. |
| [[VoteIndex]] | Voting index, implemented as a [[U32]] |
| [[VoterInfo]] | The activity status of a voter. |
| [[VoteThreshold]] | Voting threshold, used inside proposals to set change the voting tally |
| [[WithdrawReasons]] | The Substrate WithdrawReasons for staking |
## Polkadot types
These types are only available in Polkadot chains -
| **Types** | |
| --- | --- |
| [[AuctionIndex]] | A parachain auction index as a [[U32]] |
| [[AttestedCandidate]] | An attested candidate |
| [[Bidder]] | The desired target of a bidder in an auction. |
| [[LeasePeriod]] | The length of the lease for a parachain |
| [[LeasePeriodOf]] | The length of the lease for a parachain |
| [[IncomingParachain]] | Information regarding a parachain that will be deployed. |
| [[NewBidder]] | A bidder identifier, which is just the combination of an account ID and a sub-bidder ID. This is called `NewBidder` in order to distinguish between bidders that would deploy a *new* parachain and pre-existing parachains bidding to renew themselves. |
| [[ParachainDispatchOrigin]] | Which origin a parachain's message to the relay chain should be dispatched from. |
| [[ParaId]] | Identifier for a deployed parachain implemented as a [[U32]] |
| [[ParaIdOf]] | Identifier for a deployed parachain implemented as a [[U32]] |
| [[SlotRange]] | A compactly represented sub-range from the series (0, 1, 2, 3) |
| [[SubId]] | A sub-bidder identifier. Used to distinguish between different logical bidders coming from the same account ID. |
| [[UpwardMessage]] | A message from a parachain to its Relay Chain |
| [[WinningData]] | Winning data type. This encodes the top bidders of each range together with their bid. |
| [[WinningDataEntry]] | And entry in the [[WinningData]] fixed vector |
## RPC types
These types are not used in the runtime, but are rather used in RPC results:
| **Types** | |
| --- | --- |
| [[Block]] | A block encoded with header and extrinsics |
| [[ChainProperties]] | Wraps the properties retrieved from the chain via the `system.properties` RPC call |
| [[Digest]] | A [[Header]] Digest |
| [[DigestOf]] | A [[Header]] Digest |
| [[DigestItem]] | A [[EnumType]] the specifies the specific item in the logs of a [[Digest]] |
| [[ExtrinsicStatus]] | An EnumType that indicates the status of the Extrinsic as been submitted |
| [[Header]] | A [[Block]] header |
| [[Health]] | A system health indicator, reported back over RPC |
| [[NetworkState]] | Wraps the properties retrieved from the chain via the `system.network_state` RPC call |
| [[Metadata]] | The versioned runtime metadata as a decoded structure |
| [[PeerInfo]] | A system peer info indicator, reported back over RPC |
| [[RuntimeVersion]] | A [[Tuple]] that conatins the [[ApiId]] and [[U32]] version |
| [[SignedBlock]] | A [[Block]] that has been signed and contains a [[Justification]] |
| [[StorageChangeSet]] | A set of storage changes. It contains the [[Block]] hash and a list of the actual changes |
## Derive types
These types are are specific for the Polkadot-JS derive API, so you won't find a representation of them in the SCALE codec or the Substrate core. They are used in the [api-derive](https://www.npmjs.com/package/@polkadot/api-derive) methods.
| **Types** | |
| --- | --- |
| [[HeaderExtended]] | A [[Header]] header with an additional `author` field that indicates the block author] |
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/types",
"version": "0.94.1",
"version": "0.95.2",
"description": "Implementation of the Parity codec",
"main": "index.js",
"keywords": [
@@ -26,13 +26,13 @@
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/types#readme",
"dependencies": {
"@babel/runtime": "^7.6.2",
"@polkadot/util": "^1.5.1",
"@polkadot/util-crypto": "^1.5.1",
"@babel/runtime": "^7.6.3",
"@polkadot/util": "^1.6.1",
"@polkadot/util-crypto": "^1.6.1",
"@types/memoizee": "^0.4.3",
"memoizee": "^0.4.14"
},
"devDependencies": {
"@polkadot/keyring": "^1.5.1"
"@polkadot/keyring": "^1.6.1"
}
}
@@ -15,6 +15,7 @@ import MetadataV4 from './v4';
import MetadataV5 from './v5';
import MetadataV6 from './v6';
import MetadataV7 from './v7';
import MetadataV8 from './v8';
import v0ToV1 from './v0/toV1';
import v1ToV2 from './v1/toV2';
import v2ToV3 from './v2/toV3';
@@ -22,11 +23,12 @@ import v3ToV4 from './v3/toV4';
import v4ToV5 from './v4/toV5';
import v5ToV6 from './v5/toV6';
import v6ToV7 from './v6/toV7';
import v7ToV8 from './v7/toV8';
import { getUniqTypes, toCallsOnly } from './util';
type MetaMapped = MetadataV0 | MetadataV1 | MetadataV2 | MetadataV3 | MetadataV4 | MetadataV5 | MetadataV6 | MetadataV7;
type MetaVersions = 1 | 2 | 3 | 4 | 5 | 6 | 7;
type MetaAsX = 'asV0' | 'asV1' | 'asV2' | 'asV3' | 'asV4' | 'asV5' | 'asV6';
type MetaVersions = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
type MetaAsX = 'asV0' | 'asV1' | 'asV2' | 'asV3' | 'asV4' | 'asV5' | 'asV6' | 'asV7';
class MetadataEnum extends Enum {
public constructor (value?: any, index?: number) {
@@ -38,7 +40,8 @@ class MetadataEnum extends Enum {
V4: MetadataV4, // once rolled-out, can replace this with MetadataDeprecated
V5: MetadataV5, // once rolled-out, can replace this with MetadataDeprecated
V6: MetadataV6, // once rolled-out, can replace this with MetadataDeprecated
V7: MetadataV7
V7: MetadataV7, // once rolled-out, can replace this with MetadataDeprecated
V8: MetadataV8
}, value, index);
}
@@ -114,6 +117,15 @@ class MetadataEnum extends Enum {
return this.value as MetadataV7;
}
/**
* @description Returns the wrapped values as a V8 object
*/
public get asV8 (): MetadataV8 {
assert(this.isV8, `Cannot convert '${this.type}' via asV8`);
return this.value as MetadataV8;
}
/**
* @description `true` if Deprecated
*/
@@ -176,6 +188,13 @@ class MetadataEnum extends Enum {
public get isV7 (): boolean {
return this.type === 'V7';
}
/**
* @description `true` if V8
*/
public get isV8 (): boolean {
return this.type === 'V8';
}
}
/**
@@ -215,24 +234,13 @@ export default class MetadataVersioned extends Struct {
}
/**
* @description
* @description Returns the wrapped metadata as a limited calls-only (latest) version
*/
public get magicNumber (): MagicNumber {
return this.get('magicNumber') as MagicNumber;
}
/**
* @description the metadata wrapped
*/
private get metadata (): MetadataEnum {
return this.get('metadata') as MetadataEnum;
}
/**
* @description the metadata version this structure represents
*/
public get version (): number {
return this.metadata.index;
public get asCallsOnly (): MetadataVersioned {
return new MetadataVersioned({
magicNumber: this.magicNumber,
metadata: new MetadataEnum(toCallsOnly(this.asLatest), this.version)
});
}
/**
@@ -294,20 +302,38 @@ export default class MetadataVersioned extends Struct {
}
/**
* @description Returns the wrapped metadata as a limited calls-only (latest) version
* @description Returns the wrapped values as a V8 object
*/
public get asCallsOnly (): MetadataVersioned {
return new MetadataVersioned({
magicNumber: this.magicNumber,
metadata: new MetadataEnum(toCallsOnly(this.asLatest), this.version)
});
public get asV8 (): MetadataV8 {
return this.getVersion(8, v7ToV8);
}
/**
* @description Returns the wrapped values as a latest version object
*/
public get asLatest (): MetadataV7 {
return this.asV7;
public get asLatest (): MetadataV8 {
return this.asV8;
}
/**
* @description
*/
public get magicNumber (): MagicNumber {
return this.get('magicNumber') as MagicNumber;
}
/**
* @description the metadata wrapped
*/
private get metadata (): MetadataEnum {
return this.get('metadata') as MetadataEnum;
}
/**
* @description the metadata version this structure represents
*/
public get version (): number {
return this.metadata.index;
}
public getUniqTypes (throwError: boolean): string[] {
+1 -1
View File
@@ -2,6 +2,6 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import metadata from './v7/static';
import metadata from './v8/static';
export default metadata;
@@ -32,7 +32,7 @@ type Item = {
type Storage = Option<Vec<Item> | {
// v0
functions?: Vec<Item>;
// V7
// V7+
items?: Vec<Item>;
} & Codec>;
+6 -8
View File
@@ -4,8 +4,6 @@
import '../../injector';
import extrinsicsFromMeta from '@polkadot/api-metadata/extrinsics/fromMetadata';
import { createTypeUnsafe } from '../../codec/create';
import Metadata from '../Metadata';
import Call from '../../primitive/Generic/Call';
@@ -34,18 +32,18 @@ export function decodeLatestSubstrate<Modules extends Codec> (
}
/**
* Given a `version`, MetadataV7 and MetadataV{version} should output the same
* Given a `version`, MetadataLatest and MetadataV{version} should output the same
* unique types.
*/
export function toV7<Modules extends Codec> (version: number, rpcData: string): void {
it(`converts v${version} to v7`, (): void => {
export function toLatest<Modules extends Codec> (version: number, rpcData: string): void {
it(`converts v${version} to v8`, (): void => {
const metadata = new Metadata(rpcData)[`asV${version}` as keyof Metadata];
const metadataV7 = new Metadata(rpcData).asV7;
const metadataV8 = new Metadata(rpcData).asLatest;
expect(
getUniqTypes(metadata as unknown as MetadataInterface<Modules>, true)
).toEqual(
getUniqTypes(metadataV7, true)
getUniqTypes(metadataV8, true)
);
});
}
@@ -57,7 +55,7 @@ export function defaultValues (rpcData: string): void {
describe('storage with default values', (): void => {
const metadata = new Metadata(rpcData);
Call.injectMethods(extrinsicsFromMeta(metadata));
Call.injectMetadata(metadata);
metadata.asLatest.modules
.filter(({ storage }): boolean => storage.isSome)
@@ -2,13 +2,13 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import MetadataV7 from '../v7';
import MetadataV8 from '../v8';
/**
* @description Convert from MetadataV7 to a stripped representation of MetadataV7
* @description Convert from MetadataV8 to a stripped representation of MetadataV8
*/
export default function toCallsOnly ({ modules }: MetadataV7): any {
return new MetadataV7({
export default function toCallsOnly ({ modules }: MetadataV8): any {
return new MetadataV8({
// FIXME, this needs typing, not any
modules: modules.map(({ calls, name }): any => ({
name,
@@ -6,7 +6,7 @@ import { createType } from '../../codec';
import Metadata from '../';
import latestSubstrateV0 from './static-substrate.json';
import rpcData from './static';
import { defaultValues, toV7 } from '../util/testUtil';
import { defaultValues, toLatest } from '../util/testUtil';
describe('Metadata', (): void => {
it('works with fallback', (): void => {
@@ -27,7 +27,7 @@ describe('Metadata', (): void => {
expect(json).toEqual(latestSubstrateV0);
});
toV7(0, rpcData);
toLatest(0, rpcData);
defaultValues(rpcData);
});
@@ -4,12 +4,12 @@
import staticSubstrate from './static-substrate.json';
import rpcData from './static';
import { decodeLatestSubstrate, defaultValues, toV7 } from '../util/testUtil';
import { decodeLatestSubstrate, defaultValues, toLatest } from '../util/testUtil';
describe('MetadataV1', (): void => {
decodeLatestSubstrate(1, rpcData, staticSubstrate);
toV7(1, rpcData);
toLatest(1, rpcData);
defaultValues(rpcData);
});
@@ -4,12 +4,12 @@
import staticSubstrate from './static-substrate.json';
import rpcData from './static';
import { decodeLatestSubstrate, defaultValues, toV7 } from '../util/testUtil';
import { decodeLatestSubstrate, defaultValues, toLatest } from '../util/testUtil';
describe('MetadataV2', (): void => {
decodeLatestSubstrate(2, rpcData, staticSubstrate);
toV7(2, rpcData);
toLatest(2, rpcData);
defaultValues(rpcData);
});
@@ -4,12 +4,12 @@
import staticSubstrate from './static-substrate.json';
import rpcData from './static';
import { decodeLatestSubstrate, defaultValues, toV7 } from '../util/testUtil';
import { decodeLatestSubstrate, defaultValues, toLatest } from '../util/testUtil';
describe('MetadataV3', (): void => {
decodeLatestSubstrate(3, rpcData, staticSubstrate);
toV7(3, rpcData);
toLatest(3, rpcData);
defaultValues(rpcData);
});
@@ -4,12 +4,12 @@
import staticSubstrate from './static-substrate.json';
import rpcData from './static';
import { decodeLatestSubstrate, defaultValues, toV7 } from '../util/testUtil';
import { decodeLatestSubstrate, defaultValues, toLatest } from '../util/testUtil';
describe('MetadataV4', (): void => {
decodeLatestSubstrate(4, rpcData, staticSubstrate);
toV7(4, rpcData);
toLatest(4, rpcData);
defaultValues(rpcData);
});
@@ -6,12 +6,12 @@ import polkadotJson from './static-polkadot.json';
import substrateJson from './static-substrate.json';
import polkadotData from './static.polkadot';
import substrateData from './static';
import { decodeLatestSubstrate, defaultValues, toV7 } from '../util/testUtil';
import { decodeLatestSubstrate, defaultValues, toLatest } from '../util/testUtil';
describe('MetadataV5 (substrate)', (): void => {
decodeLatestSubstrate(5, substrateData, substrateJson);
toV7(5, substrateData);
toLatest(5, substrateData);
defaultValues(substrateData);
});
@@ -19,7 +19,7 @@ describe('MetadataV5 (substrate)', (): void => {
describe('MetadataV5 (polkadot)', (): void => {
decodeLatestSubstrate(5, polkadotData, polkadotJson);
toV7(5, polkadotData);
toLatest(5, polkadotData);
defaultValues(polkadotData);
});
@@ -6,12 +6,12 @@ import polkadotJson from './static-polkadot.json';
import substrateJson from './static-substrate.json';
import polkadotData from './static.polkadot';
import substrateData from './static';
import { decodeLatestSubstrate, defaultValues, toV7 } from '../util/testUtil';
import { decodeLatestSubstrate, defaultValues, toLatest } from '../util/testUtil';
describe('MetadataV6 (substrate)', (): void => {
decodeLatestSubstrate(6, substrateData, substrateJson);
toV7(6, substrateData);
toLatest(6, substrateData);
defaultValues(substrateData);
});
@@ -19,7 +19,7 @@ describe('MetadataV6 (substrate)', (): void => {
describe('MetadataV6 (polkadot)', (): void => {
decodeLatestSubstrate(6, polkadotData, polkadotJson);
toV7(6, polkadotData);
toLatest(6, polkadotData);
defaultValues(polkadotData);
});
@@ -6,12 +6,12 @@ import polkadotJson from './static-polkadot.json';
import substrateJson from './static-substrate.json';
import polkadotData from './static.polkadot';
import substrateData from './static';
import { decodeLatestSubstrate, defaultValues, toV7 } from '../util/testUtil';
import { decodeLatestSubstrate, defaultValues, toLatest } from '../util/testUtil';
describe('MetadataV7 (substrate)', (): void => {
decodeLatestSubstrate(7, substrateData, substrateJson);
toV7(7, substrateData);
toLatest(7, substrateData);
defaultValues(substrateData);
});
@@ -19,7 +19,7 @@ describe('MetadataV7 (substrate)', (): void => {
describe('MetadataV7 (polkadot)', (): void => {
decodeLatestSubstrate(7, polkadotData, polkadotJson);
toV7(7, polkadotData);
toLatest(7, polkadotData);
defaultValues(polkadotData);
});
@@ -55,13 +55,6 @@ export class ModuleMetadataV7 extends Struct {
return this.get('name') as Text;
}
/**
* @description the module prefix
*/
public get prefix (): Text {
return this.get('prefix') as Text;
}
/**
* @description the associated module storage
*/
+25
View File
@@ -0,0 +1,25 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import MetadataV7 from './Metadata';
import MetadataV8 from '../v8';
import { ModuleMetadataV8 } from '../v8/Metadata';
/**
* Convert from MetadataV7 to MetadataV8
*/
export default function toV8 ({ modules }: MetadataV7): MetadataV8 {
return new MetadataV8({
modules: modules.map(({ calls, constants, events, name, storage }): ModuleMetadataV8 =>
new ModuleMetadataV8({
calls,
constants,
errors: [],
events,
name,
storage
})
)
});
}
@@ -0,0 +1,15 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import substrateJson from './static-substrate.json';
import substrateData from './static';
import { decodeLatestSubstrate, defaultValues, toLatest } from '../util/testUtil';
describe('MetadataV8 (substrate)', (): void => {
decodeLatestSubstrate(8, substrateData, substrateJson);
toLatest(8, substrateData);
defaultValues(substrateData);
});
+108
View File
@@ -0,0 +1,108 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ErrorMetadataV8, EventMetadataV8, FunctionMetadataV8, ModuleConstantMetadataV8 } from '../../interfaces/metadata';
import { MetadataInterface } from '../types';
import Option from '../../codec/Option';
import Struct from '../../codec/Struct';
import Vec from '../../codec/Vec';
import Text from '../../primitive/Text';
import { StorageMetadata } from './Storage';
// Note the following errors are non-duplicated and fill the first 2 slots for
// each of the modules - this means that other errors start at index 2
//
// {
// "name": "Other",
// "documentation": [
// "Other unspecified error"
// ]
// },
// {
// "name": "CannotLookup",
// "documentation": [
// "Can not lookup"
// ]
// }
/**
* @name ModuleMetadataV8
* @description
* The definition of a module in the system
*/
export class ModuleMetadataV8 extends Struct {
public constructor (value?: any) {
super({
name: 'Text',
storage: Option.with(StorageMetadata),
calls: Option.with('Vec<FunctionMetadataV8>'),
events: Option.with('Vec<EventMetadataV8>'),
constants: 'Vec<ModuleConstantMetadataV8>',
errors: 'Vec<ErrorMetadataV8>'
}, value);
}
/**
* @description the module calls
*/
public get calls (): Option<Vec<FunctionMetadataV8>> {
return this.get('calls') as Option<Vec<FunctionMetadataV8>>;
}
/**
* @description the module constants
*/
public get constants (): Vec<ModuleConstantMetadataV8> {
return this.get('constants') as Vec<ModuleConstantMetadataV8>;
}
/**
* @description the module errors
*/
public get errors (): Vec<ErrorMetadataV8> {
return this.get('errors') as Vec<ErrorMetadataV8>;
}
/**
* @description the module events
*/
public get events (): Option<Vec<EventMetadataV8>> {
return this.get('events') as Option<Vec<EventMetadataV8>>;
}
/**
* @description the module name
*/
public get name (): Text {
return this.get('name') as Text;
}
/**
* @description the associated module storage
*/
public get storage (): Option<StorageMetadata> {
return this.get('storage') as Option<StorageMetadata>;
}
}
/**
* @name MetadataV8
* @description
* The runtime metadata as a decoded structure
*/
export default class MetadataV8 extends Struct implements MetadataInterface<ModuleMetadataV8> {
public constructor (value?: any) {
super({
modules: Vec.with(ModuleMetadataV8)
}, value);
}
/**
* @description The associated modules for this structure
*/
public get modules (): Vec<ModuleMetadataV8> {
return this.get('modules') as Vec<ModuleMetadataV8>;
}
}
@@ -0,0 +1,5 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
export { StorageEntryMetadata, StorageEntryMetadataValue, StorageEntryType, StorageMetadata } from '../v7/Storage';
+11
View File
@@ -0,0 +1,11 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import MetadataV8, { ModuleMetadataV8 } from './Metadata';
export default MetadataV8;
export {
ModuleMetadataV8
};
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+112
View File
@@ -0,0 +1,112 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import '../injector';
import Text from '../primitive/Text';
import U32 from '../primitive/U32';
import Struct from './Struct';
import { CodecTo } from '../types';
import BTreeMap from './BTreeMap';
const mockU32TextMap = new Map<Text, U32>();
mockU32TextMap.set(new Text('bazzing'), new U32(69));
const mockU32TextMapString = '{"bazzing":69}';
const mockU32TextMapObject = { bazzing: 69 };
const mockU32TextMapHexString = '0x041c62617a7a696e6745000000';
const mockU32TextMapUint8Array = Uint8Array.from([4, 28, 98, 97, 122, 122, 105, 110, 103, 69, 0, 0, 0]);
const mockU32U32Map = new Map<U32, U32>();
mockU32U32Map.set(new U32(1), new U32(2));
mockU32U32Map.set(new U32(23), new U32(24));
mockU32U32Map.set(new U32(28), new U32(30));
mockU32U32Map.set(new U32(45), new U32(80));
const mockU32U32MapString = '{"1":2,"23":24,"28":30,"45":80}';
const mockU32U32MapObject = { 1: 2, 23: 24, 28: 30, 45: 80 };
const mockU32U32MapHexString = '0x10043102000000083233180000000832381e00000008343550000000';
const mockU32U32MapUint8Array = Uint8Array.from([16, 4, 49, 2, 0, 0, 0, 8, 50, 51, 24, 0, 0, 0, 8, 50, 56, 30, 0, 0, 0, 8, 52, 53, 80, 0, 0, 0]);
describe('BTreeMap', (): void => {
describe('decoding', (): void => {
const testDecode = (type: string, input: any, output: string): void =>
it(`can decode from ${type}`, (): void => {
const s = new BTreeMap(Text, U32, input);
expect(s.toString()).toBe(output);
});
testDecode('map', mockU32TextMap, mockU32TextMapString);
testDecode('hex', mockU32TextMapHexString, mockU32TextMapString);
testDecode('Uint8Array', mockU32TextMapUint8Array, mockU32TextMapString);
testDecode('map', mockU32U32Map, mockU32U32MapString);
testDecode('hex', mockU32U32MapHexString, mockU32U32MapString);
testDecode('Uint8Array', mockU32U32MapUint8Array, mockU32U32MapString);
});
describe('encoding', (): void => {
const testEncode = (to: CodecTo, expected: any): void =>
it(`can encode ${to}`, (): void => {
const s = new BTreeMap(Text, U32, mockU32TextMap);
expect(s[to]()).toEqual(expected);
});
testEncode('toHex', mockU32TextMapHexString);
testEncode('toJSON', mockU32TextMapObject);
testEncode('toU8a', mockU32TextMapUint8Array);
testEncode('toString', mockU32TextMapString);
});
describe('encoding muple values', (): void => {
const testEncode = (to: CodecTo, expected: any): void =>
it(`can encode ${to}`, (): void => {
const s = new BTreeMap(Text, U32, mockU32U32Map);
expect(s[to]()).toEqual(expected);
});
testEncode('toHex', mockU32U32MapHexString);
testEncode('toJSON', mockU32U32MapObject);
testEncode('toU8a', mockU32U32MapUint8Array);
testEncode('toString', mockU32U32MapString);
});
it('decodes null', (): void => {
expect(
new (
BTreeMap.with(Text, U32)
)(null).toString()
).toEqual('{}');
});
it('decodes within more complicated types', (): void => {
const s = new Struct({
placeholder: U32,
value: BTreeMap.with(Text, U32)
});
s.set('value', new BTreeMap(Text, U32, mockU32TextMap));
expect(s.toString()).toBe('{"placeholder":0,"value":{"bazzing":69}}');
});
it('throws when it cannot decode', (): void => {
expect(
(): BTreeMap<Text, U32> => new (
BTreeMap.with(Text, U32)
)('ABC')
).toThrowError(/BTreeMap: cannot decode type/);
});
it('correctly encodes length', (): void => {
expect(
new (
BTreeMap.with(Text, U32))(mockU32TextMap).encodedLength
).toEqual(13);
});
it('generates sane toRawTypes', (): void => {
expect(new (BTreeMap.with(Text, U32))().toRawType()).toBe('BTreeMap<Text,u32>');
expect(new (BTreeMap.with(Text, Text))().toRawType()).toBe('BTreeMap<Text,Text>');
expect(new (BTreeMap.with(Text, Struct.with({ a: U32, b: Text })))().toRawType())
.toBe('BTreeMap<Text,{"a":"u32","b":"Text"}>');
});
});
+187
View File
@@ -0,0 +1,187 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AnyJson, Constructor, Codec, IHash, InterfaceTypes } from '../types';
import { isHex, hexToU8a, isU8a, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
import { blake2AsU8a } from '@polkadot/util-crypto';
import Compact from './Compact';
import U8a from './U8a';
import { compareMap, decodeU8a, typeToConstructor } from './utils';
export default class BTreeMap<K extends Codec = Codec, V extends Codec = Codec> extends Map<K, V> implements Codec {
protected _KeyClass: Constructor<K>;
protected _ValClass: Constructor<V>;
constructor (keyType: Constructor<K> | InterfaceTypes, valType: Constructor<V> | InterfaceTypes, rawValue: any) {
const KeyClass = typeToConstructor(keyType);
const ValClass = typeToConstructor(valType);
super(BTreeMap.decodeBTreeMap(KeyClass, ValClass, rawValue));
this._KeyClass = KeyClass;
this._ValClass = ValClass;
}
/**
* Decode input to pass into constructor.
*
* @param KeyClass - Type of the map key
* @param ValClass - Type of the map value
* @param value - Value to decode, one of:
* - null
* - undefined
* - hex
* - Uint8Array
* - Map<any, any>, where both key and value types are either
* constructors or decodeable values for their types.
* @param jsonMap
*/
private static decodeBTreeMap<K extends Codec = Codec, V extends Codec = Codec> (KeyClass: Constructor<K>, ValClass: Constructor<V>, value: Uint8Array | string | Map<any, any>): Map<K, V> {
if (!value) {
return new Map<K, V>();
} else if (isHex(value)) {
return BTreeMap.decodeBTreeMap(KeyClass, ValClass, hexToU8a(value));
} else if (isU8a(value)) {
return BTreeMap.decodeBTreeMapFromU8a<K, V>(KeyClass, ValClass, u8aToU8a(value));
} else if (value instanceof Map) {
return BTreeMap.decodeBTreeMapFromMap<K, V>(KeyClass, ValClass, value);
}
throw new Error('BTreeMap: cannot decode type');
}
private static decodeBTreeMapFromU8a<K extends Codec = Codec, V extends Codec = Codec> (KeyClass: Constructor<K>, ValClass: Constructor<V>, u8a: Uint8Array): Map<K, V> {
const output = new Map<K, V>();
const [offset, length] = Compact.decodeU8a(u8a);
const types = [];
for (let i = 0; i < length.toNumber(); i++) {
types.push(KeyClass, ValClass);
}
const values = decodeU8a(u8a.subarray(offset), types);
for (let i = 0; i < values.length; i += 2) {
output.set(values[i] as K, values[i + 1] as V);
}
return output;
}
private static decodeBTreeMapFromMap<K extends Codec = Codec, V extends Codec = Codec> (KeyClass: Constructor<K>, ValClass: Constructor<V>, value: Map<any, any>): Map<K, V> {
const output = new Map<K, V>();
value.forEach((v: any, k: any) => {
let key, val;
try {
key = (k instanceof KeyClass) ? k : new KeyClass(k);
val = (v instanceof ValClass) ? v : new ValClass(v);
} catch (error) {
console.error('Failed to decode BTreeMap key or value:', error.message);
throw error;
}
output.set(key, val);
});
return output;
}
public static with<K extends Codec, V extends Codec> (keyType: Constructor<K> | InterfaceTypes, valType: Constructor<V> | InterfaceTypes): Constructor<BTreeMap<K, V>> {
return class extends BTreeMap<K, V> {
constructor (value?: any) {
super(keyType, valType, value);
}
};
}
/**
* @description The length of the value when encoded as a Uint8Array
*/
public get encodedLength (): number {
let len = Compact.encodeU8a(this.size).length;
this.forEach((v: V, k: K) => {
len += v.encodedLength + k.encodedLength;
});
return len;
}
/**
* @description Returns a hash of the value
*/
public get hash (): IHash {
return new U8a(blake2AsU8a(this.toU8a(), 256));
}
/**
* @description Checks if the value is an empty value
*/
public get isEmpty (): boolean {
return this.size === 0;
}
/**
* @description Compares the value of the input to see if there is a match
*/
public eq (other?: any): boolean {
return compareMap(this, other);
}
/**
* @description Returns a hex string representation of the value. isLe returns a LE (number-only) representation
*/
public toHex (): string {
return u8aToHex(this.toU8a());
}
/**
* @description Converts the Object to JSON, typically used for RPC transfers
*/
public toJSON (): AnyJson {
const json: any = {};
this.forEach((v: V, k: K) => {
json[k.toString()] = v.toJSON();
});
return json;
}
/**
* @description Returns the base runtime type name for this instance
*/
public toRawType (): string {
return `BTreeMap<${new this._KeyClass().toRawType()},${new this._ValClass().toRawType()}>`;
}
/**
* @description Returns the string representation of the value
*/
public toString (): string {
return JSON.stringify(this.toJSON());
}
/**
* @description Encodes the value as a Uint8Array as per the SCALE specifications
* @param isBare true when the value has none of the type-specific prefixes (internal)
*/
public toU8a (isBare?: boolean): Uint8Array {
const encoded = new Array<Uint8Array>();
if (!isBare) {
encoded.push(Compact.encodeU8a(this.size));
}
this.forEach((v: V, k: K) => {
encoded.push(k.toU8a(isBare), v.toU8a(isBare));
});
return u8aConcat(...encoded);
}
}
-12
View File
@@ -111,18 +111,6 @@ describe('Enum', (): void => {
expect(new Test(1234, 1).toJSON()).toEqual({ B: 1234 });
});
// We are currently not using this approach, none of the types in Substrate currently
// have any overrides. Instead of trying to support it (just-in-case), rather have it
// removed to simplify the code - it can be pulled-back if needed
it.skip('allows checking against defined indexes', (): void => {
expect(
new Enum(
{ 1: Text, 5: U32 },
new Uint8Array([1, 2 << 2, 49, 50])
).toString()
).toEqual('Text');
});
it('allows accessing the type and value', (): void => {
const text = new Text('foo');
const enumType = new Enum(
+1 -1
View File
@@ -19,7 +19,7 @@ export default class Result<O extends Codec, E extends Codec> extends Enum {
super({ Ok, Error }, value);
}
public static with<O extends Codec, E extends Codec> (Types: { Ok: Constructor<O> | InterfaceTypes;Error: Constructor<E> | InterfaceTypes }): Constructor<Result<O, E>> {
public static with<O extends Codec, E extends Codec> (Types: { Ok: Constructor<O> | InterfaceTypes; Error: Constructor<E> | InterfaceTypes }): Constructor<Result<O, E>> {
return class extends Result<O, E> {
public constructor (value?: any) {
super(Types.Ok, Types.Error, value);
+7 -8
View File
@@ -8,9 +8,9 @@ import { VoteThreshold } from '../interfaces/elections';
import { BlockNumber } from '../interfaces/runtime';
import { CodecTo } from '../types';
import extrinsics from '@polkadot/api-metadata/extrinsics/static';
import { ClassOf } from './create';
import Metadata from '../Metadata';
import metadataStatic from '../Metadata/static';
import Call from '../primitive/Generic/Call';
import Text from '../primitive/Text';
import U32 from '../primitive/U32';
@@ -65,17 +65,16 @@ describe('Tuple', (): void => {
).toEqual('["foo",69,42]');
});
it.skip('creates properly via actual hex string', (): void => {
Call.injectMethods(extrinsics);
it('creates properly via actual hex string', (): void => {
Call.injectMetadata(new Metadata(metadataStatic));
const test = new (Tuple.with([
ClassOf('BlockNumber'), ClassOf('Proposal'), ClassOf('VoteThreshold')
ClassOf('BlockNumber'), ClassOf('VoteThreshold')
]
))('0x62190000000000000003507b0a092230783432223a202230783433220a7d0a01');
))('0x6219000001');
expect((test[0] as BlockNumber).toNumber()).toEqual(6498);
expect((test[1] as Call).callIndex).toEqual(new Uint8Array([0, 3]));
expect((test[2] as VoteThreshold).toNumber()).toEqual(1);
expect((test[1] as VoteThreshold).toNumber()).toEqual(1);
});
it('exposes the Types', (): void => {
+1 -1
View File
@@ -48,7 +48,7 @@ export default class UInt extends AbstractInt {
*/
public toRawType (): string {
// NOTE In the case of balances, which have a special meaning on the UI
// and can be interpreted differently, return a specifc value for it so
// and can be interpreted differently, return a specific value for it so
// underlying it always matches (no matter which length it actually is)
return this instanceof ClassOf('Balance')
? 'Balance'
+10 -9
View File
@@ -2,11 +2,13 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Proposal, PropIndex } from '../interfaces/democracy';
import '../injector';
import { PropIndex } from '../interfaces/democracy';
import { Codec, CodecTo } from '../types';
import extrinsics from '@polkadot/api-metadata/extrinsics/static';
import Metadata from '../Metadata';
import metadataStatic from '../Metadata/static';
import AccountId from '../primitive/Generic/AccountId';
import Call from '../primitive/Generic/Call';
import Text from '../primitive/Text';
@@ -20,7 +22,7 @@ describe('Vec', (): void => {
beforeEach((): void => {
vector = new Vec(Text, ['1', '23', '345', '4567', new Text('56789')]);
Call.injectMethods(extrinsics);
Call.injectMetadata(new Metadata(metadataStatic));
});
it('wraps a sequence of values', (): void => {
@@ -58,15 +60,14 @@ describe('Vec', (): void => {
expect(vector.Type).toEqual('Text');
});
it.skip('decodes a complex type via construction', (): void => {
const test = createTypeUnsafe('Vec<(PropIndex, Proposal, AccountId)>', [new Uint8Array([
4, 10, 0, 0, 0, 0, 3, 80, 123, 10, 9, 34, 48, 120, 52, 50, 34, 58, 32, 34, 48, 120, 52, 51, 34, 10, 125, 10, 209, 114, 167, 76, 218, 76, 134, 89, 18, 195, 43, 160, 168, 10, 87, 174, 105, 171, 174, 65, 14, 92, 203, 89, 222, 232, 78, 47, 68, 50, 219, 79
it('decodes a complex type via construction', (): void => {
const test = createTypeUnsafe('Vec<(PropIndex, AccountId)>', [new Uint8Array([
4, 10, 0, 0, 0, 209, 114, 167, 76, 218, 76, 134, 89, 18, 195, 43, 160, 168, 10, 87, 174, 105, 171, 174, 65, 14, 92, 203, 89, 222, 232, 78, 47, 68, 50, 219, 79
])]);
const first = (test as Vec<Codec>)[0] as Tuple;
expect((first[0] as PropIndex).toNumber()).toEqual(10);
expect((first[1] as Proposal).callIndex).toEqual(new Uint8Array([0, 3]));
expect((first[2] as AccountId).toString()).toEqual('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ');
expect((first[1] as AccountId).toString()).toEqual('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaQua');
});
describe('vector-like functions', (): void => {

Some files were not shown because too many files have changed in this diff Show More