# Directory Structure ``` docs/ background/ contracts-vs-parachains.md ink-vs-cosmwasm.md ink-vs-solidity.md migrate-to-parachain.md polkadot-sdk.md precompiles.md why-riscv.md why-rust.md basics/ abi/ all.md ink.md overview.md solidity.md metadata/ ink-format.md overview.md solidity-format.md contract-template.md contract-verification.md cross-contract-calling.md env-functions.md environment.md events.md gas.md mutating-values.md precompiles.md reading-values.md selectors.md storing-values.md trait-definitions.md upgradeability.md xcm.md datastructures/ custom.md mapping.md overview.md storage-in-metadata.md storage-layout.md storagevec.md debugging/ decoding.md events.md overview.md precompiles.md replays.md return_value.md sandbox.md tracing.md faq/ faq.md migrating-from-ink-3-to-4.md migrating-from-ink-4-to-5.md migrating-from-ink-5-to-6.md getting-started/ assets/ canvas-connect-to-local.png flipper-false.png flipper-instantiate-01.png flipper-instantiate-02.png flipper-instantiate-03.png flipper-instantiate-04.png flipper-true.png send-as-transaction.png start-substrate-node.png calling.md compiling.md creating.md deploying.md setup.md integrations-and-sdks/ javascript-typescript/ core-libraries.md react.md ethereum-compatibility.md other-languages.md overview.md intro/ intro.mdx overview.md sub0-hackathon.mdx tutorials-examples.md where-to-deploy.md linter/ rules/ no_main.md non_fallible_api.md primitive_topic.md storage_never_freed.md strict_balance_equality.md overview.md macros-attributes/ anonymous.md constructor.md contract_ref.md contract.md default.md error.md event.md implementation.md message.md name.md namespace.md overview.md payable.md selector.md storage.md topic.md trait_definition.md testing/ testnet/ faucet.md Faucet.tsx overview.md e2e.md overview.md sandbox.md testing-with-live-state.md unit-integration.md ``` # Files ## File: docs/background/contracts-vs-parachains.md ````markdown --- title: Smart Contracts vs. Parachains hide_title: true slug: /background/smart-contracts-vs-parachains --- ![Polkadot Title Picture](/img/title/polkadot.svg) # Smart Contracts vs. Polkadot Parachains One of the first questions we typically get when somebody learns about the Polkadot SDK is when to develop a parachain vs. when to develop a smart contract. ## The Difference The distinction here is that in the context of Polkadot and Kusama a parachain leases a slot for a couple of months for up to two years. The deal with a lease is that the parachain gets a fixed slot for executing its business logic (typically referred to as its _state transition function_) and can persist its modified state in a block. In Polkadot SDK terminology this state transition function is called the chain's _runtime_. The distinction to other ecosystems here is that, in the context of Polkadot, parachains and smart contracts exist at different layers of the stack: _smart contracts sit on top of parachains_. Parachains would usually be described as layer-1 blockchains — except for that they don't have to build their own security, are upgradable, and interoperable. ## Polkadot Parachains It's noteworthy that a parachain's state transition function doesn't get further validated — it's up to the parachain how it utilizes its slot time. The parachain already pre-paid for its slot when it won the slot auction on Polkadot or Kusama. This means the parachain can build its own (blockchain) world! For example, it can decide on how transaction fees are charged ‒ or even if transaction fees are charged at all. These options are crucial when building new or more user-friendly business models. Other distinguishing factors between parachains that we observe in the wild are differences in how governance works or the crypto-economics. There are some constraints on how the parachain can build its world though. Like physics in the real world it has to adhere to certain ground rules. For Polkadot and Kusama that's for example the consensus algorithm for the Relay Chain to communicate with the parachain. From those ground rules the advantages of Polkadot and Kusama emerge. Advantages like the aforementioned shared security, cross-chain communication, or guaranteed execution slot time. ## Smart Contracts For smart contracts, on the other hand, an existing parachain has to include the `pallet-revive` for users to deploy smart contracts. The deployed smart contract is always untrusted code. Anyone (or any program) that has tokens of the chain can upload a smart contract without requiring permission. Smart contracts allow _permissionless_ deployment of _untrusted_ programs on a blockchain. The `pallet-revive` has to assume that these programs are adversarial, it has to put a number of safety pillars in place to ensure that the contract can not e.g. stall the chain or cause state corruption of other contracts. For `pallet-revive` those safety pillars include mechanisms like gas metering or deposits for storing data on-chain. _To restate this important distinction: developing a parachain runtime is different from developing a smart contract — a smart contract sits on top of a parachain_. ## The Trade-off ![Smart Contract vs. Parachain](../../static/img/smart-contract-vs-parachain.svg) The trade-off is that with a parachain one has the freedom to decide on (nearly) all the rules that make up the parachain. With a smart contract one is constrained by what the chain allows and the safety pillars that necessarily have to be in place. A smart contract can never be as fast as a native pallet built in the parachain runtime ‒ there is too much logic in between. A smart contract on the other hand has less friction for developing and deploying it. Developers don't have to take care of governance, crypto-economics, etc. One just needs a few tokens and can go on its merry way deploying a smart contract. It's as simple as that. ```` ## File: docs/background/ink-vs-cosmwasm.md ````markdown --- title: ink! vs. CosmWasm slug: /background/ink-vs-cosmwasm hide_title: true --- ![Cosmwasm Title Picture](/img/title/cosmwasm.svg) # ink! vs. CosmWasm This is a short comparison between [ink!](https://github.com/use-ink/ink/) and [CosmWasm](https://github.com/CosmWasm/cosmwasm) meant to onboard developers coming from the Cosmos ecosystem. ## Architecture CosmWasm is modular, meaning that any blockchain using the Cosmos SDK can add smart contract support to their chain. That is similar to the [Polkadot SDK](https://polkadot.com/platform/sdk) approach, where chains have the option to add `pallet-revive` to their runtime. Aside from that, the architecture philosophy is likely the point where CosmWasm and ink! differ the most. CosmWasm follows the actor model design pattern, while ink! follows a synchronous execution model. That means some fundamental differences in how the source code is structured. The main entry point functions of CosmWasm contracts are: - `instantiate` which bootstraps the initial contract state (assuming it's already been deployed). - `execute` which has the actor perform operations to its internal state. - `query` which retrieves data from the actor’s internal state. An ink! contract can have as many public dispatchables as the developer desires, and differently from CosmWasm, it doesn’t rely on JSON schemas for defining how the messages are structured. Instead, ink! makes heavy usage of Rust macros. The main ink! macros are: - `#[ink(constructor)]` which is called when the contract is deployed, and is responsible for bootstrapping the initial contract state into the storage. It is analogous to the CosmWasm `instantiate` function. - `#[ink(storage)]` which annotates a struct that represents the contract's internal state. - `#[ink(message)]` which marks a function as a public dispatchable, meaning that it is exposed in the contract interface to the outside world. This macro can make a function behave analogously to CosmWasm’s `execute` and `query` functions. This depends on how it affects the internal contract state and what the return types. - `#[ink(event)]` and `#[ink(topic)]` which annotates a struct and its members as the events and topics that the contract might emit. There are other ink! macros, for which details can be found at [Macros & Attributes](../macros-attributes/overview.md). ## Unit Testing Unit testing in CosmWasm is quite similar to ink!. Both use the conventional Rust `#[cfg(test)]` macro and set up a mock on-chain environment. While CosmWasm unit tests have different modules for each of the three main entry-point functions, ink! allows for a more generalised approach, where the `#[ink(test)]` macro is used for each unit test. You can read more about ink! unit tests [here](../testing/unit-integration.md). ## Compiler CosmWasm uses [cargo-wasm](https://docs.rs/crate/cargo-wasm/latest) as its main compiler, while ink! uses [cargo-contract](https://github.com/use-ink/cargo-contract). `cargo-contract` is developed specifically for building, testing, and deploying ink! contracts. # Local Development Network In terms of local development networks, the [cosmos/gaia](https://github.com/cosmos/gaia) repository acts as the basic template for a generic Cosmos node. With the addition of the `x/wasm` module and some clean-up, this template repository becomes [wasmd](https://github.com/CosmWasm/wasmd), the entry point for CosmWasm development. In terms of Polkadot SDK, [`polkadot-sdk-solochain-template`](https://github.com/paritytech/polkadot-sdk-solochain-template) is a basic generic template of a node. Similar to `x/wasm`, [`pallet-revive`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive) is the module that adds RISC-V smart contract functionality to the chain. We provide the [ink-node](https://github.com/use-ink/ink-node), which is analogous to `wasmd` — a basic template node for smart contract development. ## Testnets For CosmWasm development and on-chain testing, `wasmd` can be operated as a local setup (single or multiple nodes), or connected to the `cliffnet` public test network. For testing, ink! contracts can be deployed on a few different options: - Locally, on a single or multiple node setup of [`ink-node`](https://github.com/use-ink/ink-node). - Westend's [Asset Hub](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fasset-hub-westend-rpc.dwellir.com#/explorer) - [Pop Testnet](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frpc1.paseo.popnetwork.xyz#/explorer) (on Paseo). See [Pop CLI for one way to deploy](https://learn.onpop.io/contracts/guides/deploy). ## Development Workflow ### Dependencies and Environment Setup The first step in CosmWasm development is to [install dependencies and setup the environment](https://docs.cosmwasm.com/core/installation), namely Rust, the WebAssembly target, `cargo-generate` and `cargo-run-script`. For ink! you can also find [a setup guide](../getting-started/setup.md) which will help you with dependencies, namely Rust, `cargo-contract` and `ink-node`. ### Compile and Test CosmWasm provides a template at the [cw-template](https://github.com/CosmWasm/cw-template) repository. In order to generate a new project, all you have to do is run: ``` cargo generate --git https://github.com/CosmWasm/cw-template.git --name PROJECT_NAME ``` Replacing `PROJECT_NAME` with the name of your project. Similarly, ink! provides an [`examples`](https://github.com/use-ink/ink-examples/tree/main) directory of its main repository. A contract can be compiled from its directory via: ``` cargo contract build ``` and tested via: ``` cargo contract test ``` ### Deploy and Interact CosmWasm contracts are deployed and instantiated with help of the `wasmd` executable. The list of step is provided [here](https://docs.cosmwasm.com/wasmd). It is possible to deploy and interact with ink! contracts using either a CLI (`cargo-contract`), or a web UI ([`contracts-ui`](https://ui.use.ink)). - [Instructions for `cargo-contract`](https://github.com/use-ink/cargo-contract/blob/master/crates/extrinsics/README.md) - [Instructions for `contracts-ui`](../getting-started/deploying.md) ```` ## File: docs/background/ink-vs-solidity.md ````markdown --- title: ink! vs. Solidity hide_title: true slug: /background/ink-vs-solidity --- ![Solidity Title Picture](/img/title/solidity.svg) # ink! vs. Solidity The following table gives a brief comparison of features between ink! and Solidity:
| | ink! | Solidity | | :-------------------- |:-----------------------------|:-------------| | Virtual Machine | PolkaVM | EVM | | Encoding | SCALE or Solidity ABI | Solidity ABI | | Language | Rust | Standalone | | Overflow Protection | Enabled by default | Yes | | Constructor Functions | Multiple | Single | | Tooling | Most tools that support Rust | Custom | | Versioning | Semantic | Semantic | | Has Metadata? | Yes | Yes | | Multi-File Project | Yes | Yes | | Storage Entries | Variable | 256 bits | | Supported Types | Docs | Docs | | Has Interfaces? | Yes (Rust Traits) | Yes |
## Converting a Solidity Contract to ink! In the following, we'll explain how to convert a Solidity contract to ink!. ### 1. Generate a new ink! contract Run the following command to generate the skeleton for an ink! contract. The command will set up the boilerplate code for ink!'s "Hello, World!" (the [`flipper`](https://github.com/use-ink/ink-examples/tree/main/flipper) contract)). ``` cargo contract new ``` ### 2. Build the contract ``` cargo contract build ``` ### 3. Convert Solidity class fields to Rust struct Solidity is an object-oriented language, and uses classes. ink! (Rust) does not use classes. An example Solidity class looks like: ```C++ // SPDX-License-Identifier: MIT pragma solidity ^0.8.1; contract MyContract { bool private _theBool; event UpdatedBool(bool indexed _theBool); constructor(bool theBool) { require(theBool == true, "theBool must start as true"); _theBool = theBool; } function setBool(bool newBool) public returns (bool boolChanged) { if (_theBool == newBool) { boolChanged = false; } else { boolChanged = true; } _theBool = newBool; // emit event emit UpdatedBool(newBool); } } ``` And the equivalent contract in ink! looks like: ```rust #![cfg_attr(not(feature = "std"), no_std, no_main)] #[ink::contract] mod mycontract { #[ink(storage)] pub struct MyContract { the_bool: bool, // class members become struct fields } #[ink(event)] pub struct UpdatedBool { #[ink(topic)] // -> indexed the_bool: bool, } impl MyContract { #[ink(constructor)] pub fn new(the_bool: bool) -> Self { assert!(the_bool == true, "the_bool must start as true"); Self { the_bool } } #[ink(message)] // functions become struct implementations pub fn set_bool(&mut self, new_bool: bool) -> bool { let bool_changed: bool; if self.the_bool == new_bool{ bool_changed = false; }else{ bool_changed = true; } self.the_bool = new_bool; self.env().emit_event(UpdatedBool { the_bool: new_bool }); // return bool_changed } } } ``` A few key differences are: - Solidity class variables / members will be placed in the contract struct in ink! - All class methods in Solidity are `impl`emented for the contract struct in ink! - Solidity frequently prefixes variables with an underscore (`_name`). ink! / Rust only prefixes with an underscore for _unused_ variables. - Solidity uses camelCase. ink! uses snake_case. - In Solidity, the variable type comes before the variable name (e.g. bool myVar). While ink! specifies var type after the var name (e.g. my_var: bool) ### 4. Convert each function - Start converting each function one by one. - A recommended approach is to, if possible, skip cross-contract calls at first and use mock data instead - This way off-chain unit tests can be written to test the core functionality - unit tests are off-chain and do not work with cross-contract calls - Once fully tested, start adding in cross-contract calls and perform on-chain manual + integration tests - Ensure that function's visibility (public, private) are matched in ink! - In Solidity, if a function returns a `bool success`, ink! will use a `Result<()>` instead (`Result::Ok` or `Result::Err`). Solidity return example: ```c++ // SPDX-License-Identifier: MIT pragma solidity ^0.8.1; contract Example { uint128 public data; constructor(){} function setData(uint128 newData) public returns ( bool success, string memory reason ) { if (newData == 0) { return (false, "Data should not be zero"); } data = newData; return (true, ""); } } ``` The equivalent contract in ink!: ```rust #![cfg_attr(not(feature = "std"), no_std, no_main)] #[ink::contract] mod example { #[ink(storage)] pub struct Example { data: u128, } #[ink::scale_derive(Encode, Decode, TypeInfo)] #[derive(Debug, PartialEq, Eq)] pub enum Error { DataShouldNotBeZero, } pub type Result = core::result::Result; impl Example { #[ink(constructor)] pub fn new() -> Self { Self { data: 0 } } #[ink(message)] pub fn set_data(&mut self, new_data: u128) -> Result<()> { if new_data == 0 { return Err(Error::DataShouldNotBeZero); } self.data = new_data; Ok(()) } } } ``` ## Best Practices + Tips - If the Solidity contract uses a `string`, it is recommended to use a `Vec` to avoid the overhead of a `String`. See [here](https://substrate.stackexchange.com/questions/1174/why-is-it-a-bad-idea-to-use-string-in-an-ink-smart-contract) for more details on why. The smart contract should only contain the information that strictly needs to be placed on the blockchain and go through consensus. The UI should be used for displaying strings. - Double check all `.unwrap()`s performed. Solidity does not have as strict checking as ink! does. For example, a mapping field can be accessed as simple as `myMapping[someKey]`. ink!, however, requires `self.my_mapping.get(some_key).unwrap()`. A useful way to handle `None` cases is to use `.unwrap_or(some_val)`. - Run the contracts node with `ink-node -lerror,runtime::contracts=debug` for debug prints, and errors to be displayed in the nodes console. - Just as in Solidity, ink! does not have floating point numbers due to the non-deterministic nature. Instead, the frontend should add decimal points as needed. ## Syntax Equivalencies ### `public function` ```c++ // solidity function fnName() public {} // or // by default, functions are public function fnName() {} ``` ```rust // ink! #[ink(message)] pub fn fn_name(&self) {} ``` ### `mapping declaration` ```c++ // solidity mapping(address => uint128) private mapName; ``` ```rust //ink! use ink::storage::Mapping; #[ink(storage)] pub struct ContractName { map_name: Mapping, } ``` ### `mapping usage` ```c++ // solidity // insert / update aMap[aKey] = aValue; // get aMap[aKey] ``` ```rust // ink! //insert / update self.a_map.insert(&a_key, &a_value); // get self.a_map.get(a_key).unwrap() ``` ### `struct` ```c++ // solidity struct MyPerson{ address person; u64 favNum; } ``` ```rust // ink! struct MyPerson { person: AccountId, fav_num: u64, } ``` ### `assertions / requires` ```c++ // solidity require(someValue < 10, "someValue is not less than 10"); ``` ```rust // ink! assert!(some_value < 10, "some_value is not less than 10"); ``` ### `timestamp` ```c++ // solidity block.timestamp ``` ```rust // ink! self.env().block_timestamp() ``` ### `contract caller` ```c++ // solidity address caller = msg.sender; ``` ```rust // ink! let caller: Address = self.env().caller(); ``` ### `contract's address` ```c++ // solidity address(this) ``` ```rust // ink! self.env().account_id() ``` ### `bytes` Solidity has a type `bytes`. `bytes` is (essentially) equivalent to an array of uint8. So, `bytes` in Solidity => `Vec` or `[u8; ...]` in ink!. See [here](https://ethereum.stackexchange.com/questions/91119/difference-between-byte-and-uint8-datatypes-in-solidity) for more details. If desired, a `bytes` struct can be created in ink! to replicate the `bytes` type in Solidity. ### `uint256` Solidity uses `uint256` and `uint` to represent a 256-bit type. Solidity is 256-bit / 32-byte word optimized. Meaning, using `uint256` in Solidity contracts will reduce gas usage -- but increase storage usage. The largest size ink! has built in is a `u128`. ink! compiles to Wasm. The largest primitive Wasm has is 64bit (due to most computers using 64bit). So, there is no benefit to using any larger primitive over a collection. When porting a `uint256` from Solidity to ink!, it is recommended to, with discretion, determine the range of the value, and choose the appropriate size (u8, u16, u32, u64, u128). If a 256-bit hash value is required, ink! has a `Hash` primitive available. In the event a value needs to be 256-bit, it is recommended to use an array (e.g. `[u64; 4]`). ### `payable` ```c++ // solidity function myFunction() payable returns (uint64) {} ``` ```rust #[ink(message, payable)] pub fn my_function(&mut self) -> u64 {} ``` ### `received deposit / payment` ```C++ // solidity msg.value ``` ```rust // ink! self.env().transferred_value() ``` ### `contract balance` ```c++ // solidity address(this).balance ``` ```rust // ink! self.env().balance() ``` ### `transfer tokens from contract` ```c++ // solidity recipient.send(amount) ``` ```rust // ink! if self.env().transfer(recipient, amount).is_err() { panic!("error transferring") } ``` ### `events & indexed` ```c++ // solidity event MyCoolEvent( u128 indexed indexedValue, u128 notIndexedValue, ); // emit event emit MyCoolEvent(someValue, someOtherValue); ``` ```rust // ink! #[ink(event)] pub struct MyCoolEvent { #[ink(topic)] indexed_value: u128, not_indexed_value: u128, } // emit event self.env().emit_event(MyCoolEvent { indexed_value: some_value, not_indexed_value: some_other_value }); ``` ### `errors and returning` Solidity has several error handling mechanisms: `assert`, `require`, `revert`, and `throw`. Each of these will revert the changed state when called. See [this article](https://medium.com/blockchannel/the-use-of-revert-assert-and-require-in-solidity-and-the-new-revert-opcode-in-the-evm-1a3a7990e06e) for details on these. ink! uses a `Result` enum (`Ok(T)`, `Err(E)`), `assert!` and `panic!`. [This Stack Exchange](https://substrate.stackexchange.com/questions/2391/panic-in-ink-smart-contracts) answer and [GitHub discussion](https://github.com/use-ink/ink/issues/641) provide more details on these. #### `throw` Throw is deprecated in Solidity and would throw an invalid opcode error (no details) and revert the state. As an alternative to the `if...{throw;}` pattern in Solidity, a `Result::Err` should be returned for expected errors, and an `assert!` should be used for errors that should not occur. #### `assert` In Solidity, `assert` is used as internal guards against errors in the _code_. In general, properly functioning code should never hit a failing assert. `assert` in Solidity does not have error strings. In ink!, use `assert!`. `assert!` will `panic!` if it evaluates to _false_. The state will be reverted, and a `CalleeTrapped` will be returned. The (optional) error string will be printed to the debug buffer. ```rust // ink! assert!(caller == owner, "caller is not owner") ``` #### `require and revert` In Solidity, `require` is used for general (normal) errors -- such as errors that occur based on user input. `require` does have the option for an error string. `revert` is very similar to `require` except that `revert` will be called in `if ... else` chains. Both `require` and `revert` will revert the chain state. In ink!, `if ... { return Err(Error::SomeError) }` should be used for `require` or `revert`. When a `Result::Err` is returned in ink!, then all state is reverted. In general, `Result::Err` should be used when a _calling contract_ needs to know _why_ a function failed. Otherwise, `assert!` should be used as it has less overhead than a `Result`. ```c++ // Solidity function myFunction(bool returnError) public pure { require(!returnError, "my error here"); // or if returnError { revert("my error here"); } } ``` ```rust // ink! #[derive(Debug, PartialEq, Eq)] #[ink::scale_derive(Encode, Decode, TypeInfo)] pub enum Error { /// Provide a detailed comment on the error MyError, } // result type pub type Result = core::result::Result; // ... #[ink(message)] pub fn my_function(&self, return_error: bool) -> Result<()> { if return_error{ return Err(Error::MyError) } Ok(()) } ``` ### `cross-contract calling` See here to learn the different ways to do [cross-contract calling](../basics/cross-contract-calling.md) ### `submit generic transaction / dynamic cross-contract calling` invokes function found at `callee` contract address, sends the `transferAmount` to the `callee`, and the `transactionData` payload. ```c++ // SPDX-License-Identifier: MIT pragma solidity ^0.8.1; contract CallContract { constructor() {} function invokeTransaction( address payable callee, uint transferAmount, bytes4 functionSelector, string memory transactionData ) public returns(bool success, bytes memory message) { bytes memory _data = abi .encodePacked(functionSelector, transactionData); (success, message) = callee .call{value: transferAmount}(_data); return (success, message); } } ``` The equivalant in Ink!: ```rust #![cfg_attr(not(feature = "std"), no_std, no_main)] #[ink::contract] mod call_contract { use ink::{ env::call::{ build_call, Call, ExecutionInput, Selector }, prelude::vec::Vec, }; #[ink(storage)] #[derive(Default)] pub struct CallContract {} #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] pub enum Error { TransactionFailed, } type Result = core::result::Result; impl CallContract{ #[ink(constructor)] pub fn new() -> Self { Default::default() } #[ink(message, payable)] pub fn invoke_transaction( &mut self, callee: AccountId, transfer_amount: u128, function_selector: [u8; 4], transaction_data: Vec, gas_limit: Option, ) -> Result<()> { let transaction_result = build_call::<::Env>() .call_type( Call::new(callee) // contract to call .gas_limit(gas_limit.unwrap_or_default()) .transferred_value(transfer_amount), // value to transfer with call ) .exec_input( ExecutionInput::new(Selector::new(function_selector)) .push_arg(transaction_data), // SCALE-encoded parameters ) .returns::<()>() .try_invoke(); match transaction_result { Ok(Ok(_)) => Ok(()), _ => Err(Error::TransactionFailed), } } } } ``` Note: the `function_selector` bytes can be found in the generated `target/ink/.json`. ## Troubleshooting Errors - `"failed to load bitcode of module '...' "` This happens when trying to import a contract for cross-contract calling. **Solution** Ensure that the following is added to Cargo.toml contract import:` ``` features = ["ink-as-dependency"] ``` so the import would look like: ``` mycontract = { path = "mycontract/", default-features = false, features = ["ink-as-dependency"]} ``` ## unit testing (off-chain) - Unit tests are an integral part of smart-contract development and ensuring your code works off-chain before testing on-chain. - To run ink! tests, use the command `cargo contract test`. Add the `--nocapture` flag for debug prints to show. - From the contract module, make sure to make the contract struct and anything else that is going to be used in the unit tests public. For example: ```rust // top of file #![cfg_attr(not(feature = "std"), no_std, no_main)] pub use self::mycontract::{ MyContract }; ``` - For more complex testing that requires a running node, such as cross-contract calls,please refer to [the showcased example here](https://github.com/use-ink/ink-examples/tree/main/multi-contract-caller) - useful code to interact and modify the contract environment for testing [ink_env docs](https://use-ink.github.io/ink/ink_env/) ```rust // get the default accounts (alice, bob, ...) let accounts = ink::env::test::default_accounts::(); accounts.alice //usage example // set which account calls the contract ink::env::test::set_caller::(accounts.bob); // get the contract's address let callee = ink::env::account_id::(); // set the contracts address. // by default, this is alice's account ink::env::test::set_callee::(callee); // transfer native currency to the contract ink::env::test::set_value_transferred::(2); // increase block number (and block timestamp). // this can be placed in a loop to advance the block many times ink::env::test::advance_block::(); // generate arbitrary AccountId AccountId::from([0x01; 32]); // generate arbitrary Hash Hash::from([0x01; 32]) // macro for tests that are expected to panic. #[should_panic] ``` ```` ## File: docs/background/migrate-to-parachain.md ````markdown --- title: Migrate an ink! contract to a Parachain hide_title: true slug: /background/migrate-ink-contracts-to-polkadot-frame-parachain-rollup --- ![Polkadot Title Picture](/img/title/polkadot.svg) # Migrate an ink! contract to a Parachain Smart contracts written in ink! are a great starting point for developing applications in the Polkadot ecosystem. Developers can go from an idea to a fully functioning web3 application "in production" in a matter of hours or days. This allows faster feedback on ideas, to validate whether there is user demand in the first place, and to easily iterate and refine the implementation. For many applications, smart contracts are good enough. However, they are exposed to the inherent limitations of the smart contract execution environment: 1. Sharing of blockspace with other smart contracts, volatile "gas" fees. 2. Default model enforces gas fees being paid by the end user. 3. Relative poor performance of interpreted smart contract (untrusted) code compared to precompiled Parachain runtime (trusted) code. 4. Limited access to the host chain environment and any special functionality provided by an extensive suite of customisable FRAME pallets. Once a web3 application has proven it can work, the team may consider "upgrading" to a Parachain to unlock the full power of a dedicated App Chain. Compared to developing and deploying a smart contract, this requires considerably more time and expertise, which is why we encourage to start with ink! where possible, at least at the prototype stage. Much of the difficulty in launching a parachain comes in configuring a node implementation, bootstrapping and maintaining a collator network, deploying to testnets, managing infrastructure, acquiring "Coretime" (previously via a slot auction). All of which is time consuming and costly. This is important to note because this guide will focus on the migration of the code from ink! to `FRAME`, which might be a learning curve but overall a minor part of the overall migration, and a one-off cost. ## Utilizing existing FRAME pallets There is a rich library of FRAME pallets, which may provide a drop in replacement for some (or all) of your smart contract functionality. For example, for a ERC20 fungible token contract, this could be replaced either by the native Parachain token itself via `pallet_balances` or by an asset on `pallet_assets`. Governance functions could be replaced by e.g. `pallet_democracy`, and so on. See [`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame) for a range of pre-built pallets which can be used to handle some common functions. ## Similarities and differences between ink! and `FRAME` ### Similar The biggest advantage we have when migrating from ink! to `FRAME` is that both are Rust based DSLs, in both cases actual Rust (or Rust-like) code annotated with attributes expands into Rust code for handling all the boilerplate for integrating into their respective execution environments. Indeed the modern `FRAME 2.0` was originally inspired by the ink! approach of attribute macros annotating Rust code. So we can assume that the developer performing the migration is already familiar with Rust and its development environment, which is already a huge headstart for developing with `FRAME`. Next we can assume some familiarity with the execution environment, after all a contract is running inside of `pallet_contracts` and is invoked in a similar way via a pallet dispatchable, has access to storage (sandboxed to the contract), and can emit events. ### Different The biggest difference is that a contract is user uploaded and therefore untrusted code, so there are restrictions to what the contract is able to do and it will perform slower because it is interpreted. For example, a contract can only read and write from its own sandboxed storage. Runtime code built using `FRAME` is trusted, can be precompiled and therefore executes significantly faster (though that may change if/when contracts are able to target [PolkaVM](https://forum.polkadot.network/t/announcing-polkavm-a-new-risc-v-based-vm-for-smart-contracts-and-possibly-more/3811)). Pallets have direct access to other pallets and have full access to the Parachain storage, and the permissioning can be configured as desired. Because ink! is executing in a more constrained environment, it is able to be much more opinionated and therefore a simpler language. Because execution is metered (pay as you go execution by the user), there is no need to worry about benchmarking for "weight" calculation. `FRAME` is more powerful, but necessarily more complicated. ## Example Migration We'll use the [`DNS` example](https://github.com/use-ink/ink-examples/blob/main/dns/lib.rs) contract to demonstrate a migration. ### Setup Start by cloning the [Parachain Template](https://github.com/paritytech/polkadot-sdk-parachain-template) which contains a [template pallet](https://github.com/paritytech/polkadot-sdk-parachain-template/blob/master/pallets/template/src/lib.rs) which we can modify. Now we will move down the contract from top to bottom and begin the migration of code. ### Event Definitions First thing we encounter are events. E.g.: ```rust #[ink(event)] pub struct Register { #[ink(topic)] name: Hash, #[ink(topic)] from: AccountId, } ``` Each of these structs annotated with `#[ink(event)]` can be translated to a variant in the pallet `Error` enum annotated with `#[pallet::error]`. Any of the ink! environment type aliases (both `Hash` and `AccountId` in the above example) must be translated to their equivalent associated type on the `Config` trait e.g. `AccountId` -> `T::AccountId`. Also the `#[ink(topic)]` annotations must be removed: topics must be calculated manually when the event is emitted, and will be covered later. Remove the `#[pallet::generate_deposit(pub(super) fn deposit_event)]` and the final `Event` type will look like: ```rust #[pallet::event] pub enum Event { Register { name: T::Hash, from: T::AccountId, }, SetAddress { name: T::Hash, from: T::AccountId, old_address: Option, new_address: T::AccountId, }, Transfer { name: T::Hash, from: T::AccountId, old_owner: Option, new_owner: T::AccountId, } } ``` ### Storage The storage layout of the contract is defined by the following struct: ```rust #[ink(storage)] pub struct DomainNameService { /// A hashmap to store all name to addresses mapping. name_to_address: Mapping, /// A hashmap to store all name to owners mapping. name_to_owner: Mapping, /// The default address. default_address: AccountId, } ``` In ink!, the layout of the contract storage is defined by this top level `struct`. A brief recap of how this is used: - Constructors must return an initialized instance of this struct, which is then written to storage. - Non mutable messages e.g. `#[ink(message)] fn message(&self, ..)` will load an instance of this struct and pass it as `&self`. - Mutable messages e.g. `#[ink(message)] fn message(&mut self, ..)`, will load an instance of the struct and persist it if the message succeeds in executing. - Fields of type `Mapping` or `Lazy` are not written directly into the same storage slot as the parent, but are wrappers around direct reads/writes to storage under many or a single key respectively. In `FRAME`, all storage operations happen eagerly via "type aliases" annotated with `#[pallet::storage]`. So for each field in the `#[ink(storage)]` struct, we require a corresponding pallet storage definition. `default_address: AccountId` translates to: ```rust #[pallet::storage] pub type DefaultAddress = StorageValue<_, T::AccountId>; ``` `name_to_address: Mapping,` translates to a `StorageMap` like so: ```rust #[pallet::storage] pub type NameToAddress = StorageMap<_, Blake2_128Concat, T::Hash, T::AccountId>; ``` `name_to_owner: Mapping,` also translates to a `StorageMap`: ```rust #[pallet::storage] pub type NameToOwner = StorageMap<_, Blake2_128Concat, T::Hash, T::AccountId>; ``` Reading and writing these storage values must all be done explicitly, in contrast with ink! which can do so automatically for non "lazy" values. When it comes to migrating the messages, this will be demonstrated. ### Error Definition Simply copy across the variants of the `enum Error` to the equivalent `#[pallet::error]` definition. In our case we end up with: ```rust #[pallet::error] pub enum Error { /// Returned if the name already exists upon registration. NameAlreadyExists, /// Returned if caller is not owner while required to. CallerIsNotOwner, } ``` Note that the `T` generic parameter is not used in this case, the `error` macro handles the generation of `PhantomData`. If we use some environmental types we can use the `T` similar to the event definition. ### Constructors In this example, the single constructor is simply initializing the storage to empty values. ```rust #[ink(constructor)] pub fn new() -> Self { Default::default() } ``` This code is executed when the contract instance was initialized. Our use case is a migration, so we will assume that the existing data must be migrated from contract storage to the pallet storage. This will be covered in the [Data Migration](#data-migration) section. No code migration is required then for this constructor. ### Messages #### Mutable There are 3 mutable messages (that can change the state of the contract): `register`, `set_address` and `transfer`. This guide will demonstrate `register`, and the other two can follow a similar pattern. The message is defined as so, with added numerical comments to show the translation to the equivalent `FRAME` code. ```rust #[ink(message)] pub fn register(&mut self, name: Hash) -> Result<()> { // 1. let caller = self.env().caller(); // 2. if self.name_to_owner.contains(name) { return Err(Error::NameAlreadyExists) } // 3. self.name_to_owner.insert(name, &caller); // 4. self.env().emit_event(Register { name, from: caller }); // 5. Ok(()) } ``` Before proceeding, it is necessary to add a custom `deposit_event` function for raising events which accepts topics: ```rust impl Pallet { fn deposit_event(topics: Vec, event: Event) { >::deposit_event_indexed( &topics, ::RuntimeEvent::from(event).into() ) } } ``` Now we can translate the `register` message into a "Dispatchable": ```rust #[pallet::call_index(0)] #[pallet::weight(Weight::from_parts(10_000, 0) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)))] pub fn register(origin: OriginFor, name: T::Hash) -> DispatchResultWithPostInfo { // 1. let caller = ensure_signed(origin)?; // 2. ensure!(!NameToOwner::::contains_key(&name), Error::::NameAlreadyExists); // 3. >::insert(name, &caller); // 4. Self::deposit_event( &[name.clone(), T::Hashing::hash_of(&caller)], Event::Register { name, from: caller } ); // 5. Ok(().into()) } ``` Compare the numbered annotations from the ink! contract message and the `FRAME` dispatchable, and you can see they are very similar, just different APIs for interacting with the environment and with storage. For `4.`, in `FRAME` we need to generate the topic list manually which is done automatically in ink! via the annotations. #### Weights The `pallet::weight` attribute defines the `weight` of the dispatchable i.e. the amount of onchain resources it is estimated to consume. Because we are now writing trusted code, we can define this up front (no runtime gas metering). The number in the `weight` is typically generated via a benchmarking process. It is important to integrate this process and set a non-arbitrary value here before deploying to a production chain. You can read more [here](https://docs.polkadot.com/polkadot-protocol/basics/blocks-transactions-fees/fees/). #### Immutable (read only) messages `ink!` messages can return a value, which when executed as an RPC "dry-run" (not via a transaction), are used to read the state of contracts. Dispatchables in `FRAME` cannot return values directly. There are two ways to read the state from a FRAME pallet: 1. Reading from `#[pallet::storage]` items directly, client libraries will generate an API to do this from the runtime metadata. See e.g. [`subxt`](https://github.com/paritytech/subxt/blob/master/subxt/examples/storage_fetch.rs) 2. Via runtime APIs, RPC methods that can be wired up directly into query methods on a pallet. See [here](https://docs.polkadot.com/polkadot-protocol/basics/node-and-runtime/#runtime-apis) for more info. In our case, `1.` is good enough, so the following read only message: ```rust #[ink(message)] pub fn get_address(&self, name: Hash) -> AccountId { self.get_address_or_default(name) } fn get_address_or_default(&self, name: Hash) -> AccountId { self.name_to_address .get(name) .unwrap_or(self.default_address) } ``` Can be queried *without* any modifications to the `NameToAddress` storage type: ```rust #[pallet::storage] pub type NameToAddress = StorageMap<_, Blake2_128Concat, T::Hash, T::AccountId>; ``` `subxt` would generate the following accessor for querying the storage: ```rust let storage_query = my_custom_chain::storage().dns().name_to_address(&name); // Use that query to `fetch` a result. This returns an `Option<_>`, which will be // `None` if no value exists at the given address. You can also use `fetch_default` // where applicable, which will return the default value if none exists. let result = api .storage() .at_latest() .await? .fetch(&storage_query) .await?; ``` ### Data Migration Data migration can be done at either genesis time or once the custom parachain is up and running. #### Retrieving the data from the contract In both cases the first steps are to first download the current state of the contract at a fixed point in time, and then ensuring that no changes can be made to the contract after that. This could be done by using `set_code_hash` to update the source code of the contract to a special contract which allows only querying and downloading the state of the current contract, and no mutating messages. An alternative would be querying the contract storage directly, but currently there are no good tools for this, and it would require some key calculation for retrieving the data at all storage locations. Additionally the contract would still need to be "frozen" somehow to ensure no changes can be made to the contract state. #### Initializing the pallet Once the data has been downloaded and serialized, it can be used to initialize the state of the custom parachain runtime. This can be hardcoded in a `#[pallet::genesis_build]` impl block. See [here](https://docs.polkadot.com/develop/parachains/deployment/generate-chain-specs/) for more info. Alternatively the state could be initialized via dispatchable extrinsic(s) which initialize the storage. ### Adjusting UIs User interfaces will need to be adjusted to interact with a pallet rather than a contract. This should be relatively straightforward since client libraries usually have first-class support for interacting with Polkadot SDK pallets, and the signing etc. should already be integrated. ```` ## File: docs/background/polkadot-sdk.md ````markdown --- title: Polkadot SDK and ink! hide_title: true slug: /background/polkadot-sdk --- ![Polkadot SDK Title Picture](/img/title/polkadot.svg) # Polkadot SDK ink! is a programming language for smart contracts; blockchains built with [the Polkadot SDK](https://github.com/paritytech/polkadot-sdk) can choose from a number of smart contract languages which one(s) they want to support. ink! is one of them. It is an opinionated language that we have built by extending the popular Rust programming language with functionality needed to make it smart contract compatible. ## How does ink! tie into Polkadot SDK? [Polkadot SDK](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/index.html) is a framework for building blockchains – those can be standalone blockchains or blockchains connected to [Kusama](http://kusama.network) or [Polkadot](http://polkadot.network), so called _parachains_. The Polkadot SDK contains a number of modules, in Polkadot SDK terminology those are called _pallets_. Polkadot SDK comes with a set of pallets for many requirements modern blockchains typically have – staking, fungible tokens, non-fungible tokens, governance, etc. Polkadot SDK also ships with a module for smart contracts, this module is called [`pallet-revive`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive). If a parachain is developed in the Polkadot SDK it can easily add smart contract functionality by including this pallet. How does ink! come into play here? ink! is a programming language, specifically it is an embedded domain-specific language for the popular Rust programming language. This means that you can use all the normal Rust syntax plus some specifics that we added to make the language suitable for the smart contract world. The `pallet-revive` takes these ink! contracts and executes them safely. So in short: _with ink! you can write smart contracts in Rust for blockchains built with the Polkadot SDK that include `pallet-revive`_. ![](/img/ink-pallet-contracts.png) ## How does the `pallet-revive` work? `pallet-revive` was intentionally designed in a way that it is decoupled from the language that is used to write smart contracts. The pallet is only the execution environment and it takes RISC-V binary files as input. Smart contracts for this pallet have to be compiled to the RISC-V target architecture. For contract developers this means they can use ink! for writing smart contracts, but can also decide on other languages. Right now the pallet supports ink! (Rust) and Solidity (via [Parity's revive compiler](https://github.com/paritytech/revive)). It's not hard to add new languages. There just needs to be a compiler for the language down to RISC-V bytecode, then it's possible to implement the API of `pallet-revive`. This API at the moment consists of about 50 functions for anything a smart contract may desire: storage access, cryptographic functionality, environmental information like block numbers, access to functions for getting random numbers or self-terminate the contract, etc. Not all of those have to be implemented in the language ‒ the ink! "Hello, World!" requires just six API functions. The following schema depicts this relationship: ![](/img/ink-polkavm-riscv-solidity.svg) We think this design is more future-proof than some architectures found in competing ecosystems. There is no tight coupling between language and execution environment. RISC-V is an industry standard and a multitude of programming languages can nowadays be compiled down to it. If in, say ten years time, researchers come up with an innovative language for writing smart contracts (or a subset of an existing language) then as long as there is a compiler that supports RISC-V it will be easy to make this language compatible with `pallet-revive`. ## Why include `pallet-revive` on a parachain? There are a couple use cases for including smart contract functionality on a parachain. We distinguish three big ones. ### Use Case 1: Smart Contracts as "first-class citizens" The most obvious use case is a parachain which provides smart contracts as a “first-class citizen”, meaning smart contracts are the central value proposition of the chain. Those chains typically take the off-the-shelf `pallet-revive` and create additional innovation on top of it. An example for this is [Pop Network](https://onpop.io/). ### Use Case 2: Smart Contracts as "second-class citizens" There is another not so obvious use case for `pallet-revive`: smart contracts as “second-class citizens” on an existing chain. By this we mean that the central value proposition of the chain has nothing to do with smart contracts, but it still includes them as an add-on. The `pallet-revive` provides a [Precompile API](../basics/precompiles.md) with which a parachain can expose certain parts of its business logic to smart contract developers. Through this, smart contract developers can utilize the business logic primitives of the chain to build a new application on top of it. Think for example of a decentralized exchange blockchain. This chain would in its simplest form have an order book to place bids and asks ‒ there is no need for taking untrusted, Turing-complete, programs from the outside. The parachain could decide to expose the order book into smart contracts though, giving external developers the option of building new applications that utilize the order book. For example, to upload trading algorithms as smart contracts to the chain. Smart contracts here are an opportunity to up the user engagement and drive usage of the chain's native token. And the billing for utilizing the chain comes already built-in with the pallet ‒ users have to pay gas fees for the execution of their smart contract. ### Use Case 3: Smart Contracts as a first step into Polkadot or Kusama A third big use case for `pallet-revive` is to prototype an idea as a proof-of-concept smart contract before leasing a dedicated parachain slot on Polkadot or Kusama. The time to develop a smart contract and deploy it is shorter than the onboarding story for a parachain. One can deploy a proof-of-concept smart contract first, see if it gains traction and the idea holds up to the real world. Only subsequently, once there is a need for e.g. cheaper transaction fees, more efficient execution, or a governance mechanism for the community, the smart contract could be migrated to a dedicated parachain runtime with its own slot. ink! contracts and Polkadot SDK runtimes are both written in Rust and share similar primitives, this enables a clear path to graduate from a smart contract to its own runtime. Developers can reuse large parts of their code, their tests, as well as frontend and client code. ![](/img/ink-gateway.jpg) ## Smart Contracts vs. Parachains One of the first questions we typically get when somebody learns about Polkadot SDK, Polkadot, or Kusama is when to develop a parachain vs. when to develop a smart contract. The distinction here is that in the context of Polkadot and Kusama a parachain leases a slot for a couple of months for up to two years. The deal with a lease is that the parachain gets a fixed slot for executing its business logic (typically referred to as its _state transition function_) and can persist its modified state in a block. In the Polkadot SDK terminology this state transition function is called the chain's _runtime_. The distinction to other ecosystems here is that, in the context of Polkadot, parachains and smart contracts exist at different layers of the stack: _smart contracts sit on top of parachains_. Parachains would usually be described as layer-1 blockchains ‒ except for that they don't have to build their own security, are upgradable, and interoperable. It's noteworthy that a parachain's state transition function doesn't get further validated ‒ it's up to the parachain how it utilizes its slot time. The parachain already pre-paid for its slot when it won the slot auction on Polkadot or Kusama. This means the parachain can build its own (blockchain) world! For example, it can decide on how transaction fees are charged ‒ or even if transaction fees are charged at all. These options are crucial when building new or more user-friendly business models. Other distinguishing factors between parachains that we observe in the wild are differences in how governance works or the crypto-economics. There are some constraints on how the parachain can build its world though. Like physics in the real world it has to adhere to certain ground rules. For Polkadot and Kusama that's for example the consensus algorithm for the Relay Chain to communicate with the parachain. From those ground rules the advantages of Polkadot and Kusama emerge. Advantages like the aforementioned shared security, cross-chain communication, or guaranteed execution slot time. For smart contracts, on the other hand, an existing parachain has to include `pallet-revive` for users to deploy smart contracts. The deployed smart contract is always untrusted code. Anyone (or any program) that has tokens of the chain can upload a smart contract without requiring permission. Smart contracts allow _permissionless_ deployment of _untrusted_ programs on a blockchain. The `pallet-revive` has to assume that these programs are adversarial, it has to put a number of safety pillars in place to ensure that the contract can not e.g. stall the chain or cause state corruption of other contracts. For `pallet-revive` those safety pillars include mechanisms like gas metering or deposits for storing data on-chain. _To restate this important distinction: developing a parachain runtime is different from developing a smart contract ‒ a smart contract sits on top of a parachain_. The trade-off is that with a parachain one has the freedom to decide on (nearly) all the rules that make up the parachain. With a smart contract one is constrained by what the chain allows and the safety pillars that necessarily have to be in place. A smart contract can never be as fast as a native pallet built in the parachain runtime ‒ there is too much logic in between. A smart contract on the other hand has less friction for developing and deploying it. Developers don't have to take care of governance, crypto-economics, etc. One just needs a few tokens and can go on its merry way deploying a smart contract. It's as simple as that. ![](/img/smart-contract-vs-parachain.png) ```` ## File: docs/background/precompiles.md ````markdown --- title: Precompiles hide_title: true slug: /background/precompiles --- ![Polkadot SDK Precompiles Title Picture](/img/title/precompiles.svg) # Precompiles in Polkadot SDK Precompiles act on-chain like regular contracts: they have an address and contracts can interact with them as if they were other contracts. But their code is not stored on-chain, instead they are implemented outside the sandboxed environment in which contracts are normally executed. This makes precompiles a very efficient option to execute e.g. cryptographic functionality. But they need to be added by the chain operator. Since they run outside the sandbox, bugs or exploits here can have grievous consequences. The execution engine for ink! contracts, `pallet-revive`, supports precompiles. Some precompiles are enabled by default, others are shipped with Polakdot SDK, but are optional. An important distinction is that precompiles can be written in a way that they take either raw bytes as input, or in a way that they expose a complete Solidity interface, requiring also the Solidity ABI and encoding as the calling convention. ## Primitive Precompiles The `pallet-revive` ships with a number of precompiles that are enabled by default: | Name | Address | Called via | Enabled by default? | Implemented in ink!? | |----------------------------------------------------------------------------------------------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------|---------------------|----------------------| | [EcRecover](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/ecrecover.rs) | 0x1 | Raw bytes | ✅ | ✅| | [Sha256](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/sha256.rs) | 0x2 | Raw bytes | ✅ | ✅| | [Ripemd160](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/ripemd160.rs) | 0x3 | Raw bytes | ✅ | Not yet | | [Identity](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/identity.rs) | 0x4 | Raw bytes | ✅ | Not yet | | [Modexp](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/modexp.rs) | 0x5 | Raw bytes | ✅ | Not yet | | [Bn128Add](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/bn128.rs) | 0x6 | Raw bytes | ✅ | Not yet | | [Bn128Mul](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/bn128.rs) | 0x7 | Raw bytes | ✅ | Not yet | | [Bn128Pairing](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/bn128.rs) | 0x8 | Raw bytes | ✅ | Not yet | | [Blake2F](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/blake2f.rs) | 0x9 | Raw bytes | ✅ | Not yet | | [PointEval](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/point_eval.rs) | 0a | Raw bytes | ✅ | Not yet | | [System](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/system.rs) | 0x900 | [Solidity interface](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/uapi/src/precompiles/system.rs) | ✅ | ✅| | [Storage](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/precompiles/builtin/storage.rs) | 0x901 | [Solidity interface](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/uapi/src/precompiles/storage.rs) | ✅ | ✅| The Polkadot SDK contains a number of additional precompiles that can be enabled at will: | Name | Address | Called via | Enabled by default? | Implemented in ink!? | |----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|---------------------|----------------------| | [AssetsPrecompile](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/assets/precompiles) | [0x120, 0x320](https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs#L1192-L1196) | [Solidity interface](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/primitives/ethereum-standards/src/IERC20.sol) | ✅ | Not yet | | [XcmPrecompile](https://github.com/paritytech/polkadot-sdk/tree/master/polkadot/xcm/pallet-xcm/precompiles/) | 0xA0000 | Raw bytes | ✅ | ✅ | ## Add your own precompiles It's possible to extend the `pallet-revive` with custom precompiles. This is not relevant if you are only deploying your contracts to a chain that you don't control. But if you are building a blockchain with Polkadot SDK and want to give users the ability to access specific functionality of your blockchain runtime in their smart contracts, then that's the way to go. Through this, smart contract developers can utilize the business logic primitives of the chain to build a new application on top of it. Think for example of a decentralized exchange blockchain. This chain would in its simplest form have an order book to place bids and asks — there is no need for taking untrusted, Turing-complete, programs from the outside. The parachain could decide to expose the order book into smart contracts though, giving external developers the option of building new applications that utilize the order book. For example, to upload trading algorithms as smart contracts to the chain. Smart contracts here are an opportunity to up the user engagement and drive usage of the chain's native token. And the billing for utilizing the chain comes already built-in with the pallet — users have to pay gas fees for the execution of their smart contract. For example, on the Polkadot testnet Westend the `pallet-revive` is configured to use these additional precompiles ([here](https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs#L1192-L1196)): ```rust type Precompiles = ( ERC20, TrustBackedAssetsInstance>, ERC20, PoolAssetsInstance>, XcmPrecompile, ); ``` ## Develop your own Precompile If you are looking to develop your own custom precompile, here are some starting points: Our `ink-node` contains a simple demo precompile. You can find its source code [here](https://github.com/use-ink/ink-node/blob/main/runtime/src/demo_precompile.rs) and its Solidity interface specification [here](https://github.com/use-ink/ink-node/blob/main/runtime/src/IDemo.sol). ```rust #![cfg_attr(not(feature = "std"), no_std, no_main)] /// This trait is an implementation of the Solidity interface found at /// . /// /// Note that it's also possible to just implement the interface partially. /// This can be useful if you just want to expose part of the precompile /// functionality #[ink::contract_ref(abi = "sol")] pub trait System { /// Simple echo function. /// /// If `mode = 0`, the function reverts. /// If `mode > 0`, the input `message` is echoed back to the caller. /// /// # Note /// /// This signature is the ink! equivalent of the following Solidity signature /// /// ```solidity /// function echo(uint8 mode, bytes message) external view returns (bytes); /// ``` #[ink(message)] #[allow(non_snake_case)] fn echo(&self, mode: u8, message: ink::sol::DynBytes) -> ink::sol::DynBytes; } #[ink::contract] mod precompile_demo { use super::System; use ink::prelude::vec::Vec; #[ink(storage)] pub struct PrecompileDemo; impl PrecompileDemo { /// Initializes contract. #[ink(constructor)] #[allow(clippy::new_without_default)] pub fn new() -> Self { Self {} } /// Calls the `echo` function from `ink-node`'s `DemoPrecompile`. #[ink(message)] pub fn call_echo(&self, data: Vec) -> Vec { const DEMO_PRECOMPILE_ADDR: [u8; 20] = hex_literal::hex!("00000000000000000000000000000000000B0000"); let system_ref: super::SystemRef = ink::Address::from(DEMO_PRECOMPILE_ADDR).into(); let in_bytes = ink::sol::DynBytes(data); let out_bytes = system_ref.echo(1, in_bytes); out_bytes.0 } } #[cfg(all(test, feature = "e2e-tests"))] mod e2e_tests { use super::*; use ink_e2e::ContractsBackend; type E2EResult = std::result::Result>; #[ink_e2e::test] async fn call_echo_works(mut client: ink_e2e::Client) -> E2EResult<()> { // given let mut constructor = PrecompileDemoRef::new(); let contract = client .instantiate("precompile_demo", &ink_e2e::bob(), &mut constructor) .submit() .await .expect("instantiate failed"); let call_builder = contract.call_builder::(); // when let data = vec![0x1, 0x2, 0x3, 0x4]; let expected = data.clone(); let call_echo = call_builder.call_echo(data); let res = client .call(&ink_e2e::bob(), &call_echo) .submit() .await .expect("call_echo failed"); // then assert_eq!(res.return_value(), expected); Ok(()) } } } ``` If you want to look further, the source code of the [`AssetPrecompile`](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/assets/precompiles/src) and the [`XcmPrecompile`](https://github.com/paritytech/polkadot-sdk/tree/master/polkadot/xcm/pallet-xcm/precompiles/src) is also a good inspiration. ```` ## File: docs/background/why-riscv.md ````markdown --- title: Why RISC-V and PolkaVM for Smart Contracts? hide_title: true slug: /background/why-riscv-and-polkavm-for-smart-contracts --- import useBaseUrl from '@docusaurus/useBaseUrl'; ## 🤔 Shortcomings of WebAssembly for Smart Contracts From ink! v1 to v5, the execution platform was Substrate's smart contracts module [`pallet-contracts`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/contracts/). This pallet required the smart contracts that were uploaded to be in the _WebAssembly (Wasm) bytecode format_. So ink! contracts were always compiled to a WebAssembly binary. This could be done by invoking `cargo build`/`rustc` directly or via our CLI tool [`cargo-contract`](https://github.com/use-ink/cargo-contract) (which executes the Rust compiler with optimal flags for smart contracts). As an ongoing research project Parity was always looking at alternatives to WebAssembly for smart contract execution. Some of those investigations are persisted in the Polkadot Forum. The forum post on [the eBPF investigation](https://forum.polkadot.network/t/ebpf-contracts-hackathon/1084) (eBPF is used in Solana) highlights some shortcomings of WebAssembly for smart contracts. ## 🧑‍🔬 RISC-V + PolkaVM During 2023, Parity core developer Jan Bujak ([@koute](https://github.com/koute)) did another exploration on alternatives for WebAssembly. [His forum post](https://forum.polkadot.network/t/exploring-alternatives-to-wasm-for-smart-contracts/2434) gives a great overview on how he landed at RISC-V and its potential. His explorations yielded promising results and a new project was started: [PolkaVM](https://github.com/paritytech/polkavm) ([the announcement contains more info](https://forum.polkadot.network/t/announcing-polkavm-a-new-risc-v-based-vm-for-smart-contracts-and-possibly-more/3811)). PolkaVM is intended to be a very fast RISC-V based virtual machine. Jan regularly shared performance benchmarks in the Polkadot Forum. Those were very good and got community enthusiasm started. For blockchains a very fast performance correlates with transaction throughput and transaction costs, which implies improved scalability and reduced costs for users. ## 🤝 `pallet-revive` Parity in late 2024 forked Substrate's `pallet-contracts` into a new project called [`pallet-revive`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive). Smart contracts that are uploaded to this new pallet have to be in the RISC-V bytecode format, and no longer in WebAssembly. Besides the contract binary format, a number of other significant changes were made to provide first-class support for Solidity contracts: * Extensive changes were made in the inner logic of the pallet to bring its behavior closer to the EVM (e.g. types, events, and debugging was changed to be Solidity compatible). * In the `pallet-contracts` era, the idea for Solidity compatibility was a project called [Solang](https://github.com/hyperledger-solang/solang/). It's a Solidity compiler that parses Solidity syntax and outputs WebAssembly. Parsing the Solidity syntax turned out to be a complex undertaking. Solidity as a language is also evolving and provided a moving target.

As an iteration on that approach, for `pallet-revive` Parity started a new project called [`revive`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive/src) ᠆ a compiler from the Solidity bytecode YUL to a RISC-V contract that can be executed on `pallet-revive`. This bytecode is more stable than the language syntax. Plus Solidity developers can continue to use the Solidity compiler `solc` to compile their contracts. * An RPC wrapper that maps Ethereum RPC's onto Substrate was created. At the time of writing, `pallet-revive` is deployed to the Polkadot testnet Westend (on the AssetHub parachain). A launch on Polkadot's canary network Kusama is targeted for early Q2/25. The Polkadot launch is targeted for Q3/25. ## 🙌 Migrating ink! to RISC-V + PolkaVM + `pallet-revive` `pallet-revive` and RISC-V are seen as the future of smart contracts in the Polkadot ecosystem. We agree with that vision and are excited to work on making the ink! stack ready for it! In autumn 2024 the ink! Alliance created [a Polkadot treasury proposal](https://forum.polkadot.network/t/treasury-ink-alliance-for-a-more-successful-plaza/9692) around this. The Polkadot community signaled its alignment and gave us the mandate of migrating ink! to this new stack. Hence, v5 of ink! and `cargo-contract` were the last versions supporting `pallet-contracts` and Wasm. We can still backport important fixes, but the coming releases (`>= v6`) will all no longer be compatible. In case you want to create a PR for a backport, we have v5 release branches [here](https://github.com/use-ink/ink/tree/v5.x) and [here](https://github.com/use-ink/cargo-contract/tree/v5.x.x). We have created [this migration guide](/docs/v6/faq/migrating-from-ink-5-to-6) from ink! v5 to v6. All breaking changes and new features are documented there. What has not yet been migrated is [Contracts UI](https://github.com/use-ink/contracts-ui) and external libraries (such as [ink!athon](https://inkathon.xyz/), the [ink! Analyzer VS Code extension](https://marketplace.visualstudio.com/items?itemName=ink-analyzer.ink-analyzer), `polkadot-js`, …). We are in contact with the maintainers of these external libraries about migrating them as well. ```` ## File: docs/background/why-rust.md ````markdown --- title: Why Rust for Smart Contracts? hide_title: true slug: /background/why-rust-for-smart-contracts --- ![Rust Title Picture](/img/title/rust.svg) # Why Rust for Smart Contracts? ink! chooses not to invent a new programming language, but rather adapt a subset of Rust to serve our purpose. If this doesn't already convince you, you find many more good reasons here: * Rust is an ideal smart contract language: It is type safe, memory safe, and free of undefined behaviors. It generates small binaries because it doesn’t include extra bloat, like a garbage collector, and advanced optimizations and tree shaking remove dead code. Through compiler flags, Rust can automatically protect against integer overflow. * Rust ecosystem: You gain all the support available to the Rust ecosystem for free. As the language develops, ink! will automatically gain access to new features and functionality, improving how you can write smart contracts in the future. * Tooling: Because ink! follows Rust standards, tools like rustfmt, clippy and rust-analyzer already work out of the box. The same goes for code formatting and syntax highlighting in most modern text editors. Also, Rust has an integrated test and benchmark runner, * No overhead: Minimal runtime. * Safe & Efficient: Zero-cost & safe abstractions. * Productive: Cargo + crates.io Ecosystem. * 1st class RISC-V: The Rust compiler has excellent support for the RISC-V bytecode architecture. That's because it leverages LLVM as its backend to generate machine code for the RISC-V architecture. * Small Size: In the space-constrained blockchain world size is important. The Rust compiler is a great help for that, since it reorders struct fields in order to make each type as small as possible. Thus, Rust data structures are very compact, in many cases even more compact than in C. ink! is an [Embedded Domain Specific Language](https://wiki.haskell.org/Embedded_domain_specific_language) (eDSL): a domain-specific language of the Rust programming language. That means: * we allow only a subset of the Rust programming language features to be used for writing smart contracts. For example, it is not possible do any multi-threading operations or access the web. * we provide annotations, macros, and primitives that are needed when writing smart contracts. For example, annotations on what the smart contract's storage struct is or what an event is. ink! is just standard Rust in a well-defined "contract format" with specialized `#[ink(…)]` attribute macros. These attribute macros tell ink! what the different parts of your Rust smart contract represent, and ultimately allow ink! to do all the magic needed to create Polkadot SDK compatible RISC-V bytecode! ```` ## File: docs/basics/abi/all.md ````markdown --- title: | "All" ABI Mode hide_title: true slug: /basics/abi/all --- ![Metadata Title Picture](/img/title/metadata-revive.svg) # "All" ABI Mode The "all" ABI mode is declared in the contract's manifest file (i.e. the `Cargo.toml` file) as follows: ```toml [package.metadata.ink-lang] abi = "all" ``` When the "all" ABI is specified, the ink! code generator follows both the ink! and Solidity ABI specifications, and generates entry points for both calling conventions. This means: - For each message, two selectors are generated, one for [ink!](./ink.md) and another for [Solidity](./solidity.md) ABI. - Each selector is ABI specific and its entry point uses the corresponding input/output encoding/decoding scheme (i.e. entry points for ink! selectors use Parity's [SCALE Codec][scale-codec], while entry points for Solidity selectors use Solidity ABI encoding/decoding for input/output encoding/decoding). - Message selector manual overrides (using the [`selector` attribute][selector-attribute]) are respected for ink! ABI entry points but ignored for Solidity ABI entry points (i.e. Solidity selectors are **always** generated according to the [Solidity ABI specification for function selectors][sol-abi-selector]). - Multiple constructors are supported (as per the ink! ABI), however, if multiple constructors are defined, then one of the constructors must be annotated with the [`default` attribute][default-attribute] to identify it as the constructor to use for Solidity ABI encoded instantiation. Note that if only a single constructor is defined, then the `default` attribute annotation is unnecessary. - Call builders and [contract references][contract-refs] are generated for both ink! and Solidity ABI calling conventions. - Both an ink! and Solidity ABI encoded event are emitted for each call to `Self::env().emit_event()` or `self.env().emit_event()`. :::note Your contract sizes will get larger if you support both the ink! and Solidity ABI. ::: :::note The "all" ABI mode can only be used if all message argument and return types, the argument and return type of the constructor used for Solidity ABI encoded instantiation, and event argument types can be mapped to equivalent Solidity ABI types ([more details here][sol-type-mapping]). ::: [scale-codec]: https://docs.rs/parity-scale-codec/latest/parity_scale_codec [sol-abi-selector]: https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector [selector-attribute]: ../../macros-attributes/selector.md [default-attribute]: ../../macros-attributes/default.md [contract-refs]: ../cross-contract-calling.md#contract-references [sol-type-mapping]: ../../integrations-and-sdks/ethereum-compatibility.md#rustink-to-solidity-abi-type-mapping ```` ## File: docs/basics/abi/ink.md ````markdown --- title: ink! ABI hide_title: true slug: /basics/abi/ink --- ![Metadata Title Picture](/img/title/metadata-revive.svg) # ink! ABI The ink! ABI is declared in the contract's manifest file (i.e. the `Cargo.toml` file) as follows: ```toml [package.metadata.ink-lang] abi = "ink" ``` When the ink! ABI is specified, the ink! code generator follows the ink! ABI specification. This means: - By default, message selectors are generated according to the [ink! ABI specification for selectors][ink-spec-selector]. - Message selectors can be manually overridden using the [`selector` attribute][selector-attribute]. - Parity's [SCALE Codec][scale-codec] is used for input/output encoding/decoding. - Call builders (used for making cross-contract calls) are generated for ink! ABI calling conventions. [ink-spec-selector]: ../selectors.md [selector-attribute]: ../../macros-attributes/selector.md [scale-codec]: https://docs.rs/parity-scale-codec/latest/parity_scale_codec ```` ## File: docs/basics/abi/overview.md ````markdown --- title: Overview hide_title: true slug: /basics/abi --- ![Metadata Title Picture](/img/title/metadata-revive.svg) # ABI (Application Binary Interface) An ABI (Application Binary Interface) defines a standard way to interact with contracts (i.e. it defines the calling conventions to use for public function calls). More concretely this entails specifications for: - Computing or defining selectors which identify the entry points for public function calls - Encoding and decoding public function input and output data - Encoding and decoding event and error data With ink! v6, the ink! code generator supports two ABI specifications: - [Our own native ink! ABI specification](./ink.md) - [The Solidity ABI specification](./solidity.md) Supporting the Solidity ABI specification allows: - Solidity contracts to transparently call ink! contracts - Developers to use Solidity tools (e.g. [ethers.js][ethers-js]) to transparently interact with ink! contracts. Additionally, the ink! code generator can operate in an [`"all"` ABI mode](./all.md), where it generates a binary that supports both the ink! and Solidity ABI specifications (i.e. it generates a binary that transparently supports both ink! and Solidity calling conventions, and thus transparently supports interactions from both ink! and Solidity contracts and external tools). ## Declaring the ABI The ABI for an ink! contract is declared in the contract's manifest file (i.e. the `Cargo.toml` file), as a field `abi` of a custom `ink-lang` table in the [`package.metadata` table][package-metadata] e.g. ```toml [package.metadata.ink-lang] abi = "sol" ``` The default value for `abi` is currently `"ink"`, but we might change this before a production release. Allowed values are `"ink"`, `"sol"` and `"all"`. :::note The Solidity ABI specification can only be used if all constructor and message argument and return types, and event argument types can be mapped to equivalent Solidity ABI types ([more details here][sol-type-mapping]). ::: :::note Your contract sizes will get larger if you support both the ink! and Solidity ABI. ::: [package-metadata]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-metadata-table [ethers-js]: https://docs.ethers.org/ [sol-type-mapping]: ../../integrations-and-sdks/ethereum-compatibility.md#rustink-to-solidity-abi-type-mapping ```` ## File: docs/basics/abi/solidity.md ````markdown --- title: Solidity ABI hide_title: true slug: /basics/abi/solidity --- ![Metadata Title Picture](/img/title/solidity.svg) # Solidity ABI The Solidity ABI is declared in the contract's manifest file (i.e. the `Cargo.toml` file) as follows: ```toml [package.metadata.ink-lang] abi = "sol" ``` When the Solidity ABI is specified, the ink! code generator follows the [Solidity ABI specification][sol-abi]. This means: - Message selectors are **always** generated according to the [Solidity ABI specification for function selectors][sol-abi-selector]. - Message selector manual overrides using the [`selector` attribute][selector-attribute] are ignored. - [Solidity ABI encoding][sol-abi-codec] is used for input/output encoding/decoding. - Only one constructor can be defined for the contract. - Call builders are generated for Solidity ABI calling conventions. :::note The Solidity ABI specification can only be used if all constructor and message argument and return types, and event argument types can be mapped to equivalent Solidity ABI types ([more details here][sol-type-mapping]). ::: :::info The contract ABI only describes how external interactions with a contract are encoded/decoded. The internal storage representation of a contract is still done in the SCALE codec! _Using the Solidity ABI does not imply switching to a different storage layout!_ ::: [sol-abi]: https://docs.soliditylang.org/en/latest/abi-spec.html [sol-abi-selector]: https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector [selector-attribute]: ../../macros-attributes/selector.md [sol-abi-codec]: https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding [sol-type-mapping]: ../../integrations-and-sdks/ethereum-compatibility.md#rustink-to-solidity-abi-type-mapping ```` ## File: docs/basics/metadata/ink-format.md ````markdown --- title: ink! Format hide_title: true slug: /basics/metadata/ink --- ![Metadata Title Picture](/img/title/metadata-revive.svg) # ink! Metadata The ink! metadata is generated when a contract is built using `cargo-contract`, e.g `cargo contract build`. It can be found in your contract's target directory under the name `.json`. :::note The metadata is also contained in your `.contract` file. The difference is that the `.contract` file also contains the binary of your contract (under `source.contract_binary`). ::: ## `.json` The metadata is defined by the following **required** keys: - `source`: Information about the contract's binary. - `contract`: Metadata about the contract. - `abi`: Raw JSON of the contract's abi metadata, generated during contract compilation. It may _optionally_ contain the following keys: - `user`: Additional user-defined metadata. ```json { "source": { "hash": "...", "language": "...", "compiler": "..." }, "contract": { "name": "...", "version": "...", "authors": [ "..." ] }, "spec": { "constructors": ["..."], "messages": ["..."] } } ``` :::note Notice that we don't have an `abi` key, but we instead use the `spec` field to specify the contract's ABI. You can read more about that in the [ABI documentation](#abi). ::: The following sections will dive deeper into how these sections are made up. ### `source` This object contains information about how the contract was built. It consists of the following **required** keys: - `hash`: The hash of the contract's binary. - `language`: The language used to write the contract. - `compiler`: The compiler used to compile the contract. It may _optionally_ include the following keys: - `contract_binary`: The actual binary code of the contract, for optionally bundling the code with the metadata. - `build_info`: Extra information about the environment in which the contract was built. ```json "source": { "hash": "0x157014494527fee27a82e49bbd9eea10c0713bb0566f6def37f4595db86236ff", "language": "ink! 6.0.0", "compiler": "rustc 1.85.0" } ``` :::info If you're interested in the code reference from `cargo-contract` see [here](https://github.com/use-ink/cargo-contract/blob/master/crates/metadata/src/lib.rs#L197). ::: ### `contract` This object contains extra metadata about the contract. The **required** keys include: - `name`: The name of the smart contract. - `version`: The version of the smart contract. - `authors`: The authors of the smart contract. It can _optionally_ include the following keys: - `description`: The description of the smart contract. - `documentation`: Link to the documentation of the smart contract. - `repository`: Link to the code repository of the smart contract. - `homepage`: Link to the homepage of the smart contract. - `license`: The license of the smart contract. ```json "contract": { "name": "flipper", "version": "6.0.0", "authors": [ "Use Ink " ] } ``` :::info If you're interested in the code reference from `cargo-contract` see [here](https://github.com/use-ink/cargo-contract/blob/master/crates/metadata/src/lib.rs#L469). ::: ### ABI This is the specification of the contract. Unlike the previous metadata sections the structure of the object stored here is not defined. Instead, it is up to each programming language (e.g. ink! or Solidity) to define their own metadata format which will then be stored here. In this document we will focus on the ink! ABI. The ink! metadata consists of the following **required** sections - `spec`: The description of the contract (e.g constructors, messages, events, etc.). - `storage`: The layout of the storage data structure - `types`: A read-only registry containing types in their portable form for serialization. - `version`: The version of the ink! metadata. ```json "spec": { ... }, "storage": { ... }, "types": { ... }, "version": "..." ``` :::info If you're interested in the code reference from ink! see [here](https://github.com/use-ink/ink/blob/master/crates/metadata/src/lib.rs#L82). ::: #### `spec` The contract `spec` consists of the following **required** keys: - `constructors`: The set of constructors of the contract. - `label`: The label of the constructor. In case of a trait provided constructor the label is prefixed with the trait label. - `selector`: The selector hash of the message. - `payable`: If the constructor accepts any `value` from the caller. - `default`: If the constructor is marked as default, useful for UIs. - `args`: The parameters of the deployment handler. - `docs`: The deployment handler documentation. - `messages`: The external messages of the contract. - `label`: The label of the message. In case of trait provided messages and constructors the prefix by convention in ink! is the label of the trait. - `selector`: The selector hash of the message. - `mutates`: If the message is allowed to mutate the contract state. - `payable`: If the message accepts any `value` from the caller. - `default`: If the message is marked as default, useful for UIs. - `args`: The parameters of the message. - `return_type`: The return type of the message. - `docs`: The message documentation. - `environment`: Configuration of the types that the host blockchain operates with. You can check default types in the [Environment](../environment.md) section. - `accountId`: The type describing an account address. - `balance`: The type describing balance values. - `blockNumber`: The type describing a block number. - `timestamp`: the type describing a timestamp. - `events`: The events of the contract. - `label`: The label of the event. - `args`: The event arguments. - `docs`: The event documentation. - `docs`: The contract documentation. - `lang_error`: The language specific error type. :::note While all these keys are required, they may be empty. For example, if a contract does not define any events then the `events` key would contain an empty array `[]`. ::: :::tip ink! 3.x Compatibility Note The `lang_error` field was introduced as part of ink! 4.0. This represents an error which comes from the smart contracting language itself, and not the contract nor the underlying environment (i.e. `pallet-revive`). All ink! messages and constructors now return a `Result` which uses this as the `Error` variant (see the [`LangError`](https://use-ink.github.io/ink/ink/enum.LangError.html) docs for more). ::: ```json "spec": { "constructors": [ { "args": [ { ... } ], "docs": [ "Creates a new flipper smart contract initialized with the given value." ], "label": "new", "payable": false, "default": false, "selector": "0x9bae9d5e" } ], "docs": [], "events": [], "lang_error": { "displayName": [ "ink", "LangError" ], "type": 3 }, "messages": [ { "args": [], "docs": [ " Flips the current value of the Flipper's boolean." ], "label": "flip", "mutates": true, "payable": false, "default": false, "returnType": null, "selector": "0x633aa551" } ] } ``` #### `storage` This key describes the storage layout of an ink! contract. It tracks some of the different structures which can be placed in storage. It consists of the following _optional_ keys (depending on what data structures are used by the contract): - `root`: The root cell defines the storage key for all sub-trees - `root_key`: The root key of the sub-tree. - `layout`: The storage layout of the unbounded layout elements. - `leaf`: The root cell defines the storage key for all sub-trees - `key`: The offset key into the storage. - `ty`: The type of the encoded entity. - `hash`: A layout that hashes values into the entire storage key space. - `offset`: The key offset used by the strategy. - `strategy`: The hashing strategy to layout the underlying elements. - `layout`: The storage layout of the unbounded layout elements. - `array`: An array of associated storage cells encoded with a given type. - `offset`: The offset key of the array layout. This is the same key as the element at index 0 of the array layout. - `len`: The number of elements in the array layout. - `layout`: The layout of the elements stored in the array layout. - `struct`: A struct layout with fields of different types. - `name`: The name of the struct. - `fields`: The fields of the struct layout. - `enum`: An enum layout with a discriminant telling which variant is layed out. - `name`: The name of the enum. - `dispatch_key`: The key where the discriminant is stored to dispatch the variants. - `variants`: The variants of the enum. ```json "storage": { "root": { "layout": { "struct": { "fields": [ { "layout": { "leaf": { "key": "0x00000000", "ty": 0 } }, "name": "value" } ], "name": "Flipper" } }, "root_key": "0x00000000" } } ``` #### `types` This object contains the type registry for the smart contract. It consists of an array of type objects, each of which is defined as follows: - `id`: Numerical ID for referencing the type. - `ty`: The definition of the type. - `path`: The unique path to the type. Can be empty for built-in types. - `params`: The generic type parameters of the type in use. Empty for non generic types. - `def`: The actual type definition. - `docs`: Documentation. The type definition object (`def`) supports the following `primitive` types: - `bool`, `char`, `str`, `u8`, `u16`, `u32`, `u64`, `u128`, `i8`, `i16`, `i32`, `i64`, `i128`. It also supports a variety of complex built-in and user-defined types. However, we will not dig into them here. If you are interested in learning more take a look at the [`scale-info`](https://github.com/paritytech/scale-info) crate. ```json "types": [ { "id": 0, "type": { "def": { "primitive": "bool" } } } ] ``` Other parts of the metadata, such as the `storage` object, will reference individual types from this type registry using the `id` key. #### `version` This indicates the version of the ABI format the generated metadata conforms to. This is distinct from any concept of Rust's crate versioning. ```json "version": "6" ``` ### `user` This is an _optional_ field used to add user-defined metadata. Some examples of things you may want to include here: - `moon_phase`: Phase of the moon during which the smart contract works. - `favorite_blockchain`: The favorite blockchain of the contract authors (answer: Polkadot!). ```` ## File: docs/basics/metadata/overview.md ````markdown --- title: Overview hide_title: true slug: /basics/metadata --- ![Metadata Title Picture](/img/title/metadata-revive.svg) # Metadata You can think of "Metadata" this way: when a contract is built, the product of this process is a binary (the `.polkavm` file) that contains just the bytecode of your contract. Without further information it's not possible to know what this bytecode refers to. For example, which functions can be called in there or what their arguments are. This additional information that describes what the raw binary is about is called metadata — data that describes other data. Metadata is used to describe a contract in a language agnostic way. It is intended to be used by third party tools (e.g. UIs, block explorers e.t.c) in order to correctly call contract functions and interpret events. ink! supports two formats of metadata: * [Our own native ink! metadata format](./ink-format.md) * [The Solidity metadata format](./solidity-format.md) Supporting the Solidity metadata format allows developers to use Solidity tools (e.g. [ethers.js][ethers-js]) to transparently interact with [Solidity ABI compatible ink! contracts][sol-compat]. So developers have a choice which metadata they want to generate for a contract. They can decide when using the `--metadata` flag with `ink` or `solidity`. Generating Solidity metadata is only possible if all constructor and message argument and return types, and event argument types can be mapped to equivalent Solidity ABI types ([more details here][sol-type-mapping]). [ethers-js]: https://docs.ethers.org/ [sol-compat]: ../../integrations-and-sdks/ethereum-compatibility.md [sol-type-mapping]: ../../integrations-and-sdks/ethereum-compatibility.md#rustink-to-solidity-abi-type-mapping ```` ## File: docs/basics/metadata/solidity-format.md ````markdown --- title: Solidity Format hide_title: true slug: /basics/metadata/solidity --- ![Metadata Title Picture](/img/title/solidity.svg) # Solidity Metadata Format Solidity compatible metadata is generated by building a [Solidity ABI compatible ink! contract][sol-compat] using ```shell cargo contract build ---metadata solidity ``` This generates 2 metadata files in your contract's target directory: - `.abi`: follows the [Solidity ABI JSON format][sol-abi-json] for describing a contract's interface. It's used by tools for contract interaction (e.g. [ethers.js][ethers-js]) - `.json`: follows the [Solidity contract metadata specification][sol-metadata]. It's used for reproducible builds/compilation and verification of deployed contracts (e.g. by block explorers and contract verification tools). :::note Generating Solidity metadata is only possible if all constructor and message arguments and return types can be mapped to equivalent Solidity ABI types ([more details here][sol-type-mapping]). ::: [sol-compat]: ../../integrations-and-sdks/ethereum-compatibility.md [sol-abi-json]: https://docs.soliditylang.org/en/latest/abi-spec.html#json [sol-metadata]: https://docs.soliditylang.org/en/latest/metadata.html [ethers-js]: https://docs.ethers.org/ [sol-type-mapping]: ../../integrations-and-sdks/ethereum-compatibility.md#rustink-to-solidity-abi-type-mapping ## `.abi` The generated `.abi` file follows the [Solidity ABI JSON format][sol-abi-json]. A notable distinction is that while [ink! contracts can have multiple constructors][ink-ctor], the Solidity ABI JSON format only allows one, therefore the constructor annotated with a [`#[default]`][ink-attr-default] attribute is used. [ink-ctor]: ../../macros-attributes/constructor.md [ink-attr-default]: ../../macros-attributes/default.md ## `.json` The generated `.json` file follows the [Solidity contract metadata specification][sol-metadata] with the exception being that we repurpose the `"settings"` key to include ink! contract and build info namespaced under a `"settings.ink"` key: ### `settings.ink` It consists of the following **required** keys: - `hash`: The hash of the contract's binary. (The same content as [`source.hash`][ink-meta-source] in ink! metadata format). - `build_info`: Extra information about the environment in which the contract was built. (The same content as [`source.build_info`][ink-meta-source] in ink! metadata format). [ink-meta-source]: ./ink-format.md#source It may *optionally* include the following key: - `image`: If the contract is meant to be verifiable, then the Docker image is specified. (The same content as [`image`][verifiable-build] in ink! metadata format, which is used for [verifiable builds][verifiable-build]). [verifiable-build]: ../contract-verification.md#verifiable-build :::note The ABI JSON content (i.e. the content of the `.abi` file) is also contained in the `.json` metadata file under the `"output.abi"` key. ::: ```` ## File: docs/basics/contract-template.md ````markdown --- title: Contract Template hide_title: true slug: /basics/contract-template --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ![Macro Title Picture](/img/title/macro.svg) # Contract Template On this page we'll go over the elements of a basic contract. ## Creating a template Change into your working directory and run: ```bash cargo contract new foobar ``` ```bash pop new foobar ``` This will create a new project folder named `foobar`. ```bash cd foobar/ ``` In the `lib.rs` file you find initial scaffolded code, which you can use as a starting point. Quickly check that it compiles, and the trivial tests pass with: ```bash cargo contract test ``` ```bash pop test ``` Also check that you can build the contract by running: ```bash cargo contract build ``` ```bash pop build ``` `cargo contract test` builds the contract for `std`, `cargo contract build` for an on-chain deployment (`no_std` with a RISC-V target). If everything looks good, then we are ready to start programming! ## Template Content The template contains scaffolded code that provides a starting point for writing an ink! contract. In the following we'll take a look at what the files contain. The files you get locally will look similar, just that we added explanatory comments here. ### `Cargo.toml` ```toml [package] name = "foobar" version = "0.1.0" authors = ["[your_name] <[your_email]>"] edition = "2021" [dependencies] # The `ink` crate contains the ink! eDSL and re-exports # a number of other ink! specific crates. For example, # `ink::env` is the `ink_env` crate that contains functions # to interact with a contract's environment (querying information # about a caller, the current block number, etc.). ink = { version = "6.0.0-beta", default-features = false } [dev-dependencies] # This developer dependency is for the End-to-End testing framework. ink_e2e = { version = "6.0.0-beta", default-features = false } [lib] name = "foobar" path = "lib.rs" [features] default = ["std"] std = [ "ink/std", ] ink-as-dependency = [] # This feature is just a convention, so that the end-to-end tests # are only executed if `cargo contract test` is explicitly invoked with # `--features e2e-tests`. e2e-tests = [] ``` ### `lib.rs` Every ink! contract is required to contain: * Exactly one `#[ink(storage)]` struct. * At least one `#[ink(constructor)]` function. * At least one `#[ink(message)]` function. The scaffolded code will look similar to the following, we've changed the comments though to explain what is going on there on a high level. ```rust // If the `std` feature from the `Cargo.toml` is not enabled // we switch on `no_std`, this has the effect of Rusts standard // library not being included in our contract. // // The Rust standard library is OS-dependent and Wasm is // architecture independent. #![cfg_attr(not(feature = "std"), no_std, no_main)] // This is the ink! macro, the starting point for your contract. // Everything below it might look like Rust code, but it is actually // run through a parser in ink!. #[ink::contract] pub mod flipper { /// This is the contract's storage. #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { /// A constructor that the contract can be initialized with. #[ink(constructor)] pub fn new(init_value: bool) -> Self { /* --snip-- */ } /// An alternative constructor that the contract can be /// initialized with. #[ink(constructor)] pub fn new_default() -> Self { /* --snip-- */ } /// A state-mutating function that the contract exposes to the /// outside world. /// /// By default functions are private, they have to be annotated /// with `#[ink(message)]` and `pub` to be available from the /// outside. #[ink(message)] pub fn flip(&mut self) { /* --snip-- */ } /// A public contract function that has no side-effects. /// /// Note that while purely reading functions can be invoked /// by submitting a transaction on-chain, this is usually /// not done as they have no side-effects and the transaction /// costs would be wasted. /// Instead those functions are typically invoked via RPC to /// return a contract's state. #[ink(message)] pub fn get(&self) -> bool { /* --snip-- */ } } #[cfg(test)] mod tests { use super::*; /// This attribute denotes that the test is executed in /// a simulated, mocked blockchain environment. There are /// functions available to influence how the test environment /// is configured (e.g. setting an account to a specified balance). #[ink::test] fn default_works() { /* --snip-- */ } /* --snip-- */ } #[cfg(all(test, feature = "e2e-tests"))] mod e2e_tests { use super::*; use ink_e2e::build_message; type E2EResult = std::result::Result>; /// With this attribute the contract will be compiled and deployed /// to a Substrate node that is required to be running in the /// background. /// /// We offer API functions that enable developers to then interact /// with the contract. ink! will take care of putting contract calls /// into transactions that will be submitted to the Substrate chain. /// /// Developers can define assertions on the outcome of their transactions, /// such as checking for state mutations, transaction failures or /// incurred gas costs. #[ink_e2e::test] async fn it_works(mut client: ink_e2e::Client) -> E2EResult<()> { /* --snip-- */ } /* --snip-- */ } } ``` ```` ## File: docs/basics/contract-verification.md ````markdown --- title: Contract Verification slug: /basics/verification/contract-verification hide_title: true --- ![intro image](/img/title/verification.svg) # Contract Verification Contract verification is the process of matching a deployed ink! contract with the source code and metadata generated when it was built. The verification process for Rust-based smart contract languages is more complex than EVM-based languages such as Solidity due to the Rust compiler not providing deterministic builds of contracts. In order to verify an ink! smart contract, the verification process must recompile the contract in an identical host environment to which it was originally built. The simplest way to do this is using a Docker container. ## Verifiable build As mentioned earlier, due to the non-deterministic nature of Rust compilation, smart contract developers are advised to build their project inside a Docker container we provide. Luckily, `cargo contract build` provides the `--verifiable` flag for this purpose. The steps for the verifiable build production are: 1. [Install Docker Engine](https://docs.docker.com/engine/install/) 2. (Linux users) Make sure you complete the [post-installation step](https://docs.docker.com/engine/install/linux-postinstall/). This is required for the correct operation of the command. 3. Ensure Docker Engine is up and running, and the socket is accessible. 4. Simply run `cargo contract build --verifiable`. This will pull the image with the version that corresponds to your `cargo-contract` crate version, perform a build, and write artifacts in the standard output directory. If everything is correct, you can verify the image version in the metadata file. It should contain a key-value `image` after the `contract` information: ```json "contract": { "name": "flipper", "version": "6.0.0", "authors": [ "Use Ink " ] }, "image": "use-ink/contracts-verifiable:6.0.0", ``` You are now ready to deploy your contract to a production chain. :::note The image is `amd64` based. Therefore, the build times can be significantly slower on Apple Silicon machines. To overcome the issue enable _Rosetta for x86/amd64 emulation_ in _Settings_ → _Features in development_ tab in Docker Desktop App. ::: ## Verifying contracts Similar to Etherscan, you want to ensure that the given contract bundle is indeed a copy of some well-known contract code. `cargo contract verify` allows you to verify the given cargo project against a reference contract bundle. Simply run `cargo contract verify ` in your contract's directory. If the reference contract was not built inside a Docker container, the command will compare the build info from the reference contract with the current environment to ensure a match in environment. :::warning If you are not using standardized verifiable builds. It is your responsibility to ensure deterministic environment both for build and verification of smart contracts. ::: If the build info from the `.contract` file matches the environment and a Docker `image` is present in metadata, `cargo contract` will build the project inside the specified `image` Docker container. Otherwise, a local build is carried out. Upon completion, the built contract bundle is compared to the reference one and the result is returned. ## Advanced usage If you would like to carry out other operations inside a deterministic environment you can use our Docker image. It is available on [Docker Hub](https://hub.docker.com/repository/docker/useink/contracts-verifiable/general). The entry point is set to `cargo contract` allowing you to specify other commands to be executed. :::tip If you are building a multi-contract project, make sure you are executing the build in the parent directory in order to mount the directory of all contracts to be visible. Specify a relative manifest path to the root contract: ```bash cargo contract build --verifiable --manifest-path ink-project-a/Cargo.toml ``` ::: You can find a Dockerfile and further documentation on image usage in [the `cargo-contract` repository](https://github.com/use-ink/cargo-contract/tree/master/build-image) ```` ## File: docs/basics/cross-contract-calling.md ````markdown --- title: Cross-Contract Calling slug: /basics/cross-contract-calling hide_title: true --- ![Cross Contract Title Picture](/img/title/cross-contract.svg) # Cross-Contract Calls In ink! contracts it is possible to call messages and constructors of other on-chain contracts. There are a few approaches to performing these cross-contract calls in ink!: 1. Contract references (i.e `ContractRef`) 2. Builders (i.e `CreateBuilder` and `CallBuilder`) :::note In general, contract references should be preferred over builders because they provide higher-level type-safe interfaces. Only use builders if you need to manipulate low-level call parameters. ::: ## Contract References Contract references are wrapper types that can be used for interacting with an on-chain/"callee" contract using a high-level type-safe interface. They are either statically generated by the ink! code generation (for contract dependencies), or they can be manually defined as dynamic interfaces using the [`#[ink::contract_ref]` attribute][contract-ref-attr]. [contract-ref-attr]: ../macros-attributes/contract_ref.md ### Manually defined contract references See our section on using the [`#[ink::contract_ref]` attribute][contract-ref-attr] for a detailed description and examples of how to manually define the dynamic interface for an on-chain/"callee" contract, and use the generated contract reference for calling the on-chain/"callee" contract in a type-safe manner. :::caution A downside to manually defined contract references is that mistakes in the interface definition are not caught at compile-time. It's therefore important to make sure such interfaces are properly tested using [end-to-end testing][e2e-test] before contracts are deployed on-chain. ::: [e2e-test]: ../testing/e2e.md ### Statically generated contract references To use statically generated contract references, you need to import the contract you want to call as a dependency of your own contract. This means that this approach cannot be used if you want to interact with a contract that is either built in another language (e.g. Solidity), or has no publicly available package/crate. For those cases, you will need to use either [manually defined contract references](#manually-defined-contract-references) using the [`#[ink::contract_ref]` attribute][contract-ref-attr] (recommended), or the [`Builders`](#builders) approach instead. #### `BasicContractRef` walkthrough We will walk through the [`cross-contract-calls`][example] example in order to demonstrate how cross-contract calls using contract references work. The general workflow will be: 1. Prepare `OtherContract` to be imported to other contracts 2. Import `OtherContract` into `BasicContractRef` 3. Upload `OtherContract` on-chain 4. Instantiate `OtherContract` using `BasicContractRef` 5. Call `OtherContract` using `BasicContractRef` [example]: https://github.com/use-ink/ink-examples/tree/master/cross-contract-calls #### Prepping `OtherContract` We need to make sure that the ink! generated contract ref for `OtherContract` is available to other pieces of code. We do this by re-exporting the contract reference as follows: ```rust pub use self::other_contract::OtherContractRef; ``` :::info We intend to automatically generate this re-export in future releases of ink! v6. ::: :::note In ["all" ABI mode][abi-all], contract references are generated for both ink!/native and Solidity ABI calling conventions, with the Solidity ABI specific contract reference named with an additional `Sol` suffix (e.g. `ContractRefSol` for a contract named `Contract`). Note that, this `Sol` suffix is not necessary in ["sol" ABI mode][abi-sol] (i.e. for a contract named `Contract`, `ContractRef` will use the Solidity ABI calling conventions in "sol" ABI mode). ::: [abi-all]: ./abi/all.md [abi-sol]: ./abi/solidity.md #### Importing `OtherContract` Next, we need to import `OtherContract` to our `BasicContractRef` contract. First, we add the following lines to our `Cargo.toml` file: ```toml # In `basic_contract_ref/Cargo.toml` other_contract = { path = "other_contract", default-features = false, features = ["ink-as-dependency"] } # -- snip -- [features] default = ["std"] std = [ "ink/std", # -- snip -- "other_contract/std", ] ``` Two things to note here: 1. If we don't specify the `ink-as-dependency` feature we will end up with linking errors. 2. If we don't enable the `std` feature for `std` builds we will not be able to generate our contract's metadata. #### Wiring `BasicContractRef` First, we will import the contract reference of `OtherContract`, and declare the reference to be part of our storage struct. ```rust // In `basic_contract_ref/lib.rs` use other_contract::OtherContractRef; #[ink(storage)] pub struct BasicContractRef { other_contract: OtherContractRef, } ``` Next, we to add a way to instantiate `OtherContract`. We do this from the constructor of our of contract. ```rust // In `basic_contract_ref/lib.rs` #[ink(constructor)] pub fn new(other_contract_code_hash: Hash) -> Self { let other_contract = OtherContractRef::new(true) .code_hash(other_contract_code_hash) .endowment(0) .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) .instantiate(); Self { other_contract } } ``` Note that for instantiating a contract we need access to the uploaded on-chain `code_hash`. We will get back to this later. Once we have an instantiated reference to `OtherContract` we can call its messages just like normal Rust methods! ```rust // In `basic_contract_ref/lib.rs` #[ink(message)] pub fn flip_and_get(&mut self) -> bool { self.other_contract.flip(); self.other_contract.get() } ``` #### Uploading `OtherContract` You will need the [`ink-node`](https://github.com/use-ink/ink-node) running in the background for the next steps. We can upload `OtherContract` using `cargo-contract` as follows: ``` # In the `basic_contract_ref` directory cargo contract build --manifest-path other_contract/Cargo.toml cargo contract upload --manifest-path other_contract/Cargo.toml --suri //Alice -x ``` If successful, this will output in a `code_hash` similar to: ``` Code hash "0x74a610235df4ff0161f0247e4c9d73934b70c1520d24ef843f9df9fcc3e63caa" ``` We can then use this `code_hash` to instantiate our `BasicContractRef` contract. #### Instantiating `OtherContract` through `BasicContractRef` We will first need to instantiate `BasicContractRef`. ``` # In the `basic_contract_ref` directory cargo contract build cargo contract instantiate \ --constructor new \ --args 0x74a610235df4ff0161f0247e4c9d73934b70c1520d24ef843f9df9fcc3e63caa \ --suri //Alice --salt $(date +%s) ``` If successful, this will output in a contract address for `BasicContractRef` similar to: ``` Contract 5CWz6Xnivp9PSoZq6qPRP8xVAShZgtNVGTCLCsq3qzqPV7Rq ``` #### Calling with `OtherContract` through `BasicContractRef` Finally, we can call the `OtherContract` methods through `BasicContractRef` as follows: ``` cargo contract call --contract 5CWz6Xnivp9PSoZq6qPRP8xVAShZgtNVGTCLCsq3qzqPV7Rq \ --message flip_and_get --suri //Alice --dry-run ``` Which will result in something like: ``` Result Success! Reverted false Data Ok(true) ``` ## Builders The [`CreateBuilder`][create-builder] and [`CallBuilder`][call-builder] offer low-level, flexible interfaces for performing cross-contract calls. The `CreateBuilder` allows you to instantiate already uploaded contracts, and the `CallBuilder` allows you to call messages on instantiated contracts. [create-builder]: https://use-ink.github.io/ink/ink_env/call/struct.CreateBuilder.html [call-builder]: https://use-ink.github.io/ink/ink_env/call/struct.CallBuilder.html :::caution A downside to low-level `CreateBuilder`s and `CallBuilder`s is that mistakes in the generated calls (e.g. wrong selectors, wrong order and/or types of arguments e.t.c) are not caught at compile-time. It's therefore important to make sure such calls are properly tested using [end-to-end testing][e2e-test] before contracts are deployed on-chain. ::: ### CreateBuilder The `CreateBuilder` offers an easy way for you to **instantiate** a contract. Note that you'll still need this contract to have been previously uploaded. :::note For a refresher on the difference between `upload` and `instantiate` [see here](../getting-started/deploying.md). ::: In order to instantiate a contract you need a reference to your contract, just like in [the previous section](#contract-references). Below is an example of how to instantiate a contract using the `CreateBuilder`. We will: - instantiate the uploaded contract with a `code_hash` of `0x4242...` - with no gas limit specified (`0` means unlimited) - sending `10` units of transferred value to the contract instance - instantiating with the `new` constructor - with the following arguments - a `u8` with value `42` - a `bool` with value `true` - an array of 32 `u8` with value `0x10` - generate the address (`AccountId`) using the specified `salt_bytes` - and we expect it to return a value of type `MyContractRef` ```rust use contract::MyContractRef; let my_contract: MyContractRef = build_create::() .code_hash(Hash::from([0x42; 32])) .ref_time_limit(0) .endowment(10) .exec_input( ExecutionInput::new(Selector::new(ink::selector_bytes!("new"))) .push_arg(42) .push_arg(true) .push_arg(&[0x10u8; 32]) ) .salt_bytes(&[0xDE, 0xAD, 0xBE, 0xEF]) .returns::() .instantiate(); ``` Since `CreateBuilder::instantiate()` returns a contract reference, we can use this contract reference to call messages just like in the [previous section](#contract-references). :::note To instantiate a contract that uses a different [ABI][abi] than your contract, you can instead use an ABI-specific utility (i.e. `build_create_sol` or `build_create_ink`) ```rust build_create_sol::() ``` ::: [abi]: ./abi/overview.md ### CallBuilder The `CallBuilder` gives you a couple of ways to call messages from other contracts. There are two main approaches to this: `Call`s and `DelegateCall`s. We will briefly cover both here. #### CallBuilder: Call When using `Call`s the `CallBuilder` requires an already instantiated contract. We saw an example of how to use the `CreateBuilder` to instantiate contracts in the [previous section](#contract-references). Below is an example of how to call a contract using the `CallBuilder`. We will: - make a regular `Call` - to a contract at the address `0x4242...` - with no gas limit specified (`0` means unlimited) - sending `10` units of transferred value to the contract instance - calling the `flip` message - with the following arguments - a `u8` with value `42` - a `bool` with value `true` - an array of 32 `u8` with value `0x10` - and we expect it to return a value of type `bool` ```rust let my_return_value = build_call::() .call(H160::from([0x42; 20])) .ref_time_limit(0) .transferred_value(10) .exec_input( ExecutionInput::new(Selector::new(ink::selector_bytes!("flip"))) .push_arg(42u8) .push_arg(true) .push_arg(&[0x10u8; 32]) ) .returns::() .invoke(); ``` :::caution Message arguments will be encoded in the order in which they are provided to the `CallBuilder`. This means that they should match the order (and type) they appear in the function signature. You will not get any feedback about this at compile-time, so it's important to make sure such calls are properly tested with [end-to-end testing][e2e-test] before contracts are deployed on-chain. ::: :::note To call messages from a contract that uses a different [ABI][abi] than your contract, you can instead use an ABI-specific utility (i.e. `build_call_sol` or `build_call_ink`). ```rust build_call_sol::() ``` You can see a full example of an ink! contract calling a Solidity ABI encoded contract in the ["CallBuilder Solidity" example below](#callbuilder-solidity). ::: #### CallBuilder: Delegate Call You can also use the `CallBuilder` to craft calls using `DelegateCall` mechanics. If you need a refresher on what delegate calls are, [see this article](https://medium.com/coinmonks/delegatecall-calling-another-contract-function-in-solidity-b579f804178c). In the case of `DelegateCall`s, we don't require an already instantiated contract. We only need the `code_hash` of an uploaded contract. Below is an example of how to delegate call a contract using the `CallBuilder`. We will: - make a `DelegateCall` - to a contract with a `code_hash` (not contract address!) of `0x4242...` - calling the `flip` message - with the following arguments - a `u8` with value `42` - a `bool` with value `true` - an array of 32 `u8` with value `0x10` - and we expect it to return an `i32` ```rust let my_return_value = build_call::() .delegate(H160::from([0x42; 20])) .exec_input( ExecutionInput::new(Selector::new(ink::selector_bytes!("flip"))) .push_arg(42u8) .push_arg(true) .push_arg(&[0x10u8; 32]) ) .returns::() .invoke(); ``` ### CallBuilder Solidity `CallBuilder` also allows you to call contracts that are Solidity ABI encoded. This enables interoperability between Solidity, ink!, and other Solidity ABI encoded contracts! This requires using a Solidity compatible function selector using a `keccak256` hash of the function signature. ```rust let my_return_value = build_call_sol::() .call(H160::from([0x42; 20])) .ref_time_limit(0) .transferred_value(10) .exec_input( ExecutionInput::new([0xcd, 0xe4, 0xef, 0xa9].into()) // solidity selector: keccak256("flip()") ) .returns::() .invoke(); ``` ### Builder Error Handling The `CreateBuilder` and the `CallBuilder` both offer error handling with the `try_instantiate()` and `try_invoke()` methods respectively. These allow contract developers to handle two types of errors: 1. Errors from the underlying execution environment (e.g the Contracts pallet) 2. Error from the programming language (e.g `LangError`s) See the documentation for [`try_instantiate`](https://use-ink.github.io/ink/ink_env/call/struct.CreateBuilder.html#method.try_instantiate), [`try_invoke`](https://use-ink.github.io/ink/ink_env/call/struct.CallBuilder.html#method.try_invoke-2), [`ink::env::Error`](https://use-ink.github.io/ink/ink_env/enum.Error.html) and [`ink::LangError`](https://use-ink.github.io/ink/ink/enum.LangError.html) for more details on proper error handling. ```` ## File: docs/basics/env-functions.md ````markdown --- title: Environment Functions slug: /basics/environment-functions --- ![Env Function Title Picture](/img/title/env-function.svg) # Environment Functions ink! exposes a number of handy environment functions. A full overview [is found here](https://use-ink.github.io/ink/ink_env/#functions). In an `#[ink(constructor)]` use `Self::env()` to access those, in an `#[ink(message)]` use `self.env()`. So `Self::env().caller()` or `self.env().caller()`. Some handy functions include: * [`caller()`](https://use-ink.github.io/ink/ink_env/fn.caller.html): Returns the address of the caller of the executed contract. * [`address()`](https://use-ink.github.io/ink/ink_env/fn.address.html): Returns the address of the executed contract. * [`balance()`](https://use-ink.github.io/ink/ink_env/fn.balance.html): Returns the balance of the executed contract. * [`block_number()`](https://use-ink.github.io/ink/ink_env/fn.block_number.html): Returns the current block number. * [`emit_event(…)`](https://use-ink.github.io/ink/ink_env/fn.emit_event.html): Emits an event with the given event data. * [`transfer(…)`](https://use-ink.github.io/ink/ink_env/fn.transfer.html): Transfers value from the contract to the destination account ID. * [`hash_bytes(…)`](https://use-ink.github.io/ink/ink_env/fn.hash_bytes.html): Conducts the crypto hash of the given input and stores the result in output. * […and many more](https://use-ink.github.io/ink/ink_env/#functions). ```` ## File: docs/basics/environment.md ````markdown --- title: Chain Environment Types slug: /basics/chain-environment-types hide_title: true --- ![Environment Title Picture](/img/title/environment.svg) # Chain Environment Types ink! defines a trait [`Environment`](https://use-ink.github.io/ink/ink_env/trait.Environment.html) and also a default implementation of that trait ‒ [`DefaultEnvironment`](https://use-ink.github.io/ink/ink_env/enum.DefaultEnvironment.html). These are the types that ink! uses, if no explicit steps are taken: ```rust /// The fundamental types of the default configuration. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(TypeInfo))] pub enum DefaultEnvironment {} impl Environment for DefaultEnvironment { const MAX_EVENT_TOPICS: usize = 4; type AccountId = AccountId; type Balance = Balance; type Hash = Hash; type Timestamp = Timestamp; type BlockNumber = BlockNumber; type ChainExtension = NoChainExtension; type EventRecord = EventRecord; } ``` The context here is that you can use ink! on any blockchain that was built with the [Polkadot SDK](https://polkadot.com/platform/sdk) and includes the [`pallet-revive`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive) module. Chains built with the Polkadot SDK can decide on their own which types they want to use for e.g. the chain's block number or account id's. For example, chains that intend to be compatible to Ethereum typically use the same type as Ethereum for their `AccountId`. Most Polkadot SDK chains stay with the default types though and ink! just uses those by default as well. It is possible to configure a different environment in the contract macro ([documentation here](https://use-ink.github.io/ink/ink/attr.contract.html#header-arguments)) though: ```rust #[ink::contract(env = MyCustomTypes)] ``` :::caution If you write a contract for a chain that deviates from our default types (`DefaultEnvironment`), you have to make sure to configure that chain's `Environment` for your contract! ::: ```` ## File: docs/basics/events.md ````markdown --- title: Events slug: /basics/events hide_title: true --- ![Balloons 1 Title Picture](/img/title/balloons-1.svg) # Events An ink! smart contract may define events that it can emit during contract execution. Emitting events can be used by third party tools to query information about a contract's execution and state. ![Contract execution via transaction](/img/events-revive.svg) ## Example The following example ink! contract shows how an event `Transferred` is defined and emitted in the `#[ink(constructor)]`. ```rust #[ink::contract] mod erc20 { /// Defines an event that is emitted /// every time value is transferred. #[ink(event)] pub struct Transferred { from: Option, to: Option, value: Balance, } #[ink(storage)] pub struct Erc20 { total_supply: Balance, // more fields ... } impl Erc20 { #[ink(constructor)] pub fn new(initial_supply: Balance) -> Self { let caller = Self::env().caller(); Self::env().emit_event(Transferred { from: None, to: Some(caller), value: initial_supply, }); Self { total_supply: initial_supply } } #[ink(message)] pub fn total_supply(&self) -> Balance { self.total_supply } } } ``` See our [`ERC20 example contract`](https://github.com/use-ink/ink-examples/blob/main/erc20/lib.rs) for an elaborate example which uses events. ## Event Definition Since ink! version 5.0, events can be defined independently of the contract which emits them. Events can now be defined once and shared across multiple contracts. This is useful for events for contracts which conform to standards such as ERC-20: contract indexers/explorers are now able to group all e.g. `Transferred` events. This is how an event definition looks: ```rust use ink::primitives::AccountId; #[ink::event] pub struct Transferred { #[ink(topic)] from: Option, #[ink(topic)] to: Option, amount: u128, } ``` :::note Generics are [not currently supported](https://github.com/use-ink/ink/issues/2044), so the concrete types of `Environment` specific types such as `AccountId` must match up with the types used in the contract. ::: This definition can exist within a contract definition module (inline events), in a different module in the same crate or even in a different crate to be shared by multiple contracts. ### Legacy syntax for inline Event definitions Events defined within a `#[ink::contract]` module can continue to use the original syntax for an event definition, using the `#[ink(event)]` attribute. Under the covers this is simply expanded to the new top level `#[ink::event]` macro, so both events defined using the legacy style and using the new `event` attribute macro directly will behave exactly the same. ### Topics When an event is emitted, up to 4 topics (including the signature topic, if any) can be associated with it. The event is then indexed together with other events with the same topic value. An event's fields can be annotated with `#[ink(topic)]` (see example), which will result in a topic derived from the value of that field being emitted together with the event. Topics are a 32 byte array (`[u8; 32]`), and the topic value is encoded as follows: - If the SCALE encoded bytes of a field value are `<= 32`, then the encoded bytes are used directly as the topic value. If necessary, the topic value is padded on the right side with zero-bytes such that its length is 32 bytes. - For example, in the common case of indexing a field of type `AccountId`, where the default `AccountId` type is 32 bytes in length, the topic value will be the encoded account id itself. This makes it easy to filter for all events which have a topic of a specific `AccountId`. - If the size of the SCALE encoded bytes of the field value exceeds 32, then the encoded bytes are hashed using the `Blake2x256` hash function. :::note The topic encoding specification above only applies to native/ink! ABI encoded events. For Solidity ABI encoded events, topics (and event data) are encoded according to the [Solidity ABI specification for events][sol-abi-events] and [indexed event parameters][sol-abi-topics]. ::: [sol-abi-events]: https://docs.soliditylang.org/en/latest/abi-spec.html#events [sol-abi-topics]: https://docs.soliditylang.org/en/latest/abi-spec.html#encoding-of-indexed-event-parameters :::note Topics are a native concept in the Polkadot SDK, and can be queried via [`EventTopics`](https://docs.rs/frame-system/latest/frame_system/pallet/storage_types/struct.EventTopics.html) ::: ### How to choose which fields to make topics? A good rule of thumb is to ask yourself if somebody might want to search for this topic. For this reason the `amount` in the example `Transferred` event above was not made indexable ‒ there will most probably be a lot of different events with differing amounts each. ### Signature Topic By default all events have a signature topic. This allows indexing of all events of the same type, emitted by different contracts. The `#[ink::event]` macro generates a signature topic at compile time by hashing the name of the event concatenated with the *names of the types* of all the fields: ``` blake2b("Event(field1_type,field2_type)")` ``` So for our `Transferred` example it will be: ``` blake2b("Transferred(Option,Option,u128)")` ``` :::note The signature topic computation specification above only applies to native/ink! ABI encoded events. For Solidity ABI encoded events, the signature topic is computed as the event signature according to the [Solidity ABI specification for events][sol-abi-events]. ::: :::caution Important caveat: because the *name* of the field type is used, refactoring an event definition to use a type alias or a fully qualified type will change the signature topic, even though the underlying type is the same. Two otherwise identical definitions of an event with the same name and same field types but different field type names will have different signature topics. ::: When decoding events emitted from a contract, signature topics are now required to determine which type of event to decode into. ### Anonymous Events Events annotated with `anonymous` will not have a signature topic generated and published with the event. For inline events, this can be done by marking the event with the `anonymous` attribute e.g. ```rust #[ink(event, anonymous)] pub struct Event { .. } ``` or ```rust #[ink(event)] #[ink(anonymous)] pub struct Event { .. } ``` For events defined using the `#[ink::event]` macro, the `anonymous` flag needs to be added as an argument: ```rust #[ink::event(anonymous)] pub struct Event { .. } ``` Without a signature topic, indexers will not be able to index over the type of the event, which may be desirable for some contracts, and would be a small gas cost optimization if necessary. However, when interacting with the contract from a client, no signature topic means that another way is required to determine the type of the event to be decoded into (i.e. how do we know it is a `Transferred` event, not an `Approval` event. One way would be to try decoding for each type of event defined in the metadata of the contract until one succeeds. If calling a specific `message`, it may be known up front what type of event that message will raise, so the client code could just decode into that event directly. ## Emitting Events in a Constructor In a constructor events are emitted via `Self::env().emit_event()`. See this example: ```rust #[ink(constructor)] pub fn new(initial_value: Balance) -> Self { let caller = Self::env().caller(); let mut balances = HashMap::new(); balances.insert(caller, initial_supply); Self::env().emit_event(Transferred { from: None, to: Some(caller), amount: initial_supply }); Self { total_supply: initial_supply, balances } } ``` ## Emitting Events from Messages In a message events are emitted via `self.env().emit_event()`: ```rust #[ink(message)] pub fn transfer(&mut self, to: AccountId, amount: Balance) -> Result { let from = self.env().caller(); // implementation hidden self.env().emit_event(Transferred { from: Some(from), to: Some(to), amount }); Ok(()) } ``` :::note In ["all" ABI mode][abi-all], both an ink! and Solidity ABI encoded event are emitted for each call to `Self::env().emit_event()` or `self.env().emit_event()`. To emit a single event for a specific ABI, 2 additional ABI-specific utilities are provided in "all" ABI mode: - `emit_event_ink`: emits a single ink! ABI encoded event. - `emit_event_sol`: emits a single Solidity ABI encoded event. ::: [abi-all]: ./abi/all.md ## Cost of using Events When using events and topics, developers should be mindful of the costs associated. Firstly: if optimizing for contract size, using events will increase the size of the final code size. So minimizing or eliminating event usage where necessary will reduce contract size. The same can be said for the execution (aka gas) costs when using events. We recommend considering the cost of events when using them, and measuring the code size and gas costs with different usage patterns when optimizing. ```` ## File: docs/basics/gas.md ````markdown --- title: Gas slug: /basics/gas hide_title: true --- ![Gas Title Picture](/img/title/gas.svg) ## What is "Gas" in ink!? For ink!, the term Gas refers to the resources used by a contract call. It's important for smart contracts that the caller has to pay for any utilized resource. Those resources can be either storage space (for storing data in the contract's storage) or computational time (for executing the contract and its logic). The term Gas encompasses both of these resources: `Gas = (refTime, proofSize)`. The terms hereby refer to: `refTime`: The amount of computational time that can be used for execution, in picoseconds. `proofSize`: The amount of storage in bytes that a transaction is allowed to read. The term `refTime` comes from "reference time", referring to the Polkadot SDK Weights system, where computation time is benchmarked on reference hardware. You can read more details [here](https://docs.polkadot.com/polkadot-protocol/glossary/#weight). The term `proofSize` is only relevant for parachains on the [Polkadot](https://polkadot.network/) or [Kusama](https://kusama.network/) networks. _It can be ignored for standalone chains (like [Aleph Zero](https://alephzero.org/))._ On a high level, `proofSize` is the size of the proof that individual parachains send to the Polkadot or Kusama relay chain to allow re-executing their block for validation (this is called Proof of Validity). Phrased differently: Layer-1 chains send a proof of validity to a Layer-0 chain to validate the block. This Proof of Validity contains everything necessary to execute the block -- the code of each contract that is executed plus the storage each contract reads and writes. :::info Blockchains that support ink! are built using Polkadot SDK which uses the concept of Weight to describe the usage of resources. Specifically, the terms above come from the Polkadot SDK "Weights V2" system. For ink!, Gas is a synonym to the concept called "Weight" in this SDK. The Weights concept is similar to what smart contract developers might know from other ecosystems, but is more fine grained. It also tracks the utilized bandwidth, not just execution. For ink! smart contracts the utilized bandwidth is the `proofSize` explained above. We decided on using the term "Gas" to make onboarding easier for developers from other smart contract ecosystems. So: `Gas = Weight = (refTime, proofSize)`. ::: ```` ## File: docs/basics/mutating-values.md ````markdown --- title: Mutating Storage Values slug: /basics/mutating-values hide_title: true --- ![Storage Mutating Title Picture](/img/title/storage-mutating.svg) # Mutating Storage Values It's time to modify some storage! ## Mutable and Immutable Functions You may have noticed that the function template included `self` as the first parameter of the contract functions. It is through `self` that you gain access to all your contract functions and storage items. If you are simply _reading_ from the contract storage, you only need to pass `&self`. But if you want to _modify_ storage items, you will need to explicitly mark it as mutable, `&mut self`. ```rust impl MyContract { #[ink(message)] pub fn my_getter(&self) -> u32 { self.my_number } #[ink(message)] pub fn my_setter(&mut self, new_value: u32) { self.my_number = new_value; } } ``` ```` ## File: docs/basics/precompiles.md ````markdown --- title: Precompiles slug: /basics/precompiles hide_title: true --- ![Gas Title Picture](/img/title/gas.svg) ## Precompiles :::caution This section has not yet been created. ::: ```` ## File: docs/basics/reading-values.md ````markdown --- title: Reading Values from Storage slug: /basics/reading-values hide_title: true --- ![Storage Read Title Picture](/img/title/storage-read.svg) # Reading Values from Storage Reading from storage is where the fun begins! ## Contract Functions As you can see in the contract template, all of your contract functions are part of your contract module. ```rust impl MyContract { // Public and Private functions can go here } ``` ### Public and Private Functions In Rust, you can make as many implementations as you want. As a stylistic choice, we recommend breaking up your implementation definitions for your private and public functions: ```rust impl MyContract { /// Public function #[ink(message)] pub fn my_public_function(&self) { /* --snip-- */ } /// Private function fn my_private_function(&self) { /* --snip-- */ } /* --snip-- */ } ``` You can also choose to split things up however is most clear for your project. Note that all public functions must use the `#[ink(message)]` attribute. ## Getting a Value We already showed you how to initialize a storage value in the chapter [Storing Values](./storing-values.md). Getting the value is just as simple: ```rust impl MyContract { #[ink(message)] pub fn my_getter(&self) -> u32 { self.number } } ``` In Rust, if the last expression in a function does not have a semicolon it will be the return value. ```` ## File: docs/basics/selectors.md ````markdown --- title: Selectors hide_title: true slug: /basics/selectors --- ![Selector Hex Title Picture](/img/title/selector-hex.svg) :::note ink! v6 supports both the native ink! and [Solidity][sol-abi] ABI (Application Binary Interface) specifications for contract interactions (i.e. calling conventions used for message calls). When support for Solidity ABI calling conventions is enabled (see [here][abi-declaration] for details), Solidity ABI selectors for messages are **always** generated according to the [Solidity ABI specification for function selectors][sol-abi-selector]. So the specification below for message selector calculation only applies to native ink! ABI selectors. Learn more about ink!'s support for multiple ABIs [here][abi-support]. ::: [sol-abi]: https://docs.soliditylang.org/en/latest/abi-spec.html [sol-abi-selector]: https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector [abi-support]: ../basics/abi/overview.md [abi-declaration]: ../basics/abi/overview.md#declaring-the-abi # Selectors Selectors in ink! are a language agnostic way of identifying constructors and messages. They are four-byte hexadecimal strings which look something like: `0x633aa551`. You can find the selector of an ink! constructor or message in your [contract metadata](./metadata/overview.md) by looking for the `selector` field of the dispatchable you're interested in. Here is an example of how you can grab the message name and selector from your contract metadata using [`jq`](https://stedolan.github.io/jq/). ```bash cat target/ink/flipper.json | jq '.spec.messages[0] | "\(.label): \(.selector)"' "flip: 0x633aa551" ``` ## Selector Calculation If you do not have access to a contract's metadata, you can also calculate it yourself. The algorithm ink! uses is fairly straightforward: 1. Get _just_ the name of the constructor or message 2. Compute the `BLAKE2` hash of the name 3. Take the first four bytes of the hash as the selector Let's walk through a short example of what this looks like in practice. Consider the following message: ```rust #[ink(message)] fn frobinate(&mut self, fro: bool, bi: u32, nate: AccountId) -> bool { unimplemented!() } ``` To calculate the selector we: 1. Grab the name of the message, `frobinate` 2. Compute `BLAKE2("frobinate") = 0x8e39d7f22ef4f9f1404fe5200768179a8b4f2b67799082d7b39f6a8ca82da8f1` 3. Grab the first four bytes, `0x8e39d7f2` ## Selector Calculation: ink! Traits These rules change a bit if you define any messages using the `[ink::trait_definition]` [macro](./trait-definitions.md). For our first step, instead of taking _just_ the message name, we now also add the _trait name_ to the selector calculation. ``` cat target/ink/trait-flipper.json | jq '.spec.messages[0] | "\(.label): \(.selector)"' "Flip::flip: 0xaa97cade" ``` Let's see what this would look like in practice. Consider the following trait: ```rust #[ink::trait_definition] pub trait Frobinate { fn frobinate(&mut self, fro: bool, bi: u32, nate: AccountId) -> bool; } -- snip -- impl Frobinate for Contract { #[ink(message)] fn frobinate(&mut self, fro: bool, bi: u32, nate: AccountId) -> bool { unimplemented!() } } ``` To calculate the selector we: 1. Grab the name of the trait **and** the name of the message, `Frobinate::frobinate` 2. Compute `BLAKE2("Frobinate::frobinate") = 0x8915412ad772b2a116917cf75df4ba461b5808556a73f729bce582fb79200c5b` 3. Grab the first four bytes, `0x8915412a` :::tip Don't worry if you're not able to calculate the `BLAKE2` hash of a string by hand. You can use [Shawn's Substrate Utilities](https://www.shawntabrizi.com/substrate-js-utilities/) to do it for you! ::: ```` ## File: docs/basics/storing-values.md ````markdown --- title: Storing Values slug: /basics/storing-values hide_title: true --- ![Storage Title Picture](/img/title/storage.svg) # Storing Values Here is how you store simple values in storage: ```rust #[ink(storage)] pub struct MyContract { // Store a bool my_bool: bool, // Store some number my_number: u32, } /* --snip-- */ ``` ## Supported Types ink! contracts may store types that are encodable and decodable with the [Parity SCALE Codec](https://github.com/paritytech/parity-scale-codec) which includes most Rust common data types such as `bool`, `u{8,16,32,64,128}`, `i{8,16,32,64,128}`, `String`, tuples, and arrays. Furthermore, ink! provides [Polkadot SDK](https://polkadot.com/platform/sdk) specific types like `AccountId`, `Balance`, and `Hash` to smart contracts as if they were primitive types. ### String, Vector and More The [`ink_prelude`](https://use-ink.github.io/ink/ink_prelude/) crate provides an efficient approach to import commonly used Rust types such as `String` and `Vec`, ensuring safe usage within an ink! contract. This simplifies the type referencing process between the `std` and `no_std` environments. Typically, these types are defined within the `std` crate in the `std` environment, and the `alloc` crate in the `no_std` environment. Given that ink! smart contract code is compiled in both environments (`no_std` for production and `std` for unit tests), developers might find themselves writing intricate conditional compilation macros. The `ink_prelude` crate conveniently re-exports these types, eliminating this complexity. You can use the prelude definitions like this: ```rust #[ink::contract] mod MyContractWithStringsAndArrays { use ink::prelude::string::String; use ink::prelude::vec::Vec; #[ink(storage)] pub struct MyContract { // Store some String my_string: String, // Store some u32 in a vec my_vector: Vec, } /* --snip-- */ } ``` ### Mapping ink! also provides a `Mapping` storage type. You can read more about it [here](../datastructures/mapping.md). ### Polkadot SDK Types Here is an example of how you would store substrate types `AccountId`, `Balance` and `Hash`: ```rust #[ink::contract] mod MyContract { // Our struct will use those default ink! types #[ink(storage)] pub struct MyContract { // Store some AccountId my_account: AccountId, // Store some Balance my_balance: Balance, // Store some Hash my_hash: Hash, } /* --snip-- */ } ``` ### Enum Enum can be used as a datatype as well. It's use in the example in the [Struct](#struct) section. ```rust pub enum Status { /// An auction has not started yet. NotStarted, /// We are in the starting period of the auction, collecting initial bids. OpeningPeriod, /// We are in the ending period of the auction, where we are taking snapshots /// of the winning bids. } ``` ### Struct You can even combine all the above mentioned types in a custom `struct` which you can then store in the contract's storage. ```rust mod MyContract { use ink::prelude::string::String; use ink::prelude::vec::Vec; pub struct Auction { /// Branded name of the auction event. name: String, /// Some hash identifying the auction subject. subject: Hash, /// Auction status. status: Status, // Enum: Usage shown in next section /// Candle auction can have no winner. /// If auction is finalized, that means that the winner is determined. finalized: bool, /// vector vector: Vec, } #[ink(storage)] pub struct MyContract { // Store Auctions in a vec auctions: Vec, } } ``` The values of an enum should be referenced as `Status::OpeningPeriod`. ## Initializing Storage in Constructors Constructors are how values get initialized. Every ink! smart contract must have a constructor which is run once when a contract is created. ink! smart contracts can have multiple constructors: Note that if you have a contract whose storage contains `Mapping'`s you will need to use `ink_lang::utils::initialize_contract` in your constructor. See the [`Mapping` documentation](../datastructures/mapping.md) for more details. ```rust #[ink::contract] mod mycontract { #[ink(storage)] pub struct MyContract { number: u32, } impl MyContract { /// Constructor that initializes the `u32` value to the given `init_value`. #[ink(constructor)] pub fn new(init_value: u32) -> Self { Self { number: init_value, } } /// Constructor that initializes the `u32` value to the `u32` default. #[ink(constructor)] pub fn default() -> Self { Self { number: Default::default(), } } /* --snip-- */ } } ``` ```` ## File: docs/basics/trait-definitions.md ````markdown --- title: Trait Definitions slug: /basics/trait-definitions hide_title: true --- ![Text/trait Title Picture](/img/title/text/trait.svg) Through the `#[ink::trait_definition]` proc. macro it is now possible to define your very own trait definitions that are then implementable by ink! smart contracts. This allows to define shared smart contract interfaces to different concrete implementations. Note that this ink! trait definition can be defined anywhere, even in another crate! ## Example ### Definition Defined in the `base_erc20.rs` module. ```rust #[ink::trait_definition] pub trait BaseErc20 { /// Returns the total supply. #[ink(message)] fn total_supply(&self) -> Balance; /// Transfers `amount` from caller to `to`. #[ink(message, payable)] fn transfer(&mut self, to: AccountId, amount: Balance); } ``` ### Implementation An ink! smart contract definition can then implement this trait definition as follows: ```rust #[ink::contract] mod erc20 { use base_erc20::BaseErc20; #[ink(storage)] pub struct Erc20 { total_supply: Balance, // more fields ... } impl Erc20 { /// Creates a new ERC-20 contract and initializes it with the initial supply for the instantiator. #[ink(constructor)] fn new(initial_supply: Balance) -> Self { // implementation ... } } impl BaseErc20 for Erc20 { #[ink(message)] fn total_supply(&self) -> Balance { // implementation ... } #[ink(message, payable)] fn transfer(&mut self, to: AccountId, amount: Balance) { // implementation ... } } } ``` ### Usage Calling the above `Erc20` explicitly through its trait implementation can be done just as if it was normal Rust code: ```rust // --- Instantiating the ERC-20 contract: // let mut erc20 = ::new(1000); // --- Is just the same as: use base_erc20::BaseErc20; let mut erc20 = Erc20::new(1000); // --- Retrieving the total supply: // assert_eq!(::total_supply(&erc20), 1000); // --- Is just the same as: use base_erc20::BaseErc20; assert_eq!(erc20.total_supply(), 1000); ``` See our [`ERC20-Trait example contract`](https://github.com/use-ink/ink-examples/blob/main/trait-erc20/lib.rs) for an elaborate example which uses trait definitions. ## Limitations There are still many limitations to ink! trait definitions and trait implementations. For example, it is not possible to define associated constants or types or have default implemented methods. These limitations exist because of technical intricacies, however, please expect that many of those will be tackled in future ink! releases. ```` ## File: docs/basics/upgradeability.md ````markdown --- title: Upgradeable Contracts slug: /basics/upgradeable-contracts hide_title: true --- ![Upgradeable Contract Title Picture](/img/title/upgradeable-contract.svg) # Upgradeable Contracts Even though smart contracts are intended to be immutable by design, it is often necessary to perform an upgrade of a smart contract. The developer may need to fix a critical bug or introduce a new feature. ink! supports different upgrade strategies that we describe on this page. ## Proxy Forwarding This method relies on the ability of contracts to proxy calls to other contracts. ### Properties - Forwards any call that does not match a selector of itself to another contract. - The other contract needs to be deployed on-chain. - State is stored in the storage of the contract to which calls are forwarded. ``` User ---- tx ---> Proxy ----------> Implementation_v0 | ------------> Implementation_v1 | ------------> Implementation_v2 ``` ### Example Our proxy contract will have these 2 storage fields: ```rust #[ink(storage)] pub struct Proxy { /// The `AccountId` of a contract where any call that does not match a /// selector of this contract is forwarded to. forward_to: AccountId, /// The `AccountId` of a privileged account that can update the /// forwarding address. This address is set to the account that /// instantiated this contract. admin: AccountId, } ``` We then need a way to change the address of a contract to which we forward calls to and the actual message selector to proxy the call: ```rust impl Proxy { /// Changes the `AccountId` of the contract where any call that does /// not match a selector of this contract is forwarded to. /// /// # Note /// Only one extra message with a well-known selector `@` is allowed. #[ink(message, selector = @)] pub fn change_forward_address(&mut self, new_address: AccountId) { assert_eq!( self.env().caller(), self.admin, "caller {:?} does not have sufficient permissions, only {:?} does", self.env().caller(), self.admin, ); self.forward_to = new_address; } /// Fallback message for a contract call that doesn't match any /// of the other message selectors. /// /// # Note: /// /// - We allow payable messages here and would forward any optionally supplied /// value as well. /// - If the self receiver were `forward(&mut self)` here, this would not /// have any effect whatsoever on the contract we forward to. #[ink(message, payable, selector = _)] pub fn forward(&mut self) -> u32 { ink::env::call::build_call::() .call(self.forward_to) .transferred_value(self.env().transferred_value()) .call_flags( ink::env::CallFlags::default() .set_forward_input(true) .set_tail_call(true), ) .invoke() .unwrap_or_else(|err| { panic!( "cross-contract call to {:?} failed due to {:?}", self.forward_to, err ) }); unreachable!( "the forwarded call will never return since `tail_call` was set" ); } } ``` :::tip Take a look at the selector pattern in the attribute macro: by declaring `selector = _` we specify that all other messages should be handled by this message selector. ::: Using this pattern, you can introduce other message to your proxy contract. Any messages that are not matched in the proxy contract will be forwarded to the specified contract address. ## Delegating execution to foreign Contract Code with `delegate_call` Similar to proxy-forwarding we can delegate execution to another code hash uploaded on-chain. ### Properties - Delegates any call that does not match a selector of itself to another contract. - Code is required to be uploaded on-chain, but is not required to be instantiated. - State is stored in the storage of the original contract which submits the call. - Storage layout must be identical between both contract codes. ``` (Storage of Contract A) User ---- tx ---> Contract A ----------> Code_v0 | ^ | | ⌊_____________________⌋ Storage is delegated to ``` ### Example Suppose we have defined of the caller contract as following: ```rust #[ink(storage)] pub struct Delegator { addresses: Mapping>, counter: i32, } ``` Then let's define two messages that separately calls to update `addresses` and `counter` separately: ```rust /// Increment the current value using delegate call. #[ink(message)] pub fn inc_delegate(&self, contract_addr: ink::H160) { let selector = ink::selector_bytes!("inc"); let _ = build_call::() .delegate(contract_addr) // if the receiver is set to `&mut self`, // then any changes made in `inc_delegate()` before the delegate call // will be persisted, and any changes made within delegate call will be discarded. // Therefore, it is advised to use `&self` receiver with a mutating delegate call, // or `.set_tail_call(true)` to flag that any changes made by delegate call should be flushed into storage. // .call_flags(CallFlags::default().set_tail_call(true)) .exec_input(ExecutionInput::new(Selector::new(selector))) .returns::<()>() .try_invoke(); } /// Adds entry to `addresses` using delegate call. /// Note that we don't need `set_tail_call(true)` flag /// because `Mapping` updates the storage instantly on-demand. #[ink(message)] pub fn add_entry_delegate(&mut self, contract_addr: ink::H160) { let selector = ink::selector_bytes!("append_address_value"); let _ = build_call::() .delegate(contract_addr) .exec_input(ExecutionInput::new(Selector::new(selector))) .returns::<()>() .try_invoke(); } ``` ink! provides an intuitive call builder API for you to compose your call. As you can see that `inc_delegate()` can be built a call in slightly different manner than `add_entry_delegate()`. That's because if the delegated code modifies layout-full storage (i.e. it contains at least non-`Lazy`, non-`Mapping` field), either the receiver should be set to `&self` or the `.set_tail_call(true)` flag of `CallFlags` needs to be specified, and the storage layouts must match. This is due to the way ink! execution call stack is operated. Non-`Lazy`, non-`Mapping` field are first loaded into the memory. If `&mut self` receiver is used, then when delegate call is completed, the original state before the call will be persisted and flushed into the storage. Therefore, `.set_tail_call(true)` needs to be set to indicate that, that delegate call's storage context is the final (i.e. _tail) one that needs to be flushed. This also makes any code after the delegate call unreachable. With `&self` receiver, `.set_tail_call(true)` is not required since no storage flushing happens at the end of the original caller's function. (see [Stack Exchange Answer](https://substrate.stackexchange.com/a/3352/3098) for details on how changes are flushed into storage). :::note Key compatibility If the delegated code modifies `Lazy` or `Mapping` field, the keys must be identical and `.set_tail_call(true)` is optional regardless of the function receiver. This is because `Lazy` and `Mapping` interact with the storage directly instead of loading and flushing storage states. ::: Now let's look at the "delegatee" code: ```rust #[ink::contract] pub mod delegatee { use ink::storage::{ traits::ManualKey, Mapping, }; #[ink(storage)] pub struct Delegatee { // `ManualKey` must be the same as in the original contract. addresses: Mapping>, counter: i32, // Uncommenting below line will break storage compatibility. // flag: bool, } impl Delegatee { /// When using the delegate call. You only upload the code of the delegatee /// contract. However, the code and storage do not get initialized. /// /// Because of this. The constructor actually never gets called. #[allow(clippy::new_without_default)] #[ink(constructor)] pub fn new() -> Self { unreachable!( "Constructors are not called when upgrading using `set_code_hash`." ) } /// Increments the current value. #[ink(message)] pub fn inc(&mut self) { self.counter = self.counter.checked_add(2).unwrap(); } /// Adds current value of counter to the `addresses` #[ink(message)] pub fn append_address_value(&mut self) { let caller = self.env().caller(); self.addresses.insert(caller, &self.counter); } } } ``` As you can see, delegatee's code looks like a normal ink! Smart Contract with some important features: - Storage layout is identical to the original contract's storage - `addresses` mapping key is identical - Constructor does not have any logic, as the code is never instantiated. (It can be, but plays no effect on the execution) ## Note on the usage of wildcard selectors When working with cross-contract calls, developers are required to be aware of the some important changes. Since ink! 5 we have restricted the usage of the wildcard selector due to [security reasons](https://blog.openzeppelin.com/security-review-ink-cargo-contract#custom-selectors-could-facilitate-proxy-selector-clashing-attacks). :::danger Beware Due to [IIP-2](https://github.com/use-ink/ink/issues/1676), ink! only allows to contain a single message with a well-known selector `@` when the other message with the wildcard selector `_` is defined. ::: See [example](https://github.com/use-ink/ink-examples/tree/main/wildcard-selector) for illustration on how it can be used in practice. ## Note on `CallFlags` `CallFlags` provide fine-grained control over the cross-contract execution. Some useful properties: - Re-entry is disable by default. It can be enabled with `.set_allow_reentry(true)` flag. - The call execution context is returned to the caller by default. You can finish execution in the callee with `.set_tail_call(true)` flag. - `.set_clone_input(true)` clones the input of the caller's messages. It can be used with when `.set_tail_call(false)`. - `.set_forward_input(true)` consumes the input of the caller's message which can be used after. It can be used with when `.set_tail_call(true)`. ## Replacing Contract Code with `set_code_hash()` Following [Polkadot SDK's runtime upgradeability](https://docs.polkadot.com/develop/parachains/maintenance/runtime-upgrades/) philosophy, ink! also supports an easy way to update your contract code via the special function [`set_code_hash()`](https://use-ink.github.io/ink/ink_env/fn.set_code_hash.html). ### Properties - Updates the contract code using `set_code_hash()`. This effectively replaces the code which is executed for the contract address. - The other contract needs to be deployed on-chain. - State is stored in the storage of the originally instantiated contract. ### Example Just add the following function to the contract you want to upgrade in the future. ```rust /// Modifies the code which is used to execute calls to this contract address (`AccountId`). /// /// We use this to upgrade the contract logic. We don't do any authorization here, any caller /// can execute this method. In a production contract you would do some authorization here. #[ink(message)] pub fn set_code(&mut self, code_hash: [u8; 32]) { ink::env::set_code_hash(&code_hash).unwrap_or_else(|err| { panic!( "Failed to `set_code_hash` to {:?} due to {:?}", code_hash, err ) }); ink::env::debug_println!("Switched code hash to {:?}.", code_hash); } ``` ### Storage Compatibility It is the developer's responsibility to ensure that the new contract's storage is compatible with the storage of the contract that is replaced. :::danger Beware You should not change the order in which the contract state variables are declared, nor their type! Violating the restriction will not prevent a successful compilation, but will result in **the mix-up of values** or **failure to read the storage correctly**. This can be a result of severe errors in the application utilizing the contract. ::: If the storage of your contract looks like this: ```rust #[ink(storage)] pub struct YourContract { x: u32, y: bool, } ``` The procedures listed below will make it ***invalid*** Changing the order of variables: ```rust #[ink(storage)] pub struct YourContract { y: bool, x: u32, } ``` Removing an existing variable: ```rust #[ink(storage)] pub struct YourContract { x: u32, } ``` Changing the type of a variable: ```rust #[ink(storage)] pub struct YourContract { x: u64, y: bool, } ``` Introducing a new variable before any of the existing ones: ```rust #[ink(storage)] pub struct YourContract { z: Vec, x: u32, y: bool, } ``` ### A little note on the determinism of contract addresses :::note If your contract utilizes `set_code_hash`, it no-longer holds a deterministic address assumption. _You can no longer assume that a contract address identifies a specific code hash._ ::: ## Examples Examples of upgradable contracts can be found in [our contract examples repository](https://github.com/use-ink/ink-examples/tree/main/upgradeable-contracts). ```` ## File: docs/basics/xcm.md ````markdown --- title: XCM slug: /basics/xcm hide_title: true --- ![Xcm Title Picture](/img/title/xcm.svg) # Cross-Consensus Messaging (XCM) XCM allows for cross-chain communication, enabling ink! smart contract to interact with other chains. You can learn more about XCM in the [Polkadot Wiki](https://wiki.polkadot.network/docs/learn/xcm). We have an example contract that demonstrates how to use XCM from ink!: [`contract-xcm`](https://github.com/use-ink/ink-examples/tree/main/contract-xcm). The documentation of the relevant functions can be found here: * [`xcm_send`](https://use-ink.github.io/ink/ink_env/fn.xcm_send.html) * [`xcm_weigh`](https://use-ink.github.io/ink/ink_env/fn.xcm_weigh.html) * [`xcm_execute`](https://use-ink.github.io/ink/ink_env/fn.xcm_execute.html) :::note In ink! v6, you need to enable the `xcm` feature in your contract's `Cargo.toml` to use the XCM functions. ```toml [dependencies] ink = { version = "6.0.0-beta", default-features = false, features = ["xcm"] } ``` ::: ## `xcm_execute` The [`xcm_execute`](https://use-ink.github.io/ink/ink/struct.EnvAccess.html#method.xcm_execute) function executes the XCM locally. It first checks the message to ensure that no barriers or filters will block the execution, and then executes it locally, using the contract's account as the origin. The following code snippet demonstrates how to use `xcm_execute` to perform a [reserve-backed transfer](https://wiki.polkadot.network/docs/learn/xcm/journey/transfers-reserve#1-initiatereservewithdraw): ```rust #[ink(message)] pub fn reserve_transfer( &mut self, amount: Balance, fee: Balance, ) -> Result<(), RuntimeError> { // The beneficiary of the transfer. // Here, the beneficiary is the caller's account on the relay chain. let caller_account_id = self.env().to_account_id(self.env().caller()); let beneficiary: Location = AccountId32 { network: None, id: caller_account_id.0, }.into(); // Create an XCM message. let message: Xcm<()> = Xcm::builder_unsafe() // Withdraw the relay's native token derivative from the // contract's account. .withdraw_asset((Parent, amount)) // The `initiate_reserve_withdraw` instruction takes the // derivative token from the holding register and burns it. // It then sends the nested XCM to the reserve in this // example, the relay chain. // Upon receiving the XCM, the reserve will withdraw the // asset from our chain's sovereign account, and deposit // on the caller's account. .initiate_reserve_withdraw( All, Parent, Xcm::builder_unsafe() .buy_execution((Here, fee), Unlimited) .deposit_asset(All, beneficiary) .build(), ) .build(); let msg = VersionedXcm::V5(message); let weight = self.env().xcm_weigh(&msg).expect("`xcm_weigh` failed"); self.env() .xcm_execute(&msg, weight) .map_err(|_| RuntimeError::XcmExecuteFailed) } ``` ## `xcm_send` The [`xcm_send`](https://use-ink.github.io/ink/ink_env/fn.xcm_send.html) function enables sending XCM to be executed by another chain. Messages sent originate from the contract's account. Consequently, the receiving chain will process the message using the contract's sovereign account as the origin. The following example demonstrates how to use `xcm_send`. In this example, we send an XCM to the relay chain. This XCM will execute using the contract's sovereign account as the origin of the call. It will then transfer, some `value` from this account to the caller's account on the relay chain. ```rust #[ink(message)] pub fn send_funds( &mut self, value: Balance, fee: Balance, ) -> Result<(), RuntimeError> { // The destination of the XCM message. Assuming we run the contract // on a parachain, the parent will be the relay chain. let destination: ink::xcm::v5::Location = ink::xcm::v5::Parent.into(); // The asset to be sent, since we are sending the XCM to the relay chain, // this represents `value` amount of the relay chain's native asset. let asset: Asset = (Here, value).into(); // The beneficiary of the asset. // Here, the beneficiary is the caller's account on the relay chain. let caller_account_id = self.env().to_account_id(self.env().caller()); let beneficiary = AccountId32 { network: None, id: caller_account_id.0, }; // Create an XCM message let message: Xcm<()> = Xcm::builder() // Withdraw the asset from the origin (the sovereign account of the // contract on the relay chain) .withdraw_asset(asset.clone()) // Buy execution to pay the fee on the relay chain .buy_execution((Here, fee), WeightLimit::Unlimited) // Deposit the asset to the caller's account on the relay chain .deposit_asset(asset, beneficiary) .build(); // Send the constructed XCM message to the relay chain. self.env() .xcm_send( &VersionedLocation::V5(destination), &VersionedXcm::V5(message), ) .map_err(|_| RuntimeError::XcmSendFailed) } ``` ```` ## File: docs/datastructures/custom.md ````markdown --- title: Custom Data Structures slug: /datastructures/custom-datastructure hide_title: true --- ![Storage Title Picture](/img/title/storage.svg) # Custom Data Structures The `ink_storage` crate provides useful utilities and data structures to organize and manipulate the contract's storage. However, contract authors should know that they can also create their own custom data structures. ## Using custom types on storage Any custom type wanting to be compatible with ink! storage must implement the [`Storable`](https://use-ink.github.io/ink/ink_storage_traits/trait.Storable.html) trait, so it can be SCALE [`encoded`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.Encode.html) and [`decoded`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.Decode.html). Additionally, the traits [`StorageLayout`](https://use-ink.github.io/ink/ink_storage_traits//trait.StorageLayout.html) and [`TypeInfo`](https://docs.rs/scale-info/latest/scale_info/trait.TypeInfo.html) are required as well. But don't worry, usually these traits can just be derived: ```rust /// A custom type that we can use in our contract storage #[ink::scale_derive(Encode, Decode, TypeInfo)] #[cfg_attr( feature = "std", derive(ink::storage::traits::StorageLayout) )] pub struct Inner { value: bool, } #[ink(storage)] pub struct ContractStorage { inner: Inner, } ``` Even better: there is a macro [`#[ink::storage_item]`](https://use-ink.github.io/ink/ink_macro/attr.storage_item.html), which derives all necessary traits for you. If there is no need to implement any special behavior, the above code example can be simplified further as follows: ```rust /// A custom type that we can use in our contract storage #[ink::storage_item] pub struct Inner { value: bool, } #[ink(storage)] pub struct ContractStorage { inner: Inner, } ``` Naturally, you can as well implement any required trait manually. Please directly refer to the relevant trait documentations for more information. :::note The `#[ink::storage_item]` macro is responsible for storage key calculation of non-[`Packed`](https://use-ink.github.io/ink/ink_storage_traits//trait.Packed.html) types. Without it, the key for non-`Packed` fields will be zero. Using this macro is necessary if you don't plan to use a [`ManualKey`](https://use-ink.github.io/ink/ink_storage_traits//struct.ManualKey.html) on a non-`Packed` type. Types with custom implementations of the ink! storage traits can still use this macro only for key calculation by disabling the derives: `#[ink::storage_item(derive = false)]`. ::: ## Generic storage fields It is possible to use generic data types in your storage, as long as any generic type satisfies the required storage trait bounds. In fact, we already witnessed this in the previous sections about the [`Mapping`](https://use-ink.github.io/ink/ink_storage/struct.Mapping.html). Let's say you want a mapping where accessing a non-existent key should just return it's default value, akin to how mappings work in Solidity. Additionally, you want to know how many values there are in the mapping (its length). This could be implemented as a thin wrapper around the ink! `Mapping` as follows: ```rust /// Values for this map need to implement the `Default` trait. /// Naturally, they also must be compatible with contract storage. /// Note that the underlying `Mapping` type only supports `Packed` values. #[ink::storage_item] pub struct DefaultMap { values: Mapping, length: u32, } impl DefaultMap { /// Accessing non-existent keys will return the default value. pub fn get(&self, key: &K) -> V { self.values.get(key).unwrap_or_default() } /// Inserting into the map increases its length by one. pub fn set(&mut self, key: I, value: &U) where I: scale::EncodeLike, E: scale::EncodeLike + Storable, { if self.values.insert(key, value).is_none() { self.length += 1 } } /// Removing a value from the map decreases its length by one. pub fn remove(&mut self, key: &K) { if self.values.take(key).is_some() { self.length -= 1 } } /// Return how many values the mapping contains pub fn len(&self) -> u32 { self.length } } /// `DefaultMap` is compatible with contract storage. #[ink(storage)] pub struct MyContract { my_map: DefaultMap, } ``` :::caution Generic data types may substantially increase your contracts overall code size, making it more costly to store on-chain. The reason for this is [Rust's monomorphization][rust-monomorphization]. ::: [rust-monomorphization]: https://rustc-dev-guide.rust-lang.org/backend/monomorph.html ```` ## File: docs/datastructures/mapping.md ````markdown --- title: Working with Mapping slug: /datastructures/mapping hide_title: true --- ![Storage Title Picture](/img/title/storage.svg) # Working with Mapping In this section we demonstrate how to work with ink! [`Mapping`](https://use-ink.github.io/ink/ink_storage/struct.Mapping.html). Here is an example of a mapping from a user to a `Balance`: ```rust #[ink(storage)] pub struct MyContract { /// Assign a balance to every account. balances: ink::storage::Mapping, } ``` This means that for a given key, you can store a unique instance of a value type. In this case, each "user" gets credited their own balance. ## Example: Using a `Mapping` The following example contract utilizes a `Mapping` so that anyone can deposit and withdraw balance for their own account: ```rust #![cfg_attr(not(feature = "std"), no_std, no_main)] #[ink::contract] mod mycontract { use ink::storage::Mapping; #[ink(storage)] pub struct MyContract { /// Assign a balance to every account ID balances: Mapping, } impl MyContract { /// Constructor to initialize the contract with an empty mapping. #[ink(constructor, payable)] pub fn new() -> Self { let balances = Mapping::default(); Self { balances } } /// Retrieve the balance of the caller. #[ink(message)] pub fn get_balance(&self) -> Option { let caller = self.env().caller(); self.balances.get(caller) } /// Credit more money to the contract. #[ink(message, payable)] pub fn transfer(&mut self) { let caller = self.env().caller(); let balance = self.balances.get(caller).unwrap_or(0); let endowment = self.env().transferred_value(); self.balances.insert(caller, &(balance + endowment)); } /// Withdraw all your balance from the contract. pub fn withdraw(&mut self) { let caller = self.env().caller(); let balance = self.balances.get(caller).unwrap(); self.balances.remove(caller); self.env().transfer(caller, balance).unwrap() } } } ``` ## Considerations when using the `Mapping` type One of the main purposes of the ink! `Mapping` is to allow storing a lot of values. :::note There are many additional data structures accessible under `ink::prelude::collections`, such as `HashMap` or `BTreeMap` (to name a few). Note that these data structures all exhibit `Packed` storage loading behavior, as opposed to the ink! `Mapping`! ::: ### Storage loading behavior Each `Mapping` value lives under it's own storage key. Briefly, this means that `Mapping`s are lazily loaded in ink!. In other words, if your message only accesses a single key of a mapping, it will not load the whole mapping but only the value being accessed. ```rust // This causes only a single storage access and the decoding of a single "MyValue" struct, // no matter how many elements there are inside the mapping. let foo: MyValue = my_mapping.get(0)?; for n in 0..5 { // This causes a storage access and a decoding operation for each loop iteration. // It is not possible to "fetch" all key/value pairs directly at once. let bar: MyValue = my_mapping.get(n)?; } ``` Furthermore, it follows that mapping values do not have a contiguous storage layout, and it is not possible to iterate over the contents of a map. ### Use fallible storage methods for dynamically sized values Reading from or writing to a `Mapping` implies encoding or decoding the according `Mapping` key and value. This happens transparently under the hood. However, because the static buffer used to store the encoded data is of limited size, it can fail and trap the contract. :::note The static buffer defaults to 16KB in size. ::: This can be an issue for values with dynamically sized types. It is recommended to use fallible storage methods (prefixed with `try_`) for `Mapping`s containing dynamically sized values. Consider a `Mapping` with `String` values like so: ```rust #[ink(storage)] pub struct MyContract { on_chain_log: Mapping, nonce: u64, } ``` If the `String` overgrows the static buffer size, it will no longer fit into the mapping: ```rust #[ink(message)] pub fn do_something(&mut self, data: String) { let caller = self.env().caller(); let log_message = format!("{caller:?}: {data}"); // Panics if log_message overgrows the static buffer size! self.on_chain_log.insert(&self.nonce, &log_message); self.nonce += 1; } ``` Instead, consider using the fallible `try_insert` method to handle the situation: ```rust #[ink(message)] pub fn do_something2(&mut self, data: String) { let caller = self.env().caller(); let log_message = format!("{caller:?}: {data}"); // `try_insert` will not panic but return an error instead. if self .on_chain_log .try_insert(&self.nonce, &log_message) .is_err() { // We get the chance to handle this problem properly: // Restrain the log message to a size guaranteed to fit. let log_message = format!("{caller:?}: "); self.on_chain_log.insert(&self.nonce, &log_message); } self.nonce += 1; } ``` We provide fallible `try_` versions for all storage operations on `Mapping`. ### Updating values The attentive reader may have noticed that accessing mapping values via the `Mapping::get()` method will result in an owned value (a local copy), as opposed to a direct reference into the storage. Changes to this value won't be reflected in the contract's storage "automatically". To avoid this common pitfall, the value must be inserted again at the same key after it was modified. The `transfer` function from above example illustrates this: ```rust pub fn transfer(&mut self) { let caller = self.env().caller(); // `balance` is a local value and not a reference to the value on storage! let balance = self.balances.get(caller).unwrap_or(0); let endowment = self.env().transferred_value(); // The following line of code would have no effect to the balance of the // caller stored in contract storage: // // balance += endowment; // // Instead, we use the `insert` function to write it back like so: self.balances.insert(caller, &(balance + endowment)); } ``` ```` ## File: docs/datastructures/overview.md ````markdown --- title: Overview slug: /datastructures/overview hide_title: true --- ![Storage Title Picture](/img/title/storage.svg) # Overview The `ink_storage` crate acts as the standard storage library for ink! smart contracts. At the moment it provides two primitives for interacting with storage, [`Mapping`](https://use-ink.github.io/ink/ink_storage/struct.Mapping.html) and [`Lazy`](https://use-ink.github.io/ink/ink_storage/struct.Lazy.html). `Mapping` is a mapping of key-value pairs directly to the contract storage. It is very similar to traditional hash tables and comparable to the `mapping` type Solidity offers. As a core ingredient to the ink! language, its main advantage is being simple and lightweight: It favors being efficient in terms of gas costs and code size over providing a lot of high-level functionality found in other implementations like the `ink::prelude::collections::HashMap` type. Overall, the ink! `Mapping` will be a solid choice for most contracts. Moreover, smart contracts developers can implement advanced features themselves. `Lazy` is a wrapper type that can be used over any other storage compatible type. This allows smart contract developers fine-grained manual control over the layout of the contract storage by assigning a separate storage cell for the field. For example, it can be used to prevent the contract from eagerly loading large storage fields during each contract call. Conceivably, it may be desirable to change certain aspects on how your contract deals with its storage variables. You can find out more about this in the section about the ink! [Storage Layout](./storage-layout.md). ```` ## File: docs/datastructures/storage-in-metadata.md ````markdown --- title: Storage Metadata Format slug: /datastructures/storage-in-metadata hide_title: true --- ![Storage Title Picture](/img/title/storage.svg) :::caution This page has not yet been edited for ink! v6. There are many mentions of `pallet-contracts` and its internals here. This info needs to be checked for validity in `pallet-revive`. We should also highlight that this is for the ink! Metadata Format. TODO ::: # Storage Metadata Format The storage layout of a contract is reflected inside the metadata. It allows third-party tooling to work with contract storage and can also help to better understand the storage layout of any given contract. Given a contract with the following storage: ```rust #[ink(storage)] pub struct MyContract { balance: Balance, block: BlockNumber, lazy: Lazy, } ``` The storage will be reflected inside the metadata as like follows: ```json "root": { "layout": { "struct": { "fields": [ { "layout": { "leaf": { "key": "0x00000000", "ty": 0 } }, "name": "balance" }, { "layout": { "leaf": { "key": "0x00000000", "ty": 1 } }, "name": "block" }, { "layout": { "root": { "layout": { "leaf": { "key": "0xb1f4904e", "ty": 2 } }, "root_key": "0xb1f4904e" } }, "name": "lazy" } ], "name": "MyContract" } }, "root_key": "0x00000000" } ``` We observe that the storage layout is represented as a tree, where tangible storage values end up inside a `leaf`. Because of [`Packed`](https://use-ink.github.io/ink/ink_storage_traits//trait.Packed.html) encoding, leafs can share the same storage key, and in order to reach them you'd need to fetch and decode the whole storage cell under this key. A `root_key` is meant to either be used to directly access a `Packed` storage field or to serve as the base key for calculating the actual keys needed to access values in non-`Packed` fields (such as `Mapping`s). ## Storage key calculation for ink! `Mapping` values Base storage keys are always 4 bytes in size. However, the storage API of the contracts pallet supports keys of arbitrary length. In order to reach a mapping value, the storage key of said value is calculated at runtime. The formula to calculate the base storage key `S` used to access a mapping value under the key `K` for a mapping with base key `B` can be expressed as follows: ``` S = scale::encode(B) + scale::encode(K) ``` Where the base key `B` is the `root_key` (of type `u32`) found in the contract metadata. In words, SCALE encode the base (root) key of the mapping and concatenate it with the SCALE encoded key of the mapped value to obtain the actual storage key used to access the mapped value. Given the following contract storage, which maps accounts to a balance: ```rust #[ink(storage)] pub struct Contract { roles: Mapping>, } ``` Now let's suppose we are interested in finding the balance for the account `5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY`. The storage key is calculated as follows: 1. SCALE encode the base key of the mapping (`0x12345678u32`), resulting in `0x78563412` 2. SCALE encode the `AccountId`, which will be `0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d`. Note that you'll need to convert the SS58 into a `AccountId32` first. 3. Concatenating those two will result in the key `0x78563412d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d`. ```rust let account_id = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"; let account: AccountId32 = Ss58Codec::from_string(account_id).unwrap(); let storage_key = &(0x12345678u32, account).encode(); println!("0x{}", hex::encode(storage_key)); // 0x78563412d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d ``` ## Accessing storage items with the `contractsApi` runtime call API There are two ways to query for storage fields of smart contracts from outside a contract. Both methods are accessible via the [`polkadot-js`](https://polkadot.js.org/apps/) web UI. The straight forward way to query a contracts storage is via a [`runtime API`](https://polkadot.js.org/apps/#/runtime) call, using the `contractsApi` endpoint provided by the contracts pallet. The endpoint provides a `getStorage` method, which just expects a contract address and a storage key as arguments. For example, to access the root storage struct under the key `0x00000000` of a contract, just specify the contract's address and the storage key `0x00000000` as-is. The API call will return the scale-encoded root storage struct of the contract. ## Accessing storage items with the `childState` RPC call API Under the hood, each contract gets its own [child trie](https://paritytech.github.io/substrate/master/frame_support/storage/child/index.html), where its storage items are actually stored. Additionally, the contracts pallet uses the [`Blake2 128 Concat`](https://paritytech.github.io/substrate/master/frame_support/struct.Blake2_128Concat.html) [`Transparent hashing algorithm`](https://docs.substrate.io/build/runtime-storage/#transparent-hashing-algorithms) to calculate storage keys for any stored item inside the child trie. You'll need to account for that as well. With that in mind, to directly access storage items of any on-chain contract using a childState [`RPC call`](https://polkadot.js.org/apps/#/rpc), you'll need the following: - The child trie ID of the contract, represented as a [`PrefixedStorageKey`](https://docs.rs/sp-storage/latest/sp_storage/struct.PrefixedStorageKey.html) - The hashed storage key of the storage field ### Finding the contracts child trie ID The child trie ID is the `Blake2_256` hash of the contracts instantiation nonce concatenated to it's `AccountId`. You can find it in [`polkadot-js chainstate query interface`](https://polkadot.js.org/apps/#/chainstate), where you need to execute the `contracts_contractInfoOf` state query. It can also be calculate manually according to the following code snippet. The instantiation note of the contract must be still be known. You can get it using the `contracts_nonce` chain state query in polkadot-js UI. ```rust use sp_core::crypto::Ss58Codec; use parity_scale_codec::Encode; // Given our contract ID is 5DjcHxSfjAgCTSF9mp6wQBJWBgj9h8uh57c7TNx1mL5hdQp4 let account: AccountId32 = Ss58Codec::from_string("5DjcHxSfjAgCTSF9mp6wQBJWBgj9h8uh57c7TNx1mL5hdQp4").unwrap(); // Given our instantiation nonce was 1 let nonce: u64 = 1; // The child trie ID can be calculated as follows: let trie_id = (&account, nonce).using_encoded(Blake2_256::hash); ``` ### Calculate the `PrefixedStorageKey` from the child trie ID A `PrefixedStorageKey` based on the child trie ID can be constructed using the `ChildInfo` primitive as follows: ```rust use sp_core::storage::ChildInfo; let prefixed_storage_key = ChildInfo::new_default(&trie_id).into_prefixed_storage_key(); ``` ### Calculate the storage key using transparent hashing Finally, we calculate the hashed storage key of the storage item we are wanting to access. The algorithm is simple: `Blake2_128` hash the storage key and then concatenate the unhashed key to the hash. Given you want to access the storage item under the `0x00000000`, it will look like this in code: ```rust use frame_support::Blake2_128Concat; // The base key is 0x00000000 let storage_key = Blake2_128Concat::hash(&[0, 0, 0, 0]); ``` ### A full example Let's recap the last few paragraphs into a full example. Given: * A contract at address `5DjcHxSfjAgCTSF9mp6wQBJWBgj9h8uh57c7TNx1mL5hdQp4` * With instantiation nonce of `1` * The root storage struct is to be found at base key `0x00000000` The following Rust program demonstrates how to calculate the `PrefixedStorageKey` of the contracts child trie, as well as the hashed key for the storage struct, which can then be used with the `chilstate` RPC endpoint function `getStorage` in polkadot-js to receive the root storage struct of the contract: ```rust use frame_support::{sp_runtime::AccountId32, Blake2_128Concat, Blake2_256, StorageHasher}; use parity_scale_codec::Encode; use sp_core::{crypto::Ss58Codec, storage::ChildInfo}; use std::ops::Deref; fn main() { // Find the child storage trie ID let account_id = "5DjcHxSfjAgCTSF9mp6wQBJWBgj9h8uh57c7TNx1mL5hdQp4"; let account: AccountId32 = Ss58Codec::from_string(account_id).unwrap(); let instantiation_nonce = 1u64; let trie_id = (account, instantiation_nonce).using_encoded(Blake2_256::hash); assert_eq!( hex::encode(trie_id), "2fa252b7f996d28fd5d8b11098c09e56295eaf564299c6974421aa5ed887803b" ); // Calculate the PrefixedStorageKey based on the trie ID let prefixed_storage_key = ChildInfo::new_default(&trie_id).into_prefixed_storage_key(); println!("0x{}", hex::encode(prefixed_storage_key.deref())); // 0x3a6368696c645f73746f726167653a64656661756c743a2fa252b7f996d28fd5d8b11098c09e56295eaf564299c6974421aa5ed887803b // Calculate the storage key using transparent hashing let storage_key = Blake2_128Concat::hash(&[0, 0, 0, 0]); println!("0x{}", hex::encode(&storage_key)); // 0x11d2df4e979aa105cf552e9544ebd2b500000000 } ``` ```` ## File: docs/datastructures/storage-layout.md ````markdown --- title: Storage Layout slug: /datastructures/storage-layout hide_title: true --- import useBaseUrl from '@docusaurus/useBaseUrl'; ![Storage Title Picture](/img/title/storage.svg) # Storage Layout Smart contract authors are given some flexibility in regards on how they want to organize the storage layout of their contracts. Let's dive deeper into the concepts behind ink! storage to get a better understanding of some of its implications and limitations. ## Storage Organization The following schema depicts the storage which is exposed to ink! by the [`pallet-revive`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive/):
Storage Organization: Layout
Storage data is always encoded with the [`SCALE`](https://docs.polkadot.com/polkadot-protocol/basics/data-encoding/#scale-codec-libraries) codec. The storage API operates by storing and loading entries into and from a single storage cells, where each storage cell is accessed under its own dedicated storage key. To some extent, the storage API works similar to a traditional key-value database. ## Packed vs Non-Packed layout Types that can be stored entirely under a single storage cell are considered [`Packed`](https://use-ink.github.io/ink/ink_storage_traits//trait.Packed.html). By default, ink! tries to store all storage struct fields under a single storage cell. Consequentially, with a `Packed` storage layout, any message interacting with the contract storage will always need to operate on the entire contract storage struct. For example, if we have a somewhat small contract storage struct consisting of only a few tiny fields, pulling everything from the storage inside every message is not problematic. It may even be advantageous - especially if we expect most messages to interact with most of the storage fields. On the other hand, this can get problematic if we're storing a large `ink::prelude::vec::Vec` in the contract storage but provide messages that do not need to read and write from this `Vec`. In that scenario, each and every contract message bears runtime overhead by dealing with that `Vec`, regardless whether they access it or not. This results in extra gas costs. To solve this problem we need to turn our storage into a non-packed layout somehow.
Storage Organization: Packed
:::caution If any type exhibiting `Packed` layout gets large enough (an ever-growing `Vec` might be a prime candidate for this), it will break your contract. This is because for encoding and decoding storage items, there is a buffer with only limited capacity (around 16KB in the default configuration) available. This means any contract trying to decode more than that will trap! If you are unsure about the potential size a data structure might get, consider using an ink! `Mapping`, which can store an arbitrary number of elements, instead. ::: ## Eager Loading vs. Lazy Loading ink! provides means of breaking the storage up into smaller pieces, which can be loaded on demand, with the [`Lazy`](https://use-ink.github.io/ink/ink/storage/struct.Lazy.html) primitive. Wrapping any storage field inside a `Lazy` struct makes the storage struct in which that field appears also non-`Packed`, preventing it from being eagerly loaded during arbitrary storage operations:
Storage Organization: Layout with a Lazy field
Note that in above illustration, the key of `0x12345678` just serves as an example; we'll learn more about storage key calculation [later in this chapter](#manual-vs-automatic-key-generation). The following example demonstrates how we can solve the problem introduced in the above section. You'll notice that for the lazily loaded storage field, we now work with getters and setters to access and modify the underlying storage value: ```rust #![cfg_attr(not(feature = "std"), no_std, no_main)] #[ink::contract] mod mycontract { use ink::prelude::vec::Vec; use ink::storage::Lazy; #[derive(Default)] #[ink(storage)] pub struct MyContract { tiny_value: Balance, /// This vector might get large and expensive to work with. /// We want to enforce a non-`Packed` storage layout. large_vec: Lazy>, } impl MyContract { #[ink(constructor)] pub fn new() -> Self { Self::default() } /// Because `large_vec` is loaded lazily, this message is always cheap. #[ink(message)] pub fn get_balance(&self) -> Balance { self.tiny_value } /// Lazy fields like `large_vec` provide `get()` and `set()` storage operators. #[ink(message)] pub fn add_balance(&mut self, value: Balance) { let mut balances = self.large_vec.get_or_default(); balances.push(value); self.large_vec.set(&balances); } } } ``` :::caution `ink::prelude::vec::Vec`'s are always loaded in their entirety. This is because all elements of the `ink::prelude::vec::Vec` live under a single storage key. Wrapping the `ink::prelude::vec::Vec` inside `Lazy`, like the provided example above does, has no influence on its inner layout. If you are dealing with large or sparse arrays on contract storage, consider using a `Mapping` instead. ::: ## Manual vs. Automatic Key Generation By default, keys are calculated automatically for you, thanks to the [`AutoKey`](https://use-ink.github.io/ink/ink_storage_traits//struct.AutoKey.html) primitive. They'll be generated at compile time and ruled out for conflicts. However, for non-`Packed` types like `Lazy` or the `Mapping`, the [`ManualKey`](https://use-ink.github.io/ink/ink_storage_traits//struct.ManualKey.html) primitive allows manual control over the storage key of a field like so: ```rust #[ink(storage)] pub struct MyContract { /// The storage key for this field is always `0x0000007f` inner: Lazy>, } ``` This may be advantageous: Your storage key will always stay the same, regardless of the version of your contract or ink! itself (note that the key calculation algorithm may change with future ink! versions). :::tip Using `ManualKey` instead of `AutoKey` might be especially desirable for upgradable contracts, as using `AutoKey` might result in a different storage key for the same field in a newer version of the contract. This may break your contract after an upgrade 😱! ::: The storage key of the contracts root storage struct defaults to `0x00000000`. However, contract developers can set the key to an arbitrary 4 bytes value by providing it a `ManualKey` like so: ```rust /// Manually set the root storage key of `MyContract` to be `0xcafebabe`. #[ink(storage)] pub struct MyContract> { value: bool, } ``` ## Considerations It might be worthwhile to think about the desired storage layout of your contract. While using a `Packed` layout will keep your contracts overall code size smaller, it can cause unnecessarily high gas costs. Thus, we consider it a good practice to break up large or complex storage layouts into reasonably sized distinct storage cells. :::note ink! `Mapping`s are always non-`Packed` and loaded lazily, one key-value pair at the time. ::: ```` ## File: docs/datastructures/storagevec.md ````markdown --- title: Working with StorageVec slug: /datastructures/storagevec hide_title: true --- ![Storage Title Picture](/img/title/storage.svg) # Working with `StorageVec` In this section we demonstrate how to work with ink!'s [`StorageVec`](https://use-ink.github.io/ink/ink_storage/struct.StorageVec.html). ## Example: Using a `StorageVec` Here is an example of an append-only on-chain log: ```rust #[ink(storage)] pub struct MyContract { on_chain_log: ink::storage::StorageVec, } ``` The following example contract utilizes a `StorageVec` to log each operation on chain (similar to emitting events but the contract can access them). ```rust #![cfg_attr(not(feature = "std"), no_std, no_main)] #[ink::contract] mod mycontract { use ink::prelude::{format, string::String}; use ink::storage::StorageVec; #[ink(storage)] pub struct MyContract { on_chain_log: StorageVec, } impl MyContract { #[ink(constructor)] pub fn new() -> Self { Self { on_chain_log: Default::default(), } } /// Donate money to the contract. #[ink(message, payable)] pub fn donate(&mut self) { let caller = self.env().caller(); let endowment = self.env().transferred_value(); let log_message = format!("{caller:?} donated {endowment}"); self.on_chain_log.push(&log_message); } /// How many donations had the contract so far? #[ink(message)] pub fn log_length(&self) -> u32 { self.on_chain_log.len() } /// What was the last donation to the contract? #[ink(message)] pub fn last_donation(&self) -> Option { self.on_chain_log.peek() } } } ``` ## Difference between `StorageVec` and Rusts `Vec` type Any Rust `Vec` will exhibit `Packed` storage layout; where `StorageVec` stores each value under it's own storage key. Hence, any read or write from or to a `Vec` on storage will load or store _all_ of its elements. This can be undesirable: The cost of reading or writing a _single_ element grows linearly corresponding to the number of elements in the vector (its length). Additionally, the maximum capacity of the _whole_ vector is limited by the size of [ink!'s static buffer](https://github.com/use-ink/ink/blob/master/ARCHITECTURE.md#communication-with-the-pallet) used during ABI encoding and decoding (default 16 KiB). `StorageVec` on the other hand allows to access each element individually. Thus, it can theoretically grow to infinite size. However, we currently limit the length at 2 ^ 32 elements. In practice, even if the vector elements are single bytes, it'll allow to store more than 4 GB data in blockchain storage. ### Caveats Iterators are not provided. `StorageVec` is expected to be used to store a lot elements, where iterating through the elements would be rather inefficient. Manually iterating over the elements using a loop is possible but considered an anti-pattern for most cases. For the same reason, operations which would require re-ordering stored elements are not supported. Examples include inserting and deleting elements at arbitrary positions or sorting elements. The decision whether to use `Vec` or `StorageVec` can be seen as an optimization problem with several factors: * How large you expect the vector to grow * The size of individual elements being stored * How frequently reads, writes and iterations happen For example, if a vector is expected to stay small but is frequently iterated over. Choosing a `Vec` instead of `StorageVec` will be preferred as individual storage reads are much more expensive as opposed to retrieving and decoding the whole collection with a single storage read. ### Storage Layout At given `StorageKey` `K`, the length of the `StorageVec` is hold. Each element `E` is then stored under a combination of the `StorageVec` key `K` and the elements index. Given `StorageVec` under key `K`, the storage key `E` of the `N`th element is calculated as follows: `E = scale::Encode((K, N))` ## Considerations when using the `StorageVec` type `StorageVec` is a `Lazy` type similar to `Mapping`. Hence, the same considerations apply to `StorageVec` too: - [Storage loading behavior](../datastructures/mapping.md#storage-loading-behavior) - [Use fallible storage methods for dynamically sized values](../datastructures/mapping.md#use-fallible-storage-methods-for-dynamically-sized-values) - [Updating values](../datastructures/mapping.md#updating-values) ## Rust Docs See here for the Rust documentation of this data structure: [`StorageVec`](https://use-ink.github.io/ink/ink_storage/struct.StorageVec.html). ```` ## File: docs/debugging/decoding.md ````markdown --- title: Decode raw transactions slug: /contract-debugging/decoding-transactions hide_title: true --- ![Magnifying Glass Title Picture](/img/title/magnifying-glass.svg) # Decode Data Payload You can use a block explorer (or an app like Polkadot.js) to retrieve the data payload of a contract transaction. [cargo-contract](https://github.com/use-ink/cargo-contract) supports decoding this data. ```bash # From your contract directory cargo contract decode message -d fe5bd8ea01000000 ``` This command will output the method name and parameters encoded in the data payload: ``` Decoded data: inc_by { n: 1 } ``` If the contract was called through a cross-contract interaction, the payload will not be available in the transaction. In such cases, you can use the approach described in the next section to access it. ```` ## File: docs/debugging/events.md ````markdown --- title: Debug Events slug: /contract-debugging/debug-events hide_title: true --- ![Magnifying Glass Title Picture](/img/title/magnifying-glass.svg) # Emit debugging events The idea here is to add a feature to your contract's `Cargo.toml`. You can name it e.g. `debug`. In your contract you would then emit debug information if the flag is set. This allows for emitting debug events in the contract, that can be checked for in your tests. ```rust #![cfg_attr(not(feature = "std"), no_std, no_main)] #[ink::contract] mod debugging_strategies { #[cfg(feature = "debug")] use ink::prelude::{ borrow::ToOwned, format, string::String, }; #[ink::event] #[cfg(feature = "debug")] pub struct DebugEvent { message: String, } #[ink(storage)] #[derive(Default)] pub struct DebuggingStrategies {} impl DebuggingStrategies { #[ink(constructor)] pub fn new() -> Self { Self {} } #[ink(message)] pub fn get(&self) { #[cfg(feature = "debug")] self.env().emit_event(DebugEvent { message: format!("received {:?}", self.env().transferred_value()) .to_owned(), }); // … } } } ``` This event will be shown when you call a contract. You can also access it in E2E tests: ```rust #[ink_e2e::test(features = ["debug"])] async fn e2e_debugging_event_emitted( mut client: Client, ) -> E2EResult<()> { // given // create contract /* --snip-- */ // when // call contract /* --snip-- */ // then // the contract wil have emitted an event let contract_events = call_res.contract_emitted_events()?; assert_eq!(1, contract_events.len()); let contract_event = &contract_events[0]; let debug_event: DebugEvent = ink::scale::Decode::decode(&mut &contract_event.event.data[..]) .expect("encountered invalid contract event data buffer"); assert_eq!(debug_event.message, "received 0"); Ok(()) } ``` We've put the above into a complete example. You can see the full source code [here](https://github.com/use-ink/ink/tree/master/integration-tests/public/debugging-strategies/lib.rs). ```` ## File: docs/debugging/overview.md ````markdown --- title: Overview slug: /contract-debugging/ hide_title: true --- ![Magnifying Glass Title Picture](/img/title/magnifying-glass.svg) # Overview On a high-level there are two workflows for debugging your contract: * You can write tests using one of the mechanisms described on the [Contract Testing](../testing/overview.md) page. * You can interact with your contract via a UI or command-line. The workflow is described on the [Call Your Contract](../getting-started/calling.md) page. In each of those two options you have access to more detailed debugging information. In this chapter we'll examine different debugging techniques using these two workflows. ```` ## File: docs/debugging/precompiles.md ````markdown --- title: Precompiles slug: /contract-debugging/precompiles hide_title: true --- ![Magnifying Glass Title Picture](/img/title/magnifying-glass.svg) # Precompile We don't have any examples for debugging with precompiles yet. Our intention is to add an explanation here, once the precompile API in `pallet-revive` is released. The overarching with precompiles for debugging is to implement one that outputs log information to the node process console (`stdout` or `stderr`). This precompile could then be called from within an ink! contract. ```` ## File: docs/debugging/replays.md ````markdown --- title: Replays slug: /contract-debugging/transaction-extrinsic-replays hide_title: true --- ![Magnifying Glass Title Picture](/img/title/magnifying-glass.svg) :::caution This section has not yet been updated to ink! v6. TODO Verify if this still works. ::: # Replays On this page we'll examine possibilities of replaying on-chain action. ## Replay and Debug a Block To replay a transaction, you can use [Chopstick](https://github.com/AcalaNetwork/chopsticks) to create a local fork of the chain and replay the block with trace-level logging. Assuming you have a node that you can connect to at `$ENDPOINT` and the transaction you want to replay is in block `$BLOCK_HASH`, you can use the following command: ```bash npx @acala-network/chopsticks@latest run-block \ --endpoint $ENDPOINT \ --block $BLOCK_HASH \ --runtime-log-level 5 \ | grep runtime::contracts ``` This command replays the block with trace-level logging enabled. By filtering the output with `runtime::contracts`, you can view all the contract calls in the block: ``` runtime::contracts TRACE: call ExportedFunction::Call account: , input_data: [246, 118, 44, 201] runtime::contracts TRACE: call ExportedFunction::Call account: , input_data: [254, 91, 216, 234, 1, 0, 0, 0] runtime::contracts TRACE: call result ExecReturnValue { flags: (empty), data: [0] } runtime::contracts TRACE: call result ExecReturnValue { flags: (empty), data: [0] } ``` From here, you can identify the call you are interested in and decode the data payload: ```bash echo 254, 91, 216, 234, 1, 0, 0, 0 \ | tr ',' ' ' \ | xargs printf '%02x' \ | xargs cargo contract decode message -d ``` This command will output the following: ``` Decoded data: inc_by { n: 1 } ``` ## Fork Node and Replay Transactions :::caution This section has not yet been updated to ink! v6. TODO Verify if this still works. ::: You can also use [Chopstick](https://github.com/AcalaNetwork/chopsticks) to start a local fork of your chain. This command starts a fork beginning at block `$BLOCK_HASH`. You can connect to this fork using `ws://localhost:8000` to submit extrinsics via PolkadotJs or `cargo contract`: ```bash npx @acala-network/chopsticks@latest \ --endpoint $ENDPOINT \ --block $BLOCK_HASH \ --runtime-log-level 5 ``` Here, for example, you can re-run the transaction that we decoded in the previous section: ```bash cargo contract call \ --contract $CONTRACT_ADDR \ --message inc_by --args 1 \ --suri //Alice \ --url ws://localhost:8000 ``` Since trace-level logging is used, you will receive detailed information about all the host functions called during the execution of the contract: ``` runtime::contracts TRACE: call ExportedFunction::Call account: , input_data: [254, 91, 216, 234, 2, 0, 0, 0] runtime::contracts TRACE: call result ExecReturnValue { flags: (empty), data: [0] } runtime::contracts DEBUG: Execution finished with debug buffer: seal0::value_transferred(out_ptr: 65488, out_len_ptr: 65516) = Ok(()) seal0::input(out_ptr: 65536, out_len_ptr: 65524) = Ok(()) seal1::get_storage(key_ptr: 65536, key_len: 4, out_ptr: 65540, out_len_ptr: 65524) = Ok(Success) seal2::set_storage(key_ptr: 65536, key_len: 4, value_ptr: 65540, value_len: 4) = Ok(4) seal0::seal_return(flags: 0, data_ptr: 65536, data_len: 1) = Err(TrapReason::Return(ReturnData { flags: 0, data: [0] })) ``` ```` ## File: docs/debugging/return_value.md ````markdown --- title: Return value slug: /contract-debugging/return-value hide_title: true --- ![Magnifying Glass Title Picture](/img/title/magnifying-glass.svg) # Return an error message You can return a specific error message from your contract via [`ink::return_value(REVERT, err);`](https://use-ink.github.io/ink/ink_env/fn.return_value.html). If you do a dry-run of the contract call, you can read this data. You cannot read the data if you submit the extrinsic on-chain (i.e. execute the contract call "for real", on-chain). This is because extrinsic do not return data. They are executed in a transaction pool, asynchronous. Furthermore, since you "REVERT" the transaction, it will just fail with `ExtrinsicFailed`. Here's an example: ```rust #[ink::message] fn get(&self) { ink::return_value( ink::env::ReturnFlags::REVERT, format!("received {:?}", self.env().transferred_value()).as_bytes(); ); } ``` We've put the above into a complete example. You can see the full source code [here](https://github.com/use-ink/ink/tree/master/integration-tests/public/debugging-strategies/lib.rs). ```` ## File: docs/debugging/sandbox.md ````markdown --- title: Sandbox slug: /contract-debugging/sandbox hide_title: true --- ![Magnifying Glass Title Picture](/img/title/magnifying-glass.svg) # Sandbox API In the chapter on [Testing Strategies](../testing/sandbox.md), we explain that ink! supports two means of End-to-End testing: * `#[ink_e2e::test]`: The End-to-End tests spawn a local node process in the backend and submit transactions against it, returning the output to you. * `#[ink_sandbox::test(backend(runtime_only(sandbox = sandbox_runtime::ContractCallerSandbox,client = ink_sandbox::SandboxClient)))]` With these settings, the End-to-End tests will be executed in a sandbox. The sandbox contains the `pallet-revive`, but anything that the node would do is mocked and can be influenced (block numbers, etc.). You can utilize the DRink! library that is described on [Testing Strategies](../testing/sandbox.md) to influence the state of the mocked sandbox. This is very useful for debugging, and we invite you to read the linked page. ```` ## File: docs/debugging/tracing.md ````markdown --- title: Tracing API slug: /contract-debugging/pallet-revive-tracing-api hide_title: true --- ![Magnifying Glass Title Picture](/img/title/magnifying-glass.svg) # Tracing APIs The [`pallet-revive`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive/src) has implemented a tracing API. This is what the Ethereum-debugging tools use when interacting with `pallet-revive`. You can utilize the tracing API in your E2E tests: ```rust /// This test illustrates how to use the `pallet-revive` tracing functionality. #[ink_e2e::test] async fn e2e_tracing(mut client: Client) -> E2EResult<()> { // given let mut constructor = DebuggingStrategiesRef::new(); let contract = client .instantiate("debugging_strategies", &ink_e2e::bob(), &mut constructor) .submit() .await .expect("instantiate failed"); let call_builder = contract.call_builder::(); let call = call_builder.instantiate_and_call(contract.code_hash); let call_res = client .call(&ink_e2e::alice(), &call) .value(1_337_000_000) .submit() .await?; // when let trace: ink_e2e::CallTrace = call_res.trace.expect("trace must exist"); assert_eq!(trace.calls.len(), 2); // This is how the object looks: // ``` // CallTrace { // from: 0x9621dde636de098b43efb0fa9b61facfe328f99d, // gas: 1497105168000, // gas_used: 1548337586000, // to: 0xd71ff7085ed0e3e8b6c8e95eb6094f4311ae8e2f, // input: Bytes( // 0x829da98747d85e35d0b3ca3c7ceeac09b63ec2754e6a05eb6d2d5b92fb916da126364dd4, // ), // output: Bytes(0x0001), // error: None, // revert_reason: None, // calls: [ // CallTrace { // from: 0xd71ff7085ed0e3e8b6c8e95eb6094f4311ae8e2f, // gas: 711404887000, // gas_used: 205987649000, // to: 0xfd8bf44f34a2d2cec42b8ab31ede1bb1bc366e8e, // input: Bytes(0x9bae9d5e), // output: Bytes(0x0000), // error: None, // revert_reason: None, // calls: [], // logs: [], // value: Some(0), // call_type: Call, // }, // CallTrace { // from: 0xd71ff7085ed0e3e8b6c8e95eb6094f4311ae8e2f, // gas: 124370129000, // gas_used: 163567881000, // to: 0xfd8bf44f34a2d2cec42b8ab31ede1bb1bc366e8e, // input: Bytes(0x2f865bd9), // output: Bytes(0x0001), // error: None, // revert_reason: None, // calls: [], // logs: [], // value: Some(0), // call_type: Call, // }, // ], // logs: [], // value: Some(0), // call_type: Call, // } // ``` // then #[allow(non_upper_case_globals)] const NativeToEthRatio: u128 = 1_000_000; // todo add to environment assert_eq!( trace.value, Some(ink::U256::from(1_337_000_000 * NativeToEthRatio)) ); Ok(()) } ``` We've put the above into a complete example. You can see the full source code [here](https://github.com/use-ink/ink/tree/master/integration-tests/public/debugging-strategies/lib.rs). ```` ## File: docs/faq/faq.md ````markdown --- title: Frequently Asked Questions hide: true slug: /faq hide_table_of_contents: true --- import useBaseUrl from '@docusaurus/useBaseUrl'; ![Faq Title Picture](/img/title/faq.svg) # Frequently Asked Questions ### Who is "Squink"? Squink ‒ the ink! mascot This little cute purple squid is Squink.

Squink is the mascot of ink! and guides new users and adventurers through our presentations workshops and tutorials. It also has a romance with Rust's mascot, Ferris. Generally it is very friendly and open to learning new Rustaceans but be aware to never upset it by taking away dots from the word ink! by spelling it incorrectly! It really is into dots. Stories tell that it demanded the spelling of ink! with as many dots as possible.

Is it "ink" or "ink!"? What does the "!" stand for?

The correct spelling is _ink!_ ‒ with a lowercase "i" and an exclamation mark at the end. The history here is that: * …in the very first iteration ink! was originally a [declarative Rust macro](https://doc.rust-lang.org/book/ch19-06-macros.html#declarative-macros-with-macro_rules-for-general-metaprogramming). A contract was invoked by writing `ink!{ … }`. * …there is a real-world analogy here of writing a paper contract using ink. * …we wanted to have as many DOTs as possible in the name 😉. * …the symmetry of the top and bottom dot of i and ! is aesthetically pleasing 🌻. So please don't make poor Squink cry having to read !ink, ink, Ink!, or Ink.
Squink ‒ the ink! mascot
### What's ink!'s relationship to the Polkadot SDK/Substrate? Please see our page [Polkadot SDK](../background/polkadot-sdk.md) for more information. ### How to call other smart contracts on the same blockchain? See our [Cross-contract calling](../basics/cross-contract-calling.md) page. ### How to call other smart contracts on another rollup/parachain? See our page on [XCM](../basics/xcm.md). ### What is a contract's ABI or Metadata? In ink! a smart contract's metadata is retrieved by using the `cargo-contract` CLI tool and invoking `cargo contract build` which outputs a `.contract` file that includes both the compiled `.polkavm` of the ink! smart contract as well as the so-called metadata information of the same smart contract. The metadata is especially important for third party tools such as Polkadot JS Apps or the Contracts UI and provides useful information about the contract's constructors, messages, events, function selectors, documentation and comments of the aforementioned structures as well as how inputs and outputs shall be encoded and decoded respectively etc. ### Can a re-entrancy bug occur in ink! contracts? :::caution This page has to be reviewed in light of our ABI changes. TODO There are some reentrancy features in ink!, those should be explained here or on another page. ::: # Cross-Contract Calls ### How can my smart contract interact with the runtime? See the [Precompiles](../basics/precompiles.md) section for more information. ### How can I use ink! with a Polkadot SDK chain with a custom chain config? Please see [this section](../macros-attributes/contract.md#env-impl-environment) in our documentation. Detailed documentation is found in [the Rust docs](https://use-ink.github.io/ink/ink_macro/attr.contract.html#header-arguments) for the `#[ink(contract)]` macro. It allows you to specify your environment a la `#[ink::contract(env = MyEnvironment)]`. ### What does the `#![cfg_attr(not(feature = "std"), no_std, no_main)]` at the beginning of each contract mean? The `#[cfg(..)]` or `#[cfg_attr(..)]` annotations are how Rust does conditional compilation. ink! smart contracts can be compiled in two different modes. Through `#![cfg_attr(not(feature = "std"), no_std, no_main)]` an ink! smart contract tells the Rust compiler in which mode they are being compiled. This also plays a significant role in how ink! generates the smart contract code. The two modes are as follows: 1. On-chain mode: This is the mode chosen when compiling an ink! smart contract for deployment on a blockchain. The resulting binary is a `.polkavm` file and as such it is not possible to use certain parts of Rust's standard library. 2. Off-chain mode: This is the mode chosen when trying to test an ink! smart contract using the off-chain environment. Off-chain environment testing is very useful to check if certain ink! constructors or messages are well behaving and allow for better debuggability than when trying to debug the same smart contract deployed on a chain.

Why is Rust's standard library (stdlib) not available in ink!?

Rust's standard library consists of three different layers: 1. `core` library which defines everything that has no dependencies outside of Rust itself. Included are types such as `Option`, `Result` as well as a whole variety of modules, functions and macro. ink! smart contracts allow authors to use Rust's `core` crate. 2. `alloc` library which is depending on a global allocator and mainly defines collections that spill their elements on to the execution's heap memory. Examples for collections are `Box`, `String`, `Vec`, `HashMap`, `LinkedList` and modules such as `fmt`, `rc` (ref-counted pointers) or borrows. ink! smart contracts allow authors to use Rust's `alloc` crate. By default ink! authors use definitions from the `alloc` crate through `ink::prelude` crate. 3. `std` library is what people generally call Rust's standard library. > The Rust Standard Library is the foundation of portable Rust software, a set of minimal and battle-tested shared abstractions for the broader Rust ecosystem. It requires several operating system capabilities in order to work correctly such as input and output systems for files, networking etc. Since our RISC-V compilation target does not support Rust's standard library ink! authors cannot use it either for their own purposes. Instead the [`pallet-revive`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive) tries to provide some common functionality that would otherwise be missing for common smart contract operations. ### Overflow Safety? Being written in Rust, ink! provides robust overflow/underflow safety using compiler-level overflow checks as follows: - `const` integer arithmetic operations (i.e. expressions involving only `const` integer operands) are checked for overflows at compile-time (e.g. `255u8 + 1` will lead to a compilation error due to overflow). - For dynamic integer arithmetic operations, ink! (more specifically [`cargo-contract`][cargo-contract]) automatically enables Rust's ["overflow-checks" instrumentation][rustc-overflow-checks], which automatically adds dynamic/runtime checks that panic on overflow. [cargo-contract]: ../getting-started/setup.md#cargo-contract [rustc-overflow-checks]: https://doc.rust-lang.org/rustc/codegen-options/index.html#overflow-checks However, where possible, it's preferred to explicitly handle the possibility of overflow using the following family of methods that are provided for primitive numeric types in Rust: - `wrapping_*` methods for explicit wrapping behaviour (e.g. [`wrapping_add`][wrapping-add]) - `checked_*` methods which return `None` in case of overflow (e.g. [`checked_add`][checked-add]) - `saturating_*` methods which saturate at the type's minimum or maximum value (e.g. [`saturating_add`][saturating-add]) - `overflowing_*` methods which return the value and a `bool` flag indicating whether an overflow occurred (e.g. [`overflowing_add`][overflowing-add]) [wrapping-add]: https://doc.rust-lang.org/std/primitive.u8.html#method.wrapping_add [checked-add]: https://doc.rust-lang.org/std/primitive.u8.html#method.checked_add [saturating-add]: https://doc.rust-lang.org/std/primitive.u8.html#method.saturating_add [overflowing-add]: https://doc.rust-lang.org/std/primitive.u8.html#method.overflowing_add :::note Unlike default `rustc`/`cargo` behavior, ink! (more specifically [`cargo-contract`][cargo-contract]) automatically enables dynamic overflow checks in release mode by default (i.e. dynamic overflow checks are enabled when compiling with `cargo contract build --release`). However, `cargo-contract` still allows you to override this behavior using the ["overflow-checks" setting][cargo-overflow-checks] for the release profile in your contract's manifest file (i.e. `Cargo.toml`). ::: [cargo-overflow-checks]: https://doc.rust-lang.org/cargo/reference/profiles.html#overflow-checks :::caution Apart from [integer arithmetic operations][arithmetic-operations], another cause of implicit overflows is [integer type cast expressions (i.e. `as` conversions)][as-conversions]. However, unlike integer arithmetic operations, Rust's ["overflow-checks" instrumentation][rustc-overflow-checks] doesn't add overflow checks for integer type cast expressions (e.g. `256u16 as u8`). The motivation for this decision is explained [here][overflow-rfc-as]. As a less robust alternative, ink! provides a `cargo contract lint` command, which (in addition to our [custom lints][custom-lints]) enables the following [`clippy`][clippy] lints to check for overflowing/underflowing and lossy integer type cast expressions **in the local crate** (i.e. the following lints only check code from the local crate, they don't check code from dependencies). - https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_truncation - https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap - https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss In the future, ink! may provide more robust checks for overflows due integer type cast expressions (i.e. `as` conversions). ::: [arithmetic-operations]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators [as-conversions]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics [overflow-rfc-as]: https://rust-lang.github.io/rfcs/0560-integer-overflow.html#making-as-be-checked [custom-lints]: ../linter/overview.md [clippy]: https://doc.rust-lang.org/clippy/ ### What is the difference between memory and storage? In ink!, memory refers to computer memory, while storage refers to the on-chain storage used by a contract instance. Memory is temporary and only lasts until the contract execution is done, while storage is persistent and lasts over many contract executions. The contract storage is built on top of the runtime storage, and access is considered to be slow. ### How do I hash a value? A number of crypto hashes are built into [`pallet-revive`](../background/polkadot-sdk.md) and therefore very efficient to use. We currently support a handful of those, you can view the complete list [here](https://use-ink.github.io/ink/ink_env/hash/trait.CryptoHash.html). If you have the urgent need for another crypto hash you could introduce it through [Precompiles](../basics/precompiles.md) or make a proposal to include it into the default set of the `pallet-revive`. Using one of the built-in crypto hashes can be done as explained here: * [`self.env().hash_bytes()`](https://use-ink.github.io/ink/ink_env/fn.hash_bytes.html) * [`self.env().hash_encoded()`](https://use-ink.github.io/ink/ink_env/fn.hash_encoded.html) ### Why is it not possible to use floating point data types in ink!? How do I implement returning a decimal number? Floats are cool for all kinds of reasons, but they also have one important drawback. Floating point arithmetic is non-deterministic which means that different processors compute (slightly) different results for the same operation. Although there is an IEEE spec, non-determinism can come from specific libraries used, or even hardware. In order for the nodes in a blockchain network to reach agreement on the state of the chain, all operations must be completely deterministic. Hence, we don't allow floating point data types in ink!. Consequently, it's not possible to return a decimal number from an ink! message. What you should do instead is to have your user interface denominate the returned number to decimals. Note, that it's typical for blockchains to have the number of available tokens defined as a non-floating number and determine the denomination in the user interface. For example, 1 Bitcoin is equivalent to the smallest unit of 100,000,000 Satoshi and all Bitcoin implementations internally persist account balances in Satoshi, not as a decimal number of Bitcoin. ### Why can't I just use the standard Rust data collections in ink!? You can use them! They are exposed via the `ink_prelude` crate (e.g. `ink::prelude::vec::Vec`) and you can return them from ink! messages and also persist them to storage. _However, the Rust stdlib collections are not optimized for smart contract usage!_ So for example, if you use them to persist your data on the chain they will always occupy a single storage cell and thus always be loaded eagerly, in their entirety. This can be very costly! Just think about a `Vec` or a `HashMap` where the smart contract might only need access to a few elements, rather than the entire data collection. ### Why am I getting a `ContractTrapped` error when interacting with a contract? When it does not constitute a deliberate assertion, like for example a permission check, it is most likely a bug in your contract or in ink!. A common source of `ContractTrapped` are Integer overflows, those can cause your contract to trap as well. ### What are the `Encode`, `Decode` and `TypeInfo` arguments in `#[ink::scale_derive(Encode, Decode, TypeInfo)]` ? Polkadot SDK-based blockchains use the [SCALE codec](https://github.com/paritytech/parity-scale-codec) to encode data. As a consequence the data for every interaction with Polkadot SDK needs to be SCALE-encodable ‒ i.e. it needs to implement either `scale::Encode`, `scale::Decode`, or both. This affects e.g. data you want to return to a caller, data that you want to take as input, or data you want to store on-chain. ink! re-exports these traits and provides a useful macro `#[ink::scale_derive(Encode, Decode, TypeInfo)]` that allows to derive them in a concise way. A common error you might get when a necessary SCALE trait is not implemented for a data structure could be along the lines of `the trait "WrapperTypeEncode" is not implemented for "Foo"`. For example, you might encounter this error if you try to store a custom data structure in the contract's storage. Or e.g. when attempting to return a custom error from an ink! message. :::note The error `the trait "WrapperTypeEncode" is not implemented for …` is also a common error when a mismatching version of `parity-scale-codec` is used in the contract opposed to the version used by ink!. ::: The solution typically is to add a fitting implementation of the trait for your data structure: * `Encode` is used for encoding a data structure when it is e.g. returned to a caller or when it is persisted to the contracts storage. * `Decode` is used for the inverse, e.g. when reading from storage or taking an input from a user (or another contract). * `TypeInfo` is used to encode the information about the type that is often used for the generation of metadata. It's possible to derive those traits and oftentimes the simplest way is to just derive the missing trait for the object for which its implementation is missing using the ink! macro: ```rust #[ink::scale_derive(Encode, Decode)] struct MyCustomDataStructure { … } ``` ### How do I use `String` in my contract? In general, you should think twice if you really need `String`. Smart contracts usually don't use strings; those are typically used for user interactions and should live in your UI and not on the chain. Minimizing storage usage of your contract is a best practice and you should only persist items which you need to derive state transitions in your contract. If you still, for some reason, need to use `String`, then you should use the `String` [from the ink! prelude](https://use-ink.github.io/ink/ink_prelude/string/struct.String.html).

Getting a warning in cargo-contract about type compatibility?

ink! and Polkadot SDK both support the possibility of deciding to deviate from the default types for `Balance`, `BlockNumber`, etc. These types are called environment types. If a chain decides on custom environment types, contract authors need to specify these types that deviate from the ink! default environment in their contracts. Otherwise, undefined behavior can occur when uploading a contract with deviating types to a chain. Custom environment types can be specified in ink! via the `#[contract(env = MyCustomEnvironment)]` attribute. You can read more are about this [here](../macros-attributes/contract.md#env-impl-environment). When using `cargo-contract` to interact with a chain you might get a warning along those lines: ``` Warning: This chain does not yet support checking for compatibility of your contract types. ``` This warning appears when the chain that you are targeting (via the `--url` cli flag) does not contain a version of `pallet-revive` that does support type comparison. Type comparison is a feature that we introduced, it means we check that the environmental types of your contract are equivalent to the environmental types of the chain that you are targeting. It's a safety feature to make sure that you are not accidentally deploying a contract with e.g. `type Balance = u128` to a chain with a different `Balance` type. The `cargo-contract` warning means this check for compatible types cannot be performed. If a chain indeed requires that contract developers have to use custom environment types, this should be communicated prominently by them. ### When an ink! contract is compiled with support for the Solidity ABI (abi = "sol" or "all"), does anything about its on-chain storage change? No. The internal storage representation of a contract is still done in the SCALE codec! The contract ABI only describes how external interactions with a contract are encoded/decoded. Using the Solidity ABI does not imply switching to a different storage layout! ```` ## File: docs/faq/migrating-from-ink-3-to-4.md ````markdown --- title: "Migration: ink! v3 → v4" slug: /faq/migrating-from-ink-3-to-4 --- ![Migration 3.x To 4.0 Title Picture](/img/title/migration-3.x-to-4.0.svg) We've made a couple of breaking changes from ink! 3.x to ink! 4.0. On this page we outline how you can migrate existing clients and contracts from 3.x to 4.0. :::caution This migration guide is only for your code base! If you have an existing contract on-chain you cannot just upgrade the code on-chain ‒ you also have to migrate your data, since the way ink! 4.0 stores data and reads it (i.e. the storage layout) changes from ink! 3.x to 4.0. ::: ## Compatibility ink! 4.0 is compatible with: - Stable Rust >= 1.63.0 - `scale` >=3 - `scale-info` >= 2.3 - `pallet-contracts` >= `polkadot-v0.9.37` - `substrate-contracts-node` >= `v0.24.0` - `polkadot-js/api` and `polkadot-js/api-contract` >= 9.10.2 ## `cargo-contract` 2.0 Together with ink! 4.0 we've released `cargo-contract` 2.0. You have to use this latest version of `cargo-contract` for ink! 4.0 contracts. You can upgrade via: ```rust cargo install cargo-contract --force --version 2 ``` Make sure that e.g. your CI also uses `cargo-contract` 2 with ink! 4. If you have wrapper scripts around `cargo-contract` you should ensure that this version is enforced, otherwise users will get an error. :::note `cargo-contract` no longer requires `binaryen` or `wasm-opt` as an external dependency. We required those because of `wasm-opt` tool (which is part of `binaryen`). Fortunately we were able to find a way of installing `wasm-opt` now as part of the `cargo-contract` installation process. ::: ## Rust `stable` instead of `nightly` ink! 4.0 and `cargo-contract` use `stable` Rust now. This means no more `cargo +nightly contract` is required, you can just use a stable Rust toolchain now (>= Rust 1.63). ## New entrance `ink` crate The `ink_lang` crate has been replaced in [#1223](https://github.com/use-ink/ink/pull/1223) by a new top level `ink` crate. All existing sub-crates are reexported and should be used via the new `ink` crate, so e.g. `ink::env` instead of `ink_env`. Contract authors should now import the top level `ink` crate instead of the individual crates. ### Migration - In `Cargo.toml` Replace all individual `ink_*` crate dependencies with the `ink` crate. - In the contract source: - Remove the commonly used `use ink_lang as ink` idiom. - Replace all usages of individual crates with reexports, e.g. `ink_env` ➜ `ink::env`. ## Storage API + Layout With [#1331](https://github.com/use-ink/ink/pull/1331) the way `ink!` reads and writes to a contract's storage changed. Storage keys are generated at compile-time, and user facing abstractions which determine how contract data is laid out in storage are different now. ### Migration - Initialize `Mapping` fields with `Mapping::default()` instead of `ink_lang::utils::initialize_contract` in constructors. See [`erc20`](https://github.com/use-ink/ink-examples/blob/main/erc20/lib.rs) and other examples which use a `Mapping`. - `SpreadAllocate`, `SpreadLayout`, `PackedLayout`, `PackedAllocate` have been removed. ## Removal of `wee-alloc` support ink! uses a bump allocator by default, additionally we supported another allocator (`wee-alloc`) through a feature flag. `wee-alloc` is no longer maintained and we removed support for it in [#1403](https://github.com/use-ink/ink/pull/1403). ## Removal of `eth_compatibility` crate As part of [#1233](https://github.com/use-ink/ink/pull/1233) the `eth_compatibility` crate was removed. The `ecdsa_to_eth_address()` function from it can now be found [in the `ink_env` crate](https://docs.rs/ink_env/4.0.0/ink_env/fn.ecdsa_to_eth_address.html). ```rust ink_env::ecdsa_to_eth_address(&pub_key, &mut output); ``` ## `ink_storage::Mapping` The function signature of `Mapping::insert(key, val)` changed to `Mapping::insert(key, val) -> Option`. The return value is the size of the pre-existing value at the specified key if any (in bytes). Two new useful functions were added: - [`Mapping::contains(key)`](https://docs.rs/ink_storage/4.0.0/ink_storage/struct.Mapping.html#method.contains) in [#1224](https://github.com/use-ink/ink/pull/1224). - [`Mapping::take()`](https://docs.rs/ink_storage/4.0.0/ink_storage/struct.Mapping.html#method.take) to get a value while removing it from storage in [#1461](https://github.com/use-ink/ink/pull/1461). In case you were working around those two functions you can now use them directly; they are more gas-efficient than e.g. executing a `get(key).is_none()` instead of `contains(key)`. ## Storage functions in `ink_env` As part of [#1224](https://github.com/use-ink/ink/pull/1224) the return type of [`ink_env::set_contract_storage()`](https://docs.rs/ink_env/4.0.0/ink_env/fn.set_contract_storage.html) was changed to return an `Option` instead of `()`. A new function [`ink_env::take_contract_storage`](https://docs.rs/ink_env/4.0.0/ink_env/fn.take_contract_storage.html) was introduced. ## Removal of `ink_env::random` function We had to remove the [`ink_env::random`](https://docs.rs/ink_env/3.3.1/ink_env/fn.random.html) function (in [#1442](https://github.com/use-ink/ink/pull/1442)). This function allowed contract developers getting random entropy. There is unfortunately no way how this can be done safely enough with built-in Substrate primitives on-chain currently. We're following the recommendation of our auditors to remove it. The alternative right now is to provide random entropy off-chain to the contract, to use a random entropy oracle, or to have a chain-extension that does this, in case the chain has a possibility to do so. We hope to bring this function back in a future release of ink!, the best hope right now is that it could come back with [Sassafras](https://wiki.polkadot.network/docs/learn-consensus#badass-babe-sassafras), a block production protocol for future versions of Polkadot. If you're interested in more information on this check out [the Substrate PR](https://github.com/paritytech/substrate/pull/13204) which deprecated the random interface of `pallet-contracts`. ## Constructors can now return `Result` With [#1446](https://github.com/use-ink/ink/pull/1446) we introduced the possibility for constructors to return either `Self` (as usual) or `Result`. This enables contract developers to bubble up encoded error objects to clients/frontends about a failure. In ink! 3.x it was only possible to panic in the constructor in case an error occurred, resulting in loss of this information. ## Chain extension's `returns_result` removed The `returns_result` flag has been removed from the `#[ink(extension = …)]` attribute in [#1569](https://github.com/use-ink/ink/pull/1569). We now infer this information at compile time. If `handle_status` is set to `true`, the return type will still be wrapped into `Result` as before. ## Contract Metadata (ABI) The most detailed way to grasp what changed is to look at [this PR](https://github.com/use-ink/ink-docs/pull/138), which updated the metadata page in our documentation. ### Add support for language level errors (`LangError`) Under the hood, ink! now generates code that results in each message and constructor returning a `Result` (or for constructors `Result`). This happens even if the message/constructor doesn't have a return type, we default to the unit type `()` in that case. A [`LangError`](https://docs.rs/ink/4.0.0/ink/enum.LangError.html) is a type of error which doesn't originate from the contract itself, nor from the underlying execution environment (so the Contracts pallet in this case). An example of where this would arise is if a caller tries to use a non-existent message selector for a contract. Previously, the contract would trap and not allow the caller to do any sort of error handling if it encountered a non-existent selector. This change doesn't affect how you write a contract! It affects clients and frontends though, since it breaks the API in two ways: first, all contract messages now have a `Result` return type, and second a new field, `lang_error`, will be introduced as part of the contract spec. The second change allows other languages (such as Solang) to use an equivalent `LangError`.
Click here for a snippet of the new metadata for the Flipper contract.

```json "messages": [ { "args": [], "docs": [ " Flips the current value of the Flipper's boolean." ], "label": "flip", "mutates": true, "payable": false, "returnType": { "displayName": [ "ink", "MessageResult" ], "type": 1 }, "selector": "0x633aa551" }], "lang_error": { "displayName": [ "ink", "LangError" ], "type": 3 }, { "id": 3, "type": { "def": { "variant": { "variants": [ { "index": 1, "name": "CouldNotReadInput" } ] } }, "path": [ "ink_primitives", "LangError" ] } } ```

### Version field As part of [#1313](https://github.com/use-ink/ink/pull/1313) the ink! ABI was changed to have a proper version field as part of the ink! metadata object. This enables querying the ABI version in a less-ambiguous way. Before: ```json "source": {...}, "contract": {...}, "V3": { "spec": {...}, "storage": {...}, "types": {...} } ``` After: ```json { "source": {...}, "contract": {...}, "spec": {...}, "storage": {...}, "types": [...], "version": "4" } ``` ### The Storage Layout (`storage`) The storage layout under the `storage` key changed for v4. If you have an application that is using it consider reading the updated documentation: - [General storage documentation](../../versioned_docs/version-v4/datastructures/overview.md) - [Storage metadata format](../../versioned_docs/version-v4/datastructures/storage-in-metadata.md) ## Removal of `AccountId` `Default` implementation In [#1255](https://github.com/use-ink/ink/pull/1255) we removed the `Default` trait implementation on `AccountId`s. The `Default` implementation of `AccountId` returned the zero-address, which is problematic since the [zero-address in the `sr25519` and `ed25519` curves has a known private key](https://substrate.stackexchange.com/questions/982/why-does-the-all-0-public-key-have-a-known-private-key-in-sr25519-and-ed25519). Developers commonly reach for defaults, and the zero-address in particular, making it an unsafe trait implementation to have given the consequences. Imagine a developer sending tokens to the zero-address to be burned, only to find that they've been stolen because the private key is known. If you were previously using `AccountId`'s `Default` implementation in your code you have a couple of different options for how to move forward. These will depend on what exactly you were using the zero-address for. If you were using it as a burn address: - You can pick another address to use, assuming that you've actually picked a random address - Consider a solution that involves reducing total issuance, instead of transferring tokens to a random address If you were using it as a privileged account: - Change the account - Add checks to ensure that calls coming from the zero-address are rejected You should also now consider dealing with `AccountId`'s as `Option`'s. This is more idiomatic Rust, and also conveys the meaning of a "null" or "empty" address much better. ## Updates to the `CallBuilder` and `CreateBuilder` APIs There's been several changes to the [`CallBuilder`](https://docs.rs/ink_env/4.0.0/ink_env/call/struct.CallBuilder.html) and [`CreateBuilder`](https://docs.rs/ink_env/4.0.0/ink_env/call/struct.CreateBuilder.html) APIs. In [#1604](https://github.com/use-ink/ink/pull/1604) we renamed the `CallBuilder::fire()` method to [`CallBuilder::invoke()`](https://docs.rs/ink_env/4.0.0/ink_env/call/struct.CallBuilder.html#method.invoke-2). This brings more consistency across our APIs which were already using the `invoke` terminology. In [#1512](https://github.com/use-ink/ink/pull/1512) and [#1525](https://github.com/use-ink/ink/pull/1525) we added support for handing `LangError`s from the `CreateBuilder` and `CallBuilder`, respectively. If you want to handle errors from either `Builder` you can use the new [`CreateBuilder::try_instantiate()`](https://docs.rs/ink_env/4.0.0/ink_env/call/struct.CreateBuilder.html#method.try_instantiate) or [`CallBuilder::try_invoke()`](https://docs.rs/ink_env/4.0.0/ink_env/call/struct.CallBuilder.html#method.try_invoke-1) methods. Because of the addition of those methods we also removed any error handling from the non-`try_` methods in [#1602](https://github.com/use-ink/ink/pull/1602). This means that the `CallBuilder::invoke()` and `CreateBuilder::instantiate()` methods return values directly, and panic when they encounter an error. Lastly, in [#1636](https://github.com/use-ink/ink/pull/1636) we added two methods to the `CallBuilder` to streamline [`Call`](https://docs.rs/ink_env/4.0.0/ink_env/call/struct.Call.html) and [`DelegateCall`](https://docs.rs/ink_env/4.0.0/ink_env/call/struct.DelegateCall.html) workflows: - For `Call` you can use [`CallBuilder::call()`](https://docs.rs/ink_env/4.0.0/ink_env/call/struct.CallBuilder.html#method.call) (this replaces `CallBuilder::callee()`) - For `DelegateCall` you can use [`CallBuilder::delegate()`](https://docs.rs/ink_env/4.0.0/ink_env/call/struct.CallBuilder.html#method.delegate) ## Removal of `[lib.crate-type]` and `[lib.name]` from contract manifest Earlier versions of `cargo-contract` required that these two fields were specified in the contract manifest explicitly, as follows: ```toml [lib] name = "flipper" path = "lib.rs" crate-type = [ # Used for normal contract Wasm blobs. "cdylib", # Use to generate ABI "rlib", ] ``` However, with [cargo-contract#929](https://github.com/use-ink/cargo-contract/pull/929) we changed this behavior to: - Use the contract name by default, removing the need for the `name` field - Compile contracts as `rlib`s by default, and automatically changing to `cdylib` as needed This means that your new manifest should look like: ```toml [lib] path = "lib.rs" ``` ```` ## File: docs/faq/migrating-from-ink-4-to-5.md ````markdown --- title: "Migration: ink! v4 → v5" slug: /faq/migrating-from-ink-4-to-5 --- ![Migration 4.x To 5.0 Title Picture](/img/title/migration-4.x-to-5.0.svg) We've made a couple of breaking changes from ink! 4.x to ink! 5.0. On this page we outline how you can migrate existing dApps and contracts from 4.x to 5.0. This release addresses the majority of issues raised in [the OpenZeppelin security review](https://blog.openzeppelin.com/security-review-ink-cargo-contract). In particular, we addressed the proxy selector clashing attack. You can find the full changelog of the 5.0 release [here](https://github.com/use-ink/ink/blob/master/CHANGELOG.md#version-500). :::caution This migration guide only considers your code base! Not your storage data! If you have an existing contract on-chain you might not be able to just upgrade the code on-chain, you possibly also have to migrate your storage data. The relevant change that you have to take into consideration is [#1897](https://github.com/use-ink/ink/pull/1897). A data migration may be required when your contract reads data from storage and truncates the data when decoding it. We've described this in more detail below, in the section ["Fail when decoding from storage and not all bytes consumed"](#fail-when-decoding-from-storage-and-not-all-bytes-consumed). ::: ## How to upgrade - Change the dependency versions of `ink` and `ink_e2e` in your contracts `Cargo.toml` to `5`. - Update your local `cargo-contract` installation to 4.0. - Read through this page. ## Compatibility ### Substrate/Polkadot SDK There are four new functions that are only compatible from particular releases upwards: - v2 of `call` and `instantiate`: `>= polkadot-v1.8.0` and `substrate-contracts-node >= v0.39.0` ([explained here](#call-and-instantiate-v2)). - `lock_delegate_dependency` and `unlock_delegate_dependency`: `>= polkadot-v1.9.0` and `substrate-contracts-node >= v0.40.0` ([explained here](#upgradeable-contracts-delegate_dependency)). These four functions are all opt-in! None of them are required to use ink! 5.0, they are only required if you want to access the particular functionality they provide. Please see the linked explainers for more details about them. If you are not using any of those four functions, the same requirements as for ink! 4.0 holds: - `pallet-contracts` >= `polkadot-v0.9.37`. - `substrate-contracts-node` >= `v0.24.0` ### How do I find out if a chain is compatible with ink! 5? You can query `contracts::palletVersion()` via the chain state RPCs. It has to be `>= 9` for ink! 5.0 to be compatible, if you don't use any of the four functions mentioned above. For the above mentioned four functions please see the respective sections on this page, there we explain how to find out if a chain supports them there. You can use the [polakdot.js app](https://polkadot.js.org/apps/) to do this: Developer » Chain State » `contracts` » `palletVersion()` » Click on the `+` on the right. The following chains are in production and support ink! 5.0, if you are not using any of the four functions mentioned above: ### `cargo-contract` 4.0 Together with ink! 5.0 we've released `cargo-contract` 4.0. :::info You have to use `cargo-contract` >= 4.0 for ink! 5.0 contracts! You can upgrade via: ```rust cargo install cargo-contract --version ^4 ``` ::: Make sure that e.g. your CI also uses at least `cargo-contract` 4.0 with ink! v5.0. If you have wrapper scripts around `cargo-contract`, you should ensure that this version is enforced, otherwise users will get an error. ### Tooling & Libraries - Stable Rust >= 1.75 - `cargo-contract` >= v4.0 - `polkadot-js/api` and `polkadot-js/api-contract` >= 10.12.1 - [`use-inkathon`](https://github.com/scio-labs/use-inkathon): upgrade the `polkadot-js/api` and `polkadot-js/api-contract` dependencies in your project to >= 10.12.1 - [ink!athon](https://inkathon.xyz/) >= 0.7.0 - [`typechain-polkadot`](https://github.com/Brushfam/typechain-polkadot) >= 1.2.0 ## Important Changes We had to introduce a number of changes that require you to manually upgrade your contract from 4.x to 5.0. The steps to do this are explained in this section. ### `scale` dependencies were moved to `ink` entrance crate This change was done to ensure that you always use the correct scale dependency versions with an ink! version. The relevant PR is [#1890](https://github.com/use-ink/ink/pull/1890). We removed the requirement for contracts to have direct dependencies on `parity-scale-codec` and `scale-info` in their `Cargo.toml`. You can now remove those dependencies from your contracts `Cargo.toml`: ```diff ink = { version = "4.3", default-features = false } -scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } ``` Both crates have been re-exported from the `ink` umbrella crate: `ink::scale_info` and `ink::scale`. We created a convenience macro to derive the re-exported traits `ink::scale::Encode`, `ink::scale::Decode` and `ink::scale_info::TypeInfo`. ```rust // Previously #[scale::Encode, scale::Decode)] #[cfg_attr(feature = "std", derive(::scale_info::TypeInfo))] pub enum Error {} // Now #[ink::scale_derive(Encode, Decode, TypeInfo)] pub enum Error {} ``` The documentation of the macro can be found [here](https://docs.rs/ink/5.0.0/ink/attr.scale_derive.html). ### Wildcard selectors: only one other message is allowed in the contract besides the wildcard selector Following [our security review by OpenZeppelin](https://blog.openzeppelin.com/security-review-ink-cargo-contract), we've tightened the usage of wildcard selectors. With ink! 5.0 we allow only exactly one other contract message with a well-known reserved selector to be defined. In ink! 4.x, more than one other message was allowed. Read more in [the PR](https://github.com/use-ink/ink/pull/1708) and [IIP-2: Limit contracts with a wildcard selector to one other message](https://github.com/use-ink/ink/issues/1676). The proposal is to restrict contracts with a wildcard selector to only have one other message with a reserved/well-known selector. This guarantees that there are no selector clashes, either by chance or malicious intent, and that the Proxy will only handle messages intended for it. If a contract uses a wildcard selector `#[ink(message, payable, selector = _)]` it _MAY_ define one other message. This message _MUST_ use the reserved selector `@`. This selector _MUST_ only be used in conjunction with a wildcard selector. ```rust /// Handles any message with no matching selector in this proxy contract #[ink(message, selector = _)] pub fn fallback(&self) { // forward call to the "logic" contract which actually executes the call } #[ink::scale_derive(Decode)] pub enum ProxyMessage { UpgradeContract(Hash), } /// One other message allowed to handle messages. /// Fails to compile unless `@` is used as the selector. #[ink(message, selector = @)] pub fn handler(&self, msg: ProxyMessage) { match msg { ProxyMessage(hash) => { } } } /// An additional message. Fails to compile when uncommented. // #[ink(message)] // pub fn additional_message(&self, msg: ProxyMessage) { // match msg { // ProxyMessage(hash) => ... // } // } ``` ### Events 2.0 In prior ink! versions, events were defined inside the `#[ink::contract]` macro. With ink! 5.0 we decouple events from the `#[ink::contract]` macro, allowing events to be shared between contracts. We've updated [the Events documentation page](../basics/events.md) accordingly. The syntax of defining events within the main `#[ink::contract]` macro will continue to work, no code changes in existing contracts are required to update to the new syntax. :::caution The topic calculation changed in general, so also for events that are declared inside the `#[ink::contract]` macro! This is a breaking change for any client code which uses topics to filter events. Please see [#1827](https://github.com/use-ink/ink/pull/1827) for details. ::: #### Custom signature topics In [#2031](https://github.com/use-ink/ink/pull/2031) we introduced an optional attribute `signature_topic` to the `#[ink::event]` and `#[ink(event)]` macros. It can be used to specify the signature topic for a specific event manually, instead of the automatic topic calculation. ### No more unchecked arithmetic Unchecked arithmetic operations in a contract are no longer supported for arithmetic safety reasons. Compiling a contract that contains those will fail gracefully. If you haven't already done, you now need to handle overflows that could occur. Rust supports different possibilities of doing so (saturating, "wrap around", and unchecked arithmetic operations) . See [this](https://doc.rust-lang.org/book/ch03-02-data-types.html#scalar-types) section of the Rust Programming Language for a thorough explanation on how to do safe arithmetic operations in Rust. This change was introduced in [#1831](https://github.com/use-ink/ink/pull/1831). ### Fail when decoding from storage and not all bytes consumed If a contract previously relied on successful decoding which does not consume all bytes, then recompiling with a version of ink! which includes this change will cause that contract to trap at runtime when attempting to decode. A simple example would be if a storage cell contains some bytes which were in the first place an encoded `u32`. If the contract attempts to decode those into a `u8` this would previously have succeeded, now the contract would trap. Here's a code example of behavior that previously worked for ink! 4.x, but would error now: ```rust let key = 0u32; let value = [0x42; 32]; ink::env::set_contract_storage(&key, &value); // Only attempt to read the first byte (the `u8`) of the storage value data let _loaded_value: Option = ink::env::get_contract_storage(&key) .map_err(|e| format!("get_contract_storage failed: {:?}", e))?; ``` We introduced this change in [#1897](https://github.com/use-ink/ink/pull/1897). ### [ink_e2e] API Changes #### Builder API In [#1917](https://github.com/use-ink/ink/pull/1917) we reworked the E2E API with a builder API. `instantiate`, `call` and `upload` will now return a builder instance. You can specify optional arguments with builder methods, and submit the call for on-chain execution with the `.submit()` method, or dry-run it with `dry_run()`. ```rust let contract = client .instantiate("flipper", &ink_e2e::alice(), &mut constructor) .submit() .await .expect("instantiate failed"); let mut call_builder = contract.call_builder::(); let get = call_builder.get(); let get_res = client.call(&ink_e2e::bob(), &get).dry_run().await; assert!(matches!(get_res.return_value(), false)); ``` #### Extra gas margin As part of [#1917](https://github.com/use-ink/ink/pull/1917) we added the possibility to specify a gas margin (in percentage) as part of the on-chain call. There are cases when gas estimates may not necessarily be accurate enough due to the complexity of the smart contract logic that adds additional overhead and gas consumption. Therefore, it is helpful to allow to specify an extra portion of the gas to be added to the limit (i.e. 5%, 10%). The method `.extra_gas_portion(margin: u64)` method is part of the builder API: - [`ink_e2e::InstantiateBuilder::extra_gas_portion`](https://docs.rs/ink_e2e/5.0.0/ink_e2e/struct.InstantiateBuilder.html#method.extra_gas_portion) - [`ink_e2e::CallBuilder::extra_gas_portion`](https://docs.rs/ink_e2e/5.0.0/ink_e2e/struct.CallBuilder.html#method.extra_gas_portion) #### Improved `call()` API We removed the `build_message()` function with its unhandy callback. ```rust // Previously let first_insert = ink_e2e::build_message::(contract_id) .call(|contract| contract.insert_balance(1_000)); // Now let first_insert = ink_e2e::build_message::(contract_id) .call().insert_balance(1_000)); ``` See [#1782](https://github.com/use-ink/ink/pull/1782) for more details. #### Removed `additional_contracts` parameter `additional_contracts` parameter which is part of `#[ink_e2e:test]` has been removed in [#2098](https://github.com/use-ink/ink/pull/2098). This information is now implied from the contract's manifest. Simply, add the other contract as dependency with the `ink-as-a-dependency` feature enabled. The test will detect the contract and build it as part of the test. #### In [#2076](https://github.com/use-ink/ink/pull/2076), we've added a new [`remove_code`](https://docs.rs/ink_e2e/5.0.0/ink_e2e/trait.ContractsBackend.html#method.remove_code) function to the E2E API: ```rust let contract = client .remove_code(&ink_e2e::alice(), code_hash) // Submit the call for on-chain execution. .submit() .await .expect("remove failed"); ``` ### New Data Structure: `StorageVec` We've added a `Vec`-like data structure, built on top of Mapping. This allows to retrieve elements from a vector and grow it without having to load and push all elements. For `Vec`, the cost of reading or writing a single element grows linearly corresponding to the number of elements in the vector (its length). Additionally, the maximum capacity of the whole vector is limited by the size of [ink!'s static buffer](https://github.com/use-ink/ink/blob/master/ARCHITECTURE.md#communication-with-the-pallet) used during ABI encoding and decoding (default 16 KiB). `StorageVec` on the other hand allows to access each element individually. With a `Vec` it's possible to e.g. introduce a security issue in your contract where an attacker can fill the `Vec`, making it very costly for other users to access it or write to it. You can find verbatim documentation on `StorageVec` [here](../datastructures/storagevec.md). The page explains when to use `StorageVec` and when not. The Rust docs can be found [here](https://docs.rs/ink/5.0.0/ink/storage/struct.StorageVec.html). ### Fallible methods for `Lazy`, `Mapping`, `StorageVec` In [#1910](https://github.com/use-ink/ink/pull/1910) we added `try_*` methods for reading and writing `Lazy` and `Mapping` values to and from storage. The try methods correspond to `Mapping::{insert, get, take}`, `Lazy::{set, get}`. For `StorageVec::{peek, get, set, pop, push}` we added `try_*` methods in [#1995](https://github.com/use-ink/ink/pull/1995). Please see the individual Rust docs for these new methods: - [`StorageVec`](https://docs.rs/ink/5.0.0/ink/storage/struct.StorageVec.html) - [`Lazy`](https://docs.rs/ink/5.0.0/ink/storage/struct.Lazy.html) - [`Mapping`](https://docs.rs/ink/5.0.0/ink/storage/struct.Mapping.html). For `Mapping`, the encoded size of the key is also accounted for. You should use the `try_*` methods for dynamically sized values, unless you made sure otherwise they will fit into the static buffer. The [static buffer in ink!](https://github.com/use-ink/ink/blob/master/ARCHITECTURE.md#communication-with-the-pallet) is 16 kB by default. We added a lint to `cargo-contract` 4.0 that will detect potentially unsafe uses of methods for which there are safer alternatives: [`non_fallible_api`](../linter/rules/non_fallible_api.md). ### Chain Extension API changed + Support for multiple chain extensions With [#1958](https://github.com/use-ink/ink/pull/1958) we added support for interacting with multiple chain extensions from ink!. This is a breaking change. You can now e.g. have a contract that utilizes a PSP22 chain extension together with one for random numbers. The syntax for chain extension functions changed slightly: ```diff -#[ink(extension = 0xfecb)] +#[ink(function = 0xfecb)] fn foo() {} ``` The argument type changed from `u32` to `u16`: ```diff -/// `#[ink(extension = N: u32)]` -Extension, +/// `#[ink(function = N: u16)]` +Function, ``` The top level macro `#[ink::chain_extension]` now _requires_ an `(extension = N: u16)` argument to support multiple chain extensions. If you are using only one extension, the ID can be any `u16` number, otherwise please consult the [`#[ink::chain_extension]` macro documentation](https://use.ink/docs/v5/macros-attributes/chain-extension). ```diff -#[ink::chain_extension] +#[ink::chain_extension(extension = 1)] ``` :::note If the chain extension was not used in a tuple in the runtime configuration, `extension = N: u16` can take any `u16` number. ::: A migration in most cases should just be to rename `#[ink(extension = …)]` to `#[ink(function = …)]`, and specifying `extension` argument in top level macro. We added an example contract that illustrates the usage of multiple chain extensions in one contract: [`combined-extension`](https://github.com/use-ink/ink-examples/tree/main/combined-extension). ### `call` and `instantiate` v2 The functions to instantiate and call other contracts got an upgrade in the `polkadot-v1.8.0` release (in the [`d250a6`](https://github.com/paritytech/polkadot-sdk/commit/d250a6e4270a77f28e2737a4faa3fb78c8ea7a85) commit), The new v2 of them allows passing both `Weight` parts (`ref_time_limit` and `proof_size_limit`), as well as the `storage_deposit_limit`. The previous v1 `call` and `instantiate` functions only provided a single `gas_limit` parameter, which was used as the value for `ref_time_limit`. You can still use these `v1` versions. For `call` on a call builder obtained through [`build_call`](https://docs.rs/ink_env/5.0.0/ink_env/call/fn.build_call.html): ``` call_builder .call_v1() .gas_limit(ref_time_limit) .invoke(); ``` For `instantiate` on [`build_create`](https://docs.rs/ink_env/5.0.0/ink_env/call/fn.build_create.html): The new `v2` parameters can be set like so: ```rust call_builder // or `create_builder` .ref_time_limit(ref_time_limit) .proof_size_limit(proof_size_limit) .storage_deposit_limit(storage_deposit_limit) .invoke(); ``` You can find out if a chain supports the new `v2` functions for call/instantiate by querying the `contracts::apiVersion` constant. It has to be `1`. You can use the [polakdot.js app](https://polkadot.js.org/apps/) to do this: Developer » Chain State » Constants » `contracts` » `apiVersion` » Click on the `+` on the right. At the time of the ink! v5 release (March 2024) no parachain with ink! support had upgraded to `polkadot-v1.8.0` yet. Please note that if you are using trait definitions for cross-contract calls, direct calls from the `contract_ref!` macro are only supported with the `call_v2`. Otherwise, you need to get the `CallBuilder` from the structure and build the call manually. ```rust type Erc20Wrapper = contract_ref!(Erc20); let erc20: Erc20Wrapper = new_erc20.into(); let erc20_builder = erc20.call(); erc20_builder.total_supply().call_v1().invoke() ``` ### Metadata Changes #### Events 2.0 See [#1827](https://github.com/use-ink/ink/pull/1827) for the full details. Two fields werere added to the objects in the `events` array: `module_path` and `signature_topic`. Previously the order of the events in the `events` array was significant (i.e. the first one had an implied index of `0`), and this index could be used to determine which event to decode. Now that is replaced by the `signature_topic`, and the order of the events in the metadata no longer has any significance. See the section "[Events 2.0](#events-20)" on this page for more info. ink! 4.0: ```json "events": [ { "args": [ ... ], "docs": [ ... ], "label": "Transfer" }, ... ] ``` ink! 5.0: ```diff "events": [ { "args": [ ... ], "docs": [ ... ], "label": "...", + "module_path": "erc20::erc20", + "signature_topic": "0xb5b61a3e6a21a16be4f044b517c28ac692492f73c5bfd3f60178ad98c767f4cb" }, ... ] ``` #### New field: `staticBufferSize` With [#1880](https://github.com/use-ink/ink/pull/1880) we added a `"staticBufferSize"` field to the metadata file. The unit is bytes. See the section "[Buffer size can be customized](#buffer-size-can-be-customized)" on this page for more info. Example: ```diff "maxEventTopics": 4, + "staticBufferSize": 16384, "timestamp": { ... } ``` #### Metadata storage keys encoding change Storage keys used to access storage data are SCALE encoded. Previously, the contract metadata used big endian encoding to represent storage keys. With the ink! 5.0 release, these encoding formats have been aligned, and SCALE encoding (little endian) is now used for the metadata storage keys. This is a breaking change, and client tools that use the storage keys from contract metadata will need to adapt accordingly. Please see: [#2048](https://github.com/use-ink/ink/pull/2048) for details. Example: ```diff "storage": { "root": { "layout": { "struct": { "fields": [ { "layout": { "leaf": { - "key": "0x00000159", + "key": "0x59010000", "ty": 0 } }, "name": "value" } ], "name": "Flipper" } }, - "root_key": "0x00000159", + "root_key": "0x59010000", "ty": 1 } }, ``` ## Interesting New Features ### End-To-End testing with a chain snapshot With ink! 5.0 we introduce the possibility of running your tests against the fork (i.e. snapshot) of a live chain. See [this page](../testing/testing-with-live-state.md) in our documentation for details. ### New lints The new lints are: - [`no_main`](../linter/rules/no_main.md): enforces `no_main` for contracts. - [`primitive_topic`](../linter/rules/primitive_topic.md): no number types are allowed as event topics. - [`storage_never_freed`](../linter/rules/storage_never_freed.md): what is written into storage can be removed again. - [`strict_balance_equality`](../linter/rules/strict_balance_equality.md): detects usage of strict balance equality checks, a common smart contract vulnerability. - [`non_fallible_api`](../linter/rules/non_fallible_api.md): detects the usage of potentially unsafe methods for which there are safer alternatives. With `cargo-contract` 4.0 we added a couple new lints for common smart contract issues and best practices. You can run the linter via `cargo contract build --lint`. Details on each lint can be found [here](../linter/overview.md). ### New `cargo-contract` commands We added a bunch of helpful new commands to `cargo-contract` 4.0. For all these commands you can also supply the `--help` cli flag to get more info (e.g. `cargo contract storage --help`). - `cargo contract verify`: contract verification ([#1404](https://github.com/use-ink/cargo-contract/pull/1404), [#1306](https://github.com/use-ink/cargo-contract/pull/1306)) - `cargo contract info` now outputs the language of the deployed contract, using a heuristic ([#1329](https://github.com/use-ink/cargo-contract/pull/1329)) - `cargo contract info --binary`: outputs the on-chain Wasm of the contract ([#1311](https://github.com/use-ink/cargo-contract/pull/1311/)) - `cargo contract info --all`: displays all addresses of deployed contracts on a particular chain ([#1319](https://github.com/use-ink/cargo-contract/pull/1319)) - `cargo contract storage`: displays the storage of an on-chain contract ([#1395](https://github.com/use-ink/cargo-contract/pull/1395), [#1414](https://github.com/use-ink/cargo-contract/pull/1414))
### Alternative off-chain E2E testing backend support: DRink! DRink! is a toolbox for ink! developers that allows for testing your contracts without any running node. It has a number of features that are pretty great: - deploy and call your contracts synchronously, _without any delays_ related to block production or networking. - enhanced debugging and call tracing. - supports _arbitrary runtime_ configurations, including custom chain extensions and runtime calls. - full control over runtime state, including block number, timestamp, etc. See the [DRink!](https://github.com/inkdevhub/drink) page for more details. ### Contract Verification We added a bunch of helpful documentation and `cargo-contract` commands for contract verification. Please see the page on contract verification under "Basics" for more details. ### We improved the contract example illustrating upgradeable contracts via `delegate_call` See [here](https://github.com/use-ink/ink-examples/tree/main/upgradeable-contracts) for the contract example. ### Upgradeable Contracts: `delegate_dependency` We've added support for two new host functions: - `lock_delegate_dependency`: prevents the code at the given code hash from being removed. - `unlock_delegate_dependency`: releases the lock on preventing the code from being removed from the current contract. Having a delegate dependency allows contracts to safely delegate to another `code_hash` with the guarantee that it cannot be deleted. We've updated the [`upgradeable-contracts/delegator`](https://github.com/use-ink/ink-examples/tree/main/upgradeable-contracts#delegator) example to demonstrate these new calls. For that purpose we've also added a [`remove_code`](https://docs.rs/ink_e2e/5.0.0/ink_e2e/trait.ContractsBackend.html#method.remove_code) function to the E2E API. These two functions are only available from `polkadot-1.8.0` on. You can find out if a chain supports these new functions by querying the `contracts::apiVersion` constant. It has to be `2`. You can use the [polakdot.js app](https://polkadot.js.org/apps/) to do this: Developer » Chain State » Constants » `contracts` » `apiVersion` » Click on the `+` on the right. At the time of the ink! v5 release (March 2024) no parachain with ink! support had upgraded to `polkadot-v1.8.0` yet. ### We made `set_code_hash` generic The `self.env().set_code_hash()` method now accepts the `Hash` environment type instead of a concrete `[u8; 32]`. ```rust // Previously pub fn set_code(&mut self, code_hash: [u8; 32]) { ink::env::set_code_hash(&code_hash).unwrap_or_else(|err| {}); } // Now pub fn set_code(&mut self, code_hash: Hash) { self.env().set_code_hash(&code_hash).unwrap_or_else(|err| {}); } ``` More details in [#1906](https://github.com/use-ink/ink/pull/1906). ### Buffer size can be customized With [#1869](https://github.com/use-ink/ink/pull/1869) we added a possibility of setting a custom static buffer size for ink! to use. ink! uses a static buffer for interacting with pallet-contracts, i.e. to move data between `pallet-contracts` and a smart contract. The advantage of a static buffer is that no gas-expensive heap allocations are necessary, all allocations are done using simple pointer arithmetic. The default static buffer size is 16 kB, which is enough for on-chain smart contracts. However, the [Phala Network](https://phala.network/) parachain on Polkadot allows the deployment of ink! contracts off-chain. Hence, for their chain certain high computation contracts might require a larger buffer size. ### Stabilized `call_runtime` We stabilized `call_runtime` in [#1749](https://github.com/use-ink/ink/pull/1749). It can be used to call a runtime dispatchable from an ink! contract. You can find a contract example and a comparison with chain extensions [here](https://github.com/use-ink/ink-examples/tree/main/call-runtime). We've added an example of how to end-to-end test `call_runtime` [here](https://github.com/use-ink/ink-examples/tree/main/e2e-call-runtime). ```` ## File: docs/faq/migrating-from-ink-5-to-6.md ````markdown --- title: "Migration: ink! v5 → v6" slug: /faq/migrating-from-ink-5-to-6 --- import useBaseUrl from '@docusaurus/useBaseUrl'; We've made a number of breaking changes from ink! 5.x to ink! 6.0. On this page we outline how you can migrate existing dApps and contracts. The biggest change is that we've migrated from `pallet-contracts` + WebAssembly (executed in `wasmi`) to [`pallet-revive`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive) + RISC-V (executed in [PolkaVM](https://github.com/paritytech/polkavm/)). _This is a major breaking change, ink! v6 is only compatible with `cargo-contract` >= v6 and chains that include `pallet-revive`._ We did a detailed write-up of the background to this development and the reasoning [here](https://r0gue.medium.com/ink-project-state-q1-25-08441f4ac5d2). You can find the full changelog of the 6.0 release [here](https://github.com/use-ink/ink/blob/master/CHANGELOG.md#version-600). :::caution This migration guide only considers your code base! Not your storage data! If you have an existing contract on-chain you might not be able to just upgrade the code on-chain, you possibly also have to migrate your storage data. ::: ## Compatibility - **`polkadot-sdk`**: [`polkadot-sdk/cbab8ed4be1941420dd25dc81102fb79d8e2a7f0`](https://github.com/paritytech/polkadot-sdk/commit/cbab8ed4be1941420dd25dc81102fb79d8e2a7f0) (Oct 15, 2025) - For the latest compatibility requirements of Rust, `cargo-contract` and the `ink-node`, see the [setup instructions](/docs/v6/getting-started/setup). ### How do I find out if a chain is compatible with ink! 6.0? You can query `contracts::palletVersion()` via the chain state RPCs. It has to be `>= 9` for ink! 5.0 to be compatible, if you don't use any of the four functions mentioned above. For the above mentioned four functions please see the respective sections on this page, there we explain how to find out if a chain supports them there. You can use the [polkadot.js app](https://polkadot.js.org/apps/) to connect to the chain and check if `reviveApi` is available under Developer » Runtime calls. The following chains are in production and support ink! 6.0. ## Important Changes We had to introduce a number of changes that require you to manually upgrade your contract from 5.x to 6.0. The steps are explained in this section. ### Restrict which `cfg` attributes can be used This change was done as a recommendation from the ink! 5.x audit. In a nutshell it prevents developers from hiding functionality in a contract, that would not be visible in the metadata (so e.g. on a block explorer). The relevant PR is [#2313](https://github.com/use-ink/ink/pull/2313). From ink! 6.0 on only these attributes are allowed in `#[cfg(…)]`: - `test` - `feature` (without `std`) - `any` - `not` - `all` ### Metadata Changes The field `source.wasm` was renamed to `source.contract_binary`. ### Types #### Contract Balance: `U256` For the type of a contract's balance, `pallet-revive` uses depending on the context * either the configured `pallet_revive::Config::Currency` type (which corresponds to the `ink::Environment::Balance` type. * or a hardcoded `U256` (which corresponds to what Ethereum uses). In this alpha release we just adhere to requiring the types that `pallet-revive` uses. In an upcoming beta release this could be simplified to reduce UX friction by just using one type everywhere and converting to the `pallet-revive` one. #### Contract Address: `Address` / `H160` For a contract's account, `pallet-revive` is using either the configured `AccountId` type of the `polkadot-sdk` runtime, or `H160`. `Address` is a more semantically named type alias for `H160` defined in `ink_primitives`, and re-exported in the `ink` crate. Finding the `Address`/`H160` for an `AccountId` is done via an address derivation scheme derived in [#7662](https://github.com/paritytech/polkadot-sdk/pull/7662). After instantiating a contract, the address is no longer returned by `pallet-revive`. Instead one has to derive it from given parameters (see the linked PR). `cargo-contract` does that automatically. For contract instantiations and contract calls the pallet requires that a 1-to-1 mapping of an `AccountId` to an `Address`/`H160` has been created. This can be done via the `map_account`/`unmap_account` API. The PR [#6096](https://github.com/paritytech/polkadot-sdk/pull/6096) contains more information. Besides the publicly exposed crate functions, we've introduced a new subcommand `cargo contract account` that allows resolving the `H160` contract address to the Polkadot SDK `AccountId` which it is mapped to. #### Contract Hash: `H256` For a contract's hash value, `pallet-revive` uses a fixed `H256`, Previously, the `ink::Environment::Hash` type referenced the hash type being used for the contract's hash. Now it's just a fixed `H256`. ### Contract delegates can no longer be done by code In `pallet-contracts` (and hence up until ink! v5), a pattern for upgradeable contracts was to delegate the contract execution to a different code, e.g. to a new version of the contract's code. This distinction of contract code that was uploaded to a chain vs. an instantiated contract from this code no longer exists in `pallet-revive`. If you want to delegate the execution, you will have to specify another contract's address to which code you want to delegate to. This other contract needs to be instantiated on-chain. For the execution, the context of the contract that delegates will continue to be used (storage, caller, value). Specifically the delegate API changed like this: ```rust /// ink! v5 #[derive(Clone)] pub struct DelegateCall { code_hash: E::Hash, call_flags: CallFlags, } /// ink! v6 #[derive(Clone)] pub struct DelegateCall { address: H160, flags: CallFlags, ref_time_limit: u64, proof_size_limit: u64, deposit_limit: Option<[u8; 32]>, } ``` ### Feature `ink/unstable-hostfn` In `pallet-revive` a number of functions can only be called by smart contracts if the chain that the pallet is running on has enabled the feature `pallet-revive/unstable-hostfn`. This feature is not enabled on Kusama or Westend! It is enabled for the `ink-node` version that we linked above, and on Paseo Passet Hub. ### New debugging workflow Previously `pallet-contracts` returned a `debug_message` field with contract instantiations and dry-runs. Whenever `ink::env::debug_println` was invoked in a contract, ink! wrote debugging info to this field. This functionality has been removed. Instead `pallet-revive` now supports other means of debugging. The most relevant new debugging workflow is the tracing API. There are a number of PRs that implemented it, so we won't link a specific one here. A good starting point to look deeper into it is the [`tracing.rs`](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/tracing.rs). We have implemented barebones support for this tracing API in the 6.0.0-alpha versions of ink! + `cargo-contract`. But it's really barebones and should certainly be improved before a production release. We've updated [the Debugging chapter](../debugging/overview.md) of this documentation to reflect the new workflow. We've also added a contract example to illustrate these new debugging strategies: [`debugging-strategies`](https://github.com/use-ink/ink/tree/master/integration-tests/public/debugging-strategies). ### Removed Events In [#7164](https://github.com/paritytech/polkadot-sdk/pull/7164), Parity removed most smart-contract-specific events: `Called`, `ContractCodeUpdated, CodeStored`, `CodeRemoved`, `Terminated`, `Instantiated`, `DelegateCalled`, `StorageDepositTransferredAndHeld`, `StorageDepositTransferredAndReleased`. The `ContractEmitted` event (for events a contract emits) is still available. ### `no_main` Previously ink! contracts started with this line: ```rust #![cfg_attr(not(feature = "std"), no_std)] ``` This line instructs the Rust compiler to not link the Rust standard library with your contract. If you want to know about why: we have an entry ["Why is Rust's standard library (stdlib) not available in ink!?"](./faq.md) in our FAQ. With ink! v6, an additional crate-level attribute needs to be set: ```rust #![cfg_attr(not(feature = "std"), no_std, no_main)] ``` It instructs the compiler not to use the default `fn main() {}` function as the entry point for your smart contract. This is needed because PolkaVM uses a different entry point (the `deploy` function). ### `substrate-contracts-node` can no longer be used The `substrate-contracts-node` is still maintained by Parity for ink! v5 and `pallet-contracts`, but it does not support `pallet-revive`. We've set up a new project in its place: [`ink-node`](https://github.com/use-ink/ink-node). As before, it functions as a simple local development node. It contains `pallet-revive` in a default configuration. You can find binary releases of the node [here](https://github.com/use-ink/ink-node/releases). ### Solang can no longer be used It was previously possible to interact with Solidity contracts compiled via the Solang compiler. As we have moved from WebAssembly/`pallet-contracts` to PolkaVM/RISC-V/`pallet-revive`, users who want to deploy Solidity will use [the Parity `revive` compiler](https://github.com/paritytech/revive). It takes Solidity contracts and compile them into RISC-V for PolkaVM. ### `payable` messages are now considered state-mutating To align with how Solidity is treated by `pallet-revive`, we decided on this breaking change. The implication is that you can no longer mark `&self` ink! messages as `payable`, they have to be `&mut self` now. ```diff #[ink(message, payable)] -pub fn my_message(&self) {} +pub fn my_message(&mut self) {} ``` ### Removed `call_runtime` and Chain Extensions The `pallet-revive` no longer provides a host function to call into the runtime. Parity removed this feature as the runtime can change and changes could potentially break already deployed contracts. The way to go instead would be to create [a precompile contract](../basics/precompiles.md) and have your contract invoke either a cross-contract call or a delegate call into that one. This is also the migration path recommended for Chain Extensions. ### Renamed `ink::contract_ref!` to `ink::contract_ref_from_path!` This was necessary because we introduced a new [`#[ink::contract_ref]` attribute][contract-ref-attr]. The PR [#2648](https://github.com/use-ink/ink/pull/2648) contains more information about the motivation and benefits of this change. [contract-ref-attr]: ../macros-attributes/contract_ref.md ### Sandbox was moved out of `ink_e2e` We moved the sandbox testing environment to a separate crate. It changes the current behaviour from: ```toml [dev-dependencies] ink_e2e = { version = "…", feature = "sandbox" } ``` to ```toml [dev-dependencies] ink_e2e = { version = "6.0.0-beta" } ink_sandbox = { git = "https://github.com/use-ink/ink.git", branch = "6.0.0-beta" } ``` In the tests, you need to apply this change when using `sandbox`. Instead of: ```rust #[ink_e2e::test(backend(runtime_only(sandbox = sandbox_runtime::ContractCallerSandbox)))] ``` Change to: ```rust #[ink_sandbox::test(backend(runtime_only( sandbox = sandbox_runtime::ContractCallerSandbox, client = ink_sandbox::SandboxClient )))] ``` ## Interesting New Features ### Solidity ABI compatible ink! contracts We are introducing an `abi` field in a custom `ink-lang` table in the [`package.metadata` table][package-metadata] of a contract's manifest file (i.e. the `Cargo.toml` file). It allows building your contract in Solidity ABI compatibility mode when declared as follows: ```toml [package.metadata.ink-lang] abi = "sol" ``` The implication of supporting Solidity ABI encoding is that all types used as constructor/message argument and return types, and event argument types must define a mapping to an equivalent Solidity ABI type. You won't be able to use Rust types for which no mapping to a Solidity ABI type is defined. An error about a missing trait implementation for this type will be thrown. You can learn more about [Rust/ink! to Solidity ABI type mapping here][sol-type-mapping]. :::note This is similar to the requirement to implement `scale::Encode` and `scale::Decode` for Rust types used in the public interfaces of ink!/"native" ABI encoded contracts. ::: The default value for `abi` is currently `"ink"`, but we might change this before a production release. The other option is `abi = "all"`. In this mode, the generated contract will support both the ink! and Solidity ABI, however, the contract size will get larger. You can learn more about [supported ABI modes here][abi-declaration]. [package-metadata]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-metadata-table [abi-declaration]: ../basics/abi/overview.md#declaring-the-abi [sol-type-mapping]: ../integrations-and-sdks/ethereum-compatibility.md#rustink-to-solidity-abi-type-mapping ### Cross-contract calling Solidity contracts `CallBuilder` now allows you to call contracts that are Solidity ABI encoded. You can learn more [here](../basics/cross-contract-calling.md#callbuilder-solidity). ### Generate Solidity metadata for a Solidity ABI compatible ink! contract We added a new subcommand: ```bash cargo contract build ---metadata ``` You can learn more [here](../basics/metadata/solidity-format.md). ### Ability to build contract with features during E2E tests We've added the possibility to set a feature to build a contract with during e2e tests: ```rust #[ink_e2e::test(features = ["debug-info"])] ``` This allows for e.g. emitting debug events in the contract, which you can then check for in testing. Please see our [`debugging-strategies`](https://github.com/use-ink/ink/tree/master/integration-tests/public/debugging-strategies) example for a complete explainer. We've added a page [Debugging » Events](../debugging/events.md) to this documentation. We've also added a contract example that illustrates the usage: [`debugging-strategies`](https://github.com/use-ink/ink/tree/master/integration-tests/public/debugging-strategies). ```` ## File: docs/getting-started/calling.md ````markdown --- title: Call your contract slug: /getting-started/calling-your-contract hide_title: true --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ![Frontend Title Picture](/img/title/frontend.svg) # Call Your Contract Now that your contract has been fully deployed, we can start interacting with it! Flipper only has two functions: `flip()` and `get()`. We will show you what it's like to play with both of them. ## RPC calls vs. Transactions There are two ways of calling a contract: ### Dry-run via RPC Remote procedure calls, or RPC methods, are a way for an external program – for example, a browser or front-end application – to communicate with a Polkadot SDK node. For example, you might use an RPC method to read a stored value, submit a transaction, or request information about the chain a node is connected to. If a user interface displays the value of a contract (e.g. the balance of an account in an ERC-20 contract), then this is typically done via RPC. Specifically it is done by executing a synchronous dry-run of the contract method and returning its result. The following schema depicts this. ![Contract dry-run via RPC](/img/rpc-revive.svg) RPC calls don't require any tokens, they just require a connection to a node in the network. It's important to note that the execution won't result in any state mutations on the blockchain, it really just is a dry-run. ### State mutating via submitting a Transaction The other method of executing a call to a contract is by submitting a transaction on-chain. This requires tokens of the network to pay for the cost of the transaction. The transaction will be put in a transaction pool and asynchronously processed. The important implication here is that during submission of the transaction no result is available. This is different from an RPC call. The typical pattern for how a client can recognize the result of the contract call is to have the contract emit an event and have the client actively listen for such an event. Typically libraries (like `polkadot-js/api`) provide API functions to do just that. The important take-away is that contract developers have to make sure that events are emitted if they want clients to be able to pick up on them. ![Contract execution via transaction](/img/events-revive.svg) ## Using the Terminal When you deployed your contract you received the contract address. Use this to interact with the contract. ```bash Contract Address: 5DXR2MxThkyZvG3s4ubu9yRdNiifchZ9eNV8i6ErGx6u1sea ``` ### 1. `get()` function ```bash cargo contract call --contract --message get --suri //Alice ``` ```bash pop call contract --contract --message get --suri //Alice ``` ### 2. `flip()` function ```bash cargo contract call --contract --message flip --execute --suri //Alice ``` ```bash pop call contract --contract --message flip --execute --suri //Alice ``` :::tip For more info about interacting with your smart contract using the Pop CLI, [check this out](https://learn.onpop.io/contracts/guides/call-your-contract)! ::: ## Using the Contracts UI Go to https://ui.use.ink/ ### 1. `get()` function We set the initial value of the Flipper contract `value` to `false` when we instantiated the contract. Let's check that this is the case. In the **Message to Send** section, select the "**get(): bool**" message and accept the default values for the other options. Press **"Read"** and confirm that it returns the value `false`: ![An image of Flipper RPC call with false](/img/contracts-ui-4.png) ### 2. `flip()` function So let's make the value turn `true` now! The alternative message to send with the UI is `flip()`. Again, accept the default values for the other options and click **Call contract** ![An image of a Flipper transaction](/img/contracts-ui-5.png) If the transaction was successful, we should then be able to go back to the `get()` function and see our updated storage: ![An image of Flipper RPC call with true](/img/contracts-ui-6.png) ```` ## File: docs/getting-started/compiling.md ````markdown --- title: Compile your contract slug: /getting-started/building-your-contract hide_title: true --- import useBaseUrl from '@docusaurus/useBaseUrl'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ![Cargo Contract Title Picture](/img/title/cargo-contract.svg) # Compile Your Contract Run the following command in your `flipper` directory to compile your smart contract: ```bash cargo contract build ``` ```bash pop build ``` This command will build the following for your contract: a binary, a metadata file (which contains the contract's ABI) and a `.contract` file which bundles both. In principle, you can also build your contract using just the normal Rust build workflow (`cargo build`). We'll use `cargo-contract` though, as it invokes `cargo build` with an optimal set of flags. If all goes well, you should see a `target` folder that contains these files: ``` target └─ ink └─ flipper.polkavm <-- Raw contract binary └─ flipper.json <-- Metadata for the contract └─ flipper.contract <-- JSON file that combines binary + metadata ``` You can think of "Metadata" this way: the raw `.polkavm` binary contains just the bytecode of your contract. Without further information it's not possible to know what this bytecode refers to. For example, which functions can be called in there or what their arguments are. This additional information that describes what the raw binary is about is called metadata — data that describes other data.

The purpose of each file is: * `flipper.polkavm`: This is the raw contract bytecode that will be deployed on-chain. * `flipper.json`: The isolated metadata, which is not stored on-chain. It's big and would take up too much space and costs. This file is used by e.g. a dApp user interface to know how to communicate with the on-chain contract. * `flipper.contract`: Combines both the contract's bytecode and the metadata. This file is used when you are using `cargo-contract` to interact with a contract or when you use a developer UI like [Contracts UI](https://ui.use.ink). Let's take a look at the structure of the `flipper.json`: ```json { "source": {...}, "contract": {...}, "spec": { "constructors": [...], "docs": [], "events": [], "messages": [...], }, "storage": {...}, "types": [...], "version": "6" } ``` This file describes all the interfaces that can be used to interact with your contract: * `types` provides the custom *data types* used throughout the rest of the JSON. * `storage` defines all the *storage* items managed by your contract and how to ultimately access them. * `spec` stores information about the callable functions like *constructors* and *messages* a user can call to interact with the contract. It also has helpful information like the *events* that are emitted by the contract or any *docs*. If you look closely at the constructors and messages, you will also notice a `selector` which contains a 4-byte hash of the function name. This selector is used to route your contract calls to the correct functions. You can open up the `flipper.contract` file in any text editor. You'll notice that it's nearly the same as the `flipper.json`. The only difference is that the `.contract` file contains an additional field with the hex-encoded binary of your contract: ```json { "source": { … "contract_binary": "0x006173…", }, … } ``` :::info Pipe the `flipper.json` through [`jq`](https://jqlang.org/) to pretty-print it: `cat flipper.json | jq`. ::: ## Debug vs. Release Build By default, `cargo-contract` builds the contract in debug mode. This means that debugging information will be preserved. If you e.g. panic like this: ```rust self.env().set_code_hash(&code_hash).unwrap_or_else(|err| { panic!("Failed to `set_code_hash` to {code_hash:?} due to {err:?}") }); ``` The return value of a contract during a dry-run will contain this textual panic message. To support functionality like this the debug build of a contract includes some heavy-weight logic which increases the contract's size. For contracts that are supposed to run in production you should always build the contract with `--release`: ```bash cargo contract build --release ``` ```bash pop build --release ``` This will ensure that nothing unnecessary is compiled into the binary blob, making your contract faster and cheaper to deploy and execute. :::info With this behavior `cargo-contract` mirrors how `cargo` behaves for Rust programs: the `--release` flag has to be passed explicitly to `cargo build`. ::: ## Test Your Contract If you created a new project using a template, you can find at the bottom of the lib.rs simple test cases which verify the functionality of the contract. We can quickly test this code is functioning as expected: ```bash cargo contract test ``` ```bash pop test ``` To which you should see a successful test completion: ```bash running 2 tests test flipper::tests::it_works ... ok test flipper::tests::default_works ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` Learn more about the [testing strategies for ink! contracts](../testing/overview.md). ```` ## File: docs/getting-started/creating.md ````markdown --- title: Create an ink! Project slug: /getting-started/creating-an-ink-project hide_title: true --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ![Heart Title Picture](/img/title/heart.svg) ## Create a new project Make sure you have [installed the tooling](./setup.md) and that you are in the working directory, and then run: ```bash cargo contract new flipper ``` ```bash pop new contract ``` This command will create a new project folder named `flipper` with: ``` flipper └─ lib.rs <-- Contract Source Code └─ Cargo.toml <-- Rust Dependencies and ink! Configuration └─ .gitignore ``` :::tip The [Pop CLI](https://learn.onpop.io/contracts/guides/create-a-new-contract) has many templates to offer! ::: ## Contract Source Code For the `lib.rs` file, `cargo-contract` automatically generates the source code for the "Flipper" contract, which is about the simplest "smart" contract you can build. You can take a sneak peak as to what will come by looking at the source code here: [Flipper Example Source Code](https://github.com/use-ink/ink-examples/blob/main/flipper/lib.rs). The Flipper contract is nothing more than a `bool` which gets flipped from `true` to `false` through the `flip()` function. Now that we are feeling confident things are working, we can actually compile the contract in the next step. ```` ## File: docs/getting-started/deploying.md ````markdown --- title: Deploy your contract slug: /getting-started/deploy-your-contract hide_title: true --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import useBaseUrl from '@docusaurus/useBaseUrl'; ![Rocket Title Picture](/img/title/rocket.svg) Deploying a smart contract is the process of making your contract available on a blockchain so that it can be interacted with by others. In the Polkadot ecosystem, this involves uploading your compiled contract code to a chain that supports smart contracts (i.e. `pallet-revive`), and then creating an instance of your contract. This page will guide you through the steps to deploy your ink! contract locally, using both the command line and the Contracts UI. # Launch a local node :::tip Pro Tip The [Pop CLI](https://learn.onpop.io/contracts/guides/deploy) handles the `ink-node` for you, no need to install or launch. ::: To deploy your contract locally, you need a running blockchain node that supports ink! smart contracts. The recommended option is `ink-node`, a simple Polkadot blockchain configured with the `pallet-revive` for smart contracts ([learn more](../background/polkadot-sdk.md)). After [installing `ink-node`](./setup.md#ink-node), you can start a local development chain by running: ```bash ink-node ``` **Note:** `ink-node` uses the `--dev` flag by default. You may need to specify the `--dev` flag when running a different chain binary. You can interact with your node using `cargo-contract`, `pop` or [the Contracts UI](https://ui.use.ink/). If you use the Contracts UI, you have to configure it to connect to the locally running node: - Click on the dropdown selector at the top left corner. - Choose "Local Node". ![Connect to local node](/img/contracts-ui-local-node.png) # Set up a Local Polkadot Hub Environment You can easily launch a full Polkadot Hub setup locally using the [Pop CLI](https://learn.onpop.io/contracts/guides/deploy). This includes a local relay chain and one or more system parachains, allowing for end-to-end smart contract development and testing. To spin up the environment with the Paseo relay chain and system chains like `asset-hub` and `passet-hub`, run: ```bash pop up paseo -p asset-hub,passet-hub ``` This command will launch: - A local Paseo relay chain - [Passet Hub](../intro/where-to-deploy.md#passet-hub) as a parachain, connected and ready to deploy smart contracts You can also include additional system parachains in your local environment, such as `people` and `pop`, by extending the command: ```bash pop up paseo -p asset-hub,passet-hub,people,pop ``` Need more options or configuration details? Check out the CLI help: ```bash pop up paseo --help ``` ## Deploy the contract Now that we have generated the contract binary from our source code and connected to a local node, we want to deploy this contract onto our local node. Smart contract deployment on Polkadot is a little different than on traditional smart contract blockchains. For example, the standard ERC20 token has been deployed to Ethereum thousands of times, sometimes only with changes to the initial configuration (through the Solidity `constructor` function). Each of these instances take up space on the blockchain equivalent to the contract source code size, even though no code was actually changed. The contract deployment process in Polkadot is split into two steps: 1. Putting your contract code on the blockchain 2. Creating an instance of your contract With this pattern, contract code like the ERC20 standard can be put on the blockchain one single time, but instantiated any number of times. No need to continually upload the same source code over and waste space on the blockchain. ## Using the Terminal With `cargo-contract` or `pop` it's just a simple sequence of: ```bash cargo contract build cargo contract instantiate --suri //Alice --args true ``` ```bash pop build pop up --suri //Alice --args true ``` ## Using the Contracts UI ### 1. Upload Contract Code Here we will upload the contract code and instantiate one copy of the contract on the blockchain (which is usually why we upload the contract code in the first place): - Go to https://ui.use.ink/ - Make sure you have ink! v6 selected in the sidebar - Click the **Add New Contract** button in the sidebar. - Click the **Upload New Contract Code** button in the Add New Contract page. - Choose an **Instantiation account** (e.g. ALICE). - Give the contract a descriptive **Name** (e.g. Flipper Contract). - Drag the `flipper.contract` file that contains the bundled binary blob and metadata into the drag & drop area. You will see the UI parse the metadata and enabling the button that takes you to the next step. - Click the **Next** button ![Flipper Instantiate Contract 01](/img/contracts-ui-0.png) ### 2. Instantiate a Contract on the Blockchain Smart contracts exist as an extension of the account system on the blockchain. Thus creating an instance of this contract will create a new `AccountId` (ETH-compatible address) which will store any balance managed by the smart contract and allow us to interact with the contract. Now a screen displays the information that represents our smart contract. We are going to instantiate a copy of the smart contract: - Accept the default options for the contract **Deployment Constructor**. - Accept the default options **Max Gas Allowed** of `200000`. - Click on `Next` ![Flipper Instantiate Contract 02](/img/contracts-ui-1.png) The transaction is now queued, review your data and click **Upload and Instantiate** or go back and modify your inputs. ![Flipper Instantiate Contract 03](/img/contracts-ui-2.png) You will be redirected to a new page, where you can interact with the newly created contract instance. ![Flipper Instantiate Success](/img/contracts-ui-3.png) ```` ## File: docs/getting-started/setup.md ````markdown --- title: Setup slug: /getting-started/setup hide_title: true --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ![Setup Title Picture](/img/title/setup.svg) :::tip Pro tip Use the [Pop CLI](https://learn.onpop.io/contracts/welcome/install-pop-cli) for ink! smart contract development with the greatest developer experience. ::: # Setup On this page we describe the pre-requisites for working with ink!. ## Rust & Cargo A pre-requisite for compiling smart contracts is to install a stable Rust version (>= 1.88) and `cargo`. Please see [the official Rust installation guide](https://doc.rust-lang.org/cargo/getting-started/installation.html). ## Tooling Install [`cargo-contract`](https://github.com/use-ink/cargo-contract), a CLI tool for setting up and managing ink! smart contracts: ```bash cargo install --force --locked --version 6.0.0-beta cargo-contract ``` Make sure you have the latest stable version of Rust installed: ```bash rustup update stable ``` ### ink-node The [ink-node](https://github.com/use-ink/ink-node) is a simple Polkadot SDK blockchain with smart contract functionality. It's a comfortable option for local development and testing. There are two ways of installing the node: ### (1) Download the Binary Go to the [ink-node releases page](https://github.com/use-ink/ink-node/releases). Under `Assets` of the latest release, download the appropriate binary for your platform: - **Linux (ARM64)**: `ink-node-linux-arm64.tar.gz` - **Linux (x86)**: `ink-node-linux.tar.gz` - **macOS**: `ink-node-mac-universal.tar.gz` Make the binary executable: ```bash chmod +x ./ink-node ``` **For macOS users:** When you first try to run `ink-node`, macOS may show a security warning. To allow the binary to run: 1. Click the **question mark (?)** icon at the right top corner of the warning. 2. Follow the Apple instructions that appear. 3. Try running `ink-node` again and click **"Open Anyway"** when prompted. To confirm that `ink-node` is working correctly, run: ```bash ./ink-node --version ``` If you see version information, your installation is successful! ### (2) Install or Build it yourself Alternatively, you can build the node by yourself. This can take a while though! The build instructions and pre-requisites can be found [here](https://github.com/use-ink/ink-node?tab=readme-ov-file#build-locally). Use the [Pop CLI](https://learn.onpop.io/contracts/welcome/install-pop-cli) for ink! smart contract development with an enhanced developer experience. ```bash cargo install --git https://github.com/r0gue-io/pop-cli.git --branch v6.0.0-alpha.4 --locked ``` **Pop CLI advantages over `cargo-contract`:** - **Automated setup**: Handles all required installations and dependencies for you - **Contract templates**: Access to a range of pre-built contract templates - **Interactive UI**: Deploy and interact with contracts through an interactive command-line interface - **Built-in `ink-node`**: Automatically manages the `ink-node` without manual configuration - **Easy local network setup**: Quickly spin up local development networks - **Wallet integration**: Seamless wallet connection and management ```` ## File: docs/integrations-and-sdks/javascript-typescript/core-libraries.md ````markdown --- title: Core Libraries slug: /integrations-and-sdks/javascript-typescript/core-libraries hide_title: true --- ![Frontend Title Picture](/img/title/frontend.svg) # Core Libraries These are the foundational libraries for interacting with ink! contracts from JavaScript and TypeScript applications. Choose the level of abstraction that best fits your project needs. ## Low-Level Libraries ### RPC Interface - **[RPC Interface](https://wiki.polkadot.network/docs/build-node-interaction)** **(not recommended)** - Nodes participating in the blockchain network offer a [JSON RPC interface](https://www.jsonrpc.org/) to interact with the blockchain's state and capabilities - Direct interaction with the blockchain without any abstraction layer - Requires deep understanding of the underlying protocols ### General Polkadot SDK Libraries #### papi - **[`polkadot-api`](https://papi.how/getting-started)** **(currently recommended)** - Fully-typed TypeScript API supporting general interaction with Polkadot-SDK based blockchains - Modern, lightweight alternative to `@polkadot/api` - Excellent TypeScript support and developer experience #### @polkadot/api - **[`@polkadot/api`](https://polkadot.js.org/docs/api)** **(not recommended for new projects)** - Allows for most general interaction with Polkadot-SDK based blockchains from JavaScript - To interact with smart contracts, use the `pallet-revive` runtime calls - Legacy library, consider using `polkadot-api` for new projects ## ink!-Specific SDKs ### @polkadot-api/sdk-ink - **[`@polkadot-api/sdk-ink`](https://papi.how/sdks/ink-sdk)** **(Compatible with ink! v6)** - PAPI SDK for interacting with ink! smart contracts - Fully type-safe APIs for: - Deploying contracts - Dry-running calls - Sending messages - Estimating gas and storage deposits - Decoding events - Accessing on-chain storage of contracts ### dedot - **[`dedot`](https://docs.dedot.dev/ink-smart-contracts/intro)** **(Compatible with ink! v6)** - Next-gen TypeScript client for Polkadot & Polkadot SDK-based networks - Fully type-safe APIs for interacting with ink! smart contracts - Features: - Generates TypeScript bindings for contracts - Contract deployment and interaction - Query and transaction execution - Dry runs for validation - Event decoding with full type safety ### @polkadot/api-contract - **[`@polkadot/api-contract`](https://polkadot.js.org/docs/api-contract)** **(Compatible with ink! v6)** - Abstraction on top of `@polkadot/api` for `pallet-contracts` and `pallet-revive` - Makes interaction with smart contracts more comfortable and type-safe - Built on the legacy `@polkadot/api` foundation ```` ## File: docs/integrations-and-sdks/javascript-typescript/react.md ````markdown --- title: React Ecosystem slug: /integrations-and-sdks/javascript-typescript/react hide_title: true --- ![Frontend Title Picture](/img/title/frontend.svg) # React Ecosystem React is one of the most popular frontend frameworks for building web applications. Here are the tools and libraries specifically designed for building ink! smart contract frontends with React. ## React Hooks and Libraries ### ReactiveDOT - **[`ReactiveDOT`](https://reactivedot.dev/)** **(Compatible with ink! v6)** - A reactive library for building Substrate front-ends - Modern approach to state management for blockchain applications - Built with TypeScript and excellent developer experience ### useInkathon - **[`useInkathon`](https://github.com/scio-labs/use-inkathon)** **(not compatible with ink! v6)** - Hooks library for React with focus on smart-contract interactions - Built using `@polkadot/api` & `@polkadot/api-contract` - **Note**: Currently not updated for ink! v6 - consider alternatives for new projects ### typink - **[`typink`](https://docs.dedot.dev/typink)** **(Compatible with ink! v6)** - Comprehensive toolkit designed to simplify and accelerate ink! dApp development - Features: - Fully type-safe React hooks for smart contract interactions - Built-in CLI for bootstrapping projects - Multi-chain support - Flexible wallet connector options - Seamless developer experience ## Full-Stack Templates ### inkathon - **[`inkathon`](https://github.com/scio-labs/inkathon)** **(will be compatible with ink! v6 soon)** - Full-stack web app template using Next.js - Built on top of `useInkathon` - **Features**: - Complete project setup with best practices - Pre-configured development environment - Smart contract integration examples - Modern UI components and styling **The fastest way to get up and running with a smart contract and corresponding web app.** ```` ## File: docs/integrations-and-sdks/ethereum-compatibility.md ````markdown --- title: Ethereum Compatibility hide_title: true slug: /background/solidity-metamask-compatibility --- ![Metadata Title Picture](/img/title/solidity.svg) :::note For a gentle introduction, read our blogpost [ink! speaks Solidity on PolkaVM][blog-post]. ::: [blog-post]: https://medium.com/coinsbench/ink-solidity-abi-on-polkavm-c675c854efd3 With ink! v6, we have introduced an `abi` field in a custom `ink-lang` table in the [`package.metadata` table][package-metadata] of a contract's manifest file (i.e. the `Cargo.toml` file) - [more details here][abi-declaration]. It allows building your contract in Solidity ABI compatibility mode when declared as follows: ```toml [package.metadata.ink-lang] abi = "sol" ``` The implication of supporting Solidity ABI encoding is that all types used as constructor/message argument and return types, and event argument types must define a mapping to an equivalent Solidity ABI type. :::note This is similar to the requirement to implement [`scale::Encode` and `scale::Decode`][scale-codec] for Rust types used in the public interfaces of ink!/"native" ABI encoded contracts. ::: [package-metadata]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-metadata-table [abi-declaration]: ../basics/abi/overview.md#declaring-the-abi [scale-codec]: https://docs.rs/parity-scale-codec/latest/parity_scale_codec ## Rust/ink! to Solidity ABI type mapping This mapping is defined using the [`SolEncode`][sol-encode] and [`SolDecode`][sol-decode] traits, which are analogs to [`scale::Encode` and `scale::Decode`][scale-codec] (but for Solidity ABI encoding/decoding). You won't be able to use Rust types for which no mapping to a Solidity type is defined. An error about a missing trait implementation for this type will be thrown. [sol-encode]: https://use-ink.github.io/ink/ink/trait.SolEncode.html [sol-decode]: https://use-ink.github.io/ink/ink/trait.SolDecode.html ### Default/provided mappings [`SolEncode`][sol-encode] and [`SolDecode`][sol-decode] are implemented for the following Rust/ink! primitive types creating a mapping to the corresponding Solidity ABI types as shown in the table below: | Rust/ink! type | Solidity ABI type | Notes | | -------------- | ----------------- | ----- | | `bool` | `bool` || | `iN` for `N ∈ {8,16,32,64,128}` | `intN` | e.g `i8` ↔ `int8` | | `uN` for `N ∈ {8,16,32,64,128}` | `uintN` | e.g `u8` ↔ `uint8` | | [`ink::U256`][ink-u256] | `uint256`, `uint` | `uint` is just an alias of `uint256` in Solidity | | `String` | `string` || | `Box` | `string` || | [`ink::Address`][ink-address] / [`ink::H160`][ink-h160] | `address` | `ink::Address` is a type alias for the `ink::H160` type used for addresses in `pallet-revive` | | `[T; N]` for `const N: usize` | `T[N]` | e.g. `[i8; 64]` ↔ `int8[64]` | | `Vec` | `T[]` | e.g. `Vec` ↔ `int8[]` | | `Box<[T]>` | `T[]` | e.g. `Box<[i8]>` ↔ `int8[]` | | [`ink::sol::FixedBytes`][ink-fixed-bytes] for `1 <= N <= 32` | `bytesN` | e.g. `FixedBytes<32>` ↔ `bytes32`, `FixedBytes` is just a newtype wrapper for `[u8; N]` that also implements `From` | | [`ink::sol::DynBytes`][ink-dyn-bytes] | `bytes` | `DynBytes` is just a newtype wrapper for `Vec` that also implements `From>` | | `(T1, T2, T3, ... T12)` | `(U1, U2, U3, ... U12)` | where `T1` ↔ `U1`, ... `T12` ↔ `U12` e.g. `(bool, u8, Address)` ↔ `(bool, uint8, address)` | | `Option` | `(bool, T)` | e.g. `Option` ↔ `(bool, uint8)`| [ink-u256]: https://use-ink.github.io/ink/ink/struct.U256.html [ink-address]: https://use-ink.github.io/ink/ink/type.Address.html [ink-h160]: https://use-ink.github.io/ink/ink/struct.H160.html [ink-fixed-bytes]: https://use-ink.github.io/ink/ink/sol/struct.FixedBytes.html [ink-dyn-bytes]: https://use-ink.github.io/ink/ink/sol/struct.DynBytes.html :::note In Solidity ABI encoding, `uint8[]` and `uint8[N]` are encoded differently from `bytes` and `bytesN`. In Rust/ink!, `Vec` and `[u8; N]` are mapped to Solidity's `uint8[]` and `uint8[N]` representations, so there's a need for dedicated Rust/ink! types (i.e. [`ink::sol::DynBytes`][ink-fixed-bytes] and [`ink::sol::FixedBytes`][ink-dyn-bytes]) that map to Solidity's `bytes` and `bytesN` representations. ::: :::note Rust's `Option` type doesn't have a **semantically** equivalent Solidity ABI type, because [Solidity enums][sol-enum] are field-less. So `Option` is mapped to a tuple representation instead (i.e. `(bool, T)`), because this representation allows preservation of semantic information in Solidity, by using the `bool` as a "flag" indicating the variant (i.e. `false` for `None` and `true` for `Some`) such that: - `Option::None` is mapped to `(false, )` where `` is the zero bytes only representation of `T` (e.g. `0u8` for `u8` or `Vec::new()` for `Vec`) - `Option::Some(value)` is mapped to `(true, value)` The resulting type in Solidity can be represented as a struct with a field for the "flag" and another for the data. Note that `enum` in Solidity is encoded as `uint8` in [Solidity ABI encoding][sol-abi-types], while the encoding for `bool` is equivalent to the encoding of `uint8`, with `true` equivalent to `1` and `false` equivalent to `0`. Therefore, the `bool` "flag" can be safely interpreted as a `bool` or `enum` (or even `uint8`) in Solidity code. ::: [sol-enum]: https://docs.soliditylang.org/en/latest/types.html#enums [sol-abi-types]: https://docs.soliditylang.org/en/latest/abi-spec.html#mapping-solidity-to-abi-types [`SolEncode`][sol-encode] is additionally implemented for reference and smart pointer types below: | Rust/ink! type | Solidity ABI type | Notes | | -------------- | ----------------- | ----- | | `&str`, `&mut str` | `string` || | `&T`, `&mut T`, `Box` | `T` | e.g. `&i8 ↔ int8` | | `&[T]`, `&mut [T]` | `T[]` | e.g. `&[i8]` ↔ `int8[]` | | [`ink::sol::ByteSlice`][ink-byte-slice] | `bytes` | `ByteSlice` is a just newtype wrapper for `&[u8]` | [ink-byte-slice]: https://use-ink.github.io/ink/ink/sol/struct.ByteSlice.html ### Handling the `Result` type Rust's `Result` type doesn't have a **semantically** equivalent Solidity ABI type, because [Solidity enums][sol-enum] are field-less, so no composable mapping is provided. However, `Result` types are supported as the return type of messages and constructors, and they're handled at language level as follows: - When returning the `Result::Ok` variant, where `T` implements `SolEncode`, `T` is encoded as "normal" Solidity ABI return data. - When returning the `Result::Err` variant, `E` must implement [`SolErrorEncode`][sol-error-encode], ink! will set the revert flag in the execution environment, and `E` will be encoded as [Solidity revert error data][sol-revert], with the error data representation depending on the [`SolErrorEncode`][sol-error-encode] implementation. - Similarly, for decoding, `T` must implement `SolDecode`, while `E` must implement [`SolErrorDecode`][sol-error-decode], and the returned data is decoded as `T` (i.e. `Result::Ok`) or `E` (i.e. `Result::Err`) depending on whether the revert flag is set (i.e. `E` if the revert flag is set, and `T` otherwise). The [`SolErrorEncode`][sol-error-encode] and [`SolErrorDecode`][sol-error-decode] traits define the highest level interfaces for encoding and decoding an arbitrary Rust/ink! error type as Solidity ABI revert error data. Default implementations for both `SolErrorEncode` and `SolErrorDecode` are provided for unit (i.e. `()`), and these are equivalent to reverting with no error data in Solidity (i.e. empty output buffer). For arbitrary custom error types, `Derive` macros are provided for automatically generating implementations of `SolErrorEncode` and `SolErrorDecode` for structs and enums for which all fields (if any) implement `SolEncode` and `SolDecode`. - For structs, the struct name is used as the name of the [Solidity custom error][sol-custom-error] while the fields (if any) are the parameters - For enums, each variant is its own [Solidity custom error][sol-custom-error], with the variant name being the custom error name, and the fields (if any) being the parameters For convenience, the [`#[ink::error]`][ink-error] attribute macro is also provided for automatically deriving the following traits: - [`SolErrorEncode`][sol-error-encode]: for encoding a custom type as revert error data - [`SolErrorDecode`][sol-error-decode]: for decoding revert error data into a custom type - `SolErrorMetadata`: for generating [Solidity ABI metadata][sol-abi-json] (gated behind the `std` feature) [sol-error-encode]: https://use-ink.github.io/ink/ink/sol/trait.SolErrorEncode.html [sol-error-decode]: https://use-ink.github.io/ink/ink/sol/trait.SolErrorDecode.html [sol-revert]: https://docs.soliditylang.org/en/latest/control-structures.html#revert [sol-custom-error]: https://soliditylang.org/blog/2021/04/21/custom-errors/ [ink-error]: ../macros-attributes/error.md [sol-abi-json]: https://docs.soliditylang.org/en/latest/abi-spec.html#json ```rust // Represented as a Solidity custom error with no parameters #[ink::error] struct UnitError; // Represented as a Solidity custom error with parameters #[ink::error] struct ErrorWithParams(bool, u8, String); // Represented as a Solidity custom error with named parameters #[ink::error] struct ErrorWithNamedParams { status: bool, count: u8, reason: String, } // Represented as multiple Solidity custom errors // (i.e. each variant represents a Solidity custom error) #[ink::error] enum MultipleErrors { UnitError, ErrorWithParams(bool, u8, String), ErrorWithNamedParams { status: bool, count: u8, reason: String, } } ``` :::note In ["ink" and "all" ABI mode][abi-declaration], the [`#[ink::error]`][ink-error] attribute macro will also derive implementations of the [`scale::Encode` and `scale::Decode`][scale-codec] traits. ::: :::note For other [Solidity `revert`][sol-revert] error data representations (e.g. legacy revert strings), you can implement [`SolErrorEncode`][sol-error-encode] and [`SolErrorDecode`][sol-error-decode] manually to match those representations. ::: :::note Rust's [coherence/orphan rules][rust-coherence] mean that you can only implement the `SolErrorEncode` and `SolErrorDecode` traits for local types. However, one way around this limitation is to use the [newtype pattern][new-type-pattern]. ::: ### Mappings for arbitrary custom types For arbitrary custom types, `Derive` macros are provided for automatically generating implementations of [`SolEncode`][sol-encode] and [`SolDecode`][sol-decode] - For structs where all fields (if any) implement `SolEncode` and `SolDecode` respectively, including support for generic types - For enums where all variants are either [unit-only][enum-unit-only] or [field-less][enum-field-less] (see notes below for the rationale for this limitation) [enum-unit-only]: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.unit-only [enum-field-less]: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.fieldless ```rust use ink_macro::{SolDecode, SolEncode}; #[derive(SolDecode, SolEncode)] struct UnitStruct; #[derive(SolDecode, SolEncode)] struct TupleStruct(bool, u8, String); #[derive(SolDecode, SolEncode)] struct FieldStruct { status: bool, count: u8, reason: String, } #[derive(SolDecode, SolEncode)] enum SimpleEnum { One, Two, Three, } #[derive(SolDecode, SolEncode)] struct NestedStruct { unit: UnitStruct, tuple: TupleStruct, fields: FieldStruct, enumerate: SimpleEnum, } #[derive(SolDecode, SolEncode)] struct GenericStruct { concrete: u8, generic: T, } ``` :::note Solidity has no **semantic** equivalent for Rust/ink! enums with fields (i.e. [Solidity enums][sol-enum] can only express the equivalent of Rust [unit-only][enum-unit-only] or [field-less][enum-field-less] enums). So mapping complex Rust enums (i.e. enums with fields) to "equivalent" Solidity representations typically yields complex structures based on tuples (at [Solidity ABI encoding][sol-abi-types] level) and structs (at Solidity language level). Because of this, the `Derive` macros for `SolEncode` and `SolDecode` do NOT generate implementations for enums with fields. However, you can define custom representations for these types by manually implementing the [`SolEncode`][sol-encode] and [`SolDecode`][sol-decode] (see linked rustdoc for instructions). ::: :::note Rust's [coherence/orphan rules][rust-coherence] mean that you can only implement the [`SolEncode`][sol-encode] and [`SolDecode`][sol-decode] traits for local types. However, one way around this limitation is to use the [newtype pattern][new-type-pattern]. ::: [rust-coherence]: https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence [new-type-pattern]: https://doc.rust-lang.org/book/ch20-02-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits ## Solidity Tooling You can deploy and interact with `ink!` smart contracts using popular Solidity tools like Hardhat and Foundry thanks to the Solidity-compatible ABI output. Full Tutorial: [Use Solidity Tooling with ink! Contracts](/tutorials/ethereum-compatibility/overview) ```` ## File: docs/integrations-and-sdks/other-languages.md ````markdown --- title: Other Languages slug: /integrations-and-sdks/other-languages hide_title: true --- ![Frontend Title Picture](/img/title/frontend.svg) # Other Languages While JavaScript and TypeScript dominate web development, smart contract frontends can be built with various technologies. Here are libraries and SDKs for other platforms and languages. ## Mobile Development ### iOS - **[novasamatech/substrate-sdk-ios](https://github.com/novasamatech/substrate-sdk-ios)** - Low-level generic iOS SDK for Substrate-based blockchains - Written in Swift - Provides foundation for building native iOS apps that interact with Polkadot networks - Suitable for wallet applications and dApps requiring native iOS performance ### Android - **[novasamatech/substrate-sdk-android](https://github.com/novasamatech/substrate-sdk-android)** - Low-level Android SDK for Substrate-based blockchains - Written in Kotlin/Java - Enables native Android applications to interact with Polkadot networks - Ideal for mobile wallets and native Android dApps ## Backend and Server-Side ### Rust - **[paritytech/subxt](https://github.com/paritytech/subxt)** - Rust library to submit extrinsics (transactions) to a Substrate node via RPC - **Perfect for**: - Backend services that interact with smart contracts - CLI tools for contract management - Server-side automation and monitoring - Integration testing frameworks ### Python - **[polkascan/py-substrate-interface](https://github.com/polkascan/py-substrate-interface)** - Python library for interfacing with Substrate nodes - **Use cases**: - Data analysis and blockchain monitoring - Backend automation scripts - Integration with existing Python ecosystems - Rapid prototyping and testing ```` ## File: docs/integrations-and-sdks/overview.md ````markdown --- title: Overview slug: /integrations-and-sdks/overview hide_title: true --- ![Frontend Title Picture](../../static/img/title/frontend.svg) # Overview Now after you [wrote](../getting-started/creating.md), [compiled](../getting-started/compiling.md) and [deployed your smart contract](../getting-started/deploying.md), it is time to craft a user experience around it. This experience can take many shapes from mobile app to interactive terminal applications. In this section we are focusing on the most prominent shape in web3 right now, web apps. Although we love Rust, the native language of the web is JavaScript. Thereby naturally the best tools for creating web experiences are available for JavaScript. Hence, the tools for smart contract interaction with JavaScript are the most advanced as well. To be precise all JavaScript tools mentioned here, actually leverage TypeScript to offer a JavaScript and a typesafe TypeScript experience. ## What's in this Section This section covers: - **[JavaScript/TypeScript Libraries](./javascript-typescript/core-libraries.md)**: Core libraries and tools for JavaScript/TypeScript development - **[React Ecosystem](./javascript-typescript/react.md)**: React-specific frameworks and hooks for ink! integration - **[Other Languages](./other-languages.md)**: SDKs and libraries for Python, Rust, mobile development, and more - **[Ethereum Compatibility](./ethereum-compatibility.md)**: Use Solidity ABI compatibility mode to deploy and interact with ink! contracts using popular Ethereum tools like MetaMask, Hardhat, and Foundry ```` ## File: docs/intro/intro.mdx ```` --- title: Introduction hide_title: true slug: / --- import useBaseUrl from '@docusaurus/useBaseUrl'; ## What is ink!? ink! is a programming language for writing smart contracts that combines the power and safety of Rust with blockchain development. Here's what makes ink! special: **Built on Rust**: ink! takes the popular Rust programming language and adds everything you need for smart contract development. You get all of Rust's safety features like memory safety and type safety, plus access to the vast Rust ecosystem. **Smart Contract Ready**: While ink! uses Rust as its foundation, it's specifically designed for smart contracts. This means: - Special annotations and macros are provided for smart contract needs - Built-in support for storage, events, and contract interactions **Simple but Powerful**: ink! uses special `#[ink(...)]` attribute macros to turn your Rust code into smart contracts. These macros tell ink! what different parts of your code represent; like storage, functions that can be called, or events that can be emitted. **Compile to RISC-V**: Your ink! contracts compile to RISC-V bytecode that runs efficiently on blockchains, giving you both performance and compatibility. ## What can you do with it? ink! opens up a world of possibilities for blockchain development across the Polkadot ecosystem: ### Build Smart Contracts for Polkadot Blockchains With ink!, you can write smart contracts that run on any blockchain built with the Polkadot SDK that includes the `pallet-revive` module. This includes many parachains and standalone chains in the Polkadot ecosystem. - **DeFi Applications**: Build decentralized exchanges, lending protocols, and other financial applications - **NFT Platforms**: Create marketplaces, games, and digital collectible platforms - **Cross-Chain Applications**: Take advantage of Polkadot's interoperability to build applications that work across multiple blockchains - **Utility Contracts**: From simple storage contracts to complex business logic, ink! can handle it all ### Flexible Development Paths ink! provides different approaches depending on your needs: - **Prototype Quickly**: Start with a smart contract to test your idea and get user feedback - **Enhanced Chain Features**: Use precompiles to access special blockchain functionality beyond basic smart contracts - **Scale to Parachains**: Later migrate successful contracts to dedicated parachains for better performance and lower costs ### Composability One of ink!'s unique advantages is its compatibility with Solidity. This means: - Solidity developers can call ink! contracts seamlessly - You can use existing Ethereum tools and frameworks - Easy migration between different blockchain ecosystems Want to learn more about ink!'s relationship with the Polkadot ecosystem and its various use cases? Check out our detailed guide on [Polkadot SDK and ink!](../background/polkadot-sdk.md). Ready to get started? Head to our [Getting Started](../getting-started/setup.md) guide to begin building your first ink! smart contract. ```` ## File: docs/intro/overview.md ````markdown --- title: Overview hide_title: true slug: /overview --- import useBaseUrl from '@docusaurus/useBaseUrl'; Welcome to the ink! documentation, the Rust-based smart contract language for the Polkadot ecosystem. This documentation will take you from your first "Hello, World!" contract to building sophisticated decentralized applications. ## Overview ### **[Getting Started](../getting-started/creating.md)** Begin your ink! journey with setup instructions, creating your first contract, and deploying it to a blockchain. Perfect for newcomers to both ink! and smart contract development. ### **[Basics](../basics/contract-template.md)** Master the fundamental concepts of ink! development including storage, contract interactions, events, and the ABI system that enables interoperability with other languages like Solidity. ### **[Testing](../testing/overview.md)** Learn comprehensive testing strategies from unit tests to end-to-end testing, including working with testing tools like DRink! for robust contract development. ### **[Debugging](../debugging/overview.md)** Discover tools and techniques for debugging your contracts, from event logging to tracing execution and using development tools. ### **[Macros & Attributes](../macros-attributes/overview.md)** Deep dive into ink!'s powerful macro system that transforms your Rust code into smart contracts, including storage annotations, message definitions, and event handling. ### **[Storage & Data Structures](../datastructures/overview.md)** Understand how to efficiently store and manage data in your contracts, from simple values to complex mappings and custom data structures. ### **[Linter](../linter/overview.md)** Utilize ink!'s built-in security linter to identify common smart contract vulnerabilities and ensure your code follows best practices. ### **[Integrations and SDKs](../integrations-and-sdks/overview.md)** Connect your contracts to web applications using TypeScript/JavaScript libraries, React hooks, Solidity Tooling, and various SDK options for building complete dApps. ### **[Technical Background](../background/polkadot-sdk.md)** Understand the deeper technical aspects including why Rust and RISC-V were chosen, how ink! compares to other smart contract languages, and when to choose smart contracts vs. parachains. ```` ## File: docs/intro/sub0-hackathon.mdx ```` --- title: sub0 Hackathon 2025 hide_title: true slug: /sub0-hackathon-2025 hide_table_of_contents: true --- import useBaseUrl from '@docusaurus/useBaseUrl'; # Welcome _sub0 Hackathon_ participants! This page contains all necessary info to participate in the [sub0 HACK](https://luma.com/sub0hack) using ink! v6. * The hackathon takes place from Nov 14 - Nov 16, 2025. * $50,000 in prize money. * Remote participation is fine! ## 🚑 Support If you don't use Telegram, please create a GitHub issue [here](https://github.com/use-ink/ink/issues). ## 🤖 LLMs We have an [`llms.txt`](https://use.ink/llms.txt) that contains all documentation from this website. If you copy/paste it into your prompt/context window, this will help your AI friend a lot to provide help. ## 🚀 Fast Track Install Rust (>= 1.88) and `cargo`: [Installation Guide](https://doc.rust-lang.org/cargo/getting-started/installation.html). Download the binary for a local development node [here](https://github.com/use-ink/ink-node/releases). ```toml # Install our cli tool: `cargo-contract`. # It wraps around Rust's `cargo build` to build contracts with optimal # flags for blockchains. It also allows for deploying + interacting # with contracts. $ rustup component add rust-src $ cargo install --locked --force --version 6.0.0-beta cargo-contract # Create a simple contract. $ cargo contract new flipper && cd flipper $ cargo contract build --release # Download our local development node. # Find the binary here: https://github.com/use-ink/ink-node/releases/latest # Start your local development node in a separate shell session $ ink-node # Instantiate your contract on-chain. $ cargo contract instantiate --suri //Alice # Dry-run a call of it. $ cargo contract call --suri //Alice --contract 0x… --message get # Execute a contract call, as a transaction on-chain. $ cargo contract call --suri //Alice --contract 0x… --message flip -x ```
Please see the chapter [Getting started](../getting-started/setup.md) of this documentation for a deeper introduction. ## You need to use ink! v6.0.0-beta! Prior releases of ink! are not supported for the hackathon! You won't be able to deploy them on Passet Hub. Make sure your `Cargo.toml` contains ```toml [dependencies] ink = { version = "6.0.0-beta" } [dev-dependencies] ink_e2e = { version = "6.0.0-beta" } # we moved the sandbox testing environment to a separate crate # this one cannot be published to crates.io yet ink_sandbox = { git = "https://github.com/use-ink/ink.git", branch = "6.0.0-beta" } ``` Your `cargo-contract` version must be `6.0.0-beta` too: ```bash cargo install --force --locked --version 6.0.0-beta cargo-contract ``` ## 🚀 Where to deploy? You can deploy locally via our local development node [`ink-node`](https://github.com/use-ink/ink-node/releases). As a testnet you need to use [Paseo Passet Hub](https://use.ink/docs/v6/where-to-deploy/#passet-hub). You can find the faucet [here](https://faucet.polkadot.io/?parachain=1111). ## 🏰 dApp Templates We recommend using [ink!athon](https://inkathon.xyz/) to generate dApp templates that contain contract and frontend code. You can find a hardcoded frontend for our `flipper` example [here](https://github.com/use-ink/ink-examples/tree/main/flipper). ## 🤔 Smart Contract Examples You can find many contract examples in our `ink-examples` repository.

Our "Hello, World!".
» view example

An ERC-20 implementation.
» view example


An upgradeable contract.
» view example

A multi-signature wallet.
» view example

Calling Solidity contracts.
» view example

```` ## File: docs/intro/tutorials-examples.md ````markdown --- title: Tutorials and Examples slug: /getting-started/tutorials-and-examples hide_title: true --- import useBaseUrl from '@docusaurus/useBaseUrl'; ![Heart Title Picture](/img/title/heart.svg) # Tutorials and Examples ## Tutorials Ready to dive deeper into ink! development? Check out our [tutorials](/tutorials/overview) that will guide you through building real-world decentralised applications step by step. ### Contribute a Tutorial Have you built something awesome with ink!? We'd love to feature your tutorial! **Help the community learn by contributing your own tutorial.** Whether it's a unique use case, an innovative pattern, or a step-by-step guide for beginners, your contribution makes a difference. [Learn how to contribute tutorials →](/tutorials/guide) ## Smart Contract Examples Explore ready-to-use [smart contract examples](https://github.com/use-ink/ink-examples) to understand different patterns and use cases:

Our "Hello, World!".
» view example

An ERC-20 implementation.
» view example

An upgradeable contract.
» view example

A multi-signature wallet.
» view example

Allow runtime access.
» view example

```` ## File: docs/intro/where-to-deploy.md ````markdown --- title: Where to Deploy slug: /where-to-deploy hide_title: true --- import useBaseUrl from '@docusaurus/useBaseUrl'; ![Rocket Title Picture](/img/title/rocket.svg) # Where to Deploy Your ink! Contracts Ready to deploy your ink! smart contracts? You have several options depending on your needs, from local development to live testnets. Here's your complete guide to deploying ink! v6 contracts. ## Local Development Perfect for initial development and testing, check out [deploying your first contract](./../getting-started/deploying.md). ## Live Testnets Make sure you have a Polkadot account, check out the [guide](https://support.polkadot.network/support/solutions/articles/65000098878-how-to-create-a-dot-account) or [video](https://www.youtube.com/watch?v=DNU0p5G0Gqc) on how to do this. ### Passet Hub Passet hub is Polkadot's Getting Started: 1. **Get PAS Tokens**: Use the [Passet Hub Faucet](https://faucet.polkadot.io/?parachain=1111) 2. **Developer Console**: https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpasset-hub-paseo.ibp.network#/explorer 3. **URL**: `wss://testnet-passet-hub.polkadot.io` ### Pop Network **Experimental parachain for smart contracts and cross-chain features** **Getting Started:** 1. **Get PAS tokens on Pop**: Follow [this guide](https://learn.onpop.io/contracts/guides/bridge-tokens-to-pop-network) to transfer from Paseo to Pop 2. **Developer Console**: https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frpc1.paseo.popnetwork.xyz#/explorer 3. **URL**: `wss://rpc1.paseo.popnetwork.xyz` ### Ready to deploy Check out how to deploy your contract [here](../getting-started/deploying.md). ```` ## File: docs/linter/rules/no_main.md ````markdown --- title: no_main hide_title: true description: no_main lint documentation --- # no_main ## What it does Checks if a contract is annotated with the `no_main` inner attribute. ## Why is this necessary? Contracts must be annotated with `no_main` inner attribute when compiled for on-chain execution. ## Example ```rust // Bad: Contract does not contain the `no_main` attribute, // so it cannot be compiled to Wasm #![cfg_attr(not(feature = "std"), no_std)] #[ink::contract] mod my_contract { /* ... */ } ``` Use instead: ```rust #![cfg_attr(not(feature = "std"), no_std, no_main)] #[ink::contract] mod my_contract { /* ... */ } ``` ```` ## File: docs/linter/rules/non_fallible_api.md ````markdown --- title: non_fallible_api hide_title: true description: non_fallible_api lint documentation --- # non_fallible_api ## What it does The lint detects potentially unsafe uses of methods for which there are safer alternatives. ## Why is this bad? In some standard collections in ink!, there are two types of implementations: non-fallible (e.g. `get`) and fallible (e.g. `try_get`). Fallible alternatives are considered safer, as they perform additional checks for incorrect input parameters and return `Result::Err` when they are used improperly. On the other hand, non-fallible methods do not provide these checks and will panic on incorrect input, placing the responsibility on the user to implement these checks. For more context, see: [ink#1910](https://github.com/use-ink/ink/pull/1910). ## Example Consider the contract that has the following `Mapping` field: ```rust #[ink(storage)] pub struct Example { map: Mapping } ``` The following usage of the non-fallible API is unsafe: ```rust // Bad: can panic if `input_string` doesn't fit into the static buffer self.map.insert(input_string, &self.sender); ``` It could be replaced with the fallible version of `Mapping::insert`: ```rust // Good: returns Result::Err on incorrect input self.map.try_insert(input_string, &self.sender); ``` Otherwise, the user could explicitly check the encoded size of the argument in their code: ```rust // Good: explicitly checked encoded size of the input if String::encoded_size(&input_string) < ink_env::BUFFER_SIZE { self.map.insert(input_string, &self.sender); } ``` ```` ## File: docs/linter/rules/primitive_topic.md ````markdown --- title: primitive_topic hide_title: true description: primitive_topic lint documentation --- # primitive_topic ## What it does Checks for ink! contracts that use the [`#[ink(topic)]`](../../macros-attributes/topic.md) annotation with primitive number types. Topics are discrete events for which it makes sense to filter. Typical examples of fields that should be filtered are `AccountId`, `bool` or `enum` variants. ## Why is this bad? It typically doesn't make sense to annotate types like `u32` or `i32` as a topic, if those fields can take continuous values that could be anywhere between `::MIN` and `::MAX`. An example of a case where it doesn't make sense at all to have a topic on the storage field is something like `value: Balance` in the examle below. ## Example ```rust // Bad // It typically makes no sense to filter `Balance`, since its value may varies from `::MAX` // to `::MIN`. #[ink(event)] pub struct Transaction { #[ink(topic)] src: Option, #[ink(topic)] dst: Option, #[ink(topic)] value: Balance, } ``` Use instead: ```rust // Good // Filtering transactions based on source and destination addresses. #[ink(event)] pub struct Transaction { #[ink(topic)] src: Option, #[ink(topic)] dst: Option, value: Balance, } ``` ```` ## File: docs/linter/rules/storage_never_freed.md ````markdown --- title: storage_never_freed hide_title: true description: storage_never_freed lint documentation --- # storage_never_freed ## What it does This lint ensures that for every storage field with a collection type, when there is an operation to insert new elements, there's also an operation for removing elements. ## Why is this bad? When a user executes a contract function that writes to storage, they have to put a deposit down for the amount of storage space used. Whoever frees up that storage at some later point gets the deposit back. Therefore, it is always a good idea to make it possible for users to free up their storage space. ## Example In the following example there is a storage field with the `Mapping` type that has an function that inserts new elements: ```rust #[ink(storage)] pub struct Transaction { values: Mapping, } fn add_value(&mut self, k: &AccountId, v: &AccountId) { // ... self.values.insert(k, v); // ... } ``` But, ideally, there also should be a function that allows the user to remove elements from the Mapping freeing storage space: ```rust fn del_value(&mut self, k: &AccountId) { // ... self.values.remove(k); // ... } ``` ```` ## File: docs/linter/rules/strict_balance_equality.md ````markdown --- title: strict_balance_equality hide_title: true description: strict_balance_equality lint documentation --- # strict_balance_equality ## What it does Looks for strict equalities with balance in ink! contracts. ## Why is this bad? The problem with strict balance equality is that it is always possible to forcibly send tokens to a contract. For example, using [`terminate_contract`](https://use-ink.github.io/ink/ink_env/fn.terminate_contract.html). In such a case, the condition involving the contract balance will work incorrectly, what may lead to security issues, including DoS attacks and draining contract's gas. ## Known problems There are many ways to implement balance comparison in ink! contracts. This lint is not trying to be exhaustive. Instead, it addresses the most common cases that may occur in real-world contracts and focuses on precision and lack of false positives. ## Example Assume, there is an attacker contract that sends all its funds to the target contract when terminated: ```rust #[ink::contract] pub mod attacker { // ... #[ink(message)] pub fn attack(&mut self, target: &AccountId) { self.env().terminate_contract(target); } } ``` If the target contains a condition with strict balance equality, this may be manipulated by the attacker: ```rust #[ink::contract] pub mod target { // ... #[ink(message)] pub fn do_something(&mut self) { if self.env().balance() != 100 { // Bad: Strict balance equality // ... some logic } } } ``` This could be mitigated using non-strict equality operators in the condition with the balance: ```rust #[ink::contract] pub mod target { // ... #[ink(message)] pub fn do_something(&mut self) { if self.env().balance() < 100 { // Good: Non-strict equality // ... some logic } } } ``` ```` ## File: docs/linter/overview.md ````markdown --- title: Overview hide_title: true description: An overview of ink! linter --- ![Text/linter Title Picture](/img/title/text/linter.svg) # Overview # Overview ink! includes the linter — a security tool designed to identify typical security issues in smart contracts. The linter is meant to seamlessly fit into the smart contracts development process, ensuring that contracts are thoroughly checked during the build phase before they are deployed to the blockchain. ## Installation Our linter requires two crates and a fixed Rust toolchain version. You can use these commands to install the required dependencies: ```bash export TOOLCHAIN_VERSION=nightly-2025-05-14 rustup install $TOOLCHAIN_VERSION rustup component add rust-src --toolchain $TOOLCHAIN_VERSION rustup run $TOOLCHAIN_VERSION cargo install cargo-dylint dylint-link ``` Note that the linter requires this specific version of the toolchain, since it uses the internal Rust compiler API. That's also why we require nightly for the linter, these internal crates are not accessible on stable. ## Usage The linter operates via `cargo-contract`. To perform a build with extra code analysis (i.e. the ink! linting rules), run the following command within the contract directory: ```bash cargo contract build --lint ``` This command compiles the contract and applies all linting checks. You can find the complete list of lints along with their descriptions in this documentation. ## Suppressing linter warnings To suppress linter warnings in your ink! smart-contract, you can use `allow` attributes. You can apply these attributes either to a particular piece of code or globally. Here's how to suppress the specific linter warnings: ```rust // Suppressing the `primitive_topic` lint globally #[cfg_attr(dylint_lib = "ink_linting", allow(primitive_topic))] #[ink(message)] pub fn test(&mut self) { // Suppressing the `strict_balance_equality` lint in a specific place #[cfg_attr(dylint_lib = "ink_linting", allow(strict_balance_equality))] if self.env().balance() == 10 { /* ... */ } } ``` ```` ## File: docs/macros-attributes/anonymous.md ````markdown --- title: "#[ink(anonymous)]" slug: /macros-attributes/anonymous hide_title: true --- ![Text/anon Title Picture](/img/title/text/anon.svg) Applicable to ink! events. Tells the ink! codegen to treat the ink! event as anonymous which omits the event signature as topic upon emitting. Similar to anonymous events in Solidity. Anonymous events have similar semantics as in Solidity in that their event signature won't be included in their event topics serialization to reduce event emitting overhead. This is especially useful for user defined events. The signature of the event is by default one of the topics of the event, except if you annotate the event with `#[ink(anonymous)]`. The attribute implies that it is not possible to filter for specific anonymous events by the signature topic. ## Example ```rust #[ink(event)] #[ink(anonymous)] pub struct MyEvent { #[ink(topic)] field_1: i32, field_2: bool, } ``` The equivalent syntax for standalone `#[ink::event]` definitions (not defined inline in a contract) is: ```rust #[ink::event(anonymous)] pub struct MyEvent { #[ink(topic)] field_1: i32, field_2: bool, } ``` ```` ## File: docs/macros-attributes/constructor.md ````markdown --- title: "#[ink(constructor)]" slug: /macros-attributes/constructor hide_title: true --- ![Text/constructor Title Picture](/img/title/text/constructor.svg) Applicable to a method. Flags a method (or multiple methods) for the ink! storage struct as constructor making it available to the API for instantiating the contract. There must be at least one `#[ink(constructor)]` defined method. Methods flagged with `#[ink(constructor)]` are special in that they are dispatchable upon contract instantiation. A contract may define multiple such constructors which allow users of the contract to instantiate a contract in multiple different ways. ## Example ```rust #[ink::contract] mod erc20 { #[ink(storage)] pub struct Erc20 { ... } impl Erc20 { #[ink(constructor)] pub fn new(initial_supply: Balance) -> Self { .. } #[ink(constructor)] pub fn total_supply(&self) -> Balance { .. } // etc. } } ``` ```` ## File: docs/macros-attributes/contract_ref.md ````markdown --- title: "#[ink::contract_ref]" hide_title: true slug: /macros-attributes/contract_ref --- ![Text/contract_ref Title Picture](/img/title/text/contract_ref.svg) Defines the interface of a "callee" contract and generates a wrapper type which can be used for interacting with the contract. The interface is defined using a trait, and the macro generates a native Rust type (a contract reference) that implements this trait, so it can be used in any Rust context that expects types. :::note A key difference between an `#[ink::contract_ref]` and [`#[ink::trait_definition]`][trait-def] is that a `#[ink::contract_ref]` dynamically declares the interface of an on-chain/"callee" contract with a possibly different ABI from the root/"caller" contract, while a [`#[ink::trait_definition]`][trait-def] is an interface that defines shared behavior to be implemented (or reused/inherited) by the root contract, where the ABI is inferred from the root contract. ::: [trait-def]: ../basics/trait-definitions.md ## Example ### Definition ```rust #[ink::contract_ref(abi = "sol")] pub trait Erc20 { /// Returns the total supply of the ERC-20 smart contract. #[ink(message)] fn total_supply(&self) -> ink::U256; /// Transfers balance from the caller to the given address. #[ink(message)] fn transfer(&mut self, amount: ink::U256, to: ink::Address) -> bool; // etc. } ``` ### Usage Given the above interface, you can use the generated contract reference in a "caller" contract as shown below: ```rust #[ink::contract] mod erc20_caller { use ink::U256; #[ink(storage)] pub struct Erc20Caller { callee: ink::Address, } impl Erc20Caller { #[ink(constructor)] pub fn new(addr: ink::Address) -> Self { Self { callee: addr } } #[ink(message)] pub fn call_erc20(&self) { // Calls the ERC20 contract using the contract ref generated above. let total = Erc20Ref::from(self.callee).total_supply(); // Do some fun stuff! } } } ``` :::caution A downside to manually defined contract references is that mistakes in the interface definition are not caught at compile-time. It's therefore important to make sure such interfaces are properly tested using [end-to-end testing][e2e-test] before contracts are deployed on-chain. ::: [e2e-test]: ../testing/e2e.md ## Header Arguments The `#[ink::contract_ref]` macro can be provided with some additional comma-separated header arguments: ### `abi: String` Specifies the ABI (Application Binary Interface) of the "callee" contract. **Usage Example:** ```rust #[ink::contract_ref(abi = "sol")] pub trait Callee { #[ink(message)] fn message1(&self); #[ink(message, selector = 42)] fn message2(&self); } ``` **Default value:** Empty. **Allowed values:** `"ink"`, `"sol"` **NOTE**: When no value is provided, the generated contract reference will use the ABI of the root contract (i.e "ink" in ["ink" and "all" ABI mode][abi-mode] and "sol" in ["sol" ABI mode][abi-mode]). [abi-mode]: ../basics/abi/overview.md ### `env: impl Environment` Specifies the environment to use for the generated contract reference. This should be the same environment used by the root contract (if any). The environment must implement the `Environment` (defined in `ink_env`) trait and provides all the necessary fundamental type definitions for `Balance`, `AccountId` etc. **Usage Example:** Given a custom `Environment` implementation: ```rust #[derive(Clone)] pub struct MyEnvironment; impl ink_env::Environment for MyEnvironment { const NATIVE_TO_ETH_RATIO: u32 = 100_000_000; type AccountId = [u8; 16]; type Balance = u128; type Hash = [u8; 32]; type Timestamp = u64; type BlockNumber = u32; type EventRecord = (); } ``` A user might define an interface (and generate a contract reference) that uses the above custom `Environment` implementation as demonstrated below: ```rust #[ink::contract_ref(env = MyEnvironment)] pub trait Callee { #[ink(message)] fn message(&self); // ... } ``` **Default value:** `DefaultEnvironment` defined in `ink_env` crate. ```` ## File: docs/macros-attributes/contract.md ````markdown --- title: "#[ink::contract]" hide_title: true slug: /macros-attributes/contract --- ![Text/contract Title Picture](/img/title/text/contract.svg) # \#[ink::contract] The `#[ink::contract]` macro is the entry point for writing ink! smart contracts. If you are a beginner trying to learn ink! we recommend starting from the [Getting Started](../getting-started/setup.md) page of this documentation. ## Description The macro does analysis on the provided smart contract code and generates proper code. ## Usage ### Header Arguments The `#[ink::contract]` macro can be provided with some additional comma-separated header arguments: ### `keep_attr: String` Tells the ink! code generator which attributes should be passed to call builders. Call builders are used for making cross-contract calls and are automatically generated for contracts. **Usage Example:** ```rust #[ink::contract(keep_attr = "foo, bar")] mod my_contract { #[ink(storage)] pub struct MyStorage; impl MyStorage { #[ink(constructor)] #[bar] pub fn construct() -> Self { MyStorage {} } #[ink(message)] #[foo] pub fn message(&self) {} } // ... } ``` **Allowed attributes by default:** `cfg`, `cfg_attr`, `allow`, `warn`, `deny`, `forbid`, `deprecated`, `must_use`, `doc`, `rustfmt`. ### `env: impl Environment` Tells the ink! code generator which environment to use for the ink! smart contract. The environment must implement the `Environment` (defined in `ink_env`) trait and provides all the necessary fundamental type definitions for `Balance`, `AccountId` etc. When using a custom `Environment` implementation for a smart contract all types that it exposes to the ink! smart contract and the mirrored types used in the runtime must be aligned with respect to SCALE encoding and semantics. **Usage Example:** Given a custom `Environment` implementation: ```rust pub struct MyEnvironment; impl ink::env::Environment for MyEnvironment { const MAX_EVENT_TOPICS: usize = 3; type AccountId = u64; type Balance = u128; type Hash = [u8; 32]; type Timestamp = u64; type BlockNumber = u32; type ChainExtension = ::ink::env::NoChainExtension; } ``` A user might implement their ink! smart contract using the above custom `Environment` implementation as demonstrated below: ```rust #[ink::contract(env = MyEnvironment)] mod my_contract { pub struct MyEnvironment; impl ink::env::Environment for MyEnvironment { const MAX_EVENT_TOPICS: usize = 3; type AccountId = u64; type Balance = u128; type Hash = [u8; 32]; type Timestamp = u64; type BlockNumber = u32; type ChainExtension = ::ink::env::NoChainExtension; } #[ink(storage)] pub struct MyStorage; impl MyStorage { #[ink(constructor)] pub fn construct() -> Self { MyStorage {} } #[ink(message)] pub fn message(&self) {} } // ... } ``` **Default value:** `DefaultEnvironment` defined in `ink_env` crate. ## Analysis The `#[ink::contract]` macro fully analyses its input smart contract against invalid arguments and structure. Some example rules include but are not limited to: - There must be exactly one `#[ink(storage)]` struct. This struct defines the layout of the storage that the ink! smart contract operates on. The user is able to use a variety of built-in facilities, combine them in various ways or even provide their own implementations of storage data structures. For more information visit the `ink_storage` crate documentation. **Example:** ```rust #[ink::contract] mod flipper { #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { #[ink(constructor)] pub fn construct() -> Self { Flipper { value: false } } #[ink(message)] pub fn message(&self) {} } } ``` - There must be at least one `#[ink(constructor)]` defined method. Methods flagged with `#[ink(constructor)]` are special in that they are dispatchable upon contract instantiation. A contract may define multiple such constructors which allow users of the contract to instantiate a contract in multiple different ways. **Example:** Given the `Flipper` contract definition above we add an `#[ink(constructor)]` as follows: ```rust #[ink::contract] mod flipper { #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { #[ink(constructor)] pub fn new(initial_value: bool) -> Self { Flipper { value: false } } #[ink(message)] pub fn message(&self) {} } } ``` - There must be at least one `#[ink(message)]` defined method. Methods flagged with `#[ink(message)]` are special in that they are dispatchable upon contract invocation. The set of ink! messages defined for an ink! smart contract define its API surface with which users are allowed to interact. An ink! smart contract can have multiple such ink! messages defined. **Note:** - An ink! message with a `&self` receiver may only read state whereas an ink! message with a `&mut self` receiver may modify state. **Example:** Given the `Flipper` contract definition above we add some `#[ink(message)]` definitions as follows: ```rust #[ink::contract] mod flipper { #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { #[ink(constructor)] pub fn new(initial_value: bool) -> Self { Flipper { value: false } } /// Flips the current value. #[ink(message)] pub fn flip(&mut self) { self.value = !self.value; } /// Returns the current value. #[ink(message)] pub fn get(&self) -> bool { self.value } } } ``` **Payable Messages:** An ink! message by default will reject calls that additional fund the smart contract. Authors of ink! smart contracts can make an ink! message payable by adding the `payable` flag to it. An example below: Note that payable ink! messages inherently modify the blockchain state, and therefore must have a `&mut self` receiver. Note that ink! constructors are always implicitly payable and thus cannot be flagged as such. ```rust #[ink::contract] mod flipper { #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { #[ink(constructor)] pub fn new(initial_value: bool) -> Self { Flipper { value: false } } /// Flips the current value. #[ink(message)] #[ink(payable)] // You can either specify payable out-of-line. pub fn flip(&mut self) { self.value = !self.value; } /// Flips the current value. #[ink(message, payable)] // ...or specify payable inline. pub fn flip_2(&mut self) { self.value = !self.value; } /// Returns the current value. #[ink(message)] pub fn get(&self) -> bool { self.value } } } ``` **Controlling the messages selector:** Every ink! message and ink! constructor has a unique selector with which the message or constructor can be uniquely identified within the ink! smart contract. These selectors are mainly used to drive the contract's dispatch upon calling it. An ink! smart contract author can control the selector of an ink! message or ink! constructor using the `selector` flag. An example is shown below: ```rust #[ink::contract] mod flipper { #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { #[ink(constructor)] #[ink(selector = "0xDEADBEEF")] // Works on constructors as well. pub fn new(initial_value: bool) -> Self { Flipper { value: false } } /// Flips the current value. #[ink(message)] #[ink(selector = "0xCAFEBABE")] // You can either specify selector out-of-line. pub fn flip(&mut self) { self.value = !self.value; } /// Returns the current value. #[ink(message, selector = "0xFEEDBEEF")] // ...or specify selector inline. pub fn get(&self) -> bool { self.value } } } ``` ## Interacting with the Contract Executor The `ink_env` crate provides facilities to interact with the contract executor that connects ink! smart contracts with the outer world. For example it is possible to query the current call's caller via: ```rust use ink_env; ink::env::test::run_test::(|_| { let caller = ink::env::caller::(); let _caller = caller; Ok(()) }).unwrap(); ``` However, ink! provides a much simpler way to interact with the contract executor via its environment accessor. An example below: ```rust #[ink::contract] mod greeter { #[ink(storage)] pub struct Greeter; impl Greeter { #[ink(constructor)] pub fn new() -> Self { let caller = Self::env().caller(); let message = format!("thanks for instantiation {:?}", caller); ink::env::debug_println(&message); Greeter {} } #[ink(message, payable)] pub fn fund(&mut self) { let caller = self.env().caller(); let value = self.env().transferred_balance(); let message = format!("thanks for the funding of {:?} from {:?}", value, caller); ink::env::debug_println(&message); } } } ``` ## Events An ink! smart contract may define events that it can emit during contract execution. Emitting events can be used by third party tools to query information about a contract's execution and state. The following example ink! contract shows how an event `Transferred` is defined and emitted in the `#[ink(constructor)]`. ```rust #[ink::contract] mod erc20 { /// Defines an event that is emitted every time value is transferred. #[ink(event)] pub struct Transferred { from: Option, to: Option, value: Balance, } #[ink(storage)] pub struct Erc20 { total_supply: Balance, // more fields ... } impl Erc20 { #[ink(constructor)] pub fn new(initial_supply: Balance) -> Self { let caller = Self::env().caller(); Self::env().emit_event(Transferred { from: None, to: Some(caller), value: initial_supply, }); Self { total_supply: initial_supply } } #[ink(message)] pub fn total_supply(&self) -> Balance { self.total_supply } } } ``` ## Example: Flipper The below code shows the complete implementation of the so-called Flipper ink! smart contract. For us it acts as the "Hello, World!" of the ink! smart contracts because it is minimal while still providing some more or less useful functionality. It controls a single `bool` value that can be either `false` or `true` and allows the user to flip this value using the `Flipper::flip` message or retrieve the current value using `Flipper::get`. ```rust #[ink::contract] pub mod flipper { #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { /// Creates a new flipper smart contract initialized with the given value. #[ink(constructor)] pub fn new(init_value: bool) -> Self { Self { value: init_value } } /// Flips the current value of the Flipper's bool. #[ink(message)] pub fn flip(&mut self) { self.value = !self.value; } /// Returns the current value of the Flipper's bool. #[ink(message)] pub fn get(&self) -> bool { self.value } } } ``` ```` ## File: docs/macros-attributes/default.md ````markdown --- title: "#[ink(default)]" slug: /macros-attributes/default hide_title: true --- ![Text/default Title Picture](/img/title/text/default.svg) Applicable to ink! messages and constructors. Works as a hint for UIs to determine if constructor/message should be picked as default. It's also used to select the constructor to include in Solidity compatible metadata. At most one constructor or message can be marked as default. ## Example ```rust #[ink(message, default)] pub fn im_default(&self) { } ``` ```` ## File: docs/macros-attributes/error.md ````markdown --- title: "#[ink::error]" slug: /macros-attributes/error hide_title: true --- ![Text/error Title Picture](/img/title/text/error.svg) Applicable on `struct` and `enum` definitions. It derives traits necessary for encoding/decoding a custom type as revert error data. The following traits are derived depending on the ABI mode: - In ["ink"][abi-ink] and ["all"][abi-all] ABI mode: - [`scale::Encode` and `scale::Decode`][scale-codec] for encoding/decoding ink! revert error data - [`scale_info::TypeInfo`][scale-info] for generating ink! contract metadata (gated behind the `std` feature) - In ["sol"][abi-sol] and ["all"][abi-all] ABI mode: - [`SolErrorEncode`][sol-error-encode] and [`SolErrorDecode`][sol-error-decode] for encoding/decoding custom types as [Solidity custom errors][sol-custom-error] - `SolErrorMetadata` for generating [Solidity ABI metadata][sol-abi-json] (gated behind the `std` feature) [scale-codec]: https://docs.rs/parity-scale-codec/latest/parity_scale_codec [sol-error-encode]: https://use-ink.github.io/ink/ink/sol/trait.SolErrorEncode.html [sol-error-decode]: https://use-ink.github.io/ink/ink/sol/trait.SolErrorDecode.html [sol-custom-error]: https://soliditylang.org/blog/2021/04/21/custom-errors/ [sol-abi-json]: https://docs.soliditylang.org/en/latest/abi-spec.html#json [scale-info]: https://docs.rs/scale-info/latest/scale_info/ [abi-ink]: ../basics/abi/ink.md [abi-sol]: ../basics/abi/solidity.md [abi-all]: ../basics/abi/all.md ## Example ```rust #[ink::error] struct UnitError; #[ink::error] enum MultipleErrors { UnitError, ErrorWithParams(bool, u8, String), ErrorWithNamedParams { status: bool, count: u8, reason: String, } } ``` :::note See our [Solidity ABI compatibility docs][sol-result] for more details about handling Solidity ABI encoded [revert error data][sol-revert]. ::: [sol-revert]: https://docs.soliditylang.org/en/latest/control-structures.html#revert [sol-result]: ../integrations-and-sdks/ethereum-compatibility.md#handling-the-resultt-e-type ```` ## File: docs/macros-attributes/event.md ````markdown --- title: "#[ink::event]" slug: /macros-attributes/event hide_title: true --- ![Text/event2 Title Picture](/img/title/text/event2.svg) Applicable on `struct` definitions. Defines an ink! event. A contract can define multiple such ink! events. Events can now be defined independently of contracts. The legacy syntax of events defined within a contract module using `#[ink(event)]` continues to be valid. [See our section on Events](../basics/events.md) for a detailed description and examples. ```` ## File: docs/macros-attributes/implementation.md ````markdown --- title: "#[ink(impl)]" slug: /macros-attributes/impl hide_title: true --- ![Text/impl Title Picture](/img/title/text/impl.svg) This attribute supports a niche case that is rarely needed. Can be applied on ink! implementation blocks in order to make ink! aware of them. This is useful if such an implementation block doesn't contain any other ink! attributes, so it would be flagged by ink! as a Rust item. Adding `#[ink(impl)]` on such implementation blocks makes them treated as ink! implementation blocks thus allowing to access the environment etc. Note that ink! messages and constructors still need to be explicitly flagged as such. ## Example An implementation block can be defined as a trait implementation for the ink! storage struct using the `#[ink(impl)]` annotation ‒ even if none of its interior items have any ink! specific attributes on them: ```rust use core::convert::TryFrom; #[ink::contract] mod my_module { #[ink(storage)] pub struct MyStorage { /* storage fields */ } #[ink(impl)] impl MyStorage { fn my_method(&self) -> i32 { /* method implementation */ } } impl MyStorage { #[ink(constructor)] pub fn my_constructor() -> Self { /* constructor implementation */ } #[ink(message)] pub fn my_message(&self) { /* message implementation */ } } } ``` ```` ## File: docs/macros-attributes/message.md ````markdown --- title: "#[ink(message)]" slug: /macros-attributes/message hide_title: true --- ![Text/message Title Picture](/img/title/text/message.svg) Applicable to methods. Flags a method for the ink! storage struct as message making it available to the API for calling the contract. Note that all public functions must use the `#[ink(message)]` attribute There must be at least one `#[ink(message)]` defined method. Methods flagged with `#[ink(message)]` are special in that they are dispatchable upon contract invocation. The set of ink! messages defined for an ink! smart contract define its API surface with which users are allowed to interact. An ink! smart contract can have multiple such ink! messages defined. An ink! message with a `&self` receiver may only read state whereas an ink! message with a `&mut self` receiver may modify state. ```rust #[ink(message)] pub fn read_only(&self, from: AccountId) { // actual implementation } #[ink(message)] pub fn modifies_state(&mut self, from: AccountId) { // actual implementation } ``` ## Messages Return Value The return value of a message needs to implement `scale::Encode`. It is notable that the collections under `ink_storage` ‒ such as e.g. `Vec` or `HashMap` ‒ don't implement `scale::Encode`. This means you can't just return a `Vec` from an ink! message. This restriction is intentional ‒ returning a complete data structure with a potentially unbounded content is an anti-pattern for smart contracts. Just think about the unpredictable gas costs. If you _really really_ need to return a data structure in its entirety then use the ones from `ink_prelude` (e.g. `ink_prelude::vec::Vec`). Those implement `scale::Encode`. :::note In ["sol"][abi-sol] and ["all"][abi-all] ABI mode, the return value of a message must either implement [`SolEncode`][sol-encode], or be a `Result` type where `T` implements [`SolEncode`][sol-encode] and `E` implements [`SolErrorEncode`][sol-error-encode]. See our [Solidity ABI compatibility docs][sol-abi-compat] for more details. ::: [abi-all]: ../basics/abi/all.md [abi-sol]: ../basics/abi/solidity.md [sol-encode]: https://use-ink.github.io/ink/ink/trait.SolEncode.html [sol-error-encode]: https://use-ink.github.io/ink/ink/sol/trait.SolErrorEncode.html [sol-abi-compat]: ../integrations-and-sdks/ethereum-compatibility.md ## Example Given the `Flipper` contract definition above we add some `#[ink(message)]` definitions as follows: ```rust #[ink::contract] mod flipper { #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { #[ink(constructor)] pub fn new(initial_value: bool) -> Self { Flipper { value: false } } /// Flips the current value. #[ink(message)] pub fn flip(&mut self) { self.value = !self.value; } /// Returns the current value. #[ink(message)] pub fn get(&self) -> bool { self.value } } } ``` ```` ## File: docs/macros-attributes/name.md ````markdown --- title: "#[ink(name = \"…\")]" slug: /macros-attributes/name hide_title: true --- ![Text/name Title Picture](/img/title/text/name.svg) Applicable to ink! messages, ink! constructors and ink! events. Specifies a name/identifier override that is used in place of the item's name/identifier for: - [Selector][selector] computation for ink! messages and ink! constructors - [Signature topic][signature-topic] computation for ink! events - [Contract metadata][metadata] generation for the ink! messages, ink! constructors or ink! events [selector]: ./selector.md [signature-topic]: ../basics/events.md#signature-topic [metadata]: ../basics/metadata/overview.md#topics In general, `name` overrides should mainly be used to: - Implement contracts compliant with Ethereum/Solidity contract standards (i.e. ERCs) that require/use overloaded interfaces - Define interfaces (e.g. via trait definitions) for interacting with existing Solidity ABI encoded contracts with overloaded interfaces - As a more transparent alternative to custom selectors for the "name-changing while maintaining the same selector" use case for ink! ABI contracts :::note For native/ink! ABI, message and constructor selectors are computed from the item name/identifier alone, so multiple messages with the same `name` attribute override will have the same computed selector, which results in a compilation error about the overlapping selectors. In general, more semantic interfaces with descriptive and unique item names/identifiers are encouraged for new contracts (especially contracts that support the ink! ABI i.e. "ink" or "all" ABI mode). ::: ## Examples ```rust #[ink(constructor, name = "myConstructor")] fn my_constructor(&self) {} #[ink(message, name = "myMessage")] fn my_message(&self) {} #[ink::event(name = "MyEvent")] pub struct Event { ... } ``` This changes the resulting selectors of the ink! message and ink! constructor, and the signature topic for the ink! event, as well as their names in contract metadata. :::note For native/ink! ABI, the [`selector` attribute][selector] has higher precedence than the `name` attribute. This means that the manually provided selector is used when an ink! message or ink! constructor is annotated with both the `selector` and `name` attributes e.g. in the example below, the selector for the ink! message is `0x1`. ``` #[ink(message, name = "myMessage", selector = 0x1)] fn my_message(&self) {} ``` ::: ```` ## File: docs/macros-attributes/namespace.md ````markdown --- title: "#[ink(namespace = \"…\")]" slug: /macros-attributes/namespace hide_title: true --- ![Text/namespace Title Picture](/img/title/text/namespace.svg) Applicable to ink! trait implementation blocks. Applied on ink! trait implementation blocks to disambiguate other trait implementation blocks with equal names. ## Example ```rust #[ink(namespace = "my_namespace")] impl MyTrait for MyStorage { #[ink(message)] fn my_message(&self) {} } ``` This changes the resulting selectors of all the ink! messages and ink! constructors within the trait implementation. Thus allowing disambiguation between trait implementations with overlapping message or constructor names. ```` ## File: docs/macros-attributes/overview.md ````markdown --- title: Overview slug: /macros-attributes hide_title: true --- ![Text/contract Title Picture](/img/title/text/contract.svg) An ink! module is the module that is flagged by `#[ink::contract]` containing all the ink! definitions. All ink! attributes are available to specify inside an ink! module. ## Merging Attributes It is possible to merge attributes that share a common flagged entity. The example below demonstrates this for a payable message with a custom selector. ```rust #[ink(message)] #[ink(payable)] #[ink(selector = "0xCAFEBABE")] pub fn transfer(&mut self, from: AccountId, to: AccountId, value: Balance) -> Result<(), Error> { // actual implementation } ``` We can also write the above ink! message definition in the following way: ```rust #[ink(message, payable, selector = "0xCAFEBABE")] pub fn transfer(&mut self, from: AccountId, to: AccountId, value: Balance) -> Result<(), Error> { // actual implementation } ``` ```` ## File: docs/macros-attributes/payable.md ````markdown --- title: "#[ink(payable)]" slug: /macros-attributes/payable hide_title: true --- ![Text/payable Title Picture](/img/title/text/payable.svg) Applicable to ink! messages. Allows receiving value as part of the call of the ink! message. ink! constructors are implicitly payable, due to the initial endowment which a contract requires. An ink! message by default will reject calls that additional fund the smart contract. Authors of ink! smart contracts can make an ink! message payable by adding the `payable` flag to it. An example below: Note that payable ink! messages inherently modify the blockchain state, and therefore must have a `&mut self` receiver. Note that ink! constructors are always implicitly payable and thus cannot be flagged as such. ```rust #[ink::contract] mod flipper { #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { #[ink(constructor)] pub fn new(initial_value: bool) -> Self { Flipper { value: false } } /// Flips the current value. #[ink(message)] #[ink(payable)] // You can either specify payable out-of-line. pub fn flip(&mut self) { self.value = !self.value; } /// Flips the current value. #[ink(message, payable)] // or specify payable inline. pub fn flip_2(&mut self) { self.value = !self.value; } /// Returns the current value. #[ink(message)] pub fn get(&self) -> bool { self.value } } } ``` ## Example ```rust #[ink(message, payable)] pub fn pay_me(&mut self) { let _transferred = self.env().transferred_value(); } ``` See the [`examples/contract-transfer`](https://github.com/use-ink/ink-examples/blob/main/contract-transfer/lib.rs) contract for a more extensive example. ```` ## File: docs/macros-attributes/selector.md ````markdown --- title: "#[ink(selector = S:u32)]" slug: /macros-attributes/selector hide_title: true --- ![Text/selector Title Picture](/img/title/text/selector.svg) :::note ink! v6 supports both the native ink! and [Solidity][sol-abi] ABI (Application Binary Interface) specifications for contract interactions (i.e. calling conventions used for message calls). When support for Solidity ABI calling conventions is enabled (see [here][abi-declaration] for details), Solidity ABI selectors for messages are **always** generated according to the [Solidity ABI specification for function selectors][sol-abi-selector]. So the instructions below for **controlling message selectors only apply to native ink! ABI selectors** (i.e. message selector manual overrides are ignored when generating Solidity ABI selectors for messages). Learn more about ink!'s support for multiple ABIs [here][abi-support]. ::: [sol-abi]: https://docs.soliditylang.org/en/latest/abi-spec.html [sol-abi-selector]: https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector [abi-support]: ../basics/abi/overview.md [abi-declaration]: ../basics/abi/overview.md#declaring-the-abi Applicable to ink! messages and ink! constructors. By default, ink! creates a selector for each message and constructor. This is necessary since the contract is compiled to a binary blob and functions are invoked by invoking the selector, which identifies a method ‒ method names are no longer available in these underlying layers. Using this attribute it is possible to specify a concrete dispatch selector for the flagged entity. This allows a contract author to precisely control the selectors of their APIs making it possible to rename their API without breakage. A selector must be a `u32` decodable integer. For example - `selector = 0xCAFEBABE` - `selector = 42` An exception is the fallback selector `_`, allowing contract calls not matching any of the other message selectors to be dispatched to a fallback message. Fallback messages can be `payable`. :::info The term wildcard selector is just a synonym for fallback selector. ::: ## Examples ```rust #[ink(message, selector = 0xC0DECAFE)] fn my_message_1(&self) {} #[ink(message, selector = 42)] fn my_message_2(&self) {} #[ink(message, payable, selector = _)] fn my_fallback(&mut self) {} ``` … then the selector of `my_message_1` is `[0xC0, 0xDE, 0xCA, 0xFE]` and the selector of `my_message_2` is `[0, 0, 0, 42]` since setting the selector manually overrides the automatically generated selector. ## Controlling message and constructor selectors Every ink! message and ink! constructor has a selector with which the message or constructor can be uniquely identified within the ink! smart contract. Non-unique message or constructor selector lead to a compile time error. These selectors are mainly used to drive the contract's dispatch upon calling it. An ink! smart contract author can control the selector of an ink! message or ink! constructor using the `selector` flag. An example is shown below: ```rust #[ink::contract] mod flipper { #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { #[ink(constructor)] #[ink(selector = 0xDEADBEEF)] // Works on constructors as well. pub fn new(initial_value: bool) -> Self { Flipper { value: initial_value } } #[ink(message)] #[ink(selector = 0xCAFEBABE)] // You can either specify selector out-of-line. pub fn flip(&mut self) { self.value = !self.value; } #[ink(message, selector = 0xC0DECAFE)] // ...or specify the selector inline. pub fn get(&self) -> bool { self.value } } } ``` ```` ## File: docs/macros-attributes/storage.md ````markdown --- title: "#[ink(storage)]" slug: /macros-attributes/storage hide_title: true --- ![Text/storage Title Picture](/img/title/text/storage.svg) Applicable on `struct` definitions. Applied on `struct` types in order to flag them for being the contract's storage definition. There can only be one ink! storage definition per contract. There must be exactly one `#[ink(storage)]` struct. This struct defines the layout of the storage that the ink! smart contract operates on. The user is able to use a variety of built-in facilities, combine them in various ways or even provide their own implementations of storage data structures. For more information visit the `ink_storage` crate documentation. ## Example ```rust #[ink::contract] mod flipper { #[ink(storage)] pub struct Flipper { value: bool, } impl Flipper { #[ink(constructor)] pub fn construct() -> Self { Flipper { value: false } } #[ink(message)] pub fn message(&self) {} } } ``` ```` ## File: docs/macros-attributes/topic.md ````markdown --- title: "#[ink(topic)]" slug: /macros-attributes/topic hide_title: true --- ![Text/topic Title Picture](/img/title/text/topic.svg) Applied on fields of ink! event types to indicate that they are topics. Tells the ink! codegen to provide a topic hash for the given field. Every ink! event can only have a limited number of such topic field. The semantics are similar to indexed event arguments in Solidity. ## Example ```rust #[ink(event)] pub struct Transferred { #[ink(topic)] from: Option, #[ink(topic)] to: Option, amount: Balance } ``` ```` ## File: docs/macros-attributes/trait_definition.md ````markdown --- title: "#[ink::trait_definition]" slug: /macros-attributes/trait_definition hide_title: true --- ![Text/trait Title Picture](/img/title/text/trait.svg) Marks trait definitions to ink! as special ink! trait definitions. There are some restrictions that apply to ink! trait definitions that this macro checks. Also ink! trait definitions are required to have specialized structure so that the main [`#[ink::contract]`](./contract.md) macro can properly generate code for its implementations. [See our section on Trait Definitions](../basics/trait-definitions.md) for a detailed description and examples. ```` ## File: docs/testing/testnet/faucet.md ````markdown --- title: Faucet slug: /faucet hide_title: true --- import useBaseUrl from '@docusaurus/useBaseUrl'; ![Faucet Title Picture](/img/title/faucet.svg) # Faucet The community-maintained Polkadot testnet "Paseo" provides a faucet: [Paseo Faucet](https://faucet.polkadot.io/). By requesting funds from the link above you will receive `PAS` tokens to your account. The polkadot-js UI will display them under [the "Accounts" tab](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpaseo.dotters.network#/accounts): Paseo testnet tokens in wallet You can deploy your contract with PAS token on [Pop's Testnet](https://learn.onpop.io/contracts/tutorials/your-first-ink-smart-contract). See [Pop's guide to getting tokens](https://learn.onpop.io/contracts/guides/bridge-tokens-to-pop-network). ```` ## File: docs/testing/testnet/Faucet.tsx ````typescript import React, { useMemo, useState } from 'react' import ReCAPTCHA from 'react-google-recaptcha' const RECAPTCHA_SITE_KEY = '6LcgFI4nAAAAAATrEMoJ6zBacsx5udc1UhGFXemH' const FAUCET_URL = 'https://rococo-faucet.parity-testnet.parity.io/drip/web' const Faucet = () => { const [captcha, setCaptcha] = useState(null) const acc = useMemo(() => { if (typeof window === 'undefined') return ''; const params = new URLSearchParams(window?.location?.search); return params?.get('acc') || undefined; }, []) const [address, setAddress] = useState(acc) const [hash, setHash] = useState() const [error, setError] = useState() const [inProgress, setInProgress] = useState(false) const handleRequest = async () => { try { setHash(undefined) setError(undefined) setInProgress(true) const body = { address, parachain_id: '1002', recaptcha: captcha, } const fetchResult = await fetch(FAUCET_URL, { method: 'POST', body: JSON.stringify(body), headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, }) const result = await fetchResult.json() if ('error' in result) { setError(result.error) } else { setHash(result.hash) } } catch (e) { // eslint-disable-next-line no-console console.error(e) setError('Hmm... something went wrong.') } finally { setInProgress(false) } } return (

Get Testnet Tokens

illustration of a sea grass plant illustration of a sea plant
treasure chest
{ setAddress(e.target.value) setError(undefined) setHash(undefined) }} />
{hash && ( )} {error &&

{error}

}
) } export default Faucet ```` ## File: docs/testing/testnet/overview.md ````markdown --- title: Contracts on Paseo hide_title: true slug: /testnet --- import useBaseUrl from '@docusaurus/useBaseUrl'; ![Testnet Title Picture](/img/title/testnet.svg) # Contracts on Paseo (using Pop Testnet) - [Paseo](https://wiki.polkadot.network/docs/build-pdk#paseo-testnet) is Polkadot's main testnet for parachains. - [Pop](https://learn.onpop.io/contracts) is a parachain on Paseo that allows you to deploy smart contracts – and uses Paseo's token (PAS). ## How can I use it? ### (1) Create an Account As a first step, you should create an account. This can be done via command-line tools (e.g. `subxt`) or via a wallet (e.g. with the `polkadot-js` browser extension). See [here](https://wiki.polkadot.network/docs/learn-account-generation) for a detailed guide. ### (2) Get Testnet Tokens As a second step, you have to get `PAS` testnet tokens through the [Paseo Faucet](https://faucet.polkadot.io/). For Pop, make sure to select Asset Hub as the destination (see [this guide](https://learn.onpop.io/contracts/guides/bridge-tokens-to-pop-network) for details). Alternatively, you can use the [Matrix chat room](https://wiki.polkadot.network/docs/learn-DOT#getting-tokens-on-the-paseo-testnet). You must send a message like this: ``` !drip ``` If everything worked out, the `PAS` tokens will show up in your account. In case you are using the `polkadot-js` frontend, you can see them under [the "Accounts" tab for Paseo](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpaseo.dotters.network#/accounts). Paseo testnet tokens in wallet ### (3) Deploy Your Contract Once you have `PAS` on Paseo you can [bridge them from Paseo to Pop](https://learn.onpop.io/contracts/guides/bridge-tokens-to-pop-network) and deploy by following the instructions in the Pop Docs [here](https://learn.onpop.io/contracts/guides/deploy#deploy-to-custom-or-public-network). ```` ## File: docs/testing/e2e.md ````markdown --- title: "Full E2E" hide_title: true slug: /contract-testing/end-to-end-e2e-testing --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ![Testing1 Title Picture](/img/title/testing1.svg) # End-to-End (E2E) Tests E2E testing enables developers to write a test that will not only test the contract in an isolated manner; instead the contract will be tested _together_ with all components that will be involved on-chain – so from end to end. This way of testing resembles closely how the contract will actually behave in production. As part of the test, the contract will be compiled and deployed to a Polkadot SDK node that is running in the background. ink! offers API functions that enable developers to then interact with the contract via transactions that they create and submit to the blockchain. You as a developer can define assertions on the outcome of their transactions, such as checking for state mutations, transaction failures or incurred gas costs. Your chain configuration will be tested together with the smart contract. And if your chain has pallets that are involved with the smart contract execution, those will be part of the test execution as well. ink! does not put any requirements on the Polkadot SDK node in the background – for example, you can run a node that contains a snapshot of a live network. ## Example The following code example illustrates a basic E2E test for the [flipper example](https://github.com/use-ink/ink-examples/blob/main/flipper/lib.rs). ```rust #[ink_e2e::test] async fn default_works(mut client: Client) -> E2EResult<()> { // When the function is entered, the contract was already // built in the background via `cargo contract build`. // The `client` object exposes an interface to interact // with the Polkadot SDK node. // given let mut constructor = FlipperRef::new_default(); // when let contract = client .instantiate("flipper", &ink_e2e::bob(), &mut constructor) .submit() .await .expect("instantiate failed"); let call_builder = contract.call_builder::(); // then let get = call_builder.get(); let get_res = client.call(&ink_e2e::bob(), &get).dry_run().await?; assert!(matches!(get_res.return_value(), false)); Ok(()) } ``` You can run the above test by going to the `flipper` folder in [the ink! examples directory](https://github.com/use-ink/ink-examples/tree/main). Before you can run the test, you have to install a Polkadot SDK node with `pallet-revive`. By default, e2e tests require that you install [`ink-node`](https://github.com/use-ink/ink-node). You do not need to run it in the background since the node is started for each test independently. The easiest way is to [download a binary from our releases page](https://github.com/use-ink/ink-node/releases) (Linux and Mac). Alternatively, you can build the node by yourself. The build instructions and pre-requisites can be found [here](https://github.com/use-ink/ink-node?tab=readme-ov-file#build-locally). If you want to run any other node with `pallet-revive` you need to change `CONTRACTS_NODE` environment variable: ```bash export CONTRACTS_NODE="YOUR_CONTRACTS_NODE_PATH" ``` And finally execute the following command to start e2e test execution. ```bash cargo contract test --features e2e-tests ``` ```bash pop test --e2e ``` ```` ## File: docs/testing/overview.md ````markdown --- title: Overview hide_title: true slug: /contract-testing/overview --- ![Testing1 Title Picture](/img/title/testing1.svg) # Testing Strategies ink! supports three different stages of testing: unit, integration and end-to-end tests. In this chapter we'll explain what the purpose of each stage is about and how to use it. ![ink! Testing Strategies](/img/testing.png) Generally you can think of those three types of testing as a pyramid with the top being the most elaborate test. The End-to-End (E2E) tests at the top will test the lower layers of the pyramid as part of them. ```` ## File: docs/testing/sandbox.md ````markdown --- title: "Sandboxed E2E" hide_title: true slug: /contract-testing/drink --- ![Drink Title Picture](/img/title/drink.svg) :::note TODO This page has not yet been reviewed for ink! v6. ::: # DRink! Apart from the core ink! testing framework, we also provide the [DRink!](https://github.com/use-ink/drink) library. It offers an intermediate solution between integration and E2E testing. Intuitively, DRink! maintains a full in-memory blockchain state and allows you to interact with it directly. This gives a notably robust methodology in contrast to the off-chain engine facilitated by the `ink::test` macro. Nevertheless, it is essential to note that the absence of the entire node layer makes the environment less realistic compared to the comprehensive setup employed in the end-to-end tests. ## Comparison to the other testing strategies To better assess when DRink! performs better than other testing methods, it is crucial to gain a deeper understanding of the consequences of its unique design and the trade-offs it entails. 1. **Speed:** since DRink! doesn't spawn any node or background process, everything happens locally, within the testing thread. This means that the execution can be synchronous and significantly faster than the E2E tests. Therefore, its performance should be comparable to the unit or integration testing. Also, there is no block production or finalization delay, which is a noticeable factor in the E2E tests. Thanks to that, we can launch long-running simulations in a reasonable time. 2. **Testing multiple contracts:** since we are working with a full blockchain state, we can perform any interaction with the contracts, which includes working with mutliple contracts at the same time. Of course, this is the same as in the E2E tests, but it is not possible in either the unit or integration tests. 3. **Working with arbitrary runtimes:** similarly to the E2E tests, where we can spawn any node with customized runtime (Polkadot's term for the state transition function), in DRink! tests we can work with any blockchain runtime we want. 4. **Full control over runtime state:** we hold the state of the blockchain and exercise full control over it, so we can easily manipulate it however we want. This covers manipulating block number, timestamp, account balances, etc. Some of these are also possible in the E2E tests, but usually they require more effort or overhead. 5. **Powerful features:** thanks to the unique design of DRink!, we can easily take advantage of some powerful, not available in other testing strategies, features: - **contract mocking:** you can mock any contract or message you want, specifying the default behavior or the exact return value. - **enhanced debugging and call tracing:** you can get more insights into the contract execution process, like stack trace, debug buffers and more. Nevertheless, there are some drawbacks of DRink! as well: 1. **No node layer:** since we don't spawn any node, we don't have access to the node layer, which means that we can't test any node-related functionality, like RPC calls, block production, etc. 2. **Artificial, isolated environment:** this is the main trade-off of DRink!. It might give a false sense of security, while in the real environment, the contract could behave differently. The discrepancy can be mitigated by a careful and precise simulation and setup of the environment, but it is still a factor to consider. 3. **No typed contract API:** currently, DRink! works with string-encoded arguments and values, which means that we lose the type safety and convenience that was present in the other testing frameworks. Fortunately, this is going to change soon, as there is an ongoing effort to integrate it with [ink-wrapper](https://github.com/Cardinal-Cryptography/ink-wrapper) library. ## When to use `DRink!`? Usually, DRink! is a good choice for the development phase of your project. When the iteration speed is crucial, and you want to quickly test your contracts, DRink! will offer a versatile, yet highly efficient testing environment. However, you must not forget that it is not a replacement for the E2E tests, which should be run before the deployment to the production network, as well as in your CI/CD pipelines. DRink! also comes in handy when you need to: - mock some parts of your contract suite - debug the execution process - launch long-running simulations, that would normally take a lot of time when relying on a real block-time ## How to use DRink!? There are three ways to use DRink!: ### Directly as a library This way you gain access to full DRink! power in your test suites. `drink` library is continuously published to [crates.io](https://crates.io/crates/drink), so you can use it in your project with either `cargo add drink` or by adding the following line to your `Cargo.toml`: ```toml drink = { version = "0.8" } ``` Then, you can write your tests like this: ```rust #[cfg(test)] mod tests { /// This will take care of building all contract dependencies in the compilation phase and gather all contract /// bundles (metadata and the compiled code) into a single registry. #[drink::contract_bundle_provider] enum BundleProvider {} /// Within `drink::test` macro, you are provided with a `session` object, which is a wrapper around the /// blockchain state. You can use it to deploy contracts, call their methods, and more. #[drink::test] fn deploy_and_call_a_contract(mut session: Session) -> Result<(), Box> { let result: bool = session .deploy_bundle_and(BundleProvider::local(), "new", &["true"], NO_SALT, NO_ENDOWMENT)? .call_and("flip", NO_ARGS, NO_ENDOWMENT)? .call_and("flip", NO_ARGS, NO_ENDOWMENT)? .call_and("flip", NO_ARGS, NO_ENDOWMENT)? .call("get", NO_ARGS, NO_ENDOWMENT)??; assert_eq!(result, false); } } ``` You can check some helpful and verbose examples [here](https://github.com/inkdevhub/drink/tree/main/examples), including the [**quick start guide**](https://github.com/inkdevhub/drink/tree/main/examples/quick-start-with-drink). ### As an alternative backend to ink!'s E2E testing framework DRink! is already integrated with the ink! framework and can be used as a drop-in replacement for the standard E2E testing environment. Import `ink_sandbox` in your Cargo.toml: ```toml ink_sandbox = { git = "https://github.com/use-ink/ink", branch = "6.0.0-beta" } ``` And just use corresponding argument in the test macro: ```rust #[ink_sandbox::test(backend(runtime_only( sandbox = sandbox_runtime::ContractCallerSandbox, client = ink_sandbox::SandboxClient )))] ``` to your test function and you have just switched from E2E testcase to DRink!-based one, that doesn't use any running node in the background! For a full example check out [ink! repository](https://github.com/use-ink/ink-examples/tree/main/e2e-runtime-only-backend). ### With a command line tool We provide a CLI which puts DRink! behind friendly TUI. For more details, consult [its README](https://github.com/inkdevhub/drink/blob/main/drink-cli/README.md). Similarly to `drink` library, `drink-cli` is published to [crates.io](https://crates.io/crates/drink-cli) as well. You can install it with: ```shell cargo install drink-cli ``` ```` ## File: docs/testing/testing-with-live-state.md ````markdown --- title: Testing with Chain Snapshots hide_title: true slug: /contract-testing/chain-snapshot --- ![Blockchain Fork Title Picture](/img/title/blockchain-fork.svg) # Test your Contract with a Chain Snapshot :::caution This page has not yet been updated to ink! v6. TODO ::: On this page we explain how to test ink! contracts with the fork of an existing chain. We'll take a snapshot of an existing chain for this purpose. The snapshot contains the chains full state, but can be modified locally without affecting the live chain. We'll use the [Chopsticks](https://github.com/AcalaNetwork/chopsticks) tool for this purpose. This is a powerful workflow that you can use to e.g. * Test a contract upgrade or migration locally before running it in production. * Debug the behavior of an on-chain contract with on-chain state locally. * Get detailed debug info and replay blocks as you want. * …and much more! In the first section of this page we explain the general concept, using a local `ink-node` that will play the role of our "live chain". The `ink-node` is just for exemplary purposes, you can also apply the exact same workflow to production chains like Astar, Aleph Zero, Pendulum and others. ## General Concept First you need a node that has produced some blocks with state. We'll use `ink-node` for this purpose. [See here](../getting-started/deploying.md) for how to run it. You should get output similar to: ``` ink-node 2023-09-26 07:58:28.885 INFO main sc_cli::runner: ink! Node 2023-09-26 07:58:28.887 INFO main sc_cli::runner: ✌️ version 0.30.0-124c159ba94 2023-09-26 07:58:28.887 INFO main sc_cli::runner: ❤️ by Parity Technologies , 2021-2023 2023-09-26 07:58:28.887 INFO main sc_cli::runner: 📋 Chain specification: Development 2023-09-26 07:58:28.887 INFO main sc_cli::runner: 🏷 Node name: chilly-desire-6458 2023-09-26 07:58:28.887 INFO main sc_cli::runner: 👤 Role: AUTHORITY 2023-09-26 07:58:28.887 INFO main sc_cli::runner: 💾 Database: ParityDb at /tmp/substrateoKCAts/chains/dev/paritydb/full 2023-09-26 07:58:38.723 INFO main sc_rpc_server: Running JSON-RPC server: addr=127.0.0.1:9944, allowed origins=["*"] ``` Note that the node is running on port 9944. Next, we'll create some state and produce a bunch of blocks. You can do this by deploying [our `flipper` example](https://github.com/use-ink/ink-examples/tree/main/flipper): ``` cd ink-examples/flipper/ cargo contract build --release cargo contract instantiate --suri //Alice --args true -x ``` You can check that the contract exists by querying its state via `cargo-contract`: ``` cargo contract storage --contract 5FgRdaReCLFtwbzYiVd2hoz9P3oERdNy2njnFmUBHu4FYg7s +-------+----------+--------+-------------------------+ | Index | Root Key | Parent | Value | +=====================================================+ | 0 | 00000000 | root | Flipper { value: true } | +-------+----------+--------+-------------------------+ ``` ### Setup Chopsticks We will now set up [Chopsticks](https://github.com/AcalaNetwork/chopsticks), a powerful tool in our ecosystem that allows us to create a parallel reality of an existing network. We will run it and have it mirror the `ink-node` that is already running on our machine from the previous step. The following schema illustrates the setup that we will create: Chain Snapshot Clone chopsticks: ``` git clone https://github.com/AcalaNetwork/chopsticks ``` Modify the `dev.yml` config file in the cloned repository (or create one from scratch) : ``` endpoint: ws://127.0.0.1:9944 mock-signature-host: true block: 1 db: ./db.sqlite ``` :::info In the example above chopsticks will be mirroring up until block 1 from the `ink-node`. For production chains (like Aleph Zero or Astar) you would want to use a different block number and different endpoint. The Chopsticks repository already contains a wide number of configurations for ink! production chains (see [here](https://github.com/AcalaNetwork/chopsticks/tree/master/configs)). If you don't find a fitting configuration there, see the section "[Application to Production Chains](#application-to-production-chains)". ::: You can either run chopsticks locally by following the instructions [here](https://github.com/AcalaNetwork/chopsticks#install), or you can run it using npx: ``` npx @acala-network/chopsticks@latest --config=configs/dev.yml ``` You should get output similar to: ``` npx @acala-network/chopsticks@latest --config=configs/dev.yml [08:22:31.231] INFO (rpc/3037748): Development RPC listening on port 8000 ``` The Chopsticks node is running on port 8000. If you now execute the `cargo-contract` storage command against this node, you'll see that the `flipper` contract exists there as well: ``` cargo contract storage --contract 5FgRdaReCLFtwbzYiVd2hoz9P3oERdNy2njnFmUBHu4FYg7s --url=ws://localhost:8000 +-------+----------+--------+-------------------------+ | Index | Root Key | Parent | Value | +=====================================================+ | 0 | 00000000 | root | Flipper { value: true } | +-------+----------+--------+-------------------------+ ``` Chopsticks has branched off from the live chain. You can now submit transactions to the Chopsticks node on port 8000, without affecting the node/chain on port 9944. ### Run ink! E2E Tests Recap: We have our "live" `ink-node` running on port 9944 and our test node with the branched state running on port 8000. Next we would like to run some tests against the contract on our forked chain. Our `flipper/lib.rs` contains a test that illustrates how to do this. The test reads an environment variable `CONTRACT_ADDR_HEX` that refers to the `flipper` on-chain address. Here's the code for it: ```rust #[ink_e2e::test] #[ignore] async fn e2e_test_deployed_contract( mut client: Client, ) -> E2EResult<()> { // given let addr = std::env::var("CONTRACT_ADDR_HEX") .unwrap() .replace("0x", ""); let acc_id = hex::decode(addr).unwrap(); let acc_id = AccountId::try_from(&acc_id[..]).unwrap(); // when // Invoke `Flipper::flip()` from Bob's account let call_builder = ink_e2e::create_call_builder::(acc_id); let flip = call_builder.flip(); let _flip_res = client.call(&ink_e2e::bob(), &flip).submit().await?; // then let get = call_builder.get(); let get_res = client.call(&ink_e2e::bob(), &get).dry_run().await?; assert!(matches!(get_res.return_value(), false)); Ok(()) } ``` The test is marked as `#[ignore]`, as it requires the pre-conditions that we went through above to succeed. :::info You can convert SS58 addresses to hex using [the `subkey` tool](https://crates.io/crates/subkey): ``` subkey inspect ``` ::: Here's the process to execute the above test: ``` # Address of your on-chain contract export CONTRACT_HEX=0x2c75f0aa09dbfbfd49e6286a0f2edd3b4913f04a58b13391c79e96782f5713e3 # This env variable needs to be set to reference the Chopsticks node. # If this env variable is not set, `ink_e2e` will spawn a new node # process (typically of `ink-node`) for each test. export CONTRACTS_NODE_URL=ws://127.0.0.1:8000 cargo contract test --features e2e-tests e2e_test_deployed_contract -- --ignored ``` You will get output similar to the following: ``` running 1 tests test flipper::e2e_tests::e2e_test_deployed_contract ... ok ``` If you query the contract storage on our Chopsticks fork, you'll see that the E2E test flipped the boolean: ``` cargo contract storage --contract 5FgRdaReCLFtwbzYiVd2hoz9P3oERdNy2njnFmUBHu4FYg7s --url=ws://localhost:8000 +-------+----------+--------+-------------------------+ | Index | Root Key | Parent | Value | +=====================================================+ | 0 | 00000000 | root | Flipper { value: false } | +-------+----------+--------+-------------------------+ ``` On the "original" `ink-node` chain the boolean will be untouched. ``` cargo contract storage --contract 5FgRdaReCLFtwbzYiVd2hoz9P3oERdNy2njnFmUBHu4FYg7s --url=ws://localhost:9944 +-------+----------+--------+-------------------------+ | Index | Root Key | Parent | Value | +=====================================================+ | 0 | 00000000 | root | Flipper { value: true } | +-------+----------+--------+-------------------------+ ``` Success! We just ran an ink! end-to-end test against the snapshot of a chain! ## Application to Production Chains You can apply the workflow explained above to ink! production chains. You would want to use a different block number and different endpoint. The Chopsticks repository already contains a wide number of configurations for ink! production chains (see [here](https://github.com/AcalaNetwork/chopsticks/tree/master/configs)). If a pre-made config for chain you want to fork from is not available, you can just modify the `dev.yml`. You can use [polkadot-js/apps](https://polkadot.js.org/apps) to the URL of an endpoint to use: ```` ## File: docs/testing/unit-integration.md ````markdown --- title: Unit & Integration hide_title: true slug: /contract-testing/unit-integration-tests --- ![Testing1 Title Picture](/img/title/testing1.svg) # Tests On this page we lay out the different use-cases for unit vs. integration tests. ## Unit Tests Testing contracts off-chain is done by `cargo contract test` and users can simply use the standard Rust routines of creating unit test modules within the ink! project: ```rust #[cfg(test)] mod tests { use super::*; #[test] fn my_test() { ... } } ``` Test instances of contracts can be created with something like: ```rust let contract = MyContract::my_constructor(a, b); ``` Messages can simply be called on the returned instance as if `MyContract::my_constructor` returns a `Self` instance. See the [flipper example](https://github.com/use-ink/ink-examples/blob/main/flipper/lib.rs). ## Integration Tests For integration tests, the test is annotated with our `#[ink::test]` attribute instead of `#[test]`. This attribute denotes that the test is then executed in a simulated, mocked blockchain environment. Here functions are available to influence how the test environment is configured (e.g. setting a specified balance of an account to simulate how a contract would behave when interacting with it). If you annotate a test with the `#[ink::test]` attribute it will be executed in a simulated environment, similar to as it would be run on-chain. You then have fine-grained control over how a contract is called; for example you can influence the block advancement, the value transferred to it, by which account it is called, which storage it is run with, etc.. See the [`examples/erc20`](https://github.com/use-ink/ink-examples/blob/main/erc20/lib.rs) contract on how to utilize those or [the documentation](https://use-ink.github.io/ink/ink/attr.test.html) for details. At the moment there are some known limitations to our off-chain environment, and we are working on making it behave as close to the real chain environment as possible. :::note One limitation of the off-chain testing framework is that it currently only supports a `DefaultEnvironment`. See [here](../basics/environment.md) for an explanation of what an environment is. ::: ### Example ```rust #[cfg(test)] mod tests { // Conventional unit test that works with assertions. #[ink::test] fn test1() { // test code comes here as usual } // Conventional unit test that returns some Result. // The test code can make use of operator-`?`. #[ink::test] fn test2() -> Result<(), ink::env::Error> { // test code that returns a Rust Result type } } ``` ## How do you find out if a test requires the off-chain environment? If the test recursively uses or invokes methods that call a function defined in `self.env()` or `Self::env()`. An example is the following: ```rust let caller: AccountId = self.env().caller(); ``` ````