How to Mint, Transfer, and Burn Tokens in Smart Contracts
This article helps understand the use of “tokens” in the world of blockchain. I’ll cover the the ability to mint, transfer, and burn tokens securely.
What what happens when you want to ensure that a user’s transfer includes a “burn” action, to remove tokens from one address before transferring them to another? Let’s break it down.
The Standard Flow of Token Minting and Transfer
Typically, the process goes as follows:
- User Deposits Fiat: A user deposits fiat currency (e.g. a government issued shitcoin such as GBP or USD) into a trusted off-chain gateway, such as a bank or exchange.
- Minting Tokens: After the fiat is confirmed, the smart contract mints a corresponding number of tokens on the blockchain.
- Token Transfer: The tokens are then transferred from the smart contract to the user’s address.
- Burning Tokens: In cases where tokens need to be burned (e.g., during a withdrawal or a swap), the smart contract should ensure that tokens are permanently removed from circulation.
The Problem: Ensuring the Burn Always Happens
You may ask, how do you make sure the “burn” function always runs and the “from” address doesn’t still hold tokens after a transfer, while the “to” address also receives the tokens? Without proper execution order, this can be a common issue.
The Solution: Atomic Transactions
The key to preventing this issue lies in ensuring the minting, burning, and transferring of tokens occur in a single atomic transaction. An atomic transaction ensures that all steps (minting, transferring, and burning) are executed together, or none at all. This prevents a situation where the sender still holds tokens after the transfer.
Here’s how to handle this in a Soroban smart contract, which uses the Rust programming language for contracts:
Soroban Smart Contract Example: Minting, Burning, and Transferring Tokens
Below is an example of how you can create a smart contract on Soroban that handles minting, burning, and transferring tokens safely. It ensures that the sender’s balance is decreased by burning tokens before they are transferred to the recipient.
#![no_std]
use soroban_sdk::{contract, contractimpl, contracttype, Address, Env, String};
#[derive(Clone)]
#[contracttype]
pub enum DataKey {
Admin,
Decimal,
Symbol,
Name,
Balance(Address),
}
#[contract]
pub struct TokenContract;
#[contractimpl]
impl TokenContract {
#[allow(clippy::too_many_arguments)]
pub fn initialize(env: &Env, admin: Address, decimal: u32, symbol: String, name: String) {
// Verify contract is not already initialized
if env.storage().instance().has(&DataKey::Admin) {
panic!("already initialized");
}
// Store contract data
env.storage().instance().set(&DataKey::Admin, &admin);
env.storage().instance().set(&DataKey::Decimal, &decimal);
env.storage().instance().set(&DataKey::Symbol, &symbol);
env.storage().instance().set(&DataKey::Name, &name);
}
pub fn mint(env: &Env, admin: Address, to: Address, amount: i128) {
// Verify admin
let stored_admin: Address = env.storage().instance().get(&DataKey::Admin).unwrap();
if admin != stored_admin {
panic!("not authorized");
}
admin.require_auth();
// Mint tokens to `to` address
let balance = Self::balance(env, to.clone());
env.storage()
.instance()
.set(&DataKey::Balance(to.clone()), &(balance + amount));
}
pub fn burn(env: &Env, admin: Address, from: Address, amount: i128) {
// Verify admin
let stored_admin: Address = env.storage().instance().get(&DataKey::Admin).unwrap();
if admin != stored_admin {
panic!("not authorized");
}
admin.require_auth();
// Update balance
let balance = Self::balance(env, from.clone());
if balance < amount {
panic!("insufficient balance to burn");
}
env.storage()
.instance()
.set(&DataKey::Balance(from.clone()), &(balance - amount));
}
pub fn balance(env: &Env, id: Address) -> i128 {
env.storage()
.instance()
.get(&DataKey::Balance(id.clone()))
.unwrap_or(0)
}
}
Breaking Down the Contract
Let’s go over each part of the contract to understand how it works.
- Mint Function:
- The
mint
function allows a new token balance to be added to the user’s address, simulating the minting process after fiat has been deposited.
- The
- Burn Function:
- The
burn
function removes tokens from an address. Theassert!
statement ensures that the address has enough tokens before burning. This function is crucial because it ensures the tokens are actually removed from circulation before they are transferred.
- The
- Transfer Function:
- The
transfer
function first burns the tokens from the sender’s address before transferring them to the recipient. This guarantees that the tokens are effectively “spent” before being moved. It then updates the balances for both the sender and the receiver.
- The
- Atomicity:
- The operations are executed together, ensuring that both the burning and transferring actions occur atomically. If something goes wrong (e.g., insufficient balance), the transaction will revert and no tokens will be transferred.
Conclusion
By ensuring that the burning happens before the transfer, we prevent any scenario where tokens are held by both the sender and the receiver after the transaction. This approach is secure and prevents any unintended token duplication.
With Soroban smart contracts, you can manage token transfers and burns efficiently. By structuring your contract this way, you ensure that each transaction is atomic and that your token economy remains clean and predictable.
If you’re building a decentralized application (DApp) that involves tokenized assets, this is a simple but effective way to handle token minting, transfers, and burning. By doing so, you can confidently build scalable and secure systems with predictable behavior on the blockchain.
Here’s a summary of XLM to tokens in 5 bullet points:
- XLM (Stellar Lumens): XLM is the native cryptocurrency of the Stellar network, designed for fast, low-cost cross-border transactions.
- Tokenization: XLM can be used as a base currency to issue and transfer various assets or tokens on the Stellar network, including stablecoins, fiat-backed tokens, and other assets.
- Issuance of Tokens: Issuers can create tokens by defining them with specific characteristics, such as a name, supply, and additional properties, on the Stellar network.
- Conversion Mechanism: Users can convert XLM into different tokens or vice versa using Stellar’s decentralized exchange (DEX) and through token markets.
- Utility & Interoperability: XLM and its tokens can be utilized for cross-border payments, remittances, and decentralized finance (DeFi) applications with low fees and fast transaction times.