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}