Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6dce57b394 | ||
|
|
ca7edf1593 | ||
|
|
59e069f091 | ||
|
|
65ff5c8f30 | ||
|
|
1c327c60d9 | ||
|
|
de9f033d99 | ||
|
|
9c913fb482 | ||
|
|
e19e530c1c | ||
|
|
aa91e0b8b5 | ||
|
|
9a6ba2fe0f | ||
|
|
de853d9cc0 | ||
|
|
07063134b8 | ||
|
|
20b8cd762d | ||
|
|
bd3338c3df | ||
|
|
4c328964d5 | ||
|
|
70e5e2b60a | ||
|
|
4329c0a411 | ||
|
|
0713afa0e0 | ||
|
|
8b518a909b | ||
|
|
794f1fe398 | ||
|
|
51423e20b5 | ||
|
|
d4b27ba670 | ||
|
|
8ca194a3d2 | ||
|
|
5fd2c70924 | ||
|
|
d36ee7de2f | ||
|
|
3683f9e5ff | ||
|
|
18c302d2cf | ||
|
|
1686f8b357 | ||
|
|
15158b763c | ||
|
|
f5f338a9ae | ||
|
|
458dec53dc | ||
|
|
ab05045686 | ||
|
|
b2c84eb461 | ||
|
|
1ee1d70d55 | ||
|
|
7de647ec0b | ||
|
|
cedbd8fa06 | ||
|
|
cba34b4b65 | ||
|
|
1a99d67c77 | ||
|
|
2a5c5ce3fe | ||
|
|
e4ca0a1c64 | ||
|
|
e6018f2f75 | ||
|
|
a9b4f8d841 | ||
|
|
7fe68857a0 | ||
|
|
4f63fc77a3 | ||
|
|
6e2ad7789e | ||
|
|
edb856c94f | ||
|
|
2f215fe2de | ||
|
|
ffa1279c64 | ||
|
|
83aca87dac | ||
|
|
bf782f6f65 | ||
|
|
7adad82786 | ||
|
|
693cf855f0 | ||
|
|
854a520517 | ||
|
|
6e6fc98cd1 | ||
|
|
3db15e73a5 | ||
|
|
215b659a9a | ||
|
|
7ef945d15b | ||
|
|
73ec345fcc | ||
|
|
c1c537a3b5 | ||
|
|
dc64076c79 | ||
|
|
da8ff51615 | ||
|
|
60b1bc87a4 | ||
|
|
7ed1857589 | ||
|
|
4c0e60f3d6 | ||
|
|
20ed3bb5fe | ||
|
|
be3f9c8fe8 | ||
|
|
e850955e55 | ||
|
|
eb5ee9860b | ||
|
|
f31bbdde02 | ||
|
|
f67c435378 | ||
|
|
bf9a60a202 | ||
|
|
9c3c07fa9b | ||
|
|
11786ca102 | ||
|
|
ffaea83e3e | ||
|
|
954540b944 | ||
|
|
204cf6769d | ||
|
|
f319bc4c50 | ||
|
|
7b9a11ac25 | ||
|
|
5d2feca2d4 | ||
|
|
dd97e9daee | ||
|
|
be258a1f7c | ||
|
|
72e9474f6f | ||
|
|
d1f63a7864 | ||
|
|
07ca18502b | ||
|
|
cddbe411f7 | ||
|
|
ffa60d1cfa | ||
|
|
88193b6a75 | ||
|
|
cc4a4607f1 | ||
|
|
6c25d0ab0d | ||
|
|
fbbbcd2612 | ||
|
|
dd57b1a007 | ||
|
|
47d0e68f7d | ||
|
|
7b6397215d | ||
|
|
5739b69757 |
+1
-1
@@ -1 +1 @@
|
||||
16
|
||||
17
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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']
|
||||
]
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
@@ -9,5 +9,5 @@
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "0.100.1"
|
||||
"version": "1.0.1"
|
||||
}
|
||||
|
||||
+7
-10
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
));
|
||||
|
||||
@@ -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[]);
|
||||
}
|
||||
|
||||
@@ -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[]> =>
|
||||
|
||||
@@ -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]
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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 =>
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
}))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -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';
|
||||
@@ -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
|
||||
}))
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -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)
|
||||
))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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 => ({
|
||||
|
||||
@@ -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: [] });
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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 =>
|
||||
|
||||
@@ -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[] = [];
|
||||
|
||||
|
||||
@@ -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
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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] || {})
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)');
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
@@ -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,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';
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user