Initia (Closed Testnet)
  • Reminder
    • ⛔Confidentiality Disclaimer
  • WELCOME TO CLOSED TESTNET
    • Welcome to Closed Testnet
  • About Initia
    • What is the Initia Platform?
      • Architecture
        • Layer 1
        • Layer 2
      • Aligning Initia (coming soon!)
    • InitiaDEX
    • Enshrined Liquidity and Staking
  • Developers
    • Initiad
      • Download Initiad
      • Using Initiad
    • Get INIT token
    • Build your own Minitia
      • Simple Minitia Setup
      • Connect Minitia to L1
        • OPinit Stack
          • OPinit Module
          • OPinit Bots
        • Relayer
          • Fetching Oracle Prices
    • Virtual Machines
      • MoveVM
        • Interact with CLI
      • WasmVM
    • Contracts
      • Move Contracts
      • CosmWasm Contracts
      • EVM Contracts (Coming Soon)
    • Oracles
  • Initia Developer Tutorials
    • 1. Create account
    • 2. Send Move coin
    • 3. Interchain Message
    • 4. Create your own Move coin
    • 5. Create your own Move NFT
    • 6. Build and Publish Contracts
      • Move Module
      • CosmWasm Contract
  • Core Applications
    • Core Applications
      • Wallet
      • Initia App
      • Usernames
      • Initia Scan
  • Node Operators
    • Running Initia Node
      • Prerequisites
      • Oracle
      • Boot an Initia Node
      • Connect to Initia Network
      • Cosmovisor Guide
    • Configuring Initia Validator
  • References and Tools
    • Move Language
    • Rust Language (CosmWasm)
    • Closed Testnet Chain Information
    • Chain Parameters
    • Initia.js
    • API Docs
    • API Docs (minimove)
    • API Docs (miniwasm)
    • Whitelisted Tokens and Pairs
Powered by GitBook
On this page
  • Step 1: Initialize Coin
  • Step 2: Mint Coin
  1. Initia Developer Tutorials

4. Create your own Move coin

This tutorial covers how to make my own coin and mint them using 0x1::managed_coin module, and how to interact with the Move module.

Previous3. Interchain MessageNext5. Create your own Move NFT

Last updated 1 year ago

Step 1: Initialize Coin

Call function and start creating a new coin on Initia.

public entry fun initialize(
    account: &signer,
    maximum_supply: Option<u128>,
    name: String,
    symbol: String,
    decimals: u8,
    icon_uri: String,
    project_uri: String,
)

TIP: On the entry function, signer is included in msg sender and is omitted on msg args.

> initiad tx move execute 0x1 managed_coin initialize \
  --args "option<u128>:null string:my_coin string:MYCOIN u8:6 string: string:" \
  --from [key-name] \
  --gas auto --gas-adjustment 1.5 --gas-prices 0.15uinit \
  --node [rpc-url]:[rpc-port] --chain-id [chain-id]
import {
  bcs,
  LCDClient,
  MnemonicKey,
  MsgExecute,
  Wallet,
} from '@initia/initia.js';

async function createCoin() {
  const lcd = new LCDClient('[rest-url]', {
    gasPrices: '0.15uinit',
    gasAdjustment: '1.5',
  });

  const key = new MnemonicKey({
    mnemonic: 'beauty sniff protect ...',
  });
  const wallet = new Wallet(lcd, key);

  const msgs = [
    new MsgExecute(
      key.accAddress,
      '0x1',
      'managed_coin',
      'initialize',
      [],
      [
        // max supply, if you want to set max supply, insert number instaed of null
        bcs.option(bcs.u128()).serialize(null).toBase64(),
        bcs.string().serialize('my_coin').toBase64(), // name
        bcs.string().serialize('MYCOIN').toBase64(), // symbol
        // decimal point (raw value 1 consider to 10 ** (- decimalPoint))
        bcs.u8().serialize(6).toBase64(),
        bcs.string().serialize('').toBase64(), // icon uri
        bcs.string().serialize('').toBase64(), // project uri
      ]
    ),
  ];

  // sign tx
  const signedTx = await wallet.createAndSignTx({ msgs });
  // send(broadcast) tx
  lcd.tx.broadcastSync(signedTx).then(res => console.log(res));
  // {
  //   height: 0,
  //   txhash: '40E0D5633D37E207B2463D275F5B479FC67D545B666C37DC7B121ED551FA18FC',
  //   raw_log: '[]'
  // }
}

createCoin();

Step 2: Mint Coin

public entry fun mint(
    account: &signer,
    dst_addr: address,
    metadata: Object<Metadata>,
    amount: u64,
)

What is metadata?

How do I get metadata?

A view function 0x1::coin::metadata can be used to get metadata of a coin. You can also get the metadata by using sha3_256(creator+symbol+0xFE).

> initiad query move view 0x1 coin metadata \
    --args "address:[addr] string:MYCOIN" \
    --node [rpc-url]:[rpc-port]

data: '"0x2d81ce0b6708fccc77a537d3d1abac8c9f1f674f4f76390e3e78a89a52d4aacb"'
import { bcs, LCDClient, MnemonicKey } from '@initia/initia.js';
import * as crypto from 'crypto';

async function getCoinMetadata() {
  const lcd = new LCDClient('https://lcd.mahalo-1.initia.xyz', {
    gasPrices: '0.15uinit',
    gasAdjustment: '1.5',
  });

  const key = new MnemonicKey({
    mnemonic: 'beauty sniff protect ...',
  });

  // Method 1: use view function
  lcd.move
    .viewFunction(
      '0x1',
      'coin',
      'metadata',
      [],
      [
        bcs.address().serialize(key.accAddress).toBase64(),
        bcs.string().serialize('MYCOIN').toBase64(),
      ]
    )
    .then(console.log);
  // 0xcf921815f2b4827930ac01b3116ed3caad08ccd443f9df6eb22cd5344a548660

  // Method 2: use sha3-256
  console.log(coinMetadata(key.accAddress, 'MYCOIN'));
  // cf921815f2b4827930ac01b3116ed3caad08ccd443f9df6eb22cd5344a548660
}

getCoinMetadata();

function coinMetadata(creator: string, symbol: string): string {
  const OBJECT_FROM_SEED_ADDRESS_SCHEME = 0xfe;
  const addrBytes = bcs.address().serialize(creator).toBytes();
  const seed = Buffer.from(symbol, 'ascii');
  const bytes = [...addrBytes, ...seed, OBJECT_FROM_SEED_ADDRESS_SCHEME];
  const hash = crypto.createHash('SHA3-256');
  const digest = hash.update(Buffer.from(bytes)).digest();
  return digest.toString('hex');
}

Now that we know the metadata address, let's mint coins.

> initiad tx move execute 0x1 managed_coin mint \
  --args "address:[addr] object:0x2d81ce0b6708fccc77a537d3d1abac8c9f1f674f4f76390e3e78a89a52d4aacb u64:100000000" \
  --from [key-name] \
  --gas auto --gas-adjustment 1.5 --gas-prices 0.15uinit \
  --node [rpc-url]:[rpc-port] --chain-id [chain-id]
import {
  bcs,
  LCDClient,
  MnemonicKey,
  MsgExecute,
  Wallet,
} from '@initia/initia.js';
import * as crypto from 'crypto';

async function mintCoin() {
  const lcd = new LCDClient('[rest-url]', {
    gasPrices: '0.15uinit',
    gasAdjustment: '1.5',
  });

  const key = new MnemonicKey({
    mnemonic: 'beauty sniff protect ...',
  });
  const wallet = new Wallet(lcd, key);

  const msgs = [
    new MsgExecute(
      key.accAddress,
      '0x1',
      'managed_coin',
      'mint',
      [],
      [
        bcs.address().serialize(key.accAddress).toBase64(),
        bcs
          .object()
          .serialize(coinMetadata(key.accAddress, 'MYCOIN'))
          .toBase64(),
        bcs.u64().serialize(100000000).toBase64(),
      ]
    ),
  ];

  // sign tx
  const signedTx = await wallet.createAndSignTx({ msgs });
  // send(broadcast) tx
  lcd.tx.broadcastSync(signedTx).then(res => console.log(res));
  // {
  //   height: 0,
  //   txhash: '593827F58F3E811686EC6FFDAD2E27E91DA707965F0FF33093DC071D47A46786',
  //   raw_log: '[]'
  // }
}

mintCoin();

function coinMetadata(creator: string, symbol: string): string {
  const OBJECT_FROM_SEED_ADDRESS_SCHEME = 0xfe;
  const addrBytes = bcs.address().serialize(creator).toBytes();
  const seed = Buffer.from(symbol, 'ascii');
  const bytes = [...addrBytes, ...seed, OBJECT_FROM_SEED_ADDRESS_SCHEME];
  const hash = crypto.createHash('SHA3-256');
  const digest = hash.update(Buffer.from(bytes)).digest();
  return digest.toString('hex');
}

Check the minted coins by querying the balances.

initiad query bank balances [addr] \
    --node [rpc-url]:[rpc-port]
balances:
- amount: "100000000"
  denom: move/2d81ce0b6708fccc77a537d3d1abac8c9f1f674f4f76390e3e78a89a52d4aacb
- amount: "99482105"
  denom: uinit
pagination:
  next_key: null
  total: "0"
import { LCDClient, MnemonicKey } from '@initia/initia.js';

async function checkBalances() {
  const lcd = new LCDClient('[rest-url]', {
    gasPrices: '0.15uinit',
    gasAdjustment: '1.5',
  });

  const key = new MnemonicKey({
    mnemonic:
      'beauty sniff protect ...',
  });
  const balances = await lcd.bank.balance(key.accAddress);

  console.log('balances:', balances[0]);
  // Coins {
  //   _coins: {
  //     uinit: Coin { denom: 'uinit', amount: '99531690', isDecimal: false },
  //     'move/cf921815f2b4827930ac01b3116ed3caad08ccd443f9df6eb22cd5344a548660': Coin {
  //       denom: 'move/cf921815f2b4827930ac01b3116ed3caad08ccd443f9df6eb22cd5344a548660',
  //       amount: '100000000',
  //       isDecimal: false
  //     }
  //   }
  // }
}

checkBalances();

TIP: If creator is 0x1, cosmos denom is equal to the symbol. If not, cosmos denom is equal to move/{metadata_address}

Call function and mint the tokens create on Step 1.

Metadata is the coins unique identity. To be more specific, it is or an address where 0x1::fungible_asset::Metadata is saved. Fungible asset is using named object to generate deterministic address which is the form of sha3_256(creator+symbol+0xFE).

0x1::managed_coin::initialize
0x1::managed_coin::mint
an object