Skip to main content

Assembling a contract

Sol2Ink has everything it needs; now, it needs to mix it. Here we will clarify what may not be obvious.


Each contract and library will contain the following error definition:

#[derive(Debug, Encode, Decode, PartialEq)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum Error {

This error will be used as the error type when returning results from the contract functions. In the future versions, we plan on creating an Error enum variant for each error a contract can produce. So instead of Err(Error::Custom(String::from("No allowance"))) Sol2Ink will produce Err(Error::NoAllowance).


Openbrush simplifies the work with storage and allows the upgradeability of the storage; that is why we use the following approach. This approach will also streamline our future development when our contract uses multiple traits, etc. For now, we define a storage key inside the contract, the state variables in a struct which will use this storage key, and this struct itself is the member of the contract storage. The whole storage will look something like this:

pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data);

#[derive(Default, Debug)]
pub struct Data {
pub value: u128,

#[derive(Default, SpreadAllocate, Storage)]
pub struct Contract {
data: Data,

Accessing the value state variables inside the contract looks like

Sol2Ink will generate the functions of the contract inside the impl section. Note the following:

  • the constructor will be called new and will have the #[ink(constructor)] attribute
  • the constructor will be generated even if it is empty or does not exist in the original contract
  • public/external messages will have the #[ink(message)] attribute
  • private/internal functions will be prefixed with _