Convert api-contract usage of api.rpc.* to api.call.* (#5107)

* Convert api-contract usage of api.rpc.* to api.call.*

* Cast call (augmentation not available in build)

* Revert tx check assert

* Call mock
This commit is contained in:
Jaco
2022-07-25 16:22:26 +03:00
committed by GitHub
parent 6e65bdbb5c
commit 0c79e13aba
4 changed files with 49 additions and 48 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ export abstract class Base<ApiType extends ApiTypes> {
if (!api || !api.isConnected || !api.tx) {
throw new Error('Your API has not been initialized correctly and is not connected to a chain');
} else if (!api.tx.contracts || !Object.keys(api.tx.contracts).length) {
} else if (!api.tx.contracts || !Object.keys(api.tx.contracts).length || !api.call.contractsApi) {
throw new Error('You need to connect to a chain with a runtime that supports contracts');
} else if (!isFunction(api.tx.contracts.instantiateWithCode)) {
throw new Error('You need to connect to a chain with a runtime with a V3 contracts module. The runtime does not expose api.tx.contracts.instantiateWithCode');
+39 -47
View File
@@ -82,12 +82,12 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
});
}
public get hasRpcContractsCall (): boolean {
return isFunction(this.api.rx.rpc.contracts?.call);
public get hasRpcContractsApi (): boolean {
return isFunction(this.api.rx.call.contractsApi?.call);
}
public get query (): MapMessageQuery<ApiType> {
if (!this.hasRpcContractsCall) {
if (!this.hasRpcContractsApi) {
throw new Error(ERROR_NO_CALL);
}
@@ -112,35 +112,31 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
};
#exec = (messageOrId: AbiMessage | string | number, { gasLimit = BN_ZERO, storageDepositLimit = null, value = BN_ZERO }: ContractOptions, params: unknown[]): SubmittableExtrinsic<ApiType> => {
const hasStorageDeposit = this.api.tx.contracts.call.meta.args.length === 5;
const gas = this.#getGas(gasLimit);
const encParams = this.abi.findMessage(messageOrId).toU8a(params);
const tx = hasStorageDeposit
? this.api.tx.contracts.call(this.address, value, gas, storageDepositLimit, encParams)
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore old style without storage deposit
: this.api.tx.contracts.call(this.address, value, gas, encParams);
return tx.withResultTransform((result: ISubmittableResult) =>
// ContractEmitted is the current generation, ContractExecution is the previous generation
new ContractSubmittableResult(result, applyOnEvent(result, ['ContractEmitted', 'ContractExecution'], (records: EventRecord[]) =>
records
.map(({ event: { data: [, data] } }): DecodedEvent | null => {
try {
return this.abi.decodeEvent(data as Bytes);
} catch (error) {
l.error(`Unable to decode contract event: ${(error as Error).message}`);
return this.api.tx.contracts
.call(this.address, value, gas, storageDepositLimit, encParams)
.withResultTransform((result: ISubmittableResult) =>
// ContractEmitted is the current generation, ContractExecution is the previous generation
new ContractSubmittableResult(result, applyOnEvent(result, ['ContractEmitted', 'ContractExecution'], (records: EventRecord[]) =>
records
.map(({ event: { data: [, data] } }): DecodedEvent | null => {
try {
return this.abi.decodeEvent(data as Bytes);
} catch (error) {
l.error(`Unable to decode contract event: ${(error as Error).message}`);
return null;
}
})
.filter((decoded): decoded is DecodedEvent => !!decoded)
))
);
return null;
}
})
.filter((decoded): decoded is DecodedEvent => !!decoded)
))
);
};
#read = (messageOrId: AbiMessage | string | number, { gasLimit = BN_ZERO, storageDepositLimit = null, value = BN_ZERO }: ContractOptions, params: unknown[]): ContractCallSend<ApiType> => {
if (!this.hasRpcContractsCall) {
if (!this.hasRpcContractsApi) {
throw new Error(ERROR_NO_CALL);
}
@@ -148,28 +144,24 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
return {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
send: this._decorateMethod((origin: string | AccountId | Uint8Array) => {
const hasStorageDeposit = this.api.tx.contracts.call.meta.args.length === 5;
const inputData = message.toU8a(params);
const rpc = hasStorageDeposit
? this.api.rx.rpc.contracts.call({ dest: this.address, gasLimit: this.#getGas(gasLimit, true), inputData, origin, storageDepositLimit, value })
: this.api.rx.rpc.contracts.call({ dest: this.address, gasLimit: this.#getGas(gasLimit, true), inputData, origin, value });
const mapFn = ({ debugMessage, gasConsumed, gasRequired, result, storageDeposit }: ContractExecResult): ContractCallOutcome => ({
debugMessage,
gasConsumed,
gasRequired: gasRequired && !gasRequired.isZero()
? gasRequired
: gasConsumed,
output: result.isOk && message.returnType
? this.abi.registry.createTypeUnsafe(message.returnType.lookupName || message.returnType.type, [result.asOk.data.toU8a(true)], { isPedantic: true })
: null,
result,
storageDeposit
});
return rpc.pipe(map(mapFn));
})
send: this._decorateMethod((origin: string | AccountId | Uint8Array) =>
this.api.rx.call.contractsApi
.call<ContractExecResult>(origin, this.address, value, this.#getGas(gasLimit, true), storageDepositLimit, message.toU8a(params))
.pipe(
map(({ debugMessage, gasConsumed, gasRequired, result, storageDeposit }): ContractCallOutcome => ({
debugMessage,
gasConsumed,
gasRequired: gasRequired && !gasRequired.isZero()
? gasRequired
: gasConsumed,
output: result.isOk && message.returnType
? this.abi.registry.createTypeUnsafe(message.returnType.lookupName || message.returnType.type, [result.asOk.data.toU8a(true)], { isPedantic: true })
: null,
result,
storageDeposit
}))
)
)
};
};
}
+7
View File
@@ -7,6 +7,13 @@ import { TypeRegistry } from '@polkadot/types';
const registry = new TypeRegistry();
export const mockApi = {
call: {
contractsApi: {
call: (): never => {
throw new Error('mock');
}
}
},
isConnected: true,
registry,
tx: {