ERC-1155 Tokens (Go)
This guide shows the core steps to use ULedger’s native ERC-1155-style token transactions with the ULedger Go SDK.
ERC-1155 tokens are multi-tokens: a single token collection can manage many token IDs, where each tokenId represents a different
asset type. Each tokenId can be fungible (quantities like tickets, credits, items) or non-fungible (unique editions),
all under the same token address.
ERC-1155 is commonly used for:
- game items and inventories (multiple item types under one collection)
- ticketing and event access (e.g., “General Admission”, “VIP”, “Backstage” as different IDs)
- mixed catalogs where you want standardized IDs and efficient mint/transfer patterns
In ULedger, ERC-1155-style tokens are supported as native protocol transactions (no ULVM smart contract required). That means you can manage a multi-token collection using standard transaction types such as:
CREATE_TOKEN— define token collection metadata (name,symbol,baseURI)MINT_MULTI_TOKEN— mint units for a giventokenIdTRANSFER_TOKEN— transfer atokenId+amountbetween walletsAPPROVE_TOKEN— grant a spender an allowanceTRANSFER_TOKEN(with payloadFrom) — transfer on behalf of an owner using an allowance/approvalBURN_TOKEN— destroy token units to reduce supply (if burnable)CONVERT_TOKEN— convert units of onetokenIdinto another (optional utility operation)
Because these actions are normal ULedger transactions, token operations inherit ULedger’s core capabilities: wallet-based identity, cryptographic signatures, tamper-evident history, and an auditable trail of token events across the chain.
Your wallet must be registered on-chain (CREATE_WALLET) before it can submit token transactions.
Make sure your wallet is registered.
1) Prerequisites
You need:
- A node endpoint (the examples use
https://your-node-urlas a placeholder, so replace it with the URL of your network) - A
blockchainId(Testnet:08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2) - A wallet you can sign with (recommended: load from
.ukey) - A basic understanding that:
- Token Address = the
TransactionIdreturned byCREATE_TOKEN
- Token Address = the
2) Load a wallet
Load from a .ukey file instead of hardcoding keys:
w, err := wallet.LoadFromFile("./wallets/my_wallet.ukey", "")
if err != nil {
return fmt.Errorf("load wallet: %w", err)
}
3) Create a transaction session
Create a session bound to a node and wallet:
session, err := transaction.NewUL_TransactionSession(nodeEndpoint, w)
if err != nil {
return fmt.Errorf("create session: %w", err)
}
4) Create an ERC-1155 collection (CREATE_TOKEN)
4.1 Build the payload
func buildCreateERC1155Payload() ([]byte, error) {
return json.Marshal(transaction.CreateTokenPayload{
TokenType: transaction.ERC1155_TOKEN_TYPE,
Name: "Concert Tickets",
Symbol: "$CTIX",
BaseURI: "https://tickets.example.com/",
Mintable: true,
Burnable: true,
})
}
4.2 Submit the transaction
payloadBytes, err := buildCreateERC1155Payload()
if err != nil {
return err
}
input := transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: w.Address,
PayloadType: transaction.CREATE_TOKEN.String(),
Payload: string(payloadBytes),
}
tx, err := session.GenerateTransaction(input)
if err != nil {
return fmt.Errorf("create collection tx: %w", err)
}
tokenAddress := tx.TransactionId // ✅ Save this
fmt.Println("Token address:", tokenAddress)
fmt.Println("Status:", tx.Status, "Output:", tx.Output)
✅ The returned
tx.TransactionIdis used as the collection’s “token address” in future calls.
5) Mint tokens (MINT_MULTI_TOKEN)
:::info Confirm the recipient before you send
The recipient must be a wallet on this same blockchain with a matching key type. Transfers are final, and the network credits the address it is given: an address with no wallet on this chain holds a balance that cannot be spent. Run this check before every mint or transfer in this guide.
curl -o /dev/null -w '%{http_code}\n' \
"https://your-node-url/blockchains/{blockchainId}/wallets/{recipientAddress}"
# 200 = registered here 404 = not on this chain
:::
Mint creates token units under a specific tokenId.
5.1 Build the payload
func buildMintERC1155Payload(tokenAddress, to string, tokenId uint64, amount uint64, tokenURI string) ([]byte, error) {
return json.Marshal(transaction.MintTokenPayload{
TokenAddress: tokenAddress,
To: to,
TokenId: tokenId,
Amount: amount,
TokenURI: tokenURI,
})
}
5.2 Submit the transaction
payloadBytes, err := buildMintERC1155Payload(
tokenAddress,
toAddress,
1, // tokenId
1000, // amount
"Ticket URIs!",
)
if err != nil {
return err
}
input := transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: w.Address,
PayloadType: transaction.MINT_MULTI_TOKEN.String(),
Payload: string(payloadBytes),
}
tx, err := session.GenerateTransaction(input)
if err != nil {
return fmt.Errorf("mint tx: %w", err)
}
fmt.Println("Mint tx:", tx.TransactionId)
fmt.Println("Status:", tx.Status, "Output:", tx.Output)
6) Transfer tokens (TRANSFER_TOKEN)
ERC-1155 transfers move a specific tokenId and amount.
6.1 Build the payload
func buildTransferERC1155Payload(tokenAddress, to string, tokenId uint64, amount uint64) ([]byte, error) {
return json.Marshal(transaction.TransferTokenPayload{
TokenAddress: tokenAddress,
To: to,
TokenId: tokenId,
Amount: amount,
})
}
6.2 Submit the transaction
payloadBytes, err := buildTransferERC1155Payload(tokenAddress, toAddress, 1, 5)
if err != nil {
return err
}
input := transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: w.Address,
PayloadType: transaction.TRANSFER_TOKEN.String(),
Payload: string(payloadBytes),
}
tx, err := session.GenerateTransaction(input)
if err != nil {
return fmt.Errorf("transfer tx: %w", err)
}
fmt.Println("Transfer tx:", tx.TransactionId)
fmt.Println("Status:", tx.Status, "Output:", tx.Output)
7) Approve a spender (APPROVE_TOKEN)
Approvals allow a spender to transfer tokens on behalf of the token owner (allowance-style).
7.1 Build the payload
func buildApproveERC1155Payload(tokenAddress, spender string, amount uint64) ([]byte, error) {
return json.Marshal(transaction.ApproveTokenPayload{
TokenAddress: tokenAddress,
Spender: spender,
Amount: amount,
})
}
7.2 Submit the transaction
payloadBytes, err := buildApproveERC1155Payload(tokenAddress, spenderAddress, 5000)
if err != nil {
return err
}
input := transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: w.Address, // token owner
PayloadType: transaction.APPROVE_TOKEN.String(),
Payload: string(payloadBytes),
}
tx, err := session.GenerateTransaction(input)
if err != nil {
return fmt.Errorf("approve tx: %w", err)
}
fmt.Println("Approve tx:", tx.TransactionId)
fmt.Println("Status:", tx.Status, "Output:", tx.Output)
8) Transfer using approval (TRANSFER_TOKEN with payload From)
:::warning The recipient must not be the spender
In an allowance transfer the signer is the spender, and the network rejects any transfer whose signer is also the recipient. Send to a third address instead.
The rule applies to ERC-20, NFTs and multi-tokens. A transfer that breaches it is accepted at submit and then not applied while the allowance is unchanged, so check the recipient first if you see that. :::
This pattern submits a transfer where:
- the transaction signer (
input.From) is the spender - the payload From is the token owner whose balance is being moved
8.1 Build the payload
func buildTransferApprovalERC1155Payload(tokenAddress, to, owner string, amount uint64) ([]byte, error) {
return json.Marshal(transaction.TransferTokenPayload{
TokenAddress: tokenAddress,
To: to,
From: owner,
Amount: amount,
})
}
8.2 Submit the transaction
payloadBytes, err := buildTransferApprovalERC1155Payload(tokenAddress, finalRecipient, ownerAddress, 3000)
if err != nil {
return err
}
input := transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: spenderWallet.Address,
PayloadType: transaction.TRANSFER_TOKEN.String(),
Payload: string(payloadBytes),
}
spenderSession, err := transaction.NewUL_TransactionSession(nodeEndpoint, spenderWallet)
if err != nil {
return err
}
tx, err := spenderSession.GenerateTransaction(input)
if err != nil {
return fmt.Errorf("transfer using approval tx: %w", err)
}
fmt.Println("Transfer (approval) tx:", tx.TransactionId)
fmt.Println("Status:", tx.Status, "Output:", tx.Output)
9) Burn tokens (BURN_TOKEN)
9.1 Build the payload
func buildBurnERC1155Payload(tokenAddress string, amount uint64) ([]byte, error) {
return json.Marshal(transaction.BurnTokenPayload{
TokenAddress: tokenAddress,
Amount: amount,
})
}
9.2 Submit the transaction
payloadBytes, err := buildBurnERC1155Payload(tokenAddress, 5)
if err != nil {
return err
}
input := transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: w.Address,
PayloadType: transaction.BURN_TOKEN.String(),
Payload: string(payloadBytes),
}
tx, err := session.GenerateTransaction(input)
if err != nil {
return fmt.Errorf("burn tx: %w", err)
}
fmt.Println("Burn tx:", tx.TransactionId)
fmt.Println("Status:", tx.Status, "Output:", tx.Output)
10) Convert tokens (CONVERT_TOKEN)
CONVERT_TOKEN converts units of an existing tokenId into a new representation (based on your chain rules).
A common use is converting a token into a new state, such as "unused" → "used", by producing a new token URI and optionally burning the original units.
10.1 Build the payload
func buildConvertERC1155Payload(tokenAddress string, fromTokenId uint64, amount uint64) ([]byte, error) {
return json.Marshal(transaction.ConvertTokenPayload{
TokenAddress: tokenAddress,
FromTokenId: fromTokenId,
Amount: amount,
NewTokenURI: "https://commemorative.example.com/used_ticket",
PreserveTokens: false,
})
}
10.2 Submit the transaction
payloadBytes, err := buildConvertERC1155Payload(tokenAddress, 1, 5)
if err != nil {
return err
}
input := transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: w.Address,
PayloadType: transaction.CONVERT_TOKEN.String(),
Payload: string(payloadBytes),
}
tx, err := session.GenerateTransaction(input)
if err != nil {
return fmt.Errorf("convert tx: %w", err)
}
fmt.Println("Convert tx:", tx.TransactionId)
fmt.Println("Status:", tx.Status, "Output:", tx.Output)
11) Full example
This single example shows:
- Create collection
- Mint
tokenId=1withamount=1000 - Transfer
tokenId=1withamount=5 - Approve spender
- Transfer using approval
- Burn tokens
- Convert tokens
package main
import (
"encoding/json"
"fmt"
"github.com/ULedgerInc/golang-sdk/pkg/transaction"
"github.com/ULedgerInc/golang-sdk/pkg/wallet"
)
func main() {
nodeEndpoint := "http://localhost:8080"
blockchainId := "MyBlockchain1"
ownerWallet, err := wallet.LoadFromFile("./wallets/owner.ukey", "")
if err != nil { panic(err) }
spenderWallet, err := wallet.LoadFromFile("./wallets/spender.ukey", "")
if err != nil { panic(err) }
ownerSession, err := transaction.NewUL_TransactionSession(nodeEndpoint, ownerWallet)
if err != nil { panic(err) }
// 1) CREATE_TOKEN (ERC1155)
createPayload, _ := json.Marshal(transaction.CreateTokenPayload{
TokenType: transaction.ERC1155_TOKEN_TYPE,
Name: "Concert Tickets",
Symbol: "$CTIX",
BaseURI: "https://tickets.example.com/",
Mintable: true,
Burnable: true,
})
createTx, err := ownerSession.GenerateTransaction(transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: ownerWallet.Address,
PayloadType: transaction.CREATE_TOKEN.String(),
Payload: string(createPayload),
})
if err != nil { panic(err) }
tokenAddress := createTx.TransactionId
fmt.Println("Token address:", tokenAddress)
// 2) MINT_MULTI_TOKEN (tokenId=1, amount=1000)
mintPayload, _ := json.Marshal(transaction.MintTokenPayload{
TokenAddress: tokenAddress,
To: ownerWallet.Address,
TokenId: 1,
Amount: 1000,
TokenURI: "Ticket URIs!",
})
mintTx, err := ownerSession.GenerateTransaction(transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: ownerWallet.Address,
PayloadType: transaction.MINT_MULTI_TOKEN.String(),
Payload: string(mintPayload),
})
if err != nil { panic(err) }
fmt.Println("Mint tx:", mintTx.TransactionId)
// 3) TRANSFER_TOKEN (tokenId=1, amount=5)
transferPayload, _ := json.Marshal(transaction.TransferTokenPayload{
TokenAddress: tokenAddress,
To: spenderWallet.Address,
TokenId: 1,
Amount: 5,
})
transferTx, err := ownerSession.GenerateTransaction(transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: ownerWallet.Address,
PayloadType: transaction.TRANSFER_TOKEN.String(),
Payload: string(transferPayload),
})
if err != nil { panic(err) }
fmt.Println("Transfer tx:", transferTx.TransactionId)
// 4) APPROVE_TOKEN (approve spender)
approvePayload, _ := json.Marshal(transaction.ApproveTokenPayload{
TokenType: "", // not required for approve
TokenAddress: tokenAddress,
Spender: spenderWallet.Address,
Amount: 50,
})
approveTx, err := ownerSession.GenerateTransaction(transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: ownerWallet.Address,
PayloadType: transaction.APPROVE_TOKEN.String(),
Payload: string(approvePayload),
})
if err != nil { panic(err) }
fmt.Println("Approve tx:", approveTx.TransactionId)
// 5) TRANSFER_TOKEN using approval (spender spends owner allowance)
spenderSession, err := transaction.NewUL_TransactionSession(nodeEndpoint, spenderWallet)
if err != nil { panic(err) }
transferApprovalPayload, _ := json.Marshal(transaction.TransferTokenPayload{
TokenAddress: tokenAddress,
From: ownerWallet.Address,
To: "DESTINATION_ADDRESS", // replace
Amount: 10,
})
transferApprovalTx, err := spenderSession.GenerateTransaction(transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: spenderWallet.Address,
PayloadType: transaction.TRANSFER_TOKEN.String(),
Payload: string(transferApprovalPayload),
})
if err != nil { panic(err) }
fmt.Println("Transfer (approval) tx:", transferApprovalTx.TransactionId)
// 6) BURN_TOKEN
burnPayload, _ := json.Marshal(transaction.BurnTokenPayload{
TokenAddress: tokenAddress,
Amount: 5,
})
burnTx, err := ownerSession.GenerateTransaction(transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: ownerWallet.Address,
PayloadType: transaction.BURN_TOKEN.String(),
Payload: string(burnPayload),
})
if err != nil { panic(err) }
fmt.Println("Burn tx:", burnTx.TransactionId)
// 7) CONVERT_TOKEN
convertPayload, _ := json.Marshal(transaction.ConvertTokenPayload{
TokenAddress: tokenAddress,
FromTokenId: 1,
Amount: 5,
NewTokenURI: "https://commemorative.example.com/used_ticket",
PreserveTokens: false,
})
convertTx, err := ownerSession.GenerateTransaction(transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: ownerWallet.Address,
PayloadType: transaction.CONVERT_TOKEN.String(),
Payload: string(convertPayload),
})
if err != nil { panic(err) }
fmt.Println("Convert tx:", convertTx.TransactionId)
}