Fill signAsync with expanded chain options (#1753)
* Fill signAsync with expanded chain options * Use mapTo * Fill test with defined storage value * Remove .only
This commit is contained in:
@@ -90,6 +90,15 @@ describe('ApiPromise', (): void => {
|
||||
|
||||
describe('decorator.signAsync', (): void => {
|
||||
it('signs a transfer using an external signer', async (): Promise<void> => {
|
||||
provider.subscriptions.state_subscribeStorage.lastValue = {
|
||||
changes: [
|
||||
[
|
||||
'0x26aa394eea5630e07c48ae0c9558cef79c2f82b23e5fd031fb54c292794b4cc4d560eb8d00e57357cf76492334e43bb2ecaa9f28df6a8c4426d7b6090f7ad3c9',
|
||||
'0x00'
|
||||
]
|
||||
]
|
||||
};
|
||||
|
||||
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);
|
||||
@@ -97,7 +106,7 @@ describe('ApiPromise', (): void => {
|
||||
await transfer.signAsync(aliceEd, {});
|
||||
|
||||
expect(transfer.signature.toHex()).toEqual(
|
||||
'0x97f3cfe5088fcd575313e983f45d02b0f630e7b94ff9a3ac50e20cd096a8f554fda73d42ead891b5a1d3ce5607d83f20b0c6570b555e949cfb5763d0abcd590b'
|
||||
'0x6b9ccc95afbd4e916d30c65c720f4f7b70a77db545735b48a763844aa5210e695aa346686bad1224af77d00bcfbf6fc8d2c216a60731027835d5a414186a2607'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Callback, Codec, Constructor, IKeyringPair, Registry, SignatureOptions
|
||||
import { ApiInterfaceRx, ApiTypes, SignerResult } from '../types';
|
||||
import { 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 { assert, isBn, isFunction, isNumber, isUndefined } from '@polkadot/util';
|
||||
@@ -84,15 +84,8 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
|
||||
// also supports signing through external signers
|
||||
public signAsync (account: IKeyringPair | string | AccountId | Address, optionsOrNonce: Partial<SignerOptions>): SubmittableThis<ApiType, this> {
|
||||
return this._decorateMethod(
|
||||
(): Observable<this> => {
|
||||
const optionsWithNonce = this._optionsOrNonce(optionsOrNonce);
|
||||
|
||||
return from(
|
||||
isKeyringPair(account)
|
||||
? Promise.resolve(this.sign(account, optionsWithNonce))
|
||||
: this._signViaSigner(account, this._makeSignOptions(optionsWithNonce, {}), null)
|
||||
).pipe(mapTo(this));
|
||||
}
|
||||
(): Observable<this> =>
|
||||
this._signObservable(account, optionsOrNonce).pipe(mapTo(this))
|
||||
)();
|
||||
}
|
||||
|
||||
@@ -109,27 +102,15 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
|
||||
public signAndSend (account: IKeyringPair | string | AccountId | Address, 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,6 +144,26 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
|
||||
return [options, statusCb];
|
||||
}
|
||||
|
||||
private _signObservable (account: IKeyringPair | string | AccountId | Address, 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: | string | AccountId | Address, options: SignatureOptions, header: Header | null): Promise<number> {
|
||||
const signer = options.signer || this._api.signer;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import Metadata from '@polkadot/metadata/Decorated';
|
||||
import rpcMetadata from '@polkadot/metadata/Metadata/static';
|
||||
import interfaces from '@polkadot/jsonrpc';
|
||||
import testKeyring from '@polkadot/keyring/testing';
|
||||
import rpcHeader from '@polkadot/types/json/Header.004.json';
|
||||
import rpcSignedBlock from '@polkadot/types/json/SignedBlock.004.immortal.json';
|
||||
import { createType } from '@polkadot/types';
|
||||
import { bnToU8a, logger, u8aToHex } from '@polkadot/util';
|
||||
@@ -51,19 +52,18 @@ export default class Mock implements ProviderInterface {
|
||||
|
||||
private registry: Registry;
|
||||
|
||||
private prevNumber = new BN(-1);
|
||||
|
||||
private requests: Record<string, (...params: any[]) => any> = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
chain_getBlock: (hash: string): any => createType(this.registry, 'SignedBlock', rpcSignedBlock.result).toJSON(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
chain_getBlockHash: (blockNumber: number): string => '0x1234',
|
||||
chain_getHeader: (): any => createType(this.registry, 'Header', rpcHeader.result).toJSON(),
|
||||
state_getRuntimeVersion: (): string => createType(this.registry, 'RuntimeVersion').toHex(),
|
||||
state_getStorage: (storage: MockStateDb, params: any[]): string => {
|
||||
return u8aToHex(
|
||||
storage[(params[0] as string)]
|
||||
);
|
||||
},
|
||||
system_chain: (): string => 'mockChain',
|
||||
state_getMetadata: (): string => rpcMetadata,
|
||||
state_getStorage: (storage: MockStateDb, params: any[]): string => u8aToHex(storage[(params[0] as string)]),
|
||||
system_chain: (): string => 'mockChain',
|
||||
system_name: (): string => 'mockClient',
|
||||
system_properties: (): Record<string, number | string> => ({ ss58Format: 42 }),
|
||||
system_version: (): string => '9.8.7'
|
||||
@@ -157,7 +157,7 @@ export default class Mock implements ProviderInterface {
|
||||
private init (): void {
|
||||
const emitEvents: ProviderInterfaceEmitted[] = ['connected', 'disconnected'];
|
||||
let emitIndex = 0;
|
||||
let newHead = this.makeBlockHeader(new BN(-1));
|
||||
let newHead = this.makeBlockHeader();
|
||||
let counter = -1;
|
||||
|
||||
const metadata = new Metadata(this.registry, rpcMetadata);
|
||||
@@ -169,7 +169,7 @@ export default class Mock implements ProviderInterface {
|
||||
}
|
||||
|
||||
// create a new header (next block)
|
||||
newHead = this.makeBlockHeader(newHead.number.toBn());
|
||||
newHead = this.makeBlockHeader();
|
||||
|
||||
// increment the balances and nonce for each account
|
||||
keyring.getPairs().forEach(({ publicKey }, index): void => {
|
||||
@@ -192,10 +192,9 @@ export default class Mock implements ProviderInterface {
|
||||
}, INTERVAL);
|
||||
}
|
||||
|
||||
private makeBlockHeader (prevNumber: BN): Header {
|
||||
const blockNumber = prevNumber.addn(1);
|
||||
|
||||
return createType(this.registry, 'Header', {
|
||||
private makeBlockHeader (): Header {
|
||||
const blockNumber = this.prevNumber.addn(1);
|
||||
const header = createType(this.registry, 'Header', {
|
||||
digest: {
|
||||
logs: []
|
||||
},
|
||||
@@ -203,9 +202,13 @@ export default class Mock implements ProviderInterface {
|
||||
number: blockNumber,
|
||||
parentHash: blockNumber.isZero()
|
||||
? new Uint8Array(32)
|
||||
: bnToU8a(prevNumber, 256, false),
|
||||
: bnToU8a(this.prevNumber, 256, false),
|
||||
stateRoot: bnToU8a(blockNumber, 256, false)
|
||||
});
|
||||
|
||||
this.prevNumber = blockNumber;
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
private setStateBn (key: Uint8Array, value: BN | number): void {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"digest": {
|
||||
"logs": [
|
||||
"0x0642414245b5010100000000d968651f00000000c8a188930c6c1a8fb15316992a36f29671049dfdb96d9248747e90b80c48547af89b3238620eaec599e6a5bfedf3ae538a6cb4e19326ac2af9c21494713fc70af38629db7bcc42bf8110655d7b3bb1cec3790e39c660111e7fac4a0cba058305",
|
||||
"0x05424142450101168781581fefb96e500cfd56dbf5b9709a6babb19f74369ea7b660ea861e180c08899182e4beb8da95848b87a16a64132f497cea3cb7aa6e3f3224adb9945989"
|
||||
]
|
||||
},
|
||||
"extrinsicsRoot": "0x82faad984718975bccbfd58fdc67f59d367d678419a918f79c7a58cbb8e34a5b",
|
||||
"number": "0x14fd",
|
||||
"parentHash": "0xf0b30ecdc94c481ca96234d2a17408fef6c401f705a1f5f911e58d2a1f33fcb6",
|
||||
"stateRoot": "0xaa796217f92ed5a40ec03d184b05ad1e1824d2824559719b9bef3304ee3bff55"
|
||||
},
|
||||
"id": 1
|
||||
}
|
||||
Reference in New Issue
Block a user