diff --git a/sui/escrow_vault/Move.lock b/sui/escrow_vault/Move.lock new file mode 100644 index 0000000000..8e2d9a4568 --- /dev/null +++ b/sui/escrow_vault/Move.lock @@ -0,0 +1,60 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 3 +manifest_digest = "22A69063EDA69DCB6B671D6EDC8D98E83EEF216DBCDC2A034C6AB69DEF967BB4" +deps_digest = "397E6A9F7A624706DBDFEE056CE88391A15876868FD18A88504DA74EB458D697" +dependencies = [ + { id = "Bridge", name = "Bridge" }, + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, + { id = "SuiSystem", name = "SuiSystem" }, + { id = "ibc", name = "ibc" }, +] + +[[move.package]] +id = "Bridge" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "db951a5ea6b125f6253a6b7f436ddba46eb0feb3", subdir = "crates/sui-framework/packages/bridge" } + +dependencies = [ + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, + { id = "SuiSystem", name = "SuiSystem" }, +] + +[[move.package]] +id = "MoveStdlib" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "db951a5ea6b125f6253a6b7f436ddba46eb0feb3", subdir = "crates/sui-framework/packages/move-stdlib" } + +[[move.package]] +id = "Sui" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "db951a5ea6b125f6253a6b7f436ddba46eb0feb3", subdir = "crates/sui-framework/packages/sui-framework" } + +dependencies = [ + { id = "MoveStdlib", name = "MoveStdlib" }, +] + +[[move.package]] +id = "SuiSystem" +source = { git = "https://github.com/MystenLabs/sui.git", rev = "db951a5ea6b125f6253a6b7f436ddba46eb0feb3", subdir = "crates/sui-framework/packages/sui-system" } + +dependencies = [ + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, +] + +[[move.package]] +id = "ibc" +source = { local = "../ibc" } + +dependencies = [ + { id = "Bridge", name = "Bridge" }, + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, + { id = "SuiSystem", name = "SuiSystem" }, +] + +[move.toolchain-version] +compiler-version = "1.55.0" +edition = "2024.beta" +flavor = "sui" diff --git a/sui/escrow_vault/Move.toml b/sui/escrow_vault/Move.toml new file mode 100644 index 0000000000..614626771e --- /dev/null +++ b/sui/escrow_vault/Move.toml @@ -0,0 +1,14 @@ +[package] +edition = "2024.beta" +name = "escrow_vault" + +[dependencies] +ibc = { local = "../ibc" } + +[addresses] +escrow_vault = "0x0" +ibc = "0x0" + +[dev-addresses] +escrow_vault = "0x2222" +ibc = "0x1111" diff --git a/sui/escrow_vault/sources/escrow_vault.move b/sui/escrow_vault/sources/escrow_vault.move new file mode 100644 index 0000000000..e83b15f81c --- /dev/null +++ b/sui/escrow_vault/sources/escrow_vault.move @@ -0,0 +1,258 @@ +// License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved. +// "Business Source License" is a trademark of MariaDB Corporation Ab. + +// Parameters + +// Licensor: Union.fi, Labs Inc. +// Licensed Work: All files under https://github.com/unionlabs/union's sui subdirectory +// The Licensed Work is (c) 2024 Union.fi, Labs Inc. +// Change Date: Four years from the date the Licensed Work is published. +// Change License: Apache-2.0 +// + +// For information about alternative licensing arrangements for the Licensed Work, +// please contact info@union.build. + +// Notice + +// Business Source License 1.1 + +// Terms + +// The Licensor hereby grants you the right to copy, modify, create derivative +// works, redistribute, and make non-production use of the Licensed Work. The +// Licensor may make an Additional Use Grant, above, permitting limited production use. + +// Effective on the Change Date, or the fourth anniversary of the first publicly +// available distribution of a specific version of the Licensed Work under this +// License, whichever comes first, the Licensor hereby grants you rights under +// the terms of the Change License, and the rights granted in the paragraph +// above terminate. + +// If your use of the Licensed Work does not comply with the requirements +// currently in effect as described in this License, you must purchase a +// commercial license from the Licensor, its affiliated entities, or authorized +// resellers, or you must refrain from using the Licensed Work. + +// All copies of the original and modified Licensed Work, and derivative works +// of the Licensed Work, are subject to this License. This License applies +// separately for each version of the Licensed Work and the Change Date may vary +// for each version of the Licensed Work released by Licensor. + +// You must conspicuously display this License on each original or modified copy +// of the Licensed Work. If you receive the Licensed Work in original or +// modified form from a third party, the terms and conditions set forth in this +// License apply to your use of that work. + +// Any use of the Licensed Work in violation of this License will automatically +// terminate your rights under this License for the current and all other +// versions of the Licensed Work. + +// This License does not grant you any right in any trademark or logo of +// Licensor or its affiliates (provided that you may use a trademark or logo of +// Licensor as expressly required by this License). + +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +module escrow_vault::escrow_vault { + use sui::bcs; + use sui::table::{Self, Table}; + use sui::object_bag::{Self, ObjectBag}; + use sui::coin::{Self, Coin}; + use std::type_name; + + const E_UNAUTHORIZED: u64 = 1; + const E_INVALID_PACKET_HASH: u64 = 2; + const E_INTENT_WHITELISTED_ONLY: u64 = 3; + const E_BASE_AMOUNT_MUST_COVER_QUOTE_AMOUNT: u64 = 4; + const E_INVALID_QUOTE_TOKEN: u64 = 6; + const E_ONLY_MAKER: u64 = 0xdeadc0de; + + public struct EscrowVault has key { + id: UID, + admin: address, + coin_bag: ObjectBag, + intent_whitelists: Table, + fungible_counterparties: Table, + } + + public struct ZkgmCap has key, store { + id: UID + } + + public struct FungibleLane has copy, drop, store { + token: vector, + path: u256, + channel: u32, + base_token: vector, + } + + public struct FungibleCounterparty has copy, drop, store { + beneficiary: vector + } + + public struct IntentWhitelistKey has copy, drop, store { + token: vector, + packet_hash: vector, + } + + fun init(ctx: &mut TxContext) { + transfer::transfer( + ZkgmCap { + id: object::new(ctx) + }, + ctx.sender() + ); + transfer::share_object(EscrowVault { + id: object::new(ctx), + admin: ctx.sender(), + coin_bag: object_bag::new(ctx), + intent_whitelists: table::new(ctx), + fungible_counterparties: table::new(ctx), + }); + } + + public fun set_fungible_counterparty( + vault: &mut EscrowVault, + path: u256, + channel: u32, + base_token: vector, + beneficiary: vector, + ctx: &mut TxContext, + ) { + assert!(vault.admin == ctx.sender(), E_UNAUTHORIZED); + + vault.fungible_counterparties.add( + FungibleLane { + token: type_name::get().into_string().into_bytes(), + path, + channel, + base_token + }, + FungibleCounterparty { + beneficiary + } + ); + } + + public fun whitelist_intent( + vault: &mut EscrowVault, + packet_hashes: vector>, + whitelist: bool, + ctx: &mut TxContext, + ) { + assert!(vault.admin == ctx.sender(), E_UNAUTHORIZED); + + packet_hashes.do!(|hash| { + assert!(hash.length() == 32, E_INVALID_PACKET_HASH); + + let whitelist_key = IntentWhitelistKey { + token: type_name::get().into_string().into_bytes(), + packet_hash: hash + }; + + if (vault.intent_whitelists.contains(whitelist_key)) { + if (!whitelist) { + let _ = vault.intent_whitelists.remove(whitelist_key); + }; + } else { + vault.intent_whitelists.add(whitelist_key, true); + }; + }); + } + + public fun solve( + vault: &mut EscrowVault, + _: &ZkgmCap, + packet: ibc::packet::Packet, + base_token: vector, + quote_token: vector, + base_amount: u256, + quote_amount: u256, + receiver: vector, + path: u256, + relayer: address, + _relayer_msg: vector, + intent: bool, + ctx: &mut TxContext, + ): (vector, u64) { + if (type_name::get().into_string().into_bytes() != quote_token) { + return (vector::empty(), E_INVALID_QUOTE_TOKEN) + }; + + if (intent) { + let packet_hash = ibc::commitment::commit_packet(&packet); + if (!vault.intent_whitelists.contains(IntentWhitelistKey { + token: quote_token, + packet_hash + })) { + return (vector::empty(), E_INTENT_WHITELISTED_ONLY) + }; + }; + + let fungibility = FungibleLane { + token: quote_token, + path, + channel: packet.destination_channel_id(), + base_token, + }; + + if (!vault.fungible_counterparties.contains(fungibility)) { + return (vector::empty(), E_ONLY_MAKER) + }; + + let counterparty_beneficiary = vault.fungible_counterparties.borrow(fungibility).beneficiary; + + if (quote_amount > base_amount) { + return (vector::empty(), E_BASE_AMOUNT_MUST_COVER_QUOTE_AMOUNT) + }; + + let (base_amount, quote_amount) = (base_amount, quote_amount); + + let fee = base_amount - quote_amount; + if (fee > 0) { + vault.unescrow(fee as u64, relayer, ctx); + }; + + if (quote_amount > 0) { + let receiver = bcs::new(receiver).peel_address(); + vault.unescrow(fee as u64, receiver, ctx); + }; + + (counterparty_beneficiary, 0) + } + + fun unescrow( + vault: &mut EscrowVault, + amount: u64, + recipient: address, + ctx: &mut TxContext + ) { + let coin: &mut Coin = vault.coin_bag.borrow_mut(type_name::get()); + let coin = coin.split(amount, ctx); + transfer::public_transfer(coin, recipient); + } + + public fun escrow( + vault: &mut EscrowVault, + _: &ZkgmCap, + coin: Coin, + ) { + let key = type_name::get(); + if (vault.coin_bag.contains(key)) { + let self_coin: &mut Coin = vault.coin_bag.borrow_mut(key); + coin::join(self_coin, coin) + } else{ + vault.coin_bag.add(key, coin) + } + } + + #[test_only] + public fun init_for_tests(ctx: &mut TxContext) { + init(ctx); + } +} diff --git a/sui/ibc/Move.lock b/sui/ibc/Move.lock index e46fddaea4..136c99a184 100644 --- a/sui/ibc/Move.lock +++ b/sui/ibc/Move.lock @@ -2,7 +2,7 @@ [move] version = 3 -manifest_digest = "3E8A3117790F554B149DB37E9C96C2B3D833769E367372EC672B41846C878E5D" +manifest_digest = "E61644EDE4644CB2BBEBF2A871578979BAD6FCE235435C5807618BDB3B11F423" deps_digest = "F9B494B64F0615AED0E98FC12A85B85ECD2BC5185C22D30E7F67786BB52E507C" dependencies = [ { id = "Bridge", name = "Bridge" }, @@ -43,7 +43,7 @@ dependencies = [ ] [move.toolchain-version] -compiler-version = "1.58.1" +compiler-version = "1.55.0" edition = "2024.beta" flavor = "sui" diff --git a/sui/ibc/Move.toml b/sui/ibc/Move.toml index 9110228115..0e6606df9e 100644 --- a/sui/ibc/Move.toml +++ b/sui/ibc/Move.toml @@ -1,41 +1,9 @@ [package] -edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move -name = "ibc" -published-at = "0xf36048b090671467af3d6a6109403d179aaa0a699307ff9df218b893b8f6bd98" -# original = 0xf7afcb48d53dcd8f1b75bd73779a23fb80e0750e3db7a9fd7e59fe22bb7cd7d4 -# license = "" # e.g., "MIT", "GPL", "Apache 2.0" -# authors = ["..."] # e.g., ["Joe Smith (joesmith@noemail.com)", "John Snow (johnsnow@noemail.com)"] - -[dependencies] -# Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" } - -# For remote import, use the `{ git = "...", subdir = "...", rev = "..." }`. -# Revision can be a branch, a tag, and a commit hash. -# MyRemotePackage = { git = "https://some.remote/host.git", subdir = "remote/path", rev = "main" } - -# For local dependencies use `local = path`. Path is relative to the package root -# Local = { local = "../path/to" } - -# To resolve a version conflict and force a specific version for dependency -# override use `override = true` -# Override = { local = "../conflicting/version", override = true } +edition = "2024.beta" +name = "ibc" [addresses] ibc = "_" -# ibc = "_" - -# Named addresses will be accessible in Move as `@name`. They're also exported: -# for example, `std = "0x1"` is exported by the Standard Library. -# alice = "0xA11CE" - -[dev-dependencies] -# The dev-dependencies section allows overriding dependencies for `--test` and -# `--dev` modes. You can introduce test-only dependencies here. -# Local = { local = "../path/to/dev-build" } - [dev-addresses] -ibc = "0x22222" -# The dev-addresses section allows overwriting named addresses for the `--test` -# and `--dev` modes. -# alice = "0xB0B" +ibc = "0x1111" diff --git a/sui/ibc/sources/channel_end.move b/sui/ibc/sources/channel_end.move index 14cdbc38ca..4eec20bec4 100644 --- a/sui/ibc/sources/channel_end.move +++ b/sui/ibc/sources/channel_end.move @@ -59,9 +59,7 @@ // TITLE. module ibc::channel { - use std::option::{Self, Option}; use std::string::{Self, String}; - use std::vector; use ibc::ethabi; const E_PACKET_VERSION_LENGTH_EXCEEDS_MAX: u64 = 1; diff --git a/sui/ibc/sources/cometbls_light_client.move b/sui/ibc/sources/cometbls_light_client.move index 847a3f2641..0715aa9952 100644 --- a/sui/ibc/sources/cometbls_light_client.move +++ b/sui/ibc/sources/cometbls_light_client.move @@ -59,11 +59,9 @@ // TITLE. module ibc::cometbls_light_client { - use std::option::{Self, Option}; use std::string::{Self, String}; use sui::table::{Self, Table}; use sui::clock; - use sui::object::{Self, UID}; use sui::bcs::{Self, BCS}; use ibc::ethabi; use ibc::height::{Self, Height}; @@ -71,7 +69,7 @@ module ibc::cometbls_light_client { use ibc::ics23; use ibc::groth16_verifier::{Self, ZKP}; - const E_INVALID_CLIENT_STATE: u64 = 35100; + // const E_INVALID_CLIENT_STATE: u64 = 35100; const E_CONSENSUS_STATE_TIMESTAMP_ZERO: u64 = 35101; const E_SIGNED_HEADER_HEIGHT_NOT_MORE_RECENT: u64 = 35102; const E_SIGNED_HEADER_TIMESTAMP_NOT_MORE_RECENT: u64 = 35103; @@ -80,8 +78,7 @@ module ibc::cometbls_light_client { const E_VALIDATORS_HASH_MISMATCH: u64 = 35106; const E_INVALID_ZKP: u64 = 35107; const E_FROZEN_CLIENT: u64 = 35108; - const E_INVALID_MISBEHAVIOUR: u64 = 35109; - const E_UNIMPLEMENTED: u64 = 35199; + // const E_INVALID_MISBEHAVIOUR: u64 = 35109; const E_HEIGHT_NOT_FOUND_ON_CONSENSUS_STATE: u64 = 0x99999; @@ -139,7 +136,7 @@ module ibc::cometbls_light_client { public(package) fun create_client( - client_id: u32, + _client_id: u32, client_state_bytes: vector, consensus_state_bytes: vector, ctx: &mut TxContext, @@ -164,12 +161,12 @@ module ibc::cometbls_light_client { 0 } - public(package) fun check_for_misbehaviour(client: &Client, header: vector): bool { + public(package) fun check_for_misbehaviour(_client: &Client, _header: vector): bool { false } public(package) fun misbehaviour( - client: &Client, misbehaviour: vector, relayer: address + _client: &Client, _misbehaviour: vector, _relayer: address ) { } diff --git a/sui/ibc/sources/connection_end.move b/sui/ibc/sources/connection_end.move index 1f2e717150..0e29f807eb 100644 --- a/sui/ibc/sources/connection_end.move +++ b/sui/ibc/sources/connection_end.move @@ -59,8 +59,6 @@ // TITLE. module ibc::connection_end { - use ibc::ethabi; - use sui::bcs; use sui::address; diff --git a/sui/ibc/sources/create_lens_client_event.move b/sui/ibc/sources/create_lens_client_event.move index 7a38b59368..bc45d7a70a 100644 --- a/sui/ibc/sources/create_lens_client_event.move +++ b/sui/ibc/sources/create_lens_client_event.move @@ -59,7 +59,7 @@ // TITLE. module ibc::create_lens_client_event { - use std::string::{String, utf8}; + use std::string::{String}; public struct CreateLensClientEvent has copy, drop, store { client_id: u32, @@ -93,6 +93,9 @@ module ibc::create_lens_client_event { self.l2_client_id } + #[test_only] + use std::string::utf8; + #[test] fun test_create_and_getters_ok() { let ev = new(7, utf8(b"lens-sepolia"), 1001, 2002); diff --git a/sui/ibc/sources/eth_abi.move b/sui/ibc/sources/eth_abi.move index 8cf7fb95ca..6536aac7ed 100644 --- a/sui/ibc/sources/eth_abi.move +++ b/sui/ibc/sources/eth_abi.move @@ -60,41 +60,34 @@ module ibc::ethabi { use sui::bcs; - use std::vector; use std::string::{Self, String}; - const ZERO_32_BYTES: vector = vector[ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 - ]; - public fun encode_string(buf: &mut vector, str: &String) { - encode_bytes(buf, string::bytes(str)) + encode_bytes(buf, str.as_bytes()) } public fun encode_bytes(buf: &mut vector, bytes: &vector) { - let len = vector::length(bytes); + let len = bytes.length(); let mut len_bytes = bcs::to_bytes(&(len as u256)); - vector::reverse(&mut len_bytes); // Reverse the bytes to big-endian + len_bytes.reverse(); // Reverse the bytes to big-endian - vector::append(buf, len_bytes); - vector::append(buf, *bytes); + buf.append(len_bytes); + buf.append(*bytes); // Calculate padding to align to 32 bytes let padding_len = (32 - (len % 32)) % 32; let mut padding = vector::empty(); let mut i = 0; while (i < padding_len) { - vector::push_back(&mut padding, 0); + padding.push_back(0); i = i + 1; }; - // Append the padding - vector::append(buf, padding); + buf.append(padding); } public fun encode_address(buf: &mut vector, addr: address) { let sender_bytes = bcs::to_bytes(&addr); - vector::append(buf, sender_bytes); + buf.append(sender_bytes); } diff --git a/sui/ibc/sources/groth16_verifier.move b/sui/ibc/sources/groth16_verifier.move index 3157eaa9a6..a700439a05 100644 --- a/sui/ibc/sources/groth16_verifier.move +++ b/sui/ibc/sources/groth16_verifier.move @@ -1,5 +1,67 @@ + +// License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved. +// "Business Source License" is a trademark of MariaDB Corporation Ab. + +// Parameters + +// Licensor: Union.fi, Labs Inc. +// Licensed Work: All files under https://github.com/unionlabs/union's sui subdirectory +// The Licensed Work is (c) 2024 Union.fi, Labs Inc. +// Change Date: Four years from the date the Licensed Work is published. +// Change License: Apache-2.0 +// + +// For information about alternative licensing arrangements for the Licensed Work, +// please contact info@union.build. + +// Notice + +// Business Source License 1.1 + +// Terms + +// The Licensor hereby grants you the right to copy, modify, create derivative +// works, redistribute, and make non-production use of the Licensed Work. The +// Licensor may make an Additional Use Grant, above, permitting limited production use. + +// Effective on the Change Date, or the fourth anniversary of the first publicly +// available distribution of a specific version of the Licensed Work under this +// License, whichever comes first, the Licensor hereby grants you rights under +// the terms of the Change License, and the rights granted in the paragraph +// above terminate. + +// If your use of the Licensed Work does not comply with the requirements +// currently in effect as described in this License, you must purchase a +// commercial license from the Licensor, its affiliated entities, or authorized +// resellers, or you must refrain from using the Licensed Work. + +// All copies of the original and modified Licensed Work, and derivative works +// of the Licensed Work, are subject to this License. This License applies +// separately for each version of the Licensed Work and the Change Date may vary +// for each version of the Licensed Work released by Licensor. + +// You must conspicuously display this License on each original or modified copy +// of the Licensed Work. If you receive the Licensed Work in original or +// modified form from a third party, the terms and conditions set forth in this +// License apply to your use of that work. + +// Any use of the Licensed Work in violation of this License will automatically +// terminate your rights under this License for the current and all other +// versions of the Licensed Work. + +// This License does not grant you any right in any trademark or logo of +// Licensor or its affiliates (provided that you may use a trademark or logo of +// Licensor as expressly required by this License). + +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +#[allow(implicit_const_copy)] module ibc::groth16_verifier { - use sui::bls12381::{Self, G1, G2, GT, scalar_one, g1_from_bytes, scalar_from_bytes, g1_mul, g1_multi_scalar_multiplication, g1_add, g2_from_bytes, pairing, gt_add, g1_to_uncompressed_g1}; + use sui::bls12381::{Self, G1, G2, g1_from_bytes, scalar_from_bytes, g1_mul, g1_add, g2_from_bytes, pairing, gt_add, g1_to_uncompressed_g1}; use sui::group_ops::{Self, Element}; use sui::hash::keccak256; use sui::bcs; @@ -55,12 +117,12 @@ module ibc::groth16_verifier { inputs_hash.push_back(0); i = i + 1; }; - inputs_hash.append(*chain_id.bytes()); + inputs_hash.append(*chain_id.as_bytes()); inputs_hash.append(light_header_hash); inputs_hash.append(*trusted_validators_hash); let mut inputs_hash = sha2_256(inputs_hash); - let mut first_elem = inputs_hash.borrow_mut(0); + let first_elem = inputs_hash.borrow_mut(0); *first_elem = 0; let inputs_hash = scalar_from_bytes(&inputs_hash); @@ -182,7 +244,7 @@ module ibc::groth16_verifier { keccak256(&outer) } - fun hash_commitment_bytes(mut buffer: vector, prime: vector): u256 { + fun hash_commitment_bytes(buffer: vector, prime: vector): u256 { let mut hmac = hmac_keccak(&buffer); hmac.reverse(); diff --git a/sui/ibc/sources/height.move b/sui/ibc/sources/height.move index ea5e2a2314..8720aa95af 100644 --- a/sui/ibc/sources/height.move +++ b/sui/ibc/sources/height.move @@ -60,8 +60,6 @@ module ibc::height { use sui::bcs::BCS; - use std::vector; - use sui::bcs; public struct Height has drop, copy, store { revision_number: u64, @@ -114,14 +112,14 @@ module ibc::height { } public fun decode_bcs(buf: &mut BCS): Height { - // let length = bcs_utils::peel_length_prefix(buf); - // assert!(length == 2, 1); // TODO: Better error code here Height { revision_number: buf.peel_u64(), revision_height: buf.peel_u64() } } + #[test_only] + use sui::bcs; #[test] fun test_new_and_getters_ok() { diff --git a/sui/ibc/sources/ibc.move b/sui/ibc/sources/ibc.move index c6b6bf453f..79888dffaf 100644 --- a/sui/ibc/sources/ibc.move +++ b/sui/ibc/sources/ibc.move @@ -58,88 +58,42 @@ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. - +#[allow(implicit_const_copy)] module ibc::ibc { use std::string::{String, utf8}; use sui::table::{Self, Table}; - use sui::object::{Self, UID}; use sui::hash::keccak256; use sui::clock; - use sui::transfer; - use std::string; use sui::clock::Clock; - #[test_only] - use sui::test_scenario; - use ibc::packet::{Self, Packet}; use ibc::connection_end::{Self, ConnectionEnd}; use ibc::channel::{Self, Channel}; use ibc::light_client::{Self, LightClientManager}; use ibc::commitment; - use ibc::create_lens_client_event; - use std::debug; - use sui::bcs; use sui::event; - const IBC_APP_SEED: vector = b"union-ibc-app-v1"; const COMMITMENT_MAGIC: vector = x"0100000000000000000000000000000000000000000000000000000000000000"; const COMMITMENT_MAGIC_ACK: vector = x"0200000000000000000000000000000000000000000000000000000000000000"; - const CLIENT_TYPE_COMETBLS: vector = b"cometbls"; - - const CHAN_STATE_UNINITIALIZED: u8 = 0; const CHAN_STATE_INIT: u8 = 1; const CHAN_STATE_TRYOPEN: u8 = 2; const CHAN_STATE_OPEN: u8 = 3; - const CHAN_STATE_CLOSED: u8 = 4; - const CHAN_ORDERING_NONE: u8 = 0; - const CHAN_ORDERING_UNORDERED: u8 = 1; - const CHAN_ORDERING_ORDERED: u8 = 2; - - const CONN_STATE_UNSPECIFIED: u8 = 0; const CONN_STATE_INIT: u8 = 1; const CONN_STATE_TRYOPEN: u8 = 2; const CONN_STATE_OPEN: u8 = 3; - const VAULT_SEED: vector = b"IBC_VAULT_SEED"; - - const E_NOT_ENOUGH_PERMISSIONS_TO_INITIALIZE: u64 = 1001; const E_CLIENT_NOT_FOUND: u64 = 1002; - const E_VERSION_MUST_BE_UNSET: u64 = 1006; - const E_UNSUPPORTED_VERSION: u64 = 1007; const E_INVALID_CONNECTION_STATE: u64 = 1008; - const E_CONNECTION_ALREADY_EXISTS: u64 = 1009; - const E_CONN_NOT_SINGLE_HOP: u64 = 1011; - const E_CONN_NOT_SINGLE_VERSION: u64 = 1012; - const E_UNSUPPORTED_FEATURE: u64 = 1013; - const E_PORT_ID_MUST_BE_LOWERCASE: u64 = 1015; const E_INVALID_CHANNEL_STATE: u64 = 1016; - const E_COUNTERPARTY_CHANNEL_NOT_EMPTY: u64 = 1017; - const E_INVALID_TIMEOUT_HEIGHT: u64 = 1018; const E_LATEST_TIMESTAMP_NOT_FOUND: u64 = 1019; const E_UNAUTHORIZED: u64 = 1020; - const E_INVALID_TIMEOUT_TIMESTAMP: u64 = 1021; - const E_LATEST_HEIGHT_NOT_FOUND: u64 = 1022; - const E_SOURCE_AND_COUNTERPARTY_PORT_MISMATCH: u64 = 1023; - const E_SOURCE_AND_COUNTERPARTY_CHANNEL_MISMATCH: u64 = 1022; const E_TIMESTAMP_TIMEOUT: u64 = 1023; - const E_HEIGHT_TIMEOUT: u64 = 1024; const E_PACKET_ALREADY_RECEIVED: u64 = 1025; - const E_PACKET_SEQUENCE_NEXT_SEQUENCE_MISMATCH: u64 = 1026; - const E_UNKNOWN_CHANNEL_ORDERING: u64 = 1027; - const E_CONNECTION_DOES_NOT_EXIST: u64 = 1028; const E_ACKNOWLEDGEMENT_IS_EMPTY: u64 = 1028; - const E_ACKNOWLEDGEMENT_ALREADY_EXISTS: u64 = 1029; - const E_DESTINATION_AND_COUNTERPARTY_PORT_MISMATCH: u64 = 1030; - const E_DESTINATION_AND_COUNTERPARTY_CHANNEL_MISMATCH: u64 = 1031; const E_PACKET_COMMITMENT_NOT_FOUND: u64 = 1032; - const E_INVALID_PACKET_COMMITMENT: u64 = 1033; const E_TIMESTAMP_TIMEOUT_NOT_REACHED: u64 = 1034; - const E_TIMEOUT_HEIGHT_NOT_REACHED: u64 = 1035; - const E_INVALID_UPDATE: u64 = 1036; - const E_NEXT_SEQUENCE_MUST_BE_GREATER_THAN_TIMEOUT_SEQUENCE: u64 = 1037; const E_CLIENT_NOT_ACTIVE: u64 = 1038; const E_NOT_ENOUGH_PACKETS: u64 = 1040; const E_PACKET_NOT_RECEIVED: u64 = 1041; @@ -314,7 +268,7 @@ module ibc::ibc { } #[test_only] - fun init_for_tests(ctx: &mut TxContext) { + public fun init_for_tests(ctx: &mut TxContext) { transfer::share_object(IBCStore { id: object::new(ctx), commitments: table::new(ctx), @@ -746,7 +700,7 @@ module ibc::ibc { CHAN_STATE_INIT, connection.counterparty_connection_id(), 0, - *port_id.bytes(), + *port_id.as_bytes(), counterparty_version ); @@ -807,7 +761,6 @@ module ibc::ibc { /// The name MUST be `IbcAppWitness`. public fun channel_open_ack( ibc_store: &mut IBCStore, - port_id: String, channel_id: u32, counterparty_version: String, counterparty_channel_id: u32, @@ -845,7 +798,7 @@ module ibc::ibc { CHAN_STATE_TRYOPEN, connection.counterparty_connection_id(), channel_id, - *port_id.bytes(), + *port_id.as_bytes(), counterparty_version ); @@ -923,7 +876,7 @@ module ibc::ibc { CHAN_STATE_OPEN, connection.counterparty_connection_id(), channel_id, - *port_id.bytes(), + *port_id.as_bytes(), *channel.version() ); @@ -1182,7 +1135,7 @@ module ibc::ibc { assert!(parts.length() >= 3, 1); - let mut a = sui::address::from_ascii_bytes(parts[0].bytes()).to_ascii_string(); + let mut a = sui::address::from_ascii_bytes(parts[0].as_bytes()).to_ascii_string(); a.append(std::ascii::string(b"::")); a.append(parts[1].to_ascii()); @@ -1193,8 +1146,6 @@ module ibc::ibc { port_id: String, _: T, ) { - let caller_t = std::type_name::get(); - let mut addr_module = deconstruct_port_id(port_id); addr_module.append(std::ascii::string(b"::IbcAppWitness")); @@ -1405,8 +1356,6 @@ module ibc::ibc { let channel = ibc_store.channels.borrow(source_channel); assert!(channel.state() == CHAN_STATE_OPEN, E_INVALID_CHANNEL_STATE); - let destination_channel = packets[0].destination_channel_id(); - let connection = ibc_store.connections.borrow(channel.connection_id()); assert!(connection.state() == CONN_STATE_OPEN, E_INVALID_CONNECTION_STATE); @@ -1591,8 +1540,6 @@ module ibc::ibc { let port_id = *ibc_store.channel_to_port.borrow(source_channel); validate_port(port_id, witness); - let destination_channel = packet.destination_channel_id(); - if(!ibc_store.channels.contains(source_channel)) { abort E_CHANNEL_NOT_FOUND }; @@ -1647,6 +1594,13 @@ module ibc::ibc { #[test_only] const TEST_LATEST_HEIGHT: u64 = 10_000; + #[test_only] + use sui::test_scenario; + + #[test_only] + use std::string; + + #[test_only] fun open_channel_for_tests(t: &mut test_scenario::Scenario) { t.next_tx(@0x0); @@ -1662,13 +1616,12 @@ module ibc::ibc { t.next_tx(@0x0); let port = string::utf8( - b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" + b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" ); ibc_store.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); ibc_store.channel_open_ack( - string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, @@ -1754,7 +1707,7 @@ module ibc::ibc { assert!(connection.counterparty_client_id() == counterparty_client_id, E_CONNECTION_NOT_FOUND); let key = commitment::connection_commitment_key(connection_id); - assert!(ibc_store.commitments.contains(key), E_CONNECTION_DOES_NOT_EXIST); + assert!(ibc_store.commitments.contains(key), 1); assert!(ibc_store.next_connection_sequence == 2, 1); @@ -1792,8 +1745,8 @@ module ibc::ibc { let k1 = commitment::connection_commitment_key(1); let k2 = commitment::connection_commitment_key(2); - assert!(ibc_store.commitments.contains(k1), E_CONNECTION_DOES_NOT_EXIST); - assert!(ibc_store.commitments.contains(k2), E_CONNECTION_DOES_NOT_EXIST); + assert!(ibc_store.commitments.contains(k1), 1); + assert!(ibc_store.commitments.contains(k2), 1); assert!(ibc_store.next_connection_sequence == 3, 1); @@ -1825,7 +1778,7 @@ module ibc::ibc { assert!(c.counterparty_connection_id() == 11, 1); let key = commitment::connection_commitment_key(connection_id); - assert!(ibc_store.commitments.contains(key), E_CONNECTION_DOES_NOT_EXIST); + assert!(ibc_store.commitments.contains(key), 1); assert!(ibc_store.next_connection_sequence == 2, 1); test_scenario::return_shared(ibc_store); @@ -1857,7 +1810,7 @@ module ibc::ibc { assert!(c.counterparty_connection_id() == 9, 1); let key = commitment::connection_commitment_key(1); - assert!(ibc_store.commitments.contains(key), E_CONNECTION_DOES_NOT_EXIST); + assert!(ibc_store.commitments.contains(key), 1); test_scenario::return_shared(ibc_store); test_case.end(); @@ -1887,7 +1840,7 @@ module ibc::ibc { assert!(c.state() == CONN_STATE_OPEN, E_INVALID_CONNECTION_STATE); let key = commitment::connection_commitment_key(1); - assert!(ibc_store.commitments.contains(key), E_CONNECTION_DOES_NOT_EXIST); + assert!(ibc_store.commitments.contains(key), 1); test_scenario::return_shared(ibc_store); test_case.end(); @@ -1910,7 +1863,7 @@ module ibc::ibc { ibc_store.connection_open_ack(1, 9, b"p", 1); test_case.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc_store.channel_open_init( port, b"cp-port", @@ -1922,7 +1875,7 @@ module ibc::ibc { let ch_id = 1; let ch = ibc_store.channels.borrow(ch_id); assert!(channel::state(ch) == CHAN_STATE_INIT, E_INVALID_CHANNEL_STATE); - assert!(*ibc_store.channel_to_port.borrow(ch_id) == string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"), 1); + assert!(*ibc_store.channel_to_port.borrow(ch_id) == string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"), 1); let key = commitment::channel_commitment_key(ch_id); assert!(ibc_store.commitments.contains(key), 1); @@ -1946,7 +1899,7 @@ module ibc::ibc { ibc_store.connection_open_confirm(1, b"p", 1); test_case.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc_store.channel_open_try( port, 1, @@ -1987,7 +1940,7 @@ module ibc::ibc { ibc_store.connection_open_ack(1, 9, b"p", 1); test_case.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc_store.channel_open_init( port, b"cp-port", @@ -1998,7 +1951,6 @@ module ibc::ibc { test_case.next_tx(@0x0); ibc_store.channel_open_ack( - string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 22, @@ -2033,7 +1985,7 @@ module ibc::ibc { ibc_store.connection_open_confirm(1, b"p", 1); test_case.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc_store.channel_open_try( port, 1, @@ -2221,7 +2173,7 @@ module ibc::ibc { t.next_tx(@0x0); let port = string::utf8( - b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" + b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" ); ibc_store.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); @@ -2244,7 +2196,7 @@ module ibc::ibc { t.next_tx(@0x0); let port = string::utf8( - b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" + b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" ); ibc_store.channel_open_try( port, @@ -2280,7 +2232,7 @@ module ibc::ibc { t.next_tx(@0x0); let port = string::utf8( - b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" + b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" ); ibc_store.channel_open_try( port, @@ -2296,7 +2248,6 @@ module ibc::ibc { t.next_tx(@0x0); ibc_store.channel_open_ack( - string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 22, @@ -2327,7 +2278,7 @@ module ibc::ibc { t.next_tx(@0x0); let port = string::utf8( - b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" + b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" ); ibc_store.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); @@ -2361,11 +2312,11 @@ module ibc::ibc { ibc_store.connection_open_ack(1, 9, b"p", 1); t.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc_store.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); - ibc_store.channel_open_ack(string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); + ibc_store.channel_open_ack(1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); t.next_tx(@0x0); let clk = t.take_shared(); @@ -2400,11 +2351,11 @@ module ibc::ibc { ibc_store.connection_open_ack(1, 9, b"p", 1); t.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc_store.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); - ibc_store.channel_open_ack(string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); + ibc_store.channel_open_ack(1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); t.next_tx(@0x0); let clk = t.take_shared(); @@ -2439,11 +2390,11 @@ module ibc::ibc { ibc_store.connection_open_ack(1, 9, b"p", 1); t.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc_store.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); - ibc_store.channel_open_ack(string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); + ibc_store.channel_open_ack(1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); t.next_tx(@0x0); let clk = t.take_shared(); @@ -2478,11 +2429,11 @@ module ibc::ibc { ibc_store.connection_open_ack(1, 9, b"p", 1); t.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc_store.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); - ibc_store.channel_open_ack(string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); + ibc_store.channel_open_ack(1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); t.next_tx(@0x0); let clk = t.take_shared(); @@ -2518,11 +2469,11 @@ module ibc::ibc { ibc_store.connection_open_ack(1, 9, b"p", 1); t.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc_store.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); - ibc_store.channel_open_ack(string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); + ibc_store.channel_open_ack(1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); t.next_tx(@0x0); let clk = t.take_shared(); @@ -2557,11 +2508,11 @@ module ibc::ibc { ibc_store.connection_open_ack(1, 9, b"p", 1); t.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc_store.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); - ibc_store.channel_open_ack(string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); + ibc_store.channel_open_ack(1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); t.next_tx(@0x0); let clk = t.take_shared(); @@ -2596,11 +2547,11 @@ module ibc::ibc { ibc_store.connection_open_ack(1, 9, b"p", 1); t.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc_store.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); - ibc_store.channel_open_ack(string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); + ibc_store.channel_open_ack(1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); t.next_tx(@0x0); let pkt = packet::new(1, 1, b"x", 0, 999999999999); @@ -2666,12 +2617,11 @@ module ibc::ibc { t.next_tx(@0x0); let port = string::utf8( - b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" + b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" ); ibc.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); ibc.channel_open_ack( - string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, @@ -2717,12 +2667,11 @@ module ibc::ibc { t.next_tx(@0x0); let port = string::utf8( - b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" + b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea" ); ibc.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); ibc.channel_open_ack( - string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, @@ -2897,10 +2846,10 @@ module ibc::ibc { t.next_tx(@0x0); ibc.connection_open_ack(1, 9, b"p", 1); t.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); - ibc.channel_open_ack(string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); + ibc.channel_open_ack(1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); t.next_tx(@0x0); let pkt = packet::new(1, 1, b"z", 0, 1); @@ -2936,10 +2885,10 @@ module ibc::ibc { t.next_tx(@0x0); ibc.connection_open_ack(1, 9, b"p", 1); t.next_tx(@0x0); - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); ibc.channel_open_init(port, b"cp-port", 1, string::utf8(b"v1"), IbcAppWitness {}); t.next_tx(@0x0); - ibc.channel_open_ack(string::utf8(b"ignored"), 1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); + ibc.channel_open_ack(1, string::utf8(b"v1-cp"), 1, b"p", 1, IbcAppWitness {}); t.next_tx(@0x0); let clk = t.take_shared(); let now_ns = clock::timestamp_ms(&clk) * 1_000_000; @@ -2956,7 +2905,7 @@ module ibc::ibc { public struct IbcAppWitness has drop {} #[test] fun validate_port_bro() { - let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000022222::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); + let port = string::utf8(b"0x0000000000000000000000000000000000000000000000000000000000001111::ibc::0xbe0f436bb8f8b30e0cad1c1bf27ede5bb158d47375c3a4ce108f435bd1cc9bea"); validate_port( port, diff --git a/sui/ibc/sources/ibc_commitment.move b/sui/ibc/sources/ibc_commitment.move index c59a87694d..b139d65df0 100644 --- a/sui/ibc/sources/ibc_commitment.move +++ b/sui/ibc/sources/ibc_commitment.move @@ -59,7 +59,6 @@ // TITLE. #[allow(implicit_const_copy, unused_const)] module ibc::commitment { - use sui::hash; use sui::address; use std::bcs; use ibc::packet::{Self, Packet, PacketBcs}; @@ -267,7 +266,7 @@ module ibc::commitment { let final_offset = offsets.pop_back(); let final_offset_bytes = bcs::to_bytes(&final_offset); - let mut comm_bcs = PacketCommitmentBcs { + let comm_bcs = PacketCommitmentBcs { offset_0x20: address::from_u256(0x20), // 30 bytes len: x"000000000000000000000000000000000000000000000000000000000000", diff --git a/sui/ibc/sources/ics23.move b/sui/ibc/sources/ics23.move index b4b2bb83ad..a26f8c315f 100644 --- a/sui/ibc/sources/ics23.move +++ b/sui/ibc/sources/ics23.move @@ -59,14 +59,12 @@ // TITLE. module ibc::ics23 { - use std::vector; - use std::option::Option; use std::hash; use sui::bcs::{Self, BCS}; const E_EMPTY_LEAF_PREFIX: u64 = 35200; - const E_EMPTY_LEAF_KEY: u64 = 35201; + // const E_EMPTY_LEAF_KEY: u64 = 35201; const E_EMPTY_INNER_KEY: u64 = 35202; const E_EMPTY_CHILD: u64 = 35203; const E_PROOF_KEY_MISMATCH: u64 = 35204; @@ -93,11 +91,11 @@ module ibc::ics23 { suffix: vector } - public struct NonExistenceProof has drop { - key: vector, - left: Option, - right: Option - } + // public struct NonExistenceProof has drop { + // key: vector, + // left: Option, + // right: Option + // } public struct ProofSpec has drop { child_size: u64, diff --git a/sui/ibc/sources/light_client.move b/sui/ibc/sources/light_client.move index 2ea449240d..2833c2a657 100644 --- a/sui/ibc/sources/light_client.move +++ b/sui/ibc/sources/light_client.move @@ -59,14 +59,12 @@ // TITLE. module ibc::light_client { - use std::option::Option; use std::string::{Self, String}; use sui::table::{Self, Table}; use sui::clock::Clock; use sui::object_bag::{Self, ObjectBag}; - use ibc::height::Height; use ibc::create_lens_client_event::CreateLensClientEvent; use ibc::cometbls_light_client; @@ -107,7 +105,7 @@ module ibc::light_client { return (client_state_bytes, consensus_state_bytes, string::utf8(b"test-chain-id"), option::none()) }; - let (csb, consb, c_cid, l_event) = if (client_type.bytes() == b"cometbls") { + let (csb, consb, c_cid, l_event) = if (client_type.as_bytes() == b"cometbls") { let (client, csb, consb, c_cid, l_event) = cometbls_light_client::create_client(client_id, client_state_bytes, consensus_state_bytes, ctx); store.clients.add(client_id, client); (csb, consb, c_cid, l_event) @@ -124,11 +122,11 @@ module ibc::light_client { client_id: u32 ): u64 { if (store.test_mode) { - return 0; + return 0 }; let client_type = store.client_id_to_type.borrow(client_id); - if (client_type.bytes() == b"cometbls") { + if (client_type.as_bytes() == b"cometbls") { store.clients.borrow(client_id).status() } else { abort E_CLIENT_TYPE_NOT_SUPPORTED @@ -146,7 +144,7 @@ module ibc::light_client { }; let client_type = store.client_id_to_type.borrow(client_id); - if (client_type.bytes() == b"cometbls") { + if (client_type.as_bytes() == b"cometbls") { store.clients.borrow_mut(client_id).misbehaviour(misbehaviour, relayer); } else { abort E_CLIENT_TYPE_NOT_SUPPORTED @@ -159,7 +157,7 @@ module ibc::light_client { }; let client_type = store.client_id_to_type.borrow(client_id); - if (client_type.bytes() == b"cometbls") { + if (client_type.as_bytes() == b"cometbls") { store.clients.borrow(client_id).get_timestamp_at_height(height) } else { abort E_CLIENT_TYPE_NOT_SUPPORTED @@ -178,7 +176,7 @@ module ibc::light_client { }; let client_type = store.client_id_to_type.borrow(client_id); - if (client_type.bytes() == b"cometbls") { + if (client_type.as_bytes() == b"cometbls") { store.clients.borrow(client_id).verify_non_membership(height, proof, path) } else { abort E_CLIENT_TYPE_NOT_SUPPORTED @@ -197,7 +195,7 @@ module ibc::light_client { }; let client_type = store.client_id_to_type.borrow(client_id); - if (client_type.bytes() == b"cometbls") { + if (client_type.as_bytes() == b"cometbls") { store.clients.borrow_mut(client_id).update_client(clock, client_msg, relayer) } else { abort E_CLIENT_TYPE_NOT_SUPPORTED @@ -213,7 +211,7 @@ module ibc::light_client { }; let client_type = store.client_id_to_type.borrow(client_id); - if (client_type.bytes() == b"cometbls") { + if (client_type.as_bytes() == b"cometbls") { store.clients.borrow(client_id).latest_height() } else { abort E_CLIENT_TYPE_NOT_SUPPORTED @@ -233,7 +231,7 @@ module ibc::light_client { }; let client_type = store.client_id_to_type.borrow(client_id); - if (client_type.bytes() == b"cometbls") { + if (client_type.as_bytes() == b"cometbls") { store.clients.borrow(client_id).verify_membership(height, proof, key, value) } else { abort E_CLIENT_TYPE_NOT_SUPPORTED @@ -245,7 +243,7 @@ module ibc::light_client { client_id: u32 ): vector { let client_type = store.client_id_to_type.borrow(client_id); - if (client_type.bytes() == b"cometbls") { + if (client_type.as_bytes() == b"cometbls") { store.clients.borrow(client_id).get_client_state() } else { abort E_CLIENT_TYPE_NOT_SUPPORTED @@ -258,7 +256,7 @@ module ibc::light_client { height: u64, ): vector { let client_type = store.client_id_to_type.borrow(client_id); - if (client_type.bytes() == b"cometbls") { + if (client_type.as_bytes() == b"cometbls") { store.clients.borrow(client_id).get_consensus_state(height) } else { abort E_CLIENT_TYPE_NOT_SUPPORTED diff --git a/sui/ibc/sources/packet.move b/sui/ibc/sources/packet.move index 23e21e2f6a..0e070767e5 100644 --- a/sui/ibc/sources/packet.move +++ b/sui/ibc/sources/packet.move @@ -59,7 +59,6 @@ // TITLE. module ibc::packet { - use ibc::ethabi; use sui::address; use sui::bcs; @@ -271,18 +270,6 @@ module ibc::packet { encoded } - // public fun encode(packet: &Packet): vector { - // let mut buf = vector::empty(); - - // ethabi::encode_uint(&mut buf, packet.source_channel_id); - // ethabi::encode_uint(&mut buf, packet.destination_channel_id); - // ethabi::encode_uint(&mut buf, 5 * 0x20); - // ethabi::encode_uint(&mut buf, packet.timeout_height); - // ethabi::encode_uint(&mut buf, packet.timeout_timestamp); - // ethabi::encode_bytes(&mut buf, &packet.data); - // buf - // } - // #[test] fun test_encode_packet() { let output = x"0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000007968656c6c6f20776f726c6468656c6c6f20776f726c6468656c6c6f20776f726c6468656c6c6f20776f726c6468656c6c6f20776f726c6468656c6c6f20776f726c6468656c6c6f20776f726c6468656c6c6f20776f726c6468656c6c6f20776f726c6468656c6c6f20776f726c6468656c6c6f20776f726c6400000000000000"; diff --git a/sui/muno/.gitignore b/sui/muno/.gitignore deleted file mode 100644 index 60b32c83a2..0000000000 --- a/sui/muno/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/* -.trace -.coverage* diff --git a/sui/vault/Move.lock b/sui/owned_vault/Move.lock similarity index 82% rename from sui/vault/Move.lock rename to sui/owned_vault/Move.lock index 8f850babe2..d337397730 100644 --- a/sui/vault/Move.lock +++ b/sui/owned_vault/Move.lock @@ -2,7 +2,7 @@ [move] version = 3 -manifest_digest = "10978C130166F19D21AACFCF669E7D5674C503A02E42779AF23CC55CBA8F29BA" +manifest_digest = "71987C0DA3AE94A0C9A74F2DE4D1457A1B1B8B3AFB71486891ACB4A26118C18A" deps_digest = "397E6A9F7A624706DBDFEE056CE88391A15876868FD18A88504DA74EB458D697" dependencies = [ { id = "Bridge", name = "Bridge" }, @@ -14,7 +14,7 @@ dependencies = [ [[move.package]] id = "Bridge" -source = { git = "https://github.com/MystenLabs/sui.git", rev = "b448b1d971bd6c1aac8ef4eee4305943806d5d5b", subdir = "crates/sui-framework/packages/bridge" } +source = { git = "https://github.com/MystenLabs/sui.git", rev = "db951a5ea6b125f6253a6b7f436ddba46eb0feb3", subdir = "crates/sui-framework/packages/bridge" } dependencies = [ { id = "MoveStdlib", name = "MoveStdlib" }, @@ -24,11 +24,11 @@ dependencies = [ [[move.package]] id = "MoveStdlib" -source = { git = "https://github.com/MystenLabs/sui.git", rev = "b448b1d971bd6c1aac8ef4eee4305943806d5d5b", subdir = "crates/sui-framework/packages/move-stdlib" } +source = { git = "https://github.com/MystenLabs/sui.git", rev = "db951a5ea6b125f6253a6b7f436ddba46eb0feb3", subdir = "crates/sui-framework/packages/move-stdlib" } [[move.package]] id = "Sui" -source = { git = "https://github.com/MystenLabs/sui.git", rev = "b448b1d971bd6c1aac8ef4eee4305943806d5d5b", subdir = "crates/sui-framework/packages/sui-framework" } +source = { git = "https://github.com/MystenLabs/sui.git", rev = "db951a5ea6b125f6253a6b7f436ddba46eb0feb3", subdir = "crates/sui-framework/packages/sui-framework" } dependencies = [ { id = "MoveStdlib", name = "MoveStdlib" }, @@ -36,7 +36,7 @@ dependencies = [ [[move.package]] id = "SuiSystem" -source = { git = "https://github.com/MystenLabs/sui.git", rev = "b448b1d971bd6c1aac8ef4eee4305943806d5d5b", subdir = "crates/sui-framework/packages/sui-system" } +source = { git = "https://github.com/MystenLabs/sui.git", rev = "db951a5ea6b125f6253a6b7f436ddba46eb0feb3", subdir = "crates/sui-framework/packages/sui-system" } dependencies = [ { id = "MoveStdlib", name = "MoveStdlib" }, @@ -55,7 +55,7 @@ dependencies = [ ] [move.toolchain-version] -compiler-version = "1.56.3" +compiler-version = "1.55.0" edition = "2024.beta" flavor = "sui" diff --git a/sui/owned_vault/Move.toml b/sui/owned_vault/Move.toml new file mode 100644 index 0000000000..7407954c04 --- /dev/null +++ b/sui/owned_vault/Move.toml @@ -0,0 +1,14 @@ +[package] +edition = "2024.beta" +name = "owned_vault" + +[dependencies] +ibc = { local = "../ibc" } + +[addresses] +ibc = "_" +owned_vault = "_" + +[dev-addresses] +ibc = "0x1111" +owned_vault = "0x3333" diff --git a/sui/vault/sources/metadata.move b/sui/owned_vault/sources/metadata.move similarity index 99% rename from sui/vault/sources/metadata.move rename to sui/owned_vault/sources/metadata.move index f9795835ff..e427a06ac5 100644 --- a/sui/vault/sources/metadata.move +++ b/sui/owned_vault/sources/metadata.move @@ -58,7 +58,7 @@ // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. -module vault::metadata { +module owned_vault::metadata { use std::string::String; public struct Metadata has copy, drop, store { diff --git a/sui/vault/sources/vault.move b/sui/owned_vault/sources/vault.move similarity index 71% rename from sui/vault/sources/vault.move rename to sui/owned_vault/sources/vault.move index c009b25a5d..0001096de3 100644 --- a/sui/vault/sources/vault.move +++ b/sui/owned_vault/sources/vault.move @@ -58,16 +58,16 @@ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. -module vault::vault { +module owned_vault::owned_vault { use sui::bcs; use sui::table::{Self, Table}; use sui::object_bag::{Self, ObjectBag}; use sui::coin::{Self, Coin, TreasuryCap, CoinMetadata}; use sui::balance; - use std::string::{Self, String}; + use std::string; use std::type_name; - use vault::metadata::{Self, Metadata}; + use owned_vault::metadata::{Self, Metadata}; const E_UNAUTHORIZED: u64 = 1; const E_INVALID_PACKET_HASH: u64 = 2; @@ -77,14 +77,14 @@ module vault::vault { const E_INVALID_QUOTE_TOKEN: u64 = 6; const E_ONLY_MAKER: u64 = 0xdeadc0de; - public struct Vault has key { + public struct OwnedVault has key { id: UID, token_type_to_treasury: ObjectBag, intent_whitelists: Table, fungible_counterparties: Table, } - public struct VaultCap has key, store { + public struct ZkgmCap has key, store { id: UID } @@ -109,24 +109,28 @@ module vault::vault { cap: TreasuryCap, metadata: Metadata, } + + public struct TreasuryCapReleaseCtx { + metadata: Metadata, + } fun init(ctx: &mut TxContext) { transfer::transfer( - VaultCap { + ZkgmCap { id: object::new(ctx) }, ctx.sender() ); - transfer::share_object(Vault { + transfer::share_object(OwnedVault { id: object::new(ctx), token_type_to_treasury: object_bag::new(ctx), intent_whitelists: table::new(ctx), fungible_counterparties: table::new(ctx), }); } - + public fun register_capability( - vault: &mut Vault, + vault: &mut OwnedVault, mut capability: TreasuryCap, metadata: &CoinMetadata, owner: address, @@ -141,8 +145,7 @@ module vault::vault { abort 0 }; - let typename_t = type_name::get(); - vault.token_type_to_treasury.add(string::from_ascii(typename_t.into_string()), TreasuryCapWithMetadata { + vault.token_type_to_treasury.add(type_name::get().into_string().into_bytes(), TreasuryCapWithMetadata { id: object::new(ctx), cap: capability, metadata: metadata::new( @@ -157,21 +160,21 @@ module vault::vault { } public fun set_fungible_counterparty( - vault: &mut Vault, + vault: &mut OwnedVault, path: u256, channel: u32, base_token: vector, beneficiary: vector, ctx: &mut TxContext, ) { - let token = string::from_ascii(type_name::get().into_string()); + let token = type_name::get().into_string().into_bytes(); let cap: &TreasuryCapWithMetadata = vault.token_type_to_treasury.borrow(token); assert!(cap.metadata.owner() == ctx.sender(), E_UNAUTHORIZED); vault.fungible_counterparties.add( FungibleLane { - token: token.into_bytes(), + token, path, channel, base_token @@ -183,7 +186,7 @@ module vault::vault { } public fun whitelist_intent( - vault: &mut Vault, + vault: &mut OwnedVault, packet_hashes: vector>, whitelist: bool, ctx: &mut TxContext, @@ -212,8 +215,8 @@ module vault::vault { } public fun solve( - vault: &mut Vault, - _: &VaultCap, + vault: &mut OwnedVault, + _: &ZkgmCap, packet: ibc::packet::Packet, base_token: vector, quote_token: vector, @@ -259,7 +262,7 @@ module vault::vault { let (base_amount, quote_amount) = (base_amount, quote_amount); - let capability = vault.get_treasury_cap(); + let capability = vault.borrow_mut_treasury_cap(); let fee = base_amount - quote_amount; if (fee > 0) { coin::mint_and_transfer(capability, fee as u64, relayer, ctx); @@ -273,116 +276,96 @@ module vault::vault { (counterparty_beneficiary, 0) } - public fun burn_with_cap(vault: &mut Vault, _: &VaultCap, c: Coin, ctx: &TxContext): u64 { - vault.burn_internal(false, c, ctx) + // Temporarily get access to the `TreasuryCap`. Note that it is enforced to give it back to this contract via + // `give_back_treasury_cap` or the PTB will fail since the `TreasuryCapReleaseCtx` has no drop ability. So, it must + // be consumed by the `give_back_treasury_cap` function. + // + // We could just return a mutable ref to the `TreasuryCap` but it's not allowed in the MoveVM to return a mutable reference + // from a PTB command. + public fun release_treasury_cap(vault: &mut OwnedVault, ctx: &TxContext): (TreasuryCap, TreasuryCapReleaseCtx) { + let token = type_name::get().into_string().into_bytes(); + let cap: TreasuryCapWithMetadata = vault.token_type_to_treasury.remove(token); + + assert!(ctx.sender() == cap.metadata.owner(), E_UNAUTHORIZED); + + let TreasuryCapWithMetadata { + cap, + metadata, + id + } = cap; + + object::delete(id); + + (cap, TreasuryCapReleaseCtx { + metadata + }) } - public fun mint_with_cap( - vault: &mut Vault, - _: &VaultCap, - value: u64, - ctx: &mut TxContext - ): Coin { - vault.mint_internal(false, value, ctx) - } + // Give back the temporarily accessed `TreasuryCap` + public fun give_back_treasury_cap(vault: &mut OwnedVault, cap: TreasuryCap, handle: TreasuryCapReleaseCtx, ctx: &mut TxContext) { + assert!(ctx.sender() == handle.metadata.owner(), E_UNAUTHORIZED); - public fun mint_and_transfer_with_cap( - vault: &mut Vault, - _: &VaultCap, - amount: u64, - recipient: address, - ctx: &mut TxContext - ) { - vault.mint_and_transfer_internal(false, amount, recipient, ctx); + let token = type_name::get().into_string().into_bytes(); + let TreasuryCapReleaseCtx { + metadata + } = handle; + vault.token_type_to_treasury.add(token, TreasuryCapWithMetadata { + id: object::new(ctx), + cap, + metadata + }); } + public fun burn(vault: &mut OwnedVault, _: &ZkgmCap, c: Coin): u64 { + let cap = vault.borrow_mut_treasury_cap(); - public fun burn(vault: &mut Vault, c: Coin, ctx: &TxContext): u64 { - vault.burn_internal(true, c, ctx) + coin::burn(cap, c) } - - /// Coin admin functions public fun mint( - vault: &mut Vault, - value: u64, - ctx: &mut TxContext - ): Coin { - vault.mint_internal(true, value, ctx) - } - - public fun mint_and_transfer( - vault: &mut Vault, + vault: &mut OwnedVault, + _: &ZkgmCap, amount: u64, recipient: address, ctx: &mut TxContext ) { - vault.mint_and_transfer_internal(true, amount, recipient, ctx); - } - - fun burn_internal(vault: &mut Vault, owner_check: bool, c: Coin, ctx: &TxContext): u64 { - let typename_t = type_name::get(); - let cap = vault.token_type_to_treasury.borrow_mut>(string::from_ascii(typename_t.into_string())); + let cap = vault.borrow_mut_treasury_cap(); - if (owner_check) { - assert!(ctx.sender() == cap.metadata.owner(), E_UNAUTHORIZED); - }; - - coin::burn(&mut cap.cap, c) - } - - - /// Coin admin functions - fun mint_internal( - vault: &mut Vault, - owner_check: bool, - value: u64, - ctx: &mut TxContext - ): Coin { - let typename_t = string::from_ascii(type_name::get().into_string()); - let cap: &mut TreasuryCapWithMetadata = vault.token_type_to_treasury.borrow_mut(typename_t); - - if (owner_check) { - assert!(ctx.sender() == cap.metadata.owner(), E_UNAUTHORIZED); - }; - - coin::mint(&mut cap.cap, value, ctx) - } - - fun mint_and_transfer_internal( - vault: &mut Vault, - owner_check: bool, - amount: u64, - recipient: address, - ctx: &mut TxContext - ) { - let typename_t = string::from_ascii(type_name::get().into_string()); - let cap: &mut TreasuryCapWithMetadata = vault.token_type_to_treasury.borrow_mut(typename_t); - - if (owner_check) { - assert!(ctx.sender() == cap.metadata.owner(), E_UNAUTHORIZED); - }; - - coin::mint_and_transfer(&mut cap.cap, amount, recipient, ctx); + coin::mint_and_transfer(cap, amount, recipient, ctx); } public fun get_metadata( - vault: &Vault, + vault: &OwnedVault, ): &Metadata { - let typename_t = string::from_ascii(type_name::get().into_string()); + let typename_t = type_name::get().into_string().into_bytes(); let cap: &TreasuryCapWithMetadata = vault.token_type_to_treasury.borrow(typename_t); &cap.metadata } - fun get_treasury_cap( - vault: &mut Vault + fun borrow_mut_treasury_cap( + vault: &mut OwnedVault ): &mut TreasuryCap { - let typename_t = type_name::get(); - let key = string::from_ascii(typename_t.into_string()); + let key = type_name::get().into_string().into_bytes(); if (!vault.token_type_to_treasury.contains(key)) { abort E_NO_TREASURY_CAPABILITY }; - &mut vault.token_type_to_treasury.borrow_mut>(key).cap + &mut vault.token_type_to_treasury.borrow_mut<_, TreasuryCapWithMetadata>(key).cap + } + + + #[test_only] + public fun init_for_tests(ctx: &mut TxContext) { + transfer::share_object(OwnedVault { + id: object::new(ctx), + token_type_to_treasury: object_bag::new(ctx), + intent_whitelists: table::new(ctx), + fungible_counterparties: table::new(ctx), + }); + + transfer::transfer( + ZkgmCap { id: object::new(ctx) }, + ctx.sender() + ); } } diff --git a/sui/vault/tests/vault_tests.move b/sui/owned_vault/tests/vault_tests.move similarity index 100% rename from sui/vault/tests/vault_tests.move rename to sui/owned_vault/tests/vault_tests.move diff --git a/sui/u/.gitignore b/sui/u/.gitignore deleted file mode 100644 index 60b32c83a2..0000000000 --- a/sui/u/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/* -.trace -.coverage* diff --git a/sui/ucs03_zkgm/Move.lock b/sui/ucs03_zkgm/Move.lock index 7a1a1b08ee..7496828b8f 100644 --- a/sui/ucs03_zkgm/Move.lock +++ b/sui/ucs03_zkgm/Move.lock @@ -2,15 +2,16 @@ [move] version = 3 -manifest_digest = "D1D60C42F4FC7F4C809B75ED3582A55FE3A61984289A6215531A848F3EAF282B" -deps_digest = "52B406A7A21811BEF51751CF88DA0E76DAEFFEAC888D4F4060B1A72BBE7D8D35" +manifest_digest = "4C39E6F377CC2C635F728C8628FE5C35AC6A42B77CC6A99E90CCA6FDD42C03A4" +deps_digest = "CAFAD8A7CF51067FB4358215BECB86BD100DD64E57C2AC8A7AE7D74B688F5965" dependencies = [ { id = "Bridge", name = "Bridge" }, { id = "MoveStdlib", name = "MoveStdlib" }, { id = "Sui", name = "Sui" }, { id = "SuiSystem", name = "SuiSystem" }, + { id = "escrow_vault", name = "escrow_vault" }, { id = "ibc", name = "ibc" }, - { id = "vault", name = "vault" }, + { id = "owned_vault", name = "owned_vault" }, ] [[move.package]] @@ -44,6 +45,18 @@ dependencies = [ { id = "Sui", name = "Sui" }, ] +[[move.package]] +id = "escrow_vault" +source = { local = "../escrow_vault" } + +dependencies = [ + { id = "Bridge", name = "Bridge" }, + { id = "MoveStdlib", name = "MoveStdlib" }, + { id = "Sui", name = "Sui" }, + { id = "SuiSystem", name = "SuiSystem" }, + { id = "ibc", name = "ibc" }, +] + [[move.package]] id = "ibc" source = { local = "../ibc" } @@ -56,8 +69,8 @@ dependencies = [ ] [[move.package]] -id = "vault" -source = { local = "../vault" } +id = "owned_vault" +source = { local = "../owned_vault" } dependencies = [ { id = "Bridge", name = "Bridge" }, diff --git a/sui/ucs03_zkgm/Move.toml b/sui/ucs03_zkgm/Move.toml index 62f147b59e..c2e4ceb207 100644 --- a/sui/ucs03_zkgm/Move.toml +++ b/sui/ucs03_zkgm/Move.toml @@ -1,23 +1,20 @@ [package] -edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move +edition = "2024.beta" name = "zkgm" -# license = "" # e.g., "MIT", "GPL", "Apache 2.0" -# authors = ["..."] # e.g., ["Joe Smith (joesmith@noemail.com)", "John Snow (johnsnow@noemail.com)"] [dependencies] -ibc = { local = "../ibc" } -vault = { local = "../vault" } +escrow_vault = { local = "../escrow_vault" } +ibc = { local = "../ibc" } +owned_vault = { local = "../owned_vault" } [addresses] -# ibc = "0xd5b50a4b934303c39baf1999ddf84cfcd65b4c6f73b2226bfea77987c21fbff8" -# vault = "0xc113302f2d081c65299ac245ce043c124368af79b5a9ce38d86855841b64d386" -# zkgm = "0x0" - -ibc = "_" -vault = "_" -zkgm = "_" +escrow_vault = "_" +ibc = "_" +owned_vault = "_" +zkgm = "_" [dev-addresses] -ibc = "0x22222" -vault = "0x2334" -zkgm = "0x4444444444444" +escrow_vault = "0x4444" +ibc = "0x1111" +owned_vault = "0x3333" +zkgm = "0x2222" diff --git a/sui/ucs03_zkgm/sources/eth_abi.move b/sui/ucs03_zkgm/sources/eth_abi.move index cd85eba75f..122c5cf919 100644 --- a/sui/ucs03_zkgm/sources/eth_abi.move +++ b/sui/ucs03_zkgm/sources/eth_abi.move @@ -209,18 +209,6 @@ module zkgm::zkgm_ethabi { result } - public fun encode_u8(buf: &mut vector, data: u8) { - let u8_data = bcs::to_bytes(&(data as u8)); - vector::append(buf, u8_data); - } - - public fun decode_u8(buf: &vector, index: &mut u64): u8 { - let padded_bytes = vector_slice(buf, *index, *index + 1); - // let padded_bytes = vector::slice(buf, *index, *index + 1); - - *index = *index + 1; - bcs::new(padded_bytes).peel_u8() - } public macro fun encode_vector<$T>( diff --git a/sui/ucs03_zkgm/sources/helpers.move b/sui/ucs03_zkgm/sources/helpers.move index 1a08e5b274..8acf56038a 100644 --- a/sui/ucs03_zkgm/sources/helpers.move +++ b/sui/ucs03_zkgm/sources/helpers.move @@ -251,4 +251,91 @@ module zkgm::helper { hash::keccak256(&data) } + + #[test] + fun test_is_allowed_flags() { + assert!(is_allowed_batch_instruction(0x01), 1); + assert!(is_allowed_batch_instruction(0x03), 2); + assert!(!is_allowed_batch_instruction(0x00), 3); + assert!(!is_allowed_batch_instruction(0x02), 4); + + assert!(is_allowed_forward(0x01), 5); + assert!(is_allowed_forward(0x02), 6); + assert!(is_allowed_forward(0x03), 7); + assert!(!is_allowed_forward(0xFF), 8); + } + + + #[test] + fun test_derive_batch_salt_determinism_and_uniqueness() { + let s0 = derive_batch_salt(0, b"seed"); + let s1 = derive_batch_salt(1, b"seed"); + let s1b = derive_batch_salt(1, b"seed"); + let s1_other_seed = derive_batch_salt(1, b"seed2"); + + assert!(s1 == s1b, 1); + assert!(s0 != s1, 2); + assert!(s1 != s1_other_seed, 3); + } + + + #[test, expected_failure(abort_code = 2)] + fun test_update_channel_path_hop_limit_aborts_on_9th() { + + let mut path: u256 = 0; + path = update_channel_path(path, 1); + path = update_channel_path(path, 2); + path = update_channel_path(path, 3); + path = update_channel_path(path, 4); + path = update_channel_path(path, 5); + path = update_channel_path(path, 6); + path = update_channel_path(path, 7); + path = update_channel_path(path, 8); + + let _ = update_channel_path(path, 9); + } + + #[test] + fun test_pop_on_zero_path() { + let (t, h) = pop_channel_from_path(0); + assert!(t == 0 && h == 0, 1); + } + + #[test] + fun test_fls_examples() { + assert!(fls(0) == 256, 1); + assert!(fls(1) == 0, 2); + assert!(fls(2) == 1, 3); + assert!(fls(16) == 4, 4); + assert!(fls(255) == 7, 5); + assert!(fls(((1 as u256) << 16)) == 16, 6); + assert!(fls(((1 as u256) << 32)) == 32, 7); + assert!(fls(((1 as u256) << 64)) == 64, 8); + } + + #[test] + fun test_compute_salt_consistency_and_sensitivity() { + let path: u256 = 0xAABBCC; + let channel: u32 = 42; + + let metadata = b"hello-metadata"; + let metadata_image = hash::keccak256(&metadata); + + let s1 = compute_salt(path, channel, b"BASE", b"hello-metadata"); + let s2 = compute_salt_from_metadata_image(path, channel, b"BASE", metadata_image); + assert!(s1 == s2, 1); + + let s_path = compute_salt(path + 1, channel, b"BASE", b"hello-metadata"); + assert!(s_path != s1, 2); + + let s_ch = compute_salt(path, channel + 1, b"BASE", b"hello-metadata"); + assert!(s_ch != s1, 3); + + let s_tok = compute_salt(path, channel, b"BASE2", b"hello-metadata"); + assert!(s_tok != s1, 4); + + let s_meta = compute_salt(path, channel, b"BASE", b"hello-metadata!"); + assert!(s_meta != s1, 5); + } + } diff --git a/sui/ucs03_zkgm/sources/types/solver_metadata.move b/sui/ucs03_zkgm/sources/types/solver_metadata.move index f58806d954..0dd86b0064 100644 --- a/sui/ucs03_zkgm/sources/types/solver_metadata.move +++ b/sui/ucs03_zkgm/sources/types/solver_metadata.move @@ -92,4 +92,99 @@ module zkgm::solver_metadata { } } + public fun encode(meta: &SolverMetadata): vector { + let mut buf = vector::empty(); + + let mut solver_address = vector::empty(); + zkgm_ethabi::encode_bytes(&mut solver_address, &meta.solver_address); + + let mut metadata = vector::empty(); + zkgm_ethabi::encode_bytes(&mut metadata, &meta.metadata); + + // Each static slot is 32 bytes. There are 2 dynamic fields, so we store offsets. + let mut dyn_offset = 0x20 * 2; + + // offset for solver_address + zkgm_ethabi::encode_uint(&mut buf, dyn_offset); + dyn_offset = dyn_offset + vector::length(&solver_address); + + // offset for metadata + zkgm_ethabi::encode_uint(&mut buf, dyn_offset); + + vector::append(&mut buf, solver_address); + vector::append(&mut buf, metadata); + + buf + } + + /// Encode into an existing buffer using *absolute offsets* from the start of `buf`. + public fun encode_into(buf: &mut vector, m: &SolverMetadata) { + + let mut body_solver = vector::empty(); + zkgm_ethabi::encode_bytes(&mut body_solver, solver_address(m)); + let mut body_meta = vector::empty(); + zkgm_ethabi::encode_bytes(&mut body_meta, metadata(m)); + + let base: u64 = vector::length(buf) as u64; + + + let off_solver: u64 = base + 64; + + let off_meta: u64 = off_solver + (vector::length(&body_solver) as u64); + + zkgm_ethabi::encode_uint(buf, off_solver); + zkgm_ethabi::encode_uint(buf, off_meta); + + vector::append(buf, body_solver); + vector::append(buf, body_meta); + } + + #[test] + public fun test_solver_metadata_roundtrip() { + use sui::bcs; + + let m = new( + bcs::to_bytes(&@0x1111111111111111111111111111111111111111), + b"hello-world" + ); + let enc = encode(&m); + let dec = decode(&enc); + + assert!(*solver_address(&dec) + == *solver_address(&m), 1); + assert!(*metadata(&dec) + == *metadata(&m), 2); + } + + #[test] + public fun test_solver_metadata_empty_metadata() { + use sui::bcs; + + let m = new( + bcs::to_bytes(&@0x0c8C6f58156D10d18193A8fFdD853e1b9F8D8836), + x"" + ); + let enc = encode(&m); + + + std::debug::print(&std::string::utf8(b"encoded solvermetadata::")); + std::debug::print(&enc); + + let dec = decode(&enc); + + assert!(*solver_address(&dec) + == *solver_address(&m), 1); + assert!(*metadata(&dec) + == *metadata(&m), 2); + + + let data_is = x"000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d7d5df03683eeb343cb259ff2bab8dc590ea8d4c0c0d96bfdcf86846f7dcb2aa"; + + let decoded = decode(&data_is); + + std::debug::print(&std::string::utf8(b"decoded::")); + std::debug::print(&decoded); + } + + } diff --git a/sui/ucs03_zkgm/sources/types/sui_token_metadata.move b/sui/ucs03_zkgm/sources/types/sui_token_metadata.move index e15a850432..01dd55c229 100644 --- a/sui/ucs03_zkgm/sources/types/sui_token_metadata.move +++ b/sui/ucs03_zkgm/sources/types/sui_token_metadata.move @@ -127,4 +127,85 @@ module zkgm::sui_token_metadata { public(package) fun description(m: &SuiTokenMetadata): &String { &m.description } + #[test] + fun test_decode_with_icon_some() { + use std::option; + + let name = string::utf8(b"Token"); + let symbol = string::utf8(b"TKN"); + let decimals: u8 = 9; + let owner: address = @0xA11CE; + let icon = string::utf8(b"https://icon"); + let description = string::utf8(b"desc"); + + let mut buf: vector = vector::empty(); + buf.append(bcs::to_bytes(&name.into_bytes())); + buf.append(bcs::to_bytes(&symbol.into_bytes())); + buf.append(bcs::to_bytes(&decimals)); + buf.append(bcs::to_bytes(&owner)); + buf.append(bcs::to_bytes(&option::some(icon.into_bytes()))); + buf.append(bcs::to_bytes(&description.into_bytes())); + + let m = decode(buf); + assert!(*name(&m) == string::utf8(b"Token"), 1); + assert!(*symbol(&m) == string::utf8(b"TKN"), 2); + assert!(decimals(&m) == 9, 3); + assert!(owner(&m) == @0xA11CE, 4); + let iu = icon_url(&m); + assert!(option::is_some(iu), 5); + let iu_ref = option::borrow(iu); + assert!(*iu_ref == string::utf8(b"https://icon"), 6); + assert!(*description(&m) == string::utf8(b"desc"), 7); + } + + #[test] + fun test_decode_with_icon_none() { + use std::option; + + let name = string::utf8(b"N"); + let symbol = string::utf8(b"S"); + let decimals: u8 = 6; + let owner: address = @0xB0B; + let description = string::utf8(b"D"); + + let mut buf: vector = vector::empty(); + buf.append(bcs::to_bytes(&name.into_bytes())); + buf.append(bcs::to_bytes(&symbol.into_bytes())); + buf.append(bcs::to_bytes(&decimals)); + buf.append(bcs::to_bytes(&owner)); + buf.append(bcs::to_bytes(&option::none>())); + buf.append(bcs::to_bytes(&description.into_bytes())); + + let m = decode(buf); + assert!(*name(&m) == string::utf8(b"N"), 1); + assert!(*symbol(&m) == string::utf8(b"S"), 2); + assert!(decimals(&m) == 6, 3); + assert!(owner(&m) == @0xB0B, 4); + assert!(option::is_none(icon_url(&m)), 5); + assert!(*description(&m) == string::utf8(b"D"), 6); + } + + #[test] + fun test_new_and_getters() { + use std::option; + + let m = new( + string::utf8(b"Alpha"), + string::utf8(b"ALP"), + 8, + @0xC0FFEE, + option::some(string::utf8(b"https://a")), + string::utf8(b"zzz"), + ); + assert!(*name(&m) == string::utf8(b"Alpha"), 1); + assert!(*symbol(&m) == string::utf8(b"ALP"), 2); + assert!(decimals(&m) == 8, 3); + assert!(owner(&m) == @0xC0FFEE, 4); + let iu = icon_url(&m); + assert!(option::is_some(iu), 5); + let iu_ref = option::borrow(iu); + assert!(*iu_ref == string::utf8(b"https://a"), 6); + assert!(*description(&m) == string::utf8(b"zzz"), 7); + } + } diff --git a/sui/ucs03_zkgm/sources/types/token_order.move b/sui/ucs03_zkgm/sources/types/token_order.move index 67c1019fae..e003723fb5 100644 --- a/sui/ucs03_zkgm/sources/types/token_order.move +++ b/sui/ucs03_zkgm/sources/types/token_order.move @@ -154,7 +154,7 @@ module zkgm::token_order { // quote_token offset zkgm_ethabi::encode_uint(&mut buf, dyn_offset); zkgm_ethabi::encode_uint(&mut buf, order.quote_amount); - dyn_offset = dyn_offset + vector::length(&metadata); + dyn_offset = dyn_offset + vector::length("e_token); zkgm_ethabi::encode_uint(&mut buf, order.kind); // metadata offset @@ -185,21 +185,25 @@ module zkgm::token_order { #[test] fun test_encode_decode() { - let encoded = x"000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000000fa000000000000000000000000000000000000000000000000000000000000006344444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004424242420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044343434300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006761736466736e6564666c6561736e64666c656e6173646c66656e6173656c646e6c6561736e64666c65616e7364666c656e6173646c65666e616c73656e64666c656e61736466656c6e61736c6564666c6561736e64666c656e61736c6465666e6c65616e7364660000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000634444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444440000000000000000000000000000000000000000000000000000000000"; + let encoded = x"000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000fa000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000002abcd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032222220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000344444400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020dafe631cbe5cf0e5dfb68f6b5f6ed2ebaa139a6807b47c9402d7bce691ee732d"; let packet = decode(&encoded); let expected_packet = TokenOrderV2 { - sender: b"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", - receiver: b"BBBB", - base_token: b"CCCC", + sender: x"abcd", + receiver: x"111111", + base_token: x"222222", base_amount: 100, - quote_token: b"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", + quote_token: x"444444", quote_amount: 250, kind: 1, - metadata: b"asdfsnedfleasndflenasdlfenaseldnleasndfleansdflenasdlefnalsendflenasdfelnasledfleasndflenasldefnleansdf", + metadata: x"000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020dafe631cbe5cf0e5dfb68f6b5f6ed2ebaa139a6807b47c9402d7bce691ee732d", }; - + std::debug::print(&std::string::utf8(b"DECODED PACKET METADATA IS:")); + std::debug::print(&packet); assert!(packet == expected_packet, 1); - assert!(encode(&packet) == encoded, 1); + let test_encoded = encode(&packet); + std::debug::print(&std::string::utf8(b"RE-ENCODED PACKET IS:")); + std::debug::print(&test_encoded); + assert!(test_encoded== encoded, 1); } } diff --git a/sui/ucs03_zkgm/sources/zkgm.move b/sui/ucs03_zkgm/sources/zkgm.move index 299d514dd5..45fbe95683 100644 --- a/sui/ucs03_zkgm/sources/zkgm.move +++ b/sui/ucs03_zkgm/sources/zkgm.move @@ -73,7 +73,9 @@ module zkgm::zkgm { use ibc::ibc; use ibc::packet::{Self, Packet}; - use vault::vault::{Vault, VaultCap}; + use owned_vault::owned_vault::{Self, OwnedVault}; + + use escrow_vault::escrow_vault::{Self, EscrowVault}; use zkgm::ack::{Self, Ack}; use zkgm::batch; @@ -88,6 +90,10 @@ module zkgm::zkgm { use zkgm::zkgm_packet; use zkgm::solver_metadata; + #[test_only] + use sui::test_scenario; + + // Constants const VERSION: vector = b"ucs03-zkgm-0"; const ACK_SUCCESS: u256 = 1; @@ -137,21 +143,21 @@ module zkgm::zkgm { const E_INVALID_SOLVER_ADDRESS: u64 = 45; const E_INVALID_QUOTE_TOKEN: u64 = 46; const E_EXECUTION_ALREADY_COMPLETE: u64 = 47; - const E_VAULT_MISMATCH: u64 = 48; // const E_ONLY_MAKER: u64 = 0xdeadc0de; - const VAULT_CAP_OBJECT_KEY: vector = b"VAULT_CAP"; + const OWNED_VAULT_OBJECT_KEY: vector = b"ucs03-zkgm-owned-vault"; + const ESCROW_VAULT_OBJECT_KEY: vector = b"ucs03-zkgm-escrow-vault"; public struct IbcAppWitness has drop {} public struct RelayStore has key { id: UID, - vault_id: ID, in_flight_packet: Table, Packet>, channel_balance: Table, token_origin: Table, u256>, wrapped_denom_to_t: Table, String>, object_store: ObjectBag, + test_mode: bool, } public struct CreateWrappedToken has copy, drop, store { @@ -220,20 +226,27 @@ module zkgm::zkgm { transfer::share_object(RelayStore { id: id, - vault_id: object::id_from_address(@vault), in_flight_packet: table::new(ctx), channel_balance: table::new(ctx), token_origin: table::new(ctx), object_store: object_bag::new(ctx), wrapped_denom_to_t: table::new(ctx), + test_mode: false, }); } - public fun register_vault_cap( + public fun register_owned_vault_cap( zkgm: &mut RelayStore, - vault_cap: VaultCap, + vault_cap: owned_vault::ZkgmCap, ) { - zkgm.object_store.add(VAULT_CAP_OBJECT_KEY, vault_cap); + zkgm.object_store.add(OWNED_VAULT_OBJECT_KEY, vault_cap); + } + + public fun register_escrow_vault_cap( + zkgm: &mut RelayStore, + vault_cap: escrow_vault::ZkgmCap, + ) { + zkgm.object_store.add(ESCROW_VAULT_OBJECT_KEY, vault_cap); } public fun channel_open_init( @@ -342,7 +355,7 @@ module zkgm::zkgm { public fun send_with_coin( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, ibc_store: &mut ibc::IBCStore, coin: Coin, version: u8, @@ -468,15 +481,14 @@ module zkgm::zkgm { public fun recv_packet( ibc: &mut ibc::IBCStore, zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, + escrow_vault: &mut EscrowVault, clock: &Clock, relayer: address, relayer_msg: vector, mut exec_ctx: RecvCtx, ctx: &mut TxContext ): RecvCtx { - // assert!(object::id(vault) == zkgm.vault_id, E_VAULT_MISMATCH); - // aborts if there is not a session let packet_cursor = exec_ctx.cursor; let packet = exec_ctx.packets[exec_ctx.cursor]; @@ -499,6 +511,7 @@ module zkgm::zkgm { let (ack, err) = zkgm.execute_internal( vault, + escrow_vault, ibc, packet, zkgm_packet, @@ -575,7 +588,8 @@ module zkgm::zkgm { fun execute_internal( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, + escrow_vault: &mut EscrowVault, ibc: &mut ibc::IBCStore, packet: Packet, packet_ctx: &ZkgmPacketCtx, @@ -595,6 +609,7 @@ module zkgm::zkgm { }; zkgm.execute_token_order( vault, + escrow_vault, packet, relayer, relayer_msg, @@ -674,8 +689,9 @@ module zkgm::zkgm { public fun acknowledge_packet( ibc: &mut ibc::IBCStore, - vault: &mut Vault, zkgm: &mut RelayStore, + vault: &mut OwnedVault, + escrow_vault: &mut EscrowVault, relayer: address, mut ack_ctx: AckCtx, ctx: &mut TxContext @@ -722,6 +738,7 @@ module zkgm::zkgm { zkgm.acknowledge_internal( vault, + escrow_vault, packet, relayer, zkgm_packet.path, @@ -804,7 +821,7 @@ module zkgm::zkgm { public fun timeout_packet( ibc: &mut ibc::IBCStore, - vault: &mut Vault, + vault: &mut OwnedVault, zkgm: &mut RelayStore, relayer: address, mut timeout_ctx: TimeoutCtx, @@ -887,7 +904,8 @@ module zkgm::zkgm { fun market_maker_fill( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, + escrow_vault: &mut EscrowVault, ibc_packet: Packet, relayer: address, relayer_msg: vector, @@ -900,6 +918,7 @@ module zkgm::zkgm { if (order.kind() == TOKEN_ORDER_KIND_SOLVE) { return zkgm.solver_fill( vault, + escrow_vault, ibc_packet, order, path, @@ -924,7 +943,8 @@ module zkgm::zkgm { fun solver_fill( zkgm: &RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, + escrow_vault: &mut EscrowVault, ibc_packet: Packet, order: TokenOrderV2, path: u256, @@ -934,40 +954,52 @@ module zkgm::zkgm { ): (vector, u64) { let metadata = solver_metadata::decode(order.metadata()); - let solver = bcs::new(*metadata.solver_address()).peel_address(); - - if (solver != @vault) { - return (vector::empty(), E_INVALID_SOLVER_ADDRESS) - }; - let quote_token = *order.quote_token(); if (type_name::get().into_string().into_bytes() != quote_token) { return (vector::empty(), E_INVALID_QUOTE_TOKEN) }; + + let solver = metadata.solver_address(); - vault.solve( - zkgm.object_store.borrow(VAULT_CAP_OBJECT_KEY), - ibc_packet, - *order.base_token(), - quote_token, - order.base_amount(), - order.quote_amount(), - *order.receiver(), - path, - relayer, - vector::empty(), - intent, - ctx - ) + match (solver) { + OWNED_VAULT_OBJECT_KEY => vault.solve( + zkgm.object_store.borrow(OWNED_VAULT_OBJECT_KEY), + ibc_packet, + *order.base_token(), + quote_token, + order.base_amount(), + order.quote_amount(), + *order.receiver(), + path, + relayer, + vector::empty(), + intent, + ctx + ), + ESCROW_VAULT_OBJECT_KEY => escrow_vault.solve( + zkgm.object_store.borrow(ESCROW_VAULT_OBJECT_KEY), + ibc_packet, + *order.base_token(), + quote_token, + order.base_amount(), + order.quote_amount(), + *order.receiver(), + path, + relayer, + vector::empty(), + intent, + ctx + ), + _ => (vector::empty(), E_INVALID_SOLVER_ADDRESS) + } } - fun distribute_coin( + fun split_coin( relay_store: &mut RelayStore, - receiver: address, amount: u64, ctx: &mut TxContext - ) { + ): Coin { let typename_t = type_name::get(); let key = typename_t.into_string(); if(!relay_store.object_store.contains(string::from_ascii(key))) { @@ -975,13 +1007,22 @@ module zkgm::zkgm { }; let coin = relay_store.object_store.borrow_mut>(string::from_ascii(key)); - let transferred_coin = coin.split(amount, ctx); + coin.split(amount, ctx) + } + + fun distribute_coin( + relay_store: &mut RelayStore, + receiver: address, + amount: u64, + ctx: &mut TxContext + ) { + let transferred_coin = relay_store.split_coin(amount, ctx); transfer::public_transfer(transferred_coin, receiver); } fun protocol_fill_mint( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, _channel_id: u32, _path: u256, wrapped_token: vector, @@ -999,16 +1040,16 @@ module zkgm::zkgm { return (vector::empty(), E_ANOTHER_TOKEN_IS_REGISTERED) }; if (quote_amount > 0) { - vault.mint_and_transfer_with_cap( - zkgm.object_store.borrow(VAULT_CAP_OBJECT_KEY), + vault.mint( + zkgm.object_store.borrow(OWNED_VAULT_OBJECT_KEY), quote_amount as u64, receiver, ctx ); }; if (fee > 0){ - vault.mint_and_transfer_with_cap( - zkgm.object_store.borrow(VAULT_CAP_OBJECT_KEY), + vault.mint( + zkgm.object_store.borrow(OWNED_VAULT_OBJECT_KEY), fee, relayer, ctx @@ -1142,7 +1183,8 @@ module zkgm::zkgm { fun execute_token_order( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, + escrow_vault: &mut EscrowVault, ibc_packet: Packet, relayer: address, relayer_msg: vector, @@ -1162,6 +1204,7 @@ module zkgm::zkgm { if (intent || order.kind() == TOKEN_ORDER_KIND_SOLVE) { return zkgm.market_maker_fill( vault, + escrow_vault, ibc_packet, relayer, relayer_msg, @@ -1253,6 +1296,7 @@ module zkgm::zkgm { // non wrapped assets). zkgm.market_maker_fill( vault, + escrow_vault, ibc_packet, relayer, relayer_msg, @@ -1334,7 +1378,7 @@ module zkgm::zkgm { fun verify_internal( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, ibc_store: &mut ibc::IBCStore, coin: Option>, sender: address, @@ -1380,13 +1424,13 @@ module zkgm::zkgm { fun verify_token_order( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, coin: Coin, _sender: address, channel_id: u32, path: u256, order: TokenOrderV2, - ctx: &TxContext + _: &TxContext ) { let base_token = *order.base_token(); @@ -1422,10 +1466,9 @@ module zkgm::zkgm { // We don't have to verify that metadataImage matches the stored one // because the prediction would fail otherwise and we would fall // back in the else branch. - vault.burn_with_cap( - zkgm.object_store.borrow<_, VaultCap>(VAULT_CAP_OBJECT_KEY), - coin, - ctx + vault.burn( + zkgm.object_store.borrow<_, owned_vault::ZkgmCap>(OWNED_VAULT_OBJECT_KEY), + coin ); } else { @@ -1444,7 +1487,7 @@ module zkgm::zkgm { fun verify_forward( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, ibc_store: &mut ibc::IBCStore, coin: Option>, sender: address, @@ -1471,7 +1514,8 @@ module zkgm::zkgm { fun acknowledge_internal( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, + escrow_vault: &mut EscrowVault, ibc_packet: Packet, relayer: address, path: u256, @@ -1490,6 +1534,7 @@ module zkgm::zkgm { zkgm.acknowledge_token_order( vault, + escrow_vault, ibc_packet, relayer, path, @@ -1507,6 +1552,7 @@ module zkgm::zkgm { assert!(version == INSTR_VERSION_0, E_UNSUPPORTED_VERSION); zkgm.acknowledge_forward( vault, + escrow_vault, ibc_packet, relayer, salt, @@ -1525,7 +1571,8 @@ module zkgm::zkgm { fun acknowledge_token_order( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, + escrow_vault: &mut EscrowVault, ibc_packet: Packet, _relayer: address, path: u256, @@ -1545,8 +1592,8 @@ module zkgm::zkgm { let market_maker = bcs::new(*asset_order_ack.market_maker()).peel_address(); if (order.kind() == TOKEN_ORDER_KIND_UNESCROW) { - vault.mint_and_transfer_with_cap( - zkgm.object_store.borrow(VAULT_CAP_OBJECT_KEY), + vault.mint( + zkgm.object_store.borrow(OWNED_VAULT_OBJECT_KEY), order.base_amount() as u64, market_maker, ctx @@ -1567,16 +1614,20 @@ module zkgm::zkgm { ); coin.split(order.base_amount() as u64, ctx) }; - vault.burn_with_cap( - zkgm.object_store.borrow(VAULT_CAP_OBJECT_KEY), - coin, - ctx + vault.burn( + zkgm.object_store.borrow(OWNED_VAULT_OBJECT_KEY), + coin + ); + } else if (bcs::to_bytes(&market_maker) == ESCROW_VAULT_OBJECT_KEY) { + let coin = zkgm.split_coin(order.base_amount() as u64, ctx); + escrow_vault.escrow( + zkgm.object_store.borrow(ESCROW_VAULT_OBJECT_KEY), + coin ); } else { zkgm.distribute_coin(market_maker, order.base_amount() as u64, ctx); }; } - } else { abort E_INVALID_FILL_TYPE }; @@ -1594,7 +1645,8 @@ module zkgm::zkgm { fun acknowledge_forward( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, + escrow_vault: &mut EscrowVault, ibc_packet: Packet, relayer: address, salt: vector, @@ -1605,6 +1657,7 @@ module zkgm::zkgm { ) { zkgm.acknowledge_internal( vault, + escrow_vault, ibc_packet, relayer, forward_packet.path(), @@ -1618,7 +1671,7 @@ module zkgm::zkgm { fun timeout_internal( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, ibc_packet: Packet, relayer: address, path: u256, @@ -1662,7 +1715,7 @@ module zkgm::zkgm { fun timeout_token_order( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, packet: Packet, path: u256, order: TokenOrderV2, @@ -1679,7 +1732,7 @@ module zkgm::zkgm { fun refund( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, source_channel: u32, path: u256, order: TokenOrderV2, @@ -1688,7 +1741,10 @@ module zkgm::zkgm { let sender = bcs::new(*order.sender()).peel_address(); if (order.kind() == TOKEN_ORDER_KIND_UNESCROW) { - vault.mint_and_transfer(order.base_amount() as u64, sender, ctx); + vault.mint( + zkgm.object_store.borrow(OWNED_VAULT_OBJECT_KEY), + order.base_amount() as u64, sender, ctx + ); } else { zkgm.decrease_outstanding( source_channel, @@ -1704,7 +1760,7 @@ module zkgm::zkgm { fun timeout_forward( zkgm: &mut RelayStore, - vault: &mut Vault, + vault: &mut OwnedVault, packet: Packet, relayer: address, path: u256, @@ -1723,7 +1779,7 @@ module zkgm::zkgm { fun claim_wrapped_denom( zkgm: &mut RelayStore, - vault: &Vault, + vault: &OwnedVault, wrapped_denom: vector, metadata: Option, ): bool { @@ -1790,4 +1846,356 @@ module zkgm::zkgm { true } } + + #[test_only] + public fun init_for_tests(ctx: &mut TxContext) { + let id = object::new(ctx); + + transfer::share_object(RelayStore { + id: id, + in_flight_packet: table::new(ctx), + channel_balance: table::new(ctx), + token_origin: table::new(ctx), + object_store: object_bag::new(ctx), + wrapped_denom_to_t: table::new(ctx), + test_mode: true, + }); + } + + #[test] + fun test_is_valid_version_true() { + assert!(is_valid_version(string::utf8(b"ucs03-zkgm-0")), 1) + } + + #[test] + fun test_is_valid_version_false() { + assert!(!is_valid_version(string::utf8(b"ucs03-zkgm-1")), 1) + } + + #[test] + fun test_increase_then_decrease_outstanding_ok() { + let mut t = test_scenario::begin(@0x0); + + t.next_tx(@0x0); + init(t.ctx()); + + t.next_tx(@0x0); + let mut store = t.take_shared(); + + let channel: u32 = 7; + let path: u256 = 0xAA; + let token: vector = b"TKN"; + let meta: vector = b"IMG"; + let amt: u256 = 5; + + increase_outstanding(&mut store, channel, path, token, meta, amt); + let rc1 = decrease_outstanding(&mut store, channel, path, token, meta, amt); + assert!(rc1 == 0, rc1); + + test_scenario::return_shared(store); + t.end(); + } + + #[test] + fun test_decrease_outstanding_pair_not_found_code() { + let mut t = test_scenario::begin(@0x0); + + t.next_tx(@0x0); + init(t.ctx()); + + t.next_tx(@0x0); + let mut store = t.take_shared(); + + let rc = decrease_outstanding( + &mut store, + 1, + 0x1, + b"A", + b"B", + 1 + ); + assert!(rc == E_CHANNEL_BALANCE_PAIR_NOT_FOUND, rc); + + test_scenario::return_shared(store); + t.end(); + } + + #[test] + fun test_send_flow_escrow_sui_single_tx() { + use std::string; + use std::ascii; + use std::type_name; + use sui::test_scenario; + use sui::clock; + use sui::clock::Clock; + use sui::coin; + use sui::bcs; + + let mut t = test_scenario::begin(@0x0); + let (mut ibc, mut zkgm, mut owned_vault, escrow_vault) = prepare_test_ctx(&mut t); + let zkgm_cap = test_scenario::take_from_sender(&t); + zkgm.register_owned_vault_cap(zkgm_cap); + + let amount: u64 = 1_000; + let sui_coin = coin::mint_for_testing(amount, t.ctx()); + + let sender = t.sender(); + let receiver = t.sender(); + let base_token = b"BASE"; + let quote_token = std::type_name::get().into_string().into_bytes(); + let md = vector[ + 0u8,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1, + 2,3,4,5,6,7,8,9, + 10,11,12,13,14,15,16,17 + ]; + + let order = zkgm::token_order::new( + sui::bcs::to_bytes(&sender), + sui::bcs::to_bytes(&receiver), + base_token, + amount as u256, + quote_token, + 0, + 0x01, + x"000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040756e696f6e31793035653070326a6376686a7a66376b63717372717839336434673375393368633268796b6171386872766b717270356c7472737361677a7964" + ); + + let instr = zkgm::instruction::new( + INSTR_VERSION_2, + OP_TOKEN_ORDER, + order.encode() + ); + + let salt = b"SALT"; + let mut send_ctx = begin_send(1, salt); + send_ctx = send_with_coin( + &mut zkgm, + &mut owned_vault, + &mut ibc, + sui_coin, + INSTR_VERSION_2, + OP_TOKEN_ORDER, + order.encode(), + send_ctx, + t.ctx() + ); + + + let clk_ref = t.take_shared(); + let now_ns = clock::timestamp_ms(&clk_ref) * 1_000_000; + let timeout_ns = now_ns + 1_000_000_000; + zkgm::zkgm::end_send( + &mut ibc, + &clk_ref, + 0, + timeout_ns, + send_ctx, + t.ctx() + ); + + + let key = string::from_ascii(type_name::get().into_string()); + assert!(zkgm.object_store.contains(key), 1); + let bag_coin: &Coin = zkgm.object_store.borrow(key); + assert!(coin::value(bag_coin) == amount, 2); + + let pair = ChannelBalancePair { + channel: 1, + path: 0, + token: base_token, + metadata_image: quote_token, + }; + assert!(zkgm.channel_balance.contains(pair), 3); + let tracked: u256 = *zkgm.channel_balance.borrow(pair); + assert!(tracked == (amount as u256), 4); + + end_test( + clk_ref, + ibc, + zkgm, + owned_vault, + escrow_vault, + ); + + t.end(); + } + + #[test] + fun test_recv_flow_solve_sui_single_tx() { + use sui::test_scenario; + use sui::clock; + + let mut t = test_scenario::begin(@0x0); + + let (mut ibc, mut zkgm, mut owned_vault, mut escrow_vault) = prepare_test_ctx(&mut t); + let zkgm_cap = test_scenario::take_from_sender(&t); + + let base_token = b"SUI"; + + let coin = coin::mint_for_testing(100_000, t.ctx()); + + escrow_vault.set_fungible_counterparty( + 0, + 1, + base_token, + b"beneficiary", + t.ctx(), + ); + + escrow_vault.escrow( + &zkgm_cap, + coin + ); + + zkgm.register_escrow_vault_cap(zkgm_cap); + + let amount: u64 = 1_000; + let quote_token = type_name::get().into_string().into_bytes(); + + let sender = t.sender(); + let receiver = t.sender(); + + let solver_md = solver_metadata::new( + ESCROW_VAULT_OBJECT_KEY, + x"", + ); + let solver_md = solver_md.encode(); + + let order = zkgm::token_order::new( + bcs::to_bytes(&sender), + bcs::to_bytes(&receiver), + base_token, + (amount as u256), + quote_token, + (amount as u256), + 0x03, + solver_md + ); + + let instr = zkgm::instruction::new( + zkgm::zkgm::INSTR_VERSION_2, + zkgm::zkgm::OP_TOKEN_ORDER, + order.encode() + ); + + let salt = b"SALT_SOLVE"; + let path: u256 = 0; + let packet_bytes = zkgm::zkgm_packet::new( + salt, + path, + instr + ).encode(); + + let clk_ref = t.take_shared(); + let mut rctx = begin_recv( + vector[1], + vector[1], + vector[packet_bytes], + vector[0], + vector[clock::timestamp_ms(&clk_ref) * 1_000_000 + 1_000_000_000] + ); + + let relayer: address = @0xCAFE; + let relayer_msg = b"MM-proof-or-data"; + + rctx = recv_packet( + &mut ibc, + &mut zkgm, + &mut owned_vault, + &mut escrow_vault, + &clk_ref, + relayer, + relayer_msg, + rctx, + t.ctx() + ); + + end_recv( + &mut ibc, + &clk_ref, + b"proof", + 1, + relayer, + relayer_msg, + rctx + ); + + end_test( + clk_ref, + ibc, + zkgm, + owned_vault, + escrow_vault, + ); + t.end(); + } + + #[test_only] + fun prepare_test_ctx(t: &mut test_scenario::Scenario): (ibc::IBCStore, RelayStore, OwnedVault, EscrowVault) { + use std::ascii; + use sui::test_scenario; + use sui::clock; + + init_for_tests(t.ctx()); + ibc::init_for_tests(t.ctx()); + owned_vault::init_for_tests(t.ctx()); + escrow_vault::init_for_tests(t.ctx()); + + + let mut clk0 = clock::create_for_testing(t.ctx()); + clock::increment_for_testing(&mut clk0, 1_000); + clock::share_for_testing(clk0); + + t.next_tx(@0x0); + let mut ibc = t.take_shared(); + let mut zkgm = t.take_shared(); + let mut owned_vault = t.take_shared(); + let mut escrow_vault = t.take_shared(); + + // Open client/connection/channel like in send test + let mut clk = clock::create_for_testing(t.ctx()); + clock::increment_for_testing(&mut clk, 1_000); + clock::share_for_testing(clk); + + ibc.create_client( + string::utf8(b"cometbls"), + b"cs", + b"cons", + t.ctx() + ); + ibc.connection_open_init(1, 2); + ibc.connection_open_ack(1, 9, b"p", 1); + + let mut port = type_name::get().into_string(); + port.append(ascii::string(b"::any")); + ibc.channel_open_init( + port.to_string(), + b"cp-port", + 1, + string::utf8(b"ucs03-zkgm-0"), + zkgm::zkgm::IbcAppWitness {} + ); + ibc.channel_open_ack( + string::utf8(b"ignored-here"), + 1, + string::utf8(b"ucs03-zkgm-0"), + 1, + b"p", + 1, + zkgm::zkgm::IbcAppWitness {} + ); + + (ibc, zkgm, owned_vault, escrow_vault) + } + + #[test_only] + fun end_test(a: A, b: B, c: C, d: D, e: E) { + test_scenario::return_shared(a); + test_scenario::return_shared(b); + test_scenario::return_shared(c); + test_scenario::return_shared(d); + test_scenario::return_shared(e); + } + } diff --git a/sui/vault/.gitignore b/sui/vault/.gitignore deleted file mode 100644 index 60b32c83a2..0000000000 --- a/sui/vault/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/* -.trace -.coverage* diff --git a/sui/vault/Move.toml b/sui/vault/Move.toml deleted file mode 100644 index fdaa88a598..0000000000 --- a/sui/vault/Move.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move -name = "vault" -published-at = "0x3dd0287ae5f29902b4a2d00988d4b3d69f29ea431811df7b9dd5b4f13d829d2e" -# license = "" # e.g., "MIT", "GPL", "Apache 2.0" -# authors = ["..."] # e.g., ["Joe Smith (joesmith@noemail.com)", "John Snow (johnsnow@noemail.com)"] - -[dependencies] -ibc = { local = "../ibc" } - -[addresses] -# ibc = "0xd5b50a4b934303c39baf1999ddf84cfcd65b4c6f73b2226bfea77987c21fbff8" -# vault = "0x0" -ibc = "_" -vault = "_" - -[dev-dependencies] -[dev-addresses] -ibc = "0x222" -vault = "0x111"