Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
32 changes: 32 additions & 0 deletions Cargo.lock

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

81 changes: 81 additions & 0 deletions contracts/bridge/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Error types for the bridge contract (Issue #101 - extracted from lib.rs)

#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum Error {
Unauthorized,
TokenNotFound,
InvalidChain,
BridgeNotSupported,
InsufficientSignatures,
RequestExpired,
AlreadySigned,
InvalidRequest,
BridgePaused,
InvalidMetadata,
DuplicateRequest,
GasLimitExceeded,
}

impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Error::Unauthorized => write!(f, "Caller is not authorized"),
Error::TokenNotFound => write!(f, "Token does not exist"),
Error::InvalidChain => write!(f, "Invalid chain ID"),
Error::BridgeNotSupported => write!(f, "Bridge not supported for this token"),
Error::InsufficientSignatures => write!(f, "Insufficient signatures collected"),
Error::RequestExpired => write!(f, "Bridge request has expired"),
Error::AlreadySigned => write!(f, "Already signed this request"),
Error::InvalidRequest => write!(f, "Invalid bridge request"),
Error::BridgePaused => write!(f, "Bridge operations are paused"),
Error::InvalidMetadata => write!(f, "Invalid metadata"),
Error::DuplicateRequest => write!(f, "Duplicate bridge request"),
Error::GasLimitExceeded => write!(f, "Gas limit exceeded"),
}
}
}

impl ContractError for Error {
fn error_code(&self) -> u32 {
match self {
Error::Unauthorized => bridge_codes::BRIDGE_UNAUTHORIZED,
Error::TokenNotFound => bridge_codes::BRIDGE_TOKEN_NOT_FOUND,
Error::InvalidChain => bridge_codes::BRIDGE_INVALID_CHAIN,
Error::BridgeNotSupported => bridge_codes::BRIDGE_NOT_SUPPORTED,
Error::InsufficientSignatures => bridge_codes::BRIDGE_INSUFFICIENT_SIGNATURES,
Error::RequestExpired => bridge_codes::BRIDGE_REQUEST_EXPIRED,
Error::AlreadySigned => bridge_codes::BRIDGE_ALREADY_SIGNED,
Error::InvalidRequest => bridge_codes::BRIDGE_INVALID_REQUEST,
Error::BridgePaused => bridge_codes::BRIDGE_PAUSED,
Error::InvalidMetadata => bridge_codes::BRIDGE_INVALID_METADATA,
Error::DuplicateRequest => bridge_codes::BRIDGE_DUPLICATE_REQUEST,
Error::GasLimitExceeded => bridge_codes::BRIDGE_GAS_LIMIT_EXCEEDED,
}
}

fn error_description(&self) -> &'static str {
match self {
Error::Unauthorized => "Caller does not have permission to perform this operation",
Error::TokenNotFound => "The specified token does not exist",
Error::InvalidChain => "The destination chain ID is invalid",
Error::BridgeNotSupported => "Cross-chain bridging is not supported for this token",
Error::InsufficientSignatures => {
"Not enough signatures collected for bridge operation"
}
Error::RequestExpired => {
"The bridge request has expired and can no longer be executed"
}
Error::AlreadySigned => "You have already signed this bridge request",
Error::InvalidRequest => "The bridge request is invalid or malformed",
Error::BridgePaused => "Bridge operations are temporarily paused",
Error::InvalidMetadata => "The token metadata is invalid",
Error::DuplicateRequest => "A bridge request with these parameters already exists",
Error::GasLimitExceeded => "The operation exceeded the gas limit",
}
}

fn error_category(&self) -> ErrorCategory {
ErrorCategory::Bridge
}
}
190 changes: 2 additions & 188 deletions contracts/bridge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,98 +11,7 @@ use scale_info::prelude::vec::Vec;
mod bridge {
use super::*;

/// Error types for the bridge contract
#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum Error {
/// Caller is not authorized
Unauthorized,
/// Token does not exist
TokenNotFound,
/// Invalid chain ID
InvalidChain,
/// Bridge not supported for this token
BridgeNotSupported,
/// Insufficient signatures collected
InsufficientSignatures,
/// Bridge request has expired
RequestExpired,
/// Already signed this request
AlreadySigned,
/// Invalid bridge request
InvalidRequest,
/// Bridge operations are paused
BridgePaused,
/// Invalid metadata
InvalidMetadata,
/// Duplicate bridge request
DuplicateRequest,
/// Gas limit exceeded
GasLimitExceeded,
}

impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Error::Unauthorized => write!(f, "Caller is not authorized"),
Error::TokenNotFound => write!(f, "Token does not exist"),
Error::InvalidChain => write!(f, "Invalid chain ID"),
Error::BridgeNotSupported => write!(f, "Bridge not supported for this token"),
Error::InsufficientSignatures => write!(f, "Insufficient signatures collected"),
Error::RequestExpired => write!(f, "Bridge request has expired"),
Error::AlreadySigned => write!(f, "Already signed this request"),
Error::InvalidRequest => write!(f, "Invalid bridge request"),
Error::BridgePaused => write!(f, "Bridge operations are paused"),
Error::InvalidMetadata => write!(f, "Invalid metadata"),
Error::DuplicateRequest => write!(f, "Duplicate bridge request"),
Error::GasLimitExceeded => write!(f, "Gas limit exceeded"),
}
}
}

impl ContractError for Error {
fn error_code(&self) -> u32 {
match self {
Error::Unauthorized => bridge_codes::BRIDGE_UNAUTHORIZED,
Error::TokenNotFound => bridge_codes::BRIDGE_TOKEN_NOT_FOUND,
Error::InvalidChain => bridge_codes::BRIDGE_INVALID_CHAIN,
Error::BridgeNotSupported => bridge_codes::BRIDGE_NOT_SUPPORTED,
Error::InsufficientSignatures => bridge_codes::BRIDGE_INSUFFICIENT_SIGNATURES,
Error::RequestExpired => bridge_codes::BRIDGE_REQUEST_EXPIRED,
Error::AlreadySigned => bridge_codes::BRIDGE_ALREADY_SIGNED,
Error::InvalidRequest => bridge_codes::BRIDGE_INVALID_REQUEST,
Error::BridgePaused => bridge_codes::BRIDGE_PAUSED,
Error::InvalidMetadata => bridge_codes::BRIDGE_INVALID_METADATA,
Error::DuplicateRequest => bridge_codes::BRIDGE_DUPLICATE_REQUEST,
Error::GasLimitExceeded => bridge_codes::BRIDGE_GAS_LIMIT_EXCEEDED,
}
}

fn error_description(&self) -> &'static str {
match self {
Error::Unauthorized => "Caller does not have permission to perform this operation",
Error::TokenNotFound => "The specified token does not exist",
Error::InvalidChain => "The destination chain ID is invalid",
Error::BridgeNotSupported => "Cross-chain bridging is not supported for this token",
Error::InsufficientSignatures => {
"Not enough signatures collected for bridge operation"
}
Error::RequestExpired => {
"The bridge request has expired and can no longer be executed"
}
Error::AlreadySigned => "You have already signed this bridge request",
Error::InvalidRequest => "The bridge request is invalid or malformed",
Error::BridgePaused => "Bridge operations are temporarily paused",
Error::InvalidMetadata => "The token metadata is invalid",
Error::DuplicateRequest => "A bridge request with these parameters already exists",
Error::GasLimitExceeded => "The operation exceeded the gas limit",
}
}

fn error_category(&self) -> ErrorCategory {
ErrorCategory::Bridge
}
}
include!("errors.rs");

/// Bridge contract for cross-chain property token transfers
#[ink(storage)]
Expand Down Expand Up @@ -774,100 +683,5 @@ mod bridge {
}
}

// Unit tests
#[cfg(test)]
mod tests {
use super::*;
use ink::env::{test, DefaultEnvironment};

fn setup_bridge() -> PropertyBridge {
let supported_chains = vec![1, 2, 3];
PropertyBridge::new(supported_chains, 2, 5, 100, 500000)
}

#[ink::test]
fn test_constructor_works() {
let bridge = setup_bridge();
let config = bridge.get_config();
assert_eq!(config.min_signatures_required, 2);
assert_eq!(config.max_signatures_required, 5);
}

#[ink::test]
fn test_initiate_bridge_multisig() {
let mut bridge = setup_bridge();
let accounts = test::default_accounts::<DefaultEnvironment>();
test::set_caller::<DefaultEnvironment>(accounts.alice);

let metadata = PropertyMetadata {
location: String::from("Test Property"),
size: 1000,
legal_description: String::from("Test"),
valuation: 100000,
documents_url: String::from("ipfs://test"),
};

let result = bridge.initiate_bridge_multisig(1, 2, accounts.bob, 2, Some(50), metadata);
assert!(result.is_ok());
}

#[ink::test]
fn test_sign_bridge_request() {
let mut bridge = setup_bridge();
let accounts = test::default_accounts::<DefaultEnvironment>();

// First create a request
test::set_caller::<DefaultEnvironment>(accounts.alice);
let metadata = PropertyMetadata {
location: String::from("Test Property"),
size: 1000,
legal_description: String::from("Test"),
valuation: 100000,
documents_url: String::from("ipfs://test"),
};

let request_id = bridge
.initiate_bridge_multisig(1, 2, accounts.bob, 2, Some(50), metadata)
.expect("Bridge initiation should succeed in test");

// Now sign it as a bridge operator
let accounts = test::default_accounts::<DefaultEnvironment>();
test::set_caller::<DefaultEnvironment>(accounts.alice); // Use default admin account
let result = bridge.sign_bridge_request(request_id, true);
assert!(result.is_ok());
}

#[ink::test]
fn test_cross_chain_trade_lifecycle() {
let mut bridge = setup_bridge();
let accounts = test::default_accounts::<DefaultEnvironment>();
test::set_caller::<DefaultEnvironment>(accounts.bob);

let trade_id = bridge
.register_cross_chain_trade(9, Some(7), 2, accounts.charlie, 50_000, 49_000)
.expect("cross-chain trade registration should succeed");
let trade = bridge
.get_cross_chain_trade(trade_id)
.expect("trade should be stored");
assert_eq!(trade.status, CrossChainTradeStatus::Pending);
assert_eq!(trade.destination_chain, 2);

bridge
.attach_bridge_request_to_trade(trade_id, 33)
.expect("trader can attach bridge request");
let attached = bridge
.get_cross_chain_trade(trade_id)
.expect("attached trade should exist");
assert_eq!(attached.bridge_request_id, Some(33));

test::set_caller::<DefaultEnvironment>(accounts.alice);
bridge
.settle_cross_chain_trade(trade_id)
.expect("admin can settle trade");
let settled = bridge
.get_cross_chain_trade(trade_id)
.expect("settled trade should exist");
assert_eq!(settled.status, CrossChainTradeStatus::Settled);
}
}
include!("tests.rs");
}
Loading
Loading