Add Signer with status updates (#675)
* Add Signer with status updates * Remove useless (now) updateId check * Don't send updates for non-owned extrinsics * opt -> options
This commit is contained in:
@@ -5,12 +5,13 @@
|
||||
import { KeyringPair } from '@polkadot/keyring/types';
|
||||
import { Struct, Vector } from '@polkadot/types/codec';
|
||||
import { AccountId, Address, Extrinsic, ExtrinsicStatus, EventRecord, Hash, Index, Method, RuntimeVersion, SignedBlock, Text } from '@polkadot/types/index';
|
||||
import { SignatureOptions } from '@polkadot/types/ExtrinsicSignature';
|
||||
import { AnyNumber, AnyU8a, CodecCallback } from '@polkadot/types/types';
|
||||
import { ApiInterface$Rx, ApiType, OnCallDefinition, Signer } from './types';
|
||||
|
||||
import { Observable, of, combineLatest } from 'rxjs';
|
||||
import { first, map, mergeMap, switchMap } from 'rxjs/operators';
|
||||
import { isBn, isFunction, isNumber, isUndefined, assert } from '@polkadot/util';
|
||||
import { first, map, mergeMap, switchMap, tap } from 'rxjs/operators';
|
||||
import { assert, isBn, isFunction, isNumber, isUndefined } from '@polkadot/util';
|
||||
|
||||
import filterEvents from './util/filterEvents';
|
||||
|
||||
@@ -77,6 +78,12 @@ export default class SubmittableExtrinsic<CodecResult, SubscriptionResult> exten
|
||||
this._onCall = onCall;
|
||||
}
|
||||
|
||||
private updateSigner (updateId: number, status: Hash | SubmittableResult): void {
|
||||
if ((updateId !== -1) && this._api.signer && this._api.signer.update) {
|
||||
this._api.signer.update(updateId, status);
|
||||
}
|
||||
}
|
||||
|
||||
private statusObservable (status: ExtrinsicStatus): Observable<SubmittableResult> {
|
||||
if (status.type !== 'Finalised') {
|
||||
return of(
|
||||
@@ -103,20 +110,37 @@ export default class SubmittableExtrinsic<CodecResult, SubscriptionResult> exten
|
||||
);
|
||||
}
|
||||
|
||||
private sendObservable (): Observable<Hash> {
|
||||
return this._api.rpc.author.submitExtrinsic(this) as Observable<Hash>;
|
||||
private sendObservable (updateId: number = -1): Observable<Hash> {
|
||||
return (this._api.rpc.author
|
||||
.submitExtrinsic(this) as Observable<Hash>)
|
||||
.pipe(
|
||||
tap((hash) => {
|
||||
this.updateSigner(updateId, hash);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private subscribeObservable (): Observable<SubmittableResult> {
|
||||
private subscribeObservable (updateId: number = -1): Observable<SubmittableResult> {
|
||||
return (this._api.rpc.author
|
||||
.submitAndWatchExtrinsic(this) as Observable<ExtrinsicStatus>)
|
||||
.pipe(
|
||||
switchMap((status) =>
|
||||
this.statusObservable(status)
|
||||
)
|
||||
),
|
||||
tap((status) => {
|
||||
this.updateSigner(updateId, status);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private expandOptions (options: SignatureOptionsPartial): SignatureOptions {
|
||||
return {
|
||||
blockHash: this._api.genesisHash,
|
||||
version: this._api.runtimeVersion,
|
||||
...options
|
||||
};
|
||||
}
|
||||
|
||||
send (): SumbitableResultResult<CodecResult, SubscriptionResult>;
|
||||
send (statusCb: (result: SubmittableResult) => any): SumbitableResultSubscription<CodecResult, SubscriptionResult>;
|
||||
send (statusCb?: (result: SubmittableResult) => any): SumbitableResultResult<CodecResult, SubscriptionResult> | SumbitableResultSubscription<CodecResult, SubscriptionResult> {
|
||||
@@ -142,11 +166,7 @@ export default class SubmittableExtrinsic<CodecResult, SubscriptionResult> exten
|
||||
? { nonce: _options as any as number }
|
||||
: _options;
|
||||
|
||||
super.sign(account, {
|
||||
blockHash: this._api.genesisHash,
|
||||
version: this._api.runtimeVersion,
|
||||
...options
|
||||
});
|
||||
super.sign(account, this.expandOptions(options));
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -165,6 +185,8 @@ export default class SubmittableExtrinsic<CodecResult, SubscriptionResult> exten
|
||||
const isSubscription = this._noStatusCb || !!statusCb;
|
||||
const isKeyringPair = isFunction((account as KeyringPair).address) && isFunction((account as KeyringPair).sign);
|
||||
const address = isKeyringPair ? (account as KeyringPair).address() : account.toString();
|
||||
let updateId: number | undefined;
|
||||
|
||||
return this._onCall(
|
||||
() => (
|
||||
isUndefined(options.nonce)
|
||||
@@ -177,18 +199,14 @@ export default class SubmittableExtrinsic<CodecResult, SubscriptionResult> exten
|
||||
this.sign(account as KeyringPair, { ...options, nonce });
|
||||
} else {
|
||||
assert(this._api.signer, 'no signer exists');
|
||||
await (this._api.signer as Signer).sign(this, address, {
|
||||
blockHash: options.blockHash || this._api.genesisHash,
|
||||
version: options.version || this._api.runtimeVersion,
|
||||
era: options.era,
|
||||
nonce
|
||||
});
|
||||
|
||||
updateId = await (this._api.signer as Signer).sign(this, address, this.expandOptions({ ...options, nonce }));
|
||||
}
|
||||
}),
|
||||
switchMap(() => {
|
||||
return isSubscription
|
||||
? this.subscribeObservable()
|
||||
: this.sendObservable() as any; // ???
|
||||
? this.subscribeObservable(updateId)
|
||||
: this.sendObservable(updateId) as any; // ???
|
||||
})
|
||||
),
|
||||
[],
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
|
||||
export { default as ApiPromise } from './promise';
|
||||
export { default as ApiRx } from './rx';
|
||||
export { default as SubmittableExtrinsic, SubmittableResult } from './SubmittableExtrinsic';
|
||||
|
||||
@@ -12,7 +12,7 @@ import { MethodFunction } from '@polkadot/types/Method';
|
||||
import { StorageFunction } from '@polkadot/types/StorageKey';
|
||||
|
||||
import { RxResult } from './rx/types';
|
||||
import SubmittableExtrinsic from './SubmittableExtrinsic';
|
||||
import SubmittableExtrinsic, { SubmittableResult } from './SubmittableExtrinsic';
|
||||
import ApiBase from './Base';
|
||||
|
||||
export type OnCallDefinition<CodecResult, SubscriptionResult> = (method: OnCallFunction<RxResult, RxResult>, params?: Array<CodecArg>, callback?: CodecCallback, needsCallback?: boolean) => CodecResult | SubscriptionResult;
|
||||
@@ -142,5 +142,13 @@ export interface ApiBaseInterface<CodecResult, SubscriptionResult> extends Reado
|
||||
}
|
||||
|
||||
export interface Signer {
|
||||
sign (extrinsic: Extrinsic, address: string, opt: SignatureOptions): Promise<void>;
|
||||
/**
|
||||
* @description Signs an extrinsic, returning an id (>0) that can be used to retrieve updates
|
||||
*/
|
||||
sign (extrinsic: Extrinsic, address: string, options: SignatureOptions): Promise<number>;
|
||||
|
||||
/**
|
||||
* @description Receives an update for the extrinsic signed by a `signer.sign`
|
||||
*/
|
||||
update?: (id: number, status: Hash | SubmittableResult) => void;
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
export default class SingleAccountSigner{
|
||||
constructor(keyringPair){
|
||||
this.keyringPair = keyringPair;
|
||||
}
|
||||
|
||||
async sign(extrinsic, address, opt) {
|
||||
if(!this.keyringPair || String(address) !== this.keyringPair.address()){
|
||||
throw new Error('does not have the keyringPair');
|
||||
}
|
||||
extrinsic.sign(this.keyringPair, opt);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// 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 { SignatureOptions } from '@polkadot/types/ExtrinsicSignature';
|
||||
import { Extrinsic } from '@polkadot/types/index';
|
||||
|
||||
let id = 0;
|
||||
|
||||
export default class SingleAccountSigner {
|
||||
private keyringPair: KeyringPair;
|
||||
|
||||
constructor (keyringPair: KeyringPair) {
|
||||
this.keyringPair = keyringPair;
|
||||
}
|
||||
|
||||
async sign (extrinsic: Extrinsic, address: string, options: SignatureOptions) {
|
||||
if (!this.keyringPair || String(address) !== this.keyringPair.address()) {
|
||||
throw new Error('does not have the keyringPair');
|
||||
}
|
||||
|
||||
extrinsic.sign(this.keyringPair, options);
|
||||
|
||||
return ++id;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user