Mint and Burn FunctionsExtending Token Contract
6/11 tutorials
55%

Implementing Mint and Burn Functions

Let's focus on implementing the mint and burn functions to manage the token supply.

  1. Mint Function:
    • The mint function mints new tokens and adds them to the specified account's balance.
    • It checks if the value is zero and panics if it is.
    • The mint function also calculates the new total supply and the new balance for the account.
    • If the new token balance for the account is valid, the mint function updates the balances and total supply.
    • Finally, it emits a Minted event.
  2. Burn Function:
    • The burn function burns tokens from the specified account's balance.
    • It checks if the value is zero and panics if it is.
    • The burn function also calculates the new total supply and the new balance for the account.
    • If the new token for the account balance is valid, the burn function updates the balances and total supply.
    • If the new balance is zero, it removes the account from the balances.
    • Finally, it emits a Burned event.
  3. Admin management
    • The change_admin function provides the current administrator with the ability to transfer their administrative privileges to another address. This ensures that control over the contract can be handed over smoothly when required.
    • Before making any changes, the function first verifies that the caller is indeed the current administrator by using the only_admin function. If the caller is authorized, the ADMIN variable is then updated to reflect the new administrator's address.
    • The admin_address function allows users to query the current administrator's address. By calling this method, any user can retrieve the ActorId of the admin stored in the contract.

Congratulations on completing the lesson! You've learned how to write programs using the Sails framework.

Next Steps:

#![no_std]
use sails_rs::prelude::*;
use vft::{Service as BaseVftService, Storage};

#[derive(Encode, Decode, TypeInfo)]
pub enum Events {
    Minted { to: ActorId, value: U256 },
    Burned { from: ActorId, value: U256 },
}

#[derive(Clone)]
pub struct VftService {
    vft: BaseVftService,
}

impl VftService {
    pub fn init(name: String, symbol: String, decimals: u8) -> Self {
        VftService {
            vft: <BaseVftService>::seed(name, symbol, decimals),
        }
    }
}
#[service(extends = BaseVftService, events = Events)]
impl VftService {
    pub fn new() -> Self {
        Self {
            vft: BaseVftService::new(),
        }
    }
    pub fn mint(&mut self, to: ActorId, value: U256) {
        let balances = Storage::balances();
        let total_supply = Storage::total_supply();

        let new_total_supply = total_supply
            .checked_add(value)
            .unwrap_or_else(|| panic!("Numeric overflow occurred"));

        balances
            .entry(to)
            .and_modify(|a| *a = *a + value)
            .or_insert(value);

        *total_supply = new_total_supply;
        let _ = self.notify_on(Events::Minted { to, value });
    }

    pub fn burn(&mut self, from: ActorId, value: U256) {
        let balances = Storage::balances();
        let total_supply = Storage::total_supply();

        let new_total_supply = total_supply
            .checked_sub(value)
            .unwrap_or_else(|| panic!("Numeric unferflow occurred"));

        let balance = balances.get(&from).expect("Account has no balance");

        let new_balance = balance
            .checked_sub(value)
            .unwrap_or_else(|| panic!("Insufficient balance"));

        if !new_balance.is_zero() {
            balances.insert(from, new_balance);
        } else {
            balances.remove(&from);
        }

        *total_supply = new_total_supply;

        let _ = self.notify_on(Events::Burned { from, value });
    }
}

impl AsRef<BaseVftService> for VftService {
    fn as_ref(&self) -> &BaseVftService {
        &self.vft
    }
}

pub struct MyProgram;

#[program]
impl MyProgram {
    pub fn new(name: String, symbol: String, decimals: u8) -> Self {
        VftService::init(name, symbol, decimals);
        Self
    }

    pub fn vft(&self) -> VftService {
        VftService::new()
    }
}