Documentation
¶
Overview ¶
Package bridgesolana detects cross-chain bridge events from Solana program logs.
Build a BridgeDetector once at process start, then hand it the raw log strings from a Solana transaction's metadata. BridgeDetector.Detect returns one Detection per matched bridge event.
A Detection carries the bridge identity (name, description, leg type) and one of two payloads:
- A populated CorrelationID — extracted in-band from an Anchor "Program data:" event. The detection is fully resolved.
- A non-nil Resolution — the bridge fires through a CPI without emitting an event. The caller fetches the relevant on-chain data via RPC and passes it to Resolution.Resolve to obtain the correlation ID.
Bridge configurations are embedded JSON, currently covering Circle CCTP V1 and V2 source/destination legs.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BridgeDetector ¶
type BridgeDetector struct {
// contains filtered or unexported fields
}
BridgeDetector scans Solana program logs and emits Detection records. It is read-only after construction and safe to share across goroutines.
func NewBridgeDetector ¶
func NewBridgeDetector() (*BridgeDetector, error)
NewBridgeDetector builds a detector from the embedded bridge configs.
Example ¶
ExampleNewBridgeDetector shows how to construct a detector. It is cheap and safe to call once at process start.
package main
import (
"fmt"
"github.com/miradorlabs/bridgesolana"
)
func main() {
_, err := bridgesolana.NewBridgeDetector()
fmt.Println(err)
}
Output: <nil>
func (*BridgeDetector) Detect ¶
func (d *BridgeDetector) Detect(logs []string) []Detection
Detect scans logs (the raw "Program ..." strings from a single Solana transaction's metadata) and returns one Detection per matched bridge event. The detector tracks the program invocation stack across log lines, so both "Program data:" events and "Program log: Instruction:" lines are scoped to the program currently executing.
A Detection with a non-empty CorrelationID is fully resolved. A Detection with a non-nil Resolution requires the caller to fetch the relevant account or instruction data via RPC and call the package helpers to extract the correlation ID.
Example ¶
ExampleBridgeDetector_Detect shows the common path: pass the raw program log strings from a Solana transaction and read off each detection. A Detection with a populated CorrelationID is fully resolved; one with a non-nil Resolution requires the caller to fetch the relevant account or instruction data from RPC and pass it to Resolution.Resolve.
package main
import (
"fmt"
"github.com/miradorlabs/bridgesolana"
)
func main() {
d, _ := bridgesolana.NewBridgeDetector()
logs := []string{
"Program CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd invoke [1]",
"Program log: Instruction: ReceiveMessage",
"Program CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd success",
}
for _, det := range d.Detect(logs) {
fmt.Printf("%s %s leg (needs RPC follow-up: %t)\n",
det.BridgeName, det.BridgeLegType, det.Resolution != nil)
}
}
Output: cctp destination leg (needs RPC follow-up: true)
func (*BridgeDetector) ProgramIDs ¶
func (d *BridgeDetector) ProgramIDs() []string
ProgramIDs returns the unique set of Solana program IDs the detector matches against, sorted for stable output. Pass these to LogsSubscribeMentions / SubscribeProgramLogs to receive every transaction the detector can recognize.
type Detection ¶
type Detection struct {
BridgeName string
BridgeDescription string
BridgeLegType LegType
CorrelationID string
Resolution *Resolution
}
Detection is a single bridge event extracted from a Solana transaction's program logs.
CorrelationID is populated when the detector could extract it directly from the logs (Anchor "Program data:" events). Otherwise Resolution is non-nil and the caller must fetch the relevant on-chain data via RPC and pass it to Resolution.Resolve to obtain the correlation ID.
type LegType ¶
type LegType string
LegType identifies whether a detected bridge event is the source leg or the destination leg of a cross-chain transfer.
type Resolution ¶
type Resolution struct {
// MessageProgramID is the program that holds the on-chain data
// containing the correlation ID — a MessageSent account for source
// legs, the ReceiveMessage instruction data for destination legs.
MessageProgramID string
// AccountDiscriminator is the 8-byte Anchor account discriminator
// used to identify the relevant account among the transaction's
// accounts. Set for source legs only; zero for destination legs,
// which dispatches Resolve to the instruction-data parser.
AccountDiscriminator [8]byte
// contains filtered or unexported fields
}
Resolution describes how to obtain the correlation ID for an instruction-mode detection that did not carry it in-band. The caller uses MessageProgramID (and AccountDiscriminator on source legs) to locate the on-chain bytes, then hands them to Resolution.Resolve.
func (*Resolution) Resolve ¶ added in v0.2.0
func (r *Resolution) Resolve(data []byte) (id string, matched bool, err error)
Resolve extracts the correlation ID from raw on-chain data.
Both legs gate parsing on the leading 8-byte Anchor discriminator and return ("", false, nil) when it does not match. For source legs the scan-and-skip semantic lets callers walk a transaction's candidate accounts cheaply; for destination legs matched=false indicates the caller fed the wrong instruction data and should be treated as a data-shape failure.
matched=false can mean two distinct things: discriminator mismatch (err=nil) or the discriminator matched but the body parse failed (err!=nil). Callers must check err alongside matched — writing `if !matched { continue }` alone silently drops parse errors.
For source legs (AccountDiscriminator non-zero), pass the full source account data including its leading 8-byte Anchor discriminator. Resolve verifies the discriminator, parses the account body, and returns (id, true, nil) on success.
For destination legs (AccountDiscriminator zero), pass the full destination instruction data including its leading 8-byte Anchor instruction discriminator. Resolve verifies the discriminator, extracts the message bytes, and returns (id, true, nil) on success.
Resolve dispatches between source and destination by AccountDiscriminator being non-zero. This encodes the "source = account, destination = instruction data" pattern that fits every Anchor bridge surveyed so far. A future bridge with an account-backed destination leg would need an explicit LegType field on Resolution.
Data-shape errors past the discriminator gate (truncated payload, malformed correlation field) return ("", false, err).