Welcome to Day 6.
Day 4 was state.rs. The data model. The containers. Day 5 was errors.rs. The ten promises. The safety guarantees.
Today is events.rs. And this one is different from the last two.
state.rs and errors.rs are about what CHAKRA remembers and what CHAKRA refuses to do. They are internal. They define the shape and the limits of the protocol.
events.rs is about how CHAKRA talks.
Specifically - how the on-chain Solana program talks to the off-chain Sentinel Network without any trusted intermediary between them.
This is one of the most underrated design problems in all of cross-chain development. You have a Solana program running inside the Solana Virtual Machine. You have Rust processes running on three different servers. How do they communicate? Who tells the servers when to start working? How do the servers know what work to do?
The answer is in this file. Three structs. Thirty lines of code. Let me show you.
Part 1: What Is a Solana Event
Before the code, the concept.
When an Anchor program emits an event, it writes structured data to the transaction logs of that transaction. Not to an account. Not to storage. To the logs.
Every Solana transaction produces logs. They are public. Anyone watching the network can read them. And crucially anyone can subscribe to them in real time via WebSocket.
So when CHAKRA's on-chain program emits a ControlIntent event, it is not sending a message to anyone specifically. It is publishing structured data to a public channel. The Sentinel Nodes are subscribed to that channel. They hear it. They act on it.
No intermediary. No message broker. No trusted relay. Just a public log and three processes listening to it.
This design means the communication channel itself cannot be corrupted. The Sentinel Nodes read directly from Solana. If they hear a ControlIntent event it is because the CHAKRA program actually emitted it, which means a user actually called initialize_intent, which means funds are actually locked in an escrow PDA. The Sentinel Nodes do not need to trust anyone who tells them to start working. They verify the source themselves.
Part 2: The File
rust
use anchor_lang::prelude::*;
#[event]
pub struct ControlIntent {
pub owner: Pubkey,
pub target_chain_id: u64,
pub nonce: u64,
pub amount: u64,
pub source_chain: [u8; 32],
pub target_chain: [u8; 32],
pub target_address: [u8; 64],
pub escrow_pda: Pubkey,
pub timeout_slot: u64,
}
#[event]
pub struct IntentFinalized {
pub escrow_pda: Pubkey,
pub tx_hash: [u8; 64],
}
#[event]
pub struct IntentCancelled {
pub escrow_pda: Pubkey,
}Three events. Each one marks a different moment in the lifecycle of a cross-chain intent.
Part 3: ControlIntent — The Starting Gun
rust
#[event]
pub struct ControlIntent {
pub owner: Pubkey,
pub target_chain_id: u64,
pub nonce: u64,
pub amount: u64,
pub source_chain: [u8; 32],
pub target_chain: [u8; 32],
pub target_address: [u8; 64],
pub escrow_pda: Pubkey,
pub timeout_slot: u64,
}This is the event that starts everything.
When a user calls initialize_intent and it succeeds funds locked, escrow created, all validations passed - the CHAKRA Controller emits this event to the transaction logs.
The Sentinel Nodes are watching. They parse it. They start the signing ceremony.
Let me walk through every field and explain why it is here.
owner — the Pubkey of the user who created the intent. The Sentinel Nodes need this to verify that the escrow PDA they are about to work on actually belongs to the person they think it belongs to. It is also in the escrow account on-chain. The Sentinel cross-references both.
target_chain_id — which blockchain to execute on. Base Sepolia is 84532. This number goes into the message payload that the Sentinel Nodes sign. The same number goes into the ChakraReceiver.sol call on the target chain. The ChakraReceiver verifies it. If the Sentinel tried to execute on a different chain than the one the user specified, the signature would not verify because the chain ID would be wrong.
nonce — the uniqueness identifier for this specific intent. Combined with the owner's address and the chain ID it is part of the PDA seed. So when the Sentinel has the nonce, it can deterministically compute the escrow PDA address and fetch the account to cross-check all the other fields.
amount — how many lamports are locked. This also goes into the signing payload. The ChakraReceiver contract verifies the signature over this amount. If a Sentinel tried to execute a different amount than what the user specified, the signature would fail verification on the target chain.
source_chain and target_chain — both 32-byte arrays identifying the chains involved. source_chain is always "solana" in the current implementation. target_chain is "base" or "ethereum" etc. These go into the event so the Sentinel Nodes can route the execution correctly. If CHAKRA supports five target chains in the future, the Sentinel Network uses this field to know which chain's RPC to call.
target_address — 64 bytes. The destination address on the target chain where the execution should happen or the funds should go. This is the most sensitive field in the event. If this were tampered with, the execution would go to the wrong address. The fact that it is signed as part of the TSS payload means any tampering would invalidate the signature and the ChakraReceiver would reject it.
escrow_pda — the address of the escrow account holding the user's funds. The Sentinel Nodes use this to verify the event data matches what is actually on-chain before starting the signing ceremony. This is the cross-check. The event data could theoretically be crafted. But the escrow account on-chain cannot be faked. The Sentinel fetches the escrow by this PDA and verifies everything matches.
timeout_slot — the absolute deadline. The Sentinel Network must complete execution and submit proof before this slot. The coordinator checks the current slot against this value before starting work. If it is already past the deadline — maybe the event was delayed, maybe the signing took too long — the coordinator aborts rather than wasting gas on an execution that can never be verified on time.
Every field in ControlIntent has a job. Nothing is there by accident.
Part 4: IntentFinalized — The Confirmation
rust
#[event]
pub struct IntentFinalized {
pub escrow_pda: Pubkey,
pub tx_hash: [u8; 64],
}This event fires when submit_proof succeeds.
The TSS signature verified. The escrow closed. The lamports went to treasury.
Two fields.
escrow_pda — which intent was finalized. Any indexer, any dashboard, any monitoring tool watching CHAKRA's program logs can use this to track intent states in real time.
tx_hash — the transaction hash of the execution on the target chain. This is the receipt. When a user wants to verify that their intent was actually executed on Base Sepolia, this is the hash they take to the Base Sepolia block explorer. It is stored in the event so it is permanently on-chain as part of the Solana transaction record.
This matters for auditability. In a world where "trust me it happened on the other chain" is not acceptable, IntentFinalized puts the cross-chain receipt permanently on Solana. Every intent execution is publicly verifiable from the Solana side.
Part 5: IntentCancelled — The Safe Exit
rust
#[event]
pub struct IntentCancelled {
pub escrow_pda: Pubkey,
}The simplest event. One field.
This fires when cancel_intent succeeds. The timeout passed. The Sentinel Network did not complete in time. The user called cancel. The funds returned.
One field because there is nothing else to record. The escrow PDA tells you which intent was cancelled. There is no target chain transaction hash because no target chain execution happened. There is no amount because the amount went back to the user and that is a Solana-side operation recorded in the cancel transaction itself.
The simplicity of IntentCancelled is actually a design signal. If you see mostly IntentFinalized events in the logs, the protocol is working well. If you start seeing a lot of IntentCancelled events, something is wrong with the Sentinel Network. The events tell the story of protocol health in real time.
Part 6: How the Sentinel Actually Reads These
This is the part most people do not think about.
Anchor events are emitted as base64-encoded binary data in the transaction logs. They look like garbage to a human reading the raw logs. The Sentinel Nodes have to:
Subscribe to Solana transaction logs for the CHAKRA program via WebSocket
Filter for logs that contain "Program data:" — that is where Anchor encodes events
Base64-decode the data
Check the first 8 bytes he Anchor event discriminator
Verify it matches the discriminator for ControlIntent specifically
Deserialize the remaining bytes into the ControlIntent struct
The discriminator is computed as the first 8 bytes of SHA256("event:ControlIntent"). This is how the Sentinel knows it is looking at a ControlIntent and not some other event or log line.
If the discriminator does not match, the Sentinel ignores it and moves on. If it does match, the Sentinel trusts the data not because the event claimed to be valid, but because the event came from the CHAKRA program's address and the Solana validator already verified that the program executed correctly.
This is the security model of Solana events. You do not trust the data in isolation. You trust it because of where it came from and the fact that it is permanently embedded in a finalized transaction.
With state.rs, errors.rs, and now events.rs completely laid out, you have seen the entire structural anatomy of CHAKRA:
The Container: How we pack every byte tightly on-chain to minimize user rent.
The Guardrails: The ten strict promises that make our protocol refuse to collapse.
The Voice: How we broadcast cryptographically verifiable signals to the off-chain world without middlemen.
We are officially done with the setup files. The architectural blueprint is complete.
In the upcoming days, things turn even more interesting. We are shifting from structure to action opening up the heavy-hitting instruction engines, starting with the file that triggers the entire machine: initialize_intent.rs. Every read from here on out gets closer to the live mainframe.
and see y'all for Day 7.
Thankyou for reading. And here are some resources you can refer to
https://solanacookbook.com/references/programs.html#how-to-transfer-sol-in-a-program

Written by Maha..



