A Go SDK for the Mintlayer blockchain.
go get github.com/mintlayer/go-sdk
Requires Go 1.21+. No CGO. The WASM cryptography runtime is embedded in the binary.
| Guide | Description |
|---|---|
| docs/indexer.md | Full indexer client reference: chain, blocks, transactions, addresses, pools, tokens, orders, statistics |
| docs/node.md | Full node client reference: chainstate, mempool, P2P, block submission |
| docs/wallet.md | Full wallet client reference: lifecycle, accounts, balances, transactions |
| docs/wasm.md | Full WASM client reference: keys, addresses, inputs, outputs, signing, fees |
| docs/transactions.md | Step-by-step guide to building and signing transactions without the wallet daemon |
| docs/staking.md | Staking pools and delegations: creation, funding, withdrawal, and read queries |
| docs/tokens.md | Fungible token and NFT lifecycle: issuance, minting, freezing, authority, manual encoding |
The SDK is organised as four independent sub-clients plus a top-level Client that wires them together.
| Package | Purpose | Default port |
|---|---|---|
github.com/mintlayer/go-sdk/node | JSON-RPC 2.0 client for the node daemon | 3030 (mainnet) |
github.com/mintlayer/go-sdk/indexer | REST client for the indexer (api-web-server) | 3000 |
github.com/mintlayer/go-sdk/wallet | JSON-RPC 2.0 client for the wallet daemon | 3034 (mainnet) |
github.com/mintlayer/go-sdk/wasm | Cryptography & transaction-building via WASM | — |
Use the top-level client when you need multiple sub-clients, or import sub-packages directly when you only need one.
package main
import (
"context""fmt""log"
sdk "github.com/mintlayer/go-sdk"
)
funcmain() {
client:=sdk.New(sdk.Config{
NodeURL: "http://127.0.0.1:3030",
IndexerURL: "http://127.0.0.1:3000",
WalletURL: "http://127.0.0.1:3034",
})
ctx:=context.Background()
// Query the chain tip from the indexer.tip, err:=client.Indexer.GetTip(ctx)
iferr!=nil {
log.Fatal(err)
}
fmt.Printf("chain tip: height=%d id=%s\n", tip.BlockHeight, tip.BlockID)
// Optionally initialise the embedded WASM cryptography runtime (~400 ms).iferr:=client.InitWASM(ctx); err!=nil {
log.Fatal(err)
}
deferclient.Close()
privKey, err:=client.WASM.MakePrivateKey()
iferr!=nil {
log.Fatal(err)
}
pubKey, err:=client.WASM.PublicKeyFromPrivateKey(privKey)
iferr!=nil {
log.Fatal(err)
}
addr, err:=client.WASM.PubkeyToPubkeyHashAddress(pubKey, sdk.Mainnet)
iferr!=nil {
log.Fatal(err)
}
fmt.Println("address:", addr)
}JSON-RPC 2.0 client for the Mintlayer node daemon. Supports Basic Auth for nodes with authentication enabled.
import"github.com/mintlayer/go-sdk/node"c:=node.New("http://127.0.0.1:3030",
node.WithBasicAuth("user", "pass"), // optionalnode.WithTimeout(10*time.Second), // optional
)
ctx:=context.Background()
// Chain stateinfo, err:=c.ChainstateInfo(ctx)
height, err:=c.BestBlockHeight(ctx)
blockID, err:=c.BestBlockID(ctx)
// Look up a blockblockHex, err:=c.GetBlock(ctx, blockID)
blockJSON, err:=c.GetBlockJSON(ctx, blockID)
// Token / order infotokenInfo, err:=c.TokenInfo(ctx, "ttml1...")
orderInfo, err:=c.OrderInfo(ctx, "order1...")
// Mempoolerr=c.SubmitTransaction(ctx, signedTxHex, node.TrustPolicyUntrusted)
feeRate, err:=c.GetFeeRate(ctx, 1)
// P2PpeerCount, err:=c.GetPeerCount(ctx)
peers, err:=c.GetConnectedPeers(ctx)Errors from the daemon are returned as *node.RPCError with a numeric Code and Message.
REST client for api-web-server. All paths are relative to /api/v2/.
import"github.com/mintlayer/go-sdk/indexer"c:=indexer.New("http://127.0.0.1:3000",
indexer.WithTimeout(15*time.Second), // optional
)
ctx:=context.Background()
// Chaintip, err:=c.GetTip(ctx)
blockIDAtHeight, err:=c.GetBlockIDAtHeight(ctx, 100_000)
// Blockblock, err:=c.GetBlock(ctx, "00000000...")
txIDs, err:=c.GetBlockTransactionIDs(ctx, "00000000...")
// Transactiontx, err:=c.GetTransaction(ctx, "aabbcc...")
txID, err:=c.SubmitTransaction(ctx, signedTxHex) // requires --enable-post-routes// Addressutxos, err:=c.GetSpendableUTXOs(ctx, "mxtc1...")
info, err:=c.GetAddressInfo(ctx, "mxtc1...")
// Pool / stakingpools, err:=c.ListPools(ctx, indexer.PoolListOpts{Sort: "by_pledge"})
pool, err:=c.GetPool(ctx, "pool1...")
// Tokenstoken, err:=c.GetToken(ctx, "ttml1...")
tokens, err:=c.FindTokensByTicker(ctx, "MYTOKEN", indexer.PageOpts{Items: 10})
// Ordersorders, err:=c.ListOrders(ctx, indexer.PageOpts{Offset: 0, Items: 20})
order, err:=c.GetOrder(ctx, "order1...")
// Statisticsstats, err:=c.GetCoinStatistics(ctx)Non-2xx responses are returned as *indexer.HTTPError with a StatusCode field.
JSON-RPC 2.0 client for wallet-rpc-daemon. The wallet daemon manages key storage, signing, and broadcasting.
import"github.com/mintlayer/go-sdk/wallet"c:=wallet.New("http://127.0.0.1:3034",
wallet.WithBasicAuth("user", "pass"), // optional
)
ctx:=context.Background()
// Wallet lifecycleerr=c.OpenWallet(ctx, "/path/to/wallet.dat", "")
deferc.CloseWallet(ctx)
err=c.SyncWallet(ctx)
// Accounts and addressesinfo, err:=c.GetWalletInfo(ctx)
addr, err:=c.NewAddress(ctx, 0/*account*/)
balance, err:=c.GetBalance(ctx, 0)
// Send coins (account 0, auto fee)result, err:=c.AddressSend(ctx, wallet.SendParams{
Account: 0,
Address: "mxtc1...",
Amount: wallet.Amount{Atoms: "100000000000"}, // 1 MLSelectedUtxos: nil,
ChangeAddress: nil,
Options: nil,
})
fmt.Println("tx id:", result.TxID)
// Token operationsissueResult, err:=c.IssueToken(ctx, wallet.IssueTokenParams{
Account: 0,
Ticker: "MYTOKEN",
NumberOfDecimals: 2,
MetadataUri: "https://example.com/token",
DestinationAddress: addr,
TotalSupply: wallet.TokenTotalSupplyParams{Type: "Lockable"},
IsFreezable: "No",
Options: nil,
})
mintResult, err:=c.MintTokens(ctx, wallet.MintParams{
Account: 0,
TokenID: issueResult.TokenID,
Address: addr,
Amount: wallet.Amount{Atoms: "1000"},
Options: nil,
})
// Stakingerr=c.StartStaking(ctx, 0)
pools, err:=c.ListOwnedPools(ctx, 0)
// Compose and sign a raw transaction (cold wallet flow)composed, err:=c.ComposeTransaction(ctx, wallet.ComposeParams{...})
signed, err:=c.SignRawTransaction(ctx, 0, composed.Hex)
submitResult, err:=c.SubmitTransaction(ctx, signed.Hex, false)Cryptographic primitives and binary transaction encoding via an embedded WebAssembly module.
Initialisation takes ~400 ms; use sync.Once or Client.InitWASM to call it once per process.
import (
"context"
mintlayer "github.com/mintlayer/go-sdk/wasm"
)
ctx:=context.Background()
c, err:=mintlayer.New(ctx)
iferr!=nil {
log.Fatal(err)
}
deferc.Close()
// Key derivation (BIP-44 path 44'/mintlayer_coin_type'/0')mnemonic:="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"accountKey, err:=c.MakeDefaultAccountPrivkey(mnemonic, mintlayer.Mainnet)
recvKey, err:=c.MakeReceivingAddress(accountKey, 0)
pubKey, err:=c.PublicKeyFromPrivateKey(recvKey)
addr, err:=c.PubkeyToPubkeyHashAddress(pubKey, mintlayer.Mainnet)
// Transaction buildingsrcID, err:=c.EncodeOutpointSourceId(txIDBytes, mintlayer.SourceTransaction)
input, err:=c.EncodeInputForUtxo(srcID, outputIndex)
output, err:=c.EncodeOutputTransfer(
mintlayer.NewAmount("100000000000"), // 1 MLdestAddr,
mintlayer.Mainnet,
)
tx, err:=c.EncodeTransaction(input, output, 0/*flags*/)
txID, err:=c.GetTransactionID(tx, true)
// Signingwitness, err:=c.EncodeWitness(
mintlayer.SigHashAll,
recvKey,
addr,
tx,
utxoBytes, // see examples/send-coins for encoding details0, // input index
mintlayer.TxAdditionalInfo{},
blockHeight,
mintlayer.Mainnet,
)
signedTx, err:=c.EncodeSignedTransaction(tx, witness)See examples/send-coins/ for a complete end-to-end transaction flow.
sdk.New constructs only the sub-clients whose URL is non-empty.
// Node + WASM only — no wallet or indexer client is created.client:=sdk.New(sdk.Config{
NodeURL: "http://127.0.0.1:3030",
Username: "user",
Password: "pass",
})
// Call InitWASM before using client.WASM.iferr:=client.InitWASM(ctx); err!=nil {
log.Fatal(err)
}
deferclient.Close()Convenience type aliases (sdk.Amount, sdk.Network, sdk.Mainnet, …) are re-exported so callers
that only import the top-level package do not need to also import github.com/mintlayer/go-sdk/wasm.
| Example | Description |
|---|---|
| examples/send-coins/ | Derive key → fetch UTXOs → build, sign, and submit a transaction |
| examples/issue-token/ | Issue a fungible token and mint an initial supply via the wallet daemon |
All coin and token amounts use the Amount type, which stores the value as a decimal string of
atoms — the smallest indivisible unit. 1 ML = 100,000,000,000 atoms (11 decimal places).
one:=mintlayer.NewAmount("100000000000") // 1 MLzero:=mintlayer.NewAmountZero()
fmt.Println(one.Atoms()) // "100000000000"The indexer and wallet clients use their own Amount struct with both Atoms and Decimal fields
populated by the server.
| Constant | Value | Use |
|---|---|---|
Mainnet | 0 | Production network |
Testnet | 1 | Public test network |
Regtest | 2 | Local regression testing |
Signet | 3 | Signet |
Pass the network constant to any function that derives addresses or encodes transactions.
node.RPCError— JSON-RPC error from the node daemon (Code,Message)wallet.RPCError— JSON-RPC error from the wallet daemonindexer.HTTPError— non-2xx HTTP response from the indexer (StatusCode,Body)- WASM errors are plain
errorvalues with a descriptive message prefixed bymintlayer:.