What is Ask!

Ask! is an Embedded Domain Specific Language (EDSL) to write WebAssembly smart contracts on Substrate using typescript.

Unlike solidity, Ask! is not a standalone language but more like an Assemblyscript “contract format” with customized decorators. Those decorators tell the compiler how the smart contract is defined and further compiles them to WASM bytecode compatible with Substrate’s pallet-contract.

Why Ask!

  1. Being a variant of TypeScript makes it easy to compile to WebAssembly without learning a new language.
  2. AssemblyScript is the most popular language for WASM besides C/CPP/Rust.
  3. AssemblyScript targets WebAssembly’s feature set specifically, giving developers low-level control over their code.
  4. Integrates with the existing JS ecosystem — no heavy toolchains to set up. Simply npm install it!
  5. Small WASM size and good contract execution performance compared to Rust.

First Ask! project — Flipper

Setup Ask! env

mkdir flipper
cd flipper
npx pl-ask-cli init

Create index.ts in flipper/contracts, and copy the following code:

@contract
class Flipper {
    @state flag: bool;

    constructor() {
    }

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

    @message
    flip(): void {
        const v = this.flag;
        this.flag = !v;
    }

    @message({"mutates": false})
    get(): bool {
        return this.flag;
    }
}

Decorators

@contract

Marks this class as a contract and defines the entry point for the compiler.

@constructor

Method decorator for contract instantiation.

@message

Methods with @message decorator will be exposed to the blockchain as contract methods. Users will be able to interact with them using RPC calls.

@message({"mutates": false})

Unlike the @message decorator above, methods with @message({"mutates": false}) will not change the blockchain state while executing.

Compile the contract using ask-cli

npx pl-ask-cli compile contracts/flipper.ts

Which creates /build/index.wasm and /build/metadata.json .wasm is the compiled binary file of your smart contract while metadata.json defines the ABI of your contract.

metadata.json

The metadata.json file tells them contract-pallet how to interact with your blockchain. The selector is a blake2b hash of your contract method. type defines the data type and data storage and how the frontend displays the data type correctly.

Event

When a user is interacting with the contract, usually you want to expose that information to the public, so the outside world knows what happens with your contract.

To do so, we introduce @event.

Let’s make the following changes to the contract.

import {AccountId, msg, Event} from "ask-lang";

@event
class Flip extends Event {
    from: AccountId;
    flip_result: bool;


    constructor(from: AccountId,  flip_result: bool) {
      super();
      this.from = from;
      this.flip_result = flip_result;
    }
}

Then, edit the flip method

@message
flip(): void {
    const v = this.flag;
    this.flag = !v;
    (new Flip(msg.sender, this.flag)).emit();
}

msg.sender

msg.sender is the environment variable that is a variable available across the contract. You can use this variable to get the RPC caller's information, current block number, etc.

Then compile it again: npx pl-ask-cli compile contracts/flipper.ts

In metadata.json, you will see the events section is now filled up.

"events": [
  {
    "name": "Flip",
    "args": [
      {
        "indexed": false,
        "type": {
          "type": 3,
          "displayName": [
            "AccountId"
          ]
        },
        "docs": [
          ""
        ],
        "name": "from"
      },
      {
        "indexed": false,
        "type": {
          "type": 1,
          "displayName": [
            "bool"
          ]
        },
        "docs": [
          ""
        ],
        "name": "flip_result"
      }
    ],
    "docs": []
  }
],

@topic

Now, change from: AccountId to

@topic from: AccountId;

And compile it again: npx pl-ask-cli compile contracts/flipper.ts

You will see the first arg of events is changed to

{
        "indexed": true,
        "type": {
          "type": 3,
          "displayName": [
            "AccountId"
          ]
        },
        "docs": [
          ""
        ],
        "name": "from"
      },

@topic allow Dapps to index certain values. For example, Etherscan uses @topic to track dex trades.

The Patract Tutorial Series is Patract Labs’ most recent open technical sharing course. Through this series, we hope to provide a top-down, in-depth look at the technical principles and implementation details of Patract. We welcome you to join us for this technical sharing event and discuss it with us——https://discord.gg/znbmjYfvBR.

About Patract Labs

Patract Labs is providing solutions for the development of Parachains and DApps in the Wasm smart contract ecosystem of Polkadot. We help the community to design and develop on-chain contract modules and Runtime support, and provide DApp developers with full-stack tools and services support, covering development, testing, debugging deployment, monitoring, data provider, and front-end development stages.

Website | Github|Discord| Element|Twitter|YouTube|Telegram