Skip to main content

Smart-contract Stack

Smart Contract Runtime Environment

Astar & Shiden runtimes are based on Substrate. Both networks incorporate pallet-contracts to enable Wasm smart-contract capabilities. The pallet-contracts is a sandbox environment to deploy and execute WebAssembly smart contracts. Any language that compiles to Wasm can be used. But the code should be compatible with pallet-contracts API.

To avoid unnecessary complexity, and boilerplate code, the best way is to use an eDSL that specifically targets the pallet-contracts like ink! (based on Rust) or ask! (based on AssemblyScript). More supported language and eDSL will come as the ecosystem grows.

The Wasm blob is then deployed and stored on-chain.

Gas Model

Similar to Substrate, pallet-contracts uses weight as a gas model.

One gas is equivalent to one weight, defined as one picosecond of execution time on the runtime's reference machine.

Transaction Weight is Substrate documentation

Additionally to the weight, there is also a fee paid for on-chain storage called automatic deposit collection. This additional fee is paid by the caller and is calculated with the price set for each storage item DepositPerItem and the price charged for each byte of storage DepositPerByte.

The automatic deposit collection can be simplified as follows:

A caller of a contract pays a deposit to each contract in which new storage was created as a result of the executed call. In a similar way, a caller gets a refund from all the contracts that the call removed storage from.

ink! 3.0 Blog Post by Parity

Execution Engine

Pallet-contracts uses wasmi as a wasm-interpreter to execute the smart-contract Wasm blob. Even though there is a faster JIT interpreter like wasmtime used in the native runtime, smart contracts are an untrusted environment and that’s why the high degree of correctness of wasmi makes it the best option.

Two-step Deployment of Contracts

The contract code (Wasm blob) and the contract address and storage are decoupled from each other. To deploy a non-existing contract on-chain:

  1. First, upload the Wasm contract on-chain (every contract Wasm code has a code_hash as an identifier).
  2. Second, instantiate the contract - it will create an address and storage for that contract.
  3. Anyone can instantiate a contract based on its code_hash.

There are several perks of decoupling contract code and address/storage:

  • It will save space on-chain. Since a contract can have several constructors and several instantiations, it will just create a new instance based on the same underlying code. Think about standardized tokens, like PSP22 & PSP34, that will have one code_hash & blob leaving on-chain, and as many instantiations as it is needed rather than having code uploaded at each new instantiation (like in Ethereum).
  • To instantiate a contract from within contract code (see delegator example), only code_hash needs to be provided.
  • Some standards contracts (PSP22, PSP34) will only be uploaded on-chain once, preventing users from paying the gas fees of uploading new code.
  • Update contract code for an address: replace the contract code at the specified address with a new code (see set_code_hash). Storage and balances will be preserved.

Documentation about pallet-contracts

Smart Contracts

To facilitate development it is better to use a language targeting specifically pallet-contracts.

There are two eDSLs currently available

  • ink! written in Rust
  • ask! written in AssemblyScript

Client APIs

The only library available to communicate with smart contracts is PolkadotJS API.

This API provides application developers the ability to query a node and interact with the Polkadot or Substrate chains using Javascript.

Parity also developed a web application to interact with contracts called contracts-ui.

Stack comparison to Ethereum

L1 ArchitectureEthereum clientsSubstrate
Smart Contract Runtime EnvironmentEVMpallet-contract, EVM via frontier
Gas Modelfixed price per instructionweight + storage fees
Smart Contract DSLsSolidity and Vyperink! (Rust) and ask! (AssemblyScript)