Create Fungible Token with Golang
This document gives instructions and examples on how to use our pkg/client
package to create and
manage fungible token.
Complete code
Complete code with go.mod
file you can find
here
P.S. If you have issues with go mod tidy
command, just copy go.mod
file from the example above.
!!!include(/docs/tutorials/get-started/golang)!!!
Creating fungible token
Here is the example of creating new token uabc
with initial supply of 100 000 000:
senderAddress, err := senderInfo.GetAddress()
if err != nil {
panic(err)
}
const subunit = "uabc"
msgIssue := &assetfttypes.MsgIssue{
Issuer: senderAddress.String(),
Symbol: "ABC",
Subunit: subunit,
Precision: 6,
InitialAmount: sdkmath.NewInt(100_000_000),
Description: "ABC coin",
Features: []assetfttypes.Feature{assetfttypes.Feature_freezing},
}
ctx := context.Background()
_, err = client.BroadcastTx(
ctx,
clientCtx.WithFromAddress(senderAddress),
txFactory,
msgIssue,
)
if err != nil {
panic(err)
}
Querying the initial supply
After creating the token, initial supply is available on the issuer's account:
// Query initial balance hold by the admin (issuer of the token)
denom := subunit + "-" + senderAddress.String()
bankClient := banktypes.NewQueryClient(clientCtx)
resp, err := bankClient.Balance(ctx, &banktypes.QueryBalanceRequest{
Address: senderAddress.String(),
Denom: denom,
})
if err != nil {
panic(err)
}
fmt.Printf("Issuer's balance: %s\n", resp.Balance)
Sending tokens
Now admin may send those tokens to someone:
denom := subunit + "-" + senderAddress.String()
bankClient := banktypes.NewQueryClient(clientCtx)
resp, err := bankClient.Balance(ctx, &banktypes.QueryBalanceRequest{
Address: senderAddress.String(),
Denom: denom,
})
if err != nil {
panic(err)
}
fmt.Printf("Issuer's balance: %s\n", resp.Balance)
// Send issued token to someone
recipientInfo, _, err := clientCtx.Keyring().NewMnemonic(
"recipient",
keyring.English,
sdk.GetConfig().GetFullBIP44Path(),
"",
hd.Secp256k1,
)
if err != nil {
panic(err)
}
recipientAddress, err := recipientInfo.GetAddress()
if err != nil {
panic(err)
}
msgSend := &banktypes.MsgSend{
FromAddress: senderAddress.String(),
ToAddress: recipientAddress.String(),
Amount: sdk.NewCoins(sdk.NewInt64Coin(denom, 1_000_000)),
}
_, err = client.BroadcastTx(
ctx,
clientCtx.WithFromAddress(senderAddress),
txFactory,
msgSend,
)
if err != nil {
panic(err)
}
// Query the balance of the recipient
resp, err = bankClient.Balance(ctx, &banktypes.QueryBalanceRequest{
Address: recipientAddress.String(),
Denom: denom,
})
if err != nil {
panic(err)
}
fmt.Printf("Recipient's balance: %s\n", resp.Balance)
Freezing
Because admin enabled freezing
feature during token issuance, he/she might freeze the portion of
the recipient's balance:
msgFreeze := &assetfttypes.MsgFreeze{
Sender: senderAddress.String(),
Account: recipientAddress.String(),
Coin: sdk.NewInt64Coin(denom, 500_000),
}
_, err = client.BroadcastTx(
ctx,
clientCtx.WithFromAddress(senderAddress),
txFactory,
msgFreeze,
)
if err != nil {
panic(err)
}
Transfer Admin
Transfer the administrative rights of a fungible token (FT) to another account. This allows the new admin to manage the token, including minting, burning, freezing, and other administrative actions.
assetftClient := assetfttypes.NewQueryClient(clientCtx)
res, err := assetftClient.Token(ctx, &assetfttypes.QueryTokenRequest{
Denom: denom,
})
if err != nil {
panic(err)
}
fmt.Printf("Token admin: %s\n", res.Token.Admin)
// Transfer admin rights
msgTransferAdmin := &assetfttypes.MsgTransferAdmin{
Sender: senderAddress.String(),
Account: recipientAddress.String(),
Denom: denom,
}
_, err = client.BroadcastTx(
ctx,
clientCtx.WithFromAddress(senderAddress),
txFactory,
msgTransferAdmin,
)
if err != nil {
panic(err)
}
fmt.Println("Admin transfer message broadcasted successfully")
Clear Admin
Remove the administrative rights of a fungible token (FT). Once cleared, no account will have administrative control over the token, meaning no further administrative actions like minting, burning, or freezing can be performed
res, err = assetftClient.Token(ctx, &assetfttypes.QueryTokenRequest{
Denom: denom,
})
if err != nil {
panic(err)
}
fmt.Printf("Token admin: %s\n", res.Token.Admin)
// Transfer admin rights
msgClearAdmin := &assetfttypes.MsgClearAdmin{
Sender: recipientAddress.String(),
Denom: denom,
}
_, err = client.BroadcastTx(
ctx,
clientCtx.WithFromAddress(recipientAddress),
txFactory,
msgClearAdmin,
)
if err != nil {
panic(err)
}
fmt.Println("Admin clear message broadcasted successfully")
res, err = assetftClient.Token(ctx, &assetfttypes.QueryTokenRequest{
Denom: denom,
})
if err != nil {
panic(err)
}
if res.Token.Admin == "" {
fmt.Print("Token admin: no one\n")
} else {
fmt.Printf("Token admin: %s\n", res.Token.Admin)
}
After doing this, recipient is not allowed to transfer 500_000uabc from its account.
All the other features may be used in a similar fashion. More info is available in the documentation