Skip to main content
Version: 4.x

Storing Values

Here is how you store simple values in storage:

#[ink(storage)]
pub struct MyContract {
// Store a bool
my_bool: bool,
// Store some number
my_number: u32,
}
/* --snip-- */

Supported Types

Substrate contracts may store types that are encodable and decodable with Parity 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 substrate specific types like AccountId, Balance, and Hash to smart contracts as if they were primitive types.

String, Vector and More

The 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:

#[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<u32>,
}
/* --snip-- */
}

Mapping

ink! also provides a Mapping storage type. You can read more about it here.

Substrate Types

Here is an example of how you would store substrate types AccountId, Balance and Hash:

#[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 section.

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.

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<u8>,
}

#[ink(storage)]
pub struct MyContract {
// Store Auctions in a vec
auctions: Vec<Auction>,
}
}

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 for more details.

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