use om_primitives_types::transaction::payload::{TokenBridgeAndMintPayload, TokenBurnAndBridgePayload};
use om_rest_types::{
requests::{TokenBridgeAndMintRequest, TokenBurnAndBridgeRequest},
responses::TransactionResponse,
};
use crate::{
client::{
Client,
config::{
api_path,
endpoints::bridge::{BRIDGE_AND_MINT, BURN_AND_BRIDGE},
},
},
crypto::sign_transaction_payload,
error::Result,
};
impl Client {
pub async fn bridge_and_mint(
&self,
payload: TokenBridgeAndMintPayload,
private_key: &str,
) -> Result<TransactionResponse> {
let signature = sign_transaction_payload(&payload, private_key)?;
let request = TokenBridgeAndMintRequest {
data: payload,
signature,
};
self.post(&api_path(BRIDGE_AND_MINT), &request).await
}
pub async fn burn_and_bridge(
&self,
payload: TokenBurnAndBridgePayload,
private_key: &str,
) -> Result<TransactionResponse> {
let signature = sign_transaction_payload(&payload, private_key)?;
let request = TokenBurnAndBridgeRequest {
data: payload,
signature,
};
self.post(&api_path(BURN_AND_BRIDGE), &request).await
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use alloy_primitives::{Address, Bytes, U256};
use super::*;
use crate::{
NamedChain,
client::config::endpoints::bridge::{BRIDGE_AND_MINT, BURN_AND_BRIDGE},
};
#[test]
fn test_bridge_and_mint_api_path_construction() {
let path = api_path(BRIDGE_AND_MINT);
assert_eq!(path, "/v1/tokens/bridge_and_mint");
}
#[test]
fn test_burn_and_bridge_api_path_construction() {
let path = api_path(BURN_AND_BRIDGE);
assert_eq!(path, "/v1/tokens/burn_and_bridge");
}
#[test]
fn test_token_bridge_and_mint_payload_structure() {
let recipient =
Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0").expect("Test data should be valid");
let token = Address::from_str("0x1234567890abcdef1234567890abcdef12345678").expect("Test data should be valid");
let payload = TokenBridgeAndMintPayload {
chain_id: NamedChain::TESTNET_CHAIN_ID,
nonce: 1,
recipient,
value: U256::from(5000000000000000000u64),
token,
source_chain_id: 1,
source_tx_hash: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef".to_string(),
bridge_metadata: "".to_string(),
};
assert_eq!(payload.chain_id, NamedChain::TESTNET_CHAIN_ID);
assert_eq!(payload.nonce, 1);
assert_eq!(payload.recipient, recipient);
assert_eq!(payload.value, U256::from(5000000000000000000u64));
assert_eq!(payload.token, token);
assert_eq!(payload.source_chain_id, 1);
}
#[test]
fn test_token_burn_and_bridge_payload_structure() {
let sender =
Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0").expect("Test data should be valid");
let token = Address::from_str("0x1234567890abcdef1234567890abcdef12345678").expect("Test data should be valid");
let payload = TokenBurnAndBridgePayload {
chain_id: NamedChain::TESTNET_CHAIN_ID,
nonce: 5,
sender,
value: U256::from(3000000000000000000u64),
token,
destination_chain_id: 1,
destination_address: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd".to_string(),
escrow_fee: U256::from(1000000u64),
bridge_metadata: "".to_string(),
bridge_param: Bytes::default(),
};
assert_eq!(payload.chain_id, NamedChain::TESTNET_CHAIN_ID);
assert_eq!(payload.nonce, 5);
assert_eq!(payload.sender, sender);
assert_eq!(payload.value, U256::from(3000000000000000000u64));
assert_eq!(payload.token, token);
assert_eq!(payload.destination_chain_id, 1);
}
#[test]
fn test_bridge_and_mint_payload_alloy_rlp_encoding() {
use alloy_rlp::Encodable as AlloyEncodable;
let payload = TokenBridgeAndMintPayload {
chain_id: NamedChain::TESTNET_CHAIN_ID,
nonce: 1,
recipient: Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")
.expect("Test data should be valid"),
value: U256::from(5000000000000000000u64),
token: Address::from_str("0x1234567890abcdef1234567890abcdef12345678").expect("Test data should be valid"),
source_chain_id: 1,
source_tx_hash: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef".to_string(),
bridge_metadata: "".to_string(),
};
let mut encoded = Vec::new();
payload.encode(&mut encoded);
assert!(!encoded.is_empty());
assert!(encoded.len() > 100);
}
#[test]
fn test_burn_and_bridge_payload_alloy_rlp_encoding() {
use alloy_rlp::Encodable as AlloyEncodable;
let payload = TokenBurnAndBridgePayload {
chain_id: NamedChain::TESTNET_CHAIN_ID,
nonce: 5,
sender: Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0").expect("Test data should be valid"),
value: U256::from(3000000000000000000u64),
token: Address::from_str("0x1234567890abcdef1234567890abcdef12345678").expect("Test data should be valid"),
destination_chain_id: 1,
destination_address: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd".to_string(),
escrow_fee: U256::from(1000000u64),
bridge_metadata: "".to_string(),
bridge_param: Bytes::default(),
};
let mut encoded = Vec::new();
payload.encode(&mut encoded);
assert!(!encoded.is_empty());
assert!(encoded.len() > 100);
}
#[test]
fn test_bridge_payloads_different_encodings() {
use alloy_rlp::Encodable as AlloyEncodable;
let payload1 = TokenBridgeAndMintPayload {
chain_id: NamedChain::TESTNET_CHAIN_ID,
nonce: 1,
recipient: Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")
.expect("Test data should be valid"),
value: U256::from(5000000000000000000u64),
token: Address::from_str("0x1234567890abcdef1234567890abcdef12345678").expect("Test data should be valid"),
source_chain_id: 1,
source_tx_hash: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef".to_string(),
bridge_metadata: "".to_string(),
};
let payload2 = TokenBridgeAndMintPayload {
chain_id: NamedChain::TESTNET_CHAIN_ID,
nonce: 2,
recipient: Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")
.expect("Test data should be valid"),
value: U256::from(5000000000000000000u64),
token: Address::from_str("0x1234567890abcdef1234567890abcdef12345678").expect("Test data should be valid"),
source_chain_id: 1,
source_tx_hash: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef".to_string(),
bridge_metadata: "".to_string(),
};
let mut encoded1 = Vec::new();
payload1.encode(&mut encoded1);
let mut encoded2 = Vec::new();
payload2.encode(&mut encoded2);
assert_ne!(encoded1, encoded2);
}
#[test]
fn test_bridge_payload_encoding_deterministic() {
use alloy_rlp::Encodable as AlloyEncodable;
let payload = TokenBurnAndBridgePayload {
chain_id: NamedChain::TESTNET_CHAIN_ID,
nonce: 1,
sender: Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0").expect("Test data should be valid"),
value: U256::from(1000000000000000000u64),
token: Address::from_str("0x1234567890abcdef1234567890abcdef12345678").expect("Test data should be valid"),
destination_chain_id: 1,
destination_address: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd".to_string(),
escrow_fee: U256::from(1000000u64),
bridge_metadata: "".to_string(),
bridge_param: Bytes::default(),
};
let mut encoded1 = Vec::new();
payload.encode(&mut encoded1);
let mut encoded2 = Vec::new();
payload.encode(&mut encoded2);
assert_eq!(encoded1, encoded2);
}
#[test]
fn test_bridge_request_structure() {
use om_rest_types::common::RestSignature;
let payload = TokenBridgeAndMintPayload {
chain_id: NamedChain::TESTNET_CHAIN_ID,
nonce: 1,
recipient: Address::from_str("0x742d35Cc6634C0532925a3b8D91D6F4A81B8Cbc0")
.expect("Test data should be valid"),
value: U256::from(5000000000000000000u64),
token: Address::from_str("0x1234567890abcdef1234567890abcdef12345678").expect("Test data should be valid"),
source_chain_id: 1,
source_tx_hash: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef".to_string(),
bridge_metadata: "".to_string(),
};
let signature = RestSignature::new(
U256::from_str("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
.expect("Test data should be valid"),
U256::from_str("0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321")
.expect("Test data should be valid"),
27,
);
let request = TokenBridgeAndMintRequest {
data: payload.clone(),
signature: signature.clone(),
};
assert_eq!(request.data.chain_id, NamedChain::TESTNET_CHAIN_ID);
assert_eq!(request.signature.v, 27);
}
}