diff --git a/.github/scripts/update_move_toml.sh b/.github/scripts/update_move_toml.sh index beebab1fd..b0b11205f 100644 --- a/.github/scripts/update_move_toml.sh +++ b/.github/scripts/update_move_toml.sh @@ -2,23 +2,49 @@ MOVE_TOML_PATH="protocol-units/bridge/move-modules/Move.toml" +# Initialize Aptos and capture output INIT_OUTPUT=$(aptos init 2>&1) - echo "$INIT_OUTPUT" +# Extract the account address from the initialization output ADDRESS=$(echo "$INIT_OUTPUT" | grep -oE '0x[a-f0-9]{64}' | head -1) - if [[ -z "$ADDRESS" ]]; then echo "Error: Failed to extract the Aptos account address." exit 1 fi -echo "$ADDRESS" +# Generate a random seed +RANDOM_SEED=$(shuf -i 0-1000000 -n 1) +echo "Seed: $RANDOM_SEED" + +# Derive the resource account address using the random seed +RESOURCE_OUTPUT=$(aptos account derive-resource-account-address --address "$ADDRESS" --seed "" --seed-encoding hex 2>&1) +echo "Resource address derivation output: $RESOURCE_OUTPUT" + +# Extract the resource address directly +RESOURCE_ADDRESS=$(echo "$RESOURCE_OUTPUT" | grep -oE '[a-f0-9]{64}') + +if [[ -z "$RESOURCE_ADDRESS" ]]; then + echo "Error: Failed to extract the resource account address." + exit 1 +fi + +# Prepend the 0x to the resource address +RESOURCE_ADDRESS="0x$RESOURCE_ADDRESS" + +echo "Extracted address: $ADDRESS" +echo "Derived resource address: $RESOURCE_ADDRESS" + +# Update the Move.toml file with the addresses +sed -i "s/^resource_addr = \".*\"/resource_addr = \"$RESOURCE_ADDRESS\"/" "$MOVE_TOML_PATH" +sed -i "s/^atomic_bridge = \".*\"/atomic_bridge = \"$RESOURCE_ADDRESS\"/" "$MOVE_TOML_PATH" +sed -i "s/^moveth = \".*\"/moveth = \"$RESOURCE_ADDRESS\"/" "$MOVE_TOML_PATH" +sed -i "s/^master_minter = \".*\"/master_minter = \"$RESOURCE_ADDRESS\"/" "$MOVE_TOML_PATH" +sed -i "s/^minter = \".*\"/minter = \"$RESOURCE_ADDRESS\"/" "$MOVE_TOML_PATH" +sed -i "s/^admin = \".*\"/admin = \"$RESOURCE_ADDRESS\"/" "$MOVE_TOML_PATH" +sed -i "s/^origin_addr = \".*\"/origin_addr = \"$ADDRESS\"/" "$MOVE_TOML_PATH" -sed -i "s/^atomic_bridge = \".*\"/atomic_bridge = \"$ADDRESS\"/" "$MOVE_TOML_PATH" -sed -i "s/^moveth = \".*\"/moveth = \"$ADDRESS\"/" "$MOVE_TOML_PATH" -sed -i "s/^master_minter = \".*\"/master_minter = \"$ADDRESS\"/" "$MOVE_TOML_PATH" -sed -i "s/^minter = \".*\"/minter = \"$ADDRESS\"/" "$MOVE_TOML_PATH" -sed -i "s/^admin = \".*\"/admin = \"$ADDRESS\"/" "$MOVE_TOML_PATH" +echo "Move.toml updated with ADDRESS: $ADDRESS and RESOURCE_ADDRESS: $RESOURCE_ADDRESS" -echo "Move.toml updated with address: $ADDRESS" \ No newline at end of file +echo "Contents of $MOVE_TOML_PATH:" +cat "$MOVE_TOML_PATH" \ No newline at end of file diff --git a/protocol-units/bridge/move-modules/Move.toml b/protocol-units/bridge/move-modules/Move.toml index 0b6be281e..56ab1a2b1 100644 --- a/protocol-units/bridge/move-modules/Move.toml +++ b/protocol-units/bridge/move-modules/Move.toml @@ -11,7 +11,6 @@ moveth = "0xc3bb8488ab1a5815a9d543d7e41b0e0df46a7396f89b22821f07a4362f75ddc5" master_minter = "0xc3bb8488ab1a5815a9d543d7e41b0e0df46a7396f89b22821f07a4362f75ddc5" minter = "0xc3bb8488ab1a5815a9d543d7e41b0e0df46a7396f89b22821f07a4362f75ddc5" admin = "0xc3bb8488ab1a5815a9d543d7e41b0e0df46a7396f89b22821f07a4362f75ddc5" -source_account = "0xc3bb8488ab1a5815a9d543d7e41b0e0df46a7396f89b22821f07a4362f75ddc5" pauser = "0xdafe" denylister = "0xcade" diff --git a/protocol-units/bridge/move-modules/README.md b/protocol-units/bridge/move-modules/README.md index 6807ed21b..49436bbb4 100644 --- a/protocol-units/bridge/move-modules/README.md +++ b/protocol-units/bridge/move-modules/README.md @@ -172,4 +172,4 @@ This works because in the `moveth` module, the `init_module` function was modifi vector::push_back(&mut minters, @0xc3bb8488ab1a5815a9d543d7e41b0e0df46a7396f89b22821f07a4362f75ddc5); ``` -Avoiding the need to add and then remove caller as minter, and simply having the resource signer facilitate minting, appears to be more efficient. \ No newline at end of file +Avoiding the need to add and then remove caller as minter, and simply having the resource signer facilitate minting, appears to be more efficient. diff --git a/protocol-units/bridge/move-modules/sources/atomic_bridge_counterparty.move b/protocol-units/bridge/move-modules/sources/atomic_bridge_counterparty.move index 759cfe6db..6925fbb8c 100644 --- a/protocol-units/bridge/move-modules/sources/atomic_bridge_counterparty.move +++ b/protocol-units/bridge/move-modules/sources/atomic_bridge_counterparty.move @@ -1,8 +1,8 @@ module atomic_bridge::atomic_bridge_counterparty { use std::signer; - use std::event; use std::vector; use aptos_framework::account; + use aptos_framework::event::{Self, EventHandle}; #[test_only] use aptos_framework::account::create_account_for_test; use aptos_framework::resource_account; @@ -11,19 +11,25 @@ module atomic_bridge::atomic_bridge_counterparty { use aptos_std::smart_table::{Self, SmartTable}; use moveth::moveth; - /// A mapping of bridge transfer IDs to their details + const LOCKED: u8 = 1; + const COMPLETED: u8 = 2; + const CANCELLED: u8 = 3; + + /// A mapping of bridge transfer IDs to their bridge_transfer struct BridgeTransferStore has key, store { - pending_transfers: SmartTable, BridgeTransferDetails>, - completed_transfers: SmartTable, BridgeTransferDetails>, - aborted_transfers: SmartTable, BridgeTransferDetails>, + transfers: SmartTable, BridgeTransfer>, + bridge_transfer_locked_events: EventHandle, + bridge_transfer_completed_events: EventHandle, + bridge_transfer_cancelled_events: EventHandle, } - struct BridgeTransferDetails has key, store { - initiator: vector, // eth address + struct BridgeTransfer has key, store { + originator: vector, // eth address, recipient: address, amount: u64, hash_lock: vector, time_lock: u64, + state: u8, } struct BridgeConfig has key { @@ -34,8 +40,9 @@ module atomic_bridge::atomic_bridge_counterparty { #[event] /// An event triggered upon locking assets for a bridge transfer - struct BridgeTransferAssetsLockedEvent has store, drop { + struct BridgeTransferLockedEvent has store, drop { bridge_transfer_id: vector, + originator: vector, recipient: address, amount: u64, hash_lock: vector, @@ -55,27 +62,47 @@ module atomic_bridge::atomic_bridge_counterparty { bridge_transfer_id: vector, } - entry fun init_module(resource: &signer) { + fun init_module(resource: &signer) { let resource_signer_cap = resource_account::retrieve_resource_account_cap(resource, @origin_addr); - let bridge_transfer_store = BridgeTransferStore { - pending_transfers: smart_table::new(), - completed_transfers: smart_table::new(), - aborted_transfers: smart_table::new(), - }; - let bridge_config = BridgeConfig { + move_to(resource, BridgeTransferStore { + transfers: aptos_std::smart_table::new, BridgeTransfer>(), + bridge_transfer_locked_events: account::new_event_handle(resource), + bridge_transfer_completed_events: account::new_event_handle(resource), + bridge_transfer_cancelled_events: account::new_event_handle(resource), + }); + move_to(resource,BridgeConfig { moveth_minter: signer::address_of(resource), bridge_module_deployer: signer::address_of(resource), signer_cap: resource_signer_cap + }); + } + + #[view] + public fun bridge_transfers(bridge_transfer_id: vector): (vector, address, u64, vector, u64, u8) acquires BridgeTransferStore, BridgeConfig { + let config_address = borrow_global(@atomic_bridge).bridge_module_deployer; + let store = borrow_global(config_address); + + if (!aptos_std::smart_table::contains(&store.transfers, bridge_transfer_id)) { + abort 0x1; }; - move_to(resource, bridge_transfer_store); - move_to(resource, bridge_config); + + let bridge_transfer_ref = aptos_std::smart_table::borrow(&store.transfers, bridge_transfer_id); + + ( + bridge_transfer_ref.originator, + bridge_transfer_ref.recipient, + bridge_transfer_ref.amount, + bridge_transfer_ref.hash_lock, + bridge_transfer_ref.time_lock, + bridge_transfer_ref.state + ) } - - public fun lock_bridge_transfer_assets( + + public fun lock_bridge_transfer( caller: &signer, - initiator: vector, //eth address + originator: vector, //eth address bridge_transfer_id: vector, hash_lock: vector, time_lock: u64, @@ -83,26 +110,27 @@ module atomic_bridge::atomic_bridge_counterparty { amount: u64 ): bool acquires BridgeTransferStore { assert!(signer::address_of(caller) == @origin_addr, 1); - let bridge_store = borrow_global_mut(@resource_addr); - let details = BridgeTransferDetails { + let store = borrow_global_mut(@resource_addr); + let bridge_transfer = BridgeTransfer { + originator, recipient, - initiator, amount, hash_lock, - time_lock: timestamp::now_seconds() + time_lock + time_lock: timestamp::now_seconds() + time_lock, + state: LOCKED, }; - smart_table::add(&mut bridge_store.pending_transfers, bridge_transfer_id, details); - event::emit( - BridgeTransferAssetsLockedEvent { + smart_table::add(&mut store.transfers, bridge_transfer_id, bridge_transfer); + + event::emit_event(&mut store.bridge_transfer_locked_events, BridgeTransferLockedEvent { + amount, bridge_transfer_id, + originator, recipient, - amount, hash_lock, time_lock, }, ); - true } @@ -113,18 +141,18 @@ module atomic_bridge::atomic_bridge_counterparty { ) acquires BridgeTransferStore, BridgeConfig, { let config_address = borrow_global(@resource_addr).bridge_module_deployer; let resource_signer = account::create_signer_with_capability(&borrow_global(@resource_addr).signer_cap); - let bridge_store = borrow_global_mut(config_address); - let details: BridgeTransferDetails = smart_table::remove(&mut bridge_store.pending_transfers, bridge_transfer_id); + let store = borrow_global_mut(config_address); + let bridge_transfer = aptos_std::smart_table::borrow_mut(&mut store.transfers, bridge_transfer_id); let computed_hash = keccak256(pre_image); - assert!(computed_hash == details.hash_lock, 2); + assert!(computed_hash == bridge_transfer.hash_lock, 2); + assert!(bridge_transfer.state == LOCKED, 3); + bridge_transfer.state = COMPLETED; - moveth::mint(&resource_signer, details.recipient, details.amount); + moveth::mint(&resource_signer, bridge_transfer.recipient, bridge_transfer.amount); - smart_table::add(&mut bridge_store.completed_transfers, bridge_transfer_id, details); - event::emit( - BridgeTransferCompletedEvent { - bridge_transfer_id, + event::emit_event(&mut store.bridge_transfer_completed_events, BridgeTransferCompletedEvent { + bridge_transfer_id: copy bridge_transfer_id, pre_image, }, ); @@ -136,15 +164,16 @@ module atomic_bridge::atomic_bridge_counterparty { ) acquires BridgeTransferStore, BridgeConfig { // check that the signer is the bridge_module_deployer assert!(signer::address_of(caller) == borrow_global(signer::address_of(caller)).bridge_module_deployer, 1); - let bridge_store = borrow_global_mut(signer::address_of(caller)); - let details: BridgeTransferDetails = smart_table::remove(&mut bridge_store.pending_transfers, bridge_transfer_id); + let store = borrow_global_mut(signer::address_of(caller)); + let bridge_transfer = aptos_std::smart_table::borrow_mut(&mut store.transfers, bridge_transfer_id); // Ensure the timelock has expired - assert!(timestamp::now_seconds() > details.time_lock, 2); + assert!(timestamp::now_seconds() > bridge_transfer.time_lock, 2); + assert!(bridge_transfer.state == LOCKED, 3); + + bridge_transfer.state = CANCELLED; - smart_table::add(&mut bridge_store.aborted_transfers, bridge_transfer_id, details); - event::emit( - BridgeTransferCancelledEvent { + event::emit_event(&mut store.bridge_transfer_cancelled_events, BridgeTransferCancelledEvent { bridge_transfer_id, }, ); @@ -171,7 +200,7 @@ module atomic_bridge::atomic_bridge_counterparty { use aptos_framework::create_signer::create_signer; use aptos_framework::primary_fungible_store; - #[test(origin_account = @origin_addr, resource_addr = @resource_addr, aptos_framework = @0x1, creator = @atomic_bridge, source_account = @source_account, moveth = @moveth, admin = @admin, client = @0xdca, master_minter = @master_minter)] + #[test(origin_account = @origin_addr, resource_addr = @resource_addr, aptos_framework = @0x1, creator = @atomic_bridge, moveth = @moveth, admin = @admin, client = @0xdca, master_minter = @master_minter)] fun test_complete_bridge_transfer( origin_account: &signer, resource_addr: signer, @@ -180,7 +209,6 @@ module atomic_bridge::atomic_bridge_counterparty { master_minter: &signer, creator: &signer, moveth: &signer, - source_account: &signer ) acquires BridgeTransferStore, BridgeConfig { set_up_test(origin_account, &resource_addr); @@ -196,7 +224,7 @@ module atomic_bridge::atomic_bridge_counterparty { let hash_lock = keccak256(pre_image); let time_lock = 3600; let amount = 100; - let result = lock_bridge_transfer_assets( + let result = lock_bridge_transfer( origin_account, initiator, bridge_transfer_id, @@ -207,12 +235,12 @@ module atomic_bridge::atomic_bridge_counterparty { ); assert!(result, 1); // Verify that the transfer is stored in pending_transfers - let bridge_store = borrow_global(signer::address_of(&resource_addr)); - let transfer_details: &BridgeTransferDetails = smart_table::borrow(&bridge_store.pending_transfers, bridge_transfer_id); - assert!(transfer_details.recipient == recipient, 2); - assert!(transfer_details.initiator == initiator, 3); - assert!(transfer_details.amount == amount, 5); - assert!(transfer_details.hash_lock == hash_lock, 5); + let store = borrow_global(signer::address_of(&resource_addr)); + let bridge_transfer: &BridgeTransfer = smart_table::borrow(&store.transfers, bridge_transfer_id); + assert!(bridge_transfer.recipient == recipient, 2); + assert!(bridge_transfer.originator == initiator, 3); + assert!(bridge_transfer.amount == amount, 5); + assert!(bridge_transfer.hash_lock == hash_lock, 5); let pre_image = b"secret"; let msg:vector = b"secret"; debug::print(&utf8(msg)); @@ -223,11 +251,51 @@ module atomic_bridge::atomic_bridge_counterparty { ); debug::print(&utf8(msg)); // Verify that the transfer is stored in completed_transfers - let bridge_store = borrow_global(signer::address_of(&resource_addr)); - let transfer_details: &BridgeTransferDetails = smart_table::borrow(&bridge_store. completed_transfers, bridge_transfer_id); - assert!(transfer_details.recipient == recipient, 1); - assert!(transfer_details.amount == amount, 2); - assert!(transfer_details.hash_lock == hash_lock, 3); - assert!(transfer_details.initiator == initiator, 4); + let store = borrow_global(signer::address_of(&resource_addr)); + let bridge_transfer: &BridgeTransfer = smart_table::borrow(&store.transfers, bridge_transfer_id); + assert!(bridge_transfer.recipient == recipient, 1); + assert!(bridge_transfer.amount == amount, 2); + assert!(bridge_transfer.hash_lock == hash_lock, 3); + assert!(bridge_transfer.originator == initiator, 4); + } + + #[test(origin_account = @origin_addr, resource_addr = @resource_addr, aptos_framework = @0x1, creator = @atomic_bridge, moveth = @moveth, admin = @admin, client = @0xdca, master_minter = @master_minter)] + fun test_get_bridge_transfer_details_from_id( + origin_account: &signer, + resource_addr: signer, + client: &signer, + aptos_framework: signer, + master_minter: &signer, + creator: &signer, + moveth: &signer, + ) acquires BridgeTransferStore, BridgeConfig { + set_up_test(origin_account, &resource_addr); + + timestamp::set_time_has_started_for_testing(&aptos_framework); + moveth::init_for_test(moveth); + let receiver_address = @0xdada; + let initiator = b"0x123"; //In real world this would be an ethereum address + let recipient = @0xface; + let asset = moveth::metadata(); + + let bridge_transfer_id = b"transfer1"; + let pre_image = b"secret"; + let hash_lock = keccak256(pre_image); + let time_lock = 3600; + let amount = 100; + let result = lock_bridge_transfer( + origin_account, + initiator, + bridge_transfer_id, + hash_lock, + time_lock, + recipient, + amount + ); + assert!(result, 1); + + let (transfer_originator, transfer_recipient, transfer_amount, transfer_hash_lock, transfer_time_lock, transfer_state) = bridge_transfers(bridge_transfer_id); + assert!(transfer_recipient == recipient, 2); + assert!(transfer_originator == initiator, 3); } } diff --git a/protocol-units/bridge/move-modules/sources/atomic_bridge_initiator.move b/protocol-units/bridge/move-modules/sources/atomic_bridge_initiator.move index e00468bd2..f47202293 100644 --- a/protocol-units/bridge/move-modules/sources/atomic_bridge_initiator.move +++ b/protocol-units/bridge/move-modules/sources/atomic_bridge_initiator.move @@ -13,9 +13,9 @@ module atomic_bridge::atomic_bridge_initiator { use std::debug; use moveth::moveth; - const INITIALIZED: u8 = 0; - const COMPLETED: u8 = 1; - const REFUNDED: u8 = 2; + const INITIALIZED: u8 = 1; + const COMPLETED: u8 = 2; + const REFUNDED: u8 = 3; const EINSUFFICIENT_AMOUNT: u64 = 0; const EINSUFFICIENT_BALANCE: u64 = 1; @@ -25,10 +25,10 @@ module atomic_bridge::atomic_bridge_initiator { const ETIMELOCK_EXPIRED: u64 = 5; const ENOT_EXPIRED: u64 = 6; - struct BridgeTransfer has key, store, drop { - amount: u64, + struct BridgeTransfer has key, store, drop, copy { originator: address, recipient: vector, // eth address + amount: u64, hash_lock: vector, time_lock: u64, state: u8, @@ -65,7 +65,7 @@ module atomic_bridge::atomic_bridge_initiator { bridge_transfer_id: vector, } - entry fun init_module(deployer: &signer) { + fun init_module(deployer: &signer) { let deployer_addr = signer::address_of(deployer); move_to(deployer, BridgeTransferStore { transfers: aptos_std::smart_table::new, BridgeTransfer>(), @@ -80,13 +80,34 @@ module atomic_bridge::atomic_bridge_initiator { }); } + #[view] + public fun bridge_transfers(bridge_transfer_id: vector): (address, vector, u64, vector, u64, u8) acquires BridgeTransferStore, BridgeConfig { + let config_address = borrow_global(@atomic_bridge).bridge_module_deployer; + let store = borrow_global(config_address); + + if (!aptos_std::smart_table::contains(&store.transfers, bridge_transfer_id)) { + abort 0x1; + }; + + let bridge_transfer_ref = aptos_std::smart_table::borrow(&store.transfers, bridge_transfer_id); + + ( + bridge_transfer_ref.originator, + bridge_transfer_ref.recipient, + bridge_transfer_ref.amount, + bridge_transfer_ref.hash_lock, + bridge_transfer_ref.time_lock, + bridge_transfer_ref.state + ) + } + public fun initiate_bridge_transfer( initiator: &signer, recipient: vector, // eth address hash_lock: vector, time_lock: u64, amount: u64 - ): vector acquires BridgeTransferStore, BridgeConfig { + ) : vector acquires BridgeTransferStore, BridgeConfig { let addr = signer::address_of(initiator); let asset = moveth::metadata(); let config_address = borrow_global(@atomic_bridge).bridge_module_deployer; @@ -157,8 +178,6 @@ module atomic_bridge::atomic_bridge_initiator { bridge_transfer_id: copy bridge_transfer_id, pre_image: pre_image, }); - - aptos_std::smart_table::remove(&mut store.transfers, copy bridge_transfer_id); } public fun refund_bridge_transfer( @@ -187,8 +206,6 @@ module atomic_bridge::atomic_bridge_initiator { event::emit_event(&mut store.bridge_transfer_refunded_events, BridgeTransferRefundedEvent { bridge_transfer_id: copy bridge_transfer_id, }); - - aptos_std::smart_table::remove(&mut store.transfers, copy bridge_transfer_id); } #[test_only] @@ -342,7 +359,8 @@ module atomic_bridge::atomic_bridge_initiator { ); let bridge_addr = signer::address_of(atomic_bridge); let store = borrow_global(bridge_addr); - assert!(!aptos_std::smart_table::contains(&store.transfers, copy bridge_transfer_id), 300); + // complete bridge doesn't delete the transfer from the store + assert!(aptos_std::smart_table::contains(&store.transfers, copy bridge_transfer_id), 300); } #[test(creator = @moveth, aptos_framework = @0x1, sender = @0xdaff, atomic_bridge = @atomic_bridge)] @@ -476,4 +494,45 @@ module atomic_bridge::atomic_bridge_initiator { assert!(transfer.state == COMPLETED, 300); } + + #[test(creator = @moveth, aptos_framework = @0x1, sender = @0xdaff, atomic_bridge = @atomic_bridge)] + public fun test_bridge_transfers_view( + sender: &signer, + creator: &signer, + aptos_framework: &signer, + atomic_bridge: &signer + ) acquires BridgeTransferStore, BridgeConfig { + init_test(sender, creator, aptos_framework, atomic_bridge); + + let recipient = b"recipient_address"; + let pre_image = b"pre_image_value"; + let hash_lock = aptos_std::aptos_hash::keccak256(bcs::to_bytes(&pre_image)); + assert!(aptos_std::aptos_hash::keccak256(bcs::to_bytes(&pre_image)) == hash_lock, 5); + let time_lock = 1000; + let amount = 1000; + let sender_address = signer::address_of(sender); + moveth::mint(atomic_bridge, sender_address, amount); + + let bridge_transfer_id = initiate_bridge_transfer( + sender, + recipient, + hash_lock, + time_lock, + amount + ); + + aptos_std::debug::print(&bridge_transfer_id); + // returns a valid transfer + let (transfer_originator, transfer_recipient, transfer_amount, transfer_hash_lock, transfer_time_lock, transfer_state) = bridge_transfers(bridge_transfer_id); + + assert!(transfer_state == INITIALIZED, 6); + aptos_std::debug::print(&transfer_state); + complete_bridge_transfer( + sender, + bridge_transfer_id, + pre_image, + atomic_bridge + ); + aptos_std::debug::print(&transfer_state); + } } \ No newline at end of file