Skip to content

Commit

Permalink
feat(axelar-core-std): query tx hash and nonce from the amplifier con…
Browse files Browse the repository at this point in the history
…tracts (#615)
  • Loading branch information
fish-sammy authored Sep 16, 2024
1 parent 8f410b2 commit 9f3d33f
Show file tree
Hide file tree
Showing 51 changed files with 636 additions and 258 deletions.
25 changes: 25 additions & 0 deletions 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ multisig = { version = "^1.0.0", path = "contracts/multisig" }
multisig-prover = { version = "^1.0.0", path = "contracts/multisig-prover" }
num-traits = { version = "0.2.14", default-features = false }
quote = "1.0.36"
rand = "0.8.5"
report = { version = "^1.0.0", path = "packages/report" }
rewards = { version = "^1.1.0", path = "contracts/rewards" }
router = { version = "^1.0.0", path = "contracts/router" }
Expand All @@ -71,6 +72,7 @@ tokio = "1.38.0"
tokio-stream = "0.1.11"
tokio-util = "0.7.11"
voting-verifier = { version = "^1.0.0", path = "contracts/voting-verifier" }
axelar-core-std = { version = "^1.0.0", path = "packages/axelar-core-std" }

[workspace.lints.clippy]
arithmetic_side_effects = "deny"
Expand Down
2 changes: 1 addition & 1 deletion ampd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ elliptic-curve = "0.13.5"
faux = "0.1.10"
generic-array = "0.14.7"
multisig = { workspace = true, features = ["test", "library"] }
rand = "0.8.5"
rand = { workspace = true }
random-string = "1.0.0"
tokio = { workspace = true, features = ["test-util"] }

Expand Down
3 changes: 3 additions & 0 deletions contracts/axelarnet-gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ optimize = """docker run --rm -v "$(pwd)":/code \
"""

[dependencies]
axelar-core-std = { workspace = true }
axelar-wasm-std = { workspace = true, features = ["derive"] }
client = { workspace = true }
cosmwasm-schema = { workspace = true }
Expand All @@ -51,6 +52,8 @@ thiserror = { workspace = true }
assert_ok = { workspace = true }
cw-multi-test = { workspace = true }
goldie = { workspace = true }
hex = { workspace = true }
rand = { workspace = true }

[lints]
workspace = true
9 changes: 5 additions & 4 deletions contracts/axelarnet-gateway/src/clients/external.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, HexBinary, QuerierWrapper, WasmMsg};
use cosmwasm_std::{Addr, CosmosMsg, HexBinary, QuerierWrapper};
use router_api::{Address, CrossChainId};

/// `AxelarExecutableMsg` is a struct containing the args used by the axelarnet gateway to execute a destination contract on Axelar.
Expand All @@ -20,17 +20,17 @@ enum ExecuteMsg {
}

pub struct Client<'a> {
client: client::Client<'a, ExecuteMsg, ()>,
client: client::ContractClient<'a, ExecuteMsg, ()>,
}

impl<'a> Client<'a> {
pub fn new(querier: QuerierWrapper<'a>, destination: &'a Addr) -> Self {
Client {
client: client::Client::new(querier, destination),
client: client::ContractClient::new(querier, destination),
}
}

pub fn execute(&self, msg: AxelarExecutableMsg) -> WasmMsg {
pub fn execute(&self, msg: AxelarExecutableMsg) -> CosmosMsg {
self.client.execute(&ExecuteMsg::Execute(msg))
}
}
Expand Down Expand Up @@ -64,6 +64,7 @@ mod test {
msg: to_json_binary(&external::ExecuteMsg::Execute(executable_msg)).unwrap(),
funds: vec![],
}
.into()
);
}
}
29 changes: 18 additions & 11 deletions contracts/axelarnet-gateway/src/clients/gateway.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use axelar_wasm_std::vec::VecExt;
use cosmwasm_std::{Addr, HexBinary, WasmMsg};
use cosmwasm_std::{Addr, CosmosMsg, HexBinary};
use error_stack::{Result, ResultExt};
use router_api::{Address, ChainName, CrossChainId, Message};

Expand All @@ -11,14 +11,14 @@ pub enum Error {
QueryChainName(Addr),
}

impl<'a> From<client::Client<'a, ExecuteMsg, QueryMsg>> for Client<'a> {
fn from(client: client::Client<'a, ExecuteMsg, QueryMsg>) -> Self {
impl<'a> From<client::ContractClient<'a, ExecuteMsg, QueryMsg>> for Client<'a> {
fn from(client: client::ContractClient<'a, ExecuteMsg, QueryMsg>) -> Self {
Client { client }
}
}

pub struct Client<'a> {
client: client::Client<'a, ExecuteMsg, QueryMsg>,
client: client::ContractClient<'a, ExecuteMsg, QueryMsg>,
}

impl<'a> Client<'a> {
Expand All @@ -27,19 +27,19 @@ impl<'a> Client<'a> {
destination_chain: ChainName,
destination_address: Address,
payload: HexBinary,
) -> WasmMsg {
) -> CosmosMsg {
self.client.execute(&ExecuteMsg::CallContract {
destination_chain,
destination_address,
payload,
})
}

pub fn execute(&self, cc_id: CrossChainId, payload: HexBinary) -> WasmMsg {
pub fn execute(&self, cc_id: CrossChainId, payload: HexBinary) -> CosmosMsg {
self.client.execute(&ExecuteMsg::Execute { cc_id, payload })
}

pub fn route_messages(&self, msgs: Vec<Message>) -> Option<WasmMsg> {
pub fn route_messages(&self, msgs: Vec<Message>) -> Option<CosmosMsg> {
msgs.to_none_if_empty()
.map(|messages| self.client.execute(&ExecuteMsg::RouteMessages(messages)))
}
Expand All @@ -56,7 +56,9 @@ mod test {
use std::str::FromStr;

use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info, MockQuerier};
use cosmwasm_std::{from_json, to_json_binary, Addr, DepsMut, QuerierWrapper, WasmQuery};
use cosmwasm_std::{
from_json, to_json_binary, Addr, DepsMut, QuerierWrapper, WasmMsg, WasmQuery,
};

use super::*;
use crate::contract::{instantiate, query};
Expand All @@ -65,7 +67,8 @@ mod test {
#[test]
fn chain_name() {
let (querier, _, addr) = setup();
let client: Client = client::Client::new(QuerierWrapper::new(&querier), &addr).into();
let client: Client =
client::ContractClient::new(QuerierWrapper::new(&querier), &addr).into();

assert_eq!(
client.chain_name().unwrap(),
Expand All @@ -76,7 +79,8 @@ mod test {
#[test]
fn call_contract() {
let (querier, _, addr) = setup();
let client: Client = client::Client::new(QuerierWrapper::new(&querier), &addr).into();
let client: Client =
client::ContractClient::new(QuerierWrapper::new(&querier), &addr).into();

let destination_chain: ChainName = "destination-chain".parse().unwrap();
let destination_address: Address = "destination-address".parse().unwrap();
Expand All @@ -100,13 +104,15 @@ mod test {
.unwrap(),
funds: vec![],
}
.into()
);
}

#[test]
fn execute_message() {
let (querier, _, addr) = setup();
let client: Client = client::Client::new(QuerierWrapper::new(&querier), &addr).into();
let client: Client =
client::ContractClient::new(QuerierWrapper::new(&querier), &addr).into();

let payload = HexBinary::from(vec![1, 2, 3]);
let cc_id = CrossChainId::new("source-chain", "message-id").unwrap();
Expand All @@ -120,6 +126,7 @@ mod test {
msg: to_json_binary(&ExecuteMsg::Execute { cc_id, payload }).unwrap(),
funds: vec![],
}
.into()
);
}

Expand Down
4 changes: 2 additions & 2 deletions contracts/axelarnet-gateway/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub fn instantiate(
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
deps: DepsMut,
env: Env,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
Expand All @@ -75,7 +75,7 @@ pub fn execute(
payload,
} => execute::call_contract(
deps.storage,
env.block.height,
deps.querier,
info.sender,
execute::CallContractData {
destination_chain,
Expand Down
44 changes: 21 additions & 23 deletions contracts/axelarnet-gateway/src/contract/execute.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::str::FromStr;

use axelar_core_std::nexus;
use axelar_wasm_std::msg_id::HexTxHashAndEventIndex;
use axelar_wasm_std::{address, FnExt, IntoContractError};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, DepsMut, HexBinary, Response, Storage, Uint256};
use cosmwasm_std::{Addr, DepsMut, HexBinary, QuerierWrapper, Response, Storage};
use error_stack::{bail, ensure, report, Result, ResultExt};
use itertools::Itertools;
use router_api::client::Router;
Expand Down Expand Up @@ -42,6 +43,10 @@ pub enum Error {
InvalidSourceAddress(Addr),
#[error("invalid destination address {0}")]
InvalidDestinationAddress(String),
#[error("failed to query the nexus module")]
Nexus,
#[error("nonce from the nexus module overflowed u32")]
NonceOverflow,
}

#[cw_serde]
Expand All @@ -65,14 +70,24 @@ impl CallContractData {

pub fn call_contract(
storage: &mut dyn Storage,
block_height: u64,
querier: QuerierWrapper,
sender: Addr,
call_contract: CallContractData,
) -> Result<Response, Error> {
let Config { router, chain_name } = state::load_config(storage);

let id = generate_cross_chain_id(storage, block_height, chain_name)
.change_context(Error::CrossChainIdGeneration)?;
let client: nexus::Client = client::CosmosClient::new(querier).into();
let nexus::query::TxHashAndNonceResponse { tx_hash, nonce } =
client.tx_hash_and_nonce().change_context(Error::Nexus)?;

let id = CrossChainId::new(
chain_name,
HexTxHashAndEventIndex::new(
tx_hash,
u32::try_from(nonce).change_context(Error::NonceOverflow)?,
),
)
.change_context(Error::InvalidCrossChainId)?;
let source_address = Address::from_str(sender.as_str())
.change_context(Error::InvalidSourceAddress(sender.clone()))?;
let msg = call_contract.to_message(id, source_address);
Expand All @@ -82,7 +97,7 @@ pub fn call_contract(
.change_context(Error::SaveRoutableMessage)?;

Ok(
route_to_router(storage, &Router { address: router }, vec![msg.clone()])?.add_event(
route_to_router(storage, &Router::new(router), vec![msg.clone()])?.add_event(
AxelarnetGatewayEvent::ContractCalled {
msg,
payload: call_contract.payload,
Expand All @@ -98,7 +113,7 @@ pub fn route_messages(
msgs: Vec<Message>,
) -> Result<Response, Error> {
let Config { chain_name, router } = state::load_config(storage);
let router = Router { address: router };
let router = Router::new(router);

if sender == router.address {
Ok(prepare_msgs_for_execution(storage, chain_name, msgs)?)
Expand Down Expand Up @@ -145,23 +160,6 @@ fn ensure_same_payload_hash(
}
}

fn generate_cross_chain_id(
storage: &mut dyn Storage,
block_height: u64,
chain_name: ChainName,
) -> Result<CrossChainId, Error> {
// TODO: Retrieve the actual tx hash from core, since cosmwasm doesn't provide it.
// Use the block height as the placeholder in the meantime.
let message_id = HexTxHashAndEventIndex {
tx_hash: Uint256::from(block_height).to_be_bytes(),
event_index: state::ROUTABLE_MESSAGES_INDEX
.incr(storage)
.change_context(Error::EventIndex)?,
};

CrossChainId::new(chain_name, message_id).change_context(Error::InvalidCrossChainId)
}

fn panic_if_already_exists(err: &state::Error, cc_id: &CrossChainId) {
if matches!(err, state::Error::MessageAlreadyExists(..)) {
panic!(
Expand Down
2 changes: 0 additions & 2 deletions contracts/axelarnet-gateway/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use axelar_wasm_std::counter::Counter;
use axelar_wasm_std::{FnExt, IntoContractError};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, StdError, Storage};
Expand All @@ -8,7 +7,6 @@ use router_api::{ChainName, CrossChainId, Message};

const CONFIG: Item<Config> = Item::new("config");
const ROUTABLE_MESSAGES: Map<&CrossChainId, Message> = Map::new("routable_messages");
pub const ROUTABLE_MESSAGES_INDEX: Counter<u32> = Counter::new("routable_message_index");
const EXECUTABLE_MESSAGES: Map<&CrossChainId, ExecutableMessage> = Map::new("executable_messages");

#[derive(thiserror::Error, Debug, PartialEq, IntoContractError)]
Expand Down
Loading

0 comments on commit 9f3d33f

Please sign in to comment.