[][src]Attribute Macro ink_lang::contract

#[contract]

Entry point for writing ink! smart contracts.

If you are a beginner trying to learn ink! we recommend you to check out our extensive ink! workshop.

Note: In all below examples we will be using ink_lang crate aliased as just ink. You can do this yourself by adding the following line to your code: use ink_lang as ink;

Description

The macro does analysis on the provided smart contract code and generates proper code.

ink! smart contracts can compile in several different modes. There are two main compilation models using either

We generally use the on-chain mode for actual smart contract deployment whereas we use the off-chain mode for smart contract testing using the off-chain environment provided by the ink_env crate.

Usage

Header Arguments

The #[ink::contract] macro can be provided with some additional comma-separated header arguments:

Anaylsis

The #[ink::contract] macro fully analyses its input smart contract against invalid arguments and structure.

Some example rules include but are not limited to:

Interacting with the Contract Executor

The ink_env crate provides facitilies 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:

let caller = ink_env::caller::<ink_env::DefaultEnvironment>();

However, ink! provides a much simpler way to interact with the contract executor via its environment accessor. An example below:

#[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)].

#[ink::contract]
mod erc20 {
    /// Defines an event that is emitted every time value is transferred.
    #[ink(event)]
    pub struct Transferred {
        from: Option<AccountId>,
        to: Option<AccountId>,
        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.

use ink_lang as ink;

#[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
        }
    }
}