stellar_axelar_gateway/
executable.rs

1pub use stellar_axelar_std::AxelarExecutable;
2use stellar_axelar_std::{derive_only, ensure, Address, Bytes, Env, String};
3
4use crate::AxelarGatewayMessagingClient;
5
6derive_only!();
7
8/// Interface for an Axelar Executable app. Use the [`AxelarExecutable`] derive macro to implement this interface.
9///
10/// **DO NOT IMPLEMENT THIS MANUALLY!**
11pub trait AxelarExecutableInterface: CustomAxelarExecutable + DeriveOnly {
12    /// Return the trusted gateway contract id.
13    fn gateway(env: &Env) -> Address;
14
15    /// Execute a cross-chain message with the given payload. This function must validate that the message is received from the trusted gateway.
16    fn execute(
17        env: &Env,
18        source_chain: String,
19        message_id: String,
20        source_address: String,
21        payload: Bytes,
22    ) -> Result<(), <Self as CustomAxelarExecutable>::Error>;
23}
24
25/// Encapsulates the logic for executing a cross-chain message. This trait must be implemented by a contract to be compatible with the [`AxelarExecutableInterface`].
26///
27/// Do NOT add the implementation of [`CustomAxelarExecutable`] to the public interface of the contract, i.e. do not annotate the `impl` block with `#[contractimpl]`
28pub trait CustomAxelarExecutable {
29    type Error: Into<stellar_axelar_std::Error>;
30
31    /// Custom implementation of the gateway query function that's called by [`AxelarExecutableInterface::gateway`].
32    fn __gateway(env: &Env) -> Address;
33
34    /// Custom implementation of the execute function that's called by [`AxelarExecutableInterface::execute`] after validation has succeeded.
35    /// It is guaranteed that the [`validate_message`] function has already been called when this function is executed.
36    fn __execute(
37        env: &Env,
38        source_chain: String,
39        message_id: String,
40        source_address: String,
41        payload: Bytes,
42    ) -> Result<(), Self::Error>;
43}
44
45/// Validate if a gateway has approved a message.
46/// This is called as part of the generated implementation of [`AxelarExecutableInterface::execute`] before running [`CustomAxelarExecutable::__execute`].
47pub fn validate_message<T: CustomAxelarExecutable>(
48    env: &Env,
49    source_chain: &String,
50    message_id: &String,
51    source_address: &String,
52    payload: &Bytes,
53) -> Result<(), ValidationError> {
54    let gateway = AxelarGatewayMessagingClient::new(env, &T::__gateway(env));
55
56    // Validate that the message was approved by the gateway
57    ensure!(
58        gateway.validate_message(
59            &env.current_contract_address(),
60            source_chain,
61            message_id,
62            source_address,
63            &env.crypto().keccak256(payload).into(),
64        ),
65        ValidationError::NotApproved
66    );
67
68    Ok(())
69}
70
71pub enum ValidationError {
72    NotApproved,
73}