MNet
  • đŸ’ĢWelcome
  • 🌅Our Vision
  • MNet
    • â„šī¸About
    • đŸ’ģTechnology
      • Security
      • Technical Stack
    • 💠Token Economy
      • Continuum - NUUM
      • Pioneer - NEER
    • 🌠Core Components
      • Bit Country
      • Bit Avatar
      • SP Protocol
      • ESE Framework SDK
      • Blockchain Protocol
    • âš’ī¸Developers
      • EVM
        • Configure MetaMask
        • Getting a free Alpha Testnet Faucet Token
        • Deploy Smart Contract on MEVM
      • WASM
        • Set up !ink environment.
        • Create a Flipper Contract
        • Deploy Wasm with Polkadot.js
    • đŸ›Ŗī¸Roadmap
    • đŸĸGovernance
    • 📑Glossary
    • 📂Open Source
    • 🆕Development Updates
    • 🔐Security Audit Report
    • Change Logs
    • Official Links
    • Disclaimer
  • Testnet
    • Testnet $NUUM
    • Run a testnet node
    • Get a Polkadot Wallet
Powered by GitBook
On this page
  • 1. Create from scratch
  • 2. Use cargo-contract to generate a flipper contract as example
  • Compile Your Contract
  1. MNet
  2. Developers
  3. WASM

Create a Flipper Contract

PreviousSet up !ink environment.NextDeploy Wasm with Polkadot.js

Last updated 1 year ago

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

Create new folder, run cargo init flipperthen 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

flipper
  └─ lib.rs                <-- Contract Source Code
  └─ Cargo.toml            <-- Rust Dependencies and ink! Configuration
  └─ .gitignore

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:

target
  └─ ink
    └─ flipper.contract
    └─ flipper.wasm
    └─ flipper.json

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

{
  "source": {...},
  "contract": {...},
  "spec": {
    "constructors": [...],
    "docs": [],
    "events": [],
    "messages": [...],
  },
  "storage": {...},
  "types": [...],
  "version": "4"
}

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.

âš’ī¸
code example.