From f768a231ae10752393856280328ed27b9b8a1a85 Mon Sep 17 00:00:00 2001 From: Evan Gray Date: Tue, 8 Apr 2025 15:04:01 -0400 Subject: [PATCH 1/5] sui: initial commit --- README.md | 2 +- sui/executor/.gitignore | 1 + sui/executor/Move.lock | 48 +++++ sui/executor/Move.toml | 14 ++ sui/executor/sources/executor.move | 62 +++++++ sui/executor/sources/utils/bytes.move | 231 +++++++++++++++++++++++++ sui/executor/sources/utils/cursor.move | 59 +++++++ sui/executor/tests/executor_tests.move | 145 ++++++++++++++++ 8 files changed, 561 insertions(+), 1 deletion(-) create mode 100644 sui/executor/.gitignore create mode 100644 sui/executor/Move.lock create mode 100644 sui/executor/Move.toml create mode 100644 sui/executor/sources/executor.move create mode 100644 sui/executor/sources/utils/bytes.move create mode 100644 sui/executor/sources/utils/cursor.move create mode 100644 sui/executor/tests/executor_tests.move diff --git a/README.md b/README.md index 4361b54..706a001 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Provide an execution framework and proof-of-concept (PoC) service for [Wormhole] - [x] [EVM](./evm/) - [x] [SVM](./svm/) -- [ ] Sui Move +- [x] Sui Move - [ ] Aptos Move ## Background diff --git a/sui/executor/.gitignore b/sui/executor/.gitignore new file mode 100644 index 0000000..a007fea --- /dev/null +++ b/sui/executor/.gitignore @@ -0,0 +1 @@ +build/* diff --git a/sui/executor/Move.lock b/sui/executor/Move.lock new file mode 100644 index 0000000..4eed0d6 --- /dev/null +++ b/sui/executor/Move.lock @@ -0,0 +1,48 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 3 +manifest_digest = "FD655AA2017BCDC2BE9BFC9C9A9D9E5E751C2C64258FFA7FB25E2DC0F287E4CA" +deps_digest = "F9B494B64F0615AED0E98FC12A85B85ECD2BC5185C22D30E7F67786BB52E507C" +dependencies = [ + { id = "Bridge", name = "Bridge" }, + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, + { id = "SuiSystem", name = "SuiSystem" }, +] + +[[move.package]] +id = "Bridge" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "04f11afaf5e0", subdir = "crates/sui-framework/packages/bridge" } + +dependencies = [ + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, + { id = "SuiSystem", name = "SuiSystem" }, +] + +[[move.package]] +id = "MoveStdlib" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "04f11afaf5e0", subdir = "crates/sui-framework/packages/move-stdlib" } + +[[move.package]] +id = "Sui" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "04f11afaf5e0", subdir = "crates/sui-framework/packages/sui-framework" } + +dependencies = [ + { id = "MoveStdlib", name = "MoveStdlib" }, +] + +[[move.package]] +id = "SuiSystem" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "04f11afaf5e0", subdir = "crates/sui-framework/packages/sui-system" } + +dependencies = [ + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, +] + +[move.toolchain-version] +compiler-version = "1.46.1" +edition = "2024.beta" +flavor = "sui" diff --git a/sui/executor/Move.toml b/sui/executor/Move.toml new file mode 100644 index 0000000..aa5b744 --- /dev/null +++ b/sui/executor/Move.toml @@ -0,0 +1,14 @@ +[package] +name = "executor" +edition = "2024.beta" +license = "Apache 2.0" +authors = ["Wormhole Labs"] + +[dependencies] + +[addresses] +executor = "0x0" + +[dev-dependencies] + +[dev-addresses] diff --git a/sui/executor/sources/executor.move b/sui/executor/sources/executor.move new file mode 100644 index 0000000..7d9ee16 --- /dev/null +++ b/sui/executor/sources/executor.move @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: Apache-2.0 + +module executor::executor { + use executor::bytes; + use executor::cursor; + use sui::clock::Clock; + use sui::coin::{Coin}; + use sui::event; + use sui::sui::{SUI}; + + const CHAIN_ID: u16 = 21; + + const E_QUOTE_SRC_CHAIN_MISMATCH: u64 = 0; + const E_QUOTE_DST_CHAIN_MISMATCH: u64 = 1; + const E_QUOTE_EXPIRED: u64 = 2; + + public struct RequestForExecution has copy, drop { + quoter_address: vector, + amt_paid: u64, + dst_chain: u16, + dst_addr: vector, + refund_addr: address, + signed_quote: vector, + request_bytes: vector, + relay_instructions: vector, + } + + public fun request_execution( + amount: Coin, + clock: &Clock, + dst_chain: u16, + dst_addr: vector, + refund_addr: address, + signed_quote_bytes: vector, + request_bytes: vector, + relay_instructions: vector + ) { + let mut cursor = cursor::new(signed_quote_bytes); + bytes::take_bytes(&mut cursor, 4); // prefix + let quoter_address = bytes::take_bytes(&mut cursor, 20); + let payee_address = sui::address::from_bytes(bytes::take_bytes(&mut cursor, 32)); + let quote_src_chain = bytes::take_u16_be(&mut cursor); + assert!(quote_src_chain == CHAIN_ID, E_QUOTE_SRC_CHAIN_MISMATCH); + let quote_dst_chain = bytes::take_u16_be(&mut cursor); + assert!(quote_dst_chain == dst_chain, E_QUOTE_DST_CHAIN_MISMATCH); + let expiry_time = bytes::take_u64_be(&mut cursor); + assert!(expiry_time > clock.timestamp_ms() / 1000, E_QUOTE_EXPIRED); + cursor.take_rest(); + let amt_paid = amount.value(); + transfer::public_transfer(amount, payee_address); + event::emit(RequestForExecution { + quoter_address, + amt_paid, + dst_chain, + dst_addr, + refund_addr, + signed_quote: signed_quote_bytes, + request_bytes, + relay_instructions + }); + } +} diff --git a/sui/executor/sources/utils/bytes.move b/sui/executor/sources/utils/bytes.move new file mode 100644 index 0000000..da4e439 --- /dev/null +++ b/sui/executor/sources/utils/bytes.move @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: Apache-2.0 +// Adapted from https://github.com/wormhole-foundation/wormhole/blob/cc9d8222858827afa9f4780164fcce32ba0dfb3a/sui/wormhole/sources/utils/bytes.move + +/// This module implements a library that serializes and deserializes specific +/// types into a buffer (i.e. `vector`). For serialization, the first +/// argument will be of `&mut vector`. For deserialization, the first +/// argument will be of `&mut Cursor` (see `executor::cursor` for more +/// details). +module executor::bytes { + use std::bcs::{Self}; + use executor::cursor::{Self, Cursor}; + + public fun push_u8(buf: &mut vector, v: u8) { + vector::push_back(buf, v); + } + + public fun push_u16_be(buf: &mut vector, value: u16) { + push_reverse(buf, value); + } + + public fun push_u32_be(buf: &mut vector, value: u32) { + push_reverse(buf, value); + } + + public fun push_u64_be(buf: &mut vector, value: u64) { + push_reverse(buf, value); + } + + public fun push_u128_be(buf: &mut vector, value: u128) { + push_reverse(buf, value); + } + + public fun push_u256_be(buf: &mut vector, value: u256) { + push_reverse(buf, value); + } + + public fun take_u8(cur: &mut Cursor): u8 { + cursor::poke(cur) + } + + public fun take_u16_be(cur: &mut Cursor): u16 { + let mut out = 0; + let mut i = 0; + while (i < 2) { + out = (out << 8) + (cursor::poke(cur) as u16); + i = i + 1; + }; + out + } + + public fun take_u32_be(cur: &mut Cursor): u32 { + let mut out = 0; + let mut i = 0; + while (i < 4) { + out = (out << 8) + (cursor::poke(cur) as u32); + i = i + 1; + }; + out + } + + public fun take_u64_be(cur: &mut Cursor): u64 { + let mut out = 0; + let mut i =0; + while (i < 8) { + out = (out << 8) + (cursor::poke(cur) as u64); + i = i + 1; + }; + out + } + + public fun take_u128_be(cur: &mut Cursor): u128 { + let mut out = 0; + let mut i = 0; + while (i < 16) { + out = (out << 8) + (cursor::poke(cur) as u128); + i = i + 1; + }; + out + } + + public fun take_u256_be(cur: &mut Cursor): u256 { + let mut out = 0; + let mut i = 0; + while (i < 32) { + out = (out << 8) + (cursor::poke(cur) as u256); + i = i + 1; + }; + out + } + + public fun take_bytes(cur: &mut Cursor, num_bytes: u64): vector { + let mut out = vector::empty(); + let mut i = 0; + while (i < num_bytes) { + vector::push_back(&mut out, cursor::poke(cur)); + i = i + 1; + }; + out + } + + fun push_reverse(buf: &mut vector, v: T) { + let mut data = bcs::to_bytes(&v); + vector::reverse(&mut data); + vector::append(buf, data); + } +} + +#[test_only] +module executor::bytes_tests { + use executor::bytes::{Self}; + use executor::cursor::{Self}; + + #[test] + fun test_push_u8(){ + let u = 0x12; + let mut s = vector::empty(); + bytes::push_u8(&mut s, u); + let mut cur = cursor::new(s); + let p = bytes::take_u8(&mut cur); + cursor::destroy_empty(cur); + assert!(p==u, 0); + } + + #[test] + fun test_push_u16_be(){ + let u = 0x1234; + let mut s = vector::empty(); + bytes::push_u16_be(&mut s, u); + let mut cur = cursor::new(s); + let p = bytes::take_u16_be(&mut cur); + cursor::destroy_empty(cur); + assert!(p==u, 0); + } + + #[test] + fun test_push_u32_be(){ + let u = 0x12345678; + let mut s = vector::empty(); + bytes::push_u32_be(&mut s, u); + let mut cur = cursor::new(s); + let p = bytes::take_u32_be(&mut cur); + cursor::destroy_empty(cur); + assert!(p==u, 0); + } + + #[test] + fun test_push_u64_be(){ + let u = 0x1234567812345678; + let mut s = vector::empty(); + bytes::push_u64_be(&mut s, u); + let mut cur = cursor::new(s); + let p = bytes::take_u64_be(&mut cur); + cursor::destroy_empty(cur); + assert!(p==u, 0); + } + + #[test] + fun test_push_u128_be(){ + let u = 0x12345678123456781234567812345678; + let mut s = vector::empty(); + bytes::push_u128_be(&mut s, u); + let mut cur = cursor::new(s); + let p = bytes::take_u128_be(&mut cur); + cursor::destroy_empty(cur); + assert!(p==u, 0); + } + + #[test] + fun test_push_u256_be(){ + let u = + 0x4738691759099793746170047375612500000000000000000000000000009876; + let mut s = vector::empty(); + bytes::push_u256_be(&mut s, u); + assert!( + s == x"4738691759099793746170047375612500000000000000000000000000009876", + 0 + ); + } + + #[test] + fun test_take_u8() { + let mut cursor = cursor::new(x"99"); + let byte = bytes::take_u8(&mut cursor); + assert!(byte==0x99, 0); + cursor::destroy_empty(cursor); + } + + #[test] + fun test_take_u16_be() { + let mut cursor = cursor::new(x"9987"); + let u = bytes::take_u16_be(&mut cursor); + assert!(u == 0x9987, 0); + cursor::destroy_empty(cursor); + } + + #[test] + fun test_take_u32_be() { + let mut cursor = cursor::new(x"99876543"); + let u = bytes::take_u32_be(&mut cursor); + assert!(u == 0x99876543, 0); + cursor::destroy_empty(cursor); + } + + #[test] + fun test_take_u64_be() { + let mut cursor = cursor::new(x"1300000025000001"); + let u = bytes::take_u64_be(&mut cursor); + assert!(u == 0x1300000025000001, 0); + cursor::destroy_empty(cursor); + } + + #[test] + fun test_take_u128_be() { + let mut cursor = cursor::new(x"130209AB2500FA0113CD00AE25000001"); + let u = bytes::take_u128_be(&mut cursor); + assert!(u == 0x130209AB2500FA0113CD00AE25000001, 0); + cursor::destroy_empty(cursor); + } + + #[test] + fun test_to_bytes() { + let mut cursor = cursor::new(b"hello world"); + let hello = bytes::take_bytes(&mut cursor, 5); + bytes::take_u8(&mut cursor); + let world = bytes::take_bytes(&mut cursor, 5); + assert!(hello == b"hello", 0); + assert!(world == b"world", 0); + cursor::destroy_empty(cursor); + } + +} diff --git a/sui/executor/sources/utils/cursor.move b/sui/executor/sources/utils/cursor.move new file mode 100644 index 0000000..8decf42 --- /dev/null +++ b/sui/executor/sources/utils/cursor.move @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: Apache-2.0 +// Adapted from https://github.com/wormhole-foundation/wormhole/blob/cc9d8222858827afa9f4780164fcce32ba0dfb3a/sui/wormhole/sources/utils/cursor.move + +/// This module implements a custom type that allows consuming a vector +/// incrementally for parsing operations. It has no drop ability, and the only +/// way to deallocate it is by calling the `destroy_empty` method, which will +/// fail if the whole input hasn't been consumed. +/// +/// This setup statically guarantees that the parsing methods consume the full +/// input. +module executor::cursor { + /// Container for the underlying `vector` data to be consumed. + public struct Cursor { + data: vector, + } + + /// Initialises a cursor from a vector. + public fun new(mut data: vector): Cursor { + // reverse the array so we have access to the first element easily + vector::reverse(&mut data); + Cursor { data } + } + + /// Retrieve underlying data. + public fun data(self: &Cursor): &vector { + &self.data + } + + /// Check whether the underlying data is empty. This method is useful for + /// iterating over a `Cursor` to exhaust its contents. + public fun is_empty(self: &Cursor): bool { + vector::is_empty(&self.data) + } + + /// Destroys an empty cursor. This method aborts if the cursor is not empty. + public fun destroy_empty(cursor: Cursor) { + let Cursor { data } = cursor; + vector::destroy_empty(data); + } + + /// Consumes the rest of the cursor (thus destroying it) and returns the + /// remaining bytes. + /// + /// NOTE: Only use this function if you intend to consume the rest of the + /// bytes. Since the result is a vector, which can be dropped, it is not + /// possible to statically guarantee that the rest will be used. + public fun take_rest(cursor: Cursor): vector { + let Cursor { mut data } = cursor; + // Because the data was reversed in initialization, we need to reverse + // again so it is in the same order as the original input. + vector::reverse(&mut data); + data + } + + /// Retrieve the first element of the cursor and advances it. + public fun poke(self: &mut Cursor): T { + vector::pop_back(&mut self.data) + } +} diff --git a/sui/executor/tests/executor_tests.move b/sui/executor/tests/executor_tests.move new file mode 100644 index 0000000..054db91 --- /dev/null +++ b/sui/executor/tests/executor_tests.move @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module executor::executor_tests { + use executor::executor; + use sui::clock; + use sui::coin::{Self, Coin}; + use sui::sui::{SUI}; + use sui::test_scenario; + + #[test] + fun test_executor() { + let user = @0xCAFE; + let mut my_scenario = test_scenario::begin(user); + let scenario = &mut my_scenario; + let the_clock = clock::create_for_testing(test_scenario::ctx(scenario)); + let amount = coin::mint_for_testing( + 100, + test_scenario::ctx(scenario) + ); + let expected_payee = @0x000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a; + assert!(test_scenario::most_recent_id_for_address>(expected_payee).is_none(), 0); + executor::request_execution( + amount, + &the_clock, + 6, + x"1234567891234567891234567891234512345678912345678912345678912345", + user, + x"455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a001500060000000067dc8c0a00000000000003e800000000000000020000120430544c000000002bb3cab500199f0dc83362b168ade5aa32a99747a0d0b4d7c7d7f9acdee2c62b89de7661dc6968d845bf9c0997553f6f9c0418ba3cee97787eb9c19266754892124c8c65751b", + x"45524e312712000000000000000000000000e2a90da727f328e2324536fe2b4837f6c77dda7d0000000000000000000000000000000000000000000000000000000000000006", + x"0100000000000000000000000000061a8000000000000000000000000000000000" + ); + let effects = test_scenario::next_tx(scenario, user); + assert!(test_scenario::num_user_events(&effects) == 1, 0); + assert!(test_scenario::most_recent_id_for_address>(expected_payee).is_some(), 0); + clock::destroy_for_testing(the_clock); + test_scenario::end(my_scenario); + } + + #[test] + #[expected_failure] + fun test_executor_fail_with_invalid_quote_header() { + let user = @0xCAFE; + let mut my_scenario = test_scenario::begin(user); + let scenario = &mut my_scenario; + let the_clock = clock::create_for_testing(test_scenario::ctx(scenario)); + executor::request_execution( + coin::mint_for_testing( + 100, + test_scenario::ctx(scenario) + ), + &the_clock, + 6, + x"1234567891234567891234567891234512345678912345678912345678912345", + user, + x"455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a001500060000000067dc8c", + x"45524e312712000000000000000000000000e2a90da727f328e2324536fe2b4837f6c77dda7d0000000000000000000000000000000000000000000000000000000000000006", + x"0100000000000000000000000000061a8000000000000000000000000000000000" + ); + let effects = test_scenario::next_tx(scenario, user); + assert!(test_scenario::num_user_events(&effects) == 1, 0); + clock::destroy_for_testing(the_clock); + test_scenario::end(my_scenario); + } + + #[test] + #[expected_failure(abort_code = executor::E_QUOTE_SRC_CHAIN_MISMATCH)] + fun test_executor_fail_with_invalid_source_chain() { + let user = @0xCAFE; + let mut my_scenario = test_scenario::begin(user); + let scenario = &mut my_scenario; + let the_clock = clock::create_for_testing(test_scenario::ctx(scenario)); + executor::request_execution( + coin::mint_for_testing( + 100, + test_scenario::ctx(scenario) + ), + &the_clock, + 6, + x"1234567891234567891234567891234512345678912345678912345678912345", + user, + x"455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a000600060000000067dc8c0a00000000000003e800000000000000020000120430544c000000002bb3cab500199f0dc83362b168ade5aa32a99747a0d0b4d7c7d7f9acdee2c62b89de7661dc6968d845bf9c0997553f6f9c0418ba3cee97787eb9c19266754892124c8c65751b", + x"45524e312712000000000000000000000000e2a90da727f328e2324536fe2b4837f6c77dda7d0000000000000000000000000000000000000000000000000000000000000006", + x"0100000000000000000000000000061a8000000000000000000000000000000000" + ); + let effects = test_scenario::next_tx(scenario, user); + assert!(test_scenario::num_user_events(&effects) == 1, 0); + clock::destroy_for_testing(the_clock); + test_scenario::end(my_scenario); + } + + #[test] + #[expected_failure(abort_code = executor::E_QUOTE_DST_CHAIN_MISMATCH)] + fun test_executor_fail_with_invalid_destination_chain() { + let user = @0xCAFE; + let mut my_scenario = test_scenario::begin(user); + let scenario = &mut my_scenario; + let the_clock = clock::create_for_testing(test_scenario::ctx(scenario)); + executor::request_execution( + coin::mint_for_testing( + 100, + test_scenario::ctx(scenario) + ), + &the_clock, + 10002, + x"1234567891234567891234567891234512345678912345678912345678912345", + user, + x"455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a001500060000000067dc8c0a00000000000003e800000000000000020000120430544c000000002bb3cab500199f0dc83362b168ade5aa32a99747a0d0b4d7c7d7f9acdee2c62b89de7661dc6968d845bf9c0997553f6f9c0418ba3cee97787eb9c19266754892124c8c65751b", + x"45524e312712000000000000000000000000e2a90da727f328e2324536fe2b4837f6c77dda7d0000000000000000000000000000000000000000000000000000000000000006", + x"0100000000000000000000000000061a8000000000000000000000000000000000" + ); + let effects = test_scenario::next_tx(scenario, user); + assert!(test_scenario::num_user_events(&effects) == 1, 0); + clock::destroy_for_testing(the_clock); + test_scenario::end(my_scenario); + } + + #[test] + #[expected_failure(abort_code = executor::E_QUOTE_EXPIRED)] + fun test_executor_fail_with_expired_quote() { + let user = @0xCAFE; + let mut my_scenario = test_scenario::begin(user); + let scenario = &mut my_scenario; + let mut the_clock = clock::create_for_testing(test_scenario::ctx(scenario)); + clock::set_for_testing(&mut the_clock, 1742507018*1000); + executor::request_execution( + coin::mint_for_testing( + 100, + test_scenario::ctx(scenario) + ), + &the_clock, + 6, + x"1234567891234567891234567891234512345678912345678912345678912345", + user, + x"455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a001500060000000067dc8c0a00000000000003e800000000000000020000120430544c000000002bb3cab500199f0dc83362b168ade5aa32a99747a0d0b4d7c7d7f9acdee2c62b89de7661dc6968d845bf9c0997553f6f9c0418ba3cee97787eb9c19266754892124c8c65751b", + x"45524e312712000000000000000000000000e2a90da727f328e2324536fe2b4837f6c77dda7d0000000000000000000000000000000000000000000000000000000000000006", + x"0100000000000000000000000000061a8000000000000000000000000000000000" + ); + let effects = test_scenario::next_tx(scenario, user); + assert!(test_scenario::num_user_events(&effects) == 1, 0); + clock::destroy_for_testing(the_clock); + test_scenario::end(my_scenario); + } + +} From 7c0e8ba28612e33531b06c12f9097c1f36c889c0 Mon Sep 17 00:00:00 2001 From: Evan Gray Date: Tue, 8 Apr 2025 16:41:34 -0400 Subject: [PATCH 2/5] sui: ci --- .github/workflows/sui.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/sui.yml diff --git a/.github/workflows/sui.yml b/.github/workflows/sui.yml new file mode 100644 index 0000000..8a67353 --- /dev/null +++ b/.github/workflows/sui.yml @@ -0,0 +1,17 @@ +name: sui + +on: + pull_request: + +jobs: + test: + name: Sui Test + runs-on: ubuntu-latest + # pushed Apr 8, 2025 at 4:10 pm + container: mysten/sui-tools:sui-v1.46.0-release@sha256:c39b509328319dad3b73dbb4ae3a76d6c502f838b81f908fbc6a4e1da81c7855 + defaults: + run: + working-directory: sui/executor + steps: + - uses: actions/checkout@v4 + - run: sui move test From 15beafd37076cd9d4554f0573e7bfdb5207367b9 Mon Sep 17 00:00:00 2001 From: Evan Gray Date: Tue, 8 Apr 2025 17:12:36 -0400 Subject: [PATCH 3/5] sui: testnet deploy --- sui/executor/Move.lock | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sui/executor/Move.lock b/sui/executor/Move.lock index 4eed0d6..4e03c11 100644 --- a/sui/executor/Move.lock +++ b/sui/executor/Move.lock @@ -46,3 +46,11 @@ dependencies = [ compiler-version = "1.46.1" edition = "2024.beta" flavor = "sui" + +[env] + +[env.testnet] +chain-id = "4c78adac" +original-published-id = "0xe3db3cba7f693dea37ac0d403ddae4defa169d76f99f5664fb8aa354ee8ad187" +latest-published-id = "0xe3db3cba7f693dea37ac0d403ddae4defa169d76f99f5664fb8aa354ee8ad187" +published-version = "1" From 50a47da261fc99252a671ba164b6256537c0e5ef Mon Sep 17 00:00:00 2001 From: Evan Gray Date: Wed, 9 Apr 2025 10:19:44 -0400 Subject: [PATCH 4/5] sui: executor_requests --- sui/executor_requests/.gitignore | 1 + sui/executor_requests/Move.lock | 68 +++++++++++++++++++ sui/executor_requests/Move.toml | 15 ++++ .../sources/executor_requests.move | 35 ++++++++++ .../tests/executor_requests_tests.move | 46 +++++++++++++ 5 files changed, 165 insertions(+) create mode 100644 sui/executor_requests/.gitignore create mode 100644 sui/executor_requests/Move.lock create mode 100644 sui/executor_requests/Move.toml create mode 100644 sui/executor_requests/sources/executor_requests.move create mode 100644 sui/executor_requests/tests/executor_requests_tests.move diff --git a/sui/executor_requests/.gitignore b/sui/executor_requests/.gitignore new file mode 100644 index 0000000..a007fea --- /dev/null +++ b/sui/executor_requests/.gitignore @@ -0,0 +1 @@ +build/* diff --git a/sui/executor_requests/Move.lock b/sui/executor_requests/Move.lock new file mode 100644 index 0000000..a1d030f --- /dev/null +++ b/sui/executor_requests/Move.lock @@ -0,0 +1,68 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 3 +manifest_digest = "2EB121A47DDF68A19733CCDFA38A690E056017B248E4FB1A3B4B53A8BFE42ECF" +deps_digest = "397E6A9F7A624706DBDFEE056CE88391A15876868FD18A88504DA74EB458D697" +dependencies = [ + { id = "Bridge", name = "Bridge" }, + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, + { id = "SuiSystem", name = "SuiSystem" }, + { id = "executor", name = "executor" }, +] + +[[move.package]] +id = "Bridge" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "04f11afaf5e0", subdir = "crates/sui-framework/packages/bridge" } + +dependencies = [ + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, + { id = "SuiSystem", name = "SuiSystem" }, +] + +[[move.package]] +id = "MoveStdlib" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "04f11afaf5e0", subdir = "crates/sui-framework/packages/move-stdlib" } + +[[move.package]] +id = "Sui" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "04f11afaf5e0", subdir = "crates/sui-framework/packages/sui-framework" } + +dependencies = [ + { id = "MoveStdlib", name = "MoveStdlib" }, +] + +[[move.package]] +id = "SuiSystem" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "04f11afaf5e0", subdir = "crates/sui-framework/packages/sui-system" } + +dependencies = [ + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, +] + +[[move.package]] +id = "executor" +source = { local = "../executor" } + +dependencies = [ + { id = "Bridge", name = "Bridge" }, + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, + { id = "SuiSystem", name = "SuiSystem" }, +] + +[move.toolchain-version] +compiler-version = "1.46.1" +edition = "2024.beta" +flavor = "sui" + +[env] + +[env.testnet] +chain-id = "4c78adac" +original-published-id = "0xb34c38614f2a4a875f3cd76ffe9f23f85bbb7a176e44c4c448bb669c28c945f9" +latest-published-id = "0xb34c38614f2a4a875f3cd76ffe9f23f85bbb7a176e44c4c448bb669c28c945f9" +published-version = "1" diff --git a/sui/executor_requests/Move.toml b/sui/executor_requests/Move.toml new file mode 100644 index 0000000..00dc4ef --- /dev/null +++ b/sui/executor_requests/Move.toml @@ -0,0 +1,15 @@ +[package] +name = "executor_requests" +edition = "2024.beta" +license = "Apache 2.0" +authors = ["Wormhole Labs"] + +[dependencies.executor] +local = "../executor" + +[addresses] +executor_requests = "0x0" + +[dev-dependencies] + +[dev-addresses] diff --git a/sui/executor_requests/sources/executor_requests.move b/sui/executor_requests/sources/executor_requests.move new file mode 100644 index 0000000..27509d8 --- /dev/null +++ b/sui/executor_requests/sources/executor_requests.move @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 + +module executor_requests::executor_requests { + use executor::bytes; + + const REQ_VAA_V1: vector = b"ERV1"; + const REQ_CCTP_V1: vector = b"ERC1"; + + const E_INVALID_VEC_LENGTH: u64 = 0; + + public fun make_vaa_v1_request( + emitter_chain: u16, + emitter_address: vector, + sequence: u64 + ): vector { + assert!(emitter_address.length() == 32,E_INVALID_VEC_LENGTH); + let mut ret = vector::empty(); + ret.append(REQ_VAA_V1); + bytes::push_u16_be(&mut ret, emitter_chain); + ret.append(emitter_address); + bytes::push_u64_be(&mut ret, sequence); + ret + } + + public fun make_cctp_v1_request( + src_domain: u32, + nonce: u64, + ): vector { + let mut ret = vector::empty(); + ret.append(REQ_CCTP_V1); + bytes::push_u32_be(&mut ret, src_domain); + bytes::push_u64_be(&mut ret, nonce); + ret + } +} diff --git a/sui/executor_requests/tests/executor_requests_tests.move b/sui/executor_requests/tests/executor_requests_tests.move new file mode 100644 index 0000000..d4d3f83 --- /dev/null +++ b/sui/executor_requests/tests/executor_requests_tests.move @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module executor_requests::executor_requests_tests { + use executor_requests::executor_requests; + + #[test] + fun test_make_vaa_v1_request() { + let res = executor_requests::make_vaa_v1_request( + 10002, + x"000000000000000000000000d4a6a72a025599fd7357c0f157c718d0f5e38c76", + 29 + ); + assert!(res == x"455256312712000000000000000000000000d4a6a72a025599fd7357c0f157c718d0f5e38c76000000000000001d", 0); + } + + #[test] + fun test_make_cctp_v1_request() { + let res = executor_requests::make_cctp_v1_request( + 6, + 6344 + ); + assert!(res == x"455243310000000600000000000018c8", 0); + } + + #[test] + #[expected_failure(abort_code = executor_requests::E_INVALID_VEC_LENGTH)] + fun test_make_vaa_v1_request_fail_with_emitter_too_short() { + executor_requests::make_vaa_v1_request( + 10002, + x"000000000000000000000000d4a6a72a025599fd7357c0f157c718d0f5e38c", + 29 + ); + } + + #[test] + #[expected_failure(abort_code = executor_requests::E_INVALID_VEC_LENGTH)] + fun test_make_vaa_v1_request_fail_with_emitter_too_long() { + executor_requests::make_vaa_v1_request( + 10002, + x"000000000000000000000000d4a6a72a025599fd7357c0f157c718d0f5e38c7600", + 29 + ); + } + +} From 51d27013b85e232bdcf17fea1ab22a244dd05fd5 Mon Sep 17 00:00:00 2001 From: Evan Gray Date: Thu, 10 Apr 2025 10:31:14 -0400 Subject: [PATCH 5/5] sui: dst_addr bytes32 --- sui/executor/Move.lock | 4 ++-- sui/executor/sources/executor.move | 4 ++-- sui/executor/tests/executor_tests.move | 10 +++++----- sui/executor_requests/Move.lock | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sui/executor/Move.lock b/sui/executor/Move.lock index 4e03c11..f5aca3d 100644 --- a/sui/executor/Move.lock +++ b/sui/executor/Move.lock @@ -51,6 +51,6 @@ flavor = "sui" [env.testnet] chain-id = "4c78adac" -original-published-id = "0xe3db3cba7f693dea37ac0d403ddae4defa169d76f99f5664fb8aa354ee8ad187" -latest-published-id = "0xe3db3cba7f693dea37ac0d403ddae4defa169d76f99f5664fb8aa354ee8ad187" +original-published-id = "0x4000cfe2955d8355b3d3cf186f854fea9f787a457257056926fde1ec977670eb" +latest-published-id = "0x4000cfe2955d8355b3d3cf186f854fea9f787a457257056926fde1ec977670eb" published-version = "1" diff --git a/sui/executor/sources/executor.move b/sui/executor/sources/executor.move index 7d9ee16..43c0f9a 100644 --- a/sui/executor/sources/executor.move +++ b/sui/executor/sources/executor.move @@ -18,7 +18,7 @@ module executor::executor { quoter_address: vector, amt_paid: u64, dst_chain: u16, - dst_addr: vector, + dst_addr: address, refund_addr: address, signed_quote: vector, request_bytes: vector, @@ -29,7 +29,7 @@ module executor::executor { amount: Coin, clock: &Clock, dst_chain: u16, - dst_addr: vector, + dst_addr: address, // akin to bytes32 refund_addr: address, signed_quote_bytes: vector, request_bytes: vector, diff --git a/sui/executor/tests/executor_tests.move b/sui/executor/tests/executor_tests.move index 054db91..aa01f32 100644 --- a/sui/executor/tests/executor_tests.move +++ b/sui/executor/tests/executor_tests.move @@ -24,7 +24,7 @@ module executor::executor_tests { amount, &the_clock, 6, - x"1234567891234567891234567891234512345678912345678912345678912345", + @0x1234567891234567891234567891234512345678912345678912345678912345, user, x"455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a001500060000000067dc8c0a00000000000003e800000000000000020000120430544c000000002bb3cab500199f0dc83362b168ade5aa32a99747a0d0b4d7c7d7f9acdee2c62b89de7661dc6968d845bf9c0997553f6f9c0418ba3cee97787eb9c19266754892124c8c65751b", x"45524e312712000000000000000000000000e2a90da727f328e2324536fe2b4837f6c77dda7d0000000000000000000000000000000000000000000000000000000000000006", @@ -51,7 +51,7 @@ module executor::executor_tests { ), &the_clock, 6, - x"1234567891234567891234567891234512345678912345678912345678912345", + @0x1234567891234567891234567891234512345678912345678912345678912345, user, x"455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a001500060000000067dc8c", x"45524e312712000000000000000000000000e2a90da727f328e2324536fe2b4837f6c77dda7d0000000000000000000000000000000000000000000000000000000000000006", @@ -77,7 +77,7 @@ module executor::executor_tests { ), &the_clock, 6, - x"1234567891234567891234567891234512345678912345678912345678912345", + @0x1234567891234567891234567891234512345678912345678912345678912345, user, x"455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a000600060000000067dc8c0a00000000000003e800000000000000020000120430544c000000002bb3cab500199f0dc83362b168ade5aa32a99747a0d0b4d7c7d7f9acdee2c62b89de7661dc6968d845bf9c0997553f6f9c0418ba3cee97787eb9c19266754892124c8c65751b", x"45524e312712000000000000000000000000e2a90da727f328e2324536fe2b4837f6c77dda7d0000000000000000000000000000000000000000000000000000000000000006", @@ -103,7 +103,7 @@ module executor::executor_tests { ), &the_clock, 10002, - x"1234567891234567891234567891234512345678912345678912345678912345", + @0x1234567891234567891234567891234512345678912345678912345678912345, user, x"455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a001500060000000067dc8c0a00000000000003e800000000000000020000120430544c000000002bb3cab500199f0dc83362b168ade5aa32a99747a0d0b4d7c7d7f9acdee2c62b89de7661dc6968d845bf9c0997553f6f9c0418ba3cee97787eb9c19266754892124c8c65751b", x"45524e312712000000000000000000000000e2a90da727f328e2324536fe2b4837f6c77dda7d0000000000000000000000000000000000000000000000000000000000000006", @@ -130,7 +130,7 @@ module executor::executor_tests { ), &the_clock, 6, - x"1234567891234567891234567891234512345678912345678912345678912345", + @0x1234567891234567891234567891234512345678912345678912345678912345, user, x"455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a001500060000000067dc8c0a00000000000003e800000000000000020000120430544c000000002bb3cab500199f0dc83362b168ade5aa32a99747a0d0b4d7c7d7f9acdee2c62b89de7661dc6968d845bf9c0997553f6f9c0418ba3cee97787eb9c19266754892124c8c65751b", x"45524e312712000000000000000000000000e2a90da727f328e2324536fe2b4837f6c77dda7d0000000000000000000000000000000000000000000000000000000000000006", diff --git a/sui/executor_requests/Move.lock b/sui/executor_requests/Move.lock index a1d030f..fd915f2 100644 --- a/sui/executor_requests/Move.lock +++ b/sui/executor_requests/Move.lock @@ -63,6 +63,6 @@ flavor = "sui" [env.testnet] chain-id = "4c78adac" -original-published-id = "0xb34c38614f2a4a875f3cd76ffe9f23f85bbb7a176e44c4c448bb669c28c945f9" -latest-published-id = "0xb34c38614f2a4a875f3cd76ffe9f23f85bbb7a176e44c4c448bb669c28c945f9" +original-published-id = "0x2d9ccf3cce3f7dce408e5455e90b80a8161ad9673d1366c2a5def60ad93657a8" +latest-published-id = "0x2d9ccf3cce3f7dce408e5455e90b80a8161ad9673d1366c2a5def60ad93657a8" published-version = "1"