Use new object utilities (as applicable) (#4161)
* Use new object utilities (as applicable) * Extract utility functions * Renames * Comment cleanup * Fix types
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Observable } from 'rxjs';
|
||||
import type { DeriveCustom } from '@polkadot/api-derive';
|
||||
import type { RpcInterface } from '@polkadot/rpc-core/types';
|
||||
import type { Option, Raw, StorageKey, Text, u64 } from '@polkadot/types';
|
||||
import type { Call, Hash, RuntimeVersion } from '@polkadot/types/interfaces';
|
||||
@@ -18,7 +19,7 @@ import { ExactDerive, getAvailableDerives } from '@polkadot/api-derive';
|
||||
import { memo, RpcCore } from '@polkadot/rpc-core';
|
||||
import { WsProvider } from '@polkadot/rpc-provider';
|
||||
import { expandMetadata, lazyMethod, lazyMethods, Metadata, TypeRegistry, unwrapStorageType } from '@polkadot/types';
|
||||
import { arrayChunk, arrayFlatten, assert, BN, BN_ZERO, compactStripLength, logger, u8aToHex } from '@polkadot/util';
|
||||
import { arrayChunk, arrayFlatten, assert, BN, BN_ZERO, compactStripLength, logger, objectSpread, u8aToHex } from '@polkadot/util';
|
||||
|
||||
import { createSubmittable } from '../submittable';
|
||||
import { augmentObject } from '../util/augmentObject';
|
||||
@@ -721,10 +722,7 @@ export abstract class Decorate<ApiType extends ApiTypes> extends Events {
|
||||
const specName = this._runtimeVersion?.specName.toString();
|
||||
|
||||
// Pull in derive from api-derive
|
||||
const available = getAvailableDerives(this.#instanceId, this._rx, {
|
||||
...this._options.derives,
|
||||
...(this._options.typesBundle?.spec?.[specName || '']?.derives || {})
|
||||
});
|
||||
const available = getAvailableDerives(this.#instanceId, this._rx, objectSpread<DeriveCustom>({}, this._options.derives, this._options.typesBundle?.spec?.[specName || '']?.derives));
|
||||
|
||||
return decorateDeriveSections<'rxjs', ExactDerive>(decorateMethod, available);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import type { Observable, Subscription } from 'rxjs';
|
||||
import type { Text } from '@polkadot/types';
|
||||
import type { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types';
|
||||
import type { ChainProperties, Hash, RuntimeVersion, RuntimeVersionPartial } from '@polkadot/types/interfaces';
|
||||
import type { Registry } from '@polkadot/types/types';
|
||||
import type { BN } from '@polkadot/util';
|
||||
@@ -13,7 +14,7 @@ import { firstValueFrom, map, of, switchMap } from 'rxjs';
|
||||
|
||||
import { Metadata, TypeRegistry } from '@polkadot/types';
|
||||
import { getSpecAlias, getSpecExtensions, getSpecHasher, getSpecRpc, getSpecTypes, getUpgradeVersion } from '@polkadot/types-known';
|
||||
import { assert, BN_ZERO, isUndefined, logger, stringify, u8aEq, u8aToHex, u8aToU8a } from '@polkadot/util';
|
||||
import { assert, BN_ZERO, isUndefined, logger, objectSpread, stringify, u8aEq, u8aToHex, u8aToU8a } from '@polkadot/util';
|
||||
import { cryptoWaitReady } from '@polkadot/util-crypto';
|
||||
|
||||
import { detectedCapabilities } from './capabilities';
|
||||
@@ -94,10 +95,7 @@ export abstract class Init<ApiType extends ApiTypes> extends Decorate<ApiType> {
|
||||
registry.knownTypes.typesAlias = getSpecAlias(registry, chain, version.specName);
|
||||
}
|
||||
|
||||
registry.setMetadata(metadata, undefined, {
|
||||
...getSpecExtensions(registry, chain, version.specName),
|
||||
...(this._options.signedExtensions || {})
|
||||
});
|
||||
registry.setMetadata(metadata, undefined, objectSpread<ExtDef>({}, getSpecExtensions(registry, chain, version.specName), this._options.signedExtensions));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import type { SignerPayloadRawBase } from '@polkadot/types/types';
|
||||
import type { ApiOptions, ApiTypes, DecorateMethod, Signer } from '../types';
|
||||
|
||||
import { assert, isString, u8aToHex, u8aToU8a } from '@polkadot/util';
|
||||
import { assert, isString, objectSpread, u8aToHex, u8aToU8a } from '@polkadot/util';
|
||||
|
||||
import { Getters } from './Getters';
|
||||
|
||||
@@ -72,11 +72,9 @@ export abstract class ApiBase<ApiType extends ApiTypes> extends Getters<ApiType>
|
||||
assert(_signer?.signRaw, 'No signer exists with a signRaw interface. You possibly need to pass through an explicit keypair for the origin so it can be used for signing.');
|
||||
|
||||
return (
|
||||
await _signer.signRaw({
|
||||
type: 'bytes',
|
||||
...data,
|
||||
address
|
||||
})
|
||||
await _signer.signRaw(
|
||||
objectSpread({ type: 'bytes' }, data, { address })
|
||||
)
|
||||
).signature;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { ApiOptions, DecorateFn, DecorateMethodOptions, ObsInnerType, Stora
|
||||
|
||||
import { catchError, EMPTY, Subscription, tap } from 'rxjs';
|
||||
|
||||
import { assert, isFunction } from '@polkadot/util';
|
||||
import { assert, isFunction, objectSpread } from '@polkadot/util';
|
||||
|
||||
import { ApiBase } from '../base';
|
||||
import { Combinator, CombinatorCallback, CombinatorFunction } from './Combinator';
|
||||
@@ -277,10 +277,9 @@ export class ApiPromise extends ApiBase<'promise'> {
|
||||
* @description Returns a clone of this ApiPromise instance (new underlying provider connection)
|
||||
*/
|
||||
public clone (): ApiPromise {
|
||||
return new ApiPromise({
|
||||
...this._options,
|
||||
source: this
|
||||
});
|
||||
return new ApiPromise(
|
||||
objectSpread({}, this._options, { source: this })
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,8 @@ import type { ApiOptions, DecorateFn } from '../types';
|
||||
|
||||
import { from, Observable } from 'rxjs';
|
||||
|
||||
import { objectSpread } from '@polkadot/util';
|
||||
|
||||
import { ApiBase } from '../base';
|
||||
|
||||
export function decorateMethod <Method extends DecorateFn<Codec>> (method: Method): Method {
|
||||
@@ -180,9 +182,8 @@ export class ApiRx extends ApiBase<'rxjs'> {
|
||||
* @description Returns a clone of this ApiRx instance (new underlying provider connection)
|
||||
*/
|
||||
public clone (): ApiRx {
|
||||
return new ApiRx({
|
||||
...this._options,
|
||||
source: this
|
||||
});
|
||||
return new ApiRx(
|
||||
objectSpread({}, this._options, { source: this })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import type { AddressOrPair, SignerOptions, SubmittableDryRunResult, Submittable
|
||||
|
||||
import { catchError, first, map, mapTo, mergeMap, of, switchMap, tap } from 'rxjs';
|
||||
|
||||
import { assert, isBn, isFunction, isNumber, isString, isU8a } from '@polkadot/util';
|
||||
import { assert, isBn, isFunction, isNumber, isString, isU8a, objectSpread } from '@polkadot/util';
|
||||
|
||||
import { ApiBase } from '../base';
|
||||
import { filterEvents, isKeyringPair } from '../util';
|
||||
@@ -25,6 +25,55 @@ interface SubmittableOptions<ApiType extends ApiTypes> {
|
||||
|
||||
const identity = <T> (input: T): T => input;
|
||||
|
||||
function makeEraOptions (api: ApiInterfaceRx, registry: Registry, partialOptions: Partial<SignerOptions>, { header, mortalLength, nonce }: { header: Header | null; mortalLength: number; nonce: Index }): SignatureOptions {
|
||||
if (!header) {
|
||||
if (isNumber(partialOptions.era)) {
|
||||
// since we have no header, it is immortal, remove any option overrides
|
||||
// so we only supply the genesisHash and no era to the construction
|
||||
delete partialOptions.era;
|
||||
delete partialOptions.blockHash;
|
||||
}
|
||||
|
||||
return makeSignOptions(api, partialOptions, { nonce });
|
||||
}
|
||||
|
||||
return makeSignOptions(api, partialOptions, {
|
||||
blockHash: header.hash,
|
||||
era: registry.createType('ExtrinsicEra', {
|
||||
current: header.number,
|
||||
period: partialOptions.era || mortalLength
|
||||
}),
|
||||
nonce
|
||||
});
|
||||
}
|
||||
|
||||
function makeSignAndSendOptions (partialOptions?: Partial<SignerOptions> | Callback<ISubmittableResult>, statusCb?: Callback<ISubmittableResult>): [Partial<SignerOptions>, Callback<ISubmittableResult>?] {
|
||||
let options: Partial<SignerOptions> = {};
|
||||
|
||||
if (isFunction(partialOptions)) {
|
||||
statusCb = partialOptions;
|
||||
} else {
|
||||
options = objectSpread({}, partialOptions);
|
||||
}
|
||||
|
||||
return [options, statusCb];
|
||||
}
|
||||
|
||||
function makeSignOptions (api: ApiInterfaceRx, partialOptions: Partial<SignerOptions>, extras: { blockHash?: Hash; era?: ExtrinsicEra; nonce?: Index }): SignatureOptions {
|
||||
return objectSpread(
|
||||
{ blockHash: api.genesisHash, genesisHash: api.genesisHash },
|
||||
partialOptions,
|
||||
extras,
|
||||
{ runtimeVersion: api.runtimeVersion, signedExtensions: api.registry.signedExtensions, version: api.extrinsicType }
|
||||
);
|
||||
}
|
||||
|
||||
function optionsOrNonce (partialOptions: Partial<SignerOptions> = {}): Partial<SignerOptions> {
|
||||
return isBn(partialOptions) || isNumber(partialOptions)
|
||||
? { nonce: partialOptions }
|
||||
: partialOptions;
|
||||
}
|
||||
|
||||
export function createClass <ApiType extends ApiTypes> ({ api, apiType, decorateMethod }: SubmittableOptions<ApiType>): Constructor<SubmittableExtrinsic<ApiType>> {
|
||||
// an instance of the base extrinsic for us to extend
|
||||
const ExtrinsicBase = api.registry.createClass('Extrinsic');
|
||||
@@ -67,7 +116,7 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, decorate
|
||||
);
|
||||
}
|
||||
|
||||
const [allOptions] = this.#makeSignAndSendOptions(optionsOrHash);
|
||||
const [allOptions] = makeSignAndSendOptions(optionsOrHash);
|
||||
const address = isKeyringPair(account) ? account.address : account.toString();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-call
|
||||
@@ -77,8 +126,8 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, decorate
|
||||
first(),
|
||||
switchMap((signingInfo): Observable<RuntimeDispatchInfo> => {
|
||||
// setup our options (same way as in signAndSend)
|
||||
const eraOptions = this.#makeEraOptions(allOptions, signingInfo);
|
||||
const signOptions = this.#makeSignOptions(eraOptions, {});
|
||||
const eraOptions = makeEraOptions(api, this.registry, allOptions, signingInfo);
|
||||
const signOptions = makeSignOptions(api, eraOptions, {});
|
||||
|
||||
this.signFake(address, signOptions);
|
||||
|
||||
@@ -110,8 +159,8 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, decorate
|
||||
* @description Sign a transaction, returning the this to allow chaining, i.e. .sign(...).send(). When options, e.g. nonce/blockHash are not specified, it will be inferred. To retrieve eg. nonce use `signAsync` (the preferred interface, this is provided for backwards compatibility)
|
||||
* @deprecated
|
||||
*/
|
||||
public override sign (account: IKeyringPair, optionsOrNonce?: Partial<SignerOptions>): this {
|
||||
super.sign(account, this.#makeSignOptions(this.#optionsOrNonce(optionsOrNonce), {}));
|
||||
public override sign (account: IKeyringPair, partialOptions?: Partial<SignerOptions>): this {
|
||||
super.sign(account, makeSignOptions(api, optionsOrNonce(partialOptions), {}));
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -119,26 +168,26 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, decorate
|
||||
/**
|
||||
* @description Signs a transaction, returning `this` to allow chaining. E.g.: `sign(...).send()`. Like `.signAndSend` this will retrieve the nonce and blockHash to send the tx with.
|
||||
*/
|
||||
public signAsync (account: AddressOrPair, optionsOrNonce?: Partial<SignerOptions>): SubmittableThis<ApiType, this> {
|
||||
public signAsync (account: AddressOrPair, partialOptions?: Partial<SignerOptions>): SubmittableThis<ApiType, this> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-call
|
||||
return decorateMethod(
|
||||
(): Observable<this> =>
|
||||
this.#observeSign(account, optionsOrNonce).pipe(mapTo(this) as OperatorFunction<number | undefined, this>)
|
||||
this.#observeSign(account, partialOptions).pipe(mapTo<number | undefined, this>(this))
|
||||
)();
|
||||
}
|
||||
|
||||
// signAndSend with an immediate Hash result
|
||||
public signAndSend (account: AddressOrPair, options?: Partial<SignerOptions>): SubmittableResultResult<ApiType>;
|
||||
public signAndSend (account: AddressOrPair, partialOptions?: Partial<SignerOptions>): SubmittableResultResult<ApiType>;
|
||||
|
||||
// signAndSend with a subscription, i.e. callback provided
|
||||
public signAndSend (account: AddressOrPair, statusCb: Callback<ISubmittableResult>): SubmittableResultSubscription<ApiType>;
|
||||
|
||||
// signAndSend with options and a callback
|
||||
public signAndSend (account: AddressOrPair, options: Partial<SignerOptions>, statusCb?: Callback<ISubmittableResult>): SubmittableResultSubscription<ApiType>;
|
||||
public signAndSend (account: AddressOrPair, partialOptions: Partial<SignerOptions>, statusCb?: Callback<ISubmittableResult>): SubmittableResultSubscription<ApiType>;
|
||||
|
||||
// signAndSend implementation for all 3 cases above
|
||||
public signAndSend (account: AddressOrPair, optionsOrStatus?: Partial<SignerOptions> | Callback<ISubmittableResult>, optionalStatusCb?: Callback<ISubmittableResult>): SubmittableResultResult<ApiType> | SubmittableResultSubscription<ApiType> {
|
||||
const [options, statusCb] = this.#makeSignAndSendOptions(optionsOrStatus, optionalStatusCb);
|
||||
public signAndSend (account: AddressOrPair, partialOptions?: Partial<SignerOptions> | Callback<ISubmittableResult>, optionalStatusCb?: Callback<ISubmittableResult>): SubmittableResultResult<ApiType> | SubmittableResultSubscription<ApiType> {
|
||||
const [options, statusCb] = makeSignAndSendOptions(partialOptions, optionalStatusCb);
|
||||
const isSubscription = api.hasSubscriptions && (this.#ignoreStatusCb || !!statusCb);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-call
|
||||
@@ -161,61 +210,15 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, decorate
|
||||
return this;
|
||||
}
|
||||
|
||||
#makeEraOptions = (options: Partial<SignerOptions>, { header, mortalLength, nonce }: { header: Header | null; mortalLength: number; nonce: Index }): SignatureOptions => {
|
||||
if (!header) {
|
||||
if (isNumber(options.era)) {
|
||||
// since we have no header, it is immortal, remove any option overrides
|
||||
// so we only supply the genesisHash and no era to the construction
|
||||
delete options.era;
|
||||
delete options.blockHash;
|
||||
}
|
||||
|
||||
return this.#makeSignOptions(options, { nonce });
|
||||
}
|
||||
|
||||
return this.#makeSignOptions(options, {
|
||||
blockHash: header.hash,
|
||||
era: this.registry.createType('ExtrinsicEra', {
|
||||
current: header.number,
|
||||
period: options.era || mortalLength
|
||||
}),
|
||||
nonce
|
||||
});
|
||||
};
|
||||
|
||||
#makeSignOptions = (options: Partial<SignerOptions>, extras: { blockHash?: Hash; era?: ExtrinsicEra; nonce?: Index }): SignatureOptions => {
|
||||
return {
|
||||
blockHash: api.genesisHash,
|
||||
genesisHash: api.genesisHash,
|
||||
...options,
|
||||
...extras,
|
||||
runtimeVersion: api.runtimeVersion,
|
||||
signedExtensions: api.registry.signedExtensions,
|
||||
version: api.extrinsicType
|
||||
} as SignatureOptions;
|
||||
};
|
||||
|
||||
#makeSignAndSendOptions = (optionsOrStatus?: Partial<SignerOptions> | Callback<ISubmittableResult>, statusCb?: Callback<ISubmittableResult>): [Partial<SignerOptions>, Callback<ISubmittableResult>?] => {
|
||||
let options: Partial<SignerOptions> = {};
|
||||
|
||||
if (isFunction(optionsOrStatus)) {
|
||||
statusCb = optionsOrStatus;
|
||||
} else {
|
||||
options = { ...optionsOrStatus };
|
||||
}
|
||||
|
||||
return [options, statusCb];
|
||||
};
|
||||
|
||||
#observeSign = (account: AddressOrPair, optionsOrNonce?: Partial<SignerOptions>): Observable<number | undefined> => {
|
||||
#observeSign = (account: AddressOrPair, partialOptions?: Partial<SignerOptions>): Observable<number | undefined> => {
|
||||
const address = isKeyringPair(account) ? account.address : account.toString();
|
||||
const options = this.#optionsOrNonce(optionsOrNonce);
|
||||
const options = optionsOrNonce(partialOptions);
|
||||
let updateId: number | undefined;
|
||||
|
||||
return api.derive.tx.signingInfo(address, options.nonce, options.era).pipe(
|
||||
first(),
|
||||
mergeMap(async (signingInfo): Promise<void> => {
|
||||
const eraOptions = this.#makeEraOptions(options, signingInfo);
|
||||
const eraOptions = makeEraOptions(api, this.registry, options, signingInfo);
|
||||
|
||||
if (isKeyringPair(account)) {
|
||||
this.sign(account, eraOptions);
|
||||
@@ -270,25 +273,16 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, decorate
|
||||
);
|
||||
};
|
||||
|
||||
// NOTE here we actually override nonce if it was specified (backwards compat for
|
||||
// the previous signature - don't let user space break, but allow then time to upgrade)
|
||||
#optionsOrNonce = (optionsOrNonce: Partial<SignerOptions> = {}): Partial<SignerOptions> => {
|
||||
return isBn(optionsOrNonce) || isNumber(optionsOrNonce)
|
||||
? { nonce: optionsOrNonce }
|
||||
: optionsOrNonce;
|
||||
};
|
||||
|
||||
#signViaSigner = async (address: Address | string | Uint8Array, options: SignatureOptions, header: Header | null): Promise<number> => {
|
||||
const signer = options.signer || api.signer;
|
||||
|
||||
assert(signer, 'No signer specified, either via api.setSigner or via sign options. You possibly need to pass through an explicit keypair for the origin so it can be used for signing.');
|
||||
|
||||
const payload = this.registry.createType('SignerPayload', {
|
||||
...options,
|
||||
const payload = this.registry.createType('SignerPayload', objectSpread({}, options, {
|
||||
address,
|
||||
blockNumber: header ? header.number : 0,
|
||||
method: this.method
|
||||
});
|
||||
}));
|
||||
let result: SignerResult;
|
||||
|
||||
if (signer.signPayload) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { lazyMethod } from '@polkadot/types';
|
||||
import { logger } from '@polkadot/util';
|
||||
import { logger, objectClear } from '@polkadot/util';
|
||||
|
||||
type Sections <T> = Record<string, Methods<T>>;
|
||||
|
||||
@@ -12,14 +12,6 @@ type StringsStrings = [string[], string[]];
|
||||
|
||||
const l = logger('api/augment');
|
||||
|
||||
function clearObject (obj: Record<string, unknown>): void {
|
||||
const keys = Object.keys(obj);
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
delete obj[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
function logLength (type: 'added' | 'removed', values: string[], and: string[] = []): string {
|
||||
return values.length
|
||||
? ` ${values.length} ${type}${and.length ? ' and' : ''}`
|
||||
@@ -106,7 +98,7 @@ function lazySection <T> (src: Methods<T>, dst: Methods<T>): void {
|
||||
* @internal
|
||||
*/
|
||||
export function augmentObject <T> (prefix: string | null, src: Sections<T>, dst: Sections<T>, fromEmpty = false): Sections<T> {
|
||||
fromEmpty && clearObject(dst);
|
||||
fromEmpty && objectClear(dst);
|
||||
|
||||
// NOTE: This part is slightly problematic since it will get the
|
||||
// values for at least all the sections and the names of the methods
|
||||
|
||||
Reference in New Issue
Block a user