Compare commits

..
94 Commits
Author SHA1 Message Date
Github Actions 6dce57b394 [CI Skip] 1.0.1
skip-checks: true
2020-01-30 16:06:14 +00:00
Jaco Greeff ca7edf1593 1.0 (#1781)
* 1.0

* signAsync typing

* Merge master
2020-01-30 16:59:04 +01:00
Jakub Pánik 59e069f091 Added unsubscribe return function to wsProvider.on() (#1780)
* Added unsubscribe return function to wsProvider.on()

* Updated mocks, added noop to http provider
2020-01-30 16:48:11 +01:00
Github Actions 65ff5c8f30 [CI Skip] 1.0.0-beta.44
skip-checks: true
2020-01-30 14:58:02 +00:00
Jaco Greeff 1c327c60d9 Metadata V11 (#1774)
* Make a start ... V11 definitions

* V11 conversion

* Fix ErrorMetadataV11

* Extension point for signed extensions

* Add V11 to mapped

* Expand toLatest comments
2020-01-30 15:49:37 +01:00
Github Actions de9f033d99 [CI Skip] 1.0.0-beta.43
skip-checks: true
2020-01-30 11:16:33 +00:00
Jaco Greeff 9c913fb482 Cleanup generated doc (only top-level docs) (#1777)
* Cleanup generated doc (only top-level docs)

* Single-line name
2020-01-30 12:09:16 +01:00
Github Actions e19e530c1c [CI Skip] 1.0.0-beta.42
skip-checks: true
2020-01-29 21:28:15 +00:00
Jaco Greeff aa91e0b8b5 Small gen doc updates (#1773) 2020-01-29 22:20:54 +01:00
Github Actions 9a6ba2fe0f [CI Skip] 1.0.0-beta.41
skip-checks: true
2020-01-29 17:33:29 +00:00
Jaco Greeff de853d9cc0 Add EVM types (#1771)
* Add EVM types

* Add findError for metadata
2020-01-29 18:26:06 +01:00
Github Actions 07063134b8 [CI Skip] 1.0.0-beta.40
skip-checks: true
2020-01-29 16:56:40 +00:00
Jaco Greeff 20b8cd762d Add sidebar doc link to TS user gen (#1770) 2020-01-29 17:49:40 +01:00
Github Actions bd3338c3df [CI Skip] 1.0.0-beta.39
skip-checks: true
2020-01-29 16:44:42 +00:00
Jaco Greeff 4c328964d5 Allow chain to use user-defined types (#1769)
* Allow chain to use user-defined types

* --package docs on chain extract
2020-01-29 17:37:19 +01:00
Github Actions 70e5e2b60a [CI Skip] 1.0.0-beta.38
skip-checks: true
2020-01-29 14:59:20 +00:00
Jaco Greeff 4329c0a411 Add polkadot-types-from-{chain,defs} (#1766)
* Add polkadot-types-from-{chain,defs}

* Generate scripts working

* User types generation docs

* Rebuild with new comment line
2020-01-29 15:51:23 +01:00
Github Actions 0713afa0e0 [CI Skip] 1.0.0-beta.37
skip-checks: true
2020-01-29 09:43:41 +00:00
Jaco Greeff 8b518a909b Bump deps (#1765) 2020-01-29 10:36:04 +01:00
Github Actions 794f1fe398 [CI Skip] 1.0.0-beta.36
skip-checks: true
2020-01-28 22:07:54 +00:00
Lae 51423e20b5 Make sure awaiting on an api object won't stuck forever on error (#1763)
* Make sure awaiting on an api object won't stuck forever when error occurs.

* Fix lint issues.
2020-01-28 23:01:07 +01:00
Github Actions d4b27ba670 [CI Skip] 1.0.0-beta.35
skip-checks: true
2020-01-28 21:52:49 +00:00
Jaco Greeff 8ca194a3d2 Cleanup society types (#1764)
* Cleanup society types

* Update types
2020-01-28 22:47:07 +01:00
Github Actions 5fd2c70924 [CI Skip] 1.0.0-beta.34
skip-checks: true
2020-01-28 21:03:11 +00:00
Jaco Greeff d36ee7de2f Add society hasDefender (#1762) 2020-01-28 21:55:55 +01:00
Github Actions 3683f9e5ff [CI Skip] 1.0.0-beta.33
skip-checks: true
2020-01-28 18:22:37 +00:00
Jaco Greeff 18c302d2cf Allow author extract from empty (#1761) 2020-01-28 19:16:08 +01:00
Github Actions 1686f8b357 [CI Skip] 1.0.0-beta.32
skip-checks: true
2020-01-28 17:58:51 +00:00
Jaco Greeff 15158b763c Bump common (#1760) 2020-01-28 18:51:17 +01:00
Github Actions f5f338a9ae [CI Skip] 1.0.0-beta.31
skip-checks: true
2020-01-28 17:17:15 +00:00
Jaco Greeff 458dec53dc Session validators availability detection (#1759) 2020-01-28 18:10:06 +01:00
Github Actions ab05045686 [CI Skip] 1.0.0-beta.30
skip-checks: true
2020-01-28 16:47:39 +00:00
Jaco Greeff b2c84eb461 Bump deps (#1758)
* Bump deps

* api detect
2020-01-28 17:40:57 +01:00
Github Actions 1ee1d70d55 [CI Skip] 1.0.0-beta.29
skip-checks: true
2020-01-28 15:25:22 +00:00
Jaco Greeff 7de647ec0b Cleanup module-specific type-overrides (#1756) 2020-01-28 16:18:40 +01:00
Github Actions cedbd8fa06 [CI Skip] 1.0.0-beta.28
skip-checks: true
2020-01-28 14:40:38 +00:00
Jaco Greeff cba34b4b65 Fill signAsync with expanded chain options (#1753)
* Fill signAsync with expanded chain options

* Use mapTo

* Fill test with defined storage value

* Remove .only
2020-01-28 15:33:44 +01:00
Github Actions 1a99d67c77 [CI Skip] 1.0.0-beta.27
skip-checks: true
2020-01-28 10:13:45 +00:00
Jaco Greeff 2a5c5ce3fe Only include derives with parent query (#1755)
* Only include derives with parent query

* Update CHANGELOG
2020-01-28 11:07:02 +01:00
Github Actions e4ca0a1c64 [CI Skip] 1.0.0-beta.26
skip-checks: true
2020-01-28 08:59:33 +00:00
Jaco Greeff e6018f2f75 Add society-specific Vote type (#1754)
* Add society-specific Vote type

* Cnvert storage types via toLatest
2020-01-28 09:52:40 +01:00
Github Actions a9b4f8d841 [CI Skip] 1.0.0-beta.25
skip-checks: true
2020-01-27 18:42:41 +00:00
Amaury Martiny 7fe68857a0 Init api when provider is already connected (#1752)
* Init api when provider is already connected

* Spacing
2020-01-27 19:35:38 +01:00
Github Actions 4f63fc77a3 [CI Skip] 1.0.0-beta.24
skip-checks: true
2020-01-27 16:20:13 +00:00
Jaco Greeff 6e2ad7789e Expose .entries() for DoubleMaps (#1750)
* Expose .entries() for DoubleMaps

* DoubleMap vs Map test

* Fix decoration

* Remove prefixed map

* Allow SoubleMap entries() with arguments

* DoubleMap with & without params

* Remove debug log

* Update CHANGELOG

* ... and working... finally.

* Cleanup debug logs
2020-01-27 17:13:53 +01:00
Github Actions edb856c94f [CI Skip] 1.0.0-beta.23
skip-checks: true
2020-01-27 14:12:40 +00:00
Jaco Greeff 2f215fe2de Cleanup entries() (#1751) 2020-01-27 15:07:00 +01:00
Github Actions ffa1279c64 [CI Skip] 1.0.0-beta.22
skip-checks: true
2020-01-27 11:56:57 +00:00
Jaco Greeff 83aca87dac Skip types.ts for typedoc (#1749) 2020-01-27 12:50:36 +01:00
Github Actions bf782f6f65 [CI Skip] 1.0.0-beta.21
skip-checks: true
2020-01-27 11:43:36 +00:00
Jaco Greeff 7adad82786 Remove v11 metadata (#1748)
* Remove v11 metadata

* Linting
2020-01-27 12:37:01 +01:00
Github Actions 693cf855f0 [CI Skip] 1.0.0-beta.20
skip-checks: true
2020-01-27 08:45:51 +00:00
Jaco Greeff 854a520517 Mark some function @internal (no doc extraction) (#1746) 2020-01-27 09:38:02 +01:00
Github Actions 6e6fc98cd1 [CI Skip] 1.0.0-beta.19
skip-checks: true
2020-01-26 09:36:27 +00:00
Jaco Greeff 3db15e73a5 Bump deps (#1745)
* Bump deps

* Fix test expectation

* Mark doc internal
2020-01-26 10:27:44 +01:00
Github Actions 215b659a9a [CI Skip] 1.0.0-beta.18
skip-checks: true
2020-01-23 17:12:43 +00:00
Jaco Greeff 7ef945d15b Make invalid V9 metadata parse (won't work, but parses) (#1743)
* Make invalid V9 metadata parse (won't work, but parses)

* Add invalid to V4 (simpler, no code)
2020-01-23 18:06:25 +01:00
Github Actions 73ec345fcc [CI Skip] 1.0.0-beta.17
skip-checks: true
2020-01-22 14:59:54 +00:00
Jaco Greeff c1c537a3b5 Type aliases on a per-module basis (#1740)
* Type aliasses on a per-module basis

* Remove test interface

* Update wrapper

* Move known types to types
2020-01-22 15:51:23 +01:00
Github Actions dc64076c79 [CI Skip] 1.0.0-beta.16
skip-checks: true
2020-01-22 14:22:49 +00:00
Jaco Greeff da8ff51615 Remove unmaintained & outdated E2E (#1739) 2020-01-22 15:14:57 +01:00
Github Actions 60b1bc87a4 [CI Skip] 1.0.0-beta.15
skip-checks: true
2020-01-22 09:41:19 +00:00
Jaco Greeff 7ed1857589 Update SlashingSpans (#1738)
* Update SlashingSpans

* Digest 0toX -> ToX
2020-01-22 10:33:05 +01:00
Github Actions 4c0e60f3d6 [CI Skip] 1.0.0-beta.14
skip-checks: true
2020-01-21 13:52:44 +00:00
Jaco Greeff 20ed3bb5fe Allow passing of signer via sign options (#1734)
* Allow passing of signer via sign options

* Pass signer via api.sign
2020-01-21 14:45:53 +01:00
Jaco Greeff be3f9c8fe8 Remove outdated derive + combineLatest comment (#1733)
As per https://github.com/polkadot-js/api/pull/1732/files#r368599021
2020-01-21 14:45:07 +01:00
Github Actions e850955e55 [CI Skip] 1.0.0-beta.13
skip-checks: true
2020-01-20 13:05:49 +00:00
Jaco Greeff eb5ee9860b Multi query adjustments (#1732) 2020-01-20 13:58:07 +01:00
Github Actions f31bbdde02 [CI Skip] 1.0.0-beta.12
skip-checks: true
2020-01-19 21:55:43 +00:00
Jaco Greeff f67c435378 Trigger build 2020-01-19 22:49:09 +01:00
Jaco Greeff bf9a60a202 Update .123trigger 2020-01-19 22:46:50 +01:00
Jaco Greeff 9c3c07fa9b Derives for society (#1727)
* Deries for society

* Candidates

* Add overview

* Candidate types

* WIP, stash before merge

* Linting

* Readability

* Typo

* Split option maps
2020-01-19 21:56:39 +01:00
Github Actions 11786ca102 [CI Skip] 1.0.0-beta.11
skip-checks: true
2020-01-19 20:14:25 +00:00
Nikolay Volf ffaea83e3e Fix typo (#1730) 2020-01-19 21:05:58 +01:00
Github Actions 954540b944 [CI Skip] 1.0.0-beta.10
skip-checks: true
2020-01-19 10:29:05 +00:00
Jaco Greeff 204cf6769d Bump mtadata (latest Substrate) (#1728) 2020-01-19 11:20:33 +01:00
Github Actions f319bc4c50 [CI Skip] 1.0.0-beta.9
skip-checks: true
2020-01-19 09:24:49 +00:00
Jaco Greeff 7b9a11ac25 Don't map empty tuples to Null (#1725)
* Don't map empty tuples to Null

* Remove unused var

* Regen with tuple Result

* Generated types lint fixes
2020-01-19 10:17:20 +01:00
Github Actions 5d2feca2d4 [CI Skip] 1.0.0-beta.8
skip-checks: true
2020-01-16 13:54:01 +00:00
Jaco Greeff dd97e9daee Add registry error lookup (#1723) 2020-01-16 14:46:21 +01:00
Github Actions be258a1f7c [CI Skip] 1.0.0-beta.7
skip-checks: true
2020-01-15 09:05:23 +00:00
Jaco Greeff 72e9474f6f imOnline Heartbeat struct (#1721) 2020-01-15 09:56:58 +01:00
Github Actions d1f63a7864 [CI Skip] 1.0.0-beta.6
skip-checks: true
2020-01-14 18:15:57 +00:00
Jaco Greeff 07ca18502b Society/Recovery types (#1719)
* Society/Recovery types

* camelCase (linting)
2020-01-14 19:08:40 +01:00
Github Actions cddbe411f7 [CI Skip] 1.0.0-beta.5
skip-checks: true
2020-01-14 15:03:44 +00:00
Jaco Greeff ffa60d1cfa Drop V1 support in derive (#1718)
* Drop V1 support in derive

* Re-do staking with multi

* Re-bump deps

* Adjusts tests (no alice_session)

* CC
2020-01-14 15:55:25 +01:00
Github Actions 88193b6a75 [CI Skip] 1.0.0-beta.4
skip-checks: true
2020-01-14 13:15:58 +00:00
Stefanie Doll cc4a4607f1 Updated child storage parameters (#1709)
* Added child_definition and child_type to chicl dtorage RPC methods

* reset comments in test file

* reverse docs re-built

* Fix linting on child storage tests
2020-01-14 14:07:41 +01:00
Github Actions 6c25d0ab0d [CI Skip] 1.0.0-beta.3
skip-checks: true
2020-01-13 21:26:52 +00:00
Amaury Martiny fbbbcd2612 Enum toJSON returns toString for a basic enum (#1697)
* Update kusama static from 1032 to 1033

* Test 1032 and 1033

* Got exact metadata from kusama

* First pass: enum TOJSON and fix some tests

* Build interfaces

* Fix import

* Use camelCase for enum toJSON

* Build interface

* Fix lint

* Fix tests

* Generate static json
2020-01-13 22:18:51 +01:00
Github Actions dd57b1a007 [CI Skip] 1.0.0-beta.2
skip-checks: true
2020-01-13 17:03:58 +00:00
Jaco Greeff 47d0e68f7d Remove old known keys (#1715)
* Remove old known keys

* Don't import removed

* Update storage keys
2020-01-13 17:55:21 +01:00
Github Actions 7b6397215d [CI Skip] 1.0.0-beta.1
skip-checks: true
2020-01-13 16:39:56 +00:00
Jaco Greeff 5739b69757 Bump to 1.0 beta (#1717)
* Bump to 1.0 beta bump

* Bump common to 2.0 beta
2020-01-13 17:31:33 +01:00
261 changed files with 14354 additions and 10877 deletions
+1 -1
View File
@@ -1 +1 @@
16
17
+18
View File
@@ -1,3 +1,21 @@
# 1.0.1
- **Breaking change** Drop support for Substrate v1 chain in all derives
- Return unsub functions from provider .on emitters (Thanks to https://github.com/jak-pan)
- Add `polkadot-types-from-chain` & `polkadot-types-from-defs` TypeScript generators to `@polkadot/types`
- Only decorate derives where relevant parent `api.query.*` is available
- Support `.entries(arg?: any)` lookups on DoubleMaps (in addition to previously supported maps)
- Remove un-deployed support for v11 metadata (this was decided against on Substrate)
- Allow v9 metadata to parse even in cases where it was wrongly deployed pre-v10
- Allow type-aliasses on a per-module basis (e.g. `Judgement` in identity as well as society)
- Allow passing `{ signer }` to both `api.tx.*` and `api.sign` (in addition to `api.setSigner`)
- Add derives for the society module
- Don't map empy tuples, e.. `()` to `Null`, rather keep them empty
- Add lookups to the metadata erros via `findMetaError`
- Update metadata and types for the lastest Substrate & Polkadot versions
- Support metadata V11 as per lastest Substrate
- Remove old known types for Substrate V1
# 0.100.1
- **Important** This will the the last API version with Substrate 1.x support. Although you will still be able to use subsequent versions with older chans, dependent libraries such as sr25519 may not be compatible.
+1
View File
@@ -45,6 +45,7 @@ module.exports = {
['start/types.extend.md', 'Extending types'],
['start/extrinsic.extend.md', 'Extending extrinsics'],
['start/typescript.md', 'TypeScript interfaces'],
['start/typescript.user.md', 'TypeScript user generated'],
['start/FAQ.md', 'FAQ']
]
},
+1
View File
@@ -17,6 +17,7 @@
- [Type basics](start/types.basics.md)
- [Type extension](start/types.extend.md)
- [TypeScript interfaces](start/typescript.md)
- [TypeScript user generated](start/typescript.user.md)
## Packages
+2 -7
View File
@@ -46,11 +46,6 @@ As of this writing, there are still some gray areas to type detection, specifica
- `.at` & `.multi` on `api.query` does not (yet) have a `<TypeOverride>` interface. This means `as <TypeOverride>` casts are presently needed for these results
- `api.queryMulti` does not (yet) allow you to provide a hint to the types returned, this ties to the previous point
In addition to expanding the type coverage, we wish to make the actual generation script for the types from `@polkadot/types/interfaces` available in 2 ways -
## Adding user types
- allowing you to point to a folder of types and auto-generate the TypeScript typings from those. (Which is akin to what we do internally). This would allow a reduction in type classes explicitly written and injected.
- once the metadata itself supports full type definitions, the script can be used to generate interface definitions specifically tailored for a chain
## And that's a wrap
This brings us to the end of our overview and jump through the API. While the documentation is still very much and ever evolving item, we can encourage you to try out what you have learned with some [examples](../examples). As we [indicated right at the start of this journey](README.md#help-us-help-others), if there are areas for improvement, let us know.
In addition to the generated and available interfaces, there is also the ability to [create TypeScript interfaces from your own definitions and well as your on-chain modules](typescript.user.md).
+26
View File
@@ -0,0 +1,26 @@
# TypeScript user generated
In the previous section we looked at the TypeScript definitions that are available and is generated from both the chain and definitions. Here we will expand upon the use of the infrastructure created to define types as part of the `@polkadot/types` library and see how to use them to generate your onw defintions and chain types.
## Definitions
A large part of the type definitions are defined not as classes, but rather as structures from which type definitions are extracted and that can be used as-is to let the API know how to decode a type. By now you should be familiar with [type extensions](types.extend.md), but effectively the [types library does exactly the same](https://github.com/polkadot-js/api/tree/master/packages/types/src/interfaces).
To create TypeScript-aware definitions and keep your files in a single place, you can follow the same approach. Assuming you have a package named `@MeInc/stuff` where you have the definitions in an `stuff/interfaces` folder. Each sub-folder would indicate a runtime module, e.g.
- `stuff/interfaces/<module>/definitions.ts` for each module (`types.ts` & `index.ts` will be generated)
- `stuff/interfaces/defnitions.ts` importing all sub-definitions`
With this structure setup, you can generate TypeScript defintions.
In the root of your project (with the `@polkadot/api`), you can run `yarn polkadot-types-from-defs --input ./stuff/interfaces --package @MeInc/stuff/interfaces` which will create `types.ts` and `index.ts` files with the generated types. You can use these in exactly the same way as you would use your types from `@polkadot/types/interfaces`.
## Chain modules
In the same way as the type library provides defaults from a substrate-base chain, you can also, directly from chain from metadata, generate a complete `api.{consts,query}.*` defintion for your specific chain. The command will create 2 files, `{consts, query}.types.ts` which you can either use to augment the TypeScript defintions, or replace those in `@polkadot/api/*` with your versions (copy, TypeScript replacement or browser/node aliassing).
In the root of your project, you can run `yarn polkadot-types-from-chain --endpoint wss://<url> --output ./stuff` and it will create the required output. (Here you can specify an optional `--package @MeInc/stuff` to read definitions for the targetted output folder with the specified package name.)
## And that's a wrap
This brings us to the end of our overview and jump through the API. While the documentation is still very much and ever evolving item, we can encourage you to try out what you have learned with some [examples](../examples). As we [indicated right at the start of this journey](README.md#help-us-help-others), if there are areas for improvement, let us know.
+1 -1
View File
@@ -9,5 +9,5 @@
"packages": [
"packages/*"
],
"version": "0.100.1"
"version": "1.0.1"
}
+7 -10
View File
@@ -1,5 +1,5 @@
{
"version": "0.100.1",
"version": "1.0.1",
"private": true,
"engines": {
"yarn": "^1.10.1"
@@ -9,7 +9,7 @@
],
"resolutions": {
"babel-core": "^7.0.0-bridge.0",
"typescript": "^3.7.4"
"typescript": "^3.7.5"
},
"scripts": {
"build": "yarn build:interfaces && polkadot-dev-build-ts",
@@ -22,17 +22,14 @@
"postinstall": "polkadot-dev-yarn-only",
"test": "jest --coverage --runInBand --testPathIgnorePatterns e2e",
"test:all": "jest",
"test:e2e": "jest packages/api/test/e2e",
"test:e2e-docker": "TEST_DOCKER=1 jest packages/api/test/e2e",
"test:e2e-remote": "TEST_REMOTE=1 jest packages/api/test/e2e",
"test:one": "jest",
"test:watch": "jest --coverage --watch"
},
"devDependencies": {
"@babel/core": "^7.7.7",
"@babel/register": "^7.7.7",
"@babel/runtime": "^7.7.7",
"@polkadot/dev": "^0.32.14",
"@polkadot/ts": "^0.1.90"
"@babel/core": "^7.8.3",
"@babel/register": "^7.8.3",
"@babel/runtime": "^7.8.3",
"@polkadot/dev": "^0.33.3",
"@polkadot/ts": "^0.2.1"
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-contract",
"version": "0.100.1",
"version": "1.0.1",
"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.7.7",
"@polkadot/types": "^0.100.1"
"@babel/runtime": "^7.8.3",
"@polkadot/types": "^1.0.1"
}
}
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-derive",
"version": "0.100.1",
"version": "1.0.1",
"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.7.7",
"@polkadot/api": "^0.100.1",
"@polkadot/types": "^0.100.1"
"@babel/runtime": "^7.8.3",
"@polkadot/api": "^1.0.1",
"@polkadot/types": "^1.0.1"
},
"devDependencies": {
"@polkadot/keyring": "^1.8.1"
"@polkadot/keyring": "^2.0.1"
}
}
+11 -20
View File
@@ -14,10 +14,10 @@ import { bnMax } from '@polkadot/util';
import { memo } from '../util';
type ResultBalance = [Balance, Balance, BalanceLock[], Option<VestingSchedule>];
type Result = [AccountId, BlockNumber, ResultBalance, Index];
type ResultBalance = [Balance, Balance, BalanceLock[], Option<VestingSchedule>, Index];
type Result = [AccountId, BlockNumber, ResultBalance];
function calcBalances (api: ApiInterfaceRx, [accountId, bestNumber, [freeBalance, reservedBalance, locks, vesting], accountNonce]: Result): DerivedBalances {
function calcBalances (api: ApiInterfaceRx, [accountId, bestNumber, [freeBalance, reservedBalance, locks, vesting, accountNonce]]: Result): DerivedBalances {
let lockedBalance = createType(api.registry, 'Balance');
let lockedBreakdown: BalanceLock[] = [];
@@ -64,15 +64,6 @@ function calcBalances (api: ApiInterfaceRx, [accountId, bestNumber, [freeBalance
};
}
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.
@@ -96,15 +87,15 @@ export function all (api: ApiInterfaceRx): (address: AccountIndex | AccountId |
? combineLatest([
of(accountId),
api.derive.chain.bestNumber(),
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)
api.queryMulti<[Balance, Balance, Vec<BalanceLock>, Option<VestingSchedule>, Index]>([
[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]
])
])
: of([createType(api.registry, 'AccountId'), createType(api.registry, 'BlockNumber'), [createType(api.registry, 'Balance'), createType(api.registry, 'Balance'), createType(api.registry, 'Vec<BalanceLock>'), createType(api.registry, 'Option<VestingSchedule>', null)], createType(api.registry, 'Index')])
: of([createType(api.registry, 'AccountId'), createType(api.registry, 'BlockNumber'), [createType(api.registry, 'Balance'), createType(api.registry, 'Balance'), createType(api.registry, 'Vec<BalanceLock>'), createType(api.registry, 'Option<VestingSchedule>', null), createType(api.registry, 'Index')]])
)
),
map((result): DerivedBalances => calcBalances(api, result))
+1 -16
View File
@@ -13,7 +13,7 @@ import { memo } from '../util';
type Result = [Balance, Balance, Balance, Balance, Balance];
function queryV2 (api: ApiInterfaceRx): Observable<Result> {
function query (api: ApiInterfaceRx): Observable<Result> {
const paymentBase = api.consts.transactionPayment || api.consts.balances;
return of([
@@ -27,17 +27,6 @@ function queryV2 (api: ApiInterfaceRx): Observable<Result> {
]);
}
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
]);
}
/**
* @name fees
* @returns An object containing the combined results of the storage queries for
@@ -52,10 +41,6 @@ function queryV1 (api: ApiInterfaceRx): Observable<Result> {
* ```
*/
export function fees (api: ApiInterfaceRx): () => Observable<DerivedFees> {
const query = api.consts.balances
? queryV2
: queryV1;
return memo((): Observable<DerivedFees> =>
query(api).pipe(
map(([creationFee, existentialDeposit, transferFee, transactionBaseFee, transactionByteFee]): DerivedFees => ({
@@ -4,7 +4,7 @@
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Observable, combineLatest } from 'rxjs';
import { Observable, combineLatest, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { HeaderExtended } from '../type';
@@ -27,9 +27,11 @@ export function subscribeNewHeads (api: ApiInterfaceRx): () => Observable<Header
return memo((): Observable<HeaderExtended> =>
combineLatest([
api.rpc.chain.subscribeNewHeads(),
api.derive.staking.validators()
api.query.session
? api.query.session.validators()
: of([])
]).pipe(
map(([header, { validators }]): HeaderExtended =>
map(([header, validators]): HeaderExtended =>
new HeaderExtended(api.registry, header, validators)
)
));
+26 -27
View File
@@ -4,41 +4,40 @@
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Hash, Proposal, Votes } from '@polkadot/types/interfaces';
import { DerivedCollectiveProposals } from '../types';
import { DerivedCollectiveProposal } from '../types';
import { combineLatest, Observable, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Option } from '@polkadot/types';
export function proposals (api: ApiInterfaceRx, section: 'council' | 'technicalCommittee'): () => Observable<DerivedCollectiveProposals> {
return (): Observable<DerivedCollectiveProposals> =>
api.query[section]
? api.query[section].proposals()
.pipe(
switchMap((hashes: Hash[]): Observable<[Hash[], Option<Proposal>[], Option<Votes>[]]> => {
return combineLatest([
of(hashes),
combineLatest(
hashes.map((hash): Observable<Option<Proposal>> => api.query[section].proposalOf(hash))
),
api.query[section].voting.multi<Option<Votes>>(hashes)
]);
}),
map(([hashes, proposals, votes]): DerivedCollectiveProposals => {
const result: DerivedCollectiveProposals = [];
type Result = [Hash[], Option<Proposal>[], Option<Votes>[]];
proposals.forEach((proposalOpt, index): void => {
if (proposalOpt.isSome) {
result.push({
export function proposals (api: ApiInterfaceRx, section: 'council' | 'technicalCommittee'): () => Observable<DerivedCollectiveProposal[]> {
return (): Observable<DerivedCollectiveProposal[]> =>
api.query[section]
? api.query[section].proposals().pipe(
switchMap((hashes: Hash[]): Observable<Result> =>
hashes.length
? combineLatest([
of(hashes),
api.query[section].proposalOf.multi<Option<Proposal>>(hashes),
api.query[section].voting.multi<Option<Votes>>(hashes)
])
: of([[], [], []])
),
map(([hashes, proposals, votes]: Result): DerivedCollectiveProposal[] =>
proposals
.map((proposalOpt, index): DerivedCollectiveProposal | null =>
proposalOpt.isSome
? {
hash: hashes[index],
proposal: proposalOpt.unwrap(),
votes: votes[index].unwrapOr(null)
});
}
});
return result;
})
}
: null
)
.filter((proposal): boolean => !!proposal) as DerivedCollectiveProposal[]
)
: of([] as DerivedCollectiveProposals);
)
: of([] as DerivedCollectiveProposal[]);
}
+13 -13
View File
@@ -64,20 +64,20 @@ function parse (api: ApiInterfaceRx, { depositors, proposals, preimages }: Resul
export function proposals (api: ApiInterfaceRx): () => Observable<DeriveProposal[]> {
return memo((): Observable<DeriveProposal[]> =>
api.query.democracy?.publicProps
? api.query.democracy
.publicProps<Proposals>()
.pipe(
switchMap((proposals) =>
combineLatest([
of(proposals),
api.query.democracy.preimages.multi<PreImage>(proposals.map(([, hash]): Hash => hash)),
api.query.democracy.depositOf.multi<Depositors>(proposals.map(([index]): PropIndex => index))
])
),
map(([proposals, preimages, depositors]): DeriveProposal[] =>
parse(api, { depositors, proposals, preimages })
)
? api.query.democracy.publicProps<Proposals>().pipe(
switchMap((proposals) =>
combineLatest([
of(proposals),
api.query.democracy.preimages.multi<PreImage>(
proposals.map(([, hash]): Hash => hash)),
api.query.democracy.depositOf.multi<Depositors>(
proposals.map(([index]): PropIndex => index))
])
),
map(([proposals, preimages, depositors]): DeriveProposal[] =>
parse(api, { depositors, proposals, preimages })
)
)
: of([] as DeriveProposal[])
);
}
@@ -9,7 +9,7 @@ import BN from 'bn.js';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option, Vec } from '@polkadot/types';
import { Option } from '@polkadot/types';
import { memo } from '../util';
import { retrieveInfo } from './referendumInfo';
@@ -17,9 +17,9 @@ import { retrieveInfo } from './referendumInfo';
export function referendumInfos (api: ApiInterfaceRx): (ids?: (BN | number)[]) => Observable<DerivedReferendum[]> {
return memo((ids: (BN | number)[] = []): Observable<DerivedReferendum[]> =>
(
!ids || !ids.length
!ids?.length
? of([] as Option<ReferendumInfo>[])
: api.query.democracy.referendumInfoOf.multi(ids) as Observable<Vec<Option<ReferendumInfo>>>
: api.query.democracy.referendumInfoOf.multi<Option<ReferendumInfo>>(ids)
).pipe(
switchMap((infos): Observable<(DerivedReferendum | null)[]> =>
combineLatest(
@@ -19,7 +19,7 @@ export function referendumVotesFor (api: ApiInterfaceRx): (referendumId: BN | nu
switchMap((votersFor): Observable<[Vec<AccountId>, Vote[], DerivedBalances[]]> =>
combineLatest([
of(votersFor),
api.derive.democracy.votes(referendumId as BN, votersFor),
api.derive.democracy.votes(referendumId, votersFor),
api.derive.balances.votingBalances(votersFor)
])
),
@@ -14,10 +14,9 @@ import { memo } from '../util';
export function referendums (api: ApiInterfaceRx): () => Observable<DerivedReferendum[]> {
return memo((): Observable<DerivedReferendum[]> =>
// V2 vs V1 (and early V2)
api.query.democracy?.lowestUnbaked || api.query.democracy?.nextTally
api.query.democracy?.lowestUnbaked
? api.queryMulti<[ReferendumIndex, ReferendumIndex]>([
api.query.democracy.lowestUnbaked || api.query.democracy.nextTally,
api.query.democracy.lowestUnbaked,
api.query.democracy.referendumCount
]).pipe(
switchMap(([earliest, referendumCount]): Observable<DerivedReferendum[]> =>
+3 -3
View File
@@ -10,12 +10,12 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { memo } from '../util';
export function votes (api: ApiInterfaceRx): (referendumId: BN, accountIds?: AccountId[]) => Observable<Vote[]> {
return memo((referendumId: BN, accountIds: AccountId[] = []): Observable<Vote[]> =>
export function votes (api: ApiInterfaceRx): (referendumId: BN | number, accountIds?: AccountId[]) => Observable<Vote[]> {
return memo((referendumId: BN | number, accountIds: AccountId[] = []): Observable<Vote[]> =>
!accountIds || !accountIds.length
? of([] as Vote[])
: api.query.democracy.voteOf.multi<Vote>(
accountIds.map((accountId): [BN, AccountId] =>
accountIds.map((accountId): [BN | number, AccountId] =>
[referendumId, accountId]
)
)
+14 -29
View File
@@ -5,7 +5,7 @@
import { AccountId, Balance, BlockNumber } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { Observable, combineLatest } from 'rxjs';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { createType, Vec, u32 } from '@polkadot/types';
@@ -13,39 +13,24 @@ import { createType, Vec, u32 } from '@polkadot/types';
import { DerivedElectionsInfo } from '../types';
import { memo } from '../util';
function deriveElections (api: ApiInterfaceRx, candidates: AccountId[], members: [AccountId, Balance][], runnersUp: [AccountId, Balance][], candidacyBond: Balance, desiredSeats: u32, termDuration: BlockNumber, votingBond: Balance): DerivedElectionsInfo {
return {
candidates,
candidateCount: createType(api.registry, 'u32', candidates.length),
candidacyBond,
desiredSeats,
members: members.sort((a, b): number => b[1].cmp(a[1])),
runnersUp: runnersUp.sort((a, b): number => b[1].cmp(a[1])),
termDuration,
votingBond
};
}
function queryElections (api: ApiInterfaceRx): Observable<DerivedElectionsInfo> {
const section = api.query.electionsPhragmen ? 'electionsPhragmen' : 'elections';
// NOTE We have an issue where candidates can return `null` for an empty array, hence
// we are not using multi queries here, so empty array is empty (instead of space-filled)
return combineLatest([
api.query[section].candidates<Vec<AccountId>>(),
api.query[section].members<Vec<ITuple<[AccountId, Balance]>>>(),
api.query[section].runnersUp<Vec<ITuple<[AccountId, Balance]>>>()
return api.queryMulti<[Vec<AccountId>, Vec<ITuple<[AccountId, Balance]>>, Vec<ITuple<[AccountId, Balance]>>]>([
api.query[section].candidates,
api.query[section].members,
api.query[section].runnersUp
]).pipe(
map(([candidates, members, runnersUp]): DerivedElectionsInfo => deriveElections(
api,
map(([candidates, members, runnersUp]): DerivedElectionsInfo => ({
candidates,
members,
runnersUp,
api.consts[section].candidacyBond as Balance,
api.consts[section].desiredMembers as u32,
api.consts[section].termDuration as BlockNumber,
api.consts[section].votingBond as Balance
))
candidateCount: createType(api.registry, 'u32', candidates.length),
candidacyBond: api.consts[section].candidacyBond as Balance,
desiredSeats: api.consts[section].desiredMembers as u32,
members: members.sort((a, b): number => b[1].cmp(a[1])),
runnersUp: runnersUp.sort((a, b): number => b[1].cmp(a[1])),
termDuration: api.consts[section].termDuration as BlockNumber,
votingBond: api.consts[section].votingBond as Balance
}))
);
}
@@ -17,13 +17,15 @@ import { memo } from '../util';
*/
export function receivedHeartbeats (api: ApiInterfaceRx): () => Observable<DerivedHeartbeats> {
return memo((): Observable<DerivedHeartbeats> =>
api.query.imOnline?.receivedHeartbeats && api.query.imOnline.authoredBlocks
api.query.imOnline?.receivedHeartbeats
? api.derive.staking.overview().pipe(
switchMap(({ currentIndex, validators }): Observable<[AccountId[], Option<Bytes>[], u32[]]> =>
combineLatest([
of(validators),
api.query.imOnline.receivedHeartbeats.multi<Option<Bytes>>(validators.map((_address, index): [SessionIndex, number] => [currentIndex, index])),
api.query.imOnline.authoredBlocks.multi<u32>(validators.map((address): [SessionIndex, AccountId] => [currentIndex, address]))
api.query.imOnline.receivedHeartbeats.multi<Option<Bytes>>(
validators.map((_address, index): [SessionIndex, number] => [currentIndex, index])),
api.query.imOnline.authoredBlocks.multi<u32>(
validators.map((address): [SessionIndex, AccountId] => [currentIndex, address]))
])
),
map(([validators, heartbeats, numBlocks]): DerivedHeartbeats =>
+26 -3
View File
@@ -16,12 +16,15 @@ import * as democracy from './democracy';
import * as elections from './elections';
import * as imOnline from './imOnline';
import * as session from './session';
import * as society from './society';
import * as staking from './staking';
import * as technicalCommittee from './technicalCommittee';
import * as treasury from './treasury';
export * from './type';
export const derive = { accounts, balances, chain, contracts, council, democracy, elections, imOnline, session, society, staking, technicalCommittee, treasury };
type DeriveSection<Section> = {
[Method in keyof Section]: Section[Method] extends AnyFunction
? ReturnType<Section[Method]> // ReturnType<Section[Method]> will be the inner function, i.e. without (api) argument
@@ -33,13 +36,35 @@ type DeriveAllSections<AllSections> = {
export type DeriveCustom = Record<string, Record<string, (api: ApiInterfaceRx) => (...args: any[]) => Observable<any>>>;
export type ExactDerive = DeriveAllSections<typeof derive>;
// Enable derive only if some of these modules are available
const deriveAvail: Record<string, string[]> = {
contracts: ['contracts'],
council: ['council'],
democracy: ['democracy'],
elections: ['electionsPhragmen', 'elections'],
imOnline: ['imOnline'],
session: ['session'],
society: ['society'],
staking: ['staking'],
technicalCommittee: ['technicalCommittee'],
treasury: ['treasury']
};
/**
* Returns an object that will inject `api` into all the functions inside
* `allSections`, and keep the object architecture of `allSections`.
*/
/** @internal */
function injectFunctions<AllSections> (api: ApiInterfaceRx, allSections: AllSections): DeriveAllSections<AllSections> {
const queryKeys = Object.keys(api.query);
return Object
.keys(allSections)
.filter((sectionName): boolean =>
!deriveAvail[sectionName] || deriveAvail[sectionName].some((query): boolean => queryKeys.includes(query))
)
.reduce((deriveAcc, sectionName): DeriveAllSections<AllSections> => {
const section = allSections[sectionName as keyof AllSections];
@@ -59,11 +84,9 @@ function injectFunctions<AllSections> (api: ApiInterfaceRx, allSections: AllSect
}, {} as DeriveAllSections<AllSections>);
}
export const derive = { accounts, balances, chain, contracts, council, democracy, elections, imOnline, session, staking, technicalCommittee, treasury };
export type ExactDerive = DeriveAllSections<typeof derive>;
// FIXME The return type of this function should be {...ExactDerive, ...DeriveCustom}
// For now we just drop the custom derive typings
/** @internal */
export default function decorateDerive (api: ApiInterfaceRx, custom: DeriveCustom = {}): ExactDerive {
return {
...injectFunctions(api, derive),
+5 -52
View File
@@ -2,50 +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 { BlockNumber, SessionIndex } from '@polkadot/types/interfaces';
import { SessionIndex } from '@polkadot/types/interfaces';
import { DerivedSessionInfo, DeriveSessionIndexes } from '../types';
import { Observable, combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option, u64, createType } from '@polkadot/types';
import { u64, createType } from '@polkadot/types';
import { memo } from '../util';
type ResultV1Session = [Option<BlockNumber>, BlockNumber, BlockNumber, SessionIndex];
type ResultV1 = [BlockNumber, DeriveSessionIndexes, ResultV1Session];
type ResultSlots = [u64, u64, u64, SessionIndex];
type ResultType = [boolean, u64, SessionIndex];
type Result = [ResultType, DeriveSessionIndexes, ResultSlots];
// internal helper to just split the logic - take all inputs, do the calculations and combine
function createDerivedV1 (api: ApiInterfaceRx, [bestNumber, { currentIndex, validatorCount }, [_lastLengthChange, sessionLength, lastEraLengthChange, sessionsPerEra]]: ResultV1): DerivedSessionInfo {
const lastLengthChange = _lastLengthChange?.unwrapOr(null) || createType(api.registry, 'BlockNumber');
const sessionProgress = bestNumber
.sub(lastLengthChange)
.add(sessionLength)
.mod(sessionLength);
const currentEra = currentIndex
.sub(lastEraLengthChange)
.mod(sessionsPerEra);
const eraProgress = currentEra
.mul(sessionLength)
.add(sessionProgress);
return {
currentEra: createType(api.registry, 'EraIndex', currentEra),
currentIndex,
eraLength: createType(api.registry, 'BlockNumber', sessionLength.mul(sessionsPerEra)),
eraProgress: createType(api.registry, 'BlockNumber', eraProgress),
isEpoch: false,
sessionLength,
sessionsPerEra,
sessionProgress: createType(api.registry, 'BlockNumber', sessionProgress),
validatorCount
};
}
function createDerivedLatest (api: ApiInterfaceRx, [[hasBabe, epochDuration, sessionsPerEra], { currentIndex, currentEra, validatorCount }, [currentSlot, epochIndex, epochOrGenesisStartSlot, currentEraStartSessionIndex]]: Result): DerivedSessionInfo {
const epochStartSlot = epochIndex.mul(epochDuration).add(epochOrGenesisStartSlot);
const sessionProgress = currentSlot.sub(epochStartSlot);
@@ -64,21 +34,6 @@ function createDerivedLatest (api: ApiInterfaceRx, [[hasBabe, epochDuration, ses
};
}
function infoV1 (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
return combineLatest([
api.derive.chain.bestNumber(),
api.derive.session.indexes(),
api.queryMulti<ResultV1Session>([
api.query.session.lastLengthChange,
api.query.session.sessionLength,
api.query.staking.lastEraLengthChange,
api.query.staking.sessionsPerEra
])
]).pipe(
map((result): DerivedSessionInfo => createDerivedV1(api, result))
);
}
function infoLatestAura (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
return api.derive.session.indexes().pipe(
map((indexes): DerivedSessionInfo =>
@@ -115,11 +70,9 @@ function infoLatestBabe (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
* @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 query = api.consts.timestamp || api.consts.babe || api.consts.aura
? api.consts.babe
? infoLatestBabe // 2.x with Babe
: infoLatestAura // 2.x with Aura (not all info there)
: infoV1;
const query = api.consts.babe
? infoLatestBabe // 2.x with Babe
: infoLatestAura; // 2.x with Aura (not all info there)
return memo((): Observable<DerivedSessionInfo> =>
query(api));
@@ -0,0 +1,42 @@
// Copyright 2017-2020 @polkadot/api-derive 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 { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, BalanceOf, Bid, BidKind } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { DeriveSocietyCandidate } from '../types';
import { combineLatest, of, Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Option, Vec } from '@polkadot/types';
import { memo } from '../util';
type ResultSuspend = Option<ITuple<[BalanceOf, BidKind]>>;
type Result = [Bid[], ResultSuspend[]]
/**
* @description Get the candidate info for a society
*/
export function candidates (api: ApiInterfaceRx): () => Observable<DeriveSocietyCandidate[]> {
return memo((): Observable<DeriveSocietyCandidate[]> =>
api.query.society.candidates<Vec<Bid>>().pipe(
switchMap((candidates: Vec<Bid>): Observable<Result> =>
combineLatest([
of(candidates),
api.query.society.suspendedCandidates.multi<ResultSuspend>(
candidates.map(({ who }): AccountId => who))
])
),
map(([candidates, suspended]: Result): DeriveSocietyCandidate[] =>
candidates.map(({ who, kind, value }, index) => ({
accountId: who,
isSuspended: suspended[index].isSome,
kind,
value
}))
)
)
);
}
+8
View File
@@ -0,0 +1,8 @@
// Copyright 2017-2020 @polkadot/api-derive 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 * from './candidates';
export * from './info';
export * from './member';
export * from './members';
+41
View File
@@ -0,0 +1,41 @@
// Copyright 2017-2020 @polkadot/api-derive 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 { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, BalanceOf, Bid } from '@polkadot/types/interfaces';
import { DeriveSociety } from '../types';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Option, Vec, u32 } from '@polkadot/types';
import { memo } from '../util';
type Result = [Vec<Bid>, Option<AccountId>, Option<AccountId>, Option<AccountId>, u32, BalanceOf]
/**
* @description Get the overall info for a society
*/
export function info (api: ApiInterfaceRx): () => Observable<DeriveSociety> {
return memo((): Observable<DeriveSociety> =>
api.queryMulti<Result>([
api.query.society.bids,
api.query.society.defender,
api.query.society.founder,
api.query.society.head,
api.query.society.maxMembers,
api.query.society.pot
]).pipe(
map(([bids, defender, founder, head, maxMembers, pot]: Result): DeriveSociety => ({
bids,
defender: defender.unwrapOr(undefined),
hasDefender: (defender.isSome && head.isSome && !head.eq(defender)) || false,
head: head.unwrapOr(undefined),
founder: founder.unwrapOr(undefined),
maxMembers,
pot
}))
)
);
}
+40
View File
@@ -0,0 +1,40 @@
// Copyright 2017-2020 @polkadot/api-derive 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 { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, Balance, BlockNumber, SocietyVote, StrikeCount, VouchingStatus } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { DeriveSocietyMember } from '../types';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { bool, Option, Vec } from '@polkadot/types';
import { memo } from '../util';
type Result = [Vec<ITuple<[BlockNumber, Balance]>>, StrikeCount, Option<SocietyVote>, bool, Option<VouchingStatus>];
/**
* @description Get the member info for a society
*/
export function member (api: ApiInterfaceRx): (accountId: AccountId) => Observable<DeriveSocietyMember> {
return memo((accountId: AccountId): Observable<DeriveSocietyMember> =>
api.queryMulti<Result>([
[api.query.society.payouts, accountId],
[api.query.society.strikes, accountId],
[api.query.society.defenderVotes, accountId],
[api.query.society.suspendedMembers, accountId],
[api.query.society.vouching, accountId]
]).pipe(
map(([payouts, strikes, defenderVote, suspended, vouching]: Result): DeriveSocietyMember => ({
accountId,
payouts,
isSuspended: suspended.isTrue,
strikes,
vote: defenderVote.unwrapOr(undefined),
vouching: vouching.unwrapOr(undefined)
}))
)
);
}
@@ -0,0 +1,27 @@
// Copyright 2017-2020 @polkadot/api-derive 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 { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId } from '@polkadot/types/interfaces';
import { DeriveSocietyMember } from '../types';
import { combineLatest, Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { memo } from '../util';
/**
* @description Get the member info for a society
*/
export function members (api: ApiInterfaceRx): () => Observable<DeriveSocietyMember[]> {
return memo((): Observable<DeriveSocietyMember[]> =>
api.query.society.members<AccountId[]>().pipe(
switchMap((members): Observable<DeriveSocietyMember[]> =>
combineLatest(members.map((accountId): Observable<DeriveSocietyMember> =>
api.derive.society.member(accountId)
))
)
)
);
}
+1 -18
View File
@@ -13,10 +13,7 @@ import { Option, Vec } from '@polkadot/types';
import { memo } from '../util';
// NOTE Unused ATM, preparing for V2-only
type Result = [Option<AccountId>, [Vec<AccountId>], RewardDestination, Exposure, ValidatorPrefs, Option<Keys>?];
type ResultV1 = [Option<AccountId>, ITuple<[Vec<AccountId>]>, RewardDestination, Exposure, ValidatorPrefs];
type ResultV2 = [Option<AccountId>, ITuple<[Vec<AccountId>]>, RewardDestination, Exposure, ValidatorPrefs, Option<Keys>];
function parse (stashId: AccountId, [_controllerId, [nominators], rewardDestination, stakers, validatorPrefs, _nextKeys]: Result): DerivedStakingStash {
@@ -31,17 +28,7 @@ function parse (stashId: AccountId, [_controllerId, [nominators], rewardDestinat
};
}
function retrieveV1 (api: ApiInterfaceRx, stashId: AccountId): Observable<Result> {
return api.queryMulti<ResultV1>([
[api.query.staking.bonded, stashId],
[api.query.staking.nominators, stashId],
[api.query.staking.payee, stashId],
[api.query.staking.stakers, stashId],
[api.query.staking.validators, stashId]
]);
}
function retrieveV2 (api: ApiInterfaceRx, stashId: AccountId): Observable<Result> {
function query (api: ApiInterfaceRx, stashId: AccountId): Observable<Result> {
return api.queryMulti<ResultV2>([
[api.query.staking.bonded, stashId],
[api.query.staking.nominators, stashId],
@@ -53,10 +40,6 @@ function retrieveV2 (api: ApiInterfaceRx, stashId: AccountId): Observable<Result
}
export function infoStash (api: ApiInterfaceRx): (stashId: AccountId) => Observable<DerivedStakingStash> {
const query = api.consts.session
? retrieveV2
: retrieveV1;
return memo((stashId: AccountId): Observable<DerivedStakingStash> =>
query(api, stashId).pipe(
map((result): DerivedStakingStash => parse(stashId, result))
+1 -5
View File
@@ -8,7 +8,6 @@ import { DerivedStakingOverview } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { createType } from '@polkadot/types';
import { memo } from '../util';
@@ -24,10 +23,7 @@ export function overview (api: ApiInterfaceRx): () => Observable<DerivedStakingO
switchMap(([{ currentEra, currentIndex, validatorCount }, { currentElected, validators }]) =>
combineLatest([
of({ currentElected, currentEra, currentIndex, validators, validatorCount }),
// this will change on a per block basis, keep it innermost (and it needs eraIndex)
api.query.staking?.currentEraPointsEarned
? api.query.staking.currentEraPointsEarned<EraPoints>(currentEra)
: of(createType(api.registry, 'EraPoints'))
api.query.staking.currentEraPointsEarned<EraPoints>(currentEra)
])
),
map(([{ currentElected, currentEra, currentIndex, validators, validatorCount }, eraPoints]): DerivedStakingOverview => ({
+37 -118
View File
@@ -13,142 +13,61 @@ import { createType, Option, Vec } from '@polkadot/types';
import { memo } from '../util';
interface ParseInput {
accountId: AccountId;
controllerId: AccountId;
nominators: AccountId[];
rewardDestination: RewardDestination;
queuedKeys?: [AccountId, Keys][];
stakers: Exposure;
stakingLedger: Option<StakingLedger>;
stashId: AccountId;
validatorPrefs: ValidatorPrefs;
nextKeys?: Option<Keys>;
nextKeyFor?: Option<AccountId>;
}
type MultiResultV2 = [Option<AccountId>, Option<ITuple<[Nominations]>>, RewardDestination, Exposure, [ValidatorPrefs], Option<Keys>, Option<StakingLedger>];
function unwrapSessionIds (stashId: AccountId, queuedKeys: Option<AccountId> | [AccountId, Keys][], nextKeys: Option<Keys>): { nextSessionIds: AccountId[]; sessionIds: AccountId[] } {
// for 2.x we have a Vec<(ValidatorId,Keys)> of the keys
if (Array.isArray(queuedKeys)) {
const sessionIds = (queuedKeys.find(([currentId]): boolean =>
currentId.eq(stashId)
) || [undefined, [] as AccountId[]])[1];
const nextSessionIds = nextKeys.unwrapOr([] as AccountId[]);
return {
nextSessionIds,
sessionIds
};
}
// substrate 1.x
const nextSessionIds = queuedKeys.isSome
? [queuedKeys.unwrap()]
: [];
function unwrapSessionIds (stashId: AccountId, queuedKeys: [AccountId, Keys][], nextKeys: Option<Keys>): { nextSessionIds: AccountId[]; sessionIds: AccountId[] } {
const sessionIds = (queuedKeys.find(([currentId]): boolean =>
currentId.eq(stashId)
) || [undefined, [] as AccountId[]])[1];
const nextSessionIds = nextKeys.unwrapOr([] as AccountId[]);
return {
nextSessionIds,
sessionIds: nextSessionIds
sessionIds
};
}
function parseResult (api: ApiInterfaceRx, { accountId, controllerId, stashId, nextKeyFor, queuedKeys, stakingLedger, nominators, rewardDestination, stakers, validatorPrefs, nextKeys }: ParseInput): DerivedStakingQuery {
const _stakingLedger = stakingLedger.unwrapOr(undefined);
const _nextKeyFor = nextKeyFor || createType(api.registry, 'Option<AccountId>', null);
const _nextKeys = nextKeys || createType(api.registry, 'Option<Keys>', null);
return {
accountId,
controllerId,
nominators,
rewardDestination,
stakers,
stakingLedger: _stakingLedger,
stashId,
validatorPrefs,
...unwrapSessionIds(stashId, queuedKeys || _nextKeyFor, _nextKeys)
};
}
type MultiResultV1 = [Option<AccountId>, Option<StakingLedger>, [Vec<AccountId>], RewardDestination, Exposure, ITuple<[ValidatorPrefs]>];
function retrieveInfoV1 (api: ApiInterfaceRx, accountId: AccountId, stashId: AccountId, controllerId: AccountId): Observable<DerivedStakingQuery> {
return (
api.queryMulti([
[api.query.session.nextKeyFor, controllerId],
[api.query.staking.ledger, controllerId],
[api.query.staking.nominators, stashId],
[api.query.staking.payee, stashId],
[api.query.staking.stakers, stashId],
[api.query.staking.validators, stashId]
]) as Observable<MultiResultV1>
).pipe(map(([nextKeyFor, stakingLedger, [nominators], rewardDestination, stakers, [validatorPrefs]]: MultiResultV1): DerivedStakingQuery =>
parseResult(api, {
accountId, controllerId, stashId, nextKeyFor, stakingLedger, nominators, rewardDestination, stakers, validatorPrefs
})
));
}
type MultiResultV2 = [[Vec<AccountId>] | Option<ITuple<[Nominations]>>, RewardDestination, Exposure, [ValidatorPrefs], Option<Keys>, Option<StakingLedger>];
function retrieveInfoV2 (api: ApiInterfaceRx, accountId: AccountId, stashId: AccountId, controllerId: AccountId): Observable<DerivedStakingQuery> {
function retrieve (api: ApiInterfaceRx, stashId: AccountId): Observable<[Vec<ITuple<[AccountId, Keys]>>, MultiResultV2]> {
return combineLatest([
api.query.session.queuedKeys<Vec<ITuple<[AccountId, Keys]>>>(),
api.queryMulti([
[api.query.staking.bonded, stashId],
[api.query.staking.nominators, stashId],
[api.query.staking.payee, stashId],
[api.query.staking.stakers, stashId],
[api.query.staking.validators, stashId],
[api.query.session.nextKeys, [api.consts.session.dedupKeyPrefix, stashId]],
[api.query.staking.ledger, controllerId]
[api.query.session.nextKeys, [api.consts.session.dedupKeyPrefix, stashId]]
]) as Observable<MultiResultV2>
]).pipe(map(([queuedKeys, [_nominators, rewardDestination, stakers, [validatorPrefs], nextKeys, stakingLedger]]: [[AccountId, Keys][], MultiResultV2]): DerivedStakingQuery => {
// if we have staking.storageVersion it indicates the new structure, unwrap as needed
// FIXME We really want to be pulling all the new (valuable) info along
const nominators: AccountId[] = api.query.staking.storageVersion
? (_nominators as Option<ITuple<[Nominations]>>).isSome
? (_nominators as Option<ITuple<[Nominations]>>).unwrap()[0].targets
: []
: (_nominators as [Vec<AccountId>])[0];
return parseResult(api, {
accountId, controllerId, stashId, queuedKeys, stakingLedger, nominators, rewardDestination, stakers, validatorPrefs, nextKeys
});
}));
}
function retrieveV1 (api: ApiInterfaceRx, accountId: AccountId): Observable<DerivedStakingQuery> {
// depending on where we come from, this may be a controller or stash
return combineLatest([
api.query.staking.bonded<Option<AccountId>>(accountId),
api.query.staking.ledger<Option<StakingLedger>>(accountId)
]).pipe(switchMap(([bonded, stakingLedger]): Observable<DerivedStakingQuery> =>
stakingLedger.isSome
? retrieveInfoV1(api, accountId, stakingLedger.unwrap().stash, accountId)
: bonded.isSome
? retrieveInfoV1(api, accountId, accountId, bonded.unwrap())
: of({ accountId: accountId, nextSessionIds: [], sessionIds: [] })
));
}
function retrieveV2 (api: ApiInterfaceRx, stashId: AccountId): Observable<DerivedStakingQuery> {
return api.query.staking
.bonded<Option<AccountId>>(stashId)
.pipe(switchMap((controllerId): Observable<DerivedStakingQuery> =>
controllerId.isSome
? retrieveInfoV2(api, stashId, stashId, controllerId.unwrap())
: of({ accountId: stashId, nextSessionIds: [], sessionIds: [] })
));
]);
}
/**
* @description From a stash, retrieve the controllerId and fill in all the relevant staking details
* @description From a stash, retrieve the controllerId and all relevant details
*/
export function query (api: ApiInterfaceRx): (_accountId: Uint8Array | string) => Observable<DerivedStakingQuery> {
const retrieve = api.consts.session
? retrieveV2
: retrieveV1;
export function query (api: ApiInterfaceRx): (accountId: Uint8Array | string) => Observable<DerivedStakingQuery> {
return memo((accountId: Uint8Array | string): Observable<DerivedStakingQuery> => {
const stashId = createType(api.registry, 'AccountId', accountId);
return memo((accountId: Uint8Array | string): Observable<DerivedStakingQuery> =>
retrieve(api, createType(api.registry, 'AccountId', accountId)));
return retrieve(api, stashId).pipe(
switchMap(([queuedKeys, [controllerIdOpt, nominatorsOpt, rewardDestination, stakers, [validatorPrefs], nextKeys]]): Observable<DerivedStakingQuery> => {
const controllerId = controllerIdOpt.unwrapOr(null);
return controllerId
? api.query.staking.ledger(controllerId).pipe(
map((stakingLedgerOpt): DerivedStakingQuery => ({
accountId: stashId,
controllerId,
nominators: nominatorsOpt.unwrapOr([{ targets: [] }])[0].targets,
rewardDestination,
stakers,
stakingLedger: stakingLedgerOpt.unwrapOr(undefined),
stashId,
validatorPrefs,
...unwrapSessionIds(stashId, queuedKeys, nextKeys)
}))
)
: of({ accountId: stashId, nextSessionIds: [], sessionIds: [] });
})
);
});
}
+12 -13
View File
@@ -2,13 +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 { AccountId } from '@polkadot/types/interfaces';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { DeriveStakingValidators } from '../types';
import { Observable, of } from 'rxjs';
import { Observable, combineLatest, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { Vec } from '@polkadot/types';
import { memo } from '../util';
@@ -17,16 +15,17 @@ import { memo } from '../util';
*/
export function validators (api: ApiInterfaceRx): () => Observable<DeriveStakingValidators> {
return memo((): Observable<DeriveStakingValidators> =>
(
// Sadly the node-template is (for some obscure reason) not comprehensive, so while the derive works
// in all actual real-world deployed chains, it does create some confusion for limited template chains
api.query.session && api.query.staking
? api.queryMulti<[Vec<AccountId>, Vec<AccountId>]>([
api.query.session.validators,
api.query.staking.currentElected
])
: of([[], []] as [AccountId[], AccountId[]])
).pipe(
// Sadly the node-template is (for some obscure reason) not comprehensive, so while the derive works
// in all actual real-world deployed chains, it does create some confusion for limited template chains
// NOTE: Not doing multi queries here, since we have validators as a single in the derived newHead
combineLatest([
api.query.session
? api.query.session.validators()
: of([]),
api.query.staking
? api.query.staking.currentElected()
: of([])
]).pipe(
map(([validators, currentElected]): DeriveStakingValidators => ({
currentElected, validators
}))
@@ -62,10 +62,7 @@ function retrieveProposals (api: ApiInterfaceRx, proposalCount: ProposalIndex, a
const allIds = [...proposalIds, ...approvalIds];
return combineLatest([
// We are doing single subscriptions on all these, multi may yield old results
combineLatest(
allIds.map((id): Observable<Option<TreasuryProposal>> => api.query.treasury.proposals(id))
),
api.query.treasury.proposals.multi<Option<TreasuryProposal>>(allIds),
api.derive.council.proposals()
]).pipe(
map(([allProposals, councilProposals]: [Option<TreasuryProposal>[], DerivedCollectiveProposals]): DerivedTreasuryProposals =>
+27 -1
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, AccountIndex, Balance, BalanceLock, BlockNumber, EraIndex, EraPoints, Exposure, Hash, Index, Keys, Proposal, PropIndex, ProposalIndex, ReferendumInfo, RegistrationJudgement, RewardDestination, SessionIndex, SetIndex, StakingLedger, TreasuryProposal, ValidatorPrefs, Vote, Votes, VoteIndex } from '@polkadot/types/interfaces';
import { AccountId, AccountIndex, Balance, BalanceLock, BalanceOf, Bid, BidKind, BlockNumber, EraIndex, EraPoints, Exposure, Hash, Index, Keys, Proposal, PropIndex, ProposalIndex, ReferendumInfo, RegistrationJudgement, RewardDestination, SessionIndex, SetIndex, SocietyVote, StakingLedger, StrikeCount, TreasuryProposal, ValidatorPrefs, Vote, Votes, VoteIndex, VouchingStatus } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import { u32, Vec } from '@polkadot/types';
@@ -149,6 +149,32 @@ export interface DerivedSessionInfo extends DeriveSessionIndexes {
sessionProgress: BlockNumber;
}
export interface DeriveSociety {
bids: Bid[];
defender?: AccountId;
hasDefender: boolean;
head?: AccountId;
founder?: AccountId;
maxMembers: u32;
pot: BalanceOf;
}
export interface DeriveSocietyCandidate {
accountId: AccountId;
kind: BidKind;
value: Balance;
isSuspended: boolean;
}
export interface DeriveSocietyMember {
accountId: AccountId;
isSuspended: boolean;
payouts: [BlockNumber, Balance][];
strikes: StrikeCount;
vote?: SocietyVote;
vouching?: VouchingStatus;
}
export interface DerivedStakingElected {
currentElected: AccountId[];
info: DerivedStakingQuery[];
@@ -6,6 +6,7 @@ import { ApprovalFlag } from '@polkadot/types/interfaces/elections';
import { Vec } from '@polkadot/types';
/** @internal */
export function approvalFlagsToBools (flags: Vec<ApprovalFlag> | ApprovalFlag[]): boolean[] {
const bools: boolean[] = [];
+1
View File
@@ -15,6 +15,7 @@ const normalizer = JSON.stringify;
// Wraps a derive, doing 2 things to optimize calls -
// 1. creates a memo of the inner fn -> Observable, removing when unsubscribed
// 2. wraps the observable in a drr() (which includes an unsub delay)
/** @internal */
export function memo <T> (inner: ObsFn<T>): ObsFn<T> {
const cached = createMemo(
(...params: any[]): Observable<T> =>
+13 -10
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api",
"version": "0.100.1",
"version": "1.0.1",
"description": "Promise and RxJS wrappers around the Polkadot JS RPC",
"main": "index.js",
"keywords": [
@@ -25,17 +25,20 @@
"url": "https://github.com/polkadot-js/api/issues"
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api#readme",
"browser": {
"../package.json": "./package.json"
},
"dependencies": {
"@babel/runtime": "^7.7.7",
"@polkadot/api-derive": "^0.100.1",
"@polkadot/keyring": "^1.8.1",
"@polkadot/metadata": "^0.100.1",
"@polkadot/rpc-core": "^0.100.1",
"@polkadot/rpc-provider": "^0.100.1",
"@polkadot/types": "^0.100.1",
"@polkadot/util-crypto": "^1.8.1"
"@babel/runtime": "^7.8.3",
"@polkadot/api-derive": "^1.0.1",
"@polkadot/keyring": "^2.0.1",
"@polkadot/metadata": "^1.0.1",
"@polkadot/rpc-core": "^1.0.1",
"@polkadot/rpc-provider": "^1.0.1",
"@polkadot/types": "^1.0.1",
"@polkadot/util-crypto": "^2.0.1"
},
"devDependencies": {
"@polkadot/keyring": "^1.8.1"
"@polkadot/keyring": "^2.0.1"
}
}
+31 -36
View File
@@ -4,27 +4,24 @@
import { Constants, Storage } from '@polkadot/metadata/Decorated/types';
import { RpcInterface } from '@polkadot/rpc-core/jsonrpc.types';
import { InterfaceRegistry } from '@polkadot/types/interfaceRegistry';
import { Call, Hash, RuntimeVersion } from '@polkadot/types/interfaces';
import { AnyFunction, CallFunction, Codec, CodecArg as Arg, ITuple, ModulesWithCalls, Registry } from '@polkadot/types/types';
import { AnyFunction, CallFunction, Codec, CodecArg as Arg, ITuple, InterfaceTypes, ModulesWithCalls, Registry, RegistryTypes } from '@polkadot/types/types';
import { SubmittableExtrinsic } from '../submittable/types';
import {
ApiInterfaceRx, ApiOptions, ApiTypes,
DecorateMethod, DecoratedRpc, DecoratedRpcSection,
QueryableModuleStorage, QueryableStorage, QueryableStorageEntry, QueryableStorageMulti, QueryableStorageMultiArg,
SubmittableExtrinsicFunction, SubmittableExtrinsics, SubmittableModuleExtrinsics
} from '../types';
import { ApiInterfaceRx, ApiOptions, ApiTypes, DecorateMethod, DecoratedRpc, DecoratedRpcSection, QueryableModuleStorage, QueryableStorage, QueryableStorageEntry, QueryableStorageMulti, QueryableStorageMultiArg, SubmittableExtrinsicFunction, SubmittableExtrinsics, SubmittableModuleExtrinsics } from '../types';
import BN from 'bn.js';
import { BehaviorSubject, Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import decorateDerive, { ExactDerive } from '@polkadot/api-derive';
import getHasher from '@polkadot/metadata/Decorated/storage/fromMetadata/getHasher';
import RpcCore from '@polkadot/rpc-core';
import { WsProvider } from '@polkadot/rpc-provider';
import { Metadata, Null, Option, TypeRegistry, u64, Vec } from '@polkadot/types';
import Linkage, { LinkageResult } from '@polkadot/types/codec/Linkage';
import { DEFAULT_VERSION as EXTRINSIC_DEFAULT_VERSION } from '@polkadot/types/primitive/Extrinsic/constants';
import StorageKey, { StorageEntry } from '@polkadot/types/primitive/StorageKey';
import { assert, compactStripLength, u8aToHex } from '@polkadot/util';
import { assert, compactStripLength, isNull, isUndefined, u8aConcat, u8aToHex } from '@polkadot/util';
import { createSubmittable } from '../submittable';
import { decorateSections, DeriveAllSections } from '../util/decorate';
@@ -132,6 +129,10 @@ export default abstract class Decorate<ApiType extends ApiTypes> extends Events
this._rx.registry = this.registry;
}
public abstract createType <K extends InterfaceTypes> (type: K, ...params: any[]): InterfaceRegistry[K];
public abstract registerTypes (types?: RegistryTypes): void;
/**
* @returns `true` if the API operates with subscriptions
*/
@@ -257,10 +258,8 @@ export default abstract class Decorate<ApiType extends ApiTypes> extends Events
: [creator, ...args];
// FIXME We probably want to be able to query the full list with non-subs as well
const decorated = this.hasSubscriptions && creator.iterKey && (creator.meta.type.asMap.kind.isLinkedMap || creator.meta.type.asMap.kind.isPrefixedMap)
? creator.meta.type.asMap.kind.isLinkedMap
? this.decorateStorageLinked(creator, decorateMethod)
: this.decorateStoragePrefixed(creator, decorateMethod)
const decorated = this.hasSubscriptions && creator.iterKey && creator.meta.type.isMap && creator.meta.type.asMap.linked.isTrue
? this.decorateStorageLinked(creator, decorateMethod)
: decorateMethod((...args: any[]): Observable<Codec> => (
this.hasSubscriptions
? this._rpcCore.state
@@ -277,8 +276,8 @@ export default abstract class Decorate<ApiType extends ApiTypes> extends Events
decorated.at = decorateMethod((hash: Hash, arg1?: Arg, arg2?: Arg): Observable<Codec> =>
this._rpcCore.state.getStorage(getArgs(arg1, arg2), hash));
decorated.entries = decorateMethod((): Observable<[StorageKey, Codec][]> =>
this.retrieveMapEntries(creator));
decorated.entries = decorateMethod((doubleMapArg?: Arg): Observable<[StorageKey, Codec][]> =>
this.retrieveMapEntries(creator, doubleMapArg));
decorated.hash = decorateMethod((arg1?: Arg, arg2?: Arg): Observable<Hash> =>
this._rpcCore.state.getStorageHash(getArgs(arg1, arg2)));
@@ -371,15 +370,26 @@ export default abstract class Decorate<ApiType extends ApiTypes> extends Events
);
}
private retrieveMapData (creator: StorageEntry): Observable<[StorageKey[], Vec<Codec>]> {
assert(creator.meta.type.isMap, 'entries can only be retrieved on maps');
private retrieveMapEntries (creator: StorageEntry, arg?: Arg): Observable<[StorageKey, Codec][]> {
assert(creator.iterKey && (creator.meta.type.isMap || creator.meta.type.isDoubleMap), 'entries can only be retrieved on maps, linked maps and double maps');
const outputType = creator.meta.type.asMap.value.toString();
const outputType = creator.meta.type.isMap
? creator.meta.type.asMap.value.toString()
: creator.meta.type.asDoubleMap.value.toString();
return this._rpcCore.state
// FIXME This should really be some sort of subscription, so we can get stuff as
// it changes (as of now it is a one-shot query). Not sure how to do this though...
.getKeys(creator.iterKey)
.getKeys(
this.createType('Raw', u8aConcat(
creator.iterKey,
creator.meta.type.isDoubleMap && !isUndefined(arg) && !isNull(arg)
? getHasher(creator.meta.type.asDoubleMap.hasher)(
this.createType(creator.meta.type.asDoubleMap.key1.toString() as 'Raw', arg).toU8a()
)
: new Uint8Array([])
))
)
.pipe(
switchMap((keys): Observable<[StorageKey[], Vec<Codec>]> =>
combineLatest([
@@ -389,28 +399,13 @@ export default abstract class Decorate<ApiType extends ApiTypes> extends Events
keys.map((key) => key.setOutputType(outputType))
)
])
),
map(([keys, values]): [StorageKey, Codec][] =>
keys.map((key, index): [StorageKey, Codec] => [key, values[index]])
)
);
}
private retrieveMapEntries (creator: StorageEntry): Observable<[StorageKey, Codec][]> {
return this.retrieveMapData(creator).pipe(
map(([keys, values]): [StorageKey, Codec][] =>
keys.map((key, index): [StorageKey, Codec] => [key, values[index]])
)
);
}
private decorateStoragePrefixed<ApiType extends ApiTypes> (creator: StorageEntry, decorateMethod: DecorateMethod<ApiType>): ReturnType<DecorateMethod<ApiType>> {
return decorateMethod((...args: any[]): Observable<Codec> =>
args.length
? this._rpcCore.state
.subscribeStorage<[Codec]>([[creator, ...args]])
.pipe(map(([data]): Codec => data))
: this.retrieveMapData(creator).pipe(map(([, values]): Vec<Codec> => values))
);
}
protected decorateDeriveRx (decorateMethod: DecorateMethod<ApiType>): DeriveAllSections<'rxjs', ExactDerive> {
// Pull in derive from api-derive
const derive = decorateDerive(this._rx as ApiInterfaceRx, this._options.derives);
+8 -4
View File
@@ -3,18 +3,17 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { SignedBlock } from '@polkadot/types/interfaces';
import { RegistryTypes } from '@polkadot/types/types';
import { ApiBase, ApiOptions, ApiTypes, DecorateMethod } from '../types';
import DecoratedMeta from '@polkadot/metadata/Decorated';
import { Metadata, u32 as U32 } from '@polkadot/types';
import { getChainTypes, getMetadataTypes } from '@polkadot/types/known';
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';
import Decorate from './Decorate';
import { getChainTypes, getMetadataTypes } from './typeInjector';
const KEEPALIVE_INTERVAL = 15000;
@@ -46,9 +45,14 @@ export default abstract class Init<ApiType extends ApiTypes> extends Decorate<Ap
this._rpcCore.provider.on('disconnected', this._onProviderDisconnect);
this._rpcCore.provider.on('error', this._onProviderError);
this._rpcCore.provider.on('connected', this._onProviderConnect);
}
public abstract registerTypes (types?: RegistryTypes): void;
// If the provider was instantiated earlier, and has already emitted a
// 'connected' event, then the `on('connected')` won't fire anymore. To
// cater for this case, we call manually `this._onProviderConnect`.
if (this._rpcCore.provider.isConnected()) {
this._onProviderConnect();
}
}
protected async loadMeta (): Promise<boolean> {
const { metadata = {} } = this._options;
+21 -9
View File
@@ -6,7 +6,7 @@ import { Constants } from '@polkadot/metadata/Decorated/types';
import { RpcInterface } from '@polkadot/rpc-core/jsonrpc.types';
import { Hash, RuntimeVersion } from '@polkadot/types/interfaces';
import { InterfaceRegistry } from '@polkadot/types/interfaceRegistry';
import { CallFunction, InterfaceTypes, RegistryTypes, SignerPayloadRawBase } from '@polkadot/types/types';
import { CallFunction, InterfaceTypes, RegistryError, RegistryTypes, SignerPayloadRawBase } from '@polkadot/types/types';
import { ApiInterfaceRx, ApiOptions, ApiTypes, DecoratedRpc, DecorateMethod, QueryableStorage, QueryableStorageMulti, SubmittableExtrinsics, Signer } from '../types';
import { Metadata, createType } from '@polkadot/types';
@@ -18,6 +18,10 @@ interface KeyringSigner {
sign (message: Uint8Array): Uint8Array;
}
interface SignerRawOptions {
signer?: Signer;
}
let pkgJson: { name: string; version: string };
try {
@@ -239,12 +243,19 @@ export default abstract class ApiBase<ApiType extends ApiTypes> extends Init<Api
}
/**
* @description Finds the definition for a specific [[Call]] based on the index supplied
* @description Finds the definition for a specific [[CallFunction]] based on the index supplied
*/
public findCall (callIndex: Uint8Array | string): CallFunction {
return this.registry.findMetaCall(u8aToU8a(callIndex));
}
/**
* @description Finds the definition for a specific [[RegistryError]] based on the index supplied
*/
public findError (errorIndex: Uint8Array | string): RegistryError {
return this.registry.findMetaError(u8aToU8a(errorIndex));
}
/**
* @description Register additional user-defined of chain-specific types in the type registry
*/
@@ -262,20 +273,21 @@ export default abstract class ApiBase<ApiType extends ApiTypes> extends Init<Api
/**
* @description Signs a raw signer payload, string or Uint8Array
*/
public async sign (signer: KeyringSigner | string, data: SignerPayloadRawBase): Promise<string> {
// NOTE Do we really want to do this? Or turn it into an observable for rxjs?
if (isString(signer)) {
assert(this._rx.signer?.signRaw, 'No signer exists with a signRaw interface');
public async sign (address: KeyringSigner | string, data: SignerPayloadRawBase, { signer }: SignerRawOptions = {}): Promise<string> {
if (isString(address)) {
const _signer = signer || this._rx.signer;
assert(_signer?.signRaw, 'No signer exists with a signRaw interface');
return (
await this._rx.signer.signRaw({
await _signer.signRaw({
type: 'bytes',
...data,
address: signer
address
})
).signature;
}
return u8aToHex(signer.sign(u8aToU8a(data.data)));
return u8aToHex(address.sign(u8aToU8a(data.data)));
}
}
-101
View File
@@ -1,101 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 { RuntimeVersion } from '@polkadot/types/interfaces';
import { RegistryTypes } from '@polkadot/types/types';
import { Text } from '@polkadot/types';
import { isUndefined } from '@polkadot/util';
interface VersionedType {
minmax: [number?, number?]; // min (v >= min) and max (v <= max)
types: RegistryTypes;
}
// these are override types for Polkadot & Kusama chains
// NOTE The SessionKeys definition for Polkadot and Substrate (OpaqueKeys
// implementation) are different. Detect Polkadot and inject the `Keys`
// definition as applicable. (4 keys in substrate vs 5 in Polkadot/CC3).
const TYPES_POLKADOT_VERSIONED: VersionedType[] = [
{
minmax: [1000, undefined], // from launch
types: {
Keys: 'SessionKeys5'
}
}
];
const TYPES_KUSAMA_VERSIONED: VersionedType[] = [
{
minmax: [1019, 1031], // CC3, from launch
types: {
DispatchError: 'DispatchErrorTo198',
Keys: 'SessionKeys5'
}
},
{
minmax: [1032, undefined], // CC3, with DispatchError
types: {
Keys: 'SessionKeys5'
}
}
];
// Type overrides based on specific nodes
const TYPES_CHAIN: Record<string, VersionedType[]> = {};
// Type overrides based on metadata versions
const TYPES_META: VersionedType[] = [
{
// NOTE this is for support of old, e.g. Alex, old metadata and BlockNumber/Index
// This is detected based on metadata version, since this is what we have up-front
// v3 = Alex
// v4 = v1.0 branch
minmax: [0, 4],
types: {
BlockNumber: 'u64',
Index: 'u64',
EventRecord: 'EventRecordTo76',
ValidatorPrefs: 'ValidatorPrefsTo145'
}
}
];
// Type overrides for specific spec types & versions as given in runtimeVersion
const TYPES_SPEC: Record<string, VersionedType[]> = {
kusama: TYPES_KUSAMA_VERSIONED,
polkadot: TYPES_POLKADOT_VERSIONED
};
// flatten a VersionedType[] into a Record<string, string>
function filterVersions (versions: VersionedType[] = [], version: number): RegistryTypes {
return versions
.filter(({ minmax: [min, max] }): boolean =>
(isUndefined(min) || version >= min) &&
(isUndefined(max) || version <= max)
)
.reduce((result: RegistryTypes, { types }): RegistryTypes => ({
...result,
...types
}), {});
}
// based on the metadata version, return the registry types
export function getMetadataTypes (version: number): RegistryTypes {
return filterVersions(TYPES_META, version);
}
// based on the chain and runtimeVersion, get the applicable types (ready for registration)
export function getChainTypes (chainName: Text, { specName, specVersion }: RuntimeVersion, typesChain: Record<string, RegistryTypes> = {}, typesSpec: Record<string, RegistryTypes> = {}): RegistryTypes {
const _chainName = chainName.toString();
const _specName = specName.toString();
const _specVersion = specVersion.toNumber();
return {
...filterVersions(TYPES_SPEC[_specName], _specVersion),
...filterVersions(TYPES_CHAIN[_chainName], _specVersion),
...(typesSpec[_specName] || {}),
...(typesChain[_chainName] || {})
};
}
+13 -6
View File
@@ -1,8 +1,8 @@
// Auto-generated via `yarn build:interfaces`, do not edit
// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
/* eslint-disable @typescript-eslint/no-empty-interface */
import { Bytes, u32, u64 } from '@polkadot/types';
import { Balance, BalanceOf, BlockNumber, Moment, Permill } from '@polkadot/types/interfaces/runtime';
import { Balance, BalanceOf, BlockNumber, Moment, Percent, Permill } from '@polkadot/types/interfaces/runtime';
import { Gas } from '@polkadot/types/interfaces/contracts';
import { SessionIndex } from '@polkadot/types/interfaces/session';
import { EraIndex } from '@polkadot/types/interfaces/staking';
@@ -68,6 +68,10 @@ declare module '@polkadot/metadata/Decorated/types' {
proposalBondMinimum: BalanceOf & ConstantCodec;
spendPeriod: BlockNumber & ConstantCodec;
burn: Permill & ConstantCodec;
tipCountdown: BlockNumber & ConstantCodec;
tipFindersFee: Percent & ConstantCodec;
tipReportDepositBase: BalanceOf & ConstantCodec;
tipReportDepositPerByte: BalanceOf & ConstantCodec;
};
contracts: {
[index: string]: Codec;
@@ -88,11 +92,14 @@ declare module '@polkadot/metadata/Decorated/types' {
maxValueSize: u32 & ConstantCodec;
blockGasLimit: Gas & ConstantCodec;
};
nicks: {
society: {
[index: string]: Codec;
reservationFee: BalanceOf & ConstantCodec;
minLength: u32 & ConstantCodec;
maxLength: u32 & ConstantCodec;
candidateDeposit: BalanceOf & ConstantCodec;
wrongSideDeduction: BalanceOf & ConstantCodec;
maxStrikes: u32 & ConstantCodec;
periodSpend: BalanceOf & ConstantCodec;
rotationPeriod: BlockNumber & ConstantCodec;
challengePeriod: BlockNumber & ConstantCodec;
};
}
}
+10 -2
View File
@@ -2,9 +2,17 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { assertSingletonPackage } from '@polkadot/util';
import { detectPackage } from '@polkadot/util';
assertSingletonPackage('@polkadot/api');
let pkgJson;
try {
pkgJson = require('./package.json');
} catch (error) {
pkgJson = require('../package.json');
}
detectPackage(pkgJson);
export { Keyring } from '@polkadot/keyring';
export { WsProvider } from '@polkadot/rpc-provider';
+45 -9
View File
@@ -4,16 +4,24 @@
import { ApiOptions } from '../types';
import testingPairs from '@polkadot/keyring/testingPairs';
import createPair from '@polkadot/keyring/pair';
import testKeyring from '@polkadot/keyring/testing';
import Mock from '@polkadot/rpc-provider/mock/index';
import { createType, TypeRegistry } from '@polkadot/types';
import { hexToU8a } from '@polkadot/util';
import { SingleAccountSigner } from '../../test/util';
import ApiPromise from './Api';
describe('ApiPromise', (): void => {
const registry = new TypeRegistry();
const keyring = testingPairs({ type: 'ed25519' });
const keyring = testKeyring({ type: 'ed25519' });
const aliceEd = keyring.addPair(
createPair('ed25519', {
secretKey: hexToU8a('0xabf8e5bdbe30c65656c0a3cbd181ff8a56294a69dfedd27982aace4a7690911588dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee'),
publicKey: hexToU8a('0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee')
})
);
let provider: Mock;
beforeEach((): void => {
@@ -52,6 +60,25 @@ describe('ApiPromise', (): void => {
expect(api.tx).toBeDefined();
expect(api.derive).toBeDefined();
});
it('Create API instance will error on failure to await ready', async (): Promise<void> => {
class ErrorApiPromise extends ApiPromise {
constructor () {
super({ provider });
}
protected loadMeta (): Promise<boolean> {
throw new Error('Simulate failure to load meta');
}
}
try {
await new ErrorApiPromise().isReady;
fail('Expected an error but none occurred.');
} catch {
// Pass
}
});
});
describe('api.sign', (): void => {
@@ -63,7 +90,7 @@ describe('ApiPromise', (): void => {
const api = new ApiPromise({ provider, registry });
expect(
await api.sign(keyring.alice_session, TEST)
await api.sign(aliceEd, TEST)
).toEqual(SIG);
});
@@ -71,7 +98,7 @@ describe('ApiPromise', (): void => {
const api = new ApiPromise({
provider,
registry,
signer: new SingleAccountSigner(registry, keyring.alice_session)
signer: new SingleAccountSigner(registry, aliceEd)
});
expect(
@@ -82,14 +109,23 @@ describe('ApiPromise', (): void => {
describe('decorator.signAsync', (): void => {
it('signs a transfer using an external signer', async (): Promise<void> => {
const signer = new SingleAccountSigner(registry, keyring.alice_session);
const api = await ApiPromise.create({ provider, registry, signer });
const transfer = api.tx.balances.transfer(keyring.eve.address, 12345);
provider.subscriptions.state_subscribeStorage.lastValue = {
changes: [
[
'0x26aa394eea5630e07c48ae0c9558cef79c2f82b23e5fd031fb54c292794b4cc4d560eb8d00e57357cf76492334e43bb2ecaa9f28df6a8c4426d7b6090f7ad3c9',
'0x00'
]
]
};
await transfer.signAsync(keyring.alice_session, {});
const signer = new SingleAccountSigner(registry, aliceEd);
const api = await ApiPromise.create({ provider, registry, signer });
const transfer = api.tx.balances.transfer(keyring.getPair('0xe659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e').address, 12345);
await transfer.signAsync(aliceEd, {});
expect(transfer.signature.toHex()).toEqual(
'0x97f3cfe5088fcd575313e983f45d02b0f630e7b94ff9a3ac50e20cd096a8f554fda73d42ead891b5a1d3ce5607d83f20b0c6570b555e949cfb5763d0abcd590b'
'0x6b9ccc95afbd4e916d30c65c720f4f7b70a77db545735b48a763844aa5210e695aa346686bad1224af77d00bcfbf6fc8d2c216a60731027835d5a414186a2607'
);
});
});
+4 -1
View File
@@ -216,10 +216,13 @@ export default class ApiPromise extends ApiBase<'promise'> {
constructor (options?: ApiOptions) {
super(options, 'promise', decorateMethod);
this._isReadyPromise = new Promise((resolve): void => {
this._isReadyPromise = new Promise((resolve, reject): void => {
super.once('ready', (): void => {
resolve(this);
});
super.once('error', (e): void => {
reject(e);
});
});
}
+47 -9
View File
@@ -1,9 +1,9 @@
// Auto-generated via `yarn build:interfaces`, do not edit
// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
/* eslint-disable @typescript-eslint/no-empty-interface */
import { Observable } from 'rxjs';
import { Option, Raw, Vec } from '@polkadot/types/codec';
import { Bytes, Null, bool, u32, u64 } from '@polkadot/types';
import { Bytes, Data, bool, u32, u64 } from '@polkadot/types';
import { AccountId, AccountIndex, Balance, BalanceOf, BlockNumber, Hash, Index, KeyTypeId, Moment, Perbill, ValidatorId, Weight } from '@polkadot/types/interfaces/runtime';
import { UncleEntryItem } from '@polkadot/types/interfaces/authorship';
import { BabeAuthorityWeight, MaybeVrf } from '@polkadot/types/interfaces/babe';
@@ -14,16 +14,20 @@ import { CodeHash, ContractInfo, Gas, PrefabWasmModule, Schedule } from '@polkad
import { Conviction, PropIndex, Proposal, ReferendumIndex, ReferendumInfo } from '@polkadot/types/interfaces/democracy';
import { Vote, VoteThreshold } from '@polkadot/types/interfaces/elections';
import { AuthorityList, SetId, StoredPendingChange, StoredState } from '@polkadot/types/interfaces/grandpa';
import { RegistrarInfo, Registration } from '@polkadot/types/interfaces/identity';
import { AuthIndex } from '@polkadot/types/interfaces/imOnline';
import { Kind, OffenceDetails, OpaqueTimeSlot, ReportIdOf } from '@polkadot/types/interfaces/offences';
import { ActiveRecovery, RecoveryConfig } from '@polkadot/types/interfaces/recovery';
import { Keys, SessionIndex } from '@polkadot/types/interfaces/session';
import { Bid, BidKind, SocietyVote, StrikeCount, VouchingStatus } from '@polkadot/types/interfaces/society';
import { EraIndex, EraPoints, Exposure, Forcing, MomentOf, Nominations, RewardDestination, SlashingSpans, SpanIndex, SpanRecord, StakingLedger, UnappliedSlash, ValidatorPrefs } from '@polkadot/types/interfaces/staking';
import { DigestOf, EventIndex, EventRecord } from '@polkadot/types/interfaces/system';
import { TreasuryProposal } from '@polkadot/types/interfaces/treasury';
import { OpenTip, TreasuryProposal } from '@polkadot/types/interfaces/treasury';
import { Multiplier } from '@polkadot/types/interfaces/txpayment';
import { Multisig } from '@polkadot/types/interfaces/utility';
import { ITuple } from '@polkadot/types/types';
declare module './types' {
declare module '@polkadot/api/types' {
export interface QueryableStorageExact<ApiType> {
system: {
[index: string]: QueryableStorageEntry<ApiType>;
@@ -39,7 +43,11 @@ declare module './types' {
digest: StorageEntryExact<ApiType, () => Observable<DigestOf>> & QueryableStorageEntry<ApiType>;
events: StorageEntryExact<ApiType, () => Observable<Vec<EventRecord>>> & QueryableStorageEntry<ApiType>;
eventCount: StorageEntryExact<ApiType, () => Observable<EventIndex>> & QueryableStorageEntry<ApiType>;
eventTopics: StorageEntryExact<ApiType, (key1: Null, key2: Hash | Uint8Array | string) => Observable<Vec<ITuple<[BlockNumber, EventIndex]>>>> & QueryableStorageEntry<ApiType>;
eventTopics: StorageEntryExact<ApiType, (arg: Hash | Uint8Array | string) => Observable<Vec<ITuple<[BlockNumber, EventIndex]>>>> & QueryableStorageEntry<ApiType>;
};
utility: {
[index: string]: QueryableStorageEntry<ApiType>;
multisigs: StorageEntryExact<ApiType, (key1: AccountId | Uint8Array | string, key2: Raw | Uint8Array | string) => Observable<Option<Multisig>>> & QueryableStorageEntry<ApiType>;
};
babe: {
[index: string]: QueryableStorageEntry<ApiType>;
@@ -127,9 +135,9 @@ declare module './types' {
preimages: StorageEntryExact<ApiType, (arg: Hash | Uint8Array | string) => Observable<Option<ITuple<[Bytes, AccountId, BalanceOf, BlockNumber]>>>> & QueryableStorageEntry<ApiType>;
depositOf: StorageEntryExact<ApiType, (arg: PropIndex | Uint8Array | number | string) => Observable<Option<ITuple<[BalanceOf, Vec<AccountId>]>>>> & QueryableStorageEntry<ApiType>;
referendumCount: StorageEntryExact<ApiType, () => Observable<ReferendumIndex>> & QueryableStorageEntry<ApiType>;
nextTally: StorageEntryExact<ApiType, () => Observable<ReferendumIndex>> & QueryableStorageEntry<ApiType>;
lowestUnbaked: StorageEntryExact<ApiType, () => Observable<ReferendumIndex>> & QueryableStorageEntry<ApiType>;
referendumInfoOf: StorageEntryExact<ApiType, (arg: ReferendumIndex | Uint8Array | number | string) => Observable<Option<ReferendumInfo>>> & QueryableStorageEntry<ApiType>;
dispatchQueue: StorageEntryExact<ApiType, (arg: BlockNumber | Uint8Array | number | string) => Observable<Vec<Option<ITuple<[Hash, ReferendumIndex]>>>>> & QueryableStorageEntry<ApiType>;
dispatchQueue: StorageEntryExact<ApiType, () => Observable<Vec<ITuple<[BlockNumber, Hash, ReferendumIndex]>>>> & QueryableStorageEntry<ApiType>;
votersFor: StorageEntryExact<ApiType, (arg: ReferendumIndex | Uint8Array | number | string) => Observable<Vec<AccountId>>> & QueryableStorageEntry<ApiType>;
voteOf: StorageEntryExact<ApiType, (arg: ITuple<[ReferendumIndex, AccountId]>) => Observable<Vote>> & QueryableStorageEntry<ApiType>;
proxy: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<Option<AccountId>>> & QueryableStorageEntry<ApiType>;
@@ -183,6 +191,8 @@ declare module './types' {
proposalCount: StorageEntryExact<ApiType, () => Observable<ProposalIndex>> & QueryableStorageEntry<ApiType>;
proposals: StorageEntryExact<ApiType, (arg: ProposalIndex | Uint8Array | number | string) => Observable<Option<TreasuryProposal>>> & QueryableStorageEntry<ApiType>;
approvals: StorageEntryExact<ApiType, () => Observable<Vec<ProposalIndex>>> & QueryableStorageEntry<ApiType>;
tips: StorageEntryExact<ApiType, (arg: Hash | Uint8Array | string) => Observable<Option<OpenTip>>> & QueryableStorageEntry<ApiType>;
reasons: StorageEntryExact<ApiType, (arg: Hash | Uint8Array | string) => Observable<Option<Bytes>>> & QueryableStorageEntry<ApiType>;
};
contracts: {
[index: string]: QueryableStorageEntry<ApiType>;
@@ -215,9 +225,37 @@ declare module './types' {
[index: string]: QueryableStorageEntry<ApiType>;
randomMaterial: StorageEntryExact<ApiType, () => Observable<Vec<Hash>>> & QueryableStorageEntry<ApiType>;
};
nicks: {
identity: {
[index: string]: QueryableStorageEntry<ApiType>;
nameOf: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<Option<ITuple<[Bytes, BalanceOf]>>>> & QueryableStorageEntry<ApiType>;
identityOf: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<Option<Registration>>> & QueryableStorageEntry<ApiType>;
superOf: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<Option<ITuple<[AccountId, Data]>>>> & QueryableStorageEntry<ApiType>;
subsOf: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<ITuple<[BalanceOf, Vec<AccountId>]>>> & QueryableStorageEntry<ApiType>;
registrars: StorageEntryExact<ApiType, () => Observable<Vec<Option<RegistrarInfo>>>> & QueryableStorageEntry<ApiType>;
};
society: {
[index: string]: QueryableStorageEntry<ApiType>;
founder: StorageEntryExact<ApiType, () => Observable<Option<AccountId>>> & QueryableStorageEntry<ApiType>;
rules: StorageEntryExact<ApiType, () => Observable<Option<Hash>>> & QueryableStorageEntry<ApiType>;
candidates: StorageEntryExact<ApiType, () => Observable<Vec<Bid>>> & QueryableStorageEntry<ApiType>;
suspendedCandidates: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<Option<ITuple<[BalanceOf, BidKind]>>>> & QueryableStorageEntry<ApiType>;
pot: StorageEntryExact<ApiType, () => Observable<BalanceOf>> & QueryableStorageEntry<ApiType>;
head: StorageEntryExact<ApiType, () => Observable<Option<AccountId>>> & QueryableStorageEntry<ApiType>;
members: StorageEntryExact<ApiType, () => Observable<Vec<AccountId>>> & QueryableStorageEntry<ApiType>;
suspendedMembers: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<bool>> & QueryableStorageEntry<ApiType>;
bids: StorageEntryExact<ApiType, () => Observable<Vec<Bid>>> & QueryableStorageEntry<ApiType>;
vouching: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<Option<VouchingStatus>>> & QueryableStorageEntry<ApiType>;
payouts: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<Vec<ITuple<[BlockNumber, BalanceOf]>>>> & QueryableStorageEntry<ApiType>;
strikes: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<StrikeCount>> & QueryableStorageEntry<ApiType>;
votes: StorageEntryExact<ApiType, (key1: AccountId | Uint8Array | string, key2: AccountId | Uint8Array | string) => Observable<Option<SocietyVote>>> & QueryableStorageEntry<ApiType>;
defender: StorageEntryExact<ApiType, () => Observable<Option<AccountId>>> & QueryableStorageEntry<ApiType>;
defenderVotes: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<Option<SocietyVote>>> & QueryableStorageEntry<ApiType>;
maxMembers: StorageEntryExact<ApiType, () => Observable<u32>> & QueryableStorageEntry<ApiType>;
};
recovery: {
[index: string]: QueryableStorageEntry<ApiType>;
recoverable: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<Option<RecoveryConfig>>> & QueryableStorageEntry<ApiType>;
activeRecoveries: StorageEntryExact<ApiType, (key1: AccountId | Uint8Array | string, key2: AccountId | Uint8Array | string) => Observable<Option<ActiveRecovery>>> & QueryableStorageEntry<ApiType>;
recovered: StorageEntryExact<ApiType, (arg: AccountId | Uint8Array | string) => Observable<Option<AccountId>>> & QueryableStorageEntry<ApiType>;
};
}
}
+45 -44
View File
@@ -3,15 +3,15 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, Address, Call, ExtrinsicEra, ExtrinsicStatus, Hash, Header, Index, RuntimeDispatchInfo } from '@polkadot/types/interfaces';
import { Address, Call, ExtrinsicEra, ExtrinsicStatus, Hash, Header, Index, RuntimeDispatchInfo } from '@polkadot/types/interfaces';
import { Callback, Codec, Constructor, IKeyringPair, Registry, SignatureOptions } from '@polkadot/types/types';
import { ApiInterfaceRx, ApiTypes, SignerResult } from '../types';
import { SignerOptions, SubmittableExtrinsic, SubmittablePaymentResult, SubmittableResultImpl, SubmittableResultResult, SubmittableResultSubscription, SubmittableThis } from './types';
import { AddressOrPair, SignerOptions, SubmittableExtrinsic, SubmittablePaymentResult, SubmittableResultImpl, SubmittableResultResult, SubmittableResultSubscription, SubmittableThis } from './types';
import { Observable, combineLatest, from, of } from 'rxjs';
import { Observable, combineLatest, of } from 'rxjs';
import { first, map, mapTo, mergeMap, switchMap, tap } from 'rxjs/operators';
import { createType, ClassOf } from '@polkadot/types';
import { isBn, isFunction, isNumber, isUndefined } from '@polkadot/util';
import { assert, isBn, isFunction, isNumber, isUndefined } from '@polkadot/util';
import { filterEvents, isKeyringPair } from '../util';
import ApiBase from '../base';
@@ -50,7 +50,7 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
}
// calculate the payment info for this transaction (if signed and submitted)
public paymentInfo (account: IKeyringPair | string | AccountId | Address, options?: Partial<SignerOptions>): SubmittablePaymentResult<ApiType> {
public paymentInfo (account: AddressOrPair, options?: Partial<SignerOptions>): SubmittablePaymentResult<ApiType> {
const [allOptions] = this._makeSignAndSendOptions(options);
const address = isKeyringPair(account) ? account.address : account.toString();
@@ -82,54 +82,35 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
// signs a transaction, returning `this` to allow chaining. E.g.: `sign(...).send()`
//
// also supports signing through external signers
public signAsync (account: IKeyringPair, optionsOrNonce: Partial<SignerOptions>): SubmittableThis<ApiType, this> {
public signAsync (account: AddressOrPair, optionsOrNonce: Partial<SignerOptions>): SubmittableThis<ApiType, this> {
return this._decorateMethod(
(): Observable<this> => {
const optionsWithNonce = this._optionsOrNonce(optionsOrNonce);
return from(
this._api.signer
? this._signViaSigner(account.address, this._makeSignOptions(optionsWithNonce, {}), null)
: Promise.resolve(this.sign(account, optionsWithNonce))
).pipe(mapTo(this));
}
(): Observable<this> =>
this._signObservable(account, optionsOrNonce).pipe(mapTo(this))
)();
}
// signAndSend with an immediate Hash result
public signAndSend (account: IKeyringPair | string | AccountId | Address, options?: Partial<SignerOptions>): SubmittableResultResult<ApiType>;
public signAndSend (account: AddressOrPair, options?: Partial<SignerOptions>): SubmittableResultResult<ApiType>;
// signAndSend with a subscription, i.e. callback provided
public signAndSend (account: IKeyringPair | string | AccountId | Address, statusCb: Callback<SubmittableResultImpl>): SubmittableResultSubscription<ApiType>;
public signAndSend (account: AddressOrPair, statusCb: Callback<SubmittableResultImpl>): SubmittableResultSubscription<ApiType>;
// signAndSend with options and a callback
public signAndSend (account: IKeyringPair | string | AccountId | Address, options: Partial<SignerOptions>, statusCb?: Callback<SubmittableResultImpl>): SubmittableResultSubscription<ApiType>;
public signAndSend (account: AddressOrPair, options: Partial<SignerOptions>, statusCb?: Callback<SubmittableResultImpl>): SubmittableResultSubscription<ApiType>;
// signAndSend implementation for all 3 cases above
public signAndSend (account: IKeyringPair | string | AccountId | Address, optionsOrStatus?: Partial<SignerOptions> | Callback<SubmittableResultImpl>, optionalStatusCb?: Callback<SubmittableResultImpl>): SubmittableResultResult<ApiType> | SubmittableResultSubscription<ApiType> {
public signAndSend (account: AddressOrPair, optionsOrStatus?: Partial<SignerOptions> | Callback<SubmittableResultImpl>, optionalStatusCb?: Callback<SubmittableResultImpl>): SubmittableResultResult<ApiType> | SubmittableResultSubscription<ApiType> {
const [options, statusCb] = this._makeSignAndSendOptions(optionsOrStatus, optionalStatusCb);
const isSubscription = this._api.hasSubscriptions && (this._ignoreStatusCb || !!statusCb);
const address = isKeyringPair(account) ? account.address : account.toString();
let updateId: number | undefined;
return this._decorateMethod(
(): Observable<Codec> => (
this._getPrelimState(address, options).pipe(
first(),
mergeMap(async ([nonce, header]): Promise<void> => {
const eraOptions = this._makeEraOptions(options, { header, nonce });
if (isKeyringPair(account)) {
this.sign(account, eraOptions);
} else {
updateId = await this._signViaSigner(address, eraOptions, header);
}
}),
switchMap((): Observable<SubmittableResultImpl> | Observable<Hash> => {
return isSubscription
this._signObservable(account, options).pipe(
switchMap((updateId: number | undefined): Observable<SubmittableResultImpl> | Observable<Hash> =>
isSubscription
? this._subscribeObservable(updateId)
: this._sendObservable(updateId);
})
: this._sendObservable(updateId)
)
) as Observable<Codec>) // FIXME This is wrong, SubmittableResult is _not_ a codec
)(statusCb);
}
@@ -163,10 +144,30 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
return [options, statusCb];
}
private async _signViaSigner (address: string, options: SignatureOptions, header: Header | null): Promise<number> {
if (!this._api.signer) {
throw new Error('no signer attached');
}
private _signObservable (account: AddressOrPair, optionsOrNonce: Partial<SignerOptions>): Observable<number | undefined> {
const address = isKeyringPair(account) ? account.address : account.toString();
const options = this._optionsOrNonce(optionsOrNonce);
let updateId: number | undefined;
return this._getPrelimState(address, options).pipe(
first(),
mergeMap(async ([nonce, header]): Promise<void> => {
const eraOptions = this._makeEraOptions(options, { header, nonce });
if (isKeyringPair(account)) {
this.sign(account, eraOptions);
} else {
updateId = await this._signViaSigner(address, eraOptions, header);
}
}),
mapTo(updateId)
);
}
private async _signViaSigner (address: Address | string | Uint8Array, options: SignatureOptions, header: Header | null): Promise<number> {
const signer = options.signer || this._api.signer;
assert(signer, 'No signer specified, either via api.setSigner or via sign options');
const payload = createType(this.registry, 'SignerPayload', {
...options,
@@ -176,10 +177,10 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
});
let result: SignerResult;
if (this._api.signer.signPayload) {
result = await this._api.signer.signPayload(payload.toPayload());
} else if (this._api.signer.signRaw) {
result = await this._api.signer.signRaw(payload.toRaw());
if (signer.signPayload) {
result = await signer.signPayload(payload.toPayload());
} else if (signer.signRaw) {
result = await signer.signRaw(payload.toRaw());
} else {
throw new Error('Invalid signer interface, it should implement either signPayload or signRaw (or both)');
}
+9 -6
View File
@@ -4,7 +4,7 @@
import { AccountId, Address, ExtrinsicStatus, EventRecord, Hash, RuntimeDispatchInfo } from '@polkadot/types/interfaces';
import { AnyNumber, AnyU8a, Callback, IExtrinsic, IExtrinsicEra, IKeyringPair, SignatureOptions } from '@polkadot/types/types';
import { ApiTypes } from '../types';
import { ApiTypes, Signer } from '../types';
import { Observable } from 'rxjs';
@@ -48,11 +48,14 @@ export interface SignerOptions {
blockHash: AnyU8a;
era?: IExtrinsicEra | number;
nonce: AnyNumber;
signer?: Signer;
tip?: AnyNumber;
}
export type AddressOrPair = IKeyringPair | string | AccountId | Address;
export interface SubmittableExtrinsic<ApiType extends ApiTypes> extends IExtrinsic {
paymentInfo (account: IKeyringPair | string | AccountId | Address, options?: Partial<SignerOptions>): SubmittablePaymentResult<ApiType>;
paymentInfo (account: AddressOrPair, options?: Partial<SignerOptions>): SubmittablePaymentResult<ApiType>;
send(): SubmittableResultResult<ApiType>;
@@ -60,11 +63,11 @@ export interface SubmittableExtrinsic<ApiType extends ApiTypes> extends IExtrins
sign(account: IKeyringPair, _options: Partial<SignatureOptions>): this;
signAsync(account: IKeyringPair, _options: Partial<SignatureOptions>): SubmittableThis<ApiType, this>;
signAsync(account: AddressOrPair, _options: Partial<SignatureOptions>): SubmittableThis<ApiType, this>;
signAndSend(account: IKeyringPair | string | AccountId | Address, options?: Partial<SignerOptions>): SubmittableResultResult<ApiType>;
signAndSend(account: AddressOrPair, options?: Partial<SignerOptions>): SubmittableResultResult<ApiType>;
signAndSend(account: IKeyringPair | string | AccountId | Address, statusCb: Callback<SubmittableResultImpl>): SubmittableResultSubscription<ApiType>;
signAndSend(account: AddressOrPair, statusCb: Callback<SubmittableResultImpl>): SubmittableResultSubscription<ApiType>;
signAndSend(account: IKeyringPair | string | AccountId | Address, options: Partial<SignerOptions>, statusCb?: Callback<SubmittableResultImpl>): SubmittableResultSubscription<ApiType>;
signAndSend(account: AddressOrPair, options: Partial<SignerOptions>, statusCb?: Callback<SubmittableResultImpl>): SubmittableResultSubscription<ApiType>;
}
@@ -1,169 +0,0 @@
// Copyright 2017-2020 @polkadot/api-derive 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 ApiPromise from '@polkadot/api/promise/Api';
import testingPairs from '@polkadot/keyring/testingPairs';
import { WsProvider } from '@polkadot/rpc-provider';
import { SubmittableResult } from '@polkadot/api';
import { DerivedBalances, DerivedStakingAccount } from '@polkadot/api-derive/types';
import { describeE2E } from '../../util';
const ALICE_STASH = testingPairs().alice_stash.address;
describeE2E({
except: [
'remote-polkadot-alexander',
'remote-substrate-1.0'
]
})('Derive Promise e2e development', (wsUrl: string): void => {
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
it('retrieves the balances', (done): Promise<() => void> => {
return api.derive.balances.all('5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y', (balance: DerivedBalances): void => {
console.error(JSON.stringify(balance));
if (balance.freeBalance.gtn(1)) {
done();
}
});
});
it('retrieves balances for a problematic account', (done): Promise<() => void> => {
return api.derive.balances.all('5F7BJL6Z4m8RLtK7nXEqqpEqhBbd535Z3CZeYF6ccvaQAY6N', (balance: DerivedBalances): void => {
console.error(JSON.stringify(balance));
if (balance.availableBalance.eqn(0)) {
done();
}
});
});
describe('staking', (): void => {
it('retrieves all staking info (for controller)', (done): Promise<() => void> => {
const accountId = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
return api.derive.staking.account(accountId, (info: DerivedStakingAccount): void => {
console.error(JSON.stringify(info));
expect(info.accountId.eq(accountId)).toBe(true);
expect(info.controllerId!.eq(accountId)).toBe(true);
expect(info.stashId!.eq('5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY')).toBe(true);
expect(info.stashId!.eq(info.stakingLedger!.stash)).toBe(true);
done();
});
});
it('retrieves all staking info (for stash)', (done): Promise<() => void> => {
const accountId = '5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY';
return api.derive.staking.account(accountId, (info: DerivedStakingAccount): void => {
console.error(JSON.stringify(info));
if (!info.stashId || !info.controllerId || !info.stakingLedger) {
done.fail(new Error('At least one of info.stashId, info.controllerId or info.stakingLedger is undefined.'));
return;
}
expect(info.accountId.eq(accountId)).toBe(true);
expect(info.controllerId.eq('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY')).toBe(true);
expect(info.stashId.eq(accountId)).toBe(true);
expect(info.stashId.eq(info.stakingLedger.stash)).toBe(true);
done();
});
});
describe('verifies derive.staking.unlocking', (): void => {
const UNBOND_VALUE = 1;
const alicePair = testingPairs().alice;
it('unbonds dots for Alice (from Alice Stash)', (done): Promise<() => void> => {
return api.tx.staking.unbond(UNBOND_VALUE)
.signAndSend(alicePair, (result: SubmittableResult): void => {
if (result.status.isFinalized) {
done();
}
});
});
it('verifies that derive.staking.unlocking isn\'t empty/undefined', (): Promise<() => void> => {
return api.derive.staking.account(ALICE_STASH, (info: DerivedStakingAccount): void => {
expect(info.unlocking).toBeDefined();
});
});
});
describe('verifies derive.staking.rewardDestination', (): void => {
const PAYEE = 2;
const alicePair = testingPairs().alice;
it('Set payee for ALICE to 2', (done): Promise<() => void> => {
return api.tx.staking
.setPayee(PAYEE)
.signAndSend(alicePair, (result: SubmittableResult): void => {
if (result.status.isFinalized) {
done();
}
});
});
it('verifies payee for ALICE_STASH', (done): Promise<() => void> => {
return api.derive.staking.account(ALICE_STASH, (info: DerivedStakingAccount): void => {
if (!info.rewardDestination) {
return done.fail(new Error('rewardDestination is undefined.'));
} else {
expect(info.rewardDestination.toString()).toBe('Controller');
}
done();
});
});
it('staking.account updates itself after changing reward destination', async (done): Promise<void> => {
const stashId = testingPairs().alice_stash.address;
// start by setting the reqred to Staked, so we have a common starting point
await api.tx.staking
.setPayee('Staked')
.signAndSend(testingPairs().alice, ({ status }): void => {
if (status.isFinalized) {
console.error('setPayee(Staked) isFinalized');
}
});
let count = 0; // The # of times we got a callback response from api.derive.staking.account
// Subscribe to staking.account
api.derive.staking.account(stashId, (result): void => {
++count;
console.error('***', count, JSON.stringify(result));
if (count >= 2 && result.rewardDestination!.toString() === 'Stash') {
done();
}
});
// Wait a bit, and change reward destination
// eslint-disable-next-line @typescript-eslint/no-misused-promises
setTimeout(async (): Promise<void> => {
await api.tx.staking
.setPayee('Stash')
.signAndSend(testingPairs().alice, ({ status }): void => {
if (status.isFinalized) {
console.error('setPayee(Stash) isFinalized');
}
});
}, 5000);
});
});
});
});
@@ -1,71 +0,0 @@
// Copyright 2017-2020 @polkadot/api-derive 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 ApiPromise from '@polkadot/api/promise/Api';
import { WsProvider } from '@polkadot/rpc-provider';
import { HeaderExtended } from '@polkadot/api-derive/type';
import { DerivedElectionsInfo, DerivedFees, DerivedSessionInfo } from '@polkadot/api-derive/types';
import { describeE2E } from '../../util';
describeE2E()('Derive Promise e2e', (wsUrl: string): void => {
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
it('Get the latest block number', async (): Promise<void> => {
// https://github.com/polkadot-js/api/issues/777
const block1 = await api.derive.chain.bestNumber();
await new Promise((resolve): void => {
setTimeout(resolve, 10000);
});
const block2 = await api.derive.chain.bestNumber();
expect(block1.eq(block2)).toBe(false);
});
it('subscribes to newHead, retrieving the actual validator', (done): Promise<() => void> => {
return api.derive.chain.subscribeNewHeads(({ author }: HeaderExtended): void => {
console.log('author', author && author.toString());
if (author) {
done();
}
});
});
it('retrieves the fees (api.queryMulti)', (done): Promise<() => void> => {
return api.derive.balances.fees((fees: DerivedFees): void => {
console.error('fees', JSON.stringify(fees));
done();
});
});
it('retrieves elections info', (done): Promise<() => void> => {
return api.derive.elections.info((info: DerivedElectionsInfo): void => {
console.error('fees', JSON.stringify(info));
done();
});
});
it('retrieves all session info', (done): Promise<() => void> => {
let count = 0;
return api.derive.session.info((info: DerivedSessionInfo): void => {
console.error(JSON.stringify(info));
// 5 blocks only, then go our merry way
if (++count === 5) {
done();
}
});
});
});
-302
View File
@@ -1,302 +0,0 @@
// Copyright 2017-2020 @polkadot/api-derive 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 { BlockNumber } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import ApiRx from '@polkadot/api/rx/Api';
import { HeaderExtended } from '@polkadot/api-derive';
import { DerivedBalances, DerivedContractFees, DerivedElectionsInfo, DerivedFees, DerivedSessionInfo } from '@polkadot/api-derive/types';
import { createType, ClassOf, TypeRegistry } from '@polkadot/types';
import { WsProvider } from '@polkadot/rpc-provider';
import { describeE2E } from '../../util';
// Dev account Alice
const ID = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const IX = 'F7Hs';
describeE2E({
except: [
'remote-polkadot-alexander',
'remote-substrate-1.0'
]
})('Api-RX derive e2e', (wsUrl: string): void => {
const registry = new TypeRegistry();
let api: ApiRx;
beforeAll((): void => {
jest.setTimeout(10000);
});
beforeEach(async (done): Promise<void> => {
api = await ApiRx.create({ provider: new WsProvider(wsUrl) }).toPromise();
done();
});
afterAll((): void => {
jest.setTimeout(10000);
});
// These derive.accounts tests only work on localhost, not the poc-3 URL
// (and it is assuming it sent at least 1 tx)
describe('derive.accounts', (): void => {
describe('idAndIndex', (): void => {
it('looks up AccountId & AccountIndex from AccountId', (done): void => {
api.derive.accounts.idAndIndex(ID).subscribe(([accountId, accountIndex]): void => {
expect(accountId!.toString()).toEqual(ID);
// The first emitted value for ix is undefined when passing the ID
if (accountIndex) {
expect(accountIndex.toString()).toEqual(IX);
} else {
expect(accountIndex).toEqual(undefined);
}
done();
});
});
it('looks up AccountId & AccountIndex from AccountIndex', (done): void => {
api.derive.accounts.idAndIndex(IX).subscribe(([accountId, accountIndex]): void => {
// The first emitted value for id is undefined when passing the IX
if (accountId) {
expect(accountId.toString()).toEqual(ID);
} else {
expect(accountId).toEqual(undefined);
}
expect(accountIndex!.toString()).toEqual(IX);
done();
});
});
});
describe('indexToId', (): void => {
it('looks up AccountId from AccountIndex', (done): void => {
api.derive.accounts.indexToId(IX).subscribe((accountId): void => {
// The first emitted value for accountId is undefined when passing the IX
if (accountId) {
expect(accountId instanceof ClassOf(registry, 'AccountId')).toBe(true);
expect(accountId.toString()).toEqual(ID);
} else {
expect(accountId).toEqual(undefined);
}
done();
});
});
});
describe('idToIndex', (): void => {
it('looks up AccountIndex from AccountId', (done): void => {
api.derive.accounts.idToIndex(ID).subscribe((accountIndex): void => {
// The first emitted value for AccountIndex is undefined when passing the ID
if (accountIndex) {
expect(accountIndex instanceof ClassOf(registry, 'AccountIndex')).toBe(true);
expect(accountIndex.toString()).toEqual(IX);
} else {
expect(accountIndex).toEqual(undefined);
}
done();
});
});
});
describe('indexes', (): void => {
it('looks up all AccountIndexes', (done): void => {
api.derive.accounts.indexes().subscribe((accountIndexes): void => {
// A local dev chain should have the AccountIndex of Alice
expect(accountIndexes).toHaveProperty(
ID,
createType(registry, 'AccountIndex', IX)
);
done();
});
});
});
});
// these only work on localhost, not the poc-3 URL
// (and it is assuming it sent at least 1 tx)
describe('derive.balances', (): void => {
describe('all', (): void => {
it('It returns an object with all relevant balance information of an account', (done): void => {
api.derive.balances.all(ID).subscribe((balances: DerivedBalances): void => {
expect(balances).toEqual(expect.objectContaining({
accountId: expect.any(ClassOf(registry, 'AccountId')),
accountNonce: expect.any(ClassOf(registry, 'Index')),
availableBalance: expect.any(BN),
freeBalance: expect.any(BN),
lockedBalance: expect.any(BN),
reservedBalance: expect.any(BN),
vestedBalance: expect.any(BN),
votingBalance: expect.any(BN)
}));
done();
});
});
});
describe('fees', (): void => {
it('fees: It returns an object with all relevant fees of type BN', (done): void => {
api.derive.balances.fees().subscribe((fees: DerivedFees): void => {
expect(fees).toEqual(expect.objectContaining({
creationFee: expect.any(BN),
existentialDeposit: expect.any(BN),
transactionBaseFee: expect.any(BN),
transactionByteFee: expect.any(BN),
transferFee: expect.any(BN)
}));
done();
});
});
});
});
describe('derive.chain', (): void => {
describe('bestNumber', (): void => {
it('Get the latest block number', (done): void => {
api.derive.chain.bestNumber().subscribe((blockNumber: BlockNumber): void => {
expect(blockNumber instanceof ClassOf(registry, 'BlockNumber')).toBe(true);
expect(blockNumber.gten(0)).toBe(true);
done();
});
});
});
describe('bestNumberFinalized', (): void => {
it('Get the latest finalised block number', (done): void => {
api.derive.chain.bestNumberFinalized().subscribe((blockNumber: BlockNumber): void => {
expect(blockNumber instanceof ClassOf(registry, 'BlockNumber')).toBe(true);
expect(blockNumber.gten(0)).toBe(true);
done();
});
});
});
describe('bestNumberLag', (): void => {
it('lag between finalised head and best head', (done): void => {
api.derive.chain.bestNumberLag().subscribe((numberLag: BlockNumber): void => {
expect(numberLag instanceof ClassOf(registry, 'BlockNumber')).toBe(true);
expect(numberLag.gten(0)).toBe(true);
done();
});
});
});
// FIXME https://github.com/polkadot-js/api/issues/868
describe('getHeader', (): void => {
it('gets a specific block header and extended with it`s author', (done): void => {
api.derive.chain.getHeader('TODO').subscribe((headerExtended: HeaderExtended | undefined): void => {
// WIP
expect(headerExtended).toEqual(expect.arrayContaining([]));
done();
});
});
});
describe('subscribeNewHeads', (): void => {
it('gets an observable of the current block header and it\'s author', (done): void => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
api.derive.chain.subscribeNewHeads().subscribe((headerExtended: HeaderExtended): void => {
// WIP https://github.com/polkadot-js/api/issues/868
done();
});
});
});
});
describe('derive.contracts', (): void => {
describe('fees', (): void => {
it('fees: It returns an object with all relevant constract fees of type Balance', (done): void => {
api.derive.contracts.fees().subscribe((fees: DerivedContractFees): void => {
expect(fees).toEqual(expect.objectContaining({
callBaseFee: expect.any(BN),
contractFee: expect.any(BN),
createBaseFee: expect.any(BN),
creationFee: expect.any(BN),
rentByteFee: expect.any(BN),
rentDepositOffset: expect.any(BN),
tombstoneDeposit: expect.any(BN),
transactionBaseFee: expect.any(BN),
transactionByteFee: expect.any(BN),
transferFee: expect.any(BN)
}));
done();
});
});
});
});
describe('derive.elections', (): void => {
describe('info', (): void => {
it('It returns an object with all relevant elections properties', (done): void => {
api.derive.elections.info().subscribe((info: DerivedElectionsInfo): void => {
expect(info).toEqual(expect.objectContaining({
members: expect.anything(),
candidates: expect.anything(),
candidateCount: expect.any(BN),
desiredSeats: expect.any(BN),
termDuration: expect.any(BN),
voteCount: expect.any(BN)
}));
done();
});
});
});
});
describe('derive.session', (): void => {
describe('sessionProgress', (): void => {
it('derive.session.sessionProgress', (done): void => {
api.derive.session.sessionProgress().subscribe((progress: BN): void => {
expect(progress instanceof BN).toBe(true);
done();
});
});
});
describe('session.info', (): void => {
it('retrieves all session info', (done): void => {
api.derive.session.info().subscribe((info: DerivedSessionInfo): void => {
expect(info).toEqual(expect.objectContaining({
currentEra: expect.anything(),
currentIndex: expect.anything(),
eraLength: expect.anything(),
eraProgress: expect.anything(),
lastEraLengthChange: expect.anything(),
lastLengthChange: expect.anything(),
sessionLength: expect.anything(),
sessionsPerEra: expect.anything(),
sessionProgress: expect.anything()
}));
done();
});
});
});
describe('session.eraLength', (): void => {
it('derive.session.eraLength', (done): void => {
api.derive.session.eraLength().subscribe((length: BN): void => {
expect(length instanceof BN).toBe(true);
done();
});
});
});
describe('session.eraProgress', (): void => {
it('derive.session.eraProgress', (done): void => {
api.derive.session.eraProgress().subscribe((progress: BN): void => {
expect(progress instanceof BN).toBe(true);
done();
});
});
});
});
describe('derive.staking', (): void => {
describe('controllers', (): void => {
// @TODO https://github.com/polkadot-js/api/issues/868
});
});
});
@@ -1,59 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 { Extrinsic, SignedBlock } from '@polkadot/types/interfaces';
import WsProvider from '@polkadot/rpc-provider/ws';
import ApiPromise from '../../../src/promise';
import { describeE2E } from '../../util';
describeE2E({
only: [] // To run these tests locally you need to run a Alexander full archive node locally
})('Promise e2e alex archive queries (local)', (wsUrl: string): void => {
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
// https://github.com/polkadot-js/api/issues/845
it('retrieves block with no issues', async (): Promise<boolean> => {
const metadata = await api.rpc.state.getMetadata('0x6f6f9bba0eed8e3ae9446c37eee763f93118b52a315a7b46090453ba6288da1f');
console.error(JSON.stringify(metadata, null, 2));
const block = await api.rpc.chain.getBlock('0x6f6f9bba0eed8e3ae9446c37eee763f93118b52a315a7b46090453ba6288da1f');
console.error(block);
expect(block).toBeDefined();
return true;
});
// https://github.com/polkadot-js/api/issues/846
it('handles toJSON with no issues', (done): Promise<() => void> => {
return api.rpc.chain.getBlock('0x85c62b581f38cb81c3e443d34392672beb1fb877017fd7237cc87704113259dc', (result: SignedBlock): void => {
const failed: Extrinsic[] = result.block.extrinsics.filter((extrinsic: Extrinsic): boolean => {
try {
const json = extrinsic.method.toJSON();
console.error(json);
return false;
} catch (error) {
console.log(extrinsic.method);
console.log(extrinsic.method.keys());
console.error(error);
return true;
}
});
expect(failed).toBeTruthy();
done();
});
});
});
@@ -1,89 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 { AccountId, EventRecord } from '@polkadot/types/interfaces';
import WsProvider from '@polkadot/rpc-provider/ws';
import { ClassOf, Option, TypeRegistry, Vec } from '@polkadot/types';
import ApiPromise from '../../../src/promise';
import { describeE2E } from '../../util';
describeE2E({
only: ['docker-polkadot-alexander', 'remote-polkadot-alexander']
})('Promise e2e alex queries', (wsUrl: string): void => {
const registry = new TypeRegistry();
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
it('retrieves the list of validators', (done): Promise<() => void> => {
return (
api.query.staking.validators((res): void => {
console.error(res);
console.log('api.query.staking.validators():', res.toJSON());
done();
})
);
});
describe('retrieves a single value', (): void => {
it('retrieves the list of stash validators', (done): Promise<() => void> => {
return (
api.query.staking.validators('5DuiZFa184E9iCwbh4WjXYvJ88NHvWJbS8SARY8Ev1YEqrri', (res): void => {
console.error(res);
console.log('api.query.staking.validators(id):', res.toJSON());
done();
})
);
});
it('Gets the hash of the last finalized header', async (done): Promise<() => void> => {
return (
api.rpc.chain.getFinalizedHead((head): void => {
expect(head instanceof ClassOf(registry, 'Hash')).toBe(true);
done();
})
);
});
it('Subscribes to the best finalized header on ALEX', async (done): Promise<() => void> => {
return (
api.rpc.chain.subscribeFinalizedHeads((head): void => {
expect(head instanceof ClassOf(registry, 'Header')).toBe(true);
done();
})
);
});
});
it('derives a list of the controllers', (done): Promise<() => void> => {
return (
api.derive.staking.controllers((res: [AccountId[], Option<AccountId>[]]): void => {
console.log('api.derive.staking.controllers:', JSON.stringify(res));
done();
})
);
});
it('makes a query at a latest block (specified)', async (): Promise<void> => {
const header = await api.rpc.chain.getHeader();
const events = await api.query.system.events.at(header.hash);
expect(events.length).not.toEqual(0);
});
it('subscribes to events', (done): Promise<() => void> => {
return api.query.system.events((events: Vec<EventRecord>): void => {
expect(events).not.toHaveLength(0);
done();
});
});
});
@@ -1,35 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 WsProvider from '@polkadot/rpc-provider/ws';
import { ClassOf, TypeRegistry } from '@polkadot/types';
import ApiPromise from '../../../src/promise';
import { describeE2E } from '../../util';
describeE2E({
only: [
'local',
'docker-polkadot-master',
'docker-substrate-master',
'docker-substrate-2.0'
]
})('Promise e2e consts', (wsUrl: string): void => {
const registry = new TypeRegistry();
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
it('democracy.cooloffPeriod parameter type', (): void => {
expect(api.consts.democracy.cooloffPeriod).toBeInstanceOf(ClassOf(registry, 'BlockNumber'));
expect(
api.consts.democracy.cooloffPeriod.eq(432000) || // Substrate
api.consts.democracy.cooloffPeriod.eq(259200) // Polkadot
).toBeTruthy();
});
});
@@ -1,117 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 { Abi } from '@polkadot/api-contract';
import testingPairs from '@polkadot/keyring/testingPairs';
import WsProvider from '@polkadot/rpc-provider/ws';
import { Address, Hash } from '@polkadot/types/interfaces';
import { ApiPromise, SubmittableResult } from '../../../src';
import { describeE2E } from '../../util';
// Backwards compatibility:
// A breaking change was introduced by substrate runtime spec version 97. https://github.com/paritytech/substrate/pull/2911/files
// The change had to be implemented in ink! which changed the structure of the Wasm files.
// The Polkadot JS API is only supporting srml-contracts module of substrate version greater or equal spec_version 97.
import incrementerAbi from '../../../../api-contract/test/contracts/Incrementer.json'; // eslint-disable-line
const incrementerCode = fs.readFileSync(path.join(__dirname, '../../../../api-contract/test/contracts/incrementer-pruned.wasm')).toString('hex'); // eslint-disable-line
describeE2E({
except: [
'docker-polkadot-master',
'docker-polkadot-alexander',
'docker-substrate-1.0',
'remote-polkadot-alexander',
'remote-substrate-1.0'
]
})('Promise e2e contracts', (wsUrl: string): void => {
let address: Address;
let codeHash: Hash;
const keyring = testingPairs({ type: 'sr25519' });
let api: ApiPromise;
let CREATION_FEE: number;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
CREATION_FEE = 123456789123456;
done();
});
describe('incrementer', (): void => {
const MAX_GAS = 50000;
let abi: Abi;
beforeEach((): void => {
abi = new Abi(api.registry, incrementerAbi);
});
it('allows putCode', (done): Promise<() => void> => {
return (
api.tx.contracts
.putCode(MAX_GAS, `0x${incrementerCode}`)
.signAndSend(keyring.eve, (result: SubmittableResult): void => {
if (result.status.isFinalized) {
const record = result.findRecord('contracts', 'CodeStored');
if (record) {
codeHash = record.event.data[0] as Hash;
done();
}
}
})
);
});
it('Verifies that codeHash is defined', (): void => {
expect(codeHash).toBeDefined();
});
it('allows contract create', (done): Promise<() => void> => {
// An instance of a contract can only be deployed once by one specific account.
// That's why we need a random starting point for our incrementer contract to be
// able to run this test multiple times without the need of pruning the database
const randomStart = Math.floor(Date.now() / 1000);
return (
api.tx.contracts
.create(CREATION_FEE, MAX_GAS, codeHash, abi.constructors[0](randomStart))
.signAndSend(keyring.dave, (result: SubmittableResult): void => {
// console.error('create', JSON.stringify(result));
if (result.status.isFinalized) {
const record = result.findRecord('contracts', 'Instantiated');
if (record) {
address = record.event.data[1] as Address;
done();
}
}
})
);
});
it('Verifies that the contract address is defined', (): void => {
expect(address).toBeDefined();
});
it('allows contract call', (done): Promise<() => void> => {
return (
api.tx.contracts
.call(address, CREATION_FEE, MAX_GAS, abi.messages.inc(3))
.signAndSend(keyring.bob, (result: SubmittableResult): void => {
console.error('call', JSON.stringify(result));
if (result.status.isFinalized && result.findRecord('system', 'ExtrinsicSuccess')) {
done();
}
})
);
});
});
});
@@ -1,25 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 WsProvider from '@polkadot/rpc-provider/ws';
import ApiPromise from '../../../src/promise';
import { describeE2E } from '../../util';
describeE2E({
only: ['remote-polkadot-kusama']
})('Promise e2e kusama queries', (wsUrl: string): void => {
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
it('retrieves the list of validators', async (): Promise<void> => {
const intentions = await api.query.staking.validators();
console.error(JSON.parse(JSON.stringify(intentions)));
});
});
@@ -1,208 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 { Balance, Index } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import { DerivedBalances } from '@polkadot/api-derive/types';
import testingPairs from '@polkadot/keyring/testingPairs';
import WsProvider from '@polkadot/rpc-provider/ws';
import { Option, u32, createType, TypeRegistry } from '@polkadot/types';
import ApiPromise from '../../../src/promise';
import { describeE2E } from '../../util';
const ZERO = new BN(0);
// The following tests require a development node with the default funded testing accounts
describeE2E({
except: [
'remote-polkadot-alexander',
'remote-substrate-1.0'
]
})('Promise e2e development queries', (wsUrl: string): void => {
const registry = new TypeRegistry();
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
const keyring = testingPairs({ type: 'ed25519' });
it('allows retrieval of an fallback entry (once-off query)', async (): Promise<void> => {
const nonce = await api.query.system.accountNonce('5DSo5RVtfrtgHoz2c7jK7Tca7FgJgpCzFnxoRVDeYUQcKPng');
expect(nonce.toHex()).toEqual('0x0000000000000000');
});
it('allows retrieval of fallback when at query is made', async (): Promise<void> => {
const header = await api.rpc.chain.getHeader();
const nonce = await api.query.system.accountNonce.at(header.hash, '5DSo5RVtfrtgHoz2c7jK7Tca7FgJgpCzFnxoRVDeYUQcKPng');
expect(nonce.toHex()).toEqual('0x0000000000000000');
});
it('queries state for a balance', async (): Promise<() => void> => {
return api.query.balances.freeBalance(keyring.alice_stash.address, (balance: Balance): void => {
expect(balance).toBeInstanceOf(BN);
expect(balance.isZero()).toBe(false);
});
});
it('subscribes to queries', (done): Promise<() => void> => {
return (
api.query.system.accountNonce(keyring.ferdie.address, (nonce: Index): void => {
expect(nonce instanceof BN).toBe(true);
done();
})
);
});
it('subscribes to queries (default)', (done): Promise<() => void> => {
return (
api.query.staking.minimumValidatorCount((defaultCount: u32): void => {
expect(defaultCount.toNumber()).toBe(1);
done();
})
);
});
it('subscribes to multiple results (freeBalance.multi)', (done): Promise<() => void> => {
return (
api.query.balances.freeBalance.multi([
keyring.alice.address,
keyring.bob.address,
'5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y',
keyring.ferdie.address
], (balances): void => {
expect(balances).toHaveLength(4);
done();
})
);
});
it('subscribes to multiple results (api.queryMulti)', (done): Promise<() => void> => {
return api.queryMulti([
[api.query.balances.freeBalance, keyring.alice.address],
[api.query.balances.freeBalance, keyring.bob.address],
[api.query.balances.freeBalance, '5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y'],
[api.query.balances.freeBalance, keyring.ferdie.address]
], (balances: Balance[]): void => {
expect(balances).toHaveLength(4);
done();
});
});
it('subscribes to derived balances (balances.all)', (done): Promise<() => void> => {
return (
api.derive.balances.all(
keyring.bob_stash.address,
(all: DerivedBalances): void => {
expect(all.accountId.toString()).toEqual(keyring.bob_stash.address);
expect(all.freeBalance).toBeDefined();
expect(all.freeBalance.gt(ZERO)).toBe(true);
expect(all.availableBalance).toBeDefined();
expect(all.availableBalance.gt(ZERO)).toBe(true);
expect(all.reservedBalance).toBeDefined();
expect(all.lockedBalance).toBeDefined();
expect(all.vestedBalance).toBeDefined();
done();
}
)
);
});
describe('with map type', (): void => {
it('queries correct value', async (): Promise<void> => {
const balance = await api.query.balances.freeBalance(keyring.bob_stash.address);
expect(balance.isZero()).toBe(false);
});
it('queries correct value at a specified block', async (): Promise<void> => {
// assume the account Alice is only used in test(the balance of Alice does not change in this test case)
const balance = await api.query.balances.freeBalance(keyring.alice_stash.address);
const header = await api.rpc.chain.getHeader();
const balanceAt = await api.query.balances.freeBalance.at(header.hash, keyring.alice_stash.address);
expect(balanceAt.isZero()).toBe(false);
expect(balanceAt.toString()).toEqual(balance.toString());
});
it('subscribes to query and get correct result', async (done): Promise<() => void> => {
// assume the account Alice is only used in test(the balance of Alice does not change in this test case)
const balance = await api.query.balances.freeBalance(keyring.alice_stash.address);
return api.query.balances.freeBalance(keyring.alice_stash.address, (balanceSubscribed: Balance): void => {
expect(balanceSubscribed.isZero()).toBe(false);
expect(balanceSubscribed.toString()).toEqual(balance.toString());
done();
});
});
it('queries correct hash', async (): Promise<void> => {
const hash = await api.query.balances.freeBalance.hash(keyring.alice.address);
expect(hash).toBeDefined();
});
it('gets correct key', async (): Promise<void> => {
// assume the account Alice is only used in test(the balance of Alice does not change in this test case)
const key = api.query.balances.freeBalance.key(keyring.alice_stash.address);
const balanceData = await api.rpc.state.getStorage(key) as Option<any>;
const balanceRPC = createType(registry, 'Balance', balanceData.unwrapOr(undefined));
const balance = await api.query.balances.freeBalance(keyring.alice_stash.address);
expect(balanceRPC.isZero()).toBe(false);
expect(balanceRPC.toString()).toEqual(balance.toString());
});
it('queries multiple results', async (): Promise<void> => {
// assume the account Alice and Bob are only used in test(the balance of them do not change in this test case)
const balanceAlice = await api.query.balances.freeBalance(keyring.alice.address);
const balanceBob = await api.query.balances.freeBalance(keyring.bob.address);
const balances = await api.query.balances.freeBalance.multi([
keyring.alice.address,
keyring.bob.address
]);
expect(balances).toHaveLength(2);
expect((balances as any)[0].toString()).toEqual(balanceAlice.toString());
expect((balances as any)[1].toString()).toEqual(balanceBob.toString());
});
it('subscribes to multiple queries and get correct results', async (done): Promise<() => void> => {
// assume the account Alice and Bob are only used in test(the balance of them do not change in this test case)
const balanceAlice = await api.query.balances.freeBalance(keyring.alice.address);
const balanceBob = await api.query.balances.freeBalance(keyring.bob.address);
return api.query.balances.freeBalance.multi([
keyring.alice.address,
keyring.bob.address
], (balances): void => {
expect(balances).toHaveLength(2);
expect(balances[0].toString()).toEqual(balanceAlice.toString());
expect(balances[1].toString()).toEqual(balanceBob.toString());
done();
});
});
it('queries correct size', async (): Promise<void> => {
const size = await api.query.balances.freeBalance.size(keyring.alice_stash.address);
expect(size.toNumber()).not.toEqual(0);
});
});
});
@@ -1,149 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 { Keys } from '@polkadot/types/interfaces';
import testingPairs from '@polkadot/keyring/testingPairs';
import WsProvider from '@polkadot/rpc-provider/ws';
import { Option } from '@polkadot/types';
import { encodeAddress, randomAsU8a } from '@polkadot/util-crypto';
import ApiPromise from '../../../src/promise';
import { describeE2E } from '../../util';
// The following tests only run on nodes that support doubleMapType introduced by metadata v5
describeE2E({
only: [
'local',
'docker-polkadot-master',
'docker-substrate-master',
'docker-substrate-2.0'
]
})('Promise e2e doubleMap queries (since Metadata v5)', (wsUrl: string): void => {
let api: ApiPromise;
const keyring = testingPairs({ type: 'ed25519' });
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
// TODO Update ['any', '0x1234'] to the key of a known event topic and update EXPECTED_VALUE to the expected value
describe('with double map type', (): void => {
const KEY1 = 'any';
const KEY2 = '0x1234';
it('queries correct value', async (): Promise<void> => {
const eventTopics = await api.query.system.eventTopics(KEY1, KEY2);
expect(eventTopics.toJSON()).toEqual([]);
});
it('queries correct value at a specified block', async (): Promise<void> => {
const header = await api.rpc.chain.getHeader();
// TODO check & fix: this will throw the error: Encoding for input doesn't match output, created 0x00 from 0x
const eventTopicsAt = await api.query.system.eventTopics.at(header.hash, KEY1, KEY2);
expect(eventTopicsAt.toJSON()).toEqual([]);
// const eventTopicsAt = await api.query.system.eventTopics.at(header.hash, KEY1, KEY2);
// expect(eventTopicsAt.toJSON()).toEqual([]);
});
it('subscribes to query and get correct result', async (done): Promise<() => void> => {
return api.query.system.eventTopics(KEY1, KEY2, (eventTopicsAt): void => {
expect(eventTopicsAt.toJSON()).toEqual([]);
done();
});
});
it('queries correct hash', async (): Promise<void> => {
const hash = await api.query.system.eventTopics(KEY1, KEY2);
expect(hash).toBeDefined();
});
it('gets correct key', async (): Promise<void> => {
const key = api.query.system.eventTopics.key(KEY1, KEY2);
const eventTopicsData = await api.rpc.state.getStorage(key) as Option<any>;
expect(eventTopicsData.unwrapOr(undefined)).toEqual(undefined);
});
it('queries multiple results', async (): Promise<void> => {
const eventTopicsList = await api.query.system.eventTopics.multi([
[KEY1, KEY2]
]);
expect(eventTopicsList).toHaveLength(1);
expect((eventTopicsList as any)[0].toJSON()).toEqual([]);
});
it('subscribes to multiple queries and get correct results', async (done): Promise<() => void> => {
return api.query.system.eventTopics.multi([
[KEY1, KEY2]
], (eventTopicsList): void => {
expect(eventTopicsList).toHaveLength(1);
expect(eventTopicsList[0].toJSON()).toEqual([]);
done();
});
});
it('queries correct size', async (): Promise<void> => {
const size = await api.query.system.eventTopics.size(KEY1, KEY2);
expect(size.toNumber()).toEqual(0);
});
});
describe('session Keys', (): void => {
it('sets a session key, retrieves the value', (done): void => {
const babe = encodeAddress(randomAsU8a());
const grandpa = encodeAddress(randomAsU8a());
const imOnline = encodeAddress(randomAsU8a());
async function queryKeys (): Promise<void> {
console.error('*** query.session.nextKeys');
const result = JSON.stringify(
(await api.query.session.nextKeys<Keys>(
api.consts.session.dedupKeyPrefix,
keyring.bob.address
))
);
console.error(result, [grandpa, babe, imOnline]);
expect(result).toEqual(JSON.stringify([grandpa, babe, imOnline]));
done();
}
async function setKeys (): Promise<void> {
console.error('*** tx.session.setKeys');
await api.tx.session
.setKeys({ babe, grandpa, imOnline }, new Uint8Array([]))
.signAndSend(keyring.eve, (result): void => {
if (result.isCompleted) {
queryKeys();
}
});
}
async function setBond (): Promise<void> {
console.error('*** tx.staking.bond');
await api.tx.staking
.bond(keyring.eve.address, 123456789012345, 'Stash')
.signAndSend(keyring.bob, (result): void => {
if (result.isCompleted) {
setKeys();
}
});
}
setBond();
});
});
});
@@ -1,143 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 { EventRecord, Hash, Header, SessionIndex } from '@polkadot/types/interfaces';
import { HeaderExtended } from '@polkadot/api-derive';
import WsProvider from '@polkadot/rpc-provider/ws';
import { LinkageResult } from '@polkadot/types/codec/Linkage';
import { Option } from '@polkadot/types';
import ApiPromise from '../../../src/promise';
import { describeE2E } from '../../util';
describeE2E()('Promise e2e queries', (wsUrl: string): void => {
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
it('makes the runtime, rpc, state & extrinsics available', (): void => {
expect(api.genesisHash).toBeDefined();
expect(api.runtimeMetadata).toBeDefined();
expect(api.runtimeVersion).toBeDefined();
expect(api.rpc).toBeDefined();
expect(api.query).toBeDefined();
expect(api.tx).toBeDefined();
expect(api.derive).toBeDefined();
});
it('subscribes to rpc', (done): Promise<() => void> => {
return (
api.rpc.chain.subscribeNewHeads((header: Header): void => {
expect(header.number.isEmpty).toBe(false);
done();
})
);
});
it('subscribes to finalized', (done): Promise<() => void> => {
return (
api.rpc.chain.subscribeFinalizedHeads((header: Header): void => {
expect(header.number.isEmpty).toBe(false);
done();
})
);
});
it('subscribes to derive', (done): Promise<() => void> => {
return (
api.derive.chain.subscribeNewHeads((header: HeaderExtended): void => {
expect(header.number.isEmpty).toBe(false);
done();
})
);
});
it('subscribes to a linked map (staking.validators)', (done): Promise<() => void> => {
return (
api.query.staking.validators((prefs: LinkageResult): void => {
expect(prefs instanceof LinkageResult).toBe(true);
done();
})
);
});
it('can retrive header by hash', async (): Promise<void> => {
const latest = await api.rpc.chain.getHeader();
const specific = await api.rpc.chain.getHeader(latest.hash);
expect(latest.hash).toEqual(specific.hash);
});
it('makes a query at a latest block (specified)', async (): Promise<void> => {
const header = await api.rpc.chain.getHeader();
const events = await api.query.system.events.at(header.hash);
expect(events.length).not.toEqual(0);
events.forEach(({ event: { data, method, section }, phase, topics }: EventRecord): void => {
console.error(phase.toString(), `: ${section}.${method}`, data.toString(), topics.toString());
});
});
it('subscribes to events', (done): Promise<() => void> => {
return (
api.query.system.events((events): void => {
expect(events).not.toHaveLength(0);
done();
})
);
});
describe('with plain type', (): void => {
it('queries a correct value', async (): Promise<void> => {
const sessionIndex = await api.query.session.currentIndex();
expect(sessionIndex.toNumber()).toBeGreaterThanOrEqual(0);
});
it('queries correct value at a specified block', async (): Promise<void> => {
const header = await api.rpc.chain.getHeader();
const sessionIndex = await api.query.session.currentIndex.at(header.hash);
expect(sessionIndex.toNumber()).toBeGreaterThanOrEqual(0);
});
it('subscribes to query and get correct result', (done): Promise<() => void> => {
return api.query.session.currentIndex((sessionIndex: SessionIndex): void => {
expect(sessionIndex.toNumber()).toBeGreaterThanOrEqual(0);
done();
});
});
it('queries correct hash', async (): Promise<void> => {
const hash: Hash = await api.query.session.currentIndex.hash();
expect(hash).toBeDefined();
});
it('gets correct key', async (): Promise<void> => {
const key = api.query.session.currentIndex.key();
const sessionIndexData = await api.rpc.state.getStorage<Option<any>>(key);
const sessionIndexRPC = api.createType('SessionIndex', sessionIndexData.unwrapOr(undefined));
expect(sessionIndexRPC.toNumber()).toBeGreaterThanOrEqual(0);
});
it('queries correct size', async (): Promise<void> => {
const size = await api.query.session.currentIndex.size();
expect(size).not.toHaveLength(0);
expect(size.toNumber()).toBeGreaterThanOrEqual(0);
});
});
});
@@ -1,44 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 Keyring from '@polkadot/keyring';
import testingPairs from '@polkadot/keyring/testingPairs';
import WsProvider from '@polkadot/rpc-provider/ws';
import ApiPromise from '../../../src/promise';
import { describeE2E, calculateAccountDeposit, logEvents } from '../../util';
describeE2E({
except: ['remote-polkadot-alexander', 'remote-substrate-1.0']
})('Promise e2e transactions', (wsUrl: string): void => {
const keyring = testingPairs({ type: 'ed25519' });
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
it('makes a transfer, and uses new balance to transfers to new', async (done): Promise<() => void> => {
const pair = new Keyring().addFromUri('testing123', {}, 'ed25519');
const amount = calculateAccountDeposit(api);
function doOne (cb: any): Promise<() => void> {
return api.tx.balances
.transfer(pair.address, amount)
.signAndSend(keyring.bob_stash, logEvents(cb));
}
async function doTwo (cb: any): Promise<() => void> {
return api.tx.balances
.transfer(keyring.bob_stash.address, 111)
.signAndSend(pair, logEvents(cb));
}
return doOne(async (): Promise<() => void> => {
return doTwo(done);
});
});
});
@@ -1,116 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 testingPairs from '@polkadot/keyring/testingPairs';
import WsProvider from '@polkadot/rpc-provider/ws';
import { Header } from '@polkadot/types/interfaces';
import { createType, TypeRegistry } from '@polkadot/types';
import ApiPromise from '../../../src/promise';
import { Signer } from '../../../src/types';
import { describeE2E, logEvents, SingleAccountSigner } from '../../util';
describeE2E({
except: [
'remote-polkadot-alexander',
'remote-substrate-1.0',
'docker-polkadot-alexander',
'docker-substrate-1.0'
]
})('Promise e2e transactions with specified eras', (wsUrl: string): void => {
const registry = new TypeRegistry();
const keyring = testingPairs({ type: 'ed25519' });
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
describe('eras', (): void => {
it('makes a transfer (specified era)', async (done): Promise<void> => {
const signedBlock = await api.rpc.chain.getBlock();
const currentHeight = signedBlock.block.header.number;
const exERA = createType(registry, 'ExtrinsicEra', { current: currentHeight, period: 4 });
const ex = api.tx.balances.transfer(keyring.eve.address, 12345);
await ex.signAndSend(keyring.charlie, {
blockHash: signedBlock.block.header.hash,
era: exERA
}, logEvents(done));
});
it('makes a transfer (specified era, previous block)', async (done): Promise<void> => {
const signedBlock = await api.rpc.chain.getBlock();
const currentHeight = signedBlock.block.header.number.toBn().subn(1);
const exERA = createType(registry, 'ExtrinsicEra', { current: currentHeight, period: 10 });
const ex = api.tx.balances.transfer(keyring.eve.address, 12345);
await ex.signAndSend(keyring.charlie, {
blockHash: signedBlock.block.header.parentHash,
era: exERA
}, logEvents(done));
});
it('fails on a transfer with invalid time', async (done): Promise<void> => {
const nonce = await api.query.system.accountNonce(keyring.alice.address);
const signedBlock = await api.rpc.chain.getBlock();
const currentHeight = signedBlock.block.header.number;
const exERA = createType(registry, 'ExtrinsicEra', { current: currentHeight, period: 4 });
const eraDeath = exERA.asMortalEra.death(currentHeight.toNumber());
const blockHash = signedBlock.block.header.hash;
const ex = api.tx.balances.transfer(keyring.eve.address, 12345);
await api.rpc.chain.subscribeNewHeads(async (header: Header): Promise<void> => {
if (header.number.toNumber() === eraDeath - 1) {
try {
await ex.signAndSend(keyring.alice, { blockHash, era: exERA, nonce } as any);
} catch (error) {
// The "invalid-era" specific error code 127 was introduced along with the transaction version 2
// For the transaction format version 1 the error code is simply 0
expect(error.message).toMatch(
/1010: Invalid Transaction \(-127\)|1010: Invalid Transaction \(0\)/
);
}
done();
}
});
});
it('fails on a transfer with invalid time (via Signer)', async (done): Promise<void> => {
const signer: Signer = new SingleAccountSigner(registry, keyring.alice);
api.setSigner(signer);
const nonce = await api.query.system.accountNonce(keyring.bob_stash.address);
const signedBlock = await api.rpc.chain.getBlock();
const currentHeight = signedBlock.block.header.number;
const exERA = createType(registry, 'ExtrinsicEra', { current: currentHeight, period: 4 });
const eraDeath = exERA.asMortalEra.death(currentHeight.toNumber());
const blockHash = signedBlock.block.header.hash;
const ex = api.tx.balances.transfer(keyring.eve.address, 12121);
await api.rpc.chain.subscribeNewHeads(async (header: Header): Promise<void> => {
if (header.number.toNumber() === eraDeath - 1) {
try {
await ex.signAndSend(keyring.alice.address, { blockHash, era: exERA, nonce } as any);
} catch (error) {
// NOTE As per above 0 or -127 error code
expect(error.message).toMatch(
/1010: Invalid Transaction \(-127\)|1010: Invalid Transaction \(0\)/
);
}
done();
}
});
});
it('makes a transfer with custom numeric era', async (done): Promise<void> => {
await api.tx.balances
.transfer(keyring.eve.address, 12345)
.signAndSend(keyring.charlie, { era: 2 }, logEvents(done));
});
});
});
@@ -1,78 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 testingPairs from '@polkadot/keyring/testingPairs';
import WsProvider from '@polkadot/rpc-provider/ws';
import { TypeRegistry } from '@polkadot/types';
import ApiPromise from '../../../src/promise';
import { Signer } from '../../../src/types';
import { describeE2E, logEvents, SingleAccountSigner } from '../../util';
describeE2E({
except: ['remote-polkadot-alexander', 'remote-substrate-1.0']
})('Promise e2e transactions with Signer injection', (wsUrl: string): void => {
const registry = new TypeRegistry();
const keyring = testingPairs({ type: 'ed25519' });
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
describe('Signer injection', (): void => {
it('makes a transfer (signAndSend via Signer)', async (done): Promise<void> => {
const signer = new SingleAccountSigner(registry, keyring.bob_stash);
api.setSigner(signer);
await api.tx.balances
.transfer(keyring.eve.address, 12345)
.signAndSend(keyring.bob_stash.address, logEvents(done));
});
it('succeeds when waiting some blocks before submission', async (done): Promise<void> => {
// 10 second delay
const signer = new SingleAccountSigner(registry, keyring.bob_stash, 10000);
api.setSigner(signer);
await api.tx.balances
.transfer(keyring.eve.address, 12345)
.signAndSend(keyring.bob_stash.address, logEvents(done));
});
it('fails (signAndSend via Signer) with undefined Signer', async (): Promise<void> => {
const signer: any = undefined;
// no signer
api.setSigner(signer);
await expect(api.tx.balances
.transfer(keyring.eve.address, 12345)
.signAndSend(keyring.alice.address)).rejects.toThrow('no signer exists');
});
it('fails (signAndSend via Signer) with the wrong keyring pair', async (): Promise<void> => {
const signer: Signer = new SingleAccountSigner(registry, keyring.dave);
api.setSigner(signer);
// no callback
await expect(api.tx.balances
.transfer(keyring.eve.address, 12345)
.signAndSend(keyring.alice.address)).rejects.toThrow('does not have the keyringPair');
});
it('fails (signAndSend via Signer) with the wrong keyring pair with a callback', async (): Promise<void> => {
// with callback
await expect(api.tx.balances
.transfer(keyring.eve.address, 12345)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
.signAndSend(keyring.alice.address, (cb: any): void => { /* do nothing */ }))
.rejects.toThrow('no signer exists');
});
});
});
@@ -1,102 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 testingPairs from '@polkadot/keyring/testingPairs';
import WsProvider from '@polkadot/rpc-provider/ws';
import { randomAsHex } from '@polkadot/util-crypto';
import { u8aToHex } from '@polkadot/util';
import ApiPromise from '../../../src/promise';
import randomAsHex2097152 from '../../mock-data/randomAsHex_2097152';
import { calculateAccountDeposit, describeE2E, logEvents } from '../../util';
describeE2E({
except: ['remote-polkadot-alexander', 'remote-substrate-1.0']
})('Promise e2e transactions', (wsUrl: string): void => {
const keyring = testingPairs({ type: 'ed25519' });
let api: ApiPromise;
beforeEach(async (done): Promise<void> => {
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
done();
});
it('can submit an extrinsic from hex', async (done): Promise<() => void> => {
const nonce = await api.query.system.accountNonce(keyring.bob_stash.address);
const hex = api.tx.balances
.transfer(keyring.eve.address, 12345)
.sign(keyring.bob_stash, { nonce })
.toHex();
return api.tx(hex).send(logEvents(done));
});
it('invalid hex does throw a catchable exception', async (done): Promise<void> => {
const nonce = await api.query.system.accountNonce(keyring.bob_stash.address);
const hex = api.tx.balances
.transfer(keyring.eve.address, 12345)
.sign(keyring.bob_stash, { nonce })
.toHex();
// change to an invalid signature, 32 * 2 for hex
const sigIdx = hex.indexOf(u8aToHex(keyring.bob_stash.publicKey).substr(2)) + 64;
const mangled = hex.replace(
hex.substr(sigIdx, 32), // first 16 bytes of sig
hex.substr(2, 32) // replaced by first 16 bytes of tx
);
try {
await api.tx(mangled).send(logEvents(done));
} catch (error) {
console.error(error);
done();
}
});
it('makes a transfer (sign, then send)', async (done): Promise<() => void> => {
const nonce = await api.query.system.accountNonce(keyring.bob_stash.address);
return api.tx.balances
.transfer(keyring.eve.address, 12345)
.sign(keyring.bob_stash, { nonce })
.send(logEvents(done));
});
it('makes a transfer (sign, then send - compat version)', async (done): Promise<() => void> => {
const nonce = await api.query.system.accountNonce(keyring.bob_stash.address);
return api.tx.balances
.transfer(keyring.eve.address, 12345)
.sign(keyring.bob_stash, { nonce })
.send(logEvents(done));
});
it('makes a transfer (signAndSend, immortal)', async (done): Promise<() => void> => {
return api.tx.balances
.transfer(keyring.eve.address, 12345)
.signAndSend(keyring.bob_stash, { era: 0 }, logEvents(done));
});
it('makes a transfer (no callback)', async (): Promise<void> => {
const hash = await api.tx.balances
.transfer(keyring.eve.address, 12345)
.signAndSend(keyring.bob_stash);
expect(hash.toHex()).toHaveLength(66);
});
it('makes a proposal', async (done): Promise<void> => {
// don't wait for status, just get hash. Here we generate a large-ish payload
// to ensure that we can sign with the hashed version as well (and have it accepted)
const amount = calculateAccountDeposit(api);
await api.tx.democracy
.propose(
api.tx.system && api.tx.system.setCode
? api.tx.system.setCode(randomAsHex2097152) // since impl_version 94 https://github.com/paritytech/substrate/pull/2802
: api.tx.consensus.setCode(randomAsHex(4096)) // impl_version 0 - 93
, amount)
.signAndSend(keyring.bob_stash, logEvents(done));
});
});
@@ -1,35 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 BN from 'bn.js';
import testingPairs from '@polkadot/keyring/testingPairs';
import WsProvider from '@polkadot/rpc-provider/ws';
import ApiRx from '../../../src/rx';
import { describeE2E } from '../../util';
describeE2E({
except: [
'remote-polkadot-alexander',
'remote-substrate-1.0'
]
})('Rx e2e queries', (wsUrl: string): void => {
const keyring = testingPairs({ type: 'ed25519' });
let api: ApiRx;
beforeEach(async (done): Promise<void> => {
api = await ApiRx.create({ provider: new WsProvider(wsUrl) }).toPromise();
done();
});
it('queries state for a balance', (done): void => {
api.query.balances.freeBalance(keyring.alice_stash.address).subscribe((balance): void => {
expect(balance).toBeInstanceOf(BN);
expect(balance.isZero()).toBe(false);
done();
});
});
});
@@ -1,46 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 { Header } from '@polkadot/types/interfaces';
import { Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import WsProvider from '@polkadot/rpc-provider/ws';
import ApiRx from '../../../src/rx';
import { describeE2E } from '../../util';
describeE2E()('Rx e2e queries', (wsUrl: string): void => {
let api: ApiRx;
beforeEach(async (done): Promise<void> => {
api = await ApiRx.create({ provider: new WsProvider(wsUrl) }).toPromise();
done();
});
it('makes the runtime, rpc, state & extrinsics available', (): void => {
expect(api.genesisHash).toBeDefined();
expect(api.runtimeMetadata).toBeDefined();
expect(api.runtimeVersion).toBeDefined();
expect(api.rpc).toBeDefined();
expect(api.query).toBeDefined();
expect(api.tx).toBeDefined();
expect(api.derive).toBeDefined();
});
it('makes a query at a specific block', (done): void => {
api.rpc.chain
.getHeader()
.pipe(
switchMap(({ hash }: Header): Observable<any> =>
api.query.system.events.at(hash)
)
)
.subscribe((events: any): void => {
expect(events.length).not.toEqual(0);
done();
});
});
});
-71
View File
@@ -1,71 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 { Index } from '@polkadot/types/interfaces';
import { Observable } from 'rxjs';
import { first, switchMap } from 'rxjs/operators';
import testingPairs from '@polkadot/keyring/testingPairs';
import WsProvider from '@polkadot/rpc-provider/ws';
import { randomAsHex } from '@polkadot/util-crypto';
import ApiRx from '../../../src/rx';
import { SubmittableResult } from '../../../src';
import randomAsHex2097152 from '../../mock-data/randomAsHex_2097152';
import { calculateAccountDeposit, describeE2E } from '../../util';
describeE2E()('Rx e2e transactions', (wsUrl: string): void => {
const keyring = testingPairs({ type: 'ed25519' });
let api: ApiRx;
beforeEach(async (done): Promise<void> => {
api = await ApiRx.create({ provider: new WsProvider(wsUrl) }).toPromise();
done();
});
it('makes a transfer', (done): void => {
api.query.system
.accountNonce<Index>(keyring.bob_stash.address)
.pipe(
first(),
switchMap((nonce: Index): Observable<SubmittableResult> =>
api.tx.balances
.transfer(keyring.bob.address, 12345)
.sign(keyring.bob_stash, { nonce })
.send()
)
)
.subscribe(({ status }: SubmittableResult): void => {
if (status.isFinalized) {
done();
}
});
});
it('makes a proposal', (done): void => {
const amount = calculateAccountDeposit(api);
const proposal = api.tx.system && api.tx.system.setCode
? api.tx.system.setCode(randomAsHex2097152) // since impl_version 94 https://github.com/paritytech/substrate/pull/2802
: api.tx.consensus.setCode(randomAsHex(4096)); // impl_version 0 - 93
api.query.system
.accountNonce<Index>(keyring.bob_stash.address)
.pipe(
first(),
switchMap((nonce: Index): Observable<SubmittableResult> =>
api.tx.democracy
.propose(proposal, amount)
.sign(keyring.bob_stash, { nonce })
.send()
)
)
.subscribe(({ status }: SubmittableResult): void => {
if (status.isFinalized) {
done();
}
});
});
});
@@ -1,70 +0,0 @@
// Copyright 2017-2020 @polkadot/rpc-core 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 { BlockNumber, Index, SignedBlock } from '@polkadot/types/interfaces';
import Metadata from '@polkadot/metadata/Decorated';
import rpcMetadata from '@polkadot/metadata/Metadata/static';
import WsProvider from '@polkadot/rpc-provider/ws';
import { ClassOf, TypeRegistry } from '@polkadot/types';
import Rpc from '@polkadot/rpc-core';
import { describeE2E } from '../../util';
const randomAccount = '5HTqyWJHAVUieZnpb1V8gK4T1E4mnhkrUVSSzWBQd6kYgsVJ';
describeE2E({
only: [
'remote-polkadot-alexander',
'docker-polkadot-alexander'
]
})('e2e Alexander - Polkadot', (wsUrl: string): void => {
const registry = new TypeRegistry();
const metadata = new Metadata(registry, rpcMetadata);
let rpc: Rpc;
beforeEach((): void => {
rpc = new Rpc(registry, new WsProvider(wsUrl));
});
it('subscribes to storage', (done): void => {
rpc.state
.subscribeStorage<[BlockNumber, Index]>([
[metadata.query.system.accountNonce, randomAccount],
[metadata.query.session.currentIndex]
])
.subscribe((data): void => {
expect(data).toHaveLength(2);
expect(data).toEqual(
expect.arrayContaining([
expect.any(ClassOf(registry, 'Index')),
expect.any(ClassOf(registry, 'Index'))
])
);
done();
});
});
it('retrieves a block by hash (krumme lanke #1)', (done): void => {
rpc.chain
.getBlock('0x627847bffdf5f3e01ac440d057dec6a37a12a6f329db7ef8367665574b76b5df')
.subscribe((block: SignedBlock): void => {
expect(block).toBeDefined();
expect(block).toBeInstanceOf(ClassOf(registry, 'SignedBlock'));
done();
});
});
it('retrieves a block by hash (krumme lanke #2)', (done): void => {
rpc.chain
.getBlock('0x53416d53a4b1dfcae9165a89d193608e4aa770414f02267f5b2c4015a2e66091')
.subscribe((block: SignedBlock): void => {
expect(block).toBeDefined();
expect(block).toBeInstanceOf(ClassOf(registry, 'SignedBlock'));
done();
});
});
});
@@ -1,44 +0,0 @@
// Copyright 2017-2020 @polkadot/rpc-core 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 { ChainProperties, Extrinsic } from '@polkadot/types/interfaces';
import { ClassOf, TypeRegistry, Vec } from '@polkadot/types';
import WsProvider from '@polkadot/rpc-provider/ws';
import Rpc from '@polkadot/rpc-core';
import { describeE2E } from '../../util';
describeE2E({
except: [
'remote-polkadot-alexander',
'remote-substrate-1.0'
]
})('RPC-core e2e basics', (wsUrl: string): void => {
const registry = new TypeRegistry();
let rpc: Rpc;
beforeEach((): void => {
jest.setTimeout(30000);
rpc = new Rpc(registry, new WsProvider(wsUrl));
});
it('retrieves the pending extrinsics', (done): void => {
rpc.author
.pendingExtrinsics()
.subscribe((extrinsics: Vec<Extrinsic>): void => {
expect(extrinsics).toBeInstanceOf(Vec);
done();
});
});
it('retrieves the system properties', (done): void => {
rpc.system
.properties()
.subscribe((properties: ChainProperties): void => {
expect(properties).toBeInstanceOf(ClassOf(registry, 'ChainProperties'));
done();
});
});
});
@@ -1,40 +0,0 @@
// Copyright 2017-2020 @polkadot/rpc-core 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 { Header } from '@polkadot/types/interfaces';
import { ClassOf, TypeRegistry } from '@polkadot/types';
import WsProvider from '@polkadot/rpc-provider/ws';
import Rpc from '@polkadot/rpc-core';
import { describeE2E } from '../../util';
describeE2E({
except: [
'remote-polkadot-alexander',
'remote-substrate-1.0'
]
})('RPC-core e2e chain', (wsUrl: string): void => {
const registry = new TypeRegistry();
let rpc: Rpc;
beforeEach((): void => {
jest.setTimeout(30000);
rpc = new Rpc(registry, new WsProvider(wsUrl));
});
it('subscribes via subscribeNewHeads', (done): void => {
let count = 0;
rpc.chain
.subscribeNewHeads()
.subscribe((header: Header): void => {
expect(header).toBeInstanceOf(ClassOf(registry, 'Header'));
if (++count === 3) {
done();
}
});
});
});
@@ -1,151 +0,0 @@
// Copyright 2017-2020 @polkadot/rpc-core 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 { Hash } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import fs from 'fs';
import path from 'path';
import { ApiPromise, SubmittableResult } from '@polkadot/api';
import { Abi } from '@polkadot/api-contract';
import testingPairs from '@polkadot/keyring/testingPairs';
import { KeyringPair } from '@polkadot/keyring/types';
import Rpc from '@polkadot/rpc-core';
import WsProvider from '@polkadot/rpc-provider/ws';
import { H256, StorageData, StorageKey, TypeRegistry } from '@polkadot/types';
import { hexToBn, isInstanceOf } from '@polkadot/util';
import { describeE2E } from '../../util';
// Backwards compatibility:
// A breaking change was introduced by substrate runtime spec version 97. https://github.com/paritytech/substrate/pull/2911/files
// The change had to be implemented in ink! which changed the structure of the Wasm files.
// The Polkadot JS API is only supporting INK! versions that are working with substrate greater or equal to spec_version 97.
import incrementerAbi from '../../../../api-contract/test/contracts/Incrementer.json';
const incrementerCode = fs.readFileSync(path.join(__dirname, '../../../../api-contract/test/contracts/incrementer-pruned.wasm')).toString('hex');
const CHILD_STORAGE = '0x3a6368696c645f73746f726167653a'; // :child_storage:
describeE2E({
except: [
'docker-polkadot-master',
'docker-polkadot-alexander',
'docker-substrate-1.0',
'remote-polkadot-alexander',
'remote-substrate-1.0'
]
})('RPC-core e2e child-storage', (wsUrl: string): void => {
const MAX_GAS = 50000;
const registry = new TypeRegistry();
const keyring: Record<string, KeyringPair> = testingPairs({ type: 'sr25519' });
const randomStart = Math.floor(Date.now() / 1000);
let abi: Abi;
let api: ApiPromise;
let codeHash: Hash;
let rpc: Rpc;
beforeAll(async (done): Promise<() => void> => {
abi = new Abi(registry, incrementerAbi);
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
return (
api.tx.contracts
.putCode(MAX_GAS, `0x${incrementerCode}`)
.signAndSend(keyring.eve, (result: SubmittableResult): void => {
if (result.status.isFinalized) {
const record = result.findRecord('contracts', 'CodeStored');
if (record) {
codeHash = record.event.data[0] as Hash;
done();
}
}
})
);
});
beforeEach((done): void => {
rpc = new Rpc(registry, new WsProvider(wsUrl));
done();
});
// `child_storage` is currently not used anywhere in Polkadot or Substrate, that's why we need to
// add a Smart Contract that is using `child_storage` before being able to test it.
// @TODO Add tests for Polkadot once child storage is being used there.
describe('e2e state child methods', (): void => {
beforeAll(async (done): Promise<() => void> => {
abi = new Abi(registry, incrementerAbi);
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
// An instance of a contract can only be deployed once by one specific account.
// That's why we need a random starting point for our incrementer contract to be
// able to run this test multiple times without the need of pruning the database
const CREATION_FEE = api.consts && api.consts.contracts
? 123456789123456
: 12345;
return (
api.tx.contracts
.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');
if (record) {
done();
}
}
})
);
});
it('getChildKeys(): retrieves :child_storage: keys for one deployed incrementer contract', async (done):
Promise<void> => {
const storageKeys = await rpc.state.getKeys(CHILD_STORAGE).toPromise();
rpc.state
.getChildKeys(storageKeys[0], '0x')
.subscribe((keys: StorageKey[]): void => {
expect(keys.length).toBeGreaterThanOrEqual(1);
done();
});
});
it('getChildStorage(): retrieves the default value of the incrementer smart contract', async (done): Promise<void> => {
const storageKeys = await rpc.state.getKeys(CHILD_STORAGE).toPromise();
const childStorageKeys = await rpc.state.getChildKeys(storageKeys[0], '0x').toPromise();
rpc.state
.getChildStorage(storageKeys[0], childStorageKeys[0])
.subscribe((storage: StorageData): void => {
const storageValue = hexToBn(storage.toHex(), { isLe: true });
expect(storageValue).toBeInstanceOf(BN);
expect(storageValue.toNumber()).toBeGreaterThan(1500000000);
done();
});
});
it('getChildStorageHash(): retrieves the Hash of the incrementer smart contract', async (done): Promise<void> => {
const storageKeys = await rpc.state.getKeys(CHILD_STORAGE).toPromise();
const childStorageKeys = await rpc.state.getChildKeys(storageKeys[0].toHex(), '0x').toPromise();
rpc.state
.getChildStorageHash(storageKeys[0], childStorageKeys[0])
.subscribe((storage: StorageData): void => {
expect(isInstanceOf(storage, H256)).toBeTruthy();
done();
});
});
it('getChildStorageSize(): retrieves the size of the incrementer smart contract', async (done): Promise<void> => {
const storageKeys = await rpc.state.getKeys(CHILD_STORAGE).toPromise();
const childStorageKeys = await rpc.state.getChildKeys(storageKeys[0], '0x').toPromise();
rpc.state
.getChildStorageSize(storageKeys[0], childStorageKeys[0])
.subscribe((storage): void => {
expect(storage.toString()).toBe('4');
done();
});
});
});
});
@@ -1,117 +0,0 @@
// Copyright 2017-2020 @polkadot/rpc-core 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 { Balance, Moment, RuntimeVersion } from '@polkadot/types/interfaces';
import DecorateMeta from '@polkadot/metadata/Decorated';
import rpcMetadata from '@polkadot/metadata/Metadata/static';
import Rpc from '@polkadot/rpc-core';
import WsProvider from '@polkadot/rpc-provider/ws';
import { Bytes, ClassOf, Metadata, StorageKey, TypeRegistry } from '@polkadot/types';
import { describeE2E } from '../../util';
const BOB_STASH = '5HpG9w8EBLe5XCrbczpwq5TSXvedjrBGCwqxK1iQ7qUsSWFc';
const CODE = '0x3a636f6465'; // :code
const registry = new TypeRegistry();
const metadata = new DecorateMeta(registry, rpcMetadata);
describeE2E({
except: [
'remote-polkadot-alexander',
'remote-substrate-1.0'
]
})('RPC-core e2e state', (wsUrl: string): void => {
let rpc: Rpc;
beforeEach((): void => {
jest.setTimeout(30000);
rpc = new Rpc(registry, new WsProvider(wsUrl));
});
it('getMetadata(): retrieves the wasm metadata', (done): void => {
rpc.state
.getMetadata()
.subscribe((meta: Metadata): void => {
expect(meta).toBeDefined();
expect(meta).toBeInstanceOf(Metadata);
done();
});
});
it('getKeys(): retrieves storage keys for ":code"', (done): void => {
rpc.state
.getKeys(CODE)
.subscribe((keys: StorageKey[]): void => {
expect(keys.length).toEqual(1);
done();
});
});
it('retrieves the runtime version', (done): void => {
rpc.state
.getRuntimeVersion()
.subscribe((version: RuntimeVersion): void => {
expect(version).toBeInstanceOf(ClassOf(registry, 'RuntimeVersion'));
done();
});
});
describe('test-suite getStorage()', (): void => {
it('retrieves code', (done): void => {
rpc.state
.getStorage<Bytes>([
metadata.query.substrate.code
])
.subscribe((code: Bytes): void => {
expect(code).toBeDefined();
expect(code).toBeInstanceOf(Bytes);
done();
});
});
it('retrieves balances', (done): void => {
rpc.state
.getStorage<Balance>([
metadata.query.balances.freeBalance, BOB_STASH
])
.subscribe((balance): void => {
expect(balance.isZero()).not.toEqual(true);
done();
});
});
it('retrieves timestamp', (done): void => {
rpc.state
.getStorage<Moment>([
metadata.query.timestamp.now
])
.subscribe((moment: Moment): void => {
expect(moment.toNumber()).not.toEqual(0);
done();
});
});
it('accepts StorageKey as input type', async (done): Promise<void> => {
// get storage keys for ':code' storage
const keys = await rpc.state.getKeys('0x3a636f6465').toPromise();
const key = keys[0];
const storageHash = await rpc.state.getStorageHash(key, '0x').toPromise();
expect(storageHash).toBeDefined();
done();
});
it('accepts a hex value as input type', async (done): Promise<void> => {
// get storage keys for ':code' storage
const keys = await rpc.state.getKeys('0x3a636f6465').toPromise();
const key = keys[0].toHex();
const storageHash = await rpc.state.getStorageHash(key, '0x').toPromise();
expect(storageHash).toBeDefined();
done();
});
});
});
@@ -1,64 +0,0 @@
// Copyright 2017-2020 @polkadot/rpc-core 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 Metadata from '@polkadot/metadata/Decorated';
import rpcMetadata from '@polkadot/metadata/Metadata/static';
import testingPairs from '@polkadot/keyring/testingPairs';
import WsProvider from '@polkadot/rpc-provider/ws';
import Rpc from '@polkadot/rpc-core';
import { Index, Moment, SessionIndex } from '@polkadot/types/interfaces';
import { ClassOf, TypeRegistry } from '@polkadot/types';
import { describeE2E } from '../../util';
const registry = new TypeRegistry();
const metadata = new Metadata(registry, rpcMetadata);
describeE2E({
except: [
'remote-polkadot-alexander',
'remote-substrate-1.0'
]
})('RPC-core e2e subscriptions', (wsUrl: string): void => {
let rpc: Rpc;
const keyring = testingPairs({ type: 'ed25519' });
beforeEach((): void => {
jest.setTimeout(30000);
rpc = new Rpc(registry, new WsProvider(wsUrl));
});
it('subscribes to storage', (done): void => {
rpc.state
.subscribeStorage<[Index, SessionIndex]>([
[metadata.query.system.accountNonce, keyring.eve.address],
[metadata.query.session.currentIndex]
])
.subscribe((data): void => {
expect(data).toHaveLength(2);
expect(data).toEqual(
expect.arrayContaining([
expect.any(ClassOf(registry, 'Index')),
expect.any(ClassOf(registry, 'Index'))
])
);
done();
});
});
it('retrieves current timestamp', (done): void => {
let count = 0;
rpc.state
.subscribeStorage<Moment>([[metadata.query.timestamp.now]])
.subscribe((data): void => {
expect(data).toBeDefined();
if (++count === 3) {
done();
}
});
});
});
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,15 +0,0 @@
// Copyright 2017-2020 @polkadot/api 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 BN from 'bn.js';
import { ApiPromise, ApiRx } from '../../src';
export function calculateAccountDeposit (api: ApiPromise | ApiRx): number {
const minimum = api.consts.balances && api.consts.balances.existentialDeposit ? api.consts.balances.existentialDeposit.toString() : 0;
return (new BN(minimum).toNumber() < 100000000000000
? 1234 // Substrate spec_version 0 -100
: 12345678912345678 // since Substrate spec_version 101
);
}
-74
View File
@@ -1,74 +0,0 @@
// Copyright 2017-2020 @polkadot/api authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
const WS_ENDPOINTS = {
local: 'ws://127.0.0.1:9944/',
'docker-substrate-master': 'ws://127.0.0.1:9945/',
'docker-substrate-1.0': 'ws://127.0.0.1:9946/',
'docker-substrate-2.0': 'ws://127.0.0.1:9947/',
'docker-polkadot-master': 'ws://127.0.0.1:9948/',
'docker-polkadot-alexander': 'ws://127.0.0.1:9949/',
'remote-polkadot-alexander': 'wss://poc3-rpc.polkadot.io/',
'remote-polkadot-kusama': 'wss://kusama-rpc.polkadot.io/',
'remote-substrate-1.0': 'wss://substrate-rpc.parity.io/'
};
type WsName = keyof typeof WS_ENDPOINTS;
interface Options {
except?: WsName[]; // Only one of the two keys `except` `only` should be set
only?: WsName[];
}
function filterProcessEnv (wsEndpoints: WsName[]): WsName[] {
// If there's a TEST_DOCKER flag, we only run tests to Docker endpoints
// If there's a TEST_REMOTE flag, we only run tests to remote endpoints
// If none of the two is present, we only run tests on local node
return process.env.TEST_REMOTE || process.env.TEST_DOCKER
? process.env.TEST_REMOTE
? wsEndpoints.filter((wsName): boolean => wsName.startsWith('remote-'))
: wsEndpoints.filter((wsName): boolean => wsName.startsWith('docker-'))
: wsEndpoints.filter((wsName): boolean => wsName === 'local');
}
// From the options and the TEST_DOCKER and TEST_REMOTE flags, calculate on which endpoints we
// should run the tests
function getWsEndpoints (options?: Options): WsName[] {
let wsEndpoints: WsName[] = []; // The ws endpoints to test
if (options && options.only) {
wsEndpoints = options.only;
} else {
wsEndpoints = (Object.keys(WS_ENDPOINTS) as WsName[])
.filter((wsName): boolean => !options || !options.except || !options.except.includes(wsName));
}
return filterProcessEnv(wsEndpoints);
}
export function describeE2E (options?: Options): (message: string, inner: (wsUrl: string) => void) => void {
return function (message: string, inner: (wsUrl: string) => void): void {
const wsEndpoints = getWsEndpoints(options);
if (!wsEndpoints.length) {
describe('Empty test Suite', (): void => {
it('No tests found for passed endpoints', (): void => undefined);
});
} else {
wsEndpoints.map((wsName): [string, string] => [wsName, WS_ENDPOINTS[wsName]])
.forEach(([wsName, wsUrl]): void => {
describe(`${message} on ${wsName}`, (): void => {
beforeAll((): void => {
jest.setTimeout(15000);
});
afterAll((): void => {
jest.setTimeout(5000);
});
inner(wsUrl);
});
});
}
};
}
-2
View File
@@ -2,7 +2,5 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
export * from './calculateAccountDeposit';
export * from './describeE2E';
export * from './logEvents';
export * from './SingleAccountSigner';
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/metadata",
"version": "0.100.1",
"version": "1.0.1",
"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.7.7",
"@polkadot/types": "^0.100.1",
"@polkadot/util": "^1.8.1",
"@polkadot/util-crypto": "^1.8.1"
"@babel/runtime": "^7.8.3",
"@polkadot/types": "^1.0.1",
"@polkadot/util": "^2.0.1",
"@polkadot/util-crypto": "^2.0.1"
},
"devDependencies": {
"@polkadot/keyring": "^1.8.1"
"@polkadot/keyring": "^2.0.1"
}
}
@@ -12,11 +12,7 @@ import Metadata from '../../../Metadata';
const AS_STRIPPED = ['Bytes'];
/**
* Retrieve the parameter types (module constants) from the runtime metadata.
*
* @param metadata - The metadata
*/
/** @internal */
export default function fromMetadata (registry: Registry, metadata: Metadata): Constants {
return metadata.asLatest.modules.reduce((result: Constants, moduleMetadata): Constants => {
if (moduleMetadata.constants.isEmpty) {
@@ -10,15 +10,7 @@ import { AnyJsonObject, CallFunction, Registry, RegistryMetadataCall } from '@po
import { createType } from '@polkadot/types/codec/create/createType';
import { assert, stringCamelCase } from '@polkadot/util';
/**
* From the metadata of a function in the module's storage, generate the function
* that will return the an [[CallFunction]].
*
* @param section - Name of the module section.
* @param sectionIndex - Index of the module section in the modules array.
* @param methodIndex - Index of the method inside the section.
* @param callMetadata - Metadata of the call function.
*/
/** @internal */
export default function createDescriptor (registry: Registry, section: string, sectionIndex: number, methodIndex: number, callMetadata: RegistryMetadataCall): CallFunction {
const callIndex = new Uint8Array([sectionIndex, methodIndex]);
const expectedArgs = callMetadata.args;
@@ -9,11 +9,7 @@ import { stringCamelCase } from '@polkadot/util';
import extrinsics from '../';
import createUnchecked from './createUnchecked';
/**
* Return an object with the modules and the functions to use extrinsics.
*
* @param metadata - The metadata
*/
/** @internal */
export default function fromMetadata (registry: Registry, metadata: RegistryMetadata): ModulesWithCalls {
return metadata.asLatest.modules
.filter(({ calls }): boolean => calls.isSome)
@@ -37,6 +37,7 @@ const EMPTY_U8A = new Uint8Array([]);
const NULL_HASHER = (value: Uint8Array): Uint8Array => value;
// with the prefix, method & options, create both the string & raw keys
/** @internal */
function expandKey ({ method, prefix }: CreateItemFn, options: CreateItemOptions): string {
return options.key
? options.key
@@ -44,6 +45,7 @@ function expandKey ({ method, prefix }: CreateItemFn, options: CreateItemOptions
}
// get the hashers, the base (and in the case of DoubleMap), the second key
/** @internal */
function getHashers ({ meta: { type } }: CreateItemFn): [HasherFunction, HasherFunction?] {
if (type.isDoubleMap) {
return [
@@ -59,11 +61,13 @@ function getHashers ({ meta: { type } }: CreateItemFn): [HasherFunction, HasherF
}
// create a base prefixed key
/** @internal */
function createPrefixedKey ({ method, prefix }: CreateItemFn): Uint8Array {
return u8aConcat(xxhashAsU8a(prefix, 128), xxhashAsU8a(method, 128));
}
// create a key for a DoubleMap type
/** @internal */
function createKeyDoubleMap (registry: Registry, itemFn: CreateItemFn, stringKey: string, args: [CreateArgType, CreateArgType], [hasher1, hasher2]: [HasherFunction, HasherFunction?], metaVersion: number): Uint8Array {
const { meta: { name, type } } = itemFn;
@@ -97,9 +101,9 @@ function createKeyDoubleMap (registry: Registry, itemFn: CreateItemFn, stringKey
}
// create a key for either a map or a plain value
/** @internal */
function createKey (registry: Registry, itemFn: CreateItemFn, stringKey: string, arg: CreateArgType, hasher: (value: Uint8Array) => Uint8Array, metaVersion: number): Uint8Array {
const { meta: { name, type } } = itemFn;
let key: Uint8Array | undefined;
let param: Uint8Array = EMPTY_U8A;
if (type.isMap) {
@@ -108,24 +112,18 @@ function createKey (registry: Registry, itemFn: CreateItemFn, stringKey: string,
assert(!isUndefined(arg) && !isNull(arg), `${name} is a Map and requires one argument`);
param = createTypeUnsafe(registry, map.key.toString(), [arg]).toU8a();
// prefix maps are using prefixes to optimize the trie, so the key generation are
// done differently where the prefix/method are hashed separately with only the
// parameter for the key being attached via the hasher
if (map.kind.isPrefixedMap) {
key = u8aConcat(createPrefixedKey(itemFn), hasher(param));
}
}
// StorageKey is a Bytes, so is length-prefixed
return Compact.addLengthPrefix(key || (
return Compact.addLengthPrefix(
metaVersion <= 8
? hasher(u8aConcat(stringToU8a(stringKey), param))
: u8aConcat(createPrefixedKey(itemFn), param.length ? hasher(param) : EMPTY_U8A)
));
);
}
// attach the metadata to expand to a StorageFunction
/** @internal */
function expandWithMeta ({ meta, method, prefix, section }: CreateItemFn, storageFn: StorageEntry): StorageEntry {
storageFn.meta = meta;
storageFn.method = stringLowerFirst(method);
@@ -142,16 +140,18 @@ function expandWithMeta ({ meta, method, prefix, section }: CreateItemFn, storag
return storageFn;
}
function extendHeadMeta (registry: Registry, { meta: { documentation, name, type }, section }: CreateItemFn, { method }: StorageEntry, iterFn: () => Raw): StorageKey {
const map = type.asMap;
const outputType = map.key.toString();
/** @internal */
function extendHeadMeta (registry: Registry, { meta: { documentation, name, type }, section }: CreateItemFn, { method }: StorageEntry, iterFn: (arg?: any) => Raw): StorageKey {
const outputType = type.isMap
? type.asMap.key.toString()
: type.asDoubleMap.key1.toString();
// metadata with a fallback value using the type of the key, the normal
// meta fallback only applies to actual entry values, create one for head
(iterFn as IterFn).meta = createType(registry, 'StorageEntryMetadataLatest', {
name,
modifier: createType(registry, 'StorageEntryModifierLatest', 1), // required
type: createType(registry, 'StorageEntryTypeLatest', createType(registry, 'PlainTypeLatest', map.key), 0),
type: createType(registry, 'StorageEntryTypeLatest', createType(registry, 'PlainTypeLatest', type.isMap ? type.asMap.key : type.asDoubleMap.key1), 0),
fallback: createType(registry, 'Bytes', createTypeUnsafe(registry, outputType).toHex()),
documentation
});
@@ -160,6 +160,7 @@ function extendHeadMeta (registry: Registry, { meta: { documentation, name, type
}
// attach the head key hashing for linked maps
/** @internal */
function extendLinkedMap (registry: Registry, itemFn: CreateItemFn, storageFn: StorageEntry, stringKey: string, hasher: HasherFunction, metaVersion: number): StorageEntry {
const key = metaVersion <= 8
? hasher(`head of ${stringKey}`)
@@ -173,6 +174,7 @@ function extendLinkedMap (registry: Registry, itemFn: CreateItemFn, storageFn: S
}
// attach the full list hashing for prefixed maps
/** @internal */
function extendPrefixedMap (registry: Registry, itemFn: CreateItemFn, storageFn: StorageEntry): StorageEntry {
storageFn.iterKey = extendHeadMeta(registry, itemFn, storageFn, (): Raw =>
new Raw(registry, createPrefixedKey(itemFn))
@@ -181,16 +183,13 @@ function extendPrefixedMap (registry: Registry, itemFn: CreateItemFn, storageFn:
return storageFn;
}
/**
* From the schema of a function in the module's storage, generate the function
* that will return the correct storage key.
*
* @param item - The function's definition schema to create the function from.
* The schema is taken from state_getMetadata.
* @param options - Additional options when creating the function. These options
* are not known at runtime (from state_getMetadata), they need to be supplied
* by us manually at compile time.
*/
// attach the full list hashing for double maps
/** @internal */
function extendDoubleMap (registry: Registry, itemFn: CreateItemFn, storageFn: StorageEntry): StorageEntry {
return extendPrefixedMap(registry, itemFn, storageFn);
}
/** @internal */
export default function createFunction (registry: Registry, itemFn: CreateItemFn, options: CreateItemOptions): StorageEntry {
const { meta: { type } } = itemFn;
const stringKey = expandKey(itemFn, options);
@@ -210,11 +209,13 @@ export default function createFunction (registry: Registry, itemFn: CreateItemFn
if (type.isMap) {
const map = type.asMap;
if (map.kind.isLinkedMap) {
if (map.linked.isTrue) {
extendLinkedMap(registry, itemFn, storageFn, stringKey, hasher, options.metaVersion);
} else {
extendPrefixedMap(registry, itemFn, storageFn);
}
} else if (type.isDoubleMap) {
extendDoubleMap(registry, itemFn, storageFn);
}
return storageFn;
@@ -23,6 +23,7 @@ const map: Record<HasherCheck, HasherFunction> = {
isTwox64Concat: (data: HasherInput): Uint8Array => u8aConcat(xxhashAsU8a(data, 64), u8aToU8a(data))
};
/** @internal */
export default function getHasher (hasher?: StorageHasher): HasherFunction {
const [, fn] = (hasher && Object.entries(map).find(([check]): boolean =>
hasher[check as HasherCheck]
@@ -11,11 +11,7 @@ import Metadata from '../../../Metadata';
import createFunction from './createFunction';
import getStorage from './storage';
/**
* Return an object with the modules and the functions to access their storage.
*
* @param metadata - The metadata
*/
/** @internal */
export default function fromMetadata (registry: Registry, metadata: Metadata): Storage {
return metadata.asLatest.modules.reduce((result, moduleMetadata): Storage => {
if (moduleMetadata.storage.isNone) {
@@ -13,10 +13,6 @@ describe('storage', (): void => {
it('should return well known keys', (): void => {
expect(typeof storage.substrate).toBe('object');
// @deprecated: The ':auth:' (authorityPrefix) and ':auth:len' (authorityCount) storage keys
// have been removed in https://github.com/paritytech/substrate/pull/2802
expect(storage.substrate.authorityCount).toBeTruthy();
expect(storage.substrate.authorityPrefix).toBeTruthy();
expect(storage.substrate.changesTrieConfig).toBeTruthy();
expect(storage.substrate.childStorageKeyPrefix).toBeTruthy();
expect(storage.substrate.code).toBeTruthy();
@@ -8,6 +8,7 @@ import { Storage } from '../../types';
import * as substrate from './substrate';
/** @internal */
export default function getStorage (registry: Registry, metaVersion: number): Storage {
return {
substrate: Object
@@ -4,21 +4,11 @@
import { TypeRegistry } from '@polkadot/types';
import { authorityCount, authorityPrefix, changesTrieConfig, childStorageKeyPrefix, code, extrinsicIndex, heapPages } from './substrate';
import { changesTrieConfig, childStorageKeyPrefix, code, extrinsicIndex, heapPages } from './substrate';
describe('substrate', (): void => {
const registry = new TypeRegistry();
// @deprecated: The ':auth:' (authorityPrefix) and ':auth:len' (authorityCount) storage keys
// have been removed in https://github.com/paritytech/substrate/pull/2802
it('authorityCount should return the correct storage key', (): void => {
expect(authorityCount(registry, 8)()).toEqual(Uint8Array.from([36, 58, 97, 117, 116, 104, 58, 108, 101, 110])); // Length-prefixed
});
it('authorityPrefix should return the correct storage key', (): void => {
expect(authorityPrefix(registry, 8)()).toEqual(Uint8Array.from([24, 58, 97, 117, 116, 104, 58])); // Length-prefixed
});
it('changesTrieConfig should return the correct storage key', (): void => {
expect(changesTrieConfig(registry, 8)()).toEqual(Uint8Array.from([52, 58, 99, 104, 97, 110, 103, 101, 115, 95, 116, 114, 105, 101])); // Length-prefixed
});
@@ -16,6 +16,7 @@ interface SubstrateMetadata {
}
// Small helper function to factorize code on this page.
/** @internal */
function createRuntimeFunction (method: string, key: string, { documentation, type }: SubstrateMetadata): (registry: Registry, metaVersion: number) => StorageEntry {
return (registry: Registry, metaVersion: number): StorageEntry =>
createFunction(registry, {
@@ -31,18 +32,6 @@ function createRuntimeFunction (method: string, key: string, { documentation, ty
}, { key, metaVersion, skipHashing: true });
}
// @deprecated: The ':auth:' (authorityPrefix) and ':auth:len' (authorityCount) storage keys
// have been removed in https://github.com/paritytech/substrate/pull/2802
export const authorityCount = createRuntimeFunction('authorityCount', ':auth:len', {
documentation: 'Number of authorities.',
type: 'u32'
});
export const authorityPrefix = createRuntimeFunction('authorityPrefix', ':auth:', {
documentation: 'Prefix under which authorities are stored.',
type: 'u32'
});
export const code = createRuntimeFunction('code', ':code', {
documentation: 'Wasm code of the runtime.',
type: 'Bytes'
@@ -21,10 +21,11 @@ import v7ToV8 from './v7/toV8';
import v8ToV9 from './v8/toV9';
import v9ToV10 from './v9/toV10';
import v10ToV11 from './v10/toV11';
import v11ToLatest from './v11/toLatest';
import { getUniqTypes, toCallsOnly } from './util';
type MetaMapped = MetadataV0 | MetadataV1 | MetadataV2 | MetadataV3 | MetadataV4 | MetadataV5 | MetadataV6 | MetadataV7 | MetadataV8 | MetadataV9 | MetadataV10 | MetadataV11;
type MetaVersions = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11;
type MetaVersions = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
type MetaAsX = 'asV0' | 'asV1' | 'asV2' | 'asV3' | 'asV4' | 'asV5' | 'asV6' | 'asV7' | 'asV8' | 'asV9' | 'asV10' | 'asV11';
/**
@@ -165,7 +166,8 @@ export default class MetadataVersioned extends Struct {
* @description Returns the wrapped values as a latest version object
*/
public get asLatest (): MetadataLatest {
return this.asV11;
// This is non-existent & latest - applied here to do the module-specific type conversions
return this.getVersion(12, v11ToLatest);
}
/**
+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 './v9/static';
import metadata from './v11/static';
export default metadata;
@@ -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.
// Quick and dirty flatten (.flat() not available)
/** @internal */
export default function flattenUniq (list: any[]): any[] {
const flat = list.reduce((result, entry): any[] => {
return result.concat(
@@ -69,6 +69,7 @@ interface ExtractionMetadata {
};
}
/** @internal */
function unwrapCalls (mod: Module): Call[] {
return mod.calls
? mod.calls.unwrapOr([])
@@ -78,6 +79,7 @@ function unwrapCalls (mod: Module): Call[] {
: [];
}
/** @internal */
function getCallNames ({ modules }: ExtractionMetadata): string[][][] {
return modules.map((mod): string[][] =>
unwrapCalls(mod).map(({ args }): string[] =>
@@ -88,6 +90,7 @@ function getCallNames ({ modules }: ExtractionMetadata): string[][][] {
);
}
/** @internal */
function getConstantNames ({ modules }: ExtractionMetadata): string[][] {
return modules.map(({ constants }): string[] =>
constants
@@ -98,6 +101,7 @@ function getConstantNames ({ modules }: ExtractionMetadata): string[][] {
);
}
/** @internal */
function unwrapEvents (events?: Events): Event[] {
if (!events) {
return [];
@@ -106,6 +110,7 @@ function unwrapEvents (events?: Events): Event[] {
return events.unwrapOr([]);
}
/** @internal */
function getEventNames ({ modules, outerEvent }: ExtractionMetadata): string[][][] {
const mapArg = ({ args }: Event): string[] =>
args.map((arg): string =>
@@ -125,6 +130,7 @@ function getEventNames ({ modules, outerEvent }: ExtractionMetadata): string[][]
);
}
/** @internal */
function unwrapStorage (storage?: Storage): Item[] {
if (!storage) {
return [];
@@ -137,6 +143,7 @@ function unwrapStorage (storage?: Storage): Item[] {
: (data.items || data.functions) as Item[];
}
/** @internal */
function getStorageNames ({ modules }: ExtractionMetadata): string[][][] {
return modules.map(({ storage }): string[][] =>
unwrapStorage(storage).map(({ type }): string[] => {
@@ -160,6 +167,7 @@ function getStorageNames ({ modules }: ExtractionMetadata): string[][][] {
);
}
/** @internal */
export default function getUniqTypes (registry: Registry, meta: ExtractionMetadata, throwError: boolean): string[] {
const types = flattenUniq([
getCallNames(meta),
@@ -11,10 +11,7 @@ import { unwrapStorageType } from '@polkadot/types/primitive/StorageKey';
import getUniqTypes from './getUniqTypes';
import Metadata from '../Metadata';
/**
* Given the static `rpcData` and the `staticSubstrate` JSON file, Metadata
* should decode `rpcData` and output `staticSubstrate`.
*/
/** @internal */
export function decodeLatestSubstrate<Modules extends Codec> (registry: Registry, version: number, rpcData: string, staticSubstrate: object): void {
it('decodes latest substrate properly', (): void => {
const metadata = new Metadata(registry, rpcData);
@@ -31,10 +28,7 @@ export function decodeLatestSubstrate<Modules extends Codec> (registry: Registry
});
}
/**
* Given a `version`, MetadataLatest and MetadataV{version} should output the same
* unique types.
*/
/** @internal */
export function toLatest<Modules extends Codec> (registry: Registry, version: number, rpcData: string): void {
it(`converts v${version} to latest`, (): void => {
const metadata = new Metadata(registry, rpcData)[`asV${version}` as keyof Metadata];
@@ -48,9 +42,7 @@ export function toLatest<Modules extends Codec> (registry: Registry, version: nu
});
}
/**
* Given a Metadata, no type should throw when given its fallback value.
*/
/** @internal */
export function defaultValues (registry: Registry, rpcData: string): void {
describe('storage with default values', (): void => {
const metadata = new Metadata(registry, rpcData);
@@ -7,15 +7,14 @@ import { AnyJsonObject, Registry } from '@polkadot/types/types';
import { createType } from '@polkadot/types';
/**
* @description Convert from MetadataLatest to a stripped representation of MetadataLatest
*/
export default function toCallsOnly (registry: Registry, { modules }: MetadataLatest): AnyJsonObject | string {
/** @internal */
export default function toCallsOnly (registry: Registry, { extrinsic, modules }: MetadataLatest): AnyJsonObject | string {
return createType(registry, 'MetadataLatest', {
// FIXME, this needs typing, not any
modules: modules.map(({ calls, name }): any => ({
name,
calls
}))
})),
extrinsic
}).toJSON();
}
@@ -9,6 +9,7 @@ import { getTypeDef } from '@polkadot/types/codec/create';
import flattenUniq from './flattenUniq';
/** @internal */
function extractTypes (types: string[]): any[] {
return types.map((type): any => {
const decoded = getTypeDef(type);
@@ -37,6 +38,7 @@ function extractTypes (types: string[]): any[] {
});
}
/** @internal */
export default function validateTypes (registry: Registry, types: string[], throwError: boolean): void {
const missing = flattenUniq(extractTypes(types)).filter((type): boolean =>
!registry.hasType(type)
@@ -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 { createType, TypeRegistry } from '@polkadot/types/codec';
import { TypeRegistry } from '@polkadot/types/codec';
import Metadata from '../';
import latestSubstrateV0 from './static-substrate.json';
@@ -12,14 +12,7 @@ import { defaultValues, toLatest } from '../util/testUtil';
describe('Metadata', (): void => {
const registry = new TypeRegistry();
it('works with fallback', (): void => {
const metadata = new Metadata(registry, rpcData);
const metadataV0 = createType(registry, 'MetadataV0', rpcData);
expect(metadata.asV0.toString()).toEqual(metadataV0.toString());
});
it('decodes latest substrate properly', (): void => {
it('decodes into latest substrate', (): void => {
const metadata = new Metadata(registry, rpcData);
const json = metadata.asV0.toJSON();
@@ -438,7 +438,7 @@
"functions": [
{
"name": "AccountNonce",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "AccountId",
@@ -450,7 +450,7 @@
},
{
"name": "ExtrinsicCount",
"modifier": 0,
"modifier": "optional",
"type": {
"Plain": "u32"
},
@@ -459,7 +459,7 @@
},
{
"name": "BlockHash",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "BlockNumber",
@@ -471,7 +471,7 @@
},
{
"name": "ExtrinsicData",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "u32",
@@ -483,7 +483,7 @@
},
{
"name": "RandomSeed",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Hash"
},
@@ -492,7 +492,7 @@
},
{
"name": "Number",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -503,7 +503,7 @@
},
{
"name": "ParentHash",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Hash"
},
@@ -512,7 +512,7 @@
},
{
"name": "ExtrinsicsRoot",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Hash"
},
@@ -521,7 +521,7 @@
},
{
"name": "Digest",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Digest"
},
@@ -530,7 +530,7 @@
},
{
"name": "Events",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<EventRecord>"
},
@@ -586,7 +586,7 @@
"functions": [
{
"name": "Now",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Moment"
},
@@ -597,7 +597,7 @@
},
{
"name": "BlockPeriod",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Moment"
},
@@ -608,7 +608,7 @@
},
{
"name": "DidUpdate",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "bool"
},
@@ -713,7 +713,7 @@
"functions": [
{
"name": "OriginalAuthorities",
"modifier": 0,
"modifier": "optional",
"type": {
"Plain": "Vec<SessionKey>"
},
@@ -737,7 +737,7 @@
"functions": [
{
"name": "NextEnumSet",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "AccountIndex"
},
@@ -748,7 +748,7 @@
},
{
"name": "EnumSet",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "AccountIndex",
@@ -816,7 +816,7 @@
"functions": [
{
"name": "TotalIssuance",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -827,7 +827,7 @@
},
{
"name": "ExistentialDeposit",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -838,7 +838,7 @@
},
{
"name": "TransferFee",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -849,7 +849,7 @@
},
{
"name": "CreationFee",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -860,7 +860,7 @@
},
{
"name": "FreeBalance",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "AccountId",
@@ -884,7 +884,7 @@
},
{
"name": "ReservedBalance",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "AccountId",
@@ -909,7 +909,7 @@
},
{
"name": "TransactionBaseFee",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -920,7 +920,7 @@
},
{
"name": "TransactionByteFee",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -987,7 +987,7 @@
"functions": [
{
"name": "Validators",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<AccountId>"
},
@@ -998,7 +998,7 @@
},
{
"name": "SessionLength",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -1009,7 +1009,7 @@
},
{
"name": "CurrentIndex",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -1020,7 +1020,7 @@
},
{
"name": "CurrentStart",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Moment"
},
@@ -1031,7 +1031,7 @@
},
{
"name": "ForcingNewSession",
"modifier": 0,
"modifier": "optional",
"type": {
"Plain": "bool"
},
@@ -1043,7 +1043,7 @@
},
{
"name": "LastLengthChange",
"modifier": 0,
"modifier": "optional",
"type": {
"Plain": "BlockNumber"
},
@@ -1054,7 +1054,7 @@
},
{
"name": "NextKeyFor",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "AccountId",
@@ -1068,7 +1068,7 @@
},
{
"name": "NextSessionLength",
"modifier": 0,
"modifier": "optional",
"type": {
"Plain": "BlockNumber"
},
@@ -1243,7 +1243,7 @@
"functions": [
{
"name": "ValidatorCount",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "u32"
},
@@ -1254,7 +1254,7 @@
},
{
"name": "MinimumValidatorCount",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "u32"
},
@@ -1265,7 +1265,7 @@
},
{
"name": "SessionsPerEra",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -1276,7 +1276,7 @@
},
{
"name": "SessionReward",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Perbill"
},
@@ -1287,7 +1287,7 @@
},
{
"name": "OfflineSlash",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Perbill"
},
@@ -1298,7 +1298,7 @@
},
{
"name": "OfflineSlashGrace",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "u32"
},
@@ -1309,7 +1309,7 @@
},
{
"name": "BondingDuration",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -1320,7 +1320,7 @@
},
{
"name": "Invulerables",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<AccountId>"
},
@@ -1332,7 +1332,7 @@
},
{
"name": "CurrentEra",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -1343,7 +1343,7 @@
},
{
"name": "ValidatorPreferences",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "AccountId",
@@ -1357,7 +1357,7 @@
},
{
"name": "Intentions",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<AccountId>"
},
@@ -1368,7 +1368,7 @@
},
{
"name": "Nominating",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "AccountId",
@@ -1382,7 +1382,7 @@
},
{
"name": "NominatorsFor",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "AccountId",
@@ -1396,7 +1396,7 @@
},
{
"name": "CurrentNominatorsFor",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "AccountId",
@@ -1410,7 +1410,7 @@
},
{
"name": "CurrentSessionReward",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -1421,7 +1421,7 @@
},
{
"name": "CurrentOfflineSlash",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -1432,7 +1432,7 @@
},
{
"name": "NextSessionsPerEra",
"modifier": 0,
"modifier": "optional",
"type": {
"Plain": "BlockNumber"
},
@@ -1443,7 +1443,7 @@
},
{
"name": "LastEraLengthChange",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -1454,7 +1454,7 @@
},
{
"name": "StakeRange",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "(Balance,Balance)"
},
@@ -1465,7 +1465,7 @@
},
{
"name": "Bondage",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "AccountId",
@@ -1479,7 +1479,7 @@
},
{
"name": "SlashCount",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "AccountId",
@@ -1493,9 +1493,9 @@
},
{
"name": "ForcingNewEra",
"modifier": 0,
"modifier": "optional",
"type": {
"Plain": "Null"
"Plain": "()"
},
"fallback": "0x00",
"documentation": [
@@ -1619,7 +1619,7 @@
"functions": [
{
"name": "PublicPropCount",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "PropIndex"
},
@@ -1630,7 +1630,7 @@
},
{
"name": "PublicProps",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<(PropIndex,Proposal,AccountId)>"
},
@@ -1641,7 +1641,7 @@
},
{
"name": "DepositOf",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "PropIndex",
@@ -1655,7 +1655,7 @@
},
{
"name": "LaunchPeriod",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -1666,7 +1666,7 @@
},
{
"name": "MinimumDeposit",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -1677,7 +1677,7 @@
},
{
"name": "PublicDelay",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -1688,7 +1688,7 @@
},
{
"name": "MaxLockPeriods",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "LockPeriods"
},
@@ -1699,7 +1699,7 @@
},
{
"name": "VotingPeriod",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -1710,7 +1710,7 @@
},
{
"name": "ReferendumCount",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "ReferendumIndex"
},
@@ -1721,7 +1721,7 @@
},
{
"name": "NextTally",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "ReferendumIndex"
},
@@ -1732,7 +1732,7 @@
},
{
"name": "ReferendumInfoOf",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "ReferendumIndex",
@@ -1746,7 +1746,7 @@
},
{
"name": "DispatchQueue",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "BlockNumber",
@@ -1760,7 +1760,7 @@
},
{
"name": "Bondage",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "AccountId",
@@ -1774,7 +1774,7 @@
},
{
"name": "VotersFor",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "ReferendumIndex",
@@ -1788,7 +1788,7 @@
},
{
"name": "VoteOf",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "(ReferendumIndex,AccountId)",
@@ -1976,7 +1976,7 @@
"functions": [
{
"name": "CandidacyBond",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -1987,7 +1987,7 @@
},
{
"name": "VotingBond",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -1998,7 +1998,7 @@
},
{
"name": "PresentSlashPerVoter",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -2009,7 +2009,7 @@
},
{
"name": "CarryCount",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "u32"
},
@@ -2020,7 +2020,7 @@
},
{
"name": "PresentationDuration",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -2031,7 +2031,7 @@
},
{
"name": "InactiveGracePeriod",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "VoteIndex"
},
@@ -2043,7 +2043,7 @@
},
{
"name": "VotingPeriod",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -2054,7 +2054,7 @@
},
{
"name": "TermDuration",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -2065,7 +2065,7 @@
},
{
"name": "DesiredSeats",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "u32"
},
@@ -2076,7 +2076,7 @@
},
{
"name": "ActiveCouncil",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<(AccountId,BlockNumber)>"
},
@@ -2090,7 +2090,7 @@
},
{
"name": "VoteCount",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "VoteIndex"
},
@@ -2101,7 +2101,7 @@
},
{
"name": "ApprovalsOf",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "AccountId",
@@ -2116,7 +2116,7 @@
},
{
"name": "RegisterInfoOf",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "AccountId",
@@ -2131,7 +2131,7 @@
},
{
"name": "LastActiveOf",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "AccountId",
@@ -2145,7 +2145,7 @@
},
{
"name": "Voters",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<AccountId>"
},
@@ -2156,7 +2156,7 @@
},
{
"name": "Candidates",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<AccountId>"
},
@@ -2167,7 +2167,7 @@
},
{
"name": "CandidateCount",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "u32"
},
@@ -2176,7 +2176,7 @@
},
{
"name": "NextFinalise",
"modifier": 0,
"modifier": "optional",
"type": {
"Plain": "(BlockNumber,u32,Vec<AccountId>)"
},
@@ -2187,7 +2187,7 @@
},
{
"name": "SnapshotedStakes",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<Balance>"
},
@@ -2198,7 +2198,7 @@
},
{
"name": "Leaderboard",
"modifier": 0,
"modifier": "optional",
"type": {
"Plain": "Vec<(Balance,AccountId)>"
},
@@ -2284,7 +2284,7 @@
"functions": [
{
"name": "CooloffPeriod",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -2293,7 +2293,7 @@
},
{
"name": "VotingPeriod",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -2302,7 +2302,7 @@
},
{
"name": "EnactDelayPeriod",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -2313,7 +2313,7 @@
},
{
"name": "Proposals",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<(BlockNumber,Hash)>"
},
@@ -2322,7 +2322,7 @@
},
{
"name": "ProposalOf",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "Hash",
@@ -2334,7 +2334,7 @@
},
{
"name": "ProposalVoters",
"modifier": 1,
"modifier": "default",
"type": {
"Map": {
"key": "Hash",
@@ -2346,7 +2346,7 @@
},
{
"name": "CouncilVoteOf",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "(Hash,AccountId)",
@@ -2358,7 +2358,7 @@
},
{
"name": "VetoedProposal",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "Hash",
@@ -2420,7 +2420,7 @@
"functions": [
{
"name": "Proposals",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<Hash>"
},
@@ -2431,7 +2431,7 @@
},
{
"name": "ProposalOf",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "Hash",
@@ -2445,7 +2445,7 @@
},
{
"name": "Voting",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "Hash",
@@ -2459,7 +2459,7 @@
},
{
"name": "ProposalCount",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "u32"
},
@@ -2499,7 +2499,7 @@
"functions": [
{
"name": "PendingChange",
"modifier": 0,
"modifier": "optional",
"type": {
"Plain": "StoredPendingChange"
},
@@ -2608,7 +2608,7 @@
"functions": [
{
"name": "ProposalBond",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Permill"
},
@@ -2620,7 +2620,7 @@
},
{
"name": "ProposalBondMinimum",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -2631,7 +2631,7 @@
},
{
"name": "SpendPeriod",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "BlockNumber"
},
@@ -2642,7 +2642,7 @@
},
{
"name": "Burn",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Permill"
},
@@ -2653,7 +2653,7 @@
},
{
"name": "Pot",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Balance"
},
@@ -2664,7 +2664,7 @@
},
{
"name": "ProposalCount",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "ProposalIndex"
},
@@ -2675,11 +2675,11 @@
},
{
"name": "Proposals",
"modifier": 0,
"modifier": "optional",
"type": {
"Map": {
"key": "ProposalIndex",
"value": "Proposal"
"value": "TreasuryProposal"
}
},
"fallback": "0x00",
@@ -2689,7 +2689,7 @@
},
{
"name": "Approvals",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "Vec<ProposalIndex>"
},
@@ -2809,7 +2809,7 @@
"functions": [
{
"name": "Key",
"modifier": 1,
"modifier": "default",
"type": {
"Plain": "AccountId"
},
+4 -3
View File
@@ -11,12 +11,14 @@ import { stringUpperFirst } from '@polkadot/util';
import { createType, Option, Vec } from '@polkadot/types/codec';
import { Text } from '@polkadot/types/primitive';
/** @internal */
function toV1Calls (registry: Registry, { module: { call: { functions } } }: RuntimeModuleMetadataV0): Option<FunctionMetadataV1> {
return functions.length
? new Option(registry, Vec.with('FunctionMetadataV1'), functions)
: new Option(registry, Vec.with('FunctionMetadataV1'));
}
/** @internal */
function toV1Events (registry: Registry, metadataV0: MetadataV0, prefix: Text): Option<EventMetadataV1> {
const events = metadataV0.outerEvent.events.find((event): boolean => event[0].eq(prefix));
@@ -25,15 +27,14 @@ function toV1Events (registry: Registry, metadataV0: MetadataV0, prefix: Text):
: new Option(registry, Vec.with('EventMetadataV1'));
}
/** @internal */
function toV1Storage (registry: Registry, { storage }: RuntimeModuleMetadataV0): Option<StorageFunctionMetadataV1> {
return storage.isSome
? new Option(registry, 'Vec<StorageFunctionMetadataV1>', storage.unwrap().functions)
: new Option(registry, 'Vec<StorageFunctionMetadataV1>');
}
/**
* Function that converts MetadataV0 to MetadataV1
*/
/** @internal */
export default function toV1 (registry: Registry, metadataV0: MetadataV0): MetadataV1 {
return createType(registry, 'MetadataV1', {
modules: metadataV0.modules.map((mod): ModuleMetadataV1 => {

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