Skip to content

Commit

Permalink
Merge pull request #503 from movementlabsxyz/andygolay/finish-counter…
Browse files Browse the repository at this point in the history
…party-integration-tests

Stronger assertions for counterparty integration tests
  • Loading branch information
andygolay authored Sep 4, 2024
2 parents 63790a6 + 16e8c58 commit 3aa1a77
Show file tree
Hide file tree
Showing 20 changed files with 403 additions and 143 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

6 changes: 4 additions & 2 deletions protocol-units/bridge/chains/ethereum/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,8 @@ impl BridgeContractInitiator for EthClient {
hash_lock: HashLock(eth_details.hash_lock),
//@TODO unit test these wrapping to check for any nasty side effects.
time_lock: TimeLock(eth_details.time_lock.wrapping_to::<u64>()),
amount: Amount(AssetType::EthAndWeth((0, eth_details.amount.wrapping_to::<u64>()))),
amount: Amount(AssetType::EthAndWeth((0,eth_details.amount.wrapping_to::<u64>()))),
state: eth_details.state
}))
}
}
Expand Down Expand Up @@ -465,7 +466,8 @@ impl BridgeContractCounterparty for EthClient {
recipient_address: RecipientAddress(eth_details.recipient.to_vec()),
hash_lock: HashLock(eth_details.hash_lock),
time_lock: TimeLock(eth_details.time_lock.wrapping_to::<u64>()),
amount: Amount(AssetType::EthAndWeth((0, eth_details.amount.wrapping_to::<u64>()))),
amount: Amount(AssetType::EthAndWeth((0,eth_details.amount.wrapping_to::<u64>()))),
state: eth_details.state
}))
}
}
Expand Down
5 changes: 5 additions & 0 deletions protocol-units/bridge/chains/ethereum/src/event_logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ fn decode_log_data(
.as_uint()
.map(|(u, _)| u.into())
.ok_or_else(|| anyhow::anyhow!("Failed to decode TimeLock"))?;
let state = decoded.indexed.get(6)
.and_then(|val| val.as_uint())
.and_then(|(u, _)| u.try_into().ok()) // Try converting to u8
.ok_or_else(|| anyhow::anyhow!("Failed to decode state as u8"))?;

let details: BridgeTransferDetails<EthAddress, EthHash> = BridgeTransferDetails {
bridge_transfer_id: BridgeTransferId(bridge_transfer_id),
Expand All @@ -223,6 +227,7 @@ fn decode_log_data(
hash_lock: HashLock(hash_lock),
time_lock,
amount,
state
};

Ok(BridgeContractInitiatorEvent::Initiated(details))
Expand Down
1 change: 1 addition & 0 deletions protocol-units/bridge/chains/movement/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ path = "src/lib.rs"

[dependencies]
aptos-sdk = { workspace = true }
aptos-api-types = { workspace = true }
aptos-types = { workspace = true }
aptos-api = { workspace = true }
async-trait = { workspace = true }
Expand Down
120 changes: 93 additions & 27 deletions protocol-units/bridge/chains/movement/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
use crate::utils::MovementAddress;
use anyhow::Result;
use aptos_api::accounts::Account;
use aptos_sdk::{
move_types::language_storage::TypeTag,
rest_client::{Client, FaucetClient},
move_types::{identifier::Identifier, language_storage::{ModuleId, TypeTag}},
rest_client::{Client, FaucetClient, Response},
types::LocalAccount,
};
use aptos_api_types::{EntryFunctionId, MoveModuleId, ViewFunction, ViewRequest};
use aptos_types::account_address::AccountAddress;
use bridge_shared::{
bridge_contracts::{
BridgeContractCounterparty, BridgeContractCounterpartyError,
BridgeContractCounterpartyResult,
},
types::{
Amount, BridgeTransferDetails, BridgeTransferId, HashLock, HashLockPreImage,
InitiatorAddress, RecipientAddress, TimeLock,
Amount, AssetType, BridgeTransferDetails, BridgeTransferId, HashLock, HashLockPreImage, InitiatorAddress, RecipientAddress, TimeLock
},
};
use hex::{decode, FromHex};
use rand::prelude::*;
use rand::Rng;
use serde::Serialize;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::{env, fs, io::{Read, Write}, path::{Path, PathBuf}, process::{Command, Stdio}};
use std::str::FromStr;
use std::sync::{Arc, RwLock};
Expand Down Expand Up @@ -74,7 +77,7 @@ impl Config {
#[derive(Clone)]
pub struct MovementClient {
///Address of the counterparty moduke
counterparty_address: AccountAddress,
pub counterparty_address: AccountAddress,
///Address of the initiator module
initiator_address: Vec<u8>,
///The Apotos Rest Client
Expand Down Expand Up @@ -458,13 +461,18 @@ impl BridgeContractCounterparty for MovementClient {
amount: Amount,
) -> BridgeContractCounterpartyResult<()> {

let amount_value = match amount.0 {
AssetType::Moveth(value) => value,
_ => return Err(BridgeContractCounterpartyError::SerializationError),
};

let args = vec![
utils::serialize_vec(&initiator.0)?,
utils::serialize_vec(&bridge_transfer_id.0[..])?,
utils::serialize_vec(&hash_lock.0[..])?,
utils::serialize_u64(&time_lock.0)?,
utils::serialize_vec(&recipient.0.0.to_vec())?,
utils::serialize_u64(&amount.moveth())?,
utils::serialize_vec(&initiator.0)?,
utils::serialize_vec(&bridge_transfer_id.0[..])?,
utils::serialize_vec(&hash_lock.0[..])?,
utils::serialize_u64(&time_lock.0)?,
utils::serialize_vec(&recipient.0.0)?,
utils::serialize_u64(&amount_value)?
];

let payload = utils::make_aptos_payload(
Expand All @@ -475,13 +483,14 @@ impl BridgeContractCounterparty for MovementClient {
args,
);

let _ = utils::send_and_confirm_aptos_transaction(
let result = utils::send_and_confirm_aptos_transaction(
&self.rest_client,
self.signer.as_ref(),
payload,
)
.await
.map_err(|_| BridgeContractCounterpartyError::LockTransferError);

Ok(())
}

Expand All @@ -503,50 +512,107 @@ impl BridgeContractCounterparty for MovementClient {
args2,
);

self.signer.increment_sequence_number();

let _ = utils::send_and_confirm_aptos_transaction(
let result = utils::send_and_confirm_aptos_transaction(
&self.rest_client,
self.signer.as_ref(),
payload,
)
.await
.map_err(|_| BridgeContractCounterpartyError::CompleteTransferError);

Ok(())
}

async fn abort_bridge_transfer(
&mut self,
bridge_transfer_id: BridgeTransferId<Self::Hash>,
) -> BridgeContractCounterpartyResult<()> {
let args = vec![
utils::serialize_vec(&self.signer.address().to_vec())?,
utils::serialize_vec(&bridge_transfer_id.0)?,
let args3 = vec![
utils::serialize_vec(&bridge_transfer_id.0[..])?,
];
let payload = utils::make_aptos_payload(
self.counterparty_address,
COUNTERPARTY_MODULE_NAME,
"abort_bridge_transfer",
self.counterparty_type_args(Call::Abort),
args,
Vec::new(),
args3,
);
let _ = utils::send_and_confirm_aptos_transaction(
let result = utils::send_and_confirm_aptos_transaction(
&self.rest_client,
self.signer.as_ref(),
payload,
)
.await
.map_err(|_| BridgeContractCounterpartyError::AbortTransferError);

println!("Abort bridge transfer result: {:?}", &result);
Ok(())
}

async fn get_bridge_transfer_details(
&mut self,
_bridge_transfer_id: BridgeTransferId<Self::Hash>,
) -> BridgeContractCounterpartyResult<Option<BridgeTransferDetails<Self::Address, Self::Hash>>>
{
todo!();
}
bridge_transfer_id: BridgeTransferId<[u8; 32]>,
) -> Result<Option<BridgeTransferDetails<MovementAddress, [u8; 32]>>, BridgeContractCounterpartyError> {
// Convert the bridge_transfer_id to a hex string
let bridge_transfer_id_hex = format!("0x{}", hex::encode(bridge_transfer_id.0));

// Construct the ViewRequest
let view_request = ViewRequest {
function: EntryFunctionId {
module: MoveModuleId {
address: self.counterparty_address.clone().into(),
name: aptos_api_types::IdentifierWrapper(Identifier::new("atomic_bridge_counterparty")
.map_err(|_| BridgeContractCounterpartyError::FunctionViewError)?),
},
name: aptos_api_types::IdentifierWrapper(Identifier::new("bridge_transfers")
.map_err(|_| BridgeContractCounterpartyError::FunctionViewError)?),
},
type_arguments: vec![],
arguments: vec![serde_json::json!(bridge_transfer_id_hex)],
};

// Send the request to the "/view" endpoint using JSON
let response: Response<Vec<serde_json::Value>> = self.rest_client
.view(&view_request, None)
.await
.map_err(|_| BridgeContractCounterpartyError::CallError)?;

// Extract and parse the response
let values = response.inner();

if values.len() != 6 {
return Err(BridgeContractCounterpartyError::InvalidResponseLength);
}

let originator = utils::val_as_str(values.get(0))?;
let recipient = utils::val_as_str(values.get(1))?;
let amount = utils::val_as_str(values.get(2))?.parse::<u64>().map_err(|_| BridgeContractCounterpartyError::SerializationError)?;
let hash_lock = utils::val_as_str(values.get(3))?;
let time_lock = utils::val_as_str(values.get(4))?.parse::<u64>().map_err(|_| BridgeContractCounterpartyError::SerializationError)?;
let state = utils::val_as_u64(values.get(5))? as u8;

// Convert the originator, recipient, and hash_lock
let originator_address = AccountAddress::from_hex_literal(originator)
.map_err(|_| BridgeContractCounterpartyError::SerializationError)?;
let recipient_address_bytes = hex::decode(&recipient[2..])
.map_err(|_| BridgeContractCounterpartyError::SerializationError)?;
let hash_lock_array: [u8; 32] = hex::decode(&hash_lock[2..])
.map_err(|_| BridgeContractCounterpartyError::SerializationError)?
.try_into()
.map_err(|_| BridgeContractCounterpartyError::SerializationError)?;

// Create the BridgeTransferDetails struct
let details: BridgeTransferDetails<MovementAddress, [u8; 32]> = BridgeTransferDetails {
bridge_transfer_id,
initiator_address: InitiatorAddress(MovementAddress(originator_address)),
recipient_address: RecipientAddress(recipient_address_bytes),
amount: Amount(AssetType::Moveth(amount)),
hash_lock: HashLock(hash_lock_array),
time_lock: TimeLock(time_lock),
state,
};
Ok(Some(details))
}
}

impl MovementClient {
Expand Down
23 changes: 19 additions & 4 deletions protocol-units/bridge/chains/movement/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use aptos_sdk::{
};
use bridge_shared::bridge_contracts::BridgeContractCounterpartyError;
use derive_new::new;
use serde_json::Value;
use tracing::log::{info, debug};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
Expand Down Expand Up @@ -127,12 +128,16 @@ pub async fn send_and_confirm_aptos_transaction(

let signed_tx = signer.sign_transaction(raw_tx);

debug!("Signed TX: {:?}", signed_tx);

let response = rest_client
.submit_and_wait(&signed_tx)
.await
.map_err(|e| e.to_string())? // Convert the error to a String directly
.map_err(|e| e.to_string())?
.into_inner();

debug!("Response: {:?}", response);

match &response {
Transaction::UserTransaction(user_txn) => {
assert!(
Expand All @@ -147,12 +152,22 @@ pub async fn send_and_confirm_aptos_transaction(
Ok(response)
}

pub fn val_as_str(value: Option<&Value>) -> Result<&str, BridgeContractCounterpartyError> {
value.as_ref().and_then(|v| v.as_str()).ok_or(BridgeContractCounterpartyError::SerializationError)
}

pub fn val_as_u64(value: Option<&Value>) -> Result<u64, BridgeContractCounterpartyError> {
value
.as_ref()
.and_then(|v| v.as_u64())
.ok_or(BridgeContractCounterpartyError::SerializationError)
}

pub fn serialize_u64(value: &u64) -> Result<Vec<u8>, BridgeContractCounterpartyError> {
bcs::to_bytes(&value.to_le_bytes())
.map_err(|_| BridgeContractCounterpartyError::SerializationError)
bcs::to_bytes(value).map_err(|_| BridgeContractCounterpartyError::SerializationError)
}

pub fn serialize_vec(value: &[u8]) -> Result<Vec<u8>, BridgeContractCounterpartyError> {
pub fn serialize_vec<T: serde::Serialize + ?Sized>(value: &T) -> Result<Vec<u8>, BridgeContractCounterpartyError> {
bcs::to_bytes(value).map_err(|_| BridgeContractCounterpartyError::SerializationError)
}

Expand Down
Loading

0 comments on commit 3aa1a77

Please sign in to comment.