Skip to content

wip: ink v6 & revive support #569

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .api-contract/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @polkadot/api-contract

Interfaces to allow for the encoding and decoding of Substrate contract ABIs.
483 changes: 483 additions & 0 deletions .api-contract/build-deno/Abi/index.ts

Large diffs are not rendered by default.

53 changes: 53 additions & 0 deletions .api-contract/build-deno/Abi/toLatestCompatible.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type {
ContractMetadataV4,
ContractMetadataV5,
} from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { Registry } from 'https://deno.land/x/polkadot/types/types/index.ts';
import type { ContractMetadataSupported } from './index.ts';

import { v0ToV1 } from './toV1.ts';
import { v1ToV2 } from './toV2.ts';
import { v2ToV3 } from './toV3.ts';
import { v3ToV4 } from './toV4.ts';

export const enumVersions = ['V5', 'V4', 'V3', 'V2', 'V1'] as const;

type Versions = (typeof enumVersions)[number] | 'V0';

type Converter = (registry: Registry, vx: any) => ContractMetadataSupported;

function createConverter<I, O>(
next: (registry: Registry, input: O) => ContractMetadataSupported,
step: (registry: Registry, input: I) => O,
): (registry: Registry, input: I) => ContractMetadataSupported {
return (registry: Registry, input: I): ContractMetadataSupported =>
next(registry, step(registry, input));
}

export function v5ToLatestCompatible(
_registry: Registry,
v5: ContractMetadataV5,
): ContractMetadataV5 {
return v5;
}

export function v4ToLatestCompatible(
_registry: Registry,
v4: ContractMetadataV4,
): ContractMetadataV4 {
return v4;
}

export const v3ToLatestCompatible = /*#__PURE__*/ createConverter(v4ToLatestCompatible, v3ToV4);
export const v2ToLatestCompatible = /*#__PURE__*/ createConverter(v3ToLatestCompatible, v2ToV3);
export const v1ToLatestCompatible = /*#__PURE__*/ createConverter(v2ToLatestCompatible, v1ToV2);
export const v0ToLatestCompatible = /*#__PURE__*/ createConverter(v1ToLatestCompatible, v0ToV1);

export const convertVersions: [Versions, Converter][] = [
['V5', v5ToLatestCompatible],
['V4', v4ToLatestCompatible],
['V3', v3ToLatestCompatible],
['V2', v2ToLatestCompatible],
['V1', v1ToLatestCompatible],
['V0', v0ToLatestCompatible],
];
37 changes: 37 additions & 0 deletions .api-contract/build-deno/Abi/toV1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type {
ContractMetadataV0,
ContractMetadataV1,
} from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { Registry } from 'https://deno.land/x/polkadot/types/types/index.ts';

import { convertSiV0toV1 } from 'https://deno.land/x/polkadot/types/mod.ts';
import { objectSpread } from 'https://deno.land/x/polkadot/util/mod.ts';

interface Named {
name: unknown;
}

function v0ToV1Names(all: Named[]): unknown[] {
return all.map(e =>
objectSpread({}, e, {
name: Array.isArray(e.name) ? e.name : [e.name],
}),
);
}

export function v0ToV1(registry: Registry, v0: ContractMetadataV0): ContractMetadataV1 {
if (!v0.metadataVersion.length) {
throw new Error('Invalid format for V0 (detected) contract metadata');
}

return registry.createType(
'ContractMetadataV1',
objectSpread({}, v0, {
spec: objectSpread({}, v0.spec, {
constructors: v0ToV1Names(v0.spec.constructors),
messages: v0ToV1Names(v0.spec.messages),
}),
types: convertSiV0toV1(registry, v0.types),
}),
);
}
67 changes: 67 additions & 0 deletions .api-contract/build-deno/Abi/toV2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import type { Text } from 'https://deno.land/x/polkadot/types/mod.ts';
import type {
ContractConstructorSpecV0,
ContractEventSpecV0,
ContractMessageSpecV0,
ContractMetadataV1,
ContractMetadataV2,
} from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { Registry } from 'https://deno.land/x/polkadot/types/types/index.ts';

import { objectSpread } from 'https://deno.land/x/polkadot/util/mod.ts';

type WithArgs = keyof typeof ARG_TYPES;

interface NamedEntry {
name: Text | Text[];
}

type GetArgsType<T extends WithArgs> = T extends 'ContractConstructorSpec'
? ContractConstructorSpecV0
: T extends ContractEventSpecV0
? ContractEventSpecV0
: ContractMessageSpecV0;

interface ArgsEntry<T extends WithArgs> extends NamedEntry {
args: GetArgsType<T>['args'][0][];
}

const ARG_TYPES = {
ContractConstructorSpec: 'ContractMessageParamSpecV2',
ContractEventSpec: 'ContractEventParamSpecV2',
ContractMessageSpec: 'ContractMessageParamSpecV2',
} as const;

function v1ToV2Label(entry: NamedEntry): { label: Text } {
return objectSpread({}, entry, {
label: Array.isArray(entry.name) ? entry.name.join('::') : entry.name,
});
}

function v1ToV2Labels<T extends WithArgs>(
registry: Registry,
outType: T,
all: ArgsEntry<T>[],
): unknown[] {
return all.map(e =>
registry.createType(
`${outType}V2`,
objectSpread(v1ToV2Label(e), {
args: e.args.map(a => registry.createType(ARG_TYPES[outType], v1ToV2Label(a))),
}),
),
);
}

export function v1ToV2(registry: Registry, v1: ContractMetadataV1): ContractMetadataV2 {
return registry.createType(
'ContractMetadataV2',
objectSpread({}, v1, {
spec: objectSpread({}, v1.spec, {
constructors: v1ToV2Labels(registry, 'ContractConstructorSpec', v1.spec.constructors),
events: v1ToV2Labels(registry, 'ContractEventSpec', v1.spec.events),
messages: v1ToV2Labels(registry, 'ContractMessageSpec', v1.spec.messages),
}),
}),
);
}
21 changes: 21 additions & 0 deletions .api-contract/build-deno/Abi/toV3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type {
ContractMetadataV2,
ContractMetadataV3,
} from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { Registry } from 'https://deno.land/x/polkadot/types/types/index.ts';

import { objectSpread } from 'https://deno.land/x/polkadot/util/mod.ts';

export function v2ToV3(registry: Registry, v2: ContractMetadataV2): ContractMetadataV3 {
return registry.createType(
'ContractMetadataV3',
objectSpread({}, v2, {
spec: objectSpread({}, v2.spec, {
constructors: v2.spec.constructors.map(c =>
// V3 introduces the payable flag on constructors, for <V3, it is always true
registry.createType('ContractConstructorSpecV3', objectSpread({}, c, { payable: true })),
),
}),
}),
);
}
24 changes: 24 additions & 0 deletions .api-contract/build-deno/Abi/toV4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type {
ContractMetadataV3,
ContractMetadataV4,
} from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { Registry } from 'https://deno.land/x/polkadot/types/types/index.ts';

import { objectSpread } from 'https://deno.land/x/polkadot/util/mod.ts';

export function v3ToV4(registry: Registry, v3: ContractMetadataV3): ContractMetadataV4 {
return registry.createType(
'ContractMetadataV4',
objectSpread({}, v3, {
spec: objectSpread({}, v3.spec, {
constructors: v3.spec.constructors.map(c =>
registry.createType('ContractConstructorSpecV4', objectSpread({}, c)),
),
messages: v3.spec.messages.map(m =>
registry.createType('ContractMessageSpecV3', objectSpread({}, m)),
),
}),
version: registry.createType('Text', '4'),
}),
);
}
3 changes: 3 additions & 0 deletions .api-contract/build-deno/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @polkadot/api-contract

Interfaces to allow for the encoding and decoding of Substrate contract ABIs.
1 change: 1 addition & 0 deletions .api-contract/build-deno/augment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import 'https://deno.land/x/polkadot/api-augment/mod.ts';
49 changes: 49 additions & 0 deletions .api-contract/build-deno/base/Base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { ApiBase } from 'https://deno.land/x/polkadot/api/base/index.ts';
import type { ApiTypes, DecorateMethod } from 'https://deno.land/x/polkadot/api/types/index.ts';
import type { WeightV2 } from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { Registry } from 'https://deno.land/x/polkadot/types/types/index.ts';

import { isFunction } from 'https://deno.land/x/polkadot/util/mod.ts';

import { Abi } from '../Abi/index.ts';

export abstract class Base<ApiType extends ApiTypes> {
readonly abi: Abi;
readonly api: ApiBase<ApiType>;

protected readonly _decorateMethod: DecorateMethod<ApiType>;
protected readonly _isWeightV1: boolean;

constructor(
api: ApiBase<ApiType>,
abi: string | Record<string, unknown> | Abi,
decorateMethod: DecorateMethod<ApiType>,
) {
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.revive ||
!isFunction(api.tx.revive.instantiateWithCode) ||
api.tx.revive.instantiateWithCode.meta.args.length !== 6
) {
throw new Error(
'The runtime does not expose api.tx.revive.instantiateWithCode with storageDepositLimit',
);
} else if (!api.call.reviveApi || !isFunction(api.call.reviveApi.call)) {
throw new Error(
'Your runtime does not expose the api.call.reviveApi.call runtime interfaces',
);
}

this.abi = abi instanceof Abi ? abi : new Abi(abi, api.registry.getChainProperties());
this.api = api;
this._decorateMethod = decorateMethod;
this._isWeightV1 = !api.registry.createType<WeightV2>('Weight').proofSize;
}

public get registry(): Registry {
return this.api.registry;
}
}
113 changes: 113 additions & 0 deletions .api-contract/build-deno/base/Blueprint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import type { ApiBase } from 'https://deno.land/x/polkadot/api/base/index.ts';
import type { SubmittableExtrinsic } from 'https://deno.land/x/polkadot/api/submittable/types.ts';
import type { ApiTypes, DecorateMethod } from 'https://deno.land/x/polkadot/api/types/index.ts';
import type { Hash } from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { ISubmittableResult } from 'https://deno.land/x/polkadot/types/types/index.ts';
import type { Abi } from '../Abi/index.ts';
import type { AbiConstructor, BlueprintOptions } from '../types.ts';
import type { MapConstructorExec } from './types.ts';

import { SubmittableResult } from 'https://deno.land/x/polkadot/api/mod.ts';
import { BN_ZERO, isUndefined } from 'https://deno.land/x/polkadot/util/mod.ts';

import { Base } from './Base.ts';
import { Contract } from './Contract.ts';
import { convertWeight, createBluePrintTx, encodeSalt } from './util.ts';

export type BlueprintConstructor<ApiType extends ApiTypes> = new (
api: ApiBase<ApiType>,
abi: string | Record<string, unknown> | Abi,
codeHash: string | Hash | Uint8Array,
) => Blueprint<ApiType>;

export class BlueprintSubmittableResult<ApiType extends ApiTypes> extends SubmittableResult {
readonly contract?: Contract<ApiType> | undefined;

constructor(result: ISubmittableResult, contract?: Contract<ApiType>) {
super(result);

this.contract = contract;
}
}

export class Blueprint<ApiType extends ApiTypes> extends Base<ApiType> {
/**
* @description The on-chain code hash for this blueprint
*/
readonly codeHash: Hash;

readonly #tx: MapConstructorExec<ApiType> = {};

constructor(
api: ApiBase<ApiType>,
abi: string | Record<string, unknown> | Abi,
codeHash: string | Hash | Uint8Array,
decorateMethod: DecorateMethod<ApiType>,
) {
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<ApiType> {
return this.#tx;
}

#deploy = (
constructorOrId: AbiConstructor | string | number,
{ gasLimit = BN_ZERO, salt, storageDepositLimit = null, value = BN_ZERO }: BlueprintOptions,
params: unknown[],
): SubmittableExtrinsic<ApiType, BlueprintSubmittableResult<ApiType>> => {
return this.api.tx.revive
.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,
(() => {
if (result.status.isInBlock || result.status.isFinalized) {
return new Contract<ApiType>(
this.api,
this.abi,
'0x075e2a9cfb213a68dfa1f5cf6bf6d515ae212cf8',
this._decorateMethod,
);
}
return undefined;
})(),
),
);
};
}

export function extendBlueprint<ApiType extends ApiTypes>(
type: ApiType,
decorateMethod: DecorateMethod<ApiType>,
): BlueprintConstructor<ApiType> {
return class extends Blueprint<ApiType> {
static __BlueprintType = type;

constructor(
api: ApiBase<ApiType>,
abi: string | Record<string, unknown> | Abi,
codeHash: string | Hash | Uint8Array,
) {
super(api, abi, codeHash, decorateMethod);
}
};
}
137 changes: 137 additions & 0 deletions .api-contract/build-deno/base/Code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { Buffer } from 'node:buffer';

import type { ApiBase } from 'https://deno.land/x/polkadot/api/base/index.ts';
import type { SubmittableExtrinsic } from 'https://deno.land/x/polkadot/api/submittable/types.ts';
import type { ApiTypes, DecorateMethod } from 'https://deno.land/x/polkadot/api/types/index.ts';
import type { ISubmittableResult } from 'https://deno.land/x/polkadot/types/types/index.ts';
import type { Codec } from 'https://deno.land/x/polkadot/types-codec/types/index.ts';
import type { Abi } from '../Abi/index.ts';
import type { AbiConstructor, BlueprintOptions } from '../types.ts';
import type { MapConstructorExec } from './types.ts';

import { SubmittableResult } from 'https://deno.land/x/polkadot/api/mod.ts';
import {
BN_ZERO,
compactAddLength,
isRiscV,
isUndefined,
isWasm,
u8aToU8a,
} from 'https://deno.land/x/polkadot/util/mod.ts';

import { Base } from './Base.ts';
import { Blueprint } from './Blueprint.ts';
import { Contract } from './Contract.ts';
import { convertWeight, createBluePrintTx, encodeSalt } from './util.ts';

export type CodeConstructor<ApiType extends ApiTypes> = new (
api: ApiBase<ApiType>,
abi: string | Record<string, unknown> | Abi,
wasm: Uint8Array | string | Buffer | null | undefined,
) => Code<ApiType>;

export class CodeSubmittableResult<ApiType extends ApiTypes> extends SubmittableResult {
readonly blueprint?: Blueprint<ApiType> | undefined;
readonly contract?: Contract<ApiType> | undefined;

constructor(
result: ISubmittableResult,
blueprint?: Blueprint<ApiType> | undefined,
contract?: Contract<ApiType> | undefined,
) {
super(result);

this.blueprint = blueprint;
this.contract = contract;
}
}

function isValidCode(code: Uint8Array): boolean {
return isWasm(code) || isRiscV(code);
}

export class Code<ApiType extends ApiTypes> extends Base<ApiType> {
readonly code: Uint8Array;

readonly #tx: MapConstructorExec<ApiType> = {};

constructor(
api: ApiBase<ApiType>,
abi: string | Record<string, unknown> | Abi,
wasm: Uint8Array | string | Buffer | null | undefined,
decorateMethod: DecorateMethod<ApiType>,
) {
super(api, abi, decorateMethod);

this.code = isValidCode(this.abi.info.source.wasm) ? this.abi.info.source.wasm : u8aToU8a(wasm);

if (!isValidCode(this.code)) {
throw new Error('Invalid code provided');
}

this.abi.constructors.forEach((c): void => {
if (isUndefined(this.#tx[c.method])) {
this.#tx[c.method] = createBluePrintTx(c, (o, p) => this.#instantiate(c, o, p));
}
});
}

public get tx(): MapConstructorExec<ApiType> {
return this.#tx;
}

#instantiate = (
constructorOrId: AbiConstructor | string | number,
{ gasLimit = BN_ZERO, salt, storageDepositLimit = null, value = BN_ZERO }: BlueprintOptions,
params: unknown[],
): SubmittableExtrinsic<ApiType, CodeSubmittableResult<ApiType>> => {
console.log('in instantiate');
console.log(this.abi.info.source.wasmHash);
return this.api.tx.revive
.instantiateWithCode(
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,
compactAddLength(this.code),
this.abi.findConstructor(constructorOrId).toU8a(params),
encodeSalt(salt),
)
.withResultTransform(
(result: ISubmittableResult) =>
new CodeSubmittableResult(
result,
new Blueprint<ApiType>(
this.api,
this.abi,
this.abi.info.source.wasmHash,
this._decorateMethod,
),
new Contract<ApiType>(
this.api,
this.abi,
'0x075e2a9cfb213a68dfa1f5cf6bf6d515ae212cf8',
this._decorateMethod,
),
),
);
};
}

export function extendCode<ApiType extends ApiTypes>(
type: ApiType,
decorateMethod: DecorateMethod<ApiType>,
): CodeConstructor<ApiType> {
return class extends Code<ApiType> {
static __CodeType = type;

constructor(
api: ApiBase<ApiType>,
abi: string | Record<string, unknown> | Abi,
wasm: Uint8Array | string | Buffer | null | undefined,
) {
super(api, abi, wasm, decorateMethod);
}
};
}
264 changes: 264 additions & 0 deletions .api-contract/build-deno/base/Contract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
import type { ApiBase } from 'https://deno.land/x/polkadot/api/base/index.ts';
import type { SubmittableExtrinsic } from 'https://deno.land/x/polkadot/api/submittable/types.ts';
import type { ApiTypes, DecorateMethod } from 'https://deno.land/x/polkadot/api/types/index.ts';
import type {
AccountId,
AccountId20,
ContractExecResult,
EventRecord,
Weight,
WeightV2,
} from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { ISubmittableResult } from 'https://deno.land/x/polkadot/types/types/index.ts';
import type { Abi } from '../Abi/index.ts';
import type {
AbiMessage,
ContractCallOutcome,
ContractOptions,
DecodedEvent,
WeightAll,
} from '../types.ts';
import type {
ContractCallResult,
ContractCallSend,
ContractQuery,
ContractTx,
MapMessageQuery,
MapMessageTx,
} from './types.ts';

import { map } from 'https://esm.sh/rxjs@7.8.1';

import { SubmittableResult } from 'https://deno.land/x/polkadot/api/mod.ts';
import {
BN,
BN_HUNDRED,
BN_ONE,
BN_ZERO,
isUndefined,
logger,
} from 'https://deno.land/x/polkadot/util/mod.ts';

import { applyOnEvent } from '../util.ts';
import { Base } from './Base.ts';
import { convertWeight, withMeta } from './util.ts';

export type ContractConstructor<ApiType extends ApiTypes> = new (
api: ApiBase<ApiType>,
abi: string | Record<string, unknown> | Abi,
address: string | AccountId,
) => Contract<ApiType>;

const MAX_CALL_GAS = new BN(5_000_000_000_000).isub(BN_ONE);

const l = logger('Contract');

function createQuery<ApiType extends ApiTypes>(
meta: AbiMessage,
fn: (
origin: string | AccountId | Uint8Array,
options: ContractOptions,
params: unknown[],
) => ContractCallResult<ApiType, ContractCallOutcome>,
): ContractQuery<ApiType> {
return withMeta(
meta,
(
origin: string | AccountId | Uint8Array,
options: ContractOptions,
...params: unknown[]
): ContractCallResult<ApiType, ContractCallOutcome> => fn(origin, options, params),
);
}

function createTx<ApiType extends ApiTypes>(
meta: AbiMessage,
fn: (options: ContractOptions, params: unknown[]) => SubmittableExtrinsic<ApiType>,
): ContractTx<ApiType> {
return withMeta(
meta,
(options: ContractOptions, ...params: unknown[]): SubmittableExtrinsic<ApiType> =>
fn(options, params),
);
}

export class ContractSubmittableResult extends SubmittableResult {
readonly contractEvents?: DecodedEvent[] | undefined;

constructor(result: ISubmittableResult, contractEvents?: DecodedEvent[]) {
super(result);

this.contractEvents = contractEvents;
}
}

export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
/**
* @description The on-chain address for this contract
*/
readonly address: AccountId20;

readonly #query: MapMessageQuery<ApiType> = {};
readonly #tx: MapMessageTx<ApiType> = {};

constructor(
api: ApiBase<ApiType>,
abi: string | Record<string, unknown> | Abi,
address: string | AccountId20,
decorateMethod: DecorateMethod<ApiType>,
) {
super(api, abi, decorateMethod);

this.address = this.registry.createType('AccountId20', address);

this.abi.messages.forEach((m): void => {
if (isUndefined(this.#tx[m.method])) {
this.#tx[m.method] = createTx(m, (o, p) => this.#exec(m, o, p));
}

if (isUndefined(this.#query[m.method])) {
this.#query[m.method] = createQuery(m, (f, o, p) => this.#read(m, o, p).send(f));
}
});
}

public get query(): MapMessageQuery<ApiType> {
return this.#query;
}

public get tx(): MapMessageTx<ApiType> {
return this.#tx;
}

#getGas = (_gasLimit: bigint | BN | string | number | WeightV2, isCall = false): WeightAll => {
const weight = convertWeight(_gasLimit);

if (weight.v1Weight.gt(BN_ZERO)) {
return weight;
}

return convertWeight(
isCall
? MAX_CALL_GAS
: convertWeight(
this.api.consts.system.blockWeights
? (this.api.consts.system.blockWeights as unknown as { maxBlock: WeightV2 }).maxBlock
: (this.api.consts.system['maximumBlockWeight'] as Weight),
)
.v1Weight.muln(64)
.div(BN_HUNDRED),
);
};

#exec = (
messageOrId: AbiMessage | string | number,
{ gasLimit = BN_ZERO, storageDepositLimit = null, value = BN_ZERO }: ContractOptions,
params: unknown[],
): SubmittableExtrinsic<ApiType> => {
return this.api.tx.revive
.call(
this.address,
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.abi.findMessage(messageOrId).toU8a(params),
)
.withResultTransform(
(result: ISubmittableResult) =>
// ContractEmitted is the current generation, ContractExecution is the previous generation
new ContractSubmittableResult(
result,
applyOnEvent(
result,
['ContractEmitted', 'ContractExecution'],
(records: EventRecord[]) =>
records
.map((record): DecodedEvent | null => {
try {
return this.abi.decodeEvent(record);
} catch (error) {
l.error(`Unable to decode contract event: ${(error as Error).message}`);

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> => {
const message = this.abi.findMessage(messageOrId);

return {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
send: this._decorateMethod((origin: string | AccountId | Uint8Array) =>
this.api.rx.call.contractsApi
.call<ContractExecResult>(
origin,
this.address,
value,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore jiggle v1 weights, metadata points to latest
this._isWeightV1
? this.#getGas(gasLimit, true).v1Weight
: this.#getGas(gasLimit, true).v2Weight,
storageDepositLimit,
message.toU8a(params),
)
.pipe(
map(
({
debugMessage,
gasConsumed,
gasRequired,
result,
storageDeposit,
}): ContractCallOutcome => ({
debugMessage,
gasConsumed,
gasRequired:
gasRequired && !convertWeight(gasRequired).v1Weight.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,
}),
),
),
),
};
};
}

export function extendContract<ApiType extends ApiTypes>(
type: ApiType,
decorateMethod: DecorateMethod<ApiType>,
): ContractConstructor<ApiType> {
return class extends Contract<ApiType> {
static __ContractType = type;

constructor(
api: ApiBase<ApiType>,
abi: string | Record<string, unknown> | Abi,
address: string | AccountId,
) {
super(api, abi, address, decorateMethod);
}
};
}
3 changes: 3 additions & 0 deletions .api-contract/build-deno/base/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { Blueprint, BlueprintSubmittableResult, extendBlueprint } from './Blueprint.ts';
export { Code, CodeSubmittableResult, extendCode } from './Code.ts';
export { Contract, extendContract } from './Contract.ts';
28 changes: 28 additions & 0 deletions .api-contract/build-deno/base/mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { ApiBase } from 'https://deno.land/x/polkadot/api/base/index.ts';

import { TypeRegistry } from 'https://deno.land/x/polkadot/types/mod.ts';

const registry = new TypeRegistry();

const instantiateWithCode = (): never => {
throw new Error('mock');
};

instantiateWithCode.meta = { args: new Array(6) };

export const mockApi = {
call: {
contractsApi: {
call: (): never => {
throw new Error('mock');
},
},
},
isConnected: true,
registry,
tx: {
contracts: {
instantiateWithCode,
},
},
} as unknown as ApiBase<'promise'>;
50 changes: 50 additions & 0 deletions .api-contract/build-deno/base/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { Observable } from 'https://esm.sh/rxjs@7.8.1';
import type { SubmittableExtrinsic } from 'https://deno.land/x/polkadot/api/submittable/types.ts';
import type { ApiTypes, ObsInnerType } from 'https://deno.land/x/polkadot/api/types/index.ts';
import type { AccountId } from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type {
AbiMessage,
BlueprintOptions,
ContractCallOutcome,
ContractOptions,
} from '../types.ts';

export interface MessageMeta {
readonly meta: AbiMessage;
}

export interface BlueprintDeploy<ApiType extends ApiTypes> extends MessageMeta {
(options: BlueprintOptions, ...params: unknown[]): SubmittableExtrinsic<ApiType>;
}

export interface ContractQuery<ApiType extends ApiTypes> extends MessageMeta {
(
origin: AccountId | string | Uint8Array,
options: ContractOptions,
...params: unknown[]
): ContractCallResult<ApiType, ContractCallOutcome>;
}

export interface ContractTx<ApiType extends ApiTypes> extends MessageMeta {
(options: ContractOptions, ...params: unknown[]): SubmittableExtrinsic<ApiType>;
}

export type ContractGeneric<O, T> = (
messageOrId: AbiMessage | string | number,
options: O,
...params: unknown[]
) => T;

export type ContractCallResult<ApiType extends ApiTypes, T> = ApiType extends 'rxjs'
? Observable<T>
: Promise<ObsInnerType<Observable<T>>>;

export interface ContractCallSend<ApiType extends ApiTypes> {
send(account: string | AccountId | Uint8Array): ContractCallResult<ApiType, ContractCallOutcome>;
}

export type MapConstructorExec<ApiType extends ApiTypes> = Record<string, BlueprintDeploy<ApiType>>;

export type MapMessageTx<ApiType extends ApiTypes> = Record<string, ContractTx<ApiType>>;

export type MapMessageQuery<ApiType extends ApiTypes> = Record<string, ContractQuery<ApiType>>;
74 changes: 74 additions & 0 deletions .api-contract/build-deno/base/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import type { SubmittableResult } from 'https://deno.land/x/polkadot/api/mod.ts';
import type { SubmittableExtrinsic } from 'https://deno.land/x/polkadot/api/submittable/types.ts';
import type { ApiTypes } from 'https://deno.land/x/polkadot/api/types/index.ts';
import type { WeightV1, WeightV2 } from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { BN } from 'https://deno.land/x/polkadot/util/mod.ts';
import type { AbiConstructor, AbiMessage, BlueprintOptions, WeightAll } from '../types.ts';
import type { BlueprintDeploy, ContractGeneric } from './types.ts';

import { Bytes } from 'https://deno.land/x/polkadot/types/mod.ts';
import { bnToBn, compactAddLength, u8aToU8a } from 'https://deno.land/x/polkadot/util/mod.ts';
import { randomAsU8a } from 'https://deno.land/x/polkadot/util-crypto/mod.ts';

export const EMPTY_SALT = new Uint8Array();

export function withMeta<T extends { meta: AbiMessage }>(
meta: AbiMessage,
creator: Omit<T, 'meta'>,
): T {
(creator as T).meta = meta;

return creator as T;
}

export function createBluePrintTx<ApiType extends ApiTypes, R extends SubmittableResult>(
meta: AbiMessage,
fn: (options: BlueprintOptions, params: unknown[]) => SubmittableExtrinsic<ApiType, R>,
): BlueprintDeploy<ApiType> {
return withMeta(
meta,
(options: BlueprintOptions, ...params: unknown[]): SubmittableExtrinsic<ApiType, R> =>
fn(options, params),
);
}

export function createBluePrintWithId<T>(
fn: (
constructorOrId: AbiConstructor | string | number,
options: BlueprintOptions,
params: unknown[],
) => T,
): ContractGeneric<BlueprintOptions, T> {
return (
constructorOrId: AbiConstructor | string | number,
options: BlueprintOptions,
...params: unknown[]
): T => fn(constructorOrId, options, params);
}

export function encodeSalt(salt: Uint8Array | string | null = randomAsU8a()): Uint8Array {
return salt instanceof Bytes
? salt
: salt?.length
? compactAddLength(u8aToU8a(salt))
: EMPTY_SALT;
}

export function convertWeight(
weight: WeightV1 | WeightV2 | bigint | string | number | BN,
): WeightAll {
const [refTime, proofSize] = isWeightV2(weight)
? [weight.refTime.toBn(), weight.proofSize.toBn()]
: [bnToBn(weight), undefined];

return {
v1Weight: refTime,
v2Weight: { proofSize, refTime },
};
}

export function isWeightV2(
weight: WeightV1 | WeightV2 | bigint | string | number | BN,
): weight is WeightV2 {
return !!(weight as WeightV2).proofSize;
}
5 changes: 5 additions & 0 deletions .api-contract/build-deno/bundle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { Abi } from './Abi/index.ts';
export { packageInfo } from './packageInfo.ts';

export * from './promise/index.ts';
export * from './rx/index.ts';
42 changes: 42 additions & 0 deletions .api-contract/build-deno/checkTypes.manual.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'https://deno.land/x/polkadot/api-augment/mod.ts';

import type { TestKeyringMapSubstrate } from 'https://deno.land/x/polkadot/keyring/testingPairs.ts';

import { ApiPromise } from 'https://deno.land/x/polkadot/api/mod.ts';
import {
BlueprintPromise,
ContractPromise,
} from 'https://deno.land/x/polkadot/api-contract/mod.ts';
import { createTestPairs } from 'https://deno.land/x/polkadot/keyring/testingPairs.ts';

import abiIncrementer from './test/contracts/ink/v0/incrementer.json' assert { type: 'json' };

async function checkBlueprint(api: ApiPromise, pairs: TestKeyringMapSubstrate): Promise<void> {
const blueprint = new BlueprintPromise(api, abiIncrementer as Record<string, unknown>, '0x1234');

await blueprint.tx['new']({ gasLimit: 456, salt: '0x1234', value: 123 }, 42).signAndSend(
pairs.bob,
);
await blueprint.tx['new']({ gasLimit: 456, value: 123 }, 42).signAndSend(pairs.bob);
}

async function checkContract(api: ApiPromise, pairs: TestKeyringMapSubstrate): Promise<void> {
const contract = new ContractPromise(api, abiIncrementer as Record<string, unknown>, '0x1234');

// queries
await contract.query['get'](pairs.alice.address, {});

// execute
await contract.tx['inc']({ gasLimit: 1234 }, 123).signAndSend(pairs.eve);
}

async function main(): Promise<void> {
const api = await ApiPromise.create({
hasher: (data: Uint8Array): Uint8Array => data,
});
const pairs = createTestPairs();

await Promise.all([checkBlueprint(api, pairs), checkContract(api, pairs)]);
}

main().catch(console.error);
3 changes: 3 additions & 0 deletions .api-contract/build-deno/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import './packageDetect.ts';

export * from './bundle.ts';
1 change: 1 addition & 0 deletions .api-contract/build-deno/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './index.ts';
7 changes: 7 additions & 0 deletions .api-contract/build-deno/packageDetect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { packageInfo as apiInfo } from 'https://deno.land/x/polkadot/api/packageInfo.ts';
import { packageInfo as typesInfo } from 'https://deno.land/x/polkadot/types/packageInfo.ts';
import { detectPackage } from 'https://deno.land/x/polkadot/util/mod.ts';

import { packageInfo } from './packageInfo.ts';

detectPackage(packageInfo, null, [apiInfo, typesInfo]);
6 changes: 6 additions & 0 deletions .api-contract/build-deno/packageInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const packageInfo = {
name: '@polkadot/api-contract',
path: new URL(import.meta.url).pathname,
type: 'deno',
version: '15.8.1',
};
39 changes: 39 additions & 0 deletions .api-contract/build-deno/promise/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Buffer } from 'node:buffer';

import type { ApiPromise } from 'https://deno.land/x/polkadot/api/mod.ts';
import type { AccountId20, Hash } from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { Abi } from '../Abi/index.ts';

import { toPromiseMethod } from 'https://deno.land/x/polkadot/api/mod.ts';

import { Blueprint, Code, Contract } from '../base/index.ts';

export class BlueprintPromise extends Blueprint<'promise'> {
constructor(
api: ApiPromise,
abi: string | Record<string, unknown> | Abi,
codeHash: string | Hash,
) {
super(api, abi, codeHash, toPromiseMethod);
}
}

export class CodePromise extends Code<'promise'> {
constructor(
api: ApiPromise,
abi: string | Record<string, unknown> | Abi,
wasm: Uint8Array | string | Buffer | null | undefined,
) {
super(api, abi, wasm, toPromiseMethod);
}
}

export class ContractPromise extends Contract<'promise'> {
constructor(
api: ApiPromise,
abi: string | Record<string, unknown> | Abi,
address: string | AccountId20,
) {
super(api, abi, address, toPromiseMethod);
}
}
7 changes: 7 additions & 0 deletions .api-contract/build-deno/promise/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type {
BlueprintSubmittableResult as BaseBlueprintSubmittableResult,
CodeSubmittableResult as BaseCodeSubmittableResult,
} from '../base/index.ts';

export type BlueprintSubmittableResult = BaseBlueprintSubmittableResult<'promise'>;
export type CodeSubmittableResult = BaseCodeSubmittableResult<'promise'>;
35 changes: 35 additions & 0 deletions .api-contract/build-deno/rx/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Buffer } from 'node:buffer';

import type { ApiRx } from 'https://deno.land/x/polkadot/api/mod.ts';
import type { AccountId, Hash } from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { Abi } from '../Abi/index.ts';

import { toRxMethod } from 'https://deno.land/x/polkadot/api/mod.ts';

import { Blueprint, Code, Contract } from '../base/index.ts';

export class BlueprintRx extends Blueprint<'rxjs'> {
constructor(api: ApiRx, abi: string | Record<string, unknown> | Abi, codeHash: string | Hash) {
super(api, abi, codeHash, toRxMethod);
}
}

export class CodeRx extends Code<'rxjs'> {
constructor(
api: ApiRx,
abi: string | Record<string, unknown> | Abi,
wasm: Uint8Array | string | Buffer | null | undefined,
) {
super(api, abi, wasm, toRxMethod);
}
}

export class ContractRx extends Contract<'rxjs'> {
constructor(
api: ApiRx,
abi: string | Record<string, unknown> | Abi,
address: string | AccountId,
) {
super(api, abi, address, toRxMethod);
}
}
7 changes: 7 additions & 0 deletions .api-contract/build-deno/rx/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type {
BlueprintSubmittableResult as BaseBlueprintSubmittableResult,
CodeSubmittableResult as BaseCodeSubmittableResult,
} from '../base/index.ts';

export type BlueprintSubmittableResult = BaseBlueprintSubmittableResult<'promise'>;
export type CodeSubmittableResult = BaseCodeSubmittableResult<'promise'>;
13 changes: 13 additions & 0 deletions .api-contract/build-deno/test/contracts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ink from './ink/index.ts';
import solang from './solang/index.ts';
import user from './user/index.ts';

const all: Record<string, Record<string, unknown>> = {};

Object.entries({ ink, solang, user }).forEach(([type, abis]) =>
Object.entries(abis).forEach(([name, abi]): void => {
all[`${type}_${name}`] = abi;
}),
);

export default all;
9 changes: 9 additions & 0 deletions .api-contract/build-deno/test/contracts/ink/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createVersionedExport } from '../util.ts';
import * as v0 from './v0/index.ts';
import * as v1 from './v1/index.ts';
import * as v2 from './v2/index.ts';
import * as v3 from './v3/index.ts';
import * as v4 from './v4/index.ts';
import * as v5 from './v5/index.ts';

export default createVersionedExport({ v0, v1, v2, v3, v4, v5 });
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
8 changes: 8 additions & 0 deletions .api-contract/build-deno/test/contracts/ink/v0/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export { default as delegator } from './delegator.json' assert { type: 'json' };
export { default as dns } from './dns.json' assert { type: 'json' };
export { default as erc20 } from './erc20.json' assert { type: 'json' };
export { default as erc721 } from './erc721.json' assert { type: 'json' };
export { default as flipperBundle } from './flipper.contract.json' assert { type: 'json' };
export { default as flipper } from './flipper.json' assert { type: 'json' };
export { default as incrementer } from './incrementer.json' assert { type: 'json' };
export { default as multisigPlain } from './multisig_plain.json' assert { type: 'json' };
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 2 additions & 0 deletions .api-contract/build-deno/test/contracts/ink/v1/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as flipper } from './flipper.contract.json' assert { type: 'json' };
export { default as psp22 } from './psp22_minter_pauser.contract.json' assert { type: 'json' };
2 changes: 2 additions & 0 deletions .api-contract/build-deno/test/contracts/ink/v2/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as erc20 } from './erc20.contract.json' assert { type: 'json' };
export { default as flipper } from './flipper.contract.json' assert { type: 'json' };
2 changes: 2 additions & 0 deletions .api-contract/build-deno/test/contracts/ink/v3/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as flipper } from './flipper.contract.json' assert { type: 'json' };
export { default as traitErc20 } from './trait_erc20.contract.json' assert { type: 'json' };
Binary file not shown.
Binary file not shown.
4 changes: 4 additions & 0 deletions .api-contract/build-deno/test/contracts/ink/v4/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { default as erc20Contract } from './erc20.contract.json' assert { type: 'json' };
export { default as erc20Metadata } from './erc20.json' assert { type: 'json' };
export { default as flipperContract } from './flipper.contract.json' assert { type: 'json' };
export { default as flipperMetadata } from './flipper.json' assert { type: 'json' };
Binary file not shown.
Binary file not shown.
5 changes: 5 additions & 0 deletions .api-contract/build-deno/test/contracts/ink/v5/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { default as erc20Contract } from './erc20.contract.json' assert { type: 'json' };
export { default as erc20Metadata } from './erc20.json' assert { type: 'json' };
export { default as erc20AnonymousTransferMetadata } from './erc20_anonymous_transfer.json' assert { type: 'json' };
export { default as flipperContract } from './flipper.contract.json' assert { type: 'json' };
export { default as flipperMetadata } from './flipper.json' assert { type: 'json' };
4 changes: 4 additions & 0 deletions .api-contract/build-deno/test/contracts/solang/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createVersionedExport } from '../util.ts';
import * as v0 from './v0/index.ts';

export default createVersionedExport({ v0 });
1 change: 1 addition & 0 deletions .api-contract/build-deno/test/contracts/solang/v0/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as ints256 } from './ints256.json' assert { type: 'json' };
13 changes: 13 additions & 0 deletions .api-contract/build-deno/test/contracts/solang/v0/ints256.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/// @title Test 256 bits types
/// @author Sean Young <sean@mess.org>
contract ints256 {
/// Multiply two 256 bit values
function multiply(uint256 a, uint256 b) public pure returns (uint256) {
return a * b;
}

/// Add two 256 bit values
function add(uint256 a, uint256 b) public pure returns (uint256) {
return a + b;
}
}
Binary file not shown.
6 changes: 6 additions & 0 deletions .api-contract/build-deno/test/contracts/user/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createVersionedExport } from '../util.ts';
import * as v0 from './v0/index.ts';
import * as v3 from './v3/index.ts';
import * as v4 from './v4/index.ts';

export default createVersionedExport({ v0, v3, v4 });
Binary file not shown.
Binary file not shown.
4 changes: 4 additions & 0 deletions .api-contract/build-deno/test/contracts/user/v0/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { default as assetTransfer } from './assetTransfer.json' assert { type: 'json' };
export { default as enumExample } from './enumExample.json' assert { type: 'json' };
export { default as recursive } from './recursive.contract.json' assert { type: 'json' };
export { default as withString } from './withString.json' assert { type: 'json' };
1 change: 1 addition & 0 deletions .api-contract/build-deno/test/contracts/user/v3/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as ask } from './ask.json' assert { type: 'json' };
1 change: 1 addition & 0 deletions .api-contract/build-deno/test/contracts/user/v4/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as events } from './events.contract.json' assert { type: 'json' };
13 changes: 13 additions & 0 deletions .api-contract/build-deno/test/contracts/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export function createVersionedExport(
versioned: Record<string, Record<string, unknown>>,
): Record<string, Record<string, unknown>> {
const result: Record<string, Record<string, unknown>> = {};

Object.entries(versioned).forEach(([version, contracts]) =>
Object.entries(contracts).forEach(([name, contract]): void => {
result[`${version}_${name}`] = contract as Record<string, unknown>;
}),
);

return result;
}
100 changes: 100 additions & 0 deletions .api-contract/build-deno/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import type { ApiBase } from 'https://deno.land/x/polkadot/api/base/index.ts';
import type { ApiTypes } from 'https://deno.land/x/polkadot/api/types/index.ts';
import type { Text } from 'https://deno.land/x/polkadot/types/mod.ts';
import type {
ContractExecResultResult,
ContractSelector,
StorageDeposit,
Weight,
WeightV2,
} from 'https://deno.land/x/polkadot/types/interfaces/index.ts';
import type { Codec, TypeDef } from 'https://deno.land/x/polkadot/types/types/index.ts';
import type { BN } from 'https://deno.land/x/polkadot/util/mod.ts';
import type { HexString } from 'https://deno.land/x/polkadot/util/types.ts';
import type { Abi } from './index.ts';

export interface ContractBase<ApiType extends ApiTypes> {
readonly abi: Abi;
readonly api: ApiBase<ApiType>;

getMessage: (name: string) => AbiMessage;
messages: AbiMessage[];
}

export interface AbiParam {
name: string;
type: TypeDef;
}

export type AbiMessageParam = AbiParam;

export interface AbiEventParam extends AbiParam {
indexed: boolean;
}

export interface AbiEvent {
args: AbiEventParam[];
docs: string[];
fromU8a: (data: Uint8Array) => DecodedEvent;
identifier: string;
index: number;
signatureTopic?: HexString | null;
}

export interface AbiMessage {
args: AbiMessageParam[];
docs: string[];
fromU8a: (data: Uint8Array) => DecodedMessage;
identifier: string;
index: number;
isConstructor?: boolean;
isDefault?: boolean;
isMutating?: boolean;
isPayable?: boolean;
method: string;
path: string[];
returnType?: TypeDef | null;
selector: ContractSelector;
toU8a: (params: unknown[]) => Uint8Array;
}

export type AbiConstructor = AbiMessage;

export type InterfaceContractCalls = Record<string, Function>;

export interface ContractCallOutcome {
debugMessage: Text;
gasConsumed: Weight;
gasRequired: Weight;
output: Codec | null;
result: ContractExecResultResult;
storageDeposit: StorageDeposit;
}

export interface DecodedEvent {
args: Codec[];
event: AbiEvent;
}

export interface DecodedMessage {
args: Codec[];
message: AbiMessage;
}

export interface ContractOptions {
gasLimit?: bigint | string | number | BN | WeightV2;
storageDepositLimit?: bigint | string | number | BN | null;
value?: bigint | BN | string | number;
}

export interface BlueprintOptions extends ContractOptions {
salt?: Uint8Array | string | null;
}

export interface WeightAll {
v1Weight: BN;
v2Weight: {
refTime: BN;
proofSize?: BN | undefined;
};
}
20 changes: 20 additions & 0 deletions .api-contract/build-deno/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { SubmittableResult } from 'https://deno.land/x/polkadot/api/mod.ts';
import type { EventRecord } from 'https://deno.land/x/polkadot/types/interfaces/index.ts';

type ContractEvents = 'CodeStored' | 'ContractEmitted' | 'ContractExecution' | 'Instantiated';

export function applyOnEvent<T>(
result: SubmittableResult,
types: ContractEvents[],
fn: (records: EventRecord[]) => T,
): T | undefined {
if (result.isInBlock || result.isFinalized) {
const records = result.filterRecords('contracts', types);

if (records.length) {
return fn(records);
}
}

return undefined;
}
348 changes: 348 additions & 0 deletions .api-contract/build-tsc-cjs/Abi/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,348 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.Abi = void 0;
const types_1 = require('@polkadot/types');
const types_create_1 = require('@polkadot/types-create');
const util_1 = require('@polkadot/util');
const toLatestCompatible_js_1 = require('./toLatestCompatible.js');
const l = (0, util_1.logger)('Abi');
const PRIMITIVE_ALWAYS = ['AccountId', 'AccountIndex', 'Address', 'Balance'];
function findMessage(list, messageOrId) {
const message = (0, util_1.isNumber)(messageOrId)
? list[messageOrId]
: (0, util_1.isString)(messageOrId)
? list.find(({ identifier }) =>
[identifier, (0, util_1.stringCamelCase)(identifier)].includes(messageOrId.toString()),
)
: messageOrId;
return (0, util_1.assertReturn)(
message,
() => `Attempted to call an invalid contract interface, ${(0, util_1.stringify)(messageOrId)}`,
);
}
function getMetadata(registry, json) {
// this is for V1, V2, V3
const vx = toLatestCompatible_js_1.enumVersions.find(v => (0, util_1.isObject)(json[v]));
// this was added in V4
const jsonVersion = json.version;
if (
!vx &&
jsonVersion &&
!toLatestCompatible_js_1.enumVersions.find(v => v === `V${jsonVersion}`)
) {
throw new Error(`Unable to handle version ${jsonVersion}`);
}
const metadata = registry.createType(
'ContractMetadata',
vx ? { [vx]: json[vx] } : jsonVersion ? { [`V${jsonVersion}`]: json } : { V0: json },
);
const converter = toLatestCompatible_js_1.convertVersions.find(([v]) => metadata[`is${v}`]);
if (!converter) {
throw new Error(`Unable to convert ABI with version ${metadata.type} to a supported version`);
}
const upgradedMetadata = converter[1](registry, metadata[`as${converter[0]}`]);
return upgradedMetadata;
}
function parseJson(json, chainProperties) {
const registry = new types_1.TypeRegistry();
const info = registry.createType('ContractProjectInfo', json);
const metadata = getMetadata(registry, json);
const lookup = registry.createType('PortableRegistry', { types: metadata.types }, true);
// attach the lookup to the registry - now the types are known
registry.setLookup(lookup);
if (chainProperties) {
registry.setChainProperties(chainProperties);
}
// warm-up the actual type, pre-use
lookup.types.forEach(({ id }) => lookup.getTypeDef(id));
return [json, registry, metadata, info];
}
/**
* @internal
* Determines if the given input value is a ContractTypeSpec
*/
function isTypeSpec(value) {
return (
!!value &&
value instanceof Map &&
!(0, util_1.isUndefined)(value.type) &&
!(0, util_1.isUndefined)(value.displayName)
);
}
/**
* @internal
* Determines if the given input value is an Option
*/
function isOption(value) {
return !!value && value instanceof types_1.Option;
}
class Abi {
events;
constructors;
info;
json;
messages;
metadata;
registry;
environment = new Map();
constructor(abiJson, chainProperties) {
[this.json, this.registry, this.metadata, this.info] = parseJson(
(0, util_1.isString)(abiJson) ? JSON.parse(abiJson) : abiJson,
chainProperties,
);
this.constructors = this.metadata.spec.constructors.map((spec, index) =>
this.__internal__createMessage(spec, index, {
isConstructor: true,
isDefault: spec.default.isTrue,
isPayable: spec.payable.isTrue,
returnType: spec.returnType.isSome
? this.registry.lookup.getTypeDef(spec.returnType.unwrap().type)
: null,
}),
);
this.events = this.metadata.spec.events.map((_, index) => this.__internal__createEvent(index));
this.messages = this.metadata.spec.messages.map((spec, index) =>
this.__internal__createMessage(spec, index, {
isDefault: spec.default.isTrue,
isMutating: spec.mutates.isTrue,
isPayable: spec.payable.isTrue,
returnType: spec.returnType.isSome
? this.registry.lookup.getTypeDef(spec.returnType.unwrap().type)
: null,
}),
);
// NOTE See the rationale for having Option<...> values in the actual
// ContractEnvironmentV4 structure definition in interfaces/contractsAbi
// (Due to conversions, the fields may not exist)
for (const [key, opt] of this.metadata.spec.environment.entries()) {
if (isOption(opt)) {
if (opt.isSome) {
const value = opt.unwrap();
if ((0, util_1.isBn)(value)) {
this.environment.set(key, value);
} else if (isTypeSpec(value)) {
this.environment.set(key, this.registry.lookup.getTypeDef(value.type));
} else {
throw new Error(
`Invalid environment definition for ${key}:: Expected either Number or ContractTypeSpec`,
);
}
}
} else {
throw new Error(`Expected Option<*> definition for ${key} in ContractEnvironment`);
}
}
}
/**
* Warning: Unstable API, bound to change
*/
decodeEvent(record) {
switch (this.metadata.version.toString()) {
// earlier version are hoisted to v4
case '4':
return this.__internal__decodeEventV4(record);
// Latest
default:
return this.__internal__decodeEventV5(record);
}
}
__internal__decodeEventV5 = record => {
// Find event by first topic, which potentially is the signature_topic
const signatureTopic = record.topics[0];
const data = record.event.data[1];
if (signatureTopic) {
const event = this.events.find(
e =>
e.signatureTopic !== undefined &&
e.signatureTopic !== null &&
e.signatureTopic === signatureTopic.toHex(),
);
// Early return if event found by signature topic
if (event) {
return event.fromU8a(data);
}
}
// If no event returned yet, it might be anonymous
const amountOfTopics = record.topics.length;
const potentialEvents = this.events.filter(e => {
// event can't have a signature topic
if (e.signatureTopic !== null && e.signatureTopic !== undefined) {
return false;
}
// event should have same amount of indexed fields as emitted topics
const amountIndexed = e.args.filter(a => a.indexed).length;
if (amountIndexed !== amountOfTopics) {
return false;
}
// If all conditions met, it's a potential event
return true;
});
if (potentialEvents.length === 1) {
return potentialEvents[0].fromU8a(data);
}
throw new Error('Unable to determine event');
};
__internal__decodeEventV4 = record => {
const data = record.event.data[1];
const index = data[0];
const event = this.events[index];
if (!event) {
throw new Error(`Unable to find event with index ${index}`);
}
return event.fromU8a(data.subarray(1));
};
/**
* Warning: Unstable API, bound to change
*/
decodeConstructor(data) {
return this.__internal__decodeMessage('message', this.constructors, data);
}
/**
* Warning: Unstable API, bound to change
*/
decodeMessage(data) {
return this.__internal__decodeMessage('message', this.messages, data);
}
findConstructor(constructorOrId) {
return findMessage(this.constructors, constructorOrId);
}
findMessage(messageOrId) {
return findMessage(this.messages, messageOrId);
}
__internal__createArgs = (args, spec) => {
return args.map(({ label, type }, index) => {
try {
if (!(0, util_1.isObject)(type)) {
throw new Error('Invalid type definition found');
}
const displayName = type.displayName.length
? type.displayName[type.displayName.length - 1].toString()
: undefined;
const camelName = (0, util_1.stringCamelCase)(label);
if (displayName && PRIMITIVE_ALWAYS.includes(displayName)) {
return {
name: camelName,
type: {
info: types_create_1.TypeDefInfo.Plain,
type: displayName,
},
};
}
const typeDef = this.registry.lookup.getTypeDef(type.type);
return {
name: camelName,
type:
displayName && !typeDef.type.startsWith(displayName)
? { displayName, ...typeDef }
: typeDef,
};
} catch (error) {
l.error(`Error expanding argument ${index} in ${(0, util_1.stringify)(spec)}`);
throw error;
}
});
};
__internal__createMessageParams = (args, spec) => {
return this.__internal__createArgs(args, spec);
};
__internal__createEventParams = (args, spec) => {
const params = this.__internal__createArgs(args, spec);
return params.map((p, index) => ({ ...p, indexed: args[index].indexed.toPrimitive() }));
};
__internal__createEvent = index => {
// TODO TypeScript would narrow this type to the correct version,
// but version is `Text` so I need to call `toString()` here,
// which breaks the type inference.
switch (this.metadata.version.toString()) {
case '4':
return this.__internal__createEventV4(this.metadata.spec.events[index], index);
default:
return this.__internal__createEventV5(this.metadata.spec.events[index], index);
}
};
__internal__createEventV5 = (spec, index) => {
const args = this.__internal__createEventParams(spec.args, spec);
const event = {
args,
docs: spec.docs.map(d => d.toString()),
fromU8a: data => ({
args: this.__internal__decodeArgs(args, data),
event,
}),
identifier: [spec.module_path, spec.label].join('::'),
index,
signatureTopic: spec.signature_topic.isSome ? spec.signature_topic.unwrap().toHex() : null,
};
return event;
};
__internal__createEventV4 = (spec, index) => {
const args = this.__internal__createEventParams(spec.args, spec);
const event = {
args,
docs: spec.docs.map(d => d.toString()),
fromU8a: data => ({
args: this.__internal__decodeArgs(args, data),
event,
}),
identifier: spec.label.toString(),
index,
};
return event;
};
__internal__createMessage = (spec, index, add = {}) => {
const args = this.__internal__createMessageParams(spec.args, spec);
const identifier = spec.label.toString();
const message = {
...add,
args,
docs: spec.docs.map(d => d.toString()),
fromU8a: data => ({
args: this.__internal__decodeArgs(args, data),
message,
}),
identifier,
index,
isDefault: spec.default.isTrue,
method: (0, util_1.stringCamelCase)(identifier),
path: identifier.split('::').map(s => (0, util_1.stringCamelCase)(s)),
selector: spec.selector,
toU8a: params => this.__internal__encodeMessageArgs(spec, args, params),
};
return message;
};
__internal__decodeArgs = (args, data) => {
// for decoding we expect the input to be just the arg data, no selectors
// no length added (this allows use with events as well)
let offset = 0;
return args.map(({ type: { lookupName, type } }) => {
const value = this.registry.createType(lookupName || type, data.subarray(offset));
offset += value.encodedLength;
return value;
});
};
__internal__decodeMessage = (type, list, data) => {
const [, trimmed] = (0, util_1.compactStripLength)(data);
const selector = trimmed.subarray(0, 4);
const message = list.find(m => m.selector.eq(selector));
if (!message) {
throw new Error(`Unable to find ${type} with selector ${(0, util_1.u8aToHex)(selector)}`);
}
return message.fromU8a(trimmed.subarray(4));
};
__internal__encodeMessageArgs = ({ label, selector }, args, data) => {
if (data.length !== args.length) {
throw new Error(
`Expected ${args.length} arguments to contract message '${label.toString()}', found ${data.length}`,
);
}
return (0, util_1.compactAddLength)(
(0, util_1.u8aConcat)(
this.registry.createType('ContractSelector', selector).toU8a(),
...args.map(({ type: { lookupName, type } }, index) =>
this.registry.createType(lookupName || type, data[index]).toU8a(),
),
),
);
};
}
exports.Abi = Abi;
37 changes: 37 additions & 0 deletions .api-contract/build-tsc-cjs/Abi/toLatestCompatible.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.convertVersions =
exports.v0ToLatestCompatible =
exports.v1ToLatestCompatible =
exports.v2ToLatestCompatible =
exports.v3ToLatestCompatible =
exports.enumVersions =
void 0;
exports.v5ToLatestCompatible = v5ToLatestCompatible;
exports.v4ToLatestCompatible = v4ToLatestCompatible;
const toV1_js_1 = require('./toV1.js');
const toV2_js_1 = require('./toV2.js');
const toV3_js_1 = require('./toV3.js');
const toV4_js_1 = require('./toV4.js');
exports.enumVersions = ['V5', 'V4', 'V3', 'V2', 'V1'];
function createConverter(next, step) {
return (registry, input) => next(registry, step(registry, input));
}
function v5ToLatestCompatible(_registry, v5) {
return v5;
}
function v4ToLatestCompatible(_registry, v4) {
return v4;
}
exports.v3ToLatestCompatible = createConverter(v4ToLatestCompatible, toV4_js_1.v3ToV4);
exports.v2ToLatestCompatible = createConverter(exports.v3ToLatestCompatible, toV3_js_1.v2ToV3);
exports.v1ToLatestCompatible = createConverter(exports.v2ToLatestCompatible, toV2_js_1.v1ToV2);
exports.v0ToLatestCompatible = createConverter(exports.v1ToLatestCompatible, toV1_js_1.v0ToV1);
exports.convertVersions = [
['V5', v5ToLatestCompatible],
['V4', v4ToLatestCompatible],
['V3', exports.v3ToLatestCompatible],
['V2', exports.v2ToLatestCompatible],
['V1', exports.v1ToLatestCompatible],
['V0', exports.v0ToLatestCompatible],
];
27 changes: 27 additions & 0 deletions .api-contract/build-tsc-cjs/Abi/toV1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.v0ToV1 = v0ToV1;
const types_1 = require('@polkadot/types');
const util_1 = require('@polkadot/util');
function v0ToV1Names(all) {
return all.map(e =>
(0, util_1.objectSpread)({}, e, {
name: Array.isArray(e.name) ? e.name : [e.name],
}),
);
}
function v0ToV1(registry, v0) {
if (!v0.metadataVersion.length) {
throw new Error('Invalid format for V0 (detected) contract metadata');
}
return registry.createType(
'ContractMetadataV1',
(0, util_1.objectSpread)({}, v0, {
spec: (0, util_1.objectSpread)({}, v0.spec, {
constructors: v0ToV1Names(v0.spec.constructors),
messages: v0ToV1Names(v0.spec.messages),
}),
types: (0, types_1.convertSiV0toV1)(registry, v0.types),
}),
);
}
36 changes: 36 additions & 0 deletions .api-contract/build-tsc-cjs/Abi/toV2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.v1ToV2 = v1ToV2;
const util_1 = require('@polkadot/util');
const ARG_TYPES = {
ContractConstructorSpec: 'ContractMessageParamSpecV2',
ContractEventSpec: 'ContractEventParamSpecV2',
ContractMessageSpec: 'ContractMessageParamSpecV2',
};
function v1ToV2Label(entry) {
return (0, util_1.objectSpread)({}, entry, {
label: Array.isArray(entry.name) ? entry.name.join('::') : entry.name,
});
}
function v1ToV2Labels(registry, outType, all) {
return all.map(e =>
registry.createType(
`${outType}V2`,
(0, util_1.objectSpread)(v1ToV2Label(e), {
args: e.args.map(a => registry.createType(ARG_TYPES[outType], v1ToV2Label(a))),
}),
),
);
}
function v1ToV2(registry, v1) {
return registry.createType(
'ContractMetadataV2',
(0, util_1.objectSpread)({}, v1, {
spec: (0, util_1.objectSpread)({}, v1.spec, {
constructors: v1ToV2Labels(registry, 'ContractConstructorSpec', v1.spec.constructors),
events: v1ToV2Labels(registry, 'ContractEventSpec', v1.spec.events),
messages: v1ToV2Labels(registry, 'ContractMessageSpec', v1.spec.messages),
}),
}),
);
}
20 changes: 20 additions & 0 deletions .api-contract/build-tsc-cjs/Abi/toV3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.v2ToV3 = v2ToV3;
const util_1 = require('@polkadot/util');
function v2ToV3(registry, v2) {
return registry.createType(
'ContractMetadataV3',
(0, util_1.objectSpread)({}, v2, {
spec: (0, util_1.objectSpread)({}, v2.spec, {
constructors: v2.spec.constructors.map(c =>
// V3 introduces the payable flag on constructors, for <V3, it is always true
registry.createType(
'ContractConstructorSpecV3',
(0, util_1.objectSpread)({}, c, { payable: true }),
),
),
}),
}),
);
}
20 changes: 20 additions & 0 deletions .api-contract/build-tsc-cjs/Abi/toV4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.v3ToV4 = v3ToV4;
const util_1 = require('@polkadot/util');
function v3ToV4(registry, v3) {
return registry.createType(
'ContractMetadataV4',
(0, util_1.objectSpread)({}, v3, {
spec: (0, util_1.objectSpread)({}, v3.spec, {
constructors: v3.spec.constructors.map(c =>
registry.createType('ContractConstructorSpecV4', (0, util_1.objectSpread)({}, c)),
),
messages: v3.spec.messages.map(m =>
registry.createType('ContractMessageSpecV3', (0, util_1.objectSpread)({}, m)),
),
}),
version: registry.createType('Text', '4'),
}),
);
}
3 changes: 3 additions & 0 deletions .api-contract/build-tsc-cjs/augment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
require('@polkadot/api-augment');
41 changes: 41 additions & 0 deletions .api-contract/build-tsc-cjs/base/Base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.Base = void 0;
const util_1 = require('@polkadot/util');
const index_js_1 = require('../Abi/index.js');
class Base {
abi;
api;
_decorateMethod;
_isWeightV1;
constructor(api, abi, decorateMethod) {
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.revive ||
!(0, util_1.isFunction)(api.tx.revive.instantiateWithCode) ||
api.tx.revive.instantiateWithCode.meta.args.length !== 6
) {
throw new Error(
'The runtime does not expose api.tx.revive.instantiateWithCode with storageDepositLimit',
);
} else if (!api.call.reviveApi || !(0, util_1.isFunction)(api.call.reviveApi.call)) {
throw new Error(
'Your runtime does not expose the api.call.reviveApi.call runtime interfaces',
);
}
this.abi =
abi instanceof index_js_1.Abi
? abi
: new index_js_1.Abi(abi, api.registry.getChainProperties());
this.api = api;
this._decorateMethod = decorateMethod;
this._isWeightV1 = !api.registry.createType('Weight').proofSize;
}
get registry() {
return this.api.registry;
}
}
exports.Base = Base;
83 changes: 83 additions & 0 deletions .api-contract/build-tsc-cjs/base/Blueprint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.Blueprint = exports.BlueprintSubmittableResult = void 0;
exports.extendBlueprint = extendBlueprint;
const api_1 = require('@polkadot/api');
const util_1 = require('@polkadot/util');
const Base_js_1 = require('./Base.js');
const Contract_js_1 = require('./Contract.js');
const util_js_1 = require('./util.js');
class BlueprintSubmittableResult extends api_1.SubmittableResult {
contract;
constructor(result, contract) {
super(result);
this.contract = contract;
}
}
exports.BlueprintSubmittableResult = BlueprintSubmittableResult;
class Blueprint extends Base_js_1.Base {
/**
* @description The on-chain code hash for this blueprint
*/
codeHash;
__internal__tx = {};
constructor(api, abi, codeHash, decorateMethod) {
super(api, abi, decorateMethod);
this.codeHash = this.registry.createType('Hash', codeHash);
this.abi.constructors.forEach(c => {
if ((0, util_1.isUndefined)(this.__internal__tx[c.method])) {
this.__internal__tx[c.method] = (0, util_js_1.createBluePrintTx)(c, (o, p) =>
this.__internal__deploy(c, o, p),
);
}
});
}
get tx() {
return this.__internal__tx;
}
__internal__deploy = (
constructorOrId,
{ gasLimit = util_1.BN_ZERO, salt, storageDepositLimit = null, value = util_1.BN_ZERO },
params,
) => {
return this.api.tx.revive
.instantiate(
value,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore jiggle v1 weights, metadata points to latest
this._isWeightV1
? (0, util_js_1.convertWeight)(gasLimit).v1Weight
: (0, util_js_1.convertWeight)(gasLimit).v2Weight,
storageDepositLimit,
this.codeHash,
this.abi.findConstructor(constructorOrId).toU8a(params),
(0, util_js_1.encodeSalt)(salt),
)
.withResultTransform(
result =>
new BlueprintSubmittableResult(
result,
(() => {
if (result.status.isInBlock || result.status.isFinalized) {
return new Contract_js_1.Contract(
this.api,
this.abi,
'0x075e2a9cfb213a68dfa1f5cf6bf6d515ae212cf8',
this._decorateMethod,
);
}
return undefined;
})(),
),
);
};
}
exports.Blueprint = Blueprint;
function extendBlueprint(type, decorateMethod) {
return class extends Blueprint {
static __BlueprintType = type;
constructor(api, abi, codeHash) {
super(api, abi, codeHash, decorateMethod);
}
};
}
94 changes: 94 additions & 0 deletions .api-contract/build-tsc-cjs/base/Code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.Code = exports.CodeSubmittableResult = void 0;
exports.extendCode = extendCode;
const api_1 = require('@polkadot/api');
const util_1 = require('@polkadot/util');
const Base_js_1 = require('./Base.js');
const Blueprint_js_1 = require('./Blueprint.js');
const Contract_js_1 = require('./Contract.js');
const util_js_1 = require('./util.js');
class CodeSubmittableResult extends api_1.SubmittableResult {
blueprint;
contract;
constructor(result, blueprint, contract) {
super(result);
this.blueprint = blueprint;
this.contract = contract;
}
}
exports.CodeSubmittableResult = CodeSubmittableResult;
function isValidCode(code) {
return (0, util_1.isWasm)(code) || (0, util_1.isRiscV)(code);
}
class Code extends Base_js_1.Base {
code;
__internal__tx = {};
constructor(api, abi, wasm, decorateMethod) {
super(api, abi, decorateMethod);
this.code = isValidCode(this.abi.info.source.wasm)
? this.abi.info.source.wasm
: (0, util_1.u8aToU8a)(wasm);
if (!isValidCode(this.code)) {
throw new Error('Invalid code provided');
}
this.abi.constructors.forEach(c => {
if ((0, util_1.isUndefined)(this.__internal__tx[c.method])) {
this.__internal__tx[c.method] = (0, util_js_1.createBluePrintTx)(c, (o, p) =>
this.__internal__instantiate(c, o, p),
);
}
});
}
get tx() {
return this.__internal__tx;
}
__internal__instantiate = (
constructorOrId,
{ gasLimit = util_1.BN_ZERO, salt, storageDepositLimit = null, value = util_1.BN_ZERO },
params,
) => {
console.log('in instantiate');
console.log(this.abi.info.source.wasmHash);
return this.api.tx.revive
.instantiateWithCode(
value,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore jiggle v1 weights, metadata points to latest
this._isWeightV1
? (0, util_js_1.convertWeight)(gasLimit).v1Weight
: (0, util_js_1.convertWeight)(gasLimit).v2Weight,
storageDepositLimit,
(0, util_1.compactAddLength)(this.code),
this.abi.findConstructor(constructorOrId).toU8a(params),
(0, util_js_1.encodeSalt)(salt),
)
.withResultTransform(
result =>
new CodeSubmittableResult(
result,
new Blueprint_js_1.Blueprint(
this.api,
this.abi,
this.abi.info.source.wasmHash,
this._decorateMethod,
),
new Contract_js_1.Contract(
this.api,
this.abi,
'0x075e2a9cfb213a68dfa1f5cf6bf6d515ae212cf8',
this._decorateMethod,
),
),
);
};
}
exports.Code = Code;
function extendCode(type, decorateMethod) {
return class extends Code {
static __CodeType = type;
constructor(api, abi, wasm) {
super(api, abi, wasm, decorateMethod);
}
};
}
164 changes: 164 additions & 0 deletions .api-contract/build-tsc-cjs/base/Contract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.Contract = exports.ContractSubmittableResult = void 0;
exports.extendContract = extendContract;
const rxjs_1 = require('rxjs');
const api_1 = require('@polkadot/api');
const util_1 = require('@polkadot/util');
const util_js_1 = require('../util.js');
const Base_js_1 = require('./Base.js');
const util_js_2 = require('./util.js');
const MAX_CALL_GAS = new util_1.BN(5_000_000_000_000).isub(util_1.BN_ONE);
const l = (0, util_1.logger)('Contract');
function createQuery(meta, fn) {
return (0, util_js_2.withMeta)(meta, (origin, options, ...params) => fn(origin, options, params));
}
function createTx(meta, fn) {
return (0, util_js_2.withMeta)(meta, (options, ...params) => fn(options, params));
}
class ContractSubmittableResult extends api_1.SubmittableResult {
contractEvents;
constructor(result, contractEvents) {
super(result);
this.contractEvents = contractEvents;
}
}
exports.ContractSubmittableResult = ContractSubmittableResult;
class Contract extends Base_js_1.Base {
/**
* @description The on-chain address for this contract
*/
address;
__internal__query = {};
__internal__tx = {};
constructor(api, abi, address, decorateMethod) {
super(api, abi, decorateMethod);
this.address = this.registry.createType('AccountId20', address);
this.abi.messages.forEach(m => {
if ((0, util_1.isUndefined)(this.__internal__tx[m.method])) {
this.__internal__tx[m.method] = createTx(m, (o, p) => this.__internal__exec(m, o, p));
}
if ((0, util_1.isUndefined)(this.__internal__query[m.method])) {
this.__internal__query[m.method] = createQuery(m, (f, o, p) =>
this.__internal__read(m, o, p).send(f),
);
}
});
}
get query() {
return this.__internal__query;
}
get tx() {
return this.__internal__tx;
}
__internal__getGas = (_gasLimit, isCall = false) => {
const weight = (0, util_js_2.convertWeight)(_gasLimit);
if (weight.v1Weight.gt(util_1.BN_ZERO)) {
return weight;
}
return (0, util_js_2.convertWeight)(
isCall
? MAX_CALL_GAS
: (0, util_js_2.convertWeight)(
this.api.consts.system.blockWeights
? this.api.consts.system.blockWeights.maxBlock
: this.api.consts.system['maximumBlockWeight'],
)
.v1Weight.muln(64)
.div(util_1.BN_HUNDRED),
);
};
__internal__exec = (
messageOrId,
{ gasLimit = util_1.BN_ZERO, storageDepositLimit = null, value = util_1.BN_ZERO },
params,
) => {
return this.api.tx.revive
.call(
this.address,
value,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore jiggle v1 weights, metadata points to latest
this._isWeightV1
? (0, util_js_2.convertWeight)(gasLimit).v1Weight
: (0, util_js_2.convertWeight)(gasLimit).v2Weight,
storageDepositLimit,
this.abi.findMessage(messageOrId).toU8a(params),
)
.withResultTransform(
result =>
// ContractEmitted is the current generation, ContractExecution is the previous generation
new ContractSubmittableResult(
result,
(0, util_js_1.applyOnEvent)(result, ['ContractEmitted', 'ContractExecution'], records =>
records
.map(record => {
try {
return this.abi.decodeEvent(record);
} catch (error) {
l.error(`Unable to decode contract event: ${error.message}`);
return null;
}
})
.filter(decoded => !!decoded),
),
),
);
};
__internal__read = (
messageOrId,
{ gasLimit = util_1.BN_ZERO, storageDepositLimit = null, value = util_1.BN_ZERO },
params,
) => {
const message = this.abi.findMessage(messageOrId);
return {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
send: this._decorateMethod(origin =>
this.api.rx.call.contractsApi
.call(
origin,
this.address,
value,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore jiggle v1 weights, metadata points to latest
this._isWeightV1
? this.__internal__getGas(gasLimit, true).v1Weight
: this.__internal__getGas(gasLimit, true).v2Weight,
storageDepositLimit,
message.toU8a(params),
)
.pipe(
(0, rxjs_1.map)(
({ debugMessage, gasConsumed, gasRequired, result, storageDeposit }) => ({
debugMessage,
gasConsumed,
gasRequired:
gasRequired && !(0, util_js_2.convertWeight)(gasRequired).v1Weight.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,
}),
),
),
),
};
};
}
exports.Contract = Contract;
function extendContract(type, decorateMethod) {
return class extends Contract {
static __ContractType = type;
constructor(api, abi, address) {
super(api, abi, address, decorateMethod);
}
};
}
62 changes: 62 additions & 0 deletions .api-contract/build-tsc-cjs/base/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.extendContract =
exports.Contract =
exports.extendCode =
exports.CodeSubmittableResult =
exports.Code =
exports.extendBlueprint =
exports.BlueprintSubmittableResult =
exports.Blueprint =
void 0;
var Blueprint_js_1 = require('./Blueprint.js');
Object.defineProperty(exports, 'Blueprint', {
enumerable: true,
get: function () {
return Blueprint_js_1.Blueprint;
},
});
Object.defineProperty(exports, 'BlueprintSubmittableResult', {
enumerable: true,
get: function () {
return Blueprint_js_1.BlueprintSubmittableResult;
},
});
Object.defineProperty(exports, 'extendBlueprint', {
enumerable: true,
get: function () {
return Blueprint_js_1.extendBlueprint;
},
});
var Code_js_1 = require('./Code.js');
Object.defineProperty(exports, 'Code', {
enumerable: true,
get: function () {
return Code_js_1.Code;
},
});
Object.defineProperty(exports, 'CodeSubmittableResult', {
enumerable: true,
get: function () {
return Code_js_1.CodeSubmittableResult;
},
});
Object.defineProperty(exports, 'extendCode', {
enumerable: true,
get: function () {
return Code_js_1.extendCode;
},
});
var Contract_js_1 = require('./Contract.js');
Object.defineProperty(exports, 'Contract', {
enumerable: true,
get: function () {
return Contract_js_1.Contract;
},
});
Object.defineProperty(exports, 'extendContract', {
enumerable: true,
get: function () {
return Contract_js_1.extendContract;
},
});
25 changes: 25 additions & 0 deletions .api-contract/build-tsc-cjs/base/mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.mockApi = void 0;
const types_1 = require('@polkadot/types');
const registry = new types_1.TypeRegistry();
const instantiateWithCode = () => {
throw new Error('mock');
};
instantiateWithCode.meta = { args: new Array(6) };
exports.mockApi = {
call: {
contractsApi: {
call: () => {
throw new Error('mock');
},
},
},
isConnected: true,
registry,
tx: {
contracts: {
instantiateWithCode,
},
},
};
2 changes: 2 additions & 0 deletions .api-contract/build-tsc-cjs/base/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
42 changes: 42 additions & 0 deletions .api-contract/build-tsc-cjs/base/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.EMPTY_SALT = void 0;
exports.withMeta = withMeta;
exports.createBluePrintTx = createBluePrintTx;
exports.createBluePrintWithId = createBluePrintWithId;
exports.encodeSalt = encodeSalt;
exports.convertWeight = convertWeight;
exports.isWeightV2 = isWeightV2;
const types_1 = require('@polkadot/types');
const util_1 = require('@polkadot/util');
const util_crypto_1 = require('@polkadot/util-crypto');
exports.EMPTY_SALT = new Uint8Array();
function withMeta(meta, creator) {
creator.meta = meta;
return creator;
}
function createBluePrintTx(meta, fn) {
return withMeta(meta, (options, ...params) => fn(options, params));
}
function createBluePrintWithId(fn) {
return (constructorOrId, options, ...params) => fn(constructorOrId, options, params);
}
function encodeSalt(salt = (0, util_crypto_1.randomAsU8a)()) {
return salt instanceof types_1.Bytes
? salt
: salt?.length
? (0, util_1.compactAddLength)((0, util_1.u8aToU8a)(salt))
: exports.EMPTY_SALT;
}
function convertWeight(weight) {
const [refTime, proofSize] = isWeightV2(weight)
? [weight.refTime.toBn(), weight.proofSize.toBn()]
: [(0, util_1.bnToBn)(weight), undefined];
return {
v1Weight: refTime,
v2Weight: { proofSize, refTime },
};
}
function isWeightV2(weight) {
return !!weight.proofSize;
}
20 changes: 20 additions & 0 deletions .api-contract/build-tsc-cjs/bundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.packageInfo = exports.Abi = void 0;
const tslib_1 = require('tslib');
var index_js_1 = require('./Abi/index.js');
Object.defineProperty(exports, 'Abi', {
enumerable: true,
get: function () {
return index_js_1.Abi;
},
});
var packageInfo_js_1 = require('./packageInfo.js');
Object.defineProperty(exports, 'packageInfo', {
enumerable: true,
get: function () {
return packageInfo_js_1.packageInfo;
},
});
tslib_1.__exportStar(require('./promise/index.js'), exports);
tslib_1.__exportStar(require('./rx/index.js'), exports);
5 changes: 5 additions & 0 deletions .api-contract/build-tsc-cjs/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const tslib_1 = require('tslib');
require('./packageDetect.js');
tslib_1.__exportStar(require('./bundle.js'), exports);
10 changes: 10 additions & 0 deletions .api-contract/build-tsc-cjs/packageDetect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const packageInfo_1 = require('@polkadot/api/packageInfo');
const packageInfo_2 = require('@polkadot/types/packageInfo');
const util_1 = require('@polkadot/util');
const packageInfo_js_1 = require('./packageInfo.js');
(0, util_1.detectPackage)(packageInfo_js_1.packageInfo, null, [
packageInfo_1.packageInfo,
packageInfo_2.packageInfo,
]);
9 changes: 9 additions & 0 deletions .api-contract/build-tsc-cjs/packageInfo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.packageInfo = void 0;
exports.packageInfo = {
name: '@polkadot/api-contract',
path: typeof __dirname === 'string' ? __dirname : 'auto',
type: 'cjs',
version: '15.8.1',
};
23 changes: 23 additions & 0 deletions .api-contract/build-tsc-cjs/promise/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.ContractPromise = exports.CodePromise = exports.BlueprintPromise = void 0;
const api_1 = require('@polkadot/api');
const index_js_1 = require('../base/index.js');
class BlueprintPromise extends index_js_1.Blueprint {
constructor(api, abi, codeHash) {
super(api, abi, codeHash, api_1.toPromiseMethod);
}
}
exports.BlueprintPromise = BlueprintPromise;
class CodePromise extends index_js_1.Code {
constructor(api, abi, wasm) {
super(api, abi, wasm, api_1.toPromiseMethod);
}
}
exports.CodePromise = CodePromise;
class ContractPromise extends index_js_1.Contract {
constructor(api, abi, address) {
super(api, abi, address, api_1.toPromiseMethod);
}
}
exports.ContractPromise = ContractPromise;
2 changes: 2 additions & 0 deletions .api-contract/build-tsc-cjs/promise/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
23 changes: 23 additions & 0 deletions .api-contract/build-tsc-cjs/rx/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.ContractRx = exports.CodeRx = exports.BlueprintRx = void 0;
const api_1 = require('@polkadot/api');
const index_js_1 = require('../base/index.js');
class BlueprintRx extends index_js_1.Blueprint {
constructor(api, abi, codeHash) {
super(api, abi, codeHash, api_1.toRxMethod);
}
}
exports.BlueprintRx = BlueprintRx;
class CodeRx extends index_js_1.Code {
constructor(api, abi, wasm) {
super(api, abi, wasm, api_1.toRxMethod);
}
}
exports.CodeRx = CodeRx;
class ContractRx extends index_js_1.Contract {
constructor(api, abi, address) {
super(api, abi, address, api_1.toRxMethod);
}
}
exports.ContractRx = ContractRx;
2 changes: 2 additions & 0 deletions .api-contract/build-tsc-cjs/rx/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
2 changes: 2 additions & 0 deletions .api-contract/build-tsc-cjs/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
12 changes: 12 additions & 0 deletions .api-contract/build-tsc-cjs/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.applyOnEvent = applyOnEvent;
function applyOnEvent(result, types, fn) {
if (result.isInBlock || result.isFinalized) {
const records = result.filterRecords('contracts', types);
if (records.length) {
return fn(records);
}
}
return undefined;
}
351 changes: 351 additions & 0 deletions .api-contract/build-tsc-esm/Abi/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,351 @@
import { Option, TypeRegistry } from '@polkadot/types';
import { TypeDefInfo } from '@polkadot/types-create';
import {
assertReturn,
compactAddLength,
compactStripLength,
isBn,
isNumber,
isObject,
isString,
isUndefined,
logger,
stringCamelCase,
stringify,
u8aConcat,
u8aToHex,
} from '@polkadot/util';
import { convertVersions, enumVersions } from './toLatestCompatible.js';
const l = logger('Abi');
const PRIMITIVE_ALWAYS = ['AccountId', 'AccountIndex', 'Address', 'Balance'];
function findMessage(list, messageOrId) {
const message = isNumber(messageOrId)
? list[messageOrId]
: isString(messageOrId)
? list.find(({ identifier }) =>
[identifier, stringCamelCase(identifier)].includes(messageOrId.toString()),
)
: messageOrId;
return assertReturn(
message,
() => `Attempted to call an invalid contract interface, ${stringify(messageOrId)}`,
);
}
function getMetadata(registry, json) {
// this is for V1, V2, V3
const vx = enumVersions.find(v => isObject(json[v]));
// this was added in V4
const jsonVersion = json.version;
if (!vx && jsonVersion && !enumVersions.find(v => v === `V${jsonVersion}`)) {
throw new Error(`Unable to handle version ${jsonVersion}`);
}
const metadata = registry.createType(
'ContractMetadata',
vx ? { [vx]: json[vx] } : jsonVersion ? { [`V${jsonVersion}`]: json } : { V0: json },
);
const converter = convertVersions.find(([v]) => metadata[`is${v}`]);
if (!converter) {
throw new Error(`Unable to convert ABI with version ${metadata.type} to a supported version`);
}
const upgradedMetadata = converter[1](registry, metadata[`as${converter[0]}`]);
return upgradedMetadata;
}
function parseJson(json, chainProperties) {
const registry = new TypeRegistry();
const info = registry.createType('ContractProjectInfo', json);
const metadata = getMetadata(registry, json);
const lookup = registry.createType('PortableRegistry', { types: metadata.types }, true);
// attach the lookup to the registry - now the types are known
registry.setLookup(lookup);
if (chainProperties) {
registry.setChainProperties(chainProperties);
}
// warm-up the actual type, pre-use
lookup.types.forEach(({ id }) => lookup.getTypeDef(id));
return [json, registry, metadata, info];
}
/**
* @internal
* Determines if the given input value is a ContractTypeSpec
*/
function isTypeSpec(value) {
return (
!!value && value instanceof Map && !isUndefined(value.type) && !isUndefined(value.displayName)
);
}
/**
* @internal
* Determines if the given input value is an Option
*/
function isOption(value) {
return !!value && value instanceof Option;
}
export class Abi {
events;
constructors;
info;
json;
messages;
metadata;
registry;
environment = new Map();
constructor(abiJson, chainProperties) {
[this.json, this.registry, this.metadata, this.info] = parseJson(
isString(abiJson) ? JSON.parse(abiJson) : abiJson,
chainProperties,
);
this.constructors = this.metadata.spec.constructors.map((spec, index) =>
this.__internal__createMessage(spec, index, {
isConstructor: true,
isDefault: spec.default.isTrue,
isPayable: spec.payable.isTrue,
returnType: spec.returnType.isSome
? this.registry.lookup.getTypeDef(spec.returnType.unwrap().type)
: null,
}),
);
this.events = this.metadata.spec.events.map((_, index) => this.__internal__createEvent(index));
this.messages = this.metadata.spec.messages.map((spec, index) =>
this.__internal__createMessage(spec, index, {
isDefault: spec.default.isTrue,
isMutating: spec.mutates.isTrue,
isPayable: spec.payable.isTrue,
returnType: spec.returnType.isSome
? this.registry.lookup.getTypeDef(spec.returnType.unwrap().type)
: null,
}),
);
// NOTE See the rationale for having Option<...> values in the actual
// ContractEnvironmentV4 structure definition in interfaces/contractsAbi
// (Due to conversions, the fields may not exist)
for (const [key, opt] of this.metadata.spec.environment.entries()) {
if (isOption(opt)) {
if (opt.isSome) {
const value = opt.unwrap();
if (isBn(value)) {
this.environment.set(key, value);
} else if (isTypeSpec(value)) {
this.environment.set(key, this.registry.lookup.getTypeDef(value.type));
} else {
throw new Error(
`Invalid environment definition for ${key}:: Expected either Number or ContractTypeSpec`,
);
}
}
} else {
throw new Error(`Expected Option<*> definition for ${key} in ContractEnvironment`);
}
}
}
/**
* Warning: Unstable API, bound to change
*/
decodeEvent(record) {
switch (this.metadata.version.toString()) {
// earlier version are hoisted to v4
case '4':
return this.__internal__decodeEventV4(record);
// Latest
default:
return this.__internal__decodeEventV5(record);
}
}
__internal__decodeEventV5 = record => {
// Find event by first topic, which potentially is the signature_topic
const signatureTopic = record.topics[0];
const data = record.event.data[1];
if (signatureTopic) {
const event = this.events.find(
e =>
e.signatureTopic !== undefined &&
e.signatureTopic !== null &&
e.signatureTopic === signatureTopic.toHex(),
);
// Early return if event found by signature topic
if (event) {
return event.fromU8a(data);
}
}
// If no event returned yet, it might be anonymous
const amountOfTopics = record.topics.length;
const potentialEvents = this.events.filter(e => {
// event can't have a signature topic
if (e.signatureTopic !== null && e.signatureTopic !== undefined) {
return false;
}
// event should have same amount of indexed fields as emitted topics
const amountIndexed = e.args.filter(a => a.indexed).length;
if (amountIndexed !== amountOfTopics) {
return false;
}
// If all conditions met, it's a potential event
return true;
});
if (potentialEvents.length === 1) {
return potentialEvents[0].fromU8a(data);
}
throw new Error('Unable to determine event');
};
__internal__decodeEventV4 = record => {
const data = record.event.data[1];
const index = data[0];
const event = this.events[index];
if (!event) {
throw new Error(`Unable to find event with index ${index}`);
}
return event.fromU8a(data.subarray(1));
};
/**
* Warning: Unstable API, bound to change
*/
decodeConstructor(data) {
return this.__internal__decodeMessage('message', this.constructors, data);
}
/**
* Warning: Unstable API, bound to change
*/
decodeMessage(data) {
return this.__internal__decodeMessage('message', this.messages, data);
}
findConstructor(constructorOrId) {
return findMessage(this.constructors, constructorOrId);
}
findMessage(messageOrId) {
return findMessage(this.messages, messageOrId);
}
__internal__createArgs = (args, spec) => {
return args.map(({ label, type }, index) => {
try {
if (!isObject(type)) {
throw new Error('Invalid type definition found');
}
const displayName = type.displayName.length
? type.displayName[type.displayName.length - 1].toString()
: undefined;
const camelName = stringCamelCase(label);
if (displayName && PRIMITIVE_ALWAYS.includes(displayName)) {
return {
name: camelName,
type: {
info: TypeDefInfo.Plain,
type: displayName,
},
};
}
const typeDef = this.registry.lookup.getTypeDef(type.type);
return {
name: camelName,
type:
displayName && !typeDef.type.startsWith(displayName)
? { displayName, ...typeDef }
: typeDef,
};
} catch (error) {
l.error(`Error expanding argument ${index} in ${stringify(spec)}`);
throw error;
}
});
};
__internal__createMessageParams = (args, spec) => {
return this.__internal__createArgs(args, spec);
};
__internal__createEventParams = (args, spec) => {
const params = this.__internal__createArgs(args, spec);
return params.map((p, index) => ({ ...p, indexed: args[index].indexed.toPrimitive() }));
};
__internal__createEvent = index => {
// TODO TypeScript would narrow this type to the correct version,
// but version is `Text` so I need to call `toString()` here,
// which breaks the type inference.
switch (this.metadata.version.toString()) {
case '4':
return this.__internal__createEventV4(this.metadata.spec.events[index], index);
default:
return this.__internal__createEventV5(this.metadata.spec.events[index], index);
}
};
__internal__createEventV5 = (spec, index) => {
const args = this.__internal__createEventParams(spec.args, spec);
const event = {
args,
docs: spec.docs.map(d => d.toString()),
fromU8a: data => ({
args: this.__internal__decodeArgs(args, data),
event,
}),
identifier: [spec.module_path, spec.label].join('::'),
index,
signatureTopic: spec.signature_topic.isSome ? spec.signature_topic.unwrap().toHex() : null,
};
return event;
};
__internal__createEventV4 = (spec, index) => {
const args = this.__internal__createEventParams(spec.args, spec);
const event = {
args,
docs: spec.docs.map(d => d.toString()),
fromU8a: data => ({
args: this.__internal__decodeArgs(args, data),
event,
}),
identifier: spec.label.toString(),
index,
};
return event;
};
__internal__createMessage = (spec, index, add = {}) => {
const args = this.__internal__createMessageParams(spec.args, spec);
const identifier = spec.label.toString();
const message = {
...add,
args,
docs: spec.docs.map(d => d.toString()),
fromU8a: data => ({
args: this.__internal__decodeArgs(args, data),
message,
}),
identifier,
index,
isDefault: spec.default.isTrue,
method: stringCamelCase(identifier),
path: identifier.split('::').map(s => stringCamelCase(s)),
selector: spec.selector,
toU8a: params => this.__internal__encodeMessageArgs(spec, args, params),
};
return message;
};
__internal__decodeArgs = (args, data) => {
// for decoding we expect the input to be just the arg data, no selectors
// no length added (this allows use with events as well)
let offset = 0;
return args.map(({ type: { lookupName, type } }) => {
const value = this.registry.createType(lookupName || type, data.subarray(offset));
offset += value.encodedLength;
return value;
});
};
__internal__decodeMessage = (type, list, data) => {
const [, trimmed] = compactStripLength(data);
const selector = trimmed.subarray(0, 4);
const message = list.find(m => m.selector.eq(selector));
if (!message) {
throw new Error(`Unable to find ${type} with selector ${u8aToHex(selector)}`);
}
return message.fromU8a(trimmed.subarray(4));
};
__internal__encodeMessageArgs = ({ label, selector }, args, data) => {
if (data.length !== args.length) {
throw new Error(
`Expected ${args.length} arguments to contract message '${label.toString()}', found ${data.length}`,
);
}
return compactAddLength(
u8aConcat(
this.registry.createType('ContractSelector', selector).toU8a(),
...args.map(({ type: { lookupName, type } }, index) =>
this.registry.createType(lookupName || type, data[index]).toU8a(),
),
),
);
};
}
26 changes: 26 additions & 0 deletions .api-contract/build-tsc-esm/Abi/toLatestCompatible.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { v0ToV1 } from './toV1.js';
import { v1ToV2 } from './toV2.js';
import { v2ToV3 } from './toV3.js';
import { v3ToV4 } from './toV4.js';
export const enumVersions = ['V5', 'V4', 'V3', 'V2', 'V1'];
function createConverter(next, step) {
return (registry, input) => next(registry, step(registry, input));
}
export function v5ToLatestCompatible(_registry, v5) {
return v5;
}
export function v4ToLatestCompatible(_registry, v4) {
return v4;
}
export const v3ToLatestCompatible = /*#__PURE__*/ createConverter(v4ToLatestCompatible, v3ToV4);
export const v2ToLatestCompatible = /*#__PURE__*/ createConverter(v3ToLatestCompatible, v2ToV3);
export const v1ToLatestCompatible = /*#__PURE__*/ createConverter(v2ToLatestCompatible, v1ToV2);
export const v0ToLatestCompatible = /*#__PURE__*/ createConverter(v1ToLatestCompatible, v0ToV1);
export const convertVersions = [
['V5', v5ToLatestCompatible],
['V4', v4ToLatestCompatible],
['V3', v3ToLatestCompatible],
['V2', v2ToLatestCompatible],
['V1', v1ToLatestCompatible],
['V0', v0ToLatestCompatible],
];
24 changes: 24 additions & 0 deletions .api-contract/build-tsc-esm/Abi/toV1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { convertSiV0toV1 } from '@polkadot/types';
import { objectSpread } from '@polkadot/util';
function v0ToV1Names(all) {
return all.map(e =>
objectSpread({}, e, {
name: Array.isArray(e.name) ? e.name : [e.name],
}),
);
}
export function v0ToV1(registry, v0) {
if (!v0.metadataVersion.length) {
throw new Error('Invalid format for V0 (detected) contract metadata');
}
return registry.createType(
'ContractMetadataV1',
objectSpread({}, v0, {
spec: objectSpread({}, v0.spec, {
constructors: v0ToV1Names(v0.spec.constructors),
messages: v0ToV1Names(v0.spec.messages),
}),
types: convertSiV0toV1(registry, v0.types),
}),
);
}
33 changes: 33 additions & 0 deletions .api-contract/build-tsc-esm/Abi/toV2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { objectSpread } from '@polkadot/util';
const ARG_TYPES = {
ContractConstructorSpec: 'ContractMessageParamSpecV2',
ContractEventSpec: 'ContractEventParamSpecV2',
ContractMessageSpec: 'ContractMessageParamSpecV2',
};
function v1ToV2Label(entry) {
return objectSpread({}, entry, {
label: Array.isArray(entry.name) ? entry.name.join('::') : entry.name,
});
}
function v1ToV2Labels(registry, outType, all) {
return all.map(e =>
registry.createType(
`${outType}V2`,
objectSpread(v1ToV2Label(e), {
args: e.args.map(a => registry.createType(ARG_TYPES[outType], v1ToV2Label(a))),
}),
),
);
}
export function v1ToV2(registry, v1) {
return registry.createType(
'ContractMetadataV2',
objectSpread({}, v1, {
spec: objectSpread({}, v1.spec, {
constructors: v1ToV2Labels(registry, 'ContractConstructorSpec', v1.spec.constructors),
events: v1ToV2Labels(registry, 'ContractEventSpec', v1.spec.events),
messages: v1ToV2Labels(registry, 'ContractMessageSpec', v1.spec.messages),
}),
}),
);
}
14 changes: 14 additions & 0 deletions .api-contract/build-tsc-esm/Abi/toV3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { objectSpread } from '@polkadot/util';
export function v2ToV3(registry, v2) {
return registry.createType(
'ContractMetadataV3',
objectSpread({}, v2, {
spec: objectSpread({}, v2.spec, {
constructors: v2.spec.constructors.map(c =>
// V3 introduces the payable flag on constructors, for <V3, it is always true
registry.createType('ContractConstructorSpecV3', objectSpread({}, c, { payable: true })),
),
}),
}),
);
}
17 changes: 17 additions & 0 deletions .api-contract/build-tsc-esm/Abi/toV4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { objectSpread } from '@polkadot/util';
export function v3ToV4(registry, v3) {
return registry.createType(
'ContractMetadataV4',
objectSpread({}, v3, {
spec: objectSpread({}, v3.spec, {
constructors: v3.spec.constructors.map(c =>
registry.createType('ContractConstructorSpecV4', objectSpread({}, c)),
),
messages: v3.spec.messages.map(m =>
registry.createType('ContractMessageSpecV3', objectSpread({}, m)),
),
}),
version: registry.createType('Text', '4'),
}),
);
}
1 change: 1 addition & 0 deletions .api-contract/build-tsc-esm/augment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@polkadot/api-augment';
34 changes: 34 additions & 0 deletions .api-contract/build-tsc-esm/base/Base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { isFunction } from '@polkadot/util';
import { Abi } from '../Abi/index.js';
export class Base {
abi;
api;
_decorateMethod;
_isWeightV1;
constructor(api, abi, decorateMethod) {
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.revive ||
!isFunction(api.tx.revive.instantiateWithCode) ||
api.tx.revive.instantiateWithCode.meta.args.length !== 6
) {
throw new Error(
'The runtime does not expose api.tx.revive.instantiateWithCode with storageDepositLimit',
);
} else if (!api.call.reviveApi || !isFunction(api.call.reviveApi.call)) {
throw new Error(
'Your runtime does not expose the api.call.reviveApi.call runtime interfaces',
);
}
this.abi = abi instanceof Abi ? abi : new Abi(abi, api.registry.getChainProperties());
this.api = api;
this._decorateMethod = decorateMethod;
this._isWeightV1 = !api.registry.createType('Weight').proofSize;
}
get registry() {
return this.api.registry;
}
}
Loading