Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/sui.yml
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions sui/executor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/*
56 changes: 56 additions & 0 deletions sui/executor/Move.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# @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"

[env]

[env.testnet]
chain-id = "4c78adac"
original-published-id = "0x4000cfe2955d8355b3d3cf186f854fea9f787a457257056926fde1ec977670eb"
latest-published-id = "0x4000cfe2955d8355b3d3cf186f854fea9f787a457257056926fde1ec977670eb"
published-version = "1"
14 changes: 14 additions & 0 deletions sui/executor/Move.toml
Original file line number Diff line number Diff line change
@@ -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]
62 changes: 62 additions & 0 deletions sui/executor/sources/executor.move
Original file line number Diff line number Diff line change
@@ -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<u8>,
amt_paid: u64,
dst_chain: u16,
dst_addr: address,
refund_addr: address,
signed_quote: vector<u8>,
request_bytes: vector<u8>,
relay_instructions: vector<u8>,
}

public fun request_execution(
amount: Coin<SUI>,
clock: &Clock,
dst_chain: u16,
dst_addr: address, // akin to bytes32
refund_addr: address,
signed_quote_bytes: vector<u8>,
request_bytes: vector<u8>,
relay_instructions: vector<u8>
) {
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
});
}
}
231 changes: 231 additions & 0 deletions sui/executor/sources/utils/bytes.move
Original file line number Diff line number Diff line change
@@ -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<u8>`). For serialization, the first
/// argument will be of `&mut vector<u8>`. For deserialization, the first
/// argument will be of `&mut Cursor<u8>` (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<u8>, v: u8) {
vector::push_back<u8>(buf, v);
}

public fun push_u16_be(buf: &mut vector<u8>, value: u16) {
push_reverse(buf, value);
}

public fun push_u32_be(buf: &mut vector<u8>, value: u32) {
push_reverse(buf, value);
}

public fun push_u64_be(buf: &mut vector<u8>, value: u64) {
push_reverse(buf, value);
}

public fun push_u128_be(buf: &mut vector<u8>, value: u128) {
push_reverse(buf, value);
}

public fun push_u256_be(buf: &mut vector<u8>, value: u256) {
push_reverse(buf, value);
}

public fun take_u8(cur: &mut Cursor<u8>): u8 {
cursor::poke(cur)
}

public fun take_u16_be(cur: &mut Cursor<u8>): 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<u8>): 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<u8>): 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<u8>): 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<u8>): 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<u8>, num_bytes: u64): vector<u8> {
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<T: drop>(buf: &mut vector<u8>, 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);
}

}
Loading
Loading