diff --git a/CHANGELOG.md b/CHANGELOG.md index 7349c47ae5..d831af9b05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.40.1 + +- The API interfaces now require a WS-compatible provider, e.g. subscription support is a must. Previously the HTTPProvider could be use (although it was very limited in the interactions). + # 0.39.1 - The Promise API now returns a `Promise` instead of `UnsubFunction` when making subscriptions. diff --git a/lerna.json b/lerna.json index 90f9758554..615c228bf3 100644 --- a/lerna.json +++ b/lerna.json @@ -9,5 +9,5 @@ "packages": [ "packages/*" ], - "version": "0.39.12" + "version": "0.40.0" } diff --git a/packages/api-derive/package.json b/packages/api-derive/package.json index 959c4a705a..7cc287f2d3 100644 --- a/packages/api-derive/package.json +++ b/packages/api-derive/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/api-derive", - "version": "0.39.12", + "version": "0.40.0", "description": "Common functions used across Polkadot, derived from RPC calls and storage queries.", "main": "index.js", "keywords": [ @@ -31,8 +31,8 @@ "homepage": "https://github.com/polkadot-js/api/tree/master/packages/api-derive#readme", "dependencies": { "@babel/runtime": "^7.2.0", - "@polkadot/api": "^0.39.12", - "@polkadot/types": "^0.39.12", + "@polkadot/api": "^0.40.0", + "@polkadot/types": "^0.40.0", "@types/memoizee": "^0.4.2", "@types/rx": "^4.1.1", "memoizee": "^0.4.14", diff --git a/packages/api-derive/src/balances/accountIdAndIndex.ts b/packages/api-derive/src/balances/accountIdAndIndex.ts index a462fa2731..122a6c3293 100644 --- a/packages/api-derive/src/balances/accountIdAndIndex.ts +++ b/packages/api-derive/src/balances/accountIdAndIndex.ts @@ -4,7 +4,7 @@ import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { decodeAddress } from '@polkadot/keyring'; import { AccountId, AccountIndex } from '@polkadot/types/index'; @@ -14,7 +14,7 @@ import { drr } from '../util/drr'; export type IdAndIndex = [AccountId | undefined, AccountIndex | undefined]; -export function accountIdAndIndex (api: ApiRx) { +export function accountIdAndIndex (api: ApiInterface$Rx) { return (address: AccountId | AccountIndex | string | null | undefined) : Observable<(AccountIndex | AccountId | undefined)[]> => { try { diff --git a/packages/api-derive/src/balances/accountIdToIndex.ts b/packages/api-derive/src/balances/accountIdToIndex.ts index 7c0ff2a103..b16cf30e06 100644 --- a/packages/api-derive/src/balances/accountIdToIndex.ts +++ b/packages/api-derive/src/balances/accountIdToIndex.ts @@ -4,13 +4,13 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { AccountId, AccountIndex } from '@polkadot/types/index'; import { accountIndexes, AccountIndexes } from './accountIndexes'; import { drr } from '../util/drr'; -export function accountIdToIndex (api: ApiRx) { +export function accountIdToIndex (api: ApiInterface$Rx) { return (accountId: AccountId | string): Observable => accountIndexes(api)() .pipe( diff --git a/packages/api-derive/src/balances/accountIndexToId.ts b/packages/api-derive/src/balances/accountIndexToId.ts index 0b6b8d1983..5c2ad940ee 100644 --- a/packages/api-derive/src/balances/accountIndexToId.ts +++ b/packages/api-derive/src/balances/accountIndexToId.ts @@ -4,14 +4,14 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { ENUMSET_SIZE } from '@polkadot/types/AccountIndex'; import { Vector } from '@polkadot/types/codec'; import { AccountId, AccountIndex } from '@polkadot/types/index'; import { drr } from '../util/drr'; -export function accountIndexToId (api: ApiRx) { +export function accountIndexToId (api: ApiInterface$Rx) { return (accountIndex: AccountIndex | string): Observable => { const _accountIndex = accountIndex instanceof AccountIndex ? accountIndex diff --git a/packages/api-derive/src/balances/accountIndexes.ts b/packages/api-derive/src/balances/accountIndexes.ts index 9ce0d80803..6c2d6d9089 100644 --- a/packages/api-derive/src/balances/accountIndexes.ts +++ b/packages/api-derive/src/balances/accountIndexes.ts @@ -5,7 +5,7 @@ import BN from 'bn.js'; import { combineLatest, Observable } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { ENUMSET_SIZE } from '@polkadot/types/AccountIndex'; import { AccountId, AccountIndex } from '@polkadot/types/index'; @@ -13,7 +13,7 @@ import { drr } from '../util/drr'; export type AccountIndexes = { [index: string]: AccountIndex }; -export function accountIndexes (api: ApiRx) { +export function accountIndexes (api: ApiInterface$Rx) { return (): Observable => (api.query.balances.nextEnumSet() as Observable) .pipe( diff --git a/packages/api-derive/src/balances/fees.ts b/packages/api-derive/src/balances/fees.ts index 35c795f99d..a7847cecc7 100644 --- a/packages/api-derive/src/balances/fees.ts +++ b/packages/api-derive/src/balances/fees.ts @@ -5,11 +5,11 @@ import BN from 'bn.js'; import { combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { drr } from '../util/drr'; -export function fees (api: ApiRx) { +export function fees (api: ApiInterface$Rx) { return () => combineLatest( api.query.balances.creationFee(), diff --git a/packages/api-derive/src/balances/validatingBalance.ts b/packages/api-derive/src/balances/validatingBalance.ts index 5e138d3b1b..012b361139 100644 --- a/packages/api-derive/src/balances/validatingBalance.ts +++ b/packages/api-derive/src/balances/validatingBalance.ts @@ -5,7 +5,7 @@ import BN from 'bn.js'; import { combineLatest, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { AccountId, Balance } from '@polkadot/types/index'; import { DerivedBalances } from '../types'; @@ -13,7 +13,7 @@ import { drr } from '../util/drr'; import { votingBalance } from './votingBalance'; import { votingBalancesNominatorsFor } from './votingBalancesNominatorsFor'; -export function validatingBalance (api: ApiRx) { +export function validatingBalance (api: ApiInterface$Rx) { return (address: AccountId | string): Observable => combineLatest( votingBalance(api)(address), diff --git a/packages/api-derive/src/balances/validatingBalances.ts b/packages/api-derive/src/balances/validatingBalances.ts index 67fffd3c56..6911d42069 100644 --- a/packages/api-derive/src/balances/validatingBalances.ts +++ b/packages/api-derive/src/balances/validatingBalances.ts @@ -4,14 +4,14 @@ import { combineLatest, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { AccountId } from '@polkadot/types/index'; import { DerivedBalancesMap } from '../types'; import { drr } from '../util/drr'; import { validatingBalance } from './validatingBalance'; -export function validatingBalances (api: ApiRx) { +export function validatingBalances (api: ApiInterface$Rx) { return (...params: Array): Observable => { const accountIds: Array = params.slice(0, params.length - 1); diff --git a/packages/api-derive/src/balances/votingBalance.ts b/packages/api-derive/src/balances/votingBalance.ts index 0db27a2ffe..5c6bdc2466 100644 --- a/packages/api-derive/src/balances/votingBalance.ts +++ b/packages/api-derive/src/balances/votingBalance.ts @@ -4,7 +4,7 @@ import { combineLatest, of, Observable } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { AccountId, AccountIndex, Balance } from '@polkadot/types/index'; import { accountIdAndIndex } from './accountIdAndIndex'; @@ -13,7 +13,7 @@ import { drr } from '../util/drr'; const EMPTY_ACCOUNT = new AccountId(new Uint8Array(32)); -export function votingBalance (api: ApiRx) { +export function votingBalance (api: ApiInterface$Rx) { return (address: AccountIndex | AccountId | string): Observable => accountIdAndIndex(api)(address).pipe( switchMap(([accountId]) => diff --git a/packages/api-derive/src/balances/votingBalances.ts b/packages/api-derive/src/balances/votingBalances.ts index 1449241425..df56029283 100644 --- a/packages/api-derive/src/balances/votingBalances.ts +++ b/packages/api-derive/src/balances/votingBalances.ts @@ -3,14 +3,14 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { combineLatest, Observable } from 'rxjs'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { AccountId, AccountIndex } from '@polkadot/types/index'; import { DerivedBalances } from '../types'; import { drr } from '../util/drr'; import { votingBalance } from './votingBalance'; -export function votingBalances (api: ApiRx) { +export function votingBalances (api: ApiInterface$Rx) { return (...params: Array): Observable> => { const addresses: Array = params.slice(0, params.length - 1); diff --git a/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts b/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts index 62c9d71e09..b032675c92 100644 --- a/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts +++ b/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts @@ -4,14 +4,14 @@ import { Observable } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { AccountId } from '@polkadot/types/index'; import { DerivedBalances } from '../types'; import { drr } from '../util/drr'; import { votingBalances } from './votingBalances'; -export function votingBalancesNominatorsFor (api: ApiRx) { +export function votingBalancesNominatorsFor (api: ApiInterface$Rx) { return (accountId: AccountId | string): Observable> => (api.query.staking.nominatorsFor(accountId) as Observable | undefined>).pipe( map((nominators) => nominators || []), diff --git a/packages/api-derive/src/chain/bestNumber.ts b/packages/api-derive/src/chain/bestNumber.ts index 7622203432..7618941f93 100644 --- a/packages/api-derive/src/chain/bestNumber.ts +++ b/packages/api-derive/src/chain/bestNumber.ts @@ -4,7 +4,7 @@ import { Observable } from 'rxjs'; import { filter, map } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { BlockNumber, Header } from '@polkadot/types/index'; import { drr } from '../util/drr'; @@ -12,9 +12,9 @@ import { drr } from '../util/drr'; /** * Get the latest block number. */ -export function bestNumber (api: ApiRx) { +export function bestNumber (api: ApiInterface$Rx) { return (): Observable => - api.rpc.chain.subscribeNewHead() + (api.rpc.chain.subscribeNewHead() as Observable
) .pipe( filter((header: Header) => header && !!header.blockNumber), map(({ blockNumber }: Header) => blockNumber), diff --git a/packages/api-derive/src/chain/bestNumberFinalised.ts b/packages/api-derive/src/chain/bestNumberFinalised.ts index 4298a72ad6..d80a6e1cae 100644 --- a/packages/api-derive/src/chain/bestNumberFinalised.ts +++ b/packages/api-derive/src/chain/bestNumberFinalised.ts @@ -4,7 +4,7 @@ import { Observable } from 'rxjs'; import { filter, map } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { BlockNumber, Header } from '@polkadot/types/index'; import { drr } from '../util/drr'; @@ -12,9 +12,9 @@ import { drr } from '../util/drr'; /** * Get the latest finalised block number. */ -export function bestNumberFinalised (api: ApiRx) { +export function bestNumberFinalised (api: ApiInterface$Rx) { return (): Observable => - api.rpc.chain.subscribeFinalisedHeads() + (api.rpc.chain.subscribeFinalisedHeads() as Observable
) .pipe( filter((header: Header) => header && !!header.blockNumber), map(({ blockNumber }: Header) => blockNumber), diff --git a/packages/api-derive/src/democracy/referendumInfos.ts b/packages/api-derive/src/democracy/referendumInfos.ts index fae0ffc05d..b22d8c5f26 100644 --- a/packages/api-derive/src/democracy/referendumInfos.ts +++ b/packages/api-derive/src/democracy/referendumInfos.ts @@ -5,12 +5,12 @@ import BN from 'bn.js'; import { combineLatest, Observable } from 'rxjs'; import { filter } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { ReferendumInfo } from '@polkadot/types/index'; import { drr } from '../util/drr'; -export function referendumInfos (api: ApiRx) { +export function referendumInfos (api: ApiInterface$Rx) { return (...params: Array): Observable> => { const ids: Array = params.slice(0, params.length - 1); diff --git a/packages/api-derive/src/democracy/referendumVotesFor.ts b/packages/api-derive/src/democracy/referendumVotesFor.ts index cbe8eed031..07b288e4d6 100644 --- a/packages/api-derive/src/democracy/referendumVotesFor.ts +++ b/packages/api-derive/src/democracy/referendumVotesFor.ts @@ -5,7 +5,7 @@ import BN from 'bn.js'; import { combineLatest, Observable, of } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { Vector } from '@polkadot/types/codec'; import { AccountId, Balance, Vote } from '@polkadot/types/index'; @@ -14,7 +14,7 @@ import { drr } from '../util/drr'; import { votes } from './votes'; import { votingBalances } from '../balances/votingBalances'; -export function referendumVotesFor (api: ApiRx) { +export function referendumVotesFor (api: ApiInterface$Rx) { return (referendumId: BN | number): Observable> => (api.query.democracy.votersFor(referendumId) as Observable>).pipe( switchMap((votersFor) => diff --git a/packages/api-derive/src/democracy/referendums.ts b/packages/api-derive/src/democracy/referendums.ts index 602a59057c..88be585c04 100644 --- a/packages/api-derive/src/democracy/referendums.ts +++ b/packages/api-derive/src/democracy/referendums.ts @@ -4,13 +4,13 @@ import { combineLatest, Observable, of } from 'rxjs'; import { switchMap } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { ReferendumIndex, ReferendumInfo } from '@polkadot/types/index'; import { referendumInfos } from './referendumInfos'; import { drr } from '../util/drr'; -export function referendums (api: ApiRx) { +export function referendums (api: ApiInterface$Rx) { return (): Observable> => (combineLatest( api.query.democracy.nextTally(), diff --git a/packages/api-derive/src/democracy/votes.ts b/packages/api-derive/src/democracy/votes.ts index 225347d30f..b7a831ff63 100644 --- a/packages/api-derive/src/democracy/votes.ts +++ b/packages/api-derive/src/democracy/votes.ts @@ -4,12 +4,12 @@ import BN from 'bn.js'; import { combineLatest, Observable } from 'rxjs'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { AccountId, Vote } from '@polkadot/types/index'; import { drr } from '../util/drr'; -export function votes (api: ApiRx) { +export function votes (api: ApiInterface$Rx) { return (referendumId: BN, ...accountIds: Array): Observable> => combineLatest( accountIds.map( diff --git a/packages/api-derive/src/index.spec.ts b/packages/api-derive/src/index.spec.ts index f4ab5a9a6f..b4548d2d96 100644 --- a/packages/api-derive/src/index.spec.ts +++ b/packages/api-derive/src/index.spec.ts @@ -4,11 +4,12 @@ import { Observable } from 'rxjs'; import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import MockProvider from '@polkadot/rpc-provider/mock'; import { Derive } from './index'; -const testFunction = (api: ApiRx) => { +const testFunction = (api: ApiInterface$Rx) => { return < Section extends keyof Derive, Method extends keyof (typeof api.derive[Section]) diff --git a/packages/api-derive/src/index.ts b/packages/api-derive/src/index.ts index 064d5d733c..0c9245241b 100644 --- a/packages/api-derive/src/index.ts +++ b/packages/api-derive/src/index.ts @@ -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 ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import * as balances from './balances'; import * as chain from './chain'; @@ -28,7 +28,7 @@ export interface Derive { session: ReturnTypes; } -export default function decorateDerive (api: ApiRx): Derive { +export default function decorateDerive (api: ApiInterface$Rx): Derive { const derive = {} as Derive; Object.keys(functions).forEach((sectionName: string) => { diff --git a/packages/api-derive/src/session/eraLength.ts b/packages/api-derive/src/session/eraLength.ts index 7b23a5f4a1..dfbbb272f6 100644 --- a/packages/api-derive/src/session/eraLength.ts +++ b/packages/api-derive/src/session/eraLength.ts @@ -5,12 +5,12 @@ import BN from 'bn.js'; import { combineLatest, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { BlockNumber } from '@polkadot/types/index'; import { drr } from '../util/drr'; -export function eraLength (api: ApiRx) { +export function eraLength (api: ApiInterface$Rx) { return (): Observable => (combineLatest( api.query.session.sessionLength(), diff --git a/packages/api-derive/src/session/eraProgress.ts b/packages/api-derive/src/session/eraProgress.ts index 7c39fefd29..47ee24f06c 100644 --- a/packages/api-derive/src/session/eraProgress.ts +++ b/packages/api-derive/src/session/eraProgress.ts @@ -5,13 +5,13 @@ import BN from 'bn.js'; import { combineLatest, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { BlockNumber } from '@polkadot/types/index'; import { sessionProgress } from './sessionProgress'; import { drr } from '../util/drr'; -export function eraProgress (api: ApiRx) { +export function eraProgress (api: ApiInterface$Rx) { return (): Observable => (combineLatest( sessionProgress(api)(), diff --git a/packages/api-derive/src/session/sessionProgress.ts b/packages/api-derive/src/session/sessionProgress.ts index 5ce9cf7db0..05fc4b490b 100644 --- a/packages/api-derive/src/session/sessionProgress.ts +++ b/packages/api-derive/src/session/sessionProgress.ts @@ -5,13 +5,13 @@ import BN from 'bn.js'; import { combineLatest, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { BlockNumber } from '@polkadot/types/index'; import { bestNumber } from '../chain'; import { drr } from '../util/drr'; -export function sessionProgress (api: ApiRx) { +export function sessionProgress (api: ApiInterface$Rx) { return (): Observable => combineLatest( bestNumber(api)(), diff --git a/packages/api-derive/src/util/cache.spec.ts b/packages/api-derive/src/util/cache.spec.ts index 407674d4d1..8c64ff4682 100644 --- a/packages/api-derive/src/util/cache.spec.ts +++ b/packages/api-derive/src/util/cache.spec.ts @@ -2,13 +2,13 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { cache } from './cache'; describe('cache', () => { - const f = cache((api: ApiRx) => (a: number, b: number) => [api, a, b]); - const api = {} as ApiRx; + const f = cache((api: ApiInterface$Rx) => (a: number, b: number) => [api, a, b]); + const api = {} as ApiInterface$Rx; it('should hit cache when all arguments are the same', () => { const first = f(api)(2, 3); @@ -21,7 +21,7 @@ describe('cache', () => { const first = f(api)(2, 3); const second1 = f(api)(5, 3); const second2 = f(api)(2, 5); - const second3 = f({} as ApiRx)(2, 3); + const second3 = f({} as ApiInterface$Rx)(2, 3); expect(first).not.toBe(second1); expect(first).not.toBe(second2); diff --git a/packages/api-derive/src/util/cache.ts b/packages/api-derive/src/util/cache.ts index 5fe45e42f2..12086886de 100644 --- a/packages/api-derive/src/util/cache.ts +++ b/packages/api-derive/src/util/cache.ts @@ -3,7 +3,7 @@ // of the Apache-2.0 license. See the LICENSE file for details. import memoizee from 'memoizee'; -import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; /** * Create memoization for a 2-currified function. @@ -12,7 +12,7 @@ import ApiRx from '@polkadot/api/rx'; * @param map - The Map used to cache function returns. * @example * ```javascript - * const f = (api: ApiRx) => (b: number) => a * b; + * const f = (api: ApiInterface$Rx) => (b: number) => a * b; * const cached = cache(f); * f(api)(1, 2); * f(api)(1); // Cache not hit @@ -20,7 +20,7 @@ import ApiRx from '@polkadot/api/rx'; * f(api)(1, 2); // Cache hit * ``` */ -export const cache = (fn: Function, map = new WeakMap()) => (api: ApiRx) => { +export const cache = (fn: Function, map = new WeakMap()) => (api: ApiInterface$Rx) => { if (!map.has(api)) { const innerFn = fn(api); map.set(api, memoizee(innerFn)); diff --git a/packages/api-derive/test/e2e/derive.spec.ts b/packages/api-derive/test/e2e/derive.spec.ts index e309142dc2..cfd22ab3ed 100644 --- a/packages/api-derive/test/e2e/derive.spec.ts +++ b/packages/api-derive/test/e2e/derive.spec.ts @@ -4,29 +4,31 @@ import BN from 'bn.js'; import ApiRx from '@polkadot/api/rx'; +import { ApiInterface$Rx } from '@polkadot/api/types'; import { BlockNumber } from '@polkadot/types/index'; describe.skip('derive e2e', () => { - let api: ApiRx; + let api: ApiInterface$Rx; beforeAll(() => { jest.setTimeout(30000); }); - beforeEach(async () => { + beforeEach(async (done) => { api = await ApiRx.create().toPromise(); + done(); }); it('derive.chain.bestNumber', async (done) => { - api.derive.chain.bestNumber().subscribe((blockNumber: BlockNumber) => { + api.derive.chain.bestNumber().subscribe((blockNumber) => { expect(blockNumber instanceof BlockNumber).toBe(true); - expect(blockNumber.gten(0)).toBe(true); + expect((blockNumber as BlockNumber).gten(0)).toBe(true); done(); }); }); it('derive.session.sessionProgress', async (done) => { - api.derive.session.sessionProgress().subscribe((progress: BN) => { + api.derive.session.sessionProgress().subscribe((progress) => { expect(progress instanceof BN).toBe(true); done(); }); diff --git a/packages/api/package.json b/packages/api/package.json index b3f8271ebd..5b735f25e1 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/api", - "version": "0.39.12", + "version": "0.40.0", "description": "An RxJS wrapper around the Polkadot JS RPC", "main": "index.js", "keywords": [ @@ -30,12 +30,12 @@ "homepage": "https://github.com/polkadot-js/api/tree/master/packages/api#readme", "dependencies": { "@babel/runtime": "^7.2.0", - "@polkadot/api-derive": "^0.39.12", - "@polkadot/extrinsics": "^0.39.12", - "@polkadot/rpc-provider": "^0.39.12", - "@polkadot/rpc-rx": "^0.39.12", - "@polkadot/storage": "^0.39.12", - "@polkadot/types": "^0.39.12", + "@polkadot/api-derive": "^0.40.0", + "@polkadot/extrinsics": "^0.40.0", + "@polkadot/rpc-provider": "^0.40.0", + "@polkadot/rpc-rx": "^0.40.0", + "@polkadot/storage": "^0.40.0", + "@polkadot/types": "^0.40.0", "@types/rx": "^4.1.1", "rxjs": "^6.3.3" } diff --git a/packages/api/src/Base.ts b/packages/api/src/Base.ts index 9d8bf66076..0a993b97e1 100644 --- a/packages/api/src/Base.ts +++ b/packages/api/src/Base.ts @@ -3,18 +3,33 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { ProviderInterface } from '@polkadot/rpc-provider/types'; -import { ApiBaseInterface, ApiInterface$Events, ApiOptions } from './types'; +import { Storage } from '@polkadot/storage/types'; +import { + ApiBaseInterface, ApiInterface$Rx, ApiInterface$Events, ApiOptions, + DecoratedRpc, DecoratedRpc$Section, + Derive, DeriveSection, + OnCallFunction, + QueryableModuleStorage, QueryableStorage, QueryableStorageFunction, + SubmittableExtrinsicFunction, SubmittableExtrinsics, SubmittableModuleExtrinsics +} from './types'; import EventEmitter from 'eventemitter3'; -import Rpc from '@polkadot/rpc-core/index'; +import { Observable, of } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; +import decorateDerive, { Derive as DeriveInterface } from '@polkadot/api-derive/index'; import extrinsicsFromMeta from '@polkadot/extrinsics/fromMetadata'; -import { Storage } from '@polkadot/storage/types'; +import RpcBase from '@polkadot/rpc-core/index'; +import RpcRx from '@polkadot/rpc-rx/index'; import storageFromMeta from '@polkadot/storage/fromMetadata'; import registry from '@polkadot/types/codec/typeRegistry'; import { Event, Hash, Metadata, Method, RuntimeVersion } from '@polkadot/types/index'; -import { ModulesWithMethods } from '@polkadot/types/Method'; +import { MethodFunction, ModulesWithMethods } from '@polkadot/types/Method'; +import { StorageFunction } from '@polkadot/types/StorageKey'; +import { Codec } from '@polkadot/types/types'; import { assert, isFunction, isObject, isUndefined, logger } from '@polkadot/util'; +import SubmittableExtrinsic from './SubmittableExtrinsic'; + type MetaDecoration = { callIndex?: Uint8Array, meta: any, @@ -23,19 +38,34 @@ type MetaDecoration = { toJSON: () => any }; -const l = logger('api'); - const INIT_ERROR = `Api needs to be initialised before using, listen on 'ready'`; -export default abstract class ApiBase implements ApiBaseInterface { +const l = logger('api/decorator'); + +/** + * Put the `this.onCall` function of ApiRx here, because it is needed by + * `api._rx`. + */ +function rxOnCall ( + method: OnCallFunction>, + params: Array, + _isSubscription?: boolean +): Observable { + return method(...params); +} + +export default abstract class ApiBase implements ApiBaseInterface { private _eventemitter: EventEmitter; - protected _extrinsics?: E; - protected _genesisHash?: Hash; - protected _query?: S; - protected _rpc: R; - protected _rpcBase: Rpc; - protected _runtimeMetadata?: Metadata; - protected _runtimeVersion?: RuntimeVersion; + private _derive?: Derive; + private _extrinsics?: SubmittableExtrinsics; + private _genesisHash?: Hash; + private _query?: QueryableStorage; + private _rpc: DecoratedRpc; + protected _rpcBase: RpcBase; // FIXME These two could be merged + protected _rpcRx: RpcRx; // FIXME These two could be merged + private _runtimeMetadata?: Metadata; + private _runtimeVersion?: RuntimeVersion; + private _rx: Partial = {}; /** * @description Create an instance of the class @@ -61,8 +91,13 @@ export default abstract class ApiBase implements ApiBaseInterface implements ApiBaseInterface + * + * ```javascript + * api.derive.chain.bestNumber((number) => { + * console.log('best number', number); + * }); + * ``` + */ + get derive (): Derive { + assert(!isUndefined(this._derive), INIT_ERROR); + + return this._derive as Derive; + } + /** * @description Contains all the chain state modules and their subsequent methods in the API. These are attached dynamically from the runtime metadata. * @@ -119,10 +172,10 @@ export default abstract class ApiBase implements ApiBaseInterface { assert(!isUndefined(this._query), INIT_ERROR); - return this._query as S; + return this._query as QueryableStorage; } /** @@ -139,7 +192,7 @@ export default abstract class ApiBase implements ApiBaseInterface { return this._rpc; } @@ -158,10 +211,10 @@ export default abstract class ApiBase implements ApiBaseInterface { assert(!isUndefined(this._extrinsics), INIT_ERROR); - return this._extrinsics as E; + return this._extrinsics as SubmittableExtrinsics; } /** @@ -214,7 +267,7 @@ export default abstract class ApiBase implements ApiBaseInterface): void { + private emit (type: ApiInterface$Events, ...args: Array): void { this._eventemitter.emit(type, ...args); } @@ -251,8 +304,14 @@ export default abstract class ApiBase implements ApiBaseInterface implements ApiBaseInterface>, params: Array, isSubscription?: boolean): OnCall; + + private decorateFunctionMeta (input: MetaDecoration, output: MetaDecoration): MetaDecoration { output.meta = input.meta; output.method = input.method; output.section = input.section; @@ -278,7 +339,126 @@ export default abstract class ApiBase implements ApiBaseInterface ( + rpc: RpcRx, + onCall: (method: OnCallFunction>, params: Array, isSubscription?: boolean) => T + ): DecoratedRpc { + + return ['author', 'chain', 'state', 'system'].reduce((result, _sectionName) => { + const sectionName = _sectionName as keyof DecoratedRpc; + + result[sectionName] = Object.keys(rpc[sectionName]).reduce((section, methodName) => { + // FIXME Find a better way to know if a particular method is a subscription or not + const isSubscription = methodName.includes('subscribe'); + const method = (...params: any[]) => onCall(rpc[sectionName][methodName], params, isSubscription); + section[methodName] = method; + + return section; + }, {} as DecoratedRpc$Section); + + return result; + }, {} as DecoratedRpc); + } + + private decorateExtrinsics ( + extrinsics: ModulesWithMethods, + onCall: (method: OnCallFunction>, params: Array, isSubscription?: boolean) => T + ): SubmittableExtrinsics { + + return Object.keys(extrinsics).reduce((result, sectionName) => { + const section = extrinsics[sectionName]; + + result[sectionName] = Object.keys(section).reduce((result, methodName) => { + result[methodName] = this.decorateExtrinsicEntry(section[methodName], onCall); + + return result; + }, {} as SubmittableModuleExtrinsics); + + return result; + }, {} as SubmittableExtrinsics); + } + + private decorateExtrinsicEntry ( + method: MethodFunction, + onCall: (method: OnCallFunction>, params: Array, isSubscription?: boolean) => T + ): SubmittableExtrinsicFunction { + const decorated: any = (...args: Array): SubmittableExtrinsic => + new SubmittableExtrinsic(this._rx as ApiInterface$Rx, onCall, method(...args)); + + return this.decorateFunctionMeta(method, decorated) as SubmittableExtrinsicFunction; + } + + private decorateStorage ( + storage: Storage, + onCall: (method: OnCallFunction>, params: Array, isSubscription?: boolean) => T + ): QueryableStorage { + + return Object.keys(storage).reduce((result, sectionName) => { + const section = storage[sectionName]; + + result[sectionName] = Object.keys(section).reduce((result, methodName) => { + result[methodName] = this.decorateStorageEntry(section[methodName], onCall); + + return result; + }, {} as QueryableModuleStorage); + + return result; + }, {} as QueryableStorage); + } + + private decorateStorageEntry ( + method: StorageFunction, + onCall: (method: OnCallFunction>, params: Array, isSubscription?: boolean) => T + ): QueryableStorageFunction { + const decorated: any = (...args: any): T => { + + return onCall( + (...args: any) => this._rpcRx.state + .subscribeStorage([[method, args[0]]]) + .pipe( + // errors can occur in the case of malformed methods + args + catchError(() => of([])), + // state_storage returns an array of values, since we have just subscribed to + // a single entry, we pull that from the array and return it as-is + map((result: Array = []): Codec | null | undefined => + result[0] + ) + ), + args + ); + }; + + decorated.at = (hash: Hash, arg?: any): T => + onCall( + arg => this._rpcRx.state + .getStorage([method, arg], hash) + .pipe( + // same as above (for single result), in the case of errors on creation, return `undefined` + catchError(() => of()) + ), + [arg] + ); + + return this.decorateFunctionMeta(method, decorated) as QueryableStorageFunction; + } + + private decorateDerive ( + apiRx: ApiInterface$Rx, + onCall: (method: OnCallFunction>, params: Array, isSubscription?: boolean) => T + ): Derive { + const derive = decorateDerive(apiRx); + + return Object.keys(derive).reduce((result, _sectionName) => { + const sectionName = _sectionName as keyof DeriveInterface; + + result[sectionName] = Object.keys(derive[sectionName]).reduce((section, methodName) => { + const method = (...params: any[]) => onCall((derive[sectionName] as any)[methodName], params); + section[methodName] = method; + + return section; + }, {} as DeriveSection); + + return result; + }, {} as Derive); + } } diff --git a/packages/api/src/SubmittableExtrinsic.ts b/packages/api/src/SubmittableExtrinsic.ts new file mode 100644 index 0000000000..c3c95ee3b1 --- /dev/null +++ b/packages/api/src/SubmittableExtrinsic.ts @@ -0,0 +1,79 @@ +// Copyright 2017-2019 @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 { KeyringPair } from '@polkadot/keyring/types'; +import { Extrinsic, ExtrinsicStatus, Index, Method, SignedBlock } from '@polkadot/types/index'; +import { AnyNumber, AnyU8a } from '@polkadot/types/types'; +import { ApiInterface$Rx, OnCallFunction, SubmittableSendResult } from './types'; + +import { Observable, of, combineLatest } from 'rxjs'; +import { first, map, switchMap } from 'rxjs/operators'; + +import filterEvents from './util/filterEvents'; + +export default class SubmittableExtrinsic extends Extrinsic { + private _api: ApiInterface$Rx; + private _onCall: OnCallFunction; + + constructor (api: ApiInterface$Rx, onCall: OnCallFunction, extrinsic: Extrinsic | Method) { + super(extrinsic); + + this._api = api; + this._onCall = onCall; + } + + private trackStatus (status: ExtrinsicStatus, statusCb?: (result: SubmittableSendResult) => any): Observable { + if (status.type !== 'Finalised') { + return this._onCall( + () => of({ + status, + type: status.type + }), + [statusCb] + ) as unknown as Observable; + } + + const blockHash = status.asFinalised; + + return this._onCall( + () => combineLatest( + this._api.rpc.chain.getBlock(blockHash), + this._api.query.system.events.at(blockHash) + ).pipe( + map(([signedBlock, allEvents]) => ({ + events: filterEvents(this.hash, signedBlock as SignedBlock, allEvents as any), + status, + type: status.type + })) + ), + [statusCb] + ) as unknown as Observable; + } + + send (statusCb?: (result: SubmittableSendResult) => any): Observable { + return this._onCall( + (...args: any[]) => (this._api.rpc.author + .submitAndWatchExtrinsic(this) as Observable) + .pipe(switchMap((status) => this.trackStatus(status, statusCb))), + [statusCb] + ) as unknown as Observable; + } + + sign (signerPair: KeyringPair, nonce: AnyNumber, blockHash?: AnyU8a): SubmittableExtrinsic { + super.sign(signerPair, nonce, blockHash || this._api.genesisHash); + + return this; + } + + signAndSend (signerPair: KeyringPair, statusCb: (result: SubmittableSendResult) => any): Observable { + return this._api.query.system + .accountNonce(signerPair.address()) + .pipe( + first(), + switchMap((nonce) => + this.sign(signerPair, nonce as Index).send(statusCb) + ) + ); + } +} diff --git a/packages/api/src/promise/SubmittableExtrinsic.spec.ts b/packages/api/src/promise/SubmittableExtrinsic.spec.ts deleted file mode 100644 index 9b09b25566..0000000000 --- a/packages/api/src/promise/SubmittableExtrinsic.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2017-2019 @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 extrinsics from '@polkadot/extrinsics/static'; -import Extrinsic from '@polkadot/types/Extrinsic'; -import Method from '@polkadot/types/Method'; - -import SubmittableExtrinsic from './SubmittableExtrinsic'; - -describe('SubmittableExtrinsic', () => { - let api: any; - - beforeEach(() => { - Method.injectMethods(extrinsics); - - api = { - hasSubscriptions: true, - rpc: { - author: { - submitAndWatchExtrinsic: () => Promise.resolve('submitAndWatchExtrinsic'), - submitExtrinsic: () => Promise.resolve('submitExtrinsic') - } - } - }; - }); - - it('send calls submitAndWatchExtrinsic with statusCb', async () => { - const result = await new SubmittableExtrinsic( - api, - new Extrinsic('0x010200ea51b75b00000000') - ).send(() => { - // ignore - }); - - expect(result).toEqual('submitAndWatchExtrinsic'); - }); - - it('send calls submitExtrinsic without statusCb', async () => { - const result = await new SubmittableExtrinsic( - api, - new Extrinsic('0x010200ea51b75b00000000') - ).send(); - - expect(result).toEqual('submitExtrinsic'); - }); -}); diff --git a/packages/api/src/promise/SubmittableExtrinsic.ts b/packages/api/src/promise/SubmittableExtrinsic.ts deleted file mode 100644 index 15a7f3c703..0000000000 --- a/packages/api/src/promise/SubmittableExtrinsic.ts +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2017-2019 @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 { KeyringPair } from '@polkadot/keyring/types'; -import { AnyNumber, AnyU8a } from '@polkadot/types/types'; -import { SubmittableSendResult } from '../types'; -import { ApiPromiseInterface, PromiseSubscription } from './types'; - -import { EventRecord, Extrinsic, ExtrinsicStatus, Hash, Index, Method, SignedBlock } from '@polkadot/types/index'; -import { assert } from '@polkadot/util'; - -import filterEvents from '../util/filterEvents'; - -export default class SubmittableExtrinsic extends Extrinsic { - private _api: ApiPromiseInterface; - - constructor (api: ApiPromiseInterface, extrinsic: Extrinsic | Method) { - super(extrinsic); - - this._api = api; - } - - private trackStatus (statusCb: (result: SubmittableSendResult) => any): (status: ExtrinsicStatus) => Promise { - return async (status: ExtrinsicStatus): Promise => { - let events: Array | undefined = undefined; - - if (status.type === 'Finalised') { - const blockHash = status.asFinalised; - const signedBlock: SignedBlock = await this._api.rpc.chain.getBlock(blockHash); - const allEvents: Array = await this._api.query.system.events.at(blockHash) as any; - - events = filterEvents(this.hash, signedBlock, allEvents); - } - - statusCb({ - events, - status, - type: status.type - }); - }; - } - - send (statusCb?: (result: SubmittableSendResult) => any): Promise | PromiseSubscription { - if (!statusCb || !this._api.hasSubscriptions) { - return this._api.rpc.author.submitExtrinsic(this); - } - - return this._api.rpc.author.submitAndWatchExtrinsic(this, this.trackStatus(statusCb)); - } - - sign (signerPair: KeyringPair, nonce: AnyNumber, blockHash?: AnyU8a): SubmittableExtrinsic { - super.sign(signerPair, nonce, blockHash || this._api.genesisHash); - - return this; - } - - async signAndSend (signerPair: KeyringPair, statusCb: (result: SubmittableSendResult) => any): PromiseSubscription { - assert(this._api.hasSubscriptions, 'Api does not support subscriptions'); - - const signerNonce = await this._api.query.system.accountNonce(signerPair.address()); - - return this - .sign(signerPair, signerNonce as Index) - .send(statusCb) as PromiseSubscription; - } -} diff --git a/packages/api/src/promise/index.ts b/packages/api/src/promise/index.ts index d92ef83db2..019dfdcd37 100644 --- a/packages/api/src/promise/index.ts +++ b/packages/api/src/promise/index.ts @@ -2,27 +2,19 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { RpcRxInterface$Method } from '@polkadot/rpc-rx/types'; import { ProviderInterface } from '@polkadot/rpc-provider/types'; import { ApiOptions } from '../types'; -import { ApiPromiseInterface, DecoratedRpc, DecoratedRpc$Method, DecoratedRpc$Section, QueryableStorageFunction, QueryableModuleStorage, QueryableStorage, SubmittableExtrinsics, SubmittableModuleExtrinsics, SubmittableExtrinsicFunction, PromiseSubscription } from './types'; +import { ApiPromiseInterface, OnCall, PromiseSubscription } from './types'; -import { EMPTY } from 'rxjs'; -import { tap, catchError } from 'rxjs/operators'; -import Rpc from '@polkadot/rpc-core/index'; -import RpcRx from '@polkadot/rpc-rx/index'; -import { Storage } from '@polkadot/storage/types'; -import { Hash } from '@polkadot/types/index'; +import { EMPTY, Observable } from 'rxjs'; +import { catchError, first, tap } from 'rxjs/operators'; import { Codec } from '@polkadot/types/types'; -import { MethodFunction, ModulesWithMethods } from '@polkadot/types/Method'; -import { StorageFunction } from '@polkadot/types/StorageKey'; -import { isFunction, logger, assert } from '@polkadot/util'; +import { isFunction } from '@polkadot/util'; import ApiBase from '../Base'; import Combinator, { CombinatorCallback, CombinatorFunction } from './Combinator'; -import SubmittableExtrinsic from './SubmittableExtrinsic'; -const l = logger('api/promise'); +type RxFn = (...params: Array) => Observable; /** * # @polkadot/api/promise @@ -110,7 +102,7 @@ const l = logger('api/promise'); * }); * ``` */ -export default class ApiPromise extends ApiBase implements ApiPromiseInterface { +export default class ApiPromise extends ApiBase implements ApiPromiseInterface { private _isReady: Promise; /** @@ -173,65 +165,6 @@ export default class ApiPromise extends ApiBase; - const rpcrx = new RpcRx(rpc); - - return names.reduce((result, section) => { - result[section] = Object.keys(rpcrx[section]).reduce((fns, method) => { - fns[method] = this.decorateMethod( - rpcrx[section][method], - isFunction(rpc[section][method].unsubscribe) - ); - - return fns; - }, {} as DecoratedRpc$Section); - - return result; - }, {} as DecoratedRpc); - } - - protected decorateMethod (rxfn: RpcRxInterface$Method, isSubscription: boolean): DecoratedRpc$Method { - if (!isSubscription) { - return (...params: Array): Promise => - rxfn(...params).toPromise(); - } - - return (..._params: Array): PromiseSubscription => { - const cb = _params[_params.length - 1]; - - assert(isFunction(cb), 'Expected callback as last paramater for subscription'); - - return new Promise((resolve, reject) => { - let isCompleted = false; - const params = _params.slice(0, _params.length - 1); - const subscription = rxfn(...params) - .pipe( - // if we find an error (invalid params, etc), reject the promise - catchError((error) => { - if (!isCompleted) { - isCompleted = true; - - reject(error); - } - - // we don't want to continue, so empty observable it is - return EMPTY; - }), - // upon the first result, resolve the with the unsub function - tap(() => { - if (!isCompleted) { - isCompleted = true; - - resolve(() => subscription.unsubscribe()); - } - }) - ) - .subscribe(cb); - }); - }; - } - /** * @description Creates a combinator that can be used to combine the latest results from multiple subscriptions * @param fns An array of function to combine, each in the form of `(cb: (value: void)) => void` @@ -260,63 +193,46 @@ export default class ApiPromise extends ApiBase { - const section = extrinsics[sectionName]; + protected onCall (method: RxFn, params: Array, isSubscription?: boolean): OnCall { + if (!params || params.length === 0 || isSubscription === false) { + return method(...params).pipe(first()).toPromise(); + } - result[sectionName] = Object.keys(section).reduce((result, methodName) => { - result[methodName] = this.decorateExtrinsicEntry(section[methodName]); + const cb = params[params.length - 1]; + const remainingParams = params.slice(0, - 1); - return result; - }, {} as SubmittableModuleExtrinsics); + if (!isFunction(cb)) { + return method(...params).pipe(first()).toPromise(); + } - return result; - }, {} as SubmittableExtrinsics); - } + // FIXME TSLint shouts that type assertion is unnecessary, but tsc shouts + // when I remove it... + // tslint:disable-next-line + return new Promise((resolve, reject) => { + let isCompleted = false; + const subscription = method(...remainingParams) + .pipe( + // if we find an error (invalid params, etc), reject the promise + catchError((error) => { + if (!isCompleted) { + isCompleted = true; - private decorateExtrinsicEntry (method: MethodFunction): SubmittableExtrinsicFunction { - const decorated: any = (...args: Array): SubmittableExtrinsic => - new SubmittableExtrinsic(this, method(...args)); + reject(error); + } - return this.decorateFunctionMeta(method, decorated) as SubmittableExtrinsicFunction; - } + // we don't want to continue, so empty observable it is + return EMPTY; + }), + // upon the first result, resolve the with the unsub function + tap(() => { + if (!isCompleted) { + isCompleted = true; - protected decorateStorage (storage: Storage): QueryableStorage { - return Object.keys(storage).reduce((result, sectionName) => { - const section = storage[sectionName]; - - result[sectionName] = Object.keys(section).reduce((result, methodName) => { - result[methodName] = this.decorateStorageEntry(section[methodName]); - - return result; - }, {} as QueryableModuleStorage); - - return result; - }, {} as QueryableStorage); - } - - private decorateStorageEntry (method: StorageFunction): QueryableStorageFunction { - const decorated: any = (...args: Array): Promise | PromiseSubscription => { - const cb = args[args.length - 1]; - - if (args.length === 0 || !isFunction(cb)) { - return this.rpc.state.getStorage([method, args[0]]); - } else if (!this.hasSubscriptions && isFunction(cb)) { - l.warn(`Storage subscription to ${method.section}.${method.name} ignored, provider does not support subscriptions`); - - return this.rpc.state.getStorage([method, args.length === 1 ? undefined : args[0]]); - } - - return this.rpc.state.subscribeStorage( - [[method, args.length === 1 ? undefined : args[0]]], - (result: Array = []) => - cb(result[0]) - ) as PromiseSubscription; - }; - - decorated.at = (hash: Hash, arg?: any): Promise => - this.rpc.state.getStorage([method, arg], hash) as Promise; - - return this.decorateFunctionMeta(method, decorated) as QueryableStorageFunction; + resolve(() => subscription.unsubscribe()); + } + }) + ) + .subscribe(cb); + }) as PromiseSubscription; } } diff --git a/packages/api/src/promise/types.ts b/packages/api/src/promise/types.ts index 2a66dbaa41..806e41cc7d 100644 --- a/packages/api/src/promise/types.ts +++ b/packages/api/src/promise/types.ts @@ -2,61 +2,14 @@ // 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/index'; import { Codec } from '@polkadot/types/types'; -import { MethodFunction } from '@polkadot/types/Method'; -import { StorageFunction } from '@polkadot/types/StorageKey'; -import { ApiBaseInterface } from '../types'; -import SubmittableExtrinsic from './SubmittableExtrinsic'; +import ApiBase from '../Base'; + +export type OnCall = Promise | PromiseSubscription; export type PromiseSubscription = Promise<() => any>; -export type DecoratedRpc$Method = (...params: Array) => Promise | PromiseSubscription; - -export interface DecoratedRpc$Section { - [index: string]: DecoratedRpc$Method; -} - -export interface DecoratedRpc { - author: DecoratedRpc$Section; - chain: DecoratedRpc$Section; - state: DecoratedRpc$Section; - system: DecoratedRpc$Section; -} - -export interface QueryableStorageFunction$Subscribe { - (arg: any, cb: (value?: any | null) => any): PromiseSubscription; - (cb: (value?: any | null) => any): PromiseSubscription; -} - -export interface QueryableStorageFunction extends StorageFunction { - (cb: (value?: any | null) => any): PromiseSubscription; - (arg: any, cb: (value?: any | null) => any): PromiseSubscription; - (arg?: any): Promise; - at: (hash: Hash, arg?: any) => Promise; -} - -export interface QueryableModuleStorage { - [index: string]: QueryableStorageFunction; -} - -export interface QueryableStorage { - [index: string]: QueryableModuleStorage; -} - -export interface SubmittableExtrinsicFunction extends MethodFunction { - (...args: any[]): SubmittableExtrinsic; -} - -export interface SubmittableModuleExtrinsics { - [index: string]: SubmittableExtrinsicFunction; -} - -export interface SubmittableExtrinsics { - [index: string]: SubmittableModuleExtrinsics; -} - -export interface ApiPromiseInterface extends ApiBaseInterface { +export interface ApiPromiseInterface extends ApiBase { readonly isReady: Promise; } diff --git a/packages/api/src/rx/SubmittableExtrinsic.ts b/packages/api/src/rx/SubmittableExtrinsic.ts deleted file mode 100644 index 03c610dc96..0000000000 --- a/packages/api/src/rx/SubmittableExtrinsic.ts +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2017-2019 @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 { KeyringPair } from '@polkadot/keyring/types'; -import { AnyNumber, AnyU8a } from '@polkadot/types/types'; -import { SubmittableSendResult } from '../types'; -import { ApiRxInterface } from './types'; - -import { Observable, of, combineLatest } from 'rxjs'; -import { first, map, switchMap } from 'rxjs/operators'; -import { Extrinsic, ExtrinsicStatus, Index, Method } from '@polkadot/types/index'; - -import filterEvents from '../util/filterEvents'; - -export default class SubmittableExtrinsic extends Extrinsic { - private _api: ApiRxInterface; - - constructor (api: ApiRxInterface, extrinsic: Extrinsic | Method) { - super(extrinsic); - - this._api = api; - } - - private trackStatus = (status: ExtrinsicStatus): Observable => { - if (status.type !== 'Finalised') { - return of({ - status, - type: status.type - }); - } - - const blockHash = status.asFinalised; - - return combineLatest( - this._api.rpc.chain.getBlock(blockHash), - this._api.query.system.events.at(blockHash) - ).pipe( - map(([signedBlock, allEvents]) => ({ - events: filterEvents(this.hash, signedBlock, allEvents as any), - status, - type: status.type - })) - ); - } - - send (): Observable { - return this._api.rpc.author - .submitAndWatchExtrinsic(this) - .pipe(switchMap(this.trackStatus)); - } - - sign (signerPair: KeyringPair, nonce: AnyNumber, blockHash?: AnyU8a): SubmittableExtrinsic { - super.sign(signerPair, nonce, blockHash || this._api.genesisHash); - - return this; - } - - signAndSend (signerPair: KeyringPair): Observable { - return this._api.query.system - .accountNonce(signerPair.address()) - .pipe( - first(), - switchMap((nonce) => - this.sign(signerPair, nonce as Index).send() - ) - ); - } -} diff --git a/packages/api/src/rx/index.ts b/packages/api/src/rx/index.ts index fe2b3a49b3..e89617690b 100644 --- a/packages/api/src/rx/index.ts +++ b/packages/api/src/rx/index.ts @@ -3,23 +3,13 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { ProviderInterface } from '@polkadot/rpc-provider/types'; -import { ApiOptions } from '../types'; -import { ApiRxInterface, QueryableStorageFunction, QueryableModuleStorage, QueryableStorage, SubmittableExtrinsics, SubmittableModuleExtrinsics, SubmittableExtrinsicFunction } from './types'; +import { ApiRxInterface, OnCall } from './types'; +import { ApiOptions, OnCallFunction } from '../types'; -import { Observable, from, of } from 'rxjs'; -import { catchError, map } from 'rxjs/operators'; -import decorateDerive, { Derive } from '@polkadot/api-derive/index'; -import Rpc from '@polkadot/rpc-core/index'; -import RpcRx from '@polkadot/rpc-rx/index'; -import { Storage } from '@polkadot/storage/types'; -import { Hash } from '@polkadot/types/index'; +import { Observable, from } from 'rxjs'; import { Codec } from '@polkadot/types/types'; -import { MethodFunction, ModulesWithMethods } from '@polkadot/types/Method'; -import { StorageFunction } from '@polkadot/types/StorageKey'; -import { assert } from '@polkadot/util'; import ApiBase from '../Base'; -import SubmittableExtrinsic from './SubmittableExtrinsic'; /** * # @polkadot/api/rx @@ -118,8 +108,7 @@ import SubmittableExtrinsic from './SubmittableExtrinsic'; * }); * ``` */ -export default class ApiRx extends ApiBase implements ApiRxInterface { - protected _derive: Derive; +export default class ApiRx extends ApiBase implements ApiRxInterface { private _isReady: Observable; /** @@ -162,12 +151,9 @@ export default class ApiRx extends ApiBase @@ -178,15 +164,11 @@ export default class ApiRx extends ApiBase { - return this.rpc.isConnected(); + return this._rpcRx.isConnected(); } /** @@ -196,69 +178,7 @@ export default class ApiRx extends ApiBase { - const section = extrinsics[sectionName]; - - result[sectionName] = Object.keys(section).reduce((result, methodName) => { - result[methodName] = this.decorateExtrinsicEntry(section[methodName]); - - return result; - }, {} as SubmittableModuleExtrinsics); - - return result; - }, {} as SubmittableExtrinsics); - } - - private decorateExtrinsicEntry (method: MethodFunction): SubmittableExtrinsicFunction { - const decorated: any = (...args: Array): SubmittableExtrinsic => - new SubmittableExtrinsic(this, method(...args)); - - return this.decorateFunctionMeta(method, decorated) as SubmittableExtrinsicFunction; - } - - protected decorateStorage (storage: Storage): QueryableStorage { - return Object.keys(storage).reduce((result, sectionName) => { - const section = storage[sectionName]; - - result[sectionName] = Object.keys(section).reduce((result, methodName) => { - result[methodName] = this.decorateStorageEntry(section[methodName]); - - return result; - }, {} as QueryableModuleStorage); - - return result; - }, {} as QueryableStorage); - } - - private decorateStorageEntry (method: StorageFunction): QueryableStorageFunction { - const decorated: any = (arg?: any): Observable => { - - return this.rpc.state - .subscribeStorage([[method, arg]]) - .pipe( - // errors can occur in the case of malformed methods + args - catchError(() => of([])), - // state_storage returns an array of values, since we have just subscribed to - // a single entry, we pull that from the array and return it as-is - map((result: Array = []): Codec | null | undefined => - result[0] - ) - ); - }; - - decorated.at = (hash: Hash, arg?: any): Observable => - this.rpc.state - .getStorage([method, arg], hash) - .pipe( - // same as above (for single result), in the case of errors on creation, return `undefined` - catchError(() => of()) - ); - - return this.decorateFunctionMeta(method, decorated) as QueryableStorageFunction; + protected onCall (method: OnCallFunction>, params: Array): OnCall { + return method(...params); } } diff --git a/packages/api/src/rx/types.ts b/packages/api/src/rx/types.ts index 12a111bdba..9695dcc770 100644 --- a/packages/api/src/rx/types.ts +++ b/packages/api/src/rx/types.ts @@ -2,43 +2,14 @@ // 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/index'; -import { Codec } from '@polkadot/types/types'; -import { MethodFunction } from '@polkadot/types/Method'; -import { StorageFunction } from '@polkadot/types/StorageKey'; -import { ApiBaseInterface } from '../types'; - import { Observable } from 'rxjs'; -import RpcRx from '@polkadot/rpc-rx/index'; +import { Codec } from '@polkadot/types/types'; -import SubmittableExtrinsic from './SubmittableExtrinsic'; +import ApiBase from '../Base'; -export interface QueryableStorageFunction extends StorageFunction { - (arg?: any): Observable; - at: (hash: Hash, arg?: any) => Observable; -} +export type OnCall = Observable; -export interface QueryableModuleStorage { - [index: string]: QueryableStorageFunction; -} - -export interface QueryableStorage { - [index: string]: QueryableModuleStorage; -} - -export interface SubmittableExtrinsicFunction extends MethodFunction { - (...args: any[]): SubmittableExtrinsic; -} - -export interface SubmittableModuleExtrinsics { - [index: string]: SubmittableExtrinsicFunction; -} - -export interface SubmittableExtrinsics { - [index: string]: SubmittableModuleExtrinsics; -} - -export interface ApiRxInterface extends ApiBaseInterface { +export interface ApiRxInterface extends ApiBase { readonly isConnected: Observable; readonly isReady: Observable; } diff --git a/packages/api/src/types.ts b/packages/api/src/types.ts index 8873aa6447..56a3fa6ffd 100644 --- a/packages/api/src/types.ts +++ b/packages/api/src/types.ts @@ -2,24 +2,70 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. +import { Observable } from 'rxjs'; import { ProviderInterface } from '@polkadot/rpc-provider/types'; import { RpcRxInterface$Events } from '@polkadot/rpc-rx/types'; import { EventRecord, ExtrinsicStatus, Hash, Metadata, RuntimeVersion } from '@polkadot/types/index'; -import { Constructor } from '@polkadot/types/types'; +import { Codec, Constructor } from '@polkadot/types/types'; +import { MethodFunction } from '@polkadot/types/Method'; +import { StorageFunction } from '@polkadot/types/StorageKey'; -export type ApiInterface$Events = RpcRxInterface$Events | 'ready'; +import SubmittableExtrinsic from './SubmittableExtrinsic'; -export interface ApiBaseInterface { - readonly genesisHash: Hash; - readonly hasSubscriptions: boolean; - readonly runtimeMetadata: Metadata; - readonly runtimeVersion: RuntimeVersion; - readonly query: S; - readonly rpc: R; - readonly tx: E; +export type OnCallFunction = (...args: any[]) => OnCall; - on: (type: ApiInterface$Events, handler: (...args: Array) => any) => this; - once: (type: ApiInterface$Events, handler: (...args: Array) => any) => this; +export type DecoratedRpc$Method = (...params: Array) => OnCall; + +export interface DecoratedRpc$Section { + [index: string]: DecoratedRpc$Method; +} + +export interface DecoratedRpc { + author: DecoratedRpc$Section; + chain: DecoratedRpc$Section; + state: DecoratedRpc$Section; + system: DecoratedRpc$Section; +} + +export interface QueryableStorageFunction extends StorageFunction { + (arg?: any): OnCall; + at: (hash: Hash, arg?: any) => OnCall; +} + +export interface QueryableModuleStorage { + [index: string]: QueryableStorageFunction; +} + +export interface QueryableStorage { + [index: string]: QueryableModuleStorage; +} + +export interface SubmittableExtrinsicFunction extends MethodFunction { + (...args: any[]): SubmittableExtrinsic; +} + +export interface SubmittableModuleExtrinsics { + [index: string]: SubmittableExtrinsicFunction; +} + +export interface SubmittableExtrinsics { + [index: string]: SubmittableModuleExtrinsics; +} + +export type SubmittableSendResult = { + events?: Array, + status: ExtrinsicStatus, + type: string +}; + +export type DeriveMethod = (...params: Array) => OnCall; + +export interface DeriveSection { + [index: string]: DeriveMethod; +} + +export interface Derive { + [index: string]: DeriveSection; } export interface ApiOptions { @@ -32,11 +78,25 @@ export interface ApiOptions { * @description Additional types used by runtime modules. This is nessusary if the runtime modules * uses types not available in the base Substrate runtime. */ - types?: {[name: string]: Constructor}; + types?: { [name: string]: Constructor }; } -export type SubmittableSendResult = { - events?: Array, - status: ExtrinsicStatus, - type: string -}; +export interface ApiInterface$Decorated { + genesisHash: Hash; + hasSubscriptions: boolean; + runtimeMetadata: Metadata; + runtimeVersion: RuntimeVersion; + derive: Derive; + query: QueryableStorage; + rpc: DecoratedRpc; + tx: SubmittableExtrinsics; +} + +export type ApiInterface$Rx = ApiInterface$Decorated>; + +export type ApiInterface$Events = RpcRxInterface$Events | 'ready'; + +export interface ApiBaseInterface extends Readonly> { + on: (type: ApiInterface$Events, handler: (...args: Array) => any) => this; + once: (type: ApiInterface$Events, handler: (...args: Array) => any) => this; +} diff --git a/packages/api/test/e2e/promise-queries.spec.js b/packages/api/test/e2e/promise-queries.spec.js index a9502df33d..fa5f700fc6 100644 --- a/packages/api/test/e2e/promise-queries.spec.js +++ b/packages/api/test/e2e/promise-queries.spec.js @@ -12,10 +12,10 @@ const keyring = testingPairs(); describe.skip('e2e queries', () => { let api; - beforeEach(async () => { + beforeEach(async (done) => { api = await Api.create(); - - // console.error(api); + jest.setTimeout(30000); + done(); }); it('makes the runtime, rpc, state & extrinsics available', () => { @@ -25,6 +25,7 @@ describe.skip('e2e queries', () => { expect(api.rpc).toBeDefined(); expect(api.query).toBeDefined(); expect(api.tx).toBeDefined(); + expect(api.derive).toBeDefined(); }); it('queries state for a balance', async () => { diff --git a/packages/api/test/e2e/promise-tx.spec.js b/packages/api/test/e2e/promise-tx.spec.js index 8f2c09331a..df0bb340f3 100644 --- a/packages/api/test/e2e/promise-tx.spec.js +++ b/packages/api/test/e2e/promise-tx.spec.js @@ -10,11 +10,11 @@ const keyring = testingPairs(); describe.skip('e2e transactions', () => { let api; - let nonce; - beforeEach(async () => { + beforeEach(async (done) => { api = await Api.create(); jest.setTimeout(30000); + done(); }); afterEach(() => { diff --git a/packages/api/test/e2e/rx-queries.spec.js b/packages/api/test/e2e/rx-queries.spec.js index 6319467983..13979a7ec8 100644 --- a/packages/api/test/e2e/rx-queries.spec.js +++ b/packages/api/test/e2e/rx-queries.spec.js @@ -12,10 +12,10 @@ const keyring = testingPairs(); describe.skip('e2e queries', () => { let api; - beforeEach(async () => { + beforeEach(async (done) => { api = await Api.create().toPromise(); - - // console.error(api); + jest.setTimeout(30000); + done(); }); it('makes the runtime, rpc, state & extrinsics available', () => { @@ -25,6 +25,7 @@ describe.skip('e2e queries', () => { expect(api.rpc).toBeDefined(); expect(api.query).toBeDefined(); expect(api.tx).toBeDefined(); + expect(api.derive).toBeDefined(); }); it('queries state for a balance', (done) => { diff --git a/packages/api/test/e2e/rx-tx.spec.js b/packages/api/test/e2e/rx-tx.spec.js index 0539a5b13a..def6f0894b 100644 --- a/packages/api/test/e2e/rx-tx.spec.js +++ b/packages/api/test/e2e/rx-tx.spec.js @@ -12,9 +12,10 @@ const keyring = testingPairs(); describe.skip('e2e transactions', () => { let api; - beforeEach(async () => { + beforeEach(async (done) => { api = await Api.create().toPromise(); jest.setTimeout(30000); + done() }); afterEach(() => { diff --git a/packages/rpc-core/package.json b/packages/rpc-core/package.json index 6eba03b59d..6d2b9e9173 100644 --- a/packages/rpc-core/package.json +++ b/packages/rpc-core/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/rpc-core", - "version": "0.39.12", + "version": "0.40.0", "description": "A JavaScript wrapper for the Polkadot JsonRPC interface", "main": "index.js", "keywords": [ @@ -30,9 +30,9 @@ "homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-core#readme", "dependencies": { "@babel/runtime": "^7.2.0", - "@polkadot/jsonrpc": "^0.39.12", - "@polkadot/rpc-provider": "^0.39.12", - "@polkadot/types": "^0.39.12", + "@polkadot/jsonrpc": "^0.40.0", + "@polkadot/rpc-provider": "^0.40.0", + "@polkadot/types": "^0.40.0", "@polkadot/util": "^0.33.34" } } diff --git a/packages/rpc-provider/package.json b/packages/rpc-provider/package.json index 1ead53da17..6a9ab3afbe 100644 --- a/packages/rpc-provider/package.json +++ b/packages/rpc-provider/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/rpc-provider", - "version": "0.39.12", + "version": "0.40.0", "description": "Transport providers for the API", "main": "index.js", "keywords": [ @@ -31,7 +31,7 @@ "dependencies": { "@babel/runtime": "^7.2.0", "@polkadot/keyring": "^0.33.34", - "@polkadot/storage": "^0.39.12", + "@polkadot/storage": "^0.40.0", "@polkadot/util": "^0.33.34", "@polkadot/util-crypto": "^0.33.34", "@types/nock": "^9.3.0", diff --git a/packages/rpc-rx/package.json b/packages/rpc-rx/package.json index bfce63c04e..5c20435bd6 100644 --- a/packages/rpc-rx/package.json +++ b/packages/rpc-rx/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/rpc-rx", - "version": "0.39.12", + "version": "0.40.0", "description": "An RxJs wrapper around the Polkadot JS API", "main": "index.js", "keywords": [ @@ -30,8 +30,8 @@ "homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-rx#readme", "dependencies": { "@babel/runtime": "^7.2.0", - "@polkadot/rpc-core": "^0.39.12", - "@polkadot/rpc-provider": "^0.39.12", + "@polkadot/rpc-core": "^0.40.0", + "@polkadot/rpc-provider": "^0.40.0", "@types/rx": "^4.1.1", "rxjs": "^6.3.3" } diff --git a/packages/type-extrinsics/package.json b/packages/type-extrinsics/package.json index e0de7e4463..1db0b207ce 100644 --- a/packages/type-extrinsics/package.json +++ b/packages/type-extrinsics/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/extrinsics", - "version": "0.39.12", + "version": "0.40.0", "main": "index.js", "repository": "https://github.com/polkadot-js/api.git", "author": "Jaco Greeff ", @@ -11,7 +11,7 @@ "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.2.0", - "@polkadot/types": "^0.39.12", + "@polkadot/types": "^0.40.0", "@polkadot/util": "^0.33.34" } } diff --git a/packages/type-jsonrpc/package.json b/packages/type-jsonrpc/package.json index eacfc14673..fcacbc20bb 100644 --- a/packages/type-jsonrpc/package.json +++ b/packages/type-jsonrpc/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/jsonrpc", - "version": "0.39.12", + "version": "0.40.0", "description": "Method definitions for the Polkadot RPC layer", "main": "index.js", "engines": { diff --git a/packages/type-storage/package.json b/packages/type-storage/package.json index 094e379f17..4191dd14e4 100644 --- a/packages/type-storage/package.json +++ b/packages/type-storage/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/storage", - "version": "0.39.12", + "version": "0.40.0", "description": "Generic wrapper wrapper around state storage", "main": "index.js", "engines": { @@ -31,7 +31,7 @@ "dependencies": { "@babel/runtime": "^7.2.0", "@polkadot/keyring": "^0.33.34", - "@polkadot/types": "^0.39.12", + "@polkadot/types": "^0.40.0", "@polkadot/util": "^0.33.34", "@polkadot/util-crypto": "^0.33.34" } diff --git a/packages/types/package.json b/packages/types/package.json index 33490881f9..bd3eb12830 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/types", - "version": "0.39.12", + "version": "0.40.0", "description": "Implementation of the Parity codec", "main": "index.js", "keywords": [