Official Go SDK for the Lumera Protocol - a next-generation blockchain platform for AI and decentralized storage.
- 🔗 Unified APIs — Single interface unifying Lumera gRPC, SuperNode SDK, and SnApi
- 📦 Type-Safe — Full Go type definitions for all Lumera modules
- 🚀 High-Level API — Simple methods for complex operations
- 🔐 Secure — Built on Cosmos SDK's proven cryptography
- 📝 Well-Documented — Comprehensive examples and documentation
This SDK unifies three distinct Lumera interfaces behind one easy client:
- Lumera API (via gRPC): Standard blockchain queries and transactions.
- Accessed via client.Client.Blockchain, which exposes module clients like blockchain.Client.Action and blockchain.Client.SuperNode.
- SuperNode SDK: Direct interaction with Supernodes for data operations, task lifecycle, and event subscriptions.
- Accessed via client.Client.Cascade, which wraps the SuperNode SDK. Key methods: cascade.Client.Upload, cascade.Client.Download, cascade.Client.SubscribeToEvents.
- SnApi (via gRPC): Supernode gRPC interface used under the hood by the SuperNode SDK to communicate with Supernodes.
- This SDK integrates SnApi through the SuperNode SDK; direct, first-class SnApi wrappers may be added in future releases.
go get github.com/LumeraProtocol/sdk-gopackage main
import (
"context"
"log"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
lumerasdk "github.com/LumeraProtocol/sdk-go/client"
)
func main() {
ctx := context.Background()
// Initialize keyring (for queries-only flows, any key name/address placeholders are fine)
kr, err := keyring.New("lumera", "test", "/tmp", nil)
if err != nil {
log.Fatal(err)
}
// Create client
client, err := lumerasdk.New(ctx, lumerasdk.Config{
ChainID: "lumera-testnet-2",
GRPCEndpoint: "localhost:9090",
RPCEndpoint: "http://localhost:26657",
Address: "lumera1abc...",
KeyName: "my-key",
}, kr, lumerasdk.WithLogger(zap.NewExample()))
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Query an action via Lumera gRPC API
action, err := client.Blockchain.Action.GetAction(ctx, "action-123")
if err != nil {
log.Fatal(err)
}
log.Printf("Action: %+v", action)
}Note: For Cascade file operations (SuperNode SDK + SnApi), see:
If you need to register Cascade actions via an interchain account (ICS-27) while still using the SDK for metadata, uploads, and downloads, the high-level flow is:
- Resolve the controller-chain owner address and ensure the ICA host address is registered.
- Fund the ICA host address on Lumera so it can pay fees.
- Initialize
cascade.ClientwithICAOwnerKeyNameandICAOwnerHRPto allow controller-chain download signatures. - Build and submit
MsgRequestActionover ICA, then use the returned action ID for the supernode upload. - Download with a controller-chain signer (or let the client derive it).
- After the action is
DONE, sendMsgApproveActionover ICA and wait forAPPROVED.
Minimal wiring (controller-chain submit helpers are application-specific):
// setup cascade client with ICA owner config
cascadeClient, err := cascade.New(ctx, cascade.Config{
ChainID: lumeraChainID,
GRPCAddr: lumeraGRPC,
Address: lumeraAddr, // host chain address
KeyName: lumeraKeyName,
ICAOwnerKeyName: simdKeyName, // controller chain key name
ICAOwnerHRP: "cosmos", // controller chain address HRP
Timeout: 30 * time.Second,
}, kr)
// send function submits ICA MsgRequestAction and returns action id
sendFunc := func(ctx context.Context, msg *actiontypes.MsgRequestAction, _ []byte, _ string, _ *cascade.UploadOptions) (*types.ActionResult, error) {
actionIDs, err := sendICARequestTx(ctx, []*actiontypes.MsgRequestAction{msg})
if err != nil {
return nil, err
}
return &types.ActionResult{ActionID: actionIDs[0]}, nil
}
res, err := cascadeClient.Upload(ctx, icaAddr, nil, filePath,
cascade.WithICACreatorAddress(icaAddr),
cascade.WithAppPubkey(simdPubkey),
cascade.WithICASendFunc(sendFunc),
)
// download using controller address for signature (optional override)
_, err = cascadeClient.Download(ctx, res.ActionID, downloadDir, cascade.WithDownloadSignerAddress(ownerAddr))
// approve via ICA when action is DONE
approveMsg, _ := cascade.CreateApproveActionMessage(ctx, res.ActionID, cascade.WithApproveCreator(icaAddr))
_ = sendICAApproveTx(ctx, []*actiontypes.MsgApproveAction{approveMsg})Notes:
WithICASendFuncis required when usingWithICACreatorAddressand/orWithAppPubkey.- Some chains enforce
app_pubkeyfor ICA creators; set it to the controller-chain key pubkey. - The full end-to-end test lives in
../lumera/devnet/tests/hermes/ibc_hermes_ica_test.go(TestICACascadeFlow). - Devnet test link: lumera/devnet/tests/hermes/ibc_hermes_ica_test.go
The SDK includes small helpers to assemble ICS-27 packets and decode acknowledgements in ica:
PackRequestForICA: packsMsgRequestActionintogoogle.protobuf.Anybytes.BuildICAPacketData: wraps one or more Any messages intoInterchainAccountPacketDataforEXECUTE_TX.BuildMsgSendTx: builds controller-sideMsgSendTxif you submit the tx programmatically.ExtractRequestActionIDsFromAck/ExtractRequestActionIDsFromTxMsgData: pull action IDs out of acknowledgements.ParseTxHashJSON,ExtractPacketInfoFromTxJSON,DecodePacketAcknowledgementJSON: CLI-friendly helpers for tx hash, packet info, and ack decoding.
Build a packet JSON file (used by the CLI) from a MsgRequestAction:
msg, _, _ := cascadeClient.CreateRequestActionMessage(ctx, icaAddr, filePath, &cascade.UploadOptions{
ICACreatorAddress: icaAddr,
AppPubkey: simdPubkey,
})
anyBz, _ := ica.PackRequestForICA(msg)
var any codectypes.Any
_ = gogoproto.Unmarshal(anyBz, &any)
packet, _ := ica.BuildICAPacketData([]*codectypes.Any{&any})
packetJSON, _ := codec.NewProtoCodec(codectypes.NewInterfaceRegistry()).MarshalJSON(&packet)
_ = os.WriteFile("ica-packet.json", packetJSON, 0o600)Send the packet on the controller chain (example simd CLI):
simd tx interchain-accounts controller send-tx <connection-id> ica-packet.json \
--from <controller-key> \
--chain-id <controller-chain-id> \
--gas auto \
--gas-adjustment 1.3 \
--broadcast-mode sync \
--output json \
--yesOnce you have the IBC acknowledgement bytes (from relayer output or packet-ack query), decode action IDs:
ids, err := ica.ExtractRequestActionIDsFromAck(ackBytes)If you already have sdk.TxMsgData (for example, from an ack you decoded yourself), use:
ids := ica.ExtractRequestActionIDsFromTxMsgData(msgData)Packet/ack CLI helpers (controller chain):
# tx response -> packet identifiers
simd q tx <tx-hash> --output json
# packet ack query uses port/channel/sequence from send_packet event
simd q ibc channel packet-ack <port> <channel> <sequence> --output jsontxHash, _ := ica.ParseTxHashJSON(txJSON)
packetInfo, _ := ica.ExtractPacketInfoFromTxJSON(txQueryJSON)
ackBytes, _ := ica.DecodePacketAcknowledgementJSON(ackQueryJSON)
ids, _ := ica.ExtractRequestActionIDsFromAck(ackBytes)
_ = txHash
_ = packetInfoCommon helpers:
DefaultKeyringParams/NewKeyringfor consistent keyring setup.LoadKeyringFromMnemonic/ImportKeyFromMnemonicfor mnemonic-based flows.AddressFromKeyto derive HRP-specific addresses without mutating global config.NewDefaultTxConfigandSignTxWithKeyringfor signing with Cosmos SDK builders.
import (
"github.com/LumeraProtocol/sdk-go/constants"
sdkcrypto "github.com/LumeraProtocol/sdk-go/pkg/crypto"
)
kr, _ := sdkcrypto.NewKeyring(sdkcrypto.DefaultKeyringParams())
addr, _ := sdkcrypto.AddressFromKey(kr, "alice", constants.LumeraAccountHRP)
_ = addrReuse the same configuration and transports for multiple local accounts via the client factory:
import (
"context"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
lumerasdk "github.com/LumeraProtocol/sdk-go/client"
"github.com/LumeraProtocol/sdk-go/constants"
sdkcrypto "github.com/LumeraProtocol/sdk-go/pkg/crypto"
)
kr, _ := keyring.New("lumera", "os", "~/.lumera", nil)
factory, err := lumerasdk.NewFactory(lumerasdk.Config{
ChainID: "lumera-testnet-2",
GRPCEndpoint: "localhost:9090",
RPCEndpoint: "http://localhost:26657",
}, kr)
aliceAddr, _ := sdkcrypto.AddressFromKey(kr, "alice", constants.LumeraAccountHRP)
bobAddr, _ := sdkcrypto.AddressFromKey(kr, "bob", constants.LumeraAccountHRP)
alice, _ := factory.WithSigner(ctx, aliceAddr, "alice")
bob, _ := factory.WithSigner(ctx, bobAddr, "bob")
defer alice.Close()
defer bob.Close()
// Upload or query with different signers using the same underlying connections
_, _ = alice.Blockchain.Action.GetAction(ctx, "some-action-id")
_, _ = bob.Blockchain.Action.GetAction(ctx, "another-action-id")See examples/multi-account for a runnable sample.
See the examples directory for complete working examples:
- Cascade Upload - Upload files to decentralized storage
- Cascade Download - Download files from storage
- Query Actions - Query blockchain actions
- Claim Tokens - Claim tokens from old chain
- Multi-Account Factory - Reuse a config while swapping local signers
# Clone the repository
git clone https://github.com/LumeraProtocol/sdk-go.git
cd sdk-go
# Install dependencies
go mod download
# Run tests
make test
# Run linters
make lint
# Build examples
make examplesContributions are welcome! Please read our Contributing Guide for details.
Apache 2.0 - see LICENSE file for details.