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

test(example): increase ITS coverage #221

Merged
merged 19 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 200 additions & 35 deletions contracts/stellar-example/src/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ use stellar_axelar_gateway::AxelarGatewayClient;
use stellar_axelar_std::address::AddressExt;
use stellar_axelar_std::traits::BytesExt;
use stellar_axelar_std::types::Token;
use stellar_axelar_std::{auth_invocation, events};
use stellar_axelar_std::{assert_contract_err, auth_invocation, events};
use stellar_interchain_token_service::event::TrustedChainSetEvent;
use stellar_interchain_token_service::testutils::{setup_its, setup_its_token};
use stellar_interchain_token_service::InterchainTokenServiceClient;

use crate::contract::ExampleError;
use crate::event::{ExecutedEvent, TokenReceivedEvent};
use crate::{Example, ExampleClient};

Expand All @@ -31,10 +32,10 @@ struct TestConfig<'a> {
app: ExampleClient<'a>,
}

fn setup_app<'a>(env: &Env) -> TestConfig<'a> {
fn setup_app<'a>(env: &Env, chain_name: Option<String>) -> TestConfig<'a> {
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
let (signers, gateway_client) = setup_gateway(env, 0, 5);
let gas_service_client = setup_gas_service(env);
let its_client = setup_its(env, &gateway_client, &gas_service_client);
let its_client = setup_its(env, &gateway_client, &gas_service_client, chain_name);
let app = env.register(
Example,
(
Expand Down Expand Up @@ -66,7 +67,7 @@ fn gmp_example() {
gas_service_client: source_gas_service_client,
app: source_app,
..
} = setup_app(&env);
} = setup_app(&env, None);

// Setup destination Axelar gateway
let destination_chain = String::from_str(&env, DESTINATION_CHAIN_NAME);
Expand All @@ -75,7 +76,7 @@ fn gmp_example() {
gateway_client: destination_gateway_client,
app: destination_app,
..
} = setup_app(&env);
} = setup_app(&env, None);

// Set cross-chain message params
let source_address = source_app.address.to_string();
Expand Down Expand Up @@ -179,76 +180,240 @@ fn gmp_example() {
fn its_example() {
let env = Env::default();

let user = Address::generate(&env).to_string_bytes();
let user = Address::generate(&env);

let original_source_chain = String::from_str(&env, SOURCE_CHAIN_NAME);
let TestConfig {
signers,
gateway_client,
its_client,
app: example_app,
its_client: original_source_its_client,
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
app: original_source_app,
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
..
} = setup_app(&env, Some(original_source_chain.clone()));

let hub_source_chain = original_source_its_client.its_hub_chain_name();
let hub_source_address = original_source_its_client.its_hub_address();
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved

let destination_chain = String::from_str(&env, DESTINATION_CHAIN_NAME);
let TestConfig {
signers: destination_signers,
gateway_client: destination_gateway_client,
its_client: destination_its_client,
app: destination_app,
..
} = setup_app(&env);
let source_chain = its_client.its_hub_chain_name();
let source_address: String = its_client.its_hub_address();
} = setup_app(&env, Some(destination_chain.clone()));

let transfer_amount = 1000;

let amount = 1000;
let token_id = setup_its_token(&env, &its_client, &Address::generate(&env), amount);
let (token_id, token_metadata) =
setup_its_token(&env, &original_source_its_client, &user, transfer_amount);
let token_address = original_source_its_client.token_address(&token_id);

let original_source_chain = String::from_str(&env, "ethereum");
its_client
let gas_token_contract = env.register_stellar_asset_contract_v2(user.clone());
let gas_amount = 50;
let gas_token = Token {
address: gas_token_contract.address(),
amount: gas_amount,
};
StellarAssetClient::new(&env, &gas_token.address)
.mock_all_auths()
.mint(&user, &gas_token.amount);
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved

original_source_its_client
.mock_all_auths()
.set_trusted_chain(&destination_chain);

let original_source_trusted_chain_set_event =
events::fmt_last_emitted_event::<TrustedChainSetEvent>(&env);

destination_its_client
.mock_all_auths()
.set_trusted_chain(&original_source_chain);

let trusted_chain_set_event = events::fmt_last_emitted_event::<TrustedChainSetEvent>(&env);
let destination_trusted_chain_set_event =
events::fmt_last_emitted_event::<TrustedChainSetEvent>(&env);
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved

let data = Address::generate(&env).to_string_bytes();
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved

let msg = stellar_interchain_token_service::types::HubMessage::ReceiveFromHub {
original_source_its_client
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
.mock_all_auths()
.register_canonical_token(&token_address);
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved

original_source_its_client
.mock_all_auths()
.deploy_remote_canonical_token(&token_address, &destination_chain, &user, &gas_token);

let token_asset_client = StellarAssetClient::new(&env, &gas_token.address);
token_asset_client
.mock_all_auths()
.mint(&user, &transfer_amount);
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved

// DeployInterchainToken execute
let deploy_msg = stellar_interchain_token_service::types::HubMessage::ReceiveFromHub {
source_chain: original_source_chain.clone(),
message: stellar_interchain_token_service::types::Message::DeployInterchainToken(
stellar_interchain_token_service::types::DeployInterchainToken {
token_id: token_id.clone(),
name: token_metadata.name.clone(),
symbol: token_metadata.symbol.clone(),
decimals: token_metadata.decimal as u8,
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
minter: None,
},
),
};
let payload = deploy_msg.abi_encode(&env).unwrap();
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved

let message_id = String::from_str(&env, "deploy-message-id");

let deploy_messages = vec![
&env,
Message {
source_chain: hub_source_chain.clone(),
message_id: message_id.clone(),
source_address: hub_source_address.clone(),
contract_address: destination_its_client.address.clone(),
payload_hash: env.crypto().keccak256(&payload).into(),
},
];

let proof = generate_proof(
&env,
get_approve_hash(&env, deploy_messages.clone()),
destination_signers.clone(),
);

destination_gateway_client.approve_messages(&deploy_messages, &proof);

destination_its_client.execute(
&hub_source_chain,
&message_id,
&hub_source_address,
&payload,
);
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
// END DeployInterchainToken execute
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved

original_source_app.mock_all_auths().send_token(
&user,
&token_id,
&destination_chain,
&destination_app.address.to_string_bytes(),
&transfer_amount,
&Some(data.clone()),
&gas_token,
);

// InterchainTransfer execute
let transfer_msg = stellar_interchain_token_service::types::HubMessage::ReceiveFromHub {
source_chain: original_source_chain,
message: stellar_interchain_token_service::types::Message::InterchainTransfer(
stellar_interchain_token_service::types::InterchainTransfer {
token_id: token_id.clone(),
source_address: user,
destination_address: example_app.address.to_string_bytes(),
amount,
source_address: user.to_string_bytes(),
destination_address: destination_app.address.to_string_bytes(),
amount: transfer_amount,
data: Some(data.clone()),
},
),
};
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved
let payload = msg.abi_encode(&env).unwrap();
let payload = transfer_msg.abi_encode(&env).unwrap();

let message_id = String::from_str(&env, "message-id");
let message_id = String::from_str(&env, "transfer-message-id");

let messages = vec![
let transfer_messages = vec![
&env,
Message {
source_chain: source_chain.clone(),
source_chain: hub_source_chain.clone(),
message_id: message_id.clone(),
source_address: source_address.clone(),
contract_address: its_client.address.clone(),
source_address: hub_source_address.clone(),
contract_address: destination_its_client.address.clone(),
payload_hash: env.crypto().keccak256(&payload).into(),
},
];
let proof = generate_proof(&env, get_approve_hash(&env, messages.clone()), signers);

gateway_client.approve_messages(&messages, &proof);
let proof = generate_proof(
&env,
get_approve_hash(&env, transfer_messages.clone()),
destination_signers,
);

destination_gateway_client.approve_messages(&transfer_messages, &proof);

let message_approved_event = events::fmt_last_emitted_event::<MessageApprovedEvent>(&env);

its_client.execute(&source_chain, &message_id, &source_address, &payload);
destination_its_client.execute(
&hub_source_chain,
&message_id,
&hub_source_address,
&payload,
);
// END InterchainTransfer execute
nbayindirli marked this conversation as resolved.
Show resolved Hide resolved

let token_received_event = events::fmt_last_emitted_event::<TokenReceivedEvent>(&env);

goldie::assert!([
trusted_chain_set_event,
destination_trusted_chain_set_event,
original_source_trusted_chain_set_event,
message_approved_event,
token_received_event
]
.join("\n\n"));

let token = token::TokenClient::new(&env, &its_client.token_address(&token_id));
assert_eq!(token.balance(&example_app.address), 0);
let destination_token_client =
token::TokenClient::new(&env, &destination_its_client.token_address(&token_id));
assert_eq!(
destination_token_client.balance(&destination_app.address),
0
);

let recipient = Address::from_string_bytes(&data);
assert_eq!(token.balance(&recipient), amount);

assert_eq!(
destination_token_client.balance(&destination_app.address),
0
);
assert_eq!(
destination_token_client.balance(&recipient),
transfer_amount
);
}

#[test]
fn constructor_succeeds() {
let env = Env::default();

let TestConfig {
gateway_client,
gas_service_client,
its_client,
..
} = setup_app(&env, None);

let contract_id = env.register(
Example,
(
&gateway_client.address,
&gas_service_client.address,
&its_client.address,
),
);
let client = ExampleClient::new(&env, &contract_id);

assert_eq!(client.gateway(), gateway_client.address);
assert_eq!(client.gas_service(), gas_service_client.address);
assert_eq!(client.interchain_token_service(), its_client.address);
}

#[test]
fn execute_fails_with_not_approved() {
let env = Env::default();

let TestConfig { app, .. } = setup_app(&env, None);

let source_chain = String::from_str(&env, "ethereum");
let message_id = String::from_str(&env, "test");
let source_address = String::from_str(&env, "0x123");
let payload = Bytes::from_array(&env, &[1u8; 32]);

assert_contract_err!(
app.try_execute(&source_chain, &message_id, &source_address, &payload),
ExampleError::NotApproved
);
}
32 changes: 21 additions & 11 deletions contracts/stellar-example/src/tests/testdata/its_example.golden
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
TrustedChainSetEvent {
chain: String(ethereum),
chain: String(source),
}

Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMPZO)

trusted_chain_set {
#[topic] chain: String,
}

TrustedChainSetEvent {
chain: String(destination),
}

Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXI7N)
Expand All @@ -11,30 +21,30 @@ trusted_chain_set {
MessageApprovedEvent {
message: Message {
source_chain: String(axelar),
message_id: String(message-id),
message_id: String(transfer-message-id),
source_address: String(its_hub_address),
contract_address: Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXI7N),
payload_hash: BytesN<32>(237, 149, 219, 250, 141, 232, 32, 82, 24, 198, 205, 234, 25, 38, 169, 223, 11, 147, 254, 36, 100, 116, 38, 89, 4, 52, 132, 200, 218, 56, 83, 209),
contract_address: Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMPZO),
payload_hash: BytesN<32>(230, 214, 88, 245, 174, 248, 20, 10, 206, 50, 121, 178, 195, 199, 71, 151, 135, 243, 98, 124, 57, 80, 130, 70, 8, 193, 183, 238, 183, 231, 237, 240),
},
}

Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4)
Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6J5N)

message_approved {
#[topic] message: Message,
}

TokenReceivedEvent {
source_chain: String(ethereum),
message_id: String(message-id),
source_chain: String(source),
message_id: String(transfer-message-id),
source_address: Bytes(67, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 68, 50, 75, 77),
token_id: BytesN<32>(19, 164, 112, 128, 76, 247, 2, 236, 196, 20, 87, 206, 58, 2, 208, 102, 225, 238, 175, 151, 45, 250, 47, 204, 76, 253, 158, 193, 68, 73, 208, 149),
token_address: Contract(CC3SQJDCS3OA77SQI6ODO2FMMQHYS57O352TXNQ7EXE4AXVRPXX3WJ5U),
token_id: BytesN<32>(218, 212, 203, 128, 137, 130, 221, 179, 31, 34, 53, 109, 192, 54, 96, 44, 142, 247, 158, 111, 122, 211, 198, 148, 166, 90, 189, 239, 251, 41, 20, 73),
token_address: Contract(CD7FCTP5NDVVB6SOXIBBX2IBZ4W42IDKI43D653A6ZPSDW4RXRXJXLST),
amount: 1000,
payload: Bytes(67, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 52, 66, 86, 53),
payload: Bytes(67, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 66, 84, 85, 71, 55),
}

Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYRE5)
Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOHR6)

token_received {
#[topic] source_chain: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ fn interchain_transfer_execute_succeeds() {

let amount = 1000;
let deployer = Address::generate(&env);
let token_id = setup_its_token(&env, &client, &deployer, amount);
let (token_id, _) = setup_its_token(&env, &client, &deployer, amount);
let data = Bytes::from_hex(&env, "dead");
let destination_address = executable_id.to_string_bytes();
let original_source_chain = String::from_str(&env, "ethereum");
Expand Down Expand Up @@ -207,7 +207,7 @@ fn interchain_transfer_execute_fails_if_payload_is_len_one() {

let amount = 1000;
let deployer = Address::generate(&env);
let token_id = setup_its_token(&env, &client, &deployer, amount);
let (token_id, _) = setup_its_token(&env, &client, &deployer, amount);
let data_with_len_1 = Bytes::from_slice(&env, &[1]);
let destination_address = executable_id.to_string_bytes();
let original_source_chain = String::from_str(&env, "ethereum");
Expand Down
Loading
Loading