Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(axelar-gateway): use typed events #128

Merged
merged 11 commits into from
Jan 8, 2025
4 changes: 3 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions contracts/axelar-gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ axelar-soroban-std = { workspace = true }
cfg-if = { workspace = true }
ed25519-dalek = { version = "^2.1", default-features = false, optional = true }
rand = { version = "0.8.5", optional = true }
rand_chacha = "0.3"
soroban-sdk = { workspace = true }

[dev-dependencies]
axelar-gateway = { workspace = true, features = ["testutils"] }
axelar-soroban-std = { workspace = true, features = ["testutils"] }
ed25519-dalek = { version = "^2.1" }
goldie = { workspace = true }
Expand Down
9 changes: 7 additions & 2 deletions contracts/axelar-gateway/src/auth.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::error::ContractError;
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
use crate::types::{ProofSignature, ProofSigner, WeightedSigner};
use axelar_soroban_std::ensure;
use axelar_soroban_std::events::Event;
use soroban_sdk::{crypto::Hash, Bytes, BytesN, Env, Vec};

use crate::event;
use crate::event::SignersRotatedEvent;
use crate::storage_types::DataKey;
use crate::types::{Proof, WeightedSigners};

Expand Down Expand Up @@ -104,7 +105,11 @@ pub fn rotate_signers(
&new_epoch,
);

event::rotate_signers(env, new_epoch, new_signers_hash);
SignersRotatedEvent {
epoch: new_epoch,
signers_hash: new_signers_hash,
}
.emit(env);

Ok(())
}
Expand Down
15 changes: 9 additions & 6 deletions contracts/axelar-gateway/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::auth;
use crate::error::ContractError;
use crate::event::{ContractCalledEvent, MessageApprovedEvent, MessageExecutedEvent};
use crate::interface::AxelarGatewayInterface;
use crate::messaging_interface::AxelarGatewayMessagingInterface;
use crate::storage_types::{DataKey, MessageApprovalKey, MessageApprovalValue};
use crate::types::{CommandType, Message, Proof, WeightedSigners};
use crate::{auth, event};
use axelar_soroban_std::events::Event;
use axelar_soroban_std::ttl::extend_instance_ttl;
use axelar_soroban_std::{ensure, interfaces, Operatable, Ownable, Upgradable};
use soroban_sdk::xdr::ToXdr;
Expand Down Expand Up @@ -51,14 +53,14 @@ impl AxelarGatewayMessagingInterface for AxelarGateway {

let payload_hash = env.crypto().keccak256(&payload).into();

event::call_contract(
&env,
ContractCalledEvent {
caller,
destination_chain,
destination_address,
payload,
payload_hash,
);
}
.emit(&env);
}

fn is_message_approved(
Expand Down Expand Up @@ -120,14 +122,15 @@ impl AxelarGatewayMessagingInterface for AxelarGateway {
&MessageApprovalValue::Executed,
);

event::execute_message(&env, message);
MessageExecutedEvent { message }.emit(&env);
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved

return true;
}

false
}
}

#[contractimpl]
impl AxelarGatewayInterface for AxelarGateway {
fn approve_messages(
Expand Down Expand Up @@ -161,7 +164,7 @@ impl AxelarGatewayInterface for AxelarGateway {
&Self::message_approval_hash(&env, message.clone()),
);

event::approve_message(&env, message);
MessageApprovedEvent { message }.emit(&env);
}

extend_instance_ttl(&env);
Expand Down
128 changes: 95 additions & 33 deletions contracts/axelar-gateway/src/event.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,97 @@
use crate::types::Message;
use soroban_sdk::{Address, Bytes, BytesN, Env, String, Symbol};

pub fn call_contract(
env: &Env,
caller: Address,
destination_chain: String,
destination_address: String,
payload: Bytes,
payload_hash: BytesN<32>,
) {
let topics = (
Symbol::new(env, "contract_called"),
caller,
destination_chain,
destination_address,
payload_hash,
);
env.events().publish(topics, payload);
}

pub fn approve_message(env: &Env, message: Message) {
let topics = (Symbol::new(env, "message_approved"), message);
env.events().publish(topics, ());
}

pub fn execute_message(env: &Env, message: Message) {
let topics = (Symbol::new(env, "message_executed"), message);
env.events().publish(topics, ());
}

pub fn rotate_signers(env: &Env, epoch: u64, signers_hash: BytesN<32>) {
let topics = (Symbol::new(env, "signers_rotated"), epoch, signers_hash);
env.events().publish(topics, ());

use core::fmt::Debug;

use axelar_soroban_std::events::Event;
use cfg_if::cfg_if;
use soroban_sdk::{Address, Bytes, BytesN, Env, IntoVal, String, Symbol, Topics, Val, Vec};

#[derive(Debug, PartialEq, Eq)]
pub struct ContractCalledEvent {
pub caller: Address,
pub destination_chain: String,
pub destination_address: String,
pub payload: Bytes,
pub payload_hash: BytesN<32>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct MessageApprovedEvent {
pub message: Message,
}

#[derive(Debug, PartialEq, Eq)]
pub struct MessageExecutedEvent {
pub message: Message,
}

#[derive(Debug, PartialEq, Eq)]
pub struct SignersRotatedEvent {
pub epoch: u64,
pub signers_hash: BytesN<32>,
}

impl Event for ContractCalledEvent {
fn topics(&self, env: &Env) -> impl Topics + Debug {
(
Symbol::new(env, "contract_called"),
self.caller.to_val(),
self.destination_chain.to_val(),
self.destination_address.to_val(),
self.payload_hash.to_val(),
)
}

fn data(&self, _env: &Env) -> impl IntoVal<Env, Val> + Debug {
(self.payload.to_val(),)
}
}

impl Event for MessageApprovedEvent {
fn topics(&self, env: &Env) -> impl Topics + Debug {
(Symbol::new(env, "message_approved"), self.message.clone())
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
}

fn data(&self, env: &Env) -> impl IntoVal<Env, Val> + Debug {
Vec::<Val>::new(env)
}
}

impl Event for MessageExecutedEvent {
fn topics(&self, env: &Env) -> impl Topics + Debug {
(Symbol::new(env, "message_executed"), self.message.clone())
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
}

fn data(&self, env: &Env) -> impl IntoVal<Env, Val> + Debug {
Vec::<Val>::new(env)
}
}

impl Event for SignersRotatedEvent {
fn topics(&self, env: &Env) -> impl Topics + Debug {
(
Symbol::new(env, "signers_rotated"),
self.epoch,
self.signers_hash.to_val(),
)
}

fn data(&self, env: &Env) -> impl IntoVal<Env, Val> + Debug {
Vec::<Val>::new(env)
}
}

cfg_if! {
if #[cfg(any(test, feature = "testutils"))] {
use axelar_soroban_std::impl_event_testutils;

impl_event_testutils!(
ContractCalledEvent,
(Symbol, Address, String, String, BytesN<32>),
(Bytes)
);
impl_event_testutils!(MessageApprovedEvent, (Symbol, Message), ());
impl_event_testutils!(MessageExecutedEvent, (Symbol, Message), ());
impl_event_testutils!(SignersRotatedEvent, (Symbol, u64, BytesN<32>), ());
}
}
4 changes: 2 additions & 2 deletions contracts/axelar-gateway/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![no_std]

// Allows using std (and its macros) in test modules
#[cfg(test)]
#[cfg(any(test, feature = "testutils"))]
#[macro_use]
extern crate std;

Expand All @@ -24,7 +24,7 @@ cfg_if::cfg_if! {
pub use interface::{AxelarGatewayClient, AxelarGatewayInterface};
} else {
mod auth;
mod event;
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
pub mod event;
mod storage_types;
mod contract;

Expand Down
32 changes: 24 additions & 8 deletions contracts/axelar-gateway/src/testutils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::auth::{self, epoch};
use crate::{AxelarGateway, AxelarGatewayClient};
use axelar_soroban_std::{assert_last_emitted_event, assert_ok};
use ed25519_dalek::{Signature, Signer, SigningKey};
use rand::distributions::{Alphanumeric, DistString};
use rand::Rng;

use soroban_sdk::Symbol;
Expand All @@ -16,9 +17,6 @@ use crate::types::{

use axelar_soroban_std::traits::IntoVec;

const DESTINATION_CHAIN: &str = "ethereum";
const DESTINATION_ADDRESS: &str = "0x4EFE356BEDeCC817cb89B4E9b796dB8bC188DC59";

#[derive(Clone, Debug)]
pub struct TestSignerSet {
pub signer_keys: std::vec::Vec<SigningKey>,
Expand Down Expand Up @@ -59,8 +57,19 @@ pub fn get_approve_hash(env: &Env, messages: Vec<Message>) -> BytesN<32> {
.into()
}

pub fn deterministic_rng() -> rand_chacha::ChaCha20Rng {
use rand::SeedableRng;
rand_chacha::ChaCha20Rng::seed_from_u64(42)
}

pub fn generate_test_message(env: &Env) -> (Message, Bytes) {
let mut rng = rand::thread_rng();
generate_test_message_with_rng(env, rand::thread_rng())
}

pub fn generate_test_message_with_rng(
env: &Env,
mut rng: impl Rng + rand::CryptoRng,
) -> (Message, Bytes) {
let len = rng.gen_range(0..20);
let mut payload = std::vec![0u8; len];
rng.fill(&mut payload[..]);
Expand All @@ -69,9 +78,9 @@ pub fn generate_test_message(env: &Env) -> (Message, Bytes) {

(
Message {
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
source_chain: String::from_str(env, DESTINATION_CHAIN),
message_id: String::from_str(env, "test"),
source_address: String::from_str(env, DESTINATION_ADDRESS),
source_chain: String::from_str(env, &Alphanumeric.sample_string(&mut rng, 10)),
message_id: String::from_str(env, &Alphanumeric.sample_string(&mut rng, 16)),
source_address: String::from_str(env, &Alphanumeric.sample_string(&mut rng, 42)),
contract_address: Address::generate(env),
payload_hash: env.crypto().keccak256(&payload).into(),
},
Expand All @@ -88,8 +97,15 @@ pub fn generate_signers_set(
num_signers: u32,
domain_separator: BytesN<32>,
) -> TestSignerSet {
let mut rng = rand::thread_rng();
generate_signers_set_with_rng(env, num_signers, domain_separator, rand::thread_rng())
}

pub fn generate_signers_set_with_rng(
env: &Env,
num_signers: u32,
domain_separator: BytesN<32>,
mut rng: impl Rng + rand::CryptoRng,
) -> TestSignerSet {
let mut signer_keypair: std::vec::Vec<_> = (0..num_signers)
.map(|_| {
let signing_key = SigningKey::generate(&mut rng);
Expand Down
Loading
Loading