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:
@@ -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');
|
||||
|
||||
@@ -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,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: {
|
||||
|
||||
Reference in New Issue
Block a user