Skip to content
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

Add storage deposit support #4304

Merged
merged 12 commits into from
Dec 14, 2021
3 changes: 2 additions & 1 deletion packages/api-contract/src/base/Blueprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@ export class Blueprint<ApiType extends ApiTypes> extends Base<ApiType> {
return this.#tx;
}

#deploy = (constructorOrId: AbiConstructor | string | number, { gasLimit = BN_ZERO, salt, value = BN_ZERO }: BlueprintOptions, params: unknown[]): SubmittableExtrinsic<ApiType, BlueprintSubmittableResult<ApiType>> => {
#deploy = (constructorOrId: AbiConstructor | string | number, { gasLimit = BN_ZERO, storageDepositLimit = BN_ZERO, salt, value = BN_ZERO }: BlueprintOptions, params: unknown[]): SubmittableExtrinsic<ApiType, BlueprintSubmittableResult<ApiType>> => {
return this.api.tx.contracts
.instantiate(
value,
gasLimit,
storageDepositLimit,
Copy link
Member

@jacogr jacogr Dec 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backwards compat is always a HUGE issue. So, in this case (luckily) the number of paramaters changed, so it would be a case of -

this.api.tx.contracts.instantiate.meta.args.length === 6
  ? this.api.tx.contracts.instantiate(value, gasLimit, storageDepositLimit, codeHash, params, salt)
  : this.api.tx.contracts.instantiate(value, gasLimit, codeHash, params, salt)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this change necessary in case api-contract version is different than api version?
it would mean overloading the generated interfaces somehow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IT is needed since it depends on the chain it is connected to - so it needs to be detected via on-chain metadata. You can have the most recent API with an ancient node.

Copy link
Member Author

@statictype statictype Dec 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i see... tried a few things yesterday but was unable to figure out how to do that. is there a PR where you did something similar that you can point me to?

Copy link
Member

@jacogr jacogr Dec 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, it is a bit of a nightmare, since these things are short-lived - so I generally allow 3+ months leeway for people to upgrade before ripping it out, so the examples that were here (contracts specific) have been removed.

Will dig around the older versions and find it. (There is a similar approach in the apps UI as well, which tries to also give around 3 months.... but generally they end up living a "bit" longer)

Copy link
Member

@jacogr jacogr Dec 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is an example for the apps UI that does the same thing -

https://github.com/polkadot-js/apps/blob/master/packages/page-democracy/src/Overview/Fasttrack.tsx#L59-L63

There are millions of them in there... sadly...

Mostly in the API it is always only contracts since it is the one place where we add convenience wrappers around lower-level interfaces... will find an old release having some.

EDIT: Here is the 4.9.1 api release with the blueprint deploy still supporting 2 versions (it was removed in 4.10.1, aka grace-period ended... the apps UI really needs to learn from this and start cleaning up after itself...)

#deploy = (constructorOrId: AbiConstructor | string | number, { gasLimit = 0, salt, value = 0 }: BlueprintOptions, params: CodecArg[]): SubmittableExtrinsic<ApiType, BlueprintSubmittableResult<ApiType>> => {
const encodedSalt = encodeSalt(salt);
const withSalt = this.api.tx.contracts.instantiate.meta.args.length === 5;
const encoded = this.abi.findConstructor(constructorOrId).toU8a(params, withSalt ? EMPTY_SALT : encodedSalt);
const tx = withSalt
? this.api.tx.contracts.instantiate(value, gasLimit, this.codeHash, encoded, encodedSalt)
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore old style with salt included
: this.api.tx.contracts.instantiate(value, gasLimit, this.codeHash, encoded);
return tx.withResultTransform((result: ISubmittableResult) =>
new BlueprintSubmittableResult(result, applyOnEvent(result, ['Instantiated'], ([record]: EventRecord[]) =>
new Contract<ApiType>(this.api, this.abi, record.event.data[1] as AccountId, this._decorateMethod)
))
);
}
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it now! you have to ts-ignore the old style

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is slightly messy code-wise :(

… but better than dealing with the “it doesn’t work-anymore” flood of support…

Copy link
Member Author

@statictype statictype Dec 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think i got everything but still can't call. I get this rpc core error
polkadot-js/apps#6657 (comment)

There is also this contract query, but not sure if adding an extra param there would solve it and what that param should be

https://github.com/polkadot-js/apps/blob/db4f91e47531fa4c6d00c4015dcbadae2deb5683/package/page-contracts/src/shared/Messages.tsx#L67

this.codeHash,
this.abi.findConstructor(constructorOrId).toU8a(params),
encodeSalt(salt)
Expand Down
3 changes: 2 additions & 1 deletion packages/api-contract/src/base/Code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,12 @@ export class Code<ApiType extends ApiTypes> extends Base<ApiType> {
return this.#tx;
}

#instantiate = (constructorOrId: AbiConstructor | string | number, { gasLimit = BN_ZERO, salt, value = BN_ZERO }: BlueprintOptions, params: unknown[]): SubmittableExtrinsic<ApiType, CodeSubmittableResult<ApiType>> => {
#instantiate = (constructorOrId: AbiConstructor | string | number, { gasLimit = BN_ZERO, storageDepositLimit = BN_ZERO, salt, value = BN_ZERO }: BlueprintOptions, params: unknown[]): SubmittableExtrinsic<ApiType, CodeSubmittableResult<ApiType>> => {
return this.api.tx.contracts
.instantiateWithCode(
value,
gasLimit,
storageDepositLimit,
compactAddLength(this.code),
this.abi.findConstructor(constructorOrId).toU8a(params),
encodeSalt(salt)
Expand Down
15 changes: 11 additions & 4 deletions packages/api-contract/src/base/Contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,17 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
: gasLimit;
};

#exec = (messageOrId: AbiMessage | string | number, { gasLimit = BN_ZERO, value = BN_ZERO }: ContractOptions, params: unknown[]): SubmittableExtrinsic<ApiType> => {
#getStorageDepositLimitBN = (storageDepositLimit: bigint | BN | string | number): BN => {
return bnToBn(storageDepositLimit);
};

#exec = (messageOrId: AbiMessage | string | number, { gasLimit = BN_ZERO, storageDepositLimit = BN_ZERO, value = BN_ZERO }: ContractOptions, params: unknown[]): SubmittableExtrinsic<ApiType> => {
return this.api.tx.contracts
.call(
this.address,
value,
this.#getGas(gasLimit),
this.#getStorageDepositLimitBN(storageDepositLimit),
this.abi.findMessage(messageOrId).toU8a(params)
)
.withResultTransform((result: ISubmittableResult) =>
Expand All @@ -128,7 +133,7 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
);
};

#read = (messageOrId: AbiMessage | string | number, { gasLimit = BN_ZERO, value = BN_ZERO }: ContractOptions, params: unknown[]): ContractCallSend<ApiType> => {
#read = (messageOrId: AbiMessage | string | number, { gasLimit = BN_ZERO, storageDepositLimit = BN_ZERO, value = BN_ZERO }: ContractOptions, params: unknown[]): ContractCallSend<ApiType> => {
assert(this.hasRpcContractsCall, ERROR_NO_CALL);

const message = this.abi.findMessage(messageOrId);
Expand All @@ -142,10 +147,11 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
gasLimit: this.#getGas(gasLimit, true),
inputData: message.toU8a(params),
origin,
storageDepositLimit: this.#getStorageDepositLimitBN(storageDepositLimit),
value
})
.pipe(
map(({ debugMessage, gasConsumed, gasRequired, result }): ContractCallOutcome => ({
map(({ debugMessage, gasConsumed, gasRequired, result, storageDeposit }): ContractCallOutcome => ({
debugMessage,
gasConsumed,
gasRequired: gasRequired && !gasRequired.isZero()
Expand All @@ -154,7 +160,8 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
output: result.isOk && message.returnType
? this.abi.registry.createTypeUnsafe(message.returnType.lookupName || message.returnType.type, [result.asOk.data.toU8a(true)], { isPedantic: true })
: null,
result
result,
storageDeposit
}))
)
)
Expand Down
8 changes: 4 additions & 4 deletions packages/api-contract/src/base/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ import type { AbiMessage, BlueprintOptions, ContractCallOutcome, ContractOptions

export interface BlueprintDeploy<ApiType extends ApiTypes> {
(options: BlueprintOptions, ...params: unknown[]): SubmittableExtrinsic<ApiType>;
(value: bigint | string | number | BN, gasLimit: bigint | string | number | BN, ...params: unknown[]): SubmittableExtrinsic<ApiType>;
(value: bigint | string | number | BN, gasLimit: bigint | string | number | BN, storageDepositLimit: bigint | BN | string | number, ...params: unknown[]): SubmittableExtrinsic<ApiType>;
}

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

export interface ContractTx<ApiType extends ApiTypes> {
(options: ContractOptions, ...params: unknown[]): SubmittableExtrinsic<ApiType>;
(value: bigint | BN | string | number, gasLimit: bigint | BN | string | number, ...params: unknown[]): SubmittableExtrinsic<ApiType>;
(value: bigint | BN | string | number, gasLimit: bigint | BN | string | number, storageDepositLimit: bigint | BN | string | number, ...params: unknown[]): SubmittableExtrinsic<ApiType>;
}

export interface ContractGeneric<O, T> {
(messageOrId: AbiMessage | string | number, options: O, ...params: unknown[]): T;
(messageOrId: AbiMessage | string | number, value: bigint | BN | string | number, gasLimit: bigint | BN | string | number, ...params: unknown[]): T;
(messageOrId: AbiMessage | string | number, value: bigint | BN | string | number, gasLimit: bigint | BN | string | number, storageDepositLimit: bigint | BN | string | number, ...params: unknown[]): T;
}

export type ContractCallResult<ApiType extends ApiTypes, T> = ApiType extends 'rxjs'
Expand Down
5 changes: 4 additions & 1 deletion packages/api-contract/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import type { ApiBase } from '@polkadot/api/base';
import type { ApiTypes } from '@polkadot/api/types';
import type { Text, u64 } from '@polkadot/types';
import type { ContractExecResultResult, ContractSelector } from '@polkadot/types/interfaces';
import type { Balance, ContractExecResultResult, ContractSelector } from '@polkadot/types/interfaces';
import type { Codec, TypeDef } from '@polkadot/types/types';
import type { BN } from '@polkadot/util';
import type { Abi } from '.';
Expand Down Expand Up @@ -56,6 +56,7 @@ export interface ContractCallOutcome {
debugMessage: Text;
gasConsumed: u64;
gasRequired: u64;
storageDeposit: Balance;
output: Codec | null;
result: ContractExecResultResult;
}
Expand All @@ -72,11 +73,13 @@ export interface DecodedMessage {

export interface BlueprintOptions {
gasLimit?: bigint | string | number | BN;
storageDepositLimit?: bigint | BN | string | number;
salt?: Uint8Array | string | null;
value?: bigint | string | number | BN;
}

export interface ContractOptions {
gasLimit?: bigint | BN | string | number;
storageDepositLimit?: bigint | BN | string | number;
value?: bigint | BN | string | number;
}
3 changes: 2 additions & 1 deletion packages/api-contract/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function isOptions <T> (options: bigint | string | number | BN | T): opti

export function extractOptions <T extends TOptions> (value: bigint | string | number | BN, params: unknown[]): [T, unknown[]] {
const gasLimit = params.shift() as BN;
const storageDepositLimit = params.shift() as BN;

return [{ gasLimit, value } as T, params];
return [{ gasLimit, storageDepositLimit, value } as T, params];
}
4 changes: 2 additions & 2 deletions packages/api/src/augment/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,15 @@ declare module '@polkadot/rpc-core/types.jsonrpc' {
/**
* Executes a call to a contract
**/
call: AugmentedRpc<(callRequest: ContractCallRequest | { origin?: any; dest?: any; value?: any; gasLimit?: any; inputData?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractExecResult>>;
call: AugmentedRpc<(callRequest: ContractCallRequest | { origin?: any; dest?: any; value?: any; gasLimit?: any; storageDepositLimit?: any ,inputData?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractExecResult>>;
/**
* Returns the value under a specified storage key in a contract
**/
getStorage: AugmentedRpc<(address: AccountId | string | Uint8Array, key: H256 | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<Option<Bytes>>>;
/**
* Instantiate a new contract
**/
instantiate: AugmentedRpc<(request: InstantiateRequest | { origin?: any; endowment?: any; gasLimit?: any; code?: any; data?: any; salt?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractInstantiateResult>>;
instantiate: AugmentedRpc<(request: InstantiateRequest | { origin?: any; endowment?: any; gasLimit?: any; storageDepositLimit?: any; code?: any; data?: any; salt?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractInstantiateResult>>;
/**
* Returns the projected time a given contract will be able to sustain paying its rent
**/
Expand Down
6 changes: 3 additions & 3 deletions packages/api/src/augment/tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -705,15 +705,15 @@ declare module '@polkadot/api/types/submittable' {
* * If no account exists and the call value is not less than `existential_deposit`,
* a regular account will be created and any value will be transferred.
**/
call: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array, gasLimit: Compact<u64> | AnyNumber | Uint8Array, data: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>, Compact<u64>, Bytes]>;
call: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array, gasLimit: Compact<u64> | AnyNumber | Uint8Array, storageDepositLimit: Option<Compact<u64>> | AnyNumber | Uint8Array, data: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>, Compact<u64>, Bytes]>;
/**
* Instantiates a contract from a previously deployed wasm binary.
*
* This function is identical to [`Self::instantiate_with_code`] but without the
* code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary
* must be supplied.
**/
instantiate: AugmentedSubmittable<(endowment: Compact<u128> | AnyNumber | Uint8Array, gasLimit: Compact<u64> | AnyNumber | Uint8Array, codeHash: H256 | string | Uint8Array, data: Bytes | string | Uint8Array, salt: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u128>, Compact<u64>, H256, Bytes, Bytes]>;
instantiate: AugmentedSubmittable<(endowment: Compact<u128> | AnyNumber | Uint8Array, gasLimit: Compact<u64> | AnyNumber | Uint8Array, storageDepositLimit: Option<Compact<u64>> | AnyNumber | Uint8Array, codeHash: H256 | string | Uint8Array, data: Bytes | string | Uint8Array, salt: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u128>, Compact<u64>, H256, Bytes, Bytes]>;
/**
* Instantiates a new contract from the supplied `code` optionally transferring
* some balance.
Expand All @@ -738,7 +738,7 @@ declare module '@polkadot/api/types/submittable' {
* - The `endowment` is transferred to the new account.
* - The `deploy` function is executed in the context of the newly-created account.
**/
instantiateWithCode: AugmentedSubmittable<(endowment: Compact<u128> | AnyNumber | Uint8Array, gasLimit: Compact<u64> | AnyNumber | Uint8Array, code: Bytes | string | Uint8Array, data: Bytes | string | Uint8Array, salt: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u128>, Compact<u64>, Bytes, Bytes, Bytes]>;
instantiateWithCode: AugmentedSubmittable<(endowment: Compact<u128> | AnyNumber | Uint8Array, gasLimit: Compact<u64> | AnyNumber | Uint8Array, storageDepositLimit: Option<Compact<u64>> | AnyNumber | Uint8Array, code: Bytes | string | Uint8Array, data: Bytes | string | Uint8Array, salt: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u128>, Compact<u64>, Bytes, Bytes, Bytes]>;
/**
* Generic tx
**/
Expand Down
3 changes: 3 additions & 0 deletions packages/types/src/augment/lookup/substrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1975,18 +1975,21 @@ export default {
dest: 'MultiAddress',
value: 'Compact<u128>',
gasLimit: 'Compact<u64>',
storageDepositLimit: 'Option<Compact<u64>>',
data: 'Bytes',
},
instantiate_with_code: {
endowment: 'Compact<u128>',
gasLimit: 'Compact<u64>',
storageDepositLimit: 'Option<Compact<u64>>',
code: 'Bytes',
data: 'Bytes',
salt: 'Bytes',
},
instantiate: {
endowment: 'Compact<u128>',
gasLimit: 'Compact<u64>',
storageDepositLimit: 'Option<Compact<u64>>',
codeHash: 'H256',
data: 'Bytes',
salt: 'Bytes'
Expand Down
3 changes: 3 additions & 0 deletions packages/types/src/augment/lookup/types-substrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2149,12 +2149,14 @@ declare module '@polkadot/types/lookup' {
readonly dest: MultiAddress;
readonly value: Compact<u128>;
readonly gasLimit: Compact<u64>;
readonly storageDepositLimit: Option<Compact<u64>>;
readonly data: Bytes;
} & Struct;
readonly isInstantiateWithCode: boolean;
readonly asInstantiateWithCode: {
readonly endowment: Compact<u128>;
readonly gasLimit: Compact<u64>;
readonly storageDepositLimit: Option<Compact<u64>>;
readonly code: Bytes;
readonly data: Bytes;
readonly salt: Bytes;
Expand All @@ -2163,6 +2165,7 @@ declare module '@polkadot/types/lookup' {
readonly asInstantiate: {
readonly endowment: Compact<u128>;
readonly gasLimit: Compact<u64>;
readonly storageDepositLimit: Option<Compact<u64>>;
readonly codeHash: H256;
readonly data: Bytes;
readonly salt: Bytes;
Expand Down
3 changes: 2 additions & 1 deletion packages/types/src/interfaces/contracts/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export default {
dest: 'AccountId',
value: 'Balance',
gasLimit: 'u64',
storageDepositLimit: 'Option<Compact<u64>>',
inputData: 'Bytes'
},
ContractExecResultSuccessTo255: {
Expand Down Expand Up @@ -273,7 +274,7 @@ export default {
origin: 'AccountId',
endowment: 'Balance',
gasLimit: 'Gas',
code: 'Bytes',
storageDepositLimit: 'Option<Compact<u64>>',
data: 'Bytes',
salt: 'Bytes'
},
Expand Down
3 changes: 3 additions & 0 deletions packages/types/src/interfaces/contracts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ export interface ContractCallRequest extends Struct {
readonly dest: AccountId;
readonly value: Balance;
readonly gasLimit: u64;
readonly storageDepositLimit: Option<Compact<u64>>;
readonly inputData: Bytes;
}

/** @name ContractExecResult */
export interface ContractExecResult extends Struct {
readonly gasConsumed: u64;
readonly gasRequired: u64;
readonly storageDeposit: Balance;
readonly debugMessage: Text;
readonly result: ContractExecResultResult;
}
Expand Down Expand Up @@ -259,6 +261,7 @@ export interface InstantiateRequest extends Struct {
readonly origin: AccountId;
readonly endowment: Balance;
readonly gasLimit: Gas;
readonly storageDepositLimit: Option<Compact<u64>>;
readonly code: Bytes;
readonly data: Bytes;
readonly salt: Bytes;
Expand Down