The Let's Move initiative is designed to empower developers by encouraging hands-on learning of the Move programming language, particularly within the Sui blockchain ecosystem. This guide walks you through Task 2: deploying two custom coin contracts — My Coin and Faucet Coin — onto the Sui mainnet. By mastering contract deployment, minting, and burning mechanisms, you'll gain practical experience with core Sui development workflows.
Whether you're building your first token or exploring asset management in Move, this step-by-step walkthrough ensures clarity, accuracy, and real-world applicability.
Understanding the Task Requirements
To complete this phase of the Let's Move challenge, participants must:
- Study foundational concepts related to
sui::coin - Deploy My Coin to the Sui mainnet
- Deploy Faucet Coin to the Sui mainnet
- Submit both contract package IDs
- Send a test amount of My Coin to the designated address:
0x7b8e0864967427679b4e129f79dc332a885c6087ec9e187b53451a9006ee15f2
This task emphasizes secure, standards-compliant token creation using Sui’s built-in coin module — a critical skill for any aspiring Web3 developer.
👉 Discover how to accelerate your blockchain development journey with powerful tools
Core Concepts: The sui::coin Module
At the heart of every custom token on Sui lies the sui::coin library. It provides essential structures for creating and managing fungible tokens with full control over minting and burning.
The Coin<T> Structure
struct Coin<phantom T> has key, store {
id: UID,
balance: Balance<T>
}This structure represents a user-owned token with:
- A unique
UID(object identifier) - A
balancefield storing the amount held
Because it has the key ability, Coin<T> can be retrieved from global storage using its object ID. The store ability allows it to be transferred between accounts.
The Balance<T> Type
struct Balance<phantom T> has store {
value: u64
}This internal type holds the actual numeric value of the coin supply. It is wrapped inside the Coin struct and managed via safe APIs.
Creating a Custom Currency with create_currency
To launch a new token, we use the create_currency function:
public fun create_currency<T: drop>(
witness: T,
decimals: u8,
symbol: vector<u8>,
name: vector<u8>,
description: vector<u8>,
icon_url: Option<Url>,
ctx: &mut TxContext
): (TreasuryCap<T>, CoinMetadata<T>)| Parameter | Purpose |
|---|---|
decimals | Number of decimal places (e.g., 2 = divisible to 0.01) |
symbol | Ticker symbol (e.g., "MC") |
name | Full name of the token |
description | Human-readable description |
icon_url | Optional URL for token logo |
Return Values
TreasuryCap<T>: Grants authority to mint and burn tokens. Must be securely stored.CoinMetadata<T>: Stores public metadata about the token.
🔐 The TreasuryCap follows the one-time witness pattern, ensuring only one instance exists per token type — preventing unauthorized duplication.
Building Your First Coin: My Coin
Below is a complete implementation of a deployable coin module using Move:
// File: my_coin.move
module new_coin::my_coin {
use std::option;
use sui::coin::{Self, Coin, TreasuryCap};
use sui::transfer;
use sui::tx_context::{Self, TxContext};
struct MY_COIN has drop {}
fun init(witness: MY_COIN, ctx: &mut TxContext) {
let (treasury_cap, metadata) = coin::create_currency<MY_COIN>(
witness,
2,
b"MY_COIN",
b"MC",
b"Learning for letsmove, powered by alva-lin",
option::none(),
ctx
);
transfer::public_freeze_object(metadata);
transfer::public_transfer(treasury_cap, tx_context::sender(ctx));
}
public fun mint(
treasury_cap: &mut TreasuryCap<MY_COIN>,
amount: u64,
recipient: address,
ctx: &mut TxContext
) {
coin::mint_and_transfer(treasury_cap, amount, recipient, ctx);
}
public fun burn(
treasury_cap: &mut TreasuryCap<MY_COIN>,
coin: Coin<MY_COIN>
) {
coin::burn(treasury_cap, coin);
}
#[test_only]
public fun test_init(ctx: &mut TxContext) {
init(MY_COIN {}, ctx);
}
}Key Design Decisions
- Witness Pattern: The empty struct
MY_COINensures type uniqueness. - Metadata Freezing: After creation, metadata is frozen to prevent future changes — aligning with immutability best practices.
- TreasuryCap Ownership: Sent to the deployer, giving them exclusive mint/burn rights.
Testing Minting and Burning Logic
A robust test suite simulates real-world usage:
#[test_only]
module new_coin::my_coin_tests {
use new_coin::my_coin::{Self, MY_COIN};
use sui::coin::{Coin, TreasuryCap};
use sui::test_scenario::{Self, next_tx, ctx};
#[test]
fun mint_burn() {
let addr1 = @0xA;
let scenario = test_scenario::begin(addr1);
// Initialize module
my_coin::test_init(ctx(&mut scenario));
// Mint 100 units (value = 100 * 10^2 = 10000)
next_tx(&mut scenario, addr1);
let treasurycap = test_scenario::take_from_sender<TreasuryCap<MY_COIN>>(&scenario);
my_coin::mint(&mut treasurycap, 10000, addr1, test_scenario::ctx(&mut scenario));
test_scenario::return_to_address<TreasuryCap<MY_COIN>>(addr1, treasurycap);
// Burn the coin
next_tx(&mut scenario, addr1);
let coin = test_scenario::take_from_sender<Coin<MY_COIN>>(&scenario);
let treasurycap = test_scenario::take_from_sender<TreasuryCap<MY_COIN>>(&scenario);
my_coin::burn(&mut treasurycap, coin);
test_scenario::return_to_address<TreasuryCap<MY_COIN>>(addr1, treasurycap);
test_scenario::end(scenario);
}
}This test verifies that:
- Initialization succeeds
- Tokens can be minted correctly (accounting for decimal precision)
- Coins are properly destroyed upon burn
Deploying to Sui Mainnet
Before deployment, ensure your CLI is configured for production:
sui client switch --env mainnetThen publish your package:
sui client publish --gas-budget 30000Upon successful deployment, note these outputs:
- Package ID: Found under
Object Changes > Published Objects - TreasuryCap ID: In
Created Objects, type0x2::coin::TreasuryCap<...> - CoinMetadata: Also created and automatically frozen
Export them for later use:
export PACKAGE_ID=0xf9623587d620d26024868578a3539642993e2da44598c3fcaa1f384f5327f6a5
export TREASURYCAP_ID=0x97233be4acd1688c93f2c60ce81350b993a810c6b4851e8cdf214402759fad88👉 Start experimenting with smart contracts using industry-leading platforms
Minting and Burning Tokens
Minting Process
Remember: final amount = input × 10⁻ᵈᵉᶜᶦᵐᵃˡˢ
With decimals = 2, to mint 100 coins → pass 10000.
export RECIPIENT_ADDRESS=<YOUR_WALLET_ADDRESS>
sui client call --gas-budget 3000 \
--package $PACKAGE_ID \
--module my_coin \
--function mint \
--args $TREASURYCAP_ID "10000" $RECIPIENT_ADDRESSAfter execution, locate the newly created Coin object in:
Object Changes > Created Objects > Type: 0x2::coin::Coin<...>Record its Object ID:
export COIN_ID=0x3460204ae7f9385df79dc963a17d8b11eb0fa7a699f7196fac80405e1777d36cBurning Tokens
Use the same TreasuryCap to destroy tokens:
sui client call --gas-budget 7500000 \
--package $PACKAGE_ID \
--module my_coin \
--function burn \
--args $TREASURYCAP_ID $COIN_ID📌 Once burned, the coin disappears from wallet balances and cannot be queried directly by ID. Its history remains traceable via transaction logs on explorers like SuiScan.
Frequently Asked Questions (FAQ)
Q: What is the purpose of the one-time witness pattern?
A: It ensures that only one instance of a specific token type can exist. This prevents accidental or malicious re-creation of currency definitions, maintaining integrity across the network.
Q: Why should I freeze CoinMetadata after creation?
A: Freezing guarantees immutability. Once deployed, details like name, symbol, or decimals cannot change — which builds trust among users and dApps interacting with your token.
Q: Can anyone mint tokens if they get hold of the TreasuryCap?
A: Yes. The holder of the TreasuryCap has full minting and burning authority. Always keep it secure — consider multi-sig wallets or hardware signing solutions for production environments.
Q: How do I verify my contract was successfully deployed?
A: Use a block explorer like SuiScan. Enter your Package ID to view all associated objects, functions, and transaction history linked to your deployment.
Q: Is it possible to upgrade a published Move package?
A: On Sui, packages can be made upgradeable during initial publication. However, once marked as immutable, no further changes are allowed — emphasizing security through transparency.
👉 Access advanced development resources and tools to streamline your workflow
Final Thoughts
Completing this task equips you with foundational skills in Move-based token engineering. You've learned how to:
- Design secure, standards-compliant tokens
- Deploy contracts on Sui mainnet
- Manage minting and burning operations safely
These competencies open doors to deeper engagement with decentralized finance (DeFi), NFT systems, and custom asset logic on Sui.
By focusing on clean architecture and safe practices — such as freezing metadata and guarding TreasuryCaps — you're not just completing a challenge; you're building habits that define professional blockchain development.
Core Keywords: Move language, Sui blockchain, coin contract deployment, fungible tokens, TreasuryCap, mint and burn, smart contract testing, mainnet deployment