Skip to content

Commit b2f7285

Browse files
api, api-{augment, base, contract, derive}, rpc-{augment, core, provider}, types, types-{augment, codec, create, known} 12.0.1
1 parent 29949b7 commit b2f7285

File tree

21 files changed

+116
-29
lines changed

21 files changed

+116
-29
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## master
44

5+
- api, api-{augment, base, contract, derive}, rpc-{augment, core, provider}, types, types-{augment, codec, create, known} 12.0.1
56
- phishing 0.22.9
67
- api, api-{augment, base, contract, derive}, rpc-{augment, core, provider}, types, types-{augment, codec, create, known} 11.3.1
78
- api, api-{augment, base, contract, derive}, rpc-{augment, core, provider}, types, types-{augment, codec, create, known} 11.2.1

api-augment/packageInfo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11

22

3-
export const packageInfo = { name: '@polkadot/api-augment', path: new URL(import.meta.url).pathname, type: 'deno', version: '11.3.1' };
3+
export const packageInfo = { name: '@polkadot/api-augment', path: new URL(import.meta.url).pathname, type: 'deno', version: '12.0.1' };

api-base/packageInfo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11

22

3-
export const packageInfo = { name: '@polkadot/api-base', path: new URL(import.meta.url).pathname, type: 'deno', version: '11.3.1' };
3+
export const packageInfo = { name: '@polkadot/api-base', path: new URL(import.meta.url).pathname, type: 'deno', version: '12.0.1' };

api-base/types/submittable.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,16 @@ export interface SubmittableExtrinsic<ApiType extends ApiTypes, R extends ISubmi
6666

6767
signAsync (account: AddressOrPair, _options?: Partial<SignerOptions>): PromiseOrObs<ApiType, this>;
6868

69+
/**
70+
* @description Sign and broadcast the constructued transaction.
71+
*
72+
* Note for injected signers:
73+
* As of v12.0.1 and up the `SignerResult` return type for `signPayload` allows for the `signedTransaction` field.
74+
* This allows the signer to input a signed transaction that will be directly broadcasted. This
75+
* bypasses the api adding the signature to the payload. The api will ensure that the Call Data is not changed before it broadcasts the
76+
* transaction. This allows for the signer to modify the payload to add things like `mode`, and `metadataHash` for
77+
* signedExtensions such as `CheckMetadataHash`.
78+
*/
6979
signAndSend (account: AddressOrPair, options?: Partial<SignerOptions>): SubmittableResultResult<ApiType, R>;
7080

7181
signAndSend (account: AddressOrPair, statusCb: Callback<R>): SubmittableResultSubscription<ApiType>;

api-contract/packageInfo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11

22

3-
export const packageInfo = { name: '@polkadot/api-contract', path: new URL(import.meta.url).pathname, type: 'deno', version: '11.3.1' };
3+
export const packageInfo = { name: '@polkadot/api-contract', path: new URL(import.meta.url).pathname, type: 'deno', version: '12.0.1' };

api-derive/packageInfo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11

22

3-
export const packageInfo = { name: '@polkadot/api-derive', path: new URL(import.meta.url).pathname, type: 'deno', version: '11.3.1' };
3+
export const packageInfo = { name: '@polkadot/api-derive', path: new URL(import.meta.url).pathname, type: 'deno', version: '12.0.1' };

api-derive/staking/stakerRewards.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,15 @@ export function _stakerRewardsEras (instanceId: string, api: DeriveApi): (eras:
165165
}
166166

167167
export function _stakerRewards (instanceId: string, api: DeriveApi): (accountIds: (Uint8Array | string)[], eras: EraIndex[], withActive?: boolean) => Observable<DeriveStakerReward[][]> {
168-
return memo(instanceId, (accountIds: (Uint8Array | string)[], eras: EraIndex[], withActive = false): Observable<DeriveStakerReward[][]> =>
169-
combineLatest([
168+
return memo(instanceId, (accountIds: (Uint8Array | string)[], eras: EraIndex[], withActive = false): Observable<DeriveStakerReward[][]> => {
169+
// Ensures that when number or string types are passed in they are sanitized
170+
// Ref: https://github.com/polkadot-js/api/issues/5910
171+
const sanitizedEras: EraIndex[] = eras.map((e) => typeof e === 'number' || typeof e === 'string' ? api.registry.createType('u32', e) : e);
172+
173+
return combineLatest([
170174
api.derive.staking.queryMulti(accountIds, { withClaimedRewardsEras: true, withLedger: true }),
171-
api.derive.staking._stakerExposures(accountIds, eras, withActive),
172-
api.derive.staking._stakerRewardsEras(eras, withActive)
175+
api.derive.staking._stakerExposures(accountIds, sanitizedEras, withActive),
176+
api.derive.staking._stakerRewardsEras(sanitizedEras, withActive)
173177
]).pipe(
174178
switchMap(([queries, exposures, erasResult]): Observable<DeriveStakerReward[][]> => {
175179
const allRewards = queries.map(({ claimedRewardsEras, stakingLedger, stashId }, index): DeriveStakerReward[] =>
@@ -205,7 +209,8 @@ export function _stakerRewards (instanceId: string, api: DeriveApi): (accountIds
205209
)
206210
);
207211
})
208-
)
212+
);
213+
}
209214
);
210215
}
211216

api-derive/tx/signingInfo.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,13 @@ function latestNonce (api: DeriveApi, address: string): Observable<Index> {
2727
}
2828

2929
function nextNonce (api: DeriveApi, address: string): Observable<Index> {
30-
return api.rpc.system?.accountNextIndex
31-
? api.rpc.system.accountNextIndex(address)
32-
: latestNonce(api, address);
30+
if (api.call.accountNonceApi) {
31+
return api.call.accountNonceApi.accountNonce(address);
32+
} else {
33+
return api.rpc.system?.accountNextIndex
34+
? api.rpc.system.accountNextIndex(address)
35+
: latestNonce(api, address);
36+
}
3337
}
3438

3539
function signingHeader (api: DeriveApi): Observable<Header> {

api/packageInfo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11

22

3-
export const packageInfo = { name: '@polkadot/api', path: new URL(import.meta.url).pathname, type: 'deno', version: '11.3.1' };
3+
export const packageInfo = { name: '@polkadot/api', path: new URL(import.meta.url).pathname, type: 'deno', version: '12.0.1' };

api/submittable/createClass.ts

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { Observable } from 'https://esm.sh/rxjs@7.8.1';
55
import type { Address, ApplyExtrinsicResult, Call, Extrinsic, ExtrinsicEra, ExtrinsicStatus, Hash, Header, Index, RuntimeDispatchInfo, SignerPayload } from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
66
import type { Callback, Codec, CodecClass, ISubmittableResult, SignatureOptions } from 'https://deno.land/x/polkadot/types/types/index.ts';
77
import type { Registry } from 'https://deno.land/x/polkadot/types-codec/types/index.ts';
8+
import type { HexString } from 'https://deno.land/x/polkadot/util/types.ts';
89
import type { ApiBase } from '../base/index.ts';
910
import type { ApiInterfaceRx, ApiTypes, PromiseOrObs, SignerResult } from '../types/index.ts';
1011
import type { AddressOrPair, SignerOptions, SubmittableDryRunResult, SubmittableExtrinsic, SubmittablePaymentResult, SubmittableResultResult, SubmittableResultSubscription } from './types.ts';
@@ -26,6 +27,12 @@ interface SubmittableOptions<ApiType extends ApiTypes> {
2627
interface UpdateInfo {
2728
options: SignatureOptions;
2829
updateId: number;
30+
signedTransaction: HexString | Uint8Array | null;
31+
}
32+
33+
interface SignerInfo {
34+
id: number;
35+
signedTransaction?: HexString | Uint8Array;
2936
}
3037

3138
function makeEraOptions (api: ApiInterfaceRx, registry: Registry, partialOptions: Partial<SignerOptions>, { header, mortalLength, nonce }: { header: Header | null; mortalLength: number; nonce: Index }): SignatureOptions {
@@ -244,14 +251,21 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, blockHas
244251
mergeMap(async (signingInfo): Promise<UpdateInfo> => {
245252
const eraOptions = makeEraOptions(api, this.registry, options, signingInfo);
246253
let updateId = -1;
254+
let signedTx = null;
247255

248256
if (isKeyringPair(account)) {
249257
this.sign(account, eraOptions);
250258
} else {
251-
updateId = await this.#signViaSigner(address, eraOptions, signingInfo.header);
259+
const result = await this.#signViaSigner(address, eraOptions, signingInfo.header);
260+
261+
updateId = result.id;
262+
263+
if (result.signedTransaction) {
264+
signedTx = result.signedTransaction;
265+
}
252266
}
253267

254-
return { options: eraOptions, updateId };
268+
return { options: eraOptions, signedTransaction: signedTx, updateId };
255269
})
256270
);
257271
};
@@ -286,18 +300,18 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, blockHas
286300
);
287301
};
288302

289-
#observeSend = (info: UpdateInfo): Observable<Hash> => {
290-
return api.rpc.author.submitExtrinsic(this).pipe(
303+
#observeSend = (info?: UpdateInfo): Observable<Hash> => {
304+
return api.rpc.author.submitExtrinsic(info?.signedTransaction || this).pipe(
291305
tap((hash): void => {
292306
this.#updateSigner(hash, info);
293307
})
294308
);
295309
};
296310

297-
#observeSubscribe = (info: UpdateInfo): Observable<ISubmittableResult> => {
311+
#observeSubscribe = (info?: UpdateInfo): Observable<ISubmittableResult> => {
298312
const txHash = this.hash;
299313

300-
return api.rpc.author.submitAndWatchExtrinsic(this).pipe(
314+
return api.rpc.author.submitAndWatchExtrinsic(info?.signedTransaction || this).pipe(
301315
switchMap((status): Observable<ISubmittableResult> =>
302316
this.#observeStatus(txHash, status)
303317
),
@@ -307,7 +321,7 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, blockHas
307321
);
308322
};
309323

310-
#signViaSigner = async (address: Address | string | Uint8Array, options: SignatureOptions, header: Header | null): Promise<number> => {
324+
#signViaSigner = async (address: Address | string | Uint8Array, options: SignatureOptions, header: Header | null): Promise<SignerInfo> => {
311325
const signer = options.signer || api.signer;
312326

313327
if (!signer) {
@@ -323,6 +337,20 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, blockHas
323337

324338
if (isFunction(signer.signPayload)) {
325339
result = await signer.signPayload(payload.toPayload());
340+
341+
// When the signedTransaction is included by the signer, we no longer add
342+
// the signature to the parent class, but instead broadcast the signed transaction directly.
343+
if (result.signedTransaction) {
344+
const ext = this.registry.createTypeUnsafe<Extrinsic>('Extrinsic', [result.signedTransaction]);
345+
346+
if (!ext.isSigned) {
347+
throw new Error(`When using the signedTransaction field, the transaction must be signed. Recieved isSigned: ${ext.isSigned}`);
348+
}
349+
350+
this.#validateSignedTransaction(payload, ext);
351+
352+
return { id: result.id, signedTransaction: result.signedTransaction };
353+
}
326354
} else if (isFunction(signer.signRaw)) {
327355
result = await signer.signRaw(payload.toRaw());
328356
} else {
@@ -334,7 +362,7 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, blockHas
334362
// payload data is not modified from our inputs, but the signer
335363
super.addSignature(address, result.signature, payload.toPayload());
336364

337-
return result.id;
365+
return { id: result.id };
338366
};
339367

340368
#updateSigner = (status: Hash | ISubmittableResult, info?: UpdateInfo): void => {
@@ -347,6 +375,20 @@ export function createClass <ApiType extends ApiTypes> ({ api, apiType, blockHas
347375
}
348376
}
349377
};
378+
379+
/**
380+
* When a signer includes `signedTransaction` within the SignerResult this will validate
381+
* specific fields within the signed extrinsic against the original payload that was passed
382+
* to the signer.
383+
*/
384+
#validateSignedTransaction = (signerPayload: SignerPayload, signedExt: Extrinsic): void => {
385+
const payload = signerPayload.toPayload();
386+
const errMsg = (field: string) => `signAndSend: ${field} does not match the original payload`;
387+
388+
if (payload.method !== signedExt.method.toHex()) {
389+
throw new Error(errMsg('call data'));
390+
}
391+
};
350392
}
351393

352394
return Submittable;

0 commit comments

Comments
 (0)