From 9bb179d52dfcdbacb9109c6d777a266645098fbf Mon Sep 17 00:00:00 2001 From: AOXC Date: Tue, 10 Mar 2026 14:28:03 +0300 Subject: [PATCH 1/3] aoxc (#62) * Merge pull request #59 from aoxc/main (#60) aoxc * Merge pull request #59 from aoxc/main (#61) From 89a1f8f1081df0e2ead46c9f003e6c7a1a2203b2 Mon Sep 17 00:00:00 2001 From: AOXC Date: Wed, 11 Mar 2026 19:02:20 +0300 Subject: [PATCH 2/3] Expand bridge payload compatibility for EVM/Cardano/Web domains (#63) --- README.md | 1 + docs/COMPATIBILITY_MATRIX.md | 35 ++ docs/SPEC.md | 5 +- sources/bridge_payload.move | 45 +- tests/full_flow_tests.move | 1155 +--------------------------------- 5 files changed, 83 insertions(+), 1158 deletions(-) create mode 100644 docs/COMPATIBILITY_MATRIX.md diff --git a/README.md b/README.md index 08199aa..48fc218 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ Key documents include: - future readiness plan (audit closure + crypto agility roadmap) - code audit report (module-by-module findings and action plan) - architecture alignment (Sui-first execution + XLayer interoperability fit) +- compatibility matrix (EVM + Cardano + Web relay domain mapping) - production-ready report (gas/object/web4 compatibility scoring) --- diff --git a/docs/COMPATIBILITY_MATRIX.md b/docs/COMPATIBILITY_MATRIX.md new file mode 100644 index 0000000..d438bfb --- /dev/null +++ b/docs/COMPATIBILITY_MATRIX.md @@ -0,0 +1,35 @@ +# AOXC Compatibility Matrix + +Bu doküman, `aoxcon-move` payload katmanının çoklu domain uyumluluk yüzeyini özetler. + +## Bridge Envelope Domain IDs + +`bridge_payload::BridgePayload.evm_chain_id` alanı geriye dönük uyumluluk için aynı isimde tutulur; ancak pratikte **genel domain/network kimliği** olarak değerlendirilir. + +### Supported Domains + +- **XLayer / EVM** + - XLayer mainnet: `196` + - XLayer testnet: `195` + - Ethereum mainnet: `1` + - Base mainnet: `8453` + - Arbitrum One: `42161` +- **Cardano** + - Mainnet network magic: `764824073` + - Preprod network magic: `1` +- **Web Relay** + - Production domain: `90001` + - Staging domain: `90002` + +## Contract-Level Guarantees + +- Şema sürümü (`schema_version`) zorunlu doğrulanır. +- Domain/network id allowlist dışında ise işlem `E_CHAIN_ID_INVALID` ile abort eder. +- `target_module` + `kind` kombinasyonu whitelist dışına çıkamaz. +- `sender` 20-byte ve all-zero olamaz; proof root boş olamaz. + +## Integration Notes + +- EVM tarafı için chain-id tabanlı yönlendirme doğrudan uyumludur. +- Cardano ve web relay tarafında aynı envelope kullanılarak cross-stack parser sadeleştirilir. +- İmzacı/verifier katmanında domain’e özel doğrulama (örn. Cardano witness/finality) üst katmanda eklenmelidir. diff --git a/docs/SPEC.md b/docs/SPEC.md index 1f79a11..ae61bab 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -62,9 +62,10 @@ - Bridge commands must target the active quorum epoch. - Bridge command envelope `target` must match typed payload target module. -### 1.11 XLayer Compatibility Invariants +### 1.11 Multi-Domain Compatibility Invariants - Payload `schema_version` must be supported. -- `evm_chain_id` must match configured XLayer chain id. +- Envelope `evm_chain_id` field is treated as a generic domain/network id and must be in the allowlist. +- Supported families: XLayer/EVM ids, Cardano network magics, and web relay domain ids. - `target_module` must be whitelisted per action kind. ### 1.12 Phase-5 Economy Invariants diff --git a/sources/bridge_payload.move b/sources/bridge_payload.move index a2458b3..01719ef 100644 --- a/sources/bridge_payload.move +++ b/sources/bridge_payload.move @@ -5,8 +5,21 @@ module aoxc::bridge_payload { use aoxc::errors; const SCHEMA_V1: u16 = 1; + + /// EVM family chain ids. const XLAYER_MAINNET_CHAIN_ID: u64 = 196; const XLAYER_TESTNET_CHAIN_ID: u64 = 195; + const ETHEREUM_MAINNET_CHAIN_ID: u64 = 1; + const BASE_MAINNET_CHAIN_ID: u64 = 8453; + const ARBITRUM_ONE_CHAIN_ID: u64 = 42161; + + /// Cardano network-magics represented in the same u64 field. + const CARDANO_MAINNET_NETWORK_MAGIC: u64 = 764824073; + const CARDANO_PREPROD_NETWORK_MAGIC: u64 = 1; + + /// Off-chain web relay lanes (domain ids in chain-id field for envelope compatibility). + const WEB_RELAY_PROD_DOMAIN_ID: u64 = 90_001; + const WEB_RELAY_STAGE_DOMAIN_ID: u64 = 90_002; const KIND_SYSTEM_HALT: u8 = 1; const KIND_SYSTEM_RESUME: u8 = 2; @@ -80,7 +93,6 @@ module aoxc::bridge_payload { proof_root: vector, } - /// Intent-based command envelope: define expected outcome and constraints. public struct IntentPayload has copy, drop, store { schema_version: u16, evm_chain_id: u64, @@ -97,9 +109,20 @@ module aoxc::bridge_payload { assert!(version == SCHEMA_V1, errors::E_SCHEMA_VERSION); } + public fun is_supported_chain_id(chain_id: u64): bool { + chain_id == XLAYER_MAINNET_CHAIN_ID + || chain_id == XLAYER_TESTNET_CHAIN_ID + || chain_id == ETHEREUM_MAINNET_CHAIN_ID + || chain_id == BASE_MAINNET_CHAIN_ID + || chain_id == ARBITRUM_ONE_CHAIN_ID + || chain_id == CARDANO_MAINNET_NETWORK_MAGIC + || chain_id == CARDANO_PREPROD_NETWORK_MAGIC + || chain_id == WEB_RELAY_PROD_DOMAIN_ID + || chain_id == WEB_RELAY_STAGE_DOMAIN_ID + } + public fun validate_chain_id(chain_id: u64) { - let ok = chain_id == XLAYER_MAINNET_CHAIN_ID || chain_id == XLAYER_TESTNET_CHAIN_ID; - assert!(ok, errors::E_CHAIN_ID_INVALID); + assert!(is_supported_chain_id(chain_id), errors::E_CHAIN_ID_INVALID); } fun assert_sender_not_zero(sender: &vector) { @@ -139,8 +162,6 @@ module aoxc::bridge_payload { ); } - - public fun validate_intent(desired_outcome: &String, min_success_bps: u16, expiry_epoch: u64) { assert_message_not_empty(desired_outcome); assert_message_len(desired_outcome); @@ -284,7 +305,6 @@ module aoxc::bridge_payload { public fun decode_asset_mint_payload(raw: vector): BridgePayload { let decoded = bcs::from_bytes(&raw); validate_asset_route_payload(&decoded, KIND_X_MINT); - assert!(decoded.amount > 0, errors::E_AMOUNT_ZERO); new_bridge_payload(decoded.schema_version, decoded.evm_chain_id, decoded.xlayer_sender, KIND_X_MINT, decoded.target_module, decoded.ref_id, string::utf8(b"xlayer-asset-mint"), decoded.proof_root) } @@ -294,8 +314,6 @@ module aoxc::bridge_payload { new_bridge_payload(decoded.schema_version, decoded.evm_chain_id, decoded.xlayer_sender, KIND_X_BURN, decoded.target_module, decoded.ref_id, string::utf8(b"xlayer-asset-burn"), decoded.proof_root) } - - public fun encode_intent_payload( schema_version: u16, evm_chain_id: u64, @@ -340,10 +358,6 @@ module aoxc::bridge_payload { ) } - assert!(decoded.amount > 0, errors::E_AMOUNT_ZERO); - new_bridge_payload(decoded.schema_version, decoded.evm_chain_id, decoded.xlayer_sender, KIND_X_BURN, decoded.target_module, decoded.ref_id, string::utf8(b"xlayer-asset-burn"), decoded.proof_root) - } - public fun decode_governance_action(raw: vector): GovernanceAction { let decoded = bcs::from_bytes(&raw); validate_schema_version(decoded.schema_version); @@ -379,6 +393,13 @@ module aoxc::bridge_payload { public fun schema_v1(): u16 { SCHEMA_V1 } public fun xlayer_chain_id(): u64 { XLAYER_MAINNET_CHAIN_ID } public fun xlayer_testnet_chain_id(): u64 { XLAYER_TESTNET_CHAIN_ID } + public fun ethereum_chain_id(): u64 { ETHEREUM_MAINNET_CHAIN_ID } + public fun base_chain_id(): u64 { BASE_MAINNET_CHAIN_ID } + public fun arbitrum_chain_id(): u64 { ARBITRUM_ONE_CHAIN_ID } + public fun cardano_mainnet_network_magic(): u64 { CARDANO_MAINNET_NETWORK_MAGIC } + public fun cardano_preprod_network_magic(): u64 { CARDANO_PREPROD_NETWORK_MAGIC } + public fun web_relay_prod_domain_id(): u64 { WEB_RELAY_PROD_DOMAIN_ID } + public fun web_relay_stage_domain_id(): u64 { WEB_RELAY_STAGE_DOMAIN_ID } public fun target_breaker(): String { string::utf8(TARGET_BREAKER) } public fun target_treasury(): String { string::utf8(TARGET_TREASURY) } public fun target_aoxc(): String { string::utf8(TARGET_AOXC) } diff --git a/tests/full_flow_tests.move b/tests/full_flow_tests.move index 2577065..f121d4e 100644 --- a/tests/full_flow_tests.move +++ b/tests/full_flow_tests.move @@ -3,7 +3,6 @@ module aoxc::full_flow_tests { use std::string; use std::vector; use aoxc::aoxc; - use aoxc::auto_rebalancer; use aoxc::bridge_payload; use aoxc::liquidity_manager; use aoxc::marketplace; @@ -11,8 +10,6 @@ module aoxc::full_flow_tests { use aoxc::sentinel_dao; use aoxc::staking; use aoxc::treasury; - use aoxc::walrus_connector; - use aoxc::verifier_registry; fun xsender(): vector { b"12345678901234567890" } @@ -28,6 +25,7 @@ module aoxc::full_flow_tests { string::utf8(b"Bridge halt request"), b"proof-root-1", ); + let pause_raw = bridge_payload::encode_pause_payload( bridge_payload::schema_v1(), bridge_payload::xlayer_chain_id(), @@ -37,6 +35,7 @@ module aoxc::full_flow_tests { string::utf8(b"decoded halt"), b"proof-root-3", ); + let decoded_pause = bridge_payload::decode_pause_payload(pause_raw); let pause_target = bridge_payload::target_module_bytes(&decoded_pause); let action = bridge_payload::new_governance_action( @@ -65,52 +64,6 @@ module aoxc::full_flow_tests { let _ = action; } - - - #[test] - fun xlayer_asset_routes_decode() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 501, - 10, - @0xA0, - b"mint-proof", - ); - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 502, - 5, - @0xB0, - b"burn-proof", - ); - - let mint = bridge_payload::decode_asset_mint_payload(mint_raw); - let burn = bridge_payload::decode_asset_burn_payload(burn_raw); - assert!(bridge_payload::kind(&mint) == bridge_payload::kind_x_mint(), 2); - assert!(bridge_payload::kind(&burn) == bridge_payload::kind_x_burn(), 2); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_zero_sender() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 9, - string::utf8(b"invalid sender"), - b"proof", - ); - } - #[test] fun xlayer_asset_routes_decode() { let mint_raw = bridge_payload::encode_asset_mint_payload( @@ -141,111 +94,14 @@ module aoxc::full_flow_tests { } #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_zero_sender() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 9, - string::utf8(b"invalid sender"), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_empty_note() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 12, - string::utf8(b""), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 16)] - fun xlayer_asset_routes_reject_zero_amount() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 601, - 0, - @0xA0, - b"mint-proof", - ); - - let _ = bridge_payload::decode_asset_mint_payload(mint_raw); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun xlayer_asset_routes_reject_zero_recipient() { - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 602, - 7, - @0x0, - b"burn-proof", - ); - - let _ = bridge_payload::decode_asset_burn_payload(burn_raw); - } - - #[test] - #[expected_failure(abort_code = 26)] - fun typed_payload_rejects_unsupported_chain() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - 1, - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 91, - string::utf8(b"invalid chain"), - b"proof", - ); - } - - #[test] - fun xlayer_asset_routes_decode() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 501, - 10, - @0xA0, - b"mint-proof", - ); - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 502, - 5, - @0xB0, - b"burn-proof", - ); - - let mint = bridge_payload::decode_asset_mint_payload(mint_raw); - let burn = bridge_payload::decode_asset_burn_payload(burn_raw); - assert!(bridge_payload::kind(&mint) == bridge_payload::kind_x_mint(), 2); - assert!(bridge_payload::kind(&burn) == bridge_payload::kind_x_burn(), 2); + fun supports_evm_cardano_web_domains() { + assert!(bridge_payload::is_supported_chain_id(bridge_payload::ethereum_chain_id()), 10); + assert!(bridge_payload::is_supported_chain_id(bridge_payload::base_chain_id()), 11); + assert!(bridge_payload::is_supported_chain_id(bridge_payload::arbitrum_chain_id()), 12); + assert!(bridge_payload::is_supported_chain_id(bridge_payload::cardano_mainnet_network_magic()), 13); + assert!(bridge_payload::is_supported_chain_id(bridge_payload::cardano_preprod_network_magic()), 14); + assert!(bridge_payload::is_supported_chain_id(bridge_payload::web_relay_prod_domain_id()), 15); + assert!(bridge_payload::is_supported_chain_id(bridge_payload::web_relay_stage_domain_id()), 16); } #[test] @@ -317,7 +173,7 @@ module aoxc::full_flow_tests { fun typed_payload_rejects_unsupported_chain() { let _ = bridge_payload::new_bridge_payload( bridge_payload::schema_v1(), - 1, + 999_999, xsender(), bridge_payload::kind_system_halt(), bridge_payload::target_breaker(), @@ -326,993 +182,4 @@ module aoxc::full_flow_tests { b"proof", ); } - - #[test] - fun xlayer_asset_routes_decode() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 501, - 10, - @0xA0, - b"mint-proof", - ); - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 502, - 5, - @0xB0, - b"burn-proof", - ); - - let mint = bridge_payload::decode_asset_mint_payload(mint_raw); - let burn = bridge_payload::decode_asset_burn_payload(burn_raw); - assert!(bridge_payload::kind(&mint) == bridge_payload::kind_x_mint(), 2); - assert!(bridge_payload::kind(&burn) == bridge_payload::kind_x_burn(), 2); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_zero_sender() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 9, - string::utf8(b"invalid sender"), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_empty_note() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 12, - string::utf8(b""), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 16)] - fun xlayer_asset_routes_reject_zero_amount() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 601, - 0, - @0xA0, - b"mint-proof", - ); - - let _ = bridge_payload::decode_asset_mint_payload(mint_raw); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun xlayer_asset_routes_reject_zero_recipient() { - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 602, - 7, - @0x0, - b"burn-proof", - ); - - let _ = bridge_payload::decode_asset_burn_payload(burn_raw); - } - - #[test] - #[expected_failure(abort_code = 26)] - fun typed_payload_rejects_unsupported_chain() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - 1, - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 91, - string::utf8(b"invalid chain"), - b"proof", - ); - } - - #[test] - fun xlayer_asset_routes_decode() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 501, - 10, - @0xA0, - b"mint-proof", - ); - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 502, - 5, - @0xB0, - b"burn-proof", - ); - - let mint = bridge_payload::decode_asset_mint_payload(mint_raw); - let burn = bridge_payload::decode_asset_burn_payload(burn_raw); - assert!(bridge_payload::kind(&mint) == bridge_payload::kind_x_mint(), 2); - assert!(bridge_payload::kind(&burn) == bridge_payload::kind_x_burn(), 2); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_zero_sender() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 9, - string::utf8(b"invalid sender"), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_empty_note() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 12, - string::utf8(b""), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 16)] - fun xlayer_asset_routes_reject_zero_amount() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 601, - 0, - @0xA0, - b"mint-proof", - ); - - let _ = bridge_payload::decode_asset_mint_payload(mint_raw); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun xlayer_asset_routes_reject_zero_recipient() { - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 602, - 7, - @0x0, - b"burn-proof", - ); - - let _ = bridge_payload::decode_asset_burn_payload(burn_raw); - } - - #[test] - #[expected_failure(abort_code = 26)] - fun typed_payload_rejects_unsupported_chain() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - 1, - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 91, - string::utf8(b"invalid chain"), - b"proof", - ); - } - - #[test] - fun xlayer_asset_routes_decode() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 501, - 10, - @0xA0, - b"mint-proof", - ); - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 502, - 5, - @0xB0, - b"burn-proof", - ); - - let mint = bridge_payload::decode_asset_mint_payload(mint_raw); - let burn = bridge_payload::decode_asset_burn_payload(burn_raw); - assert!(bridge_payload::kind(&mint) == bridge_payload::kind_x_mint(), 2); - assert!(bridge_payload::kind(&burn) == bridge_payload::kind_x_burn(), 2); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_zero_sender() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 9, - string::utf8(b"invalid sender"), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_empty_note() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 12, - string::utf8(b""), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 16)] - fun xlayer_asset_routes_reject_zero_amount() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 601, - 0, - @0xA0, - b"mint-proof", - ); - - let _ = bridge_payload::decode_asset_mint_payload(mint_raw); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun xlayer_asset_routes_reject_zero_recipient() { - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 602, - 7, - @0x0, - b"burn-proof", - ); - - let _ = bridge_payload::decode_asset_burn_payload(burn_raw); - } - - #[test] - #[expected_failure(abort_code = 26)] - fun typed_payload_rejects_unsupported_chain() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - 1, - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 91, - string::utf8(b"invalid chain"), - b"proof", - ); - } - - #[test] - fun xlayer_asset_routes_decode() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 501, - 10, - @0xA0, - b"mint-proof", - ); - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 502, - 5, - @0xB0, - b"burn-proof", - ); - - let mint = bridge_payload::decode_asset_mint_payload(mint_raw); - let burn = bridge_payload::decode_asset_burn_payload(burn_raw); - assert!(bridge_payload::kind(&mint) == bridge_payload::kind_x_mint(), 2); - assert!(bridge_payload::kind(&burn) == bridge_payload::kind_x_burn(), 2); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_zero_sender() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 9, - string::utf8(b"invalid sender"), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_empty_note() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 12, - string::utf8(b""), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 16)] - fun xlayer_asset_routes_reject_zero_amount() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 601, - 0, - @0xA0, - b"mint-proof", - ); - - let _ = bridge_payload::decode_asset_mint_payload(mint_raw); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun xlayer_asset_routes_reject_zero_recipient() { - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 602, - 7, - @0x0, - b"burn-proof", - ); - - let _ = bridge_payload::decode_asset_burn_payload(burn_raw); - } - - #[test] - #[expected_failure(abort_code = 26)] - fun typed_payload_rejects_unsupported_chain() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - 1, - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 91, - string::utf8(b"invalid chain"), - b"proof", - ); - } - - #[test] - fun xlayer_asset_routes_decode() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 501, - 10, - @0xA0, - b"mint-proof", - ); - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 502, - 5, - @0xB0, - b"burn-proof", - ); - - let mint = bridge_payload::decode_asset_mint_payload(mint_raw); - let burn = bridge_payload::decode_asset_burn_payload(burn_raw); - assert!(bridge_payload::kind(&mint) == bridge_payload::kind_x_mint(), 2); - assert!(bridge_payload::kind(&burn) == bridge_payload::kind_x_burn(), 2); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_zero_sender() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 9, - string::utf8(b"invalid sender"), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_empty_note() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 12, - string::utf8(b""), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 16)] - fun xlayer_asset_routes_reject_zero_amount() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 601, - 0, - @0xA0, - b"mint-proof", - ); - - let _ = bridge_payload::decode_asset_mint_payload(mint_raw); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun xlayer_asset_routes_reject_zero_recipient() { - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 602, - 7, - @0x0, - b"burn-proof", - ); - - let _ = bridge_payload::decode_asset_burn_payload(burn_raw); - } - - #[test] - #[expected_failure(abort_code = 26)] - fun typed_payload_rejects_unsupported_chain() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - 1, - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 91, - string::utf8(b"invalid chain"), - b"proof", - ); - } - - #[test] - fun xlayer_asset_routes_decode() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 501, - 10, - @0xA0, - b"mint-proof", - ); - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 502, - 5, - @0xB0, - b"burn-proof", - ); - - let mint = bridge_payload::decode_asset_mint_payload(mint_raw); - let burn = bridge_payload::decode_asset_burn_payload(burn_raw); - assert!(bridge_payload::kind(&mint) == bridge_payload::kind_x_mint(), 2); - assert!(bridge_payload::kind(&burn) == bridge_payload::kind_x_burn(), 2); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_zero_sender() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 9, - string::utf8(b"invalid sender"), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_empty_note() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 12, - string::utf8(b""), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 16)] - fun xlayer_asset_routes_reject_zero_amount() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 601, - 0, - @0xA0, - b"mint-proof", - ); - - let _ = bridge_payload::decode_asset_mint_payload(mint_raw); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun xlayer_asset_routes_reject_zero_recipient() { - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 602, - 7, - @0x0, - b"burn-proof", - ); - - let _ = bridge_payload::decode_asset_burn_payload(burn_raw); - } - - #[test] - #[expected_failure(abort_code = 26)] - fun typed_payload_rejects_unsupported_chain() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - 1, - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 91, - string::utf8(b"invalid chain"), - b"proof", - ); - } - - - - #[test] - fun intent_payload_smoke() { - let intent_raw = bridge_payload::encode_intent_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_breaker(), - 777, - string::utf8(b"system enters safe state"), - 9000, - 1, - b"intent-proof", - ); - let decoded = bridge_payload::decode_intent_payload(intent_raw, bridge_payload::kind_system_halt()); - assert!(bridge_payload::kind(&decoded) == bridge_payload::kind_system_halt(), 2); - verifier_registry::validate_verifier(&verifier_registry::verifier_zk_light_client()); - } - - #[test] - fun xlayer_asset_routes_decode() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 501, - 10, - @0xA0, - b"mint-proof", - ); - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 502, - 5, - @0xB0, - b"burn-proof", - ); - - let mint = bridge_payload::decode_asset_mint_payload(mint_raw); - let burn = bridge_payload::decode_asset_burn_payload(burn_raw); - assert!(bridge_payload::kind(&mint) == bridge_payload::kind_x_mint(), 2); - assert!(bridge_payload::kind(&burn) == bridge_payload::kind_x_burn(), 2); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_zero_sender() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 9, - string::utf8(b"invalid sender"), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_empty_note() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 12, - string::utf8(b""), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 16)] - fun xlayer_asset_routes_reject_zero_amount() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 601, - 0, - @0xA0, - b"mint-proof", - ); - - let _ = bridge_payload::decode_asset_mint_payload(mint_raw); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun xlayer_asset_routes_reject_zero_recipient() { - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 602, - 7, - @0x0, - b"burn-proof", - ); - - let _ = bridge_payload::decode_asset_burn_payload(burn_raw); - } - - #[test] - #[expected_failure(abort_code = 26)] - fun typed_payload_rejects_unsupported_chain() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - 1, - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 91, - string::utf8(b"invalid chain"), - b"proof", - ); - } - - - - #[test] - fun intent_payload_smoke() { - let intent_raw = bridge_payload::encode_intent_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_breaker(), - 777, - string::utf8(b"system enters safe state"), - 9000, - 1, - b"intent-proof", - ); - let decoded = bridge_payload::decode_intent_payload(intent_raw, bridge_payload::kind_system_halt()); - assert!(bridge_payload::kind(&decoded) == bridge_payload::kind_system_halt(), 2); - verifier_registry::validate_verifier(&verifier_registry::verifier_zk_light_client()); - } - - #[test] - fun xlayer_asset_routes_decode() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 501, - 10, - @0xA0, - b"mint-proof", - ); - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 502, - 5, - @0xB0, - b"burn-proof", - ); - - let mint = bridge_payload::decode_asset_mint_payload(mint_raw); - let burn = bridge_payload::decode_asset_burn_payload(burn_raw); - assert!(bridge_payload::kind(&mint) == bridge_payload::kind_x_mint(), 2); - assert!(bridge_payload::kind(&burn) == bridge_payload::kind_x_burn(), 2); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_zero_sender() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 9, - string::utf8(b"invalid sender"), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_empty_note() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 12, - string::utf8(b""), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 16)] - fun xlayer_asset_routes_reject_zero_amount() { - let mint_raw = bridge_payload::encode_asset_mint_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_testnet_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 601, - 0, - @0xA0, - b"mint-proof", - ); - - let _ = bridge_payload::decode_asset_mint_payload(mint_raw); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun xlayer_asset_routes_reject_zero_recipient() { - let burn_raw = bridge_payload::encode_asset_burn_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_aoxc(), - 602, - 7, - @0x0, - b"burn-proof", - ); - - let _ = bridge_payload::decode_asset_burn_payload(burn_raw); - } - - #[test] - #[expected_failure(abort_code = 26)] - fun typed_payload_rejects_unsupported_chain() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - 1, - xsender(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 91, - string::utf8(b"invalid chain"), - b"proof", - ); - } - - - - #[test] - fun intent_payload_smoke() { - let intent_raw = bridge_payload::encode_intent_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_breaker(), - 777, - string::utf8(b"system enters safe state"), - 9000, - 1, - b"intent-proof", - ); - let decoded = bridge_payload::decode_intent_payload(intent_raw, bridge_payload::kind_system_halt()); - assert!(bridge_payload::kind(&decoded) == bridge_payload::kind_system_halt(), 2); - verifier_registry::validate_verifier(&verifier_registry::verifier_zk_light_client()); - } - - - - #[test] - fun web4_pipeline_smoke() { - let intent_raw = bridge_payload::encode_intent_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::target_breaker(), - 888, - string::utf8(b"normal -> anomaly -> safety"), - 9_500, - 2, - b"flow-proof", - ); - let _intent = bridge_payload::decode_intent_payload(intent_raw, bridge_payload::kind_system_halt()); - auto_rebalancer::validate_thresholds(100, 400); - walrus_connector::validate_credential_inputs(&b"issuer", &b"subject", &b"claim", &b"cert"); - let should_slash = staking::should_trigger_relayer_slash(10, 100, false); - assert!(should_slash, 2); - } - - #[test] - #[expected_failure(abort_code = 2)] - fun typed_payload_rejects_invalid_kind() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - 99, - bridge_payload::target_breaker(), - 1, - string::utf8(b"invalid"), - b"proof", - ); - } - - #[test] - #[expected_failure(abort_code = 15)] - fun typed_governance_rejects_empty_proof() { - let _ = bridge_payload::new_governance_action( - bridge_payload::schema_v1(), - bridge_payload::kind_system_halt(), - bridge_payload::target_breaker(), - 1, - string::utf8(b"missing proof"), - vector::empty(), - ); - } - - #[test] - #[expected_failure(abort_code = 23)] - fun fund_update_rejects_wrong_target() { - let _ = bridge_payload::new_bridge_payload( - bridge_payload::schema_v1(), - bridge_payload::xlayer_chain_id(), - xsender(), - bridge_payload::kind_fund_update(), - bridge_payload::target_breaker(), - 2, - string::utf8(b"wrong target"), - b"proof", - ); - } } From cda5b7d4b4d5417e43ba84bbc3e4673441338f31 Mon Sep 17 00:00:00 2001 From: AOXC Date: Wed, 11 Mar 2026 19:17:37 +0300 Subject: [PATCH 3/3] Add multi-domain bridge payload support, compatibility matrix, and updated tests (#68) * Strengthen audit-grade test coverage and mainnet readiness guidance * Add audit-grade release evidence template and CI gates --------- Signed-off-by: AOXC --- .github/workflows/move-ci.yml | 34 +++++++++++++++ README.md | 39 +++++++++++++++++ docs/AUDIT_EVIDENCE_BUNDLE.md | 62 ++++++++++++++++++++++++++ docs/RELEASE_CHECKLIST.md | 7 +++ tests/full_flow_tests.move | 40 +++++++++++++++++ tests/phase1_negative_tests.move | 74 +++++--------------------------- 6 files changed, 193 insertions(+), 63 deletions(-) create mode 100644 .github/workflows/move-ci.yml create mode 100644 docs/AUDIT_EVIDENCE_BUNDLE.md diff --git a/.github/workflows/move-ci.yml b/.github/workflows/move-ci.yml new file mode 100644 index 0000000..5c68d3d --- /dev/null +++ b/.github/workflows/move-ci.yml @@ -0,0 +1,34 @@ +name: Move CI + +on: + pull_request: + push: + branches: [main, master, work] + +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Cache cargo + uses: Swatinem/rust-cache@v2 + + - name: Install Sui CLI + run: cargo install --locked --git https://github.com/MystenLabs/sui.git sui + + - name: Verify tool versions + run: | + rustc --version + cargo --version + sui --version + + - name: Build Move package + run: sui move build + + - name: Run Move tests + run: sui move test diff --git a/README.md b/README.md index 48fc218..bdbadd7 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,7 @@ Key documents include: - code audit report (module-by-module findings and action plan) - architecture alignment (Sui-first execution + XLayer interoperability fit) - compatibility matrix (EVM + Cardano + Web relay domain mapping) +- audit evidence bundle template (mainnet-candidate release artifacts) - production-ready report (gas/object/web4 compatibility scoring) --- @@ -376,3 +377,41 @@ See the `LICENSE` file for details.
© 2026 AOXC Protocol | Secure. Auditable. Intelligent.
+ +--- + +# Mainnet-Readiness (Audit-Oriented) + +Aşağıdaki yaklaşım, "mainnet’e yakın" test ve release disiplinini minimum baseline olarak önerir. + +## 1) Test Piramidi + +- **Unit/Invariant tests (her PR):** input doğrulama, abort-code eşleşmesi, whitelist/allowlist kontrolleri. +- **Scenario tests (her PR):** bridge -> dao -> treasury akışlarında failure-recovery yolları. +- **Release-candidate tests (tag öncesi):** deterministik tekrar koşuları + event schema uyumluluğu. + +## 2) Merge Gate (zorunlu) + +Aşağıdaki kapılar geçmeden merge önerilmez: + +1. `move fmt` (veya eşdeğer format kontrolü) +2. `sui move build` +3. `sui move test` +4. Abort-code regression kontrolü (özellikle `errors.move` sabitleri) +5. Docs/spec drift kontrolü (`docs/SPEC.md` ile modül davranışı eşleşmeli) + +## 3) Audit Paketi (release artefact) + +- Commit hash + tag + build metadata +- Test çıktısı ve hashlenmiş artefact seti +- Tehdit modeli güncelleme kaydı +- Değişen modüller için "invariant impact" özeti +- İki imzacıyla release onayı (4-eyes) + +## 4) Cross-Domain Operasyon Notu + +`bridge_payload` katmanı XLayer/EVM + Cardano + web domain id allowlist’i uygular. +Domain’e özel imza/finality doğrulamaları üst katmanda ayrıca zorunlu tutulmalıdır. + + +Audit evidence template: `docs/AUDIT_EVIDENCE_BUNDLE.md`. diff --git a/docs/AUDIT_EVIDENCE_BUNDLE.md b/docs/AUDIT_EVIDENCE_BUNDLE.md new file mode 100644 index 0000000..346cdd1 --- /dev/null +++ b/docs/AUDIT_EVIDENCE_BUNDLE.md @@ -0,0 +1,62 @@ +# AOXC Audit Evidence Bundle (Mainnet-Candidate) + +Bu dosya, release anında denetçiye ve iç güvenlik ekibine teslim edilecek **zorunlu artefact setini** standartlaştırır. + +## 1) Kimlik ve İzlenebilirlik + +- Release tag (`vX.Y.Z`) ve commit SHA +- Derleme zamanı (UTC), derleyen pipeline run ID +- İlgili PR numarası ve changelog özeti + +## 2) Build/Test Kanıtı + +- `sui move build` çıktısı (tam log) +- `sui move test` çıktısı (tam log) +- Test rapor hash'i (SHA256) +- Test ortamı versiyonları (`sui`, `rustc`, `cargo`) + +## 3) Güvenlik Kanıtı + +- `docs/THREAT_MODEL.md` diff veya güncellik beyanı +- Kritik invariant etkisi (modül bazlı): + - bridge + - relay/quorum + - treasury/claims + - governance/timelock/veto +- Yeni risk kabulü varsa onaylayan kişi/rol + +## 4) Operasyonel Kanıt + +- Signer ceremony kaydı (katılımcılar + zaman damgası) +- Anahtar rotasyon kaydı (varsa) +- Incident drill kaydı (kill-switch/pause-resume tatbikatı) +- Geri alma (rollback) planı ve sorumlu kişi + +## 5) Uyum ve Dokümantasyon Kanıtı + +- `docs/SPEC.md` güncel mi? (evet/hayır + gerekçe) +- `docs/EVENT_MAP.md` ve `docs/INDEXER_RUNBOOK.md` etkisi +- Parser/API sürüm etkisi ve backward-compatibility notu + +## 6) Onaylar (4-eyes minimum) + +- Teknik onaylayan #1 (isim/rol/imza) +- Teknik onaylayan #2 (isim/rol/imza) +- Gerekirse güvenlik temsilcisi ek imza + +--- + +## Örnek Teslim Dizini + +``` +audit-bundle/ + metadata.json + build.log + test.log + hashes.txt + threat-model-note.md + invariant-impact.md + signer-ceremony.md + drill-record.md + approvals.md +``` diff --git a/docs/RELEASE_CHECKLIST.md b/docs/RELEASE_CHECKLIST.md index 1f66240..9c98488 100644 --- a/docs/RELEASE_CHECKLIST.md +++ b/docs/RELEASE_CHECKLIST.md @@ -25,3 +25,10 @@ - [ ] Signer ceremony and key rotation record attached. - [ ] Rollback/kill-switch decision owner assigned. - [ ] Release approvers listed and signed. + + +## E. Evidence Bundle Gate +- [ ] `docs/AUDIT_EVIDENCE_BUNDLE.md` template completed. +- [ ] Build/test logs archived with hashes. +- [ ] 4-eyes release approval attached. +- [ ] Cross-domain integration notes attached (EVM/Cardano/Web). diff --git a/tests/full_flow_tests.move b/tests/full_flow_tests.move index f121d4e..f304c51 100644 --- a/tests/full_flow_tests.move +++ b/tests/full_flow_tests.move @@ -104,6 +104,46 @@ module aoxc::full_flow_tests { assert!(bridge_payload::is_supported_chain_id(bridge_payload::web_relay_stage_domain_id()), 16); } + + #[test] + fun can_build_payload_for_all_supported_domains() { + let eth = bridge_payload::new_bridge_payload( + bridge_payload::schema_v1(), + bridge_payload::ethereum_chain_id(), + xsender(), + bridge_payload::kind_system_halt(), + bridge_payload::target_breaker(), + 701, + string::utf8(b"eth-halt"), + b"eth-proof", + ); + let cardano = bridge_payload::new_bridge_payload( + bridge_payload::schema_v1(), + bridge_payload::cardano_mainnet_network_magic(), + 999_999, + xsender(), + bridge_payload::kind_system_resume(), + bridge_payload::target_breaker(), + 702, + string::utf8(b"cardano-resume"), + b"cardano-proof", + ); + let web = bridge_payload::new_bridge_payload( + bridge_payload::schema_v1(), + bridge_payload::web_relay_prod_domain_id(), + xsender(), + bridge_payload::kind_fund_update(), + bridge_payload::target_treasury(), + 703, + string::utf8(b"web-fund-update"), + b"web-proof", + ); + + let _ = eth; + let _ = cardano; + let _ = web; + } + #[test] #[expected_failure(abort_code = 2)] fun typed_payload_rejects_zero_sender() { diff --git a/tests/phase1_negative_tests.move b/tests/phase1_negative_tests.move index 62de754..6b4d30f 100644 --- a/tests/phase1_negative_tests.move +++ b/tests/phase1_negative_tests.move @@ -3,20 +3,20 @@ module aoxc::phase1_negative_tests { use std::string; use std::vector; use aoxc::aoxc; + use aoxc::auto_rebalancer; use aoxc::bridge_payload; use aoxc::circuit_breaker; use aoxc::errors; - use aoxc::neural_bridge; use aoxc::liquidity_manager; use aoxc::marketplace; - use aoxc::staking; + use aoxc::neural_bridge; use aoxc::relay; use aoxc::reputation; use aoxc::sentinel_dao; + use aoxc::staking; use aoxc::treasury; - use aoxc::walrus_connector; - use aoxc::auto_rebalancer; use aoxc::verifier_registry; + use aoxc::walrus_connector; #[test, expected_failure(abort_code = errors::E_STATUS_INVALID)] fun aoxc_rejects_invalid_status() { @@ -70,8 +70,6 @@ module aoxc::phase1_negative_tests { walrus_connector::validate_blob_inputs(&vector::empty(), &b"cert", &b"bridge"); } - - #[test, expected_failure(abort_code = errors::E_POLICY_LIMIT)] fun intent_rejects_bad_success_bps() { bridge_payload::validate_intent(&string::utf8(b"ok"), 10_001, 1); @@ -87,18 +85,11 @@ module aoxc::phase1_negative_tests { walrus_connector::validate_credential_inputs(&vector::empty(), &b"subject", &b"claim", &b"cert"); } - - #[test, expected_failure(abort_code = errors::E_INVALID_ARGUMENT)] fun rebalancer_rejects_invalid_thresholds() { auto_rebalancer::validate_thresholds(100, 99); } - #[test, expected_failure(abort_code = errors::E_INVALID_ARGUMENT)] - fun rebalancer_rejects_zero_soft_threshold() { - auto_rebalancer::validate_thresholds(0, 100); - } - #[test, expected_failure(abort_code = errors::E_INVALID_ARGUMENT)] fun dao_rejects_unknown_action() { sentinel_dao::validate_action_type(200); @@ -121,8 +112,8 @@ module aoxc::phase1_negative_tests { } #[test, expected_failure(abort_code = errors::E_CHAIN_ID_INVALID)] - fun payload_rejects_bad_chain_id() { - bridge_payload::validate_chain_id(1); + fun payload_rejects_unknown_domain_id() { + bridge_payload::validate_chain_id(999_999); } #[test, expected_failure(abort_code = errors::E_CHECKSUM_MISMATCH)] @@ -137,6 +128,11 @@ module aoxc::phase1_negative_tests { staking::validate_slash_bps(5000); } + #[test, expected_failure(abort_code = errors::E_POLICY_LIMIT)] + fun staking_rejects_excessive_reward_bps() { + staking::validate_reward_bps(5000); + } + #[test, expected_failure(abort_code = errors::E_INVALID_ARGUMENT)] fun liquidity_rejects_unknown_dex() { let dex = string::utf8(b"unknown-dex"); @@ -153,38 +149,6 @@ module aoxc::phase1_negative_tests { liquidity_manager::validate_slippage_bps(4000); } - - - #[test, expected_failure(abort_code = errors::E_POLICY_LIMIT)] - fun treasury_reconciliation_rejects_non_interval_block() { - treasury::validate_reconciliation_checkpoint(1000, 1001, 0, 32); - } - - #[test, expected_failure(abort_code = errors::E_RECONCILIATION_FAILED)] - fun staking_rejects_broken_capital_equation() { - staking::validate_capital_equation(10, 15, 20); - } - - #[test, expected_failure(abort_code = errors::E_POLICY_LIMIT)] - fun treasury_reconciliation_rejects_non_interval_block() { - treasury::validate_reconciliation_checkpoint(1000, 1001, 0, 32); - } - - #[test, expected_failure(abort_code = errors::E_RECONCILIATION_FAILED)] - fun staking_rejects_broken_capital_equation() { - staking::validate_capital_equation(10, 15, 20); - } - - #[test, expected_failure(abort_code = errors::E_POLICY_LIMIT)] - fun treasury_reconciliation_rejects_non_interval_block() { - treasury::validate_reconciliation_checkpoint(1000, 1001, 0, 32); - } - - #[test, expected_failure(abort_code = errors::E_RECONCILIATION_FAILED)] - fun staking_rejects_broken_capital_equation() { - staking::validate_capital_equation(10, 15, 20); - } - #[test, expected_failure(abort_code = errors::E_POLICY_LIMIT)] fun treasury_reconciliation_rejects_non_interval_block() { treasury::validate_reconciliation_checkpoint(1000, 1001, 0, 32); @@ -195,24 +159,8 @@ module aoxc::phase1_negative_tests { staking::validate_capital_equation(10, 15, 20); } - #[test, expected_failure(abort_code = errors::E_POLICY_LIMIT)] - fun treasury_reconciliation_rejects_non_interval_block() { - treasury::validate_reconciliation_checkpoint(1000, 1001, 0, 32); - } - - #[test, expected_failure(abort_code = errors::E_RECONCILIATION_FAILED)] - fun staking_rejects_broken_capital_equation() { - staking::validate_capital_equation(10, 15, 20); - } - - #[test, expected_failure(abort_code = errors::E_POLICY_LIMIT)] - fun staking_rejects_excessive_reward_bps() { - staking::validate_reward_bps(5000); - } - #[test, expected_failure(abort_code = errors::E_POOL_NOT_ENABLED)] fun treasury_rejects_disabled_yield_policy() { treasury::validate_yield_policy(false, false, 0, 0, 0, 0); } - }