ChainIO Module
The BVS SDK consists of several components, with ChainIO being the primary one—and likely the only one you’ll interact with. ChainIO acts as an abstraction layer over the base CosmWasm API used for communicating with a CosmWasm node. It simplifies tasks like data querying, contract execution, and event indexing/sequencing. ChainIO is the main interface for interacting with a BVS contract.
Creating a context
The BVS SDK makes heavy use of Golang's goroutines, channels and thus the context package. We recommend using context.Background as it fits most usage scenarios.
import "context"
ctx := context.Background()ChainIO
To use ChainIO against the SatLayer testnet, initialize a CosmWasm client pointing at our network with your keys.
import "github.com/satlayer/satlayer-api/signer"
client, err := signer.NewCosmosClient(
"sat-bbn-testnet1", // Chain-id. For SatLayer testnet it's sat-bbn-testnet1
"https://rpc.satlayer.net", // URL to an RPC node
".", // Directory that stores the key. Only used if the keyring needs it
"your-key-name-here", // name of the key
"test", // Keyring backend. Valid values includes test, os, kwallet or file
"bbn" // Address prefix of the network
)Querying contract state
The QueryContract method allows you to query contract states (equivalent to the command babylond query wasm contract-state smart <contract-address> <query-data> .
QueryContract(cosmosClient *signer.CosmosClient, opts types.QueryOptions) (*wasmtypes.QuerySmartContractStateResponse, error)In which the QueryOptions struct is defined as follows.
type QueryOptions struct {
ContractAddr string // Address of the smart contract
QueryMsg []byte // JSON query converted to bytes
}Executing contract
The ExecuteContract method runs a contract. It works exactly like QueryContract but with options to configure gas, fees and more. It is equivalent to the babylond tx wasm execute command
ExecuteContract(cosmosClient *signer.CosmosClient, opts types.ExecuteOptions) (*sdktypes.TxResponse, error)The ExecuteOptions is defined as follow:
type ExecuteOptions struct {
ContractAddr string // Address of the smart contract
ExecuteMsg []byte // Message to be executed, represented as a struct
Funds string // Amount of funds to send to the contract, represented as a string
GasAdjustment float64 // Gas adjustment factor for adjusting the estimated gas amount
GasPrice string // Gas price, represented as a string (ex. "1bbn")
Gas uint64 // Amount of gas reserved for transaction execution
Memo string // Transaction memo (if any, could be empty)
Simulate bool // Whether to dry-run the transaction. Useful to get an estimate of the needed gas amount
}Alternative to ExecuteContract, the SendTranscation function does the same thing but it provides automatic retry and observation. Depending on the use case, the SendTransaction function could be a better option.
SendTransaction(ctx context.Context, opts types.ExecuteOptions) (*coretypes.ResultTx, error)Querying node status
The QueryNodeStatus method helps you check if a node is online and healthy.
QueryNodeStatus(cosmosClient *signer.CosmosClient) (*coretypes.ResultStatus, error)Query a historical transaction
The QueryTransaction method queries a past transaction and returns the transaction result.
QueryTransaction(cosmosClient *signer.CosmosClient, txHash string) (*coretypes.ResultTx, error)Listening for events
A key function of ChainIO is listening for events generated by a given contract, which is essential for tracking task generations and submissions within a BVS. Setting up an event listener is a bit more complicated but remains straightforward. Let’s assume the cosmosClient from previous examples is still accessible.
res, err := cosmosClient.ClientCtx.Client.Status(ctx)
if err != nil {
panic(err)
}
latestBlock := res.SyncInfo.LatestBlockHeight
evtIndexer := indexer.NewEventIndexer(
cosmosClient.ClientCtx, // client context
avsDriverContract, // Address of your AVS driver contact
latestBlock, // We start listening from the last known blokc
[]string{"wasm-ExecuteBVSOffchain"}, // List of events to listen to (usually prefixed w/ wasm-)
1, // Rate-lmiting, max events per second
10 // How many retries (aginst the node) is allowed
)
evtChain, err := evtIndexer.Run(ctx)
if err != nil {
panic(err)
}
// Now read from the channel
for evt := range evtChain {
switch evt.EventType {
case "wasm-ExecuteBVSOffchain":
do_processing_for_bvs_task()
// taskId := evt.AttrMap["taskId"] // ..for example
// fmt.Println("taskId: ", taskId)
default:
fmt.Println("unhandled event: ", evt.EventType)
}
}
Contract API wrappers
ChainIO also provides abstractions of SatLayer core contacts by allowing programmatic execution and query of the core contracts. These are simple, strongly-typed wrappers for ease of use.
Wrappers are available for:
BVS Directory
Delegation Manager
Rewards Coordinator
Slash Manager
State Bank
Strategy Base/TVL Limits/Factory/Manager
To access them, run:
import "github.com/satlayer/satlayer-sdk/chainio/api"Please refer to the SatLayer Core Contracts section for what each contract does.
Logger
The BVS SDK includes a generic logger that is integrated into components of the SDK.
The following snippet shows how the logger can be used.
package main
import "github.com/satlayer/satlayer-sdk/logger"
func main() {
l := logging.NewELKLogger("bvs1")
l.SetLogLevel("debug")
// info demo
l.INFO("this is a info log test")
// warn demo
l.WARN("this is a warn log test")
// error demo
l.ERROR("this is a error log test",
logging.WithFiled("age", 100),
logging.WithFiled("gender", "man"),
)
// debug demo
l.DEBUG("this is a debug log test")
// fatal demo
l.FATAL("this is a fatal log test")
}Last updated
Was this helpful?