Skip to main content

Contract Decorators

Class Decorator#

@contract#

Usage#

@contract is a class decorator. The decorated class will automatically become an instance of the smart contract. Its sub-fields support @constructor and @message decorator decoration.

@contract decorator implements IContract interface. IContract interface fulfills ABI interfaces defined in pallet-contract. ask! will generate methods entry points of related ABI interfaces: deploy(): i32 call(): i32 for pallet-contract. Therefore, only @contract class can be define per one contract entry file.

contructor method in @contract can have no parameters since every contract method call requires instantiation through construtor

@contract class supports inheritence

Example#

@contractexport class ERC20 {  @state balances: SpreadStorableMap<AccountId, UInt128> = new SpreadStorableMap<AccountId, UInt128>();  @state allowances: SpreadStorableMap<AccountId, SpreadStorableMap<AccountId, UInt128>> = new SpreadStorableMap<AccountId, SpreadStorableMap<AccountId, UInt128>>();
  @state totalSupply: u128 = u128.Zero;  @state name_: string = "";  @state symbol_: string = ""  @state decimal_: u8 = 0;
  constructor() {  }}

You can inherit it in another class

@contract@doc({"desc": "MyToken conract that extended erc20 contract"})class MyToken extends ERC20 {
  constructor() {    super();  }}

@dynamic#

Usage#

The @dynamic decorator is used to decorate the APIs of a contract that already exists on the chain. By declaring the contract interface on the chain in the @dynamic class, ask will automatically generate the corresponding cross-contract call code.

For details, please refer Cross-Contract calling

Property Decorator#

@state#

Usage#

@state decorator is used to mark the specific member variable as state variable while the ones not decorated are class variables. In v0.2, all variables are default as blockchain state variables. Since we moved @storage into @contract class for better inheritence, we now have to sperate blockchain state variables and normal class properties by having @state decorator.

Config#

  • lazy: boolean. While lazy is true, that means while a state variable gets changed multiple times in a contract call, only the last change will be synced to blockchain. The default value of lazy is true. While lazy is false, then every change made to the state variable will be synced to blockchain.

    eg. @state({"lazy": false})

Example#

  @state balances: SpreadStorableMap<AccountId, UInt128> = new SpreadStorableMap<AccountId, UInt128>();  @state allowances: SpreadStorableMap<AccountId, SpreadStorableMap<AccountId, UInt128>> = new SpreadStorableMap<AccountId, SpreadStorableMap<AccountId, UInt128>>();
  @state totalSupply: u128 = u128.Zero;  @state name_: string = "";  @state symbol_: string = ""  @state decimal_: u8 = 0;  @state({"lazy": false}) is_paused: boolean = false;

Method Decorator#

@constructor#

This decorator is used to decorate public methods underneath @contract class as the constructor API to instantiate contract

Usage#

  • least one @constructor method must be defined per @contract class
  • multiple @contructor methods per @contract class

Parameter <*scale-codec>#

@contructor method takes any number of parameters as long as the parameter implement SCALE codec.

Return <void>#

@contructor method doesn't support return value that means void as the return type.

Config seletor#

  • selector: string. Use specific selector instead of default selector generated by blake2b.

    eg. @constructor({ "selector": "0xAABBccdd" })

Example#

    @constructor    default(initFlag: bool): void {        this.stored.flag = initFlag;    }

@message#

This decorator is used to decorate public methods underneath @contract class

Usage#

@message method can only be declared under @contractclass

Parameter *<scale-codec>#

  • This decorator can only be used with public methods in @contract class not including static methods.

Return <scale-codec>#

  • Return: The @message method must have return value and the return type must implement SCALE codec.

Config seletor, mutate, payable#

  • selector: string. Use specific selector instead of default selector generated by blake2b. eg. @message({"selector": "0xCAFEBABE" })
  • payable: boolean, means this message can accept msg.value. eg. @message({"selector": false})
  • mutates: boolean, eg.`means if this message can modify states of this contract. eg. @message({"mutate": false})`

    @message method has msg variable to read contract state. eg. msg.sender to get the sender of contract call

Example#

  @message  transfer(recipient: AccountId, amount: u128): bool {    let from = msg.sender;    this._transfer(from, recipient, amount);    return true;  }