Creating APL Tokens on Arch Network
Complete guide to creating and managing fungible tokens using the APL Token Program
This guide shows you how to create and manage fungible tokens on Arch Network using the built-in APL (Arch Program Library) Token Program. APL tokens are based on Solana's SPL token standard and provide a robust foundation for creating and managing tokens on Arch Network.
What You'll Learn
By the end of this guide, you'll understand how to:
- Create token mints using the Arch CLI
- Initialize token accounts for holding tokens
- Mint tokens to accounts
- Transfer tokens between accounts
- Approve delegations for spending tokens
- Burn tokens and manage token lifecycle
- Use advanced features like multisig, freezing, and batch operations
Overview
:::note All arch-cli addresses, public keys, transaction IDs, and block hashes are base58 (32 bytes for IDs/pubkeys). :::
The APL Token Program is Arch Network's native token standard, providing:
- SPL Token Compatibility: Based on Solana's proven token standard
- Bitcoin Integration: All operations are recorded on Bitcoin
- Comprehensive Features: Minting, transferring, burning, delegation, freezing
- Multisig Support: Multiple signature authorities for enhanced security
- CLI Integration: Full command-line interface for token management
Prerequisites
Before starting, ensure you have:
- Rust 1.84.1+ and Cargo installed (Install Rust)
- Arch Network CLI - Download Latest
- Docker - Required for local development
- Running development environment (see Quick Start Guide)
APL Token Program ID
The APL Token Program has a fixed program ID:
AplToken111111111111111111111111
Quick Start: Create Your First Token
Step 1: Start Local Environment
# Start local development environment
arch-cli orchestrate start
# Verify services are running
arch-cli orchestrate validator-status
arch-cli get-block-height
Step 2: Create Configuration Profile
# Create a profile for local development
arch-cli config create-profile local \
--bitcoin-node-endpoint http://127.0.0.1:18443 \
--bitcoin-node-username bitcoin \
--bitcoin-node-password bitcoinpass \
--bitcoin-network regtest \
--arch-node-url http://localhost:9002 \
--titan-url http://127.0.0.1:3030
# Set as default profile
arch-cli config set-default-profile local
Step 3: Generate Demo Keys
# Create directory for demo keys
mkdir -p ~/DEMO_KEYS
# Generate keys for different roles
openssl rand -out ~/DEMO_KEYS/payer.key 32
openssl rand -out ~/DEMO_KEYS/mint_authority.key 32
openssl rand -out ~/DEMO_KEYS/mint.key 32
# Fund the payer account
arch-cli account airdrop --keypair-path ~/DEMO_KEYS/payer.key
Step 4: Create Token Mint
# Create a new token mint with 6 decimals (SPL-style)
# Provide the mint authority and payer; optionally provide a mint keypair
arch-cli token create-mint \
--decimals 6 \
--mint-authority ~/DEMO_KEYS/mint_authority.key \
--mint-keypair-path ~/DEMO_KEYS/mint.key \
--keypair-path ~/DEMO_KEYS/payer.key
# Save the mint address (disable colors to parse reliably)
export MINT=$(NO_COLOR=1 arch-cli token show-mint ~/DEMO_KEYS/mint.key | awk -F': ' '/^Address:/{print $2}')
echo "Mint address: $MINT"
Step 5: Create Token Account
# Generate a keypair for the token account owner
openssl rand -out ~/DEMO_KEYS/token_account_owner.key 32
# Create a token account for the owner
arch-cli token create-account \
--mint "$MINT" \
--owner ~/DEMO_KEYS/token_account_owner.key \
--keypair-path ~/DEMO_KEYS/payer.key
# Save the token account address from the command output
export TOKEN_ACCOUNT=$(NO_COLOR=1 arch-cli token create-account \
--mint "$MINT" \
--owner ~/DEMO_KEYS/token_account_owner.key \
--keypair-path ~/DEMO_KEYS/payer.key \
| awk -F': ' '/^Account Address:/{print $2; exit}')
echo "Token account: $TOKEN_ACCOUNT"
Step 6: Mint Tokens
# Mint 1,000 tokens to the token account (with 6 decimals)
arch-cli token mint "$MINT" 1000000000 \
--account-address "$TOKEN_ACCOUNT" \
--authority ~/DEMO_KEYS/mint_authority.key \
--auto-create-ata \
--keypair-path ~/DEMO_KEYS/payer.key
# Check the token account balance
arch-cli token balance "$TOKEN_ACCOUNT"
Advanced Token Operations
Transfer Tokens
# Create a second token account for transfers
openssl rand -out ~/DEMO_KEYS/recipient.key 32
arch-cli token create-account \
--mint "$MINT" \
--owner ~/DEMO_KEYS/recipient.key \
--keypair-path ~/DEMO_KEYS/payer.key
export RECIPIENT_ACCOUNT=$(NO_COLOR=1 arch-cli token create-account \
--mint "$MINT" \
--owner ~/DEMO_KEYS/recipient.key \
--keypair-path ~/DEMO_KEYS/payer.key \
| awk -F': ' '/^Account Address:/{print $2; exit}')
# Transfer 100 tokens (100000000 units with 6 decimals)
arch-cli token transfer "$TOKEN_ACCOUNT" "$RECIPIENT_ACCOUNT" 100000000 \
--owner ~/DEMO_KEYS/token_account_owner.key
Approve Delegation
# Generate a delegate keypair
openssl rand -out ~/DEMO_KEYS/delegate.key 32
# Approve the delegate to spend 50 tokens (use delegate's base58 public key)
export DELEGATE_PUBKEY=<DELEGATE_PUBKEY_BASE58>
arch-cli token approve "$TOKEN_ACCOUNT" "$DELEGATE_PUBKEY" 50000000 \
--owner ~/DEMO_KEYS/token_account_owner.key
# Check the balance
arch-cli token balance "$TOKEN_ACCOUNT"
Transfer from Delegate
# Transfer tokens using the delegate as the signer
arch-cli token transfer "$TOKEN_ACCOUNT" "$RECIPIENT_ACCOUNT" 25000000 \
--owner ~/DEMO_KEYS/delegate.key
Burn Tokens
# Burn 10 tokens from the token account
arch-cli token burn \
--account $TOKEN_ACCOUNT \
--amount 10000000 \
--owner ~/DEMO_KEYS/token_account_owner.key \
--keypair-path ~/DEMO_KEYS/payer.key
Token Account Management
Freeze and Thaw Accounts
# Freeze the token account (prevents transfers)
arch-cli token freeze-account "$TOKEN_ACCOUNT" \
--authority ~/DEMO_KEYS/mint_authority.key
# Thaw the account (re-enable transfers)
arch-cli token thaw-account "$TOKEN_ACCOUNT" \
--authority ~/DEMO_KEYS/freeze_authority.key
Close Token Account
# Close the token account (reclaims rent)
arch-cli token close-account "$TOKEN_ACCOUNT" <DESTINATION_PUBKEY> \
--owner ~/DEMO_KEYS/token_account_owner.key
Multisig Token Operations
Create Multisig Mint Authority
# Generate multiple authority keypairs
openssl rand -out ~/DEMO_KEYS/authority1.key 32
openssl rand -out ~/DEMO_KEYS/authority2.key 32
openssl rand -out ~/DEMO_KEYS/authority3.key 32
# Create a multisig (2-of-3)
export MULTISIG=$(NO_COLOR=1 arch-cli token create-multisig 2 \
--signers ~/DEMO_KEYS/authority1.key,~/DEMO_KEYS/authority2.key,~/DEMO_KEYS/authority3.key \
--keypair-path ~/DEMO_KEYS/payer.key | awk -F': ' '/^Multisig Address:/{print $2; exit}')
Mint with Multisig
# Set the mint's authority to the multisig address
arch-cli token set-authority "$MINT" \
--authority-type mint \
--new-authority "$MULTISIG" \
--current-authority ~/DEMO_KEYS/mint_authority.key
# Create a token account for the recipient
arch-cli token create-account \
--mint "$MINT" \
--owner ~/DEMO_KEYS/token_account_owner.key \
--keypair-path ~/DEMO_KEYS/payer.key
export MULTISIG_ACCOUNT=$(NO_COLOR=1 arch-cli token create-account \
--mint "$MINT" \
--owner ~/DEMO_KEYS/token_account_owner.key \
--keypair-path ~/DEMO_KEYS/payer.key \
| awk -F': ' '/^Account Address:/{print $2; exit}')
# Mint using multisig (provide multisig address and two signer keypairs)
arch-cli token mint "$MINT" 1000000000 \
--account-address "$MULTISIG_ACCOUNT" \
--authority ~/DEMO_KEYS/authority1.key \
--multisig "$MULTISIG" \
--signers ~/DEMO_KEYS/authority1.key,~/DEMO_KEYS/authority2.key \
--keypair-path ~/DEMO_KEYS/payer.key
Token Metadata
Set Token Metadata
# Set metadata for your token
arch-cli token set-metadata \
--mint $MINT \
--name "My Awesome Token" \
--symbol "MAT" \
--description "A demonstration token for Arch Network" \
--image "https://example.com/token-image.png" \
--mint-authority ~/DEMO_KEYS/mint_authority.key \
--keypair-path ~/DEMO_KEYS/payer.key
View Token Metadata
# View the token metadata
arch-cli token show-metadata --mint $MINT
Batch Operations
Batch Transfer
# Create multiple recipient accounts
for i in {1..3}; do
openssl rand -out ~/DEMO_KEYS/recipient$i.key 32
arch-cli token create-account \
--mint $MINT \
--owner ~/DEMO_KEYS/recipient$i.key \
--keypair-path ~/DEMO_KEYS/payer.key
done
# Batch transfer using a JSON file
# Example transfers.json: [{"source_account":"$TOKEN_ACCOUNT","destination_account":"<RECIPIENT_ACCOUNT>","amount":100000000,"owner_keypair_path":"~/DEMO_KEYS/token_account_owner.key"}]
arch-cli token batch-transfer ./transfers.json \
--keypair-path ~/DEMO_KEYS/payer.key
Error Handling and Troubleshooting
Common Issues
Insufficient Balance:
# Check account balance before operations
arch-cli token show-account --mint $MINT --owner ~/DEMO_KEYS/token_account_owner.key
Invalid Authority:
# Verify you're using the correct authority keypair
arch-cli token show-mint "$MINT"
# If you see an authority mismatch when minting:
# 1) Verify the mint's current Mint Authority matches your keypair's pubkey
NO_COLOR=1 arch-cli token show-mint "$MINT" | awk -F': ' '/^Mint Authority:/{print $2}'
# 2) If wrong, either switch to the correct keypair or update the authority:
arch-cli token set-authority "$MINT" \
--authority-type mint \
--new-authority <NEW_AUTHORITY_PUBKEY_BASE58> \
--current-authority ~/DEMO_KEYS/mint_authority.key
Verify Authority Before Minting
# Derive pubkeys without funding (amount 0 prints the public key)
OWNER_PUB=$(NO_COLOR=1 arch-cli account airdrop --keypair-path ~/DEMO_KEYS/token_account_owner.key --amount 0 2>/dev/null | awk -F': ' '/^ Public key:/{print $2}')
MINT_AUTH_PUB=$(NO_COLOR=1 arch-cli account airdrop --keypair-path ~/DEMO_KEYS/mint_authority.key --amount 0 2>/dev/null | awk -F': ' '/^ Public key:/{print $2}')
CHAIN_MINT_AUTH=$(NO_COLOR=1 arch-cli token show-mint "$MINT" | awk -F': ' '/^Mint Authority:/{print $2}')
echo "Owner: $OWNER_PUB"
echo "MintAuthKey: $MINT_AUTH_PUB"
echo "ChainMintAuth: $CHAIN_MINT_AUTH"
# Must match before minting
test "$MINT_AUTH_PUB" = "$CHAIN_MINT_AUTH" || echo "Mint authority mismatch: rotate or recreate mint."
Reset Demo Keys (Dev Only)
# Destroys local keys; only do this for demo/dev mints
rm -rf ~/DEMO_KEYS
mkdir -p ~/DEMO_KEYS
# Recreate stable keys ONCE (don’t regenerate after mint creation)
openssl rand -out ~/DEMO_KEYS/payer.key 32
openssl rand -out ~/DEMO_KEYS/mint_authority.key 32
openssl rand -out ~/DEMO_KEYS/mint.key 32
openssl rand -out ~/DEMO_KEYS/token_account_owner.key 32
# Fund payer
arch-cli account airdrop --keypair-path ~/DEMO_KEYS/payer.key
# Recreate mint (uses the mint_authority you just generated)
arch-cli token create-mint \
--decimals 6 \
--mint-authority ~/DEMO_KEYS/mint_authority.key \
--mint-keypair-path ~/DEMO_KEYS/mint.key \
--keypair-path ~/DEMO_KEYS/payer.key
export MINT=$(NO_COLOR=1 arch-cli token show-mint ~/DEMO_KEYS/mint.key | awk -F': ' '/^Address:/{print $2}')
Key Roles
- Payer (
--keypair-path
): pays fees; required when creating ATAs - Mint authority (
--authority
): must equal on-chain Mint Authority - Owner (
--account-address
): owner’s base58 pubkey; CLI derives/creates the ATA
Account Not Found:
# Ensure the token account exists
arch-cli token show-account --mint $MINT --owner ~/DEMO_KEYS/token_account_owner.key
Debug Commands
# Show detailed token information
arch-cli token show-mint "$MINT"
# Show account details
arch-cli token show-account "$TOKEN_ACCOUNT"
# Check transaction status
arch-cli tx confirm <SIGNATURE>
# View program logs
arch-cli tx log-program-messages <SIGNATURE>
Best Practices
Security
- Secure Key Management: Store private keys securely and never share them
- Use Multisig: Implement multisig for important operations
- Regular Audits: Regularly audit token operations and balances
- Access Control: Implement proper access controls for mint authorities
Performance
- Batch Operations: Use batch operations for multiple transfers
- Account Management: Close unused accounts to reclaim rent
- Efficient Decimals: Choose appropriate decimal places for your use case
- Monitor Gas: Monitor transaction costs and optimize accordingly
Development
- Test Thoroughly: Test all operations in development before production
- Error Handling: Implement proper error handling in your applications
- Documentation: Document your token's purpose and operations
- Community: Follow community best practices and standards
Integration Examples
TypeScript Integration
import { ArchNetworkClient } from '@arch-network/sdk';
const client = new ArchNetworkClient('http://localhost:9002');
// Create a token mint
const mint = await client.createTokenMint({
decimals: 6,
mintAuthority: mintAuthorityKeypair,
payer: payerKeypair
});
// Create a token account
const tokenAccount = await client.createTokenAccount({
mint: mint.publicKey,
owner: ownerKeypair.publicKey,
payer: payerKeypair
});
// Mint tokens
await client.mintTo({
mint: mint.publicKey,
destination: tokenAccount,
amount: 1000000000,
mintAuthority: mintAuthorityKeypair
});
Rust Integration
use arch_network_sdk::prelude::*;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = ArchNetworkClient::new("http://localhost:9002").await?;
// Create token mint
let mint = client.create_token_mint(
CreateTokenMintParams {
decimals: 6,
mint_authority: &mint_authority_keypair,
payer: &payer_keypair,
}
).await?;
// Create token account
let token_account = client.create_token_account(
CreateTokenAccountParams {
mint: mint.pubkey(),
owner: owner_keypair.pubkey(),
payer: &payer_keypair,
}
).await?;
// Mint tokens
client.mint_to(
MintToParams {
mint: mint.pubkey(),
destination: token_account,
amount: 1000000000,
mint_authority: &mint_authority_keypair,
}
).await?;
Ok(())
}
Next Steps
Oracle Program Guide
Learn to build price oracles
Runes Swap Guide
Build a token swap protocol
Lending Protocol
Create a lending protocol
APL Documentation
Deep dive into the APL Token Program