From ebd47f39a45af549855138efd94665833c43887e Mon Sep 17 00:00:00 2001 From: Karry <51736839+Karry2019web@users.noreply.github.com> Date: Mon, 25 May 2026 23:05:37 +0800 Subject: [PATCH 1/2] docs(examples): add tokenfactory end-to-end walkthrough README --- examples/tokenfactory/README.md | 247 ++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 examples/tokenfactory/README.md diff --git a/examples/tokenfactory/README.md b/examples/tokenfactory/README.md new file mode 100644 index 0000000..2a4973b --- /dev/null +++ b/examples/tokenfactory/README.md @@ -0,0 +1,247 @@ +# Token Factory End-to-End Example + +This example demonstrates the complete lifecycle of a **Token Factory** denom on Safrochain — +from creation through minting, transfer, metadata update, and burn — all using `safrochaind` CLI commands. + +## Prerequisites + +- [Safrochain Node](https://github.com/Safrochain-Org/safrochain-node) built and installed (`make install`) +- `safrochaind` in your `$PATH` +- Two key pairs for testing: `creator` and `recipient` + +## Quick Start + +```bash +# Build safrochaind (from repo root) +make install + +# Start a fresh local node +safrochaind init test-node --chain-id safro-testnet-1 +safrochaind keys add creator --keyring-backend test +safrochaind keys add recipient --keyring-backend test +safrochaind genesis add-genesis-account $(safrochaind keys show creator -a --keyring-backend test) 1000000000000usaft +safrochaind genesis add-genesis-account $(safrochaind keys show recipient -a --keyring-backend test) 1000000000000usaft +safrochaind genesis gentx creator 700000000usaft --chain-id safro-testnet-1 --keyring-backend test +safrochaind genesis collect-gentxs +safrochaind start +``` + +Then run the example script: + +```bash +chmod +x examples/tokenfactory/run.sh +./examples/tokenfactory/run.sh +``` + +> **Note:** The denom creation fee is `10,000,000 usaft` (default). Make sure the creator has enough balance. + +## Step-by-Step Walkthrough + +### 1. Setup + +```bash +export CHAIN_ID="safro-testnet-1" +export KEYRING="--keyring-backend test" +export NODE="http://localhost:26657" +``` + +Prepare variables for the creator and recipient addresses: + +```bash +CREATOR=$(safrochaind keys show creator -a $KEYRING) +RECIPIENT=$(safrochaind keys show recipient -a $KEYRING) +``` + +Check balances to confirm both accounts are funded: + +```bash +safrochaind query bank balances $CREATOR --node $NODE +safrochaind query bank balances $RECIPIENT --node $NODE +``` + +### 2. Create a Denom + +Create a new subdenom called `mytoken`: + +```bash +safrochaind tx tokenfactory create-denom $CREATOR mytoken --from $CREATOR $KEYRING --chain-id $CHAIN_ID --node $NODE --fees 5000usaft -y +``` + +The resulting denom will be `factory/{creator_address}/mytoken`. Query the creation fee first: + +```bash +safrochaind query tokenfactory params --node $NODE +``` + +List all denoms created by your address: + +```bash +safrochaind query tokenfactory denoms-from-creator $CREATOR --node $NODE +``` + +### 3. Set Denom Metadata + +Set the display metadata so wallets and explorers render it nicely: + +```bash +safrochaind tx tokenfactory modify-metadata $CREATOR '{ + "description": "My first token on Safrochain", + "denom_units": [ + {"denom": "factory/'"$CREATOR"'/mytoken", "exponent": 0, "aliases": ["umytoken"]}, + {"denom": "mytoken", "exponent": 6, "aliases": []} + ], + "base": "factory/'"$CREATOR"'/mytoken", + "display": "mytoken", + "name": "MyToken", + "symbol": "MYT" +}' --from $CREATOR $KEYRING --chain-id $CHAIN_ID --node $NODE --fees 5000usaft -y +``` + +Verify the metadata: + +```bash +safrochaind query bank denom-metadata --denom factory/$CREATOR/mytoken --node $NODE +``` + +### 4. Mint Tokens + +Mint 1000 tokens to the creator's own address: + +```bash +DENOM=factory/$CREATOR/mytoken +safrochaind tx tokenfactory mint $CREATOR 1000$DENOM $CREATOR --from $CREATOR $KEYRING --chain-id $CHAIN_ID --node $NODE --fees 5000usaft -y +``` + +Check the balance: + +```bash +safrochaind query bank balances $CREATOR --denom $DENOM --node $NODE +``` + +### 5. Mint to a Recipient + +Mint 500 tokens directly to the recipient address: + +```bash +safrochaind tx tokenfactory mint $CREATOR 500$DENOM $RECIPIENT --from $CREATOR $KEYRING --chain-id $CHAIN_ID --node $NODE --fees 5000usaft -y +``` + +Verify: + +```bash +safrochaind query bank balances $RECIPIENT --denom $DENOM --node $NODE +``` + +### 6. Transfer (plain `bank send`) + +The new denom behaves like any native bank coin: + +```bash +safrochaind tx bank send $CREATOR $RECIPIENT 200$DENOM --from $CREATOR $KEYRING --chain-id $CHAIN_ID --node $NODE --fees 5000usaft -y +``` + +Check recipient now has 700 (500 minted + 200 transferred): + +```bash +safrochaind query bank balances $RECIPIENT --denom $DENOM --node $NODE +``` + +### 7. Burn Tokens + +Burn 100 tokens from the creator's address: + +```bash +safrochaind tx tokenfactory burn $CREATOR 100$DENOM $CREATOR --from $CREATOR $KEYRING --chain-id $CHAIN_ID --node $NODE --fees 5000usaft -y +``` + +Check the creator balance decreased: + +```bash +safrochaind query bank balances $CREATOR --denom $DENOM --node $NODE +``` + +### 8. Change Admin + +Transfer admin control to the recipient. The admin can mint, burn, and force-transfer. + +```bash +safrochaind tx tokenfactory change-admin $CREATOR $DENOM $RECIPIENT --from $CREATOR $KEYRING --chain-id $CHAIN_ID --node $NODE --fees 5000usaft -y +``` + +Verify the new admin: + +```bash +safrochaind query tokenfactory denom-authority-metadata $DENOM --node $NODE +``` + +Now the recipient can mint on behalf of the denom: + +```bash +safrochaind tx tokenfactory mint $RECIPIENT 300$DENOM $RECIPIENT --from $RECIPIENT $KEYRING --chain-id $CHAIN_ID --node $NODE --fees 5000usaft -y +``` + +To **renounce admin** (irreversible), set the admin to a burn address: + +```bash +# Only do this if you are certain! +# safrochaind tx tokenfactory change-admin $RECIPIENT $DENOM addr_safro1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqp3q6qq # --from $RECIPIENT $KEYRING # --chain-id $CHAIN_ID # --node $NODE # --fees 5000usaft # -y +``` + +### 9. Query Options + +Query all parameters: + +```bash +safrochaind query tokenfactory params --node $NODE +``` + +Get denom authority metadata: + +```bash +safrochaind query tokenfactory denom-authority-metadata $DENOM --node $NODE +``` + +List denoms for a creator: + +```bash +safrochaind query tokenfactory denoms-from-creator $CREATOR --node $NODE +``` + +Query bank metadata: + +```bash +safrochaind query bank denom-metadata --denom $DENOM --node $NODE +``` + +Query total supply: + +```bash +safrochaind query bank total --denom $DENOM --node $NODE --count-total +``` + +### 10. Cleanup + +Stop the local node (`Ctrl+C`). To fully reset: + +```bash +pkill safrochaind 2>/dev/null || true +rm -rf ~/.safrochain +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| **Denom format** | `factory/{creator_addr}/{subdenom}` — globally unique by namespace | +| **Admin** | The account that created the denom (or a successor via `change-admin`) | +| **Mint authority** | Only the current admin can mint | +| **Burn authority** | Only the current admin can burn from any address | +| **Force transfer** | Admin can move tokens between any two addresses | +| **Renunciation** | Set admin to a burn address to make the denom permanently immutable | +| **Creation fee** | Configurable via `Params.DenomCreationFee` (default: 10,000,000 `usaft`) | + +## References + +- [Token Factory Module Source](../../x/tokenfactory/) +- [Cosmos SDK Bank Module](https://docs.cosmos.network/main/modules/bank/) +- [Safrochain Documentation](https://docs.safrochain.com) From 6a6d76f977e9b0d084eed7e983c760fa19c461c7 Mon Sep 17 00:00:00 2001 From: Karry <51736839+Karry2019web@users.noreply.github.com> Date: Mon, 25 May 2026 23:05:59 +0800 Subject: [PATCH 2/2] docs(examples): add tokenfactory automated demonstration script --- examples/tokenfactory/run.sh | 189 +++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 examples/tokenfactory/run.sh diff --git a/examples/tokenfactory/run.sh b/examples/tokenfactory/run.sh new file mode 100644 index 0000000..2971f8a --- /dev/null +++ b/examples/tokenfactory/run.sh @@ -0,0 +1,189 @@ +#!/usr/bin/env bash +# ------------------------------------------------------------------- +# examples/tokenfactory/run.sh +# +# End-to-end Token Factory lifecycle demonstration. +# Run this against a local safro-testnet-1 node that already has +# 'creator' and 'recipient' keys funded with usaft. +# +# Prerequisites: +# 1. safrochaind installed (make install from repo root) +# 2. Local node running: safrochaind start +# 3. Keys exist: +# safrochaind keys add creator --keyring-backend test +# safrochaind keys add recipient --keyring-backend test +# (or run the setup section below) +# +# Usage: +# chmod +x examples/tokenfactory/run.sh +# ./examples/tokenfactory/run.sh +# ------------------------------------------------------------------- +set -euo pipefail + +# --------------- Configuration ---------------- +CHAIN_ID="${CHAIN_ID:-safro-testnet-1}" +KEYRING="${KEYRING:---keyring-backend test}" +NODE="${NODE:-http://localhost:26657}" +FEES="${FEES:-5000usaft}" +GAS="${GAS:-auto}" +CREATOR_KEY="${CREATOR_KEY:-creator}" +RECIPIENT_KEY="${RECIPIENT_KEY:-recipient}" +SUB_DENOM="${SUB_DENOM:-mytoken}" +# ------------------------------------------------ + +C_RESET="\033[0m" +C_BOLD="\033[1m" +C_GREEN="\033[38;5;82m" +C_CYAN="\033[38;5;51m" +C_YELLOW="\033[38;5;221m" +C_RED="\033[38;5;196m" + +info() { printf "${C_CYAN}[INFO]${C_RESET} %s\n" "$*"; } +ok() { printf "${C_GREEN}[OK]${C_RESET} %s\n" "$*"; } +warn() { printf "${C_YELLOW}[WARN]${C_RESET} %s\n" "$*"; } +fail() { printf "${C_RED}[FAIL]${C_RESET} %s\n" "$*"; exit 1; } +step() { printf "\n${C_BOLD}[STEP %s]${C_RESET} %s\n" "$1" "$2"; } + +run_tx() { + safrochaind tx "$@" \ + --chain-id "$CHAIN_ID" \ + --node "$NODE" \ + --fees "$FEES" \ + --gas "$GAS" \ + $KEYRING \ + -y 2>&1 +} + +# ---- 0. Setup ---- +step "0" "Resolve addresses" + +CREATOR=$(safrochaind keys show "$CREATOR_KEY" -a $KEYRING 2>/dev/null) || fail "Key '$CREATOR_KEY' not found. Create it with: safrochaind keys add $CREATOR_KEY $KEYRING" +RECIPIENT=$(safrochaind keys show "$RECIPIENT_KEY" -a $KEYRING 2>/dev/null) || fail "Key '$RECIPIENT_KEY' not found. Create it with: safrochaind keys add $RECIPIENT_KEY $KEYRING" + +info "Creator: $CREATOR" +info "Recipient: $RECIPIENT" + +DENOM="factory/${CREATOR}/${SUB_DENOM}" + +# ---- 1. Check Balances ---- +step "1" "Check initial balances" + +safrochaind query bank balances "$CREATOR" --node "$NODE" --denom usaft 2>/dev/null +safrochaind query bank balances "$RECIPIENT" --node "$NODE" --denom usaft 2>/dev/null + +# ---- 2. Create Denom ---- +step "2" "Create denom: $DENOM" + +run_tx tokenfactory create-denom "$CREATOR" "$SUB_DENOM" --from "$CREATOR" +info "Denom created: $DENOM" + +# Verify creation +safrochaind query tokenfactory denoms-from-creator "$CREATOR" --node "$NODE" +ok "Denom created successfully" + +# ---- 3. Set Denom Metadata ---- +step "3" "Set denom metadata" + +METADATA=$(cat </dev/null +ok "Denom metadata set" + +# ---- 4. Mint Tokens to Creator ---- +step "4" "Mint 1000 $SUB_DENOM to creator" + +run_tx tokenfactory mint "$CREATOR" "1000$DENOM" "$CREATOR" --from "$CREATOR" + +BALANCE=$(safrochaind query bank balances "$CREATOR" --denom "$DENOM" --node "$NODE" -o json 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('amount','?'))" 2>/dev/null || echo "?") +info "Creator balance: $BALANCE $DENOM" + +# ---- 5. Mint Tokens to Recipient ---- +step "5" "Mint 500 $SUB_DENOM directly to recipient" + +run_tx tokenfactory mint "$CREATOR" "500$DENOM" "$RECIPIENT" --from "$CREATOR" + +RECIP_BAL=$(safrochaind query bank balances "$RECIPIENT" --denom "$DENOM" --node "$NODE" -o json 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('amount','?'))" 2>/dev/null || echo "?") +info "Recipient balance: $RECIP_BAL $DENOM" + +# ---- 6. Bank Send (plain transfer) ---- +step "6" "Transfer 200 $SUB_DENOM from creator to recipient via bank send" + +run_tx bank send "$CREATOR" "$RECIPIENT" "200$DENOM" --from "$CREATOR" + +RECIP_BAL2=$(safrochaind query bank balances "$RECIPIENT" --denom "$DENOM" --node "$NODE" -o json 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('amount','?'))" 2>/dev/null || echo "?") +info "Recipient balance after transfer: $RECIP_BAL2 $DENOM" + +# ---- 7. Burn Tokens ---- +step "7" "Burn 100 $SUB_DENOM from creator" + +run_tx tokenfactory burn "$CREATOR" "100$DENOM" "$CREATOR" --from "$CREATOR" + +BALANCE2=$(safrochaind query bank balances "$CREATOR" --denom "$DENOM" --node "$NODE" -o json 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('amount','?'))" 2>/dev/null || echo "?") +info "Creator balance after burn: $BALANCE2 $DENOM" + +# ---- 8. Force Transfer (admin power) ---- +step "8" "Force-transfer 50 $SUB_DENOM from recipient back to creator" + +run_tx tokenfactory force-transfer "$CREATOR" "50$DENOM" "$RECIPIENT" "$CREATOR" --from "$CREATOR" + +RECIP_BAL3=$(safrochaind query bank balances "$RECIPIENT" --denom "$DENOM" --node "$NODE" -o json 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('amount','?'))" 2>/dev/null || echo "?") +info "Recipient after force-transfer: $RECIP_BAL3 $DENOM" + +# ---- 9. Change Admin ---- +step "9" "Change admin from creator to recipient" + +run_tx tokenfactory change-admin "$CREATOR" "$DENOM" "$RECIPIENT" --from "$CREATOR" + +# Verify new admin +safrochaind query tokenfactory denom-authority-metadata "$DENOM" --node "$NODE" +ok "Admin changed to $RECIPIENT" + +# Recipient can now mint (as the new admin) +step "9b" "Recipient (new admin) mints 200 more $SUB_DENOM" + +run_tx tokenfactory mint "$RECIPIENT" "200$DENOM" "$RECIPIENT" --from "$RECIPIENT" + +RECIP_BAL4=$(safrochaind query bank balances "$RECIPIENT" --denom "$DENOM" --node "$NODE" -o json 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('amount','?'))" 2>/dev/null || echo "?") +info "Recipient final balance: $RECIP_BAL4 $DENOM" + +# ---- 10. Summary ---- +step "10" "Summary" + +echo "" +echo " Token Factory demonstration complete! " +echo " " +echo " Denom: $DENOM" +echo " Creator: $CREATOR" +echo " Recipient: $RECIPIENT" +echo " " +echo " Commands demonstrated: " +echo " ✅ create-denom Create a new denom " +echo " ✅ modify-metadata Set display metadata " +echo " ✅ mint Mint tokens to any address " +echo " ✅ bank send Standard Cosmos transfer " +echo " ✅ burn Burn tokens from any address " +echo " ✅ force-transfer Admin-powered transfer " +echo " ✅ change-admin Transfer admin authority " +echo " " +echo " To query at any point: " +echo " safrochaind query bank balances " +echo " safrochaind query tokenfactory params " +echo " safrochaind query tokenfactory denom-authority-metadata " +echo " safrochaind query tokenfactory denoms-from-creator " +echo " "