Create a Flipper Contract

There are two ways you can create a flipper contract.

  1. Create a contract from scratch

  2. Use cargo-contract to generate a flipper contract as example

Let's get started!

1. Create from scratch

You can refer to this Flipper contract code example. arrow-up-right

Create new folder, run cargo init flipper arrow-up-rightthen copy this code to lib.rs

#![cfg_attr(not(feature = "std"), no_std)]

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

        /// Creates a new flipper smart contract initialized to `false`.
        #[ink(constructor)]
        pub fn new_default() -> Self {
            Self::new(Default::default())
        }

        /// Flips the current value of the Flipper's boolean.
        #[ink(message)]
        pub fn flip(&mut self) {
            self.value = !self.value;
        }

        /// Returns the current value of the Flipper's boolean.
        #[ink(message)]
        pub fn get(&self) -> bool {
            self.value
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[ink::test]
        fn default_works() {
            let flipper = Flipper::new_default();
            assert!(!flipper.get());
        }

        #[ink::test]
        fn it_works() {
            let mut flipper = Flipper::new(false);
            assert!(!flipper.get());
            flipper.flip();
            assert!(flipper.get());
        }
    }

    #[cfg(all(test, feature = "e2e-tests"))]
    mod e2e_tests {
        use super::*;
        use ink_e2e::build_message;

        type E2EResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;

        #[ink_e2e::test]
        async fn it_works(mut client: ink_e2e::Client<C, E>) -> E2EResult<()> {
            // given
            let constructor = FlipperRef::new(false);
            let contract_acc_id = client
                .instantiate("flipper", &ink_e2e::alice(), constructor, 0, None)
                .await
                .expect("instantiate failed")
                .account_id;

            let get = build_message::<FlipperRef>(contract_acc_id.clone())
                .call(|flipper| flipper.get());
            let get_res = client.call_dry_run(&ink_e2e::bob(), &get, 0, None).await;
            assert!(matches!(get_res.return_value(), false));

            // when
            let flip = build_message::<FlipperRef>(contract_acc_id.clone())
                .call(|flipper| flipper.flip());
            let _flip_res = client
                .call(&ink_e2e::bob(), flip, 0, None)
                .await
                .expect("flip failed");

            // then
            let get = build_message::<FlipperRef>(contract_acc_id.clone())
                .call(|flipper| flipper.get());
            let get_res = client.call_dry_run(&ink_e2e::bob(), &get, 0, None).await;
            assert!(matches!(get_res.return_value(), true));

            Ok(())
        }

        #[ink_e2e::test]
        async fn default_works(mut client: ink_e2e::Client<C, E>) -> E2EResult<()> {
            // given
            let constructor = FlipperRef::new_default();

            // when
            let contract_acc_id = client
                .instantiate("flipper", &ink_e2e::bob(), constructor, 0, None)
                .await
                .expect("instantiate failed")
                .account_id;

            // then
            let get = build_message::<FlipperRef>(contract_acc_id.clone())
                .call(|flipper| flipper.get());
            let get_res = client.call_dry_run(&ink_e2e::bob(), &get, 0, None).await;
            assert!(matches!(get_res.return_value(), false));

            Ok(())
        }
    }
}

2. Use cargo-contract to generate a flipper contract as example

Create a new folder, then cd into your folder and run cargo contract new flipper

This command will create a new project folder named flipper

Compile Your Contract

Run the following command in your flipper directory to compile your smart contract:

cargo contract build

This command will build the following for your contract: a Wasm binary, a metadata file (which contains the contract's ABI) and a .contract file which bundles both. This .contract file can be used to deploy your contract to a chain. If all goes well, you should see a target folder which contains these files:

Let's take a look at the structure of the flipper.json:

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 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 emitted by the contract or any docs.

Last updated