CatScope Botter Lifecycle: Graph Subscription & Account Tracking
Your bot taps directly into the validator’s live account graph, streaming decoded state and relationships in real time. No RPC polling. No delays. Just raw, first-access insight — the kind that wins trades before others even see them.
Here’s how you (the bot developer) can build a bot that listens to graph updates and fires before the rest of the network catches up:
Step 1: Implement a Hook
Your bot needs to implement the graph.Hook
interface.
The validator will call methods on your Hook implementation as new updates arrive. This interface is how your bot observes slot roots and account state changes.
type Hook interface {
Init(g graph.Graph) error
OnSlot(slot graph.Slot, status graph.SlotStatus)
CommitStart(slot graph.Slot)
OnAccount(account graph.Account, isNew bool)
CommitFinish()
}
Create a struct (e.g. myBot) that implements this interface. For example:
type myBot struct {
ctx context.Context // when you are done with bot kill this context
graph graph.Graph
em *graph.EdgeManager
}
func (b *myBot) Init(g graph.Graph) error {
go func() {
<-b.ctx.Done()
g.Cancel()
}()
b.graph = g
b.em = g.EdgeManager()
// Subscribe to Orca pool and wallet token accounts
b.graph.Subscribe(b.ctx, <orcaPoolPubkey>, ^uint32(0), 2)
b.graph.Subscribe(b.ctx, <walletTokenAccount>, ^uint32(0), 1)
return nil
}
func (b *myBot) OnSlot(slot graph.Slot, status graph.SlotStatus) {
// Handle slot timing if needed
}
func (b *myBot) CommitStart(slot graph.Slot) {
// Start processing this slot
}
func (b *myBot) OnAccount(a graph.Account, isNew bool) {
// React to changes — e.g., recheck price, balances, etc.
if isNew {
data := a.Data()
// Check for price, balance, etc.
}
}
func (b *myBot) CommitFinish() {
// Submit tx if criteria are met
}
Step 2: Attach Your Hook to the CatScope Stream
The state.Client
connects to the validator and calls your hook methods as new updates arrive.
ctx:= context.context // client context for entire program
client := state.New(ctx, dialer, retryInterval)
errorC := make(chan error, 1)
go client.DetachHook(errorC, &myBot{})
This automatically:
- Opens a stream to the validator
- Subscribes to account changes
- Calls your Hook methods
Step 3: Handle Incoming Updates
Use the EdgeManager to explore connected edges and downstream accounts:
func (b *myBot) OnAccount(a graph.Account, isNew bool) {
nodeId := a.Id()
downstream := b.em.EdgeDown(nodeId)
for childId := range downstream {
childPubkey, ok := b.em.UnsafeNodeToPubkey(childId)
if ok {
childAccount := b.em.UnsafeAccount(childPubkey)
// Inspect childAccount.Data() etc.
}
}
}
You can use EdgeDown (nodeId) to follow downstream connections from any account. This is useful when your logic depends on changes to connected state (e.g. tracking liquidity pool pairs).
Next steps
Once your bot is receiving and processing updates, the next step is:
- Implement your algorithm: For example, calculate whether an arbitrage trade is profitable based on updated account data.
- Send trades to the validator: Use the Catscope transaction gateway to submit transactions.