From a730580b3a06652cb0e5aae1dff66dc2781d93af Mon Sep 17 00:00:00 2001 From: Foivos Date: Fri, 29 Nov 2024 14:19:40 +0100 Subject: [PATCH 01/68] Add a readme and some QOL code changes to abi --- .changeset/four-cows-shout.md | 5 + move/abi/README.md | 112 ++++++++++++++++++++++ move/abi/sources/abi.move | 175 ++++++++++++++++++++++------------ 3 files changed, 232 insertions(+), 60 deletions(-) create mode 100644 .changeset/four-cows-shout.md create mode 100644 move/abi/README.md diff --git a/.changeset/four-cows-shout.md b/.changeset/four-cows-shout.md new file mode 100644 index 00000000..e075fa7f --- /dev/null +++ b/.changeset/four-cows-shout.md @@ -0,0 +1,5 @@ +--- +'@axelar-network/axelar-cgp-sui': patch +--- + +Added a two utility function in abi to allow for structs and nested vectors to be encoded/decoded, added a readme to abi, and used macros to clean up the code a bit. diff --git a/move/abi/README.md b/move/abi/README.md new file mode 100644 index 00000000..6274d6fe --- /dev/null +++ b/move/abi/README.md @@ -0,0 +1,112 @@ +# Abi + +This package aims to port abi encoding and decoding capabilities to Sui. Read more about the specification of abi encoding [here](https://docs.soliditylang.org/en/develop/abi-spec.html#formal-specification-of-the-encoding) + +## Singletons + +There are no singletons in this package. + +## Types + +There are two types exported by this package: `AbiWriter` and `AbiReader`. + +### `AbiWriter` + +This type can be used to encode abi data. It has the following relevant functions: +- `abi::new_writer(length: u64): AbiWriter`: Creates a new `AbiWriter` with the specified length (number of encoded arguments) +- `abi::into_bytes(self: AbiWriter): vector`: Destroys an `AbiWriter` and returns the encoded bytes for it. +- `abi::write_u256(self: &mut AbiWriter, var: u256): &mut AbiWriter`: Writes the provided `u256` into the next slot in the `AbiWriter`. This should be used to write all fixed length variables (`u8`, `u16`, `u32`, `u64`, `u128`, `address` for example) by converting them to `u256`. +- `abi::write_u8(self: &mut AbiWriter, var: u8): &mut AbiWriter`: Wrapper for the above for `u8` specifically. +- `abi::write_bytes(self: &mut AbiWriter, var: vector): &mut AbiWriter`: Writes the provided bytes into the next slot in the `AbiWriter`. This should be used to write all types that are equivelant to `vector` (`ascii::String` and `string::String` for example) by converting them to `vector`. +- `abi::write_vector_u256(self: &mut AbiWriter, var: vector,): &mut AbiWriter`: Writes the provided `vector` into the next slot in the `AbiWriter`. This should be used for vectors of other fixed length variables as well. +- `abi::write_vector_bytes(self: &mut AbiWriter, var: vector>,): &mut AbiWriter`: Writes the provided `vector>` into the nexts slot in the `AbiWriter`. This should be used for vectors of other variable length variables as well. +- `abi::write_bytes_raw(self: &mut AbiWriter, var: vector,): &mut AbiWriter`: Writes the raw bytes provided to the next slot of the `AbiWriter`. These bytes are not length prefixed, and can therefore not be decoded as bytes. The purpose of this function is to allow for encoding of more complex, unavailable structs. + +#### Example +```rust +let mut writer = abi::new_writer(4); +writer + .write_u256(1234) + .write_bytes(b"some_bytes") + .write_vector_u256(vector[12, 34, 56]) + .write_vector_bytes(vector[b"some", b"more", b"bytes"]); +let encoded_data = writer.into_bytes(); +``` + +#### More complex types +More complex types are curently not supported. This is because Sui Move does not support any sort of type inspection (like `is_vector`) to recursively encode vectors. However with `abi::write_bytes_raw` these types can be encoded with some extra work from the user. +For example to encode a struct consisting of `u256` called `number` and a `vector` called `data` into an `AbiWriter` named `writer` a user could do +```rust +let mut struct_writer = new_writer(2); +struct_writer + .write_u256(number) + .write_bytes(data); +writer + .write_bytes_raw(struct_writer.into_bytes()); +``` +As another example, to abi encode a `vector>` named `table` into an `AbiWriter` named `writer` a user could do +```rust +let length = table.length(); + +let mut length_writer = new_writer(1); +length_writer.write_u256(length as u256); +let mut bytes = length_writer.into_bytes(); + +let mut table_writer = new_writer(length); +table.do!(|row| { + table_writer.write_vector_u256(row); +}); +bytes.append(table_writer.into_bytes()); + +writer + .write_bytes_raw(bytes); +``` + +### `AbiReader` + +This type can be used to decode abi enocded data. The relevant functions are as follows: +- `abi::new_reader(bytes: vector): AbiReader`: Creates a new `AbiReader` to decode the bytes provided. +- `abi::into_remaining_bytes(self: AbiReader): vector`: Get all the bytes stored in the `AbiReader` (name is misleading). +- `abi::read_u256(self: &mut AbiReader): u256`: Read a `u256` from the next slot of the `AbiReader`. Should be used to read other fixed length types as well. +- `abi::read_u8(self: &mut AbiReader): u8`: Wrapper for the above function for `u8`. +- `abi::skip_slot(self: &mut AbiReader)`: Used to ingore a slot on the `AbiReader`, used if it has data encoded there that should be ignored. +- `abi::read_bytes(self: &mut AbiReader): vector<8>`: Read a `vector` from the next slot of the `AbiReader`. Should be used to read other variable length types as well. +- `abi::read_vector_u256(self: &mut AbiReader): vector`: Read a `vector` from the next slot of the `AbiReader`. Should be used to read other fixed length types as well. +- `abi::read_vector_bytes(self: &mut AbiReader): vector>`: Read a `vector>` from the next slot of the `AbiReader`. Should be used to read other vectors of variable length types as well (such as `vector`). +- `abi::read_bytes_raw(self: &mut AbiReader): vector`: Read the raw bytes encoded in the next slot of the `AbiReader`. This will include any bytes encoded after the raw bytes desired which should be ignored. + +#### Example +```rust +let mut reader = abi::new_reader(data); +let number = reader.read_u256(); +let name = reader.read_bytes().to_string(); +let addresses = reader.read_vector_u256().map!(|val| sui::address::from_u256(val)); +let info = reader.read_vector_bytes(); +``` + +#### More Complex Types + +For more complex types like structs or nested vectors `read_bytes_raw` can be used and decoded. For to read a struct that contains a `u256` and a `vector` from an `AbiReader` called `reader` a user may: +```rust + let struct_bytes = reader.read_bytes_raw(); + + let mut struct_reader = new_reader(struct_bytes); + let number = struct_reader.read_u256(); + let data = struct_reader.read_bytes(); +``` +As another example, to decode a `vector>` into a variable called table from an `AbiReader` called `reader` a user can: +```rust +let mut table_bytes = reader.read_bytes_raw(); +let mut length_bytes = vector[]; + +// Split the data into the lenth and the actual table contents. +32u64.do!(|_| length_bytes.push_back(table_bytes.remove(0))); + +let mut length_reader = new_reader(length_bytes); +let length = length_reader.read_u256(); + +let mut table = vector[]; +let mut table_reader = new_reader(table_bytes); +length.do!(|_| table.push_back(table_reader.read_vector_u256())); +``` + diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 09e08a66..03d4af85 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -4,6 +4,13 @@ /// ABI Specification: https://docs.soliditylang.org/en/v0.8.26/abi-spec.html module abi::abi; +use sui::bcs; + +// --------- +// Constants +// --------- +const BYTES_IN_U256: u64 = 32; + // ----- // Types // ----- @@ -33,12 +40,8 @@ public fun new_reader(bytes: vector): AbiReader { public fun new_writer(length: u64): AbiWriter { let mut bytes = vector[]; - let mut i = 0; - while (i < 32 * length) { - bytes.push_back(0); - i = i + 1; - }; + (BYTES_IN_U256 * length).do!(|_| bytes.push_back(0)); AbiWriter { bytes, @@ -61,15 +64,11 @@ public fun into_remaining_bytes(self: AbiReader): vector { public fun read_u256(self: &mut AbiReader): u256 { let mut var = 0u256; - let mut i = 0; let pos = self.pos; - while (i < 32) { - var = (var << 8) | (self.bytes[i + pos] as u256); - i = i + 1; - }; + BYTES_IN_U256.do!(|i| var = (var << 8) | (self.bytes[i + pos] as u256)); - self.pos = pos + 32; + self.pos = pos + BYTES_IN_U256; var } @@ -79,7 +78,7 @@ public fun read_u8(self: &mut AbiReader): u8 { } public fun skip_slot(self: &mut AbiReader) { - self.pos = self.pos + 32; + self.pos = self.pos + BYTES_IN_U256; } public fun read_bytes(self: &mut AbiReader): vector { @@ -92,7 +91,7 @@ public fun read_bytes(self: &mut AbiReader): vector { let var = self.decode_bytes(); // Move position to the next slot - self.pos = pos + 32; + self.pos = pos + BYTES_IN_U256; var } @@ -107,14 +106,9 @@ public fun read_vector_u256(self: &mut AbiReader): vector { let length = self.read_u256() as u64; - let mut i = 0; + length.do!(|_| var.push_back(self.read_u256())); - while (i < length) { - var.push_back(self.read_u256()); - i = i + 1; - }; - - self.pos = pos + 32; + self.pos = pos + BYTES_IN_U256; var } @@ -133,33 +127,36 @@ public fun read_vector_bytes(self: &mut AbiReader): vector> { let length = self.read_u256() as u64; self.head = self.pos; - let mut i = 0; - - while (i < length) { - var.push_back(self.read_bytes()); - - i = i + 1; - }; + length.do!(|_| var.push_back(self.read_bytes())); // Move position to the next slot - self.pos = pos + 32; + self.pos = pos + BYTES_IN_U256; self.head = head; var } +public fun read_bytes_raw(self: &mut AbiReader): vector { + // Move position to the start of the bytes + let offset = self.read_u256() as u64; + let length = self.bytes.length() - offset; + + let mut var = vector[]; + length.do!(|i| var.push_back(self.bytes[offset + i])); + + var +} + public fun write_u256(self: &mut AbiWriter, var: u256): &mut AbiWriter { let pos = self.pos; - let mut i = 0; - while (i < 32) { + BYTES_IN_U256.do!(|i| { let exp = ((31 - i) * 8 as u8); let byte = (var >> exp & 255 as u8); *&mut self.bytes[i + pos] = byte; - i = i + 1; - }; + }); - self.pos = pos + 32; + self.pos = pos + BYTES_IN_U256; self } @@ -189,11 +186,9 @@ public fun write_vector_u256( let length = var.length(); self.append_u256(length as u256); - let mut i = 0; - while (i < length) { - self.append_u256(var[i]); - i = i + 1; - }; + var.do!(|val| { + self.append_u256(val) + }); self } @@ -209,28 +204,35 @@ public fun write_vector_bytes( self.append_u256(length as u256); let mut writer = new_writer(length); - let mut i = 0; - - while (i < length) { - writer.write_bytes(var[i]); - i = i + 1; - }; + var.do!(|val| { + writer.write_bytes(val); + }); self.append_bytes(writer.into_bytes()); self } +public fun write_bytes_raw( + self: &mut AbiWriter, + var: vector, +): &mut AbiWriter { + let offset = self.bytes.length() as u256; + self.write_u256(offset); + + self.append_bytes(var); + + self +} + // ------------------ // Internal Functions // ------------------ fun append_u256(self: &mut AbiWriter, var: u256) { - let mut i = 0; - while (i < 32) { - self.bytes.push_back(((var >> ((31 - i) * 8 as u8)) & 255 as u8)); - i = i + 1; - }; + let mut bytes = bcs::to_bytes(&var); + bytes.reverse(); + self.bytes.append(bytes) } fun append_bytes(self: &mut AbiWriter, var: vector) { @@ -241,12 +243,7 @@ fun append_bytes(self: &mut AbiWriter, var: vector) { self.bytes.append(var); - let mut i = 0u64; - - while (i < 31 - (length - 1) % 32) { - self.bytes.push_back(0); - i = i + 1; - }; + (31 - (length - 1) % 32).do!(|_| self.bytes.push_back(0)); } fun decode_bytes(self: &mut AbiReader): vector { @@ -254,12 +251,8 @@ fun decode_bytes(self: &mut AbiReader): vector { let pos = self.pos; let mut bytes = vector[]; - let mut i = 0; - while (i < length) { - bytes.push_back(self.bytes[i + pos]); - i = i + 1; - }; + length.do!(|i| bytes.push_back(self.bytes[i + pos])); bytes } @@ -358,3 +351,65 @@ fun test_multiple() { assert!(reader.read_vector_u256() == input3); assert!(reader.read_vector_bytes() == input4); } + +#[test] +fun test_raw_struct() { + let number = 3; + let data = b"data"; + + let mut writer = new_writer(1); + let mut struct_writer = new_writer(2); + struct_writer.write_u256(number).write_bytes(data); + writer.write_bytes_raw(struct_writer.into_bytes()); + + let bytes = writer.into_bytes(); + + let mut reader = new_reader(bytes); + + let struct_bytes = reader.read_bytes_raw(); + + let mut struct_reader = new_reader(struct_bytes); + + assert!(struct_reader.read_u256() == number); + assert!(struct_reader.read_bytes() == data); +} + +#[test] +fun test_raw_table() { + let table = vector[vector[1, 2, 3], vector[4, 5, 6]]; + + let mut writer = new_writer(1); + + let length = table.length(); + + let mut length_writer = new_writer(1); + length_writer.write_u256(length as u256); + let mut bytes = length_writer.into_bytes(); + + let mut table_writer = new_writer(length); + table.do!(|row| { + table_writer.write_vector_u256(row); + }); + bytes.append(table_writer.into_bytes()); + + writer.write_bytes_raw(bytes); + + let bytes = writer.into_bytes(); + + let mut reader = new_reader(bytes); + + let mut table_bytes = reader.read_bytes_raw(); + let mut length_bytes = vector[]; + + // Split the data into the lenth and the actual table contents + BYTES_IN_U256.do!(|_| length_bytes.push_back(table_bytes.remove(0))); + + let mut length_reader = new_reader(length_bytes); + let length = length_reader.read_u256(); + + let mut table_read = vector[]; + let mut table_reader = new_reader(table_bytes); + length.do!(|_| table_read.push_back(table_reader.read_vector_u256())); + + assert!(table_read == table); +} From 09b8e0ce1ae37ee670da8af8d0c4b59038f2dc56 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 2 Dec 2024 15:11:13 +0200 Subject: [PATCH 02/68] update interface --- test/testdata/interface_abi_abi.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/testdata/interface_abi_abi.json b/test/testdata/interface_abi_abi.json index a1b25056..6b321d15 100644 --- a/test/testdata/interface_abi_abi.json +++ b/test/testdata/interface_abi_abi.json @@ -112,6 +112,14 @@ }, "returnType": "vector>" }, + "read_bytes_raw": { + "name": "read_bytes_raw", + "visibility": "public", + "params": { + "self#0#0": "&mut AbiReader" + }, + "returnType": "vector" + }, "write_u256": { "name": "write_u256", "visibility": "public", @@ -156,6 +164,15 @@ "var#0#0": "vector>" }, "returnType": "&mut AbiWriter" + }, + "write_bytes_raw": { + "name": "write_bytes_raw", + "visibility": "public", + "params": { + "self#0#0": "&mut AbiWriter", + "var#0#0": "vector" + }, + "returnType": "&mut AbiWriter" } } } From 9c1c5c8fbb8b98203ac3af2fb4be99c9107b880b Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 12:02:54 +0200 Subject: [PATCH 03/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 03d4af85..fa526c48 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -44,7 +44,7 @@ public fun new_writer(length: u64): AbiWriter { (BYTES_IN_U256 * length).do!(|_| bytes.push_back(0)); AbiWriter { - bytes, + bytes: vector::tabulate!(BYTES_IN_U256 * length, |_| 0); pos: 0, } } From bd2497136149dd4c87d6dd661cacea0890a6b43f Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 12:03:53 +0200 Subject: [PATCH 04/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 1 - 1 file changed, 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index fa526c48..80e68074 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -39,7 +39,6 @@ public fun new_reader(bytes: vector): AbiReader { } public fun new_writer(length: u64): AbiWriter { - let mut bytes = vector[]; (BYTES_IN_U256 * length).do!(|_| bytes.push_back(0)); From cf0dc46b9c25bfcf6919564977702c9105b17752 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 12:03:58 +0200 Subject: [PATCH 05/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 1 - 1 file changed, 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 80e68074..a97fb752 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -40,7 +40,6 @@ public fun new_reader(bytes: vector): AbiReader { public fun new_writer(length: u64): AbiWriter { - (BYTES_IN_U256 * length).do!(|_| bytes.push_back(0)); AbiWriter { bytes: vector::tabulate!(BYTES_IN_U256 * length, |_| 0); From 411973842bb0a89a77a74d4159246a30fa64c4f8 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 12:04:52 +0200 Subject: [PATCH 06/68] fix small syntax error --- move/abi/sources/abi.move | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index a97fb752..18a8e5e9 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -39,10 +39,8 @@ public fun new_reader(bytes: vector): AbiReader { } public fun new_writer(length: u64): AbiWriter { - - AbiWriter { - bytes: vector::tabulate!(BYTES_IN_U256 * length, |_| 0); + bytes: vector::tabulate!(BYTES_IN_U256 * length, |_| 0), pos: 0, } } From 00d4f8da0fa2066fe149589b39b67086a16d56a8 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 12:05:09 +0200 Subject: [PATCH 07/68] Update .changeset/four-cows-shout.md Co-authored-by: Milap Sheth --- .changeset/four-cows-shout.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/four-cows-shout.md b/.changeset/four-cows-shout.md index e075fa7f..976b5dca 100644 --- a/.changeset/four-cows-shout.md +++ b/.changeset/four-cows-shout.md @@ -1,5 +1,5 @@ --- -'@axelar-network/axelar-cgp-sui': patch +'@axelar-network/axelar-cgp-sui': minor --- Added a two utility function in abi to allow for structs and nested vectors to be encoded/decoded, added a readme to abi, and used macros to clean up the code a bit. From cfbc9c8c3b14c9b6a1d2e82d5bce7d9b26ca75d3 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 12:05:14 +0200 Subject: [PATCH 08/68] Update .changeset/four-cows-shout.md Co-authored-by: Milap Sheth --- .changeset/four-cows-shout.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/four-cows-shout.md b/.changeset/four-cows-shout.md index 976b5dca..ef64f791 100644 --- a/.changeset/four-cows-shout.md +++ b/.changeset/four-cows-shout.md @@ -2,4 +2,4 @@ '@axelar-network/axelar-cgp-sui': minor --- -Added a two utility function in abi to allow for structs and nested vectors to be encoded/decoded, added a readme to abi, and used macros to clean up the code a bit. +Added two utility functions in `abi` to allow for structs and nested vectors to be encoded/decoded, added a readme to `abi`, and used macros to clean up the code a bit. From 3106d50b2646115ecf499202c060f1da837dcce9 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 12:06:30 +0200 Subject: [PATCH 09/68] rename constant --- move/abi/sources/abi.move | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 18a8e5e9..e581f298 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -9,7 +9,7 @@ use sui::bcs; // --------- // Constants // --------- -const BYTES_IN_U256: u64 = 32; +const U256_BYTES: u64 = 32; // ----- // Types @@ -40,7 +40,7 @@ public fun new_reader(bytes: vector): AbiReader { public fun new_writer(length: u64): AbiWriter { AbiWriter { - bytes: vector::tabulate!(BYTES_IN_U256 * length, |_| 0), + bytes: vector::tabulate!(U256_BYTES * length, |_| 0), pos: 0, } } @@ -62,9 +62,9 @@ public fun read_u256(self: &mut AbiReader): u256 { let mut var = 0u256; let pos = self.pos; - BYTES_IN_U256.do!(|i| var = (var << 8) | (self.bytes[i + pos] as u256)); + U256_BYTES.do!(|i| var = (var << 8) | (self.bytes[i + pos] as u256)); - self.pos = pos + BYTES_IN_U256; + self.pos = pos + U256_BYTES; var } @@ -74,7 +74,7 @@ public fun read_u8(self: &mut AbiReader): u8 { } public fun skip_slot(self: &mut AbiReader) { - self.pos = self.pos + BYTES_IN_U256; + self.pos = self.pos + U256_BYTES; } public fun read_bytes(self: &mut AbiReader): vector { @@ -87,7 +87,7 @@ public fun read_bytes(self: &mut AbiReader): vector { let var = self.decode_bytes(); // Move position to the next slot - self.pos = pos + BYTES_IN_U256; + self.pos = pos + U256_BYTES; var } @@ -104,7 +104,7 @@ public fun read_vector_u256(self: &mut AbiReader): vector { length.do!(|_| var.push_back(self.read_u256())); - self.pos = pos + BYTES_IN_U256; + self.pos = pos + U256_BYTES; var } @@ -126,7 +126,7 @@ public fun read_vector_bytes(self: &mut AbiReader): vector> { length.do!(|_| var.push_back(self.read_bytes())); // Move position to the next slot - self.pos = pos + BYTES_IN_U256; + self.pos = pos + U256_BYTES; self.head = head; var @@ -146,13 +146,13 @@ public fun read_bytes_raw(self: &mut AbiReader): vector { public fun write_u256(self: &mut AbiWriter, var: u256): &mut AbiWriter { let pos = self.pos; - BYTES_IN_U256.do!(|i| { + U256_BYTES.do!(|i| { let exp = ((31 - i) * 8 as u8); let byte = (var >> exp & 255 as u8); *&mut self.bytes[i + pos] = byte; }); - self.pos = pos + BYTES_IN_U256; + self.pos = pos + U256_BYTES; self } @@ -398,7 +398,7 @@ fun test_raw_table() { let mut length_bytes = vector[]; // Split the data into the lenth and the actual table contents - BYTES_IN_U256.do!(|_| length_bytes.push_back(table_bytes.remove(0))); + U256_BYTES.do!(|_| length_bytes.push_back(table_bytes.remove(0))); let mut length_reader = new_reader(length_bytes); let length = length_reader.read_u256(); From 57bdf732e79675d523d96ae362bb41b7299681f7 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 12:26:57 +0200 Subject: [PATCH 10/68] Add docstrings. --- move/abi/sources/abi.move | 44 ++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index e581f298..3a3bcefb 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -14,7 +14,6 @@ const U256_BYTES: u64 = 32; // ----- // Types // ----- - public struct AbiReader has copy, drop { bytes: vector, head: u64, @@ -29,7 +28,7 @@ public struct AbiWriter has copy, drop { // ---------------- // Public Functions // ---------------- - +/// Creates a new AbiReader from the bytes passed. public fun new_reader(bytes: vector): AbiReader { AbiReader { bytes, @@ -38,6 +37,8 @@ public fun new_reader(bytes: vector): AbiReader { } } +/// Creates a new `AbiWriter` that can fit up to length bytes before to +/// overflows. public fun new_writer(length: u64): AbiWriter { AbiWriter { bytes: vector::tabulate!(U256_BYTES * length, |_| 0), @@ -45,12 +46,14 @@ public fun new_writer(length: u64): AbiWriter { } } +/// Retrieve the bytes from an `AbiWriter`. public fun into_bytes(self: AbiWriter): vector { let AbiWriter { bytes, pos: _ } = self; bytes } +/// Retrieve the bytes from an `AbiWriter`. // TODO: check that all bytes were decoded public fun into_remaining_bytes(self: AbiReader): vector { let AbiReader { bytes, head: _, pos: _ } = self; @@ -58,6 +61,8 @@ public fun into_remaining_bytes(self: AbiReader): vector { bytes } +/// Read a `u256` from the next slot of the `AbiReader`. Should be used to read +/// other fixed length types as well. public fun read_u256(self: &mut AbiReader): u256 { let mut var = 0u256; let pos = self.pos; @@ -69,14 +74,18 @@ public fun read_u256(self: &mut AbiReader): u256 { var } +/// Wrapper for `read_u256` that casts the result into a `u8`. public fun read_u8(self: &mut AbiReader): u8 { self.read_u256() as u8 } +/// Used to ignore the next variable in an `AbiReader`. public fun skip_slot(self: &mut AbiReader) { self.pos = self.pos + U256_BYTES; } +/// Reads a variable length variable from an `AbiReader`, as bytes. Can be +/// converted to other variable length variables as well (such as `Strings`). public fun read_bytes(self: &mut AbiReader): vector { let pos = self.pos; @@ -92,6 +101,9 @@ public fun read_bytes(self: &mut AbiReader): vector { var } +/// Reads a vector of fixed length variables from an `AbiReader` as a +/// `vector`. Can also be cast into vectors of other fixed length +/// variables. public fun read_vector_u256(self: &mut AbiReader): vector { let mut var = vector[]; let pos = self.pos; @@ -109,7 +121,9 @@ public fun read_vector_u256(self: &mut AbiReader): vector { var } -/// Decode ABI-encoded 'bytes[]' +/// Reads a vector of variable length variables from an `AbiReader` as a +/// `vector>`. Can also be cast into vectors of other variable length +/// variables. public fun read_vector_bytes(self: &mut AbiReader): vector> { let mut var = vector[]; @@ -132,6 +146,17 @@ public fun read_vector_bytes(self: &mut AbiReader): vector> { var } +/// Reads the raw bytes of a variable length variable. This will return +/// additional bytes at the end of the structure as there is no way to know how +/// to decode the bytes returned. This can be used to decode structs and complex +/// nested vectors that this library does not provide a method for. For example +/// if a user calls `read_bytes_raw` to decode encoded an encoded `bytes` +/// variable this will return 32 bytes that contain the length of the encoded +/// `bytes`, followed by all remaining bytes in the `AbiReader`. To decode +/// these, a user can first parse the length from the first 32 bytes and then +/// parse the subsection of the remaining bytes with that length into a +/// `vector` (which should yield the same result as calling `read_bytes` on +/// the original `AbiReader` instead of `read_bytes_raw`). public fun read_bytes_raw(self: &mut AbiReader): vector { // Move position to the start of the bytes let offset = self.read_u256() as u64; @@ -143,6 +168,8 @@ public fun read_bytes_raw(self: &mut AbiReader): vector { var } +/// Write a `u256` into the next slot of an `AbiWriter`. Can be used to write +/// other fixed lenght variables as well. public fun write_u256(self: &mut AbiWriter, var: u256): &mut AbiWriter { let pos = self.pos; @@ -157,10 +184,13 @@ public fun write_u256(self: &mut AbiWriter, var: u256): &mut AbiWriter { self } +/// Write a `u8` into the next slot of an `AbiWriter`. public fun write_u8(self: &mut AbiWriter, var: u8): &mut AbiWriter { self.write_u256(var as u256) } +/// Write some bytes into the next slot of an `AbiWriter`. Can be used to write +/// another variable length variable, such as a `String`as well. public fun write_bytes(self: &mut AbiWriter, var: vector): &mut AbiWriter { let offset = self.bytes.length() as u256; self.write_u256(offset); @@ -172,6 +202,8 @@ public fun write_bytes(self: &mut AbiWriter, var: vector): &mut AbiWriter { self } +/// Write a `vector` into the next slot of an `AbiWriter`. Can be used to +/// encode other vectors of fixed length variables as well. public fun write_vector_u256( self: &mut AbiWriter, var: vector, @@ -189,6 +221,8 @@ public fun write_vector_u256( self } +/// Write a vector of bytes into the next slot of an `AbiWriter`. Can be used to +/// encode vectors of other variable length variables as well. public fun write_vector_bytes( self: &mut AbiWriter, var: vector>, @@ -209,6 +243,8 @@ public fun write_vector_bytes( self } +/// Write raw bytes to the next slot of an `AbiWriter`. This can be used to +/// write structs or more nested arrays that we support in this module. public fun write_bytes_raw( self: &mut AbiWriter, var: vector, @@ -224,7 +260,6 @@ public fun write_bytes_raw( // ------------------ // Internal Functions // ------------------ - fun append_u256(self: &mut AbiWriter, var: u256) { let mut bytes = bcs::to_bytes(&var); bytes.reverse(); @@ -256,7 +291,6 @@ fun decode_bytes(self: &mut AbiReader): vector { // ----- // Tests // ----- - #[test] fun test_u256() { let input = 56; From 7a1b4012467676474e14502c57fc5a4838ece810 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 12:37:12 +0200 Subject: [PATCH 11/68] Add some docstring examples --- move/abi/sources/abi.move | 51 +++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 3a3bcefb..15f68cdb 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -14,12 +14,32 @@ const U256_BYTES: u64 = 32; // ----- // Types // ----- +/// Used to decode abi encoded bytes into variables. +/// Example +/// ```rust +/// let mut reader = abi::new_reader(data); +/// let number = reader.read_u256(); +/// let name = reader.read_bytes().to_string(); +/// let addresses = reader.read_vector_u256().map!(|val| +/// sui::address::from_u256(val)); +/// let info = reader.read_vector_bytes(); +/// ``` public struct AbiReader has copy, drop { bytes: vector, head: u64, pos: u64, } +/// Used to encode variables into abi encoded bytes. +/// ```rust +/// let mut writer = abi::new_writer(4); +/// writer +/// .write_u256(1234) +/// .write_bytes(b"some_bytes") +/// .write_vector_u256(vector[12, 34, 56]) +/// .write_vector_bytes(vector[b"some", b"more", b"bytes"]); +/// let encoded_data = writer.into_bytes(); +/// ``` public struct AbiWriter has copy, drop { bytes: vector, pos: u64, @@ -149,14 +169,29 @@ public fun read_vector_bytes(self: &mut AbiReader): vector> { /// Reads the raw bytes of a variable length variable. This will return /// additional bytes at the end of the structure as there is no way to know how /// to decode the bytes returned. This can be used to decode structs and complex -/// nested vectors that this library does not provide a method for. For example -/// if a user calls `read_bytes_raw` to decode encoded an encoded `bytes` -/// variable this will return 32 bytes that contain the length of the encoded -/// `bytes`, followed by all remaining bytes in the `AbiReader`. To decode -/// these, a user can first parse the length from the first 32 bytes and then -/// parse the subsection of the remaining bytes with that length into a -/// `vector` (which should yield the same result as calling `read_bytes` on -/// the original `AbiReader` instead of `read_bytes_raw`). +/// nested vectors that this library does not provide a method for. +/// For more complex types like structs or nested vectors `read_bytes_raw` can +/// be used and decoded manualy. To read a struct that contains a `u256` and +/// a `vector` from an `AbiReader` called `reader` a user may: +/// ```rust +/// let struct_bytes = reader.read_bytes_raw(); +/// let mut struct_reader = new_reader(struct_bytes); +/// let number = struct_reader.read_u256(); +/// let data = struct_reader.read_bytes(); +/// ``` +/// As another example, to decode a `vector>` into a variable +/// called `table` from an `AbiReader` called `reader` a user can: +/// ```rust +/// let mut table_bytes = reader.read_bytes_raw(); +/// let mut length_bytes = vector[]; +/// // Split the data into the lenth and the actual table contents. +/// 32u64.do!(|_| length_bytes.push_back(table_bytes.remove(0))); +/// let mut length_reader = new_reader(length_bytes); +/// let length = length_reader.read_u256(); +/// let mut table = vector[]; +/// let mut table_reader = new_reader(table_bytes); +/// length.do!(|_| table.push_back(table_reader.read_vector_u256())); +/// ``` public fun read_bytes_raw(self: &mut AbiReader): vector { // Move position to the start of the bytes let offset = self.read_u256() as u64; From 3f8ee9265e2967fc181e5885a1c7b925c910a3fe Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 13:02:51 +0200 Subject: [PATCH 12/68] replace some do!s with vector.tabulate!s --- move/abi/sources/abi.move | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 15f68cdb..8178064f 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -125,7 +125,6 @@ public fun read_bytes(self: &mut AbiReader): vector { /// `vector`. Can also be cast into vectors of other fixed length /// variables. public fun read_vector_u256(self: &mut AbiReader): vector { - let mut var = vector[]; let pos = self.pos; // Move position to the start of the dynamic data @@ -134,7 +133,7 @@ public fun read_vector_u256(self: &mut AbiReader): vector { let length = self.read_u256() as u64; - length.do!(|_| var.push_back(self.read_u256())); + let var = vector::tabulate!(length, |_| self.read_u256()); self.pos = pos + U256_BYTES; @@ -145,8 +144,6 @@ public fun read_vector_u256(self: &mut AbiReader): vector { /// `vector>`. Can also be cast into vectors of other variable length /// variables. public fun read_vector_bytes(self: &mut AbiReader): vector> { - let mut var = vector[]; - let pos = self.pos; let head = self.head; @@ -157,8 +154,7 @@ public fun read_vector_bytes(self: &mut AbiReader): vector> { let length = self.read_u256() as u64; self.head = self.pos; - length.do!(|_| var.push_back(self.read_bytes())); - + let var = vector::tabulate!(length, |_| self.read_bytes()); // Move position to the next slot self.pos = pos + U256_BYTES; self.head = head; @@ -183,22 +179,19 @@ public fun read_vector_bytes(self: &mut AbiReader): vector> { /// called `table` from an `AbiReader` called `reader` a user can: /// ```rust /// let mut table_bytes = reader.read_bytes_raw(); -/// let mut length_bytes = vector[]; -/// // Split the data into the lenth and the actual table contents. -/// 32u64.do!(|_| length_bytes.push_back(table_bytes.remove(0))); +/// // Split the data into the lenth and the actual table contents +/// let length_bytes = vector::tabulate!(U256_BYTES, |_| table_bytes.remove(0)); /// let mut length_reader = new_reader(length_bytes); -/// let length = length_reader.read_u256(); -/// let mut table = vector[]; +/// let length = length_reader.read_u256() as u64; /// let mut table_reader = new_reader(table_bytes); -/// length.do!(|_| table.push_back(table_reader.read_vector_u256())); +/// let table = vector::tabulate!(length, |_| table_reader.read_vector_u256()); /// ``` public fun read_bytes_raw(self: &mut AbiReader): vector { // Move position to the start of the bytes let offset = self.read_u256() as u64; let length = self.bytes.length() - offset; - let mut var = vector[]; - length.do!(|i| var.push_back(self.bytes[offset + i])); + let var = vector::tabulate!(length, |i| self.bytes[offset + i]); var } @@ -316,11 +309,7 @@ fun decode_bytes(self: &mut AbiReader): vector { let length = self.read_u256() as u64; let pos = self.pos; - let mut bytes = vector[]; - - length.do!(|i| bytes.push_back(self.bytes[i + pos])); - - bytes + vector::tabulate!(length, |i| self.bytes[i + pos]) } // ----- @@ -462,19 +451,16 @@ fun test_raw_table() { let bytes = writer.into_bytes(); let mut reader = new_reader(bytes); - let mut table_bytes = reader.read_bytes_raw(); - let mut length_bytes = vector[]; // Split the data into the lenth and the actual table contents - U256_BYTES.do!(|_| length_bytes.push_back(table_bytes.remove(0))); + let length_bytes = vector::tabulate!(U256_BYTES, |_| table_bytes.remove(0)); let mut length_reader = new_reader(length_bytes); - let length = length_reader.read_u256(); + let length = length_reader.read_u256() as u64; - let mut table_read = vector[]; let mut table_reader = new_reader(table_bytes); - length.do!(|_| table_read.push_back(table_reader.read_vector_u256())); + let table_read = vector::tabulate!(length, |_| table_reader.read_vector_u256()); assert!(table_read == table); } From c30d94ec815220ae3965613e9a020e2e09ee7146 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 13:09:20 +0200 Subject: [PATCH 13/68] Remove raw reads and writes --- move/abi/README.md | 55 +------------- move/abi/sources/abi.move | 107 --------------------------- test/testdata/interface_abi_abi.json | 17 ----- 3 files changed, 2 insertions(+), 177 deletions(-) diff --git a/move/abi/README.md b/move/abi/README.md index 6274d6fe..1e436ef9 100644 --- a/move/abi/README.md +++ b/move/abi/README.md @@ -20,7 +20,6 @@ This type can be used to encode abi data. It has the following relevant function - `abi::write_bytes(self: &mut AbiWriter, var: vector): &mut AbiWriter`: Writes the provided bytes into the next slot in the `AbiWriter`. This should be used to write all types that are equivelant to `vector` (`ascii::String` and `string::String` for example) by converting them to `vector`. - `abi::write_vector_u256(self: &mut AbiWriter, var: vector,): &mut AbiWriter`: Writes the provided `vector` into the next slot in the `AbiWriter`. This should be used for vectors of other fixed length variables as well. - `abi::write_vector_bytes(self: &mut AbiWriter, var: vector>,): &mut AbiWriter`: Writes the provided `vector>` into the nexts slot in the `AbiWriter`. This should be used for vectors of other variable length variables as well. -- `abi::write_bytes_raw(self: &mut AbiWriter, var: vector,): &mut AbiWriter`: Writes the raw bytes provided to the next slot of the `AbiWriter`. These bytes are not length prefixed, and can therefore not be decoded as bytes. The purpose of this function is to allow for encoding of more complex, unavailable structs. #### Example ```rust @@ -34,33 +33,7 @@ let encoded_data = writer.into_bytes(); ``` #### More complex types -More complex types are curently not supported. This is because Sui Move does not support any sort of type inspection (like `is_vector`) to recursively encode vectors. However with `abi::write_bytes_raw` these types can be encoded with some extra work from the user. -For example to encode a struct consisting of `u256` called `number` and a `vector` called `data` into an `AbiWriter` named `writer` a user could do -```rust -let mut struct_writer = new_writer(2); -struct_writer - .write_u256(number) - .write_bytes(data); -writer - .write_bytes_raw(struct_writer.into_bytes()); -``` -As another example, to abi encode a `vector>` named `table` into an `AbiWriter` named `writer` a user could do -```rust -let length = table.length(); - -let mut length_writer = new_writer(1); -length_writer.write_u256(length as u256); -let mut bytes = length_writer.into_bytes(); - -let mut table_writer = new_writer(length); -table.do!(|row| { - table_writer.write_vector_u256(row); -}); -bytes.append(table_writer.into_bytes()); - -writer - .write_bytes_raw(bytes); -``` +More complex types are not supported yet. ### `AbiReader` @@ -73,7 +46,6 @@ This type can be used to decode abi enocded data. The relevant functions are as - `abi::read_bytes(self: &mut AbiReader): vector<8>`: Read a `vector` from the next slot of the `AbiReader`. Should be used to read other variable length types as well. - `abi::read_vector_u256(self: &mut AbiReader): vector`: Read a `vector` from the next slot of the `AbiReader`. Should be used to read other fixed length types as well. - `abi::read_vector_bytes(self: &mut AbiReader): vector>`: Read a `vector>` from the next slot of the `AbiReader`. Should be used to read other vectors of variable length types as well (such as `vector`). -- `abi::read_bytes_raw(self: &mut AbiReader): vector`: Read the raw bytes encoded in the next slot of the `AbiReader`. This will include any bytes encoded after the raw bytes desired which should be ignored. #### Example ```rust @@ -86,27 +58,4 @@ let info = reader.read_vector_bytes(); #### More Complex Types -For more complex types like structs or nested vectors `read_bytes_raw` can be used and decoded. For to read a struct that contains a `u256` and a `vector` from an `AbiReader` called `reader` a user may: -```rust - let struct_bytes = reader.read_bytes_raw(); - - let mut struct_reader = new_reader(struct_bytes); - let number = struct_reader.read_u256(); - let data = struct_reader.read_bytes(); -``` -As another example, to decode a `vector>` into a variable called table from an `AbiReader` called `reader` a user can: -```rust -let mut table_bytes = reader.read_bytes_raw(); -let mut length_bytes = vector[]; - -// Split the data into the lenth and the actual table contents. -32u64.do!(|_| length_bytes.push_back(table_bytes.remove(0))); - -let mut length_reader = new_reader(length_bytes); -let length = length_reader.read_u256(); - -let mut table = vector[]; -let mut table_reader = new_reader(table_bytes); -length.do!(|_| table.push_back(table_reader.read_vector_u256())); -``` - +More complex types are not supported yet. diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 8178064f..5fbe5a03 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -162,40 +162,6 @@ public fun read_vector_bytes(self: &mut AbiReader): vector> { var } -/// Reads the raw bytes of a variable length variable. This will return -/// additional bytes at the end of the structure as there is no way to know how -/// to decode the bytes returned. This can be used to decode structs and complex -/// nested vectors that this library does not provide a method for. -/// For more complex types like structs or nested vectors `read_bytes_raw` can -/// be used and decoded manualy. To read a struct that contains a `u256` and -/// a `vector` from an `AbiReader` called `reader` a user may: -/// ```rust -/// let struct_bytes = reader.read_bytes_raw(); -/// let mut struct_reader = new_reader(struct_bytes); -/// let number = struct_reader.read_u256(); -/// let data = struct_reader.read_bytes(); -/// ``` -/// As another example, to decode a `vector>` into a variable -/// called `table` from an `AbiReader` called `reader` a user can: -/// ```rust -/// let mut table_bytes = reader.read_bytes_raw(); -/// // Split the data into the lenth and the actual table contents -/// let length_bytes = vector::tabulate!(U256_BYTES, |_| table_bytes.remove(0)); -/// let mut length_reader = new_reader(length_bytes); -/// let length = length_reader.read_u256() as u64; -/// let mut table_reader = new_reader(table_bytes); -/// let table = vector::tabulate!(length, |_| table_reader.read_vector_u256()); -/// ``` -public fun read_bytes_raw(self: &mut AbiReader): vector { - // Move position to the start of the bytes - let offset = self.read_u256() as u64; - let length = self.bytes.length() - offset; - - let var = vector::tabulate!(length, |i| self.bytes[offset + i]); - - var -} - /// Write a `u256` into the next slot of an `AbiWriter`. Can be used to write /// other fixed lenght variables as well. public fun write_u256(self: &mut AbiWriter, var: u256): &mut AbiWriter { @@ -271,20 +237,6 @@ public fun write_vector_bytes( self } -/// Write raw bytes to the next slot of an `AbiWriter`. This can be used to -/// write structs or more nested arrays that we support in this module. -public fun write_bytes_raw( - self: &mut AbiWriter, - var: vector, -): &mut AbiWriter { - let offset = self.bytes.length() as u256; - self.write_u256(offset); - - self.append_bytes(var); - - self -} - // ------------------ // Internal Functions // ------------------ @@ -405,62 +357,3 @@ fun test_multiple() { assert!(reader.read_vector_u256() == input3); assert!(reader.read_vector_bytes() == input4); } - -#[test] -fun test_raw_struct() { - let number = 3; - let data = b"data"; - - let mut writer = new_writer(1); - let mut struct_writer = new_writer(2); - struct_writer.write_u256(number).write_bytes(data); - writer.write_bytes_raw(struct_writer.into_bytes()); - - let bytes = writer.into_bytes(); - - let mut reader = new_reader(bytes); - - let struct_bytes = reader.read_bytes_raw(); - - let mut struct_reader = new_reader(struct_bytes); - - assert!(struct_reader.read_u256() == number); - assert!(struct_reader.read_bytes() == data); -} - -#[test] -fun test_raw_table() { - let table = vector[vector[1, 2, 3], vector[4, 5, 6]]; - - let mut writer = new_writer(1); - - let length = table.length(); - - let mut length_writer = new_writer(1); - length_writer.write_u256(length as u256); - let mut bytes = length_writer.into_bytes(); - - let mut table_writer = new_writer(length); - table.do!(|row| { - table_writer.write_vector_u256(row); - }); - bytes.append(table_writer.into_bytes()); - - writer.write_bytes_raw(bytes); - - let bytes = writer.into_bytes(); - - let mut reader = new_reader(bytes); - let mut table_bytes = reader.read_bytes_raw(); - - // Split the data into the lenth and the actual table contents - let length_bytes = vector::tabulate!(U256_BYTES, |_| table_bytes.remove(0)); - - let mut length_reader = new_reader(length_bytes); - let length = length_reader.read_u256() as u64; - - let mut table_reader = new_reader(table_bytes); - let table_read = vector::tabulate!(length, |_| table_reader.read_vector_u256()); - - assert!(table_read == table); -} diff --git a/test/testdata/interface_abi_abi.json b/test/testdata/interface_abi_abi.json index 6b321d15..a1b25056 100644 --- a/test/testdata/interface_abi_abi.json +++ b/test/testdata/interface_abi_abi.json @@ -112,14 +112,6 @@ }, "returnType": "vector>" }, - "read_bytes_raw": { - "name": "read_bytes_raw", - "visibility": "public", - "params": { - "self#0#0": "&mut AbiReader" - }, - "returnType": "vector" - }, "write_u256": { "name": "write_u256", "visibility": "public", @@ -164,15 +156,6 @@ "var#0#0": "vector>" }, "returnType": "&mut AbiWriter" - }, - "write_bytes_raw": { - "name": "write_bytes_raw", - "visibility": "public", - "params": { - "self#0#0": "&mut AbiWriter", - "var#0#0": "vector" - }, - "returnType": "&mut AbiWriter" } } } From 9a562abd2c2fe716bb99dee8c2e04e6cb04a27ab Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 13:09:36 +0200 Subject: [PATCH 14/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 5fbe5a03..d0ee60b5 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -254,7 +254,7 @@ fun append_bytes(self: &mut AbiWriter, var: vector) { self.bytes.append(var); - (31 - (length - 1) % 32).do!(|_| self.bytes.push_back(0)); + ((U256_BYTES) - 1 - (length - 1) % U256_BYTES).do!(|_| self.bytes.push_back(0)); } fun decode_bytes(self: &mut AbiReader): vector { From 70499efcae4b956976bedf141fabd5b0bf23efa5 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 14:40:01 +0200 Subject: [PATCH 15/68] remove into_remaining_bytes as it makes no sense and add tests --- move/abi/sources/abi.move | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index d0ee60b5..c84856ac 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -73,14 +73,6 @@ public fun into_bytes(self: AbiWriter): vector { bytes } -/// Retrieve the bytes from an `AbiWriter`. -// TODO: check that all bytes were decoded -public fun into_remaining_bytes(self: AbiReader): vector { - let AbiReader { bytes, head: _, pos: _ } = self; - - bytes -} - /// Read a `u256` from the next slot of the `AbiReader`. Should be used to read /// other fixed length types as well. public fun read_u256(self: &mut AbiReader): u256 { @@ -357,3 +349,20 @@ fun test_multiple() { assert!(reader.read_vector_u256() == input3); assert!(reader.read_vector_bytes() == input4); } + +#[test] +fun test_read_u8() { + let val = 123; + let mut writer = new_writer(1); + writer.write_u8(val); + let bytes = writer.into_bytes(); + let mut reader = new_reader(bytes); + + assert!(reader.read_u8() == val); +} + +#[test] +fun test_append_empty_bytes() { + let mut writer = new_writer(0); + writer.append_bytes(vector[]); +} From e116874db85ed9f7199f46ca2c45568b0c08a63b Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 12 Dec 2024 15:15:09 +0200 Subject: [PATCH 16/68] update interface --- test/testdata/interface_abi_abi.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/testdata/interface_abi_abi.json b/test/testdata/interface_abi_abi.json index a1b25056..d6fcf9c2 100644 --- a/test/testdata/interface_abi_abi.json +++ b/test/testdata/interface_abi_abi.json @@ -64,14 +64,6 @@ }, "returnType": "vector" }, - "into_remaining_bytes": { - "name": "into_remaining_bytes", - "visibility": "public", - "params": { - "self#0#0": "AbiReader" - }, - "returnType": "vector" - }, "read_u256": { "name": "read_u256", "visibility": "public", From 63beb53f1832b866c184122d8d15f7d70d84e2f7 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 20 Jan 2025 18:56:07 +0200 Subject: [PATCH 17/68] changed from trusted addresses to trusted chains --- .../sources/events.move | 9 +- .../sources/interchain_token_service.move | 164 ++++--- .../sources/types/address_tracker.move | 181 -------- .../sources/types/chain_tracker.move | 146 ++++++ .../sources/types/trusted_addresses.move | 69 --- .../interchain_token_service_v0.move | 430 +++++++----------- 6 files changed, 418 insertions(+), 581 deletions(-) delete mode 100644 move/interchain_token_service/sources/types/address_tracker.move create mode 100644 move/interchain_token_service/sources/types/chain_tracker.move delete mode 100644 move/interchain_token_service/sources/types/trusted_addresses.move diff --git a/move/interchain_token_service/sources/events.move b/move/interchain_token_service/sources/events.move index 7d2ce0d3..9382d5b0 100644 --- a/move/interchain_token_service/sources/events.move +++ b/move/interchain_token_service/sources/events.move @@ -48,9 +48,8 @@ public struct UnregisteredCoinReceived has copy, drop { decimals: u8, } -public struct TrustedAddressSet has copy, drop { +public struct TrustedAddressAdded has copy, drop { chain_name: String, - trusted_address: String, } public struct TrustedAddressRemoved has copy, drop { @@ -143,13 +142,11 @@ public(package) fun unregistered_coin_received( }); } -public(package) fun trusted_address_set( +public(package) fun trusted_address_added( chain_name: String, - trusted_address: String, ) { - event::emit(TrustedAddressSet { + event::emit(TrustedAddressAdded { chain_name, - trusted_address, }); } diff --git a/move/interchain_token_service/sources/interchain_token_service.move b/move/interchain_token_service/sources/interchain_token_service.move index efa73f95..db385bf0 100644 --- a/move/interchain_token_service/sources/interchain_token_service.move +++ b/move/interchain_token_service/sources/interchain_token_service.move @@ -4,12 +4,11 @@ use axelar_gateway::channel::{ApprovedMessage, Channel}; use axelar_gateway::message_ticket::MessageTicket; use interchain_token_service::coin_info::CoinInfo; use interchain_token_service::coin_management::CoinManagement; -use interchain_token_service::interchain_transfer_ticket::{Self, InterchainTransferTicket}; use interchain_token_service::interchain_token_service_v0::{Self, InterchainTokenService_v0}; -use interchain_token_service::owner_cap::{Self, OwnerCap}; +use interchain_token_service::interchain_transfer_ticket::{Self, InterchainTransferTicket}; use interchain_token_service::operator_cap::{Self, OperatorCap}; +use interchain_token_service::owner_cap::{Self, OwnerCap}; use interchain_token_service::token_id::TokenId; -use interchain_token_service::trusted_addresses::TrustedAddresses; use relayer_discovery::discovery::RelayerDiscovery; use relayer_discovery::transaction::Transaction; use std::ascii::{Self, String}; @@ -67,7 +66,10 @@ fun init(ctx: &mut TxContext) { // Macros // ------ /// This macro also uses version control to sinplify things a bit. -macro fun value($self: &InterchainTokenService, $function_name: vector): &InterchainTokenService_v0 { +macro fun value( + $self: &InterchainTokenService, + $function_name: vector, +): &InterchainTokenService_v0 { let its = $self; let value = its.inner.load_value(); value.version_control().check(VERSION, ascii::string($function_name)); @@ -75,7 +77,10 @@ macro fun value($self: &InterchainTokenService, $function_name: vector): &In } /// This macro also uses version control to sinplify things a bit. -macro fun value_mut($self: &mut InterchainTokenService, $function_name: vector): &mut InterchainTokenService_v0 { +macro fun value_mut( + $self: &mut InterchainTokenService, + $function_name: vector, +): &mut InterchainTokenService_v0 { let its = $self; let value = its.inner.load_value_mut(); value.version_control().check(VERSION, ascii::string($function_name)); @@ -100,9 +105,7 @@ entry fun disallow_function( version: u64, function_name: String, ) { - self - .value_mut!(b"disallow_function") - .disallow_function(version, function_name); + self.value_mut!(b"disallow_function").disallow_function(version, function_name); } // ---------------- @@ -297,24 +300,24 @@ public fun set_flow_limit( // --------------- // Owner Functions // --------------- -public fun set_trusted_addresses( +public fun add_trusted_chains( self: &mut InterchainTokenService, _owner_cap: &OwnerCap, - trusted_addresses: TrustedAddresses, + chain_names: vector, ) { - let value = self.value_mut!(b"set_trusted_addresses"); + let value = self.value_mut!(b"add_trusted_chains"); - value.set_trusted_addresses(trusted_addresses); + value.add_trusted_chains(chain_names); } -public fun remove_trusted_addresses( +public fun remove_trusted_chains( self: &mut InterchainTokenService, _owner_cap: &OwnerCap, chain_names: vector, ) { - let value = self.value_mut!(b"remove_trusted_addresses"); + let value = self.value_mut!(b"remove_trusted_chains"); - value.remove_trusted_addresses(chain_names); + value.remove_trusted_chains(chain_names); } // === Getters === @@ -367,8 +370,8 @@ fun version_control(): VersionControl { b"mint_as_distributor", b"mint_to_as_distributor", b"burn_as_distributor", - b"set_trusted_addresses", - b"remove_trusted_addresses", + b"add_trusted_chains", + b"remove_trusted_chains", b"register_transaction", b"set_flow_limit", b"set_flow_limit_as_token_operator", @@ -397,13 +400,16 @@ use utils::utils; const MESSAGE_TYPE_INTERCHAIN_TRANSFER: u256 = 0; #[test_only] const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; -// onst MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER: u256 = 2; +// const MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER: u256 = 2; +#[test_only] +const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; // === HUB CONSTANTS === -// Identifier to be used as destination address for chains that route to hub. -// For Sui this will probably be every supported chain. +// Axelar. +const ITS_HUB_CHAIN_NAME: vector = b"axelar"; #[test_only] -const ITS_HUB_ROUTING_IDENTIFIER: vector = b"hub"; +// The address of the ITS HUB. +const ITS_HUB_ADDRESS: vector = b"hub_address"; #[test_only] public fun create_for_testing(ctx: &mut TxContext): InterchainTokenService { @@ -414,9 +420,8 @@ public fun create_for_testing(ctx: &mut TxContext): InterchainTokenService { version_control, ctx, ); - value.set_trusted_address( + value.add_trusted_chain( std::ascii::string(b"Chain Name"), - std::ascii::string(b"Address"), ); let inner = versioned::create( @@ -437,9 +442,7 @@ public(package) fun add_unregistered_coin_type_for_testing( token_id: interchain_token_service::token_id::UnregisteredTokenId, type_name: std::type_name::TypeName, ) { - self - .value_mut!(b"") - .add_unregistered_coin_type_for_testing(token_id, type_name); + self.value_mut!(b"").add_unregistered_coin_type_for_testing(token_id, type_name); } #[test_only] @@ -456,9 +459,7 @@ public(package) fun add_registered_coin_type_for_testing( token_id: TokenId, type_name: std::type_name::TypeName, ) { - self - .value_mut!(b"") - .add_registered_coin_type_for_testing(token_id, type_name); + self.value_mut!(b"").add_registered_coin_type_for_testing(token_id, type_name); } #[test_only] @@ -524,15 +525,13 @@ fun test_deploy_remote_interchain_token() { .write_bytes(*token_symbol.as_bytes()) .write_u256((token_decimals as u256)) .write_bytes(vector::empty()); + let mut payload = writer.into_bytes(); + its.value!(b"").wrap_payload_for_testing(&mut payload, destination_chain); - assert!( - message_ticket.source_id() == its.value!(b"").channel().to_address(), - ); - assert!(message_ticket.destination_chain() == destination_chain); - assert!( - message_ticket.destination_address() == its.value!(b"").trusted_address_for_testing(destination_chain), - ); - assert!(message_ticket.payload() == writer.into_bytes()); + assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); + assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); + assert!(message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string()); + assert!(message_ticket.payload() == payload); assert!(message_ticket.version() == 0); sui::test_utils::destroy(its); @@ -588,15 +587,15 @@ fun test_deploy_interchain_token() { .write_bytes(destination_address) .write_u256((amount as u256)) .write_bytes(b""); + let mut payload = writer.into_bytes(); + its.value!(b"").wrap_payload_for_testing(&mut payload, destination_chain); + assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); + assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); assert!( - message_ticket.source_id() == its.value!(b"").channel().to_address(), + message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string(), ); - assert!(message_ticket.destination_chain() == destination_chain); - assert!( - message_ticket.destination_address() == its.value!(b"").trusted_address_for_testing(destination_chain), - ); - assert!(message_ticket.payload() == writer.into_bytes()); + assert!(message_ticket.payload() == payload); assert!(message_ticket.version() == 0); clock.destroy_for_testing(); @@ -625,7 +624,6 @@ fun test_receive_interchain_transfer() { let token_id = register_coin(&mut its, coin_info, coin_management); let source_chain = ascii::string(b"Chain Name"); let message_id = ascii::string(b"Message Id"); - let message_source_address = ascii::string(b"Address"); let its_source_address = b"Source Address"; let destination_address = @0x1; @@ -637,12 +635,18 @@ fun test_receive_interchain_transfer() { .write_bytes(destination_address.to_bytes()) .write_u256((amount as u256)) .write_bytes(b""); - let payload = writer.into_bytes(); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer + .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) + .write_bytes(source_chain.into_bytes()) + .write_bytes(payload); + payload = writer.into_bytes(); let approved_message = channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - message_source_address, + ITS_HUB_ADDRESS.to_ascii_string(), its.value!(b"").channel().to_address(), payload, ); @@ -676,7 +680,6 @@ fun test_receive_interchain_transfer_with_data() { let token_id = its.register_coin(coin_info, coin_management); let source_chain = ascii::string(b"Chain Name"); let message_id = ascii::string(b"Message Id"); - let message_source_address = ascii::string(b"Address"); let its_source_address = b"Source Address"; let channel = channel::new(ctx); let destination_address = channel.to_address(); @@ -689,12 +692,18 @@ fun test_receive_interchain_transfer_with_data() { .write_bytes(destination_address.to_bytes()) .write_u256((amount as u256)) .write_bytes(data); - let payload = writer.into_bytes(); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer + .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) + .write_bytes(source_chain.into_bytes()) + .write_bytes(payload); + payload = writer.into_bytes(); let approved_message = channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - message_source_address, + ITS_HUB_ADDRESS.to_ascii_string(), its.value!(b"").channel().to_address(), payload, ); @@ -732,7 +741,6 @@ fun test_receive_deploy_interchain_token() { let source_chain = ascii::string(b"Chain Name"); let message_id = ascii::string(b"Message Id"); - let source_address = ascii::string(b"Address"); let name = b"Token Name"; let symbol = b"Symbol"; let decimals = 9; @@ -748,12 +756,18 @@ fun test_receive_deploy_interchain_token() { .write_bytes(symbol) .write_u256((decimals as u256)) .write_bytes(vector::empty()); - let payload = writer.into_bytes(); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer + .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) + .write_bytes(source_chain.into_bytes()) + .write_bytes(payload); + payload = writer.into_bytes(); let approved_message = channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - source_address, + ITS_HUB_ADDRESS.to_ascii_string(), its.value!(b"").channel().to_address(), payload, ); @@ -773,7 +787,10 @@ fun test_give_unregistered_coin() { let ctx = &mut tx_context::dummy(); let mut its = create_for_testing(ctx); - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -791,7 +808,10 @@ fun test_mint_as_distributor() { let symbol = b"COIN"; let decimals = 9; - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -828,7 +848,10 @@ fun test_mint_to_as_distributor() { let symbol = b"COIN"; let decimals = 9; - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -885,7 +908,7 @@ fun test_burn_as_distributor() { } #[test] -fun test_set_trusted_address() { +fun test_add_trusted_chain() { let ctx = &mut tx_context::dummy(); let mut its = create_for_testing(ctx); @@ -896,18 +919,9 @@ fun test_set_trusted_address() { let trusted_chains = vector[b"Ethereum", b"Avalance", b"Axelar"].map!( |chain| chain.to_ascii_string(), ); - let trusted_addresses = vector[ - b"ethereum address", - ITS_HUB_ROUTING_IDENTIFIER, - b"hub address", - ].map!(|chain| chain.to_ascii_string()); - let trusted_addresses = interchain_token_service::trusted_addresses::new( - trusted_chains, - trusted_addresses, - ); - its.set_trusted_addresses(&owner_cap, trusted_addresses); - its.remove_trusted_addresses(&owner_cap, trusted_chains); + its.add_trusted_chains(&owner_cap, trusted_chains); + its.remove_trusted_chains(&owner_cap, trusted_chains); sui::test_utils::destroy(its); sui::test_utils::destroy(owner_cap); @@ -921,7 +935,10 @@ fun test_set_flow_limit_as_token_operator() { let decimals = 9; let limit = 1234; - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -949,7 +966,10 @@ fun test_set_flow_limit() { let decimals = 9; let limit = 1234; - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, diff --git a/move/interchain_token_service/sources/types/address_tracker.move b/move/interchain_token_service/sources/types/address_tracker.move deleted file mode 100644 index a90b7ab4..00000000 --- a/move/interchain_token_service/sources/types/address_tracker.move +++ /dev/null @@ -1,181 +0,0 @@ -/// Q: why addresses are stored as Strings? -/// Q: why chains are Strings? -module interchain_token_service::address_tracker; - -use interchain_token_service::events; -use std::ascii::String; -use sui::table::{Self, Table}; - -// ------ -// Errors -// ------ -#[error] -const ENoAddress: vector = - b"attempt to borrow a trusted address but it's not registered"; -#[error] -const EEmptyChainName: vector = b"empty trusted chain name is unsupported"; -#[error] -const EEmptyTrustedAddress: vector = - b"empty trusted address is unsupported"; - -/// The interchain address tracker stores the trusted addresses for each chain. -public struct InterchainAddressTracker has store { - trusted_addresses: Table, -} - -// ----------------- -// Package Functions -// ----------------- -/// Get the trusted address for a chain. -public(package) fun trusted_address( - self: &InterchainAddressTracker, - chain_name: String, -): &String { - assert!(self.trusted_addresses.contains(chain_name), ENoAddress); - &self.trusted_addresses[chain_name] -} - -/// Check if the given address is trusted for the given chain. -public(package) fun is_trusted_address( - self: &InterchainAddressTracker, - chain_name: String, - addr: String, -): bool { - self.trusted_addresses.contains(chain_name) && self.trusted_addresses[chain_name] == addr -} - -/// Create a new interchain address tracker. -public(package) fun new(ctx: &mut TxContext): InterchainAddressTracker { - InterchainAddressTracker { - trusted_addresses: table::new(ctx), - } -} - -/// Set the trusted address for a chain or adds it if it doesn't exist. -public(package) fun set_trusted_address( - self: &mut InterchainAddressTracker, - chain_name: String, - trusted_address: String, -) { - assert!(chain_name.length() > 0, EEmptyChainName); - assert!(trusted_address.length() > 0, EEmptyTrustedAddress); - - if (self.trusted_addresses.contains(chain_name)) { - *&mut self.trusted_addresses[chain_name] = trusted_address; - } else { - self.trusted_addresses.add(chain_name, trusted_address); - }; - events::trusted_address_set(chain_name, trusted_address); -} - -public(package) fun remove_trusted_address( - self: &mut InterchainAddressTracker, - chain_name: String, -) { - assert!(chain_name.length() > 0, EEmptyChainName); - self.trusted_addresses.remove(chain_name); - events::trusted_address_removed(chain_name); -} - -// ----- -// Tests -// ----- -#[test] -fun test_address_tracker() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain1 = std::ascii::string(b"chain1"); - let chain2 = std::ascii::string(b"chain2"); - let address1 = std::ascii::string(b"address1"); - let address2 = std::ascii::string(b"address2"); - - self.set_trusted_address(chain1, address1); - self.set_trusted_address(chain2, address2); - - assert!(self.trusted_address(chain1) == &address1); - assert!(self.trusted_address(chain2) == &address2); - - assert!(self.is_trusted_address(chain1, address1) == true); - assert!(self.is_trusted_address(chain1, address2) == false); - assert!(self.is_trusted_address(chain2, address1) == false); - assert!(self.is_trusted_address(chain2, address2) == true); - - self.set_trusted_address(chain1, address2); - self.set_trusted_address(chain2, address1); - - assert!(self.trusted_address(chain1) == &address2); - assert!(self.trusted_address(chain2) == &address1); - - assert!(self.is_trusted_address(chain1, address1) == false); - assert!(self.is_trusted_address(chain1, address2) == true); - assert!(self.is_trusted_address(chain2, address1) == true); - assert!(self.is_trusted_address(chain2, address2) == false); - - assert!(self.trusted_addresses.contains(chain1)); - assert!(self.trusted_addresses.contains(chain2)); - - sui::test_utils::destroy(self); -} - -#[test] -#[expected_failure(abort_code = EEmptyChainName)] -fun test_set_trusted_address_empty_chain_name() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b""); - let address = std::ascii::string(b"address"); - - self.set_trusted_address(chain, address); - - sui::test_utils::destroy(self); -} - -#[test] -#[expected_failure(abort_code = EEmptyTrustedAddress)] -fun test_set_trusted_address_empty_trusted_address() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b"chain"); - let address = std::ascii::string(b""); - - self.set_trusted_address(chain, address); - - sui::test_utils::destroy(self); -} - -#[test] -fun test_remove_trusted_address() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b"chain"); - let address = std::ascii::string(b"address"); - - self.set_trusted_address(chain, address); - self.remove_trusted_address(chain); - - sui::test_utils::destroy(self); -} - -#[test] -#[expected_failure(abort_code = EEmptyChainName)] -fun test_remove_trusted_address_empty_chain_name() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b""); - - self.remove_trusted_address(chain); - - sui::test_utils::destroy(self); -} - -#[test] -#[expected_failure(abort_code = ENoAddress)] -fun test_trusted_address_no_address() { - let ctx = &mut sui::tx_context::dummy(); - let self = new(ctx); - let chain = std::ascii::string(b""); - - self.trusted_address(chain); - - sui::test_utils::destroy(self); -} diff --git a/move/interchain_token_service/sources/types/chain_tracker.move b/move/interchain_token_service/sources/types/chain_tracker.move new file mode 100644 index 00000000..e2ec3b1b --- /dev/null +++ b/move/interchain_token_service/sources/types/chain_tracker.move @@ -0,0 +1,146 @@ +/// Q: why addresses are stored as Strings? +/// Q: why chains are Strings? +module interchain_token_service::chain_tracker; + +use interchain_token_service::events; +use std::ascii::String; +use sui::table::{Self, Table}; + +// ------ +// Errors +// ------ +#[error] +const EEmptyChainName: vector = b"empty trusted chain name is unsupported"; +#[error] +const EAlreadyTrusted: vector = + b"chain is already trusted"; + +public struct TrustedChain has store, drop {} + +/// The interchain address tracker stores the trusted addresses for each chain. +public struct InterchainChainTracker has store { + trusted_addresses: Table, +} + +// ----------------- +// Package Functions +// ----------------- +/// Check if the given address is trusted for the given chain. +public(package) fun is_trusted_chain( + self: &InterchainChainTracker, + chain_name: String, +): bool { + self.trusted_addresses.contains(chain_name) +} + +/// Create a new interchain address tracker. +public(package) fun new(ctx: &mut TxContext): InterchainChainTracker { + InterchainChainTracker { + trusted_addresses: table::new(ctx), + } +} + +/// Set the trusted address for a chain or adds it if it doesn't exist. +public(package) fun add_trusted_chain( + self: &mut InterchainChainTracker, + chain_name: String, +) { + assert!(chain_name.length() > 0, EEmptyChainName); + + if (self.trusted_addresses.contains(chain_name)) { + abort EAlreadyTrusted + } else { + self.trusted_addresses.add(chain_name, TrustedChain{}); + }; + events::trusted_address_added(chain_name); +} + +public(package) fun remove_trusted_chain( + self: &mut InterchainChainTracker, + chain_name: String, +) { + assert!(chain_name.length() > 0, EEmptyChainName); + self.trusted_addresses.remove(chain_name); + events::trusted_address_removed(chain_name); +} + +// ----- +// Tests +// ----- +#[test] +fun test_chain_tracker() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain1 = std::ascii::string(b"chain1"); + let chain2 = std::ascii::string(b"chain2"); + + self.add_trusted_chain(chain1); + self.add_trusted_chain(chain2); + + assert!(self.is_trusted_chain(chain1) == true); + assert!(self.is_trusted_chain(chain2) == true); + + assert!(self.trusted_addresses.contains(chain1)); + assert!(self.trusted_addresses.contains(chain2)); + + self.remove_trusted_chain(chain1); + self.remove_trusted_chain(chain2); + + + assert!(self.is_trusted_chain(chain1) == false); + assert!(self.is_trusted_chain(chain2) == false); + + assert!(!self.trusted_addresses.contains(chain1)); + assert!(!self.trusted_addresses.contains(chain2)); + + sui::test_utils::destroy(self); +} + +#[test] +#[expected_failure(abort_code = EEmptyChainName)] +fun test_add_trusted_chain_empty_chain_name() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b""); + + self.add_trusted_chain(chain); + + sui::test_utils::destroy(self); +} + +#[test] +#[expected_failure(abort_code = EAlreadyTrusted)] +fun test_add_trusted_chain_already_trusted() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b"chain"); + + self.add_trusted_chain(chain); + self.add_trusted_chain(chain); + + sui::test_utils::destroy(self); +} + +#[test] +fun test_remove_trusted_chain() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b"chain"); + + self.add_trusted_chain(chain); + self.remove_trusted_chain(chain); + + sui::test_utils::destroy(self); +} + +#[test] +#[expected_failure(abort_code = EEmptyChainName)] +fun test_remove_trusted_chain_empty_chain_name() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b""); + + self.remove_trusted_chain(chain); + + sui::test_utils::destroy(self); +} diff --git a/move/interchain_token_service/sources/types/trusted_addresses.move b/move/interchain_token_service/sources/types/trusted_addresses.move deleted file mode 100644 index 5cf5a461..00000000 --- a/move/interchain_token_service/sources/types/trusted_addresses.move +++ /dev/null @@ -1,69 +0,0 @@ -module interchain_token_service::trusted_addresses; - -use std::ascii::String; - -/// ------ -/// Errors -/// ------ -#[error] -const EMalformedTrustedAddresses: vector = - b"trusted chains and addresses have mismatching length"; - -/// ----- -/// Types -/// ----- -public struct TrustedAddresses has copy, drop { - trusted_chains: vector, - trusted_addresses: vector, -} - -/// ---------------- -/// Public Functions -/// ---------------- -public fun new( - trusted_chains: vector, - trusted_addresses: vector, -): TrustedAddresses { - let length = trusted_chains.length(); - - assert!(length == trusted_addresses.length(), EMalformedTrustedAddresses); - - TrustedAddresses { - trusted_chains, - trusted_addresses, - } -} - -/// ----------------- -/// Package Functions -/// ----------------- -public(package) fun destroy( - self: TrustedAddresses, -): (vector, vector) { - let TrustedAddresses { trusted_chains, trusted_addresses } = self; - (trusted_chains, trusted_addresses) -} - -/// --------- -/// Test Only -/// --------- -// This does not preform sanity checks on the params -#[test_only] -public(package) fun new_for_testing( - trusted_chains: vector, - trusted_addresses: vector, -): TrustedAddresses { - TrustedAddresses { - trusted_chains, - trusted_addresses, - } -} - -/// ---- -/// Test -/// ---- -#[test] -#[expected_failure(abort_code = EMalformedTrustedAddresses)] -fun test_new_malformed() { - new(vector[], vector[b"address".to_ascii_string()]); -} diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index 96581440..76757da4 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -4,14 +4,13 @@ use abi::abi::{Self, AbiReader}; use axelar_gateway::channel::{Channel, ApprovedMessage}; use axelar_gateway::gateway; use axelar_gateway::message_ticket::MessageTicket; -use interchain_token_service::address_tracker::{Self, InterchainAddressTracker}; +use interchain_token_service::chain_tracker::{Self, InterchainChainTracker}; use interchain_token_service::coin_data::{Self, CoinData}; use interchain_token_service::coin_info::{Self, CoinInfo}; use interchain_token_service::coin_management::{Self, CoinManagement}; use interchain_token_service::events; use interchain_token_service::interchain_transfer_ticket::InterchainTransferTicket; use interchain_token_service::token_id::{Self, TokenId, UnregisteredTokenId}; -use interchain_token_service::trusted_addresses::TrustedAddresses; use interchain_token_service::unregistered_coin_data::{Self, UnregisteredCoinData}; use interchain_token_service::utils as its_utils; use relayer_discovery::discovery::RelayerDiscovery; @@ -29,14 +28,11 @@ use version_control::version_control::VersionControl; // Errors // ------ #[error] -const EUnregisteredCoin: vector = - b"trying to find a coin that doesn't exist"; +const EUnregisteredCoin: vector = b"trying to find a coin that doesn't exist"; #[error] -const EUntrustedAddress: vector = - b"the sender that sent this message is not trusted"; +const EUntrustedAddress: vector = b"the sender that sent this message is not trusted"; #[error] -const EInvalidMessageType: vector = - b"the message type received is not supported"; +const EInvalidMessageType: vector = b"the message type received is not supported"; #[error] const EWrongDestination: vector = b"the channel trying to receive this call is not the destination"; @@ -47,8 +43,7 @@ const EInterchainTransferHasData: vector = const EInterchainTransferHasNoData: vector = b"interchain transfer trying to be proccessed as an interchain transfer"; #[error] -const EModuleNameDoesNotMatchSymbol: vector = - b"the module name does not match the symbol"; +const EModuleNameDoesNotMatchSymbol: vector = b"the module name does not match the symbol"; #[error] const ENotDistributor: vector = b"only the distributor can mint"; #[error] @@ -75,16 +70,15 @@ const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; // Chain name for Axelar. This is used for routing InterchainTokenService calls via InterchainTokenService hub on // Axelar. const ITS_HUB_CHAIN_NAME: vector = b"axelar"; -// Identifier to be used as destination address for chains that route to hub. -// For Sui this will probably be every supported chain. -const ITS_HUB_ROUTING_IDENTIFIER: vector = b"hub"; +// The address of the ITS HUB. +const ITS_HUB_ADDRESS: vector = b"hub_address"; // ----- // Types // ----- public struct InterchainTokenService_v0 has store { channel: Channel, - address_tracker: InterchainAddressTracker, + chain_tracker: InterchainChainTracker, unregistered_coin_types: Table, unregistered_coins: Bag, registered_coin_types: Table, @@ -102,7 +96,7 @@ public(package) fun new( ): InterchainTokenService_v0 { InterchainTokenService_v0 { channel: axelar_gateway::channel::new(ctx), - address_tracker: address_tracker::new( + chain_tracker: chain_tracker::new( ctx, ), registered_coins: bag::new(ctx), @@ -148,42 +142,31 @@ public(package) fun relayer_discovery_id(self: &InterchainTokenService_v0): ID { self.relayer_discovery_id } -public(package) fun set_trusted_address( - self: &mut InterchainTokenService_v0, - chain_name: String, - trusted_address: String, -) { - self.address_tracker.set_trusted_address(chain_name, trusted_address); +public(package) fun add_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) { + self.chain_tracker.add_trusted_chain(chain_name); } -public(package) fun remove_trusted_address( - self: &mut InterchainTokenService_v0, - chain_name: String, -) { - self.address_tracker.remove_trusted_address(chain_name); +public(package) fun remove_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) { + self.chain_tracker.remove_trusted_chain(chain_name); } -public(package) fun set_trusted_addresses( +public(package) fun add_trusted_chains( self: &mut InterchainTokenService_v0, - trusted_addresses: TrustedAddresses, + chain_names: vector, ) { - let (chain_names, trusted_addresses) = trusted_addresses.destroy(); - - chain_names.zip_do!( - trusted_addresses, - |chain_name, trusted_address| self.set_trusted_address( + chain_names.do!( + |chain_name| self.add_trusted_chain( chain_name, - trusted_address, ), ); } -public(package) fun remove_trusted_addresses( +public(package) fun remove_trusted_chains( self: &mut InterchainTokenService_v0, chain_names: vector, ) { chain_names.do!( - |chain_name| self.remove_trusted_address( + |chain_name| self.remove_trusted_chain( chain_name, ), ); @@ -238,7 +221,9 @@ public(package) fun deploy_remote_interchain_token( destination_chain, ); - prepare_message(self, destination_chain, writer.into_bytes()) + let mut payload = writer.into_bytes(); + self.wrap_payload(&mut payload, destination_chain); + prepare_message(self, payload) } public(package) fun send_interchain_transfer( @@ -258,9 +243,7 @@ public(package) fun send_interchain_transfer( ) = ticket.destroy(); assert!(version <= current_version, ENewerTicket); - let amount = self - .coin_management_mut(token_id) - .take_balance(balance, clock); + let amount = self.coin_management_mut(token_id).take_balance(balance, clock); let (_version, data) = its_utils::decode_metadata(metadata); let mut writer = abi::new_writer(6); @@ -281,7 +264,9 @@ public(package) fun send_interchain_transfer( &data, ); - self.prepare_message(destination_chain, writer.into_bytes()) + let mut payload = writer.into_bytes(); + self.wrap_payload(&mut payload, destination_chain); + prepare_message(self, payload) } public(package) fun receive_interchain_transfer( @@ -294,10 +279,7 @@ public(package) fun receive_interchain_transfer( approved_message, ); let mut reader = abi::new_reader(payload); - assert!( - reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, - EInvalidMessageType, - ); + assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); let token_id = token_id::from_u256(reader.read_u256()); let source_address = reader.read_bytes(); @@ -307,9 +289,7 @@ public(package) fun receive_interchain_transfer( assert!(data.is_empty(), EInterchainTransferHasData); - let coin = self - .coin_management_mut(token_id) - .give_coin(amount, clock, ctx); + let coin = self.coin_management_mut(token_id).give_coin(amount, clock, ctx); transfer::public_transfer(coin, destination_address); @@ -335,10 +315,7 @@ public(package) fun receive_interchain_transfer_with_data( approved_message, ); let mut reader = abi::new_reader(payload); - assert!( - reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, - EInvalidMessageType, - ); + assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); let token_id = token_id::from_u256(reader.read_u256()); @@ -371,10 +348,7 @@ public(package) fun receive_deploy_interchain_token( ) { let (_, payload, _) = self.decode_approved_message(approved_message); let mut reader = abi::new_reader(payload); - assert!( - reader.read_u256() == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, - EInvalidMessageType, - ); + assert!(reader.read_u256() == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, EInvalidMessageType); let token_id = token_id::from_u256(reader.read_u256()); let name = string::utf8(reader.read_bytes()); @@ -404,10 +378,7 @@ public(package) fun give_unregistered_coin( mut coin_metadata: CoinMetadata, ) { assert!(treasury_cap.total_supply() == 0, ENonZeroTotalSupply); - assert!( - coin::get_icon_url(&coin_metadata).is_none(), - EUnregisteredCoinHasUrl, - ); + assert!(coin::get_icon_url(&coin_metadata).is_none(), EUnregisteredCoinHasUrl); treasury_cap.update_description(&mut coin_metadata, string::utf8(b"")); @@ -415,10 +386,7 @@ public(package) fun give_unregistered_coin( let symbol = coin_metadata.get_symbol(); let module_name = type_name::get_module(&type_name::get()); - assert!( - &module_name == &its_utils::module_from_symbol(&symbol), - EModuleNameDoesNotMatchSymbol, - ); + assert!(&module_name == &its_utils::module_from_symbol(&symbol), EModuleNameDoesNotMatchSymbol); let token_id = token_id::unregistered_token_id(&symbol, decimals); @@ -525,12 +493,12 @@ fun coin_info(self: &InterchainTokenService_v0, token_id: TokenId): &CoinInfo coin_data(self, token_id).coin_info() } -fun is_trusted_address( - self: &InterchainTokenService_v0, - source_chain: String, - source_address: String, -): bool { - self.address_tracker.is_trusted_address(source_chain, source_address) +fun is_trusted_address(source_chain: String, source_address: String): bool { + source_chain.into_bytes() == ITS_HUB_CHAIN_NAME && source_address.into_bytes() == ITS_HUB_ADDRESS +} + +fun is_trusted_chain(self: &InterchainTokenService_v0, source_chain: String): bool { + self.chain_tracker.is_trusted_chain(source_chain) } fun coin_management_mut( @@ -565,9 +533,7 @@ fun remove_unregistered_coin( self: &mut InterchainTokenService_v0, token_id: UnregisteredTokenId, ): (TreasuryCap, CoinMetadata) { - let unregistered_coins: UnregisteredCoinData = self - .unregistered_coins - .remove(token_id); + let unregistered_coins: UnregisteredCoinData = self.unregistered_coins.remove(token_id); let (treasury_cap, coin_metadata) = unregistered_coins.destroy(); remove_unregistered_coin_type(self, token_id); @@ -575,10 +541,6 @@ fun remove_unregistered_coin( (treasury_cap, coin_metadata) } -fun trusted_address(self: &InterchainTokenService_v0, chain_name: String): String { - *self.address_tracker.trusted_address(chain_name) -} - fun add_unregistered_coin_type( self: &mut InterchainTokenService_v0, token_id: UnregisteredTokenId, @@ -626,38 +588,23 @@ fun add_registered_coin( ); } -/// Send a payload to a destination chain. The destination chain needs to have a -/// trusted address. -fun prepare_message( - self: &InterchainTokenService_v0, - mut destination_chain: String, - mut payload: vector, -): MessageTicket { - let mut destination_address = self.trusted_address(destination_chain); - - // Prevent sending directly to the InterchainTokenService Hub chain. This is not supported yet, - // so fail early to prevent the user from having their funds stuck. - assert!( - destination_chain.into_bytes() != ITS_HUB_CHAIN_NAME, - EUntrustedChain, - ); +fun wrap_payload(self: &InterchainTokenService_v0, payload: &mut vector, destination_chain: String) { + assert!(self.is_trusted_chain(destination_chain), EUntrustedChain); - // Check whether the InterchainTokenService call should be routed via InterchainTokenService hub for this - // destination chain - if (destination_address.into_bytes() == ITS_HUB_ROUTING_IDENTIFIER) { - let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_SEND_TO_HUB); - writer.write_bytes(destination_chain.into_bytes()); - writer.write_bytes(payload); - payload = writer.into_bytes(); - destination_chain = ascii::string(ITS_HUB_CHAIN_NAME); - destination_address = self.trusted_address(destination_chain); - }; + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_SEND_TO_HUB); + writer.write_bytes(destination_chain.into_bytes()); + writer.write_bytes(*payload); + *payload = writer.into_bytes(); +} +/// Send a payload to a destination chain. The destination chain needs to have a +/// trusted address. +fun prepare_message(self: &InterchainTokenService_v0, payload: vector): MessageTicket { gateway::prepare_message( &self.channel, - destination_chain, - destination_address, + ITS_HUB_CHAIN_NAME.to_ascii_string(), + ITS_HUB_ADDRESS.to_ascii_string(), payload, ) } @@ -667,35 +614,19 @@ fun decode_approved_message( self: &InterchainTokenService_v0, approved_message: ApprovedMessage, ): (String, vector, String) { - let (mut source_chain, message_id, source_address, mut payload) = self + let (source_chain, message_id, source_address, payload) = self .channel .consume_approved_message(approved_message); - assert!( - self.is_trusted_address(source_chain, source_address), - EUntrustedAddress, - ); + assert!(is_trusted_address(source_chain, source_address), EUntrustedAddress); let mut reader = abi::new_reader(payload); - if (reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB) { - assert!( - source_chain.into_bytes() == ITS_HUB_CHAIN_NAME, - EUntrustedChain, - ); + assert!(reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, EInvalidMessageType); - source_chain = ascii::string(reader.read_bytes()); - payload = reader.read_bytes(); + let source_chain = ascii::string(reader.read_bytes()); + let payload = reader.read_bytes(); - assert!( - self.trusted_address(source_chain).into_bytes() == ITS_HUB_ROUTING_IDENTIFIER, - EUntrustedChain, - ); - } else { - assert!( - source_chain.into_bytes() != ITS_HUB_CHAIN_NAME, - EUntrustedChain, - ); - }; + assert!(self.is_trusted_chain(source_chain), EUntrustedChain); (source_chain, payload, message_id) } @@ -718,9 +649,8 @@ use interchain_token_service::coin::COIN; fun create_for_testing(ctx: &mut TxContext): InterchainTokenService_v0 { let mut self = new(version_control::version_control::new(vector[]), ctx); - self.set_trusted_address( + self.add_trusted_chain( std::ascii::string(b"Chain Name"), - std::ascii::string(b"Address"), ); self @@ -733,7 +663,10 @@ public fun create_unregistered_coin( decimals: u8, ctx: &mut TxContext, ) { - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -781,11 +714,8 @@ public(package) fun remove_registered_coin_type_for_testing( } #[test_only] -public(package) fun trusted_address_for_testing( - self: &InterchainTokenService_v0, - chain_name: String, -): String { - *self.address_tracker.trusted_address(chain_name) +public(package) fun wrap_payload_for_testing(self: &InterchainTokenService_v0, payload: &mut vector, destination_chain: String) { + self.wrap_payload(payload, destination_chain); } // ----- @@ -797,21 +727,19 @@ fun test_decode_approved_message_axelar_hub_sender() { let mut self = create_for_testing(ctx); let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); - let source_address = ascii::string(b"Address"); + let source_address = ascii::string(ITS_HUB_ADDRESS); let message_id = ascii::string(b"message_id"); let origin_chain = ascii::string(b"Source Chain"); let payload = b"payload"; let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); - writer.write_bytes(origin_chain.into_bytes()); - writer.write_bytes(payload); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + writer.write_bytes(origin_chain.into_bytes()); + writer.write_bytes(payload); let payload = writer.into_bytes(); - self.set_trusted_address(source_chain, source_address); - self.set_trusted_address( + self.add_trusted_chain( origin_chain, - ascii::string(ITS_HUB_ROUTING_IDENTIFIER), ); let approved_message = channel::new_approved_message( @@ -828,7 +756,7 @@ fun test_decode_approved_message_axelar_hub_sender() { } #[test] -#[expected_failure(abort_code = EUntrustedChain)] +#[expected_failure(abort_code = EUntrustedAddress)] fun test_decode_approved_message_sender_not_hub() { let ctx = &mut tx_context::dummy(); let self = create_for_testing(ctx); @@ -860,24 +788,20 @@ fun test_decode_approved_message_sender_not_hub() { #[expected_failure(abort_code = EUntrustedChain)] fun test_decode_approved_message_origin_not_hub_routed() { let ctx = &mut tx_context::dummy(); - let mut self = create_for_testing(ctx); + let self = create_for_testing(ctx); let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); - let source_address = ascii::string(b"Address"); + let source_address = ascii::string(ITS_HUB_ADDRESS); let message_id = ascii::string(b"message_id"); let origin_chain = ascii::string(b"Source Chain"); - let origin_trusted_address = ascii::string(b"Origin Trusted Address"); let payload = b"payload"; let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); - writer.write_bytes(origin_chain.into_bytes()); - writer.write_bytes(payload); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + writer.write_bytes(origin_chain.into_bytes()); + writer.write_bytes(payload); let payload = writer.into_bytes(); - self.set_trusted_address(source_chain, source_address); - self.set_trusted_address(origin_chain, origin_trusted_address); - let approved_message = channel::new_approved_message( source_chain, message_id, @@ -893,19 +817,17 @@ fun test_decode_approved_message_origin_not_hub_routed() { #[test] #[expected_failure(abort_code = EUntrustedChain)] -fun test_decode_approved_message_not_hub_message_from_hub() { +fun test_decode_approved_message_untrusted_chain() { let ctx = &mut tx_context::dummy(); - let mut self = create_for_testing(ctx); + let self = create_for_testing(ctx); let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); - let source_address = ascii::string(b"Address"); + let source_address = ascii::string(ITS_HUB_ADDRESS); let message_id = ascii::string(b"message_id"); let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); let payload = writer.into_bytes(); - self.set_trusted_address(source_chain, source_address); - let approved_message = channel::new_approved_message( source_chain, message_id, @@ -920,21 +842,16 @@ fun test_decode_approved_message_not_hub_message_from_hub() { } #[test] -#[expected_failure(abort_code = EUntrustedAddress)] -fun test_decode_approved_message_untrusted_address() { +#[expected_failure(abort_code = EInvalidMessageType)] +fun test_decode_approved_message_invalid_message_type() { let ctx = &mut tx_context::dummy(); let self = create_for_testing(ctx); let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); - let source_address = ascii::string(b"Address"); + let source_address = ascii::string(ITS_HUB_ADDRESS); let message_id = ascii::string(b"message_id"); - let origin_chain = ascii::string(b"Source Chain"); - let payload = b"payload"; - let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); - writer.write_bytes(origin_chain.into_bytes()); - writer.write_bytes(payload); + writer.write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER); let payload = writer.into_bytes(); let approved_message = channel::new_approved_message( @@ -956,46 +873,17 @@ fun test_prepare_message_to_hub() { let mut self = create_for_testing(ctx); let destination_chain = ascii::string(b"Destination Chain"); - let hub_address = ascii::string(b"Address"); - - let payload = b"payload"; - self.set_trusted_address(ascii::string(ITS_HUB_CHAIN_NAME), hub_address); - self.set_trusted_address( - destination_chain, - ascii::string(ITS_HUB_ROUTING_IDENTIFIER), - ); + let mut payload = b"payload"; - let message_ticket = self.prepare_message(destination_chain, payload); + self.add_trusted_chain(destination_chain); - assert!( - message_ticket.destination_chain() == ascii::string(ITS_HUB_CHAIN_NAME), - ); - assert!(message_ticket.destination_address() == hub_address); + self.wrap_payload(&mut payload, destination_chain); - sui::test_utils::destroy(self); - sui::test_utils::destroy(message_ticket); -} + let message_ticket = self.prepare_message(payload); -#[test] -#[expected_failure(abort_code = EUntrustedChain)] -fun test_prepare_message_to_hub_direct() { - let ctx = &mut tx_context::dummy(); - let mut self = create_for_testing(ctx); - - let destination_chain = ascii::string(ITS_HUB_CHAIN_NAME); - let hub_address = ascii::string(b"Address"); - - let payload = b"payload"; - - self.set_trusted_address(destination_chain, hub_address); - - let message_ticket = self.prepare_message(destination_chain, payload); - - assert!( - message_ticket.destination_chain() == ascii::string(ITS_HUB_CHAIN_NAME), - ); - assert!(message_ticket.destination_address() == hub_address); + assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); + assert!(message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string()); sui::test_utils::destroy(self); sui::test_utils::destroy(message_ticket); @@ -1022,7 +910,6 @@ fun test_receive_interchain_transfer_invalid_message_type() { let token_id = self.register_coin(coin_info, coin_management); let source_chain = ascii::string(b"Chain Name"); let message_id = ascii::string(b"Message Id"); - let message_source_address = ascii::string(b"Address"); let its_source_address = b"Source Address"; let destination_address = @0x1; @@ -1034,12 +921,18 @@ fun test_receive_interchain_transfer_invalid_message_type() { .write_bytes(destination_address.to_bytes()) .write_u256((amount as u256)) .write_bytes(b""); - let payload = writer.into_bytes(); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer + .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) + .write_bytes(source_chain.into_bytes()) + .write_bytes(payload); + payload = writer.into_bytes(); let approved_message = channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - message_source_address, + ITS_HUB_ADDRESS.to_ascii_string(), self.channel.to_address(), payload, ); @@ -1071,7 +964,6 @@ fun test_receive_interchain_transfer_passed_data() { let token_id = self.register_coin(coin_info, coin_management); let source_chain = ascii::string(b"Chain Name"); let message_id = ascii::string(b"Message Id"); - let message_source_address = ascii::string(b"Address"); let its_source_address = b"Source Address"; let destination_address = @0x1; @@ -1083,12 +975,18 @@ fun test_receive_interchain_transfer_passed_data() { .write_bytes(destination_address.to_bytes()) .write_u256((amount as u256)) .write_bytes(b"some data"); - let payload = writer.into_bytes(); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer + .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) + .write_bytes(source_chain.into_bytes()) + .write_bytes(payload); + payload = writer.into_bytes(); let approved_message = channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - message_source_address, + ITS_HUB_ADDRESS.to_ascii_string(), self.channel.to_address(), payload, ); @@ -1119,7 +1017,6 @@ fun test_receive_interchain_transfer_with_data_invalid_message_type() { let token_id = self.register_coin(coin_info, coin_management); let source_chain = ascii::string(b"Chain Name"); let message_id = ascii::string(b"Message Id"); - let message_source_address = ascii::string(b"Address"); let its_source_address = b"Source Address"; let channel = channel::new(ctx); let destination_address = channel.to_address(); @@ -1132,19 +1029,23 @@ fun test_receive_interchain_transfer_with_data_invalid_message_type() { .write_bytes(destination_address.to_bytes()) .write_u256((amount as u256)) .write_bytes(b"some_data"); - let payload = writer.into_bytes(); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer + .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) + .write_bytes(source_chain.into_bytes()) + .write_bytes(payload); + payload = writer.into_bytes(); let approved_message = channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - message_source_address, + ITS_HUB_ADDRESS.to_ascii_string(), self.channel.to_address(), payload, ); - let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data< - COIN, - >( + let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( approved_message, &channel, &clock, @@ -1178,7 +1079,6 @@ fun test_receive_interchain_transfer_with_data_wrong_destination() { let token_id = self.register_coin(coin_info, coin_management); let source_chain = ascii::string(b"Chain Name"); let message_id = ascii::string(b"Message Id"); - let message_source_address = ascii::string(b"Address"); let its_source_address = b"Source Address"; let channel = channel::new(ctx); let destination_address = @0x1; @@ -1191,19 +1091,23 @@ fun test_receive_interchain_transfer_with_data_wrong_destination() { .write_bytes(destination_address.to_bytes()) .write_u256((amount as u256)) .write_bytes(b"some_data"); - let payload = writer.into_bytes(); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer + .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) + .write_bytes(source_chain.into_bytes()) + .write_bytes(payload); + payload = writer.into_bytes(); let approved_message = channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - message_source_address, + ITS_HUB_ADDRESS.to_ascii_string(), self.channel.to_address(), payload, ); - let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data< - COIN, - >( + let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( approved_message, &channel, &clock, @@ -1237,7 +1141,6 @@ fun test_receive_interchain_transfer_with_data_no_data() { let token_id = self.register_coin(coin_info, coin_management); let source_chain = ascii::string(b"Chain Name"); let message_id = ascii::string(b"Message Id"); - let message_source_address = ascii::string(b"Address"); let its_source_address = b"Source Address"; let channel = channel::new(ctx); let destination_address = channel.to_address(); @@ -1250,19 +1153,23 @@ fun test_receive_interchain_transfer_with_data_no_data() { .write_bytes(destination_address.to_bytes()) .write_u256((amount as u256)) .write_bytes(b""); - let payload = writer.into_bytes(); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer + .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) + .write_bytes(source_chain.into_bytes()) + .write_bytes(payload); + payload = writer.into_bytes(); let approved_message = channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - message_source_address, + ITS_HUB_ADDRESS.to_ascii_string(), self.channel.to_address(), payload, ); - let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data< - COIN, - >( + let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( approved_message, &channel, &clock, @@ -1283,7 +1190,6 @@ fun test_receive_deploy_interchain_token_with_distributor() { let source_chain = ascii::string(b"Chain Name"); let message_id = ascii::string(b"Message Id"); - let source_address = ascii::string(b"Address"); let name = b"Token Name"; let symbol = b"Symbol"; let decimals = 9; @@ -1300,12 +1206,18 @@ fun test_receive_deploy_interchain_token_with_distributor() { .write_bytes(symbol) .write_u256((decimals as u256)) .write_bytes(distributor.to_bytes()); - let payload = writer.into_bytes(); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer + .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) + .write_bytes(source_chain.into_bytes()) + .write_bytes(payload); + payload = writer.into_bytes(); let approved_message = channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - source_address, + ITS_HUB_ADDRESS.to_ascii_string(), self.channel.to_address(), payload, ); @@ -1325,7 +1237,6 @@ fun test_receive_deploy_interchain_token_invalid_message_type() { let source_chain = ascii::string(b"Chain Name"); let message_id = ascii::string(b"Message Id"); - let source_address = ascii::string(b"Address"); let name = b"Token Name"; let symbol = b"Symbol"; let decimals = 9; @@ -1341,12 +1252,18 @@ fun test_receive_deploy_interchain_token_invalid_message_type() { .write_bytes(symbol) .write_u256((decimals as u256)) .write_bytes(b""); - let payload = writer.into_bytes(); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer + .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) + .write_bytes(source_chain.into_bytes()) + .write_bytes(payload); + payload = writer.into_bytes(); let approved_message = channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - source_address, + ITS_HUB_ADDRESS.to_ascii_string(), self.channel.to_address(), payload, ); @@ -1440,7 +1357,10 @@ fun test_give_unregistered_coin_module_name_missmatch() { let ctx = &mut tx_context::dummy(); let mut self = create_for_testing(ctx); - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -1459,7 +1379,10 @@ fun test_mint_as_distributor_not_distributor() { let symbol = b"COIN"; let decimals = 9; - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -1508,7 +1431,10 @@ fun test_mint_to_as_distributor_not_distributor() { let symbol = b"COIN"; let decimals = 9; - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -1589,7 +1515,9 @@ fun test_send_interchain_transfer_newer_ticket() { let current_version = 0; let invalid_version = 1; - let interchain_transfer_ticket = interchain_token_service::interchain_transfer_ticket::new( + let interchain_transfer_ticket = interchain_token_service::interchain_transfer_ticket::new< + COIN, + >( token_id, coin.into_balance(), source_channel.to_address(), @@ -1610,19 +1538,15 @@ fun test_send_interchain_transfer_newer_ticket() { sui::test_utils::destroy(clock); } -// no error code becaues this aborts in a macro #[test] -#[expected_failure] -fun test_set_trusted_addresses_mismatch_lengths() { +#[expected_failure(abort_code = EUntrustedChain)] +fun test_wrap_payload_untrusted_chain() { let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); + let its = create_for_testing(ctx); + let mut payload = b"payload"; + let destination_chain = b"destination_chain".to_ascii_string(); - its.set_trusted_addresses( - interchain_token_service::trusted_addresses::new_for_testing( - vector[], - vector[b"trusted address".to_ascii_string()], - ), - ); + its.wrap_payload(&mut payload, destination_chain); sui::test_utils::destroy(its); } From 7ac8025abbd1cb29f724e14231577bc225538673 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 20 Jan 2025 19:26:48 +0200 Subject: [PATCH 18/68] fixed some tests --- .../sources/interchain_token_service.move | 6 ++-- .../interchain_token_service_v0.move | 11 ++++++- move/squid/sources/squid/squid.move | 23 +++++++++++--- .../sources/squid/versioned/squid_v0.move | 19 +++++++++--- ...nterchain_token_service_chain_tracker.json | 30 +++++++++++++++++++ ...rface_interchain_token_service_events.json | 8 ++--- ...n_service_interchain_token_service_v0.json | 4 +-- 7 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 test/testdata/interface_interchain_token_service_chain_tracker.json diff --git a/move/interchain_token_service/sources/interchain_token_service.move b/move/interchain_token_service/sources/interchain_token_service.move index db385bf0..43fb4062 100644 --- a/move/interchain_token_service/sources/interchain_token_service.move +++ b/move/interchain_token_service/sources/interchain_token_service.move @@ -405,6 +405,7 @@ const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; // === HUB CONSTANTS === +#[test_only] // Axelar. const ITS_HUB_CHAIN_NAME: vector = b"axelar"; #[test_only] @@ -526,7 +527,7 @@ fun test_deploy_remote_interchain_token() { .write_u256((token_decimals as u256)) .write_bytes(vector::empty()); let mut payload = writer.into_bytes(); - its.value!(b"").wrap_payload_for_testing(&mut payload, destination_chain); + its.value!(b"").wrap_payload_sending(&mut payload, destination_chain); assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); @@ -579,7 +580,6 @@ fun test_deploy_interchain_token() { utils::assert_event>(); let mut writer = abi::new_writer(6); - writer .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) .write_u256(token_id.to_u256()) @@ -588,7 +588,7 @@ fun test_deploy_interchain_token() { .write_u256((amount as u256)) .write_bytes(b""); let mut payload = writer.into_bytes(); - its.value!(b"").wrap_payload_for_testing(&mut payload, destination_chain); + its.value!(b"").wrap_payload_sending(&mut payload, destination_chain); assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index 76757da4..80810419 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -714,10 +714,19 @@ public(package) fun remove_registered_coin_type_for_testing( } #[test_only] -public(package) fun wrap_payload_for_testing(self: &InterchainTokenService_v0, payload: &mut vector, destination_chain: String) { +public(package) fun wrap_payload_sending(self: &InterchainTokenService_v0, payload: &mut vector, destination_chain: String) { self.wrap_payload(payload, destination_chain); } +#[test_only] +public fun wrap_payload_receiving(payload: &mut vector, source_chain: String) { + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + writer.write_bytes(source_chain.into_bytes()); + writer.write_bytes(*payload); + *payload = writer.into_bytes(); +} + // ----- // Tests // ----- diff --git a/move/squid/sources/squid/squid.move b/move/squid/sources/squid/squid.move index fbd7a4c9..a7f5f1f5 100644 --- a/move/squid/sources/squid/squid.move +++ b/move/squid/sources/squid/squid.move @@ -151,6 +151,17 @@ fun new_version_control(): VersionControl { ]) } +/// --------- +/// Test Only +/// --------- +/// // === HUB CONSTANTS === +#[test_only] +// Axelar. +const ITS_HUB_CHAIN_NAME: vector = b"axelar"; +#[test_only] +// The address of the ITS HUB. +const ITS_HUB_ADDRESS: vector = b"hub_address"; + #[test_only] public fun new_for_testing(ctx: &mut TxContext): Squid { let mut version_control = new_version_control(); @@ -171,6 +182,9 @@ public fun new_for_testing(ctx: &mut TxContext): Squid { #[test_only] use interchain_token_service::coin::COIN; +/// ----- +/// Tests +/// ----- #[test] fun test_start_swap() { let ctx = &mut tx_context::dummy(); @@ -210,7 +224,6 @@ fun test_start_swap() { let source_chain = std::ascii::string(b"Chain Name"); let message_id = std::ascii::string(b"Message Id"); - let message_source_address = std::ascii::string(b"Address"); let its_source_address = b"Source Address"; let destination_address = squid.value!(b"").channel().to_address(); @@ -223,12 +236,14 @@ fun test_start_swap() { .write_bytes(destination_address.to_bytes()) .write_u256((amount as u256)) .write_bytes(data); - let payload = writer.into_bytes(); + + let mut payload = writer.into_bytes(); + interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(&mut payload, source_chain); let approved_message = axelar_gateway::channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - message_source_address, + ITS_HUB_ADDRESS.to_ascii_string(), its.channel_address(), payload, ); diff --git a/move/squid/sources/squid/versioned/squid_v0.move b/move/squid/sources/squid/versioned/squid_v0.move index a08333a4..fb0e8c57 100644 --- a/move/squid/sources/squid/versioned/squid_v0.move +++ b/move/squid/sources/squid/versioned/squid_v0.move @@ -96,6 +96,17 @@ public(package) fun withdraw( // --------- // Test Only // --------- +/// --------- +/// Test Only +/// --------- +/// // === HUB CONSTANTS === +#[test_only] +// Axelar. +const ITS_HUB_CHAIN_NAME: vector = b"axelar"; +#[test_only] +// The address of the ITS HUB. +const ITS_HUB_ADDRESS: vector = b"hub_address"; + #[test_only] public fun new_for_testing(ctx: &mut TxContext): Squid_v0 { Squid_v0 { @@ -149,7 +160,6 @@ fun test_start_swap() { let source_chain = std::ascii::string(b"Chain Name"); let message_id = std::ascii::string(b"Message Id"); - let message_source_address = std::ascii::string(b"Address"); let its_source_address = b"Source Address"; let destination_address = squid.channel().to_address(); @@ -162,12 +172,13 @@ fun test_start_swap() { .write_bytes(destination_address.to_bytes()) .write_u256((amount as u256)) .write_bytes(data); - let payload = writer.into_bytes(); + let mut payload = writer.into_bytes(); + interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(&mut payload, source_chain); let approved_message = channel::new_approved_message( - source_chain, + ITS_HUB_CHAIN_NAME.to_ascii_string(), message_id, - message_source_address, + ITS_HUB_ADDRESS.to_ascii_string(), its.channel_address(), payload, ); diff --git a/test/testdata/interface_interchain_token_service_chain_tracker.json b/test/testdata/interface_interchain_token_service_chain_tracker.json new file mode 100644 index 00000000..42c8c184 --- /dev/null +++ b/test/testdata/interface_interchain_token_service_chain_tracker.json @@ -0,0 +1,30 @@ +{ + "structs": { + "TrustedChain": { + "name": "TrustedChain", + "abilities": [ + "drop", + "store" + ], + "fields": [ + { + "name": "dummy_field", + "type": "bool" + } + ] + }, + "InterchainChainTracker": { + "name": "InterchainChainTracker", + "abilities": [ + "store" + ], + "fields": [ + { + "name": "trusted_addresses", + "type": "Table" + } + ] + } + }, + "publicFunctions": {} +} diff --git a/test/testdata/interface_interchain_token_service_events.json b/test/testdata/interface_interchain_token_service_events.json index de36422c..4c35d122 100644 --- a/test/testdata/interface_interchain_token_service_events.json +++ b/test/testdata/interface_interchain_token_service_events.json @@ -1,7 +1,7 @@ { "structs": { - "TrustedAddressSet": { - "name": "TrustedAddressSet", + "TrustedAddressAdded": { + "name": "TrustedAddressAdded", "abilities": [ "copy", "drop" @@ -10,10 +10,6 @@ { "name": "chain_name", "type": "String" - }, - { - "name": "trusted_address", - "type": "String" } ] }, diff --git a/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json b/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json index f850013e..a22c0db2 100644 --- a/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json +++ b/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json @@ -11,8 +11,8 @@ "type": "Channel" }, { - "name": "address_tracker", - "type": "InterchainAddressTracker" + "name": "chain_tracker", + "type": "InterchainChainTracker" }, { "name": "unregistered_coin_types", From 46e65b2065fbcbf686b43fe646d700761e57cf7c Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 20 Jan 2025 20:04:21 +0200 Subject: [PATCH 19/68] rename some stuff --- .../sources/types/chain_tracker.move | 20 +++++++++---------- src/common/bcs.ts | 14 ++++--------- test/bcs.js | 2 +- test/its.js | 3 +-- ...erchain_token_service_address_tracker.json | 17 ---------------- test/testutils.js | 11 +++------- 6 files changed, 19 insertions(+), 48 deletions(-) delete mode 100644 test/testdata/interface_interchain_token_service_address_tracker.json diff --git a/move/interchain_token_service/sources/types/chain_tracker.move b/move/interchain_token_service/sources/types/chain_tracker.move index e2ec3b1b..61b7b4cb 100644 --- a/move/interchain_token_service/sources/types/chain_tracker.move +++ b/move/interchain_token_service/sources/types/chain_tracker.move @@ -19,7 +19,7 @@ public struct TrustedChain has store, drop {} /// The interchain address tracker stores the trusted addresses for each chain. public struct InterchainChainTracker has store { - trusted_addresses: Table, + trusted_chains: Table, } // ----------------- @@ -30,13 +30,13 @@ public(package) fun is_trusted_chain( self: &InterchainChainTracker, chain_name: String, ): bool { - self.trusted_addresses.contains(chain_name) + self.trusted_chains.contains(chain_name) } /// Create a new interchain address tracker. public(package) fun new(ctx: &mut TxContext): InterchainChainTracker { InterchainChainTracker { - trusted_addresses: table::new(ctx), + trusted_chains: table::new(ctx), } } @@ -47,10 +47,10 @@ public(package) fun add_trusted_chain( ) { assert!(chain_name.length() > 0, EEmptyChainName); - if (self.trusted_addresses.contains(chain_name)) { + if (self.trusted_chains.contains(chain_name)) { abort EAlreadyTrusted } else { - self.trusted_addresses.add(chain_name, TrustedChain{}); + self.trusted_chains.add(chain_name, TrustedChain{}); }; events::trusted_address_added(chain_name); } @@ -60,7 +60,7 @@ public(package) fun remove_trusted_chain( chain_name: String, ) { assert!(chain_name.length() > 0, EEmptyChainName); - self.trusted_addresses.remove(chain_name); + self.trusted_chains.remove(chain_name); events::trusted_address_removed(chain_name); } @@ -80,8 +80,8 @@ fun test_chain_tracker() { assert!(self.is_trusted_chain(chain1) == true); assert!(self.is_trusted_chain(chain2) == true); - assert!(self.trusted_addresses.contains(chain1)); - assert!(self.trusted_addresses.contains(chain2)); + assert!(self.trusted_chains.contains(chain1)); + assert!(self.trusted_chains.contains(chain2)); self.remove_trusted_chain(chain1); self.remove_trusted_chain(chain2); @@ -90,8 +90,8 @@ fun test_chain_tracker() { assert!(self.is_trusted_chain(chain1) == false); assert!(self.is_trusted_chain(chain2) == false); - assert!(!self.trusted_addresses.contains(chain1)); - assert!(!self.trusted_addresses.contains(chain2)); + assert!(!self.trusted_chains.contains(chain1)); + assert!(!self.trusted_chains.contains(chain2)); sui::test_utils::destroy(self); } diff --git a/src/common/bcs.ts b/src/common/bcs.ts index 08149f5b..9abc3cc1 100644 --- a/src/common/bcs.ts +++ b/src/common/bcs.ts @@ -264,18 +264,13 @@ function getITSStructs() { const { Table, Bag, Channel } = getCommonStructs(); const { VersionControl } = getVersionControlStructs(); - const InterchainAddressTracker = bcs.struct('InterchainAddressTracker', { - trusted_addresses: Table, - }); - - const TrustedAddresses = bcs.struct('TrustedAddresses', { - trusted_chains: bcs.vector(bcs.string()), - trusted_addresses: bcs.vector(bcs.string()), + const InterchainChainTracker = bcs.struct('InterchainChainTracker', { + trusted_chains: Table, }); const InterchainTokenServiceV0 = bcs.struct('InterchainTokenService_v0', { channel: Channel, - address_tracker: InterchainAddressTracker, + address_tracker: InterchainChainTracker, unregistered_coin_types: Table, unregistered_coins: Bag, registered_coin_types: Table, @@ -291,9 +286,8 @@ function getITSStructs() { }); return { - InterchainAddressTracker, + InterchainChainTracker, InterchainTokenService, - TrustedAddresses, }; } diff --git a/test/bcs.js b/test/bcs.js index 57a2e370..a1ab0edd 100644 --- a/test/bcs.js +++ b/test/bcs.js @@ -24,7 +24,7 @@ describe('BCS', () => { it('should decode InterchainTokenService_v0 object successfully', () => { const its = bcsStructs.its.InterchainTokenService.parse(fromHEX(hexData.InterchainTokenService_v0)).value; - checkIdAndSize(its.address_tracker.trusted_addresses, '270c7f8b9757b05777d3cbf98fa1bb197e1f5a18c8ff7a8ef16e80bedf39a67f'); + checkIdAndSize(its.chain_tracker.trusted_chains, '270c7f8b9757b05777d3cbf98fa1bb197e1f5a18c8ff7a8ef16e80bedf39a67f'); checkIdAndSize(its.unregistered_coin_types, '00c101dbc800d8cf853e6d21c916aba7c92e4c2692527dc951c777dae15cf474'); checkIdAndSize(its.unregistered_coins, '44bacbed87a2d5f871ce96f3245a293b936fb287605330b3859649f3a2697668'); checkIdAndSize(its.registered_coin_types, '13bd4dc87b61a82ce5959e3ea8c3fed1e03d9c1f7246eef82722354d8e3c0d54'); diff --git a/test/its.js b/test/its.js index 3073ac33..226bf63d 100644 --- a/test/its.js +++ b/test/its.js @@ -57,7 +57,6 @@ describe('ITS', () => { // Parameters for Trusted Addresses const trustedSourceChain = 'Avalanche'; - const trustedSourceAddress = hexlify(randomBytes(20)); async function setupGateway() { calculateNextSigners(gatewayInfo, nonce); @@ -186,7 +185,7 @@ describe('ITS', () => { before(async () => { await setupGateway(); await registerItsTransaction(); - await setupTrustedAddresses(client, deployer, objectIds, deployments, [trustedSourceAddress], [trustedSourceChain]); + await setupTrustedAddresses(client, deployer, objectIds, deployments, [trustedSourceChain]); }); describe('Interchain Token Transfer', () => { diff --git a/test/testdata/interface_interchain_token_service_address_tracker.json b/test/testdata/interface_interchain_token_service_address_tracker.json deleted file mode 100644 index b159b8e7..00000000 --- a/test/testdata/interface_interchain_token_service_address_tracker.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "structs": { - "InterchainAddressTracker": { - "name": "InterchainAddressTracker", - "abilities": [ - "store" - ], - "fields": [ - { - "name": "trusted_addresses", - "type": "Table" - } - ] - } - }, - "publicFunctions": {} -} diff --git a/test/testutils.js b/test/testutils.js index 20e9f51b..2b5a0a34 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -370,18 +370,13 @@ const getSingletonChannelId = async (client, singletonObjectId) => { return '0x' + data.channel.id; }; -async function setupTrustedAddresses(client, keypair, objectIds, deployments, trustedAddresses, trustedChains = ['Ethereum']) { +async function setupTrustedAddresses(client, keypair, objectIds, deployments, trustedChains = ['Ethereum']) { // Set trusted addresses const trustedAddressTxBuilder = new TxBuilder(client); - const trustedAddressesObject = await trustedAddressTxBuilder.moveCall({ - target: `${deployments.interchain_token_service.packageId}::trusted_addresses::new`, - arguments: [trustedChains, trustedAddresses], - }); - await trustedAddressTxBuilder.moveCall({ - target: `${deployments.interchain_token_service.packageId}::interchain_token_service::set_trusted_addresses`, - arguments: [objectIds.its, objectIds.itsOwnerCap, trustedAddressesObject], + target: `${deployments.interchain_token_service.packageId}::interchain_token_service::add_trusted_chains`, + arguments: [objectIds.its, objectIds.itsOwnerCap, trustedChains], }); const trustedAddressResult = await trustedAddressTxBuilder.signAndExecute(keypair); From 1bf88f113548e51d87d3a29643840332953d7c77 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 20 Jan 2025 20:09:55 +0200 Subject: [PATCH 20/68] fix some tests --- test/its.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/its.js b/test/its.js index 226bf63d..c6d7f1f6 100644 --- a/test/its.js +++ b/test/its.js @@ -56,7 +56,9 @@ describe('ITS', () => { const nonce = 0; // Parameters for Trusted Addresses - const trustedSourceChain = 'Avalanche'; + const trustedSourceChain = 'axelar'; + const trustedSourceAddress = 'hub'; + const otherChain = 'Avalanche'; async function setupGateway() { calculateNextSigners(gatewayInfo, nonce); @@ -196,6 +198,7 @@ describe('ITS', () => { const tx = txBuilder.tx; const coin = tx.splitCoins(objectIds.token, [1e9]); + const destinationAddress = '0x1234'; const gas = tx.splitCoins(tx.gas, [1e8]); const TokenId = await txBuilder.moveCall({ @@ -212,8 +215,8 @@ describe('ITS', () => { objectIds.gasService, TokenId, coin, - trustedSourceChain, - trustedSourceAddress, + otherChain, + destinationAddress, '0x', // its token metadata deployer.toSuiAddress(), gas, @@ -231,7 +234,7 @@ describe('ITS', () => { // Approve ITS transfer message const messageType = ITSMessageType.InterchainTokenTransfer; const tokenId = objectIds.tokenId; - const sourceAddress = trustedSourceAddress; + const sourceAddress = '0x1234'; const destinationAddress = objectIds.itsChannel; // The ITS Channel ID. All ITS messages are sent to this channel const amount = 1e9; const data = '0x1234'; From eb43639bd76b53cefe360b2b18bde4bc77d0a058 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 21 Jan 2025 01:39:26 +0200 Subject: [PATCH 21/68] fix tests --- .../sources/discovery.move | 8 ++++++ src/common/bcs.ts | 2 +- src/common/types.ts | 3 +++ test/its.js | 18 +++++++++---- test/squid.js | 25 +++++++++++++------ ...nterchain_token_service_chain_tracker.json | 2 +- 6 files changed, 43 insertions(+), 15 deletions(-) diff --git a/move/interchain_token_service/sources/discovery.move b/move/interchain_token_service/sources/discovery.move index 139b65a7..acc6e8be 100644 --- a/move/interchain_token_service/sources/discovery.move +++ b/move/interchain_token_service/sources/discovery.move @@ -30,6 +30,14 @@ public fun interchain_transfer_info( ): (TokenId, address, u64, vector) { let mut reader = abi::new_reader(payload); assert!( + reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, + EInvalidMessageType, + ); + // Source chain validation is not done here. + reader.skip_slot(); + let payload = reader.read_bytes(); + reader = abi::new_reader(payload); + assert!( reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType, ); diff --git a/src/common/bcs.ts b/src/common/bcs.ts index 9abc3cc1..b9a47e7d 100644 --- a/src/common/bcs.ts +++ b/src/common/bcs.ts @@ -270,7 +270,7 @@ function getITSStructs() { const InterchainTokenServiceV0 = bcs.struct('InterchainTokenService_v0', { channel: Channel, - address_tracker: InterchainChainTracker, + chain_tracker: InterchainChainTracker, unregistered_coin_types: Table, unregistered_coins: Bag, registered_coin_types: Table, diff --git a/src/common/types.ts b/src/common/types.ts index 57da06be..aa9ffb89 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -23,6 +23,9 @@ export interface Dependency { export enum ITSMessageType { InterchainTokenTransfer = 0, InterchainTokenDeployment = 1, + SendToItsHub = 3, + ReceiveFromItsHub = 4, + RegisdterTokenMetadata = 6, } export enum GatewayMessageType { diff --git a/test/its.js b/test/its.js index c6d7f1f6..370b42f6 100644 --- a/test/its.js +++ b/test/its.js @@ -57,7 +57,7 @@ describe('ITS', () => { // Parameters for Trusted Addresses const trustedSourceChain = 'axelar'; - const trustedSourceAddress = 'hub'; + const trustedSourceAddress = 'hub_address'; const otherChain = 'Avalanche'; async function setupGateway() { @@ -187,7 +187,7 @@ describe('ITS', () => { before(async () => { await setupGateway(); await registerItsTransaction(); - await setupTrustedAddresses(client, deployer, objectIds, deployments, [trustedSourceChain]); + await setupTrustedAddresses(client, deployer, objectIds, deployments, [otherChain]); }); describe('Interchain Token Transfer', () => { @@ -247,10 +247,14 @@ describe('ITS', () => { // Channel ID for the ITS example. This will be encoded in the payload const itsExampleChannelId = await getSingletonChannelId(client, objectIds.singleton); // ITS transfer payload from Ethereum to Sui - const payload = defaultAbiCoder.encode( + let payload = defaultAbiCoder.encode( ['uint256', 'uint256', 'bytes', 'bytes', 'uint256', 'bytes'], [messageType, tokenId, sourceAddress, itsExampleChannelId, amount, data], ); + payload = defaultAbiCoder.encode( + ['uint256', 'string', 'bytes'], + [ITSMessageType.ReceiveFromItsHub, otherChain, payload], + ); const message = { source_chain: trustedSourceChain, @@ -282,7 +286,7 @@ describe('ITS', () => { objectIds.its, objectIds.gateway, objectIds.gasService, - trustedSourceChain, + otherChain, TokenId, gas, '0x', @@ -331,10 +335,14 @@ describe('ITS', () => { const distributor = '0x'; // ITS transfer payload from Ethereum to Sui - const payload = defaultAbiCoder.encode( + let payload = defaultAbiCoder.encode( ['uint256', 'uint256', 'bytes', 'bytes', 'uint256', 'bytes'], [messageType, tokenId, byteName, byteSymbol, decimals, distributor], ); + payload = defaultAbiCoder.encode( + ['uint256', 'string', 'bytes'], + [ITSMessageType.ReceiveFromItsHub, otherChain, payload], + ) const message = { source_chain: trustedSourceChain, diff --git a/test/squid.js b/test/squid.js index bf7836ca..868e9fd3 100644 --- a/test/squid.js +++ b/test/squid.js @@ -51,8 +51,9 @@ describe('Squid', () => { const nonce = 0; // Parameters for Trusted Addresses - const trustedSourceChain = 'Avalanche'; - const trustedSourceAddress = hexlify(randomBytes(20)); + const trustedSourceChain = 'axelar'; + const trustedSourceAddress = 'hub_address'; + const otherChain = 'Avalanche'; const coins = {}; const pools = {}; @@ -228,7 +229,7 @@ describe('Squid', () => { const interchainTransfer = await builder.moveCall({ target: `${deployments.interchain_token_service.packageId}::interchain_token_service::prepare_interchain_transfer`, - arguments: [tokenId, input, trustedSourceChain, '0xadd1', '0x', channel], + arguments: [tokenId, input, otherChain, '0xadd1', '0x', channel], typeArguments: [coins[coinName].type], }); @@ -425,7 +426,7 @@ describe('Squid', () => { await setupGateway(); await registerItsTransaction(); await registerSquidTransaction(); - await setupTrustedAddresses(client, deployer, objectIds, deployments, [trustedSourceAddress], [trustedSourceChain]); + await setupTrustedAddresses(client, deployer, objectIds, deployments, [otherChain]); await new Promise((resolve) => setTimeout(resolve, 1000)); await registerCoin('a'); await giveDeepToSquid(); @@ -441,16 +442,20 @@ describe('Squid', () => { const messageType = ITSMessageType.InterchainTokenTransfer; const tokenId = objectIds.tokenId; - const sourceAddress = trustedSourceAddress; + const sourceAddress = '0x1234'; const destinationAddress = objectIds.itsChannel; // The ITS Channel ID. All ITS messages are sent to this channel const data = swapData; // Channel ID for Squid. This will be encoded in the payload const squidChannelId = objectIds.squidChannel; // ITS transfer payload from Ethereum to Sui - const payload = defaultAbiCoder.encode( + let payload = defaultAbiCoder.encode( ['uint256', 'uint256', 'bytes', 'bytes', 'uint256', 'bytes'], [messageType, tokenId, sourceAddress, squidChannelId, amount, data], ); + payload = defaultAbiCoder.encode( + ['uint256', 'string', 'bytes'], + [ITSMessageType.ReceiveFromItsHub, otherChain, payload], + ) const message = { source_chain: trustedSourceChain, @@ -477,16 +482,20 @@ describe('Squid', () => { const messageType = ITSMessageType.InterchainTokenTransfer; const tokenId = objectIds.tokenId; - const sourceAddress = trustedSourceAddress; + const sourceAddress = '0x1234'; const destinationAddress = objectIds.itsChannel; // The ITS Channel ID. All ITS messages are sent to this channel const data = swapData; // Channel ID for Squid. This will be encoded in the payload const squidChannelId = objectIds.squidChannel; // ITS transfer payload from Ethereum to Sui - const payload = defaultAbiCoder.encode( + let payload = defaultAbiCoder.encode( ['uint256', 'uint256', 'bytes', 'bytes', 'uint256', 'bytes'], [messageType, tokenId, sourceAddress, squidChannelId, amount, data], ); + payload = defaultAbiCoder.encode( + ['uint256', 'string', 'bytes'], + [ITSMessageType.ReceiveFromItsHub, otherChain, payload], + ); const message = { source_chain: trustedSourceChain, diff --git a/test/testdata/interface_interchain_token_service_chain_tracker.json b/test/testdata/interface_interchain_token_service_chain_tracker.json index 42c8c184..028546b2 100644 --- a/test/testdata/interface_interchain_token_service_chain_tracker.json +++ b/test/testdata/interface_interchain_token_service_chain_tracker.json @@ -20,7 +20,7 @@ ], "fields": [ { - "name": "trusted_addresses", + "name": "trusted_chains", "type": "Table" } ] From 663bbefcb6e0271279de636707f5de55e8e117f4 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 21 Jan 2025 14:57:48 +0200 Subject: [PATCH 22/68] fix move tests --- move/axelar_gateway/sources/events.move | 6 +-- .../sources/discovery.move | 47 ++++++------------- .../sources/types/chain_tracker.move | 21 ++------- .../sources/types/coin_data.move | 4 +- .../interchain_token_service_v0.move | 24 ++++++---- test/its.js | 10 +--- test/squid.js | 10 +--- 7 files changed, 41 insertions(+), 81 deletions(-) diff --git a/move/axelar_gateway/sources/events.move b/move/axelar_gateway/sources/events.move index 29247a9b..c5494388 100644 --- a/move/axelar_gateway/sources/events.move +++ b/move/axelar_gateway/sources/events.move @@ -48,11 +48,7 @@ public struct MessageExecuted has copy, drop { // ----------------- // Package Functions // ----------------- -public(package) fun signers_rotated( - epoch: u64, - signers_hash: Bytes32, - signers: WeightedSigners, -) { +public(package) fun signers_rotated(epoch: u64, signers_hash: Bytes32, signers: WeightedSigners) { event::emit(SignersRotated { epoch, signers_hash, diff --git a/move/interchain_token_service/sources/discovery.move b/move/interchain_token_service/sources/discovery.move index acc6e8be..199d659b 100644 --- a/move/interchain_token_service/sources/discovery.move +++ b/move/interchain_token_service/sources/discovery.move @@ -13,8 +13,7 @@ use sui::address; /// Errors /// ------ #[error] -const EUnsupportedMessageType: vector = - b"the message type found is not supported"; +const EUnsupportedMessageType: vector = b"the message type found is not supported"; #[error] const EInvalidMessageType: vector = b"can only get interchain transfer info for interchain transfers"; @@ -25,22 +24,14 @@ const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; // onst MESSAGE_TYPE_SEND_TO_HUB: u256 = 3; const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; -public fun interchain_transfer_info( - payload: vector, -): (TokenId, address, u64, vector) { +public fun interchain_transfer_info(payload: vector): (TokenId, address, u64, vector) { let mut reader = abi::new_reader(payload); - assert!( - reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, - EInvalidMessageType, - ); + assert!(reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, EInvalidMessageType); // Source chain validation is not done here. reader.skip_slot(); let payload = reader.read_bytes(); reader = abi::new_reader(payload); - assert!( - reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, - EInvalidMessageType, - ); + assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); let token_id = token_id::from_u256(reader.read_u256()); reader.skip_slot(); // skip source_address @@ -95,10 +86,7 @@ public fun call_info(its: &InterchainTokenService, mut payload: vector): Tra if (message_type == MESSAGE_TYPE_INTERCHAIN_TRANSFER) { interchain_transfer_tx(its, &mut reader) } else { - assert!( - message_type == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, - EUnsupportedMessageType, - ); + assert!(message_type == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, EUnsupportedMessageType); deploy_interchain_token_tx(its, &mut reader) } } @@ -135,10 +123,7 @@ fun interchain_transfer_tx(its: &InterchainTokenService, reader: &mut AbiReader) ) } else { let mut discovery_arg = vector[0]; - discovery_arg.append(value - .relayer_discovery_id() - .id_to_address() - .to_bytes()); + discovery_arg.append(value.relayer_discovery_id().id_to_address().to_bytes()); let mut channel_id_arg = vector[1]; channel_id_arg.append(destination_address.to_bytes()); @@ -277,9 +262,7 @@ fun test_discovery_interchain_transfer() { call_info.function().package_id_from_function() == package_id(), ); assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); - assert!( - call_info.function().name() == ascii::string(b"receive_interchain_transfer"), - ); + assert!(call_info.function().name() == ascii::string(b"receive_interchain_transfer")); let mut arg = vector[0]; arg.append(object::id_address(&its).to_bytes()); @@ -330,9 +313,7 @@ fun test_discovery_interchain_transfer_with_data() { let mut reader = abi::new_reader(payload); reader.skip_slot(); // skip message_type - assert!( - call_info(&its, payload) == interchain_transfer_tx(&its, &mut reader), - ); + assert!(call_info(&its, payload) == interchain_transfer_tx(&its, &mut reader)); sui::test_utils::destroy(its); sui::test_utils::destroy(discovery); @@ -384,9 +365,7 @@ fun test_discovery_deploy_token() { call_info.function().package_id_from_function() == package_id(), ); assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); - assert!( - call_info.function().name() == ascii::string(b"receive_deploy_interchain_token"), - ); + assert!(call_info.function().name() == ascii::string(b"receive_deploy_interchain_token")); let mut arg = vector[0]; arg.append(object::id_address(&its).to_bytes()); @@ -403,6 +382,7 @@ fun test_interchain_transfer_info() { let message_type = MESSAGE_TYPE_INTERCHAIN_TRANSFER; let token_id = 1; let source_address = b"source address"; + let source_chain = b"Chain Name"; let destination = @0x3.to_bytes(); let amount = 2; let data = b"data"; @@ -415,6 +395,9 @@ fun test_interchain_transfer_info() { .write_bytes(destination) .write_u256(amount) .write_bytes(data); + let payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain).write_bytes(payload); let ( resolved_token_id, @@ -494,9 +477,7 @@ fun test_discovery_hub_message() { call_info.function().package_id_from_function() == package_id(), ); assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); - assert!( - call_info.function().name() == ascii::string(b"receive_interchain_transfer"), - ); + assert!(call_info.function().name() == ascii::string(b"receive_interchain_transfer")); let mut arg = vector[0]; arg.append(object::id_address(&its).to_bytes()); diff --git a/move/interchain_token_service/sources/types/chain_tracker.move b/move/interchain_token_service/sources/types/chain_tracker.move index 61b7b4cb..767830f3 100644 --- a/move/interchain_token_service/sources/types/chain_tracker.move +++ b/move/interchain_token_service/sources/types/chain_tracker.move @@ -12,8 +12,7 @@ use sui::table::{Self, Table}; #[error] const EEmptyChainName: vector = b"empty trusted chain name is unsupported"; #[error] -const EAlreadyTrusted: vector = - b"chain is already trusted"; +const EAlreadyTrusted: vector = b"chain is already trusted"; public struct TrustedChain has store, drop {} @@ -26,10 +25,7 @@ public struct InterchainChainTracker has store { // Package Functions // ----------------- /// Check if the given address is trusted for the given chain. -public(package) fun is_trusted_chain( - self: &InterchainChainTracker, - chain_name: String, -): bool { +public(package) fun is_trusted_chain(self: &InterchainChainTracker, chain_name: String): bool { self.trusted_chains.contains(chain_name) } @@ -41,24 +37,18 @@ public(package) fun new(ctx: &mut TxContext): InterchainChainTracker { } /// Set the trusted address for a chain or adds it if it doesn't exist. -public(package) fun add_trusted_chain( - self: &mut InterchainChainTracker, - chain_name: String, -) { +public(package) fun add_trusted_chain(self: &mut InterchainChainTracker, chain_name: String) { assert!(chain_name.length() > 0, EEmptyChainName); if (self.trusted_chains.contains(chain_name)) { abort EAlreadyTrusted } else { - self.trusted_chains.add(chain_name, TrustedChain{}); + self.trusted_chains.add(chain_name, TrustedChain {}); }; events::trusted_address_added(chain_name); } -public(package) fun remove_trusted_chain( - self: &mut InterchainChainTracker, - chain_name: String, -) { +public(package) fun remove_trusted_chain(self: &mut InterchainChainTracker, chain_name: String) { assert!(chain_name.length() > 0, EEmptyChainName); self.trusted_chains.remove(chain_name); events::trusted_address_removed(chain_name); @@ -86,7 +76,6 @@ fun test_chain_tracker() { self.remove_trusted_chain(chain1); self.remove_trusted_chain(chain2); - assert!(self.is_trusted_chain(chain1) == false); assert!(self.is_trusted_chain(chain2) == false); diff --git a/move/interchain_token_service/sources/types/coin_data.move b/move/interchain_token_service/sources/types/coin_data.move index 17c4578c..6415ccab 100644 --- a/move/interchain_token_service/sources/types/coin_data.move +++ b/move/interchain_token_service/sources/types/coin_data.move @@ -28,8 +28,6 @@ public(package) fun coin_info(self: &CoinData): &CoinInfo { &self.coin_info } -public(package) fun coin_management_mut( - self: &mut CoinData, -): &mut CoinManagement { +public(package) fun coin_management_mut(self: &mut CoinData): &mut CoinManagement { &mut self.coin_management } diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index 80810419..167631b7 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -588,7 +588,11 @@ fun add_registered_coin( ); } -fun wrap_payload(self: &InterchainTokenService_v0, payload: &mut vector, destination_chain: String) { +fun wrap_payload( + self: &InterchainTokenService_v0, + payload: &mut vector, + destination_chain: String, +) { assert!(self.is_trusted_chain(destination_chain), EUntrustedChain); let mut writer = abi::new_writer(3); @@ -714,7 +718,11 @@ public(package) fun remove_registered_coin_type_for_testing( } #[test_only] -public(package) fun wrap_payload_sending(self: &InterchainTokenService_v0, payload: &mut vector, destination_chain: String) { +public(package) fun wrap_payload_sending( + self: &InterchainTokenService_v0, + payload: &mut vector, + destination_chain: String, +) { self.wrap_payload(payload, destination_chain); } @@ -742,9 +750,9 @@ fun test_decode_approved_message_axelar_hub_sender() { let payload = b"payload"; let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); - writer.write_bytes(origin_chain.into_bytes()); - writer.write_bytes(payload); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + writer.write_bytes(origin_chain.into_bytes()); + writer.write_bytes(payload); let payload = writer.into_bytes(); self.add_trusted_chain( @@ -806,9 +814,9 @@ fun test_decode_approved_message_origin_not_hub_routed() { let payload = b"payload"; let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); - writer.write_bytes(origin_chain.into_bytes()); - writer.write_bytes(payload); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + writer.write_bytes(origin_chain.into_bytes()); + writer.write_bytes(payload); let payload = writer.into_bytes(); let approved_message = channel::new_approved_message( diff --git a/test/its.js b/test/its.js index 370b42f6..7af3d4b7 100644 --- a/test/its.js +++ b/test/its.js @@ -251,10 +251,7 @@ describe('ITS', () => { ['uint256', 'uint256', 'bytes', 'bytes', 'uint256', 'bytes'], [messageType, tokenId, sourceAddress, itsExampleChannelId, amount, data], ); - payload = defaultAbiCoder.encode( - ['uint256', 'string', 'bytes'], - [ITSMessageType.ReceiveFromItsHub, otherChain, payload], - ); + payload = defaultAbiCoder.encode(['uint256', 'string', 'bytes'], [ITSMessageType.ReceiveFromItsHub, otherChain, payload]); const message = { source_chain: trustedSourceChain, @@ -339,10 +336,7 @@ describe('ITS', () => { ['uint256', 'uint256', 'bytes', 'bytes', 'uint256', 'bytes'], [messageType, tokenId, byteName, byteSymbol, decimals, distributor], ); - payload = defaultAbiCoder.encode( - ['uint256', 'string', 'bytes'], - [ITSMessageType.ReceiveFromItsHub, otherChain, payload], - ) + payload = defaultAbiCoder.encode(['uint256', 'string', 'bytes'], [ITSMessageType.ReceiveFromItsHub, otherChain, payload]); const message = { source_chain: trustedSourceChain, diff --git a/test/squid.js b/test/squid.js index 868e9fd3..91afd1fd 100644 --- a/test/squid.js +++ b/test/squid.js @@ -452,10 +452,7 @@ describe('Squid', () => { ['uint256', 'uint256', 'bytes', 'bytes', 'uint256', 'bytes'], [messageType, tokenId, sourceAddress, squidChannelId, amount, data], ); - payload = defaultAbiCoder.encode( - ['uint256', 'string', 'bytes'], - [ITSMessageType.ReceiveFromItsHub, otherChain, payload], - ) + payload = defaultAbiCoder.encode(['uint256', 'string', 'bytes'], [ITSMessageType.ReceiveFromItsHub, otherChain, payload]); const message = { source_chain: trustedSourceChain, @@ -492,10 +489,7 @@ describe('Squid', () => { ['uint256', 'uint256', 'bytes', 'bytes', 'uint256', 'bytes'], [messageType, tokenId, sourceAddress, squidChannelId, amount, data], ); - payload = defaultAbiCoder.encode( - ['uint256', 'string', 'bytes'], - [ITSMessageType.ReceiveFromItsHub, otherChain, payload], - ); + payload = defaultAbiCoder.encode(['uint256', 'string', 'bytes'], [ITSMessageType.ReceiveFromItsHub, otherChain, payload]); const message = { source_chain: trustedSourceChain, From fcb0cc24d84859c7b024fc50f1ac8e1e0cd74fe6 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 21 Jan 2025 17:54:30 +0200 Subject: [PATCH 23/68] add a creator cap and setup to its --- .../sources/interchain_token_service.move | 49 +++++-- .../sources/types/creator_cap.move | 19 +++ .../interchain_token_service_v0.move | 126 ++++++++---------- test/its.js | 26 +++- test/squid.js | 27 +++- 5 files changed, 159 insertions(+), 88 deletions(-) create mode 100644 move/interchain_token_service/sources/types/creator_cap.move diff --git a/move/interchain_token_service/sources/interchain_token_service.move b/move/interchain_token_service/sources/interchain_token_service.move index efa73f95..a03a35ad 100644 --- a/move/interchain_token_service/sources/interchain_token_service.move +++ b/move/interchain_token_service/sources/interchain_token_service.move @@ -7,6 +7,7 @@ use interchain_token_service::coin_management::CoinManagement; use interchain_token_service::interchain_transfer_ticket::{Self, InterchainTransferTicket}; use interchain_token_service::interchain_token_service_v0::{Self, InterchainTokenService_v0}; use interchain_token_service::owner_cap::{Self, OwnerCap}; +use interchain_token_service::creator_cap::{Self, CreatorCap}; use interchain_token_service::operator_cap::{Self, OperatorCap}; use interchain_token_service::token_id::TokenId; use interchain_token_service::trusted_addresses::TrustedAddresses; @@ -37,10 +38,28 @@ public struct InterchainTokenService has key { // Setup // ----- fun init(ctx: &mut TxContext) { + transfer::public_transfer( + owner_cap::create(ctx), + ctx.sender(), + ); + + transfer::public_transfer( + operator_cap::create(ctx), + ctx.sender(), + ); + + transfer::public_transfer( + creator_cap::create(ctx), + ctx.sender(), + ); +} + +public fun setup(creator_cap: CreatorCap, chain_name: String, ctx: &mut TxContext) { let inner = versioned::create( DATA_VERSION, interchain_token_service_v0::new( version_control(), + chain_name, ctx, ), ctx, @@ -52,15 +71,7 @@ fun init(ctx: &mut TxContext) { inner, }); - transfer::public_transfer( - owner_cap::create(ctx), - ctx.sender(), - ); - - transfer::public_transfer( - operator_cap::create(ctx), - ctx.sender(), - ); + creator_cap.destroy(); } // ------ @@ -412,6 +423,7 @@ public fun create_for_testing(ctx: &mut TxContext): InterchainTokenService { let mut value = interchain_token_service_v0::new( version_control, + b"chain name".to_ascii_string(), ctx, ); value.set_trusted_address( @@ -976,8 +988,25 @@ fun test_init() { ts.next_tx(@0x0); let owner_cap = ts.take_from_sender(); - let its = ts.take_shared(); + let operator_cap = ts.take_from_sender(); + ts.return_to_sender(owner_cap); + ts.return_to_sender(operator_cap); + ts.end(); +} + +#[test] +fun test_setup() { + let mut ts = sui::test_scenario::begin(@0x0); + let creator_cap = creator_cap::create(ts.ctx()); + let chain_name = b"chain name".to_ascii_string(); + + setup(creator_cap, chain_name, ts.ctx()); + ts.next_tx(@0x0); + + let its = ts.take_shared(); + assert!(its.value!(b"send_interchain_transfer").chain_name() == chain_name); + sui::test_scenario::return_shared(its); ts.end(); } diff --git a/move/interchain_token_service/sources/types/creator_cap.move b/move/interchain_token_service/sources/types/creator_cap.move new file mode 100644 index 00000000..84e372bb --- /dev/null +++ b/move/interchain_token_service/sources/types/creator_cap.move @@ -0,0 +1,19 @@ +module interchain_token_service::creator_cap; + +// ----- +// Types +// ----- +public struct CreatorCap has key, store { + id: UID, +} + +public(package) fun create(ctx: &mut TxContext): CreatorCap { + CreatorCap { + id: object::new(ctx), + } +} + +public(package) fun destroy(self: CreatorCap) { + let CreatorCap { id } = self; + id.delete(); +} diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index 96581440..10fd84c9 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -29,14 +29,11 @@ use version_control::version_control::VersionControl; // Errors // ------ #[error] -const EUnregisteredCoin: vector = - b"trying to find a coin that doesn't exist"; +const EUnregisteredCoin: vector = b"trying to find a coin that doesn't exist"; #[error] -const EUntrustedAddress: vector = - b"the sender that sent this message is not trusted"; +const EUntrustedAddress: vector = b"the sender that sent this message is not trusted"; #[error] -const EInvalidMessageType: vector = - b"the message type received is not supported"; +const EInvalidMessageType: vector = b"the message type received is not supported"; #[error] const EWrongDestination: vector = b"the channel trying to receive this call is not the destination"; @@ -47,8 +44,7 @@ const EInterchainTransferHasData: vector = const EInterchainTransferHasNoData: vector = b"interchain transfer trying to be proccessed as an interchain transfer"; #[error] -const EModuleNameDoesNotMatchSymbol: vector = - b"the module name does not match the symbol"; +const EModuleNameDoesNotMatchSymbol: vector = b"the module name does not match the symbol"; #[error] const ENotDistributor: vector = b"only the distributor can mint"; #[error] @@ -90,6 +86,7 @@ public struct InterchainTokenService_v0 has store { registered_coin_types: Table, registered_coins: Bag, relayer_discovery_id: ID, + chain_name: String, version_control: VersionControl, } @@ -98,6 +95,7 @@ public struct InterchainTokenService_v0 has store { // ----------------- public(package) fun new( version_control: VersionControl, + chain_name: String, ctx: &mut TxContext, ): InterchainTokenService_v0 { InterchainTokenService_v0 { @@ -109,6 +107,7 @@ public(package) fun new( registered_coin_types: table::new(ctx), unregistered_coins: bag::new(ctx), unregistered_coin_types: table::new(ctx), + chain_name, relayer_discovery_id: object::id_from_address(@0x0), version_control, } @@ -258,9 +257,7 @@ public(package) fun send_interchain_transfer( ) = ticket.destroy(); assert!(version <= current_version, ENewerTicket); - let amount = self - .coin_management_mut(token_id) - .take_balance(balance, clock); + let amount = self.coin_management_mut(token_id).take_balance(balance, clock); let (_version, data) = its_utils::decode_metadata(metadata); let mut writer = abi::new_writer(6); @@ -294,10 +291,7 @@ public(package) fun receive_interchain_transfer( approved_message, ); let mut reader = abi::new_reader(payload); - assert!( - reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, - EInvalidMessageType, - ); + assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); let token_id = token_id::from_u256(reader.read_u256()); let source_address = reader.read_bytes(); @@ -307,9 +301,7 @@ public(package) fun receive_interchain_transfer( assert!(data.is_empty(), EInterchainTransferHasData); - let coin = self - .coin_management_mut(token_id) - .give_coin(amount, clock, ctx); + let coin = self.coin_management_mut(token_id).give_coin(amount, clock, ctx); transfer::public_transfer(coin, destination_address); @@ -335,10 +327,7 @@ public(package) fun receive_interchain_transfer_with_data( approved_message, ); let mut reader = abi::new_reader(payload); - assert!( - reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, - EInvalidMessageType, - ); + assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); let token_id = token_id::from_u256(reader.read_u256()); @@ -371,10 +360,7 @@ public(package) fun receive_deploy_interchain_token( ) { let (_, payload, _) = self.decode_approved_message(approved_message); let mut reader = abi::new_reader(payload); - assert!( - reader.read_u256() == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, - EInvalidMessageType, - ); + assert!(reader.read_u256() == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, EInvalidMessageType); let token_id = token_id::from_u256(reader.read_u256()); let name = string::utf8(reader.read_bytes()); @@ -404,10 +390,7 @@ public(package) fun give_unregistered_coin( mut coin_metadata: CoinMetadata, ) { assert!(treasury_cap.total_supply() == 0, ENonZeroTotalSupply); - assert!( - coin::get_icon_url(&coin_metadata).is_none(), - EUnregisteredCoinHasUrl, - ); + assert!(coin::get_icon_url(&coin_metadata).is_none(), EUnregisteredCoinHasUrl); treasury_cap.update_description(&mut coin_metadata, string::utf8(b"")); @@ -415,10 +398,7 @@ public(package) fun give_unregistered_coin( let symbol = coin_metadata.get_symbol(); let module_name = type_name::get_module(&type_name::get()); - assert!( - &module_name == &its_utils::module_from_symbol(&symbol), - EModuleNameDoesNotMatchSymbol, - ); + assert!(&module_name == &its_utils::module_from_symbol(&symbol), EModuleNameDoesNotMatchSymbol); let token_id = token_id::unregistered_token_id(&symbol, decimals); @@ -513,6 +493,10 @@ public(package) fun disallow_function( self.version_control.disallow_function(version, function_name); } +public(package) fun chain_name(self: &InterchainTokenService_v0): String { + self.chain_name +} + // ----------------- // Private Functions // ----------------- @@ -565,9 +549,7 @@ fun remove_unregistered_coin( self: &mut InterchainTokenService_v0, token_id: UnregisteredTokenId, ): (TreasuryCap, CoinMetadata) { - let unregistered_coins: UnregisteredCoinData = self - .unregistered_coins - .remove(token_id); + let unregistered_coins: UnregisteredCoinData = self.unregistered_coins.remove(token_id); let (treasury_cap, coin_metadata) = unregistered_coins.destroy(); remove_unregistered_coin_type(self, token_id); @@ -637,10 +619,7 @@ fun prepare_message( // Prevent sending directly to the InterchainTokenService Hub chain. This is not supported yet, // so fail early to prevent the user from having their funds stuck. - assert!( - destination_chain.into_bytes() != ITS_HUB_CHAIN_NAME, - EUntrustedChain, - ); + assert!(destination_chain.into_bytes() != ITS_HUB_CHAIN_NAME, EUntrustedChain); // Check whether the InterchainTokenService call should be routed via InterchainTokenService hub for this // destination chain @@ -671,17 +650,11 @@ fun decode_approved_message( .channel .consume_approved_message(approved_message); - assert!( - self.is_trusted_address(source_chain, source_address), - EUntrustedAddress, - ); + assert!(self.is_trusted_address(source_chain, source_address), EUntrustedAddress); let mut reader = abi::new_reader(payload); if (reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB) { - assert!( - source_chain.into_bytes() == ITS_HUB_CHAIN_NAME, - EUntrustedChain, - ); + assert!(source_chain.into_bytes() == ITS_HUB_CHAIN_NAME, EUntrustedChain); source_chain = ascii::string(reader.read_bytes()); payload = reader.read_bytes(); @@ -691,10 +664,7 @@ fun decode_approved_message( EUntrustedChain, ); } else { - assert!( - source_chain.into_bytes() != ITS_HUB_CHAIN_NAME, - EUntrustedChain, - ); + assert!(source_chain.into_bytes() != ITS_HUB_CHAIN_NAME, EUntrustedChain); }; (source_chain, payload, message_id) @@ -716,7 +686,11 @@ use interchain_token_service::coin::COIN; #[test_only] fun create_for_testing(ctx: &mut TxContext): InterchainTokenService_v0 { - let mut self = new(version_control::version_control::new(vector[]), ctx); + let mut self = new( + version_control::version_control::new(vector[]), + b"chain name".to_ascii_string(), + ctx, + ); self.set_trusted_address( std::ascii::string(b"Chain Name"), @@ -733,7 +707,10 @@ public fun create_unregistered_coin( decimals: u8, ctx: &mut TxContext, ) { - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -968,9 +945,7 @@ fun test_prepare_message_to_hub() { let message_ticket = self.prepare_message(destination_chain, payload); - assert!( - message_ticket.destination_chain() == ascii::string(ITS_HUB_CHAIN_NAME), - ); + assert!(message_ticket.destination_chain() == ascii::string(ITS_HUB_CHAIN_NAME)); assert!(message_ticket.destination_address() == hub_address); sui::test_utils::destroy(self); @@ -992,9 +967,7 @@ fun test_prepare_message_to_hub_direct() { let message_ticket = self.prepare_message(destination_chain, payload); - assert!( - message_ticket.destination_chain() == ascii::string(ITS_HUB_CHAIN_NAME), - ); + assert!(message_ticket.destination_chain() == ascii::string(ITS_HUB_CHAIN_NAME)); assert!(message_ticket.destination_address() == hub_address); sui::test_utils::destroy(self); @@ -1142,9 +1115,7 @@ fun test_receive_interchain_transfer_with_data_invalid_message_type() { payload, ); - let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data< - COIN, - >( + let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( approved_message, &channel, &clock, @@ -1201,9 +1172,7 @@ fun test_receive_interchain_transfer_with_data_wrong_destination() { payload, ); - let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data< - COIN, - >( + let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( approved_message, &channel, &clock, @@ -1260,9 +1229,7 @@ fun test_receive_interchain_transfer_with_data_no_data() { payload, ); - let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data< - COIN, - >( + let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( approved_message, &channel, &clock, @@ -1440,7 +1407,10 @@ fun test_give_unregistered_coin_module_name_missmatch() { let ctx = &mut tx_context::dummy(); let mut self = create_for_testing(ctx); - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -1459,7 +1429,10 @@ fun test_mint_as_distributor_not_distributor() { let symbol = b"COIN"; let decimals = 9; - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -1508,7 +1481,10 @@ fun test_mint_to_as_distributor_not_distributor() { let symbol = b"COIN"; let decimals = 9; - let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + let ( + treasury_cap, + coin_metadata, + ) = interchain_token_service::coin::create_treasury_and_metadata( symbol, decimals, ctx, @@ -1589,7 +1565,9 @@ fun test_send_interchain_transfer_newer_ticket() { let current_version = 0; let invalid_version = 1; - let interchain_transfer_ticket = interchain_token_service::interchain_transfer_ticket::new( + let interchain_transfer_ticket = interchain_token_service::interchain_transfer_ticket::new< + COIN, + >( token_id, coin.into_balance(), source_channel.to_address(), diff --git a/test/its.js b/test/its.js index 3073ac33..38e023b5 100644 --- a/test/its.js +++ b/test/its.js @@ -56,6 +56,7 @@ describe('ITS', () => { const nonce = 0; // Parameters for Trusted Addresses + const chainName = 'Chain Name'; const trustedSourceChain = 'Avalanche'; const trustedSourceAddress = hexlify(randomBytes(20)); @@ -89,6 +90,23 @@ describe('ITS', () => { discoveryInfo.discovery = objectIds.relayerDiscovery; } + async function setupIts() { + const itsSetupTxBuilder = new TxBuilder(client); + + await itsSetupTxBuilder.moveCall({ + target: `${deployments.interchain_token_service.packageId}::interchain_token_service::setup`, + arguments: [ + objectIds.itsCreatorCap, + chainName, + ], + }); + + const itsSetupReceipt = await itsSetupTxBuilder.signAndExecute(deployer); + + objectIds.its = findObjectId(itsSetupReceipt, 'interchain_token_service::InterchainTokenService'); + objectIds.itsV0 = findObjectId(itsSetupReceipt, 'interchain_token_service_v0::InterchainTokenService_v0'); + } + async function registerItsTransaction() { const registerTransactionBuilder = new TxBuilder(client); @@ -119,8 +137,6 @@ describe('ITS', () => { singleton: findObjectId(deployments.example.publishTxn, 'its::Singleton'), tokenTreasuryCap: findObjectId(deployments.example.publishTxn, `TreasuryCap<${coinType}>`), tokenCoinMetadata: findObjectId(deployments.example.publishTxn, `CoinMetadata<${coinType}>`), - its: findObjectId(deployments.interchain_token_service.publishTxn, 'interchain_token_service::InterchainTokenService'), - itsV0: findObjectId(deployments.interchain_token_service.publishTxn, 'interchain_token_service_v0::InterchainTokenService_v0'), relayerDiscovery: findObjectId( deployments.relayer_discovery.publishTxn, `${deployments.relayer_discovery.packageId}::discovery::RelayerDiscovery`, @@ -131,6 +147,10 @@ describe('ITS', () => { deployments.interchain_token_service.publishTxn, `${deployments.interchain_token_service.packageId}::owner_cap::OwnerCap`, ), + itsCreatorCap: findObjectId( + deployments.interchain_token_service.publishTxn, + `${deployments.interchain_token_service.packageId}::creator_cap::CreatorCap`, + ), }; // Mint some coins for tests const tokenTxBuilder = new TxBuilder(client); @@ -142,6 +162,8 @@ describe('ITS', () => { const mintReceipt = await tokenTxBuilder.signAndExecute(deployer); + await setupIts(); + // Find the object ids from the publish transactions objectIds = { ...objectIds, diff --git a/test/squid.js b/test/squid.js index bf7836ca..d7c4cf85 100644 --- a/test/squid.js +++ b/test/squid.js @@ -51,6 +51,7 @@ describe('Squid', () => { const nonce = 0; // Parameters for Trusted Addresses + const chainName = 'Chain Name'; const trustedSourceChain = 'Avalanche'; const trustedSourceAddress = hexlify(randomBytes(20)); const coins = {}; @@ -88,6 +89,23 @@ describe('Squid', () => { gatewayInfo.discovery = objectIds.relayerDiscovery; } + async function setupIts() { + const itsSetupTxBuilder = new TxBuilder(client); + + await itsSetupTxBuilder.moveCall({ + target: `${deployments.interchain_token_service.packageId}::interchain_token_service::setup`, + arguments: [ + objectIds.itsCreatorCap, + chainName, + ], + }); + + const itsSetupReceipt = await itsSetupTxBuilder.signAndExecute(deployer); + + objectIds.its = findObjectId(itsSetupReceipt, 'interchain_token_service::InterchainTokenService'); + objectIds.itsV0 = findObjectId(itsSetupReceipt, 'interchain_token_service_v0::InterchainTokenService_v0'); + } + // Registers the ITS in relayer discovery async function registerItsTransaction() { const registerTransactionBuilder = new TxBuilder(client); @@ -385,8 +403,6 @@ describe('Squid', () => { ...objectIds, squid: findObjectId(deployments.squid.publishTxn, 'squid::Squid'), squidV0: findObjectId(deployments.squid.publishTxn, 'squid_v0::Squid_v0'), - its: findObjectId(deployments.interchain_token_service.publishTxn, 'interchain_token_service::InterchainTokenService'), - itsV0: findObjectId(deployments.interchain_token_service.publishTxn, 'interchain_token_service_v0::InterchainTokenService_v0'), relayerDiscovery: findObjectId( deployments.relayer_discovery.publishTxn, `${deployments.relayer_discovery.packageId}::discovery::RelayerDiscovery`, @@ -397,11 +413,18 @@ describe('Squid', () => { deployments.interchain_token_service.publishTxn, `${deployments.interchain_token_service.packageId}::owner_cap::OwnerCap`, ), + itsCreatorCap: findObjectId( + deployments.interchain_token_service.publishTxn, + `${deployments.interchain_token_service.packageId}::creator_cap::CreatorCap`, + ), gateway: findObjectId( deployments.interchain_token_service.publishTxn, `${deployments.axelar_gateway.packageId}::gateway::Gateway`, ), }; + + await setupIts(); + // Find the object ids from the publish transactions objectIds = { ...objectIds, From 9f3c157a82f8fbd9e6e0bf6ca72489349e71ec32 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 21 Jan 2025 17:58:07 +0200 Subject: [PATCH 24/68] add chain name to token_id derivation --- move/interchain_token_service/sources/types/token_id.move | 4 ++++ .../sources/versioned/interchain_token_service_v0.move | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/move/interchain_token_service/sources/types/token_id.move b/move/interchain_token_service/sources/types/token_id.move index f2aba8a7..423b2e7b 100644 --- a/move/interchain_token_service/sources/types/token_id.move +++ b/move/interchain_token_service/sources/types/token_id.move @@ -34,6 +34,7 @@ public fun to_u256(token_id: &TokenId): u256 { } public fun from_info( + chain_name: &ascii::String, name: &String, symbol: &ascii::String, decimals: &u8, @@ -42,6 +43,7 @@ public fun from_info( ): TokenId { let mut vec = address::from_u256(PREFIX_SUI_TOKEN_ID).to_bytes(); vec.append(bcs::to_bytes(&type_name::get())); + vec.append(bcs::to_bytes(chain_name)); vec.append(bcs::to_bytes(name)); vec.append(bcs::to_bytes(symbol)); vec.append(bcs::to_bytes(decimals)); @@ -51,10 +53,12 @@ public fun from_info( } public(package) fun from_coin_data( + chain_name: &ascii::String, coin_info: &CoinInfo, coin_management: &CoinManagement, ): TokenId { from_info( + chain_name, &coin_info.name(), &coin_info.symbol(), &coin_info.decimals(), diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index 10fd84c9..79072ef3 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -201,7 +201,7 @@ public(package) fun register_coin( coin_info: CoinInfo, coin_management: CoinManagement, ): TokenId { - let token_id = token_id::from_coin_data(&coin_info, &coin_management); + let token_id = token_id::from_coin_data(self.chain_name(), &coin_info, &coin_management); self.add_registered_coin(token_id, coin_management, coin_info); @@ -493,8 +493,8 @@ public(package) fun disallow_function( self.version_control.disallow_function(version, function_name); } -public(package) fun chain_name(self: &InterchainTokenService_v0): String { - self.chain_name +public(package) fun chain_name(self: &InterchainTokenService_v0): &String { + &self.chain_name } // ----------------- From f335d896a8e677075b7cbe3ca1802823432b0501 Mon Sep 17 00:00:00 2001 From: Foivos Date: Wed, 22 Jan 2025 13:17:44 +0200 Subject: [PATCH 25/68] prettier and fix interfaces --- package.json | 1 + test/its.js | 5 +---- test/squid.js | 7 ++----- ...e_interchain_token_service_creator_cap.json | 18 ++++++++++++++++++ ...en_service_interchain_token_service_v0.json | 4 ++++ ...face_interchain_token_service_token_id.json | 1 + 6 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 test/testdata/interface_interchain_token_service_creator_cap.json diff --git a/package.json b/package.json index def60a32..7c71b48e 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "test-move": "./scripts/run.sh test", "test-js": "npx mocha", "test": "npm run test-move && npm run test-js", + "update-interfaces": "GOLDEN_TESTS=true npx mocha test/packages.js", "coverage": "./scripts/coverage.sh", "release": "npm run build && changeset publish", "release-snapshot": "npm run build && npm version 0.0.0-snapshot.$(git rev-parse --short HEAD) --git-tag-version=false && npm publish --no-git-checks --tag snapshot --access public", diff --git a/test/its.js b/test/its.js index 38e023b5..add291ff 100644 --- a/test/its.js +++ b/test/its.js @@ -95,10 +95,7 @@ describe('ITS', () => { await itsSetupTxBuilder.moveCall({ target: `${deployments.interchain_token_service.packageId}::interchain_token_service::setup`, - arguments: [ - objectIds.itsCreatorCap, - chainName, - ], + arguments: [objectIds.itsCreatorCap, chainName], }); const itsSetupReceipt = await itsSetupTxBuilder.signAndExecute(deployer); diff --git a/test/squid.js b/test/squid.js index d7c4cf85..7e454ba8 100644 --- a/test/squid.js +++ b/test/squid.js @@ -94,10 +94,7 @@ describe('Squid', () => { await itsSetupTxBuilder.moveCall({ target: `${deployments.interchain_token_service.packageId}::interchain_token_service::setup`, - arguments: [ - objectIds.itsCreatorCap, - chainName, - ], + arguments: [objectIds.itsCreatorCap, chainName], }); const itsSetupReceipt = await itsSetupTxBuilder.signAndExecute(deployer); @@ -424,7 +421,7 @@ describe('Squid', () => { }; await setupIts(); - + // Find the object ids from the publish transactions objectIds = { ...objectIds, diff --git a/test/testdata/interface_interchain_token_service_creator_cap.json b/test/testdata/interface_interchain_token_service_creator_cap.json new file mode 100644 index 00000000..52e2bed7 --- /dev/null +++ b/test/testdata/interface_interchain_token_service_creator_cap.json @@ -0,0 +1,18 @@ +{ + "structs": { + "CreatorCap": { + "name": "CreatorCap", + "abilities": [ + "store", + "key" + ], + "fields": [ + { + "name": "id", + "type": "UID" + } + ] + } + }, + "publicFunctions": {} +} diff --git a/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json b/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json index f850013e..11eadb98 100644 --- a/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json +++ b/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json @@ -34,6 +34,10 @@ "name": "relayer_discovery_id", "type": "ID" }, + { + "name": "chain_name", + "type": "String" + }, { "name": "version_control", "type": "VersionControl" diff --git a/test/testdata/interface_interchain_token_service_token_id.json b/test/testdata/interface_interchain_token_service_token_id.json index 4c92bbc9..0f988781 100644 --- a/test/testdata/interface_interchain_token_service_token_id.json +++ b/test/testdata/interface_interchain_token_service_token_id.json @@ -58,6 +58,7 @@ "name": "from_info", "visibility": "public", "params": { + "chain_name#0#0": "&String", "name#0#0": "&String", "symbol#0#0": "&String", "decimals#0#0": "&u8", From d1e8ddd9a647f380d605f1b1d1f8b1d9309833cc Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 23 Jan 2025 14:08:18 +0200 Subject: [PATCH 26/68] address a few comments --- move/interchain_token_service/sources/events.move | 12 ++++++------ .../sources/types/chain_tracker.move | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/move/interchain_token_service/sources/events.move b/move/interchain_token_service/sources/events.move index 9382d5b0..9317dccc 100644 --- a/move/interchain_token_service/sources/events.move +++ b/move/interchain_token_service/sources/events.move @@ -48,11 +48,11 @@ public struct UnregisteredCoinReceived has copy, drop { decimals: u8, } -public struct TrustedAddressAdded has copy, drop { +public struct TrustedChainAdded has copy, drop { chain_name: String, } -public struct TrustedAddressRemoved has copy, drop { +public struct TrustedChainRemoved has copy, drop { chain_name: String, } @@ -142,16 +142,16 @@ public(package) fun unregistered_coin_received( }); } -public(package) fun trusted_address_added( +public(package) fun trusted_chain_added( chain_name: String, ) { - event::emit(TrustedAddressAdded { + event::emit(TrustedChainAdded { chain_name, }); } -public(package) fun trusted_address_removed(chain_name: String) { - event::emit(TrustedAddressRemoved { +public(package) fun trusted_chain_removed(chain_name: String) { + event::emit(TrustedChainRemoved { chain_name, }); } diff --git a/move/interchain_token_service/sources/types/chain_tracker.move b/move/interchain_token_service/sources/types/chain_tracker.move index 767830f3..a2447e24 100644 --- a/move/interchain_token_service/sources/types/chain_tracker.move +++ b/move/interchain_token_service/sources/types/chain_tracker.move @@ -4,7 +4,7 @@ module interchain_token_service::chain_tracker; use interchain_token_service::events; use std::ascii::String; -use sui::table::{Self, Table}; +use sui::bag::{Self, Bag}; // ------ // Errors @@ -18,7 +18,7 @@ public struct TrustedChain has store, drop {} /// The interchain address tracker stores the trusted addresses for each chain. public struct InterchainChainTracker has store { - trusted_chains: Table, + trusted_chains: Bag, } // ----------------- @@ -32,7 +32,7 @@ public(package) fun is_trusted_chain(self: &InterchainChainTracker, chain_name: /// Create a new interchain address tracker. public(package) fun new(ctx: &mut TxContext): InterchainChainTracker { InterchainChainTracker { - trusted_chains: table::new(ctx), + trusted_chains: bag::new(ctx), } } @@ -45,13 +45,13 @@ public(package) fun add_trusted_chain(self: &mut InterchainChainTracker, chain_n } else { self.trusted_chains.add(chain_name, TrustedChain {}); }; - events::trusted_address_added(chain_name); + events::trusted_chain_added(chain_name); } public(package) fun remove_trusted_chain(self: &mut InterchainChainTracker, chain_name: String) { assert!(chain_name.length() > 0, EEmptyChainName); - self.trusted_chains.remove(chain_name); - events::trusted_address_removed(chain_name); + self.trusted_chains.remove(chain_name); + events::trusted_chain_removed(chain_name); } // ----- From 27150a8f3a28ea115c0cd55568fa7fc17cb58d0a Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 23 Jan 2025 14:09:16 +0200 Subject: [PATCH 27/68] rename chain_tracker to trusted_chains --- .../{chain_tracker.move => trusted_chains.move} | 2 +- .../versioned/interchain_token_service_v0.move | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) rename move/interchain_token_service/sources/types/{chain_tracker.move => trusted_chains.move} (98%) diff --git a/move/interchain_token_service/sources/types/chain_tracker.move b/move/interchain_token_service/sources/types/trusted_chains.move similarity index 98% rename from move/interchain_token_service/sources/types/chain_tracker.move rename to move/interchain_token_service/sources/types/trusted_chains.move index a2447e24..6d701550 100644 --- a/move/interchain_token_service/sources/types/chain_tracker.move +++ b/move/interchain_token_service/sources/types/trusted_chains.move @@ -1,6 +1,6 @@ /// Q: why addresses are stored as Strings? /// Q: why chains are Strings? -module interchain_token_service::chain_tracker; +module interchain_token_service::trusted_chains; use interchain_token_service::events; use std::ascii::String; diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index 167631b7..7f2f17f8 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -4,7 +4,7 @@ use abi::abi::{Self, AbiReader}; use axelar_gateway::channel::{Channel, ApprovedMessage}; use axelar_gateway::gateway; use axelar_gateway::message_ticket::MessageTicket; -use interchain_token_service::chain_tracker::{Self, InterchainChainTracker}; +use interchain_token_service::trusted_chains::{Self, InterchainChainTracker}; use interchain_token_service::coin_data::{Self, CoinData}; use interchain_token_service::coin_info::{Self, CoinInfo}; use interchain_token_service::coin_management::{Self, CoinManagement}; @@ -78,7 +78,7 @@ const ITS_HUB_ADDRESS: vector = b"hub_address"; // ----- public struct InterchainTokenService_v0 has store { channel: Channel, - chain_tracker: InterchainChainTracker, + trusted_chains: InterchainChainTracker, unregistered_coin_types: Table, unregistered_coins: Bag, registered_coin_types: Table, @@ -96,7 +96,7 @@ public(package) fun new( ): InterchainTokenService_v0 { InterchainTokenService_v0 { channel: axelar_gateway::channel::new(ctx), - chain_tracker: chain_tracker::new( + trusted_chains: trusted_chains::new( ctx, ), registered_coins: bag::new(ctx), @@ -143,11 +143,11 @@ public(package) fun relayer_discovery_id(self: &InterchainTokenService_v0): ID { } public(package) fun add_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) { - self.chain_tracker.add_trusted_chain(chain_name); + self.trusted_chains.add_trusted_chain(chain_name); } public(package) fun remove_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) { - self.chain_tracker.remove_trusted_chain(chain_name); + self.trusted_chains.remove_trusted_chain(chain_name); } public(package) fun add_trusted_chains( @@ -498,7 +498,7 @@ fun is_trusted_address(source_chain: String, source_address: String): bool { } fun is_trusted_chain(self: &InterchainTokenService_v0, source_chain: String): bool { - self.chain_tracker.is_trusted_chain(source_chain) + self.trusted_chains.is_trusted_chain(source_chain) } fun coin_management_mut( From a3aa2a730f093feadab5d84bc851d28c90d73976 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 23 Jan 2025 14:13:34 +0200 Subject: [PATCH 28/68] some more comments addressed --- .../sources/types/trusted_chains.move | 48 +++++++++---------- .../interchain_token_service_v0.move | 10 ++-- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/move/interchain_token_service/sources/types/trusted_chains.move b/move/interchain_token_service/sources/types/trusted_chains.move index 6d701550..cecbb7c1 100644 --- a/move/interchain_token_service/sources/types/trusted_chains.move +++ b/move/interchain_token_service/sources/types/trusted_chains.move @@ -17,27 +17,27 @@ const EAlreadyTrusted: vector = b"chain is already trusted"; public struct TrustedChain has store, drop {} /// The interchain address tracker stores the trusted addresses for each chain. -public struct InterchainChainTracker has store { +public struct TrustedChains has store { trusted_chains: Bag, } // ----------------- // Package Functions // ----------------- -/// Check if the given address is trusted for the given chain. -public(package) fun is_trusted_chain(self: &InterchainChainTracker, chain_name: String): bool { - self.trusted_chains.contains(chain_name) -} - /// Create a new interchain address tracker. -public(package) fun new(ctx: &mut TxContext): InterchainChainTracker { - InterchainChainTracker { +public(package) fun new(ctx: &mut TxContext): TrustedChains { + TrustedChains { trusted_chains: bag::new(ctx), } } +/// Check if the given address is trusted for the given chain. +public(package) fun is_trusted(self: &TrustedChains, chain_name: String): bool { + self.trusted_chains.contains(chain_name) +} + /// Set the trusted address for a chain or adds it if it doesn't exist. -public(package) fun add_trusted_chain(self: &mut InterchainChainTracker, chain_name: String) { +public(package) fun add(self: &mut TrustedChains, chain_name: String) { assert!(chain_name.length() > 0, EEmptyChainName); if (self.trusted_chains.contains(chain_name)) { @@ -48,7 +48,7 @@ public(package) fun add_trusted_chain(self: &mut InterchainChainTracker, chain_n events::trusted_chain_added(chain_name); } -public(package) fun remove_trusted_chain(self: &mut InterchainChainTracker, chain_name: String) { +public(package) fun remove(self: &mut TrustedChains, chain_name: String) { assert!(chain_name.length() > 0, EEmptyChainName); self.trusted_chains.remove(chain_name); events::trusted_chain_removed(chain_name); @@ -64,20 +64,20 @@ fun test_chain_tracker() { let chain1 = std::ascii::string(b"chain1"); let chain2 = std::ascii::string(b"chain2"); - self.add_trusted_chain(chain1); - self.add_trusted_chain(chain2); + self.add(chain1); + self.add(chain2); - assert!(self.is_trusted_chain(chain1) == true); - assert!(self.is_trusted_chain(chain2) == true); + assert!(self.is_trusted(chain1) == true); + assert!(self.is_trusted(chain2) == true); assert!(self.trusted_chains.contains(chain1)); assert!(self.trusted_chains.contains(chain2)); - self.remove_trusted_chain(chain1); - self.remove_trusted_chain(chain2); + self.remove(chain1); + self.remove(chain2); - assert!(self.is_trusted_chain(chain1) == false); - assert!(self.is_trusted_chain(chain2) == false); + assert!(self.is_trusted(chain1) == false); + assert!(self.is_trusted(chain2) == false); assert!(!self.trusted_chains.contains(chain1)); assert!(!self.trusted_chains.contains(chain2)); @@ -92,7 +92,7 @@ fun test_add_trusted_chain_empty_chain_name() { let mut self = new(ctx); let chain = std::ascii::string(b""); - self.add_trusted_chain(chain); + self.add(chain); sui::test_utils::destroy(self); } @@ -104,8 +104,8 @@ fun test_add_trusted_chain_already_trusted() { let mut self = new(ctx); let chain = std::ascii::string(b"chain"); - self.add_trusted_chain(chain); - self.add_trusted_chain(chain); + self.add(chain); + self.add(chain); sui::test_utils::destroy(self); } @@ -116,8 +116,8 @@ fun test_remove_trusted_chain() { let mut self = new(ctx); let chain = std::ascii::string(b"chain"); - self.add_trusted_chain(chain); - self.remove_trusted_chain(chain); + self.add(chain); + self.remove(chain); sui::test_utils::destroy(self); } @@ -129,7 +129,7 @@ fun test_remove_trusted_chain_empty_chain_name() { let mut self = new(ctx); let chain = std::ascii::string(b""); - self.remove_trusted_chain(chain); + self.remove(chain); sui::test_utils::destroy(self); } diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index 7f2f17f8..4db51c51 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -4,7 +4,7 @@ use abi::abi::{Self, AbiReader}; use axelar_gateway::channel::{Channel, ApprovedMessage}; use axelar_gateway::gateway; use axelar_gateway::message_ticket::MessageTicket; -use interchain_token_service::trusted_chains::{Self, InterchainChainTracker}; +use interchain_token_service::trusted_chains::{Self, TrustedChains}; use interchain_token_service::coin_data::{Self, CoinData}; use interchain_token_service::coin_info::{Self, CoinInfo}; use interchain_token_service::coin_management::{Self, CoinManagement}; @@ -78,7 +78,7 @@ const ITS_HUB_ADDRESS: vector = b"hub_address"; // ----- public struct InterchainTokenService_v0 has store { channel: Channel, - trusted_chains: InterchainChainTracker, + trusted_chains: TrustedChains, unregistered_coin_types: Table, unregistered_coins: Bag, registered_coin_types: Table, @@ -143,11 +143,11 @@ public(package) fun relayer_discovery_id(self: &InterchainTokenService_v0): ID { } public(package) fun add_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) { - self.trusted_chains.add_trusted_chain(chain_name); + self.trusted_chains.add(chain_name); } public(package) fun remove_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) { - self.trusted_chains.remove_trusted_chain(chain_name); + self.trusted_chains.remove(chain_name); } public(package) fun add_trusted_chains( @@ -498,7 +498,7 @@ fun is_trusted_address(source_chain: String, source_address: String): bool { } fun is_trusted_chain(self: &InterchainTokenService_v0, source_chain: String): bool { - self.trusted_chains.is_trusted_chain(source_chain) + self.trusted_chains.is_trusted(source_chain) } fun coin_management_mut( From b8d1e51b4ca16a808154bbc43bf9264fd98660b6 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 23 Jan 2025 14:14:14 +0200 Subject: [PATCH 29/68] Update move/squid/sources/squid/squid.move Co-authored-by: Milap Sheth --- move/squid/sources/squid/squid.move | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/move/squid/sources/squid/squid.move b/move/squid/sources/squid/squid.move index a7f5f1f5..be746f82 100644 --- a/move/squid/sources/squid/squid.move +++ b/move/squid/sources/squid/squid.move @@ -155,11 +155,12 @@ fun new_version_control(): VersionControl { /// Test Only /// --------- /// // === HUB CONSTANTS === +/// ITS Hub test chain name #[test_only] -// Axelar. const ITS_HUB_CHAIN_NAME: vector = b"axelar"; + +/// ITS hub test address #[test_only] -// The address of the ITS HUB. const ITS_HUB_ADDRESS: vector = b"hub_address"; #[test_only] From 5c5f1842189f88fa53dd075cd6b2f197081b4d72 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 23 Jan 2025 14:17:58 +0200 Subject: [PATCH 30/68] address some more comments --- .../sources/types/trusted_chains.move | 2 -- move/squid/sources/squid/versioned/squid_v0.move | 8 +++----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/move/interchain_token_service/sources/types/trusted_chains.move b/move/interchain_token_service/sources/types/trusted_chains.move index cecbb7c1..62ab057c 100644 --- a/move/interchain_token_service/sources/types/trusted_chains.move +++ b/move/interchain_token_service/sources/types/trusted_chains.move @@ -1,5 +1,3 @@ -/// Q: why addresses are stored as Strings? -/// Q: why chains are Strings? module interchain_token_service::trusted_chains; use interchain_token_service::events; diff --git a/move/squid/sources/squid/versioned/squid_v0.move b/move/squid/sources/squid/versioned/squid_v0.move index fb0e8c57..da5054a3 100644 --- a/move/squid/sources/squid/versioned/squid_v0.move +++ b/move/squid/sources/squid/versioned/squid_v0.move @@ -93,18 +93,16 @@ public(package) fun withdraw( let balance = self.coin_bag.exact_balance(amount); transfer::public_transfer(coin::from_balance(balance, ctx), ctx.sender()); } -// --------- -// Test Only -// --------- + /// --------- /// Test Only /// --------- /// // === HUB CONSTANTS === -#[test_only] // Axelar. -const ITS_HUB_CHAIN_NAME: vector = b"axelar"; #[test_only] +const ITS_HUB_CHAIN_NAME: vector = b"axelar"; // The address of the ITS HUB. +#[test_only] const ITS_HUB_ADDRESS: vector = b"hub_address"; #[test_only] From 1e47517d1f81740b2987e1a17bbd8682b9f8b0b1 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 23 Jan 2025 14:19:49 +0200 Subject: [PATCH 31/68] addressed a comments --- move/interchain_token_service/sources/types/token_id.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/interchain_token_service/sources/types/token_id.move b/move/interchain_token_service/sources/types/token_id.move index 423b2e7b..d37c8eec 100644 --- a/move/interchain_token_service/sources/types/token_id.move +++ b/move/interchain_token_service/sources/types/token_id.move @@ -42,8 +42,8 @@ public fun from_info( has_treasury: &bool, ): TokenId { let mut vec = address::from_u256(PREFIX_SUI_TOKEN_ID).to_bytes(); - vec.append(bcs::to_bytes(&type_name::get())); vec.append(bcs::to_bytes(chain_name)); + vec.append(bcs::to_bytes(&type_name::get())); vec.append(bcs::to_bytes(name)); vec.append(bcs::to_bytes(symbol)); vec.append(bcs::to_bytes(decimals)); From 1b76acc7e30406e4c8c5c14b4f7531d2eb1284bc Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 23 Jan 2025 15:07:41 +0200 Subject: [PATCH 32/68] fix tests --- .../sources/interchain_token_service.move | 1 - src/common/bcs.ts | 8 ++--- test/bcs.js | 2 +- test/its.js | 4 +-- test/squid.js | 2 +- ...rface_interchain_token_service_events.json | 8 ++--- ...n_service_interchain_token_service_v0.json | 4 +-- ...terchain_token_service_trusted_chains.json | 30 +++++++++++++++++++ 8 files changed, 44 insertions(+), 15 deletions(-) create mode 100644 test/testdata/interface_interchain_token_service_trusted_chains.json diff --git a/move/interchain_token_service/sources/interchain_token_service.move b/move/interchain_token_service/sources/interchain_token_service.move index 645deaa9..1a5d0176 100644 --- a/move/interchain_token_service/sources/interchain_token_service.move +++ b/move/interchain_token_service/sources/interchain_token_service.move @@ -9,7 +9,6 @@ use interchain_token_service::interchain_transfer_ticket::{Self, InterchainTrans use interchain_token_service::owner_cap::{Self, OwnerCap}; use interchain_token_service::creator_cap::{Self, CreatorCap}; use interchain_token_service::operator_cap::{Self, OperatorCap}; -use interchain_token_service::owner_cap::{Self, OwnerCap}; use interchain_token_service::token_id::TokenId; use relayer_discovery::discovery::RelayerDiscovery; use relayer_discovery::transaction::Transaction; diff --git a/src/common/bcs.ts b/src/common/bcs.ts index f72eb983..f2b332d0 100644 --- a/src/common/bcs.ts +++ b/src/common/bcs.ts @@ -266,13 +266,13 @@ function getITSStructs() { const { Table, Bag, Channel } = getCommonStructs(); const { VersionControl } = getVersionControlStructs(); - const InterchainChainTracker = bcs.struct('InterchainChainTracker', { - trusted_chains: Table, + const TrustedChains = bcs.struct('TrustedChains', { + trusted_chains: Bag, }); const InterchainTokenServiceV0 = bcs.struct('InterchainTokenService_v0', { channel: Channel, - chain_tracker: InterchainChainTracker, + trusted_chains: TrustedChains, unregistered_coin_types: Table, unregistered_coins: Bag, registered_coin_types: Table, @@ -288,7 +288,7 @@ function getITSStructs() { }); return { - InterchainChainTracker, + TrustedChains, InterchainTokenService, }; } diff --git a/test/bcs.js b/test/bcs.js index a1ab0edd..bc91144d 100644 --- a/test/bcs.js +++ b/test/bcs.js @@ -24,7 +24,7 @@ describe('BCS', () => { it('should decode InterchainTokenService_v0 object successfully', () => { const its = bcsStructs.its.InterchainTokenService.parse(fromHEX(hexData.InterchainTokenService_v0)).value; - checkIdAndSize(its.chain_tracker.trusted_chains, '270c7f8b9757b05777d3cbf98fa1bb197e1f5a18c8ff7a8ef16e80bedf39a67f'); + checkIdAndSize(its.trusted_chains.trusted_chains, '270c7f8b9757b05777d3cbf98fa1bb197e1f5a18c8ff7a8ef16e80bedf39a67f'); checkIdAndSize(its.unregistered_coin_types, '00c101dbc800d8cf853e6d21c916aba7c92e4c2692527dc951c777dae15cf474'); checkIdAndSize(its.unregistered_coins, '44bacbed87a2d5f871ce96f3245a293b936fb287605330b3859649f3a2697668'); checkIdAndSize(its.registered_coin_types, '13bd4dc87b61a82ce5959e3ea8c3fed1e03d9c1f7246eef82722354d8e3c0d54'); diff --git a/test/its.js b/test/its.js index 39a8fc84..687b7719 100644 --- a/test/its.js +++ b/test/its.js @@ -95,7 +95,7 @@ describe('ITS', () => { await itsSetupTxBuilder.moveCall({ target: `${deployments.interchain_token_service.packageId}::interchain_token_service::setup`, - arguments: [objectIds.itsCreatorCap, chainName], + arguments: [objectIds.itsCreatorCap, otherChain], }); const itsSetupReceipt = await itsSetupTxBuilder.signAndExecute(deployer); @@ -261,9 +261,9 @@ describe('ITS', () => { packageId: deployments.relayer_discovery.packageId, discovery: objectIds.relayerDiscovery, }; - // Channel ID for the ITS example. This will be encoded in the payload const itsExampleChannelId = await getSingletonChannelId(client, objectIds.singleton); + // ITS transfer payload from Ethereum to Sui let payload = defaultAbiCoder.encode( ['uint256', 'uint256', 'bytes', 'bytes', 'uint256', 'bytes'], diff --git a/test/squid.js b/test/squid.js index d67da671..fc69bf7f 100644 --- a/test/squid.js +++ b/test/squid.js @@ -94,7 +94,7 @@ describe('Squid', () => { await itsSetupTxBuilder.moveCall({ target: `${deployments.interchain_token_service.packageId}::interchain_token_service::setup`, - arguments: [objectIds.itsCreatorCap, chainName], + arguments: [objectIds.itsCreatorCap, otherChain], }); const itsSetupReceipt = await itsSetupTxBuilder.signAndExecute(deployer); diff --git a/test/testdata/interface_interchain_token_service_events.json b/test/testdata/interface_interchain_token_service_events.json index 4c35d122..463e233e 100644 --- a/test/testdata/interface_interchain_token_service_events.json +++ b/test/testdata/interface_interchain_token_service_events.json @@ -1,7 +1,7 @@ { "structs": { - "TrustedAddressAdded": { - "name": "TrustedAddressAdded", + "TrustedChainAdded": { + "name": "TrustedChainAdded", "abilities": [ "copy", "drop" @@ -13,8 +13,8 @@ } ] }, - "TrustedAddressRemoved": { - "name": "TrustedAddressRemoved", + "TrustedChainRemoved": { + "name": "TrustedChainRemoved", "abilities": [ "copy", "drop" diff --git a/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json b/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json index 227b04e2..6ce563cf 100644 --- a/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json +++ b/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json @@ -11,8 +11,8 @@ "type": "Channel" }, { - "name": "chain_tracker", - "type": "InterchainChainTracker" + "name": "trusted_chains", + "type": "TrustedChains" }, { "name": "unregistered_coin_types", diff --git a/test/testdata/interface_interchain_token_service_trusted_chains.json b/test/testdata/interface_interchain_token_service_trusted_chains.json new file mode 100644 index 00000000..baa9c83b --- /dev/null +++ b/test/testdata/interface_interchain_token_service_trusted_chains.json @@ -0,0 +1,30 @@ +{ + "structs": { + "TrustedChain": { + "name": "TrustedChain", + "abilities": [ + "drop", + "store" + ], + "fields": [ + { + "name": "dummy_field", + "type": "bool" + } + ] + }, + "TrustedChains": { + "name": "TrustedChains", + "abilities": [ + "store" + ], + "fields": [ + { + "name": "trusted_chains", + "type": "Bag" + } + ] + } + }, + "publicFunctions": {} +} From f65bd68f4acfbfb605b079b400d6a44fea329888 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 23 Jan 2025 16:28:25 +0200 Subject: [PATCH 33/68] add its_hub_address as a variable --- .../sources/interchain_token_service.move | 10 ++++++---- .../versioned/interchain_token_service_v0.move | 18 ++++++++++++------ test/its.js | 3 ++- test/squid.js | 4 +++- ...en_service_interchain_token_service_v0.json | 4 ++++ 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/move/interchain_token_service/sources/interchain_token_service.move b/move/interchain_token_service/sources/interchain_token_service.move index 1a5d0176..8b81325f 100644 --- a/move/interchain_token_service/sources/interchain_token_service.move +++ b/move/interchain_token_service/sources/interchain_token_service.move @@ -53,12 +53,13 @@ fun init(ctx: &mut TxContext) { ); } -public fun setup(creator_cap: CreatorCap, chain_name: String, ctx: &mut TxContext) { +entry fun setup(creator_cap: CreatorCap, chain_name: String, its_hub_address: String, ctx: &mut TxContext) { let inner = versioned::create( DATA_VERSION, interchain_token_service_v0::new( version_control(), chain_name, + its_hub_address, ctx, ), ctx, @@ -416,11 +417,11 @@ const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; // === HUB CONSTANTS === -#[test_only] // Axelar. -const ITS_HUB_CHAIN_NAME: vector = b"axelar"; #[test_only] +const ITS_HUB_CHAIN_NAME: vector = b"axelar"; // The address of the ITS HUB. +#[test_only] const ITS_HUB_ADDRESS: vector = b"hub_address"; #[test_only] @@ -431,6 +432,7 @@ public fun create_for_testing(ctx: &mut TxContext): InterchainTokenService { let mut value = interchain_token_service_v0::new( version_control, b"chain name".to_ascii_string(), + ITS_HUB_ADDRESS.to_ascii_string(), ctx, ); value.add_trusted_chain( @@ -1021,7 +1023,7 @@ fun test_setup() { let creator_cap = creator_cap::create(ts.ctx()); let chain_name = b"chain name".to_ascii_string(); - setup(creator_cap, chain_name, ts.ctx()); + setup(creator_cap, chain_name, ITS_HUB_ADDRESS.to_ascii_string(), ts.ctx()); ts.next_tx(@0x0); let its = ts.take_shared(); diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index 821d54c8..a76aca38 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -70,8 +70,6 @@ const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; // Chain name for Axelar. This is used for routing InterchainTokenService calls via InterchainTokenService hub on // Axelar. const ITS_HUB_CHAIN_NAME: vector = b"axelar"; -// The address of the ITS HUB. -const ITS_HUB_ADDRESS: vector = b"hub_address"; // ----- // Types @@ -85,6 +83,7 @@ public struct InterchainTokenService_v0 has store { registered_coins: Bag, relayer_discovery_id: ID, chain_name: String, + its_hub_address: String, version_control: VersionControl, } @@ -94,6 +93,7 @@ public struct InterchainTokenService_v0 has store { public(package) fun new( version_control: VersionControl, chain_name: String, + its_hub_address: String, ctx: &mut TxContext, ): InterchainTokenService_v0 { InterchainTokenService_v0 { @@ -106,6 +106,7 @@ public(package) fun new( unregistered_coins: bag::new(ctx), unregistered_coin_types: table::new(ctx), chain_name, + its_hub_address, relayer_discovery_id: object::id_from_address(@0x0), version_control, } @@ -500,8 +501,8 @@ fun coin_info(self: &InterchainTokenService_v0, token_id: TokenId): &CoinInfo coin_data(self, token_id).coin_info() } -fun is_trusted_address(source_chain: String, source_address: String): bool { - source_chain.into_bytes() == ITS_HUB_CHAIN_NAME && source_address.into_bytes() == ITS_HUB_ADDRESS +fun is_trusted_address(self: &InterchainTokenService_v0, source_chain: String, source_address: String): bool { + source_chain.into_bytes() == ITS_HUB_CHAIN_NAME && source_address == self.its_hub_address } fun is_trusted_chain(self: &InterchainTokenService_v0, source_chain: String): bool { @@ -615,7 +616,7 @@ fun prepare_message(self: &InterchainTokenService_v0, payload: vector): Mess gateway::prepare_message( &self.channel, ITS_HUB_CHAIN_NAME.to_ascii_string(), - ITS_HUB_ADDRESS.to_ascii_string(), + self.its_hub_address, payload, ) } @@ -629,7 +630,7 @@ fun decode_approved_message( .channel .consume_approved_message(approved_message); - assert!(is_trusted_address(source_chain, source_address), EUntrustedAddress); + assert!(self.is_trusted_address(source_chain, source_address), EUntrustedAddress); let mut reader = abi::new_reader(payload); assert!(reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, EInvalidMessageType); @@ -656,11 +657,16 @@ use axelar_gateway::channel; #[test_only] use interchain_token_service::coin::COIN; +// The address of the ITS HUB. +#[test_only] +const ITS_HUB_ADDRESS: vector = b"hub_address"; + #[test_only] fun create_for_testing(ctx: &mut TxContext): InterchainTokenService_v0 { let mut self = new( version_control::version_control::new(vector[]), b"chain name".to_ascii_string(), + ITS_HUB_ADDRESS.to_ascii_string(), ctx, ); diff --git a/test/its.js b/test/its.js index 687b7719..8ce1e5c6 100644 --- a/test/its.js +++ b/test/its.js @@ -59,6 +59,7 @@ describe('ITS', () => { const trustedSourceChain = 'axelar'; const trustedSourceAddress = 'hub_address'; const otherChain = 'Avalanche'; + const chainName = 'Chain Name'; async function setupGateway() { calculateNextSigners(gatewayInfo, nonce); @@ -95,7 +96,7 @@ describe('ITS', () => { await itsSetupTxBuilder.moveCall({ target: `${deployments.interchain_token_service.packageId}::interchain_token_service::setup`, - arguments: [objectIds.itsCreatorCap, otherChain], + arguments: [objectIds.itsCreatorCap, chainName, trustedSourceAddress], }); const itsSetupReceipt = await itsSetupTxBuilder.signAndExecute(deployer); diff --git a/test/squid.js b/test/squid.js index fc69bf7f..13af95b0 100644 --- a/test/squid.js +++ b/test/squid.js @@ -54,6 +54,8 @@ describe('Squid', () => { const trustedSourceChain = 'axelar'; const trustedSourceAddress = 'hub_address'; const otherChain = 'Avalanche'; + const chainName = 'Chain Name'; + const coins = {}; const pools = {}; @@ -94,7 +96,7 @@ describe('Squid', () => { await itsSetupTxBuilder.moveCall({ target: `${deployments.interchain_token_service.packageId}::interchain_token_service::setup`, - arguments: [objectIds.itsCreatorCap, otherChain], + arguments: [objectIds.itsCreatorCap, chainName, trustedSourceAddress], }); const itsSetupReceipt = await itsSetupTxBuilder.signAndExecute(deployer); diff --git a/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json b/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json index 6ce563cf..4591a75f 100644 --- a/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json +++ b/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json @@ -38,6 +38,10 @@ "name": "chain_name", "type": "String" }, + { + "name": "its_hub_address", + "type": "String" + }, { "name": "version_control", "type": "VersionControl" From e9f0c7266254011e890e761844ad0c8fcada4f07 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 23 Jan 2025 16:41:07 +0200 Subject: [PATCH 34/68] changed how wrap payload works --- .../sources/interchain_token_service.move | 8 +-- .../interchain_token_service_v0.move | 66 +++++++++++++------ test/its.js | 2 +- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/move/interchain_token_service/sources/interchain_token_service.move b/move/interchain_token_service/sources/interchain_token_service.move index 8b81325f..4eef5425 100644 --- a/move/interchain_token_service/sources/interchain_token_service.move +++ b/move/interchain_token_service/sources/interchain_token_service.move @@ -540,8 +540,8 @@ fun test_deploy_remote_interchain_token() { .write_bytes(*token_symbol.as_bytes()) .write_u256((token_decimals as u256)) .write_bytes(vector::empty()); - let mut payload = writer.into_bytes(); - its.value!(b"").wrap_payload_sending(&mut payload, destination_chain); + + let payload = its.value!(b"").wrap_payload_sending(writer.into_bytes(), destination_chain); assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); @@ -601,8 +601,8 @@ fun test_deploy_interchain_token() { .write_bytes(destination_address) .write_u256((amount as u256)) .write_bytes(b""); - let mut payload = writer.into_bytes(); - its.value!(b"").wrap_payload_sending(&mut payload, destination_chain); + + let payload = its.value!(b"").wrap_payload_sending(writer.into_bytes(), destination_chain); assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index a76aca38..ab578fbd 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -226,7 +226,7 @@ public(package) fun deploy_remote_interchain_token( ); let mut payload = writer.into_bytes(); - self.wrap_payload(&mut payload, destination_chain); + payload = self.wrap_payload(payload, destination_chain); prepare_message(self, payload) } @@ -269,7 +269,7 @@ public(package) fun send_interchain_transfer( ); let mut payload = writer.into_bytes(); - self.wrap_payload(&mut payload, destination_chain); + payload = self.wrap_payload(payload, destination_chain); prepare_message(self, payload) } @@ -501,10 +501,6 @@ fun coin_info(self: &InterchainTokenService_v0, token_id: TokenId): &CoinInfo coin_data(self, token_id).coin_info() } -fun is_trusted_address(self: &InterchainTokenService_v0, source_chain: String, source_address: String): bool { - source_chain.into_bytes() == ITS_HUB_CHAIN_NAME && source_address == self.its_hub_address -} - fun is_trusted_chain(self: &InterchainTokenService_v0, source_chain: String): bool { self.trusted_chains.is_trusted(source_chain) } @@ -598,16 +594,16 @@ fun add_registered_coin( fun wrap_payload( self: &InterchainTokenService_v0, - payload: &mut vector, + payload: vector, destination_chain: String, -) { +): vector { assert!(self.is_trusted_chain(destination_chain), EUntrustedChain); let mut writer = abi::new_writer(3); writer.write_u256(MESSAGE_TYPE_SEND_TO_HUB); writer.write_bytes(destination_chain.into_bytes()); - writer.write_bytes(*payload); - *payload = writer.into_bytes(); + writer.write_bytes(payload); + writer.into_bytes() } /// Send a payload to a destination chain. The destination chain needs to have a @@ -630,7 +626,8 @@ fun decode_approved_message( .channel .consume_approved_message(approved_message); - assert!(self.is_trusted_address(source_chain, source_address), EUntrustedAddress); + assert!(source_chain.into_bytes() == ITS_HUB_CHAIN_NAME, EUntrustedChain); + assert!(source_address == self.its_hub_address, EUntrustedAddress); let mut reader = abi::new_reader(payload); assert!(reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, EInvalidMessageType); @@ -737,19 +734,19 @@ public(package) fun remove_registered_coin_type_for_testing( #[test_only] public(package) fun wrap_payload_sending( self: &InterchainTokenService_v0, - payload: &mut vector, + payload: vector, destination_chain: String, -) { - self.wrap_payload(payload, destination_chain); +): vector { + self.wrap_payload(payload, destination_chain) } #[test_only] -public fun wrap_payload_receiving(payload: &mut vector, source_chain: String) { +public fun wrap_payload_receiving(payload: vector, source_chain: String): vector { let mut writer = abi::new_writer(3); writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); writer.write_bytes(source_chain.into_bytes()); - writer.write_bytes(*payload); - *payload = writer.into_bytes(); + writer.write_bytes(payload); + writer.into_bytes() } // ----- @@ -790,7 +787,7 @@ fun test_decode_approved_message_axelar_hub_sender() { } #[test] -#[expected_failure(abort_code = EUntrustedAddress)] +#[expected_failure(abort_code = EUntrustedChain)] fun test_decode_approved_message_sender_not_hub() { let ctx = &mut tx_context::dummy(); let self = create_for_testing(ctx); @@ -818,6 +815,35 @@ fun test_decode_approved_message_sender_not_hub() { sui::test_utils::destroy(self); } +#[test] +#[expected_failure(abort_code = EUntrustedAddress)] +fun test_decode_approved_message_sender_not_hub_address() { + let ctx = &mut tx_context::dummy(); + let self = create_for_testing(ctx); + + let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); + let source_address = ascii::string(b"Address"); + let message_id = ascii::string(b"message_id"); + + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + writer.write_bytes(b"Source Chain"); + writer.write_bytes(b"payload"); + let payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + source_chain, + message_id, + source_address, + self.channel.to_address(), + payload, + ); + + self.decode_approved_message(approved_message); + + sui::test_utils::destroy(self); +} + #[test] #[expected_failure(abort_code = EUntrustedChain)] fun test_decode_approved_message_origin_not_hub_routed() { @@ -912,7 +938,7 @@ fun test_prepare_message_to_hub() { self.add_trusted_chain(destination_chain); - self.wrap_payload(&mut payload, destination_chain); + payload = self.wrap_payload(payload, destination_chain); let message_ticket = self.prepare_message(payload); @@ -1580,7 +1606,7 @@ fun test_wrap_payload_untrusted_chain() { let mut payload = b"payload"; let destination_chain = b"destination_chain".to_ascii_string(); - its.wrap_payload(&mut payload, destination_chain); + payload = its.wrap_payload(payload, destination_chain); sui::test_utils::destroy(its); } diff --git a/test/its.js b/test/its.js index 8ce1e5c6..588898a7 100644 --- a/test/its.js +++ b/test/its.js @@ -264,7 +264,7 @@ describe('ITS', () => { }; // Channel ID for the ITS example. This will be encoded in the payload const itsExampleChannelId = await getSingletonChannelId(client, objectIds.singleton); - + // ITS transfer payload from Ethereum to Sui let payload = defaultAbiCoder.encode( ['uint256', 'uint256', 'bytes', 'bytes', 'uint256', 'bytes'], From 73ff042b74a39b871a41787aa4bd052737e8a15e Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 23 Jan 2025 16:51:16 +0200 Subject: [PATCH 35/68] changed pattern for wrapping payload a bit. --- .../sources/interchain_token_service.move | 4 +- .../interchain_token_service_v0.move | 38 +++++++++++-------- move/squid/sources/squid/squid.move | 2 +- .../sources/squid/versioned/squid_v0.move | 2 +- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/move/interchain_token_service/sources/interchain_token_service.move b/move/interchain_token_service/sources/interchain_token_service.move index 4eef5425..ef2ac199 100644 --- a/move/interchain_token_service/sources/interchain_token_service.move +++ b/move/interchain_token_service/sources/interchain_token_service.move @@ -541,7 +541,7 @@ fun test_deploy_remote_interchain_token() { .write_u256((token_decimals as u256)) .write_bytes(vector::empty()); - let payload = its.value!(b"").wrap_payload_sending(writer.into_bytes(), destination_chain); + let payload = interchain_token_service_v0::wrap_payload_sending(writer.into_bytes(), destination_chain); assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); @@ -602,7 +602,7 @@ fun test_deploy_interchain_token() { .write_u256((amount as u256)) .write_bytes(b""); - let payload = its.value!(b"").wrap_payload_sending(writer.into_bytes(), destination_chain); + let payload = interchain_token_service_v0::wrap_payload_sending(writer.into_bytes(), destination_chain); assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index ab578fbd..9bc67ae8 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -225,9 +225,9 @@ public(package) fun deploy_remote_interchain_token( destination_chain, ); - let mut payload = writer.into_bytes(); - payload = self.wrap_payload(payload, destination_chain); - prepare_message(self, payload) + let payload = writer.into_bytes(); + + self.prepare_wrapped_message(payload, destination_chain) } public(package) fun send_interchain_transfer( @@ -268,9 +268,9 @@ public(package) fun send_interchain_transfer( &data, ); - let mut payload = writer.into_bytes(); - payload = self.wrap_payload(payload, destination_chain); - prepare_message(self, payload) + let payload = writer.into_bytes(); + + self.prepare_wrapped_message(payload, destination_chain) } public(package) fun receive_interchain_transfer( @@ -592,18 +592,20 @@ fun add_registered_coin( ); } -fun wrap_payload( +fun prepare_wrapped_message( self: &InterchainTokenService_v0, - payload: vector, + mut payload: vector, destination_chain: String, -): vector { +): MessageTicket { assert!(self.is_trusted_chain(destination_chain), EUntrustedChain); let mut writer = abi::new_writer(3); writer.write_u256(MESSAGE_TYPE_SEND_TO_HUB); writer.write_bytes(destination_chain.into_bytes()); writer.write_bytes(payload); - writer.into_bytes() + payload = writer.into_bytes(); + + self.prepare_message(payload) } /// Send a payload to a destination chain. The destination chain needs to have a @@ -733,11 +735,14 @@ public(package) fun remove_registered_coin_type_for_testing( #[test_only] public(package) fun wrap_payload_sending( - self: &InterchainTokenService_v0, payload: vector, destination_chain: String, ): vector { - self.wrap_payload(payload, destination_chain) + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_SEND_TO_HUB); + writer.write_bytes(destination_chain.into_bytes()); + writer.write_bytes(payload); + writer.into_bytes() } #[test_only] @@ -938,7 +943,7 @@ fun test_prepare_message_to_hub() { self.add_trusted_chain(destination_chain); - payload = self.wrap_payload(payload, destination_chain); + payload = wrap_payload_sending(payload, destination_chain); let message_ticket = self.prepare_message(payload); @@ -1600,13 +1605,14 @@ fun test_send_interchain_transfer_newer_ticket() { #[test] #[expected_failure(abort_code = EUntrustedChain)] -fun test_wrap_payload_untrusted_chain() { +fun test_prepare_wrapped_message_untrusted_chain() { let ctx = &mut tx_context::dummy(); let its = create_for_testing(ctx); - let mut payload = b"payload"; + let payload = b"payload"; let destination_chain = b"destination_chain".to_ascii_string(); - payload = its.wrap_payload(payload, destination_chain); + let message_ticket = its.prepare_wrapped_message(payload, destination_chain); sui::test_utils::destroy(its); + sui::test_utils::destroy(message_ticket); } diff --git a/move/squid/sources/squid/squid.move b/move/squid/sources/squid/squid.move index be746f82..eede528a 100644 --- a/move/squid/sources/squid/squid.move +++ b/move/squid/sources/squid/squid.move @@ -239,7 +239,7 @@ fun test_start_swap() { .write_bytes(data); let mut payload = writer.into_bytes(); - interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(&mut payload, source_chain); + payload = interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(payload, source_chain); let approved_message = axelar_gateway::channel::new_approved_message( ITS_HUB_CHAIN_NAME.to_ascii_string(), diff --git a/move/squid/sources/squid/versioned/squid_v0.move b/move/squid/sources/squid/versioned/squid_v0.move index da5054a3..f8cb242f 100644 --- a/move/squid/sources/squid/versioned/squid_v0.move +++ b/move/squid/sources/squid/versioned/squid_v0.move @@ -171,7 +171,7 @@ fun test_start_swap() { .write_u256((amount as u256)) .write_bytes(data); let mut payload = writer.into_bytes(); - interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(&mut payload, source_chain); + payload = interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(payload, source_chain); let approved_message = channel::new_approved_message( ITS_HUB_CHAIN_NAME.to_ascii_string(), From c5b8d3705eb4d330b1249e54e236f8918ed0bba7 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 27 Jan 2025 13:58:06 +0200 Subject: [PATCH 36/68] Update move/interchain_token_service/sources/types/trusted_chains.move Co-authored-by: Milap Sheth --- move/interchain_token_service/sources/types/trusted_chains.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/interchain_token_service/sources/types/trusted_chains.move b/move/interchain_token_service/sources/types/trusted_chains.move index 62ab057c..3f31dc4f 100644 --- a/move/interchain_token_service/sources/types/trusted_chains.move +++ b/move/interchain_token_service/sources/types/trusted_chains.move @@ -14,7 +14,7 @@ const EAlreadyTrusted: vector = b"chain is already trusted"; public struct TrustedChain has store, drop {} -/// The interchain address tracker stores the trusted addresses for each chain. +/// The trusted chains where messages can be sent or received from. public struct TrustedChains has store { trusted_chains: Bag, } From 82d091c7a96a0053e9be79ed4c0ab22d8d9e6638 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 27 Jan 2025 14:45:54 +0200 Subject: [PATCH 37/68] Update move/interchain_token_service/sources/types/trusted_chains.move Co-authored-by: Milap Sheth --- .../sources/types/trusted_chains.move | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/move/interchain_token_service/sources/types/trusted_chains.move b/move/interchain_token_service/sources/types/trusted_chains.move index 3f31dc4f..24b76f06 100644 --- a/move/interchain_token_service/sources/types/trusted_chains.move +++ b/move/interchain_token_service/sources/types/trusted_chains.move @@ -37,12 +37,9 @@ public(package) fun is_trusted(self: &TrustedChains, chain_name: String): bool { /// Set the trusted address for a chain or adds it if it doesn't exist. public(package) fun add(self: &mut TrustedChains, chain_name: String) { assert!(chain_name.length() > 0, EEmptyChainName); + assert!(!self.trusted_chains.contains(chain_name), EAlreadyTrusted); - if (self.trusted_chains.contains(chain_name)) { - abort EAlreadyTrusted - } else { - self.trusted_chains.add(chain_name, TrustedChain {}); - }; + self.trusted_chains.add(chain_name, TrustedChain {}); events::trusted_chain_added(chain_name); } From 98e1163d6a3b611cf8907e75b0e9c6b11d4488c7 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 27 Jan 2025 14:46:34 +0200 Subject: [PATCH 38/68] Update move/interchain_token_service/sources/types/trusted_chains.move Co-authored-by: Milap Sheth --- move/interchain_token_service/sources/types/trusted_chains.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/interchain_token_service/sources/types/trusted_chains.move b/move/interchain_token_service/sources/types/trusted_chains.move index 24b76f06..ded83b8d 100644 --- a/move/interchain_token_service/sources/types/trusted_chains.move +++ b/move/interchain_token_service/sources/types/trusted_chains.move @@ -53,7 +53,7 @@ public(package) fun remove(self: &mut TrustedChains, chain_name: String) { // Tests // ----- #[test] -fun test_chain_tracker() { +fun test_trusted_chains() { let ctx = &mut sui::tx_context::dummy(); let mut self = new(ctx); let chain1 = std::ascii::string(b"chain1"); From 9b987a40a56cab822dce3c6aa74e3fa91c3c6cc5 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 27 Jan 2025 14:47:16 +0200 Subject: [PATCH 39/68] rename `prepare_wrapped_message` to `prepare_hub_message` --- .../sources/versioned/interchain_token_service_v0.move | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index 9bc67ae8..671cfd30 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -227,7 +227,7 @@ public(package) fun deploy_remote_interchain_token( let payload = writer.into_bytes(); - self.prepare_wrapped_message(payload, destination_chain) + self.prepare_hub_message(payload, destination_chain) } public(package) fun send_interchain_transfer( @@ -270,7 +270,7 @@ public(package) fun send_interchain_transfer( let payload = writer.into_bytes(); - self.prepare_wrapped_message(payload, destination_chain) + self.prepare_hub_message(payload, destination_chain) } public(package) fun receive_interchain_transfer( @@ -592,7 +592,7 @@ fun add_registered_coin( ); } -fun prepare_wrapped_message( +fun prepare_hub_message( self: &InterchainTokenService_v0, mut payload: vector, destination_chain: String, @@ -1605,13 +1605,13 @@ fun test_send_interchain_transfer_newer_ticket() { #[test] #[expected_failure(abort_code = EUntrustedChain)] -fun test_prepare_wrapped_message_untrusted_chain() { +fun test_prepare_hub_message_untrusted_chain() { let ctx = &mut tx_context::dummy(); let its = create_for_testing(ctx); let payload = b"payload"; let destination_chain = b"destination_chain".to_ascii_string(); - let message_ticket = its.prepare_wrapped_message(payload, destination_chain); + let message_ticket = its.prepare_hub_message(payload, destination_chain); sui::test_utils::destroy(its); sui::test_utils::destroy(message_ticket); From bff94bd8be73ed1f303245a7b2329096a86b7661 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 27 Jan 2025 14:47:59 +0200 Subject: [PATCH 40/68] cs --- .changeset/chilled-apes-lay.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/chilled-apes-lay.md diff --git a/.changeset/chilled-apes-lay.md b/.changeset/chilled-apes-lay.md new file mode 100644 index 00000000..f13c33d4 --- /dev/null +++ b/.changeset/chilled-apes-lay.md @@ -0,0 +1,5 @@ +--- +'@axelar-network/axelar-cgp-sui': minor +--- + +Change ITS from tracking addresses of remote chains to only tracking trusted chains and always using the ITS HUB. From 2db608afb4ce8aa917235d4ae4b5a1514dccf5cd Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 27 Jan 2025 14:49:32 +0200 Subject: [PATCH 41/68] added explicit check that chain is contained when trying to remove it. --- .../sources/types/trusted_chains.move | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/move/interchain_token_service/sources/types/trusted_chains.move b/move/interchain_token_service/sources/types/trusted_chains.move index ded83b8d..f9de7bf1 100644 --- a/move/interchain_token_service/sources/types/trusted_chains.move +++ b/move/interchain_token_service/sources/types/trusted_chains.move @@ -11,6 +11,8 @@ use sui::bag::{Self, Bag}; const EEmptyChainName: vector = b"empty trusted chain name is unsupported"; #[error] const EAlreadyTrusted: vector = b"chain is already trusted"; +#[error] +const ENotTrusted: vector = b"chain is not trusted"; public struct TrustedChain has store, drop {} @@ -45,6 +47,8 @@ public(package) fun add(self: &mut TrustedChains, chain_name: String) { public(package) fun remove(self: &mut TrustedChains, chain_name: String) { assert!(chain_name.length() > 0, EEmptyChainName); + assert!(self.trusted_chains.contains(chain_name), ENotTrusted); + self.trusted_chains.remove(chain_name); events::trusted_chain_removed(chain_name); } From 7c2cadb87b076e5a93e5cac7c28ce9ef8221eb37 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 27 Jan 2025 15:06:35 +0200 Subject: [PATCH 42/68] fix tests --- .../sources/versioned/interchain_token_service_v0.move | 4 ---- ...nterchain_token_service_interchain_token_service_v0.json | 6 +++--- .../interface_interchain_token_service_token_id.json | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index 53e3675b..b6ab99df 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -487,10 +487,6 @@ public(package) fun disallow_function( self.version_control.disallow_function(version, function_name); } -public(package) fun chain_name(self: &InterchainTokenService_v0): &String { - &self.chain_name -} - // ----------------- // Private Functions // ----------------- diff --git a/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json b/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json index 4591a75f..1b15e26f 100644 --- a/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json +++ b/test/testdata/interface_interchain_token_service_interchain_token_service_v0.json @@ -35,12 +35,12 @@ "type": "ID" }, { - "name": "chain_name", + "name": "its_hub_address", "type": "String" }, { - "name": "its_hub_address", - "type": "String" + "name": "chain_name_hash", + "type": "Bytes32" }, { "name": "version_control", diff --git a/test/testdata/interface_interchain_token_service_token_id.json b/test/testdata/interface_interchain_token_service_token_id.json index 0f988781..d701c09b 100644 --- a/test/testdata/interface_interchain_token_service_token_id.json +++ b/test/testdata/interface_interchain_token_service_token_id.json @@ -58,7 +58,7 @@ "name": "from_info", "visibility": "public", "params": { - "chain_name#0#0": "&String", + "chain_name_hash#0#0": "&Bytes32", "name#0#0": "&String", "symbol#0#0": "&String", "decimals#0#0": "&u8", From 02915b708b84fa569a167c5572449c5928669075 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 27 Jan 2025 18:16:29 +0200 Subject: [PATCH 43/68] update bcs --- src/common/bcs.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/bcs.ts b/src/common/bcs.ts index f2b332d0..20ad3ba6 100644 --- a/src/common/bcs.ts +++ b/src/common/bcs.ts @@ -278,6 +278,8 @@ function getITSStructs() { registered_coin_types: Table, registered_coins: Bag, relayer_discovery_id: bcs.Address, + its_hub_address: bcs.String, + chain_name_hash: bcs.Address, version_control: VersionControl, }); From d780bc909f0d6c8a754c7b2400bc4a4048b57496 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 27 Jan 2025 18:32:08 +0200 Subject: [PATCH 44/68] update bcs test for InterchainTokenServiceV0 --- test/bcs.js | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/test/bcs.js b/test/bcs.js index bc91144d..8574906c 100644 --- a/test/bcs.js +++ b/test/bcs.js @@ -7,7 +7,7 @@ const { expect } = require('chai'); // The following hex data is derived from the bcs bytes from the client.getObject() call. const hexData = { InterchainTokenService_v0: - '7d262a840033c9b6bc7a31d8ddf12bff891c6db6253dd5b8cf331bccd531a81e00000000000000006ccb9729af3569630b9171a0c1fd3eae9797d8122794be5d8cd01061b1dfcb86270c7f8b9757b05777d3cbf98fa1bb197e1f5a18c8ff7a8ef16e80bedf39a67f000000000000000000c101dbc800d8cf853e6d21c916aba7c92e4c2692527dc951c777dae15cf474000000000000000044bacbed87a2d5f871ce96f3245a293b936fb287605330b3859649f3a2697668000000000000000013bd4dc87b61a82ce5959e3ea8c3fed1e03d9c1f7246eef82722354d8e3c0d540000000000000000e5855b758d21f521071672cbce153167d49b4d15f11f5ca47528117312c2c1fa00000000000000000000000000000000000000000000000000000000000000000000000000000000010c0d72656769737465725f636f696e1e6465706c6f795f72656d6f74655f696e746572636861696e5f746f6b656e1873656e645f696e746572636861696e5f7472616e736665721b726563656976655f696e746572636861696e5f7472616e7366657225726563656976655f696e746572636861696e5f7472616e736665725f776974685f646174611f726563656976655f6465706c6f795f696e746572636861696e5f746f6b656e16676976655f756e726567697374657265645f636f696e136d696e745f61735f6469737472696275746f72166d696e745f746f5f61735f6469737472696275746f72136275726e5f61735f6469737472696275746f72157365745f747275737465645f6164647265737365731472656769737465725f7472616e73616374696f6e', + 'e167e3f1723e7de7721044908e98167df62b34eec21b225dc4de00733272687f00000000000000007ea12d713858af8412a345c4d17542de4e766a3fdb3f09e06797b18d4051f86dd3268ec782d5973178e2225a3dc2f513244471cdf03213dd343947b709ff41d30000000000000000b9283015c28a199919df7e2665238835c182013b30a4233d6e036cea0d9d373500000000000000008ab0c93b5ca5585b9f3d78f2dafd1e0b43385e5b2a854818a106d338937f178d000000000000000022917e135a1a40a6b43b7776d83513ac797b94496177c9347520ef5431dd12ce0000000000000000bc655c886b535ff1437f28f2717ae3fabdc8a2f040aceebf3dd14a011e744df1000000000000000000000000000000000000000000000000000000000000000000000000000000000b6875625f6164647265737362dcd9931dfd4b454526d130f627854784d12bc67b48810bbe659af1adfd3f5b01110d72656769737465725f636f696e1e6465706c6f795f72656d6f74655f696e746572636861696e5f746f6b656e1873656e645f696e746572636861696e5f7472616e736665721b726563656976655f696e746572636861696e5f7472616e7366657225726563656976655f696e746572636861696e5f7472616e736665725f776974685f646174611f726563656976655f6465706c6f795f696e746572636861696e5f746f6b656e16676976655f756e726567697374657265645f636f696e136d696e745f61735f6469737472696275746f72166d696e745f746f5f61735f6469737472696275746f72136275726e5f61735f6469737472696275746f72126164645f747275737465645f636861696e731572656d6f76655f747275737465645f636861696e731472656769737465725f7472616e73616374696f6e0e7365745f666c6f775f6c696d6974207365745f666c6f775f6c696d69745f61735f746f6b656e5f6f70657261746f720e616c6c6f775f66756e6374696f6e11646973616c6c6f775f66756e6374696f6e', GatewayV0: 'c15879de64dc6678674e5ad1a32c47319a1e9100bf21408173590455d01f9d160000000000000000196e295da7fe769ff56d2627c38252ee603f90829ea777bce36ce676b5e3d9d5a7f4b2d4c193987e5f01122bc9cce22a791447d10bc58299ced9e4e18db4c2c503000000000000000100000000000000537d294cfaa7dc649e43cab6a2d829674ea9c11c86517fec9e3984cdedaee42501000000000000000e59feaeb543924fabfbeb667efe707290cf4de9e667796b132260f33a84c26ee803000000000000b23c626b920100000f00000000000000010610617070726f76655f6d657373616765730e726f746174655f7369676e6572731369735f6d6573736167655f617070726f7665641369735f6d6573736167655f65786563757465641574616b655f617070726f7665645f6d6573736167650c73656e645f6d657373616765', GasServiceV0: @@ -16,35 +16,46 @@ const hexData = { '5dcab278dc93438e0705fc32023808927e09a29b1ae52eef6cb33b9250d9b87100000000000000005339d11ffc9ae10e448b36b776533e1f08c646ad0441c7a0d410b1e0e5d28e58010000000000000001031472656769737465725f7472616e73616374696f6e1272656d6f76655f7472616e73616374696f6e0f6765745f7472616e73616374696f6e', }; -describe('BCS', () => { +describe.only('BCS', () => { const checkIdAndSize = (obj, expectedId, size = '0') => { expect(obj).to.deep.include({ id: expectedId, size }); }; it('should decode InterchainTokenService_v0 object successfully', () => { const its = bcsStructs.its.InterchainTokenService.parse(fromHEX(hexData.InterchainTokenService_v0)).value; + console.log(its.version_control.allowed_functions); + checkIdAndSize(its.trusted_chains.trusted_chains, 'd3268ec782d5973178e2225a3dc2f513244471cdf03213dd343947b709ff41d3'); + checkIdAndSize(its.unregistered_coin_types, 'b9283015c28a199919df7e2665238835c182013b30a4233d6e036cea0d9d3735'); + checkIdAndSize(its.unregistered_coins, '8ab0c93b5ca5585b9f3d78f2dafd1e0b43385e5b2a854818a106d338937f178d'); + checkIdAndSize(its.registered_coin_types, '22917e135a1a40a6b43b7776d83513ac797b94496177c9347520ef5431dd12ce'); + checkIdAndSize(its.registered_coins, 'bc655c886b535ff1437f28f2717ae3fabdc8a2f040aceebf3dd14a011e744df1'); - checkIdAndSize(its.trusted_chains.trusted_chains, '270c7f8b9757b05777d3cbf98fa1bb197e1f5a18c8ff7a8ef16e80bedf39a67f'); - checkIdAndSize(its.unregistered_coin_types, '00c101dbc800d8cf853e6d21c916aba7c92e4c2692527dc951c777dae15cf474'); - checkIdAndSize(its.unregistered_coins, '44bacbed87a2d5f871ce96f3245a293b936fb287605330b3859649f3a2697668'); - checkIdAndSize(its.registered_coin_types, '13bd4dc87b61a82ce5959e3ea8c3fed1e03d9c1f7246eef82722354d8e3c0d54'); - checkIdAndSize(its.registered_coins, 'e5855b758d21f521071672cbce153167d49b4d15f11f5ca47528117312c2c1fa'); - - expect(its.channel.id).to.equal('6ccb9729af3569630b9171a0c1fd3eae9797d8122794be5d8cd01061b1dfcb86'); - expect(its.relayer_discovery_id).to.equal('0x0000000000000000000000000000000000000000000000000000000000000000'); + expect(its.channel.id).to.equal('7ea12d713858af8412a345c4d17542de4e766a3fdb3f09e06797b18d4051f86d'); + expect(its.its_hub_address).to.equal('hub_address'); + expect(its.chain_name_hash).to.equal('0x62dcd9931dfd4b454526d130f627854784d12bc67b48810bbe659af1adfd3f5b'); const allowedFunctions = its.version_control.allowed_functions[0].contents; expect(allowedFunctions) .to.be.an('array') - .that.includes( - 'register_coin', + .that.includes( 'register_coin', 'deploy_remote_interchain_token', 'send_interchain_transfer', 'receive_interchain_transfer', 'receive_interchain_transfer_with_data', 'receive_deploy_interchain_token', + 'give_unregistered_coin', + 'mint_as_distributor', + 'mint_to_as_distributor', + 'burn_as_distributor', + 'add_trusted_chains', + 'remove_trusted_chains', + 'register_transaction', + 'set_flow_limit', + 'set_flow_limit_as_token_operator', + 'allow_function', + 'disallow_function', ); - expect(allowedFunctions).to.have.lengthOf(12); + expect(allowedFunctions).to.have.lengthOf(17); }); it('should decode Gateway_v0 object successfully', () => { From 4172de71f106938615381eebe259f17e2b8ba6a0 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 28 Jan 2025 14:13:12 +0200 Subject: [PATCH 45/68] made lint happy --- test/bcs.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/bcs.js b/test/bcs.js index 8574906c..c5f9ad9b 100644 --- a/test/bcs.js +++ b/test/bcs.js @@ -16,7 +16,7 @@ const hexData = { '5dcab278dc93438e0705fc32023808927e09a29b1ae52eef6cb33b9250d9b87100000000000000005339d11ffc9ae10e448b36b776533e1f08c646ad0441c7a0d410b1e0e5d28e58010000000000000001031472656769737465725f7472616e73616374696f6e1272656d6f76655f7472616e73616374696f6e0f6765745f7472616e73616374696f6e', }; -describe.only('BCS', () => { +describe('BCS', () => { const checkIdAndSize = (obj, expectedId, size = '0') => { expect(obj).to.deep.include({ id: expectedId, size }); }; @@ -37,7 +37,8 @@ describe.only('BCS', () => { const allowedFunctions = its.version_control.allowed_functions[0].contents; expect(allowedFunctions) .to.be.an('array') - .that.includes( 'register_coin', + .that.includes( + 'register_coin', 'deploy_remote_interchain_token', 'send_interchain_transfer', 'receive_interchain_transfer', From 1b918469491f44e38f521a8ea5a4e166c771df1b Mon Sep 17 00:00:00 2001 From: Foivos Date: Wed, 29 Jan 2025 14:12:15 +0200 Subject: [PATCH 46/68] using prettier-move as part of prettier now. --- move/abi/sources/abi.move | 535 +++-- move/axelar_gateway/sources/auth.move | 486 ++-- move/axelar_gateway/sources/channel.move | 530 +++-- move/axelar_gateway/sources/events.move | 166 +- move/axelar_gateway/sources/gateway.move | 1962 ++++++++--------- .../axelar_gateway/sources/types/bytes32.move | 157 +- .../axelar_gateway/sources/types/message.move | 154 +- .../sources/types/message_status.move | 44 +- .../sources/types/message_ticket.move | 234 +- .../sources/types/owner_cap.move | 38 +- move/axelar_gateway/sources/types/proof.move | 604 +++-- .../sources/types/weighted_signer.move | 259 ++- .../sources/types/weighted_signers.move | 359 ++- .../sources/versioned/gateway_v0.move | 938 ++++---- move/example/sources/gmp/gmp.move | 158 +- move/example/sources/its/its.move | 507 ++--- move/example/sources/its/token.move | 55 +- move/example/sources/squid/token_a.move | 44 +- move/example/sources/squid/token_b.move | 44 +- move/example/sources/squid/token_c.move | 44 +- move/example/sources/utils.move | 18 +- move/gas_service/sources/events.move | 151 +- move/gas_service/sources/gas_service.move | 752 +++---- .../sources/versioned/gas_service_v0.move | 277 ++- .../sources/governance/governance.move | 948 ++++---- .../sources/interchain_token.move | 33 +- .../sources/discovery.move | 903 ++++---- .../sources/events.move | 451 ++-- .../sources/interchain_token_service.move | 1801 ++++++++------- .../sources/types/coin_data.move | 50 +- .../sources/types/coin_info.move | 151 +- .../sources/types/coin_management.move | 433 ++-- .../sources/types/creator_cap.move | 30 +- .../sources/types/flow_limit.move | 242 +- .../types/interchain_transfer_ticket.move | 110 +- .../sources/types/operator_cap.move | 22 +- .../sources/types/owner_cap.move | 22 +- .../sources/types/token_id.move | 175 +- .../sources/types/trusted_chains.move | 212 +- .../sources/types/unregistered_coin_data.move | 47 +- .../sources/utils.move | 145 +- move/interchain_token_service/tests/coin.move | 121 +- .../tests/coin_init_test.move | 45 +- move/operators/sources/operators.move | 693 +++--- move/relayer_discovery/sources/discovery.move | 367 ++- move/relayer_discovery/sources/events.move | 61 +- .../sources/types/owner_cap.move | 38 +- .../sources/types/transaction.move | 488 ++-- .../versioned/relayer_discovery_v0.move | 228 +- move/squid/sources/squid/coin_bag.move | 260 ++- move/squid/sources/squid/deepbook_v3.move | 526 ++--- move/squid/sources/squid/discovery.move | 322 ++- move/squid/sources/squid/owner_cap.move | 38 +- move/squid/sources/squid/squid.move | 524 +++-- move/squid/sources/squid/swap_info.move | 570 +++-- move/squid/sources/squid/swap_type.move | 76 +- move/squid/sources/squid/transfers.move | 401 ++-- .../sources/squid/versioned/squid_v0.move | 346 ++- move/squid/tests/squid/deepbook_v3_tests.move | 254 ++- move/utils/sources/utils/utils.move | 122 +- .../sources/version_control.move | 394 ++-- package-lock.json | 78 +- package.json | 5 +- test.move | 11 + 64 files changed, 9699 insertions(+), 10560 deletions(-) create mode 100644 test.move diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 09e08a66..3ff4524e 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -2,359 +2,352 @@ /// with EVM message format. /// /// ABI Specification: https://docs.soliditylang.org/en/v0.8.26/abi-spec.html -module abi::abi; - -// ----- -// Types -// ----- - -public struct AbiReader has copy, drop { - bytes: vector, - head: u64, - pos: u64, -} +module abi::abi { + // ----- + // Types + // ----- + + public struct AbiReader has copy, drop { + bytes: vector, + head: u64, + pos: u64, + } -public struct AbiWriter has copy, drop { - bytes: vector, - pos: u64, -} + public struct AbiWriter has copy, drop { + bytes: vector, + pos: u64, + } -// ---------------- -// Public Functions -// ---------------- + // ---------------- + // Public Functions + // ---------------- -public fun new_reader(bytes: vector): AbiReader { - AbiReader { - bytes, - head: 0, - pos: 0, + public fun new_reader(bytes: vector): AbiReader { + AbiReader { + bytes, + head: 0, + pos: 0, + } } -} -public fun new_writer(length: u64): AbiWriter { - let mut bytes = vector[]; - let mut i = 0; + public fun new_writer(length: u64): AbiWriter { + let mut bytes = vector[]; + let mut i = 0; - while (i < 32 * length) { - bytes.push_back(0); - i = i + 1; - }; + while (i < 32 * length) { + bytes.push_back(0); + i = i + 1; + }; - AbiWriter { - bytes, - pos: 0, + AbiWriter { + bytes, + pos: 0, + } } -} -public fun into_bytes(self: AbiWriter): vector { - let AbiWriter { bytes, pos: _ } = self; + public fun into_bytes(self: AbiWriter): vector { + let AbiWriter { bytes, pos: _ } = self; - bytes -} + bytes + } -// TODO: check that all bytes were decoded -public fun into_remaining_bytes(self: AbiReader): vector { - let AbiReader { bytes, head: _, pos: _ } = self; + // TODO: check that all bytes were decoded + public fun into_remaining_bytes(self: AbiReader): vector { + let AbiReader { bytes, head: _, pos: _ } = self; - bytes -} + bytes + } -public fun read_u256(self: &mut AbiReader): u256 { - let mut var = 0u256; - let mut i = 0; - let pos = self.pos; + public fun read_u256(self: &mut AbiReader): u256 { + let mut var = 0u256; + let mut i = 0; + let pos = self.pos; - while (i < 32) { - var = (var << 8) | (self.bytes[i + pos] as u256); - i = i + 1; - }; + while (i < 32) { + var = (var << 8) | (self.bytes[i + pos] as u256); + i = i + 1; + }; - self.pos = pos + 32; + self.pos = pos + 32; - var -} + var + } -public fun read_u8(self: &mut AbiReader): u8 { - self.read_u256() as u8 -} + public fun read_u8(self: &mut AbiReader): u8 { + self.read_u256() as u8 + } -public fun skip_slot(self: &mut AbiReader) { - self.pos = self.pos + 32; -} + public fun skip_slot(self: &mut AbiReader) { + self.pos = self.pos + 32; + } -public fun read_bytes(self: &mut AbiReader): vector { - let pos = self.pos; + public fun read_bytes(self: &mut AbiReader): vector { + let pos = self.pos; - // Move position to the start of the bytes - let offset = self.read_u256() as u64; - self.pos = self.head + offset; + // Move position to the start of the bytes + let offset = self.read_u256() as u64; + self.pos = self.head + offset; - let var = self.decode_bytes(); + let var = self.decode_bytes(); - // Move position to the next slot - self.pos = pos + 32; + // Move position to the next slot + self.pos = pos + 32; - var -} + var + } -public fun read_vector_u256(self: &mut AbiReader): vector { - let mut var = vector[]; - let pos = self.pos; + public fun read_vector_u256(self: &mut AbiReader): vector { + let mut var = vector[]; + let pos = self.pos; - // Move position to the start of the dynamic data - let offset = self.read_u256() as u64; - self.pos = self.head + offset; + // Move position to the start of the dynamic data + let offset = self.read_u256() as u64; + self.pos = self.head + offset; - let length = self.read_u256() as u64; + let length = self.read_u256() as u64; - let mut i = 0; + let mut i = 0; - while (i < length) { - var.push_back(self.read_u256()); - i = i + 1; - }; + while (i < length) { + var.push_back(self.read_u256()); + i = i + 1; + }; - self.pos = pos + 32; + self.pos = pos + 32; - var -} + var + } -/// Decode ABI-encoded 'bytes[]' -public fun read_vector_bytes(self: &mut AbiReader): vector> { - let mut var = vector[]; + /// Decode ABI-encoded 'bytes[]' + public fun read_vector_bytes(self: &mut AbiReader): vector> { + let mut var = vector[]; - let pos = self.pos; - let head = self.head; + let pos = self.pos; + let head = self.head; - // Move position to the start of the dynamic data - let offset = self.read_u256() as u64; - self.pos = head + offset; + // Move position to the start of the dynamic data + let offset = self.read_u256() as u64; + self.pos = head + offset; - let length = self.read_u256() as u64; - self.head = self.pos; + let length = self.read_u256() as u64; + self.head = self.pos; - let mut i = 0; + let mut i = 0; - while (i < length) { - var.push_back(self.read_bytes()); + while (i < length) { + var.push_back(self.read_bytes()); - i = i + 1; - }; + i = i + 1; + }; - // Move position to the next slot - self.pos = pos + 32; - self.head = head; + // Move position to the next slot + self.pos = pos + 32; + self.head = head; - var -} + var + } -public fun write_u256(self: &mut AbiWriter, var: u256): &mut AbiWriter { - let pos = self.pos; - let mut i = 0; + public fun write_u256(self: &mut AbiWriter, var: u256): &mut AbiWriter { + let pos = self.pos; + let mut i = 0; - while (i < 32) { - let exp = ((31 - i) * 8 as u8); - let byte = (var >> exp & 255 as u8); - *&mut self.bytes[i + pos] = byte; - i = i + 1; - }; + while (i < 32) { + let exp = ((31 - i) * 8 as u8); + let byte = (var >> exp & 255 as u8); + *&mut self.bytes[i + pos] = byte; + i = i + 1; + }; - self.pos = pos + 32; + self.pos = pos + 32; - self -} + self + } -public fun write_u8(self: &mut AbiWriter, var: u8): &mut AbiWriter { - self.write_u256(var as u256) -} + public fun write_u8(self: &mut AbiWriter, var: u8): &mut AbiWriter { + self.write_u256(var as u256) + } -public fun write_bytes(self: &mut AbiWriter, var: vector): &mut AbiWriter { - let offset = self.bytes.length() as u256; - self.write_u256(offset); + public fun write_bytes(self: &mut AbiWriter, var: vector): &mut AbiWriter { + let offset = self.bytes.length() as u256; + self.write_u256(offset); - // Write dynamic data length and bytes at the tail - self.append_u256(var.length() as u256); - self.append_bytes(var); + // Write dynamic data length and bytes at the tail + self.append_u256(var.length() as u256); + self.append_bytes(var); - self -} + self + } -public fun write_vector_u256( - self: &mut AbiWriter, - var: vector, -): &mut AbiWriter { - let offset = self.bytes.length() as u256; - self.write_u256(offset); + public fun write_vector_u256(self: &mut AbiWriter, var: vector): &mut AbiWriter { + let offset = self.bytes.length() as u256; + self.write_u256(offset); - let length = var.length(); - self.append_u256(length as u256); + let length = var.length(); + self.append_u256(length as u256); - let mut i = 0; - while (i < length) { - self.append_u256(var[i]); - i = i + 1; - }; + let mut i = 0; + while (i < length) { + self.append_u256(var[i]); + i = i + 1; + }; - self -} + self + } -public fun write_vector_bytes( - self: &mut AbiWriter, - var: vector>, -): &mut AbiWriter { - let offset = self.bytes.length() as u256; - self.write_u256(offset); + public fun write_vector_bytes(self: &mut AbiWriter, var: vector>): &mut AbiWriter { + let offset = self.bytes.length() as u256; + self.write_u256(offset); - let length = var.length(); - self.append_u256(length as u256); + let length = var.length(); + self.append_u256(length as u256); - let mut writer = new_writer(length); - let mut i = 0; + let mut writer = new_writer(length); + let mut i = 0; - while (i < length) { - writer.write_bytes(var[i]); - i = i + 1; - }; + while (i < length) { + writer.write_bytes(var[i]); + i = i + 1; + }; - self.append_bytes(writer.into_bytes()); + self.append_bytes(writer.into_bytes()); - self -} + self + } -// ------------------ -// Internal Functions -// ------------------ + // ------------------ + // Internal Functions + // ------------------ -fun append_u256(self: &mut AbiWriter, var: u256) { - let mut i = 0; - while (i < 32) { - self.bytes.push_back(((var >> ((31 - i) * 8 as u8)) & 255 as u8)); - i = i + 1; - }; -} + fun append_u256(self: &mut AbiWriter, var: u256) { + let mut i = 0; + while (i < 32) { + self.bytes.push_back(((var >> ((31 - i) * 8 as u8)) & 255 as u8)); + i = i + 1; + }; + } -fun append_bytes(self: &mut AbiWriter, var: vector) { - let length = var.length(); - if (length == 0) { - return - }; + fun append_bytes(self: &mut AbiWriter, var: vector) { + let length = var.length(); + if (length == 0) { + return + }; - self.bytes.append(var); + self.bytes.append(var); - let mut i = 0u64; + let mut i = 0u64; - while (i < 31 - (length - 1) % 32) { - self.bytes.push_back(0); - i = i + 1; - }; -} + while (i < 31 - (length - 1) % 32) { + self.bytes.push_back(0); + i = i + 1; + }; + } -fun decode_bytes(self: &mut AbiReader): vector { - let length = self.read_u256() as u64; - let pos = self.pos; + fun decode_bytes(self: &mut AbiReader): vector { + let length = self.read_u256() as u64; + let pos = self.pos; - let mut bytes = vector[]; - let mut i = 0; + let mut bytes = vector[]; + let mut i = 0; - while (i < length) { - bytes.push_back(self.bytes[i + pos]); - i = i + 1; - }; + while (i < length) { + bytes.push_back(self.bytes[i + pos]); + i = i + 1; + }; - bytes -} + bytes + } -// ----- -// Tests -// ----- + // ----- + // Tests + // ----- -#[test] -fun test_u256() { - let input = 56; - let output = - x"0000000000000000000000000000000000000000000000000000000000000038"; + #[test] + fun test_u256() { + let input = 56; + let output = x"0000000000000000000000000000000000000000000000000000000000000038"; - let mut writer = new_writer(1); - writer.write_u256(input); - assert!(writer.into_bytes() == output); + let mut writer = new_writer(1); + writer.write_u256(input); + assert!(writer.into_bytes() == output); - let mut reader = new_reader(output); - assert!(reader.read_u256() == input); -} + let mut reader = new_reader(output); + assert!(reader.read_u256() == input); + } -#[test] -fun test_skip_slot() { - let input = 56; - let output = - x"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000038"; + #[test] + fun test_skip_slot() { + let input = 56; + let output = + x"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000038"; - let mut writer = new_writer(2); - writer.write_u256(1).write_u256(input); - assert!(writer.into_bytes() == output); + let mut writer = new_writer(2); + writer.write_u256(1).write_u256(input); + assert!(writer.into_bytes() == output); - let mut reader = new_reader(output); - reader.skip_slot(); - assert!(reader.read_u256() == input); -} + let mut reader = new_reader(output); + reader.skip_slot(); + assert!(reader.read_u256() == input); + } -#[test] -fun test_read_bytes() { - let input = x"123456"; - let output = - x"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000031234560000000000000000000000000000000000000000000000000000000000"; + #[test] + fun test_read_bytes() { + let input = x"123456"; + let output = + x"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000031234560000000000000000000000000000000000000000000000000000000000"; - let mut writer = new_writer(1); - writer.write_bytes(input); - assert!(writer.into_bytes() == output); + let mut writer = new_writer(1); + writer.write_bytes(input); + assert!(writer.into_bytes() == output); - let mut reader = new_reader(output); - assert!(reader.read_bytes() == input); -} + let mut reader = new_reader(output); + assert!(reader.read_bytes() == input); + } -#[test] -fun test_read_vector_u256() { - let input = vector[1, 2, 3]; - let output = - x"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003"; + #[test] + fun test_read_vector_u256() { + let input = vector[1, 2, 3]; + let output = + x"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003"; - let mut writer = new_writer(1); - writer.write_vector_u256(input); - assert!(writer.into_bytes() == output); + let mut writer = new_writer(1); + writer.write_vector_u256(input); + assert!(writer.into_bytes() == output); - let mut reader = new_reader(output); - assert!(reader.read_vector_u256() == input); -} + let mut reader = new_reader(output); + assert!(reader.read_vector_u256() == input); + } -#[test] -fun test_read_vector_bytes() { - let input = vector[x"01", x"02", x"03", x"04"]; - let output = - x"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000102000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010400000000000000000000000000000000000000000000000000000000000000"; + #[test] + fun test_read_vector_bytes() { + let input = vector[x"01", x"02", x"03", x"04"]; + let output = + x"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000102000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010400000000000000000000000000000000000000000000000000000000000000"; - let mut writer = new_writer(1); - writer.write_vector_bytes(input); - assert!(writer.into_bytes() == output); + let mut writer = new_writer(1); + writer.write_vector_bytes(input); + assert!(writer.into_bytes() == output); - let mut reader = new_reader(output); - assert!(reader.read_vector_bytes() == input); -} + let mut reader = new_reader(output); + assert!(reader.read_vector_bytes() == input); + } -#[test] -fun test_multiple() { - let (input1, input2, input3, input4) = (1, x"02", vector[3], vector[x"04"]); - let output = - x"0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010400000000000000000000000000000000000000000000000000000000000000"; - - let mut writer = new_writer(4); - writer.write_u256(input1); - writer.write_bytes(input2); - writer.write_vector_u256(input3); - writer.write_vector_bytes(input4); - assert!(writer.into_bytes() == output); - - let mut reader = new_reader(output); - assert!(reader.read_u256() == input1); - assert!(reader.read_bytes() == input2); - assert!(reader.read_vector_u256() == input3); - assert!(reader.read_vector_bytes() == input4); + #[test] + fun test_multiple() { + let (input1, input2, input3, input4) = (1, x"02", vector[3], vector[x"04"]); + let output = + x"0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010400000000000000000000000000000000000000000000000000000000000000"; + + let mut writer = new_writer(4); + writer.write_u256(input1); + writer.write_bytes(input2); + writer.write_vector_u256(input3); + writer.write_vector_bytes(input4); + assert!(writer.into_bytes() == output); + + let mut reader = new_reader(output); + assert!(reader.read_u256() == input1); + assert!(reader.read_bytes() == input2); + assert!(reader.read_vector_u256() == input3); + assert!(reader.read_vector_bytes() == input4); + } } diff --git a/move/axelar_gateway/sources/auth.move b/move/axelar_gateway/sources/auth.move index 295c338f..aac914d9 100644 --- a/move/axelar_gateway/sources/auth.move +++ b/move/axelar_gateway/sources/auth.move @@ -1,291 +1,261 @@ -module axelar_gateway::auth; - -use axelar_gateway::bytes32::{Self, Bytes32}; -use axelar_gateway::events; -use axelar_gateway::proof::Proof; -use axelar_gateway::weighted_signers::WeightedSigners; -use sui::bcs; -use sui::clock::Clock; -use sui::table::{Self, Table}; - -// ------ -// Errors -// ------ -#[error] -const EInsufficientRotationDelay: vector = b"insufficient rotation delay"; - -#[error] -const EInvalidEpoch: vector = - b"the difference between current_epoch and signers_epoch exceeds the allowed retention period"; - -// ----- -// Types -// ----- -public struct AxelarSigners has store { - /// Epoch of the signers. - epoch: u64, - /// Epoch for the signers hash. - epoch_by_signers_hash: Table, - /// Domain separator between chains. - domain_separator: Bytes32, - /// Minimum rotation delay. - minimum_rotation_delay: u64, - /// Timestamp of the last rotation. - last_rotation_timestamp: u64, - /// Number of previous signers retained (latest signer isn't included in the - /// count). - previous_signers_retention: u64, -} +module axelar_gateway::auth { + use axelar_gateway::{bytes32::{Self, Bytes32}, events, proof::Proof, weighted_signers::WeightedSigners}; + use sui::{bcs, clock::Clock, table::{Self, Table}}; + + // ------ + // Errors + // ------ + #[error] + const EInsufficientRotationDelay: vector = b"insufficient rotation delay"; + + #[error] + const EInvalidEpoch: vector = b"the difference between current_epoch and signers_epoch exceeds the allowed retention period"; + + // ----- + // Types + // ----- + public struct AxelarSigners has store { + /// Epoch of the signers. + epoch: u64, + /// Epoch for the signers hash. + epoch_by_signers_hash: Table, + /// Domain separator between chains. + domain_separator: Bytes32, + /// Minimum rotation delay. + minimum_rotation_delay: u64, + /// Timestamp of the last rotation. + last_rotation_timestamp: u64, + /// Number of previous signers retained (latest signer isn't included in the + /// count). + previous_signers_retention: u64, + } -public struct MessageToSign has copy, drop, store { - domain_separator: Bytes32, - signers_hash: Bytes32, - data_hash: Bytes32, -} + public struct MessageToSign has copy, drop, store { + domain_separator: Bytes32, + signers_hash: Bytes32, + data_hash: Bytes32, + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun new(ctx: &mut TxContext): AxelarSigners { - AxelarSigners { - epoch: 0, - epoch_by_signers_hash: table::new(ctx), - domain_separator: bytes32::default(), - minimum_rotation_delay: 0, - last_rotation_timestamp: 0, - previous_signers_retention: 0, + // ----------------- + // Package Functions + // ----------------- + public(package) fun new(ctx: &mut TxContext): AxelarSigners { + AxelarSigners { + epoch: 0, + epoch_by_signers_hash: table::new(ctx), + domain_separator: bytes32::default(), + minimum_rotation_delay: 0, + last_rotation_timestamp: 0, + previous_signers_retention: 0, + } } -} -public(package) fun setup( - domain_separator: Bytes32, - minimum_rotation_delay: u64, - previous_signers_retention: u64, - initial_signers: WeightedSigners, - clock: &Clock, - ctx: &mut TxContext, -): AxelarSigners { - let mut signers = AxelarSigners { - epoch: 0, - epoch_by_signers_hash: table::new(ctx), - domain_separator, - minimum_rotation_delay, - last_rotation_timestamp: 0, - previous_signers_retention, - }; - - signers.rotate_signers(clock, initial_signers, false); - - signers -} + public(package) fun setup( + domain_separator: Bytes32, + minimum_rotation_delay: u64, + previous_signers_retention: u64, + initial_signers: WeightedSigners, + clock: &Clock, + ctx: &mut TxContext, + ): AxelarSigners { + let mut signers = AxelarSigners { + epoch: 0, + epoch_by_signers_hash: table::new(ctx), + domain_separator, + minimum_rotation_delay, + last_rotation_timestamp: 0, + previous_signers_retention, + }; -public(package) fun validate_proof( - self: &AxelarSigners, - data_hash: Bytes32, - proof: Proof, -): bool { - let signers = proof.signers(); - let signers_hash = signers.hash(); - let signers_epoch = self.epoch_by_signers_hash[signers_hash]; - let current_epoch = self.epoch; - let is_latest_signers = current_epoch == signers_epoch; - - assert!( - signers_epoch != 0 && - (current_epoch - signers_epoch) <= self.previous_signers_retention, - EInvalidEpoch, - ); - - proof.validate( - bcs::to_bytes( - &MessageToSign { - domain_separator: self.domain_separator, - signers_hash, - data_hash, - }, - ), - ); + signers.rotate_signers(clock, initial_signers, false); - is_latest_signers -} + signers + } -public(package) fun rotate_signers( - self: &mut AxelarSigners, - clock: &Clock, - new_signers: WeightedSigners, - enforce_rotation_delay: bool, -) { - new_signers.validate(); + public(package) fun validate_proof(self: &AxelarSigners, data_hash: Bytes32, proof: Proof): bool { + let signers = proof.signers(); + let signers_hash = signers.hash(); + let signers_epoch = self.epoch_by_signers_hash[signers_hash]; + let current_epoch = self.epoch; + let is_latest_signers = current_epoch == signers_epoch; + + assert!(signers_epoch != 0 && + (current_epoch - signers_epoch) <= self.previous_signers_retention, EInvalidEpoch); + + proof.validate( + bcs::to_bytes( + &MessageToSign { + domain_separator: self.domain_separator, + signers_hash, + data_hash, + }, + ), + ); + + is_latest_signers + } - self.update_rotation_timestamp(clock, enforce_rotation_delay); + public(package) fun rotate_signers( + self: &mut AxelarSigners, + clock: &Clock, + new_signers: WeightedSigners, + enforce_rotation_delay: bool, + ) { + new_signers.validate(); - let new_signers_hash = new_signers.hash(); - let epoch = self.epoch + 1; + self.update_rotation_timestamp(clock, enforce_rotation_delay); - // Aborts if the signers already exist - self.epoch_by_signers_hash.add(new_signers_hash, epoch); - self.epoch = epoch; + let new_signers_hash = new_signers.hash(); + let epoch = self.epoch + 1; - events::signers_rotated( - epoch, - new_signers_hash, - new_signers, - ); -} + // Aborts if the signers already exist + self.epoch_by_signers_hash.add(new_signers_hash, epoch); + self.epoch = epoch; + + events::signers_rotated( + epoch, + new_signers_hash, + new_signers, + ); + } + + // ------------------ + // Internal Functions + // ------------------ + fun update_rotation_timestamp(self: &mut AxelarSigners, clock: &Clock, enforce_rotation_delay: bool) { + let current_timestamp = clock.timestamp_ms(); -// ------------------ -// Internal Functions -// ------------------ -fun update_rotation_timestamp( - self: &mut AxelarSigners, - clock: &Clock, - enforce_rotation_delay: bool, -) { - let current_timestamp = clock.timestamp_ms(); - - // If the rotation delay is enforced, the current timestamp should be - // greater than the last rotation timestamp plus the minimum rotation delay. - assert!( - !enforce_rotation_delay || + // If the rotation delay is enforced, the current timestamp should be + // greater than the last rotation timestamp plus the minimum rotation delay. + assert!( + !enforce_rotation_delay || current_timestamp >= self.last_rotation_timestamp + self.minimum_rotation_delay, - EInsufficientRotationDelay, - ); + EInsufficientRotationDelay, + ); - self.last_rotation_timestamp = current_timestamp; -} + self.last_rotation_timestamp = current_timestamp; + } -// --------- -// Test Only -// --------- -#[test_only] -use sui::ecdsa_k1; -#[test_only] -use axelar_gateway::proof; - -#[test_only] -public fun dummy(ctx: &mut TxContext): AxelarSigners { - let mut rng = sui::random::new_generator_for_testing(); - AxelarSigners { - epoch: 0, - epoch_by_signers_hash: table::new(ctx), - domain_separator: bytes32::from_bytes(rng.generate_bytes(32)), - minimum_rotation_delay: 1, - last_rotation_timestamp: 0, - previous_signers_retention: 3, + // --------- + // Test Only + // --------- + #[test_only] + use sui::ecdsa_k1; + #[test_only] + use axelar_gateway::proof; + + #[test_only] + public fun dummy(ctx: &mut TxContext): AxelarSigners { + let mut rng = sui::random::new_generator_for_testing(); + AxelarSigners { + epoch: 0, + epoch_by_signers_hash: table::new(ctx), + domain_separator: bytes32::from_bytes(rng.generate_bytes(32)), + minimum_rotation_delay: 1, + last_rotation_timestamp: 0, + previous_signers_retention: 3, + } } -} -#[test_only] -public(package) fun new_message_to_sign( - domain_separator: Bytes32, - signers_hash: Bytes32, - data_hash: Bytes32, -): MessageToSign { - MessageToSign { - domain_separator, - signers_hash, - data_hash, + #[test_only] + public(package) fun new_message_to_sign(domain_separator: Bytes32, signers_hash: Bytes32, data_hash: Bytes32): MessageToSign { + MessageToSign { + domain_separator, + signers_hash, + data_hash, + } } -} -#[test_only] -public fun destroy_for_testing( - signers: AxelarSigners, -): (u64, Table, Bytes32, u64, u64, u64) { - let AxelarSigners { - epoch, - epoch_by_signers_hash, - domain_separator, - minimum_rotation_delay, - last_rotation_timestamp, - previous_signers_retention, - } = signers; - ( - epoch, - epoch_by_signers_hash, - domain_separator, - minimum_rotation_delay, - last_rotation_timestamp, - previous_signers_retention, - ) -} + #[test_only] + public fun destroy_for_testing(signers: AxelarSigners): (u64, Table, Bytes32, u64, u64, u64) { + let AxelarSigners { + epoch, + epoch_by_signers_hash, + domain_separator, + minimum_rotation_delay, + last_rotation_timestamp, + previous_signers_retention, + } = signers; + (epoch, epoch_by_signers_hash, domain_separator, minimum_rotation_delay, last_rotation_timestamp, previous_signers_retention) + } -#[test_only] -public(package) fun epoch_mut(self: &mut AxelarSigners): &mut u64 { - &mut self.epoch -} + #[test_only] + public(package) fun epoch_mut(self: &mut AxelarSigners): &mut u64 { + &mut self.epoch + } -#[test_only] -public(package) fun generate_proof( - data_hash: Bytes32, - domain_separator: Bytes32, - weighted_signers: WeightedSigners, - keypairs: &vector, -): Proof { - let message_to_sign = bcs::to_bytes( - &MessageToSign { - domain_separator, - signers_hash: weighted_signers.hash(), - data_hash, - }, - ); + #[test_only] + public(package) fun generate_proof( + data_hash: Bytes32, + domain_separator: Bytes32, + weighted_signers: WeightedSigners, + keypairs: &vector, + ): Proof { + let message_to_sign = bcs::to_bytes( + &MessageToSign { + domain_separator, + signers_hash: weighted_signers.hash(), + data_hash, + }, + ); - proof::generate(weighted_signers, &message_to_sign, keypairs) -} + proof::generate(weighted_signers, &message_to_sign, keypairs) + } -// ----- -// Tests -// ----- -#[test] -fun test_new() { - let ctx = &mut sui::tx_context::dummy(); - let self = new(ctx); - sui::test_utils::destroy(self); -} + // ----- + // Tests + // ----- + #[test] + fun test_new() { + let ctx = &mut sui::tx_context::dummy(); + let self = new(ctx); + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EInsufficientRotationDelay)] -fun test_update_rotation_timestamp_insufficient_rotation_delay() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); + #[test] + #[expected_failure(abort_code = EInsufficientRotationDelay)] + fun test_update_rotation_timestamp_insufficient_rotation_delay() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); - let clock = sui::clock::create_for_testing(ctx); + let clock = sui::clock::create_for_testing(ctx); - self.last_rotation_timestamp = 1; + self.last_rotation_timestamp = 1; - self.update_rotation_timestamp(&clock, true); + self.update_rotation_timestamp(&clock, true); - sui::test_utils::destroy(self); - clock.destroy_for_testing(); -} + sui::test_utils::destroy(self); + clock.destroy_for_testing(); + } -#[test] -#[expected_failure(abort_code = EInvalidEpoch)] -fun test_validate_proof_invalid_epoch() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let proof = axelar_gateway::proof::create_for_testing( - axelar_gateway::weighted_signers::create_for_testing( + #[test] + #[expected_failure(abort_code = EInvalidEpoch)] + fun test_validate_proof_invalid_epoch() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let proof = axelar_gateway::proof::create_for_testing( + axelar_gateway::weighted_signers::create_for_testing( + vector[], + 0, + bytes32::from_bytes(rng.generate_bytes(32)), + ), vector[], - 0, + ); + let signers = proof.signers(); + let signers_hash = signers.hash(); + let signers_epoch = 0; + self.epoch_by_signers_hash.add(signers_hash, signers_epoch); + + self.previous_signers_retention = 2; + self.epoch = 3; + + self.validate_proof( bytes32::from_bytes(rng.generate_bytes(32)), - ), - vector[], - ); - let signers = proof.signers(); - let signers_hash = signers.hash(); - let signers_epoch = 0; - self.epoch_by_signers_hash.add(signers_hash, signers_epoch); - - self.previous_signers_retention = 2; - self.epoch = 3; - - self.validate_proof( - bytes32::from_bytes(rng.generate_bytes(32)), - proof, - ); - - sui::test_utils::destroy(self); + proof, + ); + + sui::test_utils::destroy(self); + } } diff --git a/move/axelar_gateway/sources/channel.move b/move/axelar_gateway/sources/channel.move index 45ad15bd..f7332eef 100644 --- a/move/axelar_gateway/sources/channel.move +++ b/move/axelar_gateway/sources/channel.move @@ -4,308 +4,290 @@ /// A channel has a unique id and is treated as the destination address by the /// Axelar protocol. /// Apps can create a channel and hold on to it for cross-chain messaging. -module axelar_gateway::channel; - -use axelar_gateway::events; -use std::ascii::String; - -// ----- -// Types -// ----- - -/// The Channel object. Acts as a destination for the messages sent through -/// the bridge. The `destination_id` is compared against the `id` of the -/// `Channel` -/// when the message is consumed -public struct Channel has key, store { - /// Unique ID of the channel - id: UID, -} +module axelar_gateway::channel { + use axelar_gateway::events; + use std::ascii::String; + + // ----- + // Types + // ----- + + /// The Channel object. Acts as a destination for the messages sent through + /// the bridge. The `destination_id` is compared against the `id` of the + /// `Channel` + /// when the message is consumed + public struct Channel has key, store { + /// Unique ID of the channel + id: UID, + } -/// A HotPotato - this should be received by the application contract and -/// consumed -public struct ApprovedMessage { - /// Source chain axelar-registered name - source_chain: String, - /// Unique ID of the message - message_id: String, - /// Address of the source chain, encoded as a string (e.g. EVM address will - /// be hex string 0x1234...abcd) - source_address: String, - /// The destination Channel's UID - destination_id: address, - /// Message payload - payload: vector, -} + /// A HotPotato - this should be received by the application contract and + /// consumed + public struct ApprovedMessage { + /// Source chain axelar-registered name + source_chain: String, + /// Unique ID of the message + message_id: String, + /// Address of the source chain, encoded as a string (e.g. EVM address will + /// be hex string 0x1234...abcd) + source_address: String, + /// The destination Channel's UID + destination_id: address, + /// Message payload + payload: vector, + } -// ------ -// Errors -// ------ + // ------ + // Errors + // ------ -/// If approved message is consumed by an invalid destination id -#[error] -const EInvalidDestination: vector = b"invalid destination"; + /// If approved message is consumed by an invalid destination id + #[error] + const EInvalidDestination: vector = b"invalid destination"; -// ---------------- -// Public Functions -// ---------------- + // ---------------- + // Public Functions + // ---------------- -/// Create new `Channel` object. -/// Anyone can create their own `Channel` to receive cross-chain messages. -/// In most use cases, a package should create this on init, and hold on to it -/// forever. -public fun new(ctx: &mut TxContext): Channel { - let id = object::new(ctx); + /// Create new `Channel` object. + /// Anyone can create their own `Channel` to receive cross-chain messages. + /// In most use cases, a package should create this on init, and hold on to it + /// forever. + public fun new(ctx: &mut TxContext): Channel { + let id = object::new(ctx); - events::channel_created(id.uid_to_address()); + events::channel_created(id.uid_to_address()); - Channel { - id, + Channel { + id, + } } -} -/// Destroy a `Channel`. Allows apps to destroy the `Channel` object when it's -/// no longer needed. -public fun destroy(self: Channel) { - let Channel { id } = self; + /// Destroy a `Channel`. Allows apps to destroy the `Channel` object when it's + /// no longer needed. + public fun destroy(self: Channel) { + let Channel { id } = self; - events::channel_destroyed(id.uid_to_address()); + events::channel_destroyed(id.uid_to_address()); - id.delete(); -} + id.delete(); + } -public fun id(self: &Channel): ID { - object::id(self) -} + public fun id(self: &Channel): ID { + object::id(self) + } -public fun to_address(self: &Channel): address { - object::id_address(self) -} + public fun to_address(self: &Channel): address { + object::id_address(self) + } -/// Consume an approved message hot potato object intended for this `Channel`. -public fun consume_approved_message( - channel: &Channel, - approved_message: ApprovedMessage, -): (String, String, String, vector) { - let ApprovedMessage { - source_chain, - message_id, - source_address, - destination_id, - payload, - } = approved_message; - - // Check if the message is sent to the correct destination. - assert!(destination_id == object::id_address(channel), EInvalidDestination); - - (source_chain, message_id, source_address, payload) -} + /// Consume an approved message hot potato object intended for this `Channel`. + public fun consume_approved_message(channel: &Channel, approved_message: ApprovedMessage): (String, String, String, vector) { + let ApprovedMessage { + source_chain, + message_id, + source_address, + destination_id, + payload, + } = approved_message; + + // Check if the message is sent to the correct destination. + assert!(destination_id == object::id_address(channel), EInvalidDestination); -// ----------------- -// Package Functions -// ----------------- - -/// Create a new `ApprovedMessage` object to be sent to another chain. Is called -/// by the gateway when a message is "picked up" by the relayer. -public(package) fun create_approved_message( - source_chain: String, - message_id: String, - source_address: String, - destination_id: address, - payload: vector, -): ApprovedMessage { - ApprovedMessage { - source_chain, - message_id, - source_address, - destination_id, - payload, + (source_chain, message_id, source_address, payload) } -} -// --------- -// Test Only -// --------- -#[test_only] -use utils::utils; - -#[test_only] -public fun new_approved_message( - source_chain: String, - message_id: String, - source_address: String, - destination_id: address, - payload: vector, -): ApprovedMessage { - ApprovedMessage { - source_chain, - message_id, - source_address, - destination_id, - payload, + // ----------------- + // Package Functions + // ----------------- + + /// Create a new `ApprovedMessage` object to be sent to another chain. Is called + /// by the gateway when a message is "picked up" by the relayer. + public(package) fun create_approved_message( + source_chain: String, + message_id: String, + source_address: String, + destination_id: address, + payload: vector, + ): ApprovedMessage { + ApprovedMessage { + source_chain, + message_id, + source_address, + destination_id, + payload, + } } -} -#[test_only] -public fun destroy_for_testing(approved_message: ApprovedMessage) { - ApprovedMessage { - source_chain: _, - message_id: _, - source_address: _, - destination_id: _, - payload: _, - } = approved_message; -} + // --------- + // Test Only + // --------- + #[test_only] + use utils::utils; + + #[test_only] + public fun new_approved_message( + source_chain: String, + message_id: String, + source_address: String, + destination_id: address, + payload: vector, + ): ApprovedMessage { + ApprovedMessage { + source_chain, + message_id, + source_address, + destination_id, + payload, + } + } -#[test_only] -public(package) fun approved_message_source_chain( - self: &ApprovedMessage, -): String { - self.source_chain -} + #[test_only] + public fun destroy_for_testing(approved_message: ApprovedMessage) { + ApprovedMessage { + source_chain: _, + message_id: _, + source_address: _, + destination_id: _, + payload: _, + } = approved_message; + } -#[test_only] -public(package) fun approved_message_message_id( - self: &ApprovedMessage, -): String { - self.message_id -} + #[test_only] + public(package) fun approved_message_source_chain(self: &ApprovedMessage): String { + self.source_chain + } -#[test_only] -public(package) fun approved_message_source_address( - self: &ApprovedMessage, -): String { - self.source_address -} + #[test_only] + public(package) fun approved_message_message_id(self: &ApprovedMessage): String { + self.message_id + } -#[test_only] -public(package) fun approved_message_destination_id( - self: &ApprovedMessage, -): address { - self.destination_id -} + #[test_only] + public(package) fun approved_message_source_address(self: &ApprovedMessage): String { + self.source_address + } -#[test_only] -public(package) fun approved_message_payload( - self: &ApprovedMessage, -): vector { - self.payload -} + #[test_only] + public(package) fun approved_message_destination_id(self: &ApprovedMessage): address { + self.destination_id + } -// ----- -// Tests -// ----- -#[test] -fun test_new_and_destroy() { - let ctx = &mut sui::tx_context::dummy(); - let channel: Channel = new(ctx); - utils::assert_event(); - channel.destroy(); - utils::assert_event(); -} + #[test_only] + public(package) fun approved_message_payload(self: &ApprovedMessage): vector { + self.payload + } -#[test] -fun test_id() { - let ctx = &mut sui::tx_context::dummy(); - let channel: Channel = new(ctx); - assert!(channel.id() == object::id(&channel)); - channel.destroy() -} + // ----- + // Tests + // ----- + #[test] + fun test_new_and_destroy() { + let ctx = &mut sui::tx_context::dummy(); + let channel: Channel = new(ctx); + utils::assert_event(); + channel.destroy(); + utils::assert_event(); + } -#[test] -fun test_to_address() { - let ctx = &mut sui::tx_context::dummy(); - let channel: Channel = new(ctx); - assert!(channel.to_address() == object::id_address(&channel)); - channel.destroy() -} + #[test] + fun test_id() { + let ctx = &mut sui::tx_context::dummy(); + let channel: Channel = new(ctx); + assert!(channel.id() == object::id(&channel)); + channel.destroy() + } -#[test] -fun test_create_approved_message() { - let mut rng = sui::random::new_generator_for_testing(); - let input_source_chain = std::ascii::string(b"Source Chain"); - let input_message_id = std::ascii::string(b"message id"); - let input_source_address = std::ascii::string(b"Source Address"); - let input_destination_id = sui::address::from_bytes(rng.generate_bytes(32)); - let input_payload = rng.generate_bytes(32); - let approved_message: ApprovedMessage = create_approved_message( - input_source_chain, - input_message_id, - input_source_address, - input_destination_id, - input_payload, - ); - - let ApprovedMessage { - source_chain, - message_id, - source_address, - destination_id, - payload, - } = approved_message; - assert!(source_chain == input_source_chain); - assert!(message_id == input_message_id); - assert!(source_address == input_source_address); - assert!(destination_id == input_destination_id); - assert!(payload == input_payload); -} + #[test] + fun test_to_address() { + let ctx = &mut sui::tx_context::dummy(); + let channel: Channel = new(ctx); + assert!(channel.to_address() == object::id_address(&channel)); + channel.destroy() + } -#[test] -fun test_consume_approved_message() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let channel: Channel = new(ctx); - - let input_source_chain = std::ascii::string(b"Source Chain"); - let input_message_id = std::ascii::string(b"message id"); - let input_source_address = std::ascii::string(b"Source Address"); - let input_destination_id = channel.to_address(); - let input_payload = rng.generate_bytes(32); - let approved_message: ApprovedMessage = create_approved_message( - input_source_chain, - input_message_id, - input_source_address, - input_destination_id, - input_payload, - ); - - let ( - source_chain, - message_id, - source_address, - payload, - ) = channel.consume_approved_message(approved_message); - - assert!(source_chain == input_source_chain); - assert!(message_id == input_message_id); - assert!(source_address == input_source_address); - assert!(payload == input_payload); - - channel.destroy(); -} + #[test] + fun test_create_approved_message() { + let mut rng = sui::random::new_generator_for_testing(); + let input_source_chain = std::ascii::string(b"Source Chain"); + let input_message_id = std::ascii::string(b"message id"); + let input_source_address = std::ascii::string(b"Source Address"); + let input_destination_id = sui::address::from_bytes(rng.generate_bytes(32)); + let input_payload = rng.generate_bytes(32); + let approved_message: ApprovedMessage = create_approved_message( + input_source_chain, + input_message_id, + input_source_address, + input_destination_id, + input_payload, + ); + + let ApprovedMessage { + source_chain, + message_id, + source_address, + destination_id, + payload, + } = approved_message; + assert!(source_chain == input_source_chain); + assert!(message_id == input_message_id); + assert!(source_address == input_source_address); + assert!(destination_id == input_destination_id); + assert!(payload == input_payload); + } -#[test] -#[expected_failure(abort_code = EInvalidDestination)] -fun test_consume_approved_message_wrong_destination() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let channel: Channel = new(ctx); - - let source_chain = std::ascii::string(b"Source Chain"); - let message_id = std::ascii::string(b"message id"); - let source_address = std::ascii::string(b"Source Address"); - let destination_id = sui::address::from_bytes(rng.generate_bytes(32)); - let payload = rng.generate_bytes(32); - - let approved_message = create_approved_message( - source_chain, - message_id, - source_address, - destination_id, - payload, - ); - - channel.consume_approved_message(approved_message); - - channel.destroy(); + #[test] + fun test_consume_approved_message() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let channel: Channel = new(ctx); + + let input_source_chain = std::ascii::string(b"Source Chain"); + let input_message_id = std::ascii::string(b"message id"); + let input_source_address = std::ascii::string(b"Source Address"); + let input_destination_id = channel.to_address(); + let input_payload = rng.generate_bytes(32); + let approved_message: ApprovedMessage = create_approved_message( + input_source_chain, + input_message_id, + input_source_address, + input_destination_id, + input_payload, + ); + + let (source_chain, message_id, source_address, payload) = channel.consume_approved_message(approved_message); + + assert!(source_chain == input_source_chain); + assert!(message_id == input_message_id); + assert!(source_address == input_source_address); + assert!(payload == input_payload); + + channel.destroy(); + } + + #[test] + #[expected_failure(abort_code = EInvalidDestination)] + fun test_consume_approved_message_wrong_destination() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let channel: Channel = new(ctx); + + let source_chain = std::ascii::string(b"Source Chain"); + let message_id = std::ascii::string(b"message id"); + let source_address = std::ascii::string(b"Source Address"); + let destination_id = sui::address::from_bytes(rng.generate_bytes(32)); + let payload = rng.generate_bytes(32); + + let approved_message = create_approved_message( + source_chain, + message_id, + source_address, + destination_id, + payload, + ); + + channel.consume_approved_message(approved_message); + + channel.destroy(); + } } diff --git a/move/axelar_gateway/sources/events.move b/move/axelar_gateway/sources/events.move index c5494388..7be3d3a9 100644 --- a/move/axelar_gateway/sources/events.move +++ b/move/axelar_gateway/sources/events.move @@ -1,97 +1,95 @@ -module axelar_gateway::events; +module axelar_gateway::events { + use axelar_gateway::{bytes32::Bytes32, message::Message, weighted_signers::WeightedSigners}; + use std::ascii::String; + use sui::event; -use axelar_gateway::bytes32::Bytes32; -use axelar_gateway::message::Message; -use axelar_gateway::weighted_signers::WeightedSigners; -use std::ascii::String; -use sui::event; + // ------ + // Events + // ------ + /// Emitted when signers are rotated. + public struct SignersRotated has copy, drop { + epoch: u64, + signers_hash: Bytes32, + signers: WeightedSigners, + } -// ------ -// Events -// ------ -/// Emitted when signers are rotated. -public struct SignersRotated has copy, drop { - epoch: u64, - signers_hash: Bytes32, - signers: WeightedSigners, -} - -/// Emitted when a new channel is created. -public struct ChannelCreated has copy, drop { - id: address, -} + /// Emitted when a new channel is created. + public struct ChannelCreated has copy, drop { + id: address, + } -/// Emitted when a channel is destroyed. -public struct ChannelDestroyed has copy, drop { - id: address, -} + /// Emitted when a channel is destroyed. + public struct ChannelDestroyed has copy, drop { + id: address, + } -/// Emitted when a new message is sent from the SUI network. -public struct ContractCall has copy, drop { - source_id: address, - destination_chain: String, - destination_address: String, - payload: vector, - payload_hash: address, -} + /// Emitted when a new message is sent from the SUI network. + public struct ContractCall has copy, drop { + source_id: address, + destination_chain: String, + destination_address: String, + payload: vector, + payload_hash: address, + } -/// Emitted when a new message is approved by the gateway. -public struct MessageApproved has copy, drop { - message: Message, -} + /// Emitted when a new message is approved by the gateway. + public struct MessageApproved has copy, drop { + message: Message, + } -/// Emitted when a message is taken to be executed by a channel. -public struct MessageExecuted has copy, drop { - message: Message, -} + /// Emitted when a message is taken to be executed by a channel. + public struct MessageExecuted has copy, drop { + message: Message, + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun signers_rotated(epoch: u64, signers_hash: Bytes32, signers: WeightedSigners) { - event::emit(SignersRotated { - epoch, - signers_hash, - signers, - }); -} + // ----------------- + // Package Functions + // ----------------- + public(package) fun signers_rotated(epoch: u64, signers_hash: Bytes32, signers: WeightedSigners) { + event::emit(SignersRotated { + epoch, + signers_hash, + signers, + }); + } -public(package) fun channel_created(id: address) { - event::emit(ChannelCreated { - id, - }); -} + public(package) fun channel_created(id: address) { + event::emit(ChannelCreated { + id, + }); + } -public(package) fun channel_destroyed(id: address) { - event::emit(ChannelDestroyed { - id, - }); -} + public(package) fun channel_destroyed(id: address) { + event::emit(ChannelDestroyed { + id, + }); + } -public(package) fun contract_call( - source_id: address, - destination_chain: String, - destination_address: String, - payload: vector, - payload_hash: address, -) { - event::emit(ContractCall { - source_id, - destination_chain, - destination_address, - payload, - payload_hash, - }); -} + public(package) fun contract_call( + source_id: address, + destination_chain: String, + destination_address: String, + payload: vector, + payload_hash: address, + ) { + event::emit(ContractCall { + source_id, + destination_chain, + destination_address, + payload, + payload_hash, + }); + } -public(package) fun message_approved(message: Message) { - event::emit(MessageApproved { - message, - }); -} + public(package) fun message_approved(message: Message) { + event::emit(MessageApproved { + message, + }); + } -public(package) fun message_executed(message: Message) { - event::emit(MessageExecuted { - message, - }); + public(package) fun message_executed(message: Message) { + event::emit(MessageExecuted { + message, + }); + } } diff --git a/move/axelar_gateway/sources/gateway.move b/move/axelar_gateway/sources/gateway.move index 008ffcfd..9ef61f1c 100644 --- a/move/axelar_gateway/sources/gateway.move +++ b/move/axelar_gateway/sources/gateway.move @@ -34,1066 +34,1028 @@ /// /// The Gateway object uses a versioned field to support upgradability. The /// current implementation uses Gateway_v0. -module axelar_gateway::gateway; - -use axelar_gateway::auth::{Self, validate_proof}; -use axelar_gateway::bytes32::{Self, Bytes32}; -use axelar_gateway::channel::{Channel, ApprovedMessage}; -use axelar_gateway::gateway_v0::{Self, Gateway_v0}; -use axelar_gateway::message_ticket::{Self, MessageTicket}; -use axelar_gateway::owner_cap::{Self, OwnerCap}; -use axelar_gateway::weighted_signers; -use std::ascii::{Self, String}; -use sui::clock::Clock; -use sui::table; -use sui::versioned::{Self, Versioned}; -use utils::utils; -use version_control::version_control::{Self, VersionControl}; - -// ------- -// Version -// ------- -const VERSION: u64 = 0; - -// ------- -// Structs -// ------- -public struct Gateway has key { - id: UID, - inner: Versioned, -} +module axelar_gateway::gateway { + use axelar_gateway::{ + auth::{Self, validate_proof}, + bytes32::{Self, Bytes32}, + channel::{Channel, ApprovedMessage}, + gateway_v0::{Self, Gateway_v0}, + message_ticket::{Self, MessageTicket}, + owner_cap::{Self, OwnerCap}, + weighted_signers + }; + use std::ascii::{Self, String}; + use sui::{clock::Clock, table, versioned::{Self, Versioned}}; + use utils::utils; + use version_control::version_control::{Self, VersionControl}; + + // ------- + // Version + // ------- + const VERSION: u64 = 0; + + // ------- + // Structs + // ------- + public struct Gateway has key { + id: UID, + inner: Versioned, + } -// ----- -// Setup -// ----- + // ----- + // Setup + // ----- -/// Init the module by giving a OwnerCap to the sender to allow a full -/// `setup`. -fun init(ctx: &mut TxContext) { - let cap = owner_cap::create(ctx); + /// Init the module by giving a OwnerCap to the sender to allow a full + /// `setup`. + fun init(ctx: &mut TxContext) { + let cap = owner_cap::create(ctx); - transfer::public_transfer(cap, ctx.sender()); -} + transfer::public_transfer(cap, ctx.sender()); + } -/// Setup the module by creating a new Gateway object. -entry fun setup( - _: &OwnerCap, - operator: address, - domain_separator: address, - minimum_rotation_delay: u64, - previous_signers_retention: u64, - initial_signers: vector, - clock: &Clock, - ctx: &mut TxContext, -) { - let inner = versioned::create( - VERSION, - gateway_v0::new( - operator, - table::new(ctx), - auth::setup( - bytes32::new(domain_separator), - minimum_rotation_delay, - previous_signers_retention, - utils::peel!( - initial_signers, - |bcs| weighted_signers::peel(bcs), + /// Setup the module by creating a new Gateway object. + entry fun setup( + _: &OwnerCap, + operator: address, + domain_separator: address, + minimum_rotation_delay: u64, + previous_signers_retention: u64, + initial_signers: vector, + clock: &Clock, + ctx: &mut TxContext, + ) { + let inner = versioned::create( + VERSION, + gateway_v0::new( + operator, + table::new(ctx), + auth::setup( + bytes32::new(domain_separator), + minimum_rotation_delay, + previous_signers_retention, + utils::peel!(initial_signers, |bcs| weighted_signers::peel(bcs)), + clock, + ctx, ), - clock, - ctx, + version_control(), ), - version_control(), - ), - ctx, - ); - - // Share the gateway object for anyone to use. - transfer::share_object(Gateway { - id: object::new(ctx), - inner, - }); -} + ctx, + ); -// ------ -// Macros -// ------ -/// This macro also uses version control to sinplify things a bit. -macro fun value($self: &Gateway, $function_name: vector): &Gateway_v0 { - let gateway = $self; - let value = gateway.inner.load_value(); - value.version_control().check(VERSION, ascii::string($function_name)); - value -} + // Share the gateway object for anyone to use. + transfer::share_object(Gateway { + id: object::new(ctx), + inner, + }); + } -/// This macro also uses version control to sinplify things a bit. -macro fun value_mut( - $self: &mut Gateway, - $function_name: vector, -): &mut Gateway_v0 { - let gateway = $self; - let value = gateway.inner.load_value_mut(); - value.version_control().check(VERSION, ascii::string($function_name)); - value -} + // ------ + // Macros + // ------ + /// This macro also uses version control to sinplify things a bit. + macro fun value($self: &Gateway, $function_name: vector): &Gateway_v0 { + let gateway = $self; + let value = gateway.inner.load_value(); + value.version_control().check(VERSION, ascii::string($function_name)); + value + } -// ----------- -// Entrypoints -// ----------- - -/// The main entrypoint for approving Axelar signed messages. -/// If proof is valid, message approvals are stored in the Gateway object, if -/// not already approved before. -/// This method is only intended to be called via a Transaction Block, keeping -/// more flexibility for upgrades. -entry fun approve_messages( - self: &mut Gateway, - message_data: vector, - proof_data: vector, -) { - let value = self.value_mut!(b"approve_messages"); - value.approve_messages(message_data, proof_data); -} + /// This macro also uses version control to sinplify things a bit. + macro fun value_mut($self: &mut Gateway, $function_name: vector): &mut Gateway_v0 { + let gateway = $self; + let value = gateway.inner.load_value_mut(); + value.version_control().check(VERSION, ascii::string($function_name)); + value + } -/// The main entrypoint for rotating Axelar signers. -/// If proof is valid, signers stored on the Gateway object are rotated. -/// This method is only intended to be called via a Transaction Block, keeping -/// more flexibility for upgrades. -entry fun rotate_signers( - self: &mut Gateway, - clock: &Clock, - new_signers_data: vector, - proof_data: vector, - ctx: &TxContext, -) { - let value = self.value_mut!(b"rotate_signers"); - value.rotate_signers( - clock, - new_signers_data, - proof_data, - ctx, - ) -} + // ----------- + // Entrypoints + // ----------- + + /// The main entrypoint for approving Axelar signed messages. + /// If proof is valid, message approvals are stored in the Gateway object, if + /// not already approved before. + /// This method is only intended to be called via a Transaction Block, keeping + /// more flexibility for upgrades. + entry fun approve_messages(self: &mut Gateway, message_data: vector, proof_data: vector) { + let value = self.value_mut!(b"approve_messages"); + value.approve_messages(message_data, proof_data); + } -entry fun allow_function( - self: &mut Gateway, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self.value_mut!(b"allow_function").allow_function(version, function_name); -} + /// The main entrypoint for rotating Axelar signers. + /// If proof is valid, signers stored on the Gateway object are rotated. + /// This method is only intended to be called via a Transaction Block, keeping + /// more flexibility for upgrades. + entry fun rotate_signers(self: &mut Gateway, clock: &Clock, new_signers_data: vector, proof_data: vector, ctx: &TxContext) { + let value = self.value_mut!(b"rotate_signers"); + value.rotate_signers( + clock, + new_signers_data, + proof_data, + ctx, + ) + } -entry fun disallow_function( - self: &mut Gateway, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self - .value_mut!(b"disallow_function") - .disallow_function(version, function_name); -} + entry fun allow_function(self: &mut Gateway, _: &OwnerCap, version: u64, function_name: String) { + self.value_mut!(b"allow_function").allow_function(version, function_name); + } -// ---------------- -// Public Functions -// ---------------- - -/// Prepare a MessageTicket to call a contract on the destination chain. -public fun prepare_message( - channel: &Channel, - destination_chain: String, - destination_address: String, - payload: vector, -): MessageTicket { - message_ticket::new( - channel.to_address(), - destination_chain, - destination_address, - payload, - VERSION, - ) -} + entry fun disallow_function(self: &mut Gateway, _: &OwnerCap, version: u64, function_name: String) { + self.value_mut!(b"disallow_function").disallow_function(version, function_name); + } -/// Submit the MessageTicket which causes a contract call by sending an event -/// from an -/// authorized Channel. -public fun send_message(self: &Gateway, message: MessageTicket) { - let value = self.value!(b"send_message"); - value.send_message(message, VERSION); -} + // ---------------- + // Public Functions + // ---------------- + + /// Prepare a MessageTicket to call a contract on the destination chain. + public fun prepare_message( + channel: &Channel, + destination_chain: String, + destination_address: String, + payload: vector, + ): MessageTicket { + message_ticket::new( + channel.to_address(), + destination_chain, + destination_address, + payload, + VERSION, + ) + } -public fun is_message_approved( - self: &Gateway, - source_chain: String, - message_id: String, - source_address: String, - destination_id: address, - payload_hash: Bytes32, -): bool { - let value = self.value!(b"is_message_approved"); - value.is_message_approved( - source_chain, - message_id, - source_address, - destination_id, - payload_hash, - ) -} + /// Submit the MessageTicket which causes a contract call by sending an event + /// from an + /// authorized Channel. + public fun send_message(self: &Gateway, message: MessageTicket) { + let value = self.value!(b"send_message"); + value.send_message(message, VERSION); + } -public fun is_message_executed( - self: &Gateway, - source_chain: String, - message_id: String, -): bool { - let value = self.value!(b"is_message_executed"); - value.is_message_executed(source_chain, message_id) -} + public fun is_message_approved( + self: &Gateway, + source_chain: String, + message_id: String, + source_address: String, + destination_id: address, + payload_hash: Bytes32, + ): bool { + let value = self.value!(b"is_message_approved"); + value.is_message_approved( + source_chain, + message_id, + source_address, + destination_id, + payload_hash, + ) + } -/// To execute a message, the relayer will call `take_approved_message` -/// to get the hot potato `ApprovedMessage` object, and then trigger the app's -/// package via discovery. -public fun take_approved_message( - self: &mut Gateway, - source_chain: String, - message_id: String, - source_address: String, - destination_id: address, - payload: vector, -): ApprovedMessage { - let value = self.value_mut!(b"take_approved_message"); - value.take_approved_message( - source_chain, - message_id, - source_address, - destination_id, - payload, - ) -} + public fun is_message_executed(self: &Gateway, source_chain: String, message_id: String): bool { + let value = self.value!(b"is_message_executed"); + value.is_message_executed(source_chain, message_id) + } -// ----------------- -// Private Functions -// ----------------- - -fun version_control(): VersionControl { - version_control::new(vector[ - vector[ - b"approve_messages", - b"rotate_signers", - b"is_message_approved", - b"is_message_executed", - b"take_approved_message", - b"send_message", - b"allow_function", - b"disallow_function", - ].map!(|function_name| function_name.to_ascii_string()), - ]) -} + /// To execute a message, the relayer will call `take_approved_message` + /// to get the hot potato `ApprovedMessage` object, and then trigger the app's + /// package via discovery. + public fun take_approved_message( + self: &mut Gateway, + source_chain: String, + message_id: String, + source_address: String, + destination_id: address, + payload: vector, + ): ApprovedMessage { + let value = self.value_mut!(b"take_approved_message"); + value.take_approved_message( + source_chain, + message_id, + source_address, + destination_id, + payload, + ) + } -// --------- -// Test Only -// --------- -#[test_only] -use sui::bcs; -#[test_only] -use axelar_gateway::auth::generate_proof; -#[test_only] -use axelar_gateway::events; - -#[test_only] -public fun create_for_testing( - operator: address, - domain_separator: Bytes32, - minimum_rotation_delay: u64, - previous_signers_retention: u64, - initial_signers: weighted_signers::WeightedSigners, - clock: &Clock, - ctx: &mut TxContext, -): Gateway { - let inner = versioned::create( - VERSION, - gateway_v0::new( - operator, - table::new(ctx), - auth::setup( - domain_separator, - minimum_rotation_delay, - previous_signers_retention, - initial_signers, - clock, - ctx, + // ----------------- + // Private Functions + // ----------------- + + fun version_control(): VersionControl { + version_control::new(vector[ + vector[ + b"approve_messages", + b"rotate_signers", + b"is_message_approved", + b"is_message_executed", + b"take_approved_message", + b"send_message", + b"allow_function", + b"disallow_function", + ].map!(|function_name| function_name.to_ascii_string()), + ]) + } + + // --------- + // Test Only + // --------- + #[test_only] + use sui::bcs; + #[test_only] + use axelar_gateway::auth::generate_proof; + #[test_only] + use axelar_gateway::events; + + #[test_only] + public fun create_for_testing( + operator: address, + domain_separator: Bytes32, + minimum_rotation_delay: u64, + previous_signers_retention: u64, + initial_signers: weighted_signers::WeightedSigners, + clock: &Clock, + ctx: &mut TxContext, + ): Gateway { + let inner = versioned::create( + VERSION, + gateway_v0::new( + operator, + table::new(ctx), + auth::setup( + domain_separator, + minimum_rotation_delay, + previous_signers_retention, + initial_signers, + clock, + ctx, + ), + version_control(), ), - version_control(), - ), - ctx, - ); - Gateway { - id: object::new(ctx), - inner, + ctx, + ); + Gateway { + id: object::new(ctx), + inner, + } } -} -#[test_only] -fun dummy(ctx: &mut TxContext): Gateway { - let mut rng = sui::random::new_generator_for_testing(); - let inner = versioned::create( - VERSION, - gateway_v0::new( - sui::address::from_bytes(rng.generate_bytes(32)), - table::new(ctx), - auth::dummy(ctx), - version_control::new(vector[ - vector[ - b"approve_messages", - b"rotate_signers", - b"is_message_approved", - b"is_message_executed", - b"take_approved_message", - b"send_message", - b"allow_function", - b"disallow_function", - b"", - ].map!(|function_name| function_name.to_ascii_string()), - ]), - ), - ctx, - ); - Gateway { - id: object::new(ctx), - inner, + #[test_only] + fun dummy(ctx: &mut TxContext): Gateway { + let mut rng = sui::random::new_generator_for_testing(); + let inner = versioned::create( + VERSION, + gateway_v0::new( + sui::address::from_bytes(rng.generate_bytes(32)), + table::new(ctx), + auth::dummy(ctx), + version_control::new(vector[ + vector[ + b"approve_messages", + b"rotate_signers", + b"is_message_approved", + b"is_message_executed", + b"take_approved_message", + b"send_message", + b"allow_function", + b"disallow_function", + b"", + ].map!(|function_name| function_name.to_ascii_string()), + ]), + ), + ctx, + ); + Gateway { + id: object::new(ctx), + inner, + } } -} -#[test_only] -public fun destroy_for_testing(self: Gateway) { - let Gateway { - id, - inner, - } = self; - id.delete(); + #[test_only] + public fun destroy_for_testing(self: Gateway) { + let Gateway { + id, + inner, + } = self; + id.delete(); - let value = inner.destroy(); - let (_, messages, signers, _) = value.destroy_for_testing(); + let value = inner.destroy(); + let (_, messages, signers, _) = value.destroy_for_testing(); - let (_, table, _, _, _, _) = signers.destroy_for_testing(); - table.destroy_empty(); - messages.destroy_empty(); -} + let (_, table, _, _, _, _) = signers.destroy_for_testing(); + table.destroy_empty(); + messages.destroy_empty(); + } -// ---- -// Test -// ---- -#[test] -fun test_init() { - let mut ts = sui::test_scenario::begin(@0x0); + // ---- + // Test + // ---- + #[test] + fun test_init() { + let mut ts = sui::test_scenario::begin(@0x0); - init(ts.ctx()); - ts.next_tx(@0x0); + init(ts.ctx()); + ts.next_tx(@0x0); - let creator_cap = ts.take_from_sender(); - ts.return_to_sender(creator_cap); - ts.end(); -} + let creator_cap = ts.take_from_sender(); + ts.return_to_sender(creator_cap); + ts.end(); + } -#[test] -fun test_setup() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let operator = sui::address::from_bytes(rng.generate_bytes(32)); - let domain_separator = sui::address::from_bytes(rng.generate_bytes(32)); - let minimum_rotation_delay = rng.generate_u64(); - let previous_signers_retention = rng.generate_u64(); - let initial_signers = axelar_gateway::weighted_signers::dummy(); - let mut clock = sui::clock::create_for_testing(ctx); - let timestamp = rng.generate_u64(); - clock.increment_for_testing(timestamp); - - let owner_cap = owner_cap::create(ctx); - - let mut scenario = sui::test_scenario::begin(@0x1); - - setup( - &owner_cap, - operator, - domain_separator, - minimum_rotation_delay, - previous_signers_retention, - bcs::to_bytes(&initial_signers), - &clock, - scenario.ctx(), - ); - - let tx_effects = scenario.next_tx(@0x1); - let shared = tx_effects.shared(); - - assert!(shared.length() == 1); - - let gateway_id = shared[0]; - let gateway = scenario.take_shared_by_id(gateway_id); - let Gateway { - id, - inner, - } = gateway; - id.delete(); - - let (operator_result, messages, signers, _) = inner - .destroy() - .destroy_for_testing(); - - assert!(operator == operator_result); - messages.destroy_empty(); - - let ( - epoch, - mut epoch_by_signers_hash, - domain_separator_result, - minimum_rotation_delay_result, - last_rotation_timestamp, - previous_signers_retention_result, - ) = signers.destroy_for_testing(); - - let signer_epoch = epoch_by_signers_hash.remove(initial_signers.hash()); - epoch_by_signers_hash.destroy_empty(); - - assert!(epoch == 1); - assert!(signer_epoch == 1); - assert!(bytes32::new(domain_separator) == domain_separator_result); - assert!(minimum_rotation_delay == minimum_rotation_delay_result); - assert!(last_rotation_timestamp == timestamp); - assert!(previous_signers_retention == previous_signers_retention_result); - - clock.destroy_for_testing(); - owner_cap.destroy_for_testing(); - scenario.end(); -} + #[test] + fun test_setup() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let operator = sui::address::from_bytes(rng.generate_bytes(32)); + let domain_separator = sui::address::from_bytes(rng.generate_bytes(32)); + let minimum_rotation_delay = rng.generate_u64(); + let previous_signers_retention = rng.generate_u64(); + let initial_signers = axelar_gateway::weighted_signers::dummy(); + let mut clock = sui::clock::create_for_testing(ctx); + let timestamp = rng.generate_u64(); + clock.increment_for_testing(timestamp); + + let owner_cap = owner_cap::create(ctx); + + let mut scenario = sui::test_scenario::begin(@0x1); + + setup( + &owner_cap, + operator, + domain_separator, + minimum_rotation_delay, + previous_signers_retention, + bcs::to_bytes(&initial_signers), + &clock, + scenario.ctx(), + ); -#[test] -#[expected_failure] -fun test_setup_remaining_bytes() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let operator = sui::address::from_bytes(rng.generate_bytes(32)); - let domain_separator = sui::address::from_bytes(rng.generate_bytes(32)); - let minimum_rotation_delay = rng.generate_u64(); - let previous_signers_retention = rng.generate_u64(); - let initial_signers = axelar_gateway::weighted_signers::dummy(); - let mut clock = sui::clock::create_for_testing(ctx); - let timestamp = rng.generate_u64(); - clock.increment_for_testing(timestamp); - - let owner_cap = owner_cap::create(ctx); - - let mut scenario = sui::test_scenario::begin(@0x1); - let mut initial_signers_bytes = bcs::to_bytes(&initial_signers); - initial_signers_bytes.push_back(0); - setup( - &owner_cap, - operator, - domain_separator, - minimum_rotation_delay, - previous_signers_retention, - initial_signers_bytes, - &clock, - scenario.ctx(), - ); - - let tx_effects = scenario.next_tx(@0x1); - let shared = tx_effects.shared(); - - assert!(shared.length() == 1); - - let gateway_id = shared[0]; - let gateway = scenario.take_shared_by_id(gateway_id); - let Gateway { - id, - inner, - } = gateway; - id.delete(); - - let (operator_result, messages, signers, _) = inner - .destroy() - .destroy_for_testing(); - - assert!(operator == operator_result); - messages.destroy_empty(); - - let ( - epoch, - mut epoch_by_signers_hash, - domain_separator_result, - minimum_rotation_delay_result, - last_rotation_timestamp, - previous_signers_retention_result, - ) = signers.destroy_for_testing(); - - let signer_epoch = epoch_by_signers_hash.remove(initial_signers.hash()); - epoch_by_signers_hash.destroy_empty(); - - assert!(epoch == 1); - assert!(signer_epoch == 1); - assert!(bytes32::new(domain_separator) == domain_separator_result); - assert!(minimum_rotation_delay == minimum_rotation_delay_result); - assert!(last_rotation_timestamp == timestamp); - assert!(previous_signers_retention == previous_signers_retention_result); - - clock.destroy_for_testing(); - owner_cap.destroy_for_testing(); - scenario.end(); -} + let tx_effects = scenario.next_tx(@0x1); + let shared = tx_effects.shared(); + + assert!(shared.length() == 1); + + let gateway_id = shared[0]; + let gateway = scenario.take_shared_by_id(gateway_id); + let Gateway { + id, + inner, + } = gateway; + id.delete(); + + let (operator_result, messages, signers, _) = inner.destroy().destroy_for_testing(); + + assert!(operator == operator_result); + messages.destroy_empty(); + + let ( + epoch, + mut epoch_by_signers_hash, + domain_separator_result, + minimum_rotation_delay_result, + last_rotation_timestamp, + previous_signers_retention_result, + ) = signers.destroy_for_testing(); + + let signer_epoch = epoch_by_signers_hash.remove(initial_signers.hash()); + epoch_by_signers_hash.destroy_empty(); + + assert!(epoch == 1); + assert!(signer_epoch == 1); + assert!(bytes32::new(domain_separator) == domain_separator_result); + assert!(minimum_rotation_delay == minimum_rotation_delay_result); + assert!(last_rotation_timestamp == timestamp); + assert!(previous_signers_retention == previous_signers_retention_result); + + clock.destroy_for_testing(); + owner_cap.destroy_for_testing(); + scenario.end(); + } -#[test] -fun test_peel_weighted_signers() { - let signers = axelar_gateway::weighted_signers::dummy(); - let bytes = bcs::to_bytes(&signers); - let result = utils::peel!(bytes, |bcs| weighted_signers::peel(bcs)); + #[test] + #[expected_failure] + fun test_setup_remaining_bytes() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let operator = sui::address::from_bytes(rng.generate_bytes(32)); + let domain_separator = sui::address::from_bytes(rng.generate_bytes(32)); + let minimum_rotation_delay = rng.generate_u64(); + let previous_signers_retention = rng.generate_u64(); + let initial_signers = axelar_gateway::weighted_signers::dummy(); + let mut clock = sui::clock::create_for_testing(ctx); + let timestamp = rng.generate_u64(); + clock.increment_for_testing(timestamp); + + let owner_cap = owner_cap::create(ctx); + + let mut scenario = sui::test_scenario::begin(@0x1); + let mut initial_signers_bytes = bcs::to_bytes(&initial_signers); + initial_signers_bytes.push_back(0); + setup( + &owner_cap, + operator, + domain_separator, + minimum_rotation_delay, + previous_signers_retention, + initial_signers_bytes, + &clock, + scenario.ctx(), + ); - assert!(result == signers); -} + let tx_effects = scenario.next_tx(@0x1); + let shared = tx_effects.shared(); + + assert!(shared.length() == 1); + + let gateway_id = shared[0]; + let gateway = scenario.take_shared_by_id(gateway_id); + let Gateway { + id, + inner, + } = gateway; + id.delete(); + + let (operator_result, messages, signers, _) = inner.destroy().destroy_for_testing(); + + assert!(operator == operator_result); + messages.destroy_empty(); + + let ( + epoch, + mut epoch_by_signers_hash, + domain_separator_result, + minimum_rotation_delay_result, + last_rotation_timestamp, + previous_signers_retention_result, + ) = signers.destroy_for_testing(); + + let signer_epoch = epoch_by_signers_hash.remove(initial_signers.hash()); + epoch_by_signers_hash.destroy_empty(); + + assert!(epoch == 1); + assert!(signer_epoch == 1); + assert!(bytes32::new(domain_separator) == domain_separator_result); + assert!(minimum_rotation_delay == minimum_rotation_delay_result); + assert!(last_rotation_timestamp == timestamp); + assert!(previous_signers_retention == previous_signers_retention_result); + + clock.destroy_for_testing(); + owner_cap.destroy_for_testing(); + scenario.end(); + } -#[test] -#[expected_failure] -fun test_peel_weighted_signers_no_remaining_data() { - let signers = axelar_gateway::weighted_signers::dummy(); - let mut bytes = bcs::to_bytes(&signers); - bytes.push_back(0); + #[test] + fun test_peel_weighted_signers() { + let signers = axelar_gateway::weighted_signers::dummy(); + let bytes = bcs::to_bytes(&signers); + let result = utils::peel!(bytes, |bcs| weighted_signers::peel(bcs)); - utils::peel!(bytes, |bcs| weighted_signers::peel(bcs)); -} + assert!(result == signers); + } -#[test] -fun test_peel_proof() { - let proof = axelar_gateway::proof::dummy(); - let bytes = bcs::to_bytes(&proof); - let result = utils::peel!(bytes, |bcs| axelar_gateway::proof::peel(bcs)); + #[test] + #[expected_failure] + fun test_peel_weighted_signers_no_remaining_data() { + let signers = axelar_gateway::weighted_signers::dummy(); + let mut bytes = bcs::to_bytes(&signers); + bytes.push_back(0); - assert!(result == proof); -} + utils::peel!(bytes, |bcs| weighted_signers::peel(bcs)); + } -#[test] -#[expected_failure] -fun test_peel_proof_no_remaining_data() { - let proof = axelar_gateway::proof::dummy(); - let mut bytes = bcs::to_bytes(&proof); - bytes.push_back(0); + #[test] + fun test_peel_proof() { + let proof = axelar_gateway::proof::dummy(); + let bytes = bcs::to_bytes(&proof); + let result = utils::peel!(bytes, |bcs| axelar_gateway::proof::peel(bcs)); - utils::peel!(bytes, |bcs| axelar_gateway::proof::peel(bcs)); -} + assert!(result == proof); + } + + #[test] + #[expected_failure] + fun test_peel_proof_no_remaining_data() { + let proof = axelar_gateway::proof::dummy(); + let mut bytes = bcs::to_bytes(&proof); + bytes.push_back(0); -#[test] -fun test_take_approved_message() { - let mut rng = sui::random::new_generator_for_testing(); - let mut gateway = dummy(&mut sui::tx_context::dummy()); - let source_chain = std::ascii::string(b"Source Chain"); - let message_id = std::ascii::string(b"Message Id"); - let source_address = std::ascii::string(b"Source Address"); - let destination_id = sui::address::from_bytes(rng.generate_bytes(32)); - let payload = rng.generate_bytes(32); - let payload_hash = axelar_gateway::bytes32::new( - sui::address::from_bytes(sui::hash::keccak256(&payload)), - ); - let message = axelar_gateway::message::new( - source_chain, - message_id, - source_address, - destination_id, - payload_hash, - ); - - gateway - .value_mut!(b"") - .messages_mut() - .add( - message.command_id(), - axelar_gateway::message_status::approved(message.hash()), + utils::peel!(bytes, |bcs| axelar_gateway::proof::peel(bcs)); + } + + #[test] + fun test_take_approved_message() { + let mut rng = sui::random::new_generator_for_testing(); + let mut gateway = dummy(&mut sui::tx_context::dummy()); + let source_chain = std::ascii::string(b"Source Chain"); + let message_id = std::ascii::string(b"Message Id"); + let source_address = std::ascii::string(b"Source Address"); + let destination_id = sui::address::from_bytes(rng.generate_bytes(32)); + let payload = rng.generate_bytes(32); + let payload_hash = axelar_gateway::bytes32::new( + sui::address::from_bytes(sui::hash::keccak256(&payload)), + ); + let message = axelar_gateway::message::new( + source_chain, + message_id, + source_address, + destination_id, + payload_hash, ); - let approved_message = gateway.take_approved_message( - source_chain, - message_id, - source_address, - destination_id, - payload, - ); - - utils::assert_event(); - - let expected_approved_message = axelar_gateway::channel::create_approved_message( - source_chain, - message_id, - source_address, - destination_id, - payload, - ); - assert!(&approved_message == &expected_approved_message); - - gateway.value_mut!(b"").messages_mut().remove(message.command_id()); - - approved_message.destroy_for_testing(); - expected_approved_message.destroy_for_testing(); - gateway.destroy_for_testing(); -} + gateway + .value_mut!(b"") + .messages_mut() + .add( + message.command_id(), + axelar_gateway::message_status::approved(message.hash()), + ); -#[test] -fun test_approve_messages() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( - &rng.generate_bytes(32), - ); - let weighted_signers = weighted_signers::create_for_testing( - vector[ - axelar_gateway::weighted_signer::new( - *keypair.public_key(), - 1, - ), - ], - 1, - bytes32::from_bytes(rng.generate_bytes(32)), - ); - let operator = sui::address::from_bytes(rng.generate_bytes(32)); - let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); - let minimum_rotation_delay = rng.generate_u64(); - let previous_signers_retention = rng.generate_u64(); - let initial_signers = weighted_signers; - let clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing( - operator, - domain_separator, - minimum_rotation_delay, - previous_signers_retention, - initial_signers, - &clock, - ctx, - ); - let messages = vector[ - axelar_gateway::message::dummy(), - ]; - let data_hash = gateway_v0::approve_messages_data_hash(messages); - let proof = generate_proof( - data_hash, - domain_separator, - weighted_signers, - &vector[keypair], - ); - - self.approve_messages(bcs::to_bytes(&messages), bcs::to_bytes(&proof)); - - utils::assert_event(); - - clock.destroy_for_testing(); - sui::test_utils::destroy(self) -} + let approved_message = gateway.take_approved_message( + source_chain, + message_id, + source_address, + destination_id, + payload, + ); -#[test] -#[expected_failure] -fun test_approve_messages_remaining_data() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( - &rng.generate_bytes(32), - ); - let weighted_signers = weighted_signers::create_for_testing( - vector[ - axelar_gateway::weighted_signer::new( - *keypair.public_key(), - 1, - ), - ], - 1, - bytes32::from_bytes(rng.generate_bytes(32)), - ); - let operator = sui::address::from_bytes(rng.generate_bytes(32)); - let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); - let minimum_rotation_delay = rng.generate_u64(); - let previous_signers_retention = rng.generate_u64(); - let initial_signers = weighted_signers; - let clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing( - operator, - domain_separator, - minimum_rotation_delay, - previous_signers_retention, - initial_signers, - &clock, - ctx, - ); - let messages = vector[axelar_gateway::message::dummy()]; - let data_hash = gateway_v0::approve_messages_data_hash(messages); - let proof = generate_proof( - data_hash, - domain_separator, - weighted_signers, - &vector[keypair], - ); - let mut proof_data = bcs::to_bytes(&proof); - proof_data.push_back(0); - - self.approve_messages(bcs::to_bytes(&messages), proof_data); - - clock.destroy_for_testing(); - sui::test_utils::destroy(self) -} + utils::assert_event(); -#[test] -fun test_rotate_signers() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( - &rng.generate_bytes(32), - ); - let weighted_signers = weighted_signers::create_for_testing( - vector[ - axelar_gateway::weighted_signer::new( - *keypair.public_key(), - 1, - ), - ], - 1, - bytes32::from_bytes(rng.generate_bytes(32)), - ); - let next_weighted_signers = weighted_signers::create_for_testing( - vector[ - axelar_gateway::weighted_signer::new( - *sui::ecdsa_k1::secp256k1_keypair_from_seed( - &rng.generate_bytes(32), - ).public_key(), - 1, - ), - ], - 1, - bytes32::from_bytes(rng.generate_bytes(32)), - ); - - let operator = sui::address::from_bytes(rng.generate_bytes(32)); - let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); - let minimum_rotation_delay = rng.generate_u64(); - let previous_signers_retention = rng.generate_u64(); - let initial_signers = weighted_signers; - let mut clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing( - operator, - domain_separator, - minimum_rotation_delay, - previous_signers_retention, - initial_signers, - &clock, - ctx, - ); - - utils::assert_event(); - - let data_hash = gateway_v0::rotate_signers_data_hash(next_weighted_signers); - let proof = generate_proof( - data_hash, - domain_separator, - weighted_signers, - &vector[keypair], - ); - - clock.increment_for_testing(minimum_rotation_delay); - self.rotate_signers( - &clock, - bcs::to_bytes(&next_weighted_signers), - bcs::to_bytes(&proof), - ctx, - ); - - utils::assert_events(2); - - clock.destroy_for_testing(); - sui::test_utils::destroy(self); -} + let expected_approved_message = axelar_gateway::channel::create_approved_message( + source_chain, + message_id, + source_address, + destination_id, + payload, + ); + assert!(&approved_message == &expected_approved_message); -#[test] -#[expected_failure] -fun test_rotate_signers_remaining_data_message_data() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( - &rng.generate_bytes(32), - ); - let weighted_signers = weighted_signers::create_for_testing( - vector[ - axelar_gateway::weighted_signer::new( - *keypair.public_key(), - 1, - ), - ], - 1, - bytes32::from_bytes(rng.generate_bytes(32)), - ); - let next_weighted_signers = weighted_signers::create_for_testing( - vector[ - axelar_gateway::weighted_signer::new( - *sui::ecdsa_k1::secp256k1_keypair_from_seed( - &rng.generate_bytes(32), - ).public_key(), - 1, - ), - ], - 1, - bytes32::from_bytes(rng.generate_bytes(32)), - ); - - let operator = sui::address::from_bytes(rng.generate_bytes(32)); - let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); - let minimum_rotation_delay = rng.generate_u64(); - let previous_signers_retention = rng.generate_u64(); - let initial_signers = weighted_signers; - let mut clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing( - operator, - domain_separator, - minimum_rotation_delay, - previous_signers_retention, - initial_signers, - &clock, - ctx, - ); - - let mut message_data = bcs::to_bytes(&next_weighted_signers); - message_data.push_back(0); - - let data_hash = gateway_v0::rotate_signers_data_hash(next_weighted_signers); - let proof = generate_proof( - data_hash, - domain_separator, - weighted_signers, - &vector[keypair], - ); - - clock.increment_for_testing(minimum_rotation_delay); - self.rotate_signers(&clock, message_data, bcs::to_bytes(&proof), ctx); - - clock.destroy_for_testing(); - sui::test_utils::destroy(self); -} + gateway.value_mut!(b"").messages_mut().remove(message.command_id()); -#[test] -#[expected_failure] -fun test_rotate_signers_remaining_data_proof_data() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( - &rng.generate_bytes(32), - ); - let weighted_signers = weighted_signers::create_for_testing( - vector[ - axelar_gateway::weighted_signer::new( - *keypair.public_key(), - 1, - ), - ], - 1, - bytes32::from_bytes(rng.generate_bytes(32)), - ); - let next_weighted_signers = weighted_signers::create_for_testing( - vector[ - axelar_gateway::weighted_signer::new( - *sui::ecdsa_k1::secp256k1_keypair_from_seed( - &rng.generate_bytes(32), - ).public_key(), - 1, - ), - ], - 1, - bytes32::from_bytes(rng.generate_bytes(32)), - ); - - let operator = sui::address::from_bytes(rng.generate_bytes(32)); - let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); - let minimum_rotation_delay = rng.generate_u64(); - let previous_signers_retention = rng.generate_u64(); - let initial_signers = weighted_signers; - let mut clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing( - operator, - domain_separator, - minimum_rotation_delay, - previous_signers_retention, - initial_signers, - &clock, - ctx, - ); - - let data_hash = gateway_v0::rotate_signers_data_hash(next_weighted_signers); - let proof = generate_proof( - data_hash, - domain_separator, - weighted_signers, - &vector[keypair], - ); - let mut proof_data = bcs::to_bytes(&proof); - proof_data.push_back(0); - - clock.increment_for_testing(minimum_rotation_delay); - self.rotate_signers( - &clock, - bcs::to_bytes(&next_weighted_signers), - proof_data, - ctx, - ); - - clock.destroy_for_testing(); - sui::test_utils::destroy(self); -} + approved_message.destroy_for_testing(); + expected_approved_message.destroy_for_testing(); + gateway.destroy_for_testing(); + } -#[test] -#[expected_failure(abort_code = axelar_gateway::gateway_v0::ENotLatestSigners)] -fun test_rotate_signers_not_latest_signers() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( - &rng.generate_bytes(32), - ); - let weighted_signers = weighted_signers::create_for_testing( - vector[ - axelar_gateway::weighted_signer::new( - *keypair.public_key(), - 1, - ), - ], - 1, - bytes32::from_bytes(rng.generate_bytes(32)), - ); - let next_weighted_signers = weighted_signers::create_for_testing( - vector[ - axelar_gateway::weighted_signer::new( - *sui::ecdsa_k1::secp256k1_keypair_from_seed( - &rng.generate_bytes(32), - ).public_key(), - 1, - ), - ], - 1, - bytes32::from_bytes(rng.generate_bytes(32)), - ); - - let operator = sui::address::from_bytes(rng.generate_bytes(32)); - let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); - let minimum_rotation_delay = rng.generate_u64(); - let previous_signers_retention = rng.generate_u64(); - let initial_signers = weighted_signers; - let mut clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing( - operator, - domain_separator, - minimum_rotation_delay, - previous_signers_retention, - initial_signers, - &clock, - ctx, - ); - // Tell the gateway this is not the latest epoch - let epoch = self.value_mut!(b"rotate_signers").signers_mut().epoch_mut(); - *epoch = *epoch + 1; - - let data_hash = gateway_v0::rotate_signers_data_hash(next_weighted_signers); - let proof = generate_proof( - data_hash, - domain_separator, - weighted_signers, - &vector[keypair], - ); - - clock.increment_for_testing(minimum_rotation_delay); - self.rotate_signers( - &clock, - bcs::to_bytes(&next_weighted_signers), - bcs::to_bytes(&proof), - ctx, - ); - - clock.destroy_for_testing(); - sui::test_utils::destroy(self); -} + #[test] + fun test_approve_messages() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( + &rng.generate_bytes(32), + ); + let weighted_signers = weighted_signers::create_for_testing( + vector[ + axelar_gateway::weighted_signer::new( + *keypair.public_key(), + 1, + ), + ], + 1, + bytes32::from_bytes(rng.generate_bytes(32)), + ); + let operator = sui::address::from_bytes(rng.generate_bytes(32)); + let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); + let minimum_rotation_delay = rng.generate_u64(); + let previous_signers_retention = rng.generate_u64(); + let initial_signers = weighted_signers; + let clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing( + operator, + domain_separator, + minimum_rotation_delay, + previous_signers_retention, + initial_signers, + &clock, + ctx, + ); + let messages = vector[axelar_gateway::message::dummy()]; + let data_hash = gateway_v0::approve_messages_data_hash(messages); + let proof = generate_proof( + data_hash, + domain_separator, + weighted_signers, + &vector[keypair], + ); + + self.approve_messages(bcs::to_bytes(&messages), bcs::to_bytes(&proof)); + + utils::assert_event(); + + clock.destroy_for_testing(); + sui::test_utils::destroy(self) + } + + #[test] + #[expected_failure] + fun test_approve_messages_remaining_data() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( + &rng.generate_bytes(32), + ); + let weighted_signers = weighted_signers::create_for_testing( + vector[ + axelar_gateway::weighted_signer::new( + *keypair.public_key(), + 1, + ), + ], + 1, + bytes32::from_bytes(rng.generate_bytes(32)), + ); + let operator = sui::address::from_bytes(rng.generate_bytes(32)); + let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); + let minimum_rotation_delay = rng.generate_u64(); + let previous_signers_retention = rng.generate_u64(); + let initial_signers = weighted_signers; + let clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing( + operator, + domain_separator, + minimum_rotation_delay, + previous_signers_retention, + initial_signers, + &clock, + ctx, + ); + let messages = vector[axelar_gateway::message::dummy()]; + let data_hash = gateway_v0::approve_messages_data_hash(messages); + let proof = generate_proof( + data_hash, + domain_separator, + weighted_signers, + &vector[keypair], + ); + let mut proof_data = bcs::to_bytes(&proof); + proof_data.push_back(0); + + self.approve_messages(bcs::to_bytes(&messages), proof_data); + + clock.destroy_for_testing(); + sui::test_utils::destroy(self) + } + + #[test] + fun test_rotate_signers() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( + &rng.generate_bytes(32), + ); + let weighted_signers = weighted_signers::create_for_testing( + vector[ + axelar_gateway::weighted_signer::new( + *keypair.public_key(), + 1, + ), + ], + 1, + bytes32::from_bytes(rng.generate_bytes(32)), + ); + let next_weighted_signers = weighted_signers::create_for_testing( + vector[ + axelar_gateway::weighted_signer::new( + *sui::ecdsa_k1::secp256k1_keypair_from_seed( + &rng.generate_bytes(32), + ).public_key(), + 1, + ), + ], + 1, + bytes32::from_bytes(rng.generate_bytes(32)), + ); + + let operator = sui::address::from_bytes(rng.generate_bytes(32)); + let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); + let minimum_rotation_delay = rng.generate_u64(); + let previous_signers_retention = rng.generate_u64(); + let initial_signers = weighted_signers; + let mut clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing( + operator, + domain_separator, + minimum_rotation_delay, + previous_signers_retention, + initial_signers, + &clock, + ctx, + ); + + utils::assert_event(); + + let data_hash = gateway_v0::rotate_signers_data_hash(next_weighted_signers); + let proof = generate_proof( + data_hash, + domain_separator, + weighted_signers, + &vector[keypair], + ); + + clock.increment_for_testing(minimum_rotation_delay); + self.rotate_signers( + &clock, + bcs::to_bytes(&next_weighted_signers), + bcs::to_bytes(&proof), + ctx, + ); + + utils::assert_events(2); -#[test] -fun test_is_message_approved() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - - let source_chain = ascii::string(b"Source Chain"); - let source_address = ascii::string(b"Source Address"); - let message_id = ascii::string(b"Message Id"); - let destination_id = sui::address::from_bytes(rng.generate_bytes(32)); - let payload_hash = bytes32::from_bytes(rng.generate_bytes(32)); - let message = axelar_gateway::message::new( - source_chain, - message_id, - source_address, - destination_id, - payload_hash, - ); - - let mut gateway = dummy(ctx); - gateway.value_mut!(b"").approve_message_for_testing(message); - assert!( - gateway.is_message_approved( + clock.destroy_for_testing(); + sui::test_utils::destroy(self); + } + + #[test] + #[expected_failure] + fun test_rotate_signers_remaining_data_message_data() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( + &rng.generate_bytes(32), + ); + let weighted_signers = weighted_signers::create_for_testing( + vector[ + axelar_gateway::weighted_signer::new( + *keypair.public_key(), + 1, + ), + ], + 1, + bytes32::from_bytes(rng.generate_bytes(32)), + ); + let next_weighted_signers = weighted_signers::create_for_testing( + vector[ + axelar_gateway::weighted_signer::new( + *sui::ecdsa_k1::secp256k1_keypair_from_seed( + &rng.generate_bytes(32), + ).public_key(), + 1, + ), + ], + 1, + bytes32::from_bytes(rng.generate_bytes(32)), + ); + + let operator = sui::address::from_bytes(rng.generate_bytes(32)); + let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); + let minimum_rotation_delay = rng.generate_u64(); + let previous_signers_retention = rng.generate_u64(); + let initial_signers = weighted_signers; + let mut clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing( + operator, + domain_separator, + minimum_rotation_delay, + previous_signers_retention, + initial_signers, + &clock, + ctx, + ); + + let mut message_data = bcs::to_bytes(&next_weighted_signers); + message_data.push_back(0); + + let data_hash = gateway_v0::rotate_signers_data_hash(next_weighted_signers); + let proof = generate_proof( + data_hash, + domain_separator, + weighted_signers, + &vector[keypair], + ); + + clock.increment_for_testing(minimum_rotation_delay); + self.rotate_signers(&clock, message_data, bcs::to_bytes(&proof), ctx); + + clock.destroy_for_testing(); + sui::test_utils::destroy(self); + } + + #[test] + #[expected_failure] + fun test_rotate_signers_remaining_data_proof_data() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( + &rng.generate_bytes(32), + ); + let weighted_signers = weighted_signers::create_for_testing( + vector[ + axelar_gateway::weighted_signer::new( + *keypair.public_key(), + 1, + ), + ], + 1, + bytes32::from_bytes(rng.generate_bytes(32)), + ); + let next_weighted_signers = weighted_signers::create_for_testing( + vector[ + axelar_gateway::weighted_signer::new( + *sui::ecdsa_k1::secp256k1_keypair_from_seed( + &rng.generate_bytes(32), + ).public_key(), + 1, + ), + ], + 1, + bytes32::from_bytes(rng.generate_bytes(32)), + ); + + let operator = sui::address::from_bytes(rng.generate_bytes(32)); + let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); + let minimum_rotation_delay = rng.generate_u64(); + let previous_signers_retention = rng.generate_u64(); + let initial_signers = weighted_signers; + let mut clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing( + operator, + domain_separator, + minimum_rotation_delay, + previous_signers_retention, + initial_signers, + &clock, + ctx, + ); + + let data_hash = gateway_v0::rotate_signers_data_hash(next_weighted_signers); + let proof = generate_proof( + data_hash, + domain_separator, + weighted_signers, + &vector[keypair], + ); + let mut proof_data = bcs::to_bytes(&proof); + proof_data.push_back(0); + + clock.increment_for_testing(minimum_rotation_delay); + self.rotate_signers( + &clock, + bcs::to_bytes(&next_weighted_signers), + proof_data, + ctx, + ); + + clock.destroy_for_testing(); + sui::test_utils::destroy(self); + } + + #[test] + #[expected_failure(abort_code = axelar_gateway::gateway_v0::ENotLatestSigners)] + fun test_rotate_signers_not_latest_signers() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let keypair = sui::ecdsa_k1::secp256k1_keypair_from_seed( + &rng.generate_bytes(32), + ); + let weighted_signers = weighted_signers::create_for_testing( + vector[ + axelar_gateway::weighted_signer::new( + *keypair.public_key(), + 1, + ), + ], + 1, + bytes32::from_bytes(rng.generate_bytes(32)), + ); + let next_weighted_signers = weighted_signers::create_for_testing( + vector[ + axelar_gateway::weighted_signer::new( + *sui::ecdsa_k1::secp256k1_keypair_from_seed( + &rng.generate_bytes(32), + ).public_key(), + 1, + ), + ], + 1, + bytes32::from_bytes(rng.generate_bytes(32)), + ); + + let operator = sui::address::from_bytes(rng.generate_bytes(32)); + let domain_separator = bytes32::from_bytes(rng.generate_bytes(32)); + let minimum_rotation_delay = rng.generate_u64(); + let previous_signers_retention = rng.generate_u64(); + let initial_signers = weighted_signers; + let mut clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing( + operator, + domain_separator, + minimum_rotation_delay, + previous_signers_retention, + initial_signers, + &clock, + ctx, + ); + // Tell the gateway this is not the latest epoch + let epoch = self.value_mut!(b"rotate_signers").signers_mut().epoch_mut(); + *epoch = *epoch + 1; + + let data_hash = gateway_v0::rotate_signers_data_hash(next_weighted_signers); + let proof = generate_proof( + data_hash, + domain_separator, + weighted_signers, + &vector[keypair], + ); + + clock.increment_for_testing(minimum_rotation_delay); + self.rotate_signers( + &clock, + bcs::to_bytes(&next_weighted_signers), + bcs::to_bytes(&proof), + ctx, + ); + + clock.destroy_for_testing(); + sui::test_utils::destroy(self); + } + + #[test] + fun test_is_message_approved() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + + let source_chain = ascii::string(b"Source Chain"); + let source_address = ascii::string(b"Source Address"); + let message_id = ascii::string(b"Message Id"); + let destination_id = sui::address::from_bytes(rng.generate_bytes(32)); + let payload_hash = bytes32::from_bytes(rng.generate_bytes(32)); + let message = axelar_gateway::message::new( source_chain, message_id, source_address, destination_id, payload_hash, - ), - ); - assert!( - !gateway.is_message_executed( - source_chain, - message_id, - ), - ); + ); - sui::test_utils::destroy(gateway); -} + let mut gateway = dummy(ctx); + gateway.value_mut!(b"").approve_message_for_testing(message); + assert!( + gateway.is_message_approved( + source_chain, + message_id, + source_address, + destination_id, + payload_hash, + ), + ); + assert!( + !gateway.is_message_executed( + source_chain, + message_id, + ), + ); -#[test] -fun test_send_message() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - let channel = axelar_gateway::channel::new(ctx); - let destination_chain = ascii::string(b"Destination Chain"); - let destination_address = ascii::string(b"Destination Address"); - let payload = rng.generate_bytes(32); - let message_ticket = prepare_message( - &channel, - destination_chain, - destination_address, - payload, - ); - - let gateway = dummy(ctx); - gateway.send_message(message_ticket); - - utils::assert_event(); - - sui::test_utils::destroy(gateway); - channel.destroy(); -} + sui::test_utils::destroy(gateway); + } -#[test] -fun test_allow_function() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = dummy(ctx); - let owner_cap = owner_cap::create(ctx); - let version = 0; - let function_name = b"function_name".to_ascii_string(); + #[test] + fun test_send_message() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + let channel = axelar_gateway::channel::new(ctx); + let destination_chain = ascii::string(b"Destination Chain"); + let destination_address = ascii::string(b"Destination Address"); + let payload = rng.generate_bytes(32); + let message_ticket = prepare_message( + &channel, + destination_chain, + destination_address, + payload, + ); - self.allow_function(&owner_cap, version, function_name); + let gateway = dummy(ctx); + gateway.send_message(message_ticket); - sui::test_utils::destroy(self); - owner_cap.destroy_for_testing(); -} + utils::assert_event(); + + sui::test_utils::destroy(gateway); + channel.destroy(); + } + + #[test] + fun test_allow_function() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = dummy(ctx); + let owner_cap = owner_cap::create(ctx); + let version = 0; + let function_name = b"function_name".to_ascii_string(); + + self.allow_function(&owner_cap, version, function_name); -#[test] -fun test_disallow_function() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = dummy(ctx); - let owner_cap = owner_cap::create(ctx); - let version = 0; - let function_name = b"approve_messages".to_ascii_string(); + sui::test_utils::destroy(self); + owner_cap.destroy_for_testing(); + } + + #[test] + fun test_disallow_function() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = dummy(ctx); + let owner_cap = owner_cap::create(ctx); + let version = 0; + let function_name = b"approve_messages".to_ascii_string(); - self.disallow_function(&owner_cap, version, function_name); + self.disallow_function(&owner_cap, version, function_name); - sui::test_utils::destroy(self); - owner_cap.destroy_for_testing(); + sui::test_utils::destroy(self); + owner_cap.destroy_for_testing(); + } } diff --git a/move/axelar_gateway/sources/types/bytes32.move b/move/axelar_gateway/sources/types/bytes32.move index 704175f0..a0be8d00 100644 --- a/move/axelar_gateway/sources/types/bytes32.move +++ b/move/axelar_gateway/sources/types/bytes32.move @@ -1,80 +1,79 @@ -module axelar_gateway::bytes32; - -use sui::address; -use sui::bcs::BCS; - -// ----- -// Types -// ----- - -public struct Bytes32 has copy, drop, store { - bytes: address, -} - -// --------- -// Constants -// --------- - -const LENGTH: u64 = 32; - -// ---------------- -// Public Functions -// ---------------- - -/// Casts an address to a bytes32 -public fun new(bytes: address): Bytes32 { - Bytes32 { bytes: bytes } -} - -public fun default(): Bytes32 { - Bytes32 { bytes: @0x0 } -} - -public fun from_bytes(bytes: vector): Bytes32 { - new(address::from_bytes(bytes)) -} - -public fun from_address(addr: address): Bytes32 { - new(addr) -} - -public fun to_bytes(self: Bytes32): vector { - self.bytes.to_bytes() -} - -public fun length(_self: &Bytes32): u64 { - LENGTH -} - -public(package) fun peel(bcs: &mut BCS): Bytes32 { - new(bcs.peel_address()) -} - -// ----- -// Tests -// ----- - -#[test] -public fun test_new() { - let addr = address::from_u256(sui::random::new_generator_for_testing().generate_u256()); - let actual = new(addr); - - assert!(actual.to_bytes() == addr.to_bytes()); - assert!(actual.length() == LENGTH); -} - -#[test] -public fun test_default() { - let default = default(); - - assert!(default.bytes == @0x0); - assert!(default.length() == LENGTH); -} - -#[test] -public fun test_from_address() { - let addr = address::from_u256(sui::random::new_generator_for_testing().generate_u256()); - let bytes32 = from_address(addr); - assert!(bytes32.bytes == addr); - assert!(bytes32.length() == LENGTH); +module axelar_gateway::bytes32 { + use sui::{address, bcs::BCS}; + + // ----- + // Types + // ----- + + public struct Bytes32 has copy, drop, store { + bytes: address, + } + + // --------- + // Constants + // --------- + + const LENGTH: u64 = 32; + + // ---------------- + // Public Functions + // ---------------- + + /// Casts an address to a bytes32 + public fun new(bytes: address): Bytes32 { + Bytes32 { bytes: bytes } + } + + public fun default(): Bytes32 { + Bytes32 { bytes: @0x0 } + } + + public fun from_bytes(bytes: vector): Bytes32 { + new(address::from_bytes(bytes)) + } + + public fun from_address(addr: address): Bytes32 { + new(addr) + } + + public fun to_bytes(self: Bytes32): vector { + self.bytes.to_bytes() + } + + public fun length(_self: &Bytes32): u64 { + LENGTH + } + + public(package) fun peel(bcs: &mut BCS): Bytes32 { + new(bcs.peel_address()) + } + + // ----- + // Tests + // ----- + + #[test] + public fun test_new() { + let addr = address::from_u256(sui::random::new_generator_for_testing().generate_u256()); + let actual = new(addr); + + assert!(actual.to_bytes() == addr.to_bytes()); + assert!(actual.length() == LENGTH); + } + + #[test] + public fun test_default() { + let default = default(); + + assert!(default.bytes == @0x0); + assert!(default.length() == LENGTH); + } + + #[test] + public fun test_from_address() { + let addr = address::from_u256(sui::random::new_generator_for_testing().generate_u256()); + let bytes32 = from_address(addr); + assert!(bytes32.bytes == addr); + assert!(bytes32.length() == LENGTH); + } } diff --git a/move/axelar_gateway/sources/types/message.move b/move/axelar_gateway/sources/types/message.move index e89416cd..e84b407f 100644 --- a/move/axelar_gateway/sources/types/message.move +++ b/move/axelar_gateway/sources/types/message.move @@ -1,92 +1,88 @@ -module axelar_gateway::message; +module axelar_gateway::message { + use axelar_gateway::bytes32::{Self, Bytes32}; + use std::ascii::String; + use sui::{bcs::{Self, BCS}, hash}; -use axelar_gateway::bytes32::{Self, Bytes32}; -use std::ascii::String; -use sui::bcs::{Self, BCS}; -use sui::hash; - -/// ----- -/// Types -/// ----- -/// Cross chain message type -public struct Message has copy, drop, store { - source_chain: String, - message_id: String, - source_address: String, - destination_id: address, - payload_hash: Bytes32, -} + /// ----- + /// Types + /// ----- + /// Cross chain message type + public struct Message has copy, drop, store { + source_chain: String, + message_id: String, + source_address: String, + destination_id: address, + payload_hash: Bytes32, + } -/// ----------------- -/// Package Functions -/// ----------------- -public(package) fun new( - source_chain: String, - message_id: String, - source_address: String, - destination_id: address, - payload_hash: Bytes32, -): Message { - Message { - source_chain, - message_id, - source_address, - destination_id, - payload_hash, + /// ----------------- + /// Package Functions + /// ----------------- + public(package) fun new( + source_chain: String, + message_id: String, + source_address: String, + destination_id: address, + payload_hash: Bytes32, + ): Message { + Message { + source_chain, + message_id, + source_address, + destination_id, + payload_hash, + } } -} -public(package) fun peel(bcs: &mut BCS): Message { - // TODO: allow UTF-8 strings? Or keep it as more generic bytes? - let source_chain = bcs.peel_vec_u8().to_ascii_string(); - let message_id = bcs.peel_vec_u8().to_ascii_string(); - let source_address = bcs.peel_vec_u8().to_ascii_string(); - let destination_id = bcs.peel_address(); - let payload_hash = bytes32::peel(bcs); + public(package) fun peel(bcs: &mut BCS): Message { + // TODO: allow UTF-8 strings? Or keep it as more generic bytes? + let source_chain = bcs.peel_vec_u8().to_ascii_string(); + let message_id = bcs.peel_vec_u8().to_ascii_string(); + let source_address = bcs.peel_vec_u8().to_ascii_string(); + let destination_id = bcs.peel_address(); + let payload_hash = bytes32::peel(bcs); - Message { - source_chain, - message_id, - source_address, - destination_id, - payload_hash, + Message { + source_chain, + message_id, + source_address, + destination_id, + payload_hash, + } } -} -public(package) fun message_to_command_id( - source_chain: String, - message_id: String, -): Bytes32 { - let mut id = source_chain.into_bytes(); - id.append(b"_"); - id.append(message_id.into_bytes()); + public(package) fun message_to_command_id(source_chain: String, message_id: String): Bytes32 { + let mut id = source_chain.into_bytes(); + id.append(b"_"); + id.append(message_id.into_bytes()); - bytes32::from_bytes(hash::keccak256(&id)) -} + bytes32::from_bytes(hash::keccak256(&id)) + } -public(package) fun command_id(self: &Message): Bytes32 { - message_to_command_id(self.source_chain, self.message_id) -} + public(package) fun command_id(self: &Message): Bytes32 { + message_to_command_id(self.source_chain, self.message_id) + } -public(package) fun hash(self: &Message): Bytes32 { - bytes32::from_bytes(hash::keccak256(&bcs::to_bytes(self))) -} + public(package) fun hash(self: &Message): Bytes32 { + bytes32::from_bytes(hash::keccak256(&bcs::to_bytes(self))) + } -// --------- -// Test Only -// --------- -#[test_only] -public(package) fun dummy(): Message { - let source_chain = std::ascii::string(b"Source Chain"); - let source_address = std::ascii::string(b"Source Address"); - let message_id = std::ascii::string(b"Message Id"); - let destination_id = @0x4; - let payload_hash = bytes32::new(@0x5); - Message { - source_chain, - message_id, - source_address, - destination_id, - payload_hash, + // --------- + // Test Only + // --------- + #[test_only] + public(package) fun dummy(): Message { + let source_chain = std::ascii::string(b"Source Chain"); + let source_address = std::ascii::string(b"Source Address"); + let message_id = std::ascii::string(b"Message Id"); + let destination_id = @0x4; + let payload_hash = bytes32::new(@0x5); + Message { + source_chain, + message_id, + source_address, + destination_id, + payload_hash, + } } } diff --git a/move/axelar_gateway/sources/types/message_status.move b/move/axelar_gateway/sources/types/message_status.move index 796153f7..5024fe32 100644 --- a/move/axelar_gateway/sources/types/message_status.move +++ b/move/axelar_gateway/sources/types/message_status.move @@ -1,26 +1,26 @@ -module axelar_gateway::message_status; +module axelar_gateway::message_status { + use axelar_gateway::bytes32::Bytes32; -use axelar_gateway::bytes32::Bytes32; + // ----- + // Types + // ----- + /// The Status of the message. + /// Can be either one of two statuses: + /// - Approved: Set to the hash of the message + /// - Executed: Message was already executed + public enum MessageStatus has copy, drop, store { + Approved(Bytes32), + Executed, + } -// ----- -// Types -// ----- -/// The Status of the message. -/// Can be either one of two statuses: -/// - Approved: Set to the hash of the message -/// - Executed: Message was already executed -public enum MessageStatus has copy, drop, store { - Approved(Bytes32), - Executed, -} - -// ----------------- -// Package Functions -// ----------------- -public(package) fun approved(hash: Bytes32): MessageStatus { - MessageStatus::Approved(hash) -} + // ----------------- + // Package Functions + // ----------------- + public(package) fun approved(hash: Bytes32): MessageStatus { + MessageStatus::Approved(hash) + } -public(package) fun executed(): MessageStatus { - MessageStatus::Executed + public(package) fun executed(): MessageStatus { + MessageStatus::Executed + } } diff --git a/move/axelar_gateway/sources/types/message_ticket.move b/move/axelar_gateway/sources/types/message_ticket.move index 176bf43f..8318cc98 100644 --- a/move/axelar_gateway/sources/types/message_ticket.move +++ b/move/axelar_gateway/sources/types/message_ticket.move @@ -1,135 +1,133 @@ -module axelar_gateway::message_ticket; +module axelar_gateway::message_ticket { + use std::ascii::String; -use std::ascii::String; - -// ----- -// Types -// ----- -/// This hot potato object is created to capture all the information about a -/// remote contract call. -/// In can then be submitted to the gateway to send the Message. -/// It is advised that modules return this Message ticket to be submitted by the -/// frontend, so that when the gateway package is upgraded, the app doesn't need -/// to upgrade as well, ensuring forward compatibility. -/// The version is captured to ensure that future packages can restrict which -/// messages they can send, and to ensure that no future messages are sent from -/// earlier versions. -public struct MessageTicket { - source_id: address, - destination_chain: String, - destination_address: String, - payload: vector, - version: u64, -} + // ----- + // Types + // ----- + /// This hot potato object is created to capture all the information about a + /// remote contract call. + /// In can then be submitted to the gateway to send the Message. + /// It is advised that modules return this Message ticket to be submitted by the + /// frontend, so that when the gateway package is upgraded, the app doesn't need + /// to upgrade as well, ensuring forward compatibility. + /// The version is captured to ensure that future packages can restrict which + /// messages they can send, and to ensure that no future messages are sent from + /// earlier versions. + public struct MessageTicket { + source_id: address, + destination_chain: String, + destination_address: String, + payload: vector, + version: u64, + } -// ------- -// Getters -// ------- -public fun source_id(self: &MessageTicket): address { - self.source_id -} + // ------- + // Getters + // ------- + public fun source_id(self: &MessageTicket): address { + self.source_id + } -public fun destination_chain(self: &MessageTicket): String { - self.destination_chain -} + public fun destination_chain(self: &MessageTicket): String { + self.destination_chain + } -public fun destination_address(self: &MessageTicket): String { - self.destination_address -} + public fun destination_address(self: &MessageTicket): String { + self.destination_address + } -public fun payload(self: &MessageTicket): vector { - self.payload -} + public fun payload(self: &MessageTicket): vector { + self.payload + } -public fun version(self: &MessageTicket): u64 { - self.version -} + public fun version(self: &MessageTicket): u64 { + self.version + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun new( - source_id: address, - destination_chain: String, - destination_address: String, - payload: vector, - version: u64, -): MessageTicket { - MessageTicket { - source_id, - destination_chain, - destination_address, - payload, - version, + // ----------------- + // Package Functions + // ----------------- + public(package) fun new( + source_id: address, + destination_chain: String, + destination_address: String, + payload: vector, + version: u64, + ): MessageTicket { + MessageTicket { + source_id, + destination_chain, + destination_address, + payload, + version, + } } -} -public(package) fun destroy( - self: MessageTicket, -): (address, String, String, vector, u64) { - let MessageTicket { - source_id, - destination_chain, - destination_address, - payload, - version, - } = self; - (source_id, destination_chain, destination_address, payload, version) -} + public(package) fun destroy(self: MessageTicket): (address, String, String, vector, u64) { + let MessageTicket { + source_id, + destination_chain, + destination_address, + payload, + version, + } = self; + (source_id, destination_chain, destination_address, payload, version) + } -#[test_only] -public fun new_for_testing( - source_id: address, - destination_chain: String, - destination_address: String, - payload: vector, - version: u64, -): MessageTicket { - MessageTicket { - source_id, - destination_chain, - destination_address, - payload, - version, + #[test_only] + public fun new_for_testing( + source_id: address, + destination_chain: String, + destination_address: String, + payload: vector, + version: u64, + ): MessageTicket { + MessageTicket { + source_id, + destination_chain, + destination_address, + payload, + version, + } } -} -#[test] -fun test_all() { - let mut rng = sui::random::new_generator_for_testing(); - let source_id = sui::address::from_u256(rng.generate_u256()); - let destination_chain = std::ascii::string(b"Destination Chain"); - let destination_address = std::ascii::string( - b"Destination Address", - ); - let payload: vector = rng.generate_bytes(256); - let version: u64 = 2; + #[test] + fun test_all() { + let mut rng = sui::random::new_generator_for_testing(); + let source_id = sui::address::from_u256(rng.generate_u256()); + let destination_chain = std::ascii::string(b"Destination Chain"); + let destination_address = std::ascii::string( + b"Destination Address", + ); + let payload: vector = rng.generate_bytes(256); + let version: u64 = 2; - let message_ticket = new( - source_id, - destination_chain, - destination_address, - payload, - version, - ); + let message_ticket = new( + source_id, + destination_chain, + destination_address, + payload, + version, + ); - assert!(message_ticket.source_id() == source_id); - assert!(message_ticket.destination_chain() == destination_chain); - assert!(message_ticket.destination_address() == destination_address); - assert!(message_ticket.payload() == payload); - assert!(message_ticket.version() == version); + assert!(message_ticket.source_id() == source_id); + assert!(message_ticket.destination_chain() == destination_chain); + assert!(message_ticket.destination_address() == destination_address); + assert!(message_ticket.payload() == payload); + assert!(message_ticket.version() == version); - let ( - result_source_id, - result_destination_chain, - result_destination_address, - result_payload, - result_version, - ) = message_ticket.destroy(); + let ( + result_source_id, + result_destination_chain, + result_destination_address, + result_payload, + result_version, + ) = message_ticket.destroy(); - assert!(result_source_id == source_id); - assert!(result_destination_chain == destination_chain); - assert!(result_destination_address == destination_address); - assert!(result_payload == payload); - assert!(result_version == version); + assert!(result_source_id == source_id); + assert!(result_destination_chain == destination_chain); + assert!(result_destination_address == destination_address); + assert!(result_payload == payload); + assert!(result_version == version); + } } diff --git a/move/axelar_gateway/sources/types/owner_cap.move b/move/axelar_gateway/sources/types/owner_cap.move index 79b83a67..df0f326e 100644 --- a/move/axelar_gateway/sources/types/owner_cap.move +++ b/move/axelar_gateway/sources/types/owner_cap.move @@ -1,23 +1,23 @@ -module axelar_gateway::owner_cap; - -// ----- -// Types -// ----- -public struct OwnerCap has key, store { - id: UID, -} +module axelar_gateway::owner_cap { + // ----- + // Types + // ----- + public struct OwnerCap has key, store { + id: UID, + } -public(package) fun create(ctx: &mut TxContext): OwnerCap { - OwnerCap { - id: object::new(ctx), + public(package) fun create(ctx: &mut TxContext): OwnerCap { + OwnerCap { + id: object::new(ctx), + } } -} -/// --------- -/// Test Only -/// --------- -#[test_only] -public(package) fun destroy_for_testing(self: OwnerCap) { - let OwnerCap { id } = self; - id.delete(); + /// --------- + /// Test Only + /// --------- + #[test_only] + public(package) fun destroy_for_testing(self: OwnerCap) { + let OwnerCap { id } = self; + id.delete(); + } } diff --git a/move/axelar_gateway/sources/types/proof.move b/move/axelar_gateway/sources/types/proof.move index 0057eaf0..c08822e8 100644 --- a/move/axelar_gateway/sources/types/proof.move +++ b/move/axelar_gateway/sources/types/proof.move @@ -1,353 +1,331 @@ -module axelar_gateway::proof; - -use axelar_gateway::weighted_signers::{Self, WeightedSigners}; -use sui::bcs::BCS; -use sui::ecdsa_k1 as ecdsa; +module axelar_gateway::proof { + use axelar_gateway::weighted_signers::{Self, WeightedSigners}; + use sui::{bcs::BCS, ecdsa_k1 as ecdsa}; + + // ----- + // Types + // ----- + public struct Signature has copy, drop, store { + bytes: vector, + } -// ----- -// Types -// ----- -public struct Signature has copy, drop, store { - bytes: vector, -} + public struct Proof has copy, drop, store { + signers: WeightedSigners, + signatures: vector, + } -public struct Proof has copy, drop, store { - signers: WeightedSigners, - signatures: vector, -} + // --------- + // Constants + // --------- + /// Length of the signature + const SIGNATURE_LENGTH: u64 = 65; + + // ------ + // Errors + // ------ + /// Invalid length of the bytes + #[error] + const EInvalidSignatureLength: vector = b"invalid signature length: expected 65 bytes"; + + #[error] + const ELowSignaturesWeight: vector = b"insufficient signatures weight"; + + #[error] + const ESignerNotFound: vector = b"no signer found with the specified public key in the given range"; + + #[error] + const ERedundantSignaturesProvided: vector = b"redundant signatures provided"; + + // ----------------- + // Package Functions + // ----------------- + /// The signers of the proof + public(package) fun signers(proof: &Proof): &WeightedSigners { + &proof.signers + } -// --------- -// Constants -// --------- -/// Length of the signature -const SIGNATURE_LENGTH: u64 = 65; - -// ------ -// Errors -// ------ -/// Invalid length of the bytes -#[error] -const EInvalidSignatureLength: vector = - b"invalid signature length: expected 65 bytes"; - -#[error] -const ELowSignaturesWeight: vector = b"insufficient signatures weight"; - -#[error] -const ESignerNotFound: vector = - b"no signer found with the specified public key in the given range"; - -#[error] -const ERedundantSignaturesProvided: vector = - b"redundant signatures provided"; - -// ----------------- -// Package Functions -// ----------------- -/// The signers of the proof -public(package) fun signers(proof: &Proof): &WeightedSigners { - &proof.signers -} + /// The proof signatures + public(package) fun signatures(proof: &Proof): &vector { + &proof.signatures + } -/// The proof signatures -public(package) fun signatures(proof: &Proof): &vector { - &proof.signatures -} + public(package) fun new_signature(bytes: vector): Signature { + assert!(bytes.length() == SIGNATURE_LENGTH, EInvalidSignatureLength); -public(package) fun new_signature(bytes: vector): Signature { - assert!(bytes.length() == SIGNATURE_LENGTH, EInvalidSignatureLength); + Signature { + bytes: bytes, + } + } - Signature { - bytes: bytes, + /// Recover the public key from an EVM recoverable signature, using keccak256 as + /// the hash function + public(package) fun recover_pub_key(self: &Signature, message: &vector): vector { + ecdsa::secp256k1_ecrecover(&self.bytes, message, 0) } -} -/// Recover the public key from an EVM recoverable signature, using keccak256 as -/// the hash function -public(package) fun recover_pub_key( - self: &Signature, - message: &vector, -): vector { - ecdsa::secp256k1_ecrecover(&self.bytes, message, 0) -} + /// Validates the signatures of a message against the signers. + /// The total weight of the signatures must be greater than or equal to the + /// threshold. + /// Otherwise, the error `ELowSignaturesWeight` is raised. + public(package) fun validate(self: &Proof, message: vector) { + let signers = &self.signers; + let signatures = &self.signatures; + assert!(signatures.length() != 0, ELowSignaturesWeight); + + let threshold = signers.threshold(); + let signatures_length = signatures.length(); + let mut total_weight: u128 = 0; + let mut signer_index = 0; + let mut i = 0; + + while (i < signatures_length) { + let pub_key = signatures[i].recover_pub_key(&message); + + let (weight, index) = find_weight_by_pub_key_from( + signers, + signer_index, + &pub_key, + ); + + total_weight = total_weight + weight; + + if (total_weight >= threshold) { + if (i + 1 == signatures_length) { + return + }; + + abort ERedundantSignaturesProvided + }; -/// Validates the signatures of a message against the signers. -/// The total weight of the signatures must be greater than or equal to the -/// threshold. -/// Otherwise, the error `ELowSignaturesWeight` is raised. -public(package) fun validate(self: &Proof, message: vector) { - let signers = &self.signers; - let signatures = &self.signatures; - assert!(signatures.length() != 0, ELowSignaturesWeight); - - let threshold = signers.threshold(); - let signatures_length = signatures.length(); - let mut total_weight: u128 = 0; - let mut signer_index = 0; - let mut i = 0; - - while (i < signatures_length) { - let pub_key = signatures[i].recover_pub_key(&message); - - let (weight, index) = find_weight_by_pub_key_from( - signers, - signer_index, - &pub_key, - ); + i = i + 1; + signer_index = index + 1; + }; - total_weight = total_weight + weight; + abort ELowSignaturesWeight + } - if (total_weight >= threshold) { - if (i + 1 == signatures_length) { - return - }; + /// Finds the weight of a signer in the weighted signers by its public key. + fun find_weight_by_pub_key_from(signers: &WeightedSigners, signer_index: u64, pub_key: &vector): (u128, u64) { + let signers = signers.signers(); + let length = signers.length(); + let mut index = signer_index; - abort ERedundantSignaturesProvided + // Find the first signer that satisfies the predicate + while (index < length && signers[index].pub_key() != pub_key) { + index = index + 1; }; - i = i + 1; - signer_index = index + 1; - }; - - abort ELowSignaturesWeight -} + // If no signer satisfies the predicate, return an error + assert!(index < length, ESignerNotFound); -/// Finds the weight of a signer in the weighted signers by its public key. -fun find_weight_by_pub_key_from( - signers: &WeightedSigners, - signer_index: u64, - pub_key: &vector, -): (u128, u64) { - let signers = signers.signers(); - let length = signers.length(); - let mut index = signer_index; - - // Find the first signer that satisfies the predicate - while (index < length && signers[index].pub_key() != pub_key) { - index = index + 1; - }; - - // If no signer satisfies the predicate, return an error - assert!(index < length, ESignerNotFound); - - (signers[index].weight(), index) -} + (signers[index].weight(), index) + } -public(package) fun peel_signature(bcs: &mut BCS): Signature { - let bytes = bcs.peel_vec_u8(); + public(package) fun peel_signature(bcs: &mut BCS): Signature { + let bytes = bcs.peel_vec_u8(); - new_signature(bytes) -} + new_signature(bytes) + } -public(package) fun peel(bcs: &mut BCS): Proof { - let signers = weighted_signers::peel(bcs); - let length = bcs.peel_vec_length(); + public(package) fun peel(bcs: &mut BCS): Proof { + let signers = weighted_signers::peel(bcs); + let length = bcs.peel_vec_length(); - Proof { - signers, - signatures: vector::tabulate!(length, |_| peel_signature(bcs)), + Proof { + signers, + signatures: vector::tabulate!(length, |_| peel_signature(bcs)), + } } -} -// --------- -// Test Only -// --------- -#[test_only] -public(package) fun create_for_testing( - signers: WeightedSigners, - signatures: vector, -): Proof { - Proof { - signers, - signatures, + // --------- + // Test Only + // --------- + #[test_only] + public(package) fun create_for_testing(signers: WeightedSigners, signatures: vector): Proof { + Proof { + signers, + signatures, + } } -} -#[test_only] -public(package) fun dummy(): Proof { - let mut rng = sui::random::new_generator_for_testing(); - let signature = rng.generate_bytes(SIGNATURE_LENGTH as u16); - Proof { - signers: axelar_gateway::weighted_signers::dummy(), - signatures: vector[Signature { bytes: signature }], + #[test_only] + public(package) fun dummy(): Proof { + let mut rng = sui::random::new_generator_for_testing(); + let signature = rng.generate_bytes(SIGNATURE_LENGTH as u16); + Proof { + signers: axelar_gateway::weighted_signers::dummy(), + signatures: vector[Signature { bytes: signature }], + } } -} -#[test_only] -public(package) fun generate( - weighted_signers: WeightedSigners, - message_to_sign: &vector, - keypairs: &vector, -): Proof { - let signatures = keypairs.map_ref!( - |keypair| new_signature( - ecdsa::secp256k1_sign( - keypair.private_key(), - message_to_sign, - 0, - true, + #[test_only] + public(package) fun generate( + weighted_signers: WeightedSigners, + message_to_sign: &vector, + keypairs: &vector, + ): Proof { + let signatures = keypairs.map_ref!( + |keypair| new_signature( + ecdsa::secp256k1_sign( + keypair.private_key(), + message_to_sign, + 0, + true, + ), ), - ), - ); - create_for_testing(weighted_signers, signatures) -} + ); + create_for_testing(weighted_signers, signatures) + } -// ----- -// Tests -// ----- -#[test] -fun test_getters() { - let proof = dummy(); + // ----- + // Tests + // ----- + #[test] + fun test_getters() { + let proof = dummy(); - assert!(proof.signers() == proof.signers); - assert!(proof.signatures() == proof.signatures); -} + assert!(proof.signers() == proof.signers); + assert!(proof.signatures() == proof.signatures); + } -#[test] -#[expected_failure(abort_code = EInvalidSignatureLength)] -fun test_new_signature_invalid_signature_length() { - new_signature(vector[]); -} + #[test] + #[expected_failure(abort_code = EInvalidSignatureLength)] + fun test_new_signature_invalid_signature_length() { + new_signature(vector[]); + } -#[test] -fun test_recover_pub_key() { - let mut rng = sui::random::new_generator_for_testing(); - let keypair = ecdsa::secp256k1_keypair_from_seed(&rng.generate_bytes(32)); - let message = rng.generate_bytes(32); - let signature = new_signature( - ecdsa::secp256k1_sign(keypair.private_key(), &message, 0, true), - ); - assert!(signature.recover_pub_key(&message) == keypair.public_key()); -} + #[test] + fun test_recover_pub_key() { + let mut rng = sui::random::new_generator_for_testing(); + let keypair = ecdsa::secp256k1_keypair_from_seed(&rng.generate_bytes(32)); + let message = rng.generate_bytes(32); + let signature = new_signature( + ecdsa::secp256k1_sign(keypair.private_key(), &message, 0, true), + ); + assert!(signature.recover_pub_key(&message) == keypair.public_key()); + } -#[test] -fun test_validate() { - let mut rng = sui::random::new_generator_for_testing(); - let mut keypairs = vector[0, 1, 2].map!( - |_| ecdsa::secp256k1_keypair_from_seed(&rng.generate_bytes(32)), - ); - let pub_keys = keypairs.map_ref!(|keypair| *keypair.public_key()); - let weights = vector[0, 1, 2].map!(|_| rng.generate_u64() as u128); - let message = rng.generate_bytes(32); - let nonce = axelar_gateway::bytes32::from_bytes(rng.generate_bytes(32)); - - let weighted_signers = axelar_gateway::weighted_signers::create_for_testing( - vector[0, 1, 2].map!( - |index| axelar_gateway::weighted_signer::new( - pub_keys[index], - weights[index], + #[test] + fun test_validate() { + let mut rng = sui::random::new_generator_for_testing(); + let mut keypairs = vector[0, 1, 2].map!(|_| ecdsa::secp256k1_keypair_from_seed(&rng.generate_bytes(32))); + let pub_keys = keypairs.map_ref!(|keypair| *keypair.public_key()); + let weights = vector[0, 1, 2].map!(|_| rng.generate_u64() as u128); + let message = rng.generate_bytes(32); + let nonce = axelar_gateway::bytes32::from_bytes(rng.generate_bytes(32)); + + let weighted_signers = axelar_gateway::weighted_signers::create_for_testing( + vector[0, 1, 2].map!( + |index| axelar_gateway::weighted_signer::new( + pub_keys[index], + weights[index], + ), ), - ), - weights[0] + weights[2], - nonce, - ); - keypairs.remove(1); - let proof = generate(weighted_signers, &message, &keypairs); - proof.validate(message); -} + weights[0] + weights[2], + nonce, + ); + keypairs.remove(1); + let proof = generate(weighted_signers, &message, &keypairs); + proof.validate(message); + } -#[test] -#[expected_failure(abort_code = ERedundantSignaturesProvided)] -fun test_validate_redundant_signatures() { - let mut rng = sui::random::new_generator_for_testing(); - let keypairs = vector[0, 1, 2].map!( - |_| ecdsa::secp256k1_keypair_from_seed(&rng.generate_bytes(32)), - ); - let pub_keys = keypairs.map_ref!(|keypair| *keypair.public_key()); - let weights = vector[0, 1, 2].map!(|_| rng.generate_u64() as u128); - let message = rng.generate_bytes(32); - let nonce = axelar_gateway::bytes32::from_bytes(rng.generate_bytes(32)); - - let weighted_signers = axelar_gateway::weighted_signers::create_for_testing( - vector[0, 1, 2].map!( - |index| axelar_gateway::weighted_signer::new( - pub_keys[index], - weights[index], + #[test] + #[expected_failure(abort_code = ERedundantSignaturesProvided)] + fun test_validate_redundant_signatures() { + let mut rng = sui::random::new_generator_for_testing(); + let keypairs = vector[0, 1, 2].map!(|_| ecdsa::secp256k1_keypair_from_seed(&rng.generate_bytes(32))); + let pub_keys = keypairs.map_ref!(|keypair| *keypair.public_key()); + let weights = vector[0, 1, 2].map!(|_| rng.generate_u64() as u128); + let message = rng.generate_bytes(32); + let nonce = axelar_gateway::bytes32::from_bytes(rng.generate_bytes(32)); + + let weighted_signers = axelar_gateway::weighted_signers::create_for_testing( + vector[0, 1, 2].map!( + |index| axelar_gateway::weighted_signer::new( + pub_keys[index], + weights[index], + ), ), - ), - weights[0] + weights[1], - nonce, - ); - let proof = generate(weighted_signers, &message, &keypairs); - proof.validate(message); -} + weights[0] + weights[1], + nonce, + ); + let proof = generate(weighted_signers, &message, &keypairs); + proof.validate(message); + } -#[test] -#[expected_failure(abort_code = ELowSignaturesWeight)] -fun test_validate_empty_signers() { - let mut rng = sui::random::new_generator_for_testing(); - let message = rng.generate_bytes(32); - let nonce = axelar_gateway::bytes32::from_bytes(rng.generate_bytes(32)); - let weighted_signers = axelar_gateway::weighted_signers::create_for_testing( - vector[], - 1, - nonce, - ); - let proof = create_for_testing(weighted_signers, vector[]); - proof.validate(message); -} + #[test] + #[expected_failure(abort_code = ELowSignaturesWeight)] + fun test_validate_empty_signers() { + let mut rng = sui::random::new_generator_for_testing(); + let message = rng.generate_bytes(32); + let nonce = axelar_gateway::bytes32::from_bytes(rng.generate_bytes(32)); + let weighted_signers = axelar_gateway::weighted_signers::create_for_testing( + vector[], + 1, + nonce, + ); + let proof = create_for_testing(weighted_signers, vector[]); + proof.validate(message); + } -#[test] -#[expected_failure(abort_code = ELowSignaturesWeight)] -fun test_validate_low_signature_weight() { - let mut rng = sui::random::new_generator_for_testing(); - let keypairs = vector[0, 1, 2].map!( - |_| ecdsa::secp256k1_keypair_from_seed(&rng.generate_bytes(32)), - ); - let pub_keys = keypairs.map_ref!(|keypair| *keypair.public_key()); - let weights = vector[0, 1, 2].map!(|_| rng.generate_u64() as u128); - let message = rng.generate_bytes(32); - let nonce = axelar_gateway::bytes32::from_bytes(rng.generate_bytes(32)); - - let weighted_signers = axelar_gateway::weighted_signers::create_for_testing( - vector[0, 1, 2].map!( - |index| axelar_gateway::weighted_signer::new( - pub_keys[index], - weights[index], + #[test] + #[expected_failure(abort_code = ELowSignaturesWeight)] + fun test_validate_low_signature_weight() { + let mut rng = sui::random::new_generator_for_testing(); + let keypairs = vector[0, 1, 2].map!(|_| ecdsa::secp256k1_keypair_from_seed(&rng.generate_bytes(32))); + let pub_keys = keypairs.map_ref!(|keypair| *keypair.public_key()); + let weights = vector[0, 1, 2].map!(|_| rng.generate_u64() as u128); + let message = rng.generate_bytes(32); + let nonce = axelar_gateway::bytes32::from_bytes(rng.generate_bytes(32)); + + let weighted_signers = axelar_gateway::weighted_signers::create_for_testing( + vector[0, 1, 2].map!( + |index| axelar_gateway::weighted_signer::new( + pub_keys[index], + weights[index], + ), ), - ), - weights[0] + weights[2] + 1, - nonce, - ); - let signatures = keypairs.map!( - |keypair| new_signature( - ecdsa::secp256k1_sign(keypair.private_key(), &message, 0, true), - ), - ); - let proof = create_for_testing( - weighted_signers, - vector[signatures[0], signatures[2]], - ); - proof.validate(message); -} + weights[0] + weights[2] + 1, + nonce, + ); + let signatures = keypairs.map!( + |keypair| new_signature( + ecdsa::secp256k1_sign(keypair.private_key(), &message, 0, true), + ), + ); + let proof = create_for_testing( + weighted_signers, + vector[signatures[0], signatures[2]], + ); + proof.validate(message); + } -#[test] -#[expected_failure(abort_code = ESignerNotFound)] -fun test_validate_signer_not_found() { - let mut rng = sui::random::new_generator_for_testing(); - let keypairs = vector[0, 1, 2].map!( - |_| ecdsa::secp256k1_keypair_from_seed(&rng.generate_bytes(32)), - ); - let pub_keys = keypairs.map_ref!(|keypair| *keypair.public_key()); - let weights = vector[0, 1, 2].map!(|_| rng.generate_u64() as u128); - let message = rng.generate_bytes(32); - let nonce = axelar_gateway::bytes32::from_bytes(rng.generate_bytes(32)); - - let weighted_signers = axelar_gateway::weighted_signers::create_for_testing( - vector[0, 2].map!( - |index| axelar_gateway::weighted_signer::new( - pub_keys[index], - weights[index], + #[test] + #[expected_failure(abort_code = ESignerNotFound)] + fun test_validate_signer_not_found() { + let mut rng = sui::random::new_generator_for_testing(); + let keypairs = vector[0, 1, 2].map!(|_| ecdsa::secp256k1_keypair_from_seed(&rng.generate_bytes(32))); + let pub_keys = keypairs.map_ref!(|keypair| *keypair.public_key()); + let weights = vector[0, 1, 2].map!(|_| rng.generate_u64() as u128); + let message = rng.generate_bytes(32); + let nonce = axelar_gateway::bytes32::from_bytes(rng.generate_bytes(32)); + + let weighted_signers = axelar_gateway::weighted_signers::create_for_testing( + vector[0, 2].map!( + |index| axelar_gateway::weighted_signer::new( + pub_keys[index], + weights[index], + ), ), - ), - weights[0] + weights[2], - nonce, - ); - let signatures = keypairs.map!( - |keypair| new_signature( - ecdsa::secp256k1_sign(keypair.private_key(), &message, 0, true), - ), - ); - let proof = create_for_testing(weighted_signers, vector[signatures[1]]); - proof.validate(message); + weights[0] + weights[2], + nonce, + ); + let signatures = keypairs.map!( + |keypair| new_signature( + ecdsa::secp256k1_sign(keypair.private_key(), &message, 0, true), + ), + ); + let proof = create_for_testing(weighted_signers, vector[signatures[1]]); + proof.validate(message); + } } diff --git a/move/axelar_gateway/sources/types/weighted_signer.move b/move/axelar_gateway/sources/types/weighted_signer.move index 070d8e0b..ca0c6fc0 100644 --- a/move/axelar_gateway/sources/types/weighted_signer.move +++ b/move/axelar_gateway/sources/types/weighted_signer.move @@ -1,165 +1,162 @@ -module axelar_gateway::weighted_signer; +module axelar_gateway::weighted_signer { + use sui::bcs::BCS; -use sui::bcs::BCS; + // --------- + // Constants + // --------- -// --------- -// Constants -// --------- + /// Length of a public key + const PUB_KEY_LENGTH: u64 = 33; -/// Length of a public key -const PUB_KEY_LENGTH: u64 = 33; + // ----- + // Types + // ----- -// ----- -// Types -// ----- - -public struct WeightedSigner has copy, drop, store { - pub_key: vector, - weight: u128, -} + public struct WeightedSigner has copy, drop, store { + pub_key: vector, + weight: u128, + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun pub_key(self: &WeightedSigner): vector { - self.pub_key -} + // ----------------- + // Package Functions + // ----------------- + public(package) fun pub_key(self: &WeightedSigner): vector { + self.pub_key + } -public(package) fun weight(self: &WeightedSigner): u128 { - self.weight -} + public(package) fun weight(self: &WeightedSigner): u128 { + self.weight + } -// ------ -// Errors -// ------ + // ------ + // Errors + // ------ -#[error] -const EInvalidPubKeyLength: vector = - b"invalid public key length: expected 33 bytes"; + #[error] + const EInvalidPubKeyLength: vector = b"invalid public key length: expected 33 bytes"; -#[error] -const EInvalidWeight: vector = b"invalid weight: expected non-zero value"; + #[error] + const EInvalidWeight: vector = b"invalid weight: expected non-zero value"; -// ----------------- -// Package Functions -// ----------------- + // ----------------- + // Package Functions + // ----------------- -public(package) fun new(pub_key: vector, weight: u128): WeightedSigner { - assert!(pub_key.length() == PUB_KEY_LENGTH, EInvalidPubKeyLength); + public(package) fun new(pub_key: vector, weight: u128): WeightedSigner { + assert!(pub_key.length() == PUB_KEY_LENGTH, EInvalidPubKeyLength); - WeightedSigner { pub_key, weight } -} + WeightedSigner { pub_key, weight } + } -/// Empty weighted signer -public(package) fun default(): WeightedSigner { - let mut pub_key = @0x0.to_bytes(); - pub_key.push_back(0); + /// Empty weighted signer + public(package) fun default(): WeightedSigner { + let mut pub_key = @0x0.to_bytes(); + pub_key.push_back(0); - WeightedSigner { - pub_key, - weight: 0, + WeightedSigner { + pub_key, + weight: 0, + } } -} -public(package) fun peel(bcs: &mut BCS): WeightedSigner { - let pub_key = bcs.peel_vec_u8(); - let weight = bcs.peel_u128(); + public(package) fun peel(bcs: &mut BCS): WeightedSigner { + let pub_key = bcs.peel_vec_u8(); + let weight = bcs.peel_u128(); - new(pub_key, weight) -} + new(pub_key, weight) + } -public(package) fun validate(self: &WeightedSigner) { - assert!(self.weight != 0, EInvalidWeight); -} + public(package) fun validate(self: &WeightedSigner) { + assert!(self.weight != 0, EInvalidWeight); + } -/// Check if self.signer is less than other.signer as bytes -public(package) fun lt(self: &WeightedSigner, other: &WeightedSigner): bool { - let mut i = 0; + /// Check if self.signer is less than other.signer as bytes + public(package) fun lt(self: &WeightedSigner, other: &WeightedSigner): bool { + let mut i = 0; - while (i < PUB_KEY_LENGTH) { - if (self.pub_key[i] < other.pub_key[i]) { - return true - } else if (self.pub_key[i] > other.pub_key[i]) { - return false - }; + while (i < PUB_KEY_LENGTH) { + if (self.pub_key[i] < other.pub_key[i]) { + return true + } else if (self.pub_key[i] > other.pub_key[i]) { + return false + }; - i = i + 1; - }; + i = i + 1; + }; - false -} + false + } -// ----- -// Tests -// ----- + // ----- + // Tests + // ----- -#[test] -#[expected_failure(abort_code = EInvalidPubKeyLength)] -fun test_new_incorrect_pubkey() { - let mut rng = sui::random::new_generator_for_testing(); - new(vector[], rng.generate_u128()); -} + #[test] + #[expected_failure(abort_code = EInvalidPubKeyLength)] + fun test_new_incorrect_pubkey() { + let mut rng = sui::random::new_generator_for_testing(); + new(vector[], rng.generate_u128()); + } -#[test] -#[expected_failure(abort_code = EInvalidWeight)] -fun test_validate_invalid_weight() { - validate( - &WeightedSigner { - pub_key: vector[], - weight: 0, - }, - ) -} + #[test] + #[expected_failure(abort_code = EInvalidWeight)] + fun test_validate_invalid_weight() { + validate( + &WeightedSigner { + pub_key: vector[], + weight: 0, + }, + ) + } -#[test] -fun test_pub_key() { - let mut rng = sui::random::new_generator_for_testing(); - let pub_key = rng.generate_bytes(3); - assert!( - &WeightedSigner { + #[test] + fun test_pub_key() { + let mut rng = sui::random::new_generator_for_testing(); + let pub_key = rng.generate_bytes(3); + assert!(&WeightedSigner { pub_key, weight: 0, - }.pub_key() == &pub_key, - ); -} + }.pub_key() == &pub_key); + } -#[test] -fun verify_default_signer() { - let signer = default(); + #[test] + fun verify_default_signer() { + let signer = default(); - assert!(signer.weight == 0); - assert!(signer.pub_key.length() == PUB_KEY_LENGTH); + assert!(signer.weight == 0); + assert!(signer.pub_key.length() == PUB_KEY_LENGTH); - let mut i = 0; - while (i < PUB_KEY_LENGTH) { - assert!(signer.pub_key[i] == 0); - i = i + 1; + let mut i = 0; + while (i < PUB_KEY_LENGTH) { + assert!(signer.pub_key[i] == 0); + i = i + 1; + } } -} -#[test] -fun compare_weight_signers() { - let signer1 = new( - x"000100000000000000000000000000000000000000000000000000000000000000", - 1, - ); - let signer2 = new( - x"000200000000000000000000000000000000000000000000000000000000000000", - 2, - ); - let signer3 = new( - x"000100000000000000000000000000000000000000000000000000000000000001", - 3, - ); - - // Less than - assert!(signer1.lt(&signer2)); - assert!(signer1.lt(&signer3)); - - // Not less than - assert!(!signer2.lt(&signer1)); - assert!(!signer3.lt(&signer1)); - - // Equal - assert!(!signer1.lt(&signer1)); // !(signer1 < signer1) + #[test] + fun compare_weight_signers() { + let signer1 = new( + x"000100000000000000000000000000000000000000000000000000000000000000", + 1, + ); + let signer2 = new( + x"000200000000000000000000000000000000000000000000000000000000000000", + 2, + ); + let signer3 = new( + x"000100000000000000000000000000000000000000000000000000000000000001", + 3, + ); + + // Less than + assert!(signer1.lt(&signer2)); + assert!(signer1.lt(&signer3)); + + // Not less than + assert!(!signer2.lt(&signer1)); + assert!(!signer3.lt(&signer1)); + + // Equal + assert!(!signer1.lt(&signer1)); // !(signer1 < signer1) + } } diff --git a/move/axelar_gateway/sources/types/weighted_signers.move b/move/axelar_gateway/sources/types/weighted_signers.move index 51f6153a..50e94cb2 100644 --- a/move/axelar_gateway/sources/types/weighted_signers.move +++ b/move/axelar_gateway/sources/types/weighted_signers.move @@ -1,207 +1,194 @@ -module axelar_gateway::weighted_signers; - -use axelar_gateway::bytes32::{Self, Bytes32}; -use axelar_gateway::weighted_signer::{Self, WeightedSigner}; -use sui::bcs::{Self, BCS}; -use sui::hash; - -public struct WeightedSigners has copy, drop, store { - signers: vector, - threshold: u128, - nonce: Bytes32, -} - -/// ------ -/// Errors -/// ------ -#[error] -const EInvalidSignersLength: vector = - b"invalid signers length: expected at least 1 signer"; - -#[error] -const EInvalidThreshold: vector = - b"invalid threshold: expected non-zero value and less than or equal to the total weight of the signers"; - -#[error] -const EInvalidSignerOrder: vector = - b"invalid signer order: signers must be in ascending order by their public key"; - -/// ----------------- -/// Package Functions -/// ----------------- - -/// Decode a `WeightedSigners` from the BCS encoded bytes. -public(package) fun peel(bcs: &mut BCS): WeightedSigners { - let len = bcs.peel_vec_length(); - assert!(len > 0, EInvalidSignersLength); +module axelar_gateway::weighted_signers { + use axelar_gateway::{bytes32::{Self, Bytes32}, weighted_signer::{Self, WeightedSigner}}; + use sui::{bcs::{Self, BCS}, hash}; + + public struct WeightedSigners has copy, drop, store { + signers: vector, + threshold: u128, + nonce: Bytes32, + } - WeightedSigners { - signers: vector::tabulate!(len, |_| weighted_signer::peel(bcs)), - threshold: bcs.peel_u128(), - nonce: bytes32::peel(bcs), + /// ------ + /// Errors + /// ------ + #[error] + const EInvalidSignersLength: vector = b"invalid signers length: expected at least 1 signer"; + + #[error] + const EInvalidThreshold: vector = + b"invalid threshold: expected non-zero value and less than or equal to the total weight of the signers"; + + #[error] + const EInvalidSignerOrder: vector = b"invalid signer order: signers must be in ascending order by their public key"; + + /// ----------------- + /// Package Functions + /// ----------------- + + /// Decode a `WeightedSigners` from the BCS encoded bytes. + public(package) fun peel(bcs: &mut BCS): WeightedSigners { + let len = bcs.peel_vec_length(); + assert!(len > 0, EInvalidSignersLength); + + WeightedSigners { + signers: vector::tabulate!(len, |_| weighted_signer::peel(bcs)), + threshold: bcs.peel_u128(), + nonce: bytes32::peel(bcs), + } } -} -/// Validates the weighted signers. The following must be true: -/// 1. The signers are in ascending order by their public key. -/// 2. The threshold is greater than zero. -/// 3. The threshold is less than or equal to the total weight of the signers. -public(package) fun validate(self: &WeightedSigners) { - self.validate_signers(); - self.validate_threshold(); -} + /// Validates the weighted signers. The following must be true: + /// 1. The signers are in ascending order by their public key. + /// 2. The threshold is greater than zero. + /// 3. The threshold is less than or equal to the total weight of the signers. + public(package) fun validate(self: &WeightedSigners) { + self.validate_signers(); + self.validate_threshold(); + } -public(package) fun hash(self: &WeightedSigners): Bytes32 { - bytes32::from_bytes(hash::keccak256(&bcs::to_bytes(self))) -} + public(package) fun hash(self: &WeightedSigners): Bytes32 { + bytes32::from_bytes(hash::keccak256(&bcs::to_bytes(self))) + } -public(package) fun signers(self: &WeightedSigners): &vector { - &self.signers -} + public(package) fun signers(self: &WeightedSigners): &vector { + &self.signers + } -public(package) fun threshold(self: &WeightedSigners): u128 { - self.threshold -} + public(package) fun threshold(self: &WeightedSigners): u128 { + self.threshold + } -public(package) fun nonce(self: &WeightedSigners): Bytes32 { - self.nonce -} + public(package) fun nonce(self: &WeightedSigners): Bytes32 { + self.nonce + } -/// ----- -/// Internal Functions -/// ----- - -/// Validates the order of the signers and the length of the signers. -/// The signers must be in ascending order by their public key. -/// Otherwise, the error `EInvalidSignersLength` is raised. -fun validate_signers(self: &WeightedSigners) { - assert!(!self.signers.is_empty(), EInvalidSignersLength); - let mut previous = &weighted_signer::default(); - self.signers.do_ref!(|signer| { - signer.validate(); - assert!(previous.lt(signer), EInvalidSignerOrder); - previous = signer; - }); -} + /// ----- + /// Internal Functions + /// ----- + + /// Validates the order of the signers and the length of the signers. + /// The signers must be in ascending order by their public key. + /// Otherwise, the error `EInvalidSignersLength` is raised. + fun validate_signers(self: &WeightedSigners) { + assert!(!self.signers.is_empty(), EInvalidSignersLength); + let mut previous = &weighted_signer::default(); + self.signers.do_ref!(|signer| { + signer.validate(); + assert!(previous.lt(signer), EInvalidSignerOrder); + previous = signer; + }); + } -/// Calculates the total weight of the signers. -fun total_weight(self: &WeightedSigners): u128 { - self - .signers - .fold!(0, |acc, signer| acc + signer.weight()) -} + /// Calculates the total weight of the signers. + fun total_weight(self: &WeightedSigners): u128 { + self.signers.fold!(0, |acc, signer| acc + signer.weight()) + } -/// Validates the threshold. -/// The threshold must be greater than zero and less than or equal to the total -/// weight of the signers. -/// Otherwise, the error `EInvalidThreshold` is raised. -fun validate_threshold(self: &WeightedSigners) { - assert!( - self.threshold != 0 && self.total_weight() >= self.threshold, - EInvalidThreshold, - ); -} + /// Validates the threshold. + /// The threshold must be greater than zero and less than or equal to the total + /// weight of the signers. + /// Otherwise, the error `EInvalidThreshold` is raised. + fun validate_threshold(self: &WeightedSigners) { + assert!(self.threshold != 0 && self.total_weight() >= self.threshold, EInvalidThreshold); + } -#[test_only] -public fun create_for_testing( - signers: vector, - threshold: u128, - nonce: Bytes32, -): WeightedSigners { - WeightedSigners { - signers, - threshold, - nonce, + #[test_only] + public fun create_for_testing(signers: vector, threshold: u128, nonce: Bytes32): WeightedSigners { + WeightedSigners { + signers, + threshold, + nonce, + } } -} -#[test_only] -public fun dummy(): WeightedSigners { - let mut rng = sui::random::new_generator_for_testing(); - let pub_key = rng.generate_bytes(33); - let signer = axelar_gateway::weighted_signer::new( - pub_key, - rng.generate_u128(), - ); - let nonce = bytes32::from_bytes(rng.generate_bytes(32)); - let threshold = signer.weight(); - WeightedSigners { - signers: vector[signer], - threshold, - nonce, + #[test_only] + public fun dummy(): WeightedSigners { + let mut rng = sui::random::new_generator_for_testing(); + let pub_key = rng.generate_bytes(33); + let signer = axelar_gateway::weighted_signer::new( + pub_key, + rng.generate_u128(), + ); + let nonce = bytes32::from_bytes(rng.generate_bytes(32)); + let threshold = signer.weight(); + WeightedSigners { + signers: vector[signer], + threshold, + nonce, + } } -} -#[test] -fun tent_nonce() { - let weighted_signers = dummy(); - assert!(weighted_signers.nonce() == weighted_signers.nonce); -} + #[test] + fun tent_nonce() { + let weighted_signers = dummy(); + assert!(weighted_signers.nonce() == weighted_signers.nonce); + } -#[test] -#[expected_failure(abort_code = EInvalidSignersLength)] -fun test_peel_invalid_signers_length() { - let mut rng = sui::random::new_generator_for_testing(); - let mut bcs = bcs::new( - bcs::to_bytes( - &WeightedSigners { - signers: vector[], - threshold: rng.generate_u128(), - nonce: bytes32::from_bytes(rng.generate_bytes(32)), - }, - ), - ); - peel(&mut bcs); -} + #[test] + #[expected_failure(abort_code = EInvalidSignersLength)] + fun test_peel_invalid_signers_length() { + let mut rng = sui::random::new_generator_for_testing(); + let mut bcs = bcs::new( + bcs::to_bytes( + &WeightedSigners { + signers: vector[], + threshold: rng.generate_u128(), + nonce: bytes32::from_bytes(rng.generate_bytes(32)), + }, + ), + ); + peel(&mut bcs); + } -#[test] -#[expected_failure(abort_code = EInvalidSignersLength)] -fun test_validate_signers_invalid_signers_length() { - let mut rng = sui::random::new_generator_for_testing(); - WeightedSigners { - signers: vector[], - threshold: rng.generate_u128(), - nonce: bytes32::from_bytes(rng.generate_bytes(32)), - }.validate_signers(); -} + #[test] + #[expected_failure(abort_code = EInvalidSignersLength)] + fun test_validate_signers_invalid_signers_length() { + let mut rng = sui::random::new_generator_for_testing(); + WeightedSigners { + signers: vector[], + threshold: rng.generate_u128(), + nonce: bytes32::from_bytes(rng.generate_bytes(32)), + }.validate_signers(); + } -#[test] -#[expected_failure(abort_code = EInvalidSignerOrder)] -fun test_validate_signers_invalid_signer_order() { - let mut rng = sui::random::new_generator_for_testing(); - let mut pub_key = @0x0.to_bytes(); - pub_key.push_back(2); - let signer1 = axelar_gateway::weighted_signer::new(pub_key, 1); - pub_key = @0x0.to_bytes(); - pub_key.push_back(1); - let signer2 = axelar_gateway::weighted_signer::new(pub_key, 1); - WeightedSigners { - signers: vector[signer1, signer2], - threshold: rng.generate_u128(), - nonce: bytes32::from_bytes(rng.generate_bytes(32)), - }.validate_signers(); -} + #[test] + #[expected_failure(abort_code = EInvalidSignerOrder)] + fun test_validate_signers_invalid_signer_order() { + let mut rng = sui::random::new_generator_for_testing(); + let mut pub_key = @0x0.to_bytes(); + pub_key.push_back(2); + let signer1 = axelar_gateway::weighted_signer::new(pub_key, 1); + pub_key = @0x0.to_bytes(); + pub_key.push_back(1); + let signer2 = axelar_gateway::weighted_signer::new(pub_key, 1); + WeightedSigners { + signers: vector[signer1, signer2], + threshold: rng.generate_u128(), + nonce: bytes32::from_bytes(rng.generate_bytes(32)), + }.validate_signers(); + } -#[test] -#[expected_failure(abort_code = EInvalidThreshold)] -fun test_validate_zero_threshold() { - let mut rng = sui::random::new_generator_for_testing(); - WeightedSigners { - signers: vector[], - threshold: 0, - nonce: bytes32::from_bytes(rng.generate_bytes(32)), - }.validate_threshold(); -} + #[test] + #[expected_failure(abort_code = EInvalidThreshold)] + fun test_validate_zero_threshold() { + let mut rng = sui::random::new_generator_for_testing(); + WeightedSigners { + signers: vector[], + threshold: 0, + nonce: bytes32::from_bytes(rng.generate_bytes(32)), + }.validate_threshold(); + } -#[test] -#[expected_failure(abort_code = EInvalidThreshold)] -fun test_validate_threshold_above_weight_sum() { - let mut rng = sui::random::new_generator_for_testing(); - let pub_key = rng.generate_bytes(33); - let signer = axelar_gateway::weighted_signer::new(pub_key, 1); - WeightedSigners { - signers: vector[signer], - threshold: 2, - nonce: bytes32::from_bytes(rng.generate_bytes(32)), - }.validate_threshold(); + #[test] + #[expected_failure(abort_code = EInvalidThreshold)] + fun test_validate_threshold_above_weight_sum() { + let mut rng = sui::random::new_generator_for_testing(); + let pub_key = rng.generate_bytes(33); + let signer = axelar_gateway::weighted_signer::new(pub_key, 1); + WeightedSigners { + signers: vector[signer], + threshold: 2, + nonce: bytes32::from_bytes(rng.generate_bytes(32)), + }.validate_threshold(); + } } diff --git a/move/axelar_gateway/sources/versioned/gateway_v0.move b/move/axelar_gateway/sources/versioned/gateway_v0.move index 813e6f41..f62a72a6 100644 --- a/move/axelar_gateway/sources/versioned/gateway_v0.move +++ b/move/axelar_gateway/sources/versioned/gateway_v0.move @@ -1,405 +1,353 @@ -module axelar_gateway::gateway_v0; - -use axelar_gateway::auth::AxelarSigners; -use axelar_gateway::bytes32::{Self, Bytes32}; -use axelar_gateway::channel::{Self, ApprovedMessage}; -use axelar_gateway::events; -use axelar_gateway::message::{Self, Message}; -use axelar_gateway::message_status::{Self, MessageStatus}; -use axelar_gateway::message_ticket::MessageTicket; -use axelar_gateway::proof; -use axelar_gateway::weighted_signers; -use std::ascii::String; -use sui::address; -use sui::clock::Clock; -use sui::hash; -use sui::table::{Self, Table}; -use utils::utils; -use version_control::version_control::VersionControl; - -// ------ -// Errors -// ------ -#[error] -const EMessageNotApproved: vector = - b"trying to `take_approved_message` for a message that is not approved"; - -#[error] -const EZeroMessages: vector = b"no messages found"; - -#[error] -const ENotLatestSigners: vector = b"not latest signers"; - -#[error] -const ENewerMessage: vector = - b"message ticket created from newer versions cannot be sent here"; - -// ----- -// Types -// ----- -/// An object holding the state of the Axelar bridge. -/// The central piece in managing call approval creation and signature -/// verification. -public struct Gateway_v0 has store { - operator: address, - messages: Table, - signers: AxelarSigners, - version_control: VersionControl, -} +module axelar_gateway::gateway_v0 { + use axelar_gateway::{ + auth::AxelarSigners, + bytes32::{Self, Bytes32}, + channel::{Self, ApprovedMessage}, + events, + message::{Self, Message}, + message_status::{Self, MessageStatus}, + message_ticket::MessageTicket, + proof, + weighted_signers + }; + use std::ascii::String; + use sui::{address, clock::Clock, hash, table::{Self, Table}}; + use utils::utils; + use version_control::version_control::VersionControl; + + // ------ + // Errors + // ------ + #[error] + const EMessageNotApproved: vector = b"trying to `take_approved_message` for a message that is not approved"; + + #[error] + const EZeroMessages: vector = b"no messages found"; + + #[error] + const ENotLatestSigners: vector = b"not latest signers"; + + #[error] + const ENewerMessage: vector = b"message ticket created from newer versions cannot be sent here"; + + // ----- + // Types + // ----- + /// An object holding the state of the Axelar bridge. + /// The central piece in managing call approval creation and signature + /// verification. + public struct Gateway_v0 has store { + operator: address, + messages: Table, + signers: AxelarSigners, + version_control: VersionControl, + } -public enum CommandType { - ApproveMessages, - RotateSigners, -} + public enum CommandType { + ApproveMessages, + RotateSigners, + } -// ----------------- -// Package Functions -// ----------------- -/// Init the module by giving a OwnerCap to the sender to allow a full -/// `setup`. -public(package) fun new( - operator: address, - messages: Table, - signers: AxelarSigners, - version_control: VersionControl, -): Gateway_v0 { - Gateway_v0 { - operator, - messages, - signers, - version_control, + // ----------------- + // Package Functions + // ----------------- + /// Init the module by giving a OwnerCap to the sender to allow a full + /// `setup`. + public(package) fun new( + operator: address, + messages: Table, + signers: AxelarSigners, + version_control: VersionControl, + ): Gateway_v0 { + Gateway_v0 { + operator, + messages, + signers, + version_control, + } } -} -public(package) fun version_control(self: &Gateway_v0): &VersionControl { - &self.version_control -} + public(package) fun version_control(self: &Gateway_v0): &VersionControl { + &self.version_control + } -public(package) fun approve_messages( - self: &mut Gateway_v0, - message_data: vector, - proof_data: vector, -) { - let proof = utils::peel!(proof_data, |bcs| proof::peel(bcs)); - let messages = peel_messages(message_data); - - let _ = self - .signers - .validate_proof( - data_hash(CommandType::ApproveMessages, message_data), - proof, - ); + public(package) fun approve_messages(self: &mut Gateway_v0, message_data: vector, proof_data: vector) { + let proof = utils::peel!(proof_data, |bcs| proof::peel(bcs)); + let messages = peel_messages(message_data); - messages.do!(|message| self.approve_message(message)); -} + let _ = self + .signers + .validate_proof( + data_hash(CommandType::ApproveMessages, message_data), + proof, + ); + + messages.do!(|message| self.approve_message(message)); + } -public(package) fun rotate_signers( - self: &mut Gateway_v0, - clock: &Clock, - new_signers_data: vector, - proof_data: vector, - ctx: &TxContext, -) { - let weighted_signers = utils::peel!( - new_signers_data, - |bcs| weighted_signers::peel(bcs), - ); - let proof = utils::peel!(proof_data, |bcs| proof::peel(bcs)); - - let enforce_rotation_delay = ctx.sender() != self.operator; - - let is_latest_signers = self - .signers - .validate_proof( - data_hash(CommandType::RotateSigners, new_signers_data), - proof, + public(package) fun rotate_signers( + self: &mut Gateway_v0, + clock: &Clock, + new_signers_data: vector, + proof_data: vector, + ctx: &TxContext, + ) { + let weighted_signers = utils::peel!(new_signers_data, |bcs| weighted_signers::peel(bcs)); + let proof = utils::peel!(proof_data, |bcs| proof::peel(bcs)); + + let enforce_rotation_delay = ctx.sender() != self.operator; + + let is_latest_signers = self + .signers + .validate_proof( + data_hash(CommandType::RotateSigners, new_signers_data), + proof, + ); + assert!(!enforce_rotation_delay || is_latest_signers, ENotLatestSigners); + + // This will fail if signers are duplicated + self.signers.rotate_signers(clock, weighted_signers, enforce_rotation_delay); + } + + public(package) fun is_message_approved( + self: &Gateway_v0, + source_chain: String, + message_id: String, + source_address: String, + destination_id: address, + payload_hash: Bytes32, + ): bool { + let message = message::new( + source_chain, + message_id, + source_address, + destination_id, + payload_hash, ); - assert!(!enforce_rotation_delay || is_latest_signers, ENotLatestSigners); + let command_id = message.command_id(); - // This will fail if signers are duplicated - self - .signers - .rotate_signers(clock, weighted_signers, enforce_rotation_delay); -} + self[command_id] == message_status::approved(message.hash()) + } -public(package) fun is_message_approved( - self: &Gateway_v0, - source_chain: String, - message_id: String, - source_address: String, - destination_id: address, - payload_hash: Bytes32, -): bool { - let message = message::new( - source_chain, - message_id, - source_address, - destination_id, - payload_hash, - ); - let command_id = message.command_id(); - - self[command_id] == message_status::approved(message.hash()) -} + public(package) fun is_message_executed(self: &Gateway_v0, source_chain: String, message_id: String): bool { + let command_id = message::message_to_command_id( + source_chain, + message_id, + ); -public(package) fun is_message_executed( - self: &Gateway_v0, - source_chain: String, - message_id: String, -): bool { - let command_id = message::message_to_command_id( - source_chain, - message_id, - ); - - self[command_id] == message_status::executed() -} + self[command_id] == message_status::executed() + } -/// To execute a message, the relayer will call `take_approved_message` -/// to get the hot potato `ApprovedMessage` object, and then trigger the app's -/// package via discovery. -public(package) fun take_approved_message( - self: &mut Gateway_v0, - source_chain: String, - message_id: String, - source_address: String, - destination_id: address, - payload: vector, -): ApprovedMessage { - let command_id = message::message_to_command_id(source_chain, message_id); - - let message = message::new( - source_chain, - message_id, - source_address, - destination_id, - bytes32::from_bytes(hash::keccak256(&payload)), - ); - - assert!( - self[command_id] == message_status::approved(message.hash()), - EMessageNotApproved, - ); - - let message_status_ref = &mut self[command_id]; - *message_status_ref = message_status::executed(); - - events::message_executed( - message, - ); - - channel::create_approved_message( - source_chain, - message_id, - source_address, - destination_id, - payload, - ) -} + /// To execute a message, the relayer will call `take_approved_message` + /// to get the hot potato `ApprovedMessage` object, and then trigger the app's + /// package via discovery. + public(package) fun take_approved_message( + self: &mut Gateway_v0, + source_chain: String, + message_id: String, + source_address: String, + destination_id: address, + payload: vector, + ): ApprovedMessage { + let command_id = message::message_to_command_id(source_chain, message_id); + + let message = message::new( + source_chain, + message_id, + source_address, + destination_id, + bytes32::from_bytes(hash::keccak256(&payload)), + ); -public(package) fun send_message( - _self: &Gateway_v0, - message: MessageTicket, - current_version: u64, -) { - let ( - source_id, - destination_chain, - destination_address, - payload, - version, - ) = message.destroy(); - - assert!(version <= current_version, ENewerMessage); - - events::contract_call( - source_id, - destination_chain, - destination_address, - payload, - address::from_bytes(hash::keccak256(&payload)), - ); -} + assert!(self[command_id] == message_status::approved(message.hash()), EMessageNotApproved); -public(package) fun allow_function( - self: &mut Gateway_v0, - version: u64, - function_name: String, -) { - self.version_control.allow_function(version, function_name); -} + let message_status_ref = &mut self[command_id]; + *message_status_ref = message_status::executed(); -public(package) fun disallow_function( - self: &mut Gateway_v0, - version: u64, - function_name: String, -) { - self.version_control.disallow_function(version, function_name); -} + events::message_executed( + message, + ); -// ----------------- -// Private Functions -// ----------------- + channel::create_approved_message( + source_chain, + message_id, + source_address, + destination_id, + payload, + ) + } -#[syntax(index)] -fun borrow(self: &Gateway_v0, command_id: Bytes32): &MessageStatus { - table::borrow(&self.messages, command_id) -} + public(package) fun send_message(_self: &Gateway_v0, message: MessageTicket, current_version: u64) { + let (source_id, destination_chain, destination_address, payload, version) = message.destroy(); -#[syntax(index)] -fun borrow_mut(self: &mut Gateway_v0, command_id: Bytes32): &mut MessageStatus { - table::borrow_mut(&mut self.messages, command_id) -} + assert!(version <= current_version, ENewerMessage); -fun peel_messages(message_data: vector): vector { - utils::peel!(message_data, |bcs| { - let messages = vector::tabulate!( - bcs.peel_vec_length(), - |_| message::peel(bcs), + events::contract_call( + source_id, + destination_chain, + destination_address, + payload, + address::from_bytes(hash::keccak256(&payload)), ); - assert!(messages.length() > 0, EZeroMessages); - messages - }) -} + } -fun data_hash(command_type: CommandType, data: vector): Bytes32 { - let mut typed_data = vector::singleton(command_type.as_u8()); - typed_data.append(data); + public(package) fun allow_function(self: &mut Gateway_v0, version: u64, function_name: String) { + self.version_control.allow_function(version, function_name); + } - bytes32::from_bytes(hash::keccak256(&typed_data)) -} + public(package) fun disallow_function(self: &mut Gateway_v0, version: u64, function_name: String) { + self.version_control.disallow_function(version, function_name); + } -fun approve_message(self: &mut Gateway_v0, message: message::Message) { - let command_id = message.command_id(); + // ----------------- + // Private Functions + // ----------------- - // If the message was already approved, ignore it. - if (self.messages.contains(command_id)) { - return - }; + #[syntax(index)] + fun borrow(self: &Gateway_v0, command_id: Bytes32): &MessageStatus { + table::borrow(&self.messages, command_id) + } + + #[syntax(index)] + fun borrow_mut(self: &mut Gateway_v0, command_id: Bytes32): &mut MessageStatus { + table::borrow_mut(&mut self.messages, command_id) + } + + fun peel_messages(message_data: vector): vector { + utils::peel!(message_data, |bcs| { + let messages = vector::tabulate!(bcs.peel_vec_length(), |_| message::peel(bcs)); + assert!(messages.length() > 0, EZeroMessages); + messages + }) + } + + fun data_hash(command_type: CommandType, data: vector): Bytes32 { + let mut typed_data = vector::singleton(command_type.as_u8()); + typed_data.append(data); + + bytes32::from_bytes(hash::keccak256(&typed_data)) + } - self - .messages - .add( - command_id, - message_status::approved(message.hash()), + fun approve_message(self: &mut Gateway_v0, message: message::Message) { + let command_id = message.command_id(); + + // If the message was already approved, ignore it. + if (self.messages.contains(command_id)) { + return + }; + + self + .messages + .add( + command_id, + message_status::approved(message.hash()), + ); + + events::message_approved( + message, ); + } - events::message_approved( - message, - ); -} + fun as_u8(self: CommandType): u8 { + match (self) { + CommandType::ApproveMessages => 0, + CommandType::RotateSigners => 1, + } + } -fun as_u8(self: CommandType): u8 { - match (self) { - CommandType::ApproveMessages => 0, - CommandType::RotateSigners => 1, + /// --------- + /// Test Only + /// --------- + #[test_only] + use axelar_gateway::weighted_signers::WeightedSigners; + #[test_only] + use sui::bcs; + + #[test_only] + public(package) fun messages_mut(self: &mut Gateway_v0): &mut Table { + &mut self.messages } -} -/// --------- -/// Test Only -/// --------- -#[test_only] -use axelar_gateway::weighted_signers::WeightedSigners; -#[test_only] -use sui::bcs; - -#[test_only] -public(package) fun messages_mut( - self: &mut Gateway_v0, -): &mut Table { - &mut self.messages -} + #[test_only] + public(package) fun signers_mut(self: &mut Gateway_v0): &mut AxelarSigners { + &mut self.signers + } -#[test_only] -public(package) fun signers_mut(self: &mut Gateway_v0): &mut AxelarSigners { - &mut self.signers -} + #[test_only] + public(package) fun destroy_for_testing(self: Gateway_v0): (address, Table, AxelarSigners, VersionControl) { + let Gateway_v0 { + operator, + messages, + signers, + version_control, + } = self; + (operator, messages, signers, version_control) + } -#[test_only] -public(package) fun destroy_for_testing( - self: Gateway_v0, -): (address, Table, AxelarSigners, VersionControl) { - let Gateway_v0 { - operator, - messages, - signers, - version_control, - } = self; - (operator, messages, signers, version_control) -} + #[test_only] + fun dummy(ctx: &mut TxContext): Gateway_v0 { + new( + @0x0, + sui::table::new(ctx), + axelar_gateway::auth::dummy(ctx), + version_control::version_control::new(vector[]), + ) + } -#[test_only] -fun dummy(ctx: &mut TxContext): Gateway_v0 { - new( - @0x0, - sui::table::new(ctx), - axelar_gateway::auth::dummy(ctx), - version_control::version_control::new(vector[]), - ) -} + #[test_only] + public(package) fun approve_messages_data_hash(messages: vector): Bytes32 { + data_hash(CommandType::ApproveMessages, bcs::to_bytes(&messages)) + } -#[test_only] -public(package) fun approve_messages_data_hash( - messages: vector, -): Bytes32 { - data_hash(CommandType::ApproveMessages, bcs::to_bytes(&messages)) -} + #[test_only] + public(package) fun rotate_signers_data_hash(weighted_signers: WeightedSigners): Bytes32 { + data_hash(CommandType::RotateSigners, bcs::to_bytes(&weighted_signers)) + } -#[test_only] -public(package) fun rotate_signers_data_hash( - weighted_signers: WeightedSigners, -): Bytes32 { - data_hash(CommandType::RotateSigners, bcs::to_bytes(&weighted_signers)) -} + #[test_only] + public(package) fun approve_message_for_testing(self: &mut Gateway_v0, message: Message) { + self.approve_message(message); + } -#[test_only] -public(package) fun approve_message_for_testing( - self: &mut Gateway_v0, - message: Message, -) { - self.approve_message(message); -} + /// ----- + /// Tests + /// ----- + #[test] + #[expected_failure(abort_code = EZeroMessages)] + fun test_peel_messages_no_zero_messages() { + peel_messages(sui::bcs::to_bytes(&vector[])); + } -/// ----- -/// Tests -/// ----- -#[test] -#[expected_failure(abort_code = EZeroMessages)] -fun test_peel_messages_no_zero_messages() { - peel_messages(sui::bcs::to_bytes(&vector[])); -} + #[test] + fun test_approve_message() { + let mut rng = sui::random::new_generator_for_testing(); + let ctx = &mut sui::tx_context::dummy(); + + let message_id = std::ascii::string(b"Message Id"); + let channel = axelar_gateway::channel::new(ctx); + let source_chain = std::ascii::string(b"Source Chain"); + let source_address = std::ascii::string(b"Destination Address"); + let payload = rng.generate_bytes(32); + let payload_hash = axelar_gateway::bytes32::new( + sui::address::from_bytes(hash::keccak256(&payload)), + ); -#[test] -fun test_approve_message() { - let mut rng = sui::random::new_generator_for_testing(); - let ctx = &mut sui::tx_context::dummy(); - - let message_id = std::ascii::string(b"Message Id"); - let channel = axelar_gateway::channel::new(ctx); - let source_chain = std::ascii::string(b"Source Chain"); - let source_address = std::ascii::string(b"Destination Address"); - let payload = rng.generate_bytes(32); - let payload_hash = axelar_gateway::bytes32::new( - sui::address::from_bytes(hash::keccak256(&payload)), - ); - - let message = message::new( - source_chain, - message_id, - source_address, - channel.to_address(), - payload_hash, - ); - - let mut data = dummy(ctx); - - data.approve_message(message); - // The second approve message should do nothing. - data.approve_message(message); - - assert!( - data.is_message_approved( + let message = message::new( + source_chain, + message_id, + source_address, + channel.to_address(), + payload_hash, + ); + + let mut data = dummy(ctx); + + data.approve_message(message); + // The second approve message should do nothing. + data.approve_message(message); + + assert!( + data.is_message_approved( source_chain, message_id, source_address, @@ -407,21 +355,21 @@ fun test_approve_message() { payload_hash, ) == true, - EMessageNotApproved, - ); + EMessageNotApproved, + ); - let approved_message = data.take_approved_message( - source_chain, - message_id, - source_address, - channel.to_address(), - payload, - ); + let approved_message = data.take_approved_message( + source_chain, + message_id, + source_address, + channel.to_address(), + payload, + ); - channel.consume_approved_message(approved_message); + channel.consume_approved_message(approved_message); - assert!( - data.is_message_approved( + assert!( + data.is_message_approved( source_chain, message_id, source_address, @@ -429,139 +377,137 @@ fun test_approve_message() { payload_hash, ) == false, - EMessageNotApproved, - ); + EMessageNotApproved, + ); - assert!( - data.is_message_executed( + assert!(data.is_message_executed( source_chain, message_id, ) == - true, - EMessageNotApproved, - ); + true, EMessageNotApproved); - data.messages.remove(message.command_id()); + data.messages.remove(message.command_id()); - sui::test_utils::destroy(data); - channel.destroy(); -} + sui::test_utils::destroy(data); + channel.destroy(); + } -#[test] -fun test_peel_messages() { - let message1 = message::new( - std::ascii::string(b"Source Chain 1"), - std::ascii::string(b"Message Id 1"), - std::ascii::string(b"Source Address 1"), - @0x1, - axelar_gateway::bytes32::new(@0x2), - ); - - let message2 = message::new( - std::ascii::string(b"Source Chain 2"), - std::ascii::string(b"Message Id 2"), - std::ascii::string(b"Source Address 2"), - @0x3, - axelar_gateway::bytes32::new(@0x4), - ); - - let bytes = sui::bcs::to_bytes(&vector[message1, message2]); - - let messages = peel_messages(bytes); - - assert!(messages.length() == 2); - assert!(messages[0] == message1); - assert!(messages[1] == message2); -} + #[test] + fun test_peel_messages() { + let message1 = message::new( + std::ascii::string(b"Source Chain 1"), + std::ascii::string(b"Message Id 1"), + std::ascii::string(b"Source Address 1"), + @0x1, + axelar_gateway::bytes32::new(@0x2), + ); -#[test] -#[expected_failure] -fun test_peel_messages_no_remaining_data() { - let message1 = message::new( - std::ascii::string(b"Source Chain 1"), - std::ascii::string(b"Message Id 1"), - std::ascii::string(b"Source Address 1"), - @0x1, - axelar_gateway::bytes32::new(@0x2), - ); - - let mut bytes = sui::bcs::to_bytes(&vector[message1]); - bytes.push_back(0); - - peel_messages(bytes); -} + let message2 = message::new( + std::ascii::string(b"Source Chain 2"), + std::ascii::string(b"Message Id 2"), + std::ascii::string(b"Source Address 2"), + @0x3, + axelar_gateway::bytes32::new(@0x4), + ); -#[test] -fun test_command_type_as_u8() { - // Note: These must not be changed to avoid breaking Amplifier integration - assert!(CommandType::ApproveMessages.as_u8() == 0); - assert!(CommandType::RotateSigners.as_u8() == 1); -} + let bytes = sui::bcs::to_bytes(&vector[message1, message2]); -#[test] -fun test_data_hash() { - let mut rng = sui::random::new_generator_for_testing(); - let data = rng.generate_bytes(32); - let mut typed_data = vector::singleton(CommandType::ApproveMessages.as_u8()); - typed_data.append(data); + let messages = peel_messages(bytes); - assert!( - data_hash(CommandType::ApproveMessages, data) == - bytes32::from_bytes(hash::keccak256(&typed_data)), - EMessageNotApproved, - ); -} + assert!(messages.length() == 2); + assert!(messages[0] == message1); + assert!(messages[1] == message2); + } -#[test] -#[expected_failure(abort_code = ENewerMessage)] -fun test_send_message_newer_message() { - let mut rng = sui::random::new_generator_for_testing(); - let source_id = address::from_u256(rng.generate_u256()); - let destination_chain = std::ascii::string(b"Destination Chain"); - let destination_address = std::ascii::string(b"Destination Address"); - let payload = rng.generate_bytes(32); - let version = 1; - let message = axelar_gateway::message_ticket::new( - source_id, - destination_chain, - destination_address, - payload, - version, - ); - let ctx = &mut sui::tx_context::dummy(); - let self = dummy(ctx); - self.send_message(message, 0); - sui::test_utils::destroy(self); -} + #[test] + #[expected_failure] + fun test_peel_messages_no_remaining_data() { + let message1 = message::new( + std::ascii::string(b"Source Chain 1"), + std::ascii::string(b"Message Id 1"), + std::ascii::string(b"Source Address 1"), + @0x1, + axelar_gateway::bytes32::new(@0x2), + ); + + let mut bytes = sui::bcs::to_bytes(&vector[message1]); + bytes.push_back(0); -#[test] -#[expected_failure(abort_code = EMessageNotApproved)] -fun test_take_approved_message_message_not_approved() { - let mut rng = sui::random::new_generator_for_testing(); - let destination_id = address::from_u256(rng.generate_u256()); - let source_chain = std::ascii::string(b"Source Chain"); - let source_address = std::ascii::string(b"Source Address"); - let message_id = std::ascii::string(b"Message Id"); - let payload = rng.generate_bytes(32); - let command_id = message::message_to_command_id(source_chain, message_id); - - let ctx = &mut sui::tx_context::dummy(); - let mut self = dummy(ctx); - - self - .messages - .add( - command_id, - message_status::executed(), + peel_messages(bytes); + } + + #[test] + fun test_command_type_as_u8() { + // Note: These must not be changed to avoid breaking Amplifier integration + assert!(CommandType::ApproveMessages.as_u8() == 0); + assert!(CommandType::RotateSigners.as_u8() == 1); + } + + #[test] + fun test_data_hash() { + let mut rng = sui::random::new_generator_for_testing(); + let data = rng.generate_bytes(32); + let mut typed_data = vector::singleton(CommandType::ApproveMessages.as_u8()); + typed_data.append(data); + + assert!( + data_hash(CommandType::ApproveMessages, data) == + bytes32::from_bytes(hash::keccak256(&typed_data)), + EMessageNotApproved, ); + } - let approved_message = self.take_approved_message( - source_chain, - message_id, - source_address, - destination_id, - payload, - ); - sui::test_utils::destroy(self); - sui::test_utils::destroy(approved_message); + #[test] + #[expected_failure(abort_code = ENewerMessage)] + fun test_send_message_newer_message() { + let mut rng = sui::random::new_generator_for_testing(); + let source_id = address::from_u256(rng.generate_u256()); + let destination_chain = std::ascii::string(b"Destination Chain"); + let destination_address = std::ascii::string(b"Destination Address"); + let payload = rng.generate_bytes(32); + let version = 1; + let message = axelar_gateway::message_ticket::new( + source_id, + destination_chain, + destination_address, + payload, + version, + ); + let ctx = &mut sui::tx_context::dummy(); + let self = dummy(ctx); + self.send_message(message, 0); + sui::test_utils::destroy(self); + } + + #[test] + #[expected_failure(abort_code = EMessageNotApproved)] + fun test_take_approved_message_message_not_approved() { + let mut rng = sui::random::new_generator_for_testing(); + let destination_id = address::from_u256(rng.generate_u256()); + let source_chain = std::ascii::string(b"Source Chain"); + let source_address = std::ascii::string(b"Source Address"); + let message_id = std::ascii::string(b"Message Id"); + let payload = rng.generate_bytes(32); + let command_id = message::message_to_command_id(source_chain, message_id); + + let ctx = &mut sui::tx_context::dummy(); + let mut self = dummy(ctx); + + self + .messages + .add( + command_id, + message_status::executed(), + ); + + let approved_message = self.take_approved_message( + source_chain, + message_id, + source_address, + destination_id, + payload, + ); + sui::test_utils::destroy(self); + sui::test_utils::destroy(approved_message); + } } diff --git a/move/example/sources/gmp/gmp.move b/move/example/sources/gmp/gmp.move index c23426a8..bb2f45d1 100644 --- a/move/example/sources/gmp/gmp.move +++ b/move/example/sources/gmp/gmp.move @@ -1,102 +1,88 @@ -module example::gmp; +module example::gmp { + use axelar_gateway::{channel::{Self, Channel, ApprovedMessage}, gateway::{Self, Gateway}}; + use example::utils::concat; + use gas_service::gas_service::GasService; + use relayer_discovery::{discovery::RelayerDiscovery, transaction}; + use std::{ascii::{Self, String}, type_name}; + use sui::{address, coin::Coin, event, hex, sui::SUI}; -use axelar_gateway::channel::{Self, Channel, ApprovedMessage}; -use axelar_gateway::gateway::{Self, Gateway}; -use example::utils::concat; -use gas_service::gas_service::GasService; -use relayer_discovery::discovery::RelayerDiscovery; -use relayer_discovery::transaction; -use std::ascii::{Self, String}; -use std::type_name; -use sui::address; -use sui::coin::Coin; -use sui::event; -use sui::hex; -use sui::sui::SUI; + public struct Singleton has key { + id: UID, + channel: Channel, + } -public struct Singleton has key { - id: UID, - channel: Channel, -} - -public struct Executed has copy, drop { - data: vector, -} + public struct Executed has copy, drop { + data: vector, + } -fun init(ctx: &mut TxContext) { - let singletonId = object::new(ctx); - let channel = channel::new(ctx); - transfer::share_object(Singleton { - id: singletonId, - channel, - }); -} + fun init(ctx: &mut TxContext) { + let singletonId = object::new(ctx); + let channel = channel::new(ctx); + transfer::share_object(Singleton { + id: singletonId, + channel, + }); + } -public fun register_transaction( - discovery: &mut RelayerDiscovery, - singleton: &Singleton, -) { - let arguments = - vector[ - vector[2u8], - concat(vector[0u8], object::id_address(singleton).to_bytes()), - ]; + public fun register_transaction(discovery: &mut RelayerDiscovery, singleton: &Singleton) { + let arguments = vector[vector[2u8], concat(vector[0u8], object::id_address(singleton).to_bytes())]; - let transaction = transaction::new_transaction( - true, - vector[ - transaction::new_move_call( - transaction::new_function( - address::from_bytes( - hex::decode( - *ascii::as_bytes( - &type_name::get_address( - &type_name::get(), + let transaction = transaction::new_transaction( + true, + vector[ + transaction::new_move_call( + transaction::new_function( + address::from_bytes( + hex::decode( + *ascii::as_bytes( + &type_name::get_address( + &type_name::get(), + ), ), ), ), + ascii::string(b"gmp"), + ascii::string(b"execute"), ), - ascii::string(b"gmp"), - ascii::string(b"execute"), + arguments, + vector[], ), - arguments, - vector[], - ), - ], - ); - discovery.register_transaction(&singleton.channel, transaction); -} + ], + ); + discovery.register_transaction(&singleton.channel, transaction); + } -public fun send_call( - singleton: &Singleton, - gateway: &Gateway, - gas_service: &mut GasService, - destination_chain: String, - destination_address: String, - payload: vector, - refund_address: address, - coin: Coin, - params: vector, -) { - let message_ticket = gateway::prepare_message( - &singleton.channel, - destination_chain, - destination_address, - payload, - ); + public fun send_call( + singleton: &Singleton, + gateway: &Gateway, + gas_service: &mut GasService, + destination_chain: String, + destination_address: String, + payload: vector, + refund_address: address, + coin: Coin, + params: vector, + ) { + let message_ticket = gateway::prepare_message( + &singleton.channel, + destination_chain, + destination_address, + payload, + ); - gas_service.pay_gas( - &message_ticket, - coin, - refund_address, - params, - ); + gas_service.pay_gas( + &message_ticket, + coin, + refund_address, + params, + ); - gateway.send_message(message_ticket); -} + gateway.send_message(message_ticket); + } -public fun execute(call: ApprovedMessage, singleton: &mut Singleton) { - let (_, _, _, payload) = singleton.channel.consume_approved_message(call); + public fun execute(call: ApprovedMessage, singleton: &mut Singleton) { + let (_, _, _, payload) = singleton.channel.consume_approved_message(call); - event::emit(Executed { data: payload }); + event::emit(Executed { data: payload }); + } } diff --git a/move/example/sources/its/its.move b/move/example/sources/its/its.move index f9ac2b1f..382561e7 100644 --- a/move/example/sources/its/its.move +++ b/move/example/sources/its/its.move @@ -1,277 +1,252 @@ -module example::its; - -use axelar_gateway::channel::{Self, ApprovedMessage, Channel}; -use axelar_gateway::gateway::{Self, Gateway}; -use axelar_gateway::message_ticket::MessageTicket; -use example::utils::concat; -use gas_service::gas_service::GasService; -use interchain_token_service::coin_info; -use interchain_token_service::coin_management; -use interchain_token_service::discovery as its_discovery; -use interchain_token_service::interchain_token_service::{Self, InterchainTokenService}; -use interchain_token_service::token_id::TokenId; -use relayer_discovery::discovery::RelayerDiscovery; -use relayer_discovery::transaction::{Self, Transaction}; -use std::ascii::{Self, String}; -use std::type_name; -use sui::address; -use sui::clock::Clock; -use sui::coin::{CoinMetadata, Coin}; -use sui::event; -use sui::hex; -use sui::sui::SUI; - -// ------- -// Structs -// ------- -public struct Singleton has key { - id: UID, - channel: Channel, -} - -public struct ExecutedWithToken has copy, drop { - source_chain: String, - source_address: vector, - data: vector, - amount: u64, -} - -/// ----- -/// Setup -/// ----- -fun init(ctx: &mut TxContext) { - let singletonId = object::new(ctx); - let channel = channel::new(ctx); - transfer::share_object(Singleton { - id: singletonId, - channel, - }); -} - -// ----- -// Public Functions -// ----- - -/// This needs to be called to register the transaction so that the relayer -/// knows to call this to fulfill calls. -public fun register_transaction( - discovery: &mut RelayerDiscovery, - singleton: &Singleton, - its: &InterchainTokenService, - clock: &Clock, -) { - let arguments = vector[ - concat(vector[0u8], object::id_address(singleton).to_bytes()), - concat(vector[0u8], object::id_address(its).to_bytes()), - vector[3u8], - concat(vector[0u8], object::id_address(clock).to_bytes()), - ]; - - let transaction = transaction::new_transaction( - false, - vector[ - transaction::new_move_call( - transaction::new_function( - address::from_bytes( - hex::decode( - *ascii::as_bytes( - &type_name::get_address( - &type_name::get(), +module example::its { + use axelar_gateway::{channel::{Self, ApprovedMessage, Channel}, gateway::{Self, Gateway}, message_ticket::MessageTicket}; + use example::utils::concat; + use gas_service::gas_service::GasService; + use interchain_token_service::{ + coin_info, + coin_management, + discovery as its_discovery, + interchain_token_service::{Self, InterchainTokenService}, + token_id::TokenId + }; + use relayer_discovery::{discovery::RelayerDiscovery, transaction::{Self, Transaction}}; + use std::{ascii::{Self, String}, type_name}; + use sui::{address, clock::Clock, coin::{CoinMetadata, Coin}, event, hex, sui::SUI}; + + // ------- + // Structs + // ------- + public struct Singleton has key { + id: UID, + channel: Channel, + } + + public struct ExecutedWithToken has copy, drop { + source_chain: String, + source_address: vector, + data: vector, + amount: u64, + } + + /// ----- + /// Setup + /// ----- + fun init(ctx: &mut TxContext) { + let singletonId = object::new(ctx); + let channel = channel::new(ctx); + transfer::share_object(Singleton { + id: singletonId, + channel, + }); + } + + // ----- + // Public Functions + // ----- + + /// This needs to be called to register the transaction so that the relayer + /// knows to call this to fulfill calls. + public fun register_transaction(discovery: &mut RelayerDiscovery, singleton: &Singleton, its: &InterchainTokenService, clock: &Clock) { + let arguments = vector[ + concat(vector[0u8], object::id_address(singleton).to_bytes()), + concat(vector[0u8], object::id_address(its).to_bytes()), + vector[3u8], + concat(vector[0u8], object::id_address(clock).to_bytes()), + ]; + + let transaction = transaction::new_transaction( + false, + vector[ + transaction::new_move_call( + transaction::new_function( + address::from_bytes( + hex::decode( + *ascii::as_bytes( + &type_name::get_address( + &type_name::get(), + ), ), ), ), + ascii::string(b"its"), + ascii::string(b"get_final_transaction"), ), - ascii::string(b"its"), - ascii::string(b"get_final_transaction"), + arguments, + vector[], ), - arguments, - vector[], - ), - ], - ); - - discovery.register_transaction(&singleton.channel, transaction); -} - -public fun get_final_transaction( - singleton: &Singleton, - its: &InterchainTokenService, - payload: vector, - clock: &Clock, -): Transaction { - let arguments = vector[ - vector[2u8], - concat(vector[0u8], object::id_address(singleton).to_bytes()), - concat(vector[0u8], object::id_address(its).to_bytes()), - concat(vector[0u8], object::id_address(clock).to_bytes()), - ]; - - // Get the coin type from its - let (token_id, _, _, _) = its_discovery::interchain_transfer_info( - payload, - ); - let coin_type = (*its.registered_coin_type(token_id)).into_string(); - - let transaction = transaction::new_transaction( - true, - vector[ - transaction::new_move_call( - transaction::new_function( - address::from_bytes( - hex::decode( - *ascii::as_bytes( - &type_name::get_address( - &type_name::get(), + ], + ); + + discovery.register_transaction(&singleton.channel, transaction); + } + + public fun get_final_transaction(singleton: &Singleton, its: &InterchainTokenService, payload: vector, clock: &Clock): Transaction { + let arguments = vector[ + vector[2u8], + concat(vector[0u8], object::id_address(singleton).to_bytes()), + concat(vector[0u8], object::id_address(its).to_bytes()), + concat(vector[0u8], object::id_address(clock).to_bytes()), + ]; + + // Get the coin type from its + let (token_id, _, _, _) = its_discovery::interchain_transfer_info( + payload, + ); + let coin_type = (*its.registered_coin_type(token_id)).into_string(); + + let transaction = transaction::new_transaction( + true, + vector[ + transaction::new_move_call( + transaction::new_function( + address::from_bytes( + hex::decode( + *ascii::as_bytes( + &type_name::get_address( + &type_name::get(), + ), ), ), ), + ascii::string(b"its"), + ascii::string(b"receive_interchain_transfer"), ), - ascii::string(b"its"), - ascii::string(b"receive_interchain_transfer"), + arguments, + vector[coin_type], ), - arguments, - vector[coin_type], - ), - ], - ); - - transaction -} - -/// This function needs to be called first to register the coin for either of -/// the other two functions to work. -public fun register_coin( - its: &mut InterchainTokenService, - coin_metadata: &CoinMetadata, -): TokenId { - let coin_info = coin_info::from_info( - coin_metadata.get_name(), - coin_metadata.get_symbol(), - coin_metadata.get_decimals(), - ); - let coin_management = coin_management::new_locked(); - - its.register_coin( - coin_info, - coin_management, - ) -} - -public fun deploy_remote_interchain_token( - its: &mut InterchainTokenService, - gateway: &mut Gateway, - gas_service: &mut GasService, - destination_chain: String, - token_id: TokenId, - gas: Coin, - gas_params: vector, - refund_address: address, -) { - let message_ticket = its.deploy_remote_interchain_token( - token_id, - destination_chain, - ); - - pay_gas_and_send_message( - gateway, - gas_service, - gas, - message_ticket, - refund_address, - gas_params, - ); -} - -/// This should trigger an interchain trasnfer. -public fun send_interchain_transfer_call( - singleton: &Singleton, - its: &mut InterchainTokenService, - gateway: &mut Gateway, - gas_service: &mut GasService, - token_id: TokenId, - coin: Coin, - destination_chain: String, - destination_address: vector, - metadata: vector, - refund_address: address, - gas: Coin, - gas_params: vector, - clock: &Clock, -) { - let interchain_transfer_ticket = interchain_token_service::prepare_interchain_transfer( - token_id, - coin, - destination_chain, - destination_address, - metadata, - &singleton.channel, - ); - - let message_ticket = its.send_interchain_transfer( - interchain_transfer_ticket, - clock, - ); - - pay_gas_and_send_message( - gateway, - gas_service, - gas, - message_ticket, - refund_address, - gas_params, - ); -} - -/// This should receive some coins, give them to the executor, and emit and -/// event with all the relevant info. -#[allow(lint(self_transfer))] -public fun receive_interchain_transfer( - approved_message: ApprovedMessage, - singleton: &Singleton, - its: &mut InterchainTokenService, - clock: &Clock, - ctx: &mut TxContext, -) { - let ( - source_chain, - source_address, - data, - coin, - ) = its.receive_interchain_transfer_with_data( - approved_message, - &singleton.channel, - clock, - ctx, - ); - - event::emit(ExecutedWithToken { - source_chain, - source_address, - data, - amount: coin.value(), - }); - - // give the coin to the caller - transfer::public_transfer(coin, ctx.sender()); -} - -// ----- -// Internal Functions -// ----- -fun pay_gas_and_send_message( - gateway: &Gateway, - gas_service: &mut GasService, - gas: Coin, - message_ticket: MessageTicket, - refund_address: address, - gas_params: vector, -) { - gas_service.pay_gas( - &message_ticket, - gas, - refund_address, - gas_params, - ); - - gateway::send_message(gateway, message_ticket); + ], + ); + + transaction + } + + /// This function needs to be called first to register the coin for either of + /// the other two functions to work. + public fun register_coin(its: &mut InterchainTokenService, coin_metadata: &CoinMetadata): TokenId { + let coin_info = coin_info::from_info( + coin_metadata.get_name(), + coin_metadata.get_symbol(), + coin_metadata.get_decimals(), + ); + let coin_management = coin_management::new_locked(); + + its.register_coin( + coin_info, + coin_management, + ) + } + + public fun deploy_remote_interchain_token( + its: &mut InterchainTokenService, + gateway: &mut Gateway, + gas_service: &mut GasService, + destination_chain: String, + token_id: TokenId, + gas: Coin, + gas_params: vector, + refund_address: address, + ) { + let message_ticket = its.deploy_remote_interchain_token( + token_id, + destination_chain, + ); + + pay_gas_and_send_message( + gateway, + gas_service, + gas, + message_ticket, + refund_address, + gas_params, + ); + } + + /// This should trigger an interchain trasnfer. + public fun send_interchain_transfer_call( + singleton: &Singleton, + its: &mut InterchainTokenService, + gateway: &mut Gateway, + gas_service: &mut GasService, + token_id: TokenId, + coin: Coin, + destination_chain: String, + destination_address: vector, + metadata: vector, + refund_address: address, + gas: Coin, + gas_params: vector, + clock: &Clock, + ) { + let interchain_transfer_ticket = interchain_token_service::prepare_interchain_transfer( + token_id, + coin, + destination_chain, + destination_address, + metadata, + &singleton.channel, + ); + + let message_ticket = its.send_interchain_transfer( + interchain_transfer_ticket, + clock, + ); + + pay_gas_and_send_message( + gateway, + gas_service, + gas, + message_ticket, + refund_address, + gas_params, + ); + } + + /// This should receive some coins, give them to the executor, and emit and + /// event with all the relevant info. + #[allow(lint(self_transfer))] + public fun receive_interchain_transfer( + approved_message: ApprovedMessage, + singleton: &Singleton, + its: &mut InterchainTokenService, + clock: &Clock, + ctx: &mut TxContext, + ) { + let (source_chain, source_address, data, coin) = its.receive_interchain_transfer_with_data( + approved_message, + &singleton.channel, + clock, + ctx, + ); + + event::emit(ExecutedWithToken { + source_chain, + source_address, + data, + amount: coin.value(), + }); + + // give the coin to the caller + transfer::public_transfer(coin, ctx.sender()); + } + + // ----- + // Internal Functions + // ----- + fun pay_gas_and_send_message( + gateway: &Gateway, + gas_service: &mut GasService, + gas: Coin, + message_ticket: MessageTicket, + refund_address: address, + gas_params: vector, + ) { + gas_service.pay_gas( + &message_ticket, + gas, + refund_address, + gas_params, + ); + + gateway::send_message(gateway, message_ticket); + } } diff --git a/move/example/sources/its/token.move b/move/example/sources/its/token.move index be04f4b4..8ca34846 100644 --- a/move/example/sources/its/token.move +++ b/move/example/sources/its/token.move @@ -1,34 +1,29 @@ -module example::token; +module example::token { + use sui::coin::{Self, TreasuryCap}; -use sui::coin::{Self, TreasuryCap}; + // ------------ + // Capabilities + // ------------ + public struct TOKEN has drop {} -// ------------ -// Capabilities -// ------------ -public struct TOKEN has drop {} + // ----- + // Setup + // ----- + fun init(witness: TOKEN, ctx: &mut TxContext) { + let (treasury_cap, coin_metadata) = coin::create_currency( + witness, + 9, + b"InterchainTokenService", + b"InterchainTokenService Example Coin", + b"", + option::none(), + ctx, + ); + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); + transfer::public_transfer(coin_metadata, tx_context::sender(ctx)); + } -// ----- -// Setup -// ----- -fun init(witness: TOKEN, ctx: &mut TxContext) { - let (treasury_cap, coin_metadata) = coin::create_currency( - witness, - 9, - b"InterchainTokenService", - b"InterchainTokenService Example Coin", - b"", - option::none(), - ctx, - ); - transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); - transfer::public_transfer(coin_metadata, tx_context::sender(ctx)); -} - -public fun mint( - treasury_cap: &mut TreasuryCap, - amount: u64, - to: address, - ctx: &mut TxContext, -) { - treasury_cap.mint_and_transfer(amount, to, ctx); + public fun mint(treasury_cap: &mut TreasuryCap, amount: u64, to: address, ctx: &mut TxContext) { + treasury_cap.mint_and_transfer(amount, to, ctx); + } } diff --git a/move/example/sources/squid/token_a.move b/move/example/sources/squid/token_a.move index cd488ae9..e8129a41 100644 --- a/move/example/sources/squid/token_a.move +++ b/move/example/sources/squid/token_a.move @@ -1,25 +1,25 @@ -module example::token_a; +module example::token_a { + use sui::coin; -use sui::coin; + // ------------ + // Capabilities + // ------------ + public struct TOKEN_A has drop {} -// ------------ -// Capabilities -// ------------ -public struct TOKEN_A has drop {} - -// ----- -// Setup -// ----- -fun init(witness: TOKEN_A, ctx: &mut TxContext) { - let (treasury_cap, coin_metadata) = coin::create_currency( - witness, - 9, - b"TOKEN1", - b"Token 1", - b"", - option::none(), - ctx, - ); - transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); - transfer::public_transfer(coin_metadata, tx_context::sender(ctx)); + // ----- + // Setup + // ----- + fun init(witness: TOKEN_A, ctx: &mut TxContext) { + let (treasury_cap, coin_metadata) = coin::create_currency( + witness, + 9, + b"TOKEN1", + b"Token 1", + b"", + option::none(), + ctx, + ); + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); + transfer::public_transfer(coin_metadata, tx_context::sender(ctx)); + } } diff --git a/move/example/sources/squid/token_b.move b/move/example/sources/squid/token_b.move index 1f2f7e09..a448dbe8 100644 --- a/move/example/sources/squid/token_b.move +++ b/move/example/sources/squid/token_b.move @@ -1,25 +1,25 @@ -module example::token_b; +module example::token_b { + use sui::coin; -use sui::coin; + // ------------ + // Capabilities + // ------------ + public struct TOKEN_B has drop {} -// ------------ -// Capabilities -// ------------ -public struct TOKEN_B has drop {} - -// ----- -// Setup -// ----- -fun init(witness: TOKEN_B, ctx: &mut TxContext) { - let (treasury_cap, coin_metadata) = coin::create_currency( - witness, - 9, - b"TOKEN2", - b"Token 2", - b"", - option::none(), - ctx, - ); - transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); - transfer::public_transfer(coin_metadata, tx_context::sender(ctx)); + // ----- + // Setup + // ----- + fun init(witness: TOKEN_B, ctx: &mut TxContext) { + let (treasury_cap, coin_metadata) = coin::create_currency( + witness, + 9, + b"TOKEN2", + b"Token 2", + b"", + option::none(), + ctx, + ); + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); + transfer::public_transfer(coin_metadata, tx_context::sender(ctx)); + } } diff --git a/move/example/sources/squid/token_c.move b/move/example/sources/squid/token_c.move index 8c3630d5..efac939a 100644 --- a/move/example/sources/squid/token_c.move +++ b/move/example/sources/squid/token_c.move @@ -1,25 +1,25 @@ -module example::token_c; +module example::token_c { + use sui::coin; -use sui::coin; + // ------------ + // Capabilities + // ------------ + public struct TOKEN_C has drop {} -// ------------ -// Capabilities -// ------------ -public struct TOKEN_C has drop {} - -// ----- -// Setup -// ----- -fun init(witness: TOKEN_C, ctx: &mut TxContext) { - let (treasury_cap, coin_metadata) = coin::create_currency( - witness, - 9, - b"TOKEN3", - b"Token 3", - b"", - option::none(), - ctx, - ); - transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); - transfer::public_transfer(coin_metadata, tx_context::sender(ctx)); + // ----- + // Setup + // ----- + fun init(witness: TOKEN_C, ctx: &mut TxContext) { + let (treasury_cap, coin_metadata) = coin::create_currency( + witness, + 9, + b"TOKEN3", + b"Token 3", + b"", + option::none(), + ctx, + ); + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); + transfer::public_transfer(coin_metadata, tx_context::sender(ctx)); + } } diff --git a/move/example/sources/utils.move b/move/example/sources/utils.move index 8911ecf4..15f1c714 100644 --- a/move/example/sources/utils.move +++ b/move/example/sources/utils.move @@ -1,10 +1,10 @@ -module example::utils; - -/// ------ -/// Public Functions -/// ------ -public(package) fun concat(v1: vector, v2: vector): vector { - let mut result = v1; - result.append(v2); - result +module example::utils { + /// ------ + /// Public Functions + /// ------ + public(package) fun concat(v1: vector, v2: vector): vector { + let mut result = v1; + result.append(v2); + result + } } diff --git a/move/gas_service/sources/events.move b/move/gas_service/sources/events.move index 00b196db..fafe2d2e 100644 --- a/move/gas_service/sources/events.move +++ b/move/gas_service/sources/events.move @@ -1,89 +1,80 @@ -module gas_service::events; +module gas_service::events { + use std::ascii::String; + use sui::event; -use std::ascii::String; -use sui::event; + // ------ + // Events + // ------ + public struct GasPaid has copy, drop { + sender: address, + destination_chain: String, + destination_address: String, + payload_hash: address, + value: u64, + refund_address: address, + params: vector, + } -// ------ -// Events -// ------ -public struct GasPaid has copy, drop { - sender: address, - destination_chain: String, - destination_address: String, - payload_hash: address, - value: u64, - refund_address: address, - params: vector, -} - -public struct GasAdded has copy, drop { - message_id: String, - value: u64, - refund_address: address, - params: vector, -} + public struct GasAdded has copy, drop { + message_id: String, + value: u64, + refund_address: address, + params: vector, + } -public struct Refunded has copy, drop { - message_id: String, - value: u64, - refund_address: address, -} + public struct Refunded has copy, drop { + message_id: String, + value: u64, + refund_address: address, + } -public struct GasCollected has copy, drop { - receiver: address, - value: u64, -} + public struct GasCollected has copy, drop { + receiver: address, + value: u64, + } -// Package Functions -public(package) fun gas_paid( - sender: address, - destination_chain: String, - destination_address: String, - payload_hash: address, - value: u64, - refund_address: address, - params: vector, -) { - event::emit(GasPaid { - sender, - destination_chain, - destination_address, - payload_hash, - value, - refund_address, - params, - }); -} + // Package Functions + public(package) fun gas_paid( + sender: address, + destination_chain: String, + destination_address: String, + payload_hash: address, + value: u64, + refund_address: address, + params: vector, + ) { + event::emit(GasPaid { + sender, + destination_chain, + destination_address, + payload_hash, + value, + refund_address, + params, + }); + } -public(package) fun gas_added( - message_id: String, - value: u64, - refund_address: address, - params: vector, -) { - event::emit(GasAdded { - message_id, - value, - refund_address, - params, - }); -} + public(package) fun gas_added(message_id: String, value: u64, refund_address: address, params: vector) { + event::emit(GasAdded { + message_id, + value, + refund_address, + params, + }); + } -public(package) fun refunded( - message_id: String, - value: u64, - refund_address: address, -) { - event::emit(Refunded { - message_id, - value, - refund_address, - }); -} + public(package) fun refunded(message_id: String, value: u64, refund_address: address) { + event::emit(Refunded { + message_id, + value, + refund_address, + }); + } -public(package) fun gas_collected(receiver: address, value: u64) { - event::emit(GasCollected { - receiver, - value, - }); + public(package) fun gas_collected(receiver: address, value: u64) { + event::emit(GasCollected { + receiver, + value, + }); + } } diff --git a/move/gas_service/sources/gas_service.move b/move/gas_service/sources/gas_service.move index e95e16d1..34fc19fd 100644 --- a/move/gas_service/sources/gas_service.move +++ b/move/gas_service/sources/gas_service.move @@ -1,433 +1,391 @@ -module gas_service::gas_service; - -use axelar_gateway::message_ticket::MessageTicket; -use gas_service::gas_service_v0::{Self, GasService_v0}; -use std::ascii::{Self, String}; -use sui::coin::Coin; -use sui::hash::keccak256; -use sui::sui::SUI; -use sui::versioned::{Self, Versioned}; -use version_control::version_control::{Self, VersionControl}; - -// ------- -// Version -// ------- -const VERSION: u64 = 0; - -// ------- -// Structs -// ------- -public struct GasService has key, store { - id: UID, - inner: Versioned, -} - -public struct GasCollectorCap has key, store { - id: UID, -} +module gas_service::gas_service { + use axelar_gateway::message_ticket::MessageTicket; + use gas_service::gas_service_v0::{Self, GasService_v0}; + use std::ascii::{Self, String}; + use sui::{coin::Coin, hash::keccak256, sui::SUI, versioned::{Self, Versioned}}; + use version_control::version_control::{Self, VersionControl}; + + // ------- + // Version + // ------- + const VERSION: u64 = 0; + + // ------- + // Structs + // ------- + public struct GasService has key, store { + id: UID, + inner: Versioned, + } + + public struct GasCollectorCap has key, store { + id: UID, + } + + // ----- + // Setup + // ----- + fun init(ctx: &mut TxContext) { + transfer::share_object(GasService { + id: object::new(ctx), + inner: versioned::create( + VERSION, + gas_service_v0::new( + version_control(), + ), + ctx, + ), + }); -// ----- -// Setup -// ----- -fun init(ctx: &mut TxContext) { - transfer::share_object(GasService { - id: object::new(ctx), - inner: versioned::create( - VERSION, - gas_service_v0::new( - version_control(), + transfer::public_transfer( + GasCollectorCap { + id: object::new(ctx), + }, + ctx.sender(), + ); + } + + // ------ + // Macros + // ------ + macro fun value_mut($self: &GasService, $function_name: vector): &mut GasService_v0 { + let gas_service = $self; + let value = gas_service.inner.load_value_mut(); + value.version_control().check(VERSION, ascii::string($function_name)); + value + } + + // --------------- + // Entry Functions + // --------------- + entry fun allow_function(self: &mut GasService, _: &GasCollectorCap, version: u64, function_name: String) { + self.value_mut!(b"allow_function").allow_function(version, function_name); + } + + entry fun disallow_function(self: &mut GasService, _: &GasCollectorCap, version: u64, function_name: String) { + self.value_mut!(b"disallow_function").disallow_function(version, function_name); + } + + // ---------------- + // Public Functions + // ---------------- + /// Pay gas for a contract call. + /// This function is called by the channel that wants to pay gas for a contract + /// call. + /// It can also be called by the user to pay gas for a contract call, while + /// setting the sender as the channel ID. + public fun pay_gas( + self: &mut GasService, + message_ticket: &MessageTicket, + coin: Coin, + refund_address: address, + params: vector, + ) { + self + .value_mut!(b"pay_gas") + .pay_gas( + message_ticket, + coin, + refund_address, + params, + ); + } + + /// Add gas for an existing cross-chain contract call. + /// This function can be called by a user who wants to add gas for a contract + /// call with insufficient gas. + public fun add_gas(self: &mut GasService, coin: Coin, message_id: String, refund_address: address, params: vector) { + self + .value_mut!(b"add_gas") + .add_gas( + coin, + message_id, + refund_address, + params, + ); + } + + public fun collect_gas(self: &mut GasService, _: &GasCollectorCap, receiver: address, amount: u64, ctx: &mut TxContext) { + self + .value_mut!(b"collect_gas") + .collect_gas( + receiver, + amount, + ctx, + ) + } + + public fun refund(self: &mut GasService, _: &GasCollectorCap, message_id: String, receiver: address, amount: u64, ctx: &mut TxContext) { + self + .value_mut!(b"refund") + .refund( + message_id, + receiver, + amount, + ctx, + ); + } + + // ----------------- + // Private Functions + // ----------------- + fun version_control(): VersionControl { + version_control::new(vector[ + vector[b"pay_gas", b"add_gas", b"collect_gas", b"refund", b"allow_function", b"disallow_function"].map!( + |function_name| function_name.to_ascii_string(), ), - ctx, - ), - }); + ]) + } + + // ----- + // Tests + // ----- + #[test_only] + use sui::coin; + + #[test_only] + macro fun value($self: &GasService): &GasService_v0 { + let gas_service = $self; + gas_service.inner.load_value() + } + + #[test_only] + fun new(ctx: &mut TxContext): (GasService, GasCollectorCap) { + let service = GasService { + id: object::new(ctx), + inner: versioned::create( + VERSION, + gas_service_v0::new( + version_control(), + ), + ctx, + ), + }; - transfer::public_transfer( - GasCollectorCap { + let cap = GasCollectorCap { id: object::new(ctx), - }, - ctx.sender(), - ); -} + }; + + (service, cap) + } + + #[test_only] + fun destroy(self: GasService) { + let GasService { id, inner } = self; + id.delete(); + let data = inner.destroy(); + data.destroy_for_testing(); + } + + #[test_only] + fun destroy_cap(self: GasCollectorCap) { + let GasCollectorCap { id } = self; + id.delete(); + } + + /// ----- + /// Tests + /// ----- + #[test] + fun test_init() { + let ctx = &mut sui::tx_context::dummy(); + init(ctx); + } + + #[test] + fun test_pay_gas() { + let ctx = &mut sui::tx_context::dummy(); + let (mut service, cap) = new(ctx); + // 2 bytes of the digest for a pseudo-random 1..65,536 + let digest = ctx.digest(); + let value = (((digest[0] as u16) << 8) | (digest[1] as u16) as u64) + 1; + let c: Coin = coin::mint_for_testing(value, ctx); + let channel = axelar_gateway::channel::new(ctx); + let destination_chain = b"destination chain".to_ascii_string(); + let destination_address = b"destination address".to_ascii_string(); + let payload = b"payload"; + + let ticket = axelar_gateway::gateway::prepare_message( + &channel, + destination_chain, + destination_address, + payload, + ); -// ------ -// Macros -// ------ -macro fun value_mut( - $self: &GasService, - $function_name: vector, -): &mut GasService_v0 { - let gas_service = $self; - let value = gas_service.inner.load_value_mut(); - value.version_control().check(VERSION, ascii::string($function_name)); - value -} + service.pay_gas( + &ticket, + c, + ctx.sender(), + vector[], + ); -// --------------- -// Entry Functions -// --------------- -entry fun allow_function( - self: &mut GasService, - _: &GasCollectorCap, - version: u64, - function_name: String, -) { - self.value_mut!(b"allow_function").allow_function(version, function_name); -} + assert!(service.value!().balance().value() == value); -entry fun disallow_function( - self: &mut GasService, - _: &GasCollectorCap, - version: u64, - function_name: String, -) { - self - .value_mut!(b"disallow_function") - .disallow_function(version, function_name); -} + cap.destroy_cap(); + service.destroy(); + channel.destroy(); + sui::test_utils::destroy(ticket); + } -// ---------------- -// Public Functions -// ---------------- -/// Pay gas for a contract call. -/// This function is called by the channel that wants to pay gas for a contract -/// call. -/// It can also be called by the user to pay gas for a contract call, while -/// setting the sender as the channel ID. -public fun pay_gas( - self: &mut GasService, - message_ticket: &MessageTicket, - coin: Coin, - refund_address: address, - params: vector, -) { - self - .value_mut!(b"pay_gas") - .pay_gas( - message_ticket, - coin, - refund_address, - params, - ); -} + #[test] + fun test_add_gas() { + let ctx = &mut sui::tx_context::dummy(); + let (mut service, cap) = new(ctx); + let digest = ctx.digest(); + let value = (((digest[0] as u16) << 8) | (digest[1] as u16) as u64) + + 1; // 1..65,536 + let c: Coin = coin::mint_for_testing(value, ctx); -/// Add gas for an existing cross-chain contract call. -/// This function can be called by a user who wants to add gas for a contract -/// call with insufficient gas. -public fun add_gas( - self: &mut GasService, - coin: Coin, - message_id: String, - refund_address: address, - params: vector, -) { - self - .value_mut!(b"add_gas") - .add_gas( - coin, - message_id, - refund_address, - params, + service.add_gas( + c, + std::ascii::string(b"message id"), + @0x0, + vector[], ); -} - -public fun collect_gas( - self: &mut GasService, - _: &GasCollectorCap, - receiver: address, - amount: u64, - ctx: &mut TxContext, -) { - self - .value_mut!(b"collect_gas") - .collect_gas( - receiver, - amount, - ctx, - ) -} -public fun refund( - self: &mut GasService, - _: &GasCollectorCap, - message_id: String, - receiver: address, - amount: u64, - ctx: &mut TxContext, -) { - self - .value_mut!(b"refund") - .refund( - message_id, - receiver, - amount, - ctx, - ); -} + assert!(service.value!().balance().value() == value); -// ----------------- -// Private Functions -// ----------------- -fun version_control(): VersionControl { - version_control::new(vector[ - vector[ - b"pay_gas", - b"add_gas", - b"collect_gas", - b"refund", - b"allow_function", - b"disallow_function", - ].map!(|function_name| function_name.to_ascii_string()), - ]) -} + cap.destroy_cap(); + service.destroy(); + } -// ----- -// Tests -// ----- -#[test_only] -use sui::coin; + #[test] + fun test_collect_gas() { + let ctx = &mut sui::tx_context::dummy(); + let (mut service, cap) = new(ctx); + let digest = ctx.digest(); + let value = (((digest[0] as u16) << 8) | (digest[1] as u16) as u64) + + 1; // 1..65,536 + let c: Coin = coin::mint_for_testing(value, ctx); -#[test_only] -macro fun value($self: &GasService): &GasService_v0 { - let gas_service = $self; - gas_service.inner.load_value() -} + service.add_gas( + c, + std::ascii::string(b"message id"), + @0x0, + vector[], + ); -#[test_only] -fun new(ctx: &mut TxContext): (GasService, GasCollectorCap) { - let service = GasService { - id: object::new(ctx), - inner: versioned::create( - VERSION, - gas_service_v0::new( - version_control(), - ), + service.collect_gas( + &cap, + ctx.sender(), + value, ctx, - ), - }; - - let cap = GasCollectorCap { - id: object::new(ctx), - }; + ); - (service, cap) -} + assert!(service.value!().balance().value() == 0); -#[test_only] -fun destroy(self: GasService) { - let GasService { id, inner } = self; - id.delete(); - let data = inner.destroy(); - data.destroy_for_testing(); -} + cap.destroy_cap(); + service.destroy(); + } -#[test_only] -fun destroy_cap(self: GasCollectorCap) { - let GasCollectorCap { id } = self; - id.delete(); -} + #[test] + fun test_refund() { + let ctx = &mut sui::tx_context::dummy(); + let (mut service, cap) = new(ctx); + let digest = ctx.digest(); + let value = (((digest[0] as u16) << 8) | (digest[1] as u16) as u64) + + 1; // 1..65,536 + let c: Coin = coin::mint_for_testing(value, ctx); -/// ----- -/// Tests -/// ----- -#[test] -fun test_init() { - let ctx = &mut sui::tx_context::dummy(); - init(ctx); -} + service.add_gas( + c, + std::ascii::string(b"message id"), + @0x0, + vector[], + ); -#[test] -fun test_pay_gas() { - let ctx = &mut sui::tx_context::dummy(); - let (mut service, cap) = new(ctx); - // 2 bytes of the digest for a pseudo-random 1..65,536 - let digest = ctx.digest(); - let value = (((digest[0] as u16) << 8) | (digest[1] as u16) as u64) + 1; - let c: Coin = coin::mint_for_testing(value, ctx); - let channel = axelar_gateway::channel::new(ctx); - let destination_chain = b"destination chain".to_ascii_string(); - let destination_address = b"destination address".to_ascii_string(); - let payload = b"payload"; - - let ticket = axelar_gateway::gateway::prepare_message( - &channel, - destination_chain, - destination_address, - payload, - ); - - service.pay_gas( - &ticket, - c, - ctx.sender(), - vector[], - ); - - assert!(service.value!().balance().value() == value); - - cap.destroy_cap(); - service.destroy(); - channel.destroy(); - sui::test_utils::destroy(ticket); -} + service.refund( + &cap, + std::ascii::string(b"message id"), + ctx.sender(), + value, + ctx, + ); -#[test] -fun test_add_gas() { - let ctx = &mut sui::tx_context::dummy(); - let (mut service, cap) = new(ctx); - let digest = ctx.digest(); - let value = (((digest[0] as u16) << 8) | (digest[1] as u16) as u64) + - 1; // 1..65,536 - let c: Coin = coin::mint_for_testing(value, ctx); + assert!(service.value!().balance().value() == 0); - service.add_gas( - c, - std::ascii::string(b"message id"), - @0x0, - vector[], - ); + cap.destroy_cap(); + service.destroy(); + } - assert!(service.value!().balance().value() == value); + #[test] + #[expected_failure(abort_code = sui::balance::ENotEnough)] + fun test_collect_gas_insufficient_balance() { + let ctx = &mut sui::tx_context::dummy(); + let (mut service, cap) = new(ctx); + let digest = ctx.digest(); + let value = (((digest[0] as u16) << 8) | (digest[1] as u16) as u64) + + 1; // 1..65,536 + let c: Coin = coin::mint_for_testing(value, ctx); - cap.destroy_cap(); - service.destroy(); -} + service.add_gas( + c, + std::ascii::string(b"message id"), + @0x0, + vector[], + ); -#[test] -fun test_collect_gas() { - let ctx = &mut sui::tx_context::dummy(); - let (mut service, cap) = new(ctx); - let digest = ctx.digest(); - let value = (((digest[0] as u16) << 8) | (digest[1] as u16) as u64) + - 1; // 1..65,536 - let c: Coin = coin::mint_for_testing(value, ctx); - - service.add_gas( - c, - std::ascii::string(b"message id"), - @0x0, - vector[], - ); - - service.collect_gas( - &cap, - ctx.sender(), - value, - ctx, - ); - - assert!(service.value!().balance().value() == 0); - - cap.destroy_cap(); - service.destroy(); -} + service.collect_gas( + &cap, + ctx.sender(), + value + 1, + ctx, + ); -#[test] -fun test_refund() { - let ctx = &mut sui::tx_context::dummy(); - let (mut service, cap) = new(ctx); - let digest = ctx.digest(); - let value = (((digest[0] as u16) << 8) | (digest[1] as u16) as u64) + - 1; // 1..65,536 - let c: Coin = coin::mint_for_testing(value, ctx); - - service.add_gas( - c, - std::ascii::string(b"message id"), - @0x0, - vector[], - ); - - service.refund( - &cap, - std::ascii::string(b"message id"), - ctx.sender(), - value, - ctx, - ); - - assert!(service.value!().balance().value() == 0); - - cap.destroy_cap(); - service.destroy(); -} + cap.destroy_cap(); + service.destroy(); + } + + #[test] + #[expected_failure(abort_code = sui::balance::ENotEnough)] + fun test_refund_insufficient_balance() { + let ctx = &mut sui::tx_context::dummy(); + let (mut service, cap) = new(ctx); + let value = 10; + let c: Coin = coin::mint_for_testing(value, ctx); + + service.add_gas( + c, + std::ascii::string(b"message id"), + @0x0, + vector[], + ); -#[test] -#[expected_failure(abort_code = sui::balance::ENotEnough)] -fun test_collect_gas_insufficient_balance() { - let ctx = &mut sui::tx_context::dummy(); - let (mut service, cap) = new(ctx); - let digest = ctx.digest(); - let value = (((digest[0] as u16) << 8) | (digest[1] as u16) as u64) + - 1; // 1..65,536 - let c: Coin = coin::mint_for_testing(value, ctx); - - service.add_gas( - c, - std::ascii::string(b"message id"), - @0x0, - vector[], - ); - - service.collect_gas( - &cap, - ctx.sender(), - value + 1, - ctx, - ); - - cap.destroy_cap(); - service.destroy(); -} + service.refund( + &cap, + std::ascii::string(b"message id"), + ctx.sender(), + value + 1, + ctx, + ); -#[test] -#[expected_failure(abort_code = sui::balance::ENotEnough)] -fun test_refund_insufficient_balance() { - let ctx = &mut sui::tx_context::dummy(); - let (mut service, cap) = new(ctx); - let value = 10; - let c: Coin = coin::mint_for_testing(value, ctx); - - service.add_gas( - c, - std::ascii::string(b"message id"), - @0x0, - vector[], - ); - - service.refund( - &cap, - std::ascii::string(b"message id"), - ctx.sender(), - value + 1, - ctx, - ); - - cap.destroy_cap(); - service.destroy(); -} + cap.destroy_cap(); + service.destroy(); + } -#[test] -fun test_allow_function() { - let ctx = &mut sui::tx_context::dummy(); - let (mut self, cap) = new(ctx); - let version = 0; - let function_name = b"function_name".to_ascii_string(); + #[test] + fun test_allow_function() { + let ctx = &mut sui::tx_context::dummy(); + let (mut self, cap) = new(ctx); + let version = 0; + let function_name = b"function_name".to_ascii_string(); - self.allow_function(&cap, version, function_name); + self.allow_function(&cap, version, function_name); - sui::test_utils::destroy(self); - cap.destroy_cap(); -} + sui::test_utils::destroy(self); + cap.destroy_cap(); + } -#[test] -fun test_disallow_function() { - let ctx = &mut sui::tx_context::dummy(); - let (mut self, cap) = new(ctx); - let version = 0; - let function_name = b"pay_gas".to_ascii_string(); + #[test] + fun test_disallow_function() { + let ctx = &mut sui::tx_context::dummy(); + let (mut self, cap) = new(ctx); + let version = 0; + let function_name = b"pay_gas".to_ascii_string(); - self.disallow_function(&cap, version, function_name); + self.disallow_function(&cap, version, function_name); - sui::test_utils::destroy(self); - cap.destroy_cap(); + sui::test_utils::destroy(self); + cap.destroy_cap(); + } } diff --git a/move/gas_service/sources/versioned/gas_service_v0.move b/move/gas_service/sources/versioned/gas_service_v0.move index 88e76de2..9c1ad491 100644 --- a/move/gas_service/sources/versioned/gas_service_v0.move +++ b/move/gas_service/sources/versioned/gas_service_v0.move @@ -1,169 +1,140 @@ -module gas_service::gas_service_v0; - -use axelar_gateway::message_ticket::MessageTicket; -use gas_service::events; -use std::ascii::String; -use sui::address; -use sui::balance::{Self, Balance}; -use sui::coin::{Self, Coin}; -use sui::hash::keccak256; -use sui::sui::SUI; -use version_control::version_control::VersionControl; - -// ------- -// Structs -// ------- -public struct GasService_v0 has store { - balance: Balance, - version_control: VersionControl, -} +module gas_service::gas_service_v0 { + use axelar_gateway::message_ticket::MessageTicket; + use gas_service::events; + use std::ascii::String; + use sui::{address, balance::{Self, Balance}, coin::{Self, Coin}, hash::keccak256, sui::SUI}; + use version_control::version_control::VersionControl; + + // ------- + // Structs + // ------- + public struct GasService_v0 has store { + balance: Balance, + version_control: VersionControl, + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun new(version_control: VersionControl): GasService_v0 { - GasService_v0 { - balance: balance::zero(), - version_control, + // ----------------- + // Package Functions + // ----------------- + public(package) fun new(version_control: VersionControl): GasService_v0 { + GasService_v0 { + balance: balance::zero(), + version_control, + } } -} -public(package) fun version_control(self: &GasService_v0): &VersionControl { - &self.version_control -} + public(package) fun version_control(self: &GasService_v0): &VersionControl { + &self.version_control + } -public(package) fun pay_gas( - self: &mut GasService_v0, - message_ticket: &MessageTicket, - coin: Coin, - refund_address: address, - params: vector, -) { - let coin_value = coin.value(); - self.put(coin); - - let payload_hash = address::from_bytes( - keccak256(&message_ticket.payload()), - ); - - events::gas_paid( - message_ticket.source_id(), - message_ticket.destination_chain(), - message_ticket.destination_address(), - payload_hash, - coin_value, - refund_address, - params, - ); -} + public(package) fun pay_gas( + self: &mut GasService_v0, + message_ticket: &MessageTicket, + coin: Coin, + refund_address: address, + params: vector, + ) { + let coin_value = coin.value(); + self.put(coin); + + let payload_hash = address::from_bytes( + keccak256(&message_ticket.payload()), + ); + + events::gas_paid( + message_ticket.source_id(), + message_ticket.destination_chain(), + message_ticket.destination_address(), + payload_hash, + coin_value, + refund_address, + params, + ); + } -public(package) fun add_gas( - self: &mut GasService_v0, - coin: Coin, - message_id: String, - refund_address: address, - params: vector, -) { - let coin_value = coin.value(); - self.put(coin); - - events::gas_added( - message_id, - coin_value, - refund_address, - params, - ); -} + public(package) fun add_gas( + self: &mut GasService_v0, + coin: Coin, + message_id: String, + refund_address: address, + params: vector, + ) { + let coin_value = coin.value(); + self.put(coin); + + events::gas_added( + message_id, + coin_value, + refund_address, + params, + ); + } -public(package) fun collect_gas( - self: &mut GasService_v0, - receiver: address, - amount: u64, - ctx: &mut TxContext, -) { - transfer::public_transfer( - self.take(amount, ctx), - receiver, - ); - - events::gas_collected( - receiver, - amount, - ); -} + public(package) fun collect_gas(self: &mut GasService_v0, receiver: address, amount: u64, ctx: &mut TxContext) { + transfer::public_transfer( + self.take(amount, ctx), + receiver, + ); -public(package) fun refund( - self: &mut GasService_v0, - message_id: String, - receiver: address, - amount: u64, - ctx: &mut TxContext, -) { - transfer::public_transfer( - self.take(amount, ctx), - receiver, - ); - - events::refunded( - message_id, - amount, - receiver, - ); -} + events::gas_collected( + receiver, + amount, + ); + } -public(package) fun allow_function( - self: &mut GasService_v0, - version: u64, - function_name: String, -) { - self.version_control.allow_function(version, function_name); -} + public(package) fun refund(self: &mut GasService_v0, message_id: String, receiver: address, amount: u64, ctx: &mut TxContext) { + transfer::public_transfer( + self.take(amount, ctx), + receiver, + ); + + events::refunded( + message_id, + amount, + receiver, + ); + } -public(package) fun disallow_function( - self: &mut GasService_v0, - version: u64, - function_name: String, -) { - self.version_control.disallow_function(version, function_name); -} + public(package) fun allow_function(self: &mut GasService_v0, version: u64, function_name: String) { + self.version_control.allow_function(version, function_name); + } -// ----------------- -// Private Functions -// ----------------- -fun put(self: &mut GasService_v0, coin: Coin) { - coin::put(&mut self.balance, coin); -} + public(package) fun disallow_function(self: &mut GasService_v0, version: u64, function_name: String) { + self.version_control.disallow_function(version, function_name); + } -fun take( - self: &mut GasService_v0, - amount: u64, - ctx: &mut TxContext, -): Coin { - coin::take(&mut self.balance, amount, ctx) -} + // ----------------- + // Private Functions + // ----------------- + fun put(self: &mut GasService_v0, coin: Coin) { + coin::put(&mut self.balance, coin); + } -// --------- -// Test Only -// --------- -#[test_only] -public(package) fun version_control_mut( - self: &mut GasService_v0, -): &mut VersionControl { - &mut self.version_control -} + fun take(self: &mut GasService_v0, amount: u64, ctx: &mut TxContext): Coin { + coin::take(&mut self.balance, amount, ctx) + } -#[test_only] -public(package) fun balance(self: &GasService_v0): &Balance { - &self.balance -} + // --------- + // Test Only + // --------- + #[test_only] + public(package) fun version_control_mut(self: &mut GasService_v0): &mut VersionControl { + &mut self.version_control + } -#[test_only] -public(package) fun balance_mut(self: &mut GasService_v0): &mut Balance { - &mut self.balance -} + #[test_only] + public(package) fun balance(self: &GasService_v0): &Balance { + &self.balance + } -#[test_only] -public(package) fun destroy_for_testing(self: GasService_v0) { - let GasService_v0 { balance, version_control: _ } = self; - balance.destroy_for_testing(); + #[test_only] + public(package) fun balance_mut(self: &mut GasService_v0): &mut Balance { + &mut self.balance + } + + #[test_only] + public(package) fun destroy_for_testing(self: GasService_v0) { + let GasService_v0 { balance, version_control: _ } = self; + balance.destroy_for_testing(); + } } diff --git a/move/governance/sources/governance/governance.move b/move/governance/sources/governance/governance.move index 2933ab1c..7d92b493 100644 --- a/move/governance/sources/governance/governance.move +++ b/move/governance/sources/governance/governance.move @@ -1,204 +1,215 @@ -module governance::governance; - -use abi::abi; -use axelar_gateway::channel::{Self, Channel, ApprovedMessage}; -use std::ascii::String; -use std::type_name; -use sui::address; -use sui::hex; -use sui::package::{Self, UpgradeCap, UpgradeTicket, UpgradeReceipt}; -use sui::table::{Self, Table}; - -#[error] -const EUntrustedAddress: vector = - b"upgrade authorization attempt from an untrusted address"; - -#[error] -const EInvalidMessageType: vector = - b"invalid message type for upgrade authorization"; - -#[error] -const ENotSelfUpgradeCap: vector = - b"governance initialization requires its own upgrade capability. The provided capability belongs to a different package"; - -#[error] -const ENotNewPackage: vector = b"Not new package."; - -public struct Governance has key, store { - id: UID, - trusted_source_chain: String, - trusted_source_address: String, - message_type: u256, - channel: Channel, - caps: Table, -} +module governance::governance { + use abi::abi; + use axelar_gateway::channel::{Self, Channel, ApprovedMessage}; + use std::{ascii::String, type_name}; + use sui::{address, hex, package::{Self, UpgradeCap, UpgradeTicket, UpgradeReceipt}, table::{Self, Table}}; + + #[error] + const EUntrustedAddress: vector = b"upgrade authorization attempt from an untrusted address"; + + #[error] + const EInvalidMessageType: vector = b"invalid message type for upgrade authorization"; + + #[error] + const ENotSelfUpgradeCap: vector = + b"governance initialization requires its own upgrade capability. The provided capability belongs to a different package"; + + #[error] + const ENotNewPackage: vector = b"Not new package."; + + public struct Governance has key, store { + id: UID, + trusted_source_chain: String, + trusted_source_address: String, + message_type: u256, + channel: Channel, + caps: Table, + } -// This can only be called once since it needs its own upgrade cap which it -// deletes. -entry fun new( - trusted_source_chain: String, - trusted_source_address: String, - message_type: u256, - upgrade_cap: UpgradeCap, - ctx: &mut TxContext, -) { - let package_id = object::id_from_bytes( - hex::decode(type_name::get().get_address().into_bytes()), - ); - assert!(upgrade_cap.upgrade_package() == package_id, ENotSelfUpgradeCap); - is_cap_new(&upgrade_cap); - package::make_immutable(upgrade_cap); - - transfer::share_object(Governance { - id: object::new(ctx), - trusted_source_chain, - trusted_source_address, - message_type, - channel: channel::new(ctx), - caps: table::new(ctx), - }) -} + // This can only be called once since it needs its own upgrade cap which it + // deletes. + entry fun new( + trusted_source_chain: String, + trusted_source_address: String, + message_type: u256, + upgrade_cap: UpgradeCap, + ctx: &mut TxContext, + ) { + let package_id = object::id_from_bytes( + hex::decode(type_name::get().get_address().into_bytes()), + ); + assert!(upgrade_cap.upgrade_package() == package_id, ENotSelfUpgradeCap); + is_cap_new(&upgrade_cap); + package::make_immutable(upgrade_cap); + + transfer::share_object(Governance { + id: object::new(ctx), + trusted_source_chain, + trusted_source_address, + message_type, + channel: channel::new(ctx), + caps: table::new(ctx), + }) + } -public fun is_governance( - self: &Governance, - chain_name: String, - addr: String, -): bool { - &chain_name == + public fun is_governance(self: &Governance, chain_name: String, addr: String): bool { + &chain_name == &self.trusted_source_chain && &addr == &self.trusted_source_address -} + } -// TODO maybe check that the polcy for the upgrade cap has not been tampered -// with. -entry fun take_upgrade_cap(self: &mut Governance, upgrade_cap: UpgradeCap) { - is_cap_new(&upgrade_cap); + // TODO maybe check that the polcy for the upgrade cap has not been tampered + // with. + entry fun take_upgrade_cap(self: &mut Governance, upgrade_cap: UpgradeCap) { + is_cap_new(&upgrade_cap); + + self + .caps + .add( + object::id(&upgrade_cap), + upgrade_cap, + ) + } - self - .caps - .add( - object::id(&upgrade_cap), - upgrade_cap, - ) -} + public fun authorize_upgrade(self: &mut Governance, approved_message: ApprovedMessage): UpgradeTicket { + let (source_chain, _, source_address, payload) = self.channel.consume_approved_message(approved_message); -public fun authorize_upgrade( - self: &mut Governance, - approved_message: ApprovedMessage, -): UpgradeTicket { - let (source_chain, _, source_address, payload) = self - .channel - .consume_approved_message(approved_message); - - assert!( - is_governance(self, source_chain, source_address), - EUntrustedAddress, - ); - - let mut abi = abi::new_reader(payload); - let message_type = abi.read_u256(); - assert!(message_type == self.message_type, EInvalidMessageType); - - let cap_id = object::id_from_address(address::from_u256(abi.read_u256())); - let policy = abi.read_u8(); - let digest = abi.read_bytes(); - - package::authorize_upgrade( - table::borrow_mut(&mut self.caps, cap_id), - policy, - digest, - ) -} + assert!(is_governance(self, source_chain, source_address), EUntrustedAddress); -public fun commit_upgrade(self: &mut Governance, receipt: UpgradeReceipt) { - package::commit_upgrade( - table::borrow_mut( - &mut self.caps, - package::receipt_cap(&receipt), - ), - receipt, - ) -} + let mut abi = abi::new_reader(payload); + let message_type = abi.read_u256(); + assert!(message_type == self.message_type, EInvalidMessageType); -fun is_cap_new(cap: &UpgradeCap) { - assert!(package::version(cap) == 1, ENotNewPackage); -} + let cap_id = object::id_from_address(address::from_u256(abi.read_u256())); + let policy = abi.read_u8(); + let digest = abi.read_bytes(); -// ----- -// Tests -// ----- - -#[test_only] -use std::ascii; -#[test_only] -use sui::test_scenario; -#[test_only] -use sui::test_utils; - -#[test_only] -public fun new_for_testing( - trusted_source_chain: String, - trusted_source_address: String, - message_type: u256, - ctx: &mut TxContext, -): Governance { - Governance { - id: object::new(ctx), - trusted_source_chain, - trusted_source_address, - message_type, - channel: channel::new(ctx), - caps: table::new(ctx), + package::authorize_upgrade( + table::borrow_mut(&mut self.caps, cap_id), + policy, + digest, + ) } -} -#[test] -fun test_new() { - let trusted_source_chain = ascii::string(b"Axelar"); - let trusted_source_address = ascii::string(b"0x0"); - let message_type = 2; - let mut ctx = tx_context::dummy(); - let package_id = object::id_from_bytes( - hex::decode(type_name::get().get_address().into_bytes()), - ); - let upgrade_cap = package::test_publish(package_id, &mut ctx); - let initial_owner = @0x1; - let mut scenario = test_scenario::begin(initial_owner); - { - test_scenario::sender(&scenario); - new( + public fun commit_upgrade(self: &mut Governance, receipt: UpgradeReceipt) { + package::commit_upgrade( + table::borrow_mut( + &mut self.caps, + package::receipt_cap(&receipt), + ), + receipt, + ) + } + + fun is_cap_new(cap: &UpgradeCap) { + assert!(package::version(cap) == 1, ENotNewPackage); + } + + // ----- + // Tests + // ----- + + #[test_only] + use std::ascii; + #[test_only] + use sui::test_scenario; + #[test_only] + use sui::test_utils; + + #[test_only] + public fun new_for_testing( + trusted_source_chain: String, + trusted_source_address: String, + message_type: u256, + ctx: &mut TxContext, + ): Governance { + Governance { + id: object::new(ctx), trusted_source_chain, trusted_source_address, message_type, - upgrade_cap, - &mut ctx, - ); - }; + channel: channel::new(ctx), + caps: table::new(ctx), + } + } - test_scenario::next_tx(&mut scenario, initial_owner); - { - let governance = test_scenario::take_shared(&scenario); - test_scenario::return_shared(governance); - }; + #[test] + fun test_new() { + let trusted_source_chain = ascii::string(b"Axelar"); + let trusted_source_address = ascii::string(b"0x0"); + let message_type = 2; + let mut ctx = tx_context::dummy(); + let package_id = object::id_from_bytes( + hex::decode(type_name::get().get_address().into_bytes()), + ); + let upgrade_cap = package::test_publish(package_id, &mut ctx); + let initial_owner = @0x1; + let mut scenario = test_scenario::begin(initial_owner); + { + test_scenario::sender(&scenario); + new( + trusted_source_chain, + trusted_source_address, + message_type, + upgrade_cap, + &mut ctx, + ); + }; + + test_scenario::next_tx(&mut scenario, initial_owner); + { + let governance = test_scenario::take_shared(&scenario); + test_scenario::return_shared(governance); + }; + + test_scenario::end(scenario); + } - test_scenario::end(scenario); -} + #[test] + #[expected_failure(abort_code = test_scenario::EEmptyInventory)] + fun test_new_immutable_upgrade() { + let trusted_source_chain = ascii::string(b"Axelar"); + let trusted_source_address = ascii::string(b"0x0"); + let message_type = 2; + let mut ctx = tx_context::dummy(); + let package_id = object::id_from_bytes( + hex::decode(type_name::get().get_address().into_bytes()), + ); + let upgrade_cap = package::test_publish(package_id, &mut ctx); + let initial_owner = @0x1; + let mut scenario = test_scenario::begin(initial_owner); + { + test_scenario::sender(&scenario); + new( + trusted_source_chain, + trusted_source_address, + message_type, + upgrade_cap, + &mut ctx, + ); + }; + + test_scenario::next_tx(&mut scenario, initial_owner); + { + let upgrade_cap = test_scenario::take_shared(&scenario); + test_scenario::return_shared(upgrade_cap); + }; + + test_scenario::end(scenario); + } -#[test] -#[expected_failure(abort_code = test_scenario::EEmptyInventory)] -fun test_new_immutable_upgrade() { - let trusted_source_chain = ascii::string(b"Axelar"); - let trusted_source_address = ascii::string(b"0x0"); - let message_type = 2; - let mut ctx = tx_context::dummy(); - let package_id = object::id_from_bytes( - hex::decode(type_name::get().get_address().into_bytes()), - ); - let upgrade_cap = package::test_publish(package_id, &mut ctx); - let initial_owner = @0x1; - let mut scenario = test_scenario::begin(initial_owner); - { - test_scenario::sender(&scenario); + #[test] + #[expected_failure(abort_code = ENotSelfUpgradeCap)] + fun test_new_incorrect_upgrade_cap() { + let trusted_source_chain = ascii::string(b"Axelar"); + let trusted_source_address = ascii::string(b"0x0"); + let message_type = 2; + let mut ctx = tx_context::dummy(); + let uid = object::new(&mut ctx); + let upgrade_cap = package::test_publish( + object::uid_to_inner(&uid), + &mut ctx, + ); new( trusted_source_chain, trusted_source_address, @@ -206,331 +217,296 @@ fun test_new_immutable_upgrade() { upgrade_cap, &mut ctx, ); - }; - - test_scenario::next_tx(&mut scenario, initial_owner); - { - let upgrade_cap = test_scenario::take_shared(&scenario); - test_scenario::return_shared(upgrade_cap); - }; - test_scenario::end(scenario); -} + test_utils::destroy(uid); + } -#[test] -#[expected_failure(abort_code = ENotSelfUpgradeCap)] -fun test_new_incorrect_upgrade_cap() { - let trusted_source_chain = ascii::string(b"Axelar"); - let trusted_source_address = ascii::string(b"0x0"); - let message_type = 2; - let mut ctx = tx_context::dummy(); - let uid = object::new(&mut ctx); - let upgrade_cap = package::test_publish( - object::uid_to_inner(&uid), - &mut ctx, - ); - new( - trusted_source_chain, - trusted_source_address, - message_type, - upgrade_cap, - &mut ctx, - ); - - test_utils::destroy(uid); -} + #[test] + fun test_is_governance() { + let trusted_source_chain = ascii::string(b"Axelar"); + let trusted_source_address = ascii::string(b"0x0"); + let message_type = 2; + let mut ctx = tx_context::dummy(); -#[test] -fun test_is_governance() { - let trusted_source_chain = ascii::string(b"Axelar"); - let trusted_source_address = ascii::string(b"0x0"); - let message_type = 2; - let mut ctx = tx_context::dummy(); - - let governance = Governance { - id: object::new(&mut ctx), - trusted_source_chain, - trusted_source_address, - message_type, - channel: channel::new(&mut ctx), - caps: table::new(&mut ctx), - }; - - assert!( - governance.is_governance(trusted_source_chain, trusted_source_address), - EUntrustedAddress, - ); - - test_utils::destroy(governance); -} - -#[test] -fun test_is_governance_false_argument() { - let trusted_source_chain = ascii::string(b"Axelar"); - let trusted_source_address = ascii::string(b"0x0"); - let message_type = 2; - let mut ctx = tx_context::dummy(); - - let governance = Governance { - id: object::new(&mut ctx), - trusted_source_chain, - trusted_source_address, - message_type, - channel: channel::new(&mut ctx), - caps: table::new(&mut ctx), - }; - - assert!( - !governance.is_governance( - ascii::string(b"sui"), + let governance = Governance { + id: object::new(&mut ctx), + trusted_source_chain, trusted_source_address, - ), - EUntrustedAddress, - ); + message_type, + channel: channel::new(&mut ctx), + caps: table::new(&mut ctx), + }; - test_utils::destroy(governance); -} + assert!(governance.is_governance(trusted_source_chain, trusted_source_address), EUntrustedAddress); -#[test] -fun test_is_cap_new() { - let mut ctx = tx_context::dummy(); - let uid = object::new(&mut ctx); - let upgrade_cap = package::test_publish( - object::uid_to_inner(&uid), - &mut ctx, - ); - is_cap_new(&upgrade_cap); - - test_utils::destroy(uid); - test_utils::destroy(upgrade_cap); -} + test_utils::destroy(governance); + } -#[test] -#[expected_failure(abort_code = ENotNewPackage)] -fun test_is_cap_new_upgrade_version() { - let mut ctx = tx_context::dummy(); - let uid = object::new(&mut ctx); - let mut upgrade_cap = package::test_publish( - object::uid_to_inner(&uid), - &mut ctx, - ); - let upgrade_ticket = package::authorize_upgrade(&mut upgrade_cap, 2, b""); - let upgrade_reciept = package::test_upgrade(upgrade_ticket); - package::commit_upgrade(&mut upgrade_cap, upgrade_reciept); - is_cap_new(&upgrade_cap); - - test_utils::destroy(uid); - test_utils::destroy(upgrade_cap); -} + #[test] + fun test_is_governance_false_argument() { + let trusted_source_chain = ascii::string(b"Axelar"); + let trusted_source_address = ascii::string(b"0x0"); + let message_type = 2; + let mut ctx = tx_context::dummy(); -#[test] -fun test_take_upgrade_cap() { - let trusted_source_chain = ascii::string(b"Axelar"); - let trusted_source_address = ascii::string(b"0x0"); - let message_type = 2; - let mut ctx = tx_context::dummy(); - let package_id = object::id_from_bytes( - hex::decode(type_name::get().get_address().into_bytes()), - ); - let upgrade_cap = package::test_publish(package_id, &mut ctx); - let initial_owner = @0x1; - let mut scenario = test_scenario::begin(initial_owner); - { - test_scenario::sender(&scenario); - new( + let governance = Governance { + id: object::new(&mut ctx), trusted_source_chain, trusted_source_address, message_type, - upgrade_cap, + channel: channel::new(&mut ctx), + caps: table::new(&mut ctx), + }; + + assert!( + !governance.is_governance( + ascii::string(b"sui"), + trusted_source_address, + ), + EUntrustedAddress, + ); + + test_utils::destroy(governance); + } + + #[test] + fun test_is_cap_new() { + let mut ctx = tx_context::dummy(); + let uid = object::new(&mut ctx); + let upgrade_cap = package::test_publish( + object::uid_to_inner(&uid), &mut ctx, ); - }; + is_cap_new(&upgrade_cap); + + test_utils::destroy(uid); + test_utils::destroy(upgrade_cap); + } - test_scenario::next_tx(&mut scenario, initial_owner); - { - let mut governance = test_scenario::take_shared(&scenario); + #[test] + #[expected_failure(abort_code = ENotNewPackage)] + fun test_is_cap_new_upgrade_version() { + let mut ctx = tx_context::dummy(); + let uid = object::new(&mut ctx); + let mut upgrade_cap = package::test_publish( + object::uid_to_inner(&uid), + &mut ctx, + ); + let upgrade_ticket = package::authorize_upgrade(&mut upgrade_cap, 2, b""); + let upgrade_reciept = package::test_upgrade(upgrade_ticket); + package::commit_upgrade(&mut upgrade_cap, upgrade_reciept); + is_cap_new(&upgrade_cap); + + test_utils::destroy(uid); + test_utils::destroy(upgrade_cap); + } + + #[test] + fun test_take_upgrade_cap() { + let trusted_source_chain = ascii::string(b"Axelar"); + let trusted_source_address = ascii::string(b"0x0"); + let message_type = 2; + let mut ctx = tx_context::dummy(); + let package_id = object::id_from_bytes( + hex::decode(type_name::get().get_address().into_bytes()), + ); let upgrade_cap = package::test_publish(package_id, &mut ctx); + let initial_owner = @0x1; + let mut scenario = test_scenario::begin(initial_owner); + { + test_scenario::sender(&scenario); + new( + trusted_source_chain, + trusted_source_address, + message_type, + upgrade_cap, + &mut ctx, + ); + }; + + test_scenario::next_tx(&mut scenario, initial_owner); + { + let mut governance = test_scenario::take_shared(&scenario); + let upgrade_cap = package::test_publish(package_id, &mut ctx); + let upgrade_id = object::id(&upgrade_cap); + take_upgrade_cap(&mut governance, upgrade_cap); + let recieved_upgrade_cap = table::borrow_mut( + &mut governance.caps, + upgrade_id, + ); + assert!(object::id(recieved_upgrade_cap) == upgrade_id); + test_scenario::return_shared(governance); + }; + + test_scenario::end(scenario); + } + + #[test] + fun test_commit_upgrade() { + let mut ctx = tx_context::dummy(); + let uid = object::new(&mut ctx); + let mut upgrade_cap = package::test_publish( + object::uid_to_inner(&uid), + &mut ctx, + ); + let upgrade_ticket = package::authorize_upgrade(&mut upgrade_cap, 2, b""); + let upgrade_reciept = package::test_upgrade(upgrade_ticket); + let trusted_source_chain = ascii::string(b"Axelar"); + let trusted_source_address = ascii::string(b"0x0"); + let message_type = 2; + let mut governance = Governance { + id: object::new(&mut ctx), + trusted_source_chain, + trusted_source_address, + message_type, + channel: channel::new(&mut ctx), + caps: table::new(&mut ctx), + }; let upgrade_id = object::id(&upgrade_cap); take_upgrade_cap(&mut governance, upgrade_cap); - let recieved_upgrade_cap = table::borrow_mut( - &mut governance.caps, + commit_upgrade(&mut governance, upgrade_reciept); + let upgrade_cap_return = table::borrow( + &governance.caps, upgrade_id, ); - assert!(object::id(recieved_upgrade_cap) == upgrade_id); - test_scenario::return_shared(governance); - }; - - test_scenario::end(scenario); -} - -#[test] -fun test_commit_upgrade() { - let mut ctx = tx_context::dummy(); - let uid = object::new(&mut ctx); - let mut upgrade_cap = package::test_publish( - object::uid_to_inner(&uid), - &mut ctx, - ); - let upgrade_ticket = package::authorize_upgrade(&mut upgrade_cap, 2, b""); - let upgrade_reciept = package::test_upgrade(upgrade_ticket); - let trusted_source_chain = ascii::string(b"Axelar"); - let trusted_source_address = ascii::string(b"0x0"); - let message_type = 2; - let mut governance = Governance { - id: object::new(&mut ctx), - trusted_source_chain, - trusted_source_address, - message_type, - channel: channel::new(&mut ctx), - caps: table::new(&mut ctx), - }; - let upgrade_id = object::id(&upgrade_cap); - take_upgrade_cap(&mut governance, upgrade_cap); - commit_upgrade(&mut governance, upgrade_reciept); - let upgrade_cap_return = table::borrow( - &governance.caps, - upgrade_id, - ); - assert!(upgrade_id == object::id(upgrade_cap_return)); - assert!(package::version(upgrade_cap_return) == 2); - test_utils::destroy(uid); - test_utils::destroy(governance); -} + assert!(upgrade_id == object::id(upgrade_cap_return)); + assert!(package::version(upgrade_cap_return) == 2); + test_utils::destroy(uid); + test_utils::destroy(governance); + } -#[test] -fun test_authorize_upgrade() { - let mut ctx = tx_context::dummy(); - let trusted_source_chain = ascii::string(b"Axelar"); - let trusted_source_address = ascii::string(b"0x0"); - let channale_object = channel::new(&mut ctx); - let payload = - x"0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010400000000000000000000000000000000000000000000000000000000000000"; - let mut abi = abi::new_reader(payload); - let message_type = abi.read_u256(); - let uid = object::new(&mut ctx); - let upgrade_cap = package::test_publish( - object::uid_to_inner(&uid), - &mut ctx, - ); - let cap_id = object::id_from_address(address::from_u256(abi.read_u256())); - let approved_message = channel::new_approved_message( - trusted_source_chain, - ascii::string(b"1"), - trusted_source_address, - object::id_address(&channale_object), - payload, - ); - let mut governance = Governance { - id: object::new(&mut ctx), - trusted_source_chain, - trusted_source_address, - message_type: message_type, - channel: channale_object, - caps: table::new(&mut ctx), - }; - - governance - .caps - .add( - cap_id, - upgrade_cap, + #[test] + fun test_authorize_upgrade() { + let mut ctx = tx_context::dummy(); + let trusted_source_chain = ascii::string(b"Axelar"); + let trusted_source_address = ascii::string(b"0x0"); + let channale_object = channel::new(&mut ctx); + let payload = + x"0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010400000000000000000000000000000000000000000000000000000000000000"; + let mut abi = abi::new_reader(payload); + let message_type = abi.read_u256(); + let uid = object::new(&mut ctx); + let upgrade_cap = package::test_publish( + object::uid_to_inner(&uid), + &mut ctx, ); - let upgrade_ticket = authorize_upgrade(&mut governance, approved_message); - assert!( - package::ticket_package(&upgrade_ticket) == object::uid_to_inner(&uid), - EUntrustedAddress, - ); - let policy = abi.read_u8(); - assert!(package::ticket_policy(&upgrade_ticket) == policy); - let digest = abi.read_bytes(); - assert!(package::ticket_digest(&upgrade_ticket) == digest); - test_utils::destroy(upgrade_ticket); - test_utils::destroy(uid); - test_utils::destroy(governance); -} + let cap_id = object::id_from_address(address::from_u256(abi.read_u256())); + let approved_message = channel::new_approved_message( + trusted_source_chain, + ascii::string(b"1"), + trusted_source_address, + object::id_address(&channale_object), + payload, + ); + let mut governance = Governance { + id: object::new(&mut ctx), + trusted_source_chain, + trusted_source_address, + message_type: message_type, + channel: channale_object, + caps: table::new(&mut ctx), + }; + + governance + .caps + .add( + cap_id, + upgrade_cap, + ); + let upgrade_ticket = authorize_upgrade(&mut governance, approved_message); + assert!(package::ticket_package(&upgrade_ticket) == object::uid_to_inner(&uid), EUntrustedAddress); + let policy = abi.read_u8(); + assert!(package::ticket_policy(&upgrade_ticket) == policy); + let digest = abi.read_bytes(); + assert!(package::ticket_digest(&upgrade_ticket) == digest); + test_utils::destroy(upgrade_ticket); + test_utils::destroy(uid); + test_utils::destroy(governance); + } -#[test] -#[expected_failure(abort_code = EInvalidMessageType)] -fun test_authorize_upgrade_invalid_message_type() { - let mut ctx = tx_context::dummy(); - let trusted_source_chain = ascii::string(b"Axelar"); - let trusted_source_address = ascii::string(b"0x0"); - let channale_object = channel::new(&mut ctx); - let payload = - x"0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0"; - let approved_message = channel::new_approved_message( - trusted_source_chain, - ascii::string(b"1"), - trusted_source_address, - object::id_address(&channale_object), - payload, - ); - let mut governance = Governance { - id: object::new(&mut ctx), - trusted_source_chain, - trusted_source_address, - message_type: 2, - channel: channale_object, - caps: table::new(&mut ctx), - }; - let upgrade_ticket = authorize_upgrade(&mut governance, approved_message); - test_utils::destroy(upgrade_ticket); - test_utils::destroy(governance); -} + #[test] + #[expected_failure(abort_code = EInvalidMessageType)] + fun test_authorize_upgrade_invalid_message_type() { + let mut ctx = tx_context::dummy(); + let trusted_source_chain = ascii::string(b"Axelar"); + let trusted_source_address = ascii::string(b"0x0"); + let channale_object = channel::new(&mut ctx); + let payload = + x"0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0"; + let approved_message = channel::new_approved_message( + trusted_source_chain, + ascii::string(b"1"), + trusted_source_address, + object::id_address(&channale_object), + payload, + ); + let mut governance = Governance { + id: object::new(&mut ctx), + trusted_source_chain, + trusted_source_address, + message_type: 2, + channel: channale_object, + caps: table::new(&mut ctx), + }; + let upgrade_ticket = authorize_upgrade(&mut governance, approved_message); + test_utils::destroy(upgrade_ticket); + test_utils::destroy(governance); + } -#[test] -#[expected_failure(abort_code = EUntrustedAddress)] -fun test_authorize_upgrade_trusted_address() { - let mut ctx = tx_context::dummy(); - let trusted_source_chain = ascii::string(b"Axelar"); - let trusted_source_address = ascii::string(b"0x0"); - let channale_object = channel::new(&mut ctx); - let payload = - x"0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0"; - let approved_message = channel::new_approved_message( - ascii::string(b"sui"), - ascii::string(b"1"), - ascii::string(b"0x1"), - object::id_address(&channale_object), - payload, - ); - let mut governance = Governance { - id: object::new(&mut ctx), - trusted_source_chain, - trusted_source_address, - message_type: 2, - channel: channale_object, - caps: table::new(&mut ctx), - }; - let upgrade_ticket = authorize_upgrade(&mut governance, approved_message); - test_utils::destroy(upgrade_ticket); - test_utils::destroy(governance); -} + #[test] + #[expected_failure(abort_code = EUntrustedAddress)] + fun test_authorize_upgrade_trusted_address() { + let mut ctx = tx_context::dummy(); + let trusted_source_chain = ascii::string(b"Axelar"); + let trusted_source_address = ascii::string(b"0x0"); + let channale_object = channel::new(&mut ctx); + let payload = + x"0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0"; + let approved_message = channel::new_approved_message( + ascii::string(b"sui"), + ascii::string(b"1"), + ascii::string(b"0x1"), + object::id_address(&channale_object), + payload, + ); + let mut governance = Governance { + id: object::new(&mut ctx), + trusted_source_chain, + trusted_source_address, + message_type: 2, + channel: channale_object, + caps: table::new(&mut ctx), + }; + let upgrade_ticket = authorize_upgrade(&mut governance, approved_message); + test_utils::destroy(upgrade_ticket); + test_utils::destroy(governance); + } -#[test] -#[expected_failure(abort_code = channel::EInvalidDestination)] -fun test_authorize_invalid_destination_address() { - let mut ctx = tx_context::dummy(); - let trusted_source_chain = ascii::string(b"Axelar"); - let trusted_source_address = ascii::string(b"0x0"); - let channale_object = channel::new(&mut ctx); - let payload = x"01"; - let approved_message = channel::new_approved_message( - ascii::string(b"sui"), - ascii::string(b"1"), - ascii::string(b"0x1"), - address::from_u256(2), - payload, - ); - let mut governance = Governance { - id: object::new(&mut ctx), - trusted_source_chain, - trusted_source_address, - message_type: 2, - channel: channale_object, - caps: table::new(&mut ctx), - }; - let upgrade_ticket = authorize_upgrade(&mut governance, approved_message); - test_utils::destroy(upgrade_ticket); - test_utils::destroy(governance); + #[test] + #[expected_failure(abort_code = channel::EInvalidDestination)] + fun test_authorize_invalid_destination_address() { + let mut ctx = tx_context::dummy(); + let trusted_source_chain = ascii::string(b"Axelar"); + let trusted_source_address = ascii::string(b"0x0"); + let channale_object = channel::new(&mut ctx); + let payload = x"01"; + let approved_message = channel::new_approved_message( + ascii::string(b"sui"), + ascii::string(b"1"), + ascii::string(b"0x1"), + address::from_u256(2), + payload, + ); + let mut governance = Governance { + id: object::new(&mut ctx), + trusted_source_chain, + trusted_source_address, + message_type: 2, + channel: channale_object, + caps: table::new(&mut ctx), + }; + let upgrade_ticket = authorize_upgrade(&mut governance, approved_message); + test_utils::destroy(upgrade_ticket); + test_utils::destroy(governance); + } } diff --git a/move/interchain_token/sources/interchain_token.move b/move/interchain_token/sources/interchain_token.move index d599d600..a7615d66 100644 --- a/move/interchain_token/sources/interchain_token.move +++ b/move/interchain_token/sources/interchain_token.move @@ -1,20 +1,19 @@ -module interchain_token::q; +module interchain_token::q { + use sui::{coin, url::Url}; -use sui::coin; -use sui::url::Url; + public struct Q has drop {} -public struct Q has drop {} - -fun init(witness: Q, ctx: &mut TxContext) { - let (treasury, metadata) = coin::create_currency( - witness, - 9, - b"Q", - b"Quote", - b"", - option::none(), - ctx, - ); - transfer::public_transfer(treasury, tx_context::sender(ctx)); - transfer::public_transfer(metadata, tx_context::sender(ctx)); + fun init(witness: Q, ctx: &mut TxContext) { + let (treasury, metadata) = coin::create_currency( + witness, + 9, + b"Q", + b"Quote", + b"", + option::none(), + ctx, + ); + transfer::public_transfer(treasury, tx_context::sender(ctx)); + transfer::public_transfer(metadata, tx_context::sender(ctx)); + } } diff --git a/move/interchain_token_service/sources/discovery.move b/move/interchain_token_service/sources/discovery.move index 199d659b..0719945a 100644 --- a/move/interchain_token_service/sources/discovery.move +++ b/move/interchain_token_service/sources/discovery.move @@ -1,505 +1,480 @@ -module interchain_token_service::discovery; - -use abi::abi::{Self, AbiReader}; -use interchain_token_service::interchain_token_service::InterchainTokenService; -use interchain_token_service::token_id::{Self, TokenId}; -use relayer_discovery::discovery::RelayerDiscovery; -use relayer_discovery::transaction::{Self, Transaction, package_id}; -use std::ascii; -use std::type_name; -use sui::address; - -/// ------ -/// Errors -/// ------ -#[error] -const EUnsupportedMessageType: vector = b"the message type found is not supported"; -#[error] -const EInvalidMessageType: vector = - b"can only get interchain transfer info for interchain transfers"; - -const MESSAGE_TYPE_INTERCHAIN_TRANSFER: u256 = 0; -const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; -// onst MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER: u256 = 2; -// onst MESSAGE_TYPE_SEND_TO_HUB: u256 = 3; -const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; - -public fun interchain_transfer_info(payload: vector): (TokenId, address, u64, vector) { - let mut reader = abi::new_reader(payload); - assert!(reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, EInvalidMessageType); - // Source chain validation is not done here. - reader.skip_slot(); - let payload = reader.read_bytes(); - reader = abi::new_reader(payload); - assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); - - let token_id = token_id::from_u256(reader.read_u256()); - reader.skip_slot(); // skip source_address - let destination = address::from_bytes(reader.read_bytes()); - let amount = (reader.read_u256() as u64); - let data = reader.read_bytes(); - - (token_id, destination, amount, data) -} +module interchain_token_service::discovery { + use abi::abi::{Self, AbiReader}; + use interchain_token_service::{interchain_token_service::InterchainTokenService, token_id::{Self, TokenId}}; + use relayer_discovery::{discovery::RelayerDiscovery, transaction::{Self, Transaction, package_id}}; + use std::{ascii, type_name}; + use sui::address; + + /// ------ + /// Errors + /// ------ + #[error] + const EUnsupportedMessageType: vector = b"the message type found is not supported"; + #[error] + const EInvalidMessageType: vector = b"can only get interchain transfer info for interchain transfers"; + + const MESSAGE_TYPE_INTERCHAIN_TRANSFER: u256 = 0; + const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; + // onst MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER: u256 = 2; + // onst MESSAGE_TYPE_SEND_TO_HUB: u256 = 3; + const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; + + public fun interchain_transfer_info(payload: vector): (TokenId, address, u64, vector) { + let mut reader = abi::new_reader(payload); + assert!(reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, EInvalidMessageType); + // Source chain validation is not done here. + reader.skip_slot(); + let payload = reader.read_bytes(); + reader = abi::new_reader(payload); + assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); -public fun register_transaction( - its: &mut InterchainTokenService, - discovery: &mut RelayerDiscovery, -) { - let mut arg = vector[0]; - arg.append(object::id(its).to_bytes()); - - let arguments = vector[arg, vector[3]]; - - let function = transaction::new_function( - package_id(), - ascii::string(b"discovery"), - ascii::string(b"call_info"), - ); - - let move_call = transaction::new_move_call( - function, - arguments, - vector[], - ); - - its.register_transaction( - discovery, - transaction::new_transaction( - false, - vector[move_call], - ), - ); -} + let token_id = token_id::from_u256(reader.read_u256()); + reader.skip_slot(); // skip source_address + let destination = address::from_bytes(reader.read_bytes()); + let amount = (reader.read_u256() as u64); + let data = reader.read_bytes(); -public fun call_info(its: &InterchainTokenService, mut payload: vector): Transaction { - let mut reader = abi::new_reader(payload); - let mut message_type = reader.read_u256(); + (token_id, destination, amount, data) + } - if (message_type == MESSAGE_TYPE_RECEIVE_FROM_HUB) { - reader.skip_slot(); - payload = reader.read_bytes(); - reader = abi::new_reader(payload); - message_type = reader.read_u256(); - }; - - if (message_type == MESSAGE_TYPE_INTERCHAIN_TRANSFER) { - interchain_transfer_tx(its, &mut reader) - } else { - assert!(message_type == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, EUnsupportedMessageType); - deploy_interchain_token_tx(its, &mut reader) + public fun register_transaction(its: &mut InterchainTokenService, discovery: &mut RelayerDiscovery) { + let mut arg = vector[0]; + arg.append(object::id(its).to_bytes()); + + let arguments = vector[arg, vector[3]]; + + let function = transaction::new_function( + package_id(), + ascii::string(b"discovery"), + ascii::string(b"call_info"), + ); + + let move_call = transaction::new_move_call( + function, + arguments, + vector[], + ); + + its.register_transaction( + discovery, + transaction::new_transaction( + false, + vector[move_call], + ), + ); } -} -fun interchain_transfer_tx(its: &InterchainTokenService, reader: &mut AbiReader): Transaction { - let token_id = token_id::from_u256(reader.read_u256()); - reader.skip_slot(); // skip source_address - let destination_address = address::from_bytes(reader.read_bytes()); - reader.skip_slot(); // skip amount - let data = reader.read_bytes(); - let value = its.package_value(); + public fun call_info(its: &InterchainTokenService, mut payload: vector): Transaction { + let mut reader = abi::new_reader(payload); + let mut message_type = reader.read_u256(); + + if (message_type == MESSAGE_TYPE_RECEIVE_FROM_HUB) { + reader.skip_slot(); + payload = reader.read_bytes(); + reader = abi::new_reader(payload); + message_type = reader.read_u256(); + }; + + if (message_type == MESSAGE_TYPE_INTERCHAIN_TRANSFER) { + interchain_transfer_tx(its, &mut reader) + } else { + assert!(message_type == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, EUnsupportedMessageType); + deploy_interchain_token_tx(its, &mut reader) + } + } - if (data.is_empty()) { + fun interchain_transfer_tx(its: &InterchainTokenService, reader: &mut AbiReader): Transaction { + let token_id = token_id::from_u256(reader.read_u256()); + reader.skip_slot(); // skip source_address + let destination_address = address::from_bytes(reader.read_bytes()); + reader.skip_slot(); // skip amount + let data = reader.read_bytes(); + let value = its.package_value(); + + if (data.is_empty()) { + let mut arg = vector[0]; + arg.append(object::id_address(its).to_bytes()); + + let type_name = value.registered_coin_type(token_id); + + let arguments = vector[arg, vector[2], vector[0, 6]]; + + transaction::new_transaction( + true, + vector[ + transaction::new_move_call( + transaction::new_function( + package_id(), + ascii::string(b"interchain_token_service"), + ascii::string(b"receive_interchain_transfer"), + ), + arguments, + vector[type_name::into_string(*type_name)], + ), + ], + ) + } else { + let mut discovery_arg = vector[0]; + discovery_arg.append(value.relayer_discovery_id().id_to_address().to_bytes()); + + let mut channel_id_arg = vector[1]; + channel_id_arg.append(destination_address.to_bytes()); + + transaction::new_transaction( + false, + vector[ + transaction::new_move_call( + transaction::new_function( + package_id(), + ascii::string(b"discovery"), + ascii::string(b"get_transaction"), + ), + vector[discovery_arg, channel_id_arg], + vector[], + ), + ], + ) + } + } + + fun deploy_interchain_token_tx(its: &InterchainTokenService, reader: &mut AbiReader): Transaction { let mut arg = vector[0]; arg.append(object::id_address(its).to_bytes()); - let type_name = value.registered_coin_type(token_id); + let arguments = vector[arg, vector[2]]; - let arguments = vector[arg, vector[2], vector[0, 6]]; + reader.skip_slot(); // skip token_id + reader.skip_slot(); // skip _name + let symbol = ascii::string(reader.read_bytes()); + let decimals = (reader.read_u256() as u8); + reader.skip_slot(); // skip distributor + + let value = its.package_value(); + let type_name = value.unregistered_coin_type(&symbol, decimals); + + let move_call = transaction::new_move_call( + transaction::new_function( + package_id(), + ascii::string(b"interchain_token_service"), + ascii::string(b"receive_deploy_interchain_token"), + ), + arguments, + vector[type_name::into_string(*type_name)], + ); transaction::new_transaction( true, - vector[ - transaction::new_move_call( - transaction::new_function( - package_id(), - ascii::string(b"interchain_token_service"), - ascii::string(b"receive_interchain_transfer"), - ), - arguments, - vector[type_name::into_string(*type_name)], - ), - ], + vector[move_call], ) - } else { - let mut discovery_arg = vector[0]; - discovery_arg.append(value.relayer_discovery_id().id_to_address().to_bytes()); + } - let mut channel_id_arg = vector[1]; - channel_id_arg.append(destination_address.to_bytes()); + // === Tests === + #[test_only] + fun initial_tx(its: &InterchainTokenService): Transaction { + let mut arg = vector[0]; + arg.append(sui::bcs::to_bytes(&object::id(its))); + + let arguments = vector[arg, vector[3]]; + + let function = transaction::new_function( + package_id(), + ascii::string(b"discovery"), + ascii::string(b"call_info"), + ); + + let move_call = transaction::new_move_call( + function, + arguments, + vector[], + ); transaction::new_transaction( false, - vector[ - transaction::new_move_call( - transaction::new_function( - package_id(), - ascii::string(b"discovery"), - ascii::string(b"get_transaction"), - ), - vector[discovery_arg, channel_id_arg], - vector[], - ), - ], + vector[move_call], ) } -} -fun deploy_interchain_token_tx(its: &InterchainTokenService, reader: &mut AbiReader): Transaction { - let mut arg = vector[0]; - arg.append(object::id_address(its).to_bytes()); + #[test] + fun test_discovery_initial() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut discovery = relayer_discovery::discovery::new(ctx); - let arguments = vector[arg, vector[2]]; + register_transaction(&mut its, &mut discovery); - reader.skip_slot(); // skip token_id - reader.skip_slot(); // skip _name - let symbol = ascii::string(reader.read_bytes()); - let decimals = (reader.read_u256() as u8); - reader.skip_slot(); // skip distributor + let value = its.package_value(); + assert!(discovery.get_transaction(object::id_from_address(value.channel_address())) == initial_tx(&its)); + assert!(value.relayer_discovery_id() == object::id(&discovery)); - let value = its.package_value(); - let type_name = value.unregistered_coin_type(&symbol, decimals); + sui::test_utils::destroy(its); + sui::test_utils::destroy(discovery); + } - let move_call = transaction::new_move_call( - transaction::new_function( - package_id(), - ascii::string(b"interchain_token_service"), - ascii::string(b"receive_deploy_interchain_token"), - ), - arguments, - vector[type_name::into_string(*type_name)], - ); - - transaction::new_transaction( - true, - vector[move_call], - ) -} + #[test] + fun test_discovery_interchain_transfer() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut discovery = relayer_discovery::discovery::new(ctx); + + register_transaction(&mut its, &mut discovery); + + let token_id = @0x1234; + let source_address = b"source address"; + let target_channel = @0x5678; + let amount = 1905; + let data = b""; + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(address::to_u256(token_id)) + .write_bytes(source_address) + .write_bytes(target_channel.to_bytes()) + .write_u256(amount) + .write_bytes(data); + let payload = writer.into_bytes(); + + let type_arg = std::type_name::get(); + its.add_registered_coin_type_for_testing( + interchain_token_service::token_id::from_address(token_id), + type_arg, + ); + let tx_block = call_info(&its, payload); + + let mut reader = abi::new_reader(payload); + reader.skip_slot(); // skip message_type + + assert!(tx_block == interchain_transfer_tx(&its, &mut reader)); + assert!(tx_block.is_final() && tx_block.move_calls().length() == 1); + + let call_info = tx_block.move_calls().pop_back(); + + assert!(call_info.function().package_id_from_function() == package_id()); + assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); + assert!(call_info.function().name() == ascii::string(b"receive_interchain_transfer")); + let mut arg = vector[0]; + arg.append(object::id_address(&its).to_bytes()); -// === Tests === -#[test_only] -fun initial_tx(its: &InterchainTokenService): Transaction { - let mut arg = vector[0]; - arg.append(sui::bcs::to_bytes(&object::id(its))); - - let arguments = vector[arg, vector[3]]; - - let function = transaction::new_function( - package_id(), - ascii::string(b"discovery"), - ascii::string(b"call_info"), - ); - - let move_call = transaction::new_move_call( - function, - arguments, - vector[], - ); - - transaction::new_transaction( - false, - vector[move_call], - ) -} + let arguments = vector[arg, vector[2], vector[0, 6]]; + assert!(call_info.arguments() == arguments); + assert!(call_info.type_arguments() == vector[type_arg.into_string()]); -#[test] -fun test_discovery_initial() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut discovery = relayer_discovery::discovery::new(ctx); + sui::test_utils::destroy(its); + sui::test_utils::destroy(discovery); + } - register_transaction(&mut its, &mut discovery); + #[test] + fun test_discovery_interchain_transfer_with_data() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut discovery = relayer_discovery::discovery::new(ctx); + + register_transaction(&mut its, &mut discovery); + + assert!(discovery.get_transaction(object::id_from_address(its.package_value().channel_address())) == initial_tx(&its)); + + let token_id = @0x1234; + let source_address = b"source address"; + let target_channel = @0x5678; + let amount = 1905; + let tx_data = sui::bcs::to_bytes(&initial_tx(&its)); + let mut writer = abi::new_writer(2); + writer.write_bytes(tx_data).write_u256(1245); + let data = writer.into_bytes(); + + writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(address::to_u256(token_id)) + .write_bytes(source_address) + .write_bytes(target_channel.to_bytes()) + .write_u256(amount) + .write_bytes(data); + let payload = writer.into_bytes(); + + its.add_registered_coin_type_for_testing( + interchain_token_service::token_id::from_address(token_id), + std::type_name::get(), + ); + + let mut reader = abi::new_reader(payload); + reader.skip_slot(); // skip message_type + + assert!(call_info(&its, payload) == interchain_transfer_tx(&its, &mut reader)); + + sui::test_utils::destroy(its); + sui::test_utils::destroy(discovery); + } - let value = its.package_value(); - assert!( - discovery.get_transaction(object::id_from_address(value.channel_address())) == initial_tx(&its), - ); - assert!(value.relayer_discovery_id() == object::id(&discovery)); + #[test] + fun test_discovery_deploy_token() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut discovery = relayer_discovery::discovery::new(ctx); + + register_transaction(&mut its, &mut discovery); + + let token_id = @0x1234; + let name = b"name"; + let symbol = b"symbol"; + let decimals = 15; + let distributor = @0x0325; + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) + .write_u256(address::to_u256(token_id)) + .write_bytes(name) + .write_bytes(symbol) + .write_u256(decimals) + .write_bytes(distributor.to_bytes()); + let payload = writer.into_bytes(); + + let type_arg = std::type_name::get(); + its.add_unregistered_coin_type_for_testing( + interchain_token_service::token_id::unregistered_token_id( + &ascii::string(symbol), + (decimals as u8), + ), + type_arg, + ); + let tx_block = call_info(&its, payload); + + let mut reader = abi::new_reader(payload); + reader.skip_slot(); // skip message_type + + assert!(tx_block == deploy_interchain_token_tx(&its, &mut reader)); + + assert!(tx_block.is_final()); + let mut move_calls = tx_block.move_calls(); + assert!(move_calls.length() == 1); + let call_info = move_calls.pop_back(); + assert!(call_info.function().package_id_from_function() == package_id()); + assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); + assert!(call_info.function().name() == ascii::string(b"receive_deploy_interchain_token")); + let mut arg = vector[0]; + arg.append(object::id_address(&its).to_bytes()); - sui::test_utils::destroy(its); - sui::test_utils::destroy(discovery); -} + let arguments = vector[arg, vector[2]]; + assert!(call_info.arguments() == arguments); + assert!(call_info.type_arguments() == vector[type_arg.into_string()]); -#[test] -fun test_discovery_interchain_transfer() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut discovery = relayer_discovery::discovery::new(ctx); - - register_transaction(&mut its, &mut discovery); - - let token_id = @0x1234; - let source_address = b"source address"; - let target_channel = @0x5678; - let amount = 1905; - let data = b""; - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(address::to_u256(token_id)) - .write_bytes(source_address) - .write_bytes(target_channel.to_bytes()) - .write_u256(amount) - .write_bytes(data); - let payload = writer.into_bytes(); - - let type_arg = std::type_name::get(); - its.add_registered_coin_type_for_testing( - interchain_token_service::token_id::from_address(token_id), - type_arg, - ); - let tx_block = call_info(&its, payload); - - let mut reader = abi::new_reader(payload); - reader.skip_slot(); // skip message_type - - assert!(tx_block == interchain_transfer_tx(&its, &mut reader)); - assert!(tx_block.is_final() && tx_block.move_calls().length() == 1); - - let call_info = tx_block.move_calls().pop_back(); - - assert!( - call_info.function().package_id_from_function() == package_id(), - ); - assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); - assert!(call_info.function().name() == ascii::string(b"receive_interchain_transfer")); - let mut arg = vector[0]; - arg.append(object::id_address(&its).to_bytes()); - - let arguments = vector[arg, vector[2], vector[0, 6]]; - assert!(call_info.arguments() == arguments); - assert!(call_info.type_arguments() == vector[type_arg.into_string()]); - - sui::test_utils::destroy(its); - sui::test_utils::destroy(discovery); -} + sui::test_utils::destroy(its); + sui::test_utils::destroy(discovery); + } -#[test] -fun test_discovery_interchain_transfer_with_data() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut discovery = relayer_discovery::discovery::new(ctx); - - register_transaction(&mut its, &mut discovery); - - assert!( - discovery.get_transaction(object::id_from_address(its.package_value().channel_address())) == initial_tx(&its), - ); - - let token_id = @0x1234; - let source_address = b"source address"; - let target_channel = @0x5678; - let amount = 1905; - let tx_data = sui::bcs::to_bytes(&initial_tx(&its)); - let mut writer = abi::new_writer(2); - writer.write_bytes(tx_data).write_u256(1245); - let data = writer.into_bytes(); - - writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(address::to_u256(token_id)) - .write_bytes(source_address) - .write_bytes(target_channel.to_bytes()) - .write_u256(amount) - .write_bytes(data); - let payload = writer.into_bytes(); - - its.add_registered_coin_type_for_testing( - interchain_token_service::token_id::from_address(token_id), - std::type_name::get(), - ); - - let mut reader = abi::new_reader(payload); - reader.skip_slot(); // skip message_type - - assert!(call_info(&its, payload) == interchain_transfer_tx(&its, &mut reader)); - - sui::test_utils::destroy(its); - sui::test_utils::destroy(discovery); -} + #[test] + fun test_interchain_transfer_info() { + let message_type = MESSAGE_TYPE_INTERCHAIN_TRANSFER; + let token_id = 1; + let source_address = b"source address"; + let source_chain = b"Chain Name"; + let destination = @0x3.to_bytes(); + let amount = 2; + let data = b"data"; + + let mut writer = abi::new_writer(6); + writer + .write_u256(message_type) + .write_u256(token_id) + .write_bytes(source_address) + .write_bytes(destination) + .write_u256(amount) + .write_bytes(data); + let payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain).write_bytes(payload); + + let (resolved_token_id, resolved_destination, resolved_amount, resolved_data) = interchain_transfer_info(writer.into_bytes()); + assert!(resolved_token_id == token_id::from_u256(token_id)); + assert!(resolved_destination == address::from_bytes(destination)); + assert!(resolved_amount == (amount as u64)); + assert!(resolved_data == data); + } -#[test] -fun test_discovery_deploy_token() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut discovery = relayer_discovery::discovery::new(ctx); - - register_transaction(&mut its, &mut discovery); - - let token_id = @0x1234; - let name = b"name"; - let symbol = b"symbol"; - let decimals = 15; - let distributor = @0x0325; - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) - .write_u256(address::to_u256(token_id)) - .write_bytes(name) - .write_bytes(symbol) - .write_u256(decimals) - .write_bytes(distributor.to_bytes()); - let payload = writer.into_bytes(); - - let type_arg = std::type_name::get(); - its.add_unregistered_coin_type_for_testing( - interchain_token_service::token_id::unregistered_token_id( - &ascii::string(symbol), - (decimals as u8), - ), - type_arg, - ); - let tx_block = call_info(&its, payload); - - let mut reader = abi::new_reader(payload); - reader.skip_slot(); // skip message_type - - assert!(tx_block == deploy_interchain_token_tx(&its, &mut reader)); - - assert!(tx_block.is_final()); - let mut move_calls = tx_block.move_calls(); - assert!(move_calls.length() == 1); - let call_info = move_calls.pop_back(); - assert!( - call_info.function().package_id_from_function() == package_id(), - ); - assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); - assert!(call_info.function().name() == ascii::string(b"receive_deploy_interchain_token")); - let mut arg = vector[0]; - arg.append(object::id_address(&its).to_bytes()); - - let arguments = vector[arg, vector[2]]; - assert!(call_info.arguments() == arguments); - assert!(call_info.type_arguments() == vector[type_arg.into_string()]); - - sui::test_utils::destroy(its); - sui::test_utils::destroy(discovery); -} + #[test] + #[expected_failure(abort_code = EInvalidMessageType)] + fun test_interchain_transfer_info_invalid_message_type() { + let message_type = MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN; + let token_id = @0x1234; + let name = b"name"; + let symbol = b"symbol"; + let decimals = 15; + let distributor = @0x0325; + let mut writer = abi::new_writer(6); + writer + .write_u256(message_type) + .write_u256(address::to_u256(token_id)) + .write_bytes(name) + .write_bytes(symbol) + .write_u256(decimals) + .write_bytes(distributor.to_bytes()); + + interchain_transfer_info(writer.into_bytes()); + } -#[test] -fun test_interchain_transfer_info() { - let message_type = MESSAGE_TYPE_INTERCHAIN_TRANSFER; - let token_id = 1; - let source_address = b"source address"; - let source_chain = b"Chain Name"; - let destination = @0x3.to_bytes(); - let amount = 2; - let data = b"data"; - - let mut writer = abi::new_writer(6); - writer - .write_u256(message_type) - .write_u256(token_id) - .write_bytes(source_address) - .write_bytes(destination) - .write_u256(amount) - .write_bytes(data); - let payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain).write_bytes(payload); - - let ( - resolved_token_id, - resolved_destination, - resolved_amount, - resolved_data, - ) = interchain_transfer_info(writer.into_bytes()); - assert!(resolved_token_id == token_id::from_u256(token_id)); - assert!(resolved_destination == address::from_bytes(destination)); - assert!(resolved_amount == (amount as u64)); - assert!(resolved_data == data); -} + #[test] + fun test_discovery_hub_message() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut discovery = relayer_discovery::discovery::new(ctx); + + register_transaction(&mut its, &mut discovery); + + let token_id = @0x1234; + let source_address = b"source address"; + let target_channel = @0x5678; + let amount = 1905; + let data = b""; + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(address::to_u256(token_id)) + .write_bytes(source_address) + .write_bytes(target_channel.to_bytes()) + .write_u256(amount) + .write_bytes(data); + let inner = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(b"source_chain").write_bytes(inner); + let payload = writer.into_bytes(); + + let type_arg = std::type_name::get(); + its.add_registered_coin_type_for_testing( + interchain_token_service::token_id::from_address(token_id), + type_arg, + ); + let tx_block = call_info(&its, payload); + + assert!(tx_block == call_info(&its, payload)); + assert!(tx_block.is_final() && tx_block.move_calls().length() == 1); + + let call_info = tx_block.move_calls().pop_back(); + + assert!(call_info.function().package_id_from_function() == package_id()); + assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); + assert!(call_info.function().name() == ascii::string(b"receive_interchain_transfer")); + let mut arg = vector[0]; + arg.append(object::id_address(&its).to_bytes()); -#[test] -#[expected_failure(abort_code = EInvalidMessageType)] -fun test_interchain_transfer_info_invalid_message_type() { - let message_type = MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN; - let token_id = @0x1234; - let name = b"name"; - let symbol = b"symbol"; - let decimals = 15; - let distributor = @0x0325; - let mut writer = abi::new_writer(6); - writer - .write_u256(message_type) - .write_u256(address::to_u256(token_id)) - .write_bytes(name) - .write_bytes(symbol) - .write_u256(decimals) - .write_bytes(distributor.to_bytes()); - - interchain_transfer_info(writer.into_bytes()); -} + let arguments = vector[arg, vector[2], vector[0, 6]]; + assert!(call_info.arguments() == arguments); + assert!(call_info.type_arguments() == vector[type_arg.into_string()]); -#[test] -fun test_discovery_hub_message() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut discovery = relayer_discovery::discovery::new(ctx); - - register_transaction(&mut its, &mut discovery); - - let token_id = @0x1234; - let source_address = b"source address"; - let target_channel = @0x5678; - let amount = 1905; - let data = b""; - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(address::to_u256(token_id)) - .write_bytes(source_address) - .write_bytes(target_channel.to_bytes()) - .write_u256(amount) - .write_bytes(data); - let inner = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(b"source_chain") - .write_bytes(inner); - let payload = writer.into_bytes(); - - let type_arg = std::type_name::get(); - its.add_registered_coin_type_for_testing( - interchain_token_service::token_id::from_address(token_id), - type_arg, - ); - let tx_block = call_info(&its, payload); - - assert!(tx_block == call_info(&its, payload)); - assert!(tx_block.is_final() && tx_block.move_calls().length() == 1); - - let call_info = tx_block.move_calls().pop_back(); - - assert!( - call_info.function().package_id_from_function() == package_id(), - ); - assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); - assert!(call_info.function().name() == ascii::string(b"receive_interchain_transfer")); - let mut arg = vector[0]; - arg.append(object::id_address(&its).to_bytes()); - - let arguments = vector[arg, vector[2], vector[0, 6]]; - assert!(call_info.arguments() == arguments); - assert!(call_info.type_arguments() == vector[type_arg.into_string()]); - - sui::test_utils::destroy(its); - sui::test_utils::destroy(discovery); -} + sui::test_utils::destroy(its); + sui::test_utils::destroy(discovery); + } -#[test] -#[expected_failure(abort_code = EUnsupportedMessageType)] -fun test_call_info_unsupported_message_type() { - let ctx = &mut sui::tx_context::dummy(); - let its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + #[test] + #[expected_failure(abort_code = EUnsupportedMessageType)] + fun test_call_info_unsupported_message_type() { + let ctx = &mut sui::tx_context::dummy(); + let its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut writer = abi::new_writer(1); - writer.write_u256(5); - let payload = writer.into_bytes(); + let mut writer = abi::new_writer(1); + writer.write_u256(5); + let payload = writer.into_bytes(); - call_info(&its, payload); + call_info(&its, payload); - sui::test_utils::destroy(its); + sui::test_utils::destroy(its); + } } diff --git a/move/interchain_token_service/sources/events.move b/move/interchain_token_service/sources/events.move index 3d837dad..f09a8e24 100644 --- a/move/interchain_token_service/sources/events.move +++ b/move/interchain_token_service/sources/events.move @@ -1,231 +1,222 @@ -module interchain_token_service::events; - -use axelar_gateway::bytes32::{Self, Bytes32}; -use interchain_token_service::token_id::{TokenId, UnregisteredTokenId}; -use std::ascii::String; -use std::string; -use sui::address; -use sui::event; -use sui::hash::keccak256; - -// ----- -// Types -// ----- -public struct CoinRegistered has copy, drop { - token_id: TokenId, -} - -public struct InterchainTransfer has copy, drop { - token_id: TokenId, - source_address: address, - destination_chain: String, - destination_address: vector, - amount: u64, - data_hash: Bytes32, -} - -public struct InterchainTokenDeploymentStarted has copy, drop { - token_id: TokenId, - name: string::String, - symbol: String, - decimals: u8, - destination_chain: String, -} - -public struct InterchainTransferReceived has copy, drop { - message_id: String, - token_id: TokenId, - source_chain: String, - source_address: vector, - destination_address: address, - amount: u64, - data_hash: Bytes32, -} - -public struct UnregisteredCoinReceived has copy, drop { - token_id: UnregisteredTokenId, - symbol: String, - decimals: u8, -} - -public struct TrustedChainAdded has copy, drop { - chain_name: String, -} - -public struct TrustedChainRemoved has copy, drop { - chain_name: String, -} - -public struct FlowLimitSet has copy, drop { - token_id: TokenId, - flow_limit: Option, -} - -// ----------------- -// Package Functions -// ----------------- -public(package) fun coin_registered(token_id: TokenId) { - event::emit(CoinRegistered { - token_id, - }); -} - -public(package) fun interchain_transfer( - token_id: TokenId, - source_address: address, - destination_chain: String, - destination_address: vector, - amount: u64, - data: &vector, -) { - let data_hash = if (data.length() == 0) { - bytes32::new(@0x0) - } else { - bytes32::new(address::from_bytes(keccak256(data))) - }; - event::emit(InterchainTransfer { - token_id, - source_address, - destination_chain, - destination_address, - amount, - data_hash, - }); -} - -public(package) fun interchain_token_deployment_started( - token_id: TokenId, - name: string::String, - symbol: String, - decimals: u8, - destination_chain: String, -) { - event::emit(InterchainTokenDeploymentStarted { - token_id, - name, - symbol, - decimals, - destination_chain, - }); -} - -public(package) fun interchain_transfer_received( - message_id: String, - token_id: TokenId, - source_chain: String, - source_address: vector, - destination_address: address, - amount: u64, - data: &vector, -) { - let data_hash = bytes32::new(address::from_bytes(keccak256(data))); - event::emit(InterchainTransferReceived { - message_id, - token_id, - source_chain, - source_address, - destination_address, - amount, - data_hash, - }); -} - -public(package) fun unregistered_coin_received( - token_id: UnregisteredTokenId, - symbol: String, - decimals: u8, -) { - event::emit(UnregisteredCoinReceived { - token_id, - symbol, - decimals, - }); -} - -public(package) fun trusted_chain_added( - chain_name: String, -) { - event::emit(TrustedChainAdded { - chain_name, - }); -} - -public(package) fun trusted_chain_removed(chain_name: String) { - event::emit(TrustedChainRemoved { - chain_name, - }); -} - -public(package) fun flow_limit_set(token_id: TokenId, flow_limit: Option) { - event::emit(FlowLimitSet { - token_id, - flow_limit, - }); -} - -// --------- -// Test Only -// --------- -#[test_only] -use interchain_token_service::coin::COIN; -#[test_only] -use interchain_token_service::token_id; -#[test_only] -use utils::utils; - -// ----- -// Tests -// ----- -#[test] -fun test_interchain_transfer_empty_data() { - let token_id = token_id::from_address(@0x1); - let source_address = @0x2; - let destination_chain = b"destination chain".to_ascii_string(); - let destination_address = b"destination address"; - let amount = 123; - let data = b""; - let data_hash = bytes32::new(@0x0); - - interchain_transfer( - token_id, - source_address, - destination_chain, - destination_address, - amount, - &data, - ); - let event = utils::assert_event>(); - - assert!(event.data_hash == data_hash); - assert!(event.source_address == source_address); - assert!(event.destination_chain == destination_chain); - assert!(event.destination_address == destination_address); - assert!(event.amount == amount); -} - -#[test] -fun test_interchain_transfer_nonempty_data() { - let token_id = token_id::from_address(@0x1); - let source_address = @0x2; - let destination_chain = b"destination chain".to_ascii_string(); - let destination_address = b"destination address"; - let amount = 123; - let data = b"data"; - let data_hash = bytes32::new(address::from_bytes(keccak256(&data))); - - interchain_transfer( - token_id, - source_address, - destination_chain, - destination_address, - amount, - &data, - ); - let event = utils::assert_event>(); - - assert!(event.data_hash == data_hash); - assert!(event.source_address == source_address); - assert!(event.destination_chain == destination_chain); - assert!(event.destination_address == destination_address); - assert!(event.amount == amount); +module interchain_token_service::events { + use axelar_gateway::bytes32::{Self, Bytes32}; + use interchain_token_service::token_id::{TokenId, UnregisteredTokenId}; + use std::{ascii::String, string}; + use sui::{address, event, hash::keccak256}; + + // ----- + // Types + // ----- + public struct CoinRegistered has copy, drop { + token_id: TokenId, + } + + public struct InterchainTransfer has copy, drop { + token_id: TokenId, + source_address: address, + destination_chain: String, + destination_address: vector, + amount: u64, + data_hash: Bytes32, + } + + public struct InterchainTokenDeploymentStarted has copy, drop { + token_id: TokenId, + name: string::String, + symbol: String, + decimals: u8, + destination_chain: String, + } + + public struct InterchainTransferReceived has copy, drop { + message_id: String, + token_id: TokenId, + source_chain: String, + source_address: vector, + destination_address: address, + amount: u64, + data_hash: Bytes32, + } + + public struct UnregisteredCoinReceived has copy, drop { + token_id: UnregisteredTokenId, + symbol: String, + decimals: u8, + } + + public struct TrustedChainAdded has copy, drop { + chain_name: String, + } + + public struct TrustedChainRemoved has copy, drop { + chain_name: String, + } + + public struct FlowLimitSet has copy, drop { + token_id: TokenId, + flow_limit: Option, + } + + // ----------------- + // Package Functions + // ----------------- + public(package) fun coin_registered(token_id: TokenId) { + event::emit(CoinRegistered { + token_id, + }); + } + + public(package) fun interchain_transfer( + token_id: TokenId, + source_address: address, + destination_chain: String, + destination_address: vector, + amount: u64, + data: &vector, + ) { + let data_hash = if (data.length() == 0) { + bytes32::new(@0x0) + } else { + bytes32::new(address::from_bytes(keccak256(data))) + }; + event::emit(InterchainTransfer { + token_id, + source_address, + destination_chain, + destination_address, + amount, + data_hash, + }); + } + + public(package) fun interchain_token_deployment_started( + token_id: TokenId, + name: string::String, + symbol: String, + decimals: u8, + destination_chain: String, + ) { + event::emit(InterchainTokenDeploymentStarted { + token_id, + name, + symbol, + decimals, + destination_chain, + }); + } + + public(package) fun interchain_transfer_received( + message_id: String, + token_id: TokenId, + source_chain: String, + source_address: vector, + destination_address: address, + amount: u64, + data: &vector, + ) { + let data_hash = bytes32::new(address::from_bytes(keccak256(data))); + event::emit(InterchainTransferReceived { + message_id, + token_id, + source_chain, + source_address, + destination_address, + amount, + data_hash, + }); + } + + public(package) fun unregistered_coin_received(token_id: UnregisteredTokenId, symbol: String, decimals: u8) { + event::emit(UnregisteredCoinReceived { + token_id, + symbol, + decimals, + }); + } + + public(package) fun trusted_chain_added(chain_name: String) { + event::emit(TrustedChainAdded { + chain_name, + }); + } + + public(package) fun trusted_chain_removed(chain_name: String) { + event::emit(TrustedChainRemoved { + chain_name, + }); + } + + public(package) fun flow_limit_set(token_id: TokenId, flow_limit: Option) { + event::emit(FlowLimitSet { + token_id, + flow_limit, + }); + } + + // --------- + // Test Only + // --------- + #[test_only] + use interchain_token_service::coin::COIN; + #[test_only] + use interchain_token_service::token_id; + #[test_only] + use utils::utils; + + // ----- + // Tests + // ----- + #[test] + fun test_interchain_transfer_empty_data() { + let token_id = token_id::from_address(@0x1); + let source_address = @0x2; + let destination_chain = b"destination chain".to_ascii_string(); + let destination_address = b"destination address"; + let amount = 123; + let data = b""; + let data_hash = bytes32::new(@0x0); + + interchain_transfer( + token_id, + source_address, + destination_chain, + destination_address, + amount, + &data, + ); + let event = utils::assert_event>(); + + assert!(event.data_hash == data_hash); + assert!(event.source_address == source_address); + assert!(event.destination_chain == destination_chain); + assert!(event.destination_address == destination_address); + assert!(event.amount == amount); + } + + #[test] + fun test_interchain_transfer_nonempty_data() { + let token_id = token_id::from_address(@0x1); + let source_address = @0x2; + let destination_chain = b"destination chain".to_ascii_string(); + let destination_address = b"destination address"; + let amount = 123; + let data = b"data"; + let data_hash = bytes32::new(address::from_bytes(keccak256(&data))); + + interchain_transfer( + token_id, + source_address, + destination_chain, + destination_address, + amount, + &data, + ); + let event = utils::assert_event>(); + + assert!(event.data_hash == data_hash); + assert!(event.source_address == source_address); + assert!(event.destination_chain == destination_chain); + assert!(event.destination_address == destination_address); + assert!(event.amount == amount); + } } diff --git a/move/interchain_token_service/sources/interchain_token_service.move b/move/interchain_token_service/sources/interchain_token_service.move index 6254be0e..f40c93b1 100644 --- a/move/interchain_token_service/sources/interchain_token_service.move +++ b/move/interchain_token_service/sources/interchain_token_service.move @@ -1,1087 +1,1010 @@ -module interchain_token_service::interchain_token_service; - -use axelar_gateway::channel::{ApprovedMessage, Channel}; -use axelar_gateway::message_ticket::MessageTicket; -use interchain_token_service::coin_info::CoinInfo; -use interchain_token_service::coin_management::CoinManagement; -use interchain_token_service::interchain_token_service_v0::{Self, InterchainTokenService_v0}; -use interchain_token_service::interchain_transfer_ticket::{Self, InterchainTransferTicket}; -use interchain_token_service::owner_cap::{Self, OwnerCap}; -use interchain_token_service::creator_cap::{Self, CreatorCap}; -use interchain_token_service::operator_cap::{Self, OperatorCap}; -use interchain_token_service::token_id::TokenId; -use relayer_discovery::discovery::RelayerDiscovery; -use relayer_discovery::transaction::Transaction; -use std::ascii::{Self, String}; -use std::type_name::TypeName; -use sui::clock::Clock; -use sui::coin::{Coin, TreasuryCap, CoinMetadata}; -use sui::versioned::{Self, Versioned}; -use version_control::version_control::{Self, VersionControl}; - -// ------- -// Version -// ------- -const VERSION: u64 = 0; -const DATA_VERSION: u64 = 0; - -// ------- -// Structs -// ------- -public struct InterchainTokenService has key { - id: UID, - inner: Versioned, -} +module interchain_token_service::interchain_token_service { + use axelar_gateway::{channel::{ApprovedMessage, Channel}, message_ticket::MessageTicket}; + use interchain_token_service::{ + coin_info::CoinInfo, + coin_management::CoinManagement, + creator_cap::{Self, CreatorCap}, + interchain_token_service_v0::{Self, InterchainTokenService_v0}, + interchain_transfer_ticket::{Self, InterchainTransferTicket}, + operator_cap::{Self, OperatorCap}, + owner_cap::{Self, OwnerCap}, + token_id::TokenId + }; + use relayer_discovery::{discovery::RelayerDiscovery, transaction::Transaction}; + use std::{ascii::{Self, String}, type_name::TypeName}; + use sui::{clock::Clock, coin::{Coin, TreasuryCap, CoinMetadata}, versioned::{Self, Versioned}}; + use version_control::version_control::{Self, VersionControl}; + + // ------- + // Version + // ------- + const VERSION: u64 = 0; + const DATA_VERSION: u64 = 0; + + // ------- + // Structs + // ------- + public struct InterchainTokenService has key { + id: UID, + inner: Versioned, + } -// ----- -// Setup -// ----- -fun init(ctx: &mut TxContext) { - transfer::public_transfer( - owner_cap::create(ctx), - ctx.sender(), - ); + // ----- + // Setup + // ----- + fun init(ctx: &mut TxContext) { + transfer::public_transfer( + owner_cap::create(ctx), + ctx.sender(), + ); + + transfer::public_transfer( + operator_cap::create(ctx), + ctx.sender(), + ); + + transfer::public_transfer( + creator_cap::create(ctx), + ctx.sender(), + ); + } - transfer::public_transfer( - operator_cap::create(ctx), - ctx.sender(), - ); + entry fun setup(creator_cap: CreatorCap, chain_name: String, its_hub_address: String, ctx: &mut TxContext) { + let inner = versioned::create( + DATA_VERSION, + interchain_token_service_v0::new( + version_control(), + chain_name, + its_hub_address, + ctx, + ), + ctx, + ); - transfer::public_transfer( - creator_cap::create(ctx), - ctx.sender(), - ); -} + // Share the its object for anyone to use. + transfer::share_object(InterchainTokenService { + id: object::new(ctx), + inner, + }); -entry fun setup(creator_cap: CreatorCap, chain_name: String, its_hub_address: String, ctx: &mut TxContext) { - let inner = versioned::create( - DATA_VERSION, - interchain_token_service_v0::new( - version_control(), - chain_name, - its_hub_address, - ctx, - ), - ctx, - ); + creator_cap.destroy(); + } - // Share the its object for anyone to use. - transfer::share_object(InterchainTokenService { - id: object::new(ctx), - inner, - }); + // ------ + // Macros + // ------ + /// This macro also uses version control to sinplify things a bit. + macro fun value($self: &InterchainTokenService, $function_name: vector): &InterchainTokenService_v0 { + let its = $self; + let value = its.inner.load_value(); + value.version_control().check(VERSION, ascii::string($function_name)); + value + } - creator_cap.destroy(); -} + /// This macro also uses version control to sinplify things a bit. + macro fun value_mut($self: &mut InterchainTokenService, $function_name: vector): &mut InterchainTokenService_v0 { + let its = $self; + let value = its.inner.load_value_mut(); + value.version_control().check(VERSION, ascii::string($function_name)); + value + } -// ------ -// Macros -// ------ -/// This macro also uses version control to sinplify things a bit. -macro fun value( - $self: &InterchainTokenService, - $function_name: vector, -): &InterchainTokenService_v0 { - let its = $self; - let value = its.inner.load_value(); - value.version_control().check(VERSION, ascii::string($function_name)); - value -} + // --------------- + // Entry Functions + // --------------- + entry fun allow_function(self: &mut InterchainTokenService, _: &OwnerCap, version: u64, function_name: String) { + self.value_mut!(b"allow_function").allow_function(version, function_name); + } -/// This macro also uses version control to sinplify things a bit. -macro fun value_mut( - $self: &mut InterchainTokenService, - $function_name: vector, -): &mut InterchainTokenService_v0 { - let its = $self; - let value = its.inner.load_value_mut(); - value.version_control().check(VERSION, ascii::string($function_name)); - value -} + entry fun disallow_function(self: &mut InterchainTokenService, _: &OwnerCap, version: u64, function_name: String) { + self.value_mut!(b"disallow_function").disallow_function(version, function_name); + } -// --------------- -// Entry Functions -// --------------- -entry fun allow_function( - self: &mut InterchainTokenService, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self.value_mut!(b"allow_function").allow_function(version, function_name); -} + // ---------------- + // Public Functions + // ---------------- + public fun register_coin(self: &mut InterchainTokenService, coin_info: CoinInfo, coin_management: CoinManagement): TokenId { + let value = self.value_mut!(b"register_coin"); -entry fun disallow_function( - self: &mut InterchainTokenService, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self.value_mut!(b"disallow_function").disallow_function(version, function_name); -} + value.register_coin(coin_info, coin_management) + } -// ---------------- -// Public Functions -// ---------------- -public fun register_coin( - self: &mut InterchainTokenService, - coin_info: CoinInfo, - coin_management: CoinManagement, -): TokenId { - let value = self.value_mut!(b"register_coin"); - - value.register_coin(coin_info, coin_management) -} + public fun deploy_remote_interchain_token( + self: &InterchainTokenService, + token_id: TokenId, + destination_chain: String, + ): MessageTicket { + let value = self.value!(b"deploy_remote_interchain_token"); -public fun deploy_remote_interchain_token( - self: &InterchainTokenService, - token_id: TokenId, - destination_chain: String, -): MessageTicket { - let value = self.value!(b"deploy_remote_interchain_token"); + value.deploy_remote_interchain_token(token_id, destination_chain) + } - value.deploy_remote_interchain_token(token_id, destination_chain) -} + public fun prepare_interchain_transfer( + token_id: TokenId, + coin: Coin, + destination_chain: String, + destination_address: vector, + metadata: vector, + source_channel: &Channel, + ): InterchainTransferTicket { + interchain_transfer_ticket::new( + token_id, + coin.into_balance(), + source_channel.to_address(), + destination_chain, + destination_address, + metadata, + VERSION, + ) + } -public fun prepare_interchain_transfer( - token_id: TokenId, - coin: Coin, - destination_chain: String, - destination_address: vector, - metadata: vector, - source_channel: &Channel, -): InterchainTransferTicket { - interchain_transfer_ticket::new( - token_id, - coin.into_balance(), - source_channel.to_address(), - destination_chain, - destination_address, - metadata, - VERSION, - ) -} + public fun send_interchain_transfer( + self: &mut InterchainTokenService, + ticket: InterchainTransferTicket, + clock: &Clock, + ): MessageTicket { + let value = self.value_mut!(b"send_interchain_transfer"); + + value.send_interchain_transfer( + ticket, + VERSION, + clock, + ) + } -public fun send_interchain_transfer( - self: &mut InterchainTokenService, - ticket: InterchainTransferTicket, - clock: &Clock, -): MessageTicket { - let value = self.value_mut!(b"send_interchain_transfer"); - - value.send_interchain_transfer( - ticket, - VERSION, - clock, - ) -} + public fun receive_interchain_transfer( + self: &mut InterchainTokenService, + approved_message: ApprovedMessage, + clock: &Clock, + ctx: &mut TxContext, + ) { + let value = self.value_mut!(b"receive_interchain_transfer"); -public fun receive_interchain_transfer( - self: &mut InterchainTokenService, - approved_message: ApprovedMessage, - clock: &Clock, - ctx: &mut TxContext, -) { - let value = self.value_mut!(b"receive_interchain_transfer"); + value.receive_interchain_transfer(approved_message, clock, ctx); + } - value.receive_interchain_transfer(approved_message, clock, ctx); -} + public fun receive_interchain_transfer_with_data( + self: &mut InterchainTokenService, + approved_message: ApprovedMessage, + channel: &Channel, + clock: &Clock, + ctx: &mut TxContext, + ): (String, vector, vector, Coin) { + let value = self.value_mut!(b"receive_interchain_transfer_with_data"); + + value.receive_interchain_transfer_with_data( + approved_message, + channel, + clock, + ctx, + ) + } -public fun receive_interchain_transfer_with_data( - self: &mut InterchainTokenService, - approved_message: ApprovedMessage, - channel: &Channel, - clock: &Clock, - ctx: &mut TxContext, -): (String, vector, vector, Coin) { - let value = self.value_mut!(b"receive_interchain_transfer_with_data"); - - value.receive_interchain_transfer_with_data( - approved_message, - channel, - clock, - ctx, - ) -} + public fun receive_deploy_interchain_token(self: &mut InterchainTokenService, approved_message: ApprovedMessage) { + let value = self.value_mut!(b"receive_deploy_interchain_token"); -public fun receive_deploy_interchain_token( - self: &mut InterchainTokenService, - approved_message: ApprovedMessage, -) { - let value = self.value_mut!(b"receive_deploy_interchain_token"); + value.receive_deploy_interchain_token(approved_message); + } - value.receive_deploy_interchain_token(approved_message); -} + // We need an coin with zero supply that has the proper decimals and typing, and + // no Url. + public fun give_unregistered_coin(self: &mut InterchainTokenService, treasury_cap: TreasuryCap, coin_metadata: CoinMetadata) { + let value = self.value_mut!(b"give_unregistered_coin"); -// We need an coin with zero supply that has the proper decimals and typing, and -// no Url. -public fun give_unregistered_coin( - self: &mut InterchainTokenService, - treasury_cap: TreasuryCap, - coin_metadata: CoinMetadata, -) { - let value = self.value_mut!(b"give_unregistered_coin"); + value.give_unregistered_coin(treasury_cap, coin_metadata); + } - value.give_unregistered_coin(treasury_cap, coin_metadata); -} + public fun mint_as_distributor( + self: &mut InterchainTokenService, + channel: &Channel, + token_id: TokenId, + amount: u64, + ctx: &mut TxContext, + ): Coin { + let value = self.value_mut!(b"mint_as_distributor"); + + value.mint_as_distributor( + channel, + token_id, + amount, + ctx, + ) + } -public fun mint_as_distributor( - self: &mut InterchainTokenService, - channel: &Channel, - token_id: TokenId, - amount: u64, - ctx: &mut TxContext, -): Coin { - let value = self.value_mut!(b"mint_as_distributor"); - - value.mint_as_distributor( - channel, - token_id, - amount, - ctx, - ) -} + public fun mint_to_as_distributor( + self: &mut InterchainTokenService, + channel: &Channel, + token_id: TokenId, + to: address, + amount: u64, + ctx: &mut TxContext, + ) { + let value = self.value_mut!(b"mint_to_as_distributor"); + + value.mint_to_as_distributor( + channel, + token_id, + to, + amount, + ctx, + ); + } -public fun mint_to_as_distributor( - self: &mut InterchainTokenService, - channel: &Channel, - token_id: TokenId, - to: address, - amount: u64, - ctx: &mut TxContext, -) { - let value = self.value_mut!(b"mint_to_as_distributor"); - - value.mint_to_as_distributor( - channel, - token_id, - to, - amount, - ctx, - ); -} + public fun burn_as_distributor(self: &mut InterchainTokenService, channel: &Channel, token_id: TokenId, coin: Coin) { + let value = self.value_mut!(b"mint_to_as_distributor"); -public fun burn_as_distributor( - self: &mut InterchainTokenService, - channel: &Channel, - token_id: TokenId, - coin: Coin, -) { - let value = self.value_mut!(b"mint_to_as_distributor"); - - value.burn_as_distributor( - channel, - token_id, - coin, - ); -} + value.burn_as_distributor( + channel, + token_id, + coin, + ); + } -// This is the entrypoint for operators to set the flow limits of their tokens -// (tokenManager.setFlowLimit on EVM) -public fun set_flow_limit_as_token_operator( - self: &mut InterchainTokenService, - channel: &Channel, - token_id: TokenId, - limit: Option, -) { - let value = self.value_mut!(b"set_flow_limit_as_token_operator"); - - value.set_flow_limit_as_token_operator( - channel, - token_id, - limit, - ); -} + // This is the entrypoint for operators to set the flow limits of their tokens + // (tokenManager.setFlowLimit on EVM) + public fun set_flow_limit_as_token_operator( + self: &mut InterchainTokenService, + channel: &Channel, + token_id: TokenId, + limit: Option, + ) { + let value = self.value_mut!(b"set_flow_limit_as_token_operator"); + + value.set_flow_limit_as_token_operator( + channel, + token_id, + limit, + ); + } -// This is the entrypoint for operators to set the flow limits of their tokens -// (interchainTokenService.setFlowLimits on EVM) -public fun set_flow_limit( - self: &mut InterchainTokenService, - _: &OperatorCap, - token_ids: TokenId, - limit: Option, -) { - let value = self.value_mut!(b"set_flow_limit"); - - value.set_flow_limit( - token_ids, - limit, - ); -} + // This is the entrypoint for operators to set the flow limits of their tokens + // (interchainTokenService.setFlowLimits on EVM) + public fun set_flow_limit(self: &mut InterchainTokenService, _: &OperatorCap, token_ids: TokenId, limit: Option) { + let value = self.value_mut!(b"set_flow_limit"); -// --------------- -// Owner Functions -// --------------- -public fun add_trusted_chains( - self: &mut InterchainTokenService, - _owner_cap: &OwnerCap, - chain_names: vector, -) { - let value = self.value_mut!(b"add_trusted_chains"); - - value.add_trusted_chains(chain_names); -} + value.set_flow_limit( + token_ids, + limit, + ); + } -public fun remove_trusted_chains( - self: &mut InterchainTokenService, - _owner_cap: &OwnerCap, - chain_names: vector, -) { - let value = self.value_mut!(b"remove_trusted_chains"); + // --------------- + // Owner Functions + // --------------- + public fun add_trusted_chains(self: &mut InterchainTokenService, _owner_cap: &OwnerCap, chain_names: vector) { + let value = self.value_mut!(b"add_trusted_chains"); - value.remove_trusted_chains(chain_names); -} + value.add_trusted_chains(chain_names); + } -// === Getters === -public fun registered_coin_type(self: &InterchainTokenService, token_id: TokenId): &TypeName { - self.package_value().registered_coin_type(token_id) -} + public fun remove_trusted_chains(self: &mut InterchainTokenService, _owner_cap: &OwnerCap, chain_names: vector) { + let value = self.value_mut!(b"remove_trusted_chains"); -public fun channel_address(self: &InterchainTokenService): address { - self.package_value().channel_address() -} + value.remove_trusted_chains(chain_names); + } -// ----------------- -// Package Functions -// ----------------- -// This function allows the rest of the package to read information about InterchainTokenService -// (discovery needs this). -public(package) fun package_value(self: &InterchainTokenService): &InterchainTokenService_v0 { - self.inner.load_value() -} + // === Getters === + public fun registered_coin_type(self: &InterchainTokenService, token_id: TokenId): &TypeName { + self.package_value().registered_coin_type(token_id) + } -public(package) fun register_transaction( - self: &mut InterchainTokenService, - discovery: &mut RelayerDiscovery, - transaction: Transaction, -) { - let value = self.value_mut!(b"register_transaction"); + public fun channel_address(self: &InterchainTokenService): address { + self.package_value().channel_address() + } - value.set_relayer_discovery_id(discovery); + // ----------------- + // Package Functions + // ----------------- + // This function allows the rest of the package to read information about InterchainTokenService + // (discovery needs this). + public(package) fun package_value(self: &InterchainTokenService): &InterchainTokenService_v0 { + self.inner.load_value() + } - discovery.register_transaction( - value.channel(), - transaction, - ); -} + public(package) fun register_transaction( + self: &mut InterchainTokenService, + discovery: &mut RelayerDiscovery, + transaction: Transaction, + ) { + let value = self.value_mut!(b"register_transaction"); -// ----------------- -// Private Functions -// ----------------- -fun version_control(): VersionControl { - version_control::new(vector[ - // Version 0 - vector[ - b"register_coin", - b"deploy_remote_interchain_token", - b"send_interchain_transfer", - b"receive_interchain_transfer", - b"receive_interchain_transfer_with_data", - b"receive_deploy_interchain_token", - b"give_unregistered_coin", - b"mint_as_distributor", - b"mint_to_as_distributor", - b"burn_as_distributor", - b"add_trusted_chains", - b"remove_trusted_chains", - b"register_transaction", - b"set_flow_limit", - b"set_flow_limit_as_token_operator", - b"allow_function", - b"disallow_function", - ].map!(|function_name| function_name.to_ascii_string()), - ]) -} + value.set_relayer_discovery_id(discovery); -// --------- -// Test Only -// --------- -#[test_only] -use interchain_token_service::coin::COIN; -#[test_only] -use axelar_gateway::channel; -#[test_only] -use std::string; -#[test_only] -use abi::abi; -#[test_only] -use utils::utils; - -// === MESSAGE TYPES === -#[test_only] -const MESSAGE_TYPE_INTERCHAIN_TRANSFER: u256 = 0; -#[test_only] -const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; -// const MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER: u256 = 2; -#[test_only] -const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; - -// === HUB CONSTANTS === -// Axelar. -#[test_only] -const ITS_HUB_CHAIN_NAME: vector = b"axelar"; -// The address of the ITS HUB. -#[test_only] -const ITS_HUB_ADDRESS: vector = b"hub_address"; - -#[test_only] -public fun create_for_testing(ctx: &mut TxContext): InterchainTokenService { - let mut version_control = version_control(); - version_control.allowed_functions()[0].insert(b"".to_ascii_string()); - - let mut value = interchain_token_service_v0::new( - version_control, - b"chain name".to_ascii_string(), - ITS_HUB_ADDRESS.to_ascii_string(), - ctx, - ); - value.add_trusted_chain( - std::ascii::string(b"Chain Name"), - ); + discovery.register_transaction( + value.channel(), + transaction, + ); + } - let inner = versioned::create( - DATA_VERSION, - value, - ctx, - ); + // ----------------- + // Private Functions + // ----------------- + fun version_control(): VersionControl { + version_control::new(vector[ + // Version 0 + vector[ + b"register_coin", + b"deploy_remote_interchain_token", + b"send_interchain_transfer", + b"receive_interchain_transfer", + b"receive_interchain_transfer_with_data", + b"receive_deploy_interchain_token", + b"give_unregistered_coin", + b"mint_as_distributor", + b"mint_to_as_distributor", + b"burn_as_distributor", + b"add_trusted_chains", + b"remove_trusted_chains", + b"register_transaction", + b"set_flow_limit", + b"set_flow_limit_as_token_operator", + b"allow_function", + b"disallow_function", + ].map!(|function_name| function_name.to_ascii_string()), + ]) + } + + // --------- + // Test Only + // --------- + #[test_only] + use interchain_token_service::coin::COIN; + #[test_only] + use axelar_gateway::channel; + #[test_only] + use std::string; + #[test_only] + use abi::abi; + #[test_only] + use utils::utils; + + // === MESSAGE TYPES === + #[test_only] + const MESSAGE_TYPE_INTERCHAIN_TRANSFER: u256 = 0; + #[test_only] + const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; + // const MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER: u256 = 2; + #[test_only] + const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; + + // === HUB CONSTANTS === + // Axelar. + #[test_only] + const ITS_HUB_CHAIN_NAME: vector = b"axelar"; + // The address of the ITS HUB. + #[test_only] + const ITS_HUB_ADDRESS: vector = b"hub_address"; + + #[test_only] + public fun create_for_testing(ctx: &mut TxContext): InterchainTokenService { + let mut version_control = version_control(); + version_control.allowed_functions()[0].insert(b"".to_ascii_string()); + + let mut value = interchain_token_service_v0::new( + version_control, + b"chain name".to_ascii_string(), + ITS_HUB_ADDRESS.to_ascii_string(), + ctx, + ); + value.add_trusted_chain( + std::ascii::string(b"Chain Name"), + ); + + let inner = versioned::create( + DATA_VERSION, + value, + ctx, + ); - InterchainTokenService { - id: object::new(ctx), - inner, + InterchainTokenService { + id: object::new(ctx), + inner, + } } -} -#[test_only] -public(package) fun add_unregistered_coin_type_for_testing( - self: &mut InterchainTokenService, - token_id: interchain_token_service::token_id::UnregisteredTokenId, - type_name: std::type_name::TypeName, -) { - self.value_mut!(b"").add_unregistered_coin_type_for_testing(token_id, type_name); -} + #[test_only] + public(package) fun add_unregistered_coin_type_for_testing( + self: &mut InterchainTokenService, + token_id: interchain_token_service::token_id::UnregisteredTokenId, + type_name: std::type_name::TypeName, + ) { + self.value_mut!(b"").add_unregistered_coin_type_for_testing(token_id, type_name); + } -#[test_only] -public(package) fun remove_unregistered_coin_type_for_testing( - self: &mut InterchainTokenService, - token_id: interchain_token_service::token_id::UnregisteredTokenId, -): std::type_name::TypeName { - self.value_mut!(b"").remove_unregistered_coin_type_for_testing(token_id) -} + #[test_only] + public(package) fun remove_unregistered_coin_type_for_testing( + self: &mut InterchainTokenService, + token_id: interchain_token_service::token_id::UnregisteredTokenId, + ): std::type_name::TypeName { + self.value_mut!(b"").remove_unregistered_coin_type_for_testing(token_id) + } -#[test_only] -public(package) fun add_registered_coin_type_for_testing( - self: &mut InterchainTokenService, - token_id: TokenId, - type_name: std::type_name::TypeName, -) { - self.value_mut!(b"").add_registered_coin_type_for_testing(token_id, type_name); -} + #[test_only] + public(package) fun add_registered_coin_type_for_testing( + self: &mut InterchainTokenService, + token_id: TokenId, + type_name: std::type_name::TypeName, + ) { + self.value_mut!(b"").add_registered_coin_type_for_testing(token_id, type_name); + } -#[test_only] -public(package) fun remove_registered_coin_type_for_testing( - self: &mut InterchainTokenService, - token_id: TokenId, -): std::type_name::TypeName { - self.value_mut!(b"").remove_registered_coin_type_for_testing(token_id) -} + #[test_only] + public(package) fun remove_registered_coin_type_for_testing( + self: &mut InterchainTokenService, + token_id: TokenId, + ): std::type_name::TypeName { + self.value_mut!(b"").remove_registered_coin_type_for_testing(token_id) + } -// ----- -// Tests -// ----- -#[test] -fun test_register_coin() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = create_for_testing(ctx); + // ----- + // Tests + // ----- + #[test] + fun test_register_coin() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = create_for_testing(ctx); - let coin_info = interchain_token_service::coin_info::from_info( + let coin_info = + interchain_token_service::coin_info::from_info( string::utf8(b"Name"), ascii::string(b"Symbol"), 10, ); - let coin_management = interchain_token_service::coin_management::new_locked(); + let coin_management = interchain_token_service::coin_management::new_locked(); - register_coin(&mut its, coin_info, coin_management); - utils::assert_event>(); + register_coin(&mut its, coin_info, coin_management); + utils::assert_event>(); - sui::test_utils::destroy(its); -} + sui::test_utils::destroy(its); + } -#[test] -fun test_deploy_remote_interchain_token() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = create_for_testing(ctx); - let token_name = string::utf8(b"Name"); - let token_symbol = ascii::string(b"Symbol"); - let token_decimals = 10; + #[test] + fun test_deploy_remote_interchain_token() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = create_for_testing(ctx); + let token_name = string::utf8(b"Name"); + let token_symbol = ascii::string(b"Symbol"); + let token_decimals = 10; - let coin_info = interchain_token_service::coin_info::from_info( + let coin_info = + interchain_token_service::coin_info::from_info( token_name, token_symbol, token_decimals, ); - let coin_management = interchain_token_service::coin_management::new_locked(); - - let token_id = register_coin(&mut its, coin_info, coin_management); - let destination_chain = ascii::string(b"Chain Name"); - let message_ticket = deploy_remote_interchain_token( - &its, - token_id, - destination_chain, - ); + let coin_management = interchain_token_service::coin_management::new_locked(); - utils::assert_event>(); + let token_id = register_coin(&mut its, coin_info, coin_management); + let destination_chain = ascii::string(b"Chain Name"); + let message_ticket = deploy_remote_interchain_token( + &its, + token_id, + destination_chain, + ); - let mut writer = abi::new_writer(6); + utils::assert_event>(); - writer - .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) - .write_u256(token_id.to_u256()) - .write_bytes(*token_name.as_bytes()) - .write_bytes(*token_symbol.as_bytes()) - .write_u256((token_decimals as u256)) - .write_bytes(vector::empty()); - - let payload = interchain_token_service_v0::wrap_payload_sending(writer.into_bytes(), destination_chain); + let mut writer = abi::new_writer(6); - assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); - assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); - assert!(message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string()); - assert!(message_ticket.payload() == payload); - assert!(message_ticket.version() == 0); + writer + .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) + .write_u256(token_id.to_u256()) + .write_bytes(*token_name.as_bytes()) + .write_bytes(*token_symbol.as_bytes()) + .write_u256((token_decimals as u256)) + .write_bytes(vector::empty()); - sui::test_utils::destroy(its); - sui::test_utils::destroy(message_ticket); -} + let payload = interchain_token_service_v0::wrap_payload_sending(writer.into_bytes(), destination_chain); + + assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); + assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); + assert!(message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string()); + assert!(message_ticket.payload() == payload); + assert!(message_ticket.version() == 0); -#[test] -fun test_deploy_interchain_token() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); + sui::test_utils::destroy(its); + sui::test_utils::destroy(message_ticket); + } - let coin_info = interchain_token_service::coin_info::from_info( + #[test] + fun test_deploy_interchain_token() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); + + let coin_info = + interchain_token_service::coin_info::from_info( string::utf8(b"Name"), ascii::string(b"Symbol"), 10, ); - let coin_management = interchain_token_service::coin_management::new_locked(); - - let token_id = register_coin(&mut its, coin_info, coin_management); - - utils::assert_event>(); - - let amount = 1234; - let coin = sui::coin::mint_for_testing(amount, ctx); - let destination_chain = ascii::string(b"Chain Name"); - let destination_address = b"address"; - let metadata = b""; - let source_channel = channel::new(ctx); - let clock = sui::clock::create_for_testing(ctx); - - let interchain_transfer_ticket = prepare_interchain_transfer( - token_id, - coin, - destination_chain, - destination_address, - metadata, - &source_channel, - ); - let message_ticket = send_interchain_transfer( - &mut its, - interchain_transfer_ticket, - &clock, - ); - - utils::assert_event>(); - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(token_id.to_u256()) - .write_bytes(source_channel.to_address().to_bytes()) - .write_bytes(destination_address) - .write_u256((amount as u256)) - .write_bytes(b""); - - let payload = interchain_token_service_v0::wrap_payload_sending(writer.into_bytes(), destination_chain); - - assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); - assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); - assert!( - message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string(), - ); - assert!(message_ticket.payload() == payload); - assert!(message_ticket.version() == 0); - - clock.destroy_for_testing(); - source_channel.destroy(); - sui::test_utils::destroy(its); - sui::test_utils::destroy(message_ticket); -} + let coin_management = interchain_token_service::coin_management::new_locked(); + + let token_id = register_coin(&mut its, coin_info, coin_management); + + utils::assert_event>(); + + let amount = 1234; + let coin = sui::coin::mint_for_testing(amount, ctx); + let destination_chain = ascii::string(b"Chain Name"); + let destination_address = b"address"; + let metadata = b""; + let source_channel = channel::new(ctx); + let clock = sui::clock::create_for_testing(ctx); + + let interchain_transfer_ticket = prepare_interchain_transfer( + token_id, + coin, + destination_chain, + destination_address, + metadata, + &source_channel, + ); + let message_ticket = send_interchain_transfer( + &mut its, + interchain_transfer_ticket, + &clock, + ); + + utils::assert_event>(); + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(token_id.to_u256()) + .write_bytes(source_channel.to_address().to_bytes()) + .write_bytes(destination_address) + .write_u256((amount as u256)) + .write_bytes(b""); + + let payload = interchain_token_service_v0::wrap_payload_sending(writer.into_bytes(), destination_chain); + + assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); + assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); + assert!(message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string()); + assert!(message_ticket.payload() == payload); + assert!(message_ticket.version() == 0); + + clock.destroy_for_testing(); + source_channel.destroy(); + sui::test_utils::destroy(its); + sui::test_utils::destroy(message_ticket); + } -#[test] -fun test_receive_interchain_transfer() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut its = create_for_testing(ctx); + #[test] + fun test_receive_interchain_transfer() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut its = create_for_testing(ctx); - let coin_info = interchain_token_service::coin_info::from_info( + let coin_info = + interchain_token_service::coin_info::from_info( string::utf8(b"Name"), ascii::string(b"Symbol"), 10, ); - let amount = 1234; - let mut coin_management = interchain_token_service::coin_management::new_locked(); - let coin = sui::coin::mint_for_testing(amount, ctx); - coin_management.take_balance(coin.into_balance(), &clock); - - let token_id = register_coin(&mut its, coin_info, coin_management); - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; - let destination_address = @0x1; - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(b""); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - its.value!(b"").channel().to_address(), - payload, - ); - - receive_interchain_transfer(&mut its, approved_message, &clock, ctx); - - utils::assert_event>(); - - clock.destroy_for_testing(); - sui::test_utils::destroy(its); -} + let amount = 1234; + let mut coin_management = interchain_token_service::coin_management::new_locked(); + let coin = sui::coin::mint_for_testing(amount, ctx); + coin_management.take_balance(coin.into_balance(), &clock); + + let token_id = register_coin(&mut its, coin_info, coin_management); + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; + let destination_address = @0x1; + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(b""); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + its.value!(b"").channel().to_address(), + payload, + ); + + receive_interchain_transfer(&mut its, approved_message, &clock, ctx); + + utils::assert_event>(); + + clock.destroy_for_testing(); + sui::test_utils::destroy(its); + } -#[test] -fun test_receive_interchain_transfer_with_data() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut its = create_for_testing(ctx); + #[test] + fun test_receive_interchain_transfer_with_data() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut its = create_for_testing(ctx); - let coin_info = interchain_token_service::coin_info::from_info( + let coin_info = + interchain_token_service::coin_info::from_info( string::utf8(b"Name"), ascii::string(b"Symbol"), 10, ); - let amount = 1234; - let data = b"some_data"; - let mut coin_management = interchain_token_service::coin_management::new_locked(); - let coin = sui::coin::mint_for_testing(amount, ctx); - coin_management.take_balance(coin.into_balance(), &clock); - - let token_id = its.register_coin(coin_info, coin_management); - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; - let channel = channel::new(ctx); - let destination_address = channel.to_address(); - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(data); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - its.value!(b"").channel().to_address(), - payload, - ); + let amount = 1234; + let data = b"some_data"; + let mut coin_management = interchain_token_service::coin_management::new_locked(); + let coin = sui::coin::mint_for_testing(amount, ctx); + coin_management.take_balance(coin.into_balance(), &clock); + + let token_id = its.register_coin(coin_info, coin_management); + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; + let channel = channel::new(ctx); + let destination_address = channel.to_address(); + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(data); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + its.value!(b"").channel().to_address(), + payload, + ); + + let (received_source_chain, received_source_address, received_data, received_coin) = its.receive_interchain_transfer_with_data< + COIN, + >( + approved_message, + &channel, + &clock, + ctx, + ); - let ( - received_source_chain, - received_source_address, - received_data, - received_coin, - ) = its.receive_interchain_transfer_with_data( - approved_message, - &channel, - &clock, - ctx, - ); + utils::assert_event>(); - utils::assert_event>(); + assert!(received_source_chain == source_chain); + assert!(received_source_address == its_source_address); + assert!(received_data == data); + assert!(received_coin.value() == amount); - assert!(received_source_chain == source_chain); - assert!(received_source_address == its_source_address); - assert!(received_data == data); - assert!(received_coin.value() == amount); + clock.destroy_for_testing(); + channel.destroy(); + sui::test_utils::destroy(its); + sui::test_utils::destroy(received_coin); + } - clock.destroy_for_testing(); - channel.destroy(); - sui::test_utils::destroy(its); - sui::test_utils::destroy(received_coin); -} + #[test] + fun test_receive_deploy_interchain_token() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut its = create_for_testing(ctx); + + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let name = b"Token Name"; + let symbol = b"Symbol"; + let decimals = 9; + let token_id: u256 = 1234; + + its.value_mut!(b"").create_unregistered_coin(symbol, decimals, ctx); + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) + .write_u256(token_id) + .write_bytes(name) + .write_bytes(symbol) + .write_u256((decimals as u256)) + .write_bytes(vector::empty()); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + its.value!(b"").channel().to_address(), + payload, + ); + + receive_deploy_interchain_token(&mut its, approved_message); + + utils::assert_event>(); + + clock.destroy_for_testing(); + sui::test_utils::destroy(its); + } -#[test] -fun test_receive_deploy_interchain_token() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut its = create_for_testing(ctx); - - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let name = b"Token Name"; - let symbol = b"Symbol"; - let decimals = 9; - let token_id: u256 = 1234; - - its.value_mut!(b"").create_unregistered_coin(symbol, decimals, ctx); - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) - .write_u256(token_id) - .write_bytes(name) - .write_bytes(symbol) - .write_u256((decimals as u256)) - .write_bytes(vector::empty()); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - its.value!(b"").channel().to_address(), - payload, - ); + #[test] + fun test_give_unregistered_coin() { + let symbol = b"COIN"; + let decimals = 12; + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); - receive_deploy_interchain_token(&mut its, approved_message); + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); - utils::assert_event>(); + give_unregistered_coin(&mut its, treasury_cap, coin_metadata); - clock.destroy_for_testing(); - sui::test_utils::destroy(its); -} + sui::test_utils::destroy(its); + } -#[test] -fun test_give_unregistered_coin() { - let symbol = b"COIN"; - let decimals = 12; - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); + #[test] + fun test_mint_as_distributor() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); + let symbol = b"COIN"; + let decimals = 9; - let ( - treasury_cap, + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, ); + let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); - give_unregistered_coin(&mut its, treasury_cap, coin_metadata); + let channel = channel::new(ctx); + coin_management.add_distributor(channel.to_address()); + let amount = 1234; - sui::test_utils::destroy(its); -} - -#[test] -fun test_mint_as_distributor() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); - let symbol = b"COIN"; - let decimals = 9; - - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); - let coin_info = interchain_token_service::coin_info::from_metadata( - coin_metadata, - ); - let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); - - let channel = channel::new(ctx); - coin_management.add_distributor(channel.to_address()); - let amount = 1234; - - let token_id = register_coin(&mut its, coin_info, coin_management); - let coin = mint_as_distributor( - &mut its, - &channel, - token_id, - amount, - ctx, - ); + let token_id = register_coin(&mut its, coin_info, coin_management); + let coin = mint_as_distributor( + &mut its, + &channel, + token_id, + amount, + ctx, + ); - assert!(coin.value() == amount); + assert!(coin.value() == amount); - sui::test_utils::destroy(its); - sui::test_utils::destroy(coin); - channel.destroy(); -} + sui::test_utils::destroy(its); + sui::test_utils::destroy(coin); + channel.destroy(); + } -#[test] -fun test_mint_to_as_distributor() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); - let symbol = b"COIN"; - let decimals = 9; + #[test] + fun test_mint_to_as_distributor() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); + let symbol = b"COIN"; + let decimals = 9; - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); - let coin_info = interchain_token_service::coin_info::from_metadata( + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, ); - let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); - - let channel = channel::new(ctx); - coin_management.add_distributor(channel.to_address()); - let amount = 1234; - - let token_id = register_coin(&mut its, coin_info, coin_management); - mint_to_as_distributor( - &mut its, - &channel, - token_id, - @0x2, - amount, - ctx, - ); + let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); - sui::test_utils::destroy(its); - channel.destroy(); -} + let channel = channel::new(ctx); + coin_management.add_distributor(channel.to_address()); + let amount = 1234; -#[test] -fun test_burn_as_distributor() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); - let symbol = b"COIN"; - let decimals = 9; - let amount = 1234; + let token_id = register_coin(&mut its, coin_info, coin_management); + mint_to_as_distributor( + &mut its, + &channel, + token_id, + @0x2, + amount, + ctx, + ); - let ( - mut treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata(symbol, decimals, ctx); - let coin = treasury_cap.mint(amount, ctx); - let coin_info = interchain_token_service::coin_info::from_metadata( + sui::test_utils::destroy(its); + channel.destroy(); + } + + #[test] + fun test_burn_as_distributor() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); + let symbol = b"COIN"; + let decimals = 9; + let amount = 1234; + + let (mut treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata(symbol, decimals, ctx); + let coin = treasury_cap.mint(amount, ctx); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, ); - let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); + let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); - let channel = channel::new(ctx); - coin_management.add_distributor(channel.to_address()); + let channel = channel::new(ctx); + coin_management.add_distributor(channel.to_address()); - let token_id = register_coin(&mut its, coin_info, coin_management); - burn_as_distributor(&mut its, &channel, token_id, coin); + let token_id = register_coin(&mut its, coin_info, coin_management); + burn_as_distributor(&mut its, &channel, token_id, coin); - sui::test_utils::destroy(its); - channel.destroy(); -} - -#[test] -fun test_add_trusted_chain() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); + sui::test_utils::destroy(its); + channel.destroy(); + } - let owner_cap = owner_cap::create( - ctx, - ); + #[test] + fun test_add_trusted_chain() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); - let trusted_chains = vector[b"Ethereum", b"Avalance", b"Axelar"].map!( - |chain| chain.to_ascii_string(), - ); + let owner_cap = owner_cap::create( + ctx, + ); - its.add_trusted_chains(&owner_cap, trusted_chains); - its.remove_trusted_chains(&owner_cap, trusted_chains); + let trusted_chains = vector[b"Ethereum", b"Avalance", b"Axelar"].map!(|chain| chain.to_ascii_string()); - sui::test_utils::destroy(its); - sui::test_utils::destroy(owner_cap); -} + its.add_trusted_chains(&owner_cap, trusted_chains); + its.remove_trusted_chains(&owner_cap, trusted_chains); -#[test] -fun test_set_flow_limit_as_token_operator() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); - let symbol = b"COIN"; - let decimals = 9; - let limit = option::some(1234); + sui::test_utils::destroy(its); + sui::test_utils::destroy(owner_cap); + } - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); - let coin_info = interchain_token_service::coin_info::from_metadata( + #[test] + fun test_set_flow_limit_as_token_operator() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); + let symbol = b"COIN"; + let decimals = 9; + let limit = option::some(1234); + + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, ); - let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); + let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); - let channel = channel::new(ctx); - coin_management.add_operator(channel.to_address()); + let channel = channel::new(ctx); + coin_management.add_operator(channel.to_address()); - let token_id = register_coin(&mut its, coin_info, coin_management); - its.set_flow_limit_as_token_operator(&channel, token_id, limit); + let token_id = register_coin(&mut its, coin_info, coin_management); + its.set_flow_limit_as_token_operator(&channel, token_id, limit); - sui::test_utils::destroy(its); - channel.destroy(); -} - -#[test] -fun test_set_flow_limit() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); - let symbol = b"COIN"; - let decimals = 9; - let limit = option::some(1234); + sui::test_utils::destroy(its); + channel.destroy(); + } - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); - let coin_info = interchain_token_service::coin_info::from_metadata( + #[test] + fun test_set_flow_limit() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); + let symbol = b"COIN"; + let decimals = 9; + let limit = option::some(1234); + + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, ); - let coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); + let coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); - let operator_cap = operator_cap::create(ctx); + let operator_cap = operator_cap::create(ctx); - let token_id = register_coin(&mut its, coin_info, coin_management); - its.set_flow_limit(&operator_cap, token_id, limit); + let token_id = register_coin(&mut its, coin_info, coin_management); + its.set_flow_limit(&operator_cap, token_id, limit); - sui::test_utils::destroy(its); - sui::test_utils::destroy(operator_cap); -} + sui::test_utils::destroy(its); + sui::test_utils::destroy(operator_cap); + } -#[test] -fun test_init() { - let mut ts = sui::test_scenario::begin(@0x0); + #[test] + fun test_init() { + let mut ts = sui::test_scenario::begin(@0x0); - init(ts.ctx()); - ts.next_tx(@0x0); + init(ts.ctx()); + ts.next_tx(@0x0); - let owner_cap = ts.take_from_sender(); - let operator_cap = ts.take_from_sender(); - - ts.return_to_sender(owner_cap); - ts.return_to_sender(operator_cap); - ts.end(); -} + let owner_cap = ts.take_from_sender(); + let operator_cap = ts.take_from_sender(); -#[test] -fun test_setup() { - let mut ts = sui::test_scenario::begin(@0x0); - let creator_cap = creator_cap::create(ts.ctx()); - let chain_name = b"chain name".to_ascii_string(); + ts.return_to_sender(owner_cap); + ts.return_to_sender(operator_cap); + ts.end(); + } - setup(creator_cap, chain_name, ITS_HUB_ADDRESS.to_ascii_string(), ts.ctx()); - ts.next_tx(@0x0); + #[test] + fun test_setup() { + let mut ts = sui::test_scenario::begin(@0x0); + let creator_cap = creator_cap::create(ts.ctx()); + let chain_name = b"chain name".to_ascii_string(); - let its = ts.take_shared(); - let chain_name_hash = axelar_gateway::bytes32::from_bytes(sui::hash::keccak256(&chain_name.into_bytes())); - assert!(its.value!(b"send_interchain_transfer").chain_name_hash() == chain_name_hash); + setup(creator_cap, chain_name, ITS_HUB_ADDRESS.to_ascii_string(), ts.ctx()); + ts.next_tx(@0x0); - sui::test_scenario::return_shared(its); - ts.end(); -} + let its = ts.take_shared(); + let chain_name_hash = axelar_gateway::bytes32::from_bytes(sui::hash::keccak256(&chain_name.into_bytes())); + assert!(its.value!(b"send_interchain_transfer").chain_name_hash() == chain_name_hash); -#[test] -fun test_registered_coin_type() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); - let token_id = interchain_token_service::token_id::from_address(@0x1); - its.add_registered_coin_type_for_testing( - token_id, - std::type_name::get(), - ); - its.registered_coin_type(token_id); + sui::test_scenario::return_shared(its); + ts.end(); + } - sui::test_utils::destroy(its); -} + #[test] + fun test_registered_coin_type() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); + let token_id = interchain_token_service::token_id::from_address(@0x1); + its.add_registered_coin_type_for_testing( + token_id, + std::type_name::get(), + ); + its.registered_coin_type(token_id); + + sui::test_utils::destroy(its); + } -#[test] -fun test_channel_address() { - let ctx = &mut tx_context::dummy(); - let its = create_for_testing(ctx); + #[test] + fun test_channel_address() { + let ctx = &mut tx_context::dummy(); + let its = create_for_testing(ctx); - its.channel_address(); + its.channel_address(); - sui::test_utils::destroy(its); -} + sui::test_utils::destroy(its); + } -#[test] -fun test_allow_function() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = create_for_testing(ctx); - let owner_cap = owner_cap::create(ctx); - let version = 0; - let function_name = b"function_name".to_ascii_string(); + #[test] + fun test_allow_function() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = create_for_testing(ctx); + let owner_cap = owner_cap::create(ctx); + let version = 0; + let function_name = b"function_name".to_ascii_string(); - self.allow_function(&owner_cap, version, function_name); + self.allow_function(&owner_cap, version, function_name); - sui::test_utils::destroy(self); - sui::test_utils::destroy(owner_cap); -} + sui::test_utils::destroy(self); + sui::test_utils::destroy(owner_cap); + } -#[test] -fun test_disallow_function() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = create_for_testing(ctx); - let owner_cap = owner_cap::create(ctx); - let version = 0; - let function_name = b"send_interchain_transfer".to_ascii_string(); + #[test] + fun test_disallow_function() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = create_for_testing(ctx); + let owner_cap = owner_cap::create(ctx); + let version = 0; + let function_name = b"send_interchain_transfer".to_ascii_string(); - self.disallow_function(&owner_cap, version, function_name); + self.disallow_function(&owner_cap, version, function_name); - sui::test_utils::destroy(self); - sui::test_utils::destroy(owner_cap); + sui::test_utils::destroy(self); + sui::test_utils::destroy(owner_cap); + } } diff --git a/move/interchain_token_service/sources/types/coin_data.move b/move/interchain_token_service/sources/types/coin_data.move index 6415ccab..dbd4de7d 100644 --- a/move/interchain_token_service/sources/types/coin_data.move +++ b/move/interchain_token_service/sources/types/coin_data.move @@ -1,33 +1,29 @@ -module interchain_token_service::coin_data; +module interchain_token_service::coin_data { + use interchain_token_service::{coin_info::CoinInfo, coin_management::CoinManagement}; -use interchain_token_service::coin_info::CoinInfo; -use interchain_token_service::coin_management::CoinManagement; - -// ----- -// Types -// ----- -public struct CoinData has store { - coin_management: CoinManagement, - coin_info: CoinInfo, -} + // ----- + // Types + // ----- + public struct CoinData has store { + coin_management: CoinManagement, + coin_info: CoinInfo, + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun new( - coin_management: CoinManagement, - coin_info: CoinInfo, -): CoinData { - CoinData { - coin_management, - coin_info, + // ----------------- + // Package Functions + // ----------------- + public(package) fun new(coin_management: CoinManagement, coin_info: CoinInfo): CoinData { + CoinData { + coin_management, + coin_info, + } } -} -public(package) fun coin_info(self: &CoinData): &CoinInfo { - &self.coin_info -} + public(package) fun coin_info(self: &CoinData): &CoinInfo { + &self.coin_info + } -public(package) fun coin_management_mut(self: &mut CoinData): &mut CoinManagement { - &mut self.coin_management + public(package) fun coin_management_mut(self: &mut CoinData): &mut CoinManagement { + &mut self.coin_management + } } diff --git a/move/interchain_token_service/sources/types/coin_info.move b/move/interchain_token_service/sources/types/coin_info.move index dcd35068..99321ee2 100644 --- a/move/interchain_token_service/sources/types/coin_info.move +++ b/move/interchain_token_service/sources/types/coin_info.move @@ -1,99 +1,92 @@ /// Defines the `CoinInfo` type which allows to store information about a coin: /// either derived from `CoinMetadata` or manually provided. -module interchain_token_service::coin_info; +module interchain_token_service::coin_info { + use std::{ascii, string::String}; + use sui::coin::CoinMetadata; -use std::ascii; -use std::string::String; -use sui::coin::CoinMetadata; - -public struct CoinInfo has store { - name: String, - symbol: ascii::String, - decimals: u8, - metadata: Option>, -} + public struct CoinInfo has store { + name: String, + symbol: ascii::String, + decimals: u8, + metadata: Option>, + } -/// Create a new coin info from the given name, symbol and decimals. -public fun from_info( - name: String, - symbol: ascii::String, - decimals: u8, -): CoinInfo { - CoinInfo { - name, - symbol, - decimals, - metadata: option::none(), + /// Create a new coin info from the given name, symbol and decimals. + public fun from_info(name: String, symbol: ascii::String, decimals: u8): CoinInfo { + CoinInfo { + name, + symbol, + decimals, + metadata: option::none(), + } } -} -/// Create a new coin info from the given `CoinMetadata` object. -public fun from_metadata(metadata: CoinMetadata): CoinInfo { - CoinInfo { - name: metadata.get_name(), - symbol: metadata.get_symbol(), - decimals: metadata.get_decimals(), - metadata: option::some(metadata), + /// Create a new coin info from the given `CoinMetadata` object. + public fun from_metadata(metadata: CoinMetadata): CoinInfo { + CoinInfo { + name: metadata.get_name(), + symbol: metadata.get_symbol(), + decimals: metadata.get_decimals(), + metadata: option::some(metadata), + } } -} -// ----- -// Views -// ----- -public fun name(self: &CoinInfo): String { - self.name -} + // ----- + // Views + // ----- + public fun name(self: &CoinInfo): String { + self.name + } -public fun symbol(self: &CoinInfo): ascii::String { - self.symbol -} + public fun symbol(self: &CoinInfo): ascii::String { + self.symbol + } -public fun decimals(self: &CoinInfo): u8 { - self.decimals -} + public fun decimals(self: &CoinInfo): u8 { + self.decimals + } -public fun metadata(self: &CoinInfo): &Option> { - &self.metadata -} + public fun metadata(self: &CoinInfo): &Option> { + &self.metadata + } -// === Tests === -#[error] -#[test_only] -const EMetadataExists: vector = b"metadata was expected to be empty"; + // === Tests === + #[error] + #[test_only] + const EMetadataExists: vector = b"metadata was expected to be empty"; -#[test_only] -public fun drop(coin_info: CoinInfo) { - let CoinInfo { - name: _, - symbol: _, - decimals: _, - metadata, - } = coin_info; - if (metadata.is_some()) { - abort EMetadataExists - } else { - metadata.destroy_none() + #[test_only] + public fun drop(coin_info: CoinInfo) { + let CoinInfo { + name: _, + symbol: _, + decimals: _, + metadata, + } = coin_info; + if (metadata.is_some()) { + abort EMetadataExists + } else { + metadata.destroy_none() + } } -} -#[test] -fun test_from_metadata() { - let ctx = &mut tx_context::dummy(); - let metadata = interchain_token_service::coin::create_metadata(b"Symbol", 8, ctx); - let metadata_bytes = sui::bcs::to_bytes(&metadata); + #[test] + fun test_from_metadata() { + let ctx = &mut tx_context::dummy(); + let metadata = interchain_token_service::coin::create_metadata(b"Symbol", 8, ctx); + let metadata_bytes = sui::bcs::to_bytes(&metadata); - let name = metadata.get_name(); - let symbol = metadata.get_symbol(); - let decimals = metadata.get_decimals(); + let name = metadata.get_name(); + let symbol = metadata.get_symbol(); + let decimals = metadata.get_decimals(); - let coin_info = from_metadata(metadata); + let coin_info = from_metadata(metadata); - assert!(coin_info.name() == name); - assert!(coin_info.symbol() == symbol); - assert!(coin_info.decimals() == decimals); - assert!( - sui::bcs::to_bytes(coin_info.metadata().borrow()) == metadata_bytes, - ); + assert!(coin_info.name() == name); + assert!(coin_info.symbol() == symbol); + assert!(coin_info.decimals() == decimals); + assert!(sui::bcs::to_bytes(coin_info.metadata().borrow()) == metadata_bytes); - sui::test_utils::destroy(coin_info); + sui::test_utils::destroy(coin_info); + } } diff --git a/move/interchain_token_service/sources/types/coin_management.move b/move/interchain_token_service/sources/types/coin_management.move index aeaa7016..9dd3e55f 100644 --- a/move/interchain_token_service/sources/types/coin_management.move +++ b/move/interchain_token_service/sources/types/coin_management.move @@ -1,170 +1,138 @@ -module interchain_token_service::coin_management; - -use axelar_gateway::channel::Channel; -use interchain_token_service::flow_limit::{Self, FlowLimit}; -use sui::balance::{Self, Balance}; -use sui::clock::Clock; -use sui::coin::{Self, TreasuryCap, Coin}; - -// ------ -// Errors -// ------ -#[error] -const EDistributorNeedsTreasuryCap: vector = - b"trying to add a distributor to a `CoinManagement` that does not have a `TreasuryCap`"; -#[error] -const ENotOperator: vector = b"channel provided is not the operator"; - -/// Struct that stores information about the InterchainTokenService Coin. -public struct CoinManagement has store { - treasury_cap: Option>, - balance: Option>, - distributor: Option
, - operator: Option
, - flow_limit: FlowLimit, - dust: u256, -} +module interchain_token_service::coin_management { + use axelar_gateway::channel::Channel; + use interchain_token_service::flow_limit::{Self, FlowLimit}; + use sui::{balance::{Self, Balance}, clock::Clock, coin::{Self, TreasuryCap, Coin}}; + + // ------ + // Errors + // ------ + #[error] + const EDistributorNeedsTreasuryCap: vector = + b"trying to add a distributor to a `CoinManagement` that does not have a `TreasuryCap`"; + #[error] + const ENotOperator: vector = b"channel provided is not the operator"; + + /// Struct that stores information about the InterchainTokenService Coin. + public struct CoinManagement has store { + treasury_cap: Option>, + balance: Option>, + distributor: Option
, + operator: Option
, + flow_limit: FlowLimit, + dust: u256, + } -// ------ -// Public Functions to create CoinManagement -// ------ -/// Create a new `CoinManagement` with a `TreasuryCap`. -/// This type of `CoinManagement` allows minting and burning of coins. -public fun new_with_cap(treasury_cap: TreasuryCap): CoinManagement { - CoinManagement { - treasury_cap: option::some(treasury_cap), - balance: option::none(), - distributor: option::none(), - operator: option::none(), - flow_limit: flow_limit::new(), - dust: 0, + // ------ + // Public Functions to create CoinManagement + // ------ + /// Create a new `CoinManagement` with a `TreasuryCap`. + /// This type of `CoinManagement` allows minting and burning of coins. + public fun new_with_cap(treasury_cap: TreasuryCap): CoinManagement { + CoinManagement { + treasury_cap: option::some(treasury_cap), + balance: option::none(), + distributor: option::none(), + operator: option::none(), + flow_limit: flow_limit::new(), + dust: 0, + } } -} -/// Create a new `CoinManagement` with a `Balance`. -/// The stored `Balance` can be used to take and put coins. -public fun new_locked(): CoinManagement { - CoinManagement { - treasury_cap: option::none(), - balance: option::some(balance::zero()), - distributor: option::none(), - operator: option::none(), - flow_limit: flow_limit::new(), - dust: 0, + /// Create a new `CoinManagement` with a `Balance`. + /// The stored `Balance` can be used to take and put coins. + public fun new_locked(): CoinManagement { + CoinManagement { + treasury_cap: option::none(), + balance: option::some(balance::zero()), + distributor: option::none(), + operator: option::none(), + flow_limit: flow_limit::new(), + dust: 0, + } } -} -// ------ -// Functions that modify CoinManagement -// ------ -/// Adds the distributor address to the `CoinManagement`. -/// Only works for a `CoinManagement` with a `TreasuryCap`. -public fun add_distributor( - self: &mut CoinManagement, - distributor: address, -) { - assert!(has_capability(self), EDistributorNeedsTreasuryCap); - self.distributor.fill(distributor); -} + // ------ + // Functions that modify CoinManagement + // ------ + /// Adds the distributor address to the `CoinManagement`. + /// Only works for a `CoinManagement` with a `TreasuryCap`. + public fun add_distributor(self: &mut CoinManagement, distributor: address) { + assert!(has_capability(self), EDistributorNeedsTreasuryCap); + self.distributor.fill(distributor); + } -/// Adds the distributor address to the `CoinManagement`. -/// Only works for a `CoinManagement` with a `TreasuryCap`. -public fun add_operator(self: &mut CoinManagement, operator: address) { - self.operator.fill(operator); -} + /// Adds the distributor address to the `CoinManagement`. + /// Only works for a `CoinManagement` with a `TreasuryCap`. + public fun add_operator(self: &mut CoinManagement, operator: address) { + self.operator.fill(operator); + } -// === Protected Methods === - -/// Takes the given amount of Coins from user. Returns the amount that the InterchainTokenService -/// is supposed to give on other chains. -public(package) fun take_balance( - self: &mut CoinManagement, - to_take: Balance, - clock: &Clock, -): u64 { - self.flow_limit.add_flow_out(to_take.value(), clock); - let amount = to_take.value(); - if (has_capability(self)) { - self.burn(to_take); - } else { - self.balance.borrow_mut().join(to_take); - }; - amount -} + // === Protected Methods === + + /// Takes the given amount of Coins from user. Returns the amount that the InterchainTokenService + /// is supposed to give on other chains. + public(package) fun take_balance(self: &mut CoinManagement, to_take: Balance, clock: &Clock): u64 { + self.flow_limit.add_flow_out(to_take.value(), clock); + let amount = to_take.value(); + if (has_capability(self)) { + self.burn(to_take); + } else { + self.balance.borrow_mut().join(to_take); + }; + amount + } -/// Withdraws or mints the given amount of coins. Any leftover amount from -/// previous transfers is added to the coin here. -public(package) fun give_coin( - self: &mut CoinManagement, - amount: u64, - clock: &Clock, - ctx: &mut TxContext, -): Coin { - self.flow_limit.add_flow_in(amount, clock); - if (has_capability(self)) { - self.mint(amount, ctx) - } else { - coin::take(self.balance.borrow_mut(), amount, ctx) + /// Withdraws or mints the given amount of coins. Any leftover amount from + /// previous transfers is added to the coin here. + public(package) fun give_coin(self: &mut CoinManagement, amount: u64, clock: &Clock, ctx: &mut TxContext): Coin { + self.flow_limit.add_flow_in(amount, clock); + if (has_capability(self)) { + self.mint(amount, ctx) + } else { + coin::take(self.balance.borrow_mut(), amount, ctx) + } } -} -// helper function to mint as a distributor. -public(package) fun mint( - self: &mut CoinManagement, - amount: u64, - ctx: &mut TxContext, -): Coin { - self.treasury_cap.borrow_mut().mint(amount, ctx) -} + // helper function to mint as a distributor. + public(package) fun mint(self: &mut CoinManagement, amount: u64, ctx: &mut TxContext): Coin { + self.treasury_cap.borrow_mut().mint(amount, ctx) + } -// helper function to burn as a distributor. -public(package) fun burn(self: &mut CoinManagement, balance: Balance) { - self.treasury_cap.borrow_mut().supply_mut().decrease_supply(balance); -} + // helper function to burn as a distributor. + public(package) fun burn(self: &mut CoinManagement, balance: Balance) { + self.treasury_cap.borrow_mut().supply_mut().decrease_supply(balance); + } -/// Adds a rate limit to the `CoinManagement`. -public(package) fun set_flow_limit( - self: &mut CoinManagement, - channel: &Channel, - flow_limit: Option, -) { - assert!(self.operator.contains(&channel.to_address()), ENotOperator); - self.set_flow_limit_internal(flow_limit); -} + /// Adds a rate limit to the `CoinManagement`. + public(package) fun set_flow_limit(self: &mut CoinManagement, channel: &Channel, flow_limit: Option) { + assert!(self.operator.contains(&channel.to_address()), ENotOperator); + self.set_flow_limit_internal(flow_limit); + } -/// Adds a rate limit to the `CoinManagement`. -public(package) fun set_flow_limit_internal( - self: &mut CoinManagement, - flow_limit: Option, -) { - self.flow_limit.set_flow_limit(flow_limit); -} + /// Adds a rate limit to the `CoinManagement`. + public(package) fun set_flow_limit_internal(self: &mut CoinManagement, flow_limit: Option) { + self.flow_limit.set_flow_limit(flow_limit); + } -// === Views === + // === Views === -/// Checks if the given address is a `distributor`. -public fun is_distributor( - self: &CoinManagement, - distributor: address, -): bool { - &distributor == self.distributor.borrow() -} + /// Checks if the given address is a `distributor`. + public fun is_distributor(self: &CoinManagement, distributor: address): bool { + &distributor == self.distributor.borrow() + } -/// Returns true if the coin management has a `TreasuryCap`. -public fun has_capability(self: &CoinManagement): bool { - self.treasury_cap.is_some() -} + /// Returns true if the coin management has a `TreasuryCap`. + public fun has_capability(self: &CoinManagement): bool { + self.treasury_cap.is_some() + } -// === Tests === -#[test_only] -public struct COIN_MANAGEMENT has drop {} + // === Tests === + #[test_only] + public struct COIN_MANAGEMENT has drop {} -#[test_only] -fun create_currency(): ( - TreasuryCap, - sui::coin::CoinMetadata, -) { - sui::coin::create_currency( + #[test_only] + fun create_currency(): (TreasuryCap, sui::coin::CoinMetadata) { + sui::coin::create_currency( sui::test_utils::create_one_time_witness(), 6, b"TT", @@ -173,108 +141,109 @@ fun create_currency(): ( option::none(), &mut sui::tx_context::dummy(), ) -} -#[test] -fun test_take_balance() { - let (mut cap, metadata) = create_currency(); - let ctx = &mut sui::tx_context::dummy(); - let amount1 = 10; - let amount2 = 20; - - let mut coin = cap.mint(amount1, ctx); - let mut management1 = new_locked(); - let clock = sui::clock::create_for_testing(ctx); - management1.take_balance(coin.into_balance(), &clock); - - assert!(management1.balance.borrow().value() == amount1); - - coin = cap.mint(amount2, ctx); - let mut management2 = new_with_cap(cap); - management2.take_balance(coin.into_balance(), &clock); - - sui::test_utils::destroy(metadata); - sui::test_utils::destroy(management1); - sui::test_utils::destroy(management2); - sui::test_utils::destroy(clock); -} + } + #[test] + fun test_take_balance() { + let (mut cap, metadata) = create_currency(); + let ctx = &mut sui::tx_context::dummy(); + let amount1 = 10; + let amount2 = 20; + + let mut coin = cap.mint(amount1, ctx); + let mut management1 = new_locked(); + let clock = sui::clock::create_for_testing(ctx); + management1.take_balance(coin.into_balance(), &clock); + + assert!(management1.balance.borrow().value() == amount1); + + coin = cap.mint(amount2, ctx); + let mut management2 = new_with_cap(cap); + management2.take_balance(coin.into_balance(), &clock); + + sui::test_utils::destroy(metadata); + sui::test_utils::destroy(management1); + sui::test_utils::destroy(management2); + sui::test_utils::destroy(clock); + } -#[test] -fun test_give_coin() { - let (mut cap, metadata) = create_currency(); - let ctx = &mut sui::tx_context::dummy(); - let amount1 = 10; - let amount2 = 20; + #[test] + fun test_give_coin() { + let (mut cap, metadata) = create_currency(); + let ctx = &mut sui::tx_context::dummy(); + let amount1 = 10; + let amount2 = 20; - let mut coin = cap.mint(amount1, ctx); - let mut management1 = new_locked(); - let clock = sui::clock::create_for_testing(ctx); - management1.take_balance(coin.into_balance(), &clock); - coin = management1.give_coin(amount1, &clock, ctx); + let mut coin = cap.mint(amount1, ctx); + let mut management1 = new_locked(); + let clock = sui::clock::create_for_testing(ctx); + management1.take_balance(coin.into_balance(), &clock); + coin = management1.give_coin(amount1, &clock, ctx); - assert!(management1.balance.borrow().value() == 0); - assert!(coin.value() == amount1); + assert!(management1.balance.borrow().value() == 0); + assert!(coin.value() == amount1); - sui::test_utils::destroy(coin); + sui::test_utils::destroy(coin); - let mut management2 = new_with_cap(cap); - coin = management2.give_coin(amount2, &clock, ctx); + let mut management2 = new_with_cap(cap); + coin = management2.give_coin(amount2, &clock, ctx); - assert!(coin.value() == amount2); + assert!(coin.value() == amount2); - sui::test_utils::destroy(coin); - sui::test_utils::destroy(metadata); - sui::test_utils::destroy(management1); - sui::test_utils::destroy(management2); - sui::test_utils::destroy(clock); -} + sui::test_utils::destroy(coin); + sui::test_utils::destroy(metadata); + sui::test_utils::destroy(management1); + sui::test_utils::destroy(management2); + sui::test_utils::destroy(clock); + } -#[test] -#[expected_failure(abort_code = EDistributorNeedsTreasuryCap)] -fun test_add_distributor_no_capability() { - let mut management = new_locked(); - let distributor = @0x1; + #[test] + #[expected_failure(abort_code = EDistributorNeedsTreasuryCap)] + fun test_add_distributor_no_capability() { + let mut management = new_locked(); + let distributor = @0x1; - management.add_distributor(distributor); + management.add_distributor(distributor); - sui::test_utils::destroy(management); -} + sui::test_utils::destroy(management); + } -#[test] -fun test_add_operator() { - let mut management = new_locked(); - let operator = @0x1; + #[test] + fun test_add_operator() { + let mut management = new_locked(); + let operator = @0x1; - management.add_operator(operator); + management.add_operator(operator); - sui::test_utils::destroy(management); -} + sui::test_utils::destroy(management); + } -#[test] -fun test_set_flow_limit() { - let ctx = &mut sui::tx_context::dummy(); + #[test] + fun test_set_flow_limit() { + let ctx = &mut sui::tx_context::dummy(); - let mut management = new_locked(); - let channel = axelar_gateway::channel::new(ctx); + let mut management = new_locked(); + let channel = axelar_gateway::channel::new(ctx); - management.add_operator(channel.to_address()); - management.set_flow_limit(&channel, option::some(1)); + management.add_operator(channel.to_address()); + management.set_flow_limit(&channel, option::some(1)); - sui::test_utils::destroy(management); - sui::test_utils::destroy(channel); -} + sui::test_utils::destroy(management); + sui::test_utils::destroy(channel); + } -#[test] -#[expected_failure(abort_code = ENotOperator)] -fun test_set_flow_limit_not_operator() { - let ctx = &mut sui::tx_context::dummy(); + #[test] + #[expected_failure(abort_code = ENotOperator)] + fun test_set_flow_limit_not_operator() { + let ctx = &mut sui::tx_context::dummy(); - let mut management = new_locked(); - let channel = axelar_gateway::channel::new(ctx); - let operator = @0x1; + let mut management = new_locked(); + let channel = axelar_gateway::channel::new(ctx); + let operator = @0x1; - management.add_operator(operator); - management.set_flow_limit(&channel, option::some(1)); + management.add_operator(operator); + management.set_flow_limit(&channel, option::some(1)); - sui::test_utils::destroy(management); - sui::test_utils::destroy(channel); + sui::test_utils::destroy(management); + sui::test_utils::destroy(channel); + } } diff --git a/move/interchain_token_service/sources/types/creator_cap.move b/move/interchain_token_service/sources/types/creator_cap.move index 84e372bb..74a23886 100644 --- a/move/interchain_token_service/sources/types/creator_cap.move +++ b/move/interchain_token_service/sources/types/creator_cap.move @@ -1,19 +1,19 @@ -module interchain_token_service::creator_cap; - -// ----- -// Types -// ----- -public struct CreatorCap has key, store { - id: UID, -} +module interchain_token_service::creator_cap { + // ----- + // Types + // ----- + public struct CreatorCap has key, store { + id: UID, + } -public(package) fun create(ctx: &mut TxContext): CreatorCap { - CreatorCap { - id: object::new(ctx), + public(package) fun create(ctx: &mut TxContext): CreatorCap { + CreatorCap { + id: object::new(ctx), + } } -} -public(package) fun destroy(self: CreatorCap) { - let CreatorCap { id } = self; - id.delete(); + public(package) fun destroy(self: CreatorCap) { + let CreatorCap { id } = self; + id.delete(); + } } diff --git a/move/interchain_token_service/sources/types/flow_limit.move b/move/interchain_token_service/sources/types/flow_limit.move index a610589d..2e5ff9ad 100644 --- a/move/interchain_token_service/sources/types/flow_limit.move +++ b/move/interchain_token_service/sources/types/flow_limit.move @@ -1,147 +1,133 @@ -module interchain_token_service::flow_limit; +module interchain_token_service::flow_limit { + use sui::clock::Clock; -use sui::clock::Clock; + const EPOCH_TIME: u64 = 6 * 60 * 60 * 1000; -const EPOCH_TIME: u64 = 6 * 60 * 60 * 1000; + #[error] + const EFlowLimitExceeded: vector = b"flow limit exceeded"; -#[error] -const EFlowLimitExceeded: vector = b"flow limit exceeded"; + public struct FlowLimit has copy, drop, store { + flow_limit: Option, + flow_in: u128, + flow_out: u128, + current_epoch: u64, + } -public struct FlowLimit has store, copy, drop { - flow_limit: Option, - flow_in: u128, - flow_out: u128, - current_epoch: u64, -} + public(package) fun new(): FlowLimit { + FlowLimit { + flow_limit: option::none(), + flow_in: 0, + flow_out: 0, + current_epoch: 0, + } + } -public(package) fun new(): FlowLimit { - FlowLimit { - flow_limit: option::none(), - flow_in: 0, - flow_out: 0, - current_epoch: 0, + fun update_epoch(self: &mut FlowLimit, clock: &Clock) { + let epoch = clock.timestamp_ms() / EPOCH_TIME; + if (epoch > self.current_epoch) { + self.current_epoch = epoch; + self.flow_in = 0; + self.flow_out = 0; + } } -} -fun update_epoch(self: &mut FlowLimit, clock: &Clock) { - let epoch = clock.timestamp_ms() / EPOCH_TIME; - if (epoch > self.current_epoch) { - self.current_epoch = epoch; - self.flow_in = 0; - self.flow_out = 0; + public(package) fun add_flow_in(self: &mut FlowLimit, amount: u64, clock: &Clock) { + if (self.flow_limit.is_none()) { + return + }; + let flow_limit = *self.flow_limit.borrow() as u128; + + update_epoch(self, clock); + assert!(self.flow_in + (amount as u128) < flow_limit + self.flow_out, EFlowLimitExceeded); + self.flow_in = self.flow_in + (amount as u128); } -} -public(package) fun add_flow_in( - self: &mut FlowLimit, - amount: u64, - clock: &Clock, -) { - if (self.flow_limit.is_none()) { - return - }; - let flow_limit = *self.flow_limit.borrow() as u128; - - update_epoch(self, clock); - assert!( - self.flow_in + (amount as u128) < flow_limit + self.flow_out, - EFlowLimitExceeded, - ); - self.flow_in = self.flow_in + (amount as u128); -} + public(package) fun add_flow_out(self: &mut FlowLimit, amount: u64, clock: &Clock) { + if (self.flow_limit.is_none()) { + return + }; + let flow_limit = *self.flow_limit.borrow() as u128; -public(package) fun add_flow_out( - self: &mut FlowLimit, - amount: u64, - clock: &Clock, -) { - if (self.flow_limit.is_none()) { - return - }; - let flow_limit = *self.flow_limit.borrow() as u128; - - update_epoch(self, clock); - assert!( - self.flow_out + (amount as u128) < flow_limit + self.flow_in, - EFlowLimitExceeded, - ); - self.flow_out = self.flow_out + (amount as u128); -} + update_epoch(self, clock); + assert!(self.flow_out + (amount as u128) < flow_limit + self.flow_in, EFlowLimitExceeded); + self.flow_out = self.flow_out + (amount as u128); + } -public(package) fun set_flow_limit(self: &mut FlowLimit, flow_limit: Option) { - self.flow_limit = flow_limit; -} + public(package) fun set_flow_limit(self: &mut FlowLimit, flow_limit: Option) { + self.flow_limit = flow_limit; + } -// ----- -// Tests -// ----- -#[test] -fun test_update_epoch() { - let ctx = &mut tx_context::dummy(); - let mut flow_limit = new(); - let mut clock = sui::clock::create_for_testing(ctx); - flow_limit.update_epoch(&clock); - clock.increment_for_testing(EPOCH_TIME); - flow_limit.update_epoch(&clock); - clock.destroy_for_testing(); -} + // ----- + // Tests + // ----- + #[test] + fun test_update_epoch() { + let ctx = &mut tx_context::dummy(); + let mut flow_limit = new(); + let mut clock = sui::clock::create_for_testing(ctx); + flow_limit.update_epoch(&clock); + clock.increment_for_testing(EPOCH_TIME); + flow_limit.update_epoch(&clock); + clock.destroy_for_testing(); + } -#[test] -fun test_add_flow_in() { - let ctx = &mut tx_context::dummy(); - let mut flow_limit = new(); - let clock = sui::clock::create_for_testing(ctx); - flow_limit.set_flow_limit(option::some(2)); - flow_limit.add_flow_in(1, &clock); - clock.destroy_for_testing(); -} + #[test] + fun test_add_flow_in() { + let ctx = &mut tx_context::dummy(); + let mut flow_limit = new(); + let clock = sui::clock::create_for_testing(ctx); + flow_limit.set_flow_limit(option::some(2)); + flow_limit.add_flow_in(1, &clock); + clock.destroy_for_testing(); + } -#[test] -fun test_add_flow_out() { - let ctx = &mut tx_context::dummy(); - let mut flow_limit = new(); - let clock = sui::clock::create_for_testing(ctx); - flow_limit.set_flow_limit(option::some(2)); - flow_limit.add_flow_out(1, &clock); - clock.destroy_for_testing(); -} + #[test] + fun test_add_flow_out() { + let ctx = &mut tx_context::dummy(); + let mut flow_limit = new(); + let clock = sui::clock::create_for_testing(ctx); + flow_limit.set_flow_limit(option::some(2)); + flow_limit.add_flow_out(1, &clock); + clock.destroy_for_testing(); + } -#[test] -fun test_add_flow_in_zero_flow_limit() { - let ctx = &mut tx_context::dummy(); - let mut flow_limit = new(); - let clock = sui::clock::create_for_testing(ctx); - flow_limit.add_flow_in(1, &clock); - clock.destroy_for_testing(); -} + #[test] + fun test_add_flow_in_zero_flow_limit() { + let ctx = &mut tx_context::dummy(); + let mut flow_limit = new(); + let clock = sui::clock::create_for_testing(ctx); + flow_limit.add_flow_in(1, &clock); + clock.destroy_for_testing(); + } -#[test] -fun test_add_flow_out_zero_flow_limit() { - let ctx = &mut tx_context::dummy(); - let mut flow_limit = new(); - let clock = sui::clock::create_for_testing(ctx); - flow_limit.add_flow_out(1, &clock); - clock.destroy_for_testing(); -} + #[test] + fun test_add_flow_out_zero_flow_limit() { + let ctx = &mut tx_context::dummy(); + let mut flow_limit = new(); + let clock = sui::clock::create_for_testing(ctx); + flow_limit.add_flow_out(1, &clock); + clock.destroy_for_testing(); + } -#[test] -#[expected_failure(abort_code = EFlowLimitExceeded)] -fun test_add_flow_in_limit_exceeded() { - let ctx = &mut tx_context::dummy(); - let mut flow_limit = new(); - let clock = sui::clock::create_for_testing(ctx); - flow_limit.set_flow_limit(option::some(1)); - flow_limit.add_flow_in(1, &clock); - clock.destroy_for_testing(); -} + #[test] + #[expected_failure(abort_code = EFlowLimitExceeded)] + fun test_add_flow_in_limit_exceeded() { + let ctx = &mut tx_context::dummy(); + let mut flow_limit = new(); + let clock = sui::clock::create_for_testing(ctx); + flow_limit.set_flow_limit(option::some(1)); + flow_limit.add_flow_in(1, &clock); + clock.destroy_for_testing(); + } -#[test] -#[expected_failure(abort_code = EFlowLimitExceeded)] -fun test_add_flow_out_limit_exceeded() { - let ctx = &mut tx_context::dummy(); - let mut flow_limit = new(); - let clock = sui::clock::create_for_testing(ctx); - flow_limit.set_flow_limit(option::some(1)); - flow_limit.add_flow_out(1, &clock); - clock.destroy_for_testing(); + #[test] + #[expected_failure(abort_code = EFlowLimitExceeded)] + fun test_add_flow_out_limit_exceeded() { + let ctx = &mut tx_context::dummy(); + let mut flow_limit = new(); + let clock = sui::clock::create_for_testing(ctx); + flow_limit.set_flow_limit(option::some(1)); + flow_limit.add_flow_out(1, &clock); + clock.destroy_for_testing(); + } } diff --git a/move/interchain_token_service/sources/types/interchain_transfer_ticket.move b/move/interchain_token_service/sources/types/interchain_transfer_ticket.move index ea20d423..e177514e 100644 --- a/move/interchain_token_service/sources/types/interchain_transfer_ticket.move +++ b/move/interchain_token_service/sources/types/interchain_transfer_ticket.move @@ -1,65 +1,55 @@ -module interchain_token_service::interchain_transfer_ticket; +module interchain_token_service::interchain_transfer_ticket { + use interchain_token_service::token_id::TokenId; + use std::ascii::String; + use sui::balance::Balance; -use interchain_token_service::token_id::TokenId; -use std::ascii::String; -use sui::balance::Balance; - -/// ----- -/// Types -/// ----- -#[allow(lint(coin_field))] -public struct InterchainTransferTicket { - token_id: TokenId, - balance: Balance, - source_address: address, - destination_chain: String, - destination_address: vector, - metadata: vector, - version: u64, -} + /// ----- + /// Types + /// ----- + #[allow(lint(coin_field))] + public struct InterchainTransferTicket { + token_id: TokenId, + balance: Balance, + source_address: address, + destination_chain: String, + destination_address: vector, + metadata: vector, + version: u64, + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun new( - token_id: TokenId, - balance: Balance, - source_address: address, - destination_chain: String, - destination_address: vector, - metadata: vector, - version: u64, -): InterchainTransferTicket { - InterchainTransferTicket { - token_id, - balance, - source_address, - destination_chain, - destination_address, - metadata, - version, + // ----------------- + // Package Functions + // ----------------- + public(package) fun new( + token_id: TokenId, + balance: Balance, + source_address: address, + destination_chain: String, + destination_address: vector, + metadata: vector, + version: u64, + ): InterchainTransferTicket { + InterchainTransferTicket { + token_id, + balance, + source_address, + destination_chain, + destination_address, + metadata, + version, + } } -} -public(package) fun destroy( - self: InterchainTransferTicket, -): (TokenId, Balance, address, String, vector, vector, u64) { - let InterchainTransferTicket { - token_id, - balance, - source_address, - destination_chain, - destination_address, - metadata, - version, - } = self; - ( - token_id, - balance, - source_address, - destination_chain, - destination_address, - metadata, - version, - ) + public(package) fun destroy(self: InterchainTransferTicket): (TokenId, Balance, address, String, vector, vector, u64) { + let InterchainTransferTicket { + token_id, + balance, + source_address, + destination_chain, + destination_address, + metadata, + version, + } = self; + (token_id, balance, source_address, destination_chain, destination_address, metadata, version) + } } diff --git a/move/interchain_token_service/sources/types/operator_cap.move b/move/interchain_token_service/sources/types/operator_cap.move index e0fb8352..0370a296 100644 --- a/move/interchain_token_service/sources/types/operator_cap.move +++ b/move/interchain_token_service/sources/types/operator_cap.move @@ -1,14 +1,14 @@ -module interchain_token_service::operator_cap; - -// ----- -// Types -// ----- -public struct OperatorCap has key, store { - id: UID, -} +module interchain_token_service::operator_cap { + // ----- + // Types + // ----- + public struct OperatorCap has key, store { + id: UID, + } -public(package) fun create(ctx: &mut TxContext): OperatorCap { - OperatorCap { - id: object::new(ctx), + public(package) fun create(ctx: &mut TxContext): OperatorCap { + OperatorCap { + id: object::new(ctx), + } } } diff --git a/move/interchain_token_service/sources/types/owner_cap.move b/move/interchain_token_service/sources/types/owner_cap.move index a27f0e5d..dd2b5aed 100644 --- a/move/interchain_token_service/sources/types/owner_cap.move +++ b/move/interchain_token_service/sources/types/owner_cap.move @@ -1,14 +1,14 @@ -module interchain_token_service::owner_cap; - -// ----- -// Types -// ----- -public struct OwnerCap has key, store { - id: UID, -} +module interchain_token_service::owner_cap { + // ----- + // Types + // ----- + public struct OwnerCap has key, store { + id: UID, + } -public(package) fun create(ctx: &mut TxContext): OwnerCap { - OwnerCap { - id: object::new(ctx), + public(package) fun create(ctx: &mut TxContext): OwnerCap { + OwnerCap { + id: object::new(ctx), + } } } diff --git a/move/interchain_token_service/sources/types/token_id.move b/move/interchain_token_service/sources/types/token_id.move index c51285e9..3a88bb97 100644 --- a/move/interchain_token_service/sources/types/token_id.move +++ b/move/interchain_token_service/sources/types/token_id.move @@ -1,106 +1,97 @@ -module interchain_token_service::token_id; +module interchain_token_service::token_id { + use axelar_gateway::bytes32::Bytes32; + use interchain_token_service::{coin_info::CoinInfo, coin_management::CoinManagement}; + use std::{ascii, string::String, type_name}; + use sui::{address, bcs, hash::keccak256}; -use axelar_gateway::bytes32::Bytes32; -use interchain_token_service::coin_info::CoinInfo; -use interchain_token_service::coin_management::CoinManagement; -use std::ascii; -use std::string::String; -use std::type_name; -use sui::address; -use sui::bcs; -use sui::hash::keccak256; + // address::to_u256(address::from_bytes(keccak256(&bcs::to_bytes>(&b"prefix-sui-token-id")))); + const PREFIX_SUI_TOKEN_ID: u256 = 0x72efd4f4a47bdb9957673d9d0fabc22cad1544bc247ac18367ac54985919bfa3; -// address::to_u256(address::from_bytes(keccak256(&bcs::to_bytes>(&b"prefix-sui-token-id")))); -const PREFIX_SUI_TOKEN_ID: u256 = - 0x72efd4f4a47bdb9957673d9d0fabc22cad1544bc247ac18367ac54985919bfa3; + public struct TokenId has copy, drop, store { + id: address, + } -public struct TokenId has store, copy, drop { - id: address, -} + public struct UnregisteredTokenId has copy, drop, store { + id: address, + } -public struct UnregisteredTokenId has store, copy, drop { - id: address, -} + public fun from_address(id: address): TokenId { + TokenId { id } + } -public fun from_address(id: address): TokenId { - TokenId { id } -} + public fun from_u256(id: u256): TokenId { + TokenId { id: address::from_u256(id) } + } -public fun from_u256(id: u256): TokenId { - TokenId { id: address::from_u256(id) } -} + public fun to_u256(token_id: &TokenId): u256 { + address::to_u256(token_id.id) + } -public fun to_u256(token_id: &TokenId): u256 { - address::to_u256(token_id.id) -} + public fun from_info( + chain_name_hash: &Bytes32, + name: &String, + symbol: &ascii::String, + decimals: &u8, + has_metadata: &bool, + has_treasury: &bool, + ): TokenId { + let mut vec = address::from_u256(PREFIX_SUI_TOKEN_ID).to_bytes(); + vec.append(bcs::to_bytes(chain_name_hash)); + vec.append(bcs::to_bytes(&type_name::get())); + vec.append(bcs::to_bytes(name)); + vec.append(bcs::to_bytes(symbol)); + vec.append(bcs::to_bytes(decimals)); + vec.append(bcs::to_bytes(has_metadata)); + vec.append(bcs::to_bytes(has_treasury)); + TokenId { id: address::from_bytes(keccak256(&vec)) } + } -public fun from_info( - chain_name_hash: &Bytes32, - name: &String, - symbol: &ascii::String, - decimals: &u8, - has_metadata: &bool, - has_treasury: &bool, -): TokenId { - let mut vec = address::from_u256(PREFIX_SUI_TOKEN_ID).to_bytes(); - vec.append(bcs::to_bytes(chain_name_hash)); - vec.append(bcs::to_bytes(&type_name::get())); - vec.append(bcs::to_bytes(name)); - vec.append(bcs::to_bytes(symbol)); - vec.append(bcs::to_bytes(decimals)); - vec.append(bcs::to_bytes(has_metadata)); - vec.append(bcs::to_bytes(has_treasury)); - TokenId { id: address::from_bytes(keccak256(&vec)) } -} - -public(package) fun from_coin_data( - chain_name_hash: &Bytes32, - coin_info: &CoinInfo, - coin_management: &CoinManagement, -): TokenId { - from_info( - chain_name_hash, - &coin_info.name(), - &coin_info.symbol(), - &coin_info.decimals(), - &option::is_some(coin_info.metadata()), - &coin_management.has_capability(), - ) -} + public(package) fun from_coin_data( + chain_name_hash: &Bytes32, + coin_info: &CoinInfo, + coin_management: &CoinManagement, + ): TokenId { + from_info( + chain_name_hash, + &coin_info.name(), + &coin_info.symbol(), + &coin_info.decimals(), + &option::is_some(coin_info.metadata()), + &coin_management.has_capability(), + ) + } -public fun unregistered_token_id( - symbol: &ascii::String, - decimals: u8, -): UnregisteredTokenId { - let mut v = vector[decimals]; - v.append(*ascii::as_bytes(symbol)); - let id = address::from_bytes(keccak256(&v)); - UnregisteredTokenId { id } -} + public fun unregistered_token_id(symbol: &ascii::String, decimals: u8): UnregisteredTokenId { + let mut v = vector[decimals]; + v.append(*ascii::as_bytes(symbol)); + let id = address::from_bytes(keccak256(&v)); + UnregisteredTokenId { id } + } -// === Tests === -#[test] -fun test() { - use std::string; - use interchain_token_service::coin_info; + // === Tests === + #[test] + fun test() { + use std::string; + use interchain_token_service::coin_info; - let prefix = address::to_u256( - address::from_bytes( - keccak256(&bcs::to_bytes>(&b"prefix-sui-token-id")), - ), - ); - assert!(prefix == PREFIX_SUI_TOKEN_ID); + let prefix = address::to_u256( + address::from_bytes( + keccak256(&bcs::to_bytes>(&b"prefix-sui-token-id")), + ), + ); + assert!(prefix == PREFIX_SUI_TOKEN_ID); - let name = string::utf8(b"Name"); - let symbol = ascii::string(b"Symbol"); - let decimals: u8 = 9; - let coin_info = coin_info::from_info( - name, - symbol, - decimals, - ); - let mut vec = address::from_u256(PREFIX_SUI_TOKEN_ID).to_bytes(); + let name = string::utf8(b"Name"); + let symbol = ascii::string(b"Symbol"); + let decimals: u8 = 9; + let coin_info = coin_info::from_info( + name, + symbol, + decimals, + ); + let mut vec = address::from_u256(PREFIX_SUI_TOKEN_ID).to_bytes(); - vec.append(bcs::to_bytes>(&coin_info)); - coin_info.drop(); + vec.append(bcs::to_bytes>(&coin_info)); + coin_info.drop(); + } } diff --git a/move/interchain_token_service/sources/types/trusted_chains.move b/move/interchain_token_service/sources/types/trusted_chains.move index f9de7bf1..c10ce719 100644 --- a/move/interchain_token_service/sources/types/trusted_chains.move +++ b/move/interchain_token_service/sources/types/trusted_chains.move @@ -1,134 +1,134 @@ -module interchain_token_service::trusted_chains; - -use interchain_token_service::events; -use std::ascii::String; -use sui::bag::{Self, Bag}; - -// ------ -// Errors -// ------ -#[error] -const EEmptyChainName: vector = b"empty trusted chain name is unsupported"; -#[error] -const EAlreadyTrusted: vector = b"chain is already trusted"; -#[error] -const ENotTrusted: vector = b"chain is not trusted"; - -public struct TrustedChain has store, drop {} - -/// The trusted chains where messages can be sent or received from. -public struct TrustedChains has store { - trusted_chains: Bag, -} +module interchain_token_service::trusted_chains { + use interchain_token_service::events; + use std::ascii::String; + use sui::bag::{Self, Bag}; + + // ------ + // Errors + // ------ + #[error] + const EEmptyChainName: vector = b"empty trusted chain name is unsupported"; + #[error] + const EAlreadyTrusted: vector = b"chain is already trusted"; + #[error] + const ENotTrusted: vector = b"chain is not trusted"; + + public struct TrustedChain has drop, store {} + + /// The trusted chains where messages can be sent or received from. + public struct TrustedChains has store { + trusted_chains: Bag, + } -// ----------------- -// Package Functions -// ----------------- -/// Create a new interchain address tracker. -public(package) fun new(ctx: &mut TxContext): TrustedChains { - TrustedChains { - trusted_chains: bag::new(ctx), + // ----------------- + // Package Functions + // ----------------- + /// Create a new interchain address tracker. + public(package) fun new(ctx: &mut TxContext): TrustedChains { + TrustedChains { + trusted_chains: bag::new(ctx), + } } -} -/// Check if the given address is trusted for the given chain. -public(package) fun is_trusted(self: &TrustedChains, chain_name: String): bool { - self.trusted_chains.contains(chain_name) -} + /// Check if the given address is trusted for the given chain. + public(package) fun is_trusted(self: &TrustedChains, chain_name: String): bool { + self.trusted_chains.contains(chain_name) + } -/// Set the trusted address for a chain or adds it if it doesn't exist. -public(package) fun add(self: &mut TrustedChains, chain_name: String) { - assert!(chain_name.length() > 0, EEmptyChainName); - assert!(!self.trusted_chains.contains(chain_name), EAlreadyTrusted); + /// Set the trusted address for a chain or adds it if it doesn't exist. + public(package) fun add(self: &mut TrustedChains, chain_name: String) { + assert!(chain_name.length() > 0, EEmptyChainName); + assert!(!self.trusted_chains.contains(chain_name), EAlreadyTrusted); - self.trusted_chains.add(chain_name, TrustedChain {}); - events::trusted_chain_added(chain_name); -} + self.trusted_chains.add(chain_name, TrustedChain {}); + events::trusted_chain_added(chain_name); + } -public(package) fun remove(self: &mut TrustedChains, chain_name: String) { - assert!(chain_name.length() > 0, EEmptyChainName); - assert!(self.trusted_chains.contains(chain_name), ENotTrusted); + public(package) fun remove(self: &mut TrustedChains, chain_name: String) { + assert!(chain_name.length() > 0, EEmptyChainName); + assert!(self.trusted_chains.contains(chain_name), ENotTrusted); - self.trusted_chains.remove(chain_name); - events::trusted_chain_removed(chain_name); -} + self.trusted_chains.remove(chain_name); + events::trusted_chain_removed(chain_name); + } -// ----- -// Tests -// ----- -#[test] -fun test_trusted_chains() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain1 = std::ascii::string(b"chain1"); - let chain2 = std::ascii::string(b"chain2"); + // ----- + // Tests + // ----- + #[test] + fun test_trusted_chains() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain1 = std::ascii::string(b"chain1"); + let chain2 = std::ascii::string(b"chain2"); - self.add(chain1); - self.add(chain2); + self.add(chain1); + self.add(chain2); - assert!(self.is_trusted(chain1) == true); - assert!(self.is_trusted(chain2) == true); + assert!(self.is_trusted(chain1) == true); + assert!(self.is_trusted(chain2) == true); - assert!(self.trusted_chains.contains(chain1)); - assert!(self.trusted_chains.contains(chain2)); + assert!(self.trusted_chains.contains(chain1)); + assert!(self.trusted_chains.contains(chain2)); - self.remove(chain1); - self.remove(chain2); + self.remove(chain1); + self.remove(chain2); - assert!(self.is_trusted(chain1) == false); - assert!(self.is_trusted(chain2) == false); + assert!(self.is_trusted(chain1) == false); + assert!(self.is_trusted(chain2) == false); - assert!(!self.trusted_chains.contains(chain1)); - assert!(!self.trusted_chains.contains(chain2)); + assert!(!self.trusted_chains.contains(chain1)); + assert!(!self.trusted_chains.contains(chain2)); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EEmptyChainName)] -fun test_add_trusted_chain_empty_chain_name() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b""); + #[test] + #[expected_failure(abort_code = EEmptyChainName)] + fun test_add_trusted_chain_empty_chain_name() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b""); - self.add(chain); + self.add(chain); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EAlreadyTrusted)] -fun test_add_trusted_chain_already_trusted() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b"chain"); + #[test] + #[expected_failure(abort_code = EAlreadyTrusted)] + fun test_add_trusted_chain_already_trusted() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b"chain"); - self.add(chain); - self.add(chain); + self.add(chain); + self.add(chain); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -fun test_remove_trusted_chain() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b"chain"); + #[test] + fun test_remove_trusted_chain() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b"chain"); - self.add(chain); - self.remove(chain); + self.add(chain); + self.remove(chain); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EEmptyChainName)] -fun test_remove_trusted_chain_empty_chain_name() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b""); + #[test] + #[expected_failure(abort_code = EEmptyChainName)] + fun test_remove_trusted_chain_empty_chain_name() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b""); - self.remove(chain); + self.remove(chain); - sui::test_utils::destroy(self); + sui::test_utils::destroy(self); + } } diff --git a/move/interchain_token_service/sources/types/unregistered_coin_data.move b/move/interchain_token_service/sources/types/unregistered_coin_data.move index c31e7abf..e84becf4 100644 --- a/move/interchain_token_service/sources/types/unregistered_coin_data.move +++ b/move/interchain_token_service/sources/types/unregistered_coin_data.move @@ -1,31 +1,26 @@ -module interchain_token_service::unregistered_coin_data; +module interchain_token_service::unregistered_coin_data { + use sui::coin::{TreasuryCap, CoinMetadata}; -use sui::coin::{TreasuryCap, CoinMetadata}; - -// ----- -// Types -// ----- -public struct UnregisteredCoinData has store { - treasury_cap: TreasuryCap, - coin_metadata: CoinMetadata, -} + // ----- + // Types + // ----- + public struct UnregisteredCoinData has store { + treasury_cap: TreasuryCap, + coin_metadata: CoinMetadata, + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun new( - treasury_cap: TreasuryCap, - coin_metadata: CoinMetadata, -): UnregisteredCoinData { - UnregisteredCoinData { - treasury_cap, - coin_metadata, + // ----------------- + // Package Functions + // ----------------- + public(package) fun new(treasury_cap: TreasuryCap, coin_metadata: CoinMetadata): UnregisteredCoinData { + UnregisteredCoinData { + treasury_cap, + coin_metadata, + } } -} -public(package) fun destroy( - self: UnregisteredCoinData, -): (TreasuryCap, CoinMetadata) { - let UnregisteredCoinData { treasury_cap, coin_metadata } = self; - (treasury_cap, coin_metadata) + public(package) fun destroy(self: UnregisteredCoinData): (TreasuryCap, CoinMetadata) { + let UnregisteredCoinData { treasury_cap, coin_metadata } = self; + (treasury_cap, coin_metadata) + } } diff --git a/move/interchain_token_service/sources/utils.move b/move/interchain_token_service/sources/utils.move index 526d9ce0..fa7abd0c 100644 --- a/move/interchain_token_service/sources/utils.move +++ b/move/interchain_token_service/sources/utils.move @@ -1,92 +1,89 @@ -module interchain_token_service::utils; +module interchain_token_service::utils { + use std::ascii; -use std::ascii; + const LOWERCASE_START: u8 = 97; + const UPPERCASE_START: u8 = 65; + const NUMBERS_START: u8 = 48; + const SPACE: u8 = 32; + const UNDERSCORE: u8 = 95; + const ALPHABET_LENGTH: u8 = 26; + const NUMBERS_LENGTH: u8 = 10; -const LOWERCASE_START: u8 = 97; -const UPPERCASE_START: u8 = 65; -const NUMBERS_START: u8 = 48; -const SPACE: u8 = 32; -const UNDERSCORE: u8 = 95; -const ALPHABET_LENGTH: u8 = 26; -const NUMBERS_LENGTH: u8 = 10; - -entry fun is_lowercase(c: u8): bool { - c >= LOWERCASE_START && c < LOWERCASE_START + ALPHABET_LENGTH -} + entry fun is_lowercase(c: u8): bool { + c >= LOWERCASE_START && c < LOWERCASE_START + ALPHABET_LENGTH + } -entry fun is_uppercase(c: u8): bool { - c >= UPPERCASE_START && c < UPPERCASE_START + ALPHABET_LENGTH -} + entry fun is_uppercase(c: u8): bool { + c >= UPPERCASE_START && c < UPPERCASE_START + ALPHABET_LENGTH + } -entry fun is_number(c: u8): bool { - c >= NUMBERS_START && c < NUMBERS_START + NUMBERS_LENGTH -} + entry fun is_number(c: u8): bool { + c >= NUMBERS_START && c < NUMBERS_START + NUMBERS_LENGTH + } -public(package) fun module_from_symbol(symbol: &ascii::String): ascii::String { - let symbolBytes = ascii::as_bytes(symbol); - let mut moduleName = vector[]; + public(package) fun module_from_symbol(symbol: &ascii::String): ascii::String { + let symbolBytes = ascii::as_bytes(symbol); + let mut moduleName = vector[]; - let (mut i, length) = (0, vector::length(symbolBytes)); - while (is_number(*vector::borrow(symbolBytes, i))) { - i = i + 1; - }; - while (i < length) { - let b = *vector::borrow(symbolBytes, i); - if (is_lowercase(b) || is_number(b)) { - moduleName.push_back(b); - } else if (is_uppercase(b)) { - moduleName.push_back(b - UPPERCASE_START + LOWERCASE_START); - } else if (b == UNDERSCORE || b == SPACE) { - moduleName.push_back(UNDERSCORE); + let (mut i, length) = (0, vector::length(symbolBytes)); + while (is_number(*vector::borrow(symbolBytes, i))) { + i = i + 1; }; + while (i < length) { + let b = *vector::borrow(symbolBytes, i); + if (is_lowercase(b) || is_number(b)) { + moduleName.push_back(b); + } else if (is_uppercase(b)) { + moduleName.push_back(b - UPPERCASE_START + LOWERCASE_START); + } else if (b == UNDERSCORE || b == SPACE) { + moduleName.push_back(UNDERSCORE); + }; - i = i + 1; - }; - ascii::string(moduleName) -} - -public(package) fun decode_metadata( - mut metadata: vector, -): (u32, vector) { - if (metadata.length() < 4) { - (0, vector[]) - } else { - let mut i = 0; - let mut version: u32 = 0; - while (i < 4) { - version = - (version << (8 as u8) as u32) + (metadata.remove(0) as u32); i = i + 1; }; + ascii::string(moduleName) + } + + public(package) fun decode_metadata(mut metadata: vector): (u32, vector) { + if (metadata.length() < 4) { + (0, vector[]) + } else { + let mut i = 0; + let mut version: u32 = 0; + while (i < 4) { + version = (version << (8 as u8) as u32) + (metadata.remove(0) as u32); + i = i + 1; + }; - (version, metadata) + (version, metadata) + } } -} -// ----- -// Tests -// ----- -#[test] -fun test_get_module_from_symbol() { - let symbol = ascii::string(b"1(TheCool1234Coin) _ []!rdt"); - std::debug::print(&module_from_symbol(&symbol)); -} + // ----- + // Tests + // ----- + #[test] + fun test_get_module_from_symbol() { + let symbol = ascii::string(b"1(TheCool1234Coin) _ []!rdt"); + std::debug::print(&module_from_symbol(&symbol)); + } -#[test] -fun test_decode_metadata() { - let (version, metadata) = decode_metadata(x""); - assert!(version == 0); - assert!(metadata == x""); + #[test] + fun test_decode_metadata() { + let (version, metadata) = decode_metadata(x""); + assert!(version == 0); + assert!(metadata == x""); - let (version, metadata) = decode_metadata(x"012345"); - assert!(version == 0); - assert!(metadata == x""); + let (version, metadata) = decode_metadata(x"012345"); + assert!(version == 0); + assert!(metadata == x""); - let (version, metadata) = decode_metadata(x"00000004"); - assert!(version == 4); - assert!(metadata == x""); + let (version, metadata) = decode_metadata(x"00000004"); + assert!(version == 4); + assert!(metadata == x""); - let (version, metadata) = decode_metadata(x"000000071ab768cf"); - assert!(version == 7); - assert!(metadata == x"1ab768cf"); + let (version, metadata) = decode_metadata(x"000000071ab768cf"); + assert!(version == 7); + assert!(metadata == x"1ab768cf"); + } } diff --git a/move/interchain_token_service/tests/coin.move b/move/interchain_token_service/tests/coin.move index 398b155c..d225a70c 100644 --- a/move/interchain_token_service/tests/coin.move +++ b/move/interchain_token_service/tests/coin.move @@ -1,77 +1,68 @@ #[test_only] -module interchain_token_service::coin; +module interchain_token_service::coin { + use sui::{coin::{Self, CoinMetadata, TreasuryCap}, url::Url}; -use sui::coin::{Self, CoinMetadata, TreasuryCap}; -use sui::url::Url; + public struct COIN has drop {} -public struct COIN has drop {} + // ----- + // Coin creation functions. + // ----- -// ----- -// Coin creation functions. -// ----- + public fun create_treasury_and_metadata( + symbol: vector, + decimals: u8, + ctx: &mut TxContext, + ): (TreasuryCap, CoinMetadata) { + coin::create_currency( + COIN {}, + decimals, + symbol, + b"Name", + b"", + option::none(), + ctx, + ) + } -public fun create_treasury_and_metadata( - symbol: vector, - decimals: u8, - ctx: &mut TxContext, -): (TreasuryCap, CoinMetadata) { - coin::create_currency( - COIN {}, - decimals, - symbol, - b"Name", - b"", - option::none(), - ctx, - ) -} - -public fun create_treasury_and_metadata_custom( - name: vector, - symbol: vector, - decimals: u8, - url: Option, - ctx: &mut TxContext, -): (TreasuryCap, CoinMetadata) { - coin::create_currency( - COIN {}, - decimals, - symbol, - name, - b"", - url, - ctx, - ) -} + public fun create_treasury_and_metadata_custom( + name: vector, + symbol: vector, + decimals: u8, + url: Option, + ctx: &mut TxContext, + ): (TreasuryCap, CoinMetadata) { + coin::create_currency( + COIN {}, + decimals, + symbol, + name, + b"", + url, + ctx, + ) + } -public fun create_treasury( - symbol: vector, - decimals: u8, - ctx: &mut TxContext, -): TreasuryCap { - let (treasury, metadata) = create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); + public fun create_treasury(symbol: vector, decimals: u8, ctx: &mut TxContext): TreasuryCap { + let (treasury, metadata) = create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); - sui::test_utils::destroy(metadata); + sui::test_utils::destroy(metadata); - treasury -} + treasury + } -public fun create_metadata( - symbol: vector, - decimals: u8, - ctx: &mut TxContext, -): CoinMetadata { - let (treasury, metadata) = create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); + public fun create_metadata(symbol: vector, decimals: u8, ctx: &mut TxContext): CoinMetadata { + let (treasury, metadata) = create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); - sui::test_utils::destroy(treasury); + sui::test_utils::destroy(treasury); - metadata + metadata + } } diff --git a/move/interchain_token_service/tests/coin_init_test.move b/move/interchain_token_service/tests/coin_init_test.move index c1151f43..27e6bb60 100644 --- a/move/interchain_token_service/tests/coin_init_test.move +++ b/move/interchain_token_service/tests/coin_init_test.move @@ -1,29 +1,28 @@ #[test_only] -module interchain_token_service::thecool1234coin___; +module interchain_token_service::thecool1234coin___ { + use sui::{coin, url::Url}; -use sui::coin; -use sui::url::Url; + public struct THECOOL1234COIN___ has drop {} -public struct THECOOL1234COIN___ has drop {} + fun init(witness: THECOOL1234COIN___, ctx: &mut TxContext) { + let (treasury, metadata) = coin::create_currency( + witness, + 6, + b"THECOOL1234COIN___", + b"", + b"", + option::none(), + ctx, + ); + transfer::public_transfer(treasury, tx_context::sender(ctx)); + transfer::public_transfer(metadata, tx_context::sender(ctx)); + } -fun init(witness: THECOOL1234COIN___, ctx: &mut TxContext) { - let (treasury, metadata) = coin::create_currency( - witness, - 6, - b"THECOOL1234COIN___", - b"", - b"", - option::none(), - ctx, - ); - transfer::public_transfer(treasury, tx_context::sender(ctx)); - transfer::public_transfer(metadata, tx_context::sender(ctx)); -} - -#[test] -fun test_init() { - // use sui::test_scenario::{Self as ts, ctx}; - use sui::tx_context::dummy; + #[test] + fun test_init() { + // use sui::test_scenario::{Self as ts, ctx}; + use sui::tx_context::dummy; - init(THECOOL1234COIN___ {}, &mut dummy()); + init(THECOOL1234COIN___ {}, &mut dummy()); + } } diff --git a/move/operators/sources/operators.move b/move/operators/sources/operators.move index 482303f8..f777ba76 100644 --- a/move/operators/sources/operators.move +++ b/move/operators/sources/operators.move @@ -1,415 +1,384 @@ -module operators::operators; +module operators::operators { + use std::{ascii::String, type_name}; + use sui::{bag::{Self, Bag}, event, vec_set::{Self, VecSet}}; -use std::ascii::String; -use std::type_name; -use sui::bag::{Self, Bag}; -use sui::event; -use sui::vec_set::{Self, VecSet}; + // ----- + // Types + // ----- -// ----- -// Types -// ----- + /// The `OwnerCap` capability representing the owner of the contract. + public struct OwnerCap has key, store { + id: UID, + } -/// The `OwnerCap` capability representing the owner of the contract. -public struct OwnerCap has key, store { - id: UID, -} + /// The `OperatorCap` capability representing an approved operator. + public struct OperatorCap has key, store { + id: UID, + } -/// The `OperatorCap` capability representing an approved operator. -public struct OperatorCap has key, store { - id: UID, -} + /// The main `Operators` struct storing the capabilities and operator IDs. + public struct Operators has key { + id: UID, + // The number of operators are small in practice, and under the Sui object + // size limit, so a dynamic collection doesn't need to be used + operators: VecSet
, + // map-like collection of capabilities stored as Sui objects + caps: Bag, + } -/// The main `Operators` struct storing the capabilities and operator IDs. -public struct Operators has key { - id: UID, - // The number of operators are small in practice, and under the Sui object - // size limit, so a dynamic collection doesn't need to be used - operators: VecSet
, - // map-like collection of capabilities stored as Sui objects - caps: Bag, -} + public struct Borrow { + id: ID, + } -public struct Borrow { - id: ID, -} + // ------ + // Errors + // ------ -// ------ -// Errors -// ------ + /// When the operator is not found in the set of approved operators. + #[error] + const EOperatorNotFound: vector = b"the sender is not an operator"; -/// When the operator is not found in the set of approved operators. -#[error] -const EOperatorNotFound: vector = b"the sender is not an operator"; + /// When the capability is not found. + #[error] + const ECapNotFound: vector = b"the given capability id does not exist"; -/// When the capability is not found. -#[error] -const ECapNotFound: vector = b"the given capability id does not exist"; + /// When the cap trying to restore does not match the Borrow object. + #[error] + const ECapIdMismatch: vector = b"the ID of the returned capability does not match the ID in the Borrow object"; -/// When the cap trying to restore does not match the Borrow object. -#[error] -const ECapIdMismatch: vector = - b"the ID of the returned capability does not match the ID in the Borrow object"; + // ------ + // Events + // ------ -// ------ -// Events -// ------ + /// Event emitted when a new operator is added. + public struct OperatorAdded has copy, drop { + operator: address, + } -/// Event emitted when a new operator is added. -public struct OperatorAdded has copy, drop { - operator: address, -} + /// Event emitted when an operator is removed. + public struct OperatorRemoved has copy, drop { + operator: address, + } -/// Event emitted when an operator is removed. -public struct OperatorRemoved has copy, drop { - operator: address, -} + /// Event emitted when a capability is stored. + public struct CapabilityStored has copy, drop { + cap_id: ID, + cap_name: String, + } -/// Event emitted when a capability is stored. -public struct CapabilityStored has copy, drop { - cap_id: ID, - cap_name: String, -} + /// Event emitted when a capability is removed. + public struct CapabilityRemoved has copy, drop { + cap_id: ID, + cap_name: String, + } -/// Event emitted when a capability is removed. -public struct CapabilityRemoved has copy, drop { - cap_id: ID, - cap_name: String, -} + // ----- + // Setup + // ----- -// ----- -// Setup -// ----- + /// Initializes the contract and transfers the `OwnerCap` to the sender. + fun init(ctx: &mut TxContext) { + transfer::share_object(Operators { + id: object::new(ctx), + operators: vec_set::empty(), + caps: bag::new(ctx), + }); -/// Initializes the contract and transfers the `OwnerCap` to the sender. -fun init(ctx: &mut TxContext) { - transfer::share_object(Operators { - id: object::new(ctx), - operators: vec_set::empty(), - caps: bag::new(ctx), - }); + let cap = OwnerCap { + id: object::new(ctx), + }; - let cap = OwnerCap { - id: object::new(ctx), - }; + transfer::transfer(cap, ctx.sender()); + } - transfer::transfer(cap, ctx.sender()); -} + // ---------------- + // Public Functions + // ---------------- -// ---------------- -// Public Functions -// ---------------- - -/// Adds a new operator by issuing an `OperatorCap` and storing its ID. -public fun add_operator( - self: &mut Operators, - _: &OwnerCap, - new_operator: address, - ctx: &mut TxContext, -) { - let operator_cap = OperatorCap { - id: object::new(ctx), - }; - - transfer::transfer(operator_cap, new_operator); - self.operators.insert(new_operator); - - event::emit(OperatorAdded { - operator: new_operator, - }); -} + /// Adds a new operator by issuing an `OperatorCap` and storing its ID. + public fun add_operator(self: &mut Operators, _: &OwnerCap, new_operator: address, ctx: &mut TxContext) { + let operator_cap = OperatorCap { + id: object::new(ctx), + }; -/// Removes an operator by ID, revoking their `OperatorCap`. -public fun remove_operator( - self: &mut Operators, - _: &OwnerCap, - operator: address, -) { - self.operators.remove(&operator); - - event::emit(OperatorRemoved { - operator, - }); -} + transfer::transfer(operator_cap, new_operator); + self.operators.insert(new_operator); -/// Stores a capability in the `Operators` struct. -public fun store_cap( - self: &mut Operators, - _: &OwnerCap, - cap: T, -) { - let cap_id = object::id(&cap); - self.caps.add(cap_id, cap); - - event::emit(CapabilityStored { - cap_id, - cap_name: type_name::get().into_string(), - }); -} + event::emit(OperatorAdded { + operator: new_operator, + }); + } -/// Allows an approved operator to temporarily loan out a capability by its ID. -/// The loaned capability must be restored by the end of the transaction. -public fun loan_cap( - self: &mut Operators, - _operator_cap: &OperatorCap, - cap_id: ID, - ctx: &mut TxContext, -): (T, Borrow) { - assert!(self.operators.contains(&ctx.sender()), EOperatorNotFound); - assert!(self.caps.contains(cap_id), ECapNotFound); - - // Remove the capability from the `Operators` struct to loan it out - let cap = self.caps.remove(cap_id); - - // Create the Borrow object which tracks the id of the cap loaned. - let borrow_obj = Borrow { - id: object::id(&cap), - }; - - // Return a tuple of the borrowed capability and the Borrow hot potato - // object - (cap, borrow_obj) -} + /// Removes an operator by ID, revoking their `OperatorCap`. + public fun remove_operator(self: &mut Operators, _: &OwnerCap, operator: address) { + self.operators.remove(&operator); -/// Restores a previously loaned capability back to the `Operators` struct. -/// This function must be called before the end of the transaction to return the -/// loaned capability. -public fun restore_cap( - self: &mut Operators, - _operator_cap: &OperatorCap, - cap: T, - borrow_obj: Borrow, -) { - let cap_id = object::id(&cap); - - // Destroy the Borrow object and capture the id it tracks. - let Borrow { id } = borrow_obj; - - // Make sure the Borrow object corresponds to cap returned. - assert!(id == cap_id, ECapIdMismatch); - - // Add the capability back to the `Operators` struct - self.caps.add(cap_id, cap); -} + event::emit(OperatorRemoved { + operator, + }); + } -/// Removes a capability from the `Operators` struct. -public fun remove_cap( - self: &mut Operators, - _: &OwnerCap, - cap_id: ID, -): T { - event::emit(CapabilityRemoved { - cap_id, - cap_name: type_name::get().into_string(), - }); - - self.caps.remove(cap_id) -} + /// Stores a capability in the `Operators` struct. + public fun store_cap(self: &mut Operators, _: &OwnerCap, cap: T) { + let cap_id = object::id(&cap); + self.caps.add(cap_id, cap); + + event::emit(CapabilityStored { + cap_id, + cap_name: type_name::get().into_string(), + }); + } -// ----- -// Tests -// ----- + /// Allows an approved operator to temporarily loan out a capability by its ID. + /// The loaned capability must be restored by the end of the transaction. + public fun loan_cap(self: &mut Operators, _operator_cap: &OperatorCap, cap_id: ID, ctx: &mut TxContext): (T, Borrow) { + assert!(self.operators.contains(&ctx.sender()), EOperatorNotFound); + assert!(self.caps.contains(cap_id), ECapNotFound); -#[test_only] -fun new_operators(ctx: &mut TxContext): Operators { - Operators { - id: object::new(ctx), - operators: vec_set::empty(), - caps: bag::new(ctx), + // Remove the capability from the `Operators` struct to loan it out + let cap = self.caps.remove(cap_id); + + // Create the Borrow object which tracks the id of the cap loaned. + let borrow_obj = Borrow { + id: object::id(&cap), + }; + + // Return a tuple of the borrowed capability and the Borrow hot potato + // object + (cap, borrow_obj) } -} -#[test_only] -fun destroy_operators(operators: Operators) { - let Operators { id, operators, caps } = operators; + /// Restores a previously loaned capability back to the `Operators` struct. + /// This function must be called before the end of the transaction to return the + /// loaned capability. + public fun restore_cap(self: &mut Operators, _operator_cap: &OperatorCap, cap: T, borrow_obj: Borrow) { + let cap_id = object::id(&cap); - id.delete(); - caps.destroy_empty(); + // Destroy the Borrow object and capture the id it tracks. + let Borrow { id } = borrow_obj; - let mut keys = operators.into_keys(); + // Make sure the Borrow object corresponds to cap returned. + assert!(id == cap_id, ECapIdMismatch); - while (!keys.is_empty()) { - keys.pop_back(); - }; + // Add the capability back to the `Operators` struct + self.caps.add(cap_id, cap); + } - keys.destroy_empty(); -} + /// Removes a capability from the `Operators` struct. + public fun remove_cap(self: &mut Operators, _: &OwnerCap, cap_id: ID): T { + event::emit(CapabilityRemoved { + cap_id, + cap_name: type_name::get().into_string(), + }); -#[test_only] -fun new_owner_cap(ctx: &mut TxContext): OwnerCap { - OwnerCap { - id: object::new(ctx), + self.caps.remove(cap_id) } -} -#[test_only] -fun destroy_owner_cap(owner_cap: OwnerCap) { - let OwnerCap { id } = owner_cap; - object::delete(id); -} + // ----- + // Tests + // ----- + + #[test_only] + fun new_operators(ctx: &mut TxContext): Operators { + Operators { + id: object::new(ctx), + operators: vec_set::empty(), + caps: bag::new(ctx), + } + } -#[test_only] -fun new_operator_cap(self: &mut Operators, ctx: &mut TxContext): OperatorCap { - let operator_cap = OperatorCap { - id: object::new(ctx), - }; + #[test_only] + fun destroy_operators(operators: Operators) { + let Operators { id, operators, caps } = operators; - self.operators.insert(ctx.sender()); - operator_cap -} + id.delete(); + caps.destroy_empty(); -#[test_only] -fun destroy_operator_cap(operator_cap: OperatorCap) { - let OperatorCap { id } = operator_cap; - object::delete(id); -} + let mut keys = operators.into_keys(); -#[test] -fun test_init() { - let ctx = &mut tx_context::dummy(); - init(ctx); + while (!keys.is_empty()) { + keys.pop_back(); + }; - let owner_cap = new_owner_cap(ctx); - destroy_owner_cap(owner_cap); -} + keys.destroy_empty(); + } -#[test] -fun test_add_and_remove_operator() { - let ctx = &mut tx_context::dummy(); - let mut operators = new_operators(ctx); - let owner_cap = new_owner_cap(ctx); + #[test_only] + fun new_owner_cap(ctx: &mut TxContext): OwnerCap { + OwnerCap { + id: object::new(ctx), + } + } - let new_operator = @0x1; - add_operator(&mut operators, &owner_cap, new_operator, ctx); - assert!(operators.operators.size() == 1); + #[test_only] + fun destroy_owner_cap(owner_cap: OwnerCap) { + let OwnerCap { id } = owner_cap; + object::delete(id); + } - let operator_id = operators.operators.keys()[0]; - remove_operator(&mut operators, &owner_cap, operator_id); - assert!(operators.operators.is_empty()); + #[test_only] + fun new_operator_cap(self: &mut Operators, ctx: &mut TxContext): OperatorCap { + let operator_cap = OperatorCap { + id: object::new(ctx), + }; - destroy_owner_cap(owner_cap); - destroy_operators(operators); -} + self.operators.insert(ctx.sender()); + operator_cap + } -#[test] -fun test_store_and_remove_cap() { - let ctx = &mut tx_context::dummy(); - let mut operators = new_operators(ctx); - let owner_cap = new_owner_cap(ctx); - let operator_cap = new_operator_cap(&mut operators, ctx); - let external_cap = new_owner_cap(ctx); - - let external_id = object::id(&external_cap); - - store_cap(&mut operators, &owner_cap, external_cap); - assert!(operators.caps.contains(external_id)); - - let (cap, loaned_cap) = loan_cap( - &mut operators, - &operator_cap, - external_id, - ctx, - ); - assert!(!operators.caps.contains(external_id)); - restore_cap(&mut operators, &operator_cap, cap, loaned_cap); - assert!(operators.caps.contains(external_id)); - - let removed_cap = remove_cap( - &mut operators, - &owner_cap, - external_id, - ); - assert!(!operators.caps.contains(external_id)); - - destroy_operator_cap(operator_cap); - destroy_owner_cap(owner_cap); - destroy_owner_cap(removed_cap); - destroy_operators(operators); -} + #[test_only] + fun destroy_operator_cap(operator_cap: OperatorCap) { + let OperatorCap { id } = operator_cap; + object::delete(id); + } -#[test] -#[expected_failure(abort_code = vec_set::EKeyDoesNotExist)] -fun test_remove_operator_fail() { - let ctx = &mut tx_context::dummy(); - let mut operators = new_operators(ctx); - let owner_cap = new_owner_cap(ctx); + #[test] + fun test_init() { + let ctx = &mut tx_context::dummy(); + init(ctx); - remove_operator(&mut operators, &owner_cap, ctx.sender()); + let owner_cap = new_owner_cap(ctx); + destroy_owner_cap(owner_cap); + } - destroy_owner_cap(owner_cap); - destroy_operators(operators); -} + #[test] + fun test_add_and_remove_operator() { + let ctx = &mut tx_context::dummy(); + let mut operators = new_operators(ctx); + let owner_cap = new_owner_cap(ctx); -#[test] -#[expected_failure(abort_code = EOperatorNotFound)] -fun test_borrow_cap_not_operator() { - let ctx = &mut tx_context::dummy(); - let mut operators = new_operators(ctx); - let owner_cap = new_owner_cap(ctx); - let operator_cap = new_operator_cap(&mut operators, ctx); - let external_cap = new_owner_cap(ctx); - - let external_id = object::id(&external_cap); - - store_cap(&mut operators, &owner_cap, external_cap); - remove_operator(&mut operators, &owner_cap, ctx.sender()); - - let (cap, loaned_cap) = loan_cap( - &mut operators, - &operator_cap, - external_id, - ctx, - ); - restore_cap(&mut operators, &operator_cap, cap, loaned_cap); - - destroy_operator_cap(operator_cap); - destroy_owner_cap(owner_cap); - destroy_operators(operators); -} + let new_operator = @0x1; + add_operator(&mut operators, &owner_cap, new_operator, ctx); + assert!(operators.operators.size() == 1); -#[test] -#[expected_failure(abort_code = ECapNotFound)] -fun test_borrow_cap_no_such_cap() { - let ctx = &mut tx_context::dummy(); - let mut operators = new_operators(ctx); - let owner_cap = new_owner_cap(ctx); - let operator_cap = new_operator_cap(&mut operators, ctx); - - let operator_id = object::id(&operator_cap); - - let (cap, loaned_cap) = loan_cap( - &mut operators, - &operator_cap, - operator_id, - ctx, - ); - restore_cap(&mut operators, &operator_cap, cap, loaned_cap); - - destroy_operator_cap(operator_cap); - destroy_owner_cap(owner_cap); - destroy_operators(operators); -} + let operator_id = operators.operators.keys()[0]; + remove_operator(&mut operators, &owner_cap, operator_id); + assert!(operators.operators.is_empty()); + + destroy_owner_cap(owner_cap); + destroy_operators(operators); + } + + #[test] + fun test_store_and_remove_cap() { + let ctx = &mut tx_context::dummy(); + let mut operators = new_operators(ctx); + let owner_cap = new_owner_cap(ctx); + let operator_cap = new_operator_cap(&mut operators, ctx); + let external_cap = new_owner_cap(ctx); + + let external_id = object::id(&external_cap); + + store_cap(&mut operators, &owner_cap, external_cap); + assert!(operators.caps.contains(external_id)); + + let (cap, loaned_cap) = loan_cap( + &mut operators, + &operator_cap, + external_id, + ctx, + ); + assert!(!operators.caps.contains(external_id)); + restore_cap(&mut operators, &operator_cap, cap, loaned_cap); + assert!(operators.caps.contains(external_id)); + + let removed_cap = remove_cap( + &mut operators, + &owner_cap, + external_id, + ); + assert!(!operators.caps.contains(external_id)); + + destroy_operator_cap(operator_cap); + destroy_owner_cap(owner_cap); + destroy_owner_cap(removed_cap); + destroy_operators(operators); + } + + #[test] + #[expected_failure(abort_code = vec_set::EKeyDoesNotExist)] + fun test_remove_operator_fail() { + let ctx = &mut tx_context::dummy(); + let mut operators = new_operators(ctx); + let owner_cap = new_owner_cap(ctx); + + remove_operator(&mut operators, &owner_cap, ctx.sender()); -#[test] -#[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] -fun test_remove_cap_fail() { - let ctx = &mut tx_context::dummy(); - let mut operators = new_operators(ctx); - let owner_cap = new_owner_cap(ctx); - let operator_cap = new_operator_cap(&mut operators, ctx); - let external_cap = new_owner_cap(ctx); - - let external_id = object::id(&external_cap); - - let removed_cap = remove_cap( - &mut operators, - &owner_cap, - external_id, - ); - - destroy_operator_cap(operator_cap); - destroy_owner_cap(owner_cap); - destroy_owner_cap(external_cap); - destroy_owner_cap(removed_cap); - destroy_operators(operators); + destroy_owner_cap(owner_cap); + destroy_operators(operators); + } + + #[test] + #[expected_failure(abort_code = EOperatorNotFound)] + fun test_borrow_cap_not_operator() { + let ctx = &mut tx_context::dummy(); + let mut operators = new_operators(ctx); + let owner_cap = new_owner_cap(ctx); + let operator_cap = new_operator_cap(&mut operators, ctx); + let external_cap = new_owner_cap(ctx); + + let external_id = object::id(&external_cap); + + store_cap(&mut operators, &owner_cap, external_cap); + remove_operator(&mut operators, &owner_cap, ctx.sender()); + + let (cap, loaned_cap) = loan_cap( + &mut operators, + &operator_cap, + external_id, + ctx, + ); + restore_cap(&mut operators, &operator_cap, cap, loaned_cap); + + destroy_operator_cap(operator_cap); + destroy_owner_cap(owner_cap); + destroy_operators(operators); + } + + #[test] + #[expected_failure(abort_code = ECapNotFound)] + fun test_borrow_cap_no_such_cap() { + let ctx = &mut tx_context::dummy(); + let mut operators = new_operators(ctx); + let owner_cap = new_owner_cap(ctx); + let operator_cap = new_operator_cap(&mut operators, ctx); + + let operator_id = object::id(&operator_cap); + + let (cap, loaned_cap) = loan_cap( + &mut operators, + &operator_cap, + operator_id, + ctx, + ); + restore_cap(&mut operators, &operator_cap, cap, loaned_cap); + + destroy_operator_cap(operator_cap); + destroy_owner_cap(owner_cap); + destroy_operators(operators); + } + + #[test] + #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + fun test_remove_cap_fail() { + let ctx = &mut tx_context::dummy(); + let mut operators = new_operators(ctx); + let owner_cap = new_owner_cap(ctx); + let operator_cap = new_operator_cap(&mut operators, ctx); + let external_cap = new_owner_cap(ctx); + + let external_id = object::id(&external_cap); + + let removed_cap = remove_cap( + &mut operators, + &owner_cap, + external_id, + ); + + destroy_operator_cap(operator_cap); + destroy_owner_cap(owner_cap); + destroy_owner_cap(external_cap); + destroy_owner_cap(removed_cap); + destroy_operators(operators); + } } diff --git a/move/relayer_discovery/sources/discovery.move b/move/relayer_discovery/sources/discovery.move index c86789a9..b36eecb6 100644 --- a/move/relayer_discovery/sources/discovery.move +++ b/move/relayer_discovery/sources/discovery.move @@ -4,222 +4,191 @@ /// Warning: this solution does allow for any transaction to be executed and /// should be treated as a reference and a temporary solution until there's a /// proper discovery / execution mechanism in place. -module relayer_discovery::discovery; - -use axelar_gateway::channel::Channel; -use relayer_discovery::owner_cap::{Self, OwnerCap}; -use relayer_discovery::relayer_discovery_v0::{Self, RelayerDiscovery_v0}; -use relayer_discovery::transaction::Transaction; -use std::ascii::{Self, String}; -use sui::versioned::{Self, Versioned}; -use version_control::version_control::{Self, VersionControl}; - -/// ------- -/// Version -/// ------- -/// This is the version of the package that should change every package upgrade. -const VERSION: u64 = 0; -/// This is the version of the data that should change when we need to migrate -/// `Versioned` type (e.g. from `RelayerDiscovery_v0` to `RelayerDiscovery_v1`) -const DATA_VERSION: u64 = 0; - -/// ------- -/// Structs -/// ------- -public struct RelayerDiscovery has key { - id: UID, - inner: Versioned, -} +module relayer_discovery::discovery { + use axelar_gateway::channel::Channel; + use relayer_discovery::{owner_cap::{Self, OwnerCap}, relayer_discovery_v0::{Self, RelayerDiscovery_v0}, transaction::Transaction}; + use std::ascii::{Self, String}; + use sui::versioned::{Self, Versioned}; + use version_control::version_control::{Self, VersionControl}; + + /// ------- + /// Version + /// ------- + /// This is the version of the package that should change every package upgrade. + const VERSION: u64 = 0; + /// This is the version of the data that should change when we need to migrate + /// `Versioned` type (e.g. from `RelayerDiscovery_v0` to `RelayerDiscovery_v1`) + const DATA_VERSION: u64 = 0; + + /// ------- + /// Structs + /// ------- + public struct RelayerDiscovery has key { + id: UID, + inner: Versioned, + } -fun init(ctx: &mut TxContext) { - let inner = versioned::create( - DATA_VERSION, - relayer_discovery_v0::new( - version_control(), + fun init(ctx: &mut TxContext) { + let inner = versioned::create( + DATA_VERSION, + relayer_discovery_v0::new( + version_control(), + ctx, + ), ctx, - ), - ctx, - ); - transfer::share_object(RelayerDiscovery { - id: object::new(ctx), - inner, - }); - transfer::public_transfer(owner_cap::create(ctx), ctx.sender()); -} - -/// ------ -/// Macros -/// ------ -macro fun value( - $self: &RelayerDiscovery, - $function_name: vector, -): &RelayerDiscovery_v0 { - let relayer_discovery = $self; - let value = relayer_discovery.inner.load_value(); - value.version_control().check(VERSION, ascii::string($function_name)); - value -} + ); + transfer::share_object(RelayerDiscovery { + id: object::new(ctx), + inner, + }); + transfer::public_transfer(owner_cap::create(ctx), ctx.sender()); + } -macro fun value_mut( - $self: &mut RelayerDiscovery, - $function_name: vector, -): &mut RelayerDiscovery_v0 { - let relayer_discovery = $self; - let value = relayer_discovery.inner.load_value_mut(); - value.version_control().check(VERSION, ascii::string($function_name)); - value -} + /// ------ + /// Macros + /// ------ + macro fun value($self: &RelayerDiscovery, $function_name: vector): &RelayerDiscovery_v0 { + let relayer_discovery = $self; + let value = relayer_discovery.inner.load_value(); + value.version_control().check(VERSION, ascii::string($function_name)); + value + } -// --------------- -// Entry Functions -// --------------- -entry fun allow_function( - self: &mut RelayerDiscovery, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self.value_mut!(b"allow_function").allow_function(version, function_name); -} + macro fun value_mut($self: &mut RelayerDiscovery, $function_name: vector): &mut RelayerDiscovery_v0 { + let relayer_discovery = $self; + let value = relayer_discovery.inner.load_value_mut(); + value.version_control().check(VERSION, ascii::string($function_name)); + value + } -entry fun disallow_function( - self: &mut RelayerDiscovery, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self - .value_mut!(b"disallow_function") - .disallow_function(version, function_name); -} + // --------------- + // Entry Functions + // --------------- + entry fun allow_function(self: &mut RelayerDiscovery, _: &OwnerCap, version: u64, function_name: String) { + self.value_mut!(b"allow_function").allow_function(version, function_name); + } -// ---------------- -// Public Functions -// ---------------- -/// During the creation of the object, the UID should be passed here to -/// receive the Channel and emit an event which will be handled by the -/// Relayer. -/// -/// Example: -/// ``` -/// let id = object::new(ctx); -/// let channel = discovery::create_configuration( -/// relayer_discovery, &id, contents, ctx -/// ); -/// let wrapper = ExampleWrapper { id, channel }; -/// transfer::share_object(wrapper); -/// ``` -/// -/// Note: Wrapper must be a shared object so that Relayer can access it. -public fun register_transaction( - self: &mut RelayerDiscovery, - channel: &Channel, - tx: Transaction, -) { - let value = self.value_mut!(b"register_transaction"); - let channel_id = channel.id(); - value.set_transaction(channel_id, tx); -} + entry fun disallow_function(self: &mut RelayerDiscovery, _: &OwnerCap, version: u64, function_name: String) { + self.value_mut!(b"disallow_function").disallow_function(version, function_name); + } -public fun remove_transaction(self: &mut RelayerDiscovery, channel: &Channel) { - let value = self.value_mut!(b"remove_transaction"); - let channel_id = channel.id(); - value.remove_transaction(channel_id); -} + // ---------------- + // Public Functions + // ---------------- + /// During the creation of the object, the UID should be passed here to + /// receive the Channel and emit an event which will be handled by the + /// Relayer. + /// + /// Example: + /// ``` + /// let id = object::new(ctx); + /// let channel = discovery::create_configuration( + /// relayer_discovery, &id, contents, ctx + /// ); + /// let wrapper = ExampleWrapper { id, channel }; + /// transfer::share_object(wrapper); + /// ``` + /// + /// Note: Wrapper must be a shared object so that Relayer can access it. + public fun register_transaction(self: &mut RelayerDiscovery, channel: &Channel, tx: Transaction) { + let value = self.value_mut!(b"register_transaction"); + let channel_id = channel.id(); + value.set_transaction(channel_id, tx); + } -/// Get a transaction for a specific channel by the channel `ID`. -public fun get_transaction( - self: &RelayerDiscovery, - channel_id: ID, -): Transaction { - let value = self.value!(b"register_transaction"); - value.get_transaction(channel_id) -} + public fun remove_transaction(self: &mut RelayerDiscovery, channel: &Channel) { + let value = self.value_mut!(b"remove_transaction"); + let channel_id = channel.id(); + value.remove_transaction(channel_id); + } -/// ----------------- -/// Private Functions -/// ----------------- -fun version_control(): VersionControl { - version_control::new(vector[ - // version 0 - vector[ - b"register_transaction", - b"remove_transaction", - b"get_transaction", - b"allow_function", - b"disallow_function", - ].map!(|function_name| function_name.to_ascii_string()), - ]) -} + /// Get a transaction for a specific channel by the channel `ID`. + public fun get_transaction(self: &RelayerDiscovery, channel_id: ID): Transaction { + let value = self.value!(b"register_transaction"); + value.get_transaction(channel_id) + } -#[test_only] -use relayer_discovery::transaction; + /// ----------------- + /// Private Functions + /// ----------------- + fun version_control(): VersionControl { + version_control::new(vector[ + // version 0 + vector[b"register_transaction", b"remove_transaction", b"get_transaction", b"allow_function", b"disallow_function"].map!( + |function_name| function_name.to_ascii_string(), + ), + ]) + } -#[test_only] -public fun new(ctx: &mut TxContext): RelayerDiscovery { - RelayerDiscovery { - id: object::new(ctx), - inner: versioned::create( - VERSION, - relayer_discovery_v0::new(version_control(), ctx), - ctx, - ), + #[test_only] + use relayer_discovery::transaction; + + #[test_only] + public fun new(ctx: &mut TxContext): RelayerDiscovery { + RelayerDiscovery { + id: object::new(ctx), + inner: versioned::create( + VERSION, + relayer_discovery_v0::new(version_control(), ctx), + ctx, + ), + } } -} -#[test] -fun test_register_and_get() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let channel = axelar_gateway::channel::new(ctx); - - let move_call = transaction::new_move_call( - transaction::new_function( - @0x1234, - std::ascii::string(b"module"), - std::ascii::string(b"function"), - ), - vector::empty>(), - vector::empty(), - ); - let input_transaction = transaction::new_transaction( - true, - vector[move_call], - ); - - self.register_transaction(&channel, input_transaction); - - let transaction = self.get_transaction(channel.id()); - assert!(transaction == input_transaction); - - sui::test_utils::destroy(self); - sui::test_utils::destroy(channel); -} + #[test] + fun test_register_and_get() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let channel = axelar_gateway::channel::new(ctx); + + let move_call = transaction::new_move_call( + transaction::new_function( + @0x1234, + std::ascii::string(b"module"), + std::ascii::string(b"function"), + ), + vector::empty>(), + vector::empty(), + ); + let input_transaction = transaction::new_transaction( + true, + vector[move_call], + ); + + self.register_transaction(&channel, input_transaction); + + let transaction = self.get_transaction(channel.id()); + assert!(transaction == input_transaction); + + sui::test_utils::destroy(self); + sui::test_utils::destroy(channel); + } -#[test] -fun test_allow_function() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let owner_cap = owner_cap::create(ctx); - let version = 0; - let function_name = b"function_name".to_ascii_string(); + #[test] + fun test_allow_function() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let owner_cap = owner_cap::create(ctx); + let version = 0; + let function_name = b"function_name".to_ascii_string(); - self.allow_function(&owner_cap, version, function_name); + self.allow_function(&owner_cap, version, function_name); - sui::test_utils::destroy(self); - owner_cap.destroy_for_testing(); -} + sui::test_utils::destroy(self); + owner_cap.destroy_for_testing(); + } -#[test] -fun test_disallow_function() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let owner_cap = owner_cap::create(ctx); - let version = 0; - let function_name = b"register_transaction".to_ascii_string(); + #[test] + fun test_disallow_function() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let owner_cap = owner_cap::create(ctx); + let version = 0; + let function_name = b"register_transaction".to_ascii_string(); - self.disallow_function(&owner_cap, version, function_name); + self.disallow_function(&owner_cap, version, function_name); - sui::test_utils::destroy(self); - owner_cap.destroy_for_testing(); + sui::test_utils::destroy(self); + owner_cap.destroy_for_testing(); + } } diff --git a/move/relayer_discovery/sources/events.move b/move/relayer_discovery/sources/events.move index bc85ebe1..08a59032 100644 --- a/move/relayer_discovery/sources/events.move +++ b/move/relayer_discovery/sources/events.move @@ -1,37 +1,34 @@ -module relayer_discovery::events; +module relayer_discovery::events { + use relayer_discovery::transaction::Transaction; + use sui::event; -use relayer_discovery::transaction::Transaction; -use sui::event; + /// ------ + /// Events + /// ------ + // Emitted when a transaction is registered + public struct TransactionRegistered has copy, drop { + channel_id: ID, + transaction: Transaction, + } -/// ------ -/// Events -/// ------ -// Emitted when a transaction is registered -public struct TransactionRegistered has copy, drop { - channel_id: ID, - transaction: Transaction, -} - -// Emitted when a transaction is removed -public struct TransactionRemoved has copy, drop { - channel_id: ID, -} + // Emitted when a transaction is removed + public struct TransactionRemoved has copy, drop { + channel_id: ID, + } -/// ----------------- -/// Package Functions -/// ----------------- -public(package) fun transaction_registered( - channel_id: ID, - transaction: Transaction, -) { - event::emit(TransactionRegistered { - channel_id, - transaction, - }) -} + /// ----------------- + /// Package Functions + /// ----------------- + public(package) fun transaction_registered(channel_id: ID, transaction: Transaction) { + event::emit(TransactionRegistered { + channel_id, + transaction, + }) + } -public(package) fun transaction_removed(channel_id: ID) { - event::emit(TransactionRemoved { - channel_id, - }) + public(package) fun transaction_removed(channel_id: ID) { + event::emit(TransactionRemoved { + channel_id, + }) + } } diff --git a/move/relayer_discovery/sources/types/owner_cap.move b/move/relayer_discovery/sources/types/owner_cap.move index c6a53c9f..a87fd096 100644 --- a/move/relayer_discovery/sources/types/owner_cap.move +++ b/move/relayer_discovery/sources/types/owner_cap.move @@ -1,23 +1,23 @@ -module relayer_discovery::owner_cap; - -// ----- -// Types -// ----- -public struct OwnerCap has key, store { - id: UID, -} +module relayer_discovery::owner_cap { + // ----- + // Types + // ----- + public struct OwnerCap has key, store { + id: UID, + } -public(package) fun create(ctx: &mut TxContext): OwnerCap { - OwnerCap { - id: object::new(ctx), + public(package) fun create(ctx: &mut TxContext): OwnerCap { + OwnerCap { + id: object::new(ctx), + } } -} -/// --------- -/// Test Only -/// --------- -#[test_only] -public(package) fun destroy_for_testing(self: OwnerCap) { - let OwnerCap { id } = self; - id.delete(); + /// --------- + /// Test Only + /// --------- + #[test_only] + public(package) fun destroy_for_testing(self: OwnerCap) { + let OwnerCap { id } = self; + id.delete(); + } } diff --git a/move/relayer_discovery/sources/types/transaction.move b/move/relayer_discovery/sources/types/transaction.move index cdef88f8..fbf7a091 100644 --- a/move/relayer_discovery/sources/types/transaction.move +++ b/move/relayer_discovery/sources/types/transaction.move @@ -1,266 +1,205 @@ -module relayer_discovery::transaction; - -use std::ascii::{Self, String}; -use std::type_name; -use sui::address; -use sui::bcs::{Self, BCS}; -use sui::hex; - -/// ------ -/// Errors -/// ------ -#[error] -const EInvalidString: vector = b"Type argument was not a valid string"; - -/// ------- -/// Structs -/// ------- -public struct Function has store, copy, drop { - package_id: address, - module_name: String, - name: String, -} +module relayer_discovery::transaction { + use std::{ascii::{Self, String}, type_name}; + use sui::{address, bcs::{Self, BCS}, hex}; + + /// ------ + /// Errors + /// ------ + #[error] + const EInvalidString: vector = b"Type argument was not a valid string"; + + /// ------- + /// Structs + /// ------- + public struct Function has copy, drop, store { + package_id: address, + module_name: String, + name: String, + } -/// Arguments are prefixed with: -/// - 0 for objects followed by exactly 32 bytes that contain the object id -/// - 1 for pure types followed by the bcs encoded form of the pure value -/// - 2 for the ApprovedMessage object, followed by nothing (to be passed into -/// the target function) -/// - 3 for the payload of the contract call (to be passed into the intermediate -/// function) -/// - 4 for an argument returned from a previous move call, followed by a u8 -/// specified which call to get the return of (0 for the first transaction AFTER -/// the one that gets ApprovedMessage out), and then another u8 specifying which -/// argument to input. -/// Following are some example arguments: -/// ``` -/// 0x06: &mut Clock = 0x0006, -/// 0x810a8b960cf54ceb7ce5b796d25fc2207017785bbc952562d1e4d10f2a4b8836: &mut -/// Singleton = -/// 0x00810a8b960cf54ceb7ce5b796d25fc2207017785bbc952562d1e4d10f2a4b8836, -/// 30: u64 = 0x011e00000000000000, -/// "Name": ascii::String = 0x01044e616d65, -/// approved_call: ApprovedMessage = 0x02, -/// payload: vector = 0x03 -/// previous_return: Return (returned as the second argument of the first call) -/// = 0x40001, -/// ``` -public struct MoveCall has store, copy, drop { - function: Function, - arguments: vector>, - type_arguments: vector, -} + /// Arguments are prefixed with: + /// - 0 for objects followed by exactly 32 bytes that contain the object id + /// - 1 for pure types followed by the bcs encoded form of the pure value + /// - 2 for the ApprovedMessage object, followed by nothing (to be passed into + /// the target function) + /// - 3 for the payload of the contract call (to be passed into the intermediate + /// function) + /// - 4 for an argument returned from a previous move call, followed by a u8 + /// specified which call to get the return of (0 for the first transaction AFTER + /// the one that gets ApprovedMessage out), and then another u8 specifying which + /// argument to input. + /// Following are some example arguments: + /// ``` + /// 0x06: &mut Clock = 0x0006, + /// 0x810a8b960cf54ceb7ce5b796d25fc2207017785bbc952562d1e4d10f2a4b8836: &mut + /// Singleton = + /// 0x00810a8b960cf54ceb7ce5b796d25fc2207017785bbc952562d1e4d10f2a4b8836, + /// 30: u64 = 0x011e00000000000000, + /// "Name": ascii::String = 0x01044e616d65, + /// approved_call: ApprovedMessage = 0x02, + /// payload: vector = 0x03 + /// previous_return: Return (returned as the second argument of the first call) + /// = 0x40001, + /// ``` + public struct MoveCall has copy, drop, store { + function: Function, + arguments: vector>, + type_arguments: vector, + } -public struct Transaction has store, copy, drop { - is_final: bool, - move_calls: vector, -} + public struct Transaction has copy, drop, store { + is_final: bool, + move_calls: vector, + } -/// ---------------- -/// Public Functions -/// ---------------- -public fun new_function( - package_id: address, - module_name: String, - name: String, -): Function { - Function { - package_id, - module_name, - name, + /// ---------------- + /// Public Functions + /// ---------------- + public fun new_function(package_id: address, module_name: String, name: String): Function { + Function { + package_id, + module_name, + name, + } } -} -public fun new_function_from_bcs(bcs: &mut BCS): Function { - Function { - package_id: bcs::peel_address(bcs), - module_name: ascii::string(bcs::peel_vec_u8(bcs)), - name: ascii::string(bcs::peel_vec_u8(bcs)), + public fun new_function_from_bcs(bcs: &mut BCS): Function { + Function { + package_id: bcs::peel_address(bcs), + module_name: ascii::string(bcs::peel_vec_u8(bcs)), + name: ascii::string(bcs::peel_vec_u8(bcs)), + } } -} -public fun new_move_call( - function: Function, - arguments: vector>, - type_arguments: vector, -): MoveCall { - MoveCall { - function, - arguments, - type_arguments, + public fun new_move_call(function: Function, arguments: vector>, type_arguments: vector): MoveCall { + MoveCall { + function, + arguments, + type_arguments, + } } -} -public fun new_move_call_from_bcs(bcs: &mut BCS): MoveCall { - MoveCall { - function: new_function_from_bcs(bcs), - arguments: bcs.peel_vec_vec_u8(), - type_arguments: vector::tabulate!( - bcs.peel_vec_length(), - |_| peel_type(bcs), - ), + public fun new_move_call_from_bcs(bcs: &mut BCS): MoveCall { + MoveCall { + function: new_function_from_bcs(bcs), + arguments: bcs.peel_vec_vec_u8(), + type_arguments: vector::tabulate!(bcs.peel_vec_length(), |_| peel_type(bcs)), + } } -} -public fun new_transaction( - is_final: bool, - move_calls: vector, -): Transaction { - Transaction { - is_final, - move_calls, + public fun new_transaction(is_final: bool, move_calls: vector): Transaction { + Transaction { + is_final, + move_calls, + } } -} -public fun new_transaction_from_bcs(bcs: &mut BCS): Transaction { - Transaction { - is_final: bcs.peel_bool(), - move_calls: vector::tabulate!( - bcs.peel_vec_length(), - |_| new_move_call_from_bcs(bcs), - ), + public fun new_transaction_from_bcs(bcs: &mut BCS): Transaction { + Transaction { + is_final: bcs.peel_bool(), + move_calls: vector::tabulate!(bcs.peel_vec_length(), |_| new_move_call_from_bcs(bcs)), + } } -} -/// Helper function which returns the package id of a type. -public fun package_id(): address { - address::from_bytes( - hex::decode( - *ascii::as_bytes( - &type_name::get_address(&type_name::get()), + /// Helper function which returns the package id of a type. + public fun package_id(): address { + address::from_bytes( + hex::decode( + *ascii::as_bytes( + &type_name::get_address(&type_name::get()), + ), ), - ), - ) -} - -fun peel_type(bcs: &mut BCS): ascii::String { - let mut type_argument = ascii::try_string(bcs.peel_vec_u8()); - assert!(type_argument.is_some(), EInvalidString); - type_argument.extract() -} - -/// --------- -/// Test Only -/// --------- -#[test_only] -public fun package_id_from_function(self: &Function): address { - self.package_id -} - -#[test_only] -public fun module_name(self: &Function): ascii::String { - self.module_name -} - -#[test_only] -public fun name(self: &Function): ascii::String { - self.name -} - -#[test_only] -public fun function(self: &MoveCall): Function { - self.function -} + ) + } -#[test_only] -public fun arguments(self: &MoveCall): vector> { - self.arguments -} + fun peel_type(bcs: &mut BCS): ascii::String { + let mut type_argument = ascii::try_string(bcs.peel_vec_u8()); + assert!(type_argument.is_some(), EInvalidString); + type_argument.extract() + } -#[test_only] -public fun type_arguments(self: &MoveCall): vector { - self.type_arguments -} + /// --------- + /// Test Only + /// --------- + #[test_only] + public fun package_id_from_function(self: &Function): address { + self.package_id + } -#[test_only] -public fun is_final(self: &Transaction): bool { - self.is_final -} + #[test_only] + public fun module_name(self: &Function): ascii::String { + self.module_name + } -#[test_only] -public fun move_calls(self: &Transaction): vector { - self.move_calls -} + #[test_only] + public fun name(self: &Function): ascii::String { + self.name + } -/// ----- -/// Tests -/// ----- -#[test] -fun tx_builder() { - let function = new_function( - @0x1, - ascii::string(b"ascii"), - ascii::string(b"string"), - ); + #[test_only] + public fun function(self: &MoveCall): Function { + self.function + } - let _tx = function.new_move_call( - vector[bcs::to_bytes(&b"some_string")], - vector[], - ); -} + #[test_only] + public fun arguments(self: &MoveCall): vector> { + self.arguments + } -#[test] -fun test_new_function_from_bcs() { - let package_id = - @0x5f7809eb09754577387a816582ece609511d0262b2c52aa15306083ca3c85962; - let module_name = std::ascii::string(b"module"); - let name = std::ascii::string(b"function"); - let input = - x"5f7809eb09754577387a816582ece609511d0262b2c52aa15306083ca3c85962066d6f64756c650866756e6374696f6e"; + #[test_only] + public fun type_arguments(self: &MoveCall): vector { + self.type_arguments + } - let function = new_function_from_bcs(&mut bcs::new(input)); - assert!(function.package_id == package_id); - assert!(function.module_name == module_name); - assert!(function.name == name); -} + #[test_only] + public fun is_final(self: &Transaction): bool { + self.is_final + } -#[test] -fun test_new_move_call_from_bcs() { - let package_id = - @0x5f7809eb09754577387a816582ece609511d0262b2c52aa15306083ca3c85962; - let module_name = std::ascii::string(b"module"); - let name = std::ascii::string(b"function"); - let arguments = vector[x"1234", x"5678"]; - let type_arguments = vector[ - ascii::string(b"type1"), - ascii::string(b"type2"), - ]; - let input = bcs::to_bytes( - &MoveCall { - function: Function { - package_id, - module_name, - name, - }, - arguments, - type_arguments, - }, - ); + #[test_only] + public fun move_calls(self: &Transaction): vector { + self.move_calls + } - let move_call = new_move_call_from_bcs(&mut bcs::new(input)); - assert!(move_call.function.package_id == package_id); - assert!(move_call.function.module_name == module_name); - assert!(move_call.function.name == name); - assert!(move_call.arguments == arguments); - assert!(move_call.type_arguments == type_arguments); -} + /// ----- + /// Tests + /// ----- + #[test] + fun tx_builder() { + let function = new_function( + @0x1, + ascii::string(b"ascii"), + ascii::string(b"string"), + ); + + let _tx = function.new_move_call( + vector[bcs::to_bytes(&b"some_string")], + vector[], + ); + } -#[test] -fun test_new_transaction_from_bcs() { - let package_id = - @0x5f7809eb09754577387a816582ece609511d0262b2c52aa15306083ca3c85962; - let module_name = std::ascii::string(b"module"); - let name = std::ascii::string(b"function"); - let arguments = vector[x"1234", x"5678"]; - let type_arguments = vector[ - ascii::string(b"type1"), - ascii::string(b"type2"), - ]; + #[test] + fun test_new_function_from_bcs() { + let package_id = @0x5f7809eb09754577387a816582ece609511d0262b2c52aa15306083ca3c85962; + let module_name = std::ascii::string(b"module"); + let name = std::ascii::string(b"function"); + let input = x"5f7809eb09754577387a816582ece609511d0262b2c52aa15306083ca3c85962066d6f64756c650866756e6374696f6e"; + + let function = new_function_from_bcs(&mut bcs::new(input)); + assert!(function.package_id == package_id); + assert!(function.module_name == module_name); + assert!(function.name == name); + } - let transaction = Transaction { - is_final: true, - move_calls: vector[ - MoveCall { + #[test] + fun test_new_move_call_from_bcs() { + let package_id = @0x5f7809eb09754577387a816582ece609511d0262b2c52aa15306083ca3c85962; + let module_name = std::ascii::string(b"module"); + let name = std::ascii::string(b"function"); + let arguments = vector[x"1234", x"5678"]; + let type_arguments = vector[ascii::string(b"type1"), ascii::string(b"type2")]; + let input = bcs::to_bytes( + &MoveCall { function: Function { package_id, module_name, @@ -269,39 +208,68 @@ fun test_new_transaction_from_bcs() { arguments, type_arguments, }, - MoveCall { - function: Function { - package_id, - module_name, - name, + ); + + let move_call = new_move_call_from_bcs(&mut bcs::new(input)); + assert!(move_call.function.package_id == package_id); + assert!(move_call.function.module_name == module_name); + assert!(move_call.function.name == name); + assert!(move_call.arguments == arguments); + assert!(move_call.type_arguments == type_arguments); + } + + #[test] + fun test_new_transaction_from_bcs() { + let package_id = @0x5f7809eb09754577387a816582ece609511d0262b2c52aa15306083ca3c85962; + let module_name = std::ascii::string(b"module"); + let name = std::ascii::string(b"function"); + let arguments = vector[x"1234", x"5678"]; + let type_arguments = vector[ascii::string(b"type1"), ascii::string(b"type2")]; + + let transaction = Transaction { + is_final: true, + move_calls: vector[ + MoveCall { + function: Function { + package_id, + module_name, + name, + }, + arguments, + type_arguments, }, - arguments, - type_arguments, - }, - ], - }; + MoveCall { + function: Function { + package_id, + module_name, + name, + }, + arguments, + type_arguments, + }, + ], + }; - assert!( - transaction == new_transaction_from_bcs(&mut bcs::new(bcs::to_bytes(&transaction))), - ); -} + assert!(transaction == new_transaction_from_bcs(&mut bcs::new(bcs::to_bytes(&transaction)))); + } -#[test] -fun test_package_id() { - assert!( - package_id() == address::from_bytes( + #[test] + fun test_package_id() { + assert!( + package_id() == address::from_bytes( hex::decode( *ascii::as_bytes( &type_name::get_address(&type_name::get()), ), ), ), - ); -} + ); + } -#[test] -#[expected_failure(abort_code = EInvalidString)] -fun test_peel_type_invalid_string() { - let bcs_bytes = bcs::to_bytes(&vector[128u8]); - peel_type(&mut bcs::new(bcs_bytes)); + #[test] + #[expected_failure(abort_code = EInvalidString)] + fun test_peel_type_invalid_string() { + let bcs_bytes = bcs::to_bytes(&vector[128u8]); + peel_type(&mut bcs::new(bcs_bytes)); + } } diff --git a/move/relayer_discovery/sources/versioned/relayer_discovery_v0.move b/move/relayer_discovery/sources/versioned/relayer_discovery_v0.move index 2bde49b7..f6fb52fb 100644 --- a/move/relayer_discovery/sources/versioned/relayer_discovery_v0.move +++ b/move/relayer_discovery/sources/versioned/relayer_discovery_v0.move @@ -1,143 +1,119 @@ -module relayer_discovery::relayer_discovery_v0; +module relayer_discovery::relayer_discovery_v0 { + use relayer_discovery::{events, transaction::Transaction}; + use std::ascii::String; + use sui::table::{Self, Table}; + use version_control::version_control::VersionControl; -use relayer_discovery::events; -use relayer_discovery::transaction::Transaction; -use std::ascii::String; -use sui::table::{Self, Table}; -use version_control::version_control::VersionControl; - -// ------- -// Structs -// ------- -/// A central shared object that stores discovery configuration for the -/// Relayer. The Relayer will use this object to discover and execute the -/// transactions when a message is targeted at specific channel. -public struct RelayerDiscovery_v0 has store { - /// A map of channel IDs to the target that needs to be executed by the - /// relayer. There can be only one configuration per channel. - configurations: Table, - /// An object to manage version control. - version_control: VersionControl, -} + // ------- + // Structs + // ------- + /// A central shared object that stores discovery configuration for the + /// Relayer. The Relayer will use this object to discover and execute the + /// transactions when a message is targeted at specific channel. + public struct RelayerDiscovery_v0 has store { + /// A map of channel IDs to the target that needs to be executed by the + /// relayer. There can be only one configuration per channel. + configurations: Table, + /// An object to manage version control. + version_control: VersionControl, + } -// ------ -// Errors -// ------ -#[error] -const EChannelNotFound: vector = b"channel not found"; + // ------ + // Errors + // ------ + #[error] + const EChannelNotFound: vector = b"channel not found"; -// ----------------- -// Package Functions -// ----------------- -public(package) fun new( - version_control: VersionControl, - ctx: &mut TxContext, -): RelayerDiscovery_v0 { - RelayerDiscovery_v0 { - configurations: table::new(ctx), - version_control, + // ----------------- + // Package Functions + // ----------------- + public(package) fun new(version_control: VersionControl, ctx: &mut TxContext): RelayerDiscovery_v0 { + RelayerDiscovery_v0 { + configurations: table::new(ctx), + version_control, + } } -} -public(package) fun set_transaction( - self: &mut RelayerDiscovery_v0, - id: ID, - transaction: Transaction, -) { - if (self.configurations.contains(id)) { - self.configurations.remove(id); - }; - self.configurations.add(id, transaction); - events::transaction_registered(id, transaction); -} + public(package) fun set_transaction(self: &mut RelayerDiscovery_v0, id: ID, transaction: Transaction) { + if (self.configurations.contains(id)) { + self.configurations.remove(id); + }; + self.configurations.add(id, transaction); + events::transaction_registered(id, transaction); + } -public(package) fun remove_transaction( - self: &mut RelayerDiscovery_v0, - id: ID, -): Transaction { - assert!(self.configurations.contains(id), EChannelNotFound); - let tx = self.configurations.remove(id); - events::transaction_removed(id); - tx -} + public(package) fun remove_transaction(self: &mut RelayerDiscovery_v0, id: ID): Transaction { + assert!(self.configurations.contains(id), EChannelNotFound); + let tx = self.configurations.remove(id); + events::transaction_removed(id); + tx + } -public(package) fun get_transaction( - self: &RelayerDiscovery_v0, - id: ID, -): Transaction { - assert!(self.configurations.contains(id), EChannelNotFound); - self.configurations[id] -} + public(package) fun get_transaction(self: &RelayerDiscovery_v0, id: ID): Transaction { + assert!(self.configurations.contains(id), EChannelNotFound); + self.configurations[id] + } -public(package) fun version_control( - self: &RelayerDiscovery_v0, -): &VersionControl { - &self.version_control -} + public(package) fun version_control(self: &RelayerDiscovery_v0): &VersionControl { + &self.version_control + } -public(package) fun allow_function( - self: &mut RelayerDiscovery_v0, - version: u64, - function_name: String, -) { - self.version_control.allow_function(version, function_name); -} + public(package) fun allow_function(self: &mut RelayerDiscovery_v0, version: u64, function_name: String) { + self.version_control.allow_function(version, function_name); + } -public(package) fun disallow_function( - self: &mut RelayerDiscovery_v0, - version: u64, - function_name: String, -) { - self.version_control.disallow_function(version, function_name); -} + public(package) fun disallow_function(self: &mut RelayerDiscovery_v0, version: u64, function_name: String) { + self.version_control.disallow_function(version, function_name); + } -// --------- -// Test Only -// --------- -#[test_only] -public(package) fun destroy_for_testing(self: RelayerDiscovery_v0) { - sui::test_utils::destroy(self); -} + // --------- + // Test Only + // --------- + #[test_only] + public(package) fun destroy_for_testing(self: RelayerDiscovery_v0) { + sui::test_utils::destroy(self); + } -#[test_only] -fun dummy(ctx: &mut TxContext): RelayerDiscovery_v0 { - RelayerDiscovery_v0 { - configurations: table::new(ctx), - version_control: version_control::version_control::new(vector[]), + #[test_only] + fun dummy(ctx: &mut TxContext): RelayerDiscovery_v0 { + RelayerDiscovery_v0 { + configurations: table::new(ctx), + version_control: version_control::version_control::new(vector[]), + } } -} -// ---- -// Test -// ---- -#[test] -fun test_set_transaction_channel_not_found() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = dummy(ctx); - let id = object::id_from_address(@0x1); - let transaction = relayer_discovery::transaction::new_transaction( - true, - vector[], - ); - self.set_transaction(id, transaction); - self.set_transaction(id, transaction); - self.destroy_for_testing(); -} + // ---- + // Test + // ---- + #[test] + fun test_set_transaction_channel_not_found() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = dummy(ctx); + let id = object::id_from_address(@0x1); + let transaction = relayer_discovery::transaction::new_transaction( + true, + vector[], + ); + self.set_transaction(id, transaction); + self.set_transaction(id, transaction); + self.destroy_for_testing(); + } -#[test] -#[expected_failure(abort_code = EChannelNotFound)] -fun test_get_transaction_channel_not_found() { - let ctx = &mut sui::tx_context::dummy(); - let self = dummy(ctx); - self.get_transaction(object::id_from_address(@0x1)); - self.destroy_for_testing(); -} + #[test] + #[expected_failure(abort_code = EChannelNotFound)] + fun test_get_transaction_channel_not_found() { + let ctx = &mut sui::tx_context::dummy(); + let self = dummy(ctx); + self.get_transaction(object::id_from_address(@0x1)); + self.destroy_for_testing(); + } -#[test] -#[expected_failure(abort_code = EChannelNotFound)] -fun test_remove_transaction_channel_not_found() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = dummy(ctx); - self.remove_transaction(object::id_from_address(@0x1)); - self.destroy_for_testing(); + #[test] + #[expected_failure(abort_code = EChannelNotFound)] + fun test_remove_transaction_channel_not_found() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = dummy(ctx); + self.remove_transaction(object::id_from_address(@0x1)); + self.destroy_for_testing(); + } } diff --git a/move/squid/sources/squid/coin_bag.move b/move/squid/sources/squid/coin_bag.move index 4aaa1206..3b4219ae 100644 --- a/move/squid/sources/squid/coin_bag.move +++ b/move/squid/sources/squid/coin_bag.move @@ -1,173 +1,167 @@ -module squid::coin_bag; +module squid::coin_bag { + use std::type_name; + use sui::{address, bag::{Self, Bag}, balance::Balance, hash::keccak256}; -use std::type_name; -use sui::address; -use sui::bag::{Self, Bag}; -use sui::balance::Balance; -use sui::hash::keccak256; + #[error] + const EKeyNotExist: vector = b"key not found"; + #[error] + const ENotEnoughBalance: vector = b"not enough balance"; -#[error] -const EKeyNotExist: vector = b"key not found"; -#[error] -const ENotEnoughBalance: vector = b"not enough balance"; - -public struct CoinBag has store { - bag: Bag, -} + public struct CoinBag has store { + bag: Bag, + } -public(package) fun new(ctx: &mut TxContext): CoinBag { - CoinBag { - bag: bag::new(ctx), + public(package) fun new(ctx: &mut TxContext): CoinBag { + CoinBag { + bag: bag::new(ctx), + } } -} -public(package) fun store_balance(self: &mut CoinBag, balance: Balance) { - let key = balance_key(); - - if (self.bag.contains(key)) { - self - .bag - .borrow_mut>(key) - .join( - balance, - ); - } else { - self - .bag - .add( - key, - balance, - ) + public(package) fun store_balance(self: &mut CoinBag, balance: Balance) { + let key = balance_key(); + + if (self.bag.contains(key)) { + self + .bag + .borrow_mut>(key) + .join( + balance, + ); + } else { + self + .bag + .add( + key, + balance, + ) + } } -} -public(package) fun balance(self: &mut CoinBag): Option> { - let key = balance_key(); + public(package) fun balance(self: &mut CoinBag): Option> { + let key = balance_key(); - if (self.bag.contains(key)) { - option::some(self.bag.remove>(key)) - } else { - option::none>() + if (self.bag.contains(key)) { + option::some(self.bag.remove>(key)) + } else { + option::none>() + } } -} -public(package) fun exact_balance( - self: &mut CoinBag, - amount: u64, -): Balance { - let key = balance_key(); + public(package) fun exact_balance(self: &mut CoinBag, amount: u64): Balance { + let key = balance_key(); - assert!(self.bag.contains(key), EKeyNotExist); - let balance = self.bag.borrow_mut>(key); - assert!(balance.value() >= amount, ENotEnoughBalance); + assert!(self.bag.contains(key), EKeyNotExist); + let balance = self.bag.borrow_mut>(key); + assert!(balance.value() >= amount, ENotEnoughBalance); - balance.split(amount) -} + balance.split(amount) + } -public(package) fun balance_amount(self: &CoinBag): u64 { - let key = balance_key(); + public(package) fun balance_amount(self: &CoinBag): u64 { + let key = balance_key(); - if (self.bag.contains(key)) { - self.bag.borrow>(key).value() - } else { - 0 + if (self.bag.contains(key)) { + self.bag.borrow>(key).value() + } else { + 0 + } } -} -public(package) fun store_estimate(self: &mut CoinBag, estimate: u64) { - let key = estimate_key(); - - if (self.bag.contains(key)) { - let previous = self.bag.borrow_mut(key); - *previous = *previous + estimate; - } else { - self - .bag - .add( - key, - estimate, - ) + public(package) fun store_estimate(self: &mut CoinBag, estimate: u64) { + let key = estimate_key(); + + if (self.bag.contains(key)) { + let previous = self.bag.borrow_mut(key); + *previous = *previous + estimate; + } else { + self + .bag + .add( + key, + estimate, + ) + } } -} -public(package) fun estimate(self: &mut CoinBag): u64 { - let key = estimate_key(); + public(package) fun estimate(self: &mut CoinBag): u64 { + let key = estimate_key(); - if (self.bag.contains(key)) { - self.bag.remove(key) - } else { - 0 + if (self.bag.contains(key)) { + self.bag.remove(key) + } else { + 0 + } } -} -public(package) fun estimate_amount(self: &CoinBag): u64 { - let key = estimate_key(); + public(package) fun estimate_amount(self: &CoinBag): u64 { + let key = estimate_key(); - if (self.bag.contains(key)) { - *self.bag.borrow(key) - } else { - 0 + if (self.bag.contains(key)) { + *self.bag.borrow(key) + } else { + 0 + } } -} -public(package) fun destroy(self: CoinBag) { - let CoinBag { bag } = self; - bag.destroy_empty(); -} + public(package) fun destroy(self: CoinBag) { + let CoinBag { bag } = self; + bag.destroy_empty(); + } -fun balance_key(): address { - let mut data = vector[0]; - data.append(type_name::get().into_string().into_bytes()); - address::from_bytes(keccak256(&data)) -} + fun balance_key(): address { + let mut data = vector[0]; + data.append(type_name::get().into_string().into_bytes()); + address::from_bytes(keccak256(&data)) + } -fun estimate_key(): address { - let mut data = vector[1]; - data.append(type_name::get().into_string().into_bytes()); - address::from_bytes(keccak256(&data)) -} + fun estimate_key(): address { + let mut data = vector[1]; + data.append(type_name::get().into_string().into_bytes()); + address::from_bytes(keccak256(&data)) + } -#[test_only] -use interchain_token_service::coin::COIN; + #[test_only] + use interchain_token_service::coin::COIN; -#[test] -fun test_balance() { - let ctx = &mut tx_context::dummy(); - let mut coin_bag = new(ctx); + #[test] + fun test_balance() { + let ctx = &mut tx_context::dummy(); + let mut coin_bag = new(ctx); - assert!(coin_bag.balance_amount() == 0); + assert!(coin_bag.balance_amount() == 0); - coin_bag.store_balance(sui::balance::create_for_testing(1)); - assert!(coin_bag.balance_amount() == 1); + coin_bag.store_balance(sui::balance::create_for_testing(1)); + assert!(coin_bag.balance_amount() == 1); - coin_bag.store_balance(sui::balance::create_for_testing(2)); - let mut balance = coin_bag.balance(); - assert!(balance.borrow().value() == 3); - sui::test_utils::destroy(balance); + coin_bag.store_balance(sui::balance::create_for_testing(2)); + let mut balance = coin_bag.balance(); + assert!(balance.borrow().value() == 3); + sui::test_utils::destroy(balance); - balance = coin_bag.balance(); - assert!(balance.is_none()); - balance.destroy_none(); + balance = coin_bag.balance(); + assert!(balance.is_none()); + balance.destroy_none(); - coin_bag.destroy(); -} + coin_bag.destroy(); + } -#[test] -fun test_estimate() { - let ctx = &mut tx_context::dummy(); - let mut coin_bag = new(ctx); + #[test] + fun test_estimate() { + let ctx = &mut tx_context::dummy(); + let mut coin_bag = new(ctx); - assert!(coin_bag.estimate_amount() == 0); + assert!(coin_bag.estimate_amount() == 0); - coin_bag.store_estimate(1); - assert!(coin_bag.estimate_amount() == 1); + coin_bag.store_estimate(1); + assert!(coin_bag.estimate_amount() == 1); - coin_bag.store_estimate(2); - let mut estimate = coin_bag.estimate(); - assert!(estimate == 3); + coin_bag.store_estimate(2); + let mut estimate = coin_bag.estimate(); + assert!(estimate == 3); - estimate = coin_bag.estimate(); - assert!(estimate == 0); + estimate = coin_bag.estimate(); + assert!(estimate == 0); - coin_bag.destroy(); + coin_bag.destroy(); + } } diff --git a/move/squid/sources/squid/deepbook_v3.move b/move/squid/sources/squid/deepbook_v3.move index acfe46f8..2f52e861 100644 --- a/move/squid/sources/squid/deepbook_v3.move +++ b/move/squid/sources/squid/deepbook_v3.move @@ -1,305 +1,251 @@ -module squid::deepbook_v3; - -use deepbook::pool::Pool; -use relayer_discovery::transaction::{Self, MoveCall}; -use squid::squid::Squid; -use squid::swap_info::SwapInfo; -use squid::swap_type::{Self, SwapType}; -use std::ascii::{Self, String}; -use std::type_name; -use sui::bcs::BCS; -use sui::clock::Clock; -use token::deep::DEEP; -use utils::utils::peel; - -#[error] -const EWrongSwapType: vector = b"wrong swap type"; -#[error] -const EWrongPool: vector = b"pool argument does not match required pool"; -#[error] -const EWrongCoinType: vector = - b"coin type expected does not match type argument"; - -const FLOAT_SCALING: u128 = 1_000_000_000; - -public struct DeepbookV3SwapData has drop { - swap_type: SwapType, - pool_id: address, - has_base: bool, - min_output: u64, - base_type: String, - quote_type: String, - lot_size: u64, - should_sweep: bool, -} +module squid::deepbook_v3 { + use deepbook::pool::Pool; + use relayer_discovery::transaction::{Self, MoveCall}; + use squid::{squid::Squid, swap_info::SwapInfo, swap_type::{Self, SwapType}}; + use std::{ascii::{Self, String}, type_name}; + use sui::{bcs::BCS, clock::Clock}; + use token::deep::DEEP; + use utils::utils::peel; + + #[error] + const EWrongSwapType: vector = b"wrong swap type"; + #[error] + const EWrongPool: vector = b"pool argument does not match required pool"; + #[error] + const EWrongCoinType: vector = b"coin type expected does not match type argument"; + + const FLOAT_SCALING: u128 = 1_000_000_000; + + public struct DeepbookV3SwapData has drop { + swap_type: SwapType, + pool_id: address, + has_base: bool, + min_output: u64, + base_type: String, + quote_type: String, + lot_size: u64, + should_sweep: bool, + } -/// Estimate the output of a swap. If the output is less than the minimum -/// output, the swap is skipped. -/// If the swap is not skipped, the estimate is stored in the coin bag. -public fun estimate( - self: &mut SwapInfo, - pool: &Pool, - clock: &Clock, -) { - let (data, fallback) = self.data_estimating(); - if (fallback) return; - let swap_data = peel!(data, |data| peel_swap_data(data)); - - assert!(swap_data.swap_type == swap_type::deepbook_v3(), EWrongSwapType); - assert!(swap_data.pool_id == object::id_address(pool), EWrongPool); - - assert!( - &swap_data.base_type == &type_name::get().into_string(), - EWrongCoinType, - ); - assert!( - &swap_data.quote_type == &type_name::get().into_string(), - EWrongCoinType, - ); - - let (taker_fee, _, _) = pool.pool_trade_params(); - - if (swap_data.has_base) { - let base_quantity = self.coin_bag().estimate(); - let base_fee = mul_scaled(base_quantity, taker_fee); - let base_in = base_quantity - base_fee; - - let (base_out, quote_out, _deep_required) = pool.get_quote_quantity_out( - base_in, - clock, - ); - if (swap_data.min_output > quote_out) { - self.skip_swap(); - return - }; - if (!swap_data.should_sweep) { - self.coin_bag().store_estimate(base_out) - }; - self.coin_bag().store_estimate(quote_out); - } else { - let quote_quantity = self.coin_bag().estimate(); - let quote_fee = mul_scaled(quote_quantity, taker_fee); - let quote_in = quote_quantity - quote_fee; - - let (base_out, quote_out, _deep_required) = pool.get_base_quantity_out( - quote_in, - clock, - ); - if (swap_data.min_output > base_out) { - self.skip_swap(); - return - }; - if (!swap_data.should_sweep) { - self.coin_bag().store_estimate(quote_out) - }; - self.coin_bag().store_estimate(base_out); + /// Estimate the output of a swap. If the output is less than the minimum + /// output, the swap is skipped. + /// If the swap is not skipped, the estimate is stored in the coin bag. + public fun estimate(self: &mut SwapInfo, pool: &Pool, clock: &Clock) { + let (data, fallback) = self.data_estimating(); + if (fallback) return; + let swap_data = peel!(data, |data| peel_swap_data(data)); + + assert!(swap_data.swap_type == swap_type::deepbook_v3(), EWrongSwapType); + assert!(swap_data.pool_id == object::id_address(pool), EWrongPool); + + assert!(&swap_data.base_type == &type_name::get().into_string(), EWrongCoinType); + assert!(&swap_data.quote_type == &type_name::get().into_string(), EWrongCoinType); + + let (taker_fee, _, _) = pool.pool_trade_params(); + + if (swap_data.has_base) { + let base_quantity = self.coin_bag().estimate(); + let base_fee = mul_scaled(base_quantity, taker_fee); + let base_in = base_quantity - base_fee; + + let (base_out, quote_out, _deep_required) = pool.get_quote_quantity_out( + base_in, + clock, + ); + if (swap_data.min_output > quote_out) { + self.skip_swap(); + return + }; + if (!swap_data.should_sweep) { + self.coin_bag().store_estimate(base_out) + }; + self.coin_bag().store_estimate(quote_out); + } else { + let quote_quantity = self.coin_bag().estimate(); + let quote_fee = mul_scaled(quote_quantity, taker_fee); + let quote_in = quote_quantity - quote_fee; + + let (base_out, quote_out, _deep_required) = pool.get_base_quantity_out( + quote_in, + clock, + ); + if (swap_data.min_output > base_out) { + self.skip_swap(); + return + }; + if (!swap_data.should_sweep) { + self.coin_bag().store_estimate(quote_out) + }; + self.coin_bag().store_estimate(base_out); + } } -} -/// Perform a swap. First, check how much DEEP is required to perform the swap. -/// Then, get that amount of DEEP from squid. Get the taker_fee for this swap -/// and -/// split that amount from the input token. Store the fee in Squid. Use the -/// remaining -/// input token to perform the swap. Store the output tokens in the coin bag. -/// Store the remaining DEEP back in squid. -public fun swap( - self: &mut SwapInfo, - pool: &mut Pool, - squid: &mut Squid, - clock: &Clock, - ctx: &mut TxContext, -) { - let (data, fallback) = self.data_swapping(); - if (fallback) return; - let swap_data = peel!(data, |data| peel_swap_data(data)); - - assert!(swap_data.swap_type == swap_type::deepbook_v3(), EWrongSwapType); - assert!(swap_data.pool_id == object::id_address(pool), EWrongPool); - assert!( - &swap_data.base_type == &type_name::get().into_string(), - EWrongCoinType, - ); - assert!( - &swap_data.quote_type == &type_name::get().into_string(), - EWrongCoinType, - ); - - let (taker_fee, _, _) = pool.pool_trade_params(); - - let squid_coin_bag = squid.value_mut!(b"deepbook_v3_swap").coin_bag_mut(); - - if (swap_data.has_base) { - // Get base coin, split away taker fees and store it in Squid. - let mut base_in = self - .coin_bag() - .balance() - .destroy_some() - .into_coin(ctx); - let base_fee_amount = mul_scaled(base_in.value(), taker_fee); - let base_fee = base_in.split(base_fee_amount, ctx); - squid_coin_bag.store_balance(base_fee.into_balance()); - - // Calculate the DEEP quantity required and get it from Squid. - let (_, _, deep_required) = pool.get_quote_quantity_out( - base_in.value(), - clock, - ); - let deep_in = squid_coin_bag - .exact_balance(deep_required) - .into_coin(ctx); - - let (base_out, quote_out, deep_out) = pool.swap_exact_base_for_quote< - B, - Q, - >( - base_in, - deep_in, - swap_data.min_output, - clock, - ctx, - ); - - self.coin_bag().store_balance(quote_out.into_balance()); - squid_coin_bag.store_balance(deep_out.into_balance()); - if (swap_data.should_sweep) { - squid_coin_bag.store_balance(base_out.into_balance()); + /// Perform a swap. First, check how much DEEP is required to perform the swap. + /// Then, get that amount of DEEP from squid. Get the taker_fee for this swap + /// and + /// split that amount from the input token. Store the fee in Squid. Use the + /// remaining + /// input token to perform the swap. Store the output tokens in the coin bag. + /// Store the remaining DEEP back in squid. + public fun swap(self: &mut SwapInfo, pool: &mut Pool, squid: &mut Squid, clock: &Clock, ctx: &mut TxContext) { + let (data, fallback) = self.data_swapping(); + if (fallback) return; + let swap_data = peel!(data, |data| peel_swap_data(data)); + + assert!(swap_data.swap_type == swap_type::deepbook_v3(), EWrongSwapType); + assert!(swap_data.pool_id == object::id_address(pool), EWrongPool); + assert!(&swap_data.base_type == &type_name::get().into_string(), EWrongCoinType); + assert!(&swap_data.quote_type == &type_name::get().into_string(), EWrongCoinType); + + let (taker_fee, _, _) = pool.pool_trade_params(); + + let squid_coin_bag = squid.value_mut!(b"deepbook_v3_swap").coin_bag_mut(); + + if (swap_data.has_base) { + // Get base coin, split away taker fees and store it in Squid. + let mut base_in = self.coin_bag().balance().destroy_some().into_coin(ctx); + let base_fee_amount = mul_scaled(base_in.value(), taker_fee); + let base_fee = base_in.split(base_fee_amount, ctx); + squid_coin_bag.store_balance(base_fee.into_balance()); + + // Calculate the DEEP quantity required and get it from Squid. + let (_, _, deep_required) = pool.get_quote_quantity_out( + base_in.value(), + clock, + ); + let deep_in = squid_coin_bag.exact_balance(deep_required).into_coin(ctx); + + let (base_out, quote_out, deep_out) = pool.swap_exact_base_for_quote( + base_in, + deep_in, + swap_data.min_output, + clock, + ctx, + ); + + self.coin_bag().store_balance(quote_out.into_balance()); + squid_coin_bag.store_balance(deep_out.into_balance()); + if (swap_data.should_sweep) { + squid_coin_bag.store_balance(base_out.into_balance()); + } else { + self.coin_bag().store_balance(base_out.into_balance()); + }; } else { + // Get quote coin, split away taker fees and store it in Squid. + let mut quote_in = self.coin_bag().balance().destroy_some().into_coin(ctx); + let quote_fee_amount = mul_scaled(quote_in.value(), taker_fee); + let quote_fee = quote_in.split(quote_fee_amount, ctx); + squid_coin_bag.store_balance(quote_fee.into_balance()); + + // Calculate the DEEP quantity required and get it from Squid. + let (_, _, deep_required) = pool.get_base_quantity_out( + quote_in.value(), + clock, + ); + let deep_in = squid_coin_bag.exact_balance(deep_required).into_coin(ctx); + + let (quote_out, base_out, deep_out) = pool.swap_exact_quote_for_base( + quote_in, + deep_in, + swap_data.min_output, + clock, + ctx, + ); + self.coin_bag().store_balance(base_out.into_balance()); - }; - } else { - // Get quote coin, split away taker fees and store it in Squid. - let mut quote_in = self - .coin_bag() - .balance() - .destroy_some() - .into_coin(ctx); - let quote_fee_amount = mul_scaled(quote_in.value(), taker_fee); - let quote_fee = quote_in.split(quote_fee_amount, ctx); - squid_coin_bag.store_balance(quote_fee.into_balance()); - - // Calculate the DEEP quantity required and get it from Squid. - let (_, _, deep_required) = pool.get_base_quantity_out( - quote_in.value(), - clock, - ); - let deep_in = squid_coin_bag - .exact_balance(deep_required) - .into_coin(ctx); - - let (quote_out, base_out, deep_out) = pool.swap_exact_quote_for_base< - B, - Q, - >( - quote_in, - deep_in, - swap_data.min_output, - clock, - ctx, - ); - - self.coin_bag().store_balance(base_out.into_balance()); - squid_coin_bag.store_balance(deep_out.into_balance()); - if (swap_data.should_sweep) { - squid_coin_bag.store_balance(quote_out.into_balance()); - } else { - self.coin_bag().store_balance(quote_out.into_balance()); - }; + squid_coin_bag.store_balance(deep_out.into_balance()); + if (swap_data.should_sweep) { + squid_coin_bag.store_balance(quote_out.into_balance()); + } else { + self.coin_bag().store_balance(quote_out.into_balance()); + }; + } } -} -public(package) fun estimate_move_call( - package_id: address, - mut bcs: BCS, - swap_info_arg: vector, -): MoveCall { - let mut pool_arg = vector[0]; - pool_arg.append(bcs.peel_address().to_bytes()); - - let _has_base = bcs.peel_bool(); - let _min_output = bcs.peel_u64(); - - let type_base = ascii::string(bcs.peel_vec_u8()); - let type_quote = ascii::string(bcs.peel_vec_u8()); - - transaction::new_move_call( - transaction::new_function( - package_id, - ascii::string(b"deepbook_v3"), - ascii::string(b"estimate"), - ), - vector[swap_info_arg, pool_arg, vector[0, 6]], - vector[type_base, type_quote], - ) -} + public(package) fun estimate_move_call(package_id: address, mut bcs: BCS, swap_info_arg: vector): MoveCall { + let mut pool_arg = vector[0]; + pool_arg.append(bcs.peel_address().to_bytes()); + + let _has_base = bcs.peel_bool(); + let _min_output = bcs.peel_u64(); + + let type_base = ascii::string(bcs.peel_vec_u8()); + let type_quote = ascii::string(bcs.peel_vec_u8()); + + transaction::new_move_call( + transaction::new_function( + package_id, + ascii::string(b"deepbook_v3"), + ascii::string(b"estimate"), + ), + vector[swap_info_arg, pool_arg, vector[0, 6]], + vector[type_base, type_quote], + ) + } -public(package) fun swap_move_call( - package_id: address, - mut bcs: BCS, - swap_info_arg: vector, - squid_arg: vector, -): MoveCall { - let mut pool_arg = vector[0]; - pool_arg.append(bcs.peel_address().to_bytes()); - - let _has_base = bcs.peel_bool(); - let _min_output = bcs.peel_u64(); - - let type_base = ascii::string(bcs.peel_vec_u8()); - let type_quote = ascii::string(bcs.peel_vec_u8()); - - transaction::new_move_call( - transaction::new_function( - package_id, - ascii::string(b"deepbook_v3"), - ascii::string(b"swap"), - ), - vector[swap_info_arg, pool_arg, squid_arg, vector[0, 6]], - vector[type_base, type_quote], - ) -} + public(package) fun swap_move_call(package_id: address, mut bcs: BCS, swap_info_arg: vector, squid_arg: vector): MoveCall { + let mut pool_arg = vector[0]; + pool_arg.append(bcs.peel_address().to_bytes()); + + let _has_base = bcs.peel_bool(); + let _min_output = bcs.peel_u64(); + + let type_base = ascii::string(bcs.peel_vec_u8()); + let type_quote = ascii::string(bcs.peel_vec_u8()); + + transaction::new_move_call( + transaction::new_function( + package_id, + ascii::string(b"deepbook_v3"), + ascii::string(b"swap"), + ), + vector[swap_info_arg, pool_arg, squid_arg, vector[0, 6]], + vector[type_base, type_quote], + ) + } -public(package) fun peel_swap_data(bcs: &mut BCS): DeepbookV3SwapData { - DeepbookV3SwapData { - swap_type: swap_type::peel(bcs), - pool_id: bcs.peel_address(), - has_base: bcs.peel_bool(), - min_output: bcs.peel_u64(), - base_type: ascii::string(bcs.peel_vec_u8()), - quote_type: ascii::string(bcs.peel_vec_u8()), - lot_size: bcs.peel_u64(), - should_sweep: bcs.peel_bool(), + public(package) fun peel_swap_data(bcs: &mut BCS): DeepbookV3SwapData { + DeepbookV3SwapData { + swap_type: swap_type::peel(bcs), + pool_id: bcs.peel_address(), + has_base: bcs.peel_bool(), + min_output: bcs.peel_u64(), + base_type: ascii::string(bcs.peel_vec_u8()), + quote_type: ascii::string(bcs.peel_vec_u8()), + lot_size: bcs.peel_u64(), + should_sweep: bcs.peel_bool(), + } } -} -/// Multiply two u64 numbers and divide by FLOAT_SCALING. Rounded down. -/// Used for multiplying the balance by DeepBook's taker fee. -fun mul_scaled(x: u64, y: u64): u64 { - let x = x as u128; - let y = y as u128; + /// Multiply two u64 numbers and divide by FLOAT_SCALING. Rounded down. + /// Used for multiplying the balance by DeepBook's taker fee. + fun mul_scaled(x: u64, y: u64): u64 { + let x = x as u128; + let y = y as u128; - ((x * y / FLOAT_SCALING) as u64) -} + ((x * y / FLOAT_SCALING) as u64) + } -#[test_only] -public(package) fun new_swap_data( - swap_type: SwapType, - pool_id: address, - has_base: bool, - min_output: u64, - base_type: String, - quote_type: String, - lot_size: u64, - should_sweep: bool, -): DeepbookV3SwapData { - DeepbookV3SwapData { - swap_type, - pool_id, - has_base, - min_output, - base_type, - quote_type, - lot_size, - should_sweep, + #[test_only] + public(package) fun new_swap_data( + swap_type: SwapType, + pool_id: address, + has_base: bool, + min_output: u64, + base_type: String, + quote_type: String, + lot_size: u64, + should_sweep: bool, + ): DeepbookV3SwapData { + DeepbookV3SwapData { + swap_type, + pool_id, + has_base, + min_output, + base_type, + quote_type, + lot_size, + should_sweep, + } } } diff --git a/move/squid/sources/squid/discovery.move b/move/squid/sources/squid/discovery.move index ae705692..40e5c9be 100644 --- a/move/squid/sources/squid/discovery.move +++ b/move/squid/sources/squid/discovery.move @@ -1,173 +1,157 @@ -module squid::discovery; - -use axelar_gateway::gateway::Gateway; -use interchain_token_service::interchain_token_service::InterchainTokenService; -use relayer_discovery::discovery::RelayerDiscovery; -use relayer_discovery::transaction::{Self, MoveCall, Transaction}; -use squid::deepbook_v3; -use squid::squid::Squid; -use squid::swap_type; -use squid::transfers; -use std::ascii::{Self, String}; -use sui::bcs; - -#[error] -const EInvalidSwapType: vector = b"swap type does not exist"; - -public fun register_transaction( - squid: &Squid, - its: &InterchainTokenService, - gateway: &Gateway, - relayer_discovery: &mut RelayerDiscovery, -) { - let mut squid_arg = vector[0]; - squid_arg.append(object::id(squid).id_to_bytes()); - - let mut its_arg = vector[0]; - its_arg.append(object::id(its).id_to_bytes()); - - let mut gateway_arg = vector[0]; - gateway_arg.append(object::id(gateway).id_to_bytes()); - - let transaction = transaction::new_transaction( - false, - vector[ - transaction::new_move_call( - transaction::new_function( - transaction::package_id(), - ascii::string(b"discovery"), - ascii::string(b"transaction"), +module squid::discovery { + use axelar_gateway::gateway::Gateway; + use interchain_token_service::interchain_token_service::InterchainTokenService; + use relayer_discovery::{discovery::RelayerDiscovery, transaction::{Self, MoveCall, Transaction}}; + use squid::{deepbook_v3, squid::Squid, swap_type, transfers}; + use std::ascii::{Self, String}; + use sui::bcs; + + #[error] + const EInvalidSwapType: vector = b"swap type does not exist"; + + public fun register_transaction( + squid: &Squid, + its: &InterchainTokenService, + gateway: &Gateway, + relayer_discovery: &mut RelayerDiscovery, + ) { + let mut squid_arg = vector[0]; + squid_arg.append(object::id(squid).id_to_bytes()); + + let mut its_arg = vector[0]; + its_arg.append(object::id(its).id_to_bytes()); + + let mut gateway_arg = vector[0]; + gateway_arg.append(object::id(gateway).id_to_bytes()); + + let transaction = transaction::new_transaction( + false, + vector[ + transaction::new_move_call( + transaction::new_function( + transaction::package_id(), + ascii::string(b"discovery"), + ascii::string(b"transaction"), + ), + vector[squid_arg, its_arg, gateway_arg, vector[3]], + vector[], ), - vector[squid_arg, its_arg, gateway_arg, vector[3]], - vector[], - ), - ], - ); - - relayer_discovery.register_transaction( - squid.value!(b"register_transaction").channel(), - transaction, - ) -} - -public fun transaction( - squid: &Squid, - its: &InterchainTokenService, - gateway: &Gateway, - payload: vector, -): Transaction { - let (token_id, _, _, data) = interchain_token_service::discovery::interchain_transfer_info( - payload, - ); - let type_in = (*its.registered_coin_type(token_id)).into_string(); - let package_id = transaction::package_id(); - let swap_data = bcs::new(data).peel_vec_vec_u8(); - - let mut squid_arg = vector[0]; - squid_arg.append(object::id(squid).id_to_bytes()); - - let mut its_arg = vector[0]; - its_arg.append(object::id(its).id_to_bytes()); - - let mut gateway_arg = vector[0]; - gateway_arg.append(object::id(gateway).id_to_bytes()); - - let swap_info_arg = vector[4, 0, 0]; - - let mut move_calls = vector[ - start_swap(package_id, squid_arg, its_arg, type_in), - ]; - swap_data.do_ref!(|data| { - let mut bcs = bcs::new(*data); - let swap_type = swap_type::peel(&mut bcs); - - let call = if (swap_type == swap_type::deepbook_v3()) { - deepbook_v3::estimate_move_call( - package_id, - bcs, - swap_info_arg, - ) - } else if (swap_type == swap_type::sui_transfer()) { - transfers::sui_estimate_move_call( - package_id, - bcs, - swap_info_arg, - ) - } else { - assert!(swap_type == swap_type::its_transfer(), EInvalidSwapType); - transfers::its_estimate_move_call( - package_id, - bcs, - swap_info_arg, - ) - }; - move_calls.push_back(call); - }); - - swap_data.do!(|data| { - let mut bcs = bcs::new(data); - let swap_type = swap_type::peel(&mut bcs); - - let call = if (swap_type == swap_type::deepbook_v3()) { - deepbook_v3::swap_move_call( + ], + ); + + relayer_discovery.register_transaction( + squid.value!(b"register_transaction").channel(), + transaction, + ) + } + + public fun transaction(squid: &Squid, its: &InterchainTokenService, gateway: &Gateway, payload: vector): Transaction { + let (token_id, _, _, data) = interchain_token_service::discovery::interchain_transfer_info( + payload, + ); + let type_in = (*its.registered_coin_type(token_id)).into_string(); + let package_id = transaction::package_id(); + let swap_data = bcs::new(data).peel_vec_vec_u8(); + + let mut squid_arg = vector[0]; + squid_arg.append(object::id(squid).id_to_bytes()); + + let mut its_arg = vector[0]; + its_arg.append(object::id(its).id_to_bytes()); + + let mut gateway_arg = vector[0]; + gateway_arg.append(object::id(gateway).id_to_bytes()); + + let swap_info_arg = vector[4, 0, 0]; + + let mut move_calls = vector[start_swap(package_id, squid_arg, its_arg, type_in)]; + swap_data.do_ref!(|data| { + let mut bcs = bcs::new(*data); + let swap_type = swap_type::peel(&mut bcs); + + let call = if (swap_type == swap_type::deepbook_v3()) { + deepbook_v3::estimate_move_call( + package_id, + bcs, + swap_info_arg, + ) + } else if (swap_type == swap_type::sui_transfer()) { + transfers::sui_estimate_move_call( + package_id, + bcs, + swap_info_arg, + ) + } else { + assert!(swap_type == swap_type::its_transfer(), EInvalidSwapType); + transfers::its_estimate_move_call( + package_id, + bcs, + swap_info_arg, + ) + }; + move_calls.push_back(call); + }); + + swap_data.do!(|data| { + let mut bcs = bcs::new(data); + let swap_type = swap_type::peel(&mut bcs); + + let call = if (swap_type == swap_type::deepbook_v3()) { + deepbook_v3::swap_move_call( + package_id, + bcs, + swap_info_arg, + squid_arg, + ) + } else if (swap_type == swap_type::sui_transfer()) { + transfers::sui_transfer_move_call( + package_id, + bcs, + swap_info_arg, + ) + } else { + assert!(swap_type == swap_type::its_transfer(), EInvalidSwapType); + transfers::its_transfer_move_call( + package_id, + bcs, + swap_info_arg, + squid_arg, + gateway_arg, + its_arg, + ) + }; + move_calls.push_back(call); + }); + + move_calls.push_back(finalize(package_id, swap_info_arg)); + + transaction::new_transaction( + true, + move_calls, + ) + } + + fun start_swap(package_id: address, squid_arg: vector, its_arg: vector, type_in: String): MoveCall { + transaction::new_move_call( + transaction::new_function( package_id, - bcs, - swap_info_arg, - squid_arg, - ) - } else if (swap_type == swap_type::sui_transfer()) { - transfers::sui_transfer_move_call( - package_id, - bcs, - swap_info_arg, - ) - } else { - assert!(swap_type == swap_type::its_transfer(), EInvalidSwapType); - transfers::its_transfer_move_call( + ascii::string(b"squid"), + ascii::string(b"start_swap"), + ), + vector[squid_arg, its_arg, vector[2], vector[0, 6]], + vector[type_in], + ) + } + + fun finalize(package_id: address, swap_info_arg: vector): MoveCall { + transaction::new_move_call( + transaction::new_function( package_id, - bcs, - swap_info_arg, - squid_arg, - gateway_arg, - its_arg, - ) - }; - move_calls.push_back(call); - }); - - move_calls.push_back(finalize(package_id, swap_info_arg)); - - transaction::new_transaction( - true, - move_calls, - ) -} - -fun start_swap( - package_id: address, - squid_arg: vector, - its_arg: vector, - type_in: String, -): MoveCall { - transaction::new_move_call( - transaction::new_function( - package_id, - ascii::string(b"squid"), - ascii::string(b"start_swap"), - ), - vector[squid_arg, its_arg, vector[2], vector[0, 6]], - vector[type_in], - ) -} - -fun finalize(package_id: address, swap_info_arg: vector): MoveCall { - transaction::new_move_call( - transaction::new_function( - package_id, - ascii::string(b"squid"), - ascii::string(b"finalize"), - ), - vector[swap_info_arg], - vector[], - ) + ascii::string(b"squid"), + ascii::string(b"finalize"), + ), + vector[swap_info_arg], + vector[], + ) + } } diff --git a/move/squid/sources/squid/owner_cap.move b/move/squid/sources/squid/owner_cap.move index e029c8e3..bf1dce7c 100644 --- a/move/squid/sources/squid/owner_cap.move +++ b/move/squid/sources/squid/owner_cap.move @@ -1,23 +1,23 @@ -module squid::owner_cap; - -// ----- -// Types -// ----- -public struct OwnerCap has key, store { - id: UID, -} +module squid::owner_cap { + // ----- + // Types + // ----- + public struct OwnerCap has key, store { + id: UID, + } -public(package) fun create(ctx: &mut TxContext): OwnerCap { - OwnerCap { - id: object::new(ctx), + public(package) fun create(ctx: &mut TxContext): OwnerCap { + OwnerCap { + id: object::new(ctx), + } } -} -/// --------- -/// Test Only -/// --------- -#[test_only] -public(package) fun destroy_for_testing(self: OwnerCap) { - let OwnerCap { id } = self; - id.delete(); + /// --------- + /// Test Only + /// --------- + #[test_only] + public(package) fun destroy_for_testing(self: OwnerCap) { + let OwnerCap { id } = self; + id.delete(); + } } diff --git a/move/squid/sources/squid/squid.move b/move/squid/sources/squid/squid.move index eede528a..4a1ee268 100644 --- a/move/squid/sources/squid/squid.move +++ b/move/squid/sources/squid/squid.move @@ -1,313 +1,285 @@ -module squid::squid; - -use axelar_gateway::channel::ApprovedMessage; -use interchain_token_service::interchain_token_service::InterchainTokenService; -use squid::owner_cap::{Self, OwnerCap}; -use squid::squid_v0::{Self, Squid_v0}; -use squid::swap_info::SwapInfo; -use std::ascii::{Self, String}; -use sui::clock::Clock; -use sui::coin::Coin; -use sui::versioned::{Self, Versioned}; -use token::deep::DEEP; -use version_control::version_control::{Self, VersionControl}; - -// ------- -// Version -// ------- -const VERSION: u64 = 0; - -public struct Squid has key, store { - id: UID, - inner: Versioned, -} +module squid::squid { + use axelar_gateway::channel::ApprovedMessage; + use interchain_token_service::interchain_token_service::InterchainTokenService; + use squid::{owner_cap::{Self, OwnerCap}, squid_v0::{Self, Squid_v0}, swap_info::SwapInfo}; + use std::ascii::{Self, String}; + use sui::{clock::Clock, coin::Coin, versioned::{Self, Versioned}}; + use token::deep::DEEP; + use version_control::version_control::{Self, VersionControl}; + + // ------- + // Version + // ------- + const VERSION: u64 = 0; + + public struct Squid has key, store { + id: UID, + inner: Versioned, + } -fun init(ctx: &mut TxContext) { - transfer::share_object(Squid { - id: object::new(ctx), - inner: versioned::create( - VERSION, - squid_v0::new( - new_version_control(), + fun init(ctx: &mut TxContext) { + transfer::share_object(Squid { + id: object::new(ctx), + inner: versioned::create( + VERSION, + squid_v0::new( + new_version_control(), + ctx, + ), ctx, ), - ctx, - ), - }); - transfer::public_transfer(owner_cap::create(ctx), ctx.sender()); -} + }); + transfer::public_transfer(owner_cap::create(ctx), ctx.sender()); + } -// ------ -// Macros -// ------ -/// This macro retrieves the underlying versioned singleton by reference -public(package) macro fun value( - $self: &Squid, - $function_name: vector, -): &Squid_v0 { - let squid = $self; - let value = squid.inner().load_value(); - value.version_control().check(version(), ascii::string($function_name)); - value -} + // ------ + // Macros + // ------ + /// This macro retrieves the underlying versioned singleton by reference + public(package) macro fun value($self: &Squid, $function_name: vector): &Squid_v0 { + let squid = $self; + let value = squid.inner().load_value(); + value.version_control().check(version(), ascii::string($function_name)); + value + } -/// This macro retrieves the underlying versioned singleton by mutable reference -public(package) macro fun value_mut( - $self: &mut Squid, - $function_name: vector, -): &mut Squid_v0 { - let squid = $self; - let value = squid.inner_mut().load_value_mut(); - value.version_control().check(version(), ascii::string($function_name)); - value -} + /// This macro retrieves the underlying versioned singleton by mutable reference + public(package) macro fun value_mut($self: &mut Squid, $function_name: vector): &mut Squid_v0 { + let squid = $self; + let value = squid.inner_mut().load_value_mut(); + value.version_control().check(version(), ascii::string($function_name)); + value + } -// --------------- -// Entry Functions -// --------------- -entry fun give_deep(self: &mut Squid, deep: Coin) { - self.value_mut!(b"give_deep").give_deep(deep); -} + // --------------- + // Entry Functions + // --------------- + entry fun give_deep(self: &mut Squid, deep: Coin) { + self.value_mut!(b"give_deep").give_deep(deep); + } -entry fun allow_function( - self: &mut Squid, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self.value_mut!(b"allow_function").allow_function(version, function_name); -} + entry fun allow_function(self: &mut Squid, _: &OwnerCap, version: u64, function_name: String) { + self.value_mut!(b"allow_function").allow_function(version, function_name); + } -entry fun disallow_function( - self: &mut Squid, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self - .value_mut!(b"disallow_function") - .disallow_function(version, function_name); -} + entry fun disallow_function(self: &mut Squid, _: &OwnerCap, version: u64, function_name: String) { + self.value_mut!(b"disallow_function").disallow_function(version, function_name); + } -entry fun withdraw( - self: &mut Squid, - _: &OwnerCap, - amount: u64, - ctx: &mut TxContext, -) { - self.value_mut!(b"withdraw").withdraw(amount, ctx); -} + entry fun withdraw(self: &mut Squid, _: &OwnerCap, amount: u64, ctx: &mut TxContext) { + self.value_mut!(b"withdraw").withdraw(amount, ctx); + } -// ---------------- -// Public Functions -// ---------------- -public fun start_swap( - self: &mut Squid, - its: &mut InterchainTokenService, - approved_message: ApprovedMessage, - clock: &Clock, - ctx: &mut TxContext, -): SwapInfo { - self - .value_mut!(b"start_swap") - .start_swap(its, approved_message, clock, ctx) -} + // ---------------- + // Public Functions + // ---------------- + public fun start_swap( + self: &mut Squid, + its: &mut InterchainTokenService, + approved_message: ApprovedMessage, + clock: &Clock, + ctx: &mut TxContext, + ): SwapInfo { + self.value_mut!(b"start_swap").start_swap(its, approved_message, clock, ctx) + } -public fun finalize(swap_info: SwapInfo) { - swap_info.finalize(); -} + public fun finalize(swap_info: SwapInfo) { + swap_info.finalize(); + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun inner(self: &Squid): &Versioned { - &self.inner -} + // ----------------- + // Package Functions + // ----------------- + public(package) fun inner(self: &Squid): &Versioned { + &self.inner + } -public(package) fun inner_mut(self: &mut Squid): &mut Versioned { - &mut self.inner -} + public(package) fun inner_mut(self: &mut Squid): &mut Versioned { + &mut self.inner + } -public(package) fun version(): u64 { - VERSION -} + public(package) fun version(): u64 { + VERSION + } -/// ------- -/// Private -/// ------- -fun new_version_control(): VersionControl { - version_control::new(vector[ - // Version 0 - vector[ - b"start_swap", - b"its_transfer", - b"deepbook_v3_swap", - b"register_transaction", - b"give_deep", - b"allow_function", - b"disallow_function", - b"withdraw", - ].map!(|function_name| function_name.to_ascii_string()), - ]) -} + /// ------- + /// Private + /// ------- + fun new_version_control(): VersionControl { + version_control::new(vector[ + // Version 0 + vector[ + b"start_swap", + b"its_transfer", + b"deepbook_v3_swap", + b"register_transaction", + b"give_deep", + b"allow_function", + b"disallow_function", + b"withdraw", + ].map!(|function_name| function_name.to_ascii_string()), + ]) + } -/// --------- -/// Test Only -/// --------- -/// // === HUB CONSTANTS === -/// ITS Hub test chain name -#[test_only] -const ITS_HUB_CHAIN_NAME: vector = b"axelar"; - -/// ITS hub test address -#[test_only] -const ITS_HUB_ADDRESS: vector = b"hub_address"; - -#[test_only] -public fun new_for_testing(ctx: &mut TxContext): Squid { - let mut version_control = new_version_control(); - version_control.allowed_functions()[VERSION].insert(ascii::string(b"")); - Squid { - id: object::new(ctx), - inner: versioned::create( - VERSION, - squid_v0::new( - version_control, + /// --------- + /// Test Only + /// --------- + /// // === HUB CONSTANTS === + /// ITS Hub test chain name + #[test_only] + const ITS_HUB_CHAIN_NAME: vector = b"axelar"; + + /// ITS hub test address + #[test_only] + const ITS_HUB_ADDRESS: vector = b"hub_address"; + + #[test_only] + public fun new_for_testing(ctx: &mut TxContext): Squid { + let mut version_control = new_version_control(); + version_control.allowed_functions()[VERSION].insert(ascii::string(b"")); + Squid { + id: object::new(ctx), + inner: versioned::create( + VERSION, + squid_v0::new( + version_control, + ctx, + ), ctx, ), - ctx, - ), + } } -} - -#[test_only] -use interchain_token_service::coin::COIN; -/// ----- -/// Tests -/// ----- -#[test] -fun test_start_swap() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut squid = new_for_testing(ctx); - - let coin_info = interchain_token_service::coin_info::from_info( + #[test_only] + use interchain_token_service::coin::COIN; + + /// ----- + /// Tests + /// ----- + #[test] + fun test_start_swap() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut squid = new_for_testing(ctx); + + let coin_info = + interchain_token_service::coin_info::from_info( std::string::utf8(b"Name"), std::ascii::string(b"Symbol"), 10, ); - let amount = 1234; - let data = std::bcs::to_bytes(&vector>[]); - let coin_management = interchain_token_service::coin_management::new_locked(); - let coin = sui::coin::mint_for_testing(amount, ctx); - - let token_id = its.register_coin( - coin_info, - coin_management, - ); - - // This gives some coin to InterchainTokenService - let interchain_transfer_ticket = interchain_token_service::interchain_token_service::prepare_interchain_transfer( - token_id, - coin, - std::ascii::string(b"Chain Name"), - b"Destination Address", - b"", - squid.value!(b"").channel(), - ); - sui::test_utils::destroy(its.send_interchain_transfer( - interchain_transfer_ticket, - &clock, - )); - - let source_chain = std::ascii::string(b"Chain Name"); - let message_id = std::ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; - - let destination_address = squid.value!(b"").channel().to_address(); - - let mut writer = abi::abi::new_writer(6); - writer - .write_u256(0) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(data); - - let mut payload = writer.into_bytes(); - payload = interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(payload, source_chain); - - let approved_message = axelar_gateway::channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - its.channel_address(), - payload, - ); - - let swap_info = start_swap( - &mut squid, - &mut its, - approved_message, - &clock, - ctx, - ); + let amount = 1234; + let data = std::bcs::to_bytes(&vector>[]); + let coin_management = interchain_token_service::coin_management::new_locked(); + let coin = sui::coin::mint_for_testing(amount, ctx); + + let token_id = its.register_coin( + coin_info, + coin_management, + ); + + // This gives some coin to InterchainTokenService + let interchain_transfer_ticket = interchain_token_service::interchain_token_service::prepare_interchain_transfer( + token_id, + coin, + std::ascii::string(b"Chain Name"), + b"Destination Address", + b"", + squid.value!(b"").channel(), + ); + sui::test_utils::destroy(its.send_interchain_transfer( + interchain_transfer_ticket, + &clock, + )); + + let source_chain = std::ascii::string(b"Chain Name"); + let message_id = std::ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; + + let destination_address = squid.value!(b"").channel().to_address(); + + let mut writer = abi::abi::new_writer(6); + writer + .write_u256(0) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(data); + + let mut payload = writer.into_bytes(); + payload = interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(payload, source_chain); + + let approved_message = axelar_gateway::channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + its.channel_address(), + payload, + ); + + let swap_info = start_swap( + &mut squid, + &mut its, + approved_message, + &clock, + ctx, + ); - sui::test_utils::destroy(its); - sui::test_utils::destroy(squid); - sui::test_utils::destroy(swap_info); - clock.destroy_for_testing(); -} + sui::test_utils::destroy(its); + sui::test_utils::destroy(squid); + sui::test_utils::destroy(swap_info); + clock.destroy_for_testing(); + } -#[test] -fun test_init() { - let ctx = &mut tx_context::dummy(); - init(ctx); -} + #[test] + fun test_init() { + let ctx = &mut tx_context::dummy(); + init(ctx); + } -#[test] -fun test_allow_function() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new_for_testing(ctx); - let owner_cap = owner_cap::create(ctx); - let version = 0; - let function_name = b"function_name".to_ascii_string(); + #[test] + fun test_allow_function() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new_for_testing(ctx); + let owner_cap = owner_cap::create(ctx); + let version = 0; + let function_name = b"function_name".to_ascii_string(); - self.allow_function(&owner_cap, version, function_name); + self.allow_function(&owner_cap, version, function_name); - sui::test_utils::destroy(self); - owner_cap.destroy_for_testing(); -} + sui::test_utils::destroy(self); + owner_cap.destroy_for_testing(); + } -#[test] -fun test_disallow_function() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new_for_testing(ctx); - let owner_cap = owner_cap::create(ctx); - let version = 0; - let function_name = b"start_swap".to_ascii_string(); + #[test] + fun test_disallow_function() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new_for_testing(ctx); + let owner_cap = owner_cap::create(ctx); + let version = 0; + let function_name = b"start_swap".to_ascii_string(); - self.disallow_function(&owner_cap, version, function_name); + self.disallow_function(&owner_cap, version, function_name); - sui::test_utils::destroy(self); - owner_cap.destroy_for_testing(); -} + sui::test_utils::destroy(self); + owner_cap.destroy_for_testing(); + } -#[test] -fun test_withdraw() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new_for_testing(ctx); - let owner_cap = owner_cap::create(ctx); - let amount = 123; + #[test] + fun test_withdraw() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new_for_testing(ctx); + let owner_cap = owner_cap::create(ctx); + let amount = 123; - let balance = sui::balance::create_for_testing(amount); - self.value_mut!(b"").coin_bag_mut().store_balance(balance); - self.withdraw(&owner_cap, amount, ctx); + let balance = sui::balance::create_for_testing(amount); + self.value_mut!(b"").coin_bag_mut().store_balance(balance); + self.withdraw(&owner_cap, amount, ctx); - sui::test_utils::destroy(self); - owner_cap.destroy_for_testing(); + sui::test_utils::destroy(self); + owner_cap.destroy_for_testing(); + } } diff --git a/move/squid/sources/squid/swap_info.move b/move/squid/sources/squid/swap_info.move index 21d5b4bf..2ac76cc9 100644 --- a/move/squid/sources/squid/swap_info.move +++ b/move/squid/sources/squid/swap_info.move @@ -1,386 +1,380 @@ -module squid::swap_info; - -use squid::coin_bag::{Self, CoinBag}; -use sui::bcs; - -// ----- -// Enums -// ----- -/// Swapping: Curently performing swaps, should happen only after all estimation -/// is finished. -/// Estimating: Currently performing estimates. Once all estimates are done and -/// the output is satisfactory then we can swap. -/// Done: Done swapping and can be destroyed. -public enum SwapStatus has copy, drop, store { - Swapping { - index: u64, - fallback: bool, - }, - Estimating { - index: u64, - fallback: bool, - }, - Done, -} - -// ----- -// Types -// ----- -public struct SwapInfo { - status: SwapStatus, - swap_data: vector>, - coin_bag: CoinBag, -} - -// ------ -// Errors -// ------ -#[error] -const EOutOfEstimates: vector = - b"trying to get make an estimate but there are none left."; -#[error] -const EOutOfSwaps: vector = - b"trying to get make a swap but there are none left."; -#[error] -const ENotEstimating: vector = - b"trying to get an estimate but estimating is done."; -#[error] -const ENotDoneEstimating: vector = b"trying to swap while still swapping."; -#[error] -const EDoneSwapping: vector = b"trying to swap but swapping is finished."; -#[error] -const EAlreadySkippingSwaps: vector = - b"trying to skip swaps while swaps are skipped."; -#[error] -const ENotDone: vector = - b"trying to finalize but SwapInfo is not Done yet."; -#[error] -const EDoneEstimating: vector = - b"trying to estimate but estimating is finished."; - -// ----------------- -// Package Functions -// ----------------- -public(package) fun new(data: vector, ctx: &mut TxContext): SwapInfo { - let swap_data = bcs::new(data).peel_vec_vec_u8(); - SwapInfo { - status: SwapStatus::Estimating { index: 0, fallback: false }, - coin_bag: coin_bag::new(ctx), - swap_data, +module squid::swap_info { + use squid::coin_bag::{Self, CoinBag}; + use sui::bcs; + + // ----- + // Enums + // ----- + /// Swapping: Curently performing swaps, should happen only after all estimation + /// is finished. + /// Estimating: Currently performing estimates. Once all estimates are done and + /// the output is satisfactory then we can swap. + /// Done: Done swapping and can be destroyed. + public enum SwapStatus has copy, drop, store { + Swapping { + index: u64, + fallback: bool, + }, + Estimating { + index: u64, + fallback: bool, + }, + Done, } -} -public(package) fun data_swapping(self: &mut SwapInfo): (vector, bool) { - let (index, fallback) = match (self.status) { - SwapStatus::Swapping { index, fallback } => (index, fallback), - SwapStatus::Estimating { .. } => abort (ENotDoneEstimating), - SwapStatus::Done => abort (EDoneSwapping), - }; + // ----- + // Types + // ----- + public struct SwapInfo { + status: SwapStatus, + swap_data: vector>, + coin_bag: CoinBag, + } - assert!(index < self.swap_data.length(), EOutOfSwaps); + // ------ + // Errors + // ------ + #[error] + const EOutOfEstimates: vector = b"trying to get make an estimate but there are none left."; + #[error] + const EOutOfSwaps: vector = b"trying to get make a swap but there are none left."; + #[error] + const ENotEstimating: vector = b"trying to get an estimate but estimating is done."; + #[error] + const ENotDoneEstimating: vector = b"trying to swap while still swapping."; + #[error] + const EDoneSwapping: vector = b"trying to swap but swapping is finished."; + #[error] + const EAlreadySkippingSwaps: vector = b"trying to skip swaps while swaps are skipped."; + #[error] + const ENotDone: vector = b"trying to finalize but SwapInfo is not Done yet."; + #[error] + const EDoneEstimating: vector = b"trying to estimate but estimating is finished."; + + // ----------------- + // Package Functions + // ----------------- + public(package) fun new(data: vector, ctx: &mut TxContext): SwapInfo { + let swap_data = bcs::new(data).peel_vec_vec_u8(); + SwapInfo { + status: SwapStatus::Estimating { index: 0, fallback: false }, + coin_bag: coin_bag::new(ctx), + swap_data, + } + } - self.status = if (index + 1 < self.swap_data.length()) { - SwapStatus::Swapping { index: index + 1, fallback } - } else { - SwapStatus::Done + public(package) fun data_swapping(self: &mut SwapInfo): (vector, bool) { + let (index, fallback) = match (self.status) { + SwapStatus::Swapping { index, fallback } => (index, fallback), + SwapStatus::Estimating { .. } => abort (ENotDoneEstimating), + SwapStatus::Done => abort (EDoneSwapping), }; - (self.swap_data[index], fallback) -} + assert!(index < self.swap_data.length(), EOutOfSwaps); -public(package) fun data_estimating(self: &mut SwapInfo): (vector, bool) { - let (index, fallback) = match (self.status) { - SwapStatus::Estimating { index, fallback } => (index, fallback), - _ => abort (EDoneEstimating), - }; + self.status = if (index + 1 < self.swap_data.length()) { + SwapStatus::Swapping { index: index + 1, fallback } + } else { + SwapStatus::Done + }; - assert!(index < self.swap_data.length(), EOutOfEstimates); + (self.swap_data[index], fallback) + } - self.status = if (index + 1 < self.swap_data.length()) { - SwapStatus::Estimating { index: index + 1, fallback } - } else { - SwapStatus::Swapping { index: 0, fallback } + public(package) fun data_estimating(self: &mut SwapInfo): (vector, bool) { + let (index, fallback) = match (self.status) { + SwapStatus::Estimating { index, fallback } => (index, fallback), + _ => abort (EDoneEstimating), }; - (self.swap_data[index], fallback) -} + assert!(index < self.swap_data.length(), EOutOfEstimates); -public(package) fun coin_bag(self: &mut SwapInfo): &mut CoinBag { - &mut self.coin_bag -} + self.status = if (index + 1 < self.swap_data.length()) { + SwapStatus::Estimating { index: index + 1, fallback } + } else { + SwapStatus::Swapping { index: 0, fallback } + }; + + (self.swap_data[index], fallback) + } -public(package) fun skip_swap(self: &mut SwapInfo) { - self.status = + public(package) fun coin_bag(self: &mut SwapInfo): &mut CoinBag { + &mut self.coin_bag + } + + public(package) fun skip_swap(self: &mut SwapInfo) { + self.status = + match (self.status) { + SwapStatus::Estimating { + index, + fallback: false, + } => SwapStatus::Estimating { index, fallback: true }, + SwapStatus::Estimating { .. } => abort (EAlreadySkippingSwaps), + _ => abort (ENotEstimating), + }; + } + + public(package) fun finalize(self: SwapInfo) { match (self.status) { - SwapStatus::Estimating { - index, - fallback: false, - } => SwapStatus::Estimating { index, fallback: true }, - SwapStatus::Estimating { .. } => abort (EAlreadySkippingSwaps), - _ => abort (ENotEstimating), + SwapStatus::Done => self.destroy(), + _ => abort (ENotDone), }; -} - -public(package) fun finalize(self: SwapInfo) { - match (self.status) { - SwapStatus::Done => self.destroy(), - _ => abort (ENotDone), - }; -} + } -fun destroy(self: SwapInfo) { - let SwapInfo { - status: _, - swap_data: _, - coin_bag, - } = self; - coin_bag.destroy(); -} + fun destroy(self: SwapInfo) { + let SwapInfo { + status: _, + swap_data: _, + coin_bag, + } = self; + coin_bag.destroy(); + } -#[test] -fun test_swap_data() { - let ctx = &mut tx_context::dummy(); + #[test] + fun test_swap_data() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); + let mut swap_info = new(data, ctx); - let (mut data, _) = swap_info.data_estimating(); - assert!(data == swap1); - (data, _) = swap_info.data_estimating(); - assert!(data == swap2); - (data, _) = swap_info.data_swapping(); - assert!(data == swap1); - (data, _) = swap_info.data_swapping(); - assert!(data == swap2); + let (mut data, _) = swap_info.data_estimating(); + assert!(data == swap1); + (data, _) = swap_info.data_estimating(); + assert!(data == swap2); + (data, _) = swap_info.data_swapping(); + assert!(data == swap1); + (data, _) = swap_info.data_swapping(); + assert!(data == swap2); - swap_info.finalize(); -} + swap_info.finalize(); + } -#[test] -#[expected_failure(abort_code = ENotDoneEstimating)] -fun test_get_data_swapping_not_done_estimating() { - let ctx = &mut tx_context::dummy(); + #[test] + #[expected_failure(abort_code = ENotDoneEstimating)] + fun test_get_data_swapping_not_done_estimating() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); + let mut swap_info = new(data, ctx); - swap_info.data_swapping(); + swap_info.data_swapping(); - swap_info.destroy(); -} + swap_info.destroy(); + } -#[test] -#[expected_failure(abort_code = EDoneSwapping)] -fun test_get_data_swapping_done_swapping() { - let ctx = &mut tx_context::dummy(); + #[test] + #[expected_failure(abort_code = EDoneSwapping)] + fun test_get_data_swapping_done_swapping() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); - swap_info.status = SwapStatus::Done; + let mut swap_info = new(data, ctx); + swap_info.status = SwapStatus::Done; - swap_info.data_swapping(); + swap_info.data_swapping(); - swap_info.destroy(); -} + swap_info.destroy(); + } -#[test] -#[expected_failure(abort_code = EOutOfSwaps)] -fun test_get_data_swapping_out_of_swaps() { - let ctx = &mut tx_context::dummy(); + #[test] + #[expected_failure(abort_code = EOutOfSwaps)] + fun test_get_data_swapping_out_of_swaps() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); - swap_info.status = SwapStatus::Swapping { index: 2, fallback: false }; + let mut swap_info = new(data, ctx); + swap_info.status = SwapStatus::Swapping { index: 2, fallback: false }; - swap_info.data_swapping(); + swap_info.data_swapping(); - swap_info.destroy(); -} + swap_info.destroy(); + } -#[test] -#[expected_failure(abort_code = EAlreadySkippingSwaps)] -fun test_skip_swap_already_skipped_swaps() { - let ctx = &mut tx_context::dummy(); + #[test] + #[expected_failure(abort_code = EAlreadySkippingSwaps)] + fun test_skip_swap_already_skipped_swaps() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); + let mut swap_info = new(data, ctx); - swap_info.skip_swap(); - swap_info.skip_swap(); + swap_info.skip_swap(); + swap_info.skip_swap(); - swap_info.destroy(); -} + swap_info.destroy(); + } -#[test] -#[expected_failure(abort_code = ENotEstimating)] -fun test_skip_swap_already_not_estimating_swapping() { - let ctx = &mut tx_context::dummy(); + #[test] + #[expected_failure(abort_code = ENotEstimating)] + fun test_skip_swap_already_not_estimating_swapping() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); - swap_info.status = SwapStatus::Swapping { index: 0, fallback: false }; + let mut swap_info = new(data, ctx); + swap_info.status = SwapStatus::Swapping { index: 0, fallback: false }; - swap_info.skip_swap(); - swap_info.skip_swap(); + swap_info.skip_swap(); + swap_info.skip_swap(); - swap_info.destroy(); -} + swap_info.destroy(); + } -#[test] -#[expected_failure(abort_code = ENotEstimating)] -fun test_skip_swap_already_not_estimating_done() { - let ctx = &mut tx_context::dummy(); + #[test] + #[expected_failure(abort_code = ENotEstimating)] + fun test_skip_swap_already_not_estimating_done() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); - swap_info.status = SwapStatus::Done; + let mut swap_info = new(data, ctx); + swap_info.status = SwapStatus::Done; - swap_info.skip_swap(); - swap_info.skip_swap(); + swap_info.skip_swap(); + swap_info.skip_swap(); - swap_info.destroy(); -} + swap_info.destroy(); + } -#[test] -fun test_get_data_swapping_skip_swap() { - let ctx = &mut tx_context::dummy(); + #[test] + fun test_get_data_swapping_skip_swap() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); - swap_info.status = SwapStatus::Swapping { index: 0, fallback: true }; + let mut swap_info = new(data, ctx); + swap_info.status = SwapStatus::Swapping { index: 0, fallback: true }; - swap_info.data_swapping(); + swap_info.data_swapping(); - swap_info.destroy(); -} + swap_info.destroy(); + } -#[test] -#[expected_failure(abort_code = EOutOfEstimates)] -fun test_get_data_estimating_out_of_swaps() { - let ctx = &mut tx_context::dummy(); + #[test] + #[expected_failure(abort_code = EOutOfEstimates)] + fun test_get_data_estimating_out_of_swaps() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); - swap_info.status = SwapStatus::Estimating { index: 2, fallback: false }; + let mut swap_info = new(data, ctx); + swap_info.status = SwapStatus::Estimating { index: 2, fallback: false }; - swap_info.data_estimating(); + swap_info.data_estimating(); - swap_info.destroy(); -} + swap_info.destroy(); + } -#[test] -#[expected_failure(abort_code = EDoneEstimating)] -fun test_get_data_estimating_swapping() { - let ctx = &mut tx_context::dummy(); + #[test] + #[expected_failure(abort_code = EDoneEstimating)] + fun test_get_data_estimating_swapping() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); - swap_info.status = SwapStatus::Swapping { index: 0, fallback: false }; + let mut swap_info = new(data, ctx); + swap_info.status = SwapStatus::Swapping { index: 0, fallback: false }; - swap_info.data_estimating(); + swap_info.data_estimating(); - swap_info.destroy(); -} + swap_info.destroy(); + } -#[test] -#[expected_failure(abort_code = EDoneEstimating)] -fun test_get_data_estimating_done() { - let ctx = &mut tx_context::dummy(); + #[test] + #[expected_failure(abort_code = EDoneEstimating)] + fun test_get_data_estimating_done() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); - swap_info.status = SwapStatus::Done; + let mut swap_info = new(data, ctx); + swap_info.status = SwapStatus::Done; - swap_info.data_estimating(); + swap_info.data_estimating(); - swap_info.destroy(); -} + swap_info.destroy(); + } -#[test] -fun test_get_data_estimating_skip_swap() { - let ctx = &mut tx_context::dummy(); + #[test] + fun test_get_data_estimating_skip_swap() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); - swap_info.skip_swap(); + let mut swap_info = new(data, ctx); + swap_info.skip_swap(); - swap_info.data_estimating(); + swap_info.data_estimating(); - swap_info.destroy(); -} + swap_info.destroy(); + } -#[test] -#[expected_failure(abort_code = ENotDone)] -fun test_finalize_not_done_swapping() { - let ctx = &mut tx_context::dummy(); + #[test] + #[expected_failure(abort_code = ENotDone)] + fun test_finalize_not_done_swapping() { + let ctx = &mut tx_context::dummy(); - let swap1 = b"1"; - let swap2 = b"2"; + let swap1 = b"1"; + let swap2 = b"2"; - let data = std::bcs::to_bytes(&vector[swap1, swap2]); + let data = std::bcs::to_bytes(&vector[swap1, swap2]); - let mut swap_info = new(data, ctx); - swap_info.status = SwapStatus::Swapping { index: 0, fallback: false }; + let mut swap_info = new(data, ctx); + swap_info.status = SwapStatus::Swapping { index: 0, fallback: false }; - swap_info.finalize(); -} + swap_info.finalize(); + } -#[test] -#[expected_failure(abort_code = ENotDone)] -fun test_finalize_not_done_estimating() { - let ctx = &mut tx_context::dummy(); + #[test] + #[expected_failure(abort_code = ENotDone)] + fun test_finalize_not_done_estimating() { + let ctx = &mut tx_context::dummy(); - let data = std::bcs::to_bytes(&vector>[]); + let data = std::bcs::to_bytes(&vector>[]); - let swap_info = new(data, ctx); + let swap_info = new(data, ctx); - swap_info.finalize(); + swap_info.finalize(); + } } diff --git a/move/squid/sources/squid/swap_type.move b/move/squid/sources/squid/swap_type.move index a2a3f523..943e6cca 100644 --- a/move/squid/sources/squid/swap_type.move +++ b/move/squid/sources/squid/swap_type.move @@ -1,46 +1,46 @@ -module squid::swap_type; +module squid::swap_type { + use sui::bcs::BCS; -use sui::bcs::BCS; + // ------ + // Errors + // ------ + #[error] + const EInvalidSwapType: vector = b"invalid swap type."; -// ------ -// Errors -// ------ -#[error] -const EInvalidSwapType: vector = b"invalid swap type."; - -// ----- -// Enums -// ----- -public enum SwapType has drop, copy, store { - DeepbookV3, - SuiTransfer, - ItsTransfer, -} - -// ----------------- -// Package Functions -// ----------------- -public(package) fun deepbook_v3(): SwapType { - SwapType::DeepbookV3 -} - -public(package) fun sui_transfer(): SwapType { - SwapType::SuiTransfer -} - -public(package) fun its_transfer(): SwapType { - SwapType::ItsTransfer -} + // ----- + // Enums + // ----- + public enum SwapType has copy, drop, store { + DeepbookV3, + SuiTransfer, + ItsTransfer, + } -public(package) fun peel(bcs: &mut BCS): SwapType { - let swap_type = bcs.peel_u8(); - if (swap_type == 0) { + // ----------------- + // Package Functions + // ----------------- + public(package) fun deepbook_v3(): SwapType { SwapType::DeepbookV3 - } else if (swap_type == 1) { + } + + public(package) fun sui_transfer(): SwapType { SwapType::SuiTransfer - } else if (swap_type == 2) { + } + + public(package) fun its_transfer(): SwapType { SwapType::ItsTransfer - } else { - abort (EInvalidSwapType) + } + + public(package) fun peel(bcs: &mut BCS): SwapType { + let swap_type = bcs.peel_u8(); + if (swap_type == 0) { + SwapType::DeepbookV3 + } else if (swap_type == 1) { + SwapType::SuiTransfer + } else if (swap_type == 2) { + SwapType::ItsTransfer + } else { + abort (EInvalidSwapType) + } } } diff --git a/move/squid/sources/squid/transfers.move b/move/squid/sources/squid/transfers.move index 98166fcd..7a6d22d9 100644 --- a/move/squid/sources/squid/transfers.move +++ b/move/squid/sources/squid/transfers.move @@ -1,241 +1,210 @@ -module squid::transfers; - -use axelar_gateway::gateway::Gateway; -use interchain_token_service::interchain_token_service::{Self, InterchainTokenService}; -use interchain_token_service::token_id::{Self, TokenId}; -use relayer_discovery::transaction::{Self, MoveCall}; -use squid::squid::Squid; -use squid::swap_info::SwapInfo; -use squid::swap_type::{Self, SwapType}; -use std::ascii::{Self, String}; -use std::type_name; -use sui::bcs::BCS; -use sui::clock::Clock; -use sui::coin; -use utils::utils::peel; - -#[error] -const EWrongSwapType: vector = b"wrong swap type"; -#[error] -const EWrongCoinType: vector = - b"expected coin type does not match type argument"; - -/// fallback states whether this transfer happens normally or only on fallback -/// mode. -public struct SuiTransferSwapData has drop { - swap_type: SwapType, - coin_type: String, - recipient: address, - fallback: bool, -} +module squid::transfers { + use axelar_gateway::gateway::Gateway; + use interchain_token_service::{interchain_token_service::{Self, InterchainTokenService}, token_id::{Self, TokenId}}; + use relayer_discovery::transaction::{Self, MoveCall}; + use squid::{squid::Squid, swap_info::SwapInfo, swap_type::{Self, SwapType}}; + use std::{ascii::{Self, String}, type_name}; + use sui::{bcs::BCS, clock::Clock, coin}; + use utils::utils::peel; + + #[error] + const EWrongSwapType: vector = b"wrong swap type"; + #[error] + const EWrongCoinType: vector = b"expected coin type does not match type argument"; + + /// fallback states whether this transfer happens normally or only on fallback + /// mode. + public struct SuiTransferSwapData has drop { + swap_type: SwapType, + coin_type: String, + recipient: address, + fallback: bool, + } -/// fallback states whether this transfer happens normally or only on fallback -/// mode. -public struct ItsTransferSwapData has drop { - swap_type: SwapType, - coin_type: String, - token_id: TokenId, - destination_chain: String, - destination_address: vector, - metadata: vector, - fallback: bool, -} + /// fallback states whether this transfer happens normally or only on fallback + /// mode. + public struct ItsTransferSwapData has drop { + swap_type: SwapType, + coin_type: String, + token_id: TokenId, + destination_chain: String, + destination_address: vector, + metadata: vector, + fallback: bool, + } -fun new_sui_transfer_swap_data(bcs: &mut BCS): SuiTransferSwapData { - SuiTransferSwapData { - swap_type: swap_type::peel(bcs), - coin_type: ascii::string(bcs.peel_vec_u8()), - recipient: bcs.peel_address(), - fallback: bcs.peel_bool(), + fun new_sui_transfer_swap_data(bcs: &mut BCS): SuiTransferSwapData { + SuiTransferSwapData { + swap_type: swap_type::peel(bcs), + coin_type: ascii::string(bcs.peel_vec_u8()), + recipient: bcs.peel_address(), + fallback: bcs.peel_bool(), + } } -} -fun new_its_transfer_swap_data(bcs: &mut BCS): ItsTransferSwapData { - ItsTransferSwapData { - swap_type: swap_type::peel(bcs), - coin_type: ascii::string(bcs.peel_vec_u8()), - token_id: token_id::from_address(bcs.peel_address()), - destination_chain: ascii::string(bcs.peel_vec_u8()), - destination_address: bcs.peel_vec_u8(), - metadata: bcs.peel_vec_u8(), - fallback: bcs.peel_bool(), + fun new_its_transfer_swap_data(bcs: &mut BCS): ItsTransferSwapData { + ItsTransferSwapData { + swap_type: swap_type::peel(bcs), + coin_type: ascii::string(bcs.peel_vec_u8()), + token_id: token_id::from_address(bcs.peel_address()), + destination_chain: ascii::string(bcs.peel_vec_u8()), + destination_address: bcs.peel_vec_u8(), + metadata: bcs.peel_vec_u8(), + fallback: bcs.peel_bool(), + } } -} -public fun sui_estimate(swap_info: &mut SwapInfo) { - let (data, fallback) = swap_info.data_estimating(); - if (fallback) return; - let swap_data = peel!(data, |data| new_sui_transfer_swap_data(data)); + public fun sui_estimate(swap_info: &mut SwapInfo) { + let (data, fallback) = swap_info.data_estimating(); + if (fallback) return; + let swap_data = peel!(data, |data| new_sui_transfer_swap_data(data)); - assert!(swap_data.swap_type == swap_type::sui_transfer(), EWrongSwapType); + assert!(swap_data.swap_type == swap_type::sui_transfer(), EWrongSwapType); - assert!( - &swap_data.coin_type == &type_name::get().into_string(), - EWrongCoinType, - ); + assert!(&swap_data.coin_type == &type_name::get().into_string(), EWrongCoinType); - swap_info.coin_bag().estimate(); -} + swap_info.coin_bag().estimate(); + } -public fun its_estimate(swap_info: &mut SwapInfo) { - let (data, fallback) = swap_info.data_estimating(); - if (fallback) return; - let swap_data = peel!(data, |data| new_its_transfer_swap_data(data)); + public fun its_estimate(swap_info: &mut SwapInfo) { + let (data, fallback) = swap_info.data_estimating(); + if (fallback) return; + let swap_data = peel!(data, |data| new_its_transfer_swap_data(data)); - assert!(swap_data.swap_type == swap_type::its_transfer(), EWrongSwapType); + assert!(swap_data.swap_type == swap_type::its_transfer(), EWrongSwapType); - assert!( - &swap_data.coin_type == &type_name::get().into_string(), - EWrongCoinType, - ); + assert!(&swap_data.coin_type == &type_name::get().into_string(), EWrongCoinType); - swap_info.coin_bag().estimate(); -} + swap_info.coin_bag().estimate(); + } -public fun sui_transfer(swap_info: &mut SwapInfo, ctx: &mut TxContext) { - let (data, fallback) = swap_info.data_swapping(); - let swap_data = peel!(data, |data| new_sui_transfer_swap_data(data)); + public fun sui_transfer(swap_info: &mut SwapInfo, ctx: &mut TxContext) { + let (data, fallback) = swap_info.data_swapping(); + let swap_data = peel!(data, |data| new_sui_transfer_swap_data(data)); - // This check allows to skip the transfer if the `fallback` state does not - // match the state of the transaction here. - if (fallback != swap_data.fallback) return; + // This check allows to skip the transfer if the `fallback` state does not + // match the state of the transaction here. + if (fallback != swap_data.fallback) return; - assert!(swap_data.swap_type == swap_type::sui_transfer(), EWrongSwapType); + assert!(swap_data.swap_type == swap_type::sui_transfer(), EWrongSwapType); - assert!( - &swap_data.coin_type == &type_name::get().into_string(), - EWrongCoinType, - ); + assert!(&swap_data.coin_type == &type_name::get().into_string(), EWrongCoinType); - let option = swap_info.coin_bag().balance(); - if (option.is_none()) { - option.destroy_none(); - return - }; + let option = swap_info.coin_bag().balance(); + if (option.is_none()) { + option.destroy_none(); + return + }; - transfer::public_transfer( - coin::from_balance(option.destroy_some(), ctx), - swap_data.recipient, - ); -} + transfer::public_transfer( + coin::from_balance(option.destroy_some(), ctx), + swap_data.recipient, + ); + } -// TODO: This will break squid for now, since the MessageTicket is not submitted -// by discovery. -public fun its_transfer( - swap_info: &mut SwapInfo, - squid: &Squid, - its: &mut InterchainTokenService, - gateway: &Gateway, - clock: &Clock, - ctx: &mut TxContext, -) { - let value = squid.value!(b"its_transfer"); - - let (data, fallback) = swap_info.data_swapping(); - - if (data.length() == 0) return; - let swap_data = peel!(data, |data| new_its_transfer_swap_data(data)); - - // This check allows to skip the transfer if the `fallback` state does not - // match the state of the transaction here. - if (fallback != swap_data.fallback) return; - - assert!(swap_data.swap_type == swap_type::its_transfer(), EWrongSwapType); - - assert!( - &swap_data.coin_type == &type_name::get().into_string(), - EWrongCoinType, - ); - - let option = swap_info.coin_bag().balance(); - if (option.is_none()) { - option.destroy_none(); - return - }; - - let interchain_transfer_ticket = interchain_token_service::prepare_interchain_transfer( - swap_data.token_id, - coin::from_balance(option.destroy_some(), ctx), - swap_data.destination_chain, - swap_data.destination_address, - swap_data.metadata, - value.channel(), - ); - - let message_ticket = its.send_interchain_transfer( - interchain_transfer_ticket, - clock, - ); - gateway.send_message(message_ticket); -} + // TODO: This will break squid for now, since the MessageTicket is not submitted + // by discovery. + public fun its_transfer( + swap_info: &mut SwapInfo, + squid: &Squid, + its: &mut InterchainTokenService, + gateway: &Gateway, + clock: &Clock, + ctx: &mut TxContext, + ) { + let value = squid.value!(b"its_transfer"); + + let (data, fallback) = swap_info.data_swapping(); + + if (data.length() == 0) return; + let swap_data = peel!(data, |data| new_its_transfer_swap_data(data)); + + // This check allows to skip the transfer if the `fallback` state does not + // match the state of the transaction here. + if (fallback != swap_data.fallback) return; + + assert!(swap_data.swap_type == swap_type::its_transfer(), EWrongSwapType); + + assert!(&swap_data.coin_type == &type_name::get().into_string(), EWrongCoinType); + + let option = swap_info.coin_bag().balance(); + if (option.is_none()) { + option.destroy_none(); + return + }; + + let interchain_transfer_ticket = interchain_token_service::prepare_interchain_transfer( + swap_data.token_id, + coin::from_balance(option.destroy_some(), ctx), + swap_data.destination_chain, + swap_data.destination_address, + swap_data.metadata, + value.channel(), + ); + + let message_ticket = its.send_interchain_transfer( + interchain_transfer_ticket, + clock, + ); + gateway.send_message(message_ticket); + } -public(package) fun sui_estimate_move_call( - package_id: address, - mut bcs: BCS, - swap_info_arg: vector, -): MoveCall { - let type_arg = ascii::string(bcs.peel_vec_u8()); - transaction::new_move_call( - transaction::new_function( - package_id, - ascii::string(b"transfers"), - ascii::string(b"sui_estimate"), - ), - vector[swap_info_arg], - vector[type_arg], - ) -} + public(package) fun sui_estimate_move_call(package_id: address, mut bcs: BCS, swap_info_arg: vector): MoveCall { + let type_arg = ascii::string(bcs.peel_vec_u8()); + transaction::new_move_call( + transaction::new_function( + package_id, + ascii::string(b"transfers"), + ascii::string(b"sui_estimate"), + ), + vector[swap_info_arg], + vector[type_arg], + ) + } -public(package) fun its_estimate_move_call( - package_id: address, - mut bcs: BCS, - swap_info_arg: vector, -): MoveCall { - let type_arg = ascii::string(bcs.peel_vec_u8()); - transaction::new_move_call( - transaction::new_function( - package_id, - ascii::string(b"transfers"), - ascii::string(b"its_estimate"), - ), - vector[swap_info_arg], - vector[type_arg], - ) -} + public(package) fun its_estimate_move_call(package_id: address, mut bcs: BCS, swap_info_arg: vector): MoveCall { + let type_arg = ascii::string(bcs.peel_vec_u8()); + transaction::new_move_call( + transaction::new_function( + package_id, + ascii::string(b"transfers"), + ascii::string(b"its_estimate"), + ), + vector[swap_info_arg], + vector[type_arg], + ) + } -public(package) fun sui_transfer_move_call( - package_id: address, - mut bcs: BCS, - swap_info_arg: vector, -): MoveCall { - let type_arg = ascii::string(bcs.peel_vec_u8()); - transaction::new_move_call( - transaction::new_function( - package_id, - ascii::string(b"transfers"), - ascii::string(b"sui_transfer"), - ), - vector[swap_info_arg], - vector[type_arg], - ) -} + public(package) fun sui_transfer_move_call(package_id: address, mut bcs: BCS, swap_info_arg: vector): MoveCall { + let type_arg = ascii::string(bcs.peel_vec_u8()); + transaction::new_move_call( + transaction::new_function( + package_id, + ascii::string(b"transfers"), + ascii::string(b"sui_transfer"), + ), + vector[swap_info_arg], + vector[type_arg], + ) + } -public(package) fun its_transfer_move_call( - package_id: address, - mut bcs: BCS, - swap_info_arg: vector, - squid_arg: vector, - its_arg: vector, - gateway_arg: vector, -): MoveCall { - let type_arg = ascii::string(bcs.peel_vec_u8()); - transaction::new_move_call( - transaction::new_function( - package_id, - ascii::string(b"transfers"), - ascii::string(b"its_transfer"), - ), - vector[swap_info_arg, squid_arg, its_arg, gateway_arg, vector[0, 6]], - vector[type_arg], - ) + public(package) fun its_transfer_move_call( + package_id: address, + mut bcs: BCS, + swap_info_arg: vector, + squid_arg: vector, + its_arg: vector, + gateway_arg: vector, + ): MoveCall { + let type_arg = ascii::string(bcs.peel_vec_u8()); + transaction::new_move_call( + transaction::new_function( + package_id, + ascii::string(b"transfers"), + ascii::string(b"its_transfer"), + ), + vector[swap_info_arg, squid_arg, its_arg, gateway_arg, vector[0, 6]], + vector[type_arg], + ) + } } diff --git a/move/squid/sources/squid/versioned/squid_v0.move b/move/squid/sources/squid/versioned/squid_v0.move index f8cb242f..d85289d6 100644 --- a/move/squid/sources/squid/versioned/squid_v0.move +++ b/move/squid/sources/squid/versioned/squid_v0.move @@ -1,203 +1,187 @@ -module squid::squid_v0; - -use axelar_gateway::channel::{Self, Channel, ApprovedMessage}; -use interchain_token_service::interchain_token_service::InterchainTokenService; -use squid::coin_bag::{Self, CoinBag}; -use squid::swap_info::{Self, SwapInfo}; -use std::ascii::String; -use sui::clock::Clock; -use sui::coin::{Self, Coin}; -use token::deep::DEEP; -use version_control::version_control::VersionControl; - -// ----- -// Types -// ----- -public struct Squid_v0 has store { - channel: Channel, - coin_bag: CoinBag, - version_control: VersionControl, -} +module squid::squid_v0 { + use axelar_gateway::channel::{Self, Channel, ApprovedMessage}; + use interchain_token_service::interchain_token_service::InterchainTokenService; + use squid::{coin_bag::{Self, CoinBag}, swap_info::{Self, SwapInfo}}; + use std::ascii::String; + use sui::{clock::Clock, coin::{Self, Coin}}; + use token::deep::DEEP; + use version_control::version_control::VersionControl; + + // ----- + // Types + // ----- + public struct Squid_v0 has store { + channel: Channel, + coin_bag: CoinBag, + version_control: VersionControl, + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun new( - version_control: VersionControl, - ctx: &mut TxContext, -): Squid_v0 { - Squid_v0 { - channel: channel::new(ctx), - coin_bag: coin_bag::new(ctx), - version_control, + // ----------------- + // Package Functions + // ----------------- + public(package) fun new(version_control: VersionControl, ctx: &mut TxContext): Squid_v0 { + Squid_v0 { + channel: channel::new(ctx), + coin_bag: coin_bag::new(ctx), + version_control, + } } -} -public(package) fun channel(self: &Squid_v0): &Channel { - &self.channel -} + public(package) fun channel(self: &Squid_v0): &Channel { + &self.channel + } -public(package) fun version_control(self: &Squid_v0): &VersionControl { - &self.version_control -} + public(package) fun version_control(self: &Squid_v0): &VersionControl { + &self.version_control + } -public(package) fun coin_bag_mut(self: &mut Squid_v0): &mut CoinBag { - &mut self.coin_bag -} + public(package) fun coin_bag_mut(self: &mut Squid_v0): &mut CoinBag { + &mut self.coin_bag + } -public(package) fun start_swap( - self: &Squid_v0, - its: &mut InterchainTokenService, - approved_message: ApprovedMessage, - clock: &Clock, - ctx: &mut TxContext, -): SwapInfo { - let (_, _, data, coin) = its.receive_interchain_transfer_with_data( - approved_message, - self.channel(), - clock, - ctx, - ); - let mut swap_info = swap_info::new(data, ctx); - swap_info.coin_bag().store_estimate(coin.value()); - swap_info.coin_bag().store_balance(coin.into_balance()); - swap_info -} + public(package) fun start_swap( + self: &Squid_v0, + its: &mut InterchainTokenService, + approved_message: ApprovedMessage, + clock: &Clock, + ctx: &mut TxContext, + ): SwapInfo { + let (_, _, data, coin) = its.receive_interchain_transfer_with_data( + approved_message, + self.channel(), + clock, + ctx, + ); + let mut swap_info = swap_info::new(data, ctx); + swap_info.coin_bag().store_estimate(coin.value()); + swap_info.coin_bag().store_balance(coin.into_balance()); + swap_info + } -public(package) fun give_deep(self: &mut Squid_v0, deep: Coin) { - self.coin_bag.store_balance(deep.into_balance()); -} + public(package) fun give_deep(self: &mut Squid_v0, deep: Coin) { + self.coin_bag.store_balance(deep.into_balance()); + } -public(package) fun allow_function( - self: &mut Squid_v0, - version: u64, - function_name: String, -) { - self.version_control.allow_function(version, function_name); -} + public(package) fun allow_function(self: &mut Squid_v0, version: u64, function_name: String) { + self.version_control.allow_function(version, function_name); + } -public(package) fun disallow_function( - self: &mut Squid_v0, - version: u64, - function_name: String, -) { - self.version_control.disallow_function(version, function_name); -} + public(package) fun disallow_function(self: &mut Squid_v0, version: u64, function_name: String) { + self.version_control.disallow_function(version, function_name); + } -#[allow(lint(self_transfer))] -public(package) fun withdraw( - self: &mut Squid_v0, - amount: u64, - ctx: &mut TxContext, -) { - let balance = self.coin_bag.exact_balance(amount); - transfer::public_transfer(coin::from_balance(balance, ctx), ctx.sender()); -} + #[allow(lint(self_transfer))] + public(package) fun withdraw(self: &mut Squid_v0, amount: u64, ctx: &mut TxContext) { + let balance = self.coin_bag.exact_balance(amount); + transfer::public_transfer(coin::from_balance(balance, ctx), ctx.sender()); + } -/// --------- -/// Test Only -/// --------- -/// // === HUB CONSTANTS === -// Axelar. -#[test_only] -const ITS_HUB_CHAIN_NAME: vector = b"axelar"; -// The address of the ITS HUB. -#[test_only] -const ITS_HUB_ADDRESS: vector = b"hub_address"; - -#[test_only] -public fun new_for_testing(ctx: &mut TxContext): Squid_v0 { - Squid_v0 { - channel: channel::new(ctx), - coin_bag: coin_bag::new(ctx), - version_control: version_control::version_control::new(vector[]), + /// --------- + /// Test Only + /// --------- + /// // === HUB CONSTANTS === + // Axelar. + #[test_only] + const ITS_HUB_CHAIN_NAME: vector = b"axelar"; + // The address of the ITS HUB. + #[test_only] + const ITS_HUB_ADDRESS: vector = b"hub_address"; + + #[test_only] + public fun new_for_testing(ctx: &mut TxContext): Squid_v0 { + Squid_v0 { + channel: channel::new(ctx), + coin_bag: coin_bag::new(ctx), + version_control: version_control::version_control::new(vector[]), + } } -} -#[test_only] -use interchain_token_service::coin::COIN; -#[test_only] -use sui::test_utils::destroy; + #[test_only] + use interchain_token_service::coin::COIN; + #[test_only] + use sui::test_utils::destroy; -#[test] -fun test_start_swap() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let squid = new_for_testing(ctx); + #[test] + fun test_start_swap() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let squid = new_for_testing(ctx); - let coin_info = interchain_token_service::coin_info::from_info( + let coin_info = + interchain_token_service::coin_info::from_info( std::string::utf8(b"Name"), std::ascii::string(b"Symbol"), 10, ); - let amount = 1234; - let data = std::bcs::to_bytes(&vector>[]); - let coin_management = interchain_token_service::coin_management::new_locked(); - let coin = sui::coin::mint_for_testing(amount, ctx); - - let token_id = its.register_coin( - coin_info, - coin_management, - ); - - // This gives some coin to the service. - let interchain_transfer_ticket = interchain_token_service::interchain_token_service::prepare_interchain_transfer( - token_id, - coin, - std::ascii::string(b"Chain Name"), - b"Destination Address", - b"", - &squid.channel, - ); - destroy(its.send_interchain_transfer( - interchain_transfer_ticket, - &clock, - )); - - let source_chain = std::ascii::string(b"Chain Name"); - let message_id = std::ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; - - let destination_address = squid.channel().to_address(); - - let mut writer = abi::abi::new_writer(6); - writer - .write_u256(0) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(data); - let mut payload = writer.into_bytes(); - payload = interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(payload, source_chain); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - its.channel_address(), - payload, - ); - - let swap_info = start_swap( - &squid, - &mut its, - approved_message, - &clock, - ctx, - ); - - destroy(its); - destroy(squid); - destroy(swap_info); - clock.destroy_for_testing(); -} + let amount = 1234; + let data = std::bcs::to_bytes(&vector>[]); + let coin_management = interchain_token_service::coin_management::new_locked(); + let coin = sui::coin::mint_for_testing(amount, ctx); + + let token_id = its.register_coin( + coin_info, + coin_management, + ); + + // This gives some coin to the service. + let interchain_transfer_ticket = interchain_token_service::interchain_token_service::prepare_interchain_transfer( + token_id, + coin, + std::ascii::string(b"Chain Name"), + b"Destination Address", + b"", + &squid.channel, + ); + destroy(its.send_interchain_transfer( + interchain_transfer_ticket, + &clock, + )); + + let source_chain = std::ascii::string(b"Chain Name"); + let message_id = std::ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; + + let destination_address = squid.channel().to_address(); + + let mut writer = abi::abi::new_writer(6); + writer + .write_u256(0) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(data); + let mut payload = writer.into_bytes(); + payload = interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(payload, source_chain); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + its.channel_address(), + payload, + ); + + let swap_info = start_swap( + &squid, + &mut its, + approved_message, + &clock, + ctx, + ); + + destroy(its); + destroy(squid); + destroy(swap_info); + clock.destroy_for_testing(); + } -#[test] -fun test_new() { - let ctx = &mut tx_context::dummy(); - let self = new(version_control::version_control::new(vector[]), ctx); - destroy(self); + #[test] + fun test_new() { + let ctx = &mut tx_context::dummy(); + let self = new(version_control::version_control::new(vector[]), ctx); + destroy(self); + } } diff --git a/move/squid/tests/squid/deepbook_v3_tests.move b/move/squid/tests/squid/deepbook_v3_tests.move index 65b7ab77..89a1586a 100644 --- a/move/squid/tests/squid/deepbook_v3_tests.move +++ b/move/squid/tests/squid/deepbook_v3_tests.move @@ -1,133 +1,125 @@ #[test_only] -module squid::deepbook_v3_tests; - -use deepbook::pool::Pool; -use deepbook::pool_tests; -use squid::deepbook_v3; -use squid::swap_info; -use squid::swap_type; -use std::type_name; -use sui::clock::Clock; -use sui::coin::mint_for_testing; -use sui::object::id_to_address; -use sui::sui::SUI; -use sui::test_scenario::{begin, end}; -use sui::test_utils::{destroy, assert_eq}; -use token::deep::DEEP; - -public struct USDC has store {} - -const OWNER: address = @0x1; - -#[test] -fun test_serialize() { - let mut test = begin(OWNER); - let pool_id = pool_tests::setup_everything(&mut test); - - test.next_tx(OWNER); - let swap_data = deepbook_v3::new_swap_data( - swap_type::deepbook_v3(), - id_to_address(&pool_id), - true, - 100, - type_name::get().into_string(), - type_name::get().into_string(), - 1, - true, - ); - let swap_data_vec = std::bcs::to_bytes(&swap_data); - let data = std::bcs::to_bytes(&vector[swap_data_vec]); - let mut swap_info = swap_info::new(data, test.ctx()); - let (data2, _) = swap_info.data_estimating(); - let swap_data2 = deepbook_v3::peel_swap_data(&mut sui::bcs::new(data2)); - assert_eq(swap_data, swap_data2); - - let clock = test.take_shared(); - let pool = test.take_shared_by_id>(pool_id); - destroy(pool); - destroy(clock); - destroy(swap_info); - - end(test); -} - -#[test] -fun test_estimate() { - let mut test = begin(OWNER); - let pool_id = pool_tests::setup_everything( - &mut test, - ); - - test.next_tx(OWNER); - let swap_data = deepbook_v3::new_swap_data( - swap_type::deepbook_v3(), - id_to_address(&pool_id), - true, - 100, - type_name::get().into_string(), - type_name::get().into_string(), - 1, - true, - ); - let swap_data_vec = std::bcs::to_bytes(&swap_data); - let data = std::bcs::to_bytes(&vector[swap_data_vec]); - let mut swap_info = swap_info::new(data, test.ctx()); - // Store 100 SUI as estimate - swap_info.coin_bag().store_estimate(100_000_000_000); - - // The pool comes with a bid at $1 with quantity 1000. Taker fee of 10bps. - // When estimating, we should take 10bps worth of SUI out, then swap the - // rest for USDC. - let clock = test.take_shared(); - let mut pool = test.take_shared_by_id>(pool_id); - deepbook_v3::estimate(&mut swap_info, &pool, &clock); - - // This will call DeepBook's pool with base_in of 99.9 SUI. Since there is a - // bid at $1 - // It will output 99.9 worth of USDC can be obtained. - let estimate = swap_info.coin_bag().estimate(); - assert!(estimate == 99_900_000_000); - - // Create Squid and load it with DEEP. Load swap_info with 100 SUI. - let mut squid = squid::squid::new_for_testing(test.ctx()); - let sui_coin = mint_for_testing(100_000_000_000, test.ctx()); - let deep_coin = mint_for_testing(100_000_000_000, test.ctx()); - swap_info.coin_bag().store_balance(sui_coin.into_balance()); - squid - .value_mut!(b"") - .coin_bag_mut() - .store_balance(deep_coin.into_balance()); - - // Swap 100 SUI for 99.9 USDC - deepbook_v3::swap( - &mut swap_info, - &mut pool, - &mut squid, - &clock, - test.ctx(), - ); - - // The pool is set up with a DEEP/USDC conversion rate at 1 DEEP = 100 USDC. - // With that conversion rate and 10bps taker fee, the DEEP required - // to trade 99.9 SUI to 99.9 USDC is 99.9 * 0.001 / 100 = 0.000999 DEEP = 999_000. - - // swap_info should have a balance of 99.9 USDC - // squid should have a balance of 100 DEEP - let quote_balance = swap_info.coin_bag().balance().destroy_some(); - assert!(quote_balance.value() == 99_900_000_000); - let deep_balance = squid - .value_mut!(b"") - .coin_bag_mut() - .balance() - .destroy_some(); - assert!(deep_balance.value() == 100_000_000_000 - 999_000); - - destroy(pool); - destroy(clock); - destroy(swap_info); - destroy(squid); - destroy(quote_balance); - destroy(deep_balance); - - end(test); +module squid::deepbook_v3_tests { + use deepbook::{pool::Pool, pool_tests}; + use squid::{deepbook_v3, swap_info, swap_type}; + use std::type_name; + use sui::{ + clock::Clock, + coin::mint_for_testing, + object::id_to_address, + sui::SUI, + test_scenario::{begin, end}, + test_utils::{destroy, assert_eq} + }; + use token::deep::DEEP; + + public struct USDC has store {} + + const OWNER: address = @0x1; + + #[test] + fun test_serialize() { + let mut test = begin(OWNER); + let pool_id = pool_tests::setup_everything(&mut test); + + test.next_tx(OWNER); + let swap_data = deepbook_v3::new_swap_data( + swap_type::deepbook_v3(), + id_to_address(&pool_id), + true, + 100, + type_name::get().into_string(), + type_name::get().into_string(), + 1, + true, + ); + let swap_data_vec = std::bcs::to_bytes(&swap_data); + let data = std::bcs::to_bytes(&vector[swap_data_vec]); + let mut swap_info = swap_info::new(data, test.ctx()); + let (data2, _) = swap_info.data_estimating(); + let swap_data2 = deepbook_v3::peel_swap_data(&mut sui::bcs::new(data2)); + assert_eq(swap_data, swap_data2); + + let clock = test.take_shared(); + let pool = test.take_shared_by_id>(pool_id); + destroy(pool); + destroy(clock); + destroy(swap_info); + + end(test); + } + + #[test] + fun test_estimate() { + let mut test = begin(OWNER); + let pool_id = pool_tests::setup_everything( + &mut test, + ); + + test.next_tx(OWNER); + let swap_data = deepbook_v3::new_swap_data( + swap_type::deepbook_v3(), + id_to_address(&pool_id), + true, + 100, + type_name::get().into_string(), + type_name::get().into_string(), + 1, + true, + ); + let swap_data_vec = std::bcs::to_bytes(&swap_data); + let data = std::bcs::to_bytes(&vector[swap_data_vec]); + let mut swap_info = swap_info::new(data, test.ctx()); + // Store 100 SUI as estimate + swap_info.coin_bag().store_estimate(100_000_000_000); + + // The pool comes with a bid at $1 with quantity 1000. Taker fee of 10bps. + // When estimating, we should take 10bps worth of SUI out, then swap the + // rest for USDC. + let clock = test.take_shared(); + let mut pool = test.take_shared_by_id>(pool_id); + deepbook_v3::estimate(&mut swap_info, &pool, &clock); + + // This will call DeepBook's pool with base_in of 99.9 SUI. Since there is a + // bid at $1 + // It will output 99.9 worth of USDC can be obtained. + let estimate = swap_info.coin_bag().estimate(); + assert!(estimate == 99_900_000_000); + + // Create Squid and load it with DEEP. Load swap_info with 100 SUI. + let mut squid = squid::squid::new_for_testing(test.ctx()); + let sui_coin = mint_for_testing(100_000_000_000, test.ctx()); + let deep_coin = mint_for_testing(100_000_000_000, test.ctx()); + swap_info.coin_bag().store_balance(sui_coin.into_balance()); + squid.value_mut!(b"").coin_bag_mut().store_balance(deep_coin.into_balance()); + + // Swap 100 SUI for 99.9 USDC + deepbook_v3::swap( + &mut swap_info, + &mut pool, + &mut squid, + &clock, + test.ctx(), + ); + + // The pool is set up with a DEEP/USDC conversion rate at 1 DEEP = 100 USDC. + // With that conversion rate and 10bps taker fee, the DEEP required + // to trade 99.9 SUI to 99.9 USDC is 99.9 * 0.001 / 100 = 0.000999 DEEP = 999_000. + + // swap_info should have a balance of 99.9 USDC + // squid should have a balance of 100 DEEP + let quote_balance = swap_info.coin_bag().balance().destroy_some(); + assert!(quote_balance.value() == 99_900_000_000); + let deep_balance = squid.value_mut!(b"").coin_bag_mut().balance().destroy_some(); + assert!(deep_balance.value() == 100_000_000_000 - 999_000); + + destroy(pool); + destroy(clock); + destroy(swap_info); + destroy(squid); + destroy(quote_balance); + destroy(deep_balance); + + end(test); + } } diff --git a/move/utils/sources/utils/utils.move b/move/utils/sources/utils/utils.move index a5eb3808..7fda037c 100644 --- a/move/utils/sources/utils/utils.move +++ b/move/utils/sources/utils/utils.move @@ -1,63 +1,63 @@ /// Module: utils -module utils::utils; - -use sui::bcs::{Self, BCS}; - -// ----- -// Macros -// ----- - -/// Peel data from a BCS encoded vector -/// This macro is used to peel data from a BCS encoded vector -/// The macro will assert that there is no remaining data in the BCS after -/// peeling. If there is -/// remaining data, the macro will panic. -/// $data: The BCS encoded vector -/// $peel_fn: The function to peel the data -/// Returns: The peeled data or an error if there is any remaining data in the -/// BCS -/// -/// Example Usage: -/// ``` -/// use axelar_gateway::proof; -/// use utils::utils; -/// -/// let proof: Proof = utils::peel!(proof_data, |bcs| proof::peel(bcs)); -/// ``` -public macro fun peel<$T>($data: vector, $peel_fn: |&mut BCS| -> $T): $T { - let mut bcs = bcs::new($data); - let result = $peel_fn(&mut bcs); - assert!(bcs.into_remainder_bytes().length() == 0); - result -} - -#[test_only] -use sui::event; - -#[test_only] -public fun assert_events(event_count: u64): vector { - let events = event::events_by_type(); - assert!(events.length() == event_count); - events -} - -#[test_only] -public fun assert_event(): T { - let events = assert_events(1); - events[0] -} - -#[test] -fun peel_bcs_data_succeeds() { - let test_bytes = b"test"; - let data = bcs::to_bytes(&test_bytes); - let peeled_data: vector = peel!(data, |bcs| bcs::peel_vec_u8(bcs)); - assert!(peeled_data == test_bytes); -} - -#[test] -#[expected_failure] -fun peel_bcs_data_fails_when_data_remains() { - let data = b"ab"; - let _peeled: u8 = peel!(data, |bcs| bcs::peel_u8(bcs)); +module utils::utils { + use sui::bcs::{Self, BCS}; + + // ----- + // Macros + // ----- + + /// Peel data from a BCS encoded vector + /// This macro is used to peel data from a BCS encoded vector + /// The macro will assert that there is no remaining data in the BCS after + /// peeling. If there is + /// remaining data, the macro will panic. + /// $data: The BCS encoded vector + /// $peel_fn: The function to peel the data + /// Returns: The peeled data or an error if there is any remaining data in the + /// BCS + /// + /// Example Usage: + /// ``` + /// use axelar_gateway::proof; + /// use utils::utils; + /// + /// let proof: Proof = utils::peel!(proof_data, |bcs| proof::peel(bcs)); + /// ``` + public macro fun peel<$T>($data: vector, $peel_fn: |&mut BCS| -> $T): $T { + let mut bcs = bcs::new($data); + let result = $peel_fn(&mut bcs); + assert!(bcs.into_remainder_bytes().length() == 0); + result + } + + #[test_only] + use sui::event; + + #[test_only] + public fun assert_events(event_count: u64): vector { + let events = event::events_by_type(); + assert!(events.length() == event_count); + events + } + + #[test_only] + public fun assert_event(): T { + let events = assert_events(1); + events[0] + } + + #[test] + fun peel_bcs_data_succeeds() { + let test_bytes = b"test"; + let data = bcs::to_bytes(&test_bytes); + let peeled_data: vector = peel!(data, |bcs| bcs::peel_vec_u8(bcs)); + assert!(peeled_data == test_bytes); + } + + #[test] + #[expected_failure] + fun peel_bcs_data_fails_when_data_remains() { + let data = b"ab"; + let _peeled: u8 = peel!(data, |bcs| bcs::peel_u8(bcs)); + } } diff --git a/move/version_control/sources/version_control.move b/move/version_control/sources/version_control.move index b8aa71c3..ee48b025 100644 --- a/move/version_control/sources/version_control.move +++ b/move/version_control/sources/version_control.move @@ -1,266 +1,192 @@ /// This module implements a custom version control scheme to maximize /// versioning customizability. -module version_control::version_control; - -use std::ascii::String; -use sui::vec_set::{Self, VecSet}; - -// ------ -// Errors -// ------ -#[error] -const EFunctionNotSupported: vector = - b"function is not supported in this version"; - -#[error] -const EFunctionAlreadyAllowed: vector = - b"trying to allow a function already allowed on the specified version"; - -#[error] -const EFunctionAlreadyDisallowed: vector = - b"trying to disallow a function already disallowed on the specified version"; - -// ----- -// Types -// ----- -/// The function names are stored as Strings. They are however input as -/// vector for ease of instantiation. -public struct VersionControl has store, copy, drop { - allowed_functions: vector>, -} +module version_control::version_control { + use std::ascii::String; + use sui::vec_set::{Self, VecSet}; + + // ------ + // Errors + // ------ + #[error] + const EFunctionNotSupported: vector = b"function is not supported in this version"; + + #[error] + const EFunctionAlreadyAllowed: vector = b"trying to allow a function already allowed on the specified version"; + + #[error] + const EFunctionAlreadyDisallowed: vector = b"trying to disallow a function already disallowed on the specified version"; + + // ----- + // Types + // ----- + /// The function names are stored as Strings. They are however input as + /// vector for ease of instantiation. + public struct VersionControl has copy, drop, store { + allowed_functions: vector>, + } -// ---------------- -// Public Functions -// ---------------- - -/// Create a new Version Control object by passing in the allowed_functions -/// data. -/// You are supposed to pass a vector of the bytes of the functions that are -/// allowed per version. For example: -/// ``` -/// vector [ -/// vector [ b"v0_function" ], -/// vector [ b"v0_function", b"v1_function"], -/// ] -/// ``` -/// Would allow only `v0_function` to be called on version == 0, and both -/// `v0_function` and `v1_function` to be called on version == 1. -/// This is done to simplify the instantiation syntax of VersionControl. -public fun new(allowed_functions: vector>): VersionControl { - VersionControl { - allowed_functions: allowed_functions.map!( - |function_names| vec_set::from_keys( - function_names, + // ---------------- + // Public Functions + // ---------------- + + /// Create a new Version Control object by passing in the allowed_functions + /// data. + /// You are supposed to pass a vector of the bytes of the functions that are + /// allowed per version. For example: + /// ``` + /// vector [ + /// vector [ b"v0_function" ], + /// vector [ b"v0_function", b"v1_function"], + /// ] + /// ``` + /// Would allow only `v0_function` to be called on version == 0, and both + /// `v0_function` and `v1_function` to be called on version == 1. + /// This is done to simplify the instantiation syntax of VersionControl. + public fun new(allowed_functions: vector>): VersionControl { + VersionControl { + allowed_functions: allowed_functions.map!( + |function_names| vec_set::from_keys( + function_names, + ), ), - ), + } } -} -/// This allowes for anyone to modify the raw data of allowed functions. -/// Do not pass a mutable reference of your VersionControl to anyone you do not -/// trust because they can modify it. -public fun allowed_functions( - self: &mut VersionControl, -): &mut vector> { - &mut self.allowed_functions -} + /// This allowes for anyone to modify the raw data of allowed functions. + /// Do not pass a mutable reference of your VersionControl to anyone you do not + /// trust because they can modify it. + public fun allowed_functions(self: &mut VersionControl): &mut vector> { + &mut self.allowed_functions + } -/// If a new version does not need to deprecate any old functions, you can use -/// this to add the newly supported functions. -public fun push_back( - self: &mut VersionControl, - function_names: vector, -) { - self - .allowed_functions - .push_back( - vec_set::from_keys( - function_names, - ), - ); -} + /// If a new version does not need to deprecate any old functions, you can use + /// this to add the newly supported functions. + public fun push_back(self: &mut VersionControl, function_names: vector) { + self + .allowed_functions + .push_back( + vec_set::from_keys( + function_names, + ), + ); + } -public fun allow_function( - self: &mut VersionControl, - version: u64, - function_name: String, -) { - assert!( - !self.allowed_functions[version].contains(&function_name), - EFunctionAlreadyAllowed, - ); - self.allowed_functions[version].insert(function_name); -} + public fun allow_function(self: &mut VersionControl, version: u64, function_name: String) { + assert!(!self.allowed_functions[version].contains(&function_name), EFunctionAlreadyAllowed); + self.allowed_functions[version].insert(function_name); + } -public fun disallow_function( - self: &mut VersionControl, - version: u64, - function_name: String, -) { - assert!( - self.allowed_functions[version].contains(&function_name), - EFunctionAlreadyDisallowed, - ); - self.allowed_functions[version].remove(&function_name); -} + public fun disallow_function(self: &mut VersionControl, version: u64, function_name: String) { + assert!(self.allowed_functions[version].contains(&function_name), EFunctionAlreadyDisallowed); + self.allowed_functions[version].remove(&function_name); + } -/// Call this at the begining of each version controlled function. For example -/// ``` -/// public fun do_something(data: &mut DataType) { -/// data.version_control.check(VERSION, b"do_something"); -/// // do the thing. -/// } -/// ``` -public fun check(self: &VersionControl, version: u64, function: String) { - assert!( - self.allowed_functions[version].contains(&function), - EFunctionNotSupported, - ); -} + /// Call this at the begining of each version controlled function. For example + /// ``` + /// public fun do_something(data: &mut DataType) { + /// data.version_control.check(VERSION, b"do_something"); + /// // do the thing. + /// } + /// ``` + public fun check(self: &VersionControl, version: u64, function: String) { + assert!(self.allowed_functions[version].contains(&function), EFunctionNotSupported); + } -/// Returns the latest valid index in allowed functions. -public fun latest_version(self: &VersionControl): u64 { - self.allowed_functions.length() - 1 -} + /// Returns the latest valid index in allowed functions. + public fun latest_version(self: &VersionControl): u64 { + self.allowed_functions.length() - 1 + } -#[test] -fun test_new() { - let version_control = new(vector[ - vector[b"function_name_1"].map!( - |function_name| function_name.to_ascii_string(), - ), - ]); - assert!(version_control.allowed_functions.length() == 1); - assert!( - version_control - .allowed_functions[0] - .contains(&b"function_name_1".to_ascii_string()), - ); - assert!( - !version_control - .allowed_functions[0] - .contains(&b"function_name_2".to_ascii_string()), - ); -} + #[test] + fun test_new() { + let version_control = new(vector[vector[b"function_name_1"].map!(|function_name| function_name.to_ascii_string())]); + assert!(version_control.allowed_functions.length() == 1); + assert!(version_control.allowed_functions[0].contains(&b"function_name_1".to_ascii_string())); + assert!(!version_control.allowed_functions[0].contains(&b"function_name_2".to_ascii_string())); + } -#[test] -fun test_allowed_functions() { - let mut version_control = new(vector[ - vector[b"function_name_1"].map!( - |function_name| function_name.to_ascii_string(), - ), - ]); - assert!( - version_control.allowed_functions == version_control.allowed_functions(), - ); -} + #[test] + fun test_allowed_functions() { + let mut version_control = new(vector[vector[b"function_name_1"].map!(|function_name| function_name.to_ascii_string())]); + assert!(version_control.allowed_functions == version_control.allowed_functions()); + } -#[test] -fun test_push_back() { - let mut version_control = new(vector[ - vector[b"function_name_1"].map!( - |function_name| function_name.to_ascii_string(), - ), - ]); - version_control.push_back(vector[ - b"function_name_1", - b"function_name_2", - ].map!(|function_name| function_name.to_ascii_string())); - assert!(version_control.allowed_functions.length() == 2); - assert!( - version_control - .allowed_functions[0] - .contains(&b"function_name_1".to_ascii_string()), - ); - assert!( - !version_control - .allowed_functions[0] - .contains(&b"function_name_2".to_ascii_string()), - ); - assert!( - version_control - .allowed_functions[1] - .contains(&b"function_name_1".to_ascii_string()), - ); - assert!( - version_control - .allowed_functions[1] - .contains(&b"function_name_2".to_ascii_string()), - ); -} + #[test] + fun test_push_back() { + let mut version_control = new(vector[vector[b"function_name_1"].map!(|function_name| function_name.to_ascii_string())]); + version_control.push_back(vector[b"function_name_1", b"function_name_2"].map!(|function_name| function_name.to_ascii_string())); + assert!(version_control.allowed_functions.length() == 2); + assert!(version_control.allowed_functions[0].contains(&b"function_name_1".to_ascii_string())); + assert!(!version_control.allowed_functions[0].contains(&b"function_name_2".to_ascii_string())); + assert!(version_control.allowed_functions[1].contains(&b"function_name_1".to_ascii_string())); + assert!(version_control.allowed_functions[1].contains(&b"function_name_2".to_ascii_string())); + } -#[test] -fun test_check() { - let version_control = new(vector[ - vector[b"function_name_1"].map!( - |function_name| function_name.to_ascii_string(), - ), - ]); - version_control.check(0, b"function_name_1".to_ascii_string()); -} + #[test] + fun test_check() { + let version_control = new(vector[vector[b"function_name_1"].map!(|function_name| function_name.to_ascii_string())]); + version_control.check(0, b"function_name_1".to_ascii_string()); + } -#[test] -#[expected_failure(abort_code = EFunctionNotSupported)] -fun test_check_function_not_supported() { - let version_control = new(vector[ - vector[b"function_name_1"].map!( - |function_name| function_name.to_ascii_string(), - ), - ]); - version_control.check(0, b"function_name_2".to_ascii_string()); -} + #[test] + #[expected_failure(abort_code = EFunctionNotSupported)] + fun test_check_function_not_supported() { + let version_control = new(vector[vector[b"function_name_1"].map!(|function_name| function_name.to_ascii_string())]); + version_control.check(0, b"function_name_2".to_ascii_string()); + } -#[test] -fun test_allow_function() { - let version = 0; - let function_name = b"function_name".to_ascii_string(); - let mut self = new(vector[vector[]]); + #[test] + fun test_allow_function() { + let version = 0; + let function_name = b"function_name".to_ascii_string(); + let mut self = new(vector[vector[]]); - self.allow_function(version, function_name); + self.allow_function(version, function_name); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -fun test_disallow_function() { - let version = 0; - let function_name = b"function_name".to_ascii_string(); - let mut self = new(vector[vector[function_name]]); + #[test] + fun test_disallow_function() { + let version = 0; + let function_name = b"function_name".to_ascii_string(); + let mut self = new(vector[vector[function_name]]); - self.disallow_function(version, function_name); + self.disallow_function(version, function_name); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EFunctionAlreadyAllowed)] -fun test_allow_function_already_allowed() { - let version = 0; - let function_name = b"function_name".to_ascii_string(); - let mut self = new(vector[vector[function_name]]); + #[test] + #[expected_failure(abort_code = EFunctionAlreadyAllowed)] + fun test_allow_function_already_allowed() { + let version = 0; + let function_name = b"function_name".to_ascii_string(); + let mut self = new(vector[vector[function_name]]); - self.allow_function(version, function_name); + self.allow_function(version, function_name); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EFunctionAlreadyDisallowed)] -fun test_disallow_function_already_disallowed() { - let version = 0; - let function_name = b"function_name".to_ascii_string(); - let mut self = new(vector[vector[]]); + #[test] + #[expected_failure(abort_code = EFunctionAlreadyDisallowed)] + fun test_disallow_function_already_disallowed() { + let version = 0; + let function_name = b"function_name".to_ascii_string(); + let mut self = new(vector[vector[]]); - self.disallow_function(version, function_name); + self.disallow_function(version, function_name); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -fun test_latest_function() { - let self = new(vector[vector[]]); + #[test] + fun test_latest_function() { + let self = new(vector[vector[]]); - assert!(self.latest_version() == 0); + assert!(self.latest_version() == 0); - sui::test_utils::destroy(self); + sui::test_utils::destroy(self); + } } diff --git a/package-lock.json b/package-lock.json index d17a8bf8..e27a2e81 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "@axelar-network/axelar-cgp-sui", - "version": "1.0.0", + "version": "1.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@axelar-network/axelar-cgp-sui", - "version": "1.0.0", + "version": "1.0.2", "license": "MIT", "dependencies": { "@cosmjs/cosmwasm-stargate": "^0.32.2", + "@mysten/prettier-plugin-move": "^0.2.2", "@mysten/sui": "^1.3.0", "deepbookv3": "github:axelarnetwork/deepbookv3#mainnet-v1.38.3", "ethers": "^5.0.0", @@ -31,7 +32,7 @@ "eslint": "^8.57.0", "eslint-config-richardpringle": "^2.0.0", "mocha": "^10.4.0", - "prettier": "^2.8.7", + "prettier": "^3.0.0", "prettier-plugin-sort-imports": "^1.8.5", "typescript": "^5.5.3" }, @@ -322,6 +323,21 @@ "semver": "^7.5.3" } }, + "node_modules/@changesets/apply-release-plan/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/@changesets/assemble-release-plan": { "version": "6.0.4", "dev": true, @@ -511,6 +527,21 @@ "prettier": "^2.7.1" } }, + "node_modules/@changesets/write/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/@confio/ics23": { "version": "0.6.8", "license": "Apache-2.0", @@ -1650,6 +1681,18 @@ "bs58": "^6.0.0" } }, + "node_modules/@mysten/prettier-plugin-move": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@mysten/prettier-plugin-move/-/prettier-plugin-move-0.2.2.tgz", + "integrity": "sha512-nWw55WTOUnQmfRdAIL49CUJ6W1Zq0N9Q7zVw1Cw6xj9ciBFL0y3pW9Aw7iIiTKi1ZKwgQjLUiwsq8TxkQvjMUg==", + "dependencies": { + "prettier": "^3.3.2", + "web-tree-sitter": "^0.20.8" + }, + "bin": { + "prettier-move": "bin/prettier-move.js" + } + }, "node_modules/@mysten/sui": { "version": "1.13.0", "license": "Apache-2.0", @@ -5135,14 +5178,14 @@ } }, "node_modules/prettier": { - "version": "2.8.8", - "dev": true, - "license": "MIT", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -5159,20 +5202,6 @@ "typescript": ">4.0.0" } }, - "node_modules/prettier-plugin-sort-imports/node_modules/prettier": { - "version": "3.3.3", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/protobufjs": { "version": "6.11.4", "hasInstallScript": true, @@ -6044,6 +6073,11 @@ "version": "0.36.0", "license": "MIT" }, + "node_modules/web-tree-sitter": { + "version": "0.20.8", + "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.20.8.tgz", + "integrity": "sha512-weOVgZ3aAARgdnb220GqYuh7+rZU0Ka9k9yfKtGAzEYMa6GgiCzW9JjQRJyCJakvibQW+dfjJdihjInKuuCAUQ==" + }, "node_modules/which": { "version": "2.0.2", "dev": true, diff --git a/package.json b/package.json index 7c71b48e..83d7990f 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "cs": "changeset", "verify-web-build": "node scripts/verify-web-build.js", "lint": "eslint --fix './src/**/*.ts' './test/*.js'", - "prettier": "prettier --write './src/**/*.ts' './test/*.js'", + "prettier": "prettier --write './src/**/*.ts' './test/*.js' && npx prettier-move -w ./move/**/*.move", "docs": "./scripts/docs.sh" }, "keywords": [ @@ -90,8 +90,9 @@ "eslint": "^8.57.0", "eslint-config-richardpringle": "^2.0.0", "mocha": "^10.4.0", - "prettier": "^2.8.7", + "prettier": "^3.0.0", "prettier-plugin-sort-imports": "^1.8.5", + "@mysten/prettier-plugin-move": "^0.2.2", "typescript": "^5.5.3" }, "description": "Axelar Sui Move contracts" diff --git a/test.move b/test.move new file mode 100644 index 00000000..652a71ac --- /dev/null +++ b/test.move @@ -0,0 +1,11 @@ +module version_control::test { + public struct Test { + val: u256, + } + + public fun new(val: u256): Test { + Test { + val, + } + } +} From 66a71d6a89f9b0bb0c8d81d1e7ce459cb1f8a746 Mon Sep 17 00:00:00 2001 From: Foivos Date: Wed, 29 Jan 2025 14:19:08 +0200 Subject: [PATCH 47/68] prettier --- move/axelar_gateway/sources/events.move | 155 +++---- .../sources/events.move | 401 +++++++++--------- .../sources/types/trusted_chains.move | 212 ++++----- 3 files changed, 382 insertions(+), 386 deletions(-) diff --git a/move/axelar_gateway/sources/events.move b/move/axelar_gateway/sources/events.move index 1caf9e68..3b83895e 100644 --- a/move/axelar_gateway/sources/events.move +++ b/move/axelar_gateway/sources/events.move @@ -13,92 +13,93 @@ module axelar_gateway::events { signers: WeightedSigners, } -// ------ -// Events -// ------ -/// Emitted when signers are rotated. -public struct SignersRotated has copy, drop { - epoch: u64, - signers_hash: Bytes32, - signers: WeightedSigners, -} + // ------ + // Events + // ------ + /// Emitted when signers are rotated. + public struct SignersRotated has copy, drop { + epoch: u64, + signers_hash: Bytes32, + signers: WeightedSigners, + } -/// Emitted when a new channel is created. -public struct ChannelCreated has copy, drop { - id: address, -} + /// Emitted when a new channel is created. + public struct ChannelCreated has copy, drop { + id: address, + } -/// Emitted when a channel is destroyed. -public struct ChannelDestroyed has copy, drop { - id: address, -} + /// Emitted when a channel is destroyed. + public struct ChannelDestroyed has copy, drop { + id: address, + } -/// Emitted when a new message is sent from the SUI network. -public struct ContractCall has copy, drop { - source_id: address, - destination_chain: String, - destination_address: String, - payload: vector, - payload_hash: address, -} + /// Emitted when a new message is sent from the SUI network. + public struct ContractCall has copy, drop { + source_id: address, + destination_chain: String, + destination_address: String, + payload: vector, + payload_hash: address, + } -/// Emitted when a new message is approved by the gateway. -public struct MessageApproved has copy, drop { - message: Message, -} + /// Emitted when a new message is approved by the gateway. + public struct MessageApproved has copy, drop { + message: Message, + } -/// Emitted when a message is taken to be executed by a channel. -public struct MessageExecuted has copy, drop { - message: Message, -} + /// Emitted when a message is taken to be executed by a channel. + public struct MessageExecuted has copy, drop { + message: Message, + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun signers_rotated(epoch: u64, signers_hash: Bytes32, signers: WeightedSigners) { - event::emit(SignersRotated { - epoch, - signers_hash, - signers, - }); -} + // ----------------- + // Package Functions + // ----------------- + public(package) fun signers_rotated(epoch: u64, signers_hash: Bytes32, signers: WeightedSigners) { + event::emit(SignersRotated { + epoch, + signers_hash, + signers, + }); + } -public(package) fun channel_created(id: address) { - event::emit(ChannelCreated { - id, - }); -} + public(package) fun channel_created(id: address) { + event::emit(ChannelCreated { + id, + }); + } -public(package) fun channel_destroyed(id: address) { - event::emit(ChannelDestroyed { - id, - }); -} + public(package) fun channel_destroyed(id: address) { + event::emit(ChannelDestroyed { + id, + }); + } -public(package) fun contract_call( - source_id: address, - destination_chain: String, - destination_address: String, - payload: vector, - payload_hash: address, -) { - event::emit(ContractCall { - source_id, - destination_chain, - destination_address, - payload, - payload_hash, - }); -} + public(package) fun contract_call( + source_id: address, + destination_chain: String, + destination_address: String, + payload: vector, + payload_hash: address, + ) { + event::emit(ContractCall { + source_id, + destination_chain, + destination_address, + payload, + payload_hash, + }); + } -public(package) fun message_approved(message: Message) { - event::emit(MessageApproved { - message, - }); -} + public(package) fun message_approved(message: Message) { + event::emit(MessageApproved { + message, + }); + } -public(package) fun message_executed(message: Message) { - event::emit(MessageExecuted { - message, - }); + public(package) fun message_executed(message: Message) { + event::emit(MessageExecuted { + message, + }); + } } diff --git a/move/interchain_token_service/sources/events.move b/move/interchain_token_service/sources/events.move index d90a4e95..2539d768 100644 --- a/move/interchain_token_service/sources/events.move +++ b/move/interchain_token_service/sources/events.move @@ -11,224 +11,219 @@ module interchain_token_service::events { token_id: TokenId, } -// ----- -// Types -// ----- -public struct CoinRegistered has copy, drop { - token_id: TokenId, -} + // ----- + // Types + // ----- + public struct CoinRegistered has copy, drop { + token_id: TokenId, + } -public struct InterchainTransfer has copy, drop { - token_id: TokenId, - source_address: address, - destination_chain: String, - destination_address: vector, - amount: u64, - data_hash: Bytes32, -} + public struct InterchainTransfer has copy, drop { + token_id: TokenId, + source_address: address, + destination_chain: String, + destination_address: vector, + amount: u64, + data_hash: Bytes32, + } -public struct InterchainTokenDeploymentStarted has copy, drop { - token_id: TokenId, - name: string::String, - symbol: String, - decimals: u8, - destination_chain: String, -} + public struct InterchainTokenDeploymentStarted has copy, drop { + token_id: TokenId, + name: string::String, + symbol: String, + decimals: u8, + destination_chain: String, + } -public struct InterchainTransferReceived has copy, drop { - message_id: String, - token_id: TokenId, - source_chain: String, - source_address: vector, - destination_address: address, - amount: u64, - data_hash: Bytes32, -} + public struct InterchainTransferReceived has copy, drop { + message_id: String, + token_id: TokenId, + source_chain: String, + source_address: vector, + destination_address: address, + amount: u64, + data_hash: Bytes32, + } -public struct UnregisteredCoinReceived has copy, drop { - token_id: UnregisteredTokenId, - symbol: String, - decimals: u8, -} + public struct UnregisteredCoinReceived has copy, drop { + token_id: UnregisteredTokenId, + symbol: String, + decimals: u8, + } -public struct TrustedChainAdded has copy, drop { - chain_name: String, -} + public struct TrustedChainAdded has copy, drop { + chain_name: String, + } -public struct TrustedChainRemoved has copy, drop { - chain_name: String, -} + public struct TrustedChainRemoved has copy, drop { + chain_name: String, + } -public struct FlowLimitSet has copy, drop { - token_id: TokenId, - flow_limit: Option, -} + public struct FlowLimitSet has copy, drop { + token_id: TokenId, + flow_limit: Option, + } -// ----------------- -// Package Functions -// ----------------- -public(package) fun coin_registered(token_id: TokenId) { - event::emit(CoinRegistered { - token_id, - }); -} + // ----------------- + // Package Functions + // ----------------- + public(package) fun coin_registered(token_id: TokenId) { + event::emit(CoinRegistered { + token_id, + }); + } -public(package) fun interchain_transfer( - token_id: TokenId, - source_address: address, - destination_chain: String, - destination_address: vector, - amount: u64, - data: &vector, -) { - let data_hash = if (data.length() == 0) { - bytes32::new(@0x0) - } else { - bytes32::new(address::from_bytes(keccak256(data))) - }; - event::emit(InterchainTransfer { - token_id, - source_address, - destination_chain, - destination_address, - amount, - data_hash, - }); -} + public(package) fun interchain_transfer( + token_id: TokenId, + source_address: address, + destination_chain: String, + destination_address: vector, + amount: u64, + data: &vector, + ) { + let data_hash = if (data.length() == 0) { + bytes32::new(@0x0) + } else { + bytes32::new(address::from_bytes(keccak256(data))) + }; + event::emit(InterchainTransfer { + token_id, + source_address, + destination_chain, + destination_address, + amount, + data_hash, + }); + } -public(package) fun interchain_token_deployment_started( - token_id: TokenId, - name: string::String, - symbol: String, - decimals: u8, - destination_chain: String, -) { - event::emit(InterchainTokenDeploymentStarted { - token_id, - name, - symbol, - decimals, - destination_chain, - }); -} + public(package) fun interchain_token_deployment_started( + token_id: TokenId, + name: string::String, + symbol: String, + decimals: u8, + destination_chain: String, + ) { + event::emit(InterchainTokenDeploymentStarted { + token_id, + name, + symbol, + decimals, + destination_chain, + }); + } -public(package) fun interchain_transfer_received( - message_id: String, - token_id: TokenId, - source_chain: String, - source_address: vector, - destination_address: address, - amount: u64, - data: &vector, -) { - let data_hash = bytes32::new(address::from_bytes(keccak256(data))); - event::emit(InterchainTransferReceived { - message_id, - token_id, - source_chain, - source_address, - destination_address, - amount, - data_hash, - }); -} + public(package) fun interchain_transfer_received( + message_id: String, + token_id: TokenId, + source_chain: String, + source_address: vector, + destination_address: address, + amount: u64, + data: &vector, + ) { + let data_hash = bytes32::new(address::from_bytes(keccak256(data))); + event::emit(InterchainTransferReceived { + message_id, + token_id, + source_chain, + source_address, + destination_address, + amount, + data_hash, + }); + } -public(package) fun unregistered_coin_received( - token_id: UnregisteredTokenId, - symbol: String, - decimals: u8, -) { - event::emit(UnregisteredCoinReceived { - token_id, - symbol, - decimals, - }); -} + public(package) fun unregistered_coin_received(token_id: UnregisteredTokenId, symbol: String, decimals: u8) { + event::emit(UnregisteredCoinReceived { + token_id, + symbol, + decimals, + }); + } -public(package) fun trusted_chain_added( - chain_name: String, -) { - event::emit(TrustedChainAdded { - chain_name, - }); -} + public(package) fun trusted_chain_added(chain_name: String) { + event::emit(TrustedChainAdded { + chain_name, + }); + } -public(package) fun trusted_chain_removed(chain_name: String) { - event::emit(TrustedChainRemoved { - chain_name, - }); -} + public(package) fun trusted_chain_removed(chain_name: String) { + event::emit(TrustedChainRemoved { + chain_name, + }); + } -public(package) fun flow_limit_set(token_id: TokenId, flow_limit: Option) { - event::emit(FlowLimitSet { - token_id, - flow_limit, - }); -} + public(package) fun flow_limit_set(token_id: TokenId, flow_limit: Option) { + event::emit(FlowLimitSet { + token_id, + flow_limit, + }); + } -// --------- -// Test Only -// --------- -#[test_only] -use interchain_token_service::coin::COIN; -#[test_only] -use interchain_token_service::token_id; -#[test_only] -use utils::utils; - -// ----- -// Tests -// ----- -#[test] -fun test_interchain_transfer_empty_data() { - let token_id = token_id::from_address(@0x1); - let source_address = @0x2; - let destination_chain = b"destination chain".to_ascii_string(); - let destination_address = b"destination address"; - let amount = 123; - let data = b""; - let data_hash = bytes32::new(@0x0); - - interchain_transfer( - token_id, - source_address, - destination_chain, - destination_address, - amount, - &data, - ); - let event = utils::assert_event>(); - - assert!(event.data_hash == data_hash); - assert!(event.source_address == source_address); - assert!(event.destination_chain == destination_chain); - assert!(event.destination_address == destination_address); - assert!(event.amount == amount); -} + // --------- + // Test Only + // --------- + #[test_only] + use interchain_token_service::coin::COIN; + #[test_only] + use interchain_token_service::token_id; + #[test_only] + use utils::utils; + + // ----- + // Tests + // ----- + #[test] + fun test_interchain_transfer_empty_data() { + let token_id = token_id::from_address(@0x1); + let source_address = @0x2; + let destination_chain = b"destination chain".to_ascii_string(); + let destination_address = b"destination address"; + let amount = 123; + let data = b""; + let data_hash = bytes32::new(@0x0); + + interchain_transfer( + token_id, + source_address, + destination_chain, + destination_address, + amount, + &data, + ); + let event = utils::assert_event>(); + + assert!(event.data_hash == data_hash); + assert!(event.source_address == source_address); + assert!(event.destination_chain == destination_chain); + assert!(event.destination_address == destination_address); + assert!(event.amount == amount); + } -#[test] -fun test_interchain_transfer_nonempty_data() { - let token_id = token_id::from_address(@0x1); - let source_address = @0x2; - let destination_chain = b"destination chain".to_ascii_string(); - let destination_address = b"destination address"; - let amount = 123; - let data = b"data"; - let data_hash = bytes32::new(address::from_bytes(keccak256(&data))); - - interchain_transfer( - token_id, - source_address, - destination_chain, - destination_address, - amount, - &data, - ); - let event = utils::assert_event>(); - - assert!(event.data_hash == data_hash); - assert!(event.source_address == source_address); - assert!(event.destination_chain == destination_chain); - assert!(event.destination_address == destination_address); - assert!(event.amount == amount); + #[test] + fun test_interchain_transfer_nonempty_data() { + let token_id = token_id::from_address(@0x1); + let source_address = @0x2; + let destination_chain = b"destination chain".to_ascii_string(); + let destination_address = b"destination address"; + let amount = 123; + let data = b"data"; + let data_hash = bytes32::new(address::from_bytes(keccak256(&data))); + + interchain_transfer( + token_id, + source_address, + destination_chain, + destination_address, + amount, + &data, + ); + let event = utils::assert_event>(); + + assert!(event.data_hash == data_hash); + assert!(event.source_address == source_address); + assert!(event.destination_chain == destination_chain); + assert!(event.destination_address == destination_address); + assert!(event.amount == amount); + } } diff --git a/move/interchain_token_service/sources/types/trusted_chains.move b/move/interchain_token_service/sources/types/trusted_chains.move index f9de7bf1..c10ce719 100644 --- a/move/interchain_token_service/sources/types/trusted_chains.move +++ b/move/interchain_token_service/sources/types/trusted_chains.move @@ -1,134 +1,134 @@ -module interchain_token_service::trusted_chains; - -use interchain_token_service::events; -use std::ascii::String; -use sui::bag::{Self, Bag}; - -// ------ -// Errors -// ------ -#[error] -const EEmptyChainName: vector = b"empty trusted chain name is unsupported"; -#[error] -const EAlreadyTrusted: vector = b"chain is already trusted"; -#[error] -const ENotTrusted: vector = b"chain is not trusted"; - -public struct TrustedChain has store, drop {} - -/// The trusted chains where messages can be sent or received from. -public struct TrustedChains has store { - trusted_chains: Bag, -} +module interchain_token_service::trusted_chains { + use interchain_token_service::events; + use std::ascii::String; + use sui::bag::{Self, Bag}; + + // ------ + // Errors + // ------ + #[error] + const EEmptyChainName: vector = b"empty trusted chain name is unsupported"; + #[error] + const EAlreadyTrusted: vector = b"chain is already trusted"; + #[error] + const ENotTrusted: vector = b"chain is not trusted"; + + public struct TrustedChain has drop, store {} + + /// The trusted chains where messages can be sent or received from. + public struct TrustedChains has store { + trusted_chains: Bag, + } -// ----------------- -// Package Functions -// ----------------- -/// Create a new interchain address tracker. -public(package) fun new(ctx: &mut TxContext): TrustedChains { - TrustedChains { - trusted_chains: bag::new(ctx), + // ----------------- + // Package Functions + // ----------------- + /// Create a new interchain address tracker. + public(package) fun new(ctx: &mut TxContext): TrustedChains { + TrustedChains { + trusted_chains: bag::new(ctx), + } } -} -/// Check if the given address is trusted for the given chain. -public(package) fun is_trusted(self: &TrustedChains, chain_name: String): bool { - self.trusted_chains.contains(chain_name) -} + /// Check if the given address is trusted for the given chain. + public(package) fun is_trusted(self: &TrustedChains, chain_name: String): bool { + self.trusted_chains.contains(chain_name) + } -/// Set the trusted address for a chain or adds it if it doesn't exist. -public(package) fun add(self: &mut TrustedChains, chain_name: String) { - assert!(chain_name.length() > 0, EEmptyChainName); - assert!(!self.trusted_chains.contains(chain_name), EAlreadyTrusted); + /// Set the trusted address for a chain or adds it if it doesn't exist. + public(package) fun add(self: &mut TrustedChains, chain_name: String) { + assert!(chain_name.length() > 0, EEmptyChainName); + assert!(!self.trusted_chains.contains(chain_name), EAlreadyTrusted); - self.trusted_chains.add(chain_name, TrustedChain {}); - events::trusted_chain_added(chain_name); -} + self.trusted_chains.add(chain_name, TrustedChain {}); + events::trusted_chain_added(chain_name); + } -public(package) fun remove(self: &mut TrustedChains, chain_name: String) { - assert!(chain_name.length() > 0, EEmptyChainName); - assert!(self.trusted_chains.contains(chain_name), ENotTrusted); + public(package) fun remove(self: &mut TrustedChains, chain_name: String) { + assert!(chain_name.length() > 0, EEmptyChainName); + assert!(self.trusted_chains.contains(chain_name), ENotTrusted); - self.trusted_chains.remove(chain_name); - events::trusted_chain_removed(chain_name); -} + self.trusted_chains.remove(chain_name); + events::trusted_chain_removed(chain_name); + } -// ----- -// Tests -// ----- -#[test] -fun test_trusted_chains() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain1 = std::ascii::string(b"chain1"); - let chain2 = std::ascii::string(b"chain2"); + // ----- + // Tests + // ----- + #[test] + fun test_trusted_chains() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain1 = std::ascii::string(b"chain1"); + let chain2 = std::ascii::string(b"chain2"); - self.add(chain1); - self.add(chain2); + self.add(chain1); + self.add(chain2); - assert!(self.is_trusted(chain1) == true); - assert!(self.is_trusted(chain2) == true); + assert!(self.is_trusted(chain1) == true); + assert!(self.is_trusted(chain2) == true); - assert!(self.trusted_chains.contains(chain1)); - assert!(self.trusted_chains.contains(chain2)); + assert!(self.trusted_chains.contains(chain1)); + assert!(self.trusted_chains.contains(chain2)); - self.remove(chain1); - self.remove(chain2); + self.remove(chain1); + self.remove(chain2); - assert!(self.is_trusted(chain1) == false); - assert!(self.is_trusted(chain2) == false); + assert!(self.is_trusted(chain1) == false); + assert!(self.is_trusted(chain2) == false); - assert!(!self.trusted_chains.contains(chain1)); - assert!(!self.trusted_chains.contains(chain2)); + assert!(!self.trusted_chains.contains(chain1)); + assert!(!self.trusted_chains.contains(chain2)); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EEmptyChainName)] -fun test_add_trusted_chain_empty_chain_name() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b""); + #[test] + #[expected_failure(abort_code = EEmptyChainName)] + fun test_add_trusted_chain_empty_chain_name() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b""); - self.add(chain); + self.add(chain); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EAlreadyTrusted)] -fun test_add_trusted_chain_already_trusted() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b"chain"); + #[test] + #[expected_failure(abort_code = EAlreadyTrusted)] + fun test_add_trusted_chain_already_trusted() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b"chain"); - self.add(chain); - self.add(chain); + self.add(chain); + self.add(chain); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -fun test_remove_trusted_chain() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b"chain"); + #[test] + fun test_remove_trusted_chain() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b"chain"); - self.add(chain); - self.remove(chain); + self.add(chain); + self.remove(chain); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EEmptyChainName)] -fun test_remove_trusted_chain_empty_chain_name() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = new(ctx); - let chain = std::ascii::string(b""); + #[test] + #[expected_failure(abort_code = EEmptyChainName)] + fun test_remove_trusted_chain_empty_chain_name() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = new(ctx); + let chain = std::ascii::string(b""); - self.remove(chain); + self.remove(chain); - sui::test_utils::destroy(self); + sui::test_utils::destroy(self); + } } From e4f933244aec976dafb2ee79a0ca05c83bd3d96f Mon Sep 17 00:00:00 2001 From: Foivos Date: Wed, 29 Jan 2025 16:20:36 +0200 Subject: [PATCH 48/68] formatted everything --- move/axelar_gateway/sources/events.move | 10 - .../sources/discovery.move | 695 ++++++------- .../sources/events.move | 7 - .../sources/interchain_token_service.move | 938 +++++------------- .../sources/types/coin_data.move | 8 - move/squid/sources/squid/squid.move | 223 +---- .../sources/squid/versioned/squid_v0.move | 129 +-- src/node/node-utils.ts | 2 +- 8 files changed, 572 insertions(+), 1440 deletions(-) diff --git a/move/axelar_gateway/sources/events.move b/move/axelar_gateway/sources/events.move index 3b83895e..7be3d3a9 100644 --- a/move/axelar_gateway/sources/events.move +++ b/move/axelar_gateway/sources/events.move @@ -13,16 +13,6 @@ module axelar_gateway::events { signers: WeightedSigners, } - // ------ - // Events - // ------ - /// Emitted when signers are rotated. - public struct SignersRotated has copy, drop { - epoch: u64, - signers_hash: Bytes32, - signers: WeightedSigners, - } - /// Emitted when a new channel is created. public struct ChannelCreated has copy, drop { id: address, diff --git a/move/interchain_token_service/sources/discovery.move b/move/interchain_token_service/sources/discovery.move index 65f3256f..0719945a 100644 --- a/move/interchain_token_service/sources/discovery.move +++ b/move/interchain_token_service/sources/discovery.move @@ -13,84 +13,28 @@ module interchain_token_service::discovery { #[error] const EInvalidMessageType: vector = b"can only get interchain transfer info for interchain transfers"; -/// ------ -/// Errors -/// ------ -#[error] -const EUnsupportedMessageType: vector = b"the message type found is not supported"; -#[error] -const EInvalidMessageType: vector = - b"can only get interchain transfer info for interchain transfers"; - -const MESSAGE_TYPE_INTERCHAIN_TRANSFER: u256 = 0; -const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; -// onst MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER: u256 = 2; -// onst MESSAGE_TYPE_SEND_TO_HUB: u256 = 3; -const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; - -public fun interchain_transfer_info(payload: vector): (TokenId, address, u64, vector) { - let mut reader = abi::new_reader(payload); - assert!(reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, EInvalidMessageType); - // Source chain validation is not done here. - reader.skip_slot(); - let payload = reader.read_bytes(); - reader = abi::new_reader(payload); - assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); - - let token_id = token_id::from_u256(reader.read_u256()); - reader.skip_slot(); // skip source_address - let destination = address::from_bytes(reader.read_bytes()); - let amount = (reader.read_u256() as u64); - let data = reader.read_bytes(); - - (token_id, destination, amount, data) -} - -public fun register_transaction( - its: &mut InterchainTokenService, - discovery: &mut RelayerDiscovery, -) { - let mut arg = vector[0]; - arg.append(object::id(its).to_bytes()); - - let arguments = vector[arg, vector[3]]; - - let function = transaction::new_function( - package_id(), - ascii::string(b"discovery"), - ascii::string(b"call_info"), - ); - - let move_call = transaction::new_move_call( - function, - arguments, - vector[], - ); - - its.register_transaction( - discovery, - transaction::new_transaction( - false, - vector[move_call], - ), - ); -} + const MESSAGE_TYPE_INTERCHAIN_TRANSFER: u256 = 0; + const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; + // onst MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER: u256 = 2; + // onst MESSAGE_TYPE_SEND_TO_HUB: u256 = 3; + const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; -public fun call_info(its: &InterchainTokenService, mut payload: vector): Transaction { - let mut reader = abi::new_reader(payload); - let mut message_type = reader.read_u256(); - - if (message_type == MESSAGE_TYPE_RECEIVE_FROM_HUB) { + public fun interchain_transfer_info(payload: vector): (TokenId, address, u64, vector) { + let mut reader = abi::new_reader(payload); + assert!(reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, EInvalidMessageType); + // Source chain validation is not done here. reader.skip_slot(); let payload = reader.read_bytes(); reader = abi::new_reader(payload); assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); - if (message_type == MESSAGE_TYPE_INTERCHAIN_TRANSFER) { - interchain_transfer_tx(its, &mut reader) - } else { - assert!(message_type == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, EUnsupportedMessageType); - deploy_interchain_token_tx(its, &mut reader) + let token_id = token_id::from_u256(reader.read_u256()); + reader.skip_slot(); // skip source_address + let destination = address::from_bytes(reader.read_bytes()); + let amount = (reader.read_u256() as u64); + let data = reader.read_bytes(); + + (token_id, destination, amount, data) } public fun register_transaction(its: &mut InterchainTokenService, discovery: &mut RelayerDiscovery) { @@ -222,9 +166,7 @@ public fun call_info(its: &InterchainTokenService, mut payload: vector): Tra true, vector[move_call], ) - } else { - let mut discovery_arg = vector[0]; - discovery_arg.append(value.relayer_discovery_id().id_to_address().to_bytes()); + } // === Tests === #[test_only] @@ -251,363 +193,288 @@ public fun call_info(its: &InterchainTokenService, mut payload: vector): Tra vector[move_call], ) } -} -fun deploy_interchain_token_tx(its: &InterchainTokenService, reader: &mut AbiReader): Transaction { - let mut arg = vector[0]; - arg.append(object::id_address(its).to_bytes()); + #[test] + fun test_discovery_initial() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut discovery = relayer_discovery::discovery::new(ctx); - let arguments = vector[arg, vector[2]]; + register_transaction(&mut its, &mut discovery); - reader.skip_slot(); // skip token_id - reader.skip_slot(); // skip _name - let symbol = ascii::string(reader.read_bytes()); - let decimals = (reader.read_u256() as u8); - reader.skip_slot(); // skip distributor + let value = its.package_value(); + assert!(discovery.get_transaction(object::id_from_address(value.channel_address())) == initial_tx(&its)); + assert!(value.relayer_discovery_id() == object::id(&discovery)); - let value = its.package_value(); - let type_name = value.unregistered_coin_type(&symbol, decimals); + sui::test_utils::destroy(its); + sui::test_utils::destroy(discovery); + } - let move_call = transaction::new_move_call( - transaction::new_function( - package_id(), - ascii::string(b"interchain_token_service"), - ascii::string(b"receive_deploy_interchain_token"), - ), - arguments, - vector[type_name::into_string(*type_name)], - ); - - transaction::new_transaction( - true, - vector[move_call], - ) -} + #[test] + fun test_discovery_interchain_transfer() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut discovery = relayer_discovery::discovery::new(ctx); + + register_transaction(&mut its, &mut discovery); + + let token_id = @0x1234; + let source_address = b"source address"; + let target_channel = @0x5678; + let amount = 1905; + let data = b""; + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(address::to_u256(token_id)) + .write_bytes(source_address) + .write_bytes(target_channel.to_bytes()) + .write_u256(amount) + .write_bytes(data); + let payload = writer.into_bytes(); + + let type_arg = std::type_name::get(); + its.add_registered_coin_type_for_testing( + interchain_token_service::token_id::from_address(token_id), + type_arg, + ); + let tx_block = call_info(&its, payload); -// === Tests === -#[test_only] -fun initial_tx(its: &InterchainTokenService): Transaction { - let mut arg = vector[0]; - arg.append(sui::bcs::to_bytes(&object::id(its))); - - let arguments = vector[arg, vector[3]]; - - let function = transaction::new_function( - package_id(), - ascii::string(b"discovery"), - ascii::string(b"call_info"), - ); - - let move_call = transaction::new_move_call( - function, - arguments, - vector[], - ); - - transaction::new_transaction( - false, - vector[move_call], - ) -} + let mut reader = abi::new_reader(payload); + reader.skip_slot(); // skip message_type -#[test] -fun test_discovery_initial() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut discovery = relayer_discovery::discovery::new(ctx); + assert!(tx_block == interchain_transfer_tx(&its, &mut reader)); + assert!(tx_block.is_final() && tx_block.move_calls().length() == 1); - register_transaction(&mut its, &mut discovery); + let call_info = tx_block.move_calls().pop_back(); - let value = its.package_value(); - assert!( - discovery.get_transaction(object::id_from_address(value.channel_address())) == initial_tx(&its), - ); - assert!(value.relayer_discovery_id() == object::id(&discovery)); + assert!(call_info.function().package_id_from_function() == package_id()); + assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); + assert!(call_info.function().name() == ascii::string(b"receive_interchain_transfer")); + let mut arg = vector[0]; + arg.append(object::id_address(&its).to_bytes()); - sui::test_utils::destroy(its); - sui::test_utils::destroy(discovery); -} + let arguments = vector[arg, vector[2], vector[0, 6]]; + assert!(call_info.arguments() == arguments); + assert!(call_info.type_arguments() == vector[type_arg.into_string()]); -#[test] -fun test_discovery_interchain_transfer() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut discovery = relayer_discovery::discovery::new(ctx); - - register_transaction(&mut its, &mut discovery); - - let token_id = @0x1234; - let source_address = b"source address"; - let target_channel = @0x5678; - let amount = 1905; - let data = b""; - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(address::to_u256(token_id)) - .write_bytes(source_address) - .write_bytes(target_channel.to_bytes()) - .write_u256(amount) - .write_bytes(data); - let payload = writer.into_bytes(); - - let type_arg = std::type_name::get(); - its.add_registered_coin_type_for_testing( - interchain_token_service::token_id::from_address(token_id), - type_arg, - ); - let tx_block = call_info(&its, payload); - - let mut reader = abi::new_reader(payload); - reader.skip_slot(); // skip message_type - - assert!(tx_block == interchain_transfer_tx(&its, &mut reader)); - assert!(tx_block.is_final() && tx_block.move_calls().length() == 1); - - let call_info = tx_block.move_calls().pop_back(); - - assert!( - call_info.function().package_id_from_function() == package_id(), - ); - assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); - assert!(call_info.function().name() == ascii::string(b"receive_interchain_transfer")); - let mut arg = vector[0]; - arg.append(object::id_address(&its).to_bytes()); - - let arguments = vector[arg, vector[2], vector[0, 6]]; - assert!(call_info.arguments() == arguments); - assert!(call_info.type_arguments() == vector[type_arg.into_string()]); - - sui::test_utils::destroy(its); - sui::test_utils::destroy(discovery); -} + sui::test_utils::destroy(its); + sui::test_utils::destroy(discovery); + } -#[test] -fun test_discovery_interchain_transfer_with_data() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut discovery = relayer_discovery::discovery::new(ctx); - - register_transaction(&mut its, &mut discovery); - - assert!( - discovery.get_transaction(object::id_from_address(its.package_value().channel_address())) == initial_tx(&its), - ); - - let token_id = @0x1234; - let source_address = b"source address"; - let target_channel = @0x5678; - let amount = 1905; - let tx_data = sui::bcs::to_bytes(&initial_tx(&its)); - let mut writer = abi::new_writer(2); - writer.write_bytes(tx_data).write_u256(1245); - let data = writer.into_bytes(); - - writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(address::to_u256(token_id)) - .write_bytes(source_address) - .write_bytes(target_channel.to_bytes()) - .write_u256(amount) - .write_bytes(data); - let payload = writer.into_bytes(); - - its.add_registered_coin_type_for_testing( - interchain_token_service::token_id::from_address(token_id), - std::type_name::get(), - ); - - let mut reader = abi::new_reader(payload); - reader.skip_slot(); // skip message_type - - assert!(call_info(&its, payload) == interchain_transfer_tx(&its, &mut reader)); - - sui::test_utils::destroy(its); - sui::test_utils::destroy(discovery); -} + #[test] + fun test_discovery_interchain_transfer_with_data() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut discovery = relayer_discovery::discovery::new(ctx); + + register_transaction(&mut its, &mut discovery); + + assert!(discovery.get_transaction(object::id_from_address(its.package_value().channel_address())) == initial_tx(&its)); + + let token_id = @0x1234; + let source_address = b"source address"; + let target_channel = @0x5678; + let amount = 1905; + let tx_data = sui::bcs::to_bytes(&initial_tx(&its)); + let mut writer = abi::new_writer(2); + writer.write_bytes(tx_data).write_u256(1245); + let data = writer.into_bytes(); + + writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(address::to_u256(token_id)) + .write_bytes(source_address) + .write_bytes(target_channel.to_bytes()) + .write_u256(amount) + .write_bytes(data); + let payload = writer.into_bytes(); + + its.add_registered_coin_type_for_testing( + interchain_token_service::token_id::from_address(token_id), + std::type_name::get(), + ); -#[test] -fun test_discovery_deploy_token() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut discovery = relayer_discovery::discovery::new(ctx); - - register_transaction(&mut its, &mut discovery); - - let token_id = @0x1234; - let name = b"name"; - let symbol = b"symbol"; - let decimals = 15; - let distributor = @0x0325; - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) - .write_u256(address::to_u256(token_id)) - .write_bytes(name) - .write_bytes(symbol) - .write_u256(decimals) - .write_bytes(distributor.to_bytes()); - let payload = writer.into_bytes(); - - let type_arg = std::type_name::get(); - its.add_unregistered_coin_type_for_testing( - interchain_token_service::token_id::unregistered_token_id( - &ascii::string(symbol), - (decimals as u8), - ), - type_arg, - ); - let tx_block = call_info(&its, payload); - - let mut reader = abi::new_reader(payload); - reader.skip_slot(); // skip message_type - - assert!(tx_block == deploy_interchain_token_tx(&its, &mut reader)); - - assert!(tx_block.is_final()); - let mut move_calls = tx_block.move_calls(); - assert!(move_calls.length() == 1); - let call_info = move_calls.pop_back(); - assert!( - call_info.function().package_id_from_function() == package_id(), - ); - assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); - assert!(call_info.function().name() == ascii::string(b"receive_deploy_interchain_token")); - let mut arg = vector[0]; - arg.append(object::id_address(&its).to_bytes()); - - let arguments = vector[arg, vector[2]]; - assert!(call_info.arguments() == arguments); - assert!(call_info.type_arguments() == vector[type_arg.into_string()]); - - sui::test_utils::destroy(its); - sui::test_utils::destroy(discovery); -} + let mut reader = abi::new_reader(payload); + reader.skip_slot(); // skip message_type -#[test] -fun test_interchain_transfer_info() { - let message_type = MESSAGE_TYPE_INTERCHAIN_TRANSFER; - let token_id = 1; - let source_address = b"source address"; - let source_chain = b"Chain Name"; - let destination = @0x3.to_bytes(); - let amount = 2; - let data = b"data"; - - let mut writer = abi::new_writer(6); - writer - .write_u256(message_type) - .write_u256(token_id) - .write_bytes(source_address) - .write_bytes(destination) - .write_u256(amount) - .write_bytes(data); - let payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain).write_bytes(payload); - - let ( - resolved_token_id, - resolved_destination, - resolved_amount, - resolved_data, - ) = interchain_transfer_info(writer.into_bytes()); - assert!(resolved_token_id == token_id::from_u256(token_id)); - assert!(resolved_destination == address::from_bytes(destination)); - assert!(resolved_amount == (amount as u64)); - assert!(resolved_data == data); -} + assert!(call_info(&its, payload) == interchain_transfer_tx(&its, &mut reader)); -#[test] -#[expected_failure(abort_code = EInvalidMessageType)] -fun test_interchain_transfer_info_invalid_message_type() { - let message_type = MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN; - let token_id = @0x1234; - let name = b"name"; - let symbol = b"symbol"; - let decimals = 15; - let distributor = @0x0325; - let mut writer = abi::new_writer(6); - writer - .write_u256(message_type) - .write_u256(address::to_u256(token_id)) - .write_bytes(name) - .write_bytes(symbol) - .write_u256(decimals) - .write_bytes(distributor.to_bytes()); - - interchain_transfer_info(writer.into_bytes()); -} + sui::test_utils::destroy(its); + sui::test_utils::destroy(discovery); + } -#[test] -fun test_discovery_hub_message() { - let ctx = &mut sui::tx_context::dummy(); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut discovery = relayer_discovery::discovery::new(ctx); - - register_transaction(&mut its, &mut discovery); - - let token_id = @0x1234; - let source_address = b"source address"; - let target_channel = @0x5678; - let amount = 1905; - let data = b""; - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(address::to_u256(token_id)) - .write_bytes(source_address) - .write_bytes(target_channel.to_bytes()) - .write_u256(amount) - .write_bytes(data); - let inner = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(b"source_chain") - .write_bytes(inner); - let payload = writer.into_bytes(); - - let type_arg = std::type_name::get(); - its.add_registered_coin_type_for_testing( - interchain_token_service::token_id::from_address(token_id), - type_arg, - ); - let tx_block = call_info(&its, payload); - - assert!(tx_block == call_info(&its, payload)); - assert!(tx_block.is_final() && tx_block.move_calls().length() == 1); - - let call_info = tx_block.move_calls().pop_back(); - - assert!( - call_info.function().package_id_from_function() == package_id(), - ); - assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); - assert!(call_info.function().name() == ascii::string(b"receive_interchain_transfer")); - let mut arg = vector[0]; - arg.append(object::id_address(&its).to_bytes()); - - let arguments = vector[arg, vector[2], vector[0, 6]]; - assert!(call_info.arguments() == arguments); - assert!(call_info.type_arguments() == vector[type_arg.into_string()]); - - sui::test_utils::destroy(its); - sui::test_utils::destroy(discovery); -} + #[test] + fun test_discovery_deploy_token() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut discovery = relayer_discovery::discovery::new(ctx); + + register_transaction(&mut its, &mut discovery); + + let token_id = @0x1234; + let name = b"name"; + let symbol = b"symbol"; + let decimals = 15; + let distributor = @0x0325; + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) + .write_u256(address::to_u256(token_id)) + .write_bytes(name) + .write_bytes(symbol) + .write_u256(decimals) + .write_bytes(distributor.to_bytes()); + let payload = writer.into_bytes(); + + let type_arg = std::type_name::get(); + its.add_unregistered_coin_type_for_testing( + interchain_token_service::token_id::unregistered_token_id( + &ascii::string(symbol), + (decimals as u8), + ), + type_arg, + ); + let tx_block = call_info(&its, payload); -#[test] -#[expected_failure(abort_code = EUnsupportedMessageType)] -fun test_call_info_unsupported_message_type() { - let ctx = &mut sui::tx_context::dummy(); - let its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut reader = abi::new_reader(payload); + reader.skip_slot(); // skip message_type - let mut writer = abi::new_writer(1); - writer.write_u256(5); - let payload = writer.into_bytes(); + assert!(tx_block == deploy_interchain_token_tx(&its, &mut reader)); - call_info(&its, payload); + assert!(tx_block.is_final()); + let mut move_calls = tx_block.move_calls(); + assert!(move_calls.length() == 1); + let call_info = move_calls.pop_back(); + assert!(call_info.function().package_id_from_function() == package_id()); + assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); + assert!(call_info.function().name() == ascii::string(b"receive_deploy_interchain_token")); + let mut arg = vector[0]; + arg.append(object::id_address(&its).to_bytes()); - sui::test_utils::destroy(its); + let arguments = vector[arg, vector[2]]; + assert!(call_info.arguments() == arguments); + assert!(call_info.type_arguments() == vector[type_arg.into_string()]); + + sui::test_utils::destroy(its); + sui::test_utils::destroy(discovery); + } + + #[test] + fun test_interchain_transfer_info() { + let message_type = MESSAGE_TYPE_INTERCHAIN_TRANSFER; + let token_id = 1; + let source_address = b"source address"; + let source_chain = b"Chain Name"; + let destination = @0x3.to_bytes(); + let amount = 2; + let data = b"data"; + + let mut writer = abi::new_writer(6); + writer + .write_u256(message_type) + .write_u256(token_id) + .write_bytes(source_address) + .write_bytes(destination) + .write_u256(amount) + .write_bytes(data); + let payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain).write_bytes(payload); + + let (resolved_token_id, resolved_destination, resolved_amount, resolved_data) = interchain_transfer_info(writer.into_bytes()); + assert!(resolved_token_id == token_id::from_u256(token_id)); + assert!(resolved_destination == address::from_bytes(destination)); + assert!(resolved_amount == (amount as u64)); + assert!(resolved_data == data); + } + + #[test] + #[expected_failure(abort_code = EInvalidMessageType)] + fun test_interchain_transfer_info_invalid_message_type() { + let message_type = MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN; + let token_id = @0x1234; + let name = b"name"; + let symbol = b"symbol"; + let decimals = 15; + let distributor = @0x0325; + let mut writer = abi::new_writer(6); + writer + .write_u256(message_type) + .write_u256(address::to_u256(token_id)) + .write_bytes(name) + .write_bytes(symbol) + .write_u256(decimals) + .write_bytes(distributor.to_bytes()); + + interchain_transfer_info(writer.into_bytes()); + } + + #[test] + fun test_discovery_hub_message() { + let ctx = &mut sui::tx_context::dummy(); + let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + let mut discovery = relayer_discovery::discovery::new(ctx); + + register_transaction(&mut its, &mut discovery); + + let token_id = @0x1234; + let source_address = b"source address"; + let target_channel = @0x5678; + let amount = 1905; + let data = b""; + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(address::to_u256(token_id)) + .write_bytes(source_address) + .write_bytes(target_channel.to_bytes()) + .write_u256(amount) + .write_bytes(data); + let inner = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(b"source_chain").write_bytes(inner); + let payload = writer.into_bytes(); + + let type_arg = std::type_name::get(); + its.add_registered_coin_type_for_testing( + interchain_token_service::token_id::from_address(token_id), + type_arg, + ); + let tx_block = call_info(&its, payload); + + assert!(tx_block == call_info(&its, payload)); + assert!(tx_block.is_final() && tx_block.move_calls().length() == 1); + + let call_info = tx_block.move_calls().pop_back(); + + assert!(call_info.function().package_id_from_function() == package_id()); + assert!(call_info.function().module_name() == ascii::string(b"interchain_token_service")); + assert!(call_info.function().name() == ascii::string(b"receive_interchain_transfer")); + let mut arg = vector[0]; + arg.append(object::id_address(&its).to_bytes()); + + let arguments = vector[arg, vector[2], vector[0, 6]]; + assert!(call_info.arguments() == arguments); + assert!(call_info.type_arguments() == vector[type_arg.into_string()]); + + sui::test_utils::destroy(its); + sui::test_utils::destroy(discovery); + } + + #[test] + #[expected_failure(abort_code = EUnsupportedMessageType)] + fun test_call_info_unsupported_message_type() { + let ctx = &mut sui::tx_context::dummy(); + let its = interchain_token_service::interchain_token_service::create_for_testing(ctx); + + let mut writer = abi::new_writer(1); + writer.write_u256(5); + let payload = writer.into_bytes(); + + call_info(&its, payload); + + sui::test_utils::destroy(its); + } } diff --git a/move/interchain_token_service/sources/events.move b/move/interchain_token_service/sources/events.move index 2539d768..f09a8e24 100644 --- a/move/interchain_token_service/sources/events.move +++ b/move/interchain_token_service/sources/events.move @@ -11,13 +11,6 @@ module interchain_token_service::events { token_id: TokenId, } - // ----- - // Types - // ----- - public struct CoinRegistered has copy, drop { - token_id: TokenId, - } - public struct InterchainTransfer has copy, drop { token_id: TokenId, source_address: address, diff --git a/move/interchain_token_service/sources/interchain_token_service.move b/move/interchain_token_service/sources/interchain_token_service.move index ed740cde..f40c93b1 100644 --- a/move/interchain_token_service/sources/interchain_token_service.move +++ b/move/interchain_token_service/sources/interchain_token_service.move @@ -15,478 +15,39 @@ module interchain_token_service::interchain_token_service { use sui::{clock::Clock, coin::{Coin, TreasuryCap, CoinMetadata}, versioned::{Self, Versioned}}; use version_control::version_control::{Self, VersionControl}; -use axelar_gateway::channel::{ApprovedMessage, Channel}; -use axelar_gateway::message_ticket::MessageTicket; -use interchain_token_service::coin_info::CoinInfo; -use interchain_token_service::coin_management::CoinManagement; -use interchain_token_service::interchain_token_service_v0::{Self, InterchainTokenService_v0}; -use interchain_token_service::interchain_transfer_ticket::{Self, InterchainTransferTicket}; -use interchain_token_service::owner_cap::{Self, OwnerCap}; -use interchain_token_service::creator_cap::{Self, CreatorCap}; -use interchain_token_service::operator_cap::{Self, OperatorCap}; -use interchain_token_service::token_id::TokenId; -use relayer_discovery::discovery::RelayerDiscovery; -use relayer_discovery::transaction::Transaction; -use std::ascii::{Self, String}; -use std::type_name::TypeName; -use sui::clock::Clock; -use sui::coin::{Coin, TreasuryCap, CoinMetadata}; -use sui::versioned::{Self, Versioned}; -use version_control::version_control::{Self, VersionControl}; - -// ------- -// Version -// ------- -const VERSION: u64 = 0; -const DATA_VERSION: u64 = 0; - -// ------- -// Structs -// ------- -public struct InterchainTokenService has key { - id: UID, - inner: Versioned, -} - -// ----- -// Setup -// ----- -fun init(ctx: &mut TxContext) { - transfer::public_transfer( - owner_cap::create(ctx), - ctx.sender(), - ); - - transfer::public_transfer( - operator_cap::create(ctx), - ctx.sender(), - ); - - transfer::public_transfer( - creator_cap::create(ctx), - ctx.sender(), - ); -} - -entry fun setup(creator_cap: CreatorCap, chain_name: String, its_hub_address: String, ctx: &mut TxContext) { - let inner = versioned::create( - DATA_VERSION, - interchain_token_service_v0::new( - version_control(), - chain_name, - its_hub_address, - ctx, - ), - ctx, - ); - - // Share the its object for anyone to use. - transfer::share_object(InterchainTokenService { - id: object::new(ctx), - inner, - }); + // ------- + // Version + // ------- + const VERSION: u64 = 0; + const DATA_VERSION: u64 = 0; - creator_cap.destroy(); -} - -// ------ -// Macros -// ------ -/// This macro also uses version control to sinplify things a bit. -macro fun value( - $self: &InterchainTokenService, - $function_name: vector, -): &InterchainTokenService_v0 { - let its = $self; - let value = its.inner.load_value(); - value.version_control().check(VERSION, ascii::string($function_name)); - value -} - -/// This macro also uses version control to sinplify things a bit. -macro fun value_mut( - $self: &mut InterchainTokenService, - $function_name: vector, -): &mut InterchainTokenService_v0 { - let its = $self; - let value = its.inner.load_value_mut(); - value.version_control().check(VERSION, ascii::string($function_name)); - value -} - -// --------------- -// Entry Functions -// --------------- -entry fun allow_function( - self: &mut InterchainTokenService, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self.value_mut!(b"allow_function").allow_function(version, function_name); -} - -entry fun disallow_function( - self: &mut InterchainTokenService, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self.value_mut!(b"disallow_function").disallow_function(version, function_name); -} - -// ---------------- -// Public Functions -// ---------------- -public fun register_coin( - self: &mut InterchainTokenService, - coin_info: CoinInfo, - coin_management: CoinManagement, -): TokenId { - let value = self.value_mut!(b"register_coin"); - - value.register_coin(coin_info, coin_management) -} - -public fun deploy_remote_interchain_token( - self: &InterchainTokenService, - token_id: TokenId, - destination_chain: String, -): MessageTicket { - let value = self.value!(b"deploy_remote_interchain_token"); - - value.deploy_remote_interchain_token(token_id, destination_chain) -} - -public fun prepare_interchain_transfer( - token_id: TokenId, - coin: Coin, - destination_chain: String, - destination_address: vector, - metadata: vector, - source_channel: &Channel, -): InterchainTransferTicket { - interchain_transfer_ticket::new( - token_id, - coin.into_balance(), - source_channel.to_address(), - destination_chain, - destination_address, - metadata, - VERSION, - ) -} - -public fun send_interchain_transfer( - self: &mut InterchainTokenService, - ticket: InterchainTransferTicket, - clock: &Clock, -): MessageTicket { - let value = self.value_mut!(b"send_interchain_transfer"); - - value.send_interchain_transfer( - ticket, - VERSION, - clock, - ) -} - -public fun receive_interchain_transfer( - self: &mut InterchainTokenService, - approved_message: ApprovedMessage, - clock: &Clock, - ctx: &mut TxContext, -) { - let value = self.value_mut!(b"receive_interchain_transfer"); - - value.receive_interchain_transfer(approved_message, clock, ctx); -} - -public fun receive_interchain_transfer_with_data( - self: &mut InterchainTokenService, - approved_message: ApprovedMessage, - channel: &Channel, - clock: &Clock, - ctx: &mut TxContext, -): (String, vector, vector, Coin) { - let value = self.value_mut!(b"receive_interchain_transfer_with_data"); - - value.receive_interchain_transfer_with_data( - approved_message, - channel, - clock, - ctx, - ) -} - -public fun receive_deploy_interchain_token( - self: &mut InterchainTokenService, - approved_message: ApprovedMessage, -) { - let value = self.value_mut!(b"receive_deploy_interchain_token"); - - value.receive_deploy_interchain_token(approved_message); -} - -// We need an coin with zero supply that has the proper decimals and typing, and -// no Url. -public fun give_unregistered_coin( - self: &mut InterchainTokenService, - treasury_cap: TreasuryCap, - coin_metadata: CoinMetadata, -) { - let value = self.value_mut!(b"give_unregistered_coin"); - - value.give_unregistered_coin(treasury_cap, coin_metadata); -} - -public fun mint_as_distributor( - self: &mut InterchainTokenService, - channel: &Channel, - token_id: TokenId, - amount: u64, - ctx: &mut TxContext, -): Coin { - let value = self.value_mut!(b"mint_as_distributor"); - - value.mint_as_distributor( - channel, - token_id, - amount, - ctx, - ) -} - -public fun mint_to_as_distributor( - self: &mut InterchainTokenService, - channel: &Channel, - token_id: TokenId, - to: address, - amount: u64, - ctx: &mut TxContext, -) { - let value = self.value_mut!(b"mint_to_as_distributor"); - - value.mint_to_as_distributor( - channel, - token_id, - to, - amount, - ctx, - ); -} - -public fun burn_as_distributor( - self: &mut InterchainTokenService, - channel: &Channel, - token_id: TokenId, - coin: Coin, -) { - let value = self.value_mut!(b"mint_to_as_distributor"); - - value.burn_as_distributor( - channel, - token_id, - coin, - ); -} - -// This is the entrypoint for operators to set the flow limits of their tokens -// (tokenManager.setFlowLimit on EVM) -public fun set_flow_limit_as_token_operator( - self: &mut InterchainTokenService, - channel: &Channel, - token_id: TokenId, - limit: Option, -) { - let value = self.value_mut!(b"set_flow_limit_as_token_operator"); - - value.set_flow_limit_as_token_operator( - channel, - token_id, - limit, - ); -} - -// This is the entrypoint for operators to set the flow limits of their tokens -// (interchainTokenService.setFlowLimits on EVM) -public fun set_flow_limit( - self: &mut InterchainTokenService, - _: &OperatorCap, - token_ids: TokenId, - limit: Option, -) { - let value = self.value_mut!(b"set_flow_limit"); - - value.set_flow_limit( - token_ids, - limit, - ); -} - -// --------------- -// Owner Functions -// --------------- -public fun add_trusted_chains( - self: &mut InterchainTokenService, - _owner_cap: &OwnerCap, - chain_names: vector, -) { - let value = self.value_mut!(b"add_trusted_chains"); - - value.add_trusted_chains(chain_names); -} - -public fun remove_trusted_chains( - self: &mut InterchainTokenService, - _owner_cap: &OwnerCap, - chain_names: vector, -) { - let value = self.value_mut!(b"remove_trusted_chains"); - - value.remove_trusted_chains(chain_names); -} - -// === Getters === -public fun registered_coin_type(self: &InterchainTokenService, token_id: TokenId): &TypeName { - self.package_value().registered_coin_type(token_id) -} - -public fun channel_address(self: &InterchainTokenService): address { - self.package_value().channel_address() -} - -// ----------------- -// Package Functions -// ----------------- -// This function allows the rest of the package to read information about InterchainTokenService -// (discovery needs this). -public(package) fun package_value(self: &InterchainTokenService): &InterchainTokenService_v0 { - self.inner.load_value() -} - -public(package) fun register_transaction( - self: &mut InterchainTokenService, - discovery: &mut RelayerDiscovery, - transaction: Transaction, -) { - let value = self.value_mut!(b"register_transaction"); - - value.set_relayer_discovery_id(discovery); - - discovery.register_transaction( - value.channel(), - transaction, - ); -} - -// ----------------- -// Private Functions -// ----------------- -fun version_control(): VersionControl { - version_control::new(vector[ - // Version 0 - vector[ - b"register_coin", - b"deploy_remote_interchain_token", - b"send_interchain_transfer", - b"receive_interchain_transfer", - b"receive_interchain_transfer_with_data", - b"receive_deploy_interchain_token", - b"give_unregistered_coin", - b"mint_as_distributor", - b"mint_to_as_distributor", - b"burn_as_distributor", - b"add_trusted_chains", - b"remove_trusted_chains", - b"register_transaction", - b"set_flow_limit", - b"set_flow_limit_as_token_operator", - b"allow_function", - b"disallow_function", - ].map!(|function_name| function_name.to_ascii_string()), - ]) -} - -// --------- -// Test Only -// --------- -#[test_only] -use interchain_token_service::coin::COIN; -#[test_only] -use axelar_gateway::channel; -#[test_only] -use std::string; -#[test_only] -use abi::abi; -#[test_only] -use utils::utils; - -// === MESSAGE TYPES === -#[test_only] -const MESSAGE_TYPE_INTERCHAIN_TRANSFER: u256 = 0; -#[test_only] -const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; -// const MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER: u256 = 2; -#[test_only] -const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; - -// === HUB CONSTANTS === -// Axelar. -#[test_only] -const ITS_HUB_CHAIN_NAME: vector = b"axelar"; -// The address of the ITS HUB. -#[test_only] -const ITS_HUB_ADDRESS: vector = b"hub_address"; - -#[test_only] -public fun create_for_testing(ctx: &mut TxContext): InterchainTokenService { - let mut version_control = version_control(); - version_control.allowed_functions()[0].insert(b"".to_ascii_string()); - - let mut value = interchain_token_service_v0::new( - version_control, - b"chain name".to_ascii_string(), - ITS_HUB_ADDRESS.to_ascii_string(), - ctx, - ); - value.add_trusted_chain( - std::ascii::string(b"Chain Name"), - ); - - let inner = versioned::create( - DATA_VERSION, - value, - ctx, - ); - - InterchainTokenService { - id: object::new(ctx), - inner, + // ------- + // Structs + // ------- + public struct InterchainTokenService has key { + id: UID, + inner: Versioned, } -#[test_only] -public(package) fun add_unregistered_coin_type_for_testing( - self: &mut InterchainTokenService, - token_id: interchain_token_service::token_id::UnregisteredTokenId, - type_name: std::type_name::TypeName, -) { - self.value_mut!(b"").add_unregistered_coin_type_for_testing(token_id, type_name); -} + // ----- + // Setup + // ----- + fun init(ctx: &mut TxContext) { + transfer::public_transfer( + owner_cap::create(ctx), + ctx.sender(), + ); transfer::public_transfer( operator_cap::create(ctx), ctx.sender(), ); -#[test_only] -public(package) fun add_registered_coin_type_for_testing( - self: &mut InterchainTokenService, - token_id: TokenId, - type_name: std::type_name::TypeName, -) { - self.value_mut!(b"").add_registered_coin_type_for_testing(token_id, type_name); -} + transfer::public_transfer( + creator_cap::create(ctx), + ctx.sender(), + ); + } entry fun setup(creator_cap: CreatorCap, chain_name: String, its_hub_address: String, ctx: &mut TxContext) { let inner = versioned::create( @@ -925,21 +486,15 @@ public(package) fun add_registered_coin_type_for_testing( let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) - .write_u256(token_id.to_u256()) - .write_bytes(*token_name.as_bytes()) - .write_bytes(*token_symbol.as_bytes()) - .write_u256((token_decimals as u256)) - .write_bytes(vector::empty()); - - let payload = interchain_token_service_v0::wrap_payload_sending(writer.into_bytes(), destination_chain); - - assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); - assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); - assert!(message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string()); - assert!(message_ticket.payload() == payload); - assert!(message_ticket.version() == 0); + writer + .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) + .write_u256(token_id.to_u256()) + .write_bytes(*token_name.as_bytes()) + .write_bytes(*token_symbol.as_bytes()) + .write_u256((token_decimals as u256)) + .write_bytes(vector::empty()); + + let payload = interchain_token_service_v0::wrap_payload_sending(writer.into_bytes(), destination_chain); assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); @@ -992,24 +547,22 @@ public(package) fun add_registered_coin_type_for_testing( utils::assert_event>(); - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(token_id.to_u256()) - .write_bytes(source_channel.to_address().to_bytes()) - .write_bytes(destination_address) - .write_u256((amount as u256)) - .write_bytes(b""); - - let payload = interchain_token_service_v0::wrap_payload_sending(writer.into_bytes(), destination_chain); - - assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); - assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); - assert!( - message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string(), - ); - assert!(message_ticket.payload() == payload); - assert!(message_ticket.version() == 0); + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(token_id.to_u256()) + .write_bytes(source_channel.to_address().to_bytes()) + .write_bytes(destination_address) + .write_u256((amount as u256)) + .write_bytes(b""); + + let payload = interchain_token_service_v0::wrap_payload_sending(writer.into_bytes(), destination_chain); + + assert!(message_ticket.source_id() == its.value!(b"").channel().to_address()); + assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); + assert!(message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string()); + assert!(message_ticket.payload() == payload); + assert!(message_ticket.version() == 0); clock.destroy_for_testing(); source_channel.destroy(); @@ -1035,35 +588,32 @@ public(package) fun add_registered_coin_type_for_testing( let coin = sui::coin::mint_for_testing(amount, ctx); coin_management.take_balance(coin.into_balance(), &clock); - let token_id = register_coin(&mut its, coin_info, coin_management); - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; - let destination_address = @0x1; - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(b""); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - its.value!(b"").channel().to_address(), - payload, - ); + let token_id = register_coin(&mut its, coin_info, coin_management); + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; + let destination_address = @0x1; + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(b""); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + its.value!(b"").channel().to_address(), + payload, + ); receive_interchain_transfer(&mut its, approved_message, &clock, ctx); @@ -1092,36 +642,33 @@ public(package) fun add_registered_coin_type_for_testing( let coin = sui::coin::mint_for_testing(amount, ctx); coin_management.take_balance(coin.into_balance(), &clock); - let token_id = its.register_coin(coin_info, coin_management); - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; - let channel = channel::new(ctx); - let destination_address = channel.to_address(); - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(data); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - its.value!(b"").channel().to_address(), - payload, - ); + let token_id = its.register_coin(coin_info, coin_management); + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; + let channel = channel::new(ctx); + let destination_address = channel.to_address(); + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(data); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + its.value!(b"").channel().to_address(), + payload, + ); let (received_source_chain, received_source_address, received_data, received_coin) = its.receive_interchain_transfer_with_data< COIN, @@ -1151,38 +698,35 @@ public(package) fun add_registered_coin_type_for_testing( let clock = sui::clock::create_for_testing(ctx); let mut its = create_for_testing(ctx); - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let name = b"Token Name"; - let symbol = b"Symbol"; - let decimals = 9; - let token_id: u256 = 1234; + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let name = b"Token Name"; + let symbol = b"Symbol"; + let decimals = 9; + let token_id: u256 = 1234; its.value_mut!(b"").create_unregistered_coin(symbol, decimals, ctx); - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) - .write_u256(token_id) - .write_bytes(name) - .write_bytes(symbol) - .write_u256((decimals as u256)) - .write_bytes(vector::empty()); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - its.value!(b"").channel().to_address(), - payload, - ); + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) + .write_u256(token_id) + .write_bytes(name) + .write_bytes(symbol) + .write_u256((decimals as u256)) + .write_bytes(vector::empty()); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + its.value!(b"").channel().to_address(), + payload, + ); receive_deploy_interchain_token(&mut its, approved_message); @@ -1199,14 +743,11 @@ public(package) fun add_registered_coin_type_for_testing( let ctx = &mut tx_context::dummy(); let mut its = create_for_testing(ctx); - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); give_unregistered_coin(&mut its, treasury_cap, coin_metadata); @@ -1220,15 +761,12 @@ public(package) fun add_registered_coin_type_for_testing( let symbol = b"COIN"; let decimals = 9; - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); - let coin_info = interchain_token_service::coin_info::from_metadata( + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, ); let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); @@ -1260,15 +798,12 @@ public(package) fun add_registered_coin_type_for_testing( let symbol = b"COIN"; let decimals = 9; - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); - let coin_info = interchain_token_service::coin_info::from_metadata( + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, ); let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); @@ -1316,21 +851,19 @@ public(package) fun add_registered_coin_type_for_testing( channel.destroy(); } -#[test] -fun test_add_trusted_chain() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); + #[test] + fun test_add_trusted_chain() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); let owner_cap = owner_cap::create( ctx, ); - let trusted_chains = vector[b"Ethereum", b"Avalance", b"Axelar"].map!( - |chain| chain.to_ascii_string(), - ); + let trusted_chains = vector[b"Ethereum", b"Avalance", b"Axelar"].map!(|chain| chain.to_ascii_string()); - its.add_trusted_chains(&owner_cap, trusted_chains); - its.remove_trusted_chains(&owner_cap, trusted_chains); + its.add_trusted_chains(&owner_cap, trusted_chains); + its.remove_trusted_chains(&owner_cap, trusted_chains); sui::test_utils::destroy(its); sui::test_utils::destroy(owner_cap); @@ -1344,15 +877,12 @@ fun test_add_trusted_chain() { let decimals = 9; let limit = option::some(1234); - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); - let coin_info = interchain_token_service::coin_info::from_metadata( + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, ); let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); @@ -1375,15 +905,12 @@ fun test_add_trusted_chain() { let decimals = 9; let limit = option::some(1234); - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); - let coin_info = interchain_token_service::coin_info::from_metadata( + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, ); let coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); @@ -1393,90 +920,91 @@ fun test_add_trusted_chain() { let token_id = register_coin(&mut its, coin_info, coin_management); its.set_flow_limit(&operator_cap, token_id, limit); - sui::test_utils::destroy(its); - sui::test_utils::destroy(operator_cap); -} + sui::test_utils::destroy(its); + sui::test_utils::destroy(operator_cap); + } -#[test] -fun test_init() { - let mut ts = sui::test_scenario::begin(@0x0); + #[test] + fun test_init() { + let mut ts = sui::test_scenario::begin(@0x0); - init(ts.ctx()); - ts.next_tx(@0x0); + init(ts.ctx()); + ts.next_tx(@0x0); - let owner_cap = ts.take_from_sender(); - let operator_cap = ts.take_from_sender(); - - ts.return_to_sender(owner_cap); - ts.return_to_sender(operator_cap); - ts.end(); -} + let owner_cap = ts.take_from_sender(); + let operator_cap = ts.take_from_sender(); -#[test] -fun test_setup() { - let mut ts = sui::test_scenario::begin(@0x0); - let creator_cap = creator_cap::create(ts.ctx()); - let chain_name = b"chain name".to_ascii_string(); + ts.return_to_sender(owner_cap); + ts.return_to_sender(operator_cap); + ts.end(); + } - setup(creator_cap, chain_name, ITS_HUB_ADDRESS.to_ascii_string(), ts.ctx()); - ts.next_tx(@0x0); + #[test] + fun test_setup() { + let mut ts = sui::test_scenario::begin(@0x0); + let creator_cap = creator_cap::create(ts.ctx()); + let chain_name = b"chain name".to_ascii_string(); - let its = ts.take_shared(); - let chain_name_hash = axelar_gateway::bytes32::from_bytes(sui::hash::keccak256(&chain_name.into_bytes())); - assert!(its.value!(b"send_interchain_transfer").chain_name_hash() == chain_name_hash); + setup(creator_cap, chain_name, ITS_HUB_ADDRESS.to_ascii_string(), ts.ctx()); + ts.next_tx(@0x0); - sui::test_scenario::return_shared(its); - ts.end(); -} + let its = ts.take_shared(); + let chain_name_hash = axelar_gateway::bytes32::from_bytes(sui::hash::keccak256(&chain_name.into_bytes())); + assert!(its.value!(b"send_interchain_transfer").chain_name_hash() == chain_name_hash); -#[test] -fun test_registered_coin_type() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); - let token_id = interchain_token_service::token_id::from_address(@0x1); - its.add_registered_coin_type_for_testing( - token_id, - std::type_name::get(), - ); - its.registered_coin_type(token_id); + sui::test_scenario::return_shared(its); + ts.end(); + } - sui::test_utils::destroy(its); -} + #[test] + fun test_registered_coin_type() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); + let token_id = interchain_token_service::token_id::from_address(@0x1); + its.add_registered_coin_type_for_testing( + token_id, + std::type_name::get(), + ); + its.registered_coin_type(token_id); -#[test] -fun test_channel_address() { - let ctx = &mut tx_context::dummy(); - let its = create_for_testing(ctx); + sui::test_utils::destroy(its); + } - its.channel_address(); + #[test] + fun test_channel_address() { + let ctx = &mut tx_context::dummy(); + let its = create_for_testing(ctx); - sui::test_utils::destroy(its); -} + its.channel_address(); + + sui::test_utils::destroy(its); + } -#[test] -fun test_allow_function() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = create_for_testing(ctx); - let owner_cap = owner_cap::create(ctx); - let version = 0; - let function_name = b"function_name".to_ascii_string(); + #[test] + fun test_allow_function() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = create_for_testing(ctx); + let owner_cap = owner_cap::create(ctx); + let version = 0; + let function_name = b"function_name".to_ascii_string(); - self.allow_function(&owner_cap, version, function_name); + self.allow_function(&owner_cap, version, function_name); - sui::test_utils::destroy(self); - sui::test_utils::destroy(owner_cap); -} + sui::test_utils::destroy(self); + sui::test_utils::destroy(owner_cap); + } -#[test] -fun test_disallow_function() { - let ctx = &mut sui::tx_context::dummy(); - let mut self = create_for_testing(ctx); - let owner_cap = owner_cap::create(ctx); - let version = 0; - let function_name = b"send_interchain_transfer".to_ascii_string(); + #[test] + fun test_disallow_function() { + let ctx = &mut sui::tx_context::dummy(); + let mut self = create_for_testing(ctx); + let owner_cap = owner_cap::create(ctx); + let version = 0; + let function_name = b"send_interchain_transfer".to_ascii_string(); - self.disallow_function(&owner_cap, version, function_name); + self.disallow_function(&owner_cap, version, function_name); - sui::test_utils::destroy(self); - sui::test_utils::destroy(owner_cap); + sui::test_utils::destroy(self); + sui::test_utils::destroy(owner_cap); + } } diff --git a/move/interchain_token_service/sources/types/coin_data.move b/move/interchain_token_service/sources/types/coin_data.move index 74edd904..dbd4de7d 100644 --- a/move/interchain_token_service/sources/types/coin_data.move +++ b/move/interchain_token_service/sources/types/coin_data.move @@ -27,11 +27,3 @@ module interchain_token_service::coin_data { &mut self.coin_management } } - -public(package) fun coin_info(self: &CoinData): &CoinInfo { - &self.coin_info -} - -public(package) fun coin_management_mut(self: &mut CoinData): &mut CoinManagement { - &mut self.coin_management -} diff --git a/move/squid/sources/squid/squid.move b/move/squid/sources/squid/squid.move index e1f1e228..4a1ee268 100644 --- a/move/squid/sources/squid/squid.move +++ b/move/squid/sources/squid/squid.move @@ -12,171 +12,9 @@ module squid::squid { // ------- const VERSION: u64 = 0; -// ------- -// Version -// ------- -const VERSION: u64 = 0; - -public struct Squid has key, store { - id: UID, - inner: Versioned, -} - -fun init(ctx: &mut TxContext) { - transfer::share_object(Squid { - id: object::new(ctx), - inner: versioned::create( - VERSION, - squid_v0::new( - new_version_control(), - ctx, - ), - ctx, - ), - }); - transfer::public_transfer(owner_cap::create(ctx), ctx.sender()); -} - -// ------ -// Macros -// ------ -/// This macro retrieves the underlying versioned singleton by reference -public(package) macro fun value( - $self: &Squid, - $function_name: vector, -): &Squid_v0 { - let squid = $self; - let value = squid.inner().load_value(); - value.version_control().check(version(), ascii::string($function_name)); - value -} - -/// This macro retrieves the underlying versioned singleton by mutable reference -public(package) macro fun value_mut( - $self: &mut Squid, - $function_name: vector, -): &mut Squid_v0 { - let squid = $self; - let value = squid.inner_mut().load_value_mut(); - value.version_control().check(version(), ascii::string($function_name)); - value -} - -// --------------- -// Entry Functions -// --------------- -entry fun give_deep(self: &mut Squid, deep: Coin) { - self.value_mut!(b"give_deep").give_deep(deep); -} - -entry fun allow_function( - self: &mut Squid, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self.value_mut!(b"allow_function").allow_function(version, function_name); -} - -entry fun disallow_function( - self: &mut Squid, - _: &OwnerCap, - version: u64, - function_name: String, -) { - self - .value_mut!(b"disallow_function") - .disallow_function(version, function_name); -} - -entry fun withdraw( - self: &mut Squid, - _: &OwnerCap, - amount: u64, - ctx: &mut TxContext, -) { - self.value_mut!(b"withdraw").withdraw(amount, ctx); -} - -// ---------------- -// Public Functions -// ---------------- -public fun start_swap( - self: &mut Squid, - its: &mut InterchainTokenService, - approved_message: ApprovedMessage, - clock: &Clock, - ctx: &mut TxContext, -): SwapInfo { - self - .value_mut!(b"start_swap") - .start_swap(its, approved_message, clock, ctx) -} - -public fun finalize(swap_info: SwapInfo) { - swap_info.finalize(); -} - -// ----------------- -// Package Functions -// ----------------- -public(package) fun inner(self: &Squid): &Versioned { - &self.inner -} - -public(package) fun inner_mut(self: &mut Squid): &mut Versioned { - &mut self.inner -} - -public(package) fun version(): u64 { - VERSION -} - -/// ------- -/// Private -/// ------- -fun new_version_control(): VersionControl { - version_control::new(vector[ - // Version 0 - vector[ - b"start_swap", - b"its_transfer", - b"deepbook_v3_swap", - b"register_transaction", - b"give_deep", - b"allow_function", - b"disallow_function", - b"withdraw", - ].map!(|function_name| function_name.to_ascii_string()), - ]) -} - -/// --------- -/// Test Only -/// --------- -/// // === HUB CONSTANTS === -/// ITS Hub test chain name -#[test_only] -const ITS_HUB_CHAIN_NAME: vector = b"axelar"; - -/// ITS hub test address -#[test_only] -const ITS_HUB_ADDRESS: vector = b"hub_address"; - -#[test_only] -public fun new_for_testing(ctx: &mut TxContext): Squid { - let mut version_control = new_version_control(); - version_control.allowed_functions()[VERSION].insert(ascii::string(b"")); - Squid { - id: object::new(ctx), - inner: versioned::create( - VERSION, - squid_v0::new( - version_control, - ctx, - ), - ctx, - ), + public struct Squid has key, store { + id: UID, + inner: Versioned, } fun init(ctx: &mut TxContext) { @@ -194,15 +32,16 @@ public fun new_for_testing(ctx: &mut TxContext): Squid { transfer::public_transfer(owner_cap::create(ctx), ctx.sender()); } -/// ----- -/// Tests -/// ----- -#[test] -fun test_start_swap() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut its = interchain_token_service::interchain_token_service::create_for_testing(ctx); - let mut squid = new_for_testing(ctx); + // ------ + // Macros + // ------ + /// This macro retrieves the underlying versioned singleton by reference + public(package) macro fun value($self: &Squid, $function_name: vector): &Squid_v0 { + let squid = $self; + let value = squid.inner().load_value(); + value.version_control().check(version(), ascii::string($function_name)); + value + } /// This macro retrieves the underlying versioned singleton by mutable reference public(package) macro fun value_mut($self: &mut Squid, $function_name: vector): &mut Squid_v0 { @@ -355,31 +194,23 @@ fun test_start_swap() { &clock, )); - let source_chain = std::ascii::string(b"Chain Name"); - let message_id = std::ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; + let source_chain = std::ascii::string(b"Chain Name"); + let message_id = std::ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; let destination_address = squid.value!(b"").channel().to_address(); - let mut writer = abi::abi::new_writer(6); - writer - .write_u256(0) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(data); - - let mut payload = writer.into_bytes(); - payload = interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(payload, source_chain); - - let approved_message = axelar_gateway::channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - its.channel_address(), - payload, - ); + let mut writer = abi::abi::new_writer(6); + writer + .write_u256(0) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(data); + + let mut payload = writer.into_bytes(); + payload = interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(payload, source_chain); let approved_message = axelar_gateway::channel::new_approved_message( ITS_HUB_CHAIN_NAME.to_ascii_string(), diff --git a/move/squid/sources/squid/versioned/squid_v0.move b/move/squid/sources/squid/versioned/squid_v0.move index fd41545b..d85289d6 100644 --- a/move/squid/sources/squid/versioned/squid_v0.move +++ b/move/squid/sources/squid/versioned/squid_v0.move @@ -16,84 +16,15 @@ module squid::squid_v0 { version_control: VersionControl, } -public(package) fun channel(self: &Squid_v0): &Channel { - &self.channel -} - -public(package) fun version_control(self: &Squid_v0): &VersionControl { - &self.version_control -} - -public(package) fun coin_bag_mut(self: &mut Squid_v0): &mut CoinBag { - &mut self.coin_bag -} - -public(package) fun start_swap( - self: &Squid_v0, - its: &mut InterchainTokenService, - approved_message: ApprovedMessage, - clock: &Clock, - ctx: &mut TxContext, -): SwapInfo { - let (_, _, data, coin) = its.receive_interchain_transfer_with_data( - approved_message, - self.channel(), - clock, - ctx, - ); - let mut swap_info = swap_info::new(data, ctx); - swap_info.coin_bag().store_estimate(coin.value()); - swap_info.coin_bag().store_balance(coin.into_balance()); - swap_info -} - -public(package) fun give_deep(self: &mut Squid_v0, deep: Coin) { - self.coin_bag.store_balance(deep.into_balance()); -} - -public(package) fun allow_function( - self: &mut Squid_v0, - version: u64, - function_name: String, -) { - self.version_control.allow_function(version, function_name); -} - -public(package) fun disallow_function( - self: &mut Squid_v0, - version: u64, - function_name: String, -) { - self.version_control.disallow_function(version, function_name); -} - -#[allow(lint(self_transfer))] -public(package) fun withdraw( - self: &mut Squid_v0, - amount: u64, - ctx: &mut TxContext, -) { - let balance = self.coin_bag.exact_balance(amount); - transfer::public_transfer(coin::from_balance(balance, ctx), ctx.sender()); -} - -/// --------- -/// Test Only -/// --------- -/// // === HUB CONSTANTS === -// Axelar. -#[test_only] -const ITS_HUB_CHAIN_NAME: vector = b"axelar"; -// The address of the ITS HUB. -#[test_only] -const ITS_HUB_ADDRESS: vector = b"hub_address"; - -#[test_only] -public fun new_for_testing(ctx: &mut TxContext): Squid_v0 { - Squid_v0 { - channel: channel::new(ctx), - coin_bag: coin_bag::new(ctx), - version_control: version_control::version_control::new(vector[]), + // ----------------- + // Package Functions + // ----------------- + public(package) fun new(version_control: VersionControl, ctx: &mut TxContext): Squid_v0 { + Squid_v0 { + channel: channel::new(ctx), + coin_bag: coin_bag::new(ctx), + version_control, + } } public(package) fun channel(self: &Squid_v0): &Channel { @@ -208,30 +139,30 @@ public fun new_for_testing(ctx: &mut TxContext): Squid_v0 { &clock, )); - let source_chain = std::ascii::string(b"Chain Name"); - let message_id = std::ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; + let source_chain = std::ascii::string(b"Chain Name"); + let message_id = std::ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; let destination_address = squid.channel().to_address(); - let mut writer = abi::abi::new_writer(6); - writer - .write_u256(0) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(data); - let mut payload = writer.into_bytes(); - payload = interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(payload, source_chain); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - its.channel_address(), - payload, - ); + let mut writer = abi::abi::new_writer(6); + writer + .write_u256(0) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(data); + let mut payload = writer.into_bytes(); + payload = interchain_token_service::interchain_token_service_v0::wrap_payload_receiving(payload, source_chain); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + its.channel_address(), + payload, + ); let swap_info = start_swap( &squid, diff --git a/src/node/node-utils.ts b/src/node/node-utils.ts index 3bf89c95..b0353495 100644 --- a/src/node/node-utils.ts +++ b/src/node/node-utils.ts @@ -132,7 +132,7 @@ export function newInterchainToken(templateFilePath: string, options: Interchain const structRegex = new RegExp(`struct\\s+Q\\s+has\\s+drop\\s+{}`, 'g'); // replace the module name with the token symbol in lowercase - content = content.replace(/(module\s+)([^:]+)(::)([^;]+)/, `$1interchain_token$3${options.symbol.toLowerCase()}`); + content = content.replace(/(module\s+)([^:]+)(::)([^\{]+)/, `$1interchain_token$3${options.symbol.toLowerCase()}`); // replace the struct name with the token symbol in uppercase content = content.replace(structRegex, `struct ${options.symbol.toUpperCase()} has drop {}`); From f1a301c167e5e0c179156d32362e56a5a8da801f Mon Sep 17 00:00:00 2001 From: Foivos Date: Wed, 29 Jan 2025 16:22:55 +0200 Subject: [PATCH 49/68] remove escape character --- src/node/node-utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/node-utils.ts b/src/node/node-utils.ts index b0353495..11912d01 100644 --- a/src/node/node-utils.ts +++ b/src/node/node-utils.ts @@ -132,7 +132,7 @@ export function newInterchainToken(templateFilePath: string, options: Interchain const structRegex = new RegExp(`struct\\s+Q\\s+has\\s+drop\\s+{}`, 'g'); // replace the module name with the token symbol in lowercase - content = content.replace(/(module\s+)([^:]+)(::)([^\{]+)/, `$1interchain_token$3${options.symbol.toLowerCase()}`); + content = content.replace(/(module\s+)([^:]+)(::)([^{]+)/, `$1interchain_token$3${options.symbol.toLowerCase()}`); // replace the struct name with the token symbol in uppercase content = content.replace(structRegex, `struct ${options.symbol.toUpperCase()} has drop {}`); From 220e05a8994e1b06048db50f3a541a01673c2c53 Mon Sep 17 00:00:00 2001 From: Foivos Date: Wed, 29 Jan 2025 16:28:02 +0200 Subject: [PATCH 50/68] fix prettier --- .../interchain_token_service_v0.move | 2648 ++++++++--------- 1 file changed, 1260 insertions(+), 1388 deletions(-) diff --git a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move index ac820411..3c4f9fe5 100644 --- a/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move +++ b/move/interchain_token_service/sources/versioned/interchain_token_service_v0.move @@ -1,1593 +1,1464 @@ -module interchain_token_service::interchain_token_service_v0; - -use abi::abi::{Self, AbiReader}; -use axelar_gateway::bytes32::{Self, Bytes32}; -use axelar_gateway::channel::{Channel, ApprovedMessage}; -use axelar_gateway::gateway; -use axelar_gateway::message_ticket::MessageTicket; -use interchain_token_service::trusted_chains::{Self, TrustedChains}; -use interchain_token_service::coin_data::{Self, CoinData}; -use interchain_token_service::coin_info::{Self, CoinInfo}; -use interchain_token_service::coin_management::{Self, CoinManagement}; -use interchain_token_service::events; -use interchain_token_service::interchain_transfer_ticket::InterchainTransferTicket; -use interchain_token_service::token_id::{Self, TokenId, UnregisteredTokenId}; -use interchain_token_service::unregistered_coin_data::{Self, UnregisteredCoinData}; -use interchain_token_service::utils as its_utils; -use relayer_discovery::discovery::RelayerDiscovery; -use std::ascii::{Self, String}; -use std::string; -use std::type_name::{Self, TypeName}; -use sui::address; -use sui::bag::{Self, Bag}; -use sui::clock::Clock; -use sui::coin::{Self, TreasuryCap, CoinMetadata, Coin}; -use sui::hash::keccak256; -use sui::table::{Self, Table}; -use version_control::version_control::VersionControl; - -// ------ -// Errors -// ------ -#[error] -const EUnregisteredCoin: vector = b"trying to find a coin that doesn't exist"; -#[error] -const EUntrustedAddress: vector = b"the sender that sent this message is not trusted"; -#[error] -const EInvalidMessageType: vector = b"the message type received is not supported"; -#[error] -const EWrongDestination: vector = - b"the channel trying to receive this call is not the destination"; -#[error] -const EInterchainTransferHasData: vector = - b"interchain transfer with data trying to be processed as an interchain transfer"; -#[error] -const EInterchainTransferHasNoData: vector = - b"interchain transfer trying to be proccessed as an interchain transfer"; -#[error] -const EModuleNameDoesNotMatchSymbol: vector = b"the module name does not match the symbol"; -#[error] -const ENotDistributor: vector = b"only the distributor can mint"; -#[error] -const ENonZeroTotalSupply: vector = - b"trying to give a token that has had some supply already minted"; -#[error] -const EUnregisteredCoinHasUrl: vector = - b"the interchain token that is being registered has a URL"; -#[error] -const EUntrustedChain: vector = b"the chain is not trusted"; -#[error] -const ENewerTicket: vector = b"cannot proccess newer tickets"; -#[error] -const EOverflow: vector = b"cannot receive more than 2^64-1 coins"; - -// === MESSAGE TYPES === -const MESSAGE_TYPE_INTERCHAIN_TRANSFER: u256 = 0; -const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; -// onst MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER: u256 = 2; -const MESSAGE_TYPE_SEND_TO_HUB: u256 = 3; -const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; - -// === HUB CONSTANTS === -// Chain name for Axelar. This is used for routing InterchainTokenService calls via InterchainTokenService hub on -// Axelar. -const ITS_HUB_CHAIN_NAME: vector = b"axelar"; - -// ----- -// Types -// ----- -public struct InterchainTokenService_v0 has store { - channel: Channel, - trusted_chains: TrustedChains, - unregistered_coin_types: Table, - unregistered_coins: Bag, - registered_coin_types: Table, - registered_coins: Bag, - relayer_discovery_id: ID, - its_hub_address: String, - chain_name_hash: Bytes32, - version_control: VersionControl, -} - -// ----------------- -// Package Functions -// ----------------- -public(package) fun new( - version_control: VersionControl, - chain_name: String, - its_hub_address: String, - ctx: &mut TxContext, -): InterchainTokenService_v0 { - InterchainTokenService_v0 { - channel: axelar_gateway::channel::new(ctx), - trusted_chains: trusted_chains::new( - ctx, - ), - registered_coins: bag::new(ctx), - registered_coin_types: table::new(ctx), - unregistered_coins: bag::new(ctx), - unregistered_coin_types: table::new(ctx), - its_hub_address, - chain_name_hash: bytes32::from_bytes(keccak256(&chain_name.into_bytes())), - relayer_discovery_id: object::id_from_address(@0x0), - version_control, +module interchain_token_service::interchain_token_service_v0 { + use abi::abi::{Self, AbiReader}; + use axelar_gateway::{bytes32::{Self, Bytes32}, channel::{Channel, ApprovedMessage}, gateway, message_ticket::MessageTicket}; + use interchain_token_service::{ + coin_data::{Self, CoinData}, + coin_info::{Self, CoinInfo}, + coin_management::{Self, CoinManagement}, + events, + interchain_transfer_ticket::InterchainTransferTicket, + token_id::{Self, TokenId, UnregisteredTokenId}, + trusted_chains::{Self, TrustedChains}, + unregistered_coin_data::{Self, UnregisteredCoinData}, + utils as its_utils + }; + use relayer_discovery::discovery::RelayerDiscovery; + use std::{ascii::{Self, String}, string, type_name::{Self, TypeName}}; + use sui::{ + address, + bag::{Self, Bag}, + clock::Clock, + coin::{Self, TreasuryCap, CoinMetadata, Coin}, + hash::keccak256, + table::{Self, Table} + }; + use version_control::version_control::VersionControl; + + // ------ + // Errors + // ------ + #[error] + const EUnregisteredCoin: vector = b"trying to find a coin that doesn't exist"; + #[error] + const EUntrustedAddress: vector = b"the sender that sent this message is not trusted"; + #[error] + const EInvalidMessageType: vector = b"the message type received is not supported"; + #[error] + const EWrongDestination: vector = b"the channel trying to receive this call is not the destination"; + #[error] + const EInterchainTransferHasData: vector = b"interchain transfer with data trying to be processed as an interchain transfer"; + #[error] + const EInterchainTransferHasNoData: vector = b"interchain transfer trying to be proccessed as an interchain transfer"; + #[error] + const EModuleNameDoesNotMatchSymbol: vector = b"the module name does not match the symbol"; + #[error] + const ENotDistributor: vector = b"only the distributor can mint"; + #[error] + const ENonZeroTotalSupply: vector = b"trying to give a token that has had some supply already minted"; + #[error] + const EUnregisteredCoinHasUrl: vector = b"the interchain token that is being registered has a URL"; + #[error] + const EUntrustedChain: vector = b"the chain is not trusted"; + #[error] + const ENewerTicket: vector = b"cannot proccess newer tickets"; + #[error] + const EOverflow: vector = b"cannot receive more than 2^64-1 coins"; + + // === MESSAGE TYPES === + const MESSAGE_TYPE_INTERCHAIN_TRANSFER: u256 = 0; + const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1; + // onst MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER: u256 = 2; + const MESSAGE_TYPE_SEND_TO_HUB: u256 = 3; + const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4; + + // === HUB CONSTANTS === + // Chain name for Axelar. This is used for routing InterchainTokenService calls via InterchainTokenService hub on + // Axelar. + const ITS_HUB_CHAIN_NAME: vector = b"axelar"; + + // ----- + // Types + // ----- + public struct InterchainTokenService_v0 has store { + channel: Channel, + trusted_chains: TrustedChains, + unregistered_coin_types: Table, + unregistered_coins: Bag, + registered_coin_types: Table, + registered_coins: Bag, + relayer_discovery_id: ID, + its_hub_address: String, + chain_name_hash: Bytes32, + version_control: VersionControl, } -} -public(package) fun unregistered_coin_type( - self: &InterchainTokenService_v0, - symbol: &String, - decimals: u8, -): &TypeName { - let key = token_id::unregistered_token_id(symbol, decimals); + // ----------------- + // Package Functions + // ----------------- + public(package) fun new( + version_control: VersionControl, + chain_name: String, + its_hub_address: String, + ctx: &mut TxContext, + ): InterchainTokenService_v0 { + InterchainTokenService_v0 { + channel: axelar_gateway::channel::new(ctx), + trusted_chains: trusted_chains::new( + ctx, + ), + registered_coins: bag::new(ctx), + registered_coin_types: table::new(ctx), + unregistered_coins: bag::new(ctx), + unregistered_coin_types: table::new(ctx), + its_hub_address, + chain_name_hash: bytes32::from_bytes(keccak256(&chain_name.into_bytes())), + relayer_discovery_id: object::id_from_address(@0x0), + version_control, + } + } - assert!(self.unregistered_coin_types.contains(key), EUnregisteredCoin); - &self.unregistered_coin_types[key] -} + public(package) fun unregistered_coin_type(self: &InterchainTokenService_v0, symbol: &String, decimals: u8): &TypeName { + let key = token_id::unregistered_token_id(symbol, decimals); -public(package) fun registered_coin_type( - self: &InterchainTokenService_v0, - token_id: TokenId, -): &TypeName { - assert!(self.registered_coin_types.contains(token_id), EUnregisteredCoin); - &self.registered_coin_types[token_id] -} + assert!(self.unregistered_coin_types.contains(key), EUnregisteredCoin); + &self.unregistered_coin_types[key] + } -public(package) fun channel_address(self: &InterchainTokenService_v0): address { - self.channel.to_address() -} + public(package) fun registered_coin_type(self: &InterchainTokenService_v0, token_id: TokenId): &TypeName { + assert!(self.registered_coin_types.contains(token_id), EUnregisteredCoin); + &self.registered_coin_types[token_id] + } -public(package) fun set_relayer_discovery_id( - self: &mut InterchainTokenService_v0, - relayer_discovery: &RelayerDiscovery, -) { - self.relayer_discovery_id = object::id(relayer_discovery); -} + public(package) fun channel_address(self: &InterchainTokenService_v0): address { + self.channel.to_address() + } -public(package) fun relayer_discovery_id(self: &InterchainTokenService_v0): ID { - self.relayer_discovery_id -} + public(package) fun set_relayer_discovery_id(self: &mut InterchainTokenService_v0, relayer_discovery: &RelayerDiscovery) { + self.relayer_discovery_id = object::id(relayer_discovery); + } -public(package) fun add_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) { - self.trusted_chains.add(chain_name); -} + public(package) fun relayer_discovery_id(self: &InterchainTokenService_v0): ID { + self.relayer_discovery_id + } -public(package) fun remove_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) { - self.trusted_chains.remove(chain_name); -} + public(package) fun add_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) { + self.trusted_chains.add(chain_name); + } -public(package) fun add_trusted_chains( - self: &mut InterchainTokenService_v0, - chain_names: vector, -) { - chain_names.do!( - |chain_name| self.add_trusted_chain( - chain_name, - ), - ); -} + public(package) fun remove_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) { + self.trusted_chains.remove(chain_name); + } -public(package) fun remove_trusted_chains( - self: &mut InterchainTokenService_v0, - chain_names: vector, -) { - chain_names.do!( - |chain_name| self.remove_trusted_chain( - chain_name, - ), - ); -} + public(package) fun add_trusted_chains(self: &mut InterchainTokenService_v0, chain_names: vector) { + chain_names.do!( + |chain_name| self.add_trusted_chain( + chain_name, + ), + ); + } -public(package) fun channel(self: &InterchainTokenService_v0): &Channel { - &self.channel -} + public(package) fun remove_trusted_chains(self: &mut InterchainTokenService_v0, chain_names: vector) { + chain_names.do!( + |chain_name| self.remove_trusted_chain( + chain_name, + ), + ); + } -public(package) fun version_control(self: &InterchainTokenService_v0): &VersionControl { - &self.version_control -} + public(package) fun channel(self: &InterchainTokenService_v0): &Channel { + &self.channel + } -public(package) fun register_coin( - self: &mut InterchainTokenService_v0, - coin_info: CoinInfo, - coin_management: CoinManagement, -): TokenId { - let token_id = token_id::from_coin_data(&self.chain_name_hash, &coin_info, &coin_management); + public(package) fun version_control(self: &InterchainTokenService_v0): &VersionControl { + &self.version_control + } - self.add_registered_coin(token_id, coin_management, coin_info); + public(package) fun register_coin( + self: &mut InterchainTokenService_v0, + coin_info: CoinInfo, + coin_management: CoinManagement, + ): TokenId { + let token_id = token_id::from_coin_data(&self.chain_name_hash, &coin_info, &coin_management); - token_id -} + self.add_registered_coin(token_id, coin_management, coin_info); -public(package) fun deploy_remote_interchain_token( - self: &InterchainTokenService_v0, - token_id: TokenId, - destination_chain: String, -): MessageTicket { - let coin_info = self.coin_info(token_id); + token_id + } - let name = coin_info.name(); - let symbol = coin_info.symbol(); - let decimals = coin_info.decimals(); + public(package) fun deploy_remote_interchain_token( + self: &InterchainTokenService_v0, + token_id: TokenId, + destination_chain: String, + ): MessageTicket { + let coin_info = self.coin_info(token_id); - let mut writer = abi::new_writer(6); + let name = coin_info.name(); + let symbol = coin_info.symbol(); + let decimals = coin_info.decimals(); - writer - .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) - .write_u256(token_id.to_u256()) - .write_bytes(*name.as_bytes()) - .write_bytes(*symbol.as_bytes()) - .write_u256((decimals as u256)) - .write_bytes(vector::empty()); + let mut writer = abi::new_writer(6); - events::interchain_token_deployment_started( - token_id, - name, - symbol, - decimals, - destination_chain, - ); + writer + .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) + .write_u256(token_id.to_u256()) + .write_bytes(*name.as_bytes()) + .write_bytes(*symbol.as_bytes()) + .write_u256((decimals as u256)) + .write_bytes(vector::empty()); - let payload = writer.into_bytes(); + events::interchain_token_deployment_started( + token_id, + name, + symbol, + decimals, + destination_chain, + ); - self.prepare_hub_message(payload, destination_chain) -} + let payload = writer.into_bytes(); -public(package) fun send_interchain_transfer( - self: &mut InterchainTokenService_v0, - ticket: InterchainTransferTicket, - current_version: u64, - clock: &Clock, -): MessageTicket { - let ( - token_id, - balance, - source_address, - destination_chain, - destination_address, - metadata, - version, - ) = ticket.destroy(); - assert!(version <= current_version, ENewerTicket); - - let amount = self.coin_management_mut(token_id).take_balance(balance, clock); - let (_version, data) = its_utils::decode_metadata(metadata); - let mut writer = abi::new_writer(6); - - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(token_id.to_u256()) - .write_bytes(source_address.to_bytes()) - .write_bytes(destination_address) - .write_u256((amount as u256)) - .write_bytes(data); - - events::interchain_transfer( - token_id, - source_address, - destination_chain, - destination_address, - amount, - &data, - ); + self.prepare_hub_message(payload, destination_chain) + } - let payload = writer.into_bytes(); + public(package) fun send_interchain_transfer( + self: &mut InterchainTokenService_v0, + ticket: InterchainTransferTicket, + current_version: u64, + clock: &Clock, + ): MessageTicket { + let (token_id, balance, source_address, destination_chain, destination_address, metadata, version) = ticket.destroy(); + assert!(version <= current_version, ENewerTicket); + + let amount = self.coin_management_mut(token_id).take_balance(balance, clock); + let (_version, data) = its_utils::decode_metadata(metadata); + let mut writer = abi::new_writer(6); + + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(token_id.to_u256()) + .write_bytes(source_address.to_bytes()) + .write_bytes(destination_address) + .write_u256((amount as u256)) + .write_bytes(data); + + events::interchain_transfer( + token_id, + source_address, + destination_chain, + destination_address, + amount, + &data, + ); - self.prepare_hub_message(payload, destination_chain) -} + let payload = writer.into_bytes(); -public(package) fun receive_interchain_transfer( - self: &mut InterchainTokenService_v0, - approved_message: ApprovedMessage, - clock: &Clock, - ctx: &mut TxContext, -) { - let (source_chain, payload, message_id) = self.decode_approved_message( - approved_message, - ); - let mut reader = abi::new_reader(payload); - assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); + self.prepare_hub_message(payload, destination_chain) + } - let token_id = token_id::from_u256(reader.read_u256()); - let source_address = reader.read_bytes(); - let destination_address = address::from_bytes(reader.read_bytes()); - let amount = read_amount(&mut reader); - let data = reader.read_bytes(); + public(package) fun receive_interchain_transfer( + self: &mut InterchainTokenService_v0, + approved_message: ApprovedMessage, + clock: &Clock, + ctx: &mut TxContext, + ) { + let (source_chain, payload, message_id) = self.decode_approved_message( + approved_message, + ); + let mut reader = abi::new_reader(payload); + assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); - assert!(data.is_empty(), EInterchainTransferHasData); + let token_id = token_id::from_u256(reader.read_u256()); + let source_address = reader.read_bytes(); + let destination_address = address::from_bytes(reader.read_bytes()); + let amount = read_amount(&mut reader); + let data = reader.read_bytes(); - let coin = self.coin_management_mut(token_id).give_coin(amount, clock, ctx); + assert!(data.is_empty(), EInterchainTransferHasData); - transfer::public_transfer(coin, destination_address); + let coin = self.coin_management_mut(token_id).give_coin(amount, clock, ctx); - events::interchain_transfer_received( - message_id, - token_id, - source_chain, - source_address, - destination_address, - amount, - &b"", - ); -} + transfer::public_transfer(coin, destination_address); -public(package) fun receive_interchain_transfer_with_data( - self: &mut InterchainTokenService_v0, - approved_message: ApprovedMessage, - channel: &Channel, - clock: &Clock, - ctx: &mut TxContext, -): (String, vector, vector, Coin) { - let (source_chain, payload, message_id) = self.decode_approved_message( - approved_message, - ); - let mut reader = abi::new_reader(payload); - assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); + events::interchain_transfer_received( + message_id, + token_id, + source_chain, + source_address, + destination_address, + amount, + &b"", + ); + } - let token_id = token_id::from_u256(reader.read_u256()); + public(package) fun receive_interchain_transfer_with_data( + self: &mut InterchainTokenService_v0, + approved_message: ApprovedMessage, + channel: &Channel, + clock: &Clock, + ctx: &mut TxContext, + ): (String, vector, vector, Coin) { + let (source_chain, payload, message_id) = self.decode_approved_message( + approved_message, + ); + let mut reader = abi::new_reader(payload); + assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType); - let source_address = reader.read_bytes(); - let destination_address = address::from_bytes(reader.read_bytes()); - let amount = read_amount(&mut reader); - let data = reader.read_bytes(); + let token_id = token_id::from_u256(reader.read_u256()); - assert!(destination_address == channel.to_address(), EWrongDestination); - assert!(!data.is_empty(), EInterchainTransferHasNoData); + let source_address = reader.read_bytes(); + let destination_address = address::from_bytes(reader.read_bytes()); + let amount = read_amount(&mut reader); + let data = reader.read_bytes(); - let coin = self.coin_management_mut(token_id).give_coin(amount, clock, ctx); + assert!(destination_address == channel.to_address(), EWrongDestination); + assert!(!data.is_empty(), EInterchainTransferHasNoData); - events::interchain_transfer_received( - message_id, - token_id, - source_chain, - source_address, - destination_address, - amount, - &data, - ); + let coin = self.coin_management_mut(token_id).give_coin(amount, clock, ctx); - (source_chain, source_address, data, coin) -} + events::interchain_transfer_received( + message_id, + token_id, + source_chain, + source_address, + destination_address, + amount, + &data, + ); -public(package) fun receive_deploy_interchain_token( - self: &mut InterchainTokenService_v0, - approved_message: ApprovedMessage, -) { - let (_, payload, _) = self.decode_approved_message(approved_message); - let mut reader = abi::new_reader(payload); - assert!(reader.read_u256() == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, EInvalidMessageType); - - let token_id = token_id::from_u256(reader.read_u256()); - let name = string::utf8(reader.read_bytes()); - let symbol = ascii::string(reader.read_bytes()); - let decimals = (reader.read_u256() as u8); - let distributor_bytes = reader.read_bytes(); - let (treasury_cap, mut coin_metadata) = self.remove_unregistered_coin( - token_id::unregistered_token_id(&symbol, decimals), - ); + (source_chain, source_address, data, coin) + } - treasury_cap.update_name(&mut coin_metadata, name); + public(package) fun receive_deploy_interchain_token(self: &mut InterchainTokenService_v0, approved_message: ApprovedMessage) { + let (_, payload, _) = self.decode_approved_message(approved_message); + let mut reader = abi::new_reader(payload); + assert!(reader.read_u256() == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, EInvalidMessageType); + + let token_id = token_id::from_u256(reader.read_u256()); + let name = string::utf8(reader.read_bytes()); + let symbol = ascii::string(reader.read_bytes()); + let decimals = (reader.read_u256() as u8); + let distributor_bytes = reader.read_bytes(); + let (treasury_cap, mut coin_metadata) = self.remove_unregistered_coin( + token_id::unregistered_token_id(&symbol, decimals), + ); - let mut coin_management = coin_management::new_with_cap(treasury_cap); - let coin_info = coin_info::from_metadata(coin_metadata); + treasury_cap.update_name(&mut coin_metadata, name); - if (distributor_bytes.length() > 0) { - let distributor = address::from_bytes(distributor_bytes); - coin_management.add_distributor(distributor); - }; + let mut coin_management = coin_management::new_with_cap(treasury_cap); + let coin_info = coin_info::from_metadata(coin_metadata); - self.add_registered_coin(token_id, coin_management, coin_info); -} + if (distributor_bytes.length() > 0) { + let distributor = address::from_bytes(distributor_bytes); + coin_management.add_distributor(distributor); + }; -public(package) fun give_unregistered_coin( - self: &mut InterchainTokenService_v0, - treasury_cap: TreasuryCap, - mut coin_metadata: CoinMetadata, -) { - assert!(treasury_cap.total_supply() == 0, ENonZeroTotalSupply); - assert!(coin::get_icon_url(&coin_metadata).is_none(), EUnregisteredCoinHasUrl); + self.add_registered_coin(token_id, coin_management, coin_info); + } - treasury_cap.update_description(&mut coin_metadata, string::utf8(b"")); + public(package) fun give_unregistered_coin( + self: &mut InterchainTokenService_v0, + treasury_cap: TreasuryCap, + mut coin_metadata: CoinMetadata, + ) { + assert!(treasury_cap.total_supply() == 0, ENonZeroTotalSupply); + assert!(coin::get_icon_url(&coin_metadata).is_none(), EUnregisteredCoinHasUrl); - let decimals = coin_metadata.get_decimals(); - let symbol = coin_metadata.get_symbol(); + treasury_cap.update_description(&mut coin_metadata, string::utf8(b"")); - let module_name = type_name::get_module(&type_name::get()); - assert!(&module_name == &its_utils::module_from_symbol(&symbol), EModuleNameDoesNotMatchSymbol); + let decimals = coin_metadata.get_decimals(); + let symbol = coin_metadata.get_symbol(); - let token_id = token_id::unregistered_token_id(&symbol, decimals); + let module_name = type_name::get_module(&type_name::get()); + assert!(&module_name == &its_utils::module_from_symbol(&symbol), EModuleNameDoesNotMatchSymbol); - self.add_unregistered_coin(token_id, treasury_cap, coin_metadata); + let token_id = token_id::unregistered_token_id(&symbol, decimals); - events::unregistered_coin_received( - token_id, - symbol, - decimals, - ); -} + self.add_unregistered_coin(token_id, treasury_cap, coin_metadata); -public(package) fun mint_as_distributor( - self: &mut InterchainTokenService_v0, - channel: &Channel, - token_id: TokenId, - amount: u64, - ctx: &mut TxContext, -): Coin { - let coin_management = self.coin_management_mut(token_id); - let distributor = channel.to_address(); + events::unregistered_coin_received( + token_id, + symbol, + decimals, + ); + } - assert!(coin_management.is_distributor(distributor), ENotDistributor); + public(package) fun mint_as_distributor( + self: &mut InterchainTokenService_v0, + channel: &Channel, + token_id: TokenId, + amount: u64, + ctx: &mut TxContext, + ): Coin { + let coin_management = self.coin_management_mut(token_id); + let distributor = channel.to_address(); - coin_management.mint(amount, ctx) -} + assert!(coin_management.is_distributor(distributor), ENotDistributor); -public(package) fun mint_to_as_distributor( - self: &mut InterchainTokenService_v0, - channel: &Channel, - token_id: TokenId, - to: address, - amount: u64, - ctx: &mut TxContext, -) { - let coin_management = self.coin_management_mut(token_id); - let distributor = channel.to_address(); + coin_management.mint(amount, ctx) + } - assert!(coin_management.is_distributor(distributor), ENotDistributor); + public(package) fun mint_to_as_distributor( + self: &mut InterchainTokenService_v0, + channel: &Channel, + token_id: TokenId, + to: address, + amount: u64, + ctx: &mut TxContext, + ) { + let coin_management = self.coin_management_mut(token_id); + let distributor = channel.to_address(); - let coin = coin_management.mint(amount, ctx); + assert!(coin_management.is_distributor(distributor), ENotDistributor); - transfer::public_transfer(coin, to); -} + let coin = coin_management.mint(amount, ctx); -public(package) fun burn_as_distributor( - self: &mut InterchainTokenService_v0, - channel: &Channel, - token_id: TokenId, - coin: Coin, -) { - let coin_management = self.coin_management_mut(token_id); - let distributor = channel.to_address(); + transfer::public_transfer(coin, to); + } - assert!(coin_management.is_distributor(distributor), ENotDistributor); + public(package) fun burn_as_distributor(self: &mut InterchainTokenService_v0, channel: &Channel, token_id: TokenId, coin: Coin) { + let coin_management = self.coin_management_mut(token_id); + let distributor = channel.to_address(); - coin_management.burn(coin.into_balance()); -} + assert!(coin_management.is_distributor(distributor), ENotDistributor); -public(package) fun set_flow_limit_as_token_operator( - self: &mut InterchainTokenService_v0, - channel: &Channel, - token_id: TokenId, - limit: Option, -) { - self.coin_management_mut(token_id).set_flow_limit(channel, limit); - events::flow_limit_set(token_id, limit); -} + coin_management.burn(coin.into_balance()); + } -public(package) fun set_flow_limit( - self: &mut InterchainTokenService_v0, - token_id: TokenId, - limit: Option, -) { - self.coin_management_mut(token_id).set_flow_limit_internal(limit); - events::flow_limit_set(token_id, limit); -} + public(package) fun set_flow_limit_as_token_operator( + self: &mut InterchainTokenService_v0, + channel: &Channel, + token_id: TokenId, + limit: Option, + ) { + self.coin_management_mut(token_id).set_flow_limit(channel, limit); + events::flow_limit_set(token_id, limit); + } -public(package) fun allow_function( - self: &mut InterchainTokenService_v0, - version: u64, - function_name: String, -) { - self.version_control.allow_function(version, function_name); -} + public(package) fun set_flow_limit(self: &mut InterchainTokenService_v0, token_id: TokenId, limit: Option) { + self.coin_management_mut(token_id).set_flow_limit_internal(limit); + events::flow_limit_set(token_id, limit); + } -public(package) fun disallow_function( - self: &mut InterchainTokenService_v0, - version: u64, - function_name: String, -) { - self.version_control.disallow_function(version, function_name); -} + public(package) fun allow_function(self: &mut InterchainTokenService_v0, version: u64, function_name: String) { + self.version_control.allow_function(version, function_name); + } -// ----------------- -// Private Functions -// ----------------- -fun coin_data(self: &InterchainTokenService_v0, token_id: TokenId): &CoinData { - assert!(self.registered_coins.contains(token_id), EUnregisteredCoin); - &self.registered_coins[token_id] -} + public(package) fun disallow_function(self: &mut InterchainTokenService_v0, version: u64, function_name: String) { + self.version_control.disallow_function(version, function_name); + } -fun coin_info(self: &InterchainTokenService_v0, token_id: TokenId): &CoinInfo { - coin_data(self, token_id).coin_info() -} + // ----------------- + // Private Functions + // ----------------- + fun coin_data(self: &InterchainTokenService_v0, token_id: TokenId): &CoinData { + assert!(self.registered_coins.contains(token_id), EUnregisteredCoin); + &self.registered_coins[token_id] + } -fun is_trusted_chain(self: &InterchainTokenService_v0, source_chain: String): bool { - self.trusted_chains.is_trusted(source_chain) -} + fun coin_info(self: &InterchainTokenService_v0, token_id: TokenId): &CoinInfo { + coin_data(self, token_id).coin_info() + } -fun coin_management_mut( - self: &mut InterchainTokenService_v0, - token_id: TokenId, -): &mut CoinManagement { - let coin_data: &mut CoinData = &mut self.registered_coins[token_id]; - coin_data.coin_management_mut() -} + fun is_trusted_chain(self: &InterchainTokenService_v0, source_chain: String): bool { + self.trusted_chains.is_trusted(source_chain) + } -fun add_unregistered_coin( - self: &mut InterchainTokenService_v0, - token_id: UnregisteredTokenId, - treasury_cap: TreasuryCap, - coin_metadata: CoinMetadata, -) { - self - .unregistered_coins - .add( - token_id, - unregistered_coin_data::new( - treasury_cap, - coin_metadata, - ), - ); + fun coin_management_mut(self: &mut InterchainTokenService_v0, token_id: TokenId): &mut CoinManagement { + let coin_data: &mut CoinData = &mut self.registered_coins[token_id]; + coin_data.coin_management_mut() + } - let type_name = type_name::get(); - add_unregistered_coin_type(self, token_id, type_name); -} + fun add_unregistered_coin( + self: &mut InterchainTokenService_v0, + token_id: UnregisteredTokenId, + treasury_cap: TreasuryCap, + coin_metadata: CoinMetadata, + ) { + self + .unregistered_coins + .add( + token_id, + unregistered_coin_data::new( + treasury_cap, + coin_metadata, + ), + ); + + let type_name = type_name::get(); + add_unregistered_coin_type(self, token_id, type_name); + } -fun remove_unregistered_coin( - self: &mut InterchainTokenService_v0, - token_id: UnregisteredTokenId, -): (TreasuryCap, CoinMetadata) { - let unregistered_coins: UnregisteredCoinData = self.unregistered_coins.remove(token_id); - let (treasury_cap, coin_metadata) = unregistered_coins.destroy(); + fun remove_unregistered_coin( + self: &mut InterchainTokenService_v0, + token_id: UnregisteredTokenId, + ): (TreasuryCap, CoinMetadata) { + let unregistered_coins: UnregisteredCoinData = self.unregistered_coins.remove(token_id); + let (treasury_cap, coin_metadata) = unregistered_coins.destroy(); - remove_unregistered_coin_type(self, token_id); + remove_unregistered_coin_type(self, token_id); - (treasury_cap, coin_metadata) -} + (treasury_cap, coin_metadata) + } -fun add_unregistered_coin_type( - self: &mut InterchainTokenService_v0, - token_id: UnregisteredTokenId, - type_name: TypeName, -) { - self.unregistered_coin_types.add(token_id, type_name); -} + fun add_unregistered_coin_type(self: &mut InterchainTokenService_v0, token_id: UnregisteredTokenId, type_name: TypeName) { + self.unregistered_coin_types.add(token_id, type_name); + } -fun remove_unregistered_coin_type( - self: &mut InterchainTokenService_v0, - token_id: UnregisteredTokenId, -): TypeName { - self.unregistered_coin_types.remove(token_id) -} + fun remove_unregistered_coin_type(self: &mut InterchainTokenService_v0, token_id: UnregisteredTokenId): TypeName { + self.unregistered_coin_types.remove(token_id) + } -fun add_registered_coin_type( - self: &mut InterchainTokenService_v0, - token_id: TokenId, - type_name: TypeName, -) { - self.registered_coin_types.add(token_id, type_name); -} + fun add_registered_coin_type(self: &mut InterchainTokenService_v0, token_id: TokenId, type_name: TypeName) { + self.registered_coin_types.add(token_id, type_name); + } -fun add_registered_coin( - self: &mut InterchainTokenService_v0, - token_id: TokenId, - coin_management: CoinManagement, - coin_info: CoinInfo, -) { - self - .registered_coins - .add( + fun add_registered_coin( + self: &mut InterchainTokenService_v0, + token_id: TokenId, + coin_management: CoinManagement, + coin_info: CoinInfo, + ) { + self + .registered_coins + .add( + token_id, + coin_data::new( + coin_management, + coin_info, + ), + ); + + let type_name = type_name::get(); + add_registered_coin_type(self, token_id, type_name); + + events::coin_registered( token_id, - coin_data::new( - coin_management, - coin_info, - ), ); + } - let type_name = type_name::get(); - add_registered_coin_type(self, token_id, type_name); - - events::coin_registered( - token_id, - ); -} - -fun prepare_hub_message( - self: &InterchainTokenService_v0, - mut payload: vector, - destination_chain: String, -): MessageTicket { - assert!(self.is_trusted_chain(destination_chain), EUntrustedChain); + fun prepare_hub_message(self: &InterchainTokenService_v0, mut payload: vector, destination_chain: String): MessageTicket { + assert!(self.is_trusted_chain(destination_chain), EUntrustedChain); - let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_SEND_TO_HUB); - writer.write_bytes(destination_chain.into_bytes()); - writer.write_bytes(payload); - payload = writer.into_bytes(); + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_SEND_TO_HUB); + writer.write_bytes(destination_chain.into_bytes()); + writer.write_bytes(payload); + payload = writer.into_bytes(); - self.prepare_message(payload) -} + self.prepare_message(payload) + } -/// Send a payload to a destination chain. The destination chain needs to have a -/// trusted address. -fun prepare_message(self: &InterchainTokenService_v0, payload: vector): MessageTicket { - gateway::prepare_message( - &self.channel, - ITS_HUB_CHAIN_NAME.to_ascii_string(), - self.its_hub_address, - payload, - ) -} + /// Send a payload to a destination chain. The destination chain needs to have a + /// trusted address. + fun prepare_message(self: &InterchainTokenService_v0, payload: vector): MessageTicket { + gateway::prepare_message( + &self.channel, + ITS_HUB_CHAIN_NAME.to_ascii_string(), + self.its_hub_address, + payload, + ) + } -/// Decode an approved call and check that the source chain is trusted. -fun decode_approved_message( - self: &InterchainTokenService_v0, - approved_message: ApprovedMessage, -): (String, vector, String) { - let (source_chain, message_id, source_address, payload) = self - .channel - .consume_approved_message(approved_message); + /// Decode an approved call and check that the source chain is trusted. + fun decode_approved_message(self: &InterchainTokenService_v0, approved_message: ApprovedMessage): (String, vector, String) { + let (source_chain, message_id, source_address, payload) = self.channel.consume_approved_message(approved_message); - assert!(source_chain.into_bytes() == ITS_HUB_CHAIN_NAME, EUntrustedChain); - assert!(source_address == self.its_hub_address, EUntrustedAddress); + assert!(source_chain.into_bytes() == ITS_HUB_CHAIN_NAME, EUntrustedChain); + assert!(source_address == self.its_hub_address, EUntrustedAddress); - let mut reader = abi::new_reader(payload); - assert!(reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, EInvalidMessageType); + let mut reader = abi::new_reader(payload); + assert!(reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, EInvalidMessageType); - let source_chain = ascii::string(reader.read_bytes()); - let payload = reader.read_bytes(); + let source_chain = ascii::string(reader.read_bytes()); + let payload = reader.read_bytes(); - assert!(self.is_trusted_chain(source_chain), EUntrustedChain); + assert!(self.is_trusted_chain(source_chain), EUntrustedChain); - (source_chain, payload, message_id) -} + (source_chain, payload, message_id) + } -fun read_amount(reader: &mut AbiReader): u64 { - let amount = std::macros::try_as_u64!(reader.read_u256()); - assert!(amount.is_some(), EOverflow); - amount.destroy_some() -} + fun read_amount(reader: &mut AbiReader): u64 { + let amount = std::macros::try_as_u64!(reader.read_u256()); + assert!(amount.is_some(), EOverflow); + amount.destroy_some() + } -// --------- -// Test Only -// --------- -#[test_only] -use axelar_gateway::channel; -#[test_only] -use interchain_token_service::coin::COIN; - -// The address of the ITS HUB. -#[test_only] -const ITS_HUB_ADDRESS: vector = b"hub_address"; - -#[test_only] -fun create_for_testing(ctx: &mut TxContext): InterchainTokenService_v0 { - let mut self = new( - version_control::version_control::new(vector[]), - b"chain name".to_ascii_string(), - ITS_HUB_ADDRESS.to_ascii_string(), - ctx, - ); + // --------- + // Test Only + // --------- + #[test_only] + use axelar_gateway::channel; + #[test_only] + use interchain_token_service::coin::COIN; + + // The address of the ITS HUB. + #[test_only] + const ITS_HUB_ADDRESS: vector = b"hub_address"; + + #[test_only] + fun create_for_testing(ctx: &mut TxContext): InterchainTokenService_v0 { + let mut self = new( + version_control::version_control::new(vector[]), + b"chain name".to_ascii_string(), + ITS_HUB_ADDRESS.to_ascii_string(), + ctx, + ); - self.add_trusted_chain( - std::ascii::string(b"Chain Name"), - ); + self.add_trusted_chain( + std::ascii::string(b"Chain Name"), + ); - self -} + self + } -#[test_only] -public fun create_unregistered_coin( - self: &mut InterchainTokenService_v0, - symbol: vector, - decimals: u8, - ctx: &mut TxContext, -) { - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); - let token_id = token_id::unregistered_token_id( - &ascii::string(symbol), - decimals, - ); + #[test_only] + public fun create_unregistered_coin(self: &mut InterchainTokenService_v0, symbol: vector, decimals: u8, ctx: &mut TxContext) { + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); + let token_id = token_id::unregistered_token_id( + &ascii::string(symbol), + decimals, + ); - self.add_unregistered_coin(token_id, treasury_cap, coin_metadata); -} + self.add_unregistered_coin(token_id, treasury_cap, coin_metadata); + } -#[test_only] -public(package) fun add_unregistered_coin_type_for_testing( - self: &mut InterchainTokenService_v0, - token_id: UnregisteredTokenId, - type_name: TypeName, -) { - self.add_unregistered_coin_type(token_id, type_name); -} + #[test_only] + public(package) fun add_unregistered_coin_type_for_testing( + self: &mut InterchainTokenService_v0, + token_id: UnregisteredTokenId, + type_name: TypeName, + ) { + self.add_unregistered_coin_type(token_id, type_name); + } -#[test_only] -public(package) fun remove_unregistered_coin_type_for_testing( - self: &mut InterchainTokenService_v0, - token_id: UnregisteredTokenId, -): TypeName { - self.remove_unregistered_coin_type(token_id) -} + #[test_only] + public(package) fun remove_unregistered_coin_type_for_testing( + self: &mut InterchainTokenService_v0, + token_id: UnregisteredTokenId, + ): TypeName { + self.remove_unregistered_coin_type(token_id) + } -#[test_only] -public(package) fun add_registered_coin_type_for_testing( - self: &mut InterchainTokenService_v0, - token_id: TokenId, - type_name: TypeName, -) { - self.add_registered_coin_type(token_id, type_name); -} + #[test_only] + public(package) fun add_registered_coin_type_for_testing(self: &mut InterchainTokenService_v0, token_id: TokenId, type_name: TypeName) { + self.add_registered_coin_type(token_id, type_name); + } -#[test_only] -public(package) fun remove_registered_coin_type_for_testing( - self: &mut InterchainTokenService_v0, - token_id: TokenId, -): TypeName { - self.remove_registered_coin_type_for_testing(token_id) -} + #[test_only] + public(package) fun remove_registered_coin_type_for_testing(self: &mut InterchainTokenService_v0, token_id: TokenId): TypeName { + self.remove_registered_coin_type_for_testing(token_id) + } -#[test_only] -public(package) fun wrap_payload_sending( - payload: vector, - destination_chain: String, -): vector { - let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_SEND_TO_HUB); - writer.write_bytes(destination_chain.into_bytes()); - writer.write_bytes(payload); - writer.into_bytes() -} + #[test_only] + public(package) fun wrap_payload_sending(payload: vector, destination_chain: String): vector { + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_SEND_TO_HUB); + writer.write_bytes(destination_chain.into_bytes()); + writer.write_bytes(payload); + writer.into_bytes() + } -#[test_only] -public fun wrap_payload_receiving(payload: vector, source_chain: String): vector { - let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); - writer.write_bytes(source_chain.into_bytes()); - writer.write_bytes(payload); - writer.into_bytes() -} + #[test_only] + public fun wrap_payload_receiving(payload: vector, source_chain: String): vector { + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + writer.write_bytes(source_chain.into_bytes()); + writer.write_bytes(payload); + writer.into_bytes() + } -#[test_only] -public(package) fun chain_name_hash( - self: &InterchainTokenService_v0, -): Bytes32 { - self.chain_name_hash -} + #[test_only] + public(package) fun chain_name_hash(self: &InterchainTokenService_v0): Bytes32 { + self.chain_name_hash + } -// ----- -// Tests -// ----- -#[test] -fun test_decode_approved_message_axelar_hub_sender() { - let ctx = &mut tx_context::dummy(); - let mut self = create_for_testing(ctx); - - let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); - let source_address = ascii::string(ITS_HUB_ADDRESS); - let message_id = ascii::string(b"message_id"); - let origin_chain = ascii::string(b"Source Chain"); - let payload = b"payload"; - - let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); - writer.write_bytes(origin_chain.into_bytes()); - writer.write_bytes(payload); - let payload = writer.into_bytes(); - - self.add_trusted_chain( - origin_chain, - ); + // ----- + // Tests + // ----- + #[test] + fun test_decode_approved_message_axelar_hub_sender() { + let ctx = &mut tx_context::dummy(); + let mut self = create_for_testing(ctx); + + let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); + let source_address = ascii::string(ITS_HUB_ADDRESS); + let message_id = ascii::string(b"message_id"); + let origin_chain = ascii::string(b"Source Chain"); + let payload = b"payload"; + + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + writer.write_bytes(origin_chain.into_bytes()); + writer.write_bytes(payload); + let payload = writer.into_bytes(); + + self.add_trusted_chain( + origin_chain, + ); - let approved_message = channel::new_approved_message( - source_chain, - message_id, - source_address, - self.channel.to_address(), - payload, - ); + let approved_message = channel::new_approved_message( + source_chain, + message_id, + source_address, + self.channel.to_address(), + payload, + ); - self.decode_approved_message(approved_message); + self.decode_approved_message(approved_message); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EUntrustedChain)] -fun test_decode_approved_message_sender_not_hub() { - let ctx = &mut tx_context::dummy(); - let self = create_for_testing(ctx); - - let source_chain = ascii::string(b"Chain Name"); - let source_address = ascii::string(b"Address"); - let message_id = ascii::string(b"message_id"); - - let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); - writer.write_bytes(b"Source Chain"); - writer.write_bytes(b"payload"); - let payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - source_chain, - message_id, - source_address, - self.channel.to_address(), - payload, - ); + #[test] + #[expected_failure(abort_code = EUntrustedChain)] + fun test_decode_approved_message_sender_not_hub() { + let ctx = &mut tx_context::dummy(); + let self = create_for_testing(ctx); + + let source_chain = ascii::string(b"Chain Name"); + let source_address = ascii::string(b"Address"); + let message_id = ascii::string(b"message_id"); + + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + writer.write_bytes(b"Source Chain"); + writer.write_bytes(b"payload"); + let payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + source_chain, + message_id, + source_address, + self.channel.to_address(), + payload, + ); - self.decode_approved_message(approved_message); + self.decode_approved_message(approved_message); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EUntrustedAddress)] -fun test_decode_approved_message_sender_not_hub_address() { - let ctx = &mut tx_context::dummy(); - let self = create_for_testing(ctx); - - let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); - let source_address = ascii::string(b"Address"); - let message_id = ascii::string(b"message_id"); - - let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); - writer.write_bytes(b"Source Chain"); - writer.write_bytes(b"payload"); - let payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - source_chain, - message_id, - source_address, - self.channel.to_address(), - payload, - ); + #[test] + #[expected_failure(abort_code = EUntrustedAddress)] + fun test_decode_approved_message_sender_not_hub_address() { + let ctx = &mut tx_context::dummy(); + let self = create_for_testing(ctx); + + let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); + let source_address = ascii::string(b"Address"); + let message_id = ascii::string(b"message_id"); + + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + writer.write_bytes(b"Source Chain"); + writer.write_bytes(b"payload"); + let payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + source_chain, + message_id, + source_address, + self.channel.to_address(), + payload, + ); - self.decode_approved_message(approved_message); + self.decode_approved_message(approved_message); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EUntrustedChain)] -fun test_decode_approved_message_origin_not_hub_routed() { - let ctx = &mut tx_context::dummy(); - let self = create_for_testing(ctx); - - let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); - let source_address = ascii::string(ITS_HUB_ADDRESS); - let message_id = ascii::string(b"message_id"); - let origin_chain = ascii::string(b"Source Chain"); - let payload = b"payload"; - - let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); - writer.write_bytes(origin_chain.into_bytes()); - writer.write_bytes(payload); - let payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - source_chain, - message_id, - source_address, - self.channel.to_address(), - payload, - ); + #[test] + #[expected_failure(abort_code = EUntrustedChain)] + fun test_decode_approved_message_origin_not_hub_routed() { + let ctx = &mut tx_context::dummy(); + let self = create_for_testing(ctx); + + let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); + let source_address = ascii::string(ITS_HUB_ADDRESS); + let message_id = ascii::string(b"message_id"); + let origin_chain = ascii::string(b"Source Chain"); + let payload = b"payload"; + + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + writer.write_bytes(origin_chain.into_bytes()); + writer.write_bytes(payload); + let payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + source_chain, + message_id, + source_address, + self.channel.to_address(), + payload, + ); - self.decode_approved_message(approved_message); + self.decode_approved_message(approved_message); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EUntrustedChain)] -fun test_decode_approved_message_untrusted_chain() { - let ctx = &mut tx_context::dummy(); - let self = create_for_testing(ctx); - - let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); - let source_address = ascii::string(ITS_HUB_ADDRESS); - let message_id = ascii::string(b"message_id"); - let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); - let payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - source_chain, - message_id, - source_address, - self.channel.to_address(), - payload, - ); + #[test] + #[expected_failure(abort_code = EUntrustedChain)] + fun test_decode_approved_message_untrusted_chain() { + let ctx = &mut tx_context::dummy(); + let self = create_for_testing(ctx); + + let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); + let source_address = ascii::string(ITS_HUB_ADDRESS); + let message_id = ascii::string(b"message_id"); + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB); + let payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + source_chain, + message_id, + source_address, + self.channel.to_address(), + payload, + ); - self.decode_approved_message(approved_message); + self.decode_approved_message(approved_message); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EInvalidMessageType)] -fun test_decode_approved_message_invalid_message_type() { - let ctx = &mut tx_context::dummy(); - let self = create_for_testing(ctx); - - let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); - let source_address = ascii::string(ITS_HUB_ADDRESS); - let message_id = ascii::string(b"message_id"); - let mut writer = abi::new_writer(3); - writer.write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER); - let payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - source_chain, - message_id, - source_address, - self.channel.to_address(), - payload, - ); + #[test] + #[expected_failure(abort_code = EInvalidMessageType)] + fun test_decode_approved_message_invalid_message_type() { + let ctx = &mut tx_context::dummy(); + let self = create_for_testing(ctx); + + let source_chain = ascii::string(ITS_HUB_CHAIN_NAME); + let source_address = ascii::string(ITS_HUB_ADDRESS); + let message_id = ascii::string(b"message_id"); + let mut writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER); + let payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + source_chain, + message_id, + source_address, + self.channel.to_address(), + payload, + ); - self.decode_approved_message(approved_message); + self.decode_approved_message(approved_message); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -fun test_prepare_message_to_hub() { - let ctx = &mut tx_context::dummy(); - let mut self = create_for_testing(ctx); + #[test] + fun test_prepare_message_to_hub() { + let ctx = &mut tx_context::dummy(); + let mut self = create_for_testing(ctx); - let destination_chain = ascii::string(b"Destination Chain"); + let destination_chain = ascii::string(b"Destination Chain"); - let mut payload = b"payload"; + let mut payload = b"payload"; - self.add_trusted_chain(destination_chain); + self.add_trusted_chain(destination_chain); - payload = wrap_payload_sending(payload, destination_chain); + payload = wrap_payload_sending(payload, destination_chain); - let message_ticket = self.prepare_message(payload); + let message_ticket = self.prepare_message(payload); - assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); - assert!(message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string()); + assert!(message_ticket.destination_chain() == ITS_HUB_CHAIN_NAME.to_ascii_string()); + assert!(message_ticket.destination_address() == ITS_HUB_ADDRESS.to_ascii_string()); - sui::test_utils::destroy(self); - sui::test_utils::destroy(message_ticket); -} + sui::test_utils::destroy(self); + sui::test_utils::destroy(message_ticket); + } -#[test] -#[expected_failure(abort_code = EInvalidMessageType)] -fun test_receive_interchain_transfer_invalid_message_type() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing(ctx); + #[test] + #[expected_failure(abort_code = EInvalidMessageType)] + fun test_receive_interchain_transfer_invalid_message_type() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing(ctx); - let coin_info = interchain_token_service::coin_info::from_info( + let coin_info = + interchain_token_service::coin_info::from_info( string::utf8(b"Name"), ascii::string(b"Symbol"), 10, ); - let amount = 1234; - let mut coin_management = interchain_token_service::coin_management::new_locked(); - let coin = sui::coin::mint_for_testing(amount, ctx); - coin_management.take_balance(coin.into_balance(), &clock); - - let token_id = self.register_coin(coin_info, coin_management); - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; - let destination_address = @0x1; - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(b""); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - self.channel.to_address(), - payload, - ); + let amount = 1234; + let mut coin_management = interchain_token_service::coin_management::new_locked(); + let coin = sui::coin::mint_for_testing(amount, ctx); + coin_management.take_balance(coin.into_balance(), &clock); + + let token_id = self.register_coin(coin_info, coin_management); + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; + let destination_address = @0x1; + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(b""); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + self.channel.to_address(), + payload, + ); - self.receive_interchain_transfer(approved_message, &clock, ctx); + self.receive_interchain_transfer(approved_message, &clock, ctx); - clock.destroy_for_testing(); - sui::test_utils::destroy(self); -} + clock.destroy_for_testing(); + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EInterchainTransferHasData)] -fun test_receive_interchain_transfer_passed_data() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing(ctx); + #[test] + #[expected_failure(abort_code = EInterchainTransferHasData)] + fun test_receive_interchain_transfer_passed_data() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing(ctx); - let coin_info = interchain_token_service::coin_info::from_info( + let coin_info = + interchain_token_service::coin_info::from_info( string::utf8(b"Name"), ascii::string(b"Symbol"), 10, ); - let amount = 1234; - let mut coin_management = interchain_token_service::coin_management::new_locked(); - let coin = sui::coin::mint_for_testing(amount, ctx); - coin_management.take_balance(coin.into_balance(), &clock); - - let token_id = self.register_coin(coin_info, coin_management); - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; - let destination_address = @0x1; - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(b"some data"); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - self.channel.to_address(), - payload, - ); + let amount = 1234; + let mut coin_management = interchain_token_service::coin_management::new_locked(); + let coin = sui::coin::mint_for_testing(amount, ctx); + coin_management.take_balance(coin.into_balance(), &clock); + + let token_id = self.register_coin(coin_info, coin_management); + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; + let destination_address = @0x1; + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(b"some data"); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + self.channel.to_address(), + payload, + ); - self.receive_interchain_transfer(approved_message, &clock, ctx); + self.receive_interchain_transfer(approved_message, &clock, ctx); - clock.destroy_for_testing(); - sui::test_utils::destroy(self); -} + clock.destroy_for_testing(); + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EInvalidMessageType)] -fun test_receive_interchain_transfer_with_data_invalid_message_type() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing(ctx); - let coin_info = interchain_token_service::coin_info::from_info( + #[test] + #[expected_failure(abort_code = EInvalidMessageType)] + fun test_receive_interchain_transfer_with_data_invalid_message_type() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing(ctx); + let coin_info = + interchain_token_service::coin_info::from_info( string::utf8(b"Name"), ascii::string(b"Symbol"), 10, ); - let amount = 1234; - let mut coin_management = interchain_token_service::coin_management::new_locked(); - let coin = sui::coin::mint_for_testing(amount, ctx); - coin_management.take_balance(coin.into_balance(), &clock); - - let token_id = self.register_coin(coin_info, coin_management); - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; - let channel = channel::new(ctx); - let destination_address = channel.to_address(); - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(b"some_data"); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - self.channel.to_address(), - payload, - ); + let amount = 1234; + let mut coin_management = interchain_token_service::coin_management::new_locked(); + let coin = sui::coin::mint_for_testing(amount, ctx); + coin_management.take_balance(coin.into_balance(), &clock); + + let token_id = self.register_coin(coin_info, coin_management); + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; + let channel = channel::new(ctx); + let destination_address = channel.to_address(); + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(b"some_data"); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + self.channel.to_address(), + payload, + ); - let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( - approved_message, - &channel, - &clock, - ctx, - ); + let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( + approved_message, + &channel, + &clock, + ctx, + ); - clock.destroy_for_testing(); - channel.destroy(); - sui::test_utils::destroy(self); - sui::test_utils::destroy(received_coin); -} + clock.destroy_for_testing(); + channel.destroy(); + sui::test_utils::destroy(self); + sui::test_utils::destroy(received_coin); + } -#[test] -#[expected_failure(abort_code = EWrongDestination)] -fun test_receive_interchain_transfer_with_data_wrong_destination() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing(ctx); + #[test] + #[expected_failure(abort_code = EWrongDestination)] + fun test_receive_interchain_transfer_with_data_wrong_destination() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing(ctx); - let coin_info = interchain_token_service::coin_info::from_info( + let coin_info = + interchain_token_service::coin_info::from_info( string::utf8(b"Name"), ascii::string(b"Symbol"), 10, ); - let amount = 1234; - let mut coin_management = interchain_token_service::coin_management::new_locked(); - let coin = sui::coin::mint_for_testing(amount, ctx); - coin_management.take_balance(coin.into_balance(), &clock); - - let token_id = self.register_coin(coin_info, coin_management); - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; - let channel = channel::new(ctx); - let destination_address = @0x1; - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(b"some_data"); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - self.channel.to_address(), - payload, - ); + let amount = 1234; + let mut coin_management = interchain_token_service::coin_management::new_locked(); + let coin = sui::coin::mint_for_testing(amount, ctx); + coin_management.take_balance(coin.into_balance(), &clock); + + let token_id = self.register_coin(coin_info, coin_management); + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; + let channel = channel::new(ctx); + let destination_address = @0x1; + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(b"some_data"); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + self.channel.to_address(), + payload, + ); - let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( - approved_message, - &channel, - &clock, - ctx, - ); + let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( + approved_message, + &channel, + &clock, + ctx, + ); - clock.destroy_for_testing(); - channel.destroy(); - sui::test_utils::destroy(self); - sui::test_utils::destroy(received_coin); -} + clock.destroy_for_testing(); + channel.destroy(); + sui::test_utils::destroy(self); + sui::test_utils::destroy(received_coin); + } -#[test] -#[expected_failure(abort_code = EInterchainTransferHasNoData)] -fun test_receive_interchain_transfer_with_data_no_data() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing(ctx); + #[test] + #[expected_failure(abort_code = EInterchainTransferHasNoData)] + fun test_receive_interchain_transfer_with_data_no_data() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing(ctx); - let coin_info = interchain_token_service::coin_info::from_info( + let coin_info = + interchain_token_service::coin_info::from_info( string::utf8(b"Name"), ascii::string(b"Symbol"), 10, ); - let amount = 1234; - let mut coin_management = interchain_token_service::coin_management::new_locked(); - let coin = sui::coin::mint_for_testing(amount, ctx); - coin_management.take_balance(coin.into_balance(), &clock); - - let token_id = self.register_coin(coin_info, coin_management); - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let its_source_address = b"Source Address"; - let channel = channel::new(ctx); - let destination_address = channel.to_address(); - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(token_id.to_u256()) - .write_bytes(its_source_address) - .write_bytes(destination_address.to_bytes()) - .write_u256((amount as u256)) - .write_bytes(b""); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - self.channel.to_address(), - payload, - ); + let amount = 1234; + let mut coin_management = interchain_token_service::coin_management::new_locked(); + let coin = sui::coin::mint_for_testing(amount, ctx); + coin_management.take_balance(coin.into_balance(), &clock); + + let token_id = self.register_coin(coin_info, coin_management); + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let its_source_address = b"Source Address"; + let channel = channel::new(ctx); + let destination_address = channel.to_address(); + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(token_id.to_u256()) + .write_bytes(its_source_address) + .write_bytes(destination_address.to_bytes()) + .write_u256((amount as u256)) + .write_bytes(b""); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + self.channel.to_address(), + payload, + ); - let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( - approved_message, - &channel, - &clock, - ctx, - ); + let (_, _, _, received_coin) = self.receive_interchain_transfer_with_data( + approved_message, + &channel, + &clock, + ctx, + ); - clock.destroy_for_testing(); - channel.destroy(); - sui::test_utils::destroy(self); - sui::test_utils::destroy(received_coin); -} + clock.destroy_for_testing(); + channel.destroy(); + sui::test_utils::destroy(self); + sui::test_utils::destroy(received_coin); + } -#[test] -fun test_receive_deploy_interchain_token_with_distributor() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing(ctx); - - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let name = b"Token Name"; - let symbol = b"Symbol"; - let decimals = 9; - let token_id: u256 = 1234; - let distributor = @0x1; - - self.create_unregistered_coin(symbol, decimals, ctx); - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) - .write_u256(token_id) - .write_bytes(name) - .write_bytes(symbol) - .write_u256((decimals as u256)) - .write_bytes(distributor.to_bytes()); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - self.channel.to_address(), - payload, - ); + #[test] + fun test_receive_deploy_interchain_token_with_distributor() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing(ctx); + + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let name = b"Token Name"; + let symbol = b"Symbol"; + let decimals = 9; + let token_id: u256 = 1234; + let distributor = @0x1; + + self.create_unregistered_coin(symbol, decimals, ctx); + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) + .write_u256(token_id) + .write_bytes(name) + .write_bytes(symbol) + .write_u256((decimals as u256)) + .write_bytes(distributor.to_bytes()); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + self.channel.to_address(), + payload, + ); - self.receive_deploy_interchain_token(approved_message); + self.receive_deploy_interchain_token(approved_message); - clock.destroy_for_testing(); - sui::test_utils::destroy(self); -} + clock.destroy_for_testing(); + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EInvalidMessageType)] -fun test_receive_deploy_interchain_token_invalid_message_type() { - let ctx = &mut tx_context::dummy(); - let clock = sui::clock::create_for_testing(ctx); - let mut self = create_for_testing(ctx); - - let source_chain = ascii::string(b"Chain Name"); - let message_id = ascii::string(b"Message Id"); - let name = b"Token Name"; - let symbol = b"Symbol"; - let decimals = 9; - let token_id: u256 = 1234; - - self.create_unregistered_coin(symbol, decimals, ctx); - - let mut writer = abi::new_writer(6); - writer - .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) - .write_u256(token_id) - .write_bytes(name) - .write_bytes(symbol) - .write_u256((decimals as u256)) - .write_bytes(b""); - let mut payload = writer.into_bytes(); - writer = abi::new_writer(3); - writer - .write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB) - .write_bytes(source_chain.into_bytes()) - .write_bytes(payload); - payload = writer.into_bytes(); - - let approved_message = channel::new_approved_message( - ITS_HUB_CHAIN_NAME.to_ascii_string(), - message_id, - ITS_HUB_ADDRESS.to_ascii_string(), - self.channel.to_address(), - payload, - ); + #[test] + #[expected_failure(abort_code = EInvalidMessageType)] + fun test_receive_deploy_interchain_token_invalid_message_type() { + let ctx = &mut tx_context::dummy(); + let clock = sui::clock::create_for_testing(ctx); + let mut self = create_for_testing(ctx); + + let source_chain = ascii::string(b"Chain Name"); + let message_id = ascii::string(b"Message Id"); + let name = b"Token Name"; + let symbol = b"Symbol"; + let decimals = 9; + let token_id: u256 = 1234; + + self.create_unregistered_coin(symbol, decimals, ctx); + + let mut writer = abi::new_writer(6); + writer + .write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER) + .write_u256(token_id) + .write_bytes(name) + .write_bytes(symbol) + .write_u256((decimals as u256)) + .write_bytes(b""); + let mut payload = writer.into_bytes(); + writer = abi::new_writer(3); + writer.write_u256(MESSAGE_TYPE_RECEIVE_FROM_HUB).write_bytes(source_chain.into_bytes()).write_bytes(payload); + payload = writer.into_bytes(); + + let approved_message = channel::new_approved_message( + ITS_HUB_CHAIN_NAME.to_ascii_string(), + message_id, + ITS_HUB_ADDRESS.to_ascii_string(), + self.channel.to_address(), + payload, + ); - self.receive_deploy_interchain_token(approved_message); + self.receive_deploy_interchain_token(approved_message); - clock.destroy_for_testing(); - sui::test_utils::destroy(self); -} + clock.destroy_for_testing(); + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = EUnregisteredCoinHasUrl)] -fun test_give_unregistered_coin_with_url() { - let name = b"Coin"; - let symbol = b"COIN"; - let decimals = 12; - let ctx = &mut tx_context::dummy(); - let mut self = create_for_testing(ctx); - let url = sui::url::new_unsafe_from_bytes(b"url"); - - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata_custom( - name, - symbol, - decimals, - option::some(url), - ctx, - ); + #[test] + #[expected_failure(abort_code = EUnregisteredCoinHasUrl)] + fun test_give_unregistered_coin_with_url() { + let name = b"Coin"; + let symbol = b"COIN"; + let decimals = 12; + let ctx = &mut tx_context::dummy(); + let mut self = create_for_testing(ctx); + let url = sui::url::new_unsafe_from_bytes(b"url"); + + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata_custom( + name, + symbol, + decimals, + option::some(url), + ctx, + ); - self.give_unregistered_coin(treasury_cap, coin_metadata); + self.give_unregistered_coin(treasury_cap, coin_metadata); - sui::test_utils::destroy(self); -} + sui::test_utils::destroy(self); + } -#[test] -#[expected_failure(abort_code = ENotDistributor)] -fun test_burn_as_distributor_not_distributor() { - let ctx = &mut tx_context::dummy(); - let mut self = create_for_testing(ctx); - let symbol = b"COIN"; - let decimals = 9; - let amount = 1234; - - let ( - mut treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata(symbol, decimals, ctx); - let coin = treasury_cap.mint(amount, ctx); - let coin_info = interchain_token_service::coin_info::from_metadata( + #[test] + #[expected_failure(abort_code = ENotDistributor)] + fun test_burn_as_distributor_not_distributor() { + let ctx = &mut tx_context::dummy(); + let mut self = create_for_testing(ctx); + let symbol = b"COIN"; + let decimals = 9; + let amount = 1234; + + let (mut treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata(symbol, decimals, ctx); + let coin = treasury_cap.mint(amount, ctx); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, ); - let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); + let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); - let channel = channel::new(ctx); - coin_management.add_distributor(@0x1); + let channel = channel::new(ctx); + coin_management.add_distributor(@0x1); - let token_id = self.register_coin(coin_info, coin_management); - self.burn_as_distributor(&channel, token_id, coin); + let token_id = self.register_coin(coin_info, coin_management); + self.burn_as_distributor(&channel, token_id, coin); - sui::test_utils::destroy(self); - channel.destroy(); -} - -#[test] -#[expected_failure(abort_code = ENonZeroTotalSupply)] -fun test_give_unregistered_coin_not_zero_total_supply() { - let symbol = b"COIN"; - let decimals = 12; - let ctx = &mut tx_context::dummy(); - let mut self = create_for_testing(ctx); - - let ( - mut treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata(symbol, decimals, ctx); - let coin = treasury_cap.mint(1, ctx); + sui::test_utils::destroy(self); + channel.destroy(); + } - self.give_unregistered_coin(treasury_cap, coin_metadata); + #[test] + #[expected_failure(abort_code = ENonZeroTotalSupply)] + fun test_give_unregistered_coin_not_zero_total_supply() { + let symbol = b"COIN"; + let decimals = 12; + let ctx = &mut tx_context::dummy(); + let mut self = create_for_testing(ctx); - sui::test_utils::destroy(self); - sui::test_utils::destroy(coin); -} + let (mut treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata(symbol, decimals, ctx); + let coin = treasury_cap.mint(1, ctx); -#[test] -#[expected_failure(abort_code = EModuleNameDoesNotMatchSymbol)] -fun test_give_unregistered_coin_module_name_missmatch() { - let symbol = b"SYMBOL"; - let decimals = 12; - let ctx = &mut tx_context::dummy(); - let mut self = create_for_testing(ctx); + self.give_unregistered_coin(treasury_cap, coin_metadata); - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); + sui::test_utils::destroy(self); + sui::test_utils::destroy(coin); + } - self.give_unregistered_coin(treasury_cap, coin_metadata); + #[test] + #[expected_failure(abort_code = EModuleNameDoesNotMatchSymbol)] + fun test_give_unregistered_coin_module_name_missmatch() { + let symbol = b"SYMBOL"; + let decimals = 12; + let ctx = &mut tx_context::dummy(); + let mut self = create_for_testing(ctx); + + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); - sui::test_utils::destroy(self); -} + self.give_unregistered_coin(treasury_cap, coin_metadata); -#[test] -#[expected_failure(abort_code = ENotDistributor)] -fun test_mint_as_distributor_not_distributor() { - let ctx = &mut tx_context::dummy(); - let mut self = create_for_testing(ctx); - let symbol = b"COIN"; - let decimals = 9; + sui::test_utils::destroy(self); + } - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); - let coin_info = interchain_token_service::coin_info::from_metadata( + #[test] + #[expected_failure(abort_code = ENotDistributor)] + fun test_mint_as_distributor_not_distributor() { + let ctx = &mut tx_context::dummy(); + let mut self = create_for_testing(ctx); + let symbol = b"COIN"; + let decimals = 9; + + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, ); - let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); + let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); - let channel = channel::new(ctx); - coin_management.add_distributor(@0x1); - let amount = 1234; + let channel = channel::new(ctx); + coin_management.add_distributor(@0x1); + let amount = 1234; - let token_id = self.register_coin(coin_info, coin_management); - let coin = self.mint_as_distributor( - &channel, - token_id, - amount, - ctx, - ); - - assert!(coin.value() == amount); + let token_id = self.register_coin(coin_info, coin_management); + let coin = self.mint_as_distributor( + &channel, + token_id, + amount, + ctx, + ); - sui::test_utils::destroy(self); - sui::test_utils::destroy(coin); - channel.destroy(); -} + assert!(coin.value() == amount); -#[test] -#[expected_failure(abort_code = EUnregisteredCoin)] -fun test_coin_data_not_registered() { - let ctx = &mut tx_context::dummy(); - let self = create_for_testing(ctx); - let token_id = token_id::from_address(@0x1); + sui::test_utils::destroy(self); + sui::test_utils::destroy(coin); + channel.destroy(); + } - self.coin_data(token_id); + #[test] + #[expected_failure(abort_code = EUnregisteredCoin)] + fun test_coin_data_not_registered() { + let ctx = &mut tx_context::dummy(); + let self = create_for_testing(ctx); + let token_id = token_id::from_address(@0x1); - sui::test_utils::destroy(self); -} + self.coin_data(token_id); -#[test] -#[expected_failure(abort_code = ENotDistributor)] -fun test_mint_to_as_distributor_not_distributor() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); - let symbol = b"COIN"; - let decimals = 9; + sui::test_utils::destroy(self); + } - let ( - treasury_cap, - coin_metadata, - ) = interchain_token_service::coin::create_treasury_and_metadata( - symbol, - decimals, - ctx, - ); - let coin_info = interchain_token_service::coin_info::from_metadata( + #[test] + #[expected_failure(abort_code = ENotDistributor)] + fun test_mint_to_as_distributor_not_distributor() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); + let symbol = b"COIN"; + let decimals = 9; + + let (treasury_cap, coin_metadata) = interchain_token_service::coin::create_treasury_and_metadata( + symbol, + decimals, + ctx, + ); + let coin_info = interchain_token_service::coin_info::from_metadata( coin_metadata, ); - let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); + let mut coin_management = interchain_token_service::coin_management::new_with_cap(treasury_cap); - let channel = channel::new(ctx); - coin_management.add_distributor(@0x1); - let amount = 1234; + let channel = channel::new(ctx); + coin_management.add_distributor(@0x1); + let amount = 1234; - let token_id = register_coin(&mut its, coin_info, coin_management); - mint_to_as_distributor( - &mut its, - &channel, - token_id, - @0x2, - amount, - ctx, - ); + let token_id = register_coin(&mut its, coin_info, coin_management); + mint_to_as_distributor( + &mut its, + &channel, + token_id, + @0x2, + amount, + ctx, + ); - sui::test_utils::destroy(its); - channel.destroy(); -} + sui::test_utils::destroy(its); + channel.destroy(); + } -#[test] -#[expected_failure(abort_code = EOverflow)] -fun test_read_amount_overflow() { - let mut writer = abi::new_writer(1); - writer.write_u256(1u256 << 64); + #[test] + #[expected_failure(abort_code = EOverflow)] + fun test_read_amount_overflow() { + let mut writer = abi::new_writer(1); + writer.write_u256(1u256 << 64); - let mut reader = abi::new_reader(writer.into_bytes()); + let mut reader = abi::new_reader(writer.into_bytes()); - read_amount(&mut reader); -} + read_amount(&mut reader); + } -#[test] -#[expected_failure(abort_code = EUnregisteredCoin)] -fun test_registered_coin_type_not_registered() { - let ctx = &mut tx_context::dummy(); - let its = create_for_testing(ctx); - let token_id = token_id::from_address(@0x1); + #[test] + #[expected_failure(abort_code = EUnregisteredCoin)] + fun test_registered_coin_type_not_registered() { + let ctx = &mut tx_context::dummy(); + let its = create_for_testing(ctx); + let token_id = token_id::from_address(@0x1); - its.registered_coin_type(token_id); + its.registered_coin_type(token_id); - sui::test_utils::destroy(its); -} + sui::test_utils::destroy(its); + } -#[test] -#[expected_failure(abort_code = EUnregisteredCoin)] -fun test_unregistered_coin_type_not_registered() { - let ctx = &mut tx_context::dummy(); - let its = create_for_testing(ctx); - let symbol = &b"symbol".to_ascii_string(); - let decimals = 8; + #[test] + #[expected_failure(abort_code = EUnregisteredCoin)] + fun test_unregistered_coin_type_not_registered() { + let ctx = &mut tx_context::dummy(); + let its = create_for_testing(ctx); + let symbol = &b"symbol".to_ascii_string(); + let decimals = 8; - its.unregistered_coin_type(symbol, decimals); + its.unregistered_coin_type(symbol, decimals); - sui::test_utils::destroy(its); -} + sui::test_utils::destroy(its); + } -#[test] -#[expected_failure(abort_code = ENewerTicket)] -fun test_send_interchain_transfer_newer_ticket() { - let ctx = &mut tx_context::dummy(); - let mut its = create_for_testing(ctx); - - let token_id = token_id::from_address(@0x1); - let amount = 1234; - let coin = sui::coin::mint_for_testing(amount, ctx); - let destination_chain = ascii::string(b"Chain Name"); - let destination_address = b"address"; - let metadata = b""; - let source_channel = channel::new(ctx); - let clock = sui::clock::create_for_testing(ctx); - let current_version = 0; - let invalid_version = 1; - - let interchain_transfer_ticket = interchain_token_service::interchain_transfer_ticket::new< - COIN, - >( + #[test] + #[expected_failure(abort_code = ENewerTicket)] + fun test_send_interchain_transfer_newer_ticket() { + let ctx = &mut tx_context::dummy(); + let mut its = create_for_testing(ctx); + + let token_id = token_id::from_address(@0x1); + let amount = 1234; + let coin = sui::coin::mint_for_testing(amount, ctx); + let destination_chain = ascii::string(b"Chain Name"); + let destination_address = b"address"; + let metadata = b""; + let source_channel = channel::new(ctx); + let clock = sui::clock::create_for_testing(ctx); + let current_version = 0; + let invalid_version = 1; + + let interchain_transfer_ticket = + interchain_token_service::interchain_transfer_ticket::new( token_id, coin.into_balance(), source_channel.to_address(), @@ -1596,28 +1467,29 @@ fun test_send_interchain_transfer_newer_ticket() { metadata, invalid_version, ); - let message_ticket = its.send_interchain_transfer( - interchain_transfer_ticket, - current_version, - &clock, - ); + let message_ticket = its.send_interchain_transfer( + interchain_transfer_ticket, + current_version, + &clock, + ); - sui::test_utils::destroy(its); - sui::test_utils::destroy(source_channel); - sui::test_utils::destroy(message_ticket); - sui::test_utils::destroy(clock); -} + sui::test_utils::destroy(its); + sui::test_utils::destroy(source_channel); + sui::test_utils::destroy(message_ticket); + sui::test_utils::destroy(clock); + } -#[test] -#[expected_failure(abort_code = EUntrustedChain)] -fun test_prepare_hub_message_untrusted_chain() { - let ctx = &mut tx_context::dummy(); - let its = create_for_testing(ctx); - let payload = b"payload"; - let destination_chain = b"destination_chain".to_ascii_string(); + #[test] + #[expected_failure(abort_code = EUntrustedChain)] + fun test_prepare_hub_message_untrusted_chain() { + let ctx = &mut tx_context::dummy(); + let its = create_for_testing(ctx); + let payload = b"payload"; + let destination_chain = b"destination_chain".to_ascii_string(); - let message_ticket = its.prepare_hub_message(payload, destination_chain); + let message_ticket = its.prepare_hub_message(payload, destination_chain); - sui::test_utils::destroy(its); - sui::test_utils::destroy(message_ticket); + sui::test_utils::destroy(its); + sui::test_utils::destroy(message_ticket); + } } From fdfe1e966bfd2c78a2fd0741c9583970115a36ac Mon Sep 17 00:00:00 2001 From: Foivos Date: Wed, 29 Jan 2025 16:37:17 +0200 Subject: [PATCH 51/68] cs --- .changeset/friendly-starfishes-rush.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/friendly-starfishes-rush.md diff --git a/.changeset/friendly-starfishes-rush.md b/.changeset/friendly-starfishes-rush.md new file mode 100644 index 00000000..7c0a7010 --- /dev/null +++ b/.changeset/friendly-starfishes-rush.md @@ -0,0 +1,5 @@ +--- +'@axelar-network/axelar-cgp-sui': patch +--- + +Using prettier-move formatter for move files From 4dbadc2810dd8306101d8e49e66ce239986529e7 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 3 Feb 2025 16:20:26 +0200 Subject: [PATCH 52/68] change the prettier command --- .prettierrc | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.prettierrc b/.prettierrc index 70ea16e0..7a34d011 100644 --- a/.prettierrc +++ b/.prettierrc @@ -29,6 +29,14 @@ "options": { "tabWidth": 2 } + }, + { + "files": "*.move", + "options": { + "plugins": [ + "@mysten/prettier-plugin-move" + ] + } } ] } diff --git a/package.json b/package.json index 83d7990f..c1ea5a3d 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "cs": "changeset", "verify-web-build": "node scripts/verify-web-build.js", "lint": "eslint --fix './src/**/*.ts' './test/*.js'", - "prettier": "prettier --write './src/**/*.ts' './test/*.js' && npx prettier-move -w ./move/**/*.move", + "prettier": "prettier --write './src/**/*.ts' './test/*.js' './move/**/*.move'", "docs": "./scripts/docs.sh" }, "keywords": [ From 355a05f0a3249312aa58e2f5d037aa8ca13c4e44 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 3 Feb 2025 18:13:09 +0200 Subject: [PATCH 53/68] remove newline --- move/abi/sources/abi.move | 1 - 1 file changed, 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 280486b0..74fee8de 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -363,4 +363,3 @@ module abi::abi { writer.append_bytes(vector[]); } } - From 9e899b8991d56eb6d751c474a89b27d2ff7ab03a Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:01:16 +0200 Subject: [PATCH 54/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 1 + 1 file changed, 1 insertion(+) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 74fee8de..4f111937 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -51,6 +51,7 @@ module abi::abi { // ---------------- // Public Functions // ---------------- + /// Creates a new AbiReader from the bytes passed. public fun new_reader(bytes: vector): AbiReader { AbiReader { From 79c87b74e02fba5fbeb1c28eba704559b68ff6ea Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:01:28 +0200 Subject: [PATCH 55/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 4f111937..c6aa31c5 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -193,7 +193,7 @@ module abi::abi { } /// Write a `vector` into the next slot of an `AbiWriter`. Can be used to - /// encode other vectors of fixed length variables as well. + /// write other vectors of fixed length types as well. public fun write_vector_u256(self: &mut AbiWriter, var: vector): &mut AbiWriter { let offset = self.bytes.length() as u256; self.write_u256(offset); From 9c5f1745ec13b945bb5ac4d6144c40e2b7bf2a26 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:01:37 +0200 Subject: [PATCH 56/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index c6aa31c5..b49c0255 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -119,7 +119,7 @@ module abi::abi { /// Reads a vector of fixed length variables from an `AbiReader` as a /// `vector`. Can also be cast into vectors of other fixed length - /// variables. + /// types. public fun read_vector_u256(self: &mut AbiReader): vector { let pos = self.pos; From e26823fff2b91239c4643387cf71c43514fd5550 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:01:46 +0200 Subject: [PATCH 57/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index b49c0255..3f4ae372 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -138,7 +138,7 @@ module abi::abi { /// Reads a vector of variable length variables from an `AbiReader` as a /// `vector>`. Can also be cast into vectors of other variable length - /// variables. + /// types. public fun read_vector_bytes(self: &mut AbiReader): vector> { let pos = self.pos; let head = self.head; From 74b6b6a613dd3ab301f01140fcb9e215f7fde479 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:01:52 +0200 Subject: [PATCH 58/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 3f4ae372..4d8b646f 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -179,8 +179,8 @@ module abi::abi { self.write_u256(var as u256) } - /// Write some bytes into the next slot of an `AbiWriter`. Can be used to write - /// another variable length variable, such as a `String`as well. + /// Write a variable-length bytes into the next slot of an `AbiWriter`. Can be used to write + /// other variable length types, such as `String`. public fun write_bytes(self: &mut AbiWriter, var: vector): &mut AbiWriter { let offset = self.bytes.length() as u256; self.write_u256(offset); From 837dbb2db34eda003411ed515b2119020b84272c Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:01:58 +0200 Subject: [PATCH 59/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 4d8b646f..6f703755 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -209,7 +209,7 @@ module abi::abi { } /// Write a vector of bytes into the next slot of an `AbiWriter`. Can be used to - /// encode vectors of other variable length variables as well. + /// write vectors of other variable length types as well. public fun write_vector_bytes(self: &mut AbiWriter, var: vector>): &mut AbiWriter { let offset = self.bytes.length() as u256; self.write_u256(offset); From 87cf7ced7d421b4943ce0360aeb62c87f25a99f2 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:02:05 +0200 Subject: [PATCH 60/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 6f703755..85c7bfad 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -244,7 +244,10 @@ module abi::abi { self.bytes.append(var); - ((U256_BYTES) - 1 - (length - 1) % U256_BYTES).do!(|_| self.bytes.push_back(0)); + // Number of bytes in the overflow 32-byte slot that are filled + let filled = ((length - 1) % U256_BYTES) + 1; + let padding = U256_BYTES - filled; + padding.do!(|_| self.bytes.push_back(0)); } fun decode_bytes(self: &mut AbiReader): vector { From d7913ef034195dbf256da025fc778db43b162c32 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:02:11 +0200 Subject: [PATCH 61/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 2 ++ 1 file changed, 2 insertions(+) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 85c7bfad..c4e1af41 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -34,6 +34,8 @@ module abi::abi { } /// Used to encode variables into abi encoded bytes. + /// + /// # Examples /// ```rust /// let mut writer = abi::new_writer(4); /// writer From 442e2596f89ca81ce1ff0095375666a80a6660cb Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:02:18 +0200 Subject: [PATCH 62/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index c4e1af41..0b4141e8 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -17,8 +17,10 @@ module abi::abi { // ----- // Types // ----- + /// Used to decode abi encoded bytes into variables. - /// Example + /// + /// # Examples /// ```rust /// let mut reader = abi::new_reader(data); /// let number = reader.read_u256(); From da2731c6417a7310a980d475761e3de236873b7c Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:02:35 +0200 Subject: [PATCH 63/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 0b4141e8..2e87d3af 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -163,7 +163,7 @@ module abi::abi { } /// Write a `u256` into the next slot of an `AbiWriter`. Can be used to write - /// other fixed lenght variables as well. + /// other fixed length types as well. public fun write_u256(self: &mut AbiWriter, var: u256): &mut AbiWriter { let pos = self.pos; From 6262897475d71418eb4d8229eddea712dcfe03f5 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:05:20 +0200 Subject: [PATCH 64/68] added a unit test --- move/abi/sources/abi.move | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 2e87d3af..57b3aa4e 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -364,6 +364,17 @@ module abi::abi { assert!(reader.read_u8() == val); } + + #[test] + #[expected_failure] + fun test_read_u8_overflow() { + let val = 256; + let mut writer = new_writer(1); + writer.write_u256(val); + let bytes = writer.into_bytes(); + let mut reader = new_reader(bytes); + reader.read_u8(); + } #[test] fun test_append_empty_bytes() { From 3b38ae081cac4aa258e5f4b2d6c9c10a414e0c69 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:05:28 +0200 Subject: [PATCH 65/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 57b3aa4e..a2e1a6bb 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -94,7 +94,7 @@ module abi::abi { var } - /// Wrapper for `read_u256` that casts the result into a `u8`. + /// Read a `u8` from the next slot of the `AbiReader`. Aborts if the slot value exceeds `u8::MAX` public fun read_u8(self: &mut AbiReader): u8 { self.read_u256() as u8 } From a6cf2c8309ee94c65e5767d683db4e81da576345 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:05:46 +0200 Subject: [PATCH 66/68] Update move/abi/sources/abi.move Co-authored-by: Milap Sheth --- move/abi/sources/abi.move | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index a2e1a6bb..0d8deeec 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -104,8 +104,8 @@ module abi::abi { self.pos = self.pos + U256_BYTES; } - /// Reads a variable length variable from an `AbiReader`, as bytes. Can be - /// converted to other variable length variables as well (such as `Strings`). + /// Reads a variable length bytes from an `AbiReader`. + /// This can be used to read other variable length types, such as `String`. public fun read_bytes(self: &mut AbiReader): vector { let pos = self.pos; From c9e2cc51d153020de6871acb7599d8caa3f564ed Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:07:04 +0200 Subject: [PATCH 67/68] Changed the cs and removed the Readme --- .changeset/four-cows-shout.md | 2 +- move/abi/README.md | 61 ----------------------------------- 2 files changed, 1 insertion(+), 62 deletions(-) delete mode 100644 move/abi/README.md diff --git a/.changeset/four-cows-shout.md b/.changeset/four-cows-shout.md index ef64f791..8481efda 100644 --- a/.changeset/four-cows-shout.md +++ b/.changeset/four-cows-shout.md @@ -2,4 +2,4 @@ '@axelar-network/axelar-cgp-sui': minor --- -Added two utility functions in `abi` to allow for structs and nested vectors to be encoded/decoded, added a readme to `abi`, and used macros to clean up the code a bit. +Added a lot of comments in the abi code for clarity. diff --git a/move/abi/README.md b/move/abi/README.md deleted file mode 100644 index 1e436ef9..00000000 --- a/move/abi/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# Abi - -This package aims to port abi encoding and decoding capabilities to Sui. Read more about the specification of abi encoding [here](https://docs.soliditylang.org/en/develop/abi-spec.html#formal-specification-of-the-encoding) - -## Singletons - -There are no singletons in this package. - -## Types - -There are two types exported by this package: `AbiWriter` and `AbiReader`. - -### `AbiWriter` - -This type can be used to encode abi data. It has the following relevant functions: -- `abi::new_writer(length: u64): AbiWriter`: Creates a new `AbiWriter` with the specified length (number of encoded arguments) -- `abi::into_bytes(self: AbiWriter): vector`: Destroys an `AbiWriter` and returns the encoded bytes for it. -- `abi::write_u256(self: &mut AbiWriter, var: u256): &mut AbiWriter`: Writes the provided `u256` into the next slot in the `AbiWriter`. This should be used to write all fixed length variables (`u8`, `u16`, `u32`, `u64`, `u128`, `address` for example) by converting them to `u256`. -- `abi::write_u8(self: &mut AbiWriter, var: u8): &mut AbiWriter`: Wrapper for the above for `u8` specifically. -- `abi::write_bytes(self: &mut AbiWriter, var: vector): &mut AbiWriter`: Writes the provided bytes into the next slot in the `AbiWriter`. This should be used to write all types that are equivelant to `vector` (`ascii::String` and `string::String` for example) by converting them to `vector`. -- `abi::write_vector_u256(self: &mut AbiWriter, var: vector,): &mut AbiWriter`: Writes the provided `vector` into the next slot in the `AbiWriter`. This should be used for vectors of other fixed length variables as well. -- `abi::write_vector_bytes(self: &mut AbiWriter, var: vector>,): &mut AbiWriter`: Writes the provided `vector>` into the nexts slot in the `AbiWriter`. This should be used for vectors of other variable length variables as well. - -#### Example -```rust -let mut writer = abi::new_writer(4); -writer - .write_u256(1234) - .write_bytes(b"some_bytes") - .write_vector_u256(vector[12, 34, 56]) - .write_vector_bytes(vector[b"some", b"more", b"bytes"]); -let encoded_data = writer.into_bytes(); -``` - -#### More complex types -More complex types are not supported yet. - -### `AbiReader` - -This type can be used to decode abi enocded data. The relevant functions are as follows: -- `abi::new_reader(bytes: vector): AbiReader`: Creates a new `AbiReader` to decode the bytes provided. -- `abi::into_remaining_bytes(self: AbiReader): vector`: Get all the bytes stored in the `AbiReader` (name is misleading). -- `abi::read_u256(self: &mut AbiReader): u256`: Read a `u256` from the next slot of the `AbiReader`. Should be used to read other fixed length types as well. -- `abi::read_u8(self: &mut AbiReader): u8`: Wrapper for the above function for `u8`. -- `abi::skip_slot(self: &mut AbiReader)`: Used to ingore a slot on the `AbiReader`, used if it has data encoded there that should be ignored. -- `abi::read_bytes(self: &mut AbiReader): vector<8>`: Read a `vector` from the next slot of the `AbiReader`. Should be used to read other variable length types as well. -- `abi::read_vector_u256(self: &mut AbiReader): vector`: Read a `vector` from the next slot of the `AbiReader`. Should be used to read other fixed length types as well. -- `abi::read_vector_bytes(self: &mut AbiReader): vector>`: Read a `vector>` from the next slot of the `AbiReader`. Should be used to read other vectors of variable length types as well (such as `vector`). - -#### Example -```rust -let mut reader = abi::new_reader(data); -let number = reader.read_u256(); -let name = reader.read_bytes().to_string(); -let addresses = reader.read_vector_u256().map!(|val| sui::address::from_u256(val)); -let info = reader.read_vector_bytes(); -``` - -#### More Complex Types - -More complex types are not supported yet. From 116a57ff441129b835b4b7e4fb2a73587381a4ad Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 4 Feb 2025 13:07:21 +0200 Subject: [PATCH 68/68] prettier --- move/abi/sources/abi.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/abi/sources/abi.move b/move/abi/sources/abi.move index 0d8deeec..5137ddc8 100644 --- a/move/abi/sources/abi.move +++ b/move/abi/sources/abi.move @@ -364,7 +364,7 @@ module abi::abi { assert!(reader.read_u8() == val); } - + #[test] #[expected_failure] fun test_read_u8_overflow() {