// Copyright 2017-2023 @polkadot/api-contract authors & contributors // SPDX-License-Identifier: Apache-2.0 import type { SubmittableExtrinsic } from '@polkadot/api/submittable/types'; import type { ApiTypes, DecorateMethod } from '@polkadot/api/types'; import type { AccountId, EventRecord, Hash } from '@polkadot/types/interfaces'; import type { ISubmittableResult } from '@polkadot/types/types'; import type { AbiConstructor, BlueprintOptions } from '../types'; import type { MapConstructorExec } from './types'; import { SubmittableResult } from '@polkadot/api'; import { ApiBase } from '@polkadot/api/base'; import { BN_ZERO, isUndefined } from '@polkadot/util'; import { Abi } from '../Abi'; import { applyOnEvent } from '../util'; import { Base } from './Base'; import { Contract } from './Contract'; import { convertWeight, createBluePrintTx, encodeSalt } from './util'; export interface BlueprintConstructor { new(api: ApiBase, abi: string | Record | Abi, codeHash: string | Hash | Uint8Array): Blueprint; } export class BlueprintSubmittableResult extends SubmittableResult { readonly contract?: Contract; constructor (result: ISubmittableResult, contract?: Contract) { super(result); this.contract = contract; } } export class Blueprint extends Base { /** * @description The on-chain code hash for this blueprint */ readonly codeHash: Hash; readonly #tx: MapConstructorExec = {}; constructor (api: ApiBase, abi: string | Record | Abi, codeHash: string | Hash | Uint8Array, decorateMethod: DecorateMethod) { super(api, abi, decorateMethod); this.codeHash = this.registry.createType('Hash', codeHash); this.abi.constructors.forEach((c): void => { if (isUndefined(this.#tx[c.method])) { this.#tx[c.method] = createBluePrintTx(c, (o, p) => this.#deploy(c, o, p)); } }); } public get tx (): MapConstructorExec { return this.#tx; } #deploy = (constructorOrId: AbiConstructor | string | number, { gasLimit = BN_ZERO, salt, storageDepositLimit = null, value = BN_ZERO }: BlueprintOptions, params: unknown[]): SubmittableExtrinsic> => { return this.api.tx.contracts.instantiate( value, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore jiggle v1 weights, metadata points to latest this._isWeightV1 ? convertWeight(gasLimit).v1Weight : convertWeight(gasLimit).v2Weight, storageDepositLimit, this.codeHash, this.abi.findConstructor(constructorOrId).toU8a(params), encodeSalt(salt) ).withResultTransform((result: ISubmittableResult) => new BlueprintSubmittableResult(result, applyOnEvent(result, ['Instantiated'], ([record]: EventRecord[]) => new Contract(this.api, this.abi, record.event.data[1] as AccountId, this._decorateMethod) )) ); }; } export function extendBlueprint (type: ApiType, decorateMethod: DecorateMethod): BlueprintConstructor { return class extends Blueprint { static __BlueprintType = type; constructor (api: ApiBase, abi: string | Record | Abi, codeHash: string | Hash | Uint8Array) { super(api, abi, codeHash, decorateMethod); } }; }