Donation ink! smart contract
Tags: rust, ink, substrate, polkadot
Published: 2023-03-30 06:38:40

Donation smart contract is useful when you are learning substrate based ink! smart contract. This contract is based on `ink! v4.0.0` and use [Vec](https://paritytech.github.io/ink/ink_prelude/vec/struct.Vec.html) and [Mapping](https://paritytech.github.io/ink/ink_storage/struct.Mapping.html) data structure. Vec(i.e contiguous growable array type) is used to store and return Donation list and Mapping (i.e key-value pairs directly into contract storage) which is used to store Donation `(i.e value)` with respect to donation_id `(i.e key)`. There are also other data structure like AccountId `(i.e 32-byte type)`, u128 (to store balance) and i32 (to store donation id).

---
Through this contract you can:

1. Initialize beneficiary account while contract deployment.
2. Can change beneficiary at any time.
3. Donate the beneficiary address.
4. Can view donation list.

Before start writing `ink! smart contract`, you need to setup `rust`, `cargo` and `cargo contract` (i.e Setup and deployment tool for developing Wasm based smart contracts via ink!). You can setup rust and cargo from [here](https://doc.rust-lang.org/cargo/getting-started/installation.html) and can install latest cargo contract from [here](https://github.com/paritytech/ink#usage).

After successfully setup all requirement, you can create ink! smart contract using following command.

```
cargo contract new <contract_name>
contract_name must not start with alphabetic character and contains `alphanumeric characters and underscores`
```

Successfully create contract can be build with following command
```
cargo contract build
if you wan't to build in release, then add --release flag
```

Replace, your `#[ink(storage)]` Macros with the below code snippet. 
`owner`: Contract Address Owner
`beneficiary`: Beneficiary account where you can donate balance.
`donations`: mapping to storage donation data.
`donation_id`: id for donation
```
    #[ink(storage)]
    pub struct DonationContract {
        owner: AccountId,
        beneficiary: AccountId,
        donations: Mapping<DonationId, Donation>,
        donation_id: i32,
    }
```

`Donation` is Custom Data Structures, we have to define separately above the `#[ink(storage)]` macro. Derive traits Decode and Encode provide a way to serialize and deserialize rust data type into complete binary format, you can learn more from [here](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/). This data structure defines two fields:
`account`: AccountId, user who donate.
`amount`: u128, user how much he donate.

```
    #[derive(scale::Decode, scale::Encode)]
    #[cfg_attr(
        feature = "std",
        derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout)
    )]
    pub struct Donation {
        account: AccountId,
        amount: u128,
    }
```
Since, `ink!v4.0.0` remove AccountId [default implementation](https://github.com/paritytech/ink/pull/1255), we can't use `Default` macro inside derive, So we have to define separately just below Donation struct.

```
    // Donation struct default implementations
    impl Default for Donation {
        fn default() -> Self {
            Self {
                account: zero_address(),
                amount: 0,
            }
        }
    }
```
We defined `zero_address()` function, separately, which you can define like this:

```
   /// Helper for referencing the zero address (`0x00`). Note that in practice this address should
    /// not be treated in any special way (such as a default placeholder) since it has a known
    /// private key.
    fn zero_address() -> AccountId {
        [0u8; 32].into()
    }
```

Every ink! contract has one or more constructor. Our constructor is defined below. You can include this code in your `#[ink(constructor)]` macro. If you want to learn more [click here](https://use.ink/macros-attributes/constructor).
`Self::env().caller()` gives owner of the contract. The owner will be whoever deploy the contract.
Return all the fields from `#[ink(storage)]` macro like:
1. owner
2. beneficiary which is provided while contract instantiation.
3. donations mapping we can define like `Mapping::default()`
4. donation_id can be initialize with 1 or `Default::default()`

```
        #[ink(constructor)]
        pub fn new(beneficiary: AccountId) -> Self {
            let owner = Self::env().caller();
            Self {
                owner,
                beneficiary,
                donations: Mapping::default(),
                donation_id: 1,
            }
        }

```
Normal user can view beneficiary address anytime. Only owner of the contract can change the beneficiary address. These are public function which can be represent by `#[ink(message)]` macro, then only you can view those api while interaction with frontend. Contract must contains at least one or many `#[ink(message)]`, you can get more info from [here](https://use.ink/macros-attributes/message)

```
        #[ink(message)]
        pub fn get_beneficiary(&self) -> Option<AccountId> {
            Some(self.beneficiary)
        }

        #[ink(message)]
        pub fn change_beneficiary(&mut self, new_beneficiary: AccountId) {
            let caller = self.env().caller();
            assert!(
                self.owner == caller,
                "Only owner can change the beneficiary account"
            );
            self.beneficiary = new_beneficiary;
        }

```

`assert!()` macro check whether caller of the function is owner or not. If not owner then, he can't change the new beneficiary address. In order to update value we call `self` and mut so that beneficiary from storage can be updated easily, as you might be aware about rust.

Add another function which is also public below.

```
        #[ink(message, payable)]
        pub fn donation(&mut self) {
            // Account who is donating
            let caller = self.env().caller();
            let donation_id = self.next_donation_id();

            // Donation amount
            let donation_amount = self.env().transferred_value();
            let mut donated_so_far = self.donations.get(donation_id).unwrap_or_default();

            assert!(donation_amount > 0, "Cannot transfer 0 donation");

            // Total donation amount so far by caller
            donated_so_far.amount += donation_amount;
            donated_so_far.account = caller;

            // Insert total donation amount with respect to caller
            self.donations.insert(donation_id, &donated_so_far);

            // Send donation amount to the beneficiary account
            self.env()
                .transfer(self.beneficiary, donation_amount)
                .unwrap_or_default();
        }
```
This is function is `payable`, which means it allow receiving value. You can deep dive with this macro from [here](https://use.ink/macros-attributes/payable).
1. [caller](https://paritytech.github.io/ink/ink_env/fn.caller.html) who is calling this function while donating amount.
2. donation_id is local variable which store id from `next_donation_id()` function which is private function and  defined below.

```
        pub fn next_donation_id(&mut self) -> DonationId {
            let id = self.donation_id;
            self.donation_id += 1;
            id
        }
    }
```
3. `self.env().transferred_value()` returns the value for contract execution more info [here](https://paritytech.github.io/ink/ink_env/fn.transferred_value.html). 

 4. `donated_so_far` variable which storage donation so far by account.
5. If donation more than 0, then donation store in storage.

In this way wasm based ink! smart contract can be written. This is way basic contract for beginner level. You can find all the code in my git hub account. I haven't included here but you can find unit test of this contract as well.

**[GitHub link](https://github.com/ganesh1233456/PortfolioDapps/tree/main/donation_ink)**