From 66297fba7a97a18ea2e68dec295e5271bd9d90e3 Mon Sep 17 00:00:00 2001 From: 0xxgen1 <0xxgen@solend.fi> Date: Fri, 6 Dec 2024 22:44:22 +0000 Subject: [PATCH 1/3] - mSEND contracts - init_msend contract & tests --- contracts/init_msend/Move.toml | 43 ++++++ contracts/init_msend/sources/init_msend.move | 126 ++++++++++++++++++ .../init_msend/tests/test_init_msend.move | 124 +++++++++++++++++ .../msend_coins/msend_12_month/Move.toml | 14 ++ .../sources/msend_12_month.move | 29 ++++ contracts/msend_coins/msend_3_month/Move.toml | 14 ++ .../msend_3_month/sources/msend_3_month.move | 29 ++++ contracts/msend_coins/msend_6_month/Move.toml | 14 ++ .../msend_6_month/sources/msend_6_month.move | 29 ++++ {contract => contracts/mtoken}/Move.toml | 2 +- .../mtoken}/sources/mtoken.move | 0 .../mtoken}/tests/mtoken_tests.move | 0 .../mtoken}/tests/test_coins.move | 0 13 files changed, 423 insertions(+), 1 deletion(-) create mode 100644 contracts/init_msend/Move.toml create mode 100644 contracts/init_msend/sources/init_msend.move create mode 100644 contracts/init_msend/tests/test_init_msend.move create mode 100644 contracts/msend_coins/msend_12_month/Move.toml create mode 100644 contracts/msend_coins/msend_12_month/sources/msend_12_month.move create mode 100644 contracts/msend_coins/msend_3_month/Move.toml create mode 100644 contracts/msend_coins/msend_3_month/sources/msend_3_month.move create mode 100644 contracts/msend_coins/msend_6_month/Move.toml create mode 100644 contracts/msend_coins/msend_6_month/sources/msend_6_month.move rename {contract => contracts/mtoken}/Move.toml (97%) rename {contract => contracts/mtoken}/sources/mtoken.move (100%) rename {contract => contracts/mtoken}/tests/mtoken_tests.move (100%) rename {contract => contracts/mtoken}/tests/test_coins.move (100%) diff --git a/contracts/init_msend/Move.toml b/contracts/init_msend/Move.toml new file mode 100644 index 0000000..bc0c74e --- /dev/null +++ b/contracts/init_msend/Move.toml @@ -0,0 +1,43 @@ +[package] +name = "init_msend" +edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move +# 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/mainnet", override = true } +suilend = { git = "https://github.com/solendprotocol/suilend.git", subdir = "contracts/suilend", rev = "mainnet"} +send = { git = "https://github.com/solendprotocol/send", rev = "master" } +mtoken = { local = "../mtoken" } +msend_3_month = { local = "../msend_coins/msend_3_month" } +msend_6_month = { local = "../msend_coins/msend_6_month" } +msend_12_month = { local = "../msend_coins/msend_12_month" } + +# 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 } + +[addresses] +init_msend = "0x0" + +# 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] +# The dev-addresses section allows overwriting named addresses for the `--test` +# and `--dev` modes. +# alice = "0xB0B" + diff --git a/contracts/init_msend/sources/init_msend.move b/contracts/init_msend/sources/init_msend.move new file mode 100644 index 0000000..3d1160c --- /dev/null +++ b/contracts/init_msend/sources/init_msend.move @@ -0,0 +1,126 @@ +#[allow(lint(share_owned, self_transfer))] +module init_msend::init_msend { + use mtoken::mtoken::{Self, AdminCap, VestingManager}; + use sui::coin::{Coin, TreasuryCap}; + use sui::sui::SUI; + use send::send::SEND; + use msend_3_month::msend_3_month::MSEND_3_MONTH; + use msend_6_month::msend_6_month::MSEND_6_MONTH; + use msend_12_month::msend_12_month::MSEND_12_MONTH; + + public fun init_msend( + msend_3_month_treasury_cap: TreasuryCap, + msend_6_month_treasury_cap: TreasuryCap, + msend_12_month_treasury_cap: TreasuryCap, + send_for_3_month: Coin, + send_for_6_month: Coin, + send_for_12_month: Coin, + ctx: &mut TxContext, + ) { + // mSEND 3 month + let (admin_cap, manager, mtoken_coin) = mint_msend3( + msend_3_month_treasury_cap, + send_for_3_month, + ctx, + ); + + transfer::public_transfer(admin_cap, ctx.sender()); + transfer::public_transfer(mtoken_coin, ctx.sender()); + transfer::public_share_object(manager); + + // mSEND 6 month + let (admin_cap, manager, mtoken_coin) = mint_msend6( + msend_6_month_treasury_cap, + send_for_6_month, + ctx, + ); + + transfer::public_transfer(admin_cap, ctx.sender()); + transfer::public_transfer(mtoken_coin, ctx.sender()); + transfer::public_share_object(manager); + + // mSEND 12 month + let (admin_cap, manager, mtoken_coin) = mint_msend12( + msend_12_month_treasury_cap, + send_for_12_month, + ctx, + ); + + transfer::public_transfer(admin_cap, ctx.sender()); + transfer::public_transfer(mtoken_coin, ctx.sender()); + transfer::public_share_object(manager); + } + + public(package) fun mint_msend3( + msend_3_month_treasury_cap: TreasuryCap, + send_for_3_month: Coin, + ctx: &mut TxContext, + ): (AdminCap, VestingManager, Coin) { + // mSEND 3 month + let start_penalty_numerator = 250; // 0.25*10^(9-6) = 1_000 / 4 = 1 * 10^3 / 4 + let end_penalty_numerator = 0; + let penalty_denominator = 1; + let start_time_ts = 1733508512; + let end_time_ts = 1741802912; + + mtoken::mint_mtokens( + msend_3_month_treasury_cap, + send_for_3_month, + start_penalty_numerator, + end_penalty_numerator, + penalty_denominator, + start_time_ts, + end_time_ts, + ctx, + ) + } + + public(package) fun mint_msend6( + msend_6_month_treasury_cap: TreasuryCap, + send_for_6_month: Coin, + ctx: &mut TxContext, + ): (AdminCap, VestingManager, Coin) { + // mSEND 6 month + let start_penalty_numerator = 500; + let end_penalty_numerator = 0; + let penalty_denominator = 1; + let start_time_ts = 1733508512; + let end_time_ts = 1749748112; + + mtoken::mint_mtokens( + msend_6_month_treasury_cap, + send_for_6_month, + start_penalty_numerator, + end_penalty_numerator, + penalty_denominator, + start_time_ts, + end_time_ts, + ctx, + ) + } + + public(package) fun mint_msend12( + msend_12_month_treasury_cap: TreasuryCap, + send_for_12_month: Coin, + ctx: &mut TxContext, + ): (AdminCap, VestingManager, Coin) { + // mSEND 12 month + + let start_penalty_numerator = 375; + let end_penalty_numerator = 0; + let penalty_denominator = 1; + let start_time_ts = 1733508512; + let end_time_ts = 1749748112; + + mtoken::mint_mtokens( + msend_12_month_treasury_cap, + send_for_12_month, + start_penalty_numerator, + end_penalty_numerator, + penalty_denominator, + start_time_ts, + end_time_ts, + ctx, + ) + } +} diff --git a/contracts/init_msend/tests/test_init_msend.move b/contracts/init_msend/tests/test_init_msend.move new file mode 100644 index 0000000..1f443d1 --- /dev/null +++ b/contracts/init_msend/tests/test_init_msend.move @@ -0,0 +1,124 @@ +module init_msend::init_msend_test { + use mtoken::mtoken::{Self}; + use sui::coin; + use sui::clock; + use sui::sui::SUI; + use sui::test_scenario::{Self, ctx}; + use sui::test_utils::{destroy, assert_eq}; + use send::send::SEND; + use init_msend::init_msend::{mint_msend3, mint_msend6, mint_msend12}; + use msend_3_month::msend_3_month::MSEND_3_MONTH; + use msend_6_month::msend_6_month::MSEND_6_MONTH; + use msend_12_month::msend_12_month::MSEND_12_MONTH; + + #[test] + fun test_3msend() { + let owner = @0x10; + let mut scenario = test_scenario::begin(owner); + let mut clock = clock::create_for_testing(ctx(&mut scenario)); + clock.set_for_testing(1733508512000); + + let (admin_cap, mut manager, mtoken_coin) = mint_msend3( + coin::create_treasury_cap_for_testing(scenario.ctx()), + coin::mint_for_testing(100 * 10_u64.pow(6), scenario.ctx()), + ctx(&mut scenario), + ); + + let msend_coin = coin::mint_for_testing(100 * 10_u64.pow(6), ctx(&mut scenario)); + let mut sui_coin = coin::mint_for_testing(100 * 10_u64.pow(9), ctx(&mut scenario)); + + let send = mtoken::redeem_mtokens( + &mut manager, + msend_coin, + &mut sui_coin, + &clock, + ctx(&mut scenario), + ); + + assert_eq(send.value() / 10_u64.pow(6), 100); + assert_eq(sui_coin.value() / 10_u64.pow(9), 75); // 100 -25 + + destroy(send); + destroy(sui_coin); + destroy(clock); + destroy(mtoken_coin); + destroy(admin_cap); + destroy(manager); + + test_scenario::end(scenario); + } + + #[test] + fun test_6msend() { + let owner = @0x10; + let mut scenario = test_scenario::begin(owner); + let mut clock = clock::create_for_testing(ctx(&mut scenario)); + clock.set_for_testing(1733508512000); + + let (admin_cap, mut manager, mtoken_coin) = mint_msend6( + coin::create_treasury_cap_for_testing(scenario.ctx()), + coin::mint_for_testing(100 * 10_u64.pow(6), scenario.ctx()), + ctx(&mut scenario), + ); + + let msend_coin = coin::mint_for_testing(100 * 10_u64.pow(6), ctx(&mut scenario)); + let mut sui_coin = coin::mint_for_testing(100 * 10_u64.pow(9), ctx(&mut scenario)); + + let send = mtoken::redeem_mtokens( + &mut manager, + msend_coin, + &mut sui_coin, + &clock, + ctx(&mut scenario), + ); + + assert_eq(send.value() / 10_u64.pow(6), 100); + assert_eq(sui_coin.value() / 10_u64.pow(9), 50); // 100 - 50 + + destroy(send); + destroy(sui_coin); + destroy(clock); + destroy(mtoken_coin); + destroy(admin_cap); + destroy(manager); + + test_scenario::end(scenario); + } + + #[test] + fun test_12msend() { + let owner = @0x10; + let mut scenario = test_scenario::begin(owner); + let mut clock = clock::create_for_testing(ctx(&mut scenario)); + clock.set_for_testing(1733508512000); + + let (admin_cap, mut manager, mtoken_coin) = mint_msend12( + coin::create_treasury_cap_for_testing(scenario.ctx()), + coin::mint_for_testing(1000 * 10_u64.pow(6), scenario.ctx()), + ctx(&mut scenario), + ); + + let msend_coin = coin::mint_for_testing(1_000 * 10_u64.pow(6), ctx(&mut scenario)); + let mut sui_coin = coin::mint_for_testing(1_000 * 10_u64.pow(9), ctx(&mut scenario)); + + let send = mtoken::redeem_mtokens( + &mut manager, + msend_coin, + &mut sui_coin, + &clock, + ctx(&mut scenario), + ); + + assert_eq(send.value() / 10_u64.pow(6), 1_000); + assert_eq(sui_coin.value() / 10_u64.pow(9), 625); // 1000 - 375 + + destroy(send); + destroy(sui_coin); + destroy(clock); + destroy(mtoken_coin); + destroy(admin_cap); + destroy(manager); + + test_scenario::end(scenario); + } +} diff --git a/contracts/msend_coins/msend_12_month/Move.toml b/contracts/msend_coins/msend_12_month/Move.toml new file mode 100644 index 0000000..225d3bc --- /dev/null +++ b/contracts/msend_coins/msend_12_month/Move.toml @@ -0,0 +1,14 @@ +[package] +name = "msend_12_month" +version = "0.0.1" +edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move + +[dependencies.Sui] +git = "https://github.com/MystenLabs/sui.git" +subdir = "crates/sui-framework/packages/sui-framework" +rev = "framework/mainnet" + + +[addresses] +msend_12_month = "0x0" +sui = "0x2" diff --git a/contracts/msend_coins/msend_12_month/sources/msend_12_month.move b/contracts/msend_coins/msend_12_month/sources/msend_12_month.move new file mode 100644 index 0000000..a7b9c02 --- /dev/null +++ b/contracts/msend_coins/msend_12_month/sources/msend_12_month.move @@ -0,0 +1,29 @@ +module msend_12_month::msend_12_month { + use sui::{coin, url}; + use std::option::{some}; + + public struct MSEND_12_MONTH has drop {} + + const NAME: vector = b"mSEND Series 3"; + const SYMBOL: vector = b"mSEND"; + const DESCRIPTION: vector = b"mSEND(2024/12/12-2025/12/12) SUI 0.37->0"; + const DECIMALS: u8 = 6; + const LOGO_URL: vector = b"https://suilend-assets.s3.us-east-2.amazonaws.com/SEND/mSEND.svg"; + + fun init(otw: MSEND_12_MONTH, ctx: &mut TxContext) { + let logo_url = url::new_unsafe_from_bytes(LOGO_URL); + + let (treasury_cap, metadata) = coin::create_currency( + otw, + DECIMALS, + SYMBOL, + NAME, + DESCRIPTION, + some(logo_url), + ctx, + ); + + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); + transfer::public_share_object(metadata); + } +} \ No newline at end of file diff --git a/contracts/msend_coins/msend_3_month/Move.toml b/contracts/msend_coins/msend_3_month/Move.toml new file mode 100644 index 0000000..09018a3 --- /dev/null +++ b/contracts/msend_coins/msend_3_month/Move.toml @@ -0,0 +1,14 @@ +[package] +name = "msend_3_month" +version = "0.0.1" +edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move + +[dependencies.Sui] +git = "https://github.com/MystenLabs/sui.git" +subdir = "crates/sui-framework/packages/sui-framework" +rev = "framework/mainnet" + + +[addresses] +msend_3_month = "0x0" +sui = "0x2" diff --git a/contracts/msend_coins/msend_3_month/sources/msend_3_month.move b/contracts/msend_coins/msend_3_month/sources/msend_3_month.move new file mode 100644 index 0000000..9b5792c --- /dev/null +++ b/contracts/msend_coins/msend_3_month/sources/msend_3_month.move @@ -0,0 +1,29 @@ +module msend_3_month::msend_3_month { + use sui::{coin, url}; + use std::option::{some}; + + public struct MSEND_3_MONTH has drop {} + + const NAME: vector = b"mSEND Series 1"; + const SYMBOL: vector = b"mSEND"; + const DESCRIPTION: vector = b"mSEND(2024/12/12-2025/03/12) SUI 0.25->0"; + const DECIMALS: u8 = 6; + const LOGO_URL: vector = b"https://suilend-assets.s3.us-east-2.amazonaws.com/SEND/mSEND.svg"; + + fun init(otw: MSEND_3_MONTH, ctx: &mut TxContext) { + let logo_url = url::new_unsafe_from_bytes(LOGO_URL); + + let (treasury_cap, metadata) = coin::create_currency( + otw, + DECIMALS, + SYMBOL, + NAME, + DESCRIPTION, + some(logo_url), + ctx, + ); + + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); + transfer::public_share_object(metadata); + } +} \ No newline at end of file diff --git a/contracts/msend_coins/msend_6_month/Move.toml b/contracts/msend_coins/msend_6_month/Move.toml new file mode 100644 index 0000000..92f67cf --- /dev/null +++ b/contracts/msend_coins/msend_6_month/Move.toml @@ -0,0 +1,14 @@ +[package] +name = "msend_6_month" +version = "0.0.1" +edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move + +[dependencies.Sui] +git = "https://github.com/MystenLabs/sui.git" +subdir = "crates/sui-framework/packages/sui-framework" +rev = "framework/mainnet" + + +[addresses] +msend_6_month = "0x0" +sui = "0x2" diff --git a/contracts/msend_coins/msend_6_month/sources/msend_6_month.move b/contracts/msend_coins/msend_6_month/sources/msend_6_month.move new file mode 100644 index 0000000..ccdfc8f --- /dev/null +++ b/contracts/msend_coins/msend_6_month/sources/msend_6_month.move @@ -0,0 +1,29 @@ +module msend_6_month::msend_6_month { + use sui::{coin, url}; + use std::option::{some}; + + public struct MSEND_6_MONTH has drop {} + + const NAME: vector = b"mSEND Series 2"; + const SYMBOL: vector = b"mSEND"; + const DESCRIPTION: vector = b"mSEND(2024/12/12-2025/06/12) SUI 0.5->0"; + const DECIMALS: u8 = 6; + const LOGO_URL: vector = b"https://suilend-assets.s3.us-east-2.amazonaws.com/SEND/mSEND.svg"; + + fun init(otw: MSEND_6_MONTH, ctx: &mut TxContext) { + let logo_url = url::new_unsafe_from_bytes(LOGO_URL); + + let (treasury_cap, metadata) = coin::create_currency( + otw, + DECIMALS, + SYMBOL, + NAME, + DESCRIPTION, + some(logo_url), + ctx, + ); + + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); + transfer::public_share_object(metadata); + } +} \ No newline at end of file diff --git a/contract/Move.toml b/contracts/mtoken/Move.toml similarity index 97% rename from contract/Move.toml rename to contracts/mtoken/Move.toml index 198fd66..1030ff0 100644 --- a/contract/Move.toml +++ b/contracts/mtoken/Move.toml @@ -6,7 +6,7 @@ edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move [dependencies] Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/mainnet", override = true } -suilend = { git = "https://github.com/solendprotocol/suilend.git", subdir = "contracts/suilend", rev = "devel"} +suilend = { git = "https://github.com/solendprotocol/suilend.git", subdir = "contracts/suilend", rev = "mainnet"} # For remote import, use the `{ git = "...", subdir = "...", rev = "..." }`. # Revision can be a branch, a tag, and a commit hash. diff --git a/contract/sources/mtoken.move b/contracts/mtoken/sources/mtoken.move similarity index 100% rename from contract/sources/mtoken.move rename to contracts/mtoken/sources/mtoken.move diff --git a/contract/tests/mtoken_tests.move b/contracts/mtoken/tests/mtoken_tests.move similarity index 100% rename from contract/tests/mtoken_tests.move rename to contracts/mtoken/tests/mtoken_tests.move diff --git a/contract/tests/test_coins.move b/contracts/mtoken/tests/test_coins.move similarity index 100% rename from contract/tests/test_coins.move rename to contracts/mtoken/tests/test_coins.move From 7d505bce42f9fca13621f66cd342b38a1df24c11 Mon Sep 17 00:00:00 2001 From: 0xxgen1 <0xxgen@solend.fi> Date: Fri, 6 Dec 2024 22:56:19 +0000 Subject: [PATCH 2/3] flash loan tests --- contracts/dependencies/cetus/Move.toml | 40 + contracts/dependencies/cetus/sources/acl.move | 80 ++ .../dependencies/cetus/sources/clmm_math.move | 233 ++++ .../dependencies/cetus/sources/config.move | 287 +++++ .../dependencies/cetus/sources/factory.move | 239 ++++ .../dependencies/cetus/sources/partner.move | 216 ++++ .../dependencies/cetus/sources/pool.move | 1131 +++++++++++++++++ .../dependencies/cetus/sources/position.move | 455 +++++++ .../dependencies/cetus/sources/rewarder.move | 217 ++++ .../dependencies/cetus/sources/tick.move | 388 ++++++ .../dependencies/cetus/sources/tick_math.move | 269 ++++ .../dependencies/cetus/sources/utils.move | 18 + contracts/dependencies/integer-mate/Move.toml | 38 + .../integer-mate/sources/full_math_u128.move | 30 + .../integer-mate/sources/full_math_u64.move | 30 + .../integer-mate/sources/i128.move | 524 ++++++++ .../integer-mate/sources/i32.move | 498 ++++++++ .../integer-mate/sources/i64.move | 489 +++++++ .../integer-mate/sources/math_u128.move | 173 +++ .../integer-mate/sources/math_u256.move | 49 + .../integer-mate/sources/math_u64.move | 57 + contracts/dependencies/move-stl/Move.toml | 39 + .../move-stl/sources/linked_table.move | 193 +++ .../move-stl/sources/option_u128.move | 61 + .../move-stl/sources/option_u64.move | 54 + .../dependencies/move-stl/sources/random.move | 32 + .../move-stl/sources/skip_list.move | 278 ++++ .../move-stl/sources/skip_list_u128.move | 278 ++++ contracts/init_msend/Move.toml | 1 + contracts/init_msend/tests/msend_test.move | 236 ++++ 30 files changed, 6633 insertions(+) create mode 100644 contracts/dependencies/cetus/Move.toml create mode 100644 contracts/dependencies/cetus/sources/acl.move create mode 100644 contracts/dependencies/cetus/sources/clmm_math.move create mode 100644 contracts/dependencies/cetus/sources/config.move create mode 100644 contracts/dependencies/cetus/sources/factory.move create mode 100644 contracts/dependencies/cetus/sources/partner.move create mode 100644 contracts/dependencies/cetus/sources/pool.move create mode 100644 contracts/dependencies/cetus/sources/position.move create mode 100644 contracts/dependencies/cetus/sources/rewarder.move create mode 100644 contracts/dependencies/cetus/sources/tick.move create mode 100644 contracts/dependencies/cetus/sources/tick_math.move create mode 100644 contracts/dependencies/cetus/sources/utils.move create mode 100644 contracts/dependencies/integer-mate/Move.toml create mode 100644 contracts/dependencies/integer-mate/sources/full_math_u128.move create mode 100644 contracts/dependencies/integer-mate/sources/full_math_u64.move create mode 100644 contracts/dependencies/integer-mate/sources/i128.move create mode 100644 contracts/dependencies/integer-mate/sources/i32.move create mode 100644 contracts/dependencies/integer-mate/sources/i64.move create mode 100644 contracts/dependencies/integer-mate/sources/math_u128.move create mode 100644 contracts/dependencies/integer-mate/sources/math_u256.move create mode 100644 contracts/dependencies/integer-mate/sources/math_u64.move create mode 100644 contracts/dependencies/move-stl/Move.toml create mode 100644 contracts/dependencies/move-stl/sources/linked_table.move create mode 100644 contracts/dependencies/move-stl/sources/option_u128.move create mode 100644 contracts/dependencies/move-stl/sources/option_u64.move create mode 100644 contracts/dependencies/move-stl/sources/random.move create mode 100644 contracts/dependencies/move-stl/sources/skip_list.move create mode 100644 contracts/dependencies/move-stl/sources/skip_list_u128.move create mode 100644 contracts/init_msend/tests/msend_test.move diff --git a/contracts/dependencies/cetus/Move.toml b/contracts/dependencies/cetus/Move.toml new file mode 100644 index 0000000..f9efbc0 --- /dev/null +++ b/contracts/dependencies/cetus/Move.toml @@ -0,0 +1,40 @@ +[package] +name = "CetusClmm" +edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move +published-at= "0x70968826ad1b4ba895753f634b0aea68d0672908ca1075a2abdf0fc9e0b2fc6a" +# 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/mainnet" } +MoveStl = { local = "../move-stl" } +IntegerMate = { local = "../integer-mate" } + +# 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 } + +[addresses] +cetus_clmm = "0x1eabed72c53feb3805120a081dc15963c204dc8d091542592abaf7a35689b2fb" + +# 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] +# The dev-addresses section allows overwriting named addresses for the `--test` +# and `--dev` modes. +# alice = "0xB0B" + diff --git a/contracts/dependencies/cetus/sources/acl.move b/contracts/dependencies/cetus/sources/acl.move new file mode 100644 index 0000000..9628534 --- /dev/null +++ b/contracts/dependencies/cetus/sources/acl.move @@ -0,0 +1,80 @@ +module cetus_clmm::acl { + use move_stl::linked_table::{LinkedTable}; + + public struct ACL has store { + permissions: LinkedTable, + } + + public struct Member has copy, drop, store { + address: address, + permission: u128, + } + + public fun new(arg0: &mut TxContext) : ACL { + ACL{permissions: move_stl::linked_table::new(arg0)} + } + + public fun add_role(arg0: &mut ACL, arg1: address, arg2: u8) { + assert!(arg2 < 128, 0); + if (move_stl::linked_table::contains(&arg0.permissions, arg1)) { + let v0 = move_stl::linked_table::borrow_mut(&mut arg0.permissions, arg1); + *v0 = *v0 | 1 << arg2; + } else { + move_stl::linked_table::push_back(&mut arg0.permissions, arg1, 1 << arg2); + }; + } + + public fun get_members(arg0: &ACL) : vector { + let mut v0 = std::vector::empty(); + let mut v1 = move_stl::linked_table::head(&arg0.permissions); + while (std::option::is_some
(&v1)) { + let v2 = *std::option::borrow
(&v1); + let v3 = move_stl::linked_table::borrow_node(&arg0.permissions, v2); + let v4 = Member{ + address : v2, + permission : *move_stl::linked_table::borrow_value(v3), + }; + std::vector::push_back(&mut v0, v4); + v1 = move_stl::linked_table::next(v3); + }; + v0 + } + + public fun get_permission(arg0: &ACL, arg1: address) : u128 { + if (!move_stl::linked_table::contains(&arg0.permissions, arg1)) { + 0 + } else { + *move_stl::linked_table::borrow(&arg0.permissions, arg1) + } + } + + public fun has_role(arg0: &ACL, arg1: address, arg2: u8) : bool { + assert!(arg2 < 128, 0); + move_stl::linked_table::contains(&arg0.permissions, arg1) && *move_stl::linked_table::borrow(&arg0.permissions, arg1) & 1 << arg2 > 0 + } + + public fun remove_member(arg0: &mut ACL, arg1: address) { + if (move_stl::linked_table::contains(&arg0.permissions, arg1)) { + move_stl::linked_table::remove(&mut arg0.permissions, arg1); + }; + } + + public fun remove_role(arg0: &mut ACL, arg1: address, arg2: u8) { + assert!(arg2 < 128, 0); + if (move_stl::linked_table::contains(&arg0.permissions, arg1)) { + let v0 = move_stl::linked_table::borrow_mut(&mut arg0.permissions, arg1); + *v0 = *v0 - (1 << arg2); + }; + } + + public fun set_roles(arg0: &mut ACL, arg1: address, arg2: u128) { + if (move_stl::linked_table::contains(&arg0.permissions, arg1)) { + *move_stl::linked_table::borrow_mut(&mut arg0.permissions, arg1) = arg2; + } else { + move_stl::linked_table::push_back(&mut arg0.permissions, arg1, arg2); + }; + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/cetus/sources/clmm_math.move b/contracts/dependencies/cetus/sources/clmm_math.move new file mode 100644 index 0000000..b3ee3cf --- /dev/null +++ b/contracts/dependencies/cetus/sources/clmm_math.move @@ -0,0 +1,233 @@ +module cetus_clmm::clmm_math { + use integer_mate::i32::{I32}; + + public fun compute_swap_step(arg0: u128, arg1: u128, arg2: u128, arg3: u64, arg4: u64, arg5: bool, arg6: bool) : (u64, u64, u128, u64) { + if (arg2 == 0) { + return (0, 0, arg1, 0) + }; + if (arg5) { + assert!(arg0 >= arg1, 4); + } else { + assert!(arg0 < arg1, 4); + }; + let (v0, v1, v2, v3) = if (arg6) { + let v4 = integer_mate::full_math_u64::mul_div_floor(arg3, 1000000 - arg4, 1000000); + let v5 = get_delta_up_from_input(arg0, arg1, arg2, arg5); + let (v0, v2, v3) = if (v5 > (v4 as u256)) { + (v4, arg3 - v4, get_next_sqrt_price_from_input(arg0, arg2, v4, arg5)) + } else { + let v6 = (v5 as u64); + (v6, integer_mate::full_math_u64::mul_div_ceil(v6, arg4, 1000000 - arg4), arg1) + }; + (v0, (get_delta_down_from_output(arg0, v3, arg2, arg5) as u64), v2, v3) + } else { + let v7 = get_delta_down_from_output(arg0, arg1, arg2, arg5); + let (v1, v3) = if (v7 > (arg3 as u256)) { + (arg3, get_next_sqrt_price_from_output(arg0, arg2, arg3, arg5)) + } else { + ((v7 as u64), arg1) + }; + let v8 = (get_delta_up_from_input(arg0, v3, arg2, arg5) as u64); + (v8, v1, integer_mate::full_math_u64::mul_div_ceil(v8, arg4, 1000000 - arg4), v3) + }; + (v0, v1, v3, v2) + } + + public fun fee_rate_denominator() : u64 { + 1000000 + } + + public fun get_amount_by_liquidity(arg0: I32, arg1: I32, arg2: I32, arg3: u128, arg4: u128, arg5: bool) : (u64, u64) { + if (arg4 == 0) { + return (0, 0) + }; + if (integer_mate::i32::lt(arg2, arg0)) { + (get_delta_a(cetus_clmm::tick_math::get_sqrt_price_at_tick(arg0), cetus_clmm::tick_math::get_sqrt_price_at_tick(arg1), arg4, arg5), 0) + } else { + let (v2, v3) = if (integer_mate::i32::lt(arg2, arg1)) { + (get_delta_a(arg3, cetus_clmm::tick_math::get_sqrt_price_at_tick(arg1), arg4, arg5), get_delta_b(cetus_clmm::tick_math::get_sqrt_price_at_tick(arg0), arg3, arg4, arg5)) + } else { + (0, get_delta_b(cetus_clmm::tick_math::get_sqrt_price_at_tick(arg0), cetus_clmm::tick_math::get_sqrt_price_at_tick(arg1), arg4, arg5)) + }; + (v2, v3) + } + } + + public fun get_delta_a(arg0: u128, arg1: u128, arg2: u128, arg3: bool) : u64 { + let v0 = if (arg0 > arg1) { + arg0 - arg1 + } else { + arg1 - arg0 + }; + if (v0 == 0 || arg2 == 0) { + return 0 + }; + let (v1, v2) = integer_mate::math_u256::checked_shlw(integer_mate::full_math_u128::full_mul(arg2, v0)); + if (v2) { + abort 2 + }; + (integer_mate::math_u256::div_round(v1, integer_mate::full_math_u128::full_mul(arg0, arg1), arg3) as u64) + } + + public fun get_delta_b(arg0: u128, arg1: u128, arg2: u128, arg3: bool) : u64 { + let v0 = if (arg0 > arg1) { + arg0 - arg1 + } else { + arg1 - arg0 + }; + if (v0 == 0 || arg2 == 0) { + return 0 + }; + let v1 = integer_mate::full_math_u128::full_mul(arg2, v0); + if (arg3 && v1 & 18446744073709551615 > 0) { + return (((v1 >> 64) + 1) as u64) + }; + ((v1 >> 64) as u64) + } + + public fun get_delta_down_from_output(arg0: u128, arg1: u128, arg2: u128, arg3: bool) : u256 { + let v0 = if (arg0 > arg1) { + arg0 - arg1 + } else { + arg1 - arg0 + }; + if (v0 == 0 || arg2 == 0) { + return 0 + }; + if (arg3) { + integer_mate::full_math_u128::full_mul(arg2, v0) >> 64 + } else { + let (v2, v3) = integer_mate::math_u256::checked_shlw(integer_mate::full_math_u128::full_mul(arg2, v0)); + if (v3) { + abort 2 + }; + integer_mate::math_u256::div_round(v2, integer_mate::full_math_u128::full_mul(arg0, arg1), false) + } + } + + public fun get_delta_up_from_input(arg0: u128, arg1: u128, arg2: u128, arg3: bool) : u256 { + let v0 = if (arg0 > arg1) { + arg0 - arg1 + } else { + arg1 - arg0 + }; + if (v0 == 0 || arg2 == 0) { + return 0 + }; + if (arg3) { + let (v2, v3) = integer_mate::math_u256::checked_shlw(integer_mate::full_math_u128::full_mul(arg2, v0)); + if (v3) { + abort 2 + }; + integer_mate::math_u256::div_round(v2, integer_mate::full_math_u128::full_mul(arg0, arg1), true) + } else { + let v4 = integer_mate::full_math_u128::full_mul(arg2, v0); + if (v4 & 18446744073709551615 > 0) { + return (v4 >> 64) + 1 + }; + v4 >> 64 + } + } + + public fun get_liquidity_by_amount(tick_lower: I32, tick_upper: I32, current_tick_index: I32, current_sqrt_price: u128, amount: u64, from_a: bool) : (u128, u64, u64) { + let mut amount_a = 0; + let mut amount_b = 0; + let liquidity_delta = if (from_a) { + amount_a = amount; + if (integer_mate::i32::lt(current_tick_index, tick_lower)) { + get_liquidity_from_a(cetus_clmm::tick_math::get_sqrt_price_at_tick(tick_lower), cetus_clmm::tick_math::get_sqrt_price_at_tick(tick_upper), amount, false) + } else { + assert!(integer_mate::i32::lt(current_tick_index, tick_upper), 3018); + let liquidity_delta = get_liquidity_from_a(current_sqrt_price, cetus_clmm::tick_math::get_sqrt_price_at_tick(tick_upper), amount, false); + amount_b = get_delta_b(current_sqrt_price, cetus_clmm::tick_math::get_sqrt_price_at_tick(tick_lower), liquidity_delta, true); + liquidity_delta + } + } else { + amount_b = amount; + if (integer_mate::i32::gte(current_tick_index, tick_upper)) { + get_liquidity_from_b(cetus_clmm::tick_math::get_sqrt_price_at_tick(tick_lower), cetus_clmm::tick_math::get_sqrt_price_at_tick(tick_upper), amount, false) + } else { + assert!(integer_mate::i32::gte(current_tick_index, tick_lower), 3018); + let liquidity_delta = get_liquidity_from_b(cetus_clmm::tick_math::get_sqrt_price_at_tick(tick_lower), current_sqrt_price, amount, false); + amount_a = get_delta_a(current_sqrt_price, cetus_clmm::tick_math::get_sqrt_price_at_tick(tick_upper), liquidity_delta, true); + liquidity_delta + } + }; + (liquidity_delta, amount_a, amount_b) + // (v2, v0, v1) + } + + public fun get_liquidity_from_a(arg0: u128, arg1: u128, arg2: u64, arg3: bool) : u128 { + let v0 = if (arg0 > arg1) { + arg0 - arg1 + } else { + arg1 - arg0 + }; + (integer_mate::math_u256::div_round((integer_mate::full_math_u128::full_mul(arg0, arg1) >> 64) * (arg2 as u256), (v0 as u256), arg3) as u128) + } + + public fun get_liquidity_from_b(arg0: u128, arg1: u128, arg2: u64, arg3: bool) : u128 { + let v0 = if (arg0 > arg1) { + arg0 - arg1 + } else { + arg1 - arg0 + }; + (integer_mate::math_u256::div_round((arg2 as u256) << 64, (v0 as u256), arg3) as u128) + } + + public fun get_next_sqrt_price_a_up(arg0: u128, arg1: u128, arg2: u64, arg3: bool) : u128 { + if (arg2 == 0) { + return arg0 + }; + let (v0, v1) = integer_mate::math_u256::checked_shlw(integer_mate::full_math_u128::full_mul(arg0, arg1)); + if (v1) { + abort 2 + }; + let v2 = if (arg3) { + (integer_mate::math_u256::div_round(v0, ((arg1 as u256) << 64) + integer_mate::full_math_u128::full_mul(arg0, (arg2 as u128)), true) as u128) + } else { + (integer_mate::math_u256::div_round(v0, ((arg1 as u256) << 64) - integer_mate::full_math_u128::full_mul(arg0, (arg2 as u128)), true) as u128) + }; + if (v2 > cetus_clmm::tick_math::max_sqrt_price()) { + abort 0 + }; + if (v2 < cetus_clmm::tick_math::min_sqrt_price()) { + abort 1 + }; + v2 + } + + public fun get_next_sqrt_price_b_down(arg0: u128, arg1: u128, arg2: u64, arg3: bool) : u128 { + let v0 = if (arg3) { + arg0 + integer_mate::math_u128::checked_div_round((arg2 as u128) << 64, arg1, !arg3) + } else { + arg0 - integer_mate::math_u128::checked_div_round((arg2 as u128) << 64, arg1, !arg3) + }; + if (v0 > cetus_clmm::tick_math::max_sqrt_price()) { + abort 0 + }; + if (v0 < cetus_clmm::tick_math::min_sqrt_price()) { + abort 1 + }; + v0 + } + + public fun get_next_sqrt_price_from_input(arg0: u128, arg1: u128, arg2: u64, arg3: bool) : u128 { + if (arg3) { + get_next_sqrt_price_a_up(arg0, arg1, arg2, true) + } else { + get_next_sqrt_price_b_down(arg0, arg1, arg2, true) + } + } + + public fun get_next_sqrt_price_from_output(arg0: u128, arg1: u128, arg2: u64, arg3: bool) : u128 { + if (arg3) { + get_next_sqrt_price_b_down(arg0, arg1, arg2, false) + } else { + get_next_sqrt_price_a_up(arg0, arg1, arg2, false) + } + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/cetus/sources/config.move b/contracts/dependencies/cetus/sources/config.move new file mode 100644 index 0000000..0f00e5d --- /dev/null +++ b/contracts/dependencies/cetus/sources/config.move @@ -0,0 +1,287 @@ +module cetus_clmm::config { + use sui::event; + use sui::transfer::{transfer, share_object}; + use sui::tx_context::{sender}; + use sui::vec_map::{VecMap}; + + public struct AdminCap has store, key { + id: UID, + } + + public struct ProtocolFeeClaimCap has store, key { + id: UID, + } + + public struct FeeTier has copy, drop, store { + tick_spacing: u32, + fee_rate: u64, + } + + public struct GlobalConfig has store, key { + id: UID, + protocol_fee_rate: u64, + fee_tiers: VecMap, + acl: cetus_clmm::acl::ACL, + package_version: u64, + } + + public struct InitConfigEvent has copy, drop { + admin_cap_id: ID, + global_config_id: ID, + } + + public struct UpdateFeeRateEvent has copy, drop { + old_fee_rate: u64, + new_fee_rate: u64, + } + + public struct AddFeeTierEvent has copy, drop { + tick_spacing: u32, + fee_rate: u64, + } + + public struct UpdateFeeTierEvent has copy, drop { + tick_spacing: u32, + old_fee_rate: u64, + new_fee_rate: u64, + } + + public struct DeleteFeeTierEvent has copy, drop { + tick_spacing: u32, + fee_rate: u64, + } + + public struct SetRolesEvent has copy, drop { + member: address, + roles: u128, + } + + public struct AddRoleEvent has copy, drop { + member: address, + role: u8, + } + + public struct RemoveRoleEvent has copy, drop { + member: address, + role: u8, + } + + public struct RemoveMemberEvent has copy, drop { + member: address, + } + + public struct SetPackageVersion has copy, drop { + new_version: u64, + old_version: u64, + } + + public fun acl(arg0: &GlobalConfig) : &cetus_clmm::acl::ACL { + &arg0.acl + } + + public fun add_role(_arg0: &AdminCap, arg1: &mut GlobalConfig, arg2: address, arg3: u8) { + checked_package_version(arg1); + cetus_clmm::acl::add_role(&mut arg1.acl, arg2, arg3); + let v0 = AddRoleEvent{ + member : arg2, + role : arg3, + }; + event::emit(v0); + } + + public fun get_members(arg0: &GlobalConfig) : vector { + cetus_clmm::acl::get_members(&arg0.acl) + } + + public fun remove_member(_arg0: &AdminCap, arg1: &mut GlobalConfig, arg2: address) { + checked_package_version(arg1); + cetus_clmm::acl::remove_member(&mut arg1.acl, arg2); + let v0 = RemoveMemberEvent{member: arg2}; + event::emit(v0); + } + + public fun remove_role(_arg0: &AdminCap, arg1: &mut GlobalConfig, arg2: address, arg3: u8) { + checked_package_version(arg1); + cetus_clmm::acl::remove_role(&mut arg1.acl, arg2, arg3); + let v0 = RemoveRoleEvent{ + member : arg2, + role : arg3, + }; + event::emit(v0); + } + + public fun set_roles(_arg0: &AdminCap, arg1: &mut GlobalConfig, arg2: address, arg3: u128) { + checked_package_version(arg1); + cetus_clmm::acl::set_roles(&mut arg1.acl, arg2, arg3); + let v0 = SetRolesEvent{ + member : arg2, + roles : arg3, + }; + event::emit(v0); + } + + public fun add_fee_tier(arg0: &mut GlobalConfig, tick_spacing: u32, fee_rate: u64, arg3: &TxContext) { + assert!(fee_rate <= 200000, 3); + assert!(!sui::vec_map::contains(&arg0.fee_tiers, &tick_spacing), 1); + checked_package_version(arg0); + check_fee_tier_manager_role(arg0, sender(arg3)); + let v0 = FeeTier { + tick_spacing : tick_spacing, + fee_rate : fee_rate, + }; + sui::vec_map::insert(&mut arg0.fee_tiers, tick_spacing, v0); + let v1 = AddFeeTierEvent{ + tick_spacing : tick_spacing, + fee_rate : fee_rate, + }; + event::emit(v1); + } + + public fun check_fee_tier_manager_role(arg0: &GlobalConfig, arg1: address) { + assert!(cetus_clmm::acl::has_role(&arg0.acl, arg1, 1), 6); + } + + public fun check_partner_manager_role(arg0: &GlobalConfig, arg1: address) { + assert!(cetus_clmm::acl::has_role(&arg0.acl, arg1, 3), 7); + } + + public fun check_pool_manager_role(arg0: &GlobalConfig, arg1: address) { + assert!(cetus_clmm::acl::has_role(&arg0.acl, arg1, 0), 5); + } + + public fun check_protocol_fee_claim_role(arg0: &GlobalConfig, arg1: address) { + assert!(cetus_clmm::acl::has_role(&arg0.acl, arg1, 2), 9); + } + + public fun check_rewarder_manager_role(arg0: &GlobalConfig, arg1: address) { + assert!(cetus_clmm::acl::has_role(&arg0.acl, arg1, 4), 8); + } + + public fun checked_package_version(arg0: &GlobalConfig) { + assert!(arg0.package_version == 1, 10); + } + + public fun delete_fee_tier(arg0: &mut GlobalConfig, arg1: u32, arg2: &TxContext) { + assert!(sui::vec_map::contains(&arg0.fee_tiers, &arg1), 2); + checked_package_version(arg0); + check_fee_tier_manager_role(arg0, sender(arg2)); + let (_, v1) = sui::vec_map::remove(&mut arg0.fee_tiers, &arg1); + let v2 = v1; + let v3 = DeleteFeeTierEvent{ + tick_spacing : arg1, + fee_rate : v2.fee_rate, + }; + event::emit(v3); + } + + public fun fee_rate(arg0: &FeeTier) : u64 { + arg0.fee_rate + } + + public fun fee_tiers(arg0: &GlobalConfig) : &VecMap { + &arg0.fee_tiers + } + + public fun get_fee_rate(tick_spacing: u32, arg1: &GlobalConfig) : u64 { + assert!(sui::vec_map::contains(&arg1.fee_tiers, &tick_spacing), 2); + sui::vec_map::get(&arg1.fee_tiers, &tick_spacing).fee_rate + } + + public fun get_protocol_fee_rate(arg0: &GlobalConfig) : u64 { + arg0.protocol_fee_rate + } + + fun init(arg0: &mut TxContext) { + let v0 = GlobalConfig { + id : sui::object::new(arg0), + protocol_fee_rate : 2000, + fee_tiers : sui::vec_map::empty(), + acl : cetus_clmm::acl::new(arg0), + package_version : 1, + }; + let v1 = AdminCap { id: sui::object::new(arg0) }; + let admin_cap_id = v1.id.to_inner(); + let mut v2 = v0; + let global_config_id = v2.id.to_inner(); + let v3 = sender(arg0); + set_roles(&v1, &mut v2, v3, 0 | 1 << 0 | 1 << 1 | 1 << 4 | 1 << 3); + transfer(v1, v3); + share_object(v2); + let v4 = InitConfigEvent{ + admin_cap_id, + global_config_id, + }; + event::emit(v4); + } + + public fun max_fee_rate() : u64 { + 200000 + } + + public fun max_protocol_fee_rate() : u64 { + 3000 + } + + public fun protocol_fee_rate(arg0: &GlobalConfig) : u64 { + arg0.protocol_fee_rate + } + + public fun tick_spacing(arg0: &FeeTier) : u32 { + arg0.tick_spacing + } + + public fun update_fee_tier(arg0: &mut GlobalConfig, arg1: u32, arg2: u64, arg3: &TxContext) { + assert!(sui::vec_map::contains(&arg0.fee_tiers, &arg1), 2); + assert!(arg2 <= 200000, 3); + checked_package_version(arg0); + check_fee_tier_manager_role(arg0, sender(arg3)); + let v0 = sui::vec_map::get_mut(&mut arg0.fee_tiers, &arg1); + v0.fee_rate = arg2; + let v1 = UpdateFeeTierEvent{ + tick_spacing : arg1, + old_fee_rate : v0.fee_rate, + new_fee_rate : arg2, + }; + event::emit(v1); + } + + public fun update_package_version(_arg0: &AdminCap, arg1: &mut GlobalConfig, arg2: u64) { + arg1.package_version = arg2; + let v0 = SetPackageVersion{ + new_version : arg2, + old_version : arg1.package_version, + }; + event::emit(v0); + } + + public fun update_protocol_fee_rate(arg0: &mut GlobalConfig, arg1: u64, arg2: &TxContext) { + assert!(arg1 <= 3000, 4); + checked_package_version(arg0); + check_pool_manager_role(arg0, sender(arg2)); + arg0.protocol_fee_rate = arg1; + let v0 = UpdateFeeRateEvent{ + old_fee_rate : arg0.protocol_fee_rate, + new_fee_rate : arg1, + }; + event::emit(v0); + } + + // decompiled from Move bytecode v6 + + #[test_only] + public fun init_for_testing(arg0: &mut TxContext): (GlobalConfig, AdminCap) { + let v0 = GlobalConfig { + id : sui::object::new(arg0), + protocol_fee_rate : 2000, + fee_tiers : sui::vec_map::empty(), + acl : cetus_clmm::acl::new(arg0), + package_version : 1, + }; + let v1 = AdminCap { id: sui::object::new(arg0) }; + let mut v2 = v0; + let v3 = sender(arg0); + set_roles(&v1, &mut v2, v3, 0 | 1 << 0 | 1 << 1 | 1 << 4 | 1 << 3); + (v2, v1) + } +} + diff --git a/contracts/dependencies/cetus/sources/factory.move b/contracts/dependencies/cetus/sources/factory.move new file mode 100644 index 0000000..f9c4844 --- /dev/null +++ b/contracts/dependencies/cetus/sources/factory.move @@ -0,0 +1,239 @@ +#[allow(lint(share_owned))] +module cetus_clmm::factory { + use std::type_name::{TypeName}; + use sui::event; + use sui::clock::{Clock}; + use sui::transfer::{share_object}; + use move_stl::linked_table::LinkedTable; + + public struct PoolSimpleInfo has copy, drop, store { + pool_id: ID, + pool_key: ID, + coin_type_a: TypeName, + coin_type_b: TypeName, + tick_spacing: u32, + } + + public struct Pools has store, key { + id: UID, + list: LinkedTable, + index: u64, + } + + public struct InitFactoryEvent has copy, drop { + pools_id: ID, + } + + public struct CreatePoolEvent has copy, drop { + pool_id: ID, + coin_type_a: std::string::String, + coin_type_b: std::string::String, + tick_spacing: u32, + } + + public fun coin_types(arg0: &PoolSimpleInfo) : (TypeName, TypeName) { + (arg0.coin_type_a, arg0.coin_type_b) + } + + public fun create_pool(arg0: &mut Pools, arg1: &cetus_clmm::config::GlobalConfig, arg2: u32, arg3: u128, arg4: std::string::String, arg5: &Clock, arg6: &mut TxContext) { + cetus_clmm::config::checked_package_version(arg1); + sui::transfer::public_share_object>(create_pool_internal(arg0, arg1, arg2, arg3, arg4, arg5, arg6)); + } + + fun create_pool_internal(pools: &mut Pools, global_config: &cetus_clmm::config::GlobalConfig, tick_spacing: u32, current_sqrt_price: u128, url: std::string::String, clock: &Clock, ctx: &mut TxContext) : cetus_clmm::pool::Pool { + assert!(current_sqrt_price >= cetus_clmm::tick_math::min_sqrt_price() && current_sqrt_price <= cetus_clmm::tick_math::max_sqrt_price(), 2); + + let coin_type_a = std::type_name::get(); + let coin_type_b = std::type_name::get(); + assert!(coin_type_a != coin_type_b, 3); + + let pool_key = new_pool_key(tick_spacing); + if (move_stl::linked_table::contains(&pools.list, pool_key)) { + abort 1 + }; + let url = if (std::string::length(&url) == 0) { + std::string::utf8(b"https://bq7bkvdje7gvgmv66hrxdy7wx5h5ggtrrnmt66rdkkehb64rvz3q.arweave.net/DD4VVGknzVMyvvHjceP2coin_type_a_TGnGLWT96I1KIcPuRrnc") + } else { + url + }; + + let pool = cetus_clmm::pool::new(tick_spacing, current_sqrt_price, cetus_clmm::config::get_fee_rate(tick_spacing, global_config), url, pools.index, clock, ctx); + pools.index = pools.index + 1; + let pool_id = pool.pool_id(); + + let pool_info = PoolSimpleInfo { + pool_id, + pool_key, + coin_type_a, + coin_type_b, + tick_spacing, + }; + move_stl::linked_table::push_back(&mut pools.list, pool_key, pool_info); + + event::emit( + CreatePoolEvent{ + pool_id, + coin_type_a: std::string::from_ascii(std::type_name::into_string(coin_type_a)), + coin_type_b: std::string::from_ascii(std::type_name::into_string(coin_type_b)), + tick_spacing, + } + ); + + pool + } + + public fun create_pool_with_liquidity( + pools: &mut Pools, + config: &cetus_clmm::config::GlobalConfig, + tick_spacing: u32, + current_sqrt_price: u128, + url: std::string::String, + tick_lower: u32, + tick_upper: u32, + mut coin_a: sui::coin::Coin, + mut coin_b: sui::coin::Coin, + max_amount_a: u64, + max_amount_b: u64, + from_a: bool, + clock: &Clock, + ctx: &mut TxContext + ) : (cetus_clmm::position::Position, sui::coin::Coin, sui::coin::Coin) { + cetus_clmm::config::checked_package_version(config); + let mut pool = create_pool_internal( + pools, + config, + tick_spacing, + current_sqrt_price, + url, + clock, + ctx + ); + + let mut position = cetus_clmm::pool::open_position(config, &mut pool, tick_lower, tick_upper, ctx); + + let amount = if (from_a) { + max_amount_a + } else { + max_amount_b + }; + + let v3 = cetus_clmm::pool::add_liquidity_fix_coin( + config, + &mut pool, + &mut position, + amount, + from_a, + clock + ); + let (amount_a, amount_b) = cetus_clmm::pool::add_liquidity_pay_amount(&v3); + if (from_a) { + assert!(amount_b <= max_amount_b, 4); + } else { + assert!(amount_a <= max_amount_a, 5); + }; + + cetus_clmm::pool::repay_add_liquidity(config, &mut pool, sui::coin::into_balance(sui::coin::split(&mut coin_a, amount_a, ctx)), sui::coin::into_balance(sui::coin::split(&mut coin_b, amount_b, ctx)), v3); + sui::transfer::public_share_object>(pool); + (position, coin_a, coin_b) + } + + public fun fetch_pools(arg0: &Pools, arg1: vector, arg2: u64) : vector { + let mut v0 = std::vector::empty(); + let v1 = if (std::vector::is_empty(&arg1)) { + move_stl::linked_table::head(&arg0.list) + } else { + move_stl::linked_table::next(move_stl::linked_table::borrow_node(&arg0.list, *std::vector::borrow(&arg1, 0))) + }; + let mut v2 = v1; + let mut v3 = 0; + while (std::option::is_some(&v2) && v3 < arg2) { + let v4 = move_stl::linked_table::borrow_node(&arg0.list, *std::option::borrow(&v2)); + v2 = move_stl::linked_table::next(v4); + std::vector::push_back(&mut v0, *move_stl::linked_table::borrow_value(v4)); + v3 = v3 + 1; + }; + v0 + } + + public fun index(arg0: &Pools) : u64 { + arg0.index + } + + fun init(arg0: &mut TxContext) { + let v0 = Pools { + id : sui::object::new(arg0), + list : move_stl::linked_table::new(arg0), + index : 0, + }; + let pools_id = v0.id.to_inner(); + share_object(v0); + let v1 = InitFactoryEvent{ pools_id }; + event::emit(v1); + } + + public fun new_pool_key(tick_spacing: u32) : ID { + let type_a = std::type_name::into_string(std::type_name::get()); + let mut type_a_bytes = *std::ascii::as_bytes(&type_a); + let type_b = std::type_name::into_string(std::type_name::get()); + let type_b_bytes = *std::ascii::as_bytes(&type_b); + let mut i = 0; + let mut is_a_larger_than_b = false; + + while (i < std::vector::length(&type_b_bytes)) { + let current_b_byte = *std::vector::borrow(&type_b_bytes, i); + let can_compare_bytes = !is_a_larger_than_b && i < std::vector::length(&type_a_bytes); + if (can_compare_bytes) { + let current_a_byte = *std::vector::borrow(&type_a_bytes, i); + if (current_a_byte < current_b_byte) { + abort 6 + }; + if (current_a_byte > current_b_byte) { + is_a_larger_than_b = true; + }; + }; + std::vector::push_back(&mut type_a_bytes, current_b_byte); + i = i + 1; + continue; + abort 6 + }; + if (!is_a_larger_than_b) { + if (std::vector::length(&type_a_bytes) < std::vector::length(&type_b_bytes)) { + abort 6 + }; + if (std::vector::length(&type_a_bytes) == std::vector::length(&type_b_bytes)) { + abort 3 + }; + }; + std::vector::append(&mut type_a_bytes, std::bcs::to_bytes(&tick_spacing)); + object::id_from_bytes(sui::hash::blake2b256(&type_a_bytes)) + } + + public fun pool_id(arg0: &PoolSimpleInfo) : ID { + arg0.pool_id + } + + public fun pool_key(arg0: &PoolSimpleInfo) : ID { + arg0.pool_key + } + + public fun pool_simple_info(arg0: &Pools, arg1: ID) : &PoolSimpleInfo { + move_stl::linked_table::borrow(&arg0.list, arg1) + } + + public fun tick_spacing(arg0: &PoolSimpleInfo) : u32 { + arg0.tick_spacing + } + + // decompiled from Move bytecode v6 + + #[test_only] + public fun init_for_testing(arg0: &mut TxContext): Pools { + let v0 = Pools { + id : sui::object::new(arg0), + list : move_stl::linked_table::new(arg0), + index : 0, + }; + v0 + } +} + diff --git a/contracts/dependencies/cetus/sources/partner.move b/contracts/dependencies/cetus/sources/partner.move new file mode 100644 index 0000000..a1a9cc8 --- /dev/null +++ b/contracts/dependencies/cetus/sources/partner.move @@ -0,0 +1,216 @@ +#[allow(lint(self_transfer))] +module cetus_clmm::partner { + use sui::event; + use sui::balance::{Balance}; + use sui::clock::{Clock}; + use sui::transfer::{transfer, share_object}; + use sui::tx_context::{sender}; + use sui::vec_map::{VecMap}; + + public struct Partners has key { + id: UID, + partners: VecMap, + } + + public struct PartnerCap has store, key { + id: UID, + name: std::string::String, + partner_id: ID, + } + + public struct Partner has store, key { + id: UID, + name: std::string::String, + ref_fee_rate: u64, + start_time: u64, + end_time: u64, + balances: sui::bag::Bag, + } + + public struct InitPartnerEvent has copy, drop { + partners_id: ID, + } + + public struct CreatePartnerEvent has copy, drop { + recipient: address, + partner_id: ID, + partner_cap_id: ID, + ref_fee_rate: u64, + name: std::string::String, + start_time: u64, + end_time: u64, + } + + public struct UpdateRefFeeRateEvent has copy, drop { + partner_id: ID, + old_fee_rate: u64, + new_fee_rate: u64, + } + + public struct UpdateTimeRangeEvent has copy, drop { + partner_id: ID, + start_time: u64, + end_time: u64, + } + + public struct ReceiveRefFeeEvent has copy, drop { + partner_id: ID, + amount: u64, + type_name: std::string::String, + } + + public struct ClaimRefFeeEvent has copy, drop { + partner_id: ID, + amount: u64, + type_name: std::string::String, + } + + public fun balances(arg0: &Partner) : &sui::bag::Bag { + &arg0.balances + } + + public fun claim_ref_fee(arg0: &cetus_clmm::config::GlobalConfig, arg1: &PartnerCap, arg2: &mut Partner, arg3: &mut TxContext) { + cetus_clmm::config::checked_package_version(arg0); + assert!(arg1.partner_id == arg2.id.to_inner(), 4); + let v0 = std::string::from_ascii(std::type_name::into_string(std::type_name::get())); + assert!(sui::bag::contains(&arg2.balances, v0), 5); + let v1 = sui::bag::remove>(&mut arg2.balances, v0); + let amount = sui::balance::value(&v1); + sui::transfer::public_transfer>(sui::coin::from_balance(v1, arg3), sender(arg3)); + let v2 = ClaimRefFeeEvent{ + partner_id : arg2.id.to_inner(), + amount, + type_name : v0, + }; + event::emit(v2); + } + + public fun create_partner(arg0: &cetus_clmm::config::GlobalConfig, arg1: &mut Partners, arg2: std::string::String, arg3: u64, arg4: u64, arg5: u64, arg6: address, arg7: &Clock, arg8: &mut TxContext) { + assert!(arg5 > arg4, 2); + assert!(arg4 >= sui::clock::timestamp_ms(arg7) / 1000, 2); + assert!(arg3 < 10000, 3); + assert!(!std::string::is_empty(&arg2), 6); + assert!(!sui::vec_map::contains(&arg1.partners, &arg2), 1); + cetus_clmm::config::checked_package_version(arg0); + cetus_clmm::config::check_partner_manager_role(arg0, sender(arg8)); + let v0 = Partner { + id: sui::object::new(arg8), + name: arg2, + ref_fee_rate: arg3, + start_time: arg4, + end_time: arg5, + balances: sui::bag::new(arg8), + }; + let v1 = PartnerCap { + id : sui::object::new(arg8), + name : arg2, + partner_id : v0.id.to_inner(), + }; + + let partner_cap_id = v1.id.to_inner(); + let v2 = v0.id.to_inner(); + sui::vec_map::insert(&mut arg1.partners, arg2, v2); + share_object(v0); + transfer(v1, arg6); + let v3 = CreatePartnerEvent{ + recipient : arg6, + partner_id : v2, + partner_cap_id, + ref_fee_rate : arg3, + name : arg2, + start_time : arg4, + end_time : arg5, + }; + event::emit(v3); + } + + public fun current_ref_fee_rate(arg0: &Partner, arg1: u64) : u64 { + if (arg0.start_time > arg1 || arg0.end_time <= arg1) { + return 0 + }; + arg0.ref_fee_rate + } + + public fun end_time(arg0: &Partner) : u64 { + arg0.end_time + } + + fun init(arg0: &mut TxContext) { + let v0 = Partners{ + id : sui::object::new(arg0), + partners : sui::vec_map::empty(), + }; + let partners_id = v0.id.to_inner(); + + share_object(v0); + let v1 = InitPartnerEvent{ partners_id }; + event::emit(v1); + } + + public fun name(arg0: &Partner) : std::string::String { + arg0.name + } + + public fun receive_ref_fee(arg0: &mut Partner, arg1: Balance) { + let amount = sui::balance::value(&arg1); + let v0 = std::string::from_ascii(std::type_name::into_string(std::type_name::get())); + if (sui::bag::contains(&arg0.balances, v0)) { + sui::balance::join(sui::bag::borrow_mut>(&mut arg0.balances, v0), arg1); + } else { + sui::bag::add>(&mut arg0.balances, v0, arg1); + }; + let v1 = ReceiveRefFeeEvent{ + partner_id : arg0.id.to_inner(), + amount, + type_name : v0, + }; + event::emit(v1); + } + + public fun ref_fee_rate(arg0: &Partner) : u64 { + arg0.ref_fee_rate + } + + public fun partner_id(arg0: &Partner) : ID { + arg0.id.to_inner() + } + + public fun partners_id(arg0: &Partners) : ID { + arg0.id.to_inner() + } + + public fun start_time(arg0: &Partner) : u64 { + arg0.start_time + } + + public fun update_ref_fee_rate(arg0: &cetus_clmm::config::GlobalConfig, arg1: &mut Partner, arg2: u64, arg3: &TxContext) { + assert!(arg2 < 10000, 3); + cetus_clmm::config::checked_package_version(arg0); + cetus_clmm::config::check_partner_manager_role(arg0, sender(arg3)); + arg1.ref_fee_rate = arg2; + let v0 = UpdateRefFeeRateEvent{ + partner_id : arg1.id.to_inner(), + old_fee_rate : arg1.ref_fee_rate, + new_fee_rate : arg2, + }; + event::emit(v0); + } + + public fun update_time_range(arg0: &cetus_clmm::config::GlobalConfig, arg1: &mut Partner, arg2: u64, arg3: u64, arg4: &Clock, arg5: &mut TxContext) { + assert!(arg3 > arg2, 2); + assert!(arg3 > sui::clock::timestamp_ms(arg4) / 1000, 2); + cetus_clmm::config::checked_package_version(arg0); + cetus_clmm::config::check_partner_manager_role(arg0, sender(arg5)); + arg1.start_time = arg2; + arg1.end_time = arg3; + let v0 = UpdateTimeRangeEvent{ + partner_id : arg1.id.to_inner(), + start_time : arg2, + end_time : arg3, + }; + event::emit(v0); + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/cetus/sources/pool.move b/contracts/dependencies/cetus/sources/pool.move new file mode 100644 index 0000000..b1a2367 --- /dev/null +++ b/contracts/dependencies/cetus/sources/pool.move @@ -0,0 +1,1131 @@ +#[allow(lint(self_transfer))] +module cetus_clmm::pool { + use std::type_name::{Self, TypeName}; + use sui::event; + use sui::balance::{Self, Balance}; + use sui::clock::{Clock}; + use sui::tx_context::{sender}; + use cetus_clmm::tick::{Self, TickManager}; + use cetus_clmm::rewarder::{Self, RewarderManager, RewarderGlobalVault}; + use cetus_clmm::position::{Self, PositionManager, Position, PositionInfo}; + use integer_mate::i32::{I32}; + use cetus_clmm::tick_math; + use cetus_clmm::clmm_math; + use cetus_clmm::config; + use cetus_clmm::partner::{Self, Partner}; + + public struct POOL has drop {} + + public struct Pool has store, key { + id: UID, + coin_a: Balance, + coin_b: Balance, + tick_spacing: u32, + fee_rate: u64, + liquidity: u128, + current_sqrt_price: u128, + current_tick_index: I32, + fee_growth_global_a: u128, + fee_growth_global_b: u128, + fee_protocol_coin_a: u64, + fee_protocol_coin_b: u64, + tick_manager: TickManager, + rewarder_manager: RewarderManager, + position_manager: PositionManager, + is_pause: bool, + index: u64, + url: std::string::String, + } + + public struct SwapResult has copy, drop { + amount_in: u64, + amount_out: u64, + fee_amount: u64, + ref_fee_amount: u64, + steps: u64, + } + + public struct FlashSwapReceipt { + pool_id: ID, + a2b: bool, + partner_id: ID, + pay_amount: u64, + ref_fee_amount: u64, + } + + public struct AddLiquidityReceipt { + pool_id: ID, + amount_a: u64, + amount_b: u64, + } + + public struct CalculatedSwapResult has copy, drop, store { + amount_in: u64, + amount_out: u64, + fee_amount: u64, + fee_rate: u64, + after_sqrt_price: u128, + is_exceed: bool, + step_results: vector, + } + + public struct SwapStepResult has copy, drop, store { + current_sqrt_price: u128, + target_sqrt_price: u128, + current_liquidity: u128, + amount_in: u64, + amount_out: u64, + fee_amount: u64, + remainder_amount: u64, + } + + public struct OpenPositionEvent has copy, drop, store { + pool: ID, + tick_lower: I32, + tick_upper: I32, + position: ID, + } + + public struct ClosePositionEvent has copy, drop, store { + pool: ID, + position: ID, + } + + public struct AddLiquidityEvent has copy, drop, store { + pool: ID, + position: ID, + tick_lower: I32, + tick_upper: I32, + liquidity: u128, + after_liquidity: u128, + amount_a: u64, + amount_b: u64, + } + + public struct RemoveLiquidityEvent has copy, drop, store { + pool: ID, + position: ID, + tick_lower: I32, + tick_upper: I32, + liquidity: u128, + after_liquidity: u128, + amount_a: u64, + amount_b: u64, + } + + public struct SwapEvent has copy, drop, store { + atob: bool, + pool: ID, + partner: ID, + amount_in: u64, + amount_out: u64, + ref_amount: u64, + fee_amount: u64, + vault_a_amount: u64, + vault_b_amount: u64, + before_sqrt_price: u128, + after_sqrt_price: u128, + steps: u64, + } + + public struct CollectProtocolFeeEvent has copy, drop, store { + pool: ID, + amount_a: u64, + amount_b: u64, + } + + public struct CollectFeeEvent has copy, drop, store { + position: ID, + pool: ID, + amount_a: u64, + amount_b: u64, + } + + public struct UpdateFeeRateEvent has copy, drop, store { + pool: ID, + old_fee_rate: u64, + new_fee_rate: u64, + } + + public struct UpdateEmissionEvent has copy, drop, store { + pool: ID, + rewarder_type: TypeName, + emissions_per_second: u128, + } + + public struct AddRewarderEvent has copy, drop, store { + pool: ID, + rewarder_type: TypeName, + } + + public struct CollectRewardEvent has copy, drop, store { + position: ID, + pool: ID, + amount: u64, + } + + public(package) fun new(tick_spacing: u32, current_sqrt_price: u128, fee_rate: u64, url: std::string::String, index: u64, clock: &Clock, ctx: &mut TxContext) : Pool { + Pool { + id: object::new(ctx), + coin_a: balance::zero(), + coin_b: balance::zero(), + tick_spacing: tick_spacing, + fee_rate, + liquidity: 0, + current_sqrt_price, + current_tick_index: tick_math::get_tick_at_sqrt_price(current_sqrt_price), + fee_growth_global_a: 0, + fee_growth_global_b: 0, + fee_protocol_coin_a: 0, + fee_protocol_coin_b: 0, + tick_manager: tick::new(tick_spacing, sui::clock::timestamp_ms(clock), ctx), + rewarder_manager: rewarder::new(), + position_manager: position::new(tick_spacing, ctx), + is_pause: false, + index, + url, + } + } + + + public fun get_amount_by_liquidity(arg0: I32, arg1: I32, arg2: I32, arg3: u128, arg4: u128, arg5: bool) : (u64, u64) { + if (arg4 == 0) { + return (0, 0) + }; + if (integer_mate::i32::lt(arg2, arg0)) { + (clmm_math::get_delta_a(tick_math::get_sqrt_price_at_tick(arg0), tick_math::get_sqrt_price_at_tick(arg1), arg4, arg5), 0) + } else { + let (v2, v3) = if (integer_mate::i32::lt(arg2, arg1)) { + (clmm_math::get_delta_a(arg3, tick_math::get_sqrt_price_at_tick(arg1), arg4, arg5), clmm_math::get_delta_b(tick_math::get_sqrt_price_at_tick(arg0), arg3, arg4, arg5)) + } else { + (0, clmm_math::get_delta_b(tick_math::get_sqrt_price_at_tick(arg0), tick_math::get_sqrt_price_at_tick(arg1), arg4, arg5)) + }; + (v2, v3) + } + } + + public fun borrow_position_info(arg0: &Pool, arg1: ID) : &PositionInfo { + position::borrow_position_info(&arg0.position_manager, arg1) + } + + public fun close_position(config: &config::GlobalConfig, pool: &mut Pool, position: Position) { + config::checked_package_version(config); + assert!(!pool.is_pause, 13); + let position_id = object::id(&position); + + position::close_position(&mut pool.position_manager, position); + + event::emit(ClosePositionEvent{ + pool: pool.id.to_inner(), + position: position_id, + }); + } + + public fun fetch_positions(arg0: &Pool, arg1: vector, arg2: u64) : vector { + position::fetch_positions(&arg0.position_manager, arg1, arg2) + } + + public fun is_position_exist(arg0: &Pool, arg1: ID) : bool { + position::is_position_exist(&arg0.position_manager, arg1) + } + + public fun liquidity(pool: &Pool) : u128 { + pool.liquidity + } + + public fun open_position(config: &config::GlobalConfig, pool: &mut Pool, tick_lower: u32, tick_upper: u32, ctx: &mut TxContext) : Position { + config::checked_package_version(config); + assert!(!pool.is_pause, 13); + let tick_lower = integer_mate::i32::from_u32(tick_lower); + let tick_upper = integer_mate::i32::from_u32(tick_upper); + let pool_id = pool.id.to_inner(); + + let position = position::open_position( + &mut pool.position_manager, + pool_id, + pool.index, + pool.url, + tick_lower, + tick_upper, + ctx + ); + + event::emit(OpenPositionEvent{ + pool : pool_id, + tick_lower : tick_lower, + tick_upper : tick_upper, + position : object::id(&position), + }); + position + } + + public fun update_emission(config: &config::GlobalConfig, pool: &mut Pool, reward_vault: &RewarderGlobalVault, emissions_per_second: u128, clock: &Clock, ctx: &TxContext) { + config::checked_package_version(config); + assert!(!pool.is_pause, 13); + config::check_pool_manager_role(config, sender(ctx)); + rewarder::update_emission(reward_vault, &mut pool.rewarder_manager, pool.liquidity, emissions_per_second, sui::clock::timestamp_ms(clock) / 1000); + + event::emit(UpdateEmissionEvent{ + pool : pool.id.to_inner(), + rewarder_type : type_name::get(), + emissions_per_second : emissions_per_second, + }); + } + + public fun borrow_tick(pool: &Pool, arg1: I32) : &tick::Tick { + tick::borrow_tick(&pool.tick_manager, arg1) + } + + public fun fetch_ticks(pool: &Pool, arg1: vector, arg2: u64) : vector { + tick::fetch_ticks(&pool.tick_manager, arg1, arg2) + } + + public fun index(pool: &Pool) : u64 { + pool.index + } + + public fun add_liquidity(config: &config::GlobalConfig, pool: &mut Pool, position: &mut Position, liquidity: u128, clock: &Clock) : AddLiquidityReceipt { + config::checked_package_version(config); + assert!(liquidity != 0, 3); + add_liquidity_internal(pool, position, false, liquidity, 0, false, sui::clock::timestamp_ms(clock) / 1000) + } + + public fun add_liquidity_fix_coin(config: &config::GlobalConfig, pool: &mut Pool, position: &mut Position, amount: u64, from_a: bool, clock: &Clock) : AddLiquidityReceipt { + config::checked_package_version(config); + assert!(amount > 0, 0); + add_liquidity_internal(pool, position, true, 0, amount, from_a, sui::clock::timestamp_ms(clock) / 1000) + } + + fun add_liquidity_internal(pool: &mut Pool, position: &mut Position, get_liquidity_by_amount: bool, liquidity: u128, amount: u64, from_a: bool, current_time: u64) : AddLiquidityReceipt { + assert!(!pool.is_pause, 13); + rewarder::settle(&mut pool.rewarder_manager, pool.liquidity, current_time); + let (tick_lower, tick_upper) = position::tick_range(position); + + let (liquidity_delta, amount_a, amount_b) = if (get_liquidity_by_amount) { + let (liquidity_delta, amount_a, amount_b) = clmm_math::get_liquidity_by_amount(tick_lower, tick_upper, pool.current_tick_index, pool.current_sqrt_price, amount, from_a); + (liquidity_delta, amount_a, amount_b) + } else { + let (amount_a, amount_b) = clmm_math::get_amount_by_liquidity(tick_lower, tick_upper, pool.current_tick_index, pool.current_sqrt_price, liquidity, true); + (liquidity, amount_a, amount_b) + }; + + let (fee_a, fee_b, rewards, points) = get_fee_rewards_points_in_tick_range(pool, tick_lower, tick_upper); + tick::increase_liquidity(&mut pool.tick_manager, pool.current_tick_index, tick_lower, tick_upper, liquidity_delta, pool.fee_growth_global_a, pool.fee_growth_global_b, rewarder::points_growth_global(&pool.rewarder_manager), rewarder::rewards_growth_global(&pool.rewarder_manager)); + + if (integer_mate::i32::gte(pool.current_tick_index, tick_lower) && integer_mate::i32::lt(pool.current_tick_index, tick_upper)) { + assert!(integer_mate::math_u128::add_check(pool.liquidity, liquidity_delta), 1); + pool.liquidity = pool.liquidity + liquidity_delta; + }; + + event::emit(AddLiquidityEvent { + pool: pool.id.to_inner(), + position: object::id(position), + tick_lower: tick_lower, + tick_upper: tick_upper, + liquidity: liquidity, + after_liquidity: position::increase_liquidity(&mut pool.position_manager, position, liquidity_delta, fee_a, fee_b, points, rewards), + amount_a: amount_a, + amount_b: amount_b, + }); + + AddLiquidityReceipt{ + pool_id: pool.id.to_inner(), + amount_a: amount_a, + amount_b: amount_b, + } + } + + public fun add_liquidity_pay_amount(receipt: &AddLiquidityReceipt) : (u64, u64) { + (receipt.amount_a, receipt.amount_b) + } + + public fun balances(pool: &Pool) : (&Balance, &Balance) { + (&pool.coin_a, &pool.coin_b) + } + + public fun calculate_and_update_fee(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: ID) : (u64, u64) { + config::checked_package_version(arg0); + assert!(!arg1.is_pause, 13); + let v0 = position::borrow_position_info(&arg1.position_manager, arg2); + if (position::info_liquidity(v0) != 0) { + let (v3, v4) = position::info_tick_range(v0); + let (v5, v6) = get_fee_in_tick_range(arg1, v3, v4); + let (v7, v8) = position::update_fee(&mut arg1.position_manager, arg2, v5, v6); + (v7, v8) + } else { + let (v9, v10) = position::info_fee_owned(position::borrow_position_info(&arg1.position_manager, arg2)); + (v9, v10) + } + } + + public fun calculate_and_update_points(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: ID, arg3: &Clock) : u128 { + config::checked_package_version(arg0); + assert!(!arg1.is_pause, 13); + rewarder::settle(&mut arg1.rewarder_manager, arg1.liquidity, sui::clock::timestamp_ms(arg3) / 1000); + let v0 = position::borrow_position_info(&arg1.position_manager, arg2); + if (position::info_liquidity(v0) != 0) { + let (v2, v3) = position::info_tick_range(v0); + let points = get_points_in_tick_range(arg1, v2, v3); + position::update_points(&mut arg1.position_manager, arg2, points) + } else { + position::info_points_owned(position::borrow_position_info(&arg1.position_manager, arg2)) + } + } + + public fun calculate_and_update_reward(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: ID, arg3: &Clock) : u64 { + let mut v0 = rewarder::rewarder_index(&arg1.rewarder_manager); + assert!(std::option::is_some(&v0), 17); + let v1 = calculate_and_update_rewards(arg0, arg1, arg2, arg3); + *std::vector::borrow(&v1, std::option::extract(&mut v0)) + } + + public fun calculate_and_update_rewards(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: ID, arg3: &Clock) : vector { + config::checked_package_version(arg0); + assert!(!arg1.is_pause, 13); + rewarder::settle(&mut arg1.rewarder_manager, arg1.liquidity, sui::clock::timestamp_ms(arg3) / 1000); + let v0 = position::borrow_position_info(&arg1.position_manager, arg2); + if (position::info_liquidity(v0) != 0) { + let (v2, v3) = position::info_tick_range(v0); + let rewards = get_rewards_in_tick_range(arg1, v2, v3); + position::update_rewards(&mut arg1.position_manager, arg2, rewards) + } else { + position::rewards_amount_owned(&arg1.position_manager, arg2) + } + } + + public fun calculate_swap_result(arg0: &Pool, arg1: bool, arg2: bool, arg3: u64) : CalculatedSwapResult { + let mut v0 = arg0.current_sqrt_price; + let mut v1 = arg0.liquidity; + let mut v2 = default_swap_result(); + let mut v3 = arg3; + let mut v4 = tick::first_score_for_swap(&arg0.tick_manager, arg0.current_tick_index, arg1); + let mut v5 = CalculatedSwapResult{ + amount_in : 0, + amount_out : 0, + fee_amount : 0, + fee_rate : arg0.fee_rate, + after_sqrt_price : arg0.current_sqrt_price, + is_exceed : false, + step_results : std::vector::empty(), + }; + while (v3 > 0) { + if (move_stl::option_u64::is_none(&v4)) { + v5.is_exceed = true; + break + }; + let (v6, v7) = tick::borrow_tick_for_swap(&arg0.tick_manager, move_stl::option_u64::borrow(&v4), arg1); + v4 = v7; + let v8 = tick::sqrt_price(v6); + let (v9, v10, v11, v12) = clmm_math::compute_swap_step(v0, v8, v1, v3, arg0.fee_rate, arg1, arg2); + if (v9 != 0 || v12 != 0) { + if (arg2) { + let v13 = check_remainer_amount_sub(v3, v9); + v3 = check_remainer_amount_sub(v13, v12); + } else { + v3 = check_remainer_amount_sub(v3, v10); + }; + update_swap_result(&mut v2, v9, v10, v12); + }; + let v14 = SwapStepResult{ + current_sqrt_price : v0, + target_sqrt_price : v8, + current_liquidity : v1, + amount_in : v9, + amount_out : v10, + fee_amount : v12, + remainder_amount : v3, + }; + std::vector::push_back(&mut v5.step_results, v14); + if (v11 == v8) { + v0 = v8; + let v15 = if (arg1) { + integer_mate::i128::neg(tick::liquidity_net(v6)) + } else { + tick::liquidity_net(v6) + }; + if (!integer_mate::i128::is_neg(v15)) { + let v16 = integer_mate::i128::abs_u128(v15); + assert!(integer_mate::math_u128::add_check(v1, v16), 1); + v1 = v1 + v16; + continue + }; + let v17 = integer_mate::i128::abs_u128(v15); + assert!(v1 >= v17, 1); + v1 = v1 - v17; + continue + }; + v0 = v11; + }; + v5.amount_in = v2.amount_in; + v5.amount_out = v2.amount_out; + v5.fee_amount = v2.fee_amount; + v5.after_sqrt_price = v0; + v5 + } + + public fun calculate_swap_result_step_results(arg0: &CalculatedSwapResult) : &vector { + &arg0.step_results + } + + public fun calculated_swap_result_after_sqrt_price(arg0: &CalculatedSwapResult) : u128 { + arg0.after_sqrt_price + } + + public fun calculated_swap_result_amount_in(arg0: &CalculatedSwapResult) : u64 { + arg0.amount_in + } + + public fun calculated_swap_result_amount_out(arg0: &CalculatedSwapResult) : u64 { + arg0.amount_out + } + + public fun calculated_swap_result_fee_amount(arg0: &CalculatedSwapResult) : u64 { + arg0.fee_amount + } + + public fun calculated_swap_result_is_exceed(arg0: &CalculatedSwapResult) : bool { + arg0.is_exceed + } + + public fun calculated_swap_result_step_swap_result(arg0: &CalculatedSwapResult, arg1: u64) : &SwapStepResult { + std::vector::borrow(&arg0.step_results, arg1) + } + + public fun calculated_swap_result_steps_length(arg0: &CalculatedSwapResult) : u64 { + std::vector::length(&arg0.step_results) + } + + fun check_remainer_amount_sub(arg0: u64, arg1: u64) : u64 { + assert!(arg0 >= arg1, 5); + arg0 - arg1 + } + + public fun collect_fee(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: &Position, arg3: bool) : (Balance, Balance) { + config::checked_package_version(arg0); + assert!(!arg1.is_pause, 13); + let v0 = object::id(arg2); + let (v1, v2) = position::tick_range(arg2); + let (v3, v4) = if (arg3 && position::liquidity(arg2) != 0) { + let (v5, v6) = get_fee_in_tick_range(arg1, v1, v2); + let (v7, v8) = position::update_and_reset_fee(&mut arg1.position_manager, v0, v5, v6); + (v7, v8) + } else { + let (v9, v10) = position::reset_fee(&mut arg1.position_manager, v0); + (v9, v10) + }; + let v11 = CollectFeeEvent{ + position : v0, + pool : arg1.id.to_inner(), + amount_a : v3, + amount_b : v4, + }; + event::emit(v11); + (balance::split(&mut arg1.coin_a, v3), balance::split(&mut arg1.coin_b, v4)) + } + + public fun collect_protocol_fee(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: &TxContext) : (Balance, Balance) { + config::checked_package_version(arg0); + assert!(!arg1.is_pause, 13); + config::check_protocol_fee_claim_role(arg0, sender(arg2)); + let v0 = arg1.fee_protocol_coin_a; + let v1 = arg1.fee_protocol_coin_b; + arg1.fee_protocol_coin_a = 0; + arg1.fee_protocol_coin_b = 0; + let v2 = CollectProtocolFeeEvent{ + pool : arg1.id.to_inner(), + amount_a : v0, + amount_b : v1, + }; + event::emit(v2); + (balance::split(&mut arg1.coin_a, v0), balance::split(&mut arg1.coin_b, v1)) + } + + public fun collect_reward(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: &Position, arg3: &mut RewarderGlobalVault, arg4: bool, arg5: &Clock) : Balance { + config::checked_package_version(arg0); + assert!(!arg1.is_pause, 13); + rewarder::settle(&mut arg1.rewarder_manager, arg1.liquidity, sui::clock::timestamp_ms(arg5) / 1000); + let v0 = object::id(arg2); + let mut v1 = rewarder::rewarder_index(&arg1.rewarder_manager); + assert!(std::option::is_some(&v1), 17); + let v2 = std::option::extract(&mut v1); + let v3 = if (arg4 && position::liquidity(arg2) != 0 || position::inited_rewards_count(&arg1.position_manager, v0) <= v2) { + let (v4, v5) = position::tick_range(arg2); + let rewards = get_rewards_in_tick_range(arg1, v4, v5); + position::update_and_reset_rewards(&mut arg1.position_manager, v0, rewards, v2) + } else { + position::reset_rewarder(&mut arg1.position_manager, v0, v2) + }; + let v6 = CollectRewardEvent{ + position : v0, + pool : arg1.id.to_inner(), + amount : v3, + }; + event::emit(v6); + rewarder::withdraw_reward(arg3, v3) + } + + public fun current_sqrt_price(arg0: &Pool) : u128 { + arg0.current_sqrt_price + } + + public fun current_tick_index(arg0: &Pool) : I32 { + arg0.current_tick_index + } + + fun default_swap_result() : SwapResult { + SwapResult{ + amount_in : 0, + amount_out : 0, + fee_amount : 0, + ref_fee_amount : 0, + steps : 0, + } + } + + public fun fee_rate(arg0: &Pool) : u64 { + arg0.fee_rate + } + + public fun fees_growth_global(arg0: &Pool) : (u128, u128) { + (arg0.fee_growth_global_a, arg0.fee_growth_global_b) + } + + public fun flash_swap( + config: &config::GlobalConfig, + pool: &mut Pool, + a2b: bool, + by_amount_in: bool, + amount: u64, + sqrt_price_limit: u128, + clock: &Clock + ) : (Balance, Balance, FlashSwapReceipt) { + config::checked_package_version(config); + assert!(!pool.is_pause, 13); + flash_swap_internal( + pool, + config, + object::id_from_address(@0x0), + 0, + a2b, + by_amount_in, + amount, + sqrt_price_limit, + clock + ) + } + + fun flash_swap_internal( + pool: &mut Pool, + config: &config::GlobalConfig, + partner: ID, + ref_fee: u64, + a2b: bool, + by_amount_in: bool, + amount: u64, + sqrt_price_limit: u128, + clock: &Clock + ) : (Balance, Balance, FlashSwapReceipt) { + assert!(!pool.is_pause, 13); + rewarder::settle(&mut pool.rewarder_manager, pool.liquidity, sui::clock::timestamp_ms(clock) / 1000); + + if (a2b) { + assert!(pool.current_sqrt_price > sqrt_price_limit && sqrt_price_limit >= tick_math::min_sqrt_price(), 11); + } else { + assert!(pool.current_sqrt_price < sqrt_price_limit && sqrt_price_limit <= tick_math::max_sqrt_price(), 11); + }; + let v0 = swap_in_pool(pool, a2b, by_amount_in, sqrt_price_limit, amount, config::protocol_fee_rate(config), ref_fee); + let (v1, v2) = if (a2b) { + (balance::zero(), balance::split(&mut pool.coin_b, v0.amount_out)) + } else { + (balance::split(&mut pool.coin_a, v0.amount_out), balance::zero()) + }; + let v3 = SwapEvent{ + atob : a2b, + pool : pool.id.to_inner(), + partner : partner, + amount_in : v0.amount_in + v0.fee_amount, + amount_out : v0.amount_out, + ref_amount : v0.ref_fee_amount, + fee_amount : v0.fee_amount, + vault_a_amount : balance::value(&pool.coin_a), + vault_b_amount : balance::value(&pool.coin_b), + before_sqrt_price : pool.current_sqrt_price, + after_sqrt_price : pool.current_sqrt_price, + steps : v0.steps, + }; + event::emit(v3); + let v4 = FlashSwapReceipt{ + pool_id : pool.id.to_inner(), + a2b : a2b, + partner_id : partner, + pay_amount : v0.amount_in + v0.fee_amount, + ref_fee_amount : v0.ref_fee_amount, + }; + (v1, v2, v4) + } + + public fun flash_swap_with_partner(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: &Partner, arg3: bool, arg4: bool, arg5: u64, arg6: u128, arg7: &Clock) : (Balance, Balance, FlashSwapReceipt) { + config::checked_package_version(arg0); + flash_swap_internal(arg1, arg0, arg2.partner_id(), partner::current_ref_fee_rate(arg2, sui::clock::timestamp_ms(arg7) / 1000), arg3, arg4, arg5, arg6, arg7) + } + + public fun get_fee_in_tick_range(arg0: &Pool, arg1: I32, arg2: I32) : (u128, u128) { + tick::get_fee_in_range(arg0.current_tick_index, arg0.fee_growth_global_a, arg0.fee_growth_global_b, tick::try_borrow_tick(&arg0.tick_manager, arg1), tick::try_borrow_tick(&arg0.tick_manager, arg2)) + } + + public fun get_fee_rewards_points_in_tick_range(arg0: &Pool, tick_lower: I32, tick_upper: I32) : (u128, u128, vector, u128) { + let lower_tick = tick::try_borrow_tick(&arg0.tick_manager, tick_lower); + let upper_tick = tick::try_borrow_tick(&arg0.tick_manager, tick_upper); + let (fee_a, fee_b) = tick::get_fee_in_range(arg0.current_tick_index, arg0.fee_growth_global_a, arg0.fee_growth_global_b, lower_tick, upper_tick); + (fee_a, fee_b, tick::get_rewards_in_range(arg0.current_tick_index, rewarder::rewards_growth_global(&arg0.rewarder_manager), lower_tick, upper_tick), tick::get_points_in_range(arg0.current_tick_index, rewarder::points_growth_global(&arg0.rewarder_manager), lower_tick, upper_tick)) + } + + public fun get_liquidity_from_amount(arg0: I32, arg1: I32, arg2: I32, arg3: u128, arg4: u64, arg5: bool) : (u128, u64, u64) { + let mut v0 = 0; + let mut v1 = 0; + let v2 = if (arg5) { + v0 = arg4; + if (integer_mate::i32::lt(arg2, arg0)) { + clmm_math::get_liquidity_from_a(tick_math::get_sqrt_price_at_tick(arg0), tick_math::get_sqrt_price_at_tick(arg1), arg4, false) + } else { + assert!(integer_mate::i32::lt(arg2, arg1), 10); + let v3 = clmm_math::get_liquidity_from_a(arg3, tick_math::get_sqrt_price_at_tick(arg1), arg4, false); + v1 = clmm_math::get_delta_b(arg3, tick_math::get_sqrt_price_at_tick(arg0), v3, true); + v3 + } + } else { + v1 = arg4; + if (integer_mate::i32::gte(arg2, arg1)) { + clmm_math::get_liquidity_from_b(tick_math::get_sqrt_price_at_tick(arg0), tick_math::get_sqrt_price_at_tick(arg1), arg4, false) + } else { + assert!(integer_mate::i32::gte(arg2, arg0), 10); + let v4 = clmm_math::get_liquidity_from_b(tick_math::get_sqrt_price_at_tick(arg0), arg3, arg4, false); + v0 = clmm_math::get_delta_a(arg3, tick_math::get_sqrt_price_at_tick(arg1), v4, true); + v4 + } + }; + (v2, v0, v1) + } + + public fun get_points_in_tick_range(arg0: &Pool, arg1: I32, arg2: I32) : u128 { + tick::get_points_in_range(arg0.current_tick_index, rewarder::points_growth_global(&arg0.rewarder_manager), tick::try_borrow_tick(&arg0.tick_manager, arg1), tick::try_borrow_tick(&arg0.tick_manager, arg2)) + } + + public fun get_position_fee(arg0: &Pool, arg1: ID) : (u64, u64) { + position::info_fee_owned(position::borrow_position_info(&arg0.position_manager, arg1)) + } + + public fun get_position_points(arg0: &Pool, arg1: ID) : u128 { + position::info_points_owned(position::borrow_position_info(&arg0.position_manager, arg1)) + } + + public fun get_position_reward(arg0: &Pool, arg1: ID) : u64 { + let mut v0 = rewarder::rewarder_index(&arg0.rewarder_manager); + assert!(std::option::is_some(&v0), 17); + let v1 = position::rewards_amount_owned(&arg0.position_manager, arg1); + *std::vector::borrow(&v1, std::option::extract(&mut v0)) + } + + public fun get_position_rewards(arg0: &Pool, arg1: ID) : vector { + position::rewards_amount_owned(&arg0.position_manager, arg1) + } + + public fun get_rewards_in_tick_range(arg0: &Pool, arg1: I32, arg2: I32) : vector { + tick::get_rewards_in_range(arg0.current_tick_index, rewarder::rewards_growth_global(&arg0.rewarder_manager), tick::try_borrow_tick(&arg0.tick_manager, arg1), tick::try_borrow_tick(&arg0.tick_manager, arg2)) + } + + fun init(arg0: POOL, arg1: &mut TxContext) { + sui::transfer::public_transfer(sui::package::claim(arg0, arg1), sender(arg1)); + } + + public fun initialize_rewarder(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: &TxContext) { + config::checked_package_version(arg0); + assert!(!arg1.is_pause, 13); + config::check_pool_manager_role(arg0, sender(arg2)); + rewarder::add_rewarder(&mut arg1.rewarder_manager); + let v0 = AddRewarderEvent{ + pool : arg1.id.to_inner(), + rewarder_type : type_name::get(), + }; + event::emit(v0); + } + + public fun is_pause(arg0: &Pool) : bool { + arg0.is_pause + } + + public fun pause(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: &TxContext) { + config::checked_package_version(arg0); + config::check_pool_manager_role(arg0, sender(arg2)); + arg1.is_pause = true; + } + + public fun position_manager(arg0: &Pool) : &PositionManager { + &arg0.position_manager + } + + public fun protocol_fee(arg0: &Pool) : (u64, u64) { + (arg0.fee_protocol_coin_a, arg0.fee_protocol_coin_b) + } + + public fun pool_id(arg0: &Pool) : ID { + arg0.id.to_inner() + } + + public fun ref_fee_amount(arg0: &FlashSwapReceipt) : u64 { + arg0.ref_fee_amount + } + + public fun remove_liquidity( + config: &config::GlobalConfig, + pool: &mut Pool, + position: &mut Position, + liquidity: u128, + clock: &Clock + ) : (Balance, Balance) { + config::checked_package_version(config); + assert!(!pool.is_pause, 13); + assert!(liquidity > 0, 3); + rewarder::settle(&mut pool.rewarder_manager, pool.liquidity, sui::clock::timestamp_ms(clock) / 1000); + let (v0, v1) = position::tick_range(position); + let (v2, v3, v4, v5) = get_fee_rewards_points_in_tick_range(pool, v0, v1); + tick::decrease_liquidity(&mut pool.tick_manager, pool.current_tick_index, v0, v1, liquidity, pool.fee_growth_global_a, pool.fee_growth_global_b, rewarder::points_growth_global(&pool.rewarder_manager), rewarder::rewards_growth_global(&pool.rewarder_manager)); + if (integer_mate::i32::lte(v0, pool.current_tick_index) && integer_mate::i32::lt(pool.current_tick_index, v1)) { + pool.liquidity = pool.liquidity - liquidity; + }; + let (v6, v7) = get_amount_by_liquidity(v0, v1, pool.current_tick_index, pool.current_sqrt_price, liquidity, false); + let v8 = RemoveLiquidityEvent{ + pool : pool.id.to_inner(), + position : object::id(position), + tick_lower : v0, + tick_upper : v1, + liquidity : liquidity, + after_liquidity : position::decrease_liquidity(&mut pool.position_manager, position, liquidity, v2, v3, v5, v4), + amount_a : v6, + amount_b : v7, + }; + event::emit(v8); + (balance::split(&mut pool.coin_a, v6), balance::split(&mut pool.coin_b, v7)) + } + + public fun repay_add_liquidity(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: Balance, arg3: Balance, arg4: AddLiquidityReceipt) { + config::checked_package_version(arg0); + let AddLiquidityReceipt { + pool_id : v0, + amount_a : v1, + amount_b : v2, + } = arg4; + assert!(balance::value(&arg2) == v1, 0); + assert!(balance::value(&arg3) == v2, 0); + assert!(arg1.id.to_inner() == v0, 12); + balance::join(&mut arg1.coin_a, arg2); + balance::join(&mut arg1.coin_b, arg3); + } + + public fun repay_flash_swap(config: &config::GlobalConfig, arg1: &mut Pool, arg2: Balance, arg3: Balance, arg4: FlashSwapReceipt) { + config::checked_package_version(config); + assert!(!arg1.is_pause, 13); + let FlashSwapReceipt { + pool_id : v0, + a2b : v1, + partner_id : _, + pay_amount : v3, + ref_fee_amount : v4, + } = arg4; + assert!(arg1.id.to_inner() == v0, 14); + assert!(v4 == 0, 14); + + if (v1) { + assert!(balance::value(&arg2) == v3, 0); + balance::join(&mut arg1.coin_a, arg2); + balance::destroy_zero(arg3); + } else { + assert!(balance::value(&arg3) == v3, 0); + balance::join(&mut arg1.coin_b, arg3); + balance::destroy_zero(arg2); + }; + } + + public fun repay_flash_swap_with_partner(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: &mut Partner, mut arg3: Balance, mut arg4: Balance, arg5: FlashSwapReceipt) { + config::checked_package_version(arg0); + let FlashSwapReceipt { + pool_id : v0, + a2b : v1, + partner_id : v2, + pay_amount : v3, + ref_fee_amount : v4, + } = arg5; + assert!(arg1.id.to_inner() == v0, 14); + assert!(arg2.partner_id() == v2, 14); + if (v1) { + assert!(balance::value(&arg3) == v3, 0); + if (v4 > 0) { + partner::receive_ref_fee(arg2, balance::split(&mut arg3, v4)); + }; + balance::join(&mut arg1.coin_a, arg3); + balance::destroy_zero(arg4); + } else { + assert!(balance::value(&arg4) == v3, 0); + if (v4 > 0) { + partner::receive_ref_fee(arg2, balance::split(&mut arg4, v4)); + }; + balance::join(&mut arg1.coin_b, arg4); + balance::destroy_zero(arg3); + }; + } + + public fun rewarder_manager(arg0: &Pool) : &RewarderManager { + &arg0.rewarder_manager + } + + public fun set_display(arg0: &config::GlobalConfig, arg1: &sui::package::Publisher, arg2: std::string::String, arg3: std::string::String, arg4: std::string::String, arg5: std::string::String, arg6: std::string::String, arg7: std::string::String, arg8: &mut TxContext) { + config::checked_package_version(arg0); + let mut v0 = std::vector::empty(); + let v1 = &mut v0; + std::vector::push_back(v1, std::string::utf8(b"name")); + std::vector::push_back(v1, std::string::utf8(b"coin_a")); + std::vector::push_back(v1, std::string::utf8(b"coin_b")); + std::vector::push_back(v1, std::string::utf8(b"link")); + std::vector::push_back(v1, std::string::utf8(b"image_url")); + std::vector::push_back(v1, std::string::utf8(b"description")); + std::vector::push_back(v1, std::string::utf8(b"project_url")); + std::vector::push_back(v1, std::string::utf8(b"creator")); + let mut v2 = std::vector::empty(); + let v3 = &mut v2; + std::vector::push_back(v3, arg2); + std::vector::push_back(v3, std::string::from_ascii(type_name::into_string(type_name::get()))); + std::vector::push_back(v3, std::string::from_ascii(type_name::into_string(type_name::get()))); + std::vector::push_back(v3, arg5); + std::vector::push_back(v3, arg4); + std::vector::push_back(v3, arg3); + std::vector::push_back(v3, arg6); + std::vector::push_back(v3, arg7); + let mut v4 = sui::display::new_with_fields>(arg1, v0, v2, arg8); + sui::display::update_version>(&mut v4); + sui::transfer::public_transfer>>(v4, sender(arg8)); + } + + public fun step_swap_result_amount_in(arg0: &SwapStepResult) : u64 { + arg0.amount_in + } + + public fun step_swap_result_amount_out(arg0: &SwapStepResult) : u64 { + arg0.amount_out + } + + public fun step_swap_result_current_liquidity(arg0: &SwapStepResult) : u128 { + arg0.current_liquidity + } + + public fun step_swap_result_current_sqrt_price(arg0: &SwapStepResult) : u128 { + arg0.current_sqrt_price + } + + public fun step_swap_result_fee_amount(arg0: &SwapStepResult) : u64 { + arg0.fee_amount + } + + public fun step_swap_result_remainder_amount(arg0: &SwapStepResult) : u64 { + arg0.remainder_amount + } + + public fun step_swap_result_target_sqrt_price(arg0: &SwapStepResult) : u128 { + arg0.target_sqrt_price + } + + fun swap_in_pool(pool: &mut Pool, a2b: bool, by_amount_in: bool, sqrt_price_limit: u128, amount: u64, protocol_fee_rate: u64, ref_fee_rate: u64) : SwapResult { + assert!(ref_fee_rate <= 10000, 16); + let mut v0 = default_swap_result(); + let mut v1 = amount; + let mut v2 = tick::first_score_for_swap(&pool.tick_manager, pool.current_tick_index, a2b); + let mut v3 = 0; + + while (v1 > 0 && pool.current_sqrt_price != sqrt_price_limit) { + if (move_stl::option_u64::is_none(&v2)) { + abort 4 + }; + let (v4, v5) = tick::borrow_tick_for_swap(&pool.tick_manager, move_stl::option_u64::borrow(&v2), a2b); + v2 = v5; + let v6 = tick::index(v4); + let v7 = tick::sqrt_price(v4); + let v8 = if (a2b) { + integer_mate::math_u128::max(sqrt_price_limit, v7) + } else { + integer_mate::math_u128::min(sqrt_price_limit, v7) + }; + let (v9, v10, v11, v12) = clmm_math::compute_swap_step(pool.current_sqrt_price, v8, pool.liquidity, v1, pool.fee_rate, a2b, by_amount_in); + if (v9 != 0 || v12 != 0) { + if (by_amount_in) { + let v13 = check_remainer_amount_sub(v1, v9); + v1 = check_remainer_amount_sub(v13, v12); + } else { + v1 = check_remainer_amount_sub(v1, v10); + }; + update_swap_result(&mut v0, v9, v10, v12); + v3 = v3 + update_pool_fee(pool, v12, protocol_fee_rate, a2b); + }; + if (v11 == v7) { + pool.current_sqrt_price = v8; + let v14 = if (a2b) { + integer_mate::i32::sub(v6, integer_mate::i32::from(1)) + } else { + v6 + }; + pool.current_tick_index = v14; + pool.liquidity = tick::cross_by_swap(&mut pool.tick_manager, v6, a2b, pool.liquidity, pool.fee_growth_global_a, pool.fee_growth_global_b, rewarder::points_growth_global(&pool.rewarder_manager), rewarder::rewards_growth_global(&pool.rewarder_manager)); + continue + }; + if (pool.current_sqrt_price != v7) { + pool.current_sqrt_price = v11; + pool.current_tick_index = tick_math::get_tick_at_sqrt_price(v11); + continue + }; + }; + v0.ref_fee_amount = integer_mate::full_math_u64::mul_div_floor(v3, ref_fee_rate, 10000); + if (a2b) { + pool.fee_protocol_coin_a = pool.fee_protocol_coin_a + v3 - v0.ref_fee_amount; + } else { + pool.fee_protocol_coin_b = pool.fee_protocol_coin_b + v3 - v0.ref_fee_amount; + }; + v0 + } + + public(package) fun quote_swap_in_pool(pool: &Pool, a2b: bool, by_amount_in: bool, sqrt_price_limit: u128, amount: u64, protocol_fee_rate: u64, ref_fee_rate: u64) : (SwapResult, u128) { + assert!(ref_fee_rate <= 10000, 16); + let mut swap_result = default_swap_result(); + let mut v1 = amount; + let mut v2 = tick::first_score_for_swap(&pool.tick_manager, pool.current_tick_index, a2b); + let mut v3 = 0; + + let mut current_sqrt_price = pool.current_sqrt_price; + let mut _current_tick_index = pool.current_tick_index; + let mut liquidity = pool.liquidity; + + while (v1 > 0 && current_sqrt_price != sqrt_price_limit) { + if (move_stl::option_u64::is_none(&v2)) { + abort 4 + }; + let (v4, v5) = tick::borrow_tick_for_swap(&pool.tick_manager, move_stl::option_u64::borrow(&v2), a2b); + v2 = v5; + let v6 = tick::index(v4); + let v7 = tick::sqrt_price(v4); + let v8 = if (a2b) { + integer_mate::math_u128::max(sqrt_price_limit, v7) + } else { + integer_mate::math_u128::min(sqrt_price_limit, v7) + }; + let (v9, v10, v11, v12) = clmm_math::compute_swap_step(current_sqrt_price, v8, liquidity, v1, pool.fee_rate, a2b, by_amount_in); + if (v9 != 0 || v12 != 0) { + if (by_amount_in) { + let v13 = check_remainer_amount_sub(v1, v9); + v1 = check_remainer_amount_sub(v13, v12); + } else { + v1 = check_remainer_amount_sub(v1, v10); + }; + update_swap_result(&mut swap_result, v9, v10, v12); + v3 = v3 + quote_update_pool_fee(pool, v12, protocol_fee_rate, a2b); + }; + if (v11 == v7) { + current_sqrt_price = v8; + let v14 = if (a2b) { + integer_mate::i32::sub(v6, integer_mate::i32::from(1)) + } else { + v6 + }; + _current_tick_index = v14; + liquidity = tick::quote_cross_by_swap(&pool.tick_manager, v6, a2b, liquidity, pool.fee_growth_global_a, pool.fee_growth_global_b, rewarder::points_growth_global(&pool.rewarder_manager), rewarder::rewards_growth_global(&pool.rewarder_manager)); + continue + }; + if (current_sqrt_price != v7) { + current_sqrt_price = v11; + _current_tick_index = tick_math::get_tick_at_sqrt_price(v11); + continue + }; + }; + swap_result.ref_fee_amount = integer_mate::full_math_u64::mul_div_floor(v3, ref_fee_rate, 10000); + + (swap_result, current_sqrt_price) + } + + public fun swap_pay_amount(arg0: &FlashSwapReceipt) : u64 { + arg0.pay_amount + } + + public fun tick_manager(arg0: &Pool) : &TickManager { + &arg0.tick_manager + } + + public fun tick_spacing(arg0: &Pool) : u32 { + arg0.tick_spacing + } + + public fun unpause(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: &TxContext) { + config::checked_package_version(arg0); + config::check_pool_manager_role(arg0, sender(arg2)); + arg1.is_pause = false; + } + + public fun update_fee_rate(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: u64, arg3: &TxContext) { + config::checked_package_version(arg0); + assert!(!arg1.is_pause, 13); + if (arg2 > config::max_fee_rate()) { + abort 9 + }; + config::check_pool_manager_role(arg0, sender(arg3)); + arg1.fee_rate = arg2; + let v0 = UpdateFeeRateEvent{ + pool : arg1.id.to_inner(), + old_fee_rate : arg1.fee_rate, + new_fee_rate : arg2, + }; + event::emit(v0); + } + + fun update_pool_fee(arg0: &mut Pool, arg1: u64, arg2: u64, arg3: bool) : u64 { + let v0 = integer_mate::full_math_u64::mul_div_ceil(arg1, arg2, 10000); + let v1 = arg1 - v0; + if (v1 == 0 || arg0.liquidity == 0) { + return v0 + }; + if (arg3) { + arg0.fee_growth_global_a = integer_mate::math_u128::wrapping_add(arg0.fee_growth_global_a, ((v1 as u128) << 64) / arg0.liquidity); + } else { + arg0.fee_growth_global_b = integer_mate::math_u128::wrapping_add(arg0.fee_growth_global_b, ((v1 as u128) << 64) / arg0.liquidity); + }; + v0 + } + + fun quote_update_pool_fee(arg0: &Pool, arg1: u64, arg2: u64, _arg3: bool) : u64 { + let v0 = integer_mate::full_math_u64::mul_div_ceil(arg1, arg2, 10000); + let v1 = arg1 - v0; + if (v1 == 0 || arg0.liquidity == 0) { + return v0 + }; + + v0 + } + + public fun update_position_url(arg0: &config::GlobalConfig, arg1: &mut Pool, arg2: std::string::String, arg3: &TxContext) { + config::checked_package_version(arg0); + assert!(!arg1.is_pause, 13); + config::check_pool_manager_role(arg0, sender(arg3)); + arg1.url = arg2; + } + + fun update_swap_result(arg0: &mut SwapResult, arg1: u64, arg2: u64, arg3: u64) { + assert!(integer_mate::math_u64::add_check(arg0.amount_in, arg1), 6); + assert!(integer_mate::math_u64::add_check(arg0.amount_out, arg2), 7); + assert!(integer_mate::math_u64::add_check(arg0.fee_amount, arg3), 8); + arg0.amount_in = arg0.amount_in + arg1; + arg0.amount_out = arg0.amount_out + arg2; + arg0.fee_amount = arg0.fee_amount + arg3; + arg0.steps = arg0.steps + 1; + } + + public fun url(arg0: &Pool) : std::string::String { + arg0.url + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/cetus/sources/position.move b/contracts/dependencies/cetus/sources/position.move new file mode 100644 index 0000000..9f19403 --- /dev/null +++ b/contracts/dependencies/cetus/sources/position.move @@ -0,0 +1,455 @@ +#[allow(lint(self_transfer))] +module cetus_clmm::position { + use std::type_name::{TypeName}; + use sui::tx_context::{sender}; + use move_stl::linked_table::LinkedTable; + use integer_mate::i32::{I32}; + + public struct PositionManager has store { + tick_spacing: u32, + position_index: u64, + positions: LinkedTable, + } + + public struct POSITION has drop {} + + public struct Position has store, key { + id: UID, + pool: ID, + index: u64, + coin_type_a: TypeName, + coin_type_b: TypeName, + name: std::string::String, + description: std::string::String, + url: std::string::String, + tick_lower_index: I32, + tick_upper_index: I32, + liquidity: u128, + } + + public struct PositionInfo has copy, drop, store { + position_id: ID, + liquidity: u128, + tick_lower_index: I32, + tick_upper_index: I32, + fee_growth_inside_a: u128, + fee_growth_inside_b: u128, + fee_owned_a: u64, + fee_owned_b: u64, + points_owned: u128, + points_growth_inside: u128, + rewards: vector, + } + + public struct PositionReward has copy, drop, store { + growth_inside: u128, + amount_owned: u64, + } + + public fun is_empty(arg0: &PositionInfo) : bool { + let mut v0 = true; + let mut v1 = 0; + while (v1 < std::vector::length(&arg0.rewards)) { + let v2 = if (v0) { + let v3 = std::vector::borrow(&arg0.rewards, v1).amount_owned; + v3 == 0 + } else { + false + }; + v0 = v2; + v1 = v1 + 1; + }; + let v4 = arg0.liquidity == 0 && arg0.fee_owned_a == 0 && arg0.fee_owned_b == 0; + v4 && v0 + } + + public(package) fun new(arg0: u32, arg1: &mut TxContext) : PositionManager { + PositionManager{ + tick_spacing : arg0, + position_index : 0, + positions : move_stl::linked_table::new(arg1), + } + } + + fun borrow_mut_position_info(arg0: &mut PositionManager, arg1: ID) : &mut PositionInfo { + assert!(move_stl::linked_table::contains(&arg0.positions, arg1), 6); + let v0 = move_stl::linked_table::borrow_mut(&mut arg0.positions, arg1); + assert!(v0.position_id == arg1, 6); + v0 + } + + public fun borrow_position_info(arg0: &PositionManager, arg1: ID) : &PositionInfo { + assert!(move_stl::linked_table::contains(&arg0.positions, arg1), 6); + let v0 = move_stl::linked_table::borrow(&arg0.positions, arg1); + assert!(v0.position_id == arg1, 6); + v0 + } + + public fun check_position_tick_range(tick_lower: I32, tick_upper: I32, tick_spacing: u32) { + assert!( + integer_mate::i32::lt(tick_lower, tick_upper) + && integer_mate::i32::gte(tick_lower, cetus_clmm::tick_math::min_tick()) + && integer_mate::i32::lte(tick_upper, cetus_clmm::tick_math::max_tick()) + && integer_mate::i32::mod(tick_lower, integer_mate::i32::from(tick_spacing)) == integer_mate::i32::zero() + && integer_mate::i32::mod(tick_upper, integer_mate::i32::from(tick_spacing)) == integer_mate::i32::zero(), + 5); + } + + public(package) fun close_position(arg0: &mut PositionManager, arg1: Position) { + let v0 = arg1.id.to_inner(); + if (!is_empty(borrow_mut_position_info(arg0, v0))) { + abort 7 + }; + move_stl::linked_table::remove(&mut arg0.positions, v0); + destroy(arg1); + } + + public(package) fun decrease_liquidity(arg0: &mut PositionManager, arg1: &mut Position, arg2: u128, arg3: u128, arg4: u128, arg5: u128, arg6: vector) : u128 { + let v0 = borrow_mut_position_info(arg0, arg1.id.to_inner()); + if (arg2 == 0) { + return v0.liquidity + }; + update_fee_internal(v0, arg3, arg4); + update_points_internal(v0, arg5); + update_rewards_internal(v0, arg6); + assert!(v0.liquidity >= arg2, 9); + v0.liquidity = v0.liquidity - arg2; + arg1.liquidity = v0.liquidity; + v0.liquidity + } + + public fun description(arg0: &Position) : std::string::String { + arg0.description + } + + fun destroy(arg0: Position) { + let Position { + id : v0, + pool : _, + index : _, + coin_type_a : _, + coin_type_b : _, + name : _, + description : _, + url : _, + tick_lower_index : _, + tick_upper_index : _, + liquidity : _, + } = arg0; + sui::object::delete(v0); + } + + public fun fetch_positions(arg0: &PositionManager, arg1: vector, arg2: u64) : vector { + let mut v0 = std::vector::empty(); + let v1 = if (std::vector::is_empty(&arg1)) { + move_stl::linked_table::head(&arg0.positions) + } else { + move_stl::linked_table::next(move_stl::linked_table::borrow_node(&arg0.positions, *std::vector::borrow(&arg1, 0))) + }; + let mut v2 = v1; + let mut v3 = 0; + while (std::option::is_some(&v2)) { + let v4 = move_stl::linked_table::borrow_node(&arg0.positions, *std::option::borrow(&v2)); + v2 = move_stl::linked_table::next(v4); + std::vector::push_back(&mut v0, *move_stl::linked_table::borrow_value(v4)); + let v5 = v3 + 1; + v3 = v5; + if (v5 == arg2) { + break + }; + }; + v0 + } + + public(package) fun increase_liquidity(arg0: &mut PositionManager, arg1: &mut Position, arg2: u128, arg3: u128, arg4: u128, arg5: u128, arg6: vector) : u128 { + let v0 = borrow_mut_position_info(arg0, arg1.id.to_inner()); + update_fee_internal(v0, arg3, arg4); + update_points_internal(v0, arg5); + update_rewards_internal(v0, arg6); + assert!(integer_mate::math_u128::add_check(v0.liquidity, arg2), 8); + v0.liquidity = v0.liquidity + arg2; + arg1.liquidity = v0.liquidity; + v0.liquidity + } + + public fun index(arg0: &Position) : u64 { + arg0.index + } + + public fun info_fee_growth_inside(arg0: &PositionInfo) : (u128, u128) { + (arg0.fee_growth_inside_a, arg0.fee_growth_inside_b) + } + + public fun info_fee_owned(arg0: &PositionInfo) : (u64, u64) { + (arg0.fee_owned_a, arg0.fee_owned_b) + } + + public fun info_liquidity(arg0: &PositionInfo) : u128 { + arg0.liquidity + } + + public fun info_points_growth_inside(arg0: &PositionInfo) : u128 { + arg0.points_growth_inside + } + + public fun info_points_owned(arg0: &PositionInfo) : u128 { + arg0.points_owned + } + + public fun info_position_id(arg0: &PositionInfo) : ID { + arg0.position_id + } + + public fun info_rewards(arg0: &PositionInfo) : &vector { + &arg0.rewards + } + + public fun info_tick_range(arg0: &PositionInfo) : (I32, I32) { + (arg0.tick_lower_index, arg0.tick_upper_index) + } + + fun init(arg0: POSITION, arg1: &mut TxContext) { + let mut v0 = std::vector::empty(); + let v1 = &mut v0; + std::vector::push_back(v1, std::string::utf8(b"name")); + std::vector::push_back(v1, std::string::utf8(b"coin_a")); + std::vector::push_back(v1, std::string::utf8(b"coin_b")); + std::vector::push_back(v1, std::string::utf8(b"link")); + std::vector::push_back(v1, std::string::utf8(b"image_url")); + std::vector::push_back(v1, std::string::utf8(b"description")); + std::vector::push_back(v1, std::string::utf8(b"project_url")); + std::vector::push_back(v1, std::string::utf8(b"creator")); + let mut v2 = std::vector::empty(); + let v3 = &mut v2; + std::vector::push_back(v3, std::string::utf8(b"{name}")); + std::vector::push_back(v3, std::string::utf8(b"{coin_type_a}")); + std::vector::push_back(v3, std::string::utf8(b"{coin_type_b}")); + std::vector::push_back(v3, std::string::utf8(b"https://app.cetus.zone/position?chain=sui&id={id}")); + std::vector::push_back(v3, std::string::utf8(b"{url}")); + std::vector::push_back(v3, std::string::utf8(b"{description}")); + std::vector::push_back(v3, std::string::utf8(b"https://cetus.zone")); + std::vector::push_back(v3, std::string::utf8(b"Cetus")); + let v4 = sui::package::claim(arg0, arg1); + let mut v5 = sui::display::new_with_fields(&v4, v0, v2, arg1); + sui::display::update_version(&mut v5); + sui::transfer::public_transfer(v4, sender(arg1)); + sui::transfer::public_transfer>(v5, sender(arg1)); + } + + public fun inited_rewards_count(arg0: &PositionManager, arg1: ID) : u64 { + std::vector::length(&move_stl::linked_table::borrow(&arg0.positions, arg1).rewards) + } + + public fun is_position_exist(arg0: &PositionManager, arg1: ID) : bool { + move_stl::linked_table::contains(&arg0.positions, arg1) + } + + public fun liquidity(arg0: &Position) : u128 { + arg0.liquidity + } + + public fun name(arg0: &Position) : std::string::String { + arg0.name + } + + fun new_position_name(arg0: u64, arg1: u64) : std::string::String { + let mut v0 = std::string::utf8(b"Cetus LP | Pool"); + std::string::append(&mut v0, cetus_clmm::utils::str(arg0)); + std::string::append_utf8(&mut v0, b"-"); + std::string::append(&mut v0, cetus_clmm::utils::str(arg1)); + v0 + } + + public(package) fun open_position(arg0: &mut PositionManager, arg1: ID, arg2: u64, arg3: std::string::String, arg4: I32, arg5: I32, arg6: &mut TxContext) : Position { + check_position_tick_range(arg4, arg5, arg0.tick_spacing); + let v0 = arg0.position_index + 1; + let v1 = Position{ + id : sui::object::new(arg6), + pool : arg1, + index : v0, + coin_type_a : std::type_name::get(), + coin_type_b : std::type_name::get(), + name : new_position_name(arg2, v0), + description : std::string::utf8(b"Cetus Liquidity Position"), + url : arg3, + tick_lower_index : arg4, + tick_upper_index : arg5, + liquidity : 0, + }; + let v2 = v1.id.to_inner(); + let v3 = PositionInfo{ + position_id : v2, + liquidity : 0, + tick_lower_index : arg4, + tick_upper_index : arg5, + fee_growth_inside_a : 0, + fee_growth_inside_b : 0, + fee_owned_a : 0, + fee_owned_b : 0, + points_owned : 0, + points_growth_inside : 0, + rewards : std::vector::empty(), + }; + move_stl::linked_table::push_back(&mut arg0.positions, v2, v3); + arg0.position_index = v0; + v1 + } + + public fun pool_id(arg0: &Position) : ID { + arg0.pool + } + + public(package) fun reset_fee(arg0: &mut PositionManager, arg1: ID) : (u64, u64) { + let v0 = borrow_mut_position_info(arg0, arg1); + v0.fee_owned_a = 0; + v0.fee_owned_b = 0; + (v0.fee_owned_a, v0.fee_owned_b) + } + + public(package) fun reset_rewarder(arg0: &mut PositionManager, arg1: ID, arg2: u64) : u64 { + let v0 = std::vector::borrow_mut(&mut borrow_mut_position_info(arg0, arg1).rewards, arg2); + v0.amount_owned = 0; + v0.amount_owned + } + + public fun reward_amount_owned(arg0: &PositionReward) : u64 { + arg0.amount_owned + } + + public fun reward_growth_inside(arg0: &PositionReward) : u128 { + arg0.growth_inside + } + + public(package) fun rewards_amount_owned(arg0: &PositionManager, arg1: ID) : vector { + let v0 = info_rewards(borrow_position_info(arg0, arg1)); + let mut v1 = 0; + let mut v2 = std::vector::empty(); + while (v1 < std::vector::length(v0)) { + std::vector::push_back(&mut v2, reward_amount_owned(std::vector::borrow(v0, v1))); + v1 = v1 + 1; + }; + v2 + } + + public fun set_display(arg0: &cetus_clmm::config::GlobalConfig, arg1: &sui::package::Publisher, arg2: std::string::String, arg3: std::string::String, arg4: std::string::String, arg5: std::string::String, arg6: &mut TxContext) { + cetus_clmm::config::checked_package_version(arg0); + let mut v0 = std::vector::empty(); + let v1 = &mut v0; + std::vector::push_back(v1, std::string::utf8(b"name")); + std::vector::push_back(v1, std::string::utf8(b"coin_a")); + std::vector::push_back(v1, std::string::utf8(b"coin_b")); + std::vector::push_back(v1, std::string::utf8(b"link")); + std::vector::push_back(v1, std::string::utf8(b"image_url")); + std::vector::push_back(v1, std::string::utf8(b"description")); + std::vector::push_back(v1, std::string::utf8(b"project_url")); + std::vector::push_back(v1, std::string::utf8(b"creator")); + let mut v2 = std::vector::empty(); + let v3 = &mut v2; + std::vector::push_back(v3, std::string::utf8(b"{name}")); + std::vector::push_back(v3, std::string::utf8(b"{coin_type_a}")); + std::vector::push_back(v3, std::string::utf8(b"{coin_type_b}")); + std::vector::push_back(v3, arg3); + std::vector::push_back(v3, std::string::utf8(b"{url}")); + std::vector::push_back(v3, arg2); + std::vector::push_back(v3, arg4); + std::vector::push_back(v3, arg5); + let mut v4 = sui::display::new_with_fields(arg1, v0, v2, arg6); + sui::display::update_version(&mut v4); + sui::transfer::public_transfer>(v4, sender(arg6)); + } + + public fun tick_range(arg0: &Position) : (I32, I32) { + (arg0.tick_lower_index, arg0.tick_upper_index) + } + + public(package) fun update_and_reset_fee(arg0: &mut PositionManager, arg1: ID, arg2: u128, arg3: u128) : (u64, u64) { + let v0 = borrow_mut_position_info(arg0, arg1); + update_fee_internal(v0, arg2, arg3); + v0.fee_owned_a = 0; + v0.fee_owned_b = 0; + (v0.fee_owned_a, v0.fee_owned_b) + } + + public(package) fun update_and_reset_rewards(arg0: &mut PositionManager, arg1: ID, arg2: vector, arg3: u64) : u64 { + assert!(std::vector::length(&arg2) > arg3, 10); + let v0 = borrow_mut_position_info(arg0, arg1); + update_rewards_internal(v0, arg2); + let v1 = std::vector::borrow_mut(&mut v0.rewards, arg3); + v1.amount_owned = 0; + v1.amount_owned + } + + public(package) fun update_fee(arg0: &mut PositionManager, arg1: ID, arg2: u128, arg3: u128) : (u64, u64) { + let v0 = borrow_mut_position_info(arg0, arg1); + update_fee_internal(v0, arg2, arg3); + info_fee_owned(v0) + } + + fun update_fee_internal(arg0: &mut PositionInfo, arg1: u128, arg2: u128) { + let v0 = (integer_mate::full_math_u128::mul_shr(arg0.liquidity, integer_mate::math_u128::wrapping_sub(arg1, arg0.fee_growth_inside_a), 64) as u64); + let v1 = (integer_mate::full_math_u128::mul_shr(arg0.liquidity, integer_mate::math_u128::wrapping_sub(arg2, arg0.fee_growth_inside_b), 64) as u64); + assert!(integer_mate::math_u64::add_check(arg0.fee_owned_a, v0), 1); + assert!(integer_mate::math_u64::add_check(arg0.fee_owned_b, v1), 1); + arg0.fee_owned_a = arg0.fee_owned_a + v0; + arg0.fee_owned_b = arg0.fee_owned_b + v1; + arg0.fee_growth_inside_a = arg1; + arg0.fee_growth_inside_b = arg2; + } + + public(package) fun update_points(arg0: &mut PositionManager, arg1: ID, arg2: u128) : u128 { + let v0 = borrow_mut_position_info(arg0, arg1); + update_points_internal(v0, arg2); + v0.points_owned + } + + fun update_points_internal(arg0: &mut PositionInfo, arg1: u128) { + let v0 = integer_mate::full_math_u128::mul_shr(arg0.liquidity, integer_mate::math_u128::wrapping_sub(arg1, arg0.points_growth_inside), 64); + assert!(integer_mate::math_u128::add_check(arg0.points_owned, v0), 3); + arg0.points_owned = arg0.points_owned + v0; + arg0.points_growth_inside = arg1; + } + + public(package) fun update_rewards(arg0: &mut PositionManager, arg1: ID, arg2: vector) : vector { + let v0 = borrow_mut_position_info(arg0, arg1); + update_rewards_internal(v0, arg2); + let v1 = info_rewards(v0); + let mut v2 = 0; + let mut v3 = std::vector::empty(); + while (v2 < std::vector::length(v1)) { + std::vector::push_back(&mut v3, reward_amount_owned(std::vector::borrow(v1, v2))); + v2 = v2 + 1; + }; + v3 + } + + fun update_rewards_internal(arg0: &mut PositionInfo, arg1: vector) { + let v0 = std::vector::length(&arg1); + if (v0 > 0) { + let mut v1 = 0; + while (v1 < v0) { + let v2 = *std::vector::borrow(&arg1, v1); + if (std::vector::length(&arg0.rewards) > v1) { + let v3 = std::vector::borrow_mut(&mut arg0.rewards, v1); + let v4 = (integer_mate::full_math_u128::mul_shr(integer_mate::math_u128::wrapping_sub(v2, v3.growth_inside), arg0.liquidity, 64) as u64); + assert!(integer_mate::math_u64::add_check(v3.amount_owned, v4), 2); + v3.growth_inside = v2; + v3.amount_owned = v3.amount_owned + v4; + } else { + let v5 = PositionReward{ + growth_inside : v2, + amount_owned : (integer_mate::full_math_u128::mul_shr(v2, arg0.liquidity, 64) as u64), + }; + std::vector::push_back(&mut arg0.rewards, v5); + }; + v1 = v1 + 1; + }; + }; + } + + public fun url(arg0: &Position) : std::string::String { + arg0.url + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/cetus/sources/rewarder.move b/contracts/dependencies/cetus/sources/rewarder.move new file mode 100644 index 0000000..c6b63d8 --- /dev/null +++ b/contracts/dependencies/cetus/sources/rewarder.move @@ -0,0 +1,217 @@ +module cetus_clmm::rewarder { + use std::type_name::{TypeName}; + use sui::event; + use sui::balance::{Balance}; + use sui::transfer::{share_object}; + + public struct RewarderManager has store { + rewarders: vector, + points_released: u128, + points_growth_global: u128, + last_updated_time: u64, + } + + public struct Rewarder has copy, drop, store { + reward_coin: TypeName, + emissions_per_second: u128, + growth_global: u128, + } + + public struct RewarderGlobalVault has store, key { + id: UID, + balances: sui::bag::Bag, + } + + public struct RewarderInitEvent has copy, drop { + global_vault_id: ID, + } + + public struct DepositEvent has copy, drop, store { + reward_type: TypeName, + deposit_amount: u64, + after_amount: u64, + } + + public struct EmergentWithdrawEvent has copy, drop, store { + reward_type: TypeName, + withdraw_amount: u64, + after_amount: u64, + } + + public(package) fun new() : RewarderManager { + RewarderManager{ + rewarders : std::vector::empty(), + points_released : 0, + points_growth_global : 0, + last_updated_time : 0, + } + } + + public(package) fun add_rewarder(arg0: &mut RewarderManager) { + let v0 = rewarder_index(arg0); + assert!(std::option::is_none(&v0), 2); + let v1 = &mut arg0.rewarders; + assert!(std::vector::length(v1) <= 3 - 1, 1); + let v2 = Rewarder{ + reward_coin : std::type_name::get(), + emissions_per_second : 0, + growth_global : 0, + }; + std::vector::push_back(v1, v2); + } + + public fun balance_of(arg0: &RewarderGlobalVault) : u64 { + let v0 = std::type_name::get(); + if (!sui::bag::contains(&arg0.balances, v0)) { + return 0 + }; + sui::balance::value(sui::bag::borrow>(&arg0.balances, v0)) + } + + public fun balances(arg0: &RewarderGlobalVault) : &sui::bag::Bag { + &arg0.balances + } + + public(package) fun borrow_mut_rewarder(arg0: &mut RewarderManager) : &mut Rewarder { + let mut v0 = 0; + while (v0 < std::vector::length(&arg0.rewarders)) { + if (std::vector::borrow(&arg0.rewarders, v0).reward_coin == std::type_name::get()) { + return std::vector::borrow_mut(&mut arg0.rewarders, v0) + }; + v0 = v0 + 1; + }; + abort 5 + } + + public fun borrow_rewarder(arg0: &RewarderManager) : &Rewarder { + let mut v0 = 0; + while (v0 < std::vector::length(&arg0.rewarders)) { + if (std::vector::borrow(&arg0.rewarders, v0).reward_coin == std::type_name::get()) { + return std::vector::borrow(&arg0.rewarders, v0) + }; + v0 = v0 + 1; + }; + abort 5 + } + + public fun deposit_reward(arg0: &cetus_clmm::config::GlobalConfig, arg1: &mut RewarderGlobalVault, arg2: Balance) : u64 { + cetus_clmm::config::checked_package_version(arg0); + let v0 = std::type_name::get(); + if (!sui::bag::contains(&arg1.balances, v0)) { + sui::bag::add>(&mut arg1.balances, v0, sui::balance::zero()); + }; + let deposit_amount = sui::balance::value(&arg2); + let v1 = sui::balance::join(sui::bag::borrow_mut>(&mut arg1.balances, std::type_name::get()), arg2); + let v2 = DepositEvent{ + reward_type : std::type_name::get(), + deposit_amount, + after_amount : v1, + }; + event::emit(v2); + v1 + } + + public fun emergent_withdraw(_arg0: &cetus_clmm::config::AdminCap, arg1: &cetus_clmm::config::GlobalConfig, arg2: &mut RewarderGlobalVault, arg3: u64) : Balance { + cetus_clmm::config::checked_package_version(arg1); + let v0 = EmergentWithdrawEvent{ + reward_type : std::type_name::get(), + withdraw_amount : arg3, + after_amount : balance_of(arg2), + }; + event::emit(v0); + withdraw_reward(arg2, arg3) + } + + public fun emissions_per_second(arg0: &Rewarder) : u128 { + arg0.emissions_per_second + } + + public fun growth_global(arg0: &Rewarder) : u128 { + arg0.growth_global + } + + fun init(arg0: &mut TxContext) { + let v0 = RewarderGlobalVault{ + id : sui::object::new(arg0), + balances : sui::bag::new(arg0), + }; + let global_vault_id = v0.id.to_inner(); + share_object(v0); + let v1 = RewarderInitEvent{ global_vault_id }; + event::emit(v1); + } + + public fun last_update_time(arg0: &RewarderManager) : u64 { + arg0.last_updated_time + } + + public fun points_growth_global(arg0: &RewarderManager) : u128 { + arg0.points_growth_global + } + + public fun points_released(arg0: &RewarderManager) : u128 { + arg0.points_released + } + + public fun reward_coin(arg0: &Rewarder) : TypeName { + arg0.reward_coin + } + + public fun rewarder_index(arg0: &RewarderManager) : std::option::Option { + let mut v0 = 0; + while (v0 < std::vector::length(&arg0.rewarders)) { + if (std::vector::borrow(&arg0.rewarders, v0).reward_coin == std::type_name::get()) { + return std::option::some(v0) + }; + v0 = v0 + 1; + }; + std::option::none() + } + + public fun rewarders(arg0: &RewarderManager) : vector { + arg0.rewarders + } + + public fun rewards_growth_global(arg0: &RewarderManager) : vector { + let mut v0 = 0; + let mut v1 = std::vector::empty(); + while (v0 < std::vector::length(&arg0.rewarders)) { + std::vector::push_back(&mut v1, std::vector::borrow(&arg0.rewarders, v0).growth_global); + v0 = v0 + 1; + }; + v1 + } + + public(package) fun settle(reward_manager: &mut RewarderManager, liquidity: u128, current_time: u64) { + let last_updated_time = reward_manager.last_updated_time; + reward_manager.last_updated_time = current_time; + assert!(last_updated_time <= current_time, 3); + if (liquidity == 0 || current_time == last_updated_time) { + return + }; + let time_delta = current_time - last_updated_time; + let mut i = 0; + while (i < std::vector::length(&reward_manager.rewarders)) { + std::vector::borrow_mut(&mut reward_manager.rewarders, i).growth_global = std::vector::borrow(&reward_manager.rewarders, i).growth_global + integer_mate::full_math_u128::mul_div_floor((time_delta as u128), std::vector::borrow(&reward_manager.rewarders, i).emissions_per_second, liquidity); + i = i + 1; + }; + reward_manager.points_released = reward_manager.points_released + (time_delta as u128) * 18446744073709551616000000; + reward_manager.points_growth_global = reward_manager.points_growth_global + integer_mate::full_math_u128::mul_div_floor((time_delta as u128), 18446744073709551616000000, liquidity); + } + + public(package) fun update_emission(arg0: &RewarderGlobalVault, arg1: &mut RewarderManager, arg2: u128, arg3: u128, arg4: u64) { + assert!(arg3 >= 213503982334602, 6); + settle(arg1, arg2, arg4); + let v0 = std::type_name::get(); + assert!(sui::bag::contains(&arg0.balances, v0), 4); + assert!(sui::balance::value(sui::bag::borrow>(&arg0.balances, v0)) >= (integer_mate::full_math_u128::mul_shr(86400, arg3, 64) as u64), 4); + borrow_mut_rewarder(arg1).emissions_per_second = arg3; + } + + public(package) fun withdraw_reward(arg0: &mut RewarderGlobalVault, arg1: u64) : Balance { + sui::balance::split(sui::bag::borrow_mut>(&mut arg0.balances, std::type_name::get()), arg1) + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/cetus/sources/tick.move b/contracts/dependencies/cetus/sources/tick.move new file mode 100644 index 0000000..a518020 --- /dev/null +++ b/contracts/dependencies/cetus/sources/tick.move @@ -0,0 +1,388 @@ +module cetus_clmm::tick { + use integer_mate::i32::{I32}; + + public struct TickManager has store { + tick_spacing: u32, + ticks: move_stl::skip_list::SkipList, + } + + public struct Tick has copy, drop, store { + index: I32, + sqrt_price: u128, + liquidity_net: integer_mate::i128::I128, + liquidity_gross: u128, + fee_growth_outside_a: u128, + fee_growth_outside_b: u128, + points_growth_outside: u128, + rewards_growth_outside: vector, + } + + public(package) fun new(arg0: u32, arg1: u64, arg2: &mut TxContext) : TickManager { + let mut v0 = TickManager{ + tick_spacing : arg0, + ticks : move_stl::skip_list::new(16, 2, arg1, arg2), + }; + let v1 = cetus_clmm::tick_math::tick_bound(); + let v2 = integer_mate::i32::from(v1 - v1 % arg0); + let v3 = integer_mate::i32::neg_from(v1 - v1 % arg0); + move_stl::skip_list::insert(&mut v0.ticks, tick_score(v3), default(v3)); + move_stl::skip_list::insert(&mut v0.ticks, tick_score(v2), default(v2)); + v0 + } + + public fun borrow_tick(arg0: &TickManager, arg1: I32) : &Tick { + move_stl::skip_list::borrow(&arg0.ticks, tick_score(arg1)) + } + + public fun borrow_tick_for_swap(arg0: &TickManager, arg1: u64, arg2: bool) : (&Tick, move_stl::option_u64::OptionU64) { + let v0 = move_stl::skip_list::borrow_node(&arg0.ticks, arg1); + let v1 = if (arg2) { + move_stl::skip_list::prev_score(v0) + } else { + move_stl::skip_list::next_score(v0) + }; + (move_stl::skip_list::borrow_value(v0), v1) + } + + public(package) fun cross_by_swap(tick_manager: &mut TickManager, arg1: I32, a2b: bool, liquidity: u128, fee_growth_global_a: u128, fee_growth_global_b: u128, points_growth_global: u128, rewards_growth_global: vector) : u128 { + let v0 = move_stl::skip_list::borrow_mut(&mut tick_manager.ticks, tick_score(arg1)); + let v1 = if (a2b) { + integer_mate::i128::neg(v0.liquidity_net) + } else { + v0.liquidity_net + }; + let v2 = if (!integer_mate::i128::is_neg(v1)) { + let v3 = integer_mate::i128::abs_u128(v1); + assert!(integer_mate::math_u128::add_check(v3, liquidity), 1); + liquidity + v3 + } else { + let v4 = integer_mate::i128::abs_u128(v1); + assert!(liquidity >= v4, 1); + liquidity - v4 + }; + v0.fee_growth_outside_a = integer_mate::math_u128::wrapping_sub(fee_growth_global_a, v0.fee_growth_outside_a); + v0.fee_growth_outside_b = integer_mate::math_u128::wrapping_sub(fee_growth_global_b, v0.fee_growth_outside_b); + let v5 = std::vector::length(&rewards_growth_global); + if (v5 > 0) { + let mut v6 = 0; + while (v6 < v5) { + let v7 = *std::vector::borrow(&rewards_growth_global, v6); + if (std::vector::length(&v0.rewards_growth_outside) > v6) { + let v8 = integer_mate::math_u128::wrapping_sub(v7, *std::vector::borrow(&v0.rewards_growth_outside, v6)); + let v9 = std::vector::borrow_mut(&mut v0.rewards_growth_outside, v6); + *v9 = v8; + } else { + std::vector::push_back(&mut v0.rewards_growth_outside, v7); + }; + v6 = v6 + 1; + }; + }; + v0.points_growth_outside = integer_mate::math_u128::wrapping_sub(points_growth_global, v0.points_growth_outside); + v2 + } + + public(package) fun quote_cross_by_swap(tick_manager: &TickManager, arg1: I32, a2b: bool, liquidity: u128, _fee_growth_global_a: u128, _fee_growth_global_b: u128, _points_growth_global: u128, _rewards_growth_global: vector) : u128 { + let v0 = move_stl::skip_list::borrow(&tick_manager.ticks, tick_score(arg1)); + let v1 = if (a2b) { + integer_mate::i128::neg(v0.liquidity_net) + } else { + v0.liquidity_net + }; + let v2 = if (!integer_mate::i128::is_neg(v1)) { + let v3 = integer_mate::i128::abs_u128(v1); + assert!(integer_mate::math_u128::add_check(v3, liquidity), 1); + liquidity + v3 + } else { + let v4 = integer_mate::i128::abs_u128(v1); + assert!(liquidity >= v4, 1); + liquidity - v4 + }; + v2 + } + + public(package) fun decrease_liquidity(arg0: &mut TickManager, arg1: I32, arg2: I32, arg3: I32, arg4: u128, arg5: u128, arg6: u128, arg7: u128, arg8: vector) { + if (arg4 == 0) { + return + }; + let v0 = tick_score(arg2); + let v1 = tick_score(arg3); + assert!(move_stl::skip_list::contains(&arg0.ticks, v0), 3); + assert!(move_stl::skip_list::contains(&arg0.ticks, v1), 3); + let v2 = cetus_clmm::tick_math::tick_bound(); + if (update_by_liquidity(move_stl::skip_list::borrow_mut(&mut arg0.ticks, v0), arg1, arg4, false, false, false, arg5, arg6, arg7, arg8) == 0 && !integer_mate::i32::eq(arg2, integer_mate::i32::neg_from(v2 - v2 % arg0.tick_spacing))) { + move_stl::skip_list::remove(&mut arg0.ticks, v0); + }; + if (update_by_liquidity(move_stl::skip_list::borrow_mut(&mut arg0.ticks, v1), arg1, arg4, false, false, true, arg5, arg6, arg7, arg8) == 0 && !integer_mate::i32::eq(arg3, integer_mate::i32::from(v2 - v2 % arg0.tick_spacing))) { + move_stl::skip_list::remove(&mut arg0.ticks, v1); + }; + } + + fun default(arg0: I32) : Tick { + Tick{ + index : arg0, + sqrt_price : cetus_clmm::tick_math::get_sqrt_price_at_tick(arg0), + liquidity_net : integer_mate::i128::from(0), + liquidity_gross : 0, + fee_growth_outside_a : 0, + fee_growth_outside_b : 0, + points_growth_outside : 0, + rewards_growth_outside : std::vector::empty(), + } + } + + fun default_rewards_growth_outside(arg0: u64) : vector { + if (arg0 <= 0) { + std::vector::empty() + } else { + let mut v1 = std::vector::empty(); + let mut v2 = 0; + while (v2 < arg0) { + std::vector::push_back(&mut v1, 0); + v2 = v2 + 1; + }; + v1 + } + } + + public fun fee_growth_outside(arg0: &Tick) : (u128, u128) { + (arg0.fee_growth_outside_a, arg0.fee_growth_outside_b) + } + + public fun fetch_ticks(arg0: &TickManager, arg1: vector, arg2: u64) : vector { + let mut v0 = std::vector::empty(); + let v1 = if (std::vector::is_empty(&arg1)) { + move_stl::skip_list::head(&arg0.ticks) + } else { + move_stl::skip_list::find_next(&arg0.ticks, tick_score(integer_mate::i32::from_u32(*std::vector::borrow(&arg1, 0))), false) + }; + let mut v2 = v1; + let mut v3 = 0; + while (move_stl::option_u64::is_some(&v2)) { + let v4 = move_stl::skip_list::borrow_node(&arg0.ticks, move_stl::option_u64::borrow(&v2)); + std::vector::push_back(&mut v0, *move_stl::skip_list::borrow_value(v4)); + v2 = move_stl::skip_list::next_score(v4); + let v5 = v3 + 1; + v3 = v5; + if (v5 == arg2) { + break + }; + }; + v0 + } + + public fun first_score_for_swap(arg0: &TickManager, arg1: I32, arg2: bool) : move_stl::option_u64::OptionU64 { + if (arg2) { + move_stl::skip_list::find_prev(&arg0.ticks, tick_score(arg1), true) + } else { + move_stl::skip_list::find_next(&arg0.ticks, tick_score(arg1), false) + } + } + + public fun get_fee_in_range(arg0: I32, arg1: u128, arg2: u128, arg3: std::option::Option, arg4: std::option::Option) : (u128, u128) { + let (v0, v1) = if (std::option::is_none(&arg3)) { + (arg1, arg2) + } else { + let v2 = std::option::borrow(&arg3); + let (v3, v4) = if (integer_mate::i32::lt(arg0, v2.index)) { + (integer_mate::math_u128::wrapping_sub(arg1, v2.fee_growth_outside_a), integer_mate::math_u128::wrapping_sub(arg2, v2.fee_growth_outside_b)) + } else { + (v2.fee_growth_outside_a, v2.fee_growth_outside_b) + }; + (v3, v4) + }; + let (v5, v6) = if (std::option::is_none(&arg4)) { + (0, 0) + } else { + let v7 = std::option::borrow(&arg4); + let (v8, v9) = if (integer_mate::i32::lt(arg0, v7.index)) { + (v7.fee_growth_outside_a, v7.fee_growth_outside_b) + } else { + (integer_mate::math_u128::wrapping_sub(arg1, v7.fee_growth_outside_a), integer_mate::math_u128::wrapping_sub(arg2, v7.fee_growth_outside_b)) + }; + (v8, v9) + }; + (integer_mate::math_u128::wrapping_sub(integer_mate::math_u128::wrapping_sub(arg1, v0), v5), integer_mate::math_u128::wrapping_sub(integer_mate::math_u128::wrapping_sub(arg2, v1), v6)) + } + + public fun get_points_in_range(arg0: I32, arg1: u128, arg2: std::option::Option, arg3: std::option::Option) : u128 { + let v0 = if (std::option::is_none(&arg2)) { + arg1 + } else { + let v1 = std::option::borrow(&arg2); + let v2 = if (integer_mate::i32::lt(arg0, v1.index)) { + integer_mate::math_u128::wrapping_sub(arg1, v1.points_growth_outside) + } else { + v1.points_growth_outside + }; + v2 + }; + let v3 = if (std::option::is_none(&arg3)) { + 0 + } else { + let v4 = std::option::borrow(&arg3); + let v5 = if (integer_mate::i32::lt(arg0, v4.index)) { + v4.points_growth_outside + } else { + integer_mate::math_u128::wrapping_sub(arg1, v4.points_growth_outside) + }; + v5 + }; + integer_mate::math_u128::wrapping_sub(integer_mate::math_u128::wrapping_sub(arg1, v0), v3) + } + + public fun get_reward_growth_outside(arg0: &Tick, arg1: u64) : u128 { + if (std::vector::length(&arg0.rewards_growth_outside) <= arg1) { + 0 + } else { + *std::vector::borrow(&arg0.rewards_growth_outside, arg1) + } + } + + public fun get_rewards_in_range(arg0: I32, arg1: vector, arg2: std::option::Option, arg3: std::option::Option) : vector { + let mut v0 = std::vector::empty(); + let mut v1 = 0; + while (v1 < std::vector::length(&arg1)) { + let v2 = *std::vector::borrow(&arg1, v1); + let v3 = if (std::option::is_none(&arg2)) { + v2 + } else { + let v4 = std::option::borrow(&arg2); + let v5 = if (integer_mate::i32::lt(arg0, v4.index)) { + integer_mate::math_u128::wrapping_sub(v2, get_reward_growth_outside(v4, v1)) + } else { + get_reward_growth_outside(v4, v1) + }; + v5 + }; + let v6 = if (std::option::is_none(&arg3)) { + 0 + } else { + let v7 = std::option::borrow(&arg3); + let v8 = if (integer_mate::i32::lt(arg0, v7.index)) { + get_reward_growth_outside(v7, v1) + } else { + let v9 = get_reward_growth_outside(v7, v1); + integer_mate::math_u128::wrapping_sub(v2, v9) + }; + v8 + }; + std::vector::push_back(&mut v0, integer_mate::math_u128::wrapping_sub(integer_mate::math_u128::wrapping_sub(v2, v3), v6)); + v1 = v1 + 1; + }; + v0 + } + + public(package) fun increase_liquidity(arg0: &mut TickManager, arg1: I32, arg2: I32, arg3: I32, arg4: u128, arg5: u128, arg6: u128, arg7: u128, arg8: vector) { + if (arg4 == 0) { + return + }; + let v0 = tick_score(arg2); + let v1 = tick_score(arg3); + let mut v2 = false; + let mut v3 = false; + if (!move_stl::skip_list::contains(&arg0.ticks, v0)) { + move_stl::skip_list::insert(&mut arg0.ticks, v0, default(arg2)); + v3 = true; + }; + if (!move_stl::skip_list::contains(&arg0.ticks, v1)) { + move_stl::skip_list::insert(&mut arg0.ticks, v1, default(arg3)); + v2 = true; + }; + update_by_liquidity(move_stl::skip_list::borrow_mut(&mut arg0.ticks, v0), arg1, arg4, v3, true, false, arg5, arg6, arg7, arg8); + update_by_liquidity(move_stl::skip_list::borrow_mut(&mut arg0.ticks, v1), arg1, arg4, v2, true, true, arg5, arg6, arg7, arg8); + } + + public fun index(arg0: &Tick) : I32 { + arg0.index + } + + public fun liquidity_gross(arg0: &Tick) : u128 { + arg0.liquidity_gross + } + + public fun liquidity_net(arg0: &Tick) : integer_mate::i128::I128 { + arg0.liquidity_net + } + + public fun points_growth_outside(arg0: &Tick) : u128 { + arg0.points_growth_outside + } + + public fun rewards_growth_outside(arg0: &Tick) : &vector { + &arg0.rewards_growth_outside + } + + public fun sqrt_price(arg0: &Tick) : u128 { + arg0.sqrt_price + } + + fun tick_score(arg0: I32) : u64 { + let v0 = integer_mate::i32::as_u32(integer_mate::i32::add(arg0, integer_mate::i32::from(cetus_clmm::tick_math::tick_bound()))); + assert!(v0 >= 0 && v0 <= cetus_clmm::tick_math::tick_bound() * 2, 2); + (v0 as u64) + } + + public fun tick_spacing(arg0: &TickManager) : u32 { + arg0.tick_spacing + } + + public(package) fun try_borrow_tick(arg0: &TickManager, arg1: I32) : std::option::Option { + let v0 = tick_score(arg1); + if (!move_stl::skip_list::contains(&arg0.ticks, v0)) { + return std::option::none() + }; + std::option::some(*move_stl::skip_list::borrow(&arg0.ticks, v0)) + } + + fun update_by_liquidity(arg0: &mut Tick, arg1: I32, arg2: u128, arg3: bool, arg4: bool, arg5: bool, arg6: u128, arg7: u128, arg8: u128, arg9: vector) : u128 { + let v0 = if (arg4) { + assert!(integer_mate::math_u128::add_check(arg0.liquidity_gross, arg2), 0); + arg0.liquidity_gross + arg2 + } else { + assert!(arg0.liquidity_gross >= arg2, 1); + arg0.liquidity_gross - arg2 + }; + let (v1, v2, v3, v4) = if (arg3) { + let (v5, v6, v7, v8) = if (integer_mate::i32::lt(arg1, arg0.index)) { + (0, 0, default_rewards_growth_outside(std::vector::length(&arg9)), 0) + } else { + (arg6, arg7, arg9, arg8) + }; + (v5, v6, v7, v8) + } else { + (arg0.fee_growth_outside_a, arg0.fee_growth_outside_b, arg0.rewards_growth_outside, arg0.points_growth_outside) + }; + let (v9, v10) = if (arg4) { + let (v11, v12) = if (arg5) { + let (v13, v14) = integer_mate::i128::overflowing_sub(arg0.liquidity_net, integer_mate::i128::from(arg2)); + (v13, v14) + } else { + let (v15, v16) = integer_mate::i128::overflowing_add(arg0.liquidity_net, integer_mate::i128::from(arg2)); + (v15, v16) + }; + (v11, v12) + } else { + let (v17, v18) = if (arg5) { + let (v19, v20) = integer_mate::i128::overflowing_add(arg0.liquidity_net, integer_mate::i128::from(arg2)); + (v19, v20) + } else { + let (v21, v22) = integer_mate::i128::overflowing_sub(arg0.liquidity_net, integer_mate::i128::from(arg2)); + (v21, v22) + }; + (v17, v18) + }; + if (v10) { + abort 0 + }; + arg0.liquidity_gross = v0; + arg0.liquidity_net = v9; + arg0.fee_growth_outside_a = v1; + arg0.fee_growth_outside_b = v2; + arg0.rewards_growth_outside = v3; + arg0.points_growth_outside = v4; + v0 + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/cetus/sources/tick_math.move b/contracts/dependencies/cetus/sources/tick_math.move new file mode 100644 index 0000000..5530432 --- /dev/null +++ b/contracts/dependencies/cetus/sources/tick_math.move @@ -0,0 +1,269 @@ +module cetus_clmm::tick_math { + use integer_mate::i32::{I32}; + + fun as_u8(arg0: bool) : u8 { + if (arg0) { + 1 + } else { + 0 + } + } + + fun get_sqrt_price_at_negative_tick(arg0: I32) : u128 { + let v0 = integer_mate::i32::as_u32(integer_mate::i32::abs(arg0)); + let v1 = if (v0 & 1 != 0) { + 18445821805675392311_u128 + } else { + 18446744073709551616_u128 + }; + let mut v2 = v1; + if (v0 & 2 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v1, 18444899583751176498, 64); + }; + if (v0 & 4 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 18443055278223354162, 64); + }; + if (v0 & 8 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 18439367220385604838, 64); + }; + if (v0 & 16 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 18431993317065449817, 64); + }; + if (v0 & 32 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 18417254355718160513, 64); + }; + if (v0 & 64 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 18387811781193591352, 64); + }; + if (v0 & 128 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 18329067761203520168, 64); + }; + if (v0 & 256 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 18212142134806087854, 64); + }; + if (v0 & 512 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 17980523815641551639, 64); + }; + if (v0 & 1024 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 17526086738831147013, 64); + }; + if (v0 & 2048 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 16651378430235024244, 64); + }; + if (v0 & 4096 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 15030750278693429944, 64); + }; + if (v0 & 8192 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 12247334978882834399, 64); + }; + if (v0 & 16384 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 8131365268884726200, 64); + }; + if (v0 & 32768 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 3584323654723342297, 64); + }; + if (v0 & 65536 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 696457651847595233, 64); + }; + if (v0 & 131072 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 26294789957452057, 64); + }; + if (v0 & 262144 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 37481735321082, 64); + }; + v2 + } + + fun get_sqrt_price_at_positive_tick(arg0: I32) : u128 { + let v0 = integer_mate::i32::as_u32(integer_mate::i32::abs(arg0)); + let v1 = if (v0 & 1 != 0) { + 79232123823359799118286999567 + } else { + 79228162514264337593543950336 + }; + let mut v2 = v1; + if (v0 & 2 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v1, 79236085330515764027303304731, 96); + }; + if (v0 & 4 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 79244008939048815603706035061, 96); + }; + if (v0 & 8 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 79259858533276714757314932305, 96); + }; + if (v0 & 16 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 79291567232598584799939703904, 96); + }; + if (v0 & 32 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 79355022692464371645785046466, 96); + }; + if (v0 & 64 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 79482085999252804386437311141, 96); + }; + if (v0 & 128 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 79736823300114093921829183326, 96); + }; + if (v0 & 256 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 80248749790819932309965073892, 96); + }; + if (v0 & 512 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 81282483887344747381513967011, 96); + }; + if (v0 & 1024 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 83390072131320151908154831281, 96); + }; + if (v0 & 2048 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 87770609709833776024991924138, 96); + }; + if (v0 & 4096 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 97234110755111693312479820773, 96); + }; + if (v0 & 8192 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 119332217159966728226237229890, 96); + }; + if (v0 & 16384 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 179736315981702064433883588727, 96); + }; + if (v0 & 32768 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 407748233172238350107850275304, 96); + }; + if (v0 & 65536 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 2098478828474011932436660412517, 96); + }; + if (v0 & 131072 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 55581415166113811149459800483533, 96); + }; + if (v0 & 262144 != 0) { + v2 = integer_mate::full_math_u128::mul_shr(v2, 38992368544603139932233054999993551, 96); + }; + v2 >> 32 + } + + public fun get_sqrt_price_at_tick(arg0: I32) : u128 { + assert!(integer_mate::i32::gte(arg0, min_tick()) && integer_mate::i32::lte(arg0, max_tick()), 1); + if (integer_mate::i32::is_neg(arg0)) { + get_sqrt_price_at_negative_tick(arg0) + } else { + get_sqrt_price_at_positive_tick(arg0) + } + } + + // public fun get_tick_at_sqrt_price(current_sqrt_price: u128) : I32 { + // assert!(current_sqrt_price >= 4295048016 && current_sqrt_price <= 79226673515401279992447579055, 2); + // let v0 = as_u8(current_sqrt_price >= 18446744073709551616) << 6; + // let v1 = current_sqrt_price >> v0; + // let v2 = as_u8(v1 >= 4294967296) << 5; + // let v3 = v1 >> v2; + // let v4 = as_u8(v3 >= 65536) << 4; + // let v5 = v3 >> v4; + // let v6 = as_u8(v5 >= 256) << 3; + // let v7 = v5 >> v6; + // let v8 = as_u8(v7 >= 16) << 2; + // let v9 = v7 >> v8; + // let v10 = as_u8(v9 >= 4) << 1; + // let v11 = 0 | v0 | v2 | v4 | v6 | v8 | v10 | as_u8(v9 >> v10 >= 2) << 0; + // let mut v12 = integer_mate::i128::shl(integer_mate::i128::sub(integer_mate::i128::from((v11 as u128)), integer_mate::i128::from(64)), 32); + // let v13 = if (v11 >= 64) { + // current_sqrt_price >> v11 - 63 + // } else { + // current_sqrt_price << 63 - v11 + // }; + // let mut v14 = v13; + // let mut v15 = 31; + // while (v15 >= 18) { + // let v16 = v14 * v14 >> 63; + // let v17 = ((v16 >> 64) as u8); + // v12 = integer_mate::i128::or(v12, integer_mate::i128::shl(integer_mate::i128::from((v17 as u128)), v15)); + // v14 = v16 >> v17; + // v15 = v15 - 1; + // }; + // let v18 = integer_mate::i128::mul(v12, integer_mate::i128::from(59543866431366)); + // let v19 = integer_mate::i128::as_i32(integer_mate::i128::shr(integer_mate::i128::sub(v18, integer_mate::i128::from(184467440737095516)), 64)); + // let v20 = integer_mate::i128::as_i32(integer_mate::i128::shr(integer_mate::i128::add(v18, integer_mate::i128::from(15793534762490258745)), 64)); + // if (integer_mate::i32::eq(v19, v20)) { + // return v19 + // }; + // if (get_sqrt_price_at_tick(v20) <= current_sqrt_price) { + // return v20 + // }; + // v19 + // } + + public fun get_tick_at_sqrt_price(current_sqrt_price: u128) : I32 { + assert!(current_sqrt_price >= 4295048016 && current_sqrt_price <= 79226673515401279992447579055, 2); + let bit_shift_for_highest_bit = as_u8(current_sqrt_price >= 18446744073709551616) << 6; + let adjusted_sqrt_price = current_sqrt_price >> bit_shift_for_highest_bit; + let bit_shift_for_next_significant = as_u8(adjusted_sqrt_price >= 4294967296) << 5; + let next_significant_value = adjusted_sqrt_price >> bit_shift_for_next_significant; + let bit_shift_for_next_significant_2 = as_u8(next_significant_value >= 65536) << 4; + let next_significant_value_2 = next_significant_value >> bit_shift_for_next_significant_2; + let bit_shift_for_next_significant_3 = as_u8(next_significant_value_2 >= 256) << 3; + let next_significant_value_3 = next_significant_value_2 >> bit_shift_for_next_significant_3; + let bit_shift_for_next_significant_4 = as_u8(next_significant_value_3 >= 16) << 2; + let next_significant_value_4 = next_significant_value_3 >> bit_shift_for_next_significant_4; + let bit_shift_for_next_significant_5 = as_u8(next_significant_value_4 >= 4) << 1; + let combined_bit_shift = 0 | bit_shift_for_highest_bit | bit_shift_for_next_significant | bit_shift_for_next_significant_2 | bit_shift_for_next_significant_3 | bit_shift_for_next_significant_4 | bit_shift_for_next_significant_5 | as_u8(next_significant_value_4 >> bit_shift_for_next_significant_5 >= 2) << 0; + let mut base_tick_value = integer_mate::i128::shl(integer_mate::i128::sub(integer_mate::i128::from((combined_bit_shift as u128)), integer_mate::i128::from(64)), 32); + let adjusted_current_sqrt_price = if (combined_bit_shift >= 64) { + current_sqrt_price >> combined_bit_shift - 63 + } else { + current_sqrt_price << 63 - combined_bit_shift + }; + let mut tick_value = adjusted_current_sqrt_price; + let mut iteration_count = 31; + while (iteration_count >= 18) { + let squared_value = tick_value * tick_value >> 63; + let high_bit_value = ((squared_value >> 64) as u8); + base_tick_value = integer_mate::i128::or(base_tick_value, integer_mate::i128::shl(integer_mate::i128::from((high_bit_value as u128)), iteration_count)); + tick_value = squared_value >> high_bit_value; + iteration_count = iteration_count - 1; + }; + let final_tick_value_1 = integer_mate::i128::mul(base_tick_value, integer_mate::i128::from(59543866431366)); + + let tick_candidate_1 = integer_mate::i128::as_i32( + integer_mate::i128::shr( + integer_mate::i128::sub( + final_tick_value_1, integer_mate::i128::from(184467440737095516) + ), + 64 + ) + ); + + let tick_candidate_2 = integer_mate::i128::as_i32(integer_mate::i128::shr(integer_mate::i128::add(final_tick_value_1, integer_mate::i128::from(15793534762490258745)), 64)); + + if (integer_mate::i32::eq(tick_candidate_1, tick_candidate_2)) { + return tick_candidate_1 + }; + if (get_sqrt_price_at_tick(tick_candidate_2) <= current_sqrt_price) { + return tick_candidate_2 + }; + tick_candidate_1 + } + + public fun is_valid_index(arg0: I32, arg1: u32) : bool { + integer_mate::i32::gte(arg0, min_tick()) && integer_mate::i32::lte(arg0, max_tick()) && integer_mate::i32::mod(arg0, integer_mate::i32::from(arg1)) == integer_mate::i32::from(0) + } + + public fun max_sqrt_price() : u128 { + 79226673515401279992447579055 + } + + public fun max_tick() : I32 { + integer_mate::i32::from(443636) + } + + public fun min_sqrt_price() : u128 { + 4295048016 + } + + public fun min_tick() : I32 { + integer_mate::i32::neg_from(443636) + } + + public fun tick_bound() : u32 { + 443636 + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/cetus/sources/utils.move b/contracts/dependencies/cetus/sources/utils.move new file mode 100644 index 0000000..0e38605 --- /dev/null +++ b/contracts/dependencies/cetus/sources/utils.move @@ -0,0 +1,18 @@ +module cetus_clmm::utils { + public fun str(mut arg0: u64) : std::string::String { + if (arg0 == 0) { + return std::string::utf8(b"0") + }; + let mut v0 = std::vector::empty(); + while (arg0 > 0) { + let v1 = ((arg0 % 10) as u8); + arg0 = arg0 / 10; + std::vector::push_back(&mut v0, v1 + 48); + }; + std::vector::reverse(&mut v0); + std::string::utf8(v0) + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/integer-mate/Move.toml b/contracts/dependencies/integer-mate/Move.toml new file mode 100644 index 0000000..3761286 --- /dev/null +++ b/contracts/dependencies/integer-mate/Move.toml @@ -0,0 +1,38 @@ +[package] +name = "IntegerMate" +edition = "legacy" # edition = "legacy" to use legacy (pre-2024) Move +published-at="0xe2b515f0052c0b3f83c23db045d49dbe1732818ccfc5d4596c9482f7f2e76a85" +# 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/mainnet" } + +# 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 } + +[addresses] +integer_mate = "0x714a63a0dba6da4f017b42d5d0fb78867f18bcde904868e51d951a5a6f5b7f57" + +# 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] +# The dev-addresses section allows overwriting named addresses for the `--test` +# and `--dev` modes. +# alice = "0xB0B" + diff --git a/contracts/dependencies/integer-mate/sources/full_math_u128.move b/contracts/dependencies/integer-mate/sources/full_math_u128.move new file mode 100644 index 0000000..16fe520 --- /dev/null +++ b/contracts/dependencies/integer-mate/sources/full_math_u128.move @@ -0,0 +1,30 @@ +module integer_mate::full_math_u128 { + public fun mul_div_floor(num1: u128, num2: u128, denom: u128): u128 { + let r = full_mul(num1, num2) / (denom as u256); + (r as u128) + } + + public fun mul_div_round(num1: u128, num2: u128, denom: u128): u128 { + let r = (full_mul(num1, num2) + ((denom as u256) >> 1)) / (denom as u256); + (r as u128) + } + + public fun mul_div_ceil(num1: u128, num2: u128, denom: u128): u128 { + let r = (full_mul(num1, num2) + ((denom as u256) - 1)) / (denom as u256); + (r as u128) + } + + public fun mul_shr(num1: u128, num2: u128, shift: u8): u128 { + let product = full_mul(num1, num2) >> shift; + (product as u128) + } + + public fun mul_shl(num1: u128, num2: u128, shift: u8): u128 { + let product = full_mul(num1, num2) << shift; + (product as u128) + } + + public fun full_mul(num1: u128, num2: u128): u256 { + (num1 as u256) * (num2 as u256) + } +} \ No newline at end of file diff --git a/contracts/dependencies/integer-mate/sources/full_math_u64.move b/contracts/dependencies/integer-mate/sources/full_math_u64.move new file mode 100644 index 0000000..be19a29 --- /dev/null +++ b/contracts/dependencies/integer-mate/sources/full_math_u64.move @@ -0,0 +1,30 @@ +module integer_mate::full_math_u64 { + public fun mul_div_floor(num1: u64, num2: u64, denom: u64): u64 { + let r = full_mul(num1, num2) / (denom as u128); + (r as u64) + } + + public fun mul_div_round(num1: u64, num2: u64, denom: u64): u64 { + let r = (full_mul(num1, num2) + ((denom as u128) >> 1)) / (denom as u128); + (r as u64) + } + + public fun mul_div_ceil(num1: u64, num2: u64, denom: u64): u64 { + let r = (full_mul(num1, num2) + ((denom as u128) - 1)) / (denom as u128); + (r as u64) + } + + public fun mul_shr(num1: u64, num2: u64, shift: u8): u64 { + let r = full_mul(num1, num2) >> shift; + (r as u64) + } + + public fun mul_shl(num1: u64, num2: u64, shift: u8): u64 { + let r = full_mul(num1, num2) << shift; + (r as u64) + } + + public fun full_mul(num1: u64, num2: u64): u128 { + ((num1 as u128) * (num2 as u128)) + } +} diff --git a/contracts/dependencies/integer-mate/sources/i128.move b/contracts/dependencies/integer-mate/sources/i128.move new file mode 100644 index 0000000..787dace --- /dev/null +++ b/contracts/dependencies/integer-mate/sources/i128.move @@ -0,0 +1,524 @@ +module integer_mate::i128 { + use integer_mate::i64; + use integer_mate::i32; + + const EOverflow: u64 = 0; + + const MIN_AS_U128: u128 = 1 << 127; + const MAX_AS_U128: u128 = 0x7fffffffffffffffffffffffffffffff; + + const LT: u8 = 0; + const EQ: u8 = 1; + const GT: u8 = 2; + + struct I128 has copy, drop, store { + bits: u128 + } + + public fun zero(): I128 { + I128 { + bits: 0 + } + } + + public fun from(v: u128): I128 { + assert!(v <= MAX_AS_U128, EOverflow); + I128 { + bits: v + } + } + + public fun neg_from(v: u128): I128 { + assert!(v <= MIN_AS_U128, EOverflow); + if (v == 0) { + I128 { + bits: v + } + } else { + I128 { + bits: (u128_neg(v) + 1) | (1 << 127) + } + } + } + + public fun neg(v: I128): I128 { + if (is_neg(v)) { + abs(v) + } else { + neg_from(v.bits) + } + } + + public fun wrapping_add(num1: I128, num2:I128): I128 { + let sum = num1.bits ^ num2.bits; + let carry = (num1.bits & num2.bits) << 1; + while (carry != 0) { + let a = sum; + let b = carry; + sum = a ^ b; + carry = (a & b) << 1; + }; + I128 { + bits: sum + } + } + + public fun add(num1: I128, num2: I128): I128 { + let sum = wrapping_add(num1, num2); + let overflow = (sign(num1) & sign(num2) & u8_neg(sign(sum))) + (u8_neg(sign(num1)) & u8_neg(sign(num2)) & sign(sum)); + assert!(overflow == 0, EOverflow); + sum + } + + public fun overflowing_add(num1: I128, num2: I128): (I128, bool) { + let sum = wrapping_add(num1, num2); + let overflow = (sign(num1) & sign(num2) & u8_neg(sign(sum))) + (u8_neg(sign(num1)) & u8_neg(sign(num2)) & sign(sum)); + (sum, overflow != 0) + } + + public fun wrapping_sub(num1: I128, num2: I128): I128 { + let sub_num = wrapping_add(I128 { + bits: u128_neg(num2.bits) + }, from(1)); + wrapping_add(num1, sub_num) + } + + public fun sub(num1: I128, num2: I128): I128 { + let sub_num = wrapping_add(I128 { + bits: u128_neg(num2.bits) + }, from(1)); + add(num1, sub_num) + } + + public fun overflowing_sub(num1: I128, num2: I128): (I128, bool) { + let sub_num = wrapping_add(I128 { + bits: u128_neg(num2.bits) + }, from(1)); + let sum = wrapping_add(num1, sub_num); + let overflow = (sign(num1) & sign(sub_num) & u8_neg(sign(sum))) + (u8_neg(sign(num1)) & u8_neg(sign(sub_num)) & sign(sum)); + (sum, overflow != 0) + } + + public fun mul(num1: I128, num2: I128): I128 { + let product = abs_u128(num1) * abs_u128(num2); + if (sign(num1) != sign(num2)) { + return neg_from(product) + }; + return from(product) + } + + public fun div(num1: I128, num2: I128): I128 { + let result = abs_u128(num1) / abs_u128(num2); + if (sign(num1) != sign(num2)) { + return neg_from(result) + }; + return from(result) + } + + public fun abs(v: I128): I128 { + if (sign(v) == 0) { + v + } else { + assert!(v.bits > MIN_AS_U128, EOverflow); + I128 { + bits: u128_neg(v.bits - 1) + } + } + } + + public fun abs_u128(v: I128): u128 { + if (sign(v) == 0) { + v.bits + } else { + u128_neg(v.bits - 1) + } + } + + public fun shl(v: I128, shift: u8): I128 { + I128 { + bits: v.bits << shift + } + } + + public fun shr(v: I128, shift: u8): I128 { + if (shift == 0) { + return v + }; + let mask = 0xffffffffffffffffffffffffffffffff << (128 - shift); + if (sign(v) == 1) { + return I128 { + bits: (v.bits >> shift) | mask + } + }; + I128 { + bits: v.bits >> shift + } + } + + public fun as_u128(v: I128): u128 { + v.bits + } + + public fun as_i64(v: I128): i64::I64 { + if (is_neg(v)) { + return i64::neg_from((abs_u128(v) as u64)) + } else { + return i64::from((abs_u128(v) as u64)) + } + } + + public fun as_i32(v: I128): i32::I32 { + if (is_neg(v)) { + return i32::neg_from((abs_u128(v) as u32)) + } else { + return i32::from((abs_u128(v) as u32)) + } + } + + public fun sign(v: I128): u8 { + ((v.bits >> 127) as u8) + } + + public fun is_neg(v: I128): bool { + sign(v) == 1 + } + + public fun cmp(num1: I128, num2: I128): u8 { + if (num1.bits == num2.bits) return EQ; + if (sign(num1) > sign(num2)) return LT; + if (sign(num1) < sign(num2)) return GT; + if (num1.bits > num2.bits) { + return GT + } else { + return LT + } + } + + public fun eq(num1: I128, num2: I128): bool { + num1.bits == num2.bits + } + + public fun gt(num1: I128, num2: I128): bool { + cmp(num1, num2) == GT + } + + public fun gte(num1: I128, num2: I128): bool { + cmp(num1, num2) >= EQ + } + + public fun lt(num1: I128, num2: I128): bool { + cmp(num1, num2) == LT + } + + public fun lte(num1: I128, num2: I128): bool { + cmp(num1, num2) <= EQ + } + + public fun or(num1: I128, num2: I128): I128 { + I128 { + bits: (num1.bits | num2.bits) + } + } + + public fun and(num1: I128, num2: I128): I128 { + I128 { + bits: (num1.bits & num2.bits) + } + } + + fun u128_neg(v :u128) : u128 { + v ^ 0xffffffffffffffffffffffffffffffff + } + + fun u8_neg(v: u8): u8 { + v ^ 0xff + } + + #[test] + fun test_from_ok() { + assert!(as_u128(from(0)) == 0, 0); + assert!(as_u128(from(10)) == 10, 1); + } + + #[test] + #[expected_failure] + fun test_from_overflow() { + as_u128(from(MIN_AS_U128)); + as_u128(from(0xffffffffffffffffffffffffffffffff)); + } + + #[test] + fun test_neg_from() { + assert!(as_u128(neg_from(0)) == 0, 0); + assert!(as_u128(neg_from(1)) == 0xffffffffffffffffffffffffffffffff, 1); + assert!(as_u128(neg_from(0x7fffffffffffffffffffffffffffffff)) == 0x80000000000000000000000000000001, 2); + assert!(as_u128(neg_from(MIN_AS_U128)) == MIN_AS_U128, 2); + } + + #[test] + #[expected_failure] + fun test_neg_from_overflow() { + neg_from(0x80000000000000000000000000000001); + } + + #[test] + fun test_abs() { + assert!(as_u128(from(10)) == 10u128, 0); + assert!(as_u128(abs(neg_from(10))) == 10u128, 1); + assert!(as_u128(abs(neg_from(0))) == 0u128, 2); + assert!(as_u128(abs(neg_from(0x7fffffffffffffffffffffffffffffff))) == 0x7fffffffffffffffffffffffffffffff, 3); + assert!(as_u128(neg_from(MIN_AS_U128)) == MIN_AS_U128, 4); + } + + #[test] + #[expected_failure] + fun test_abs_overflow() { + abs(neg_from(1<<127)); + } + + #[test] + fun test_wrapping_add() { + assert!(as_u128(wrapping_add(from(0), from(1))) == 1, 0); + assert!(as_u128(wrapping_add(from(1), from(0))) == 1, 0); + assert!(as_u128(wrapping_add(from(10000), from(99999))) == 109999, 0); + assert!(as_u128(wrapping_add(from(99999), from(10000))) == 109999, 0); + assert!(as_u128(wrapping_add(from(MAX_AS_U128-1), from(1))) == MAX_AS_U128, 0); + assert!(as_u128(wrapping_add(from(0), from(0))) == 0, 0); + + assert!(as_u128(wrapping_add(neg_from(0), neg_from(0))) == 0, 1); + assert!(as_u128(wrapping_add(neg_from(1), neg_from(0))) == 0xffffffffffffffffffffffffffffffff, 1); + assert!(as_u128(wrapping_add(neg_from(0), neg_from(1))) == 0xffffffffffffffffffffffffffffffff, 1); + assert!(as_u128(wrapping_add(neg_from(10000), neg_from(99999))) == 0xfffffffffffffffffffffffffffe5251, 1); + assert!(as_u128(wrapping_add(neg_from(99999), neg_from(10000))) == 0xfffffffffffffffffffffffffffe5251, 1); + assert!(as_u128(wrapping_add(neg_from(MIN_AS_U128-1), neg_from(1))) == MIN_AS_U128, 1); + + assert!(as_u128(wrapping_add(from(0), neg_from(0))) == 0, 2); + assert!(as_u128(wrapping_add(neg_from(0), from(0))) == 0, 2); + assert!(as_u128(wrapping_add(neg_from(1), from(1))) == 0, 2); + assert!(as_u128(wrapping_add(from(1), neg_from(1))) == 0, 2); + assert!(as_u128(wrapping_add(from(10000), neg_from(99999))) == 0xfffffffffffffffffffffffffffea071, 2); + assert!(as_u128(wrapping_add(from(99999), neg_from(10000))) == 89999, 2); + assert!(as_u128(wrapping_add(neg_from(MIN_AS_U128), from(1))) == 0x80000000000000000000000000000001, 2); + assert!(as_u128(wrapping_add(from(MAX_AS_U128), neg_from(1))) == MAX_AS_U128 - 1, 2); + + assert!(as_u128(wrapping_add(from(MAX_AS_U128), from(1))) == MIN_AS_U128, 2); + } + + #[test] + fun test_add() { + assert!(as_u128(add(from(0), from(0))) == 0, 0); + assert!(as_u128(add(from(0), from(1))) == 1, 0); + assert!(as_u128(add(from(1), from(0))) == 1, 0); + assert!(as_u128(add(from(10000), from(99999))) == 109999, 0); + assert!(as_u128(add(from(99999), from(10000))) == 109999, 0); + assert!(as_u128(add(from(MAX_AS_U128-1), from(1))) == MAX_AS_U128, 0); + + assert!(as_u128(add(neg_from(0), neg_from(0))) == 0, 1); + assert!(as_u128(add(neg_from(1), neg_from(0))) == 0xffffffffffffffffffffffffffffffff, 1); + assert!(as_u128(add(neg_from(0), neg_from(1))) == 0xffffffffffffffffffffffffffffffff, 1); + assert!(as_u128(add(neg_from(10000), neg_from(99999))) == 0xfffffffffffffffffffffffffffe5251, 1); + assert!(as_u128(add(neg_from(99999), neg_from(10000))) == 0xfffffffffffffffffffffffffffe5251, 1); + assert!(as_u128(add(neg_from(MIN_AS_U128-1), neg_from(1))) == MIN_AS_U128, 1); + + assert!(as_u128(add(from(0), neg_from(0))) == 0, 2); + assert!(as_u128(add(neg_from(0), from(0))) == 0, 2); + assert!(as_u128(add(neg_from(1), from(1))) == 0, 2); + assert!(as_u128(add(from(1), neg_from(1))) == 0, 2); + assert!(as_u128(add(from(10000), neg_from(99999))) == 0xfffffffffffffffffffffffffffea071, 2); + assert!(as_u128(add(from(99999), neg_from(10000))) == 89999, 2); + assert!(as_u128(add(neg_from(MIN_AS_U128), from(1))) == 0x80000000000000000000000000000001, 2); + assert!(as_u128(add(from(MAX_AS_U128), neg_from(1))) == MAX_AS_U128 - 1, 2); + } + + #[test] + fun test_overflowing_add() { + let (result, overflow) = overflowing_add(from(MAX_AS_U128), neg_from(1)); + assert!(overflow == false && as_u128(result) == MAX_AS_U128 - 1, 1); + let (_, overflow) = overflowing_add(from(MAX_AS_U128), from(1)); + assert!(overflow == true, 1); + let (_, overflow) = overflowing_add(neg_from(MIN_AS_U128), neg_from(1)); + assert!(overflow == true, 1); + } + + #[test] + #[expected_failure] + fun test_add_overflow() { + add(from(MAX_AS_U128), from(1)); + } + + #[test] + #[expected_failure] + fun test_add_underflow() { + add(neg_from(MIN_AS_U128), neg_from(1)); + } + + #[test] + fun test_wrapping_sub() { + assert!(as_u128(wrapping_sub(from(0), from(0))) == 0, 0); + assert!(as_u128(wrapping_sub(from(1), from(0))) == 1, 0); + assert!(as_u128(wrapping_sub(from(0), from(1))) == as_u128(neg_from(1)), 0); + assert!(as_u128(wrapping_sub(from(1), from(1))) == as_u128(neg_from(0)), 0); + assert!(as_u128(wrapping_sub(from(1), neg_from(1))) == as_u128(from(2)), 0); + assert!(as_u128(wrapping_sub(neg_from(1), from(1))) == as_u128(neg_from(2)), 0); + assert!(as_u128(wrapping_sub(from(1000000), from(1))) == 999999, 0); + assert!(as_u128(wrapping_sub(neg_from(1000000), neg_from(1))) == as_u128(neg_from(999999)), 0); + assert!(as_u128(wrapping_sub(from(1), from(1000000))) == as_u128(neg_from(999999)), 0); + assert!(as_u128(wrapping_sub(from(MAX_AS_U128), from(MAX_AS_U128))) == as_u128(from(0)), 0); + assert!(as_u128(wrapping_sub(from(MAX_AS_U128), from(1))) == as_u128(from(MAX_AS_U128 - 1)), 0); + assert!(as_u128(wrapping_sub(from(MAX_AS_U128), neg_from(1))) == as_u128(neg_from(MIN_AS_U128)), 0); + assert!(as_u128(wrapping_sub(neg_from(MIN_AS_U128), neg_from(1))) == as_u128(neg_from(MIN_AS_U128 - 1)), 0); + assert!(as_u128(wrapping_sub(neg_from(MIN_AS_U128), from(1))) == as_u128(from(MAX_AS_U128)), 0); + } + + #[test] + fun test_sub() { + assert!(as_u128(sub(from(0), from(0))) == 0, 0); + assert!(as_u128(sub(from(1), from(0))) == 1, 0); + assert!(as_u128(sub(from(0), from(1))) == as_u128(neg_from(1)), 0); + assert!(as_u128(sub(from(1), from(1))) == as_u128(neg_from(0)), 0); + assert!(as_u128(sub(from(1), neg_from(1))) == as_u128(from(2)), 0); + assert!(as_u128(sub(neg_from(1), from(1))) == as_u128(neg_from(2)), 0); + assert!(as_u128(sub(from(1000000), from(1))) == 999999, 0); + assert!(as_u128(sub(neg_from(1000000), neg_from(1))) == as_u128(neg_from(999999)), 0); + assert!(as_u128(sub(from(1), from(1000000))) == as_u128(neg_from(999999)), 0); + assert!(as_u128(sub(from(MAX_AS_U128), from(MAX_AS_U128))) == as_u128(from(0)), 0); + assert!(as_u128(sub(from(MAX_AS_U128), from(1))) == as_u128(from(MAX_AS_U128 - 1)), 0); + assert!(as_u128(sub(neg_from(MIN_AS_U128), neg_from(1))) == as_u128(neg_from(MIN_AS_U128 - 1)), 0); + } + + #[test] + fun test_checked_sub() { + let (result, overflowing) = overflowing_sub(from(MAX_AS_U128), from(1)); + assert!(overflowing == false && as_u128(result) == MAX_AS_U128 - 1, 1); + + let (_, overflowing) = overflowing_sub(neg_from(MIN_AS_U128), from(1)); + assert!(overflowing == true, 1); + + let (_, overflowing) = overflowing_sub(from(MAX_AS_U128), neg_from(1)); + assert!(overflowing == true, 1); + } + + #[test] + #[expected_failure] + fun test_sub_overflow() { + sub(from(MAX_AS_U128), neg_from(1)); + } + + #[test] + #[expected_failure] + fun test_sub_underflow() { + sub(neg_from(MIN_AS_U128), from(1)); + } + + #[test] + fun test_mul() { + assert!(as_u128(mul(from(1), from(1))) == 1, 0); + assert!(as_u128(mul(from(10), from(10))) == 100, 0); + assert!(as_u128(mul(from(100), from(100))) == 10000, 0); + assert!(as_u128(mul(from(10000), from(10000))) == 100000000, 0); + + assert!(as_u128(mul(neg_from(1), from(1))) == as_u128(neg_from(1)), 0); + assert!(as_u128(mul(neg_from(10), from(10))) == as_u128(neg_from(100)), 0); + assert!(as_u128(mul(neg_from(100), from(100))) == as_u128(neg_from(10000)), 0); + assert!(as_u128(mul(neg_from(10000), from(10000))) == as_u128(neg_from(100000000)), 0); + + assert!(as_u128(mul(from(1), neg_from(1))) == as_u128(neg_from(1)), 0); + assert!(as_u128(mul(from(10), neg_from(10))) == as_u128(neg_from(100)), 0); + assert!(as_u128(mul(from(100), neg_from(100))) == as_u128(neg_from(10000)), 0); + assert!(as_u128(mul(from(10000), neg_from(10000))) == as_u128(neg_from(100000000)), 0); + assert!(as_u128(mul(from(MIN_AS_U128/2), neg_from(2))) == as_u128(neg_from(MIN_AS_U128)), 0); + } + + #[test] + #[expected_failure] + fun test_mul_overflow() { + mul(from(MIN_AS_U128/2), from(1)); + mul(neg_from(MIN_AS_U128/2), neg_from(2)); + } + + #[test] + fun test_div() { + assert!(as_u128(div(from(0), from(1))) == 0, 0); + assert!(as_u128(div(from(10), from(1))) == 10, 0); + assert!(as_u128(div(from(10), neg_from(1))) == as_u128(neg_from(10)), 0); + assert!(as_u128(div(neg_from(10), neg_from(1))) == as_u128(from(10)), 0); + + assert!(abs_u128(neg_from(MIN_AS_U128)) == MIN_AS_U128, 0); + assert!(as_u128(div(neg_from(MIN_AS_U128), from(1))) == MIN_AS_U128, 0); + } + + #[test] + #[expected_failure] + fun test_div_overflow() { + div(neg_from(MIN_AS_U128), neg_from(1)); + } + + #[test] + fun test_shl() { + assert!(as_u128(shl(from(10), 0)) == 10, 0); + assert!(as_u128(shl(neg_from(10), 0)) == as_u128(neg_from(10)), 0); + + assert!(as_u128(shl(from(10), 1)) == 20, 0); + assert!(as_u128(shl(neg_from(10), 1)) == as_u128(neg_from(20)), 0); + + assert!(as_u128(shl(from(10), 8)) == 2560, 0); + assert!(as_u128(shl(neg_from(10), 8)) == as_u128(neg_from(2560)), 0); + + assert!(as_u128(shl(from(10), 32)) == 42949672960, 0); + assert!(as_u128(shl(neg_from(10), 32)) == as_u128(neg_from(42949672960)), 0); + + assert!(as_u128(shl(from(10), 64)) == 184467440737095516160, 0); + assert!(as_u128(shl(neg_from(10), 64)) == as_u128(neg_from(184467440737095516160)), 0); + + assert!(as_u128(shl(from(10), 127)) == 0, 0); + assert!(as_u128(shl(neg_from(10), 127)) == 0, 0); + } + + #[test] + fun test_shr() { + assert!(as_u128(shr(from(10), 0)) == 10, 0); + assert!(as_u128(shr(neg_from(10), 0)) == as_u128(neg_from(10)), 0); + + assert!(as_u128(shr(from(10), 1)) == 5, 0); + assert!(as_u128(shr(neg_from(10), 1)) == as_u128(neg_from(5)), 0); + + assert!(as_u128(shr(from(MAX_AS_U128), 8)) == 0x7fffffffffffffffffffffffffffff, 0); + assert!(as_u128(shr(neg_from(MIN_AS_U128), 8)) == 0xff800000000000000000000000000000, 0); + + assert!(as_u128(shr(from(MAX_AS_U128), 96)) == 0x7fffffff, 0); + assert!(as_u128(shr(neg_from(MIN_AS_U128), 96)) == 0xffffffffffffffffffffffff80000000, 0); + + assert!(as_u128(shr(from(MAX_AS_U128), 127)) == 0, 0); + assert!(as_u128(shr(neg_from(MIN_AS_U128), 127)) == 0xffffffffffffffffffffffffffffffff, 0); + } + + #[test] + fun test_sign() { + assert!(sign(neg_from(10)) == 1u8, 0); + assert!(sign(from(10)) == 0u8, 0); + } + + #[test] + fun test_cmp() { + assert!(cmp(from(1), from(0)) == GT, 0); + assert!(cmp(from(0), from(1)) == LT, 0); + + assert!(cmp(from(0), neg_from(1)) == GT, 0); + assert!(cmp(neg_from(0), neg_from(1)) == GT, 0); + assert!(cmp(neg_from(1), neg_from(0)) == LT, 0); + + assert!(cmp(neg_from(MIN_AS_U128), from(MAX_AS_U128)) == LT, 0); + assert!(cmp(from(MAX_AS_U128), neg_from(MIN_AS_U128)) == GT, 0); + + assert!(cmp(from(MAX_AS_U128), from(MAX_AS_U128-1)) == GT, 0); + assert!(cmp(from(MAX_AS_U128-1), from(MAX_AS_U128)) == LT, 0); + + assert!(cmp(neg_from(MIN_AS_U128), neg_from(MIN_AS_U128-1)) == LT, 0); + assert!(cmp(neg_from(MIN_AS_U128-1), neg_from(MIN_AS_U128)) == GT, 0); + } + + #[test] + fun test_castdown() { + assert!((1u128 as u8) == 1u8, 0); + } +} diff --git a/contracts/dependencies/integer-mate/sources/i32.move b/contracts/dependencies/integer-mate/sources/i32.move new file mode 100644 index 0000000..13894cc --- /dev/null +++ b/contracts/dependencies/integer-mate/sources/i32.move @@ -0,0 +1,498 @@ +module integer_mate::i32 { + const EOverflow: u64 = 0; + + const MIN_AS_U32: u32 = 1 << 31; + const MAX_AS_U32: u32 = 0x7fffffff; + + const LT: u8 = 0; + const EQ: u8 = 1; + const GT: u8 = 2; + + struct I32 has copy, drop, store { + bits: u32 + } + + public fun zero(): I32 { + I32 { + bits: 0 + } + } + + public fun from_u32(v: u32): I32 { + I32 { + bits: v + } + } + + public fun from(v: u32): I32 { + assert!(v <= MAX_AS_U32, EOverflow); + I32 { + bits: v + } + } + + public fun neg_from(v: u32): I32 { + assert!(v <= MIN_AS_U32, EOverflow); + if (v == 0) { + I32 { + bits: v + } + } else { + I32 { + bits: (u32_neg(v) + 1) | (1 << 31) + } + } + } + + public fun from_u32_neg(arg0: u32, arg1: bool) : I32 { + if (arg1) { + neg_from(arg0) + } else { + from(arg0) + } + } + + public fun wrapping_add(num1: I32, num2: I32): I32 { + let sum = num1.bits ^ num2.bits; + let carry = (num1.bits & num2.bits) << 1; + while (carry != 0) { + let a = sum; + let b = carry; + sum = a ^ b; + carry = (a & b) << 1; + }; + I32 { + bits: sum + } + } + + public fun add(num1: I32, num2: I32): I32 { + let sum = wrapping_add(num1, num2); + let overflow = (sign(num1) & sign(num2) & u8_neg(sign(sum))) + + (u8_neg(sign(num1)) & u8_neg(sign(num2)) & sign(sum)); + assert!(overflow == 0, EOverflow); + sum + } + + public fun wrapping_sub(num1: I32, num2: I32): I32 { + let sub_num = wrapping_add(I32 { + bits: u32_neg(num2.bits) + }, from(1)); + wrapping_add(num1, sub_num) + } + + public fun sub(num1: I32, num2: I32): I32 { + let sub_num = wrapping_add(I32 { + bits: u32_neg(num2.bits) + }, from(1)); + add(num1, sub_num) + } + + public fun mul(num1: I32, num2: I32): I32 { + let product = abs_u32(num1) * abs_u32(num2); + if (sign(num1) != sign(num2)) { + return neg_from(product) + }; + return from(product) + } + + public fun div(num1: I32, num2: I32): I32 { + let result = abs_u32(num1) / abs_u32(num2); + if (sign(num1) != sign(num2)) { + return neg_from(result) + }; + return from(result) + } + + public fun abs(v: I32): I32 { + if (sign(v) == 0) { + v + } else { + assert!(v.bits > MIN_AS_U32, EOverflow); + I32 { + bits: u32_neg(v.bits - 1) + } + } + } + + public fun abs_u32(v: I32): u32 { + if (sign(v) == 0) { + v.bits + } else { + u32_neg(v.bits - 1) + } + } + + public fun shl(v: I32, shift: u8): I32 { + I32 { + bits: v.bits << shift + } + } + + public fun shr(v: I32, shift: u8): I32 { + if (shift == 0) { + return v + }; + let mask = 0xffffffff << (32 - shift); + if (sign(v) == 1) { + return I32 { + bits: (v.bits >> shift) | mask + } + }; + I32 { + bits: v.bits >> shift + } + } + + public fun mod(v: I32, n: I32): I32 { + if (sign(v) == 1) { + neg_from((abs_u32(v) % abs_u32(n))) + } else { + from((as_u32(v) % abs_u32(n))) + } + } + + public fun mod_euclidean(arg0: I32, arg1: u32) : I32 { + let v0 = from(arg1); + let v1 = mod(arg0, v0); + if (sign(v1) == 1) { + add(v1, v0) + } else { + v1 + } + } + + public fun as_u32(v: I32): u32 { + v.bits + } + + public fun sign(v: I32): u8 { + ((v.bits >> 31) as u8) + } + + public fun is_neg(v: I32): bool { + sign(v) == 1 + } + + public fun cmp(num1: I32, num2: I32): u8 { + if (num1.bits == num2.bits) return EQ; + if (sign(num1) > sign(num2)) return LT; + if (sign(num1) < sign(num2)) return GT; + if (num1.bits > num2.bits) { + return GT + } else { + return LT + } + } + + public fun eq(num1: I32, num2: I32): bool { + num1.bits == num2.bits + } + + public fun gt(num1: I32, num2: I32): bool { + cmp(num1, num2) == GT + } + + public fun gte(num1: I32, num2: I32): bool { + cmp(num1, num2) >= EQ + } + + public fun lt(num1: I32, num2: I32): bool { + cmp(num1, num2) == LT + } + + public fun lte(num1: I32, num2: I32): bool { + cmp(num1, num2) <= EQ + } + + public fun or(num1: I32, num2: I32): I32 { + I32 { + bits: (num1.bits | num2.bits) + } + } + + public fun and(num1: I32, num2: I32): I32 { + I32 { + bits: (num1.bits & num2.bits) + } + } + + public fun u32_neg(v: u32): u32 { + v ^ 0xffffffff + } + + fun u8_neg(v: u8): u8 { + v ^ 0xff + } + + #[test] + fun test_from_ok() { + assert!(as_u32(from(0)) == 0, 0); + assert!(as_u32(from(10)) == 10, 1); + } + + #[test] + #[expected_failure] + fun test_from_overflow() { + as_u32(from(MIN_AS_U32)); + as_u32(from(0xffffffff)); + } + + #[test] + fun test_neg_from() { + assert!(as_u32(neg_from(0)) == 0, 0); + assert!(as_u32(neg_from(1)) == 0xffffffff, 1); + assert!(as_u32(neg_from(0x7fffffff)) == 0x80000001, 2); + assert!(as_u32(neg_from(MIN_AS_U32)) == MIN_AS_U32, 2); + } + + #[test] + #[expected_failure] + fun test_neg_from_overflow() { + neg_from(0x80000001); + } + + #[test] + fun test_abs() { + assert!(as_u32(from(10)) == 10u32, 0); + assert!(as_u32(abs(neg_from(10))) == 10u32, 1); + assert!(as_u32(abs(neg_from(0))) == 0u32, 2); + assert!(as_u32(abs(neg_from(0x7fffffff))) == 0x7fffffff, 3); + assert!(as_u32(neg_from(MIN_AS_U32)) == MIN_AS_U32, 4); + } + + #[test] + #[expected_failure] + fun test_abs_overflow() { + abs(neg_from(1 << 31)); + } + + #[test] + fun test_wrapping_add() { + assert!(as_u32(wrapping_add(from(0), from(1))) == 1, 0); + assert!(as_u32(wrapping_add(from(1), from(0))) == 1, 0); + assert!(as_u32(wrapping_add(from(10000), from(99999))) == 109999, 0); + assert!(as_u32(wrapping_add(from(99999), from(10000))) == 109999, 0); + assert!(as_u32(wrapping_add(from(MAX_AS_U32 - 1), from(1))) == MAX_AS_U32, 0); + assert!(as_u32(wrapping_add(from(0), from(0))) == 0, 0); + + assert!(as_u32(wrapping_add(neg_from(0), neg_from(0))) == 0, 1); + assert!(as_u32(wrapping_add(neg_from(1), neg_from(0))) == 0xffffffff, 1); + assert!(as_u32(wrapping_add(neg_from(0), neg_from(1))) == 0xffffffff, 1); + assert!(as_u32(wrapping_add(neg_from(10000), neg_from(99999))) == 0xfffe5251, 1); + assert!(as_u32(wrapping_add(neg_from(99999), neg_from(10000))) == 0xfffe5251, 1); + assert!(as_u32(wrapping_add(neg_from(MIN_AS_U32 - 1), neg_from(1))) == MIN_AS_U32, 1); + + assert!(as_u32(wrapping_add(from(0), neg_from(0))) == 0, 2); + assert!(as_u32(wrapping_add(neg_from(0), from(0))) == 0, 2); + assert!(as_u32(wrapping_add(neg_from(1), from(1))) == 0, 2); + assert!(as_u32(wrapping_add(from(1), neg_from(1))) == 0, 2); + assert!(as_u32(wrapping_add(from(10000), neg_from(99999))) == 0xfffea071, 2); + assert!(as_u32(wrapping_add(from(99999), neg_from(10000))) == 89999, 2); + assert!(as_u32(wrapping_add(neg_from(MIN_AS_U32), from(1))) == 0x80000001, 2); + assert!(as_u32(wrapping_add(from(MAX_AS_U32), neg_from(1))) == MAX_AS_U32 - 1, 2); + + assert!(as_u32(wrapping_add(from(MAX_AS_U32), from(1))) == MIN_AS_U32, 2); + } + + #[test] + fun test_add() { + assert!(as_u32(add(from(0), from(0))) == 0, 0); + assert!(as_u32(add(from(0), from(1))) == 1, 0); + assert!(as_u32(add(from(1), from(0))) == 1, 0); + assert!(as_u32(add(from(10000), from(99999))) == 109999, 0); + assert!(as_u32(add(from(99999), from(10000))) == 109999, 0); + assert!(as_u32(add(from(MAX_AS_U32 - 1), from(1))) == MAX_AS_U32, 0); + + assert!(as_u32(add(neg_from(0), neg_from(0))) == 0, 1); + assert!(as_u32(add(neg_from(1), neg_from(0))) == 0xffffffff, 1); + assert!(as_u32(add(neg_from(0), neg_from(1))) == 0xffffffff, 1); + assert!(as_u32(add(neg_from(10000), neg_from(99999))) == 0xfffe5251, 1); + assert!(as_u32(add(neg_from(99999), neg_from(10000))) == 0xfffe5251, 1); + assert!(as_u32(add(neg_from(MIN_AS_U32 - 1), neg_from(1))) == MIN_AS_U32, 1); + + assert!(as_u32(add(from(0), neg_from(0))) == 0, 2); + assert!(as_u32(add(neg_from(0), from(0))) == 0, 2); + assert!(as_u32(add(neg_from(1), from(1))) == 0, 2); + assert!(as_u32(add(from(1), neg_from(1))) == 0, 2); + assert!(as_u32(add(from(10000), neg_from(99999))) == 0xfffea071, 2); + assert!(as_u32(add(from(99999), neg_from(10000))) == 89999, 2); + assert!(as_u32(add(neg_from(MIN_AS_U32), from(1))) == 0x80000001, 2); + assert!(as_u32(add(from(MAX_AS_U32), neg_from(1))) == MAX_AS_U32 - 1, 2); + } + + #[test] + #[expected_failure] + fun test_add_overflow() { + add(from(MAX_AS_U32), from(1)); + } + + #[test] + #[expected_failure] + fun test_add_underflow() { + add(neg_from(MIN_AS_U32), neg_from(1)); + } + + #[test] + fun test_wrapping_sub() { + assert!(as_u32(wrapping_sub(from(0), from(0))) == 0, 0); + assert!(as_u32(wrapping_sub(from(1), from(0))) == 1, 0); + assert!(as_u32(wrapping_sub(from(0), from(1))) == as_u32(neg_from(1)), 0); + assert!(as_u32(wrapping_sub(from(1), from(1))) == as_u32(neg_from(0)), 0); + assert!(as_u32(wrapping_sub(from(1), neg_from(1))) == as_u32(from(2)), 0); + assert!(as_u32(wrapping_sub(neg_from(1), from(1))) == as_u32(neg_from(2)), 0); + assert!(as_u32(wrapping_sub(from(1000000), from(1))) == 999999, 0); + assert!(as_u32(wrapping_sub(neg_from(1000000), neg_from(1))) == as_u32(neg_from(999999)), 0); + assert!(as_u32(wrapping_sub(from(1), from(1000000))) == as_u32(neg_from(999999)), 0); + assert!(as_u32(wrapping_sub(from(MAX_AS_U32), from(MAX_AS_U32))) == as_u32(from(0)), 0); + assert!(as_u32(wrapping_sub(from(MAX_AS_U32), from(1))) == as_u32(from(MAX_AS_U32 - 1)), 0); + assert!(as_u32(wrapping_sub(from(MAX_AS_U32), neg_from(1))) == as_u32(neg_from(MIN_AS_U32)), 0); + assert!(as_u32(wrapping_sub(neg_from(MIN_AS_U32), neg_from(1))) == as_u32(neg_from(MIN_AS_U32 - 1)), 0); + assert!(as_u32(wrapping_sub(neg_from(MIN_AS_U32), from(1))) == as_u32(from(MAX_AS_U32)), 0); + } + + #[test] + fun test_sub() { + assert!(as_u32(sub(from(0), from(0))) == 0, 0); + assert!(as_u32(sub(from(1), from(0))) == 1, 0); + assert!(as_u32(sub(from(0), from(1))) == as_u32(neg_from(1)), 0); + assert!(as_u32(sub(from(1), from(1))) == as_u32(neg_from(0)), 0); + assert!(as_u32(sub(from(1), neg_from(1))) == as_u32(from(2)), 0); + assert!(as_u32(sub(neg_from(1), from(1))) == as_u32(neg_from(2)), 0); + assert!(as_u32(sub(from(1000000), from(1))) == 999999, 0); + assert!(as_u32(sub(neg_from(1000000), neg_from(1))) == as_u32(neg_from(999999)), 0); + assert!(as_u32(sub(from(1), from(1000000))) == as_u32(neg_from(999999)), 0); + assert!(as_u32(sub(from(MAX_AS_U32), from(MAX_AS_U32))) == as_u32(from(0)), 0); + assert!(as_u32(sub(from(MAX_AS_U32), from(1))) == as_u32(from(MAX_AS_U32 - 1)), 0); + assert!(as_u32(sub(neg_from(MIN_AS_U32), neg_from(1))) == as_u32(neg_from(MIN_AS_U32 - 1)), 0); + } + + #[test] + #[expected_failure] + fun test_sub_overflow() { + sub(from(MAX_AS_U32), neg_from(1)); + } + + #[test] + #[expected_failure] + fun test_sub_underflow() { + sub(neg_from(MIN_AS_U32), from(1)); + } + + #[test] + fun test_mul() { + assert!(as_u32(mul(from(1), from(1))) == 1, 0); + assert!(as_u32(mul(from(10), from(10))) == 100, 0); + assert!(as_u32(mul(from(100), from(100))) == 10000, 0); + assert!(as_u32(mul(from(10000), from(10000))) == 100000000, 0); + + assert!(as_u32(mul(neg_from(1), from(1))) == as_u32(neg_from(1)), 0); + assert!(as_u32(mul(neg_from(10), from(10))) == as_u32(neg_from(100)), 0); + assert!(as_u32(mul(neg_from(100), from(100))) == as_u32(neg_from(10000)), 0); + assert!(as_u32(mul(neg_from(10000), from(10000))) == as_u32(neg_from(100000000)), 0); + + assert!(as_u32(mul(from(1), neg_from(1))) == as_u32(neg_from(1)), 0); + assert!(as_u32(mul(from(10), neg_from(10))) == as_u32(neg_from(100)), 0); + assert!(as_u32(mul(from(100), neg_from(100))) == as_u32(neg_from(10000)), 0); + assert!(as_u32(mul(from(10000), neg_from(10000))) == as_u32(neg_from(100000000)), 0); + assert!(as_u32(mul(from(MIN_AS_U32 / 2), neg_from(2))) == as_u32(neg_from(MIN_AS_U32)), 0); + } + + #[test] + #[expected_failure] + fun test_mul_overflow() { + mul(from(MIN_AS_U32 / 2), from(1)); + mul(neg_from(MIN_AS_U32 / 2), neg_from(2)); + } + + #[test] + fun test_div() { + assert!(as_u32(div(from(0), from(1))) == 0, 0); + assert!(as_u32(div(from(10), from(1))) == 10, 0); + assert!(as_u32(div(from(10), neg_from(1))) == as_u32(neg_from(10)), 0); + assert!(as_u32(div(neg_from(10), neg_from(1))) == as_u32(from(10)), 0); + + assert!(abs_u32(neg_from(MIN_AS_U32)) == MIN_AS_U32, 0); + assert!(as_u32(div(neg_from(MIN_AS_U32), from(1))) == MIN_AS_U32, 0); + } + + #[test] + #[expected_failure] + fun test_div_overflow() { + div(neg_from(MIN_AS_U32), neg_from(1)); + } + + #[test] + fun test_shl() { + assert!(as_u32(shl(from(10), 0)) == 10, 0); + assert!(as_u32(shl(neg_from(10), 0)) == as_u32(neg_from(10)), 0); + + assert!(as_u32(shl(from(10), 1)) == 20, 0); + assert!(as_u32(shl(neg_from(10), 1)) == as_u32(neg_from(20)), 0); + + assert!(as_u32(shl(from(10), 8)) == 2560, 0); + assert!(as_u32(shl(neg_from(10), 8)) == as_u32(neg_from(2560)), 0); + + assert!(as_u32(shl(from(10), 31)) == 0, 0); + assert!(as_u32(shl(neg_from(10), 31)) == 0, 0); + } + + #[test] + fun test_shr() { + assert!(as_u32(shr(from(10), 0)) == 10, 0); + assert!(as_u32(shr(neg_from(10), 0)) == as_u32(neg_from(10)), 0); + + assert!(as_u32(shr(from(10), 1)) == 5, 0); + assert!(as_u32(shr(neg_from(10), 1)) == as_u32(neg_from(5)), 0); + + assert!(as_u32(shr(from(MAX_AS_U32), 8)) == MAX_AS_U32 >> 8, 0); + assert!(as_u32(shr(neg_from(MIN_AS_U32), 8)) == 0xff800000, 0); + } + + #[test] + fun test_sign() { + assert!(sign(neg_from(10)) == 1u8, 0); + assert!(sign(from(10)) == 0u8, 0); + } + + #[test] + fun test_cmp() { + assert!(cmp(from(1), from(0)) == GT, 0); + assert!(cmp(from(0), from(1)) == LT, 0); + + assert!(cmp(from(0), neg_from(1)) == GT, 0); + assert!(cmp(neg_from(0), neg_from(1)) == GT, 0); + assert!(cmp(neg_from(1), neg_from(0)) == LT, 0); + assert!(!lt(from(5347), neg_from(765)), 0); + + assert!(cmp(neg_from(MIN_AS_U32), from(MAX_AS_U32)) == LT, 0); + assert!(cmp(from(MAX_AS_U32), neg_from(MIN_AS_U32)) == GT, 0); + + assert!(cmp(from(MAX_AS_U32), from(MAX_AS_U32 - 1)) == GT, 0); + assert!(cmp(from(MAX_AS_U32 - 1), from(MAX_AS_U32)) == LT, 0); + + assert!(cmp(neg_from(MIN_AS_U32), neg_from(MIN_AS_U32 - 1)) == LT, 0); + assert!(cmp(neg_from(MIN_AS_U32 - 1), neg_from(MIN_AS_U32)) == GT, 0); + } + + #[test] + fun test_castdown() { + assert!((1u32 as u8) == 1u8, 0); + } + + #[test] + fun test_mod() { + //use aptos_std::debug; + let i = mod(neg_from(2), from(5)); + assert!(cmp(i, neg_from(2)) == EQ, 0); + + i = mod(neg_from(2), neg_from(5)); + assert!(cmp(i, neg_from(2)) == EQ, 0); + + i = mod(from(2), from(5)); + assert!(cmp(i, from(2)) == EQ, 0); + + i = mod(from(2), neg_from(5)); + assert!(cmp(i, from(2)) == EQ, 0); + } +} diff --git a/contracts/dependencies/integer-mate/sources/i64.move b/contracts/dependencies/integer-mate/sources/i64.move new file mode 100644 index 0000000..624546c --- /dev/null +++ b/contracts/dependencies/integer-mate/sources/i64.move @@ -0,0 +1,489 @@ +module integer_mate::i64 { + const EOverflow: u64 = 0; + + const MIN_AS_U64: u64 = 1 << 63; + const MAX_AS_U64: u64 = 0x7fffffffffffffff; + + const LT: u8 = 0; + const EQ: u8 = 1; + const GT: u8 = 2; + + struct I64 has copy, drop, store { + bits: u64 + } + + public fun zero(): I64 { + I64 { + bits: 0 + } + } + + public fun from_u64(v: u64): I64 { + I64 { + bits: v + } + } + + public fun from(v: u64): I64 { + assert!(v <= MAX_AS_U64, EOverflow); + I64 { + bits: v + } + } + + public fun neg_from(v: u64): I64 { + assert!(v <= MIN_AS_U64, EOverflow); + if (v == 0) { + I64 { + bits: v + } + } else { + I64 { + bits: (u64_neg(v) + 1) | (1 << 63) + } + } + } + + public fun wrapping_add(num1: I64, num2: I64): I64 { + let sum = num1.bits ^ num2.bits; + let carry = (num1.bits & num2.bits) << 1; + while (carry != 0) { + let a = sum; + let b = carry; + sum = a ^ b; + carry = (a & b) << 1; + }; + I64 { + bits: sum + } + } + + public fun add(num1: I64, num2: I64): I64 { + let sum = wrapping_add(num1, num2); + let overflow = (sign(num1) & sign(num2) & u8_neg(sign(sum))) + (u8_neg(sign(num1)) & u8_neg(sign(num2)) & sign( + sum + )); + assert!(overflow == 0, EOverflow); + sum + } + + public fun wrapping_sub(num1: I64, num2: I64): I64 { + let sub_num = wrapping_add(I64 { + bits: u64_neg(num2.bits) + }, from(1)); + wrapping_add(num1, sub_num) + } + + public fun sub(num1: I64, num2: I64): I64 { + let sub_num = wrapping_add(I64 { + bits: u64_neg(num2.bits) + }, from(1)); + add(num1, sub_num) + } + + public fun mul(num1: I64, num2: I64): I64 { + let product = abs_u64(num1) * abs_u64(num2); + if (sign(num1) != sign(num2)) { + return neg_from(product) + }; + return from(product) + } + + public fun div(num1: I64, num2: I64): I64 { + let result = abs_u64(num1) / abs_u64(num2); + if (sign(num1) != sign(num2)) { + return neg_from(result) + }; + return from(result) + } + + public fun abs(v: I64): I64 { + if (sign(v) == 0) { + v + } else { + assert!(v.bits > MIN_AS_U64, EOverflow); + I64 { + bits: u64_neg(v.bits - 1) + } + } + } + + public fun abs_u64(v: I64): u64 { + if (sign(v) == 0) { + v.bits + } else { + u64_neg(v.bits - 1) + } + } + + public fun shl(v: I64, shift: u8): I64 { + I64 { + bits: v.bits << shift + } + } + + public fun shr(v: I64, shift: u8): I64 { + if (shift == 0) { + return v + }; + let mask = 0xffffffffffffffff << (64 - shift); + if (sign(v) == 1) { + return I64 { + bits: (v.bits >> shift) | mask + } + }; + I64 { + bits: v.bits >> shift + } + } + + public fun mod(v: I64, n: I64): I64 { + if (sign(v) == 1) { + neg_from((abs_u64(v) % abs_u64(n))) + } else { + from((as_u64(v) % abs_u64(n))) + } + } + + public fun as_u64(v: I64): u64 { + v.bits + } + + public fun sign(v: I64): u8 { + ((v.bits >> 63) as u8) + } + + public fun is_neg(v: I64): bool { + sign(v) == 1 + } + + public fun cmp(num1: I64, num2: I64): u8 { + if (num1.bits == num2.bits) return EQ; + if (sign(num1) > sign(num2)) return LT; + if (sign(num1) < sign(num2)) return GT; + if (num1.bits > num2.bits) { + return GT + } else { + return LT + } + } + + public fun eq(num1: I64, num2: I64): bool { + num1.bits == num2.bits + } + + public fun gt(num1: I64, num2: I64): bool { + cmp(num1, num2) == GT + } + + public fun gte(num1: I64, num2: I64): bool { + cmp(num1, num2) >= EQ + } + + public fun lt(num1: I64, num2: I64): bool { + cmp(num1, num2) == LT + } + + public fun lte(num1: I64, num2: I64): bool { + cmp(num1, num2) <= EQ + } + + public fun or(num1: I64, num2: I64): I64 { + I64 { + bits: (num1.bits | num2.bits) + } + } + + public fun and(num1: I64, num2: I64): I64 { + I64 { + bits: (num1.bits & num2.bits) + } + } + + fun u64_neg(v: u64): u64 { + v ^ 0xffffffffffffffff + } + + fun u8_neg(v: u8): u8 { + v ^ 0xff + } + + #[test] + fun test_from_ok() { + assert!(as_u64(from(0)) == 0, 0); + assert!(as_u64(from(10)) == 10, 1); + } + + #[test] + #[expected_failure] + fun test_from_overflow() { + as_u64(from(MIN_AS_U64)); + as_u64(from(0xffffffffffffffff)); + } + + #[test] + fun test_neg_from() { + assert!(as_u64(neg_from(0)) == 0, 0); + assert!(as_u64(neg_from(1)) == 0xffffffffffffffff, 1); + assert!(as_u64(neg_from(0x7fffffffffffffff)) == 0x8000000000000001, 2); + assert!(as_u64(neg_from(MIN_AS_U64)) == MIN_AS_U64, 2); + } + + #[test] + #[expected_failure] + fun test_neg_from_overflow() { + neg_from(0x8000000000000001); + } + + #[test] + fun test_abs() { + assert!(as_u64(from(10)) == 10u64, 0); + assert!(as_u64(abs(neg_from(10))) == 10u64, 1); + assert!(as_u64(abs(neg_from(0))) == 0u64, 2); + assert!(as_u64(abs(neg_from(0x7fffffffffffffff))) == 0x7fffffffffffffff, 3); + assert!(as_u64(neg_from(MIN_AS_U64)) == MIN_AS_U64, 4); + } + + #[test] + #[expected_failure] + fun test_abs_overflow() { + abs(neg_from(1 << 63)); + } + + #[test] + fun test_wrapping_add() { + assert!(as_u64(wrapping_add(from(0), from(1))) == 1, 0); + assert!(as_u64(wrapping_add(from(1), from(0))) == 1, 0); + assert!(as_u64(wrapping_add(from(10000), from(99999))) == 109999, 0); + assert!(as_u64(wrapping_add(from(99999), from(10000))) == 109999, 0); + assert!(as_u64(wrapping_add(from(MAX_AS_U64 - 1), from(1))) == MAX_AS_U64, 0); + assert!(as_u64(wrapping_add(from(0), from(0))) == 0, 0); + + assert!(as_u64(wrapping_add(neg_from(0), neg_from(0))) == 0, 1); + assert!(as_u64(wrapping_add(neg_from(1), neg_from(0))) == 0xffffffffffffffff, 1); + assert!(as_u64(wrapping_add(neg_from(0), neg_from(1))) == 0xffffffffffffffff, 1); + assert!(as_u64(wrapping_add(neg_from(10000), neg_from(99999))) == 0xfffffffffffe5251, 1); + assert!(as_u64(wrapping_add(neg_from(99999), neg_from(10000))) == 0xfffffffffffe5251, 1); + assert!(as_u64(wrapping_add(neg_from(MIN_AS_U64 - 1), neg_from(1))) == MIN_AS_U64, 1); + + assert!(as_u64(wrapping_add(from(0), neg_from(0))) == 0, 2); + assert!(as_u64(wrapping_add(neg_from(0), from(0))) == 0, 2); + assert!(as_u64(wrapping_add(neg_from(1), from(1))) == 0, 2); + assert!(as_u64(wrapping_add(from(1), neg_from(1))) == 0, 2); + assert!(as_u64(wrapping_add(from(10000), neg_from(99999))) == 0xfffffffffffea071, 2); + assert!(as_u64(wrapping_add(from(99999), neg_from(10000))) == 89999, 2); + assert!(as_u64(wrapping_add(neg_from(MIN_AS_U64), from(1))) == 0x8000000000000001, 2); + assert!(as_u64(wrapping_add(from(MAX_AS_U64), neg_from(1))) == MAX_AS_U64 - 1, 2); + + assert!(as_u64(wrapping_add(from(MAX_AS_U64), from(1))) == MIN_AS_U64, 2); + } + + #[test] + fun test_add() { + assert!(as_u64(add(from(0), from(0))) == 0, 0); + assert!(as_u64(add(from(0), from(1))) == 1, 0); + assert!(as_u64(add(from(1), from(0))) == 1, 0); + assert!(as_u64(add(from(10000), from(99999))) == 109999, 0); + assert!(as_u64(add(from(99999), from(10000))) == 109999, 0); + assert!(as_u64(add(from(MAX_AS_U64 - 1), from(1))) == MAX_AS_U64, 0); + + assert!(as_u64(add(neg_from(0), neg_from(0))) == 0, 1); + assert!(as_u64(add(neg_from(1), neg_from(0))) == 0xffffffffffffffff, 1); + assert!(as_u64(add(neg_from(0), neg_from(1))) == 0xffffffffffffffff, 1); + assert!(as_u64(add(neg_from(10000), neg_from(99999))) == 0xfffffffffffe5251, 1); + assert!(as_u64(add(neg_from(99999), neg_from(10000))) == 0xfffffffffffe5251, 1); + assert!(as_u64(add(neg_from(MIN_AS_U64 - 1), neg_from(1))) == MIN_AS_U64, 1); + + assert!(as_u64(add(from(0), neg_from(0))) == 0, 2); + assert!(as_u64(add(neg_from(0), from(0))) == 0, 2); + assert!(as_u64(add(neg_from(1), from(1))) == 0, 2); + assert!(as_u64(add(from(1), neg_from(1))) == 0, 2); + assert!(as_u64(add(from(10000), neg_from(99999))) == 0xfffffffffffea071, 2); + assert!(as_u64(add(from(99999), neg_from(10000))) == 89999, 2); + assert!(as_u64(add(neg_from(MIN_AS_U64), from(1))) == 0x8000000000000001, 2); + assert!(as_u64(add(from(MAX_AS_U64), neg_from(1))) == MAX_AS_U64 - 1, 2); + } + + #[test] + #[expected_failure] + fun test_add_overflow() { + add(from(MAX_AS_U64), from(1)); + } + + #[test] + #[expected_failure] + fun test_add_underflow() { + add(neg_from(MIN_AS_U64), neg_from(1)); + } + + #[test] + fun test_wrapping_sub() { + assert!(as_u64(wrapping_sub(from(0), from(0))) == 0, 0); + assert!(as_u64(wrapping_sub(from(1), from(0))) == 1, 0); + assert!(as_u64(wrapping_sub(from(0), from(1))) == as_u64(neg_from(1)), 0); + assert!(as_u64(wrapping_sub(from(1), from(1))) == as_u64(neg_from(0)), 0); + assert!(as_u64(wrapping_sub(from(1), neg_from(1))) == as_u64(from(2)), 0); + assert!(as_u64(wrapping_sub(neg_from(1), from(1))) == as_u64(neg_from(2)), 0); + assert!(as_u64(wrapping_sub(from(1000000), from(1))) == 999999, 0); + assert!(as_u64(wrapping_sub(neg_from(1000000), neg_from(1))) == as_u64(neg_from(999999)), 0); + assert!(as_u64(wrapping_sub(from(1), from(1000000))) == as_u64(neg_from(999999)), 0); + assert!(as_u64(wrapping_sub(from(MAX_AS_U64), from(MAX_AS_U64))) == as_u64(from(0)), 0); + assert!(as_u64(wrapping_sub(from(MAX_AS_U64), from(1))) == as_u64(from(MAX_AS_U64 - 1)), 0); + assert!(as_u64(wrapping_sub(from(MAX_AS_U64), neg_from(1))) == as_u64(neg_from(MIN_AS_U64)), 0); + assert!(as_u64(wrapping_sub(neg_from(MIN_AS_U64), neg_from(1))) == as_u64(neg_from(MIN_AS_U64 - 1)), 0); + assert!(as_u64(wrapping_sub(neg_from(MIN_AS_U64), from(1))) == as_u64(from(MAX_AS_U64)), 0); + } + + #[test] + fun test_sub() { + assert!(as_u64(sub(from(0), from(0))) == 0, 0); + assert!(as_u64(sub(from(1), from(0))) == 1, 0); + assert!(as_u64(sub(from(0), from(1))) == as_u64(neg_from(1)), 0); + assert!(as_u64(sub(from(1), from(1))) == as_u64(neg_from(0)), 0); + assert!(as_u64(sub(from(1), neg_from(1))) == as_u64(from(2)), 0); + assert!(as_u64(sub(neg_from(1), from(1))) == as_u64(neg_from(2)), 0); + assert!(as_u64(sub(from(1000000), from(1))) == 999999, 0); + assert!(as_u64(sub(neg_from(1000000), neg_from(1))) == as_u64(neg_from(999999)), 0); + assert!(as_u64(sub(from(1), from(1000000))) == as_u64(neg_from(999999)), 0); + assert!(as_u64(sub(from(MAX_AS_U64), from(MAX_AS_U64))) == as_u64(from(0)), 0); + assert!(as_u64(sub(from(MAX_AS_U64), from(1))) == as_u64(from(MAX_AS_U64 - 1)), 0); + assert!(as_u64(sub(neg_from(MIN_AS_U64), neg_from(1))) == as_u64(neg_from(MIN_AS_U64 - 1)), 0); + } + + #[test] + #[expected_failure] + fun test_sub_overflow() { + sub(from(MAX_AS_U64), neg_from(1)); + } + + #[test] + #[expected_failure] + fun test_sub_underflow() { + sub(neg_from(MIN_AS_U64), from(1)); + } + + #[test] + fun test_mul() { + assert!(as_u64(mul(from(1), from(1))) == 1, 0); + assert!(as_u64(mul(from(10), from(10))) == 100, 0); + assert!(as_u64(mul(from(100), from(100))) == 10000, 0); + assert!(as_u64(mul(from(10000), from(10000))) == 100000000, 0); + + assert!(as_u64(mul(neg_from(1), from(1))) == as_u64(neg_from(1)), 0); + assert!(as_u64(mul(neg_from(10), from(10))) == as_u64(neg_from(100)), 0); + assert!(as_u64(mul(neg_from(100), from(100))) == as_u64(neg_from(10000)), 0); + assert!(as_u64(mul(neg_from(10000), from(10000))) == as_u64(neg_from(100000000)), 0); + + assert!(as_u64(mul(from(1), neg_from(1))) == as_u64(neg_from(1)), 0); + assert!(as_u64(mul(from(10), neg_from(10))) == as_u64(neg_from(100)), 0); + assert!(as_u64(mul(from(100), neg_from(100))) == as_u64(neg_from(10000)), 0); + assert!(as_u64(mul(from(10000), neg_from(10000))) == as_u64(neg_from(100000000)), 0); + assert!(as_u64(mul(from(MIN_AS_U64 / 2), neg_from(2))) == as_u64(neg_from(MIN_AS_U64)), 0); + } + + #[test] + #[expected_failure] + fun test_mul_overflow() { + mul(from(MIN_AS_U64 / 2), from(1)); + mul(neg_from(MIN_AS_U64 / 2), neg_from(2)); + } + + #[test] + fun test_div() { + assert!(as_u64(div(from(0), from(1))) == 0, 0); + assert!(as_u64(div(from(10), from(1))) == 10, 0); + assert!(as_u64(div(from(10), neg_from(1))) == as_u64(neg_from(10)), 0); + assert!(as_u64(div(neg_from(10), neg_from(1))) == as_u64(from(10)), 0); + + assert!(abs_u64(neg_from(MIN_AS_U64)) == MIN_AS_U64, 0); + assert!(as_u64(div(neg_from(MIN_AS_U64), from(1))) == MIN_AS_U64, 0); + } + + #[test] + #[expected_failure] + fun test_div_overflow() { + div(neg_from(MIN_AS_U64), neg_from(1)); + } + + #[test] + fun test_shl() { + assert!(as_u64(shl(from(10), 0)) == 10, 0); + assert!(as_u64(shl(neg_from(10), 0)) == as_u64(neg_from(10)), 0); + + assert!(as_u64(shl(from(10), 1)) == 20, 0); + assert!(as_u64(shl(neg_from(10), 1)) == as_u64(neg_from(20)), 0); + + assert!(as_u64(shl(from(10), 8)) == 2560, 0); + assert!(as_u64(shl(neg_from(10), 8)) == as_u64(neg_from(2560)), 0); + + assert!(as_u64(shl(from(10), 32)) == 42949672960, 0); + assert!(as_u64(shl(neg_from(10), 32)) == as_u64(neg_from(42949672960)), 0); + + assert!(as_u64(shl(from(10), 63)) == 0, 0); + assert!(as_u64(shl(neg_from(10), 63)) == 0, 0); + } + + #[test] + fun test_shr() { + assert!(as_u64(shr(from(10), 0)) == 10, 0); + assert!(as_u64(shr(neg_from(10), 0)) == as_u64(neg_from(10)), 0); + + assert!(as_u64(shr(from(10), 1)) == 5, 0); + assert!(as_u64(shr(neg_from(10), 1)) == as_u64(neg_from(5)), 0); + + assert!(as_u64(shr(from(MAX_AS_U64), 8)) == 36028797018963967, 0); + assert!(as_u64(shr(neg_from(MIN_AS_U64), 8)) == 0xff80000000000000, 0); + + assert!(as_u64(shr(from(MAX_AS_U64), 32)) == 2147483647, 0); + assert!(as_u64(shr(neg_from(MIN_AS_U64), 32)) == 0xffffffff80000000, 0); + + assert!(as_u64(shr(from(MAX_AS_U64), 63)) == 0, 0); + assert!(as_u64(shr(neg_from(MIN_AS_U64), 63)) == 0xffffffffffffffff, 0); + } + + #[test] + fun test_sign() { + assert!(sign(neg_from(10)) == 1u8, 0); + assert!(sign(from(10)) == 0u8, 0); + } + + #[test] + fun test_cmp() { + assert!(cmp(from(1), from(0)) == GT, 0); + assert!(cmp(from(0), from(1)) == LT, 0); + + assert!(cmp(from(0), neg_from(1)) == GT, 0); + assert!(cmp(neg_from(0), neg_from(1)) == GT, 0); + assert!(cmp(neg_from(1), neg_from(0)) == LT, 0); + + assert!(cmp(neg_from(MIN_AS_U64), from(MAX_AS_U64)) == LT, 0); + assert!(cmp(from(MAX_AS_U64), neg_from(MIN_AS_U64)) == GT, 0); + + assert!(cmp(from(MAX_AS_U64), from(MAX_AS_U64 - 1)) == GT, 0); + assert!(cmp(from(MAX_AS_U64 - 1), from(MAX_AS_U64)) == LT, 0); + + assert!(cmp(neg_from(MIN_AS_U64), neg_from(MIN_AS_U64 - 1)) == LT, 0); + assert!(cmp(neg_from(MIN_AS_U64 - 1), neg_from(MIN_AS_U64)) == GT, 0); + } + + #[test] + fun test_castdown() { + assert!((1u64 as u8) == 1u8, 0); + } + + #[test] + fun test_mod() { + //use aptos_std::debug; + let i = mod(neg_from(2), from(5)); + assert!(cmp(i, neg_from(2)) == EQ, 0); + + i = mod(neg_from(2), neg_from(5)); + assert!(cmp(i, neg_from(2)) == EQ, 0); + + i = mod(from(2), from(5)); + assert!(cmp(i, from(2)) == EQ, 0); + + i = mod(from(2), neg_from(5)); + assert!(cmp(i, from(2)) == EQ, 0); + } +} diff --git a/contracts/dependencies/integer-mate/sources/math_u128.move b/contracts/dependencies/integer-mate/sources/math_u128.move new file mode 100644 index 0000000..f96f78b --- /dev/null +++ b/contracts/dependencies/integer-mate/sources/math_u128.move @@ -0,0 +1,173 @@ +module integer_mate::math_u128 { + + const MAX_U128: u128 = 0xffffffffffffffffffffffffffffffff; + + const HI_64_MASK: u128 = 0xffffffffffffffff0000000000000000; + const LO_64_MASK: u128 = 0x0000000000000000ffffffffffffffff; + const LO_128_MASK: u256 = 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff; + + const DIV_BY_ZERO: u64 = 1; + + public fun wrapping_add(n1: u128, n2: u128): u128 { + let (sum, _) = overflowing_add(n1, n2); + sum + } + + public fun overflowing_add(n1: u128, n2: u128): (u128, bool) { + let sum = (n1 as u256) + (n2 as u256); + if (sum > (MAX_U128 as u256)) { + (((sum & LO_128_MASK) as u128), true) + } else { + ((sum as u128), false) + } + } + + public fun wrapping_sub(n1: u128, n2: u128): u128 { + let (result, _) = overflowing_sub(n1, n2); + result + } + + public fun overflowing_sub(n1: u128, n2: u128): (u128, bool) { + if (n1 >= n2) { + ((n1 - n2), false) + } else { + ((MAX_U128 - n2 + n1 + 1), true) + } + } + + public fun wrapping_mul(n1: u128, n2: u128): u128 { + let (m, _) = overflowing_mul(n1, n2); + m + } + + public fun overflowing_mul(n1: u128, n2: u128): (u128, bool) { + let (c0, c1) = full_mul(n1, n2); + if (c1 > 0) { + (c0, true) + } else { + (c0, false) + } + } + + public fun full_mul(n1: u128, n2: u128): (u128, u128) { + let hi_mask: u256 = 0xffffffffffffffffffffffffffffffff00000000000000000000000000000000; + let lo_mask: u256 = 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff; + let r = (n1 as u256) * (n2 as u256); + let hi = (((r & hi_mask) >> 128) as u128); + let lo = ((r & lo_mask) as u128); + (lo, hi) + } + + public fun hi(n: u128): u64 { + (((n & HI_64_MASK) >> 64) as u64) + } + + public fun lo(n: u128): u64 { + ((n & LO_64_MASK) as u64) + } + + public fun hi_u128(n: u128): u128 { + (n & HI_64_MASK) >> 64 + } + + public fun lo_u128(n: u128): u128 { + (n & LO_64_MASK) + } + + public fun from_lo_hi(lo: u64, hi: u64): u128 { + ((hi as u128) << 64) + (lo as u128) + } + + public fun checked_div_round(num: u128, denom: u128, round_up: bool): u128 { + if (denom == 0) { + abort DIV_BY_ZERO + }; + let quotient = num / denom; + let remainer = num % denom; + if (round_up && (remainer > 0)) { + return (quotient + 1) + }; + quotient + } + + public fun max(num1: u128, num2: u128): u128 { + if (num1 > num2) { + num1 + } else { + num2 + } + } + + public fun min(num1: u128, num2: u128): u128 { + if (num1 < num2) { + num1 + } else { + num2 + } + } + + public fun add_check(num1: u128, num2: u128): bool { + (MAX_U128 - num1 >= num2) + } + + #[test] + fun test_overflowing_add() { + let (m, o) = overflowing_add(10, 10); + assert!(m == 20u128 && o == false, 0); + + let (m, o) = overflowing_add(MAX_U128, 10); + assert!(m == 9u128 && o == true, 0); + } + + #[test] + fun test_full_mul() { + let (lo, hi) = full_mul(0, 10); + assert!(hi == 0 && lo == 0, 0); + + let (lo, hi) = full_mul(10, 10); + assert!(hi == 0 && lo == 100, 0); + + let (lo, hi) = full_mul(9999, 10); + assert!(hi == 0 && lo == 99990, 0); + + let (lo, hi) = full_mul(MAX_U128, 0); + assert!(hi == 0 && lo == 0, 0); + + let (lo, hi) = full_mul(MAX_U128, 1); + assert!(hi == 0 && lo == MAX_U128, 0); + + let (lo, hi) = full_mul(MAX_U128, 10); + assert!(hi == 9 && lo == 0xfffffffffffffffffffffffffffffff6, 0); + + let (lo, hi) = full_mul(10, MAX_U128); + assert!(hi == 9 && lo == 0xfffffffffffffffffffffffffffffff6, 0); + + let (lo, hi) = full_mul(MAX_U128, MAX_U128); + assert!(hi == 0xfffffffffffffffffffffffffffffffe && lo == 1, 0); + } + + #[test] + fun test_wrapping_mul() { + assert!(wrapping_mul(0, 10) == 0, 0); + assert!(wrapping_mul(10, 0) == 0, 0); + assert!(wrapping_mul(10, 10) == 100, 0); + assert!(wrapping_mul(99999, 10) == 10 * 99999, 0); + assert!(wrapping_mul(MAX_U128, 0) == 0, 0); + assert!(wrapping_mul(MAX_U128, 1) == MAX_U128, 0); + assert!(wrapping_mul(MAX_U128, 10) == 0xfffffffffffffffffffffffffffffff6, 0); + assert!(wrapping_mul(10, MAX_U128) == 0xfffffffffffffffffffffffffffffff6, 0); + assert!(wrapping_mul(MAX_U128, MAX_U128) == 1, 0); + } + + #[test] + fun test_overflowing_mul() { + let (r, o) = overflowing_mul(0, 10); + assert!(r == 0 && o == false, 0); + + let (r, o) = overflowing_mul(10, 10); + assert!(r == 100 && o == false, 0); + + let (r, o) = overflowing_mul(MAX_U128, 10); + assert!(r == 0xfffffffffffffffffffffffffffffff6 && o == true, 0); + } +} \ No newline at end of file diff --git a/contracts/dependencies/integer-mate/sources/math_u256.move b/contracts/dependencies/integer-mate/sources/math_u256.move new file mode 100644 index 0000000..99cde05 --- /dev/null +++ b/contracts/dependencies/integer-mate/sources/math_u256.move @@ -0,0 +1,49 @@ +module integer_mate::math_u256 { + const MAX_U256: u256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; + + public fun div_mod(num: u256, denom: u256): (u256, u256) { + let p = num / denom; + let r: u256 = num - (p * denom); + (p, r) + } + + public fun shlw(n: u256): u256 { + n << 64 + } + + public fun shrw(n: u256): u256 { + n >> 64 + } + + public fun checked_shlw(n: u256): (u256, bool) { + let mask = 0xffffffffffffffff << 192; + if (n > mask) { + (0, true) + } else { + ((n << 64), false) + } + } + + public fun div_round(num: u256, denom: u256, round_up: bool): u256 { + let p = num / denom; + if (round_up && ((p * denom) != num)) { + p + 1 + } else { + p + } + } + + public fun add_check(num1: u256, num2: u256): bool { + (MAX_U256 - num1 >= num2) + } + + #[test] + fun test_div_round() { + div_round(1, 1, true); + } + + #[test] + fun test_add() { + 1000u256 + 1000u256; + } +} \ No newline at end of file diff --git a/contracts/dependencies/integer-mate/sources/math_u64.move b/contracts/dependencies/integer-mate/sources/math_u64.move new file mode 100644 index 0000000..458dbbd --- /dev/null +++ b/contracts/dependencies/integer-mate/sources/math_u64.move @@ -0,0 +1,57 @@ +module integer_mate::math_u64 { + const MAX_U64: u64 = 0xffffffffffffffff; + + const HI_64_MASK: u128 = 0xffffffffffffffff0000000000000000; + const LO_64_MASK: u128 = 0x0000000000000000ffffffffffffffff; + + public fun wrapping_add(n1: u64, n2: u64): u64 { + let (sum, _) = overflowing_add(n1, n2); + sum + } + + public fun overflowing_add(n1: u64, n2: u64): (u64, bool) { + let sum = (n1 as u128) + (n2 as u128); + if (sum > (MAX_U64 as u128)) { + (((sum & LO_64_MASK) as u64), true) + } else { + ((sum as u64), false) + } + } + + public fun wrapping_sub(n1: u64, n2: u64): u64 { + let (result, _) = overflowing_sub(n1, n2); + result + } + + public fun overflowing_sub(n1: u64, n2: u64): (u64, bool) { + if (n1 >= n2) { + ((n1 - n2), false) + } else { + ((MAX_U64 - n2 + n1 + 1), true) + } + } + + public fun wrapping_mul(n1: u64, n2: u64): u64 { + let (m, _) = overflowing_mul(n1, n2); + m + } + + public fun overflowing_mul(n1: u64, n2: u64): (u64, bool) { + let m = (n1 as u128) * (n2 as u128); + (((m & LO_64_MASK) as u64), (m & HI_64_MASK) > 0) + } + + public fun carry_add(n1: u64, n2: u64, carry: u64): (u64, u64) { + assert!(carry <= 1, 0); + let sum = (n1 as u128) + (n2 as u128) + (carry as u128); + if (sum > LO_64_MASK) { + (((sum & LO_64_MASK) as u64), 1) + } else { + ((sum as u64), 0) + } + } + + public fun add_check(n1: u64, n2: u64): bool { + (MAX_U64 - n1 >= n2) + } +} \ No newline at end of file diff --git a/contracts/dependencies/move-stl/Move.toml b/contracts/dependencies/move-stl/Move.toml new file mode 100644 index 0000000..e48907a --- /dev/null +++ b/contracts/dependencies/move-stl/Move.toml @@ -0,0 +1,39 @@ +[package] +name = "MoveStl" +edition = "legacy" # edition = "legacy" to use legacy (pre-2024) Move +# published-at="0xe93247b408fe44ed0ee5b6ac508b36325b239d6333e44ffa240dcc0c1a69cdd8" +published-at="0xe93247b408fe44ed0ee5b6ac508b36325b239d6333e44ffa240dcc0c1a69cdd8" +# 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/mainnet" } + +# 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 } + +[addresses] +move_stl = "0xbe21a06129308e0495431d12286127897aff07a8ade3970495a4404d97f9eaaa" + +# 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] +# The dev-addresses section allows overwriting named addresses for the `--test` +# and `--dev` modes. +# alice = "0xB0B" + diff --git a/contracts/dependencies/move-stl/sources/linked_table.move b/contracts/dependencies/move-stl/sources/linked_table.move new file mode 100644 index 0000000..b34f08e --- /dev/null +++ b/contracts/dependencies/move-stl/sources/linked_table.move @@ -0,0 +1,193 @@ +module move_stl::linked_table { + use std::option::{Self, Option}; + + struct LinkedTable has store, key { + id: sui::object::UID, + head: Option, + tail: Option, + size: u64, + } + + struct Node has store { + prev: Option, + next: Option, + value: T1, + } + + public fun contains(arg0: &LinkedTable, arg1: T0) : bool { + sui::dynamic_field::exists_with_type>(&arg0.id, arg1) + } + + public fun borrow(arg0: &LinkedTable, arg1: T0) : &T1 { + &sui::dynamic_field::borrow>(&arg0.id, arg1).value + } + + public fun borrow_mut(arg0: &mut LinkedTable, arg1: T0) : &mut T1 { + &mut sui::dynamic_field::borrow_mut>(&mut arg0.id, arg1).value + } + + public fun destroy_empty(arg0: LinkedTable) { + let LinkedTable { + id : v0, + head : _, + tail : _, + size : v3, + } = arg0; + assert!(v3 == 0, 0); + sui::object::delete(v0); + } + + public fun length(arg0: &LinkedTable) : u64 { + arg0.size + } + + public fun push_back(arg0: &mut LinkedTable, arg1: T0, arg2: T1) { + let v0 = Node{ + prev : arg0.tail, + next : option::none(), + value : arg2, + }; + option::swap_or_fill(&mut arg0.tail, arg1); + if (option::is_none(&arg0.head)) { + option::swap_or_fill(&mut arg0.head, arg1); + }; + if (option::is_some(&v0.prev)) { + option::swap_or_fill(&mut borrow_mut_node(arg0, *option::borrow(&v0.prev)).next, arg1); + }; + sui::dynamic_field::add>(&mut arg0.id, arg1, v0); + arg0.size = arg0.size + 1; + } + + public fun remove(arg0: &mut LinkedTable, arg1: T0) : T1 { + let Node { + prev : v0, + next : v1, + value : v2, + } = sui::dynamic_field::remove>(&mut arg0.id, arg1); + let v3 = v1; + let v4 = v0; + arg0.size = arg0.size - 1; + if (option::is_some(&v4)) { + sui::dynamic_field::borrow_mut>(&mut arg0.id, *option::borrow(&v4)).next = v3; + }; + if (option::is_some(&v3)) { + sui::dynamic_field::borrow_mut>(&mut arg0.id, *option::borrow(&v3)).prev = v4; + }; + if (option::borrow(&arg0.head) == &arg1) { + arg0.head = v3; + }; + if (option::borrow(&arg0.tail) == &arg1) { + arg0.tail = v4; + }; + v2 + } + + public fun new(arg0: &mut sui::tx_context::TxContext) : LinkedTable { + LinkedTable{ + id : sui::object::new(arg0), + head : option::none(), + tail : option::none(), + size : 0, + } + } + + public fun borrow_mut_node(arg0: &mut LinkedTable, arg1: T0) : &mut Node { + sui::dynamic_field::borrow_mut>(&mut arg0.id, arg1) + } + + public fun borrow_mut_value(arg0: &mut Node) : &mut T1 { + &mut arg0.value + } + + public fun borrow_node(arg0: &LinkedTable, arg1: T0) : &Node { + sui::dynamic_field::borrow>(&arg0.id, arg1) + } + + public fun borrow_value(arg0: &Node) : &T1 { + &arg0.value + } + + public fun drop(arg0: LinkedTable) { + let LinkedTable { + id : v0, + head : _, + tail : _, + size : _, + } = arg0; + sui::object::delete(v0); + } + + public fun head(arg0: &LinkedTable) : Option { + arg0.head + } + + public fun insert_after(arg0: &mut LinkedTable, arg1: T0, arg2: T0, arg3: T1) { + let v0 = borrow_mut_node(arg0, arg1); + let v1 = Node{ + prev : option::some(arg1), + next : v0.next, + value : arg3, + }; + option::swap_or_fill(&mut v0.next, arg2); + if (option::is_some(&v1.next)) { + option::swap_or_fill(&mut borrow_mut_node(arg0, *option::borrow(&v1.next)).prev, arg2); + } else { + option::swap_or_fill(&mut arg0.tail, arg2); + }; + sui::dynamic_field::add>(&mut arg0.id, arg2, v1); + arg0.size = arg0.size + 1; + } + + public fun insert_before(arg0: &mut LinkedTable, arg1: T0, arg2: T0, arg3: T1) { + let v0 = borrow_mut_node(arg0, arg1); + let v1 = Node{ + prev : v0.prev, + next : option::some(arg1), + value : arg3, + }; + option::swap_or_fill(&mut v0.prev, arg2); + if (option::is_some(&v1.prev)) { + option::swap_or_fill(&mut borrow_mut_node(arg0, *option::borrow(&v1.prev)).next, arg2); + } else { + option::swap_or_fill(&mut arg0.head, arg2); + }; + sui::dynamic_field::add>(&mut arg0.id, arg2, v1); + arg0.size = arg0.size + 1; + } + + public fun is_empty(arg0: &LinkedTable) : bool { + arg0.size == 0 + } + + public fun next(arg0: &Node) : Option { + arg0.next + } + + public fun prev(arg0: &Node) : Option { + arg0.prev + } + + public fun push_front(arg0: &mut LinkedTable, arg1: T0, arg2: T1) { + let v0 = Node{ + prev : option::none(), + next : arg0.head, + value : arg2, + }; + option::swap_or_fill(&mut arg0.head, arg1); + if (option::is_none(&arg0.tail)) { + option::swap_or_fill(&mut arg0.tail, arg1); + }; + if (option::is_some(&v0.next)) { + option::swap_or_fill(&mut borrow_mut_node(arg0, *option::borrow(&v0.next)).prev, arg1); + }; + sui::dynamic_field::add>(&mut arg0.id, arg1, v0); + arg0.size = arg0.size + 1; + } + + public fun tail(arg0: &LinkedTable) : Option { + arg0.tail + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/move-stl/sources/option_u128.move b/contracts/dependencies/move-stl/sources/option_u128.move new file mode 100644 index 0000000..46bc7fd --- /dev/null +++ b/contracts/dependencies/move-stl/sources/option_u128.move @@ -0,0 +1,61 @@ +module move_stl::option_u128 { + struct OptionU128 has copy, drop, store { + is_none: bool, + v: u128, + } + + public fun contains(arg0: &OptionU128, arg1: u128) : bool { + if (arg0.is_none) { + return false + }; + arg0.v == arg1 + } + + public fun borrow(arg0: &OptionU128) : u128 { + assert!(!arg0.is_none, 0); + arg0.v + } + + public fun borrow_mut(arg0: &mut OptionU128) : &mut u128 { + assert!(!arg0.is_none, 0); + &mut arg0.v + } + + public fun is_none(arg0: &OptionU128) : bool { + arg0.is_none + } + + public fun is_some(arg0: &OptionU128) : bool { + !arg0.is_none + } + + public fun is_some_and_eq(arg0: &OptionU128, arg1: u128) : bool { + !arg0.is_none && arg0.v == arg1 + } + + public fun is_some_and_lte(arg0: &OptionU128, arg1: u128) : bool { + !arg0.is_none && arg0.v <= arg1 + } + + public fun none() : OptionU128 { + OptionU128{ + is_none : true, + v : 0, + } + } + + public fun some(arg0: u128) : OptionU128 { + OptionU128{ + is_none : false, + v : arg0, + } + } + + public fun swap_or_fill(arg0: &mut OptionU128, arg1: u128) { + arg0.is_none = false; + arg0.v = arg1; + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/move-stl/sources/option_u64.move b/contracts/dependencies/move-stl/sources/option_u64.move new file mode 100644 index 0000000..071fdae --- /dev/null +++ b/contracts/dependencies/move-stl/sources/option_u64.move @@ -0,0 +1,54 @@ +module move_stl::option_u64 { + struct OptionU64 has copy, drop, store { + is_none: bool, + v: u64, + } + + public fun contains(arg0: &OptionU64, arg1: u64) : bool { + !arg0.is_none && arg0.v == arg1 + } + + public fun borrow(arg0: &OptionU64) : u64 { + assert!(!arg0.is_none, 0); + arg0.v + } + + public fun borrow_mut(arg0: &mut OptionU64) : &mut u64 { + assert!(!arg0.is_none, 0); + &mut arg0.v + } + + public fun is_none(arg0: &OptionU64) : bool { + arg0.is_none + } + + public fun is_some(arg0: &OptionU64) : bool { + !arg0.is_none + } + + public fun is_some_and_lte(arg0: &OptionU64, arg1: u64) : bool { + !arg0.is_none && arg0.v <= arg1 + } + + public fun none() : OptionU64 { + OptionU64{ + is_none : true, + v : 0, + } + } + + public fun some(arg0: u64) : OptionU64 { + OptionU64{ + is_none : false, + v : arg0, + } + } + + public fun swap_or_fill(arg0: &mut OptionU64, arg1: u64) { + arg0.is_none = false; + arg0.v = arg1; + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/move-stl/sources/random.move b/contracts/dependencies/move-stl/sources/random.move new file mode 100644 index 0000000..2c5891c --- /dev/null +++ b/contracts/dependencies/move-stl/sources/random.move @@ -0,0 +1,32 @@ +module move_stl::random { + struct Random has copy, drop, store { + seed: u64, + } + + public fun new(arg0: u64) : Random { + Random{seed: arg0} + } + + public fun rand(arg0: &mut Random) : u64 { + arg0.seed = ((9223372036854775783 * (arg0.seed as u128) + 999983 >> 1 & 18446744073709551615) as u64); + arg0.seed + } + + public fun rand_n(arg0: &mut Random, arg1: u64) : u64 { + arg0.seed = ((9223372036854775783 * ((arg0.seed as u128) + 999983) >> 1 & 18446744073709551615) as u64); + arg0.seed % arg1 + } + + public fun seed(arg0: &mut Random, arg1: u64) { + arg0.seed = (((arg0.seed as u128) + (arg1 as u128) & 18446744073709551615) as u64); + } + + public fun seed_rand(arg0: &mut Random, arg1: u64) : u64 { + arg0.seed = (((arg0.seed as u128) + (arg1 as u128) & 18446744073709551615) as u64); + arg0.seed = ((9223372036854775783 * ((arg0.seed as u128) + 999983) >> 1 & 18446744073709551615) as u64); + arg0.seed + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/move-stl/sources/skip_list.move b/contracts/dependencies/move-stl/sources/skip_list.move new file mode 100644 index 0000000..818aea2 --- /dev/null +++ b/contracts/dependencies/move-stl/sources/skip_list.move @@ -0,0 +1,278 @@ +module move_stl::skip_list { + use std::vector; + + struct SkipList has store, key { + id: sui::object::UID, + head: vector, + tail: move_stl::option_u64::OptionU64, + level: u64, + max_level: u64, + list_p: u64, + size: u64, + random: move_stl::random::Random, + } + + struct Node has store { + score: u64, + nexts: vector, + prev: move_stl::option_u64::OptionU64, + value: T0, + } + + struct Item has drop, store { + n: u64, + score: u64, + finded: move_stl::option_u64::OptionU64, + } + + public fun contains(arg0: &SkipList, arg1: u64) : bool { + sui::dynamic_field::exists_with_type>(&arg0.id, arg1) + } + + public fun borrow(arg0: &SkipList, arg1: u64) : &T0 { + &sui::dynamic_field::borrow>(&arg0.id, arg1).value + } + + public fun borrow_mut(arg0: &mut SkipList, arg1: u64) : &mut T0 { + &mut sui::dynamic_field::borrow_mut>(&mut arg0.id, arg1).value + } + + public fun destroy_empty(arg0: SkipList) { + let SkipList { + id : v0, + head : _, + tail : _, + level : _, + max_level : _, + list_p : _, + size : v6, + random : _, + } = arg0; + assert!(v6 == 0, 3); + sui::object::delete(v0); + } + + public fun length(arg0: &SkipList) : u64 { + arg0.size + } + + public fun remove(arg0: &mut SkipList, arg1: u64) : T0 { + assert!(contains(arg0, arg1), 1); + let v0 = &mut arg0.head; + let v1 = arg0.level; + let v2 = sui::dynamic_field::remove>(&mut arg0.id, arg1); + while (v1 > 0) { + let v3 = vector::borrow_mut(v0, v1 - 1); + while (move_stl::option_u64::is_some_and_lte(v3, arg1)) { + let v4 = move_stl::option_u64::borrow(v3); + if (v4 == arg1) { + let v5 = *vector::borrow(&v2.nexts, v1 - 1); + *v3 = v5; + continue + }; + v0 = &mut borrow_mut_node(arg0, v4).nexts; + let v7 = v1 - 1; + v3 = vector::borrow_mut(v0, v7); + }; + v1 = v1 - 1; + }; + if (move_stl::option_u64::borrow(&arg0.tail) == arg1) { + arg0.tail = v2.prev; + }; + let v8 = vector::borrow(&v2.nexts, 0); + if (move_stl::option_u64::is_some(v8)) { + borrow_mut_node(arg0, move_stl::option_u64::borrow(v8)).prev = v2.prev; + }; + arg0.size = arg0.size - 1; + drop_node(v2) + } + + public fun new(arg0: u64, arg1: u64, arg2: u64, arg3: &mut sui::tx_context::TxContext) : SkipList { + SkipList{ + id : sui::object::new(arg3), + head : vector::empty(), + tail : move_stl::option_u64::none(), + level : 0, + max_level : arg0, + list_p : arg1, + size : 0, + random : move_stl::random::new(arg2), + } + } + + public fun borrow_mut_node(arg0: &mut SkipList, arg1: u64) : &mut Node { + sui::dynamic_field::borrow_mut>(&mut arg0.id, arg1) + } + + public fun borrow_mut_value(arg0: &mut Node) : &mut T0 { + &mut arg0.value + } + + public fun borrow_node(arg0: &SkipList, arg1: u64) : &Node { + sui::dynamic_field::borrow>(&arg0.id, arg1) + } + + public fun borrow_value(arg0: &Node) : &T0 { + &arg0.value + } + + fun create_node(arg0: &mut SkipList, arg1: u64, arg2: T0) : (u64, Node) { + let v0 = rand_level(move_stl::random::rand(&mut arg0.random), arg0); + if (v0 > arg0.level) { + arg0.level = v0; + vector::push_back(&mut arg0.head, move_stl::option_u64::none()); + }; + let v1 = Node{ + score : arg1, + nexts : vector::empty(), + prev : move_stl::option_u64::none(), + value : arg2, + }; + (v0, v1) + } + + fun drop_node(arg0: Node) : T0 { + let Node { + score : _, + nexts : _, + prev : _, + value : v3, + } = arg0; + v3 + } + + fun find(arg0: &SkipList, arg1: u64) : move_stl::option_u64::OptionU64 { + let v0 = move_stl::option_u64::none(); + let v1 = &arg0.head; + let v2 = arg0.level; + while (v2 > 0) { + let v3 = *vector::borrow(v1, v2 - 1); + while (move_stl::option_u64::is_some_and_lte(&v3, arg1)) { + let v4 = move_stl::option_u64::borrow(&v3); + if (v4 == arg1) { + return move_stl::option_u64::some(v4) + }; + v0 = v3; + let v5 = &borrow_node(arg0, v4).nexts; + v1 = v5; + v3 = *vector::borrow(v5, v2 - 1); + }; + if (v2 == 1 && move_stl::option_u64::is_some(&v0)) { + return v0 + }; + v2 = v2 - 1; + }; + *vector::borrow(&arg0.head, 0) + } + + public fun find_next(arg0: &SkipList, arg1: u64, arg2: bool) : move_stl::option_u64::OptionU64 { + let v0 = find(arg0, arg1); + if (move_stl::option_u64::is_none(&v0)) { + return v0 + }; + let v1 = move_stl::option_u64::borrow(&v0); + if (arg2 && v1 == arg1 || v1 > arg1) { + return v0 + }; + *vector::borrow(&borrow_node(arg0, v1).nexts, 0) + } + + public fun find_prev(arg0: &SkipList, arg1: u64, arg2: bool) : move_stl::option_u64::OptionU64 { + let v0 = find(arg0, arg1); + if (move_stl::option_u64::is_none(&v0)) { + return v0 + }; + let v1 = move_stl::option_u64::borrow(&v0); + if (arg2 && v1 == arg1 || v1 < arg1) { + return v0 + }; + borrow_node(arg0, v1).prev + } + + public fun head(arg0: &SkipList) : move_stl::option_u64::OptionU64 { + if (is_empty(arg0)) { + return move_stl::option_u64::none() + }; + *vector::borrow(&arg0.head, 0) + } + + public fun insert(arg0: &mut SkipList, arg1: u64, arg2: T0) { + assert!(!contains(arg0, arg1), 0); + let (v0, v1) = create_node(arg0, arg1, arg2); + let v2 = v1; + let v3 = move_stl::option_u64::none(); + let v4 = &mut arg0.head; + let v5 = arg0.level; + let v6 = move_stl::option_u64::none(); + while (v5 > 0) { + let v7 = vector::borrow_mut(v4, v5 - 1); + while (move_stl::option_u64::is_some_and_lte(v7, arg1)) { + let v8 = sui::dynamic_field::borrow_mut>(&mut arg0.id, move_stl::option_u64::borrow(v7)); + v3 = move_stl::option_u64::some(v8.score); + v4 = &mut v8.nexts; + v7 = vector::borrow_mut(v4, v5 - 1); + }; + if (v0 >= v5) { + vector::push_back(&mut v2.nexts, *v7); + if (v5 == 1) { + v2.prev = v3; + if (move_stl::option_u64::is_some(v7)) { + v6 = *v7; + } else { + arg0.tail = move_stl::option_u64::some(arg1); + }; + }; + move_stl::option_u64::swap_or_fill(v7, arg1); + }; + v5 = v5 - 1; + }; + if (move_stl::option_u64::is_some(&v6)) { + borrow_mut_node(arg0, move_stl::option_u64::borrow(&v6)).prev = move_stl::option_u64::some(arg1); + }; + vector::reverse(&mut v2.nexts); + sui::dynamic_field::add>(&mut arg0.id, arg1, v2); + arg0.size = arg0.size + 1; + } + + public fun is_empty(arg0: &SkipList) : bool { + arg0.size == 0 + } + + public fun metadata(arg0: &SkipList) : (vector, move_stl::option_u64::OptionU64, u64, u64, u64, u64) { + (arg0.head, arg0.tail, arg0.level, arg0.max_level, arg0.list_p, arg0.size) + } + + public fun next_score(arg0: &Node) : move_stl::option_u64::OptionU64 { + *vector::borrow(&arg0.nexts, 0) + } + + public fun prev_score(arg0: &Node) : move_stl::option_u64::OptionU64 { + arg0.prev + } + + fun rand_level(arg0: u64, arg1: &SkipList) : u64 { + let v0 = 1; + let v1 = arg1.list_p; + while (arg0 % v1 == 0) { + v1 = v1 * arg1.list_p; + let v2 = v0 + 1; + v0 = v2; + if (v2 > arg1.level) { + if (v2 >= arg1.max_level) { + v0 = arg1.max_level; + break + }; + v0 = arg1.level + 1; + break + }; + }; + v0 + } + + public fun tail(arg0: &SkipList) : move_stl::option_u64::OptionU64 { + arg0.tail + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/dependencies/move-stl/sources/skip_list_u128.move b/contracts/dependencies/move-stl/sources/skip_list_u128.move new file mode 100644 index 0000000..66bc697 --- /dev/null +++ b/contracts/dependencies/move-stl/sources/skip_list_u128.move @@ -0,0 +1,278 @@ +module move_stl::skip_list_u128 { + use sui::object::UID; + + struct SkipList has store, key { + id: UID, + head: vector, + tail: move_stl::option_u128::OptionU128, + level: u64, + max_level: u64, + list_p: u64, + random: move_stl::random::Random, + inner: sui::table::Table>, + } + + struct SkipListNode has store { + score: u128, + nexts: vector, + prev: move_stl::option_u128::OptionU128, + value: T0, + } + + struct Item has drop, store { + n: u64, + score: u64, + finded: move_stl::option_u128::OptionU128, + } + + public fun contains(arg0: &SkipList, arg1: u128) : bool { + sui::table::contains>(&arg0.inner, arg1) + } + + public fun borrow(arg0: &SkipList, arg1: u128) : &T0 { + &sui::table::borrow>(&arg0.inner, arg1).value + } + + public fun borrow_mut(arg0: &mut SkipList, arg1: u128) : &mut T0 { + &mut sui::table::borrow_mut>(&mut arg0.inner, arg1).value + } + + public fun destroy_empty(arg0: SkipList) { + let SkipList { + id : v0, + head : _, + tail : _, + level : _, + max_level : _, + list_p : _, + random : _, + inner : v7, + } = arg0; + let v8 = v7; + assert!(sui::table::length>(&v8) == 0, 3); + sui::table::destroy_empty>(v8); + sui::object::delete(v0); + } + + public fun length(arg0: &SkipList) : u64 { + sui::table::length>(&arg0.inner) + } + + public fun new(arg0: u64, arg1: u64, arg2: u64, arg3: &mut sui::tx_context::TxContext) : SkipList { + SkipList{ + id : sui::object::new(arg3), + head : std::vector::empty(), + tail : move_stl::option_u128::none(), + level : 0, + max_level : arg0, + list_p : arg1, + random : move_stl::random::new(arg2), + inner : sui::table::new>(arg3), + } + } + + public fun remove(arg0: &mut SkipList, arg1: u128) : T0 { + assert!(sui::table::contains>(&arg0.inner, arg1), 1); + let v0 = &mut arg0.head; + let v1 = arg0.level; + let v2 = sui::table::remove>(&mut arg0.inner, arg1); + while (v1 > 0) { + let v3 = std::vector::borrow_mut(v0, v1 - 1); + while (move_stl::option_u128::is_some_and_lte(v3, arg1)) { + let v4 = move_stl::option_u128::borrow(v3); + if (v4 == arg1) { + let v5 = *std::vector::borrow(&v2.nexts, v1 - 1); + *v3 = v5; + continue + }; + v0 = &mut sui::table::borrow_mut>(&mut arg0.inner, v4).nexts; + let v7 = v1 - 1; + v3 = std::vector::borrow_mut(v0, v7); + }; + v1 = v1 - 1; + }; + if (move_stl::option_u128::borrow(&arg0.tail) == arg1) { + arg0.tail = v2.prev; + }; + let v8 = std::vector::borrow(&v2.nexts, 0); + if (move_stl::option_u128::is_some(v8)) { + sui::table::borrow_mut>(&mut arg0.inner, move_stl::option_u128::borrow(v8)).prev = v2.prev; + }; + drop_node(v2) + } + + public fun borrow_mut_node(arg0: &mut SkipList, arg1: u128) : &mut SkipListNode { + sui::table::borrow_mut>(&mut arg0.inner, arg1) + } + + public fun borrow_mut_value(arg0: &mut SkipListNode) : &mut T0 { + &mut arg0.value + } + + public fun borrow_node(arg0: &SkipList, arg1: u128) : &SkipListNode { + sui::table::borrow>(&arg0.inner, arg1) + } + + public fun borrow_value(arg0: &SkipListNode) : &T0 { + &arg0.value + } + + fun create_node(arg0: &mut SkipList, arg1: u128, arg2: T0) : (u64, SkipListNode) { + let v0 = rand_level(move_stl::random::rand(&mut arg0.random), arg0); + if (v0 > arg0.level) { + arg0.level = v0; + std::vector::push_back(&mut arg0.head, move_stl::option_u128::none()); + }; + let v1 = SkipListNode{ + score : arg1, + nexts : std::vector::empty(), + prev : move_stl::option_u128::none(), + value : arg2, + }; + (v0, v1) + } + + fun drop_node(arg0: SkipListNode) : T0 { + let SkipListNode { + score : _, + nexts : _, + prev : _, + value : v3, + } = arg0; + v3 + } + + fun find(arg0: &SkipList, arg1: u128) : move_stl::option_u128::OptionU128 { + let v0 = move_stl::option_u128::none(); + let v1 = &arg0.head; + let v2 = arg0.level; + while (v2 > 0) { + let v3 = *std::vector::borrow(v1, v2 - 1); + while (move_stl::option_u128::is_some_and_lte(&v3, arg1)) { + let v4 = move_stl::option_u128::borrow(&v3); + if (v4 == arg1) { + return move_stl::option_u128::some(v4) + }; + v0 = v3; + let v5 = &sui::table::borrow>(&arg0.inner, v4).nexts; + v1 = v5; + v3 = *std::vector::borrow(v5, v2 - 1); + }; + if (v2 == 1 && move_stl::option_u128::is_some(&v0)) { + return v0 + }; + v2 = v2 - 1; + }; + *std::vector::borrow(&arg0.head, 0) + } + + public fun find_next(arg0: &SkipList, arg1: u128, arg2: bool) : move_stl::option_u128::OptionU128 { + let v0 = find(arg0, arg1); + if (move_stl::option_u128::is_none(&v0)) { + return v0 + }; + let v1 = move_stl::option_u128::borrow(&v0); + if (arg2 && v1 == arg1 || v1 > arg1) { + return v0 + }; + *std::vector::borrow(&borrow_node(arg0, v1).nexts, 0) + } + + public fun find_prev(arg0: &SkipList, arg1: u128, arg2: bool) : move_stl::option_u128::OptionU128 { + let v0 = find(arg0, arg1); + if (move_stl::option_u128::is_none(&v0)) { + return v0 + }; + let v1 = move_stl::option_u128::borrow(&v0); + if (arg2 && v1 == arg1 || v1 < arg1) { + return v0 + }; + borrow_node(arg0, v1).prev + } + + public fun head(arg0: &SkipList) : move_stl::option_u128::OptionU128 { + if (is_empty(arg0)) { + return move_stl::option_u128::none() + }; + *std::vector::borrow(&arg0.head, 0) + } + + public fun insert(arg0: &mut SkipList, arg1: u128, arg2: T0) { + assert!(!sui::table::contains>(&arg0.inner, arg1), 0); + let (v0, v1) = create_node(arg0, arg1, arg2); + let v2 = v1; + let v3 = move_stl::option_u128::none(); + let v4 = &mut arg0.head; + let v5 = arg0.level; + let v6 = move_stl::option_u128::none(); + while (v5 > 0) { + let v7 = std::vector::borrow_mut(v4, v5 - 1); + while (move_stl::option_u128::is_some_and_lte(v7, arg1)) { + let v8 = sui::table::borrow_mut>(&mut arg0.inner, move_stl::option_u128::borrow(v7)); + v3 = move_stl::option_u128::some(v8.score); + v4 = &mut v8.nexts; + v7 = std::vector::borrow_mut(v4, v5 - 1); + }; + if (v0 >= v5) { + std::vector::push_back(&mut v2.nexts, *v7); + if (v5 == 1) { + v2.prev = v3; + if (move_stl::option_u128::is_some(v7)) { + v6 = *v7; + } else { + arg0.tail = move_stl::option_u128::some(arg1); + }; + }; + move_stl::option_u128::swap_or_fill(v7, arg1); + }; + v5 = v5 - 1; + }; + std::vector::reverse(&mut v2.nexts); + sui::table::add>(&mut arg0.inner, arg1, v2); + if (move_stl::option_u128::is_some(&v6)) { + sui::table::borrow_mut>(&mut arg0.inner, move_stl::option_u128::borrow(&v6)).prev = move_stl::option_u128::some(arg1); + }; + } + + public fun is_empty(arg0: &SkipList) : bool { + sui::table::length>(&arg0.inner) == 0 + } + + public fun metadata(arg0: &SkipList) : (vector, move_stl::option_u128::OptionU128, u64, u64, u64, u64) { + (arg0.head, arg0.tail, arg0.level, arg0.max_level, arg0.list_p, sui::table::length>(&arg0.inner)) + } + + public fun next_score(arg0: &SkipListNode) : move_stl::option_u128::OptionU128 { + *std::vector::borrow(&arg0.nexts, 0) + } + + public fun prev_score(arg0: &SkipListNode) : move_stl::option_u128::OptionU128 { + arg0.prev + } + + fun rand_level(arg0: u64, arg1: &SkipList) : u64 { + let v0 = 1; + let v1 = arg1.list_p; + while (arg0 % v1 == 0) { + v1 = v1 * arg1.list_p; + let v2 = v0 + 1; + v0 = v2; + if (v2 > arg1.level) { + if (v2 >= arg1.max_level) { + v0 = arg1.max_level; + break + }; + v0 = arg1.level + 1; + break + }; + }; + v0 + } + + public fun tail(arg0: &SkipList) : move_stl::option_u128::OptionU128 { + arg0.tail + } + + // decompiled from Move bytecode v6 +} + diff --git a/contracts/init_msend/Move.toml b/contracts/init_msend/Move.toml index bc0c74e..a68ad68 100644 --- a/contracts/init_msend/Move.toml +++ b/contracts/init_msend/Move.toml @@ -32,6 +32,7 @@ init_msend = "0x0" # alice = "0xA11CE" [dev-dependencies] +CetusClmm = { local = "../dependencies/cetus" } # 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" } diff --git a/contracts/init_msend/tests/msend_test.move b/contracts/init_msend/tests/msend_test.move new file mode 100644 index 0000000..b942c2c --- /dev/null +++ b/contracts/init_msend/tests/msend_test.move @@ -0,0 +1,236 @@ +#[test_only] +module init_msend::msend_test { + use std::string::utf8; + use sui::clock; + use sui::balance; + use sui::coin::{Self, TreasuryCap}; + use sui::sui::SUI; + use sui::test_utils::{destroy}; + use sui::test_scenario::{Self, Scenario, ctx}; + use sui::test_utils::{assert_eq}; + use cetus_clmm::factory; + use cetus_clmm::pool::{Pool as CetusPool}; + use cetus_clmm::config; + use sui::tx_context::sender; + use send::send::SEND; + use msend_3_month::msend_3_month::{MSEND_3_MONTH as MSEND}; + use mtoken::mtoken; + + const START_TIME_S: u64 = 1733228602; + const END_TIME_S: u64 = 1734006202; + + public fun send_decimals(val: u64): u64 { + val * 1_000_000 + } + + public fun setup_cetus_pool_split_liquidity( + scenario: &mut Scenario, + ): ( + cetus_clmm::pool::Pool, + cetus_clmm::config::GlobalConfig, + cetus_clmm::config::AdminCap, + cetus_clmm::position::Position, + ) { + let owner = sender(ctx(scenario)); + let clock = clock::create_for_testing(ctx(scenario)); + + // Supply allocated + let send_liquidity_amount = send_decimals(20_000_000_000); + + let tick_spacing = 200_u32; + + let sqrt_price = cetus_clmm::tick_math::get_sqrt_price_at_tick( + integer_mate::i32::from(46000) // 0.1 + ); + + let mut registry = factory::init_for_testing(ctx(scenario)); + let (mut config, admin_cap) = config::init_for_testing(ctx(scenario)); + let fee_rate = 10000; + config::add_fee_tier(&mut config, tick_spacing, fee_rate, ctx(scenario)); + + // Prepare coins + let send = coin::mint_for_testing(send_liquidity_amount, ctx(scenario)); + + // Ticks + let tick_a1 = 39000; // 0.05 + let tick_a2 = 69000; // 1.0 + + let (position, coin_meme, coin_sui) = factory::create_pool_with_liquidity( + &mut registry, + &config, + tick_spacing, + sqrt_price, // current_sqrt_price + utf8(b"hello"), + tick_a1, + tick_a2, + send, + coin::mint_for_testing(859622001237312227, ctx(scenario)), + send_liquidity_amount, + 859622001237312227, + true, // from_a + &clock, + ctx(scenario), + ); + + destroy(coin_meme); + destroy(coin_sui); + + test_scenario::next_tx(scenario, owner); + let pool: CetusPool = test_scenario::take_shared(scenario); + + destroy(clock); + destroy(registry); + + (pool, config, admin_cap, position) + } + + #[test] + public fun mint_mtokens() { + let mut scenario = test_scenario::begin(@0x10); + + let send = coin::mint_for_testing(100_000_000_000 * 1_000_000, scenario.ctx()); + let treasury_cap: TreasuryCap = coin::create_treasury_cap_for_testing(scenario.ctx()); + + let (admin_cap, manager, msend) = mtoken::mint_mtokens( + treasury_cap, + send, + 10, // start_penalty_numerator + 1, // end_penalty_numerator + 100_000, // penalty_denominator + START_TIME_S, // start_time_s + END_TIME_S, // end_time_s + scenario.ctx(), + ); + + transfer::public_share_object(manager); + transfer::public_transfer(admin_cap, @0x10); + transfer::public_transfer(msend, @0x10); + + scenario.end(); + } + + #[test] + public fun claim_send() { + let mut scenario = test_scenario::begin(@0x10); + let mut clock = clock::create_for_testing(scenario.ctx()); + clock.set_for_testing(START_TIME_S * 1000); + + let send = coin::mint_for_testing(100_000_000_000 * 1_000_000, scenario.ctx()); + let treasury_cap: TreasuryCap = coin::create_treasury_cap_for_testing(scenario.ctx()); + + let send_value = send.value(); + let (admin_cap, mut manager, mut msend) = mtoken::mint_mtokens( + treasury_cap, + send, + 10, // start_penalty_numerator + 1, // end_penalty_numerator + 100_000, // penalty_denominator + START_TIME_S, // start_time_s + END_TIME_S, // end_time_s + scenario.ctx(), + ); + assert!(send_value == msend.value(), 0); + + scenario.next_tx(@0x10); + + let msend_to_redeem = msend.split(1_000_000, scenario.ctx()); + let mut penalty_coin = coin::mint_for_testing(100, scenario.ctx()); + + let send = manager.redeem_mtokens( + msend_to_redeem, + &mut penalty_coin, + &clock, + scenario.ctx(), + ); + + assert!(penalty_coin.value() == 0, 1); + assert!(send.value() == 1_000_000, 2); + + destroy(manager); + destroy(admin_cap); + destroy(penalty_coin); + destroy(msend); + destroy(send); + destroy(clock); + + scenario.end(); + } + + #[test] + public fun test_flash_loan() { + let mut scenario = test_scenario::begin(@0x10); + let mut clock = clock::create_for_testing(scenario.ctx()); + clock.set_for_testing(START_TIME_S * 1000); + + let send = coin::mint_for_testing(100_000_000_000 * 1_000_000, scenario.ctx()); + let treasury_cap: TreasuryCap = coin::create_treasury_cap_for_testing(scenario.ctx()); + + let send_value = send.value(); + + let (admin_cap, mut manager, mut msend) = mtoken::mint_mtokens( + treasury_cap, + send, + 10, // start_penalty_numerator + 1, // end_penalty_numerator + 100_000, // penalty_denominator + START_TIME_S, // start_time_s + END_TIME_S, // end_time_s + scenario.ctx(), + ); + + assert!(send_value == msend.value(), 0); + + scenario.next_tx(@0x10); + + let msend_to_redeem = msend.split(1_000_000, scenario.ctx()); + + let (mut pool, config, pool_admin_cap, position) = setup_cetus_pool_split_liquidity(&mut scenario); + + let min_price = cetus_clmm::tick_math::get_sqrt_price_at_tick( + integer_mate::i32::from(23000) // 0.01 + ); + + let (mut send_bal, sui_bal, receipt) = cetus_clmm::pool::flash_swap( + &config, + &mut pool, + true, // a2b + false, // by amount_in + 100, // amount + min_price, + &clock, + ); + + assert_eq(send_bal.value(), 0); + assert_eq(sui_bal.value(), 100); + + let mut penalty_coin = coin::from_balance(sui_bal, scenario.ctx()); + + let mut send = manager.redeem_mtokens( + msend_to_redeem, + &mut penalty_coin, + &clock, + scenario.ctx(), + ); + + assert!(penalty_coin.value() == 0, 1); + assert!(send.value() == 1_000_000, 2); + + send_bal.join(send.split(receipt.swap_pay_amount(), scenario.ctx()).into_balance()); + + cetus_clmm::pool::repay_flash_swap(&config, &mut pool, send_bal, balance::zero(), receipt); + + destroy(pool); + destroy(config); + destroy(pool_admin_cap); + destroy(position); + + destroy(manager); + destroy(admin_cap); + destroy(penalty_coin); + destroy(msend); + destroy(send); + destroy(clock); + + scenario.end(); + } +} \ No newline at end of file From 300250dad02bc8a1cd7a6dd47c4c26deb94aa565 Mon Sep 17 00:00:00 2001 From: 0xxgen1 <0xxgen@solend.fi> Date: Wed, 11 Dec 2024 14:14:18 +0000 Subject: [PATCH 3/3] flash loan test on testnet --- .gitignore | 2 +- package-lock.json | 825 ++++++++++++++++++++++++++++++++++++++++- package.json | 33 +- sdk/src/consts.ts | 41 ++ sdk/src/flashLoan.ts | 162 ++++++++ sdk/src/index.ts | 56 +++ sdk/src/mintMTokens.ts | 116 ++++++ sdk/src/setupTest.ts | 119 ++++++ sdk/src/utils.ts | 34 ++ tsconfig.json | 21 ++ 10 files changed, 1381 insertions(+), 28 deletions(-) create mode 100644 sdk/src/consts.ts create mode 100644 sdk/src/flashLoan.ts create mode 100644 sdk/src/mintMTokens.ts create mode 100644 sdk/src/setupTest.ts create mode 100644 sdk/src/utils.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 59695d0..5719119 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ build .vscode - +.env node_modules diff --git a/package-lock.json b/package-lock.json index 32bb353..30b78a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,12 @@ "version": "1.0.9", "license": "MIT", "dependencies": { - "@mysten/sui": "^1.9.0", - "bn.js": "^5.2.1" + "@cetusprotocol/cetus-sui-clmm-sdk": "^5.1.10", + "@mysten/sui": "^1.16.2", + "bn.js": "^5.2.1", + "dotenv": "^16.4.7", + "tslib": "^2.8.1", + "tsx": "^4.19.2" }, "devDependencies": { "@types/bn.js": "^5.1.6", @@ -548,6 +552,416 @@ "dev": true, "license": "MIT" }, + "node_modules/@cetusprotocol/cetus-sui-clmm-sdk": { + "version": "5.1.10", + "resolved": "https://registry.npmjs.org/@cetusprotocol/cetus-sui-clmm-sdk/-/cetus-sui-clmm-sdk-5.1.10.tgz", + "integrity": "sha512-AL0bp3x48wM1CzBScF3VpgNiGhL7EbvdD70mE6TZodmwISIZ504K5yeeyXYG5Oz8NullW/0VvIjbOGVIedCzKQ==", + "license": "Apache-2.0", + "dependencies": { + "@suchipi/femver": "^1.0.0", + "@syntsugar/cc-graph": "^0.1.1", + "@types/bn.js": "^5.1.1", + "axios": "^1.4.0", + "bn.js": "^5.2.1", + "cors": "^2.8.5", + "decimal.js": "^10.4.1", + "isomorphic-fetch": "^3.0.0", + "js-base64": "^3.7.4", + "js-sha3": "^0.8.0", + "superstruct": "^1.0.3", + "tiny-invariant": "^1.1.0", + "tweetnacl": "^1.0.3", + "uuid": "^9.0.0" + }, + "peerDependencies": { + "@mysten/bcs": ">=0.8.1", + "@mysten/sui": ">=1.1.2" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@gql.tada/cli-utils": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/@gql.tada/cli-utils/-/cli-utils-1.6.3.tgz", @@ -969,22 +1383,22 @@ } }, "node_modules/@mysten/bcs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-1.1.0.tgz", - "integrity": "sha512-yy9/1Y4d0FlRywS1+9ze/T7refCbrvwFwJIOKs9M3QBK1njbcHZp+LkVeLqBvIJA5eZ3ZCzmhQ1Xq4Sed5mEBA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-1.2.0.tgz", + "integrity": "sha512-LuKonrGdGW7dq/EM6U2L9/as7dFwnhZnsnINzB/vu08Xfrj0qzWwpLOiXagAa5yZOPLK7anRZydMonczFkUPzA==", "license": "Apache-2.0", "dependencies": { "bs58": "^6.0.0" } }, "node_modules/@mysten/sui": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/@mysten/sui/-/sui-1.14.2.tgz", - "integrity": "sha512-WkkVLoP9SXhcZYh/yqtXaM8zX8KPdCTfMUY9oNjHBIFBN3K0s6M5mFRPekZdG8+PVGyRLZI1mFQOs7cRyx4xKg==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@mysten/sui/-/sui-1.16.2.tgz", + "integrity": "sha512-1Nfm7iTs3IVsiCXFPrnci9Y7fP9ldtwNOTe7JRkaHTg58VRhSe/nhHOvt6UsYiswVPUBqlsSF73KER5MpirCvw==", "license": "Apache-2.0", "dependencies": { "@graphql-typed-document-node/core": "^3.2.0", - "@mysten/bcs": "1.1.0", + "@mysten/bcs": "1.2.0", "@noble/curves": "^1.4.2", "@noble/hashes": "^1.4.0", "@scure/bip32": "^1.4.0", @@ -993,6 +1407,8 @@ "bech32": "^2.0.0", "gql.tada": "^1.8.2", "graphql": "^16.9.0", + "jose": "^5.6.3", + "poseidon-lite": "^0.2.0", "tweetnacl": "^1.0.3", "valibot": "^0.36.0" }, @@ -1096,6 +1512,15 @@ "integrity": "sha512-bprE8+K5V+DPX7q2e2K57ImqNBdfGHDIWaGI5xHxZoxbKOuQZn4wzPiUxOAHnsUr3w3xHrWXwN7gnG/iIuEMIg==", "license": "MIT" }, + "node_modules/@syntsugar/cc-graph": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@syntsugar/cc-graph/-/cc-graph-0.1.1.tgz", + "integrity": "sha512-u5ne/gnGokhYGRrLs4IfQPWcNnxwHTO2KaqyJ6t6xupOLTyBuqAIeMpblDK8SGPBcXcWgePKZcirKJmY5cgHmQ==", + "dependencies": { + "ss-queue": "1.0.x", + "ss-stack": "1.0.x" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1145,7 +1570,6 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz", "integrity": "sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -1210,7 +1634,6 @@ "version": "22.9.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.19.8" @@ -1316,6 +1739,23 @@ "node": ">=12" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -1711,6 +2151,18 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1725,6 +2177,19 @@ "dev": true, "license": "MIT" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -1780,6 +2245,12 @@ } } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "license": "MIT" + }, "node_modules/dedent": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", @@ -1815,6 +2286,15 @@ "node": ">=0.10.0" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -1835,6 +2315,18 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.55", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.55.tgz", @@ -1872,6 +2364,45 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -2000,6 +2531,40 @@ "node": ">=8" } }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2011,7 +2576,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -2075,6 +2639,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-tsconfig": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -2304,6 +2880,16 @@ "dev": true, "license": "ISC" }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -2984,6 +3570,27 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jose": { + "version": "5.9.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", + "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-base64": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==", + "license": "BSD-3-Clause" + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3155,6 +3762,27 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -3192,6 +3820,26 @@ "dev": true, "license": "MIT" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -3229,6 +3877,15 @@ "node": ">=8" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3419,6 +4076,12 @@ "node": ">=8" } }, + "node_modules/poseidon-lite": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/poseidon-lite/-/poseidon-lite-0.2.1.tgz", + "integrity": "sha512-xIr+G6HeYfOhCuswdqcFpSX47SPhm0EpisWJ6h7fHlWwaVIvH3dLnejpatrtw6Xc6HaLrpq05y7VRfvDmDGIog==", + "license": "MIT" + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -3461,6 +4124,12 @@ "node": ">= 6" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", @@ -3536,6 +4205,15 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/resolve.exports": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", @@ -3631,6 +4309,38 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/ss-comparator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ss-comparator/-/ss-comparator-1.0.1.tgz", + "integrity": "sha512-zcZ/OhyVPx3AoOYxOJ7BmGM4USzlULFuPGTeMBwf6rf2RhS/0XISyOOYQu83U7OHl62AiEKlYv+sqFccP8L0Cg==", + "dependencies": { + "ss-linked-list": "^1.1.2" + } + }, + "node_modules/ss-linked-list": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ss-linked-list/-/ss-linked-list-1.1.5.tgz", + "integrity": "sha512-l/mMqU70q01cBJLL8Mu2FWUGKlAqiYrI2F68XMkNhyOsVx+Mh9gkgCMaZMyUkXCadQwx68isMHb8S4h88lHE2Q==", + "dependencies": { + "ss-comparator": "^1.0.0" + } + }, + "node_modules/ss-queue": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/ss-queue/-/ss-queue-1.0.5.tgz", + "integrity": "sha512-1eyYJr00ZYRIbkMSBBSUrS2YAvVbjFCZ+CZZqNBw5Q7SQrOo9o3MjMhlEzPUsODhxjqPBtrqPzApuulCpjY3CQ==", + "dependencies": { + "ss-linked-list": "^1.1.1" + } + }, + "node_modules/ss-stack": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/ss-stack/-/ss-stack-1.0.8.tgz", + "integrity": "sha512-bELljop9qaG6V1ZMC65IfHQOmkHk8RhMnnvJuezlMVcItILf8431EbLJ6dzwwP9w+mVxngGiUx8042wN9v6fLA==", + "dependencies": { + "ss-linked-list": "^1.1.2" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -3719,6 +4429,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/superstruct": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz", + "integrity": "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3760,6 +4479,12 @@ "node": ">=8" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -3780,6 +4505,37 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", + "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", + "license": "MIT", + "dependencies": { + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", @@ -3827,7 +4583,6 @@ "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, "license": "MIT" }, "node_modules/update-browserslist-db": { @@ -3861,6 +4616,19 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -3882,6 +4650,15 @@ "integrity": "sha512-CjF1XN4sUce8sBK9TixrDqFM7RwNkuXdJu174/AwmQUB62QbCQADg5lLe8ldBalFgtj1uKj+pKwDJiNo4Mn+eQ==", "license": "MIT" }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -3892,6 +4669,28 @@ "makeerror": "1.0.12" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index c8aa76b..d515fac 100644 --- a/package.json +++ b/package.json @@ -6,26 +6,31 @@ "author": "Suilend", "license": "MIT", "main": "./sdk/src/index.ts", + "type": "module", "exports": { - ".": "./sdk/src/index.js" + ".": "./sdk/src/index.js" }, "types": "./sdk/src/index.ts", "scripts": { - "build": "rm -rf ./dist && bun tsc", - "eslint": "eslint --fix \"./sdk/src/**/*.ts\"", - "prettier": "prettier --write \"./sdk/src/**/*\"", - "lint": "bun eslint && bun prettier", - "release": "bun run build && bun ts-node ./prepublish.ts && cd ./dist && npm publish --access public" + "build": "rm -rf ./dist && bun tsc", + "eslint": "eslint --fix \"./sdk/src/**/*.ts\"", + "prettier": "prettier --write \"./sdk/src/**/*\"", + "lint": "bun eslint && bun prettier", + "release": "bun run build && bun ts-node ./prepublish.ts && cd ./dist && npm publish --access public" }, "dependencies": { - "@mysten/sui": "^1.9.0", - "bn.js": "^5.2.1" + "@cetusprotocol/cetus-sui-clmm-sdk": "^5.1.10", + "@mysten/sui": "^1.16.2", + "bn.js": "^5.2.1", + "dotenv": "^16.4.7", + "tslib": "^2.8.1", + "tsx": "^4.19.2" }, "devDependencies": { - "@types/bn.js": "^5.1.6", - "@types/chai": "^4.3.19", - "@types/jest": "^29.5.13", - "chai": "^5.1.1", - "jest": "^29.7.0" + "@types/bn.js": "^5.1.6", + "@types/chai": "^4.3.19", + "@types/jest": "^29.5.13", + "chai": "^5.1.1", + "jest": "^29.7.0" } - } \ No newline at end of file +} diff --git a/sdk/src/consts.ts b/sdk/src/consts.ts new file mode 100644 index 0000000..b3a0c75 --- /dev/null +++ b/sdk/src/consts.ts @@ -0,0 +1,41 @@ +// PACKAGES +export const CETUS_PKG = + "0x1239df8ed89a9c4b1d51b44f4feb155c2bc6636d1881ee7eb675b6cd07c96150"; // TESTNET + +export const MTOKEN_PKG = + "0x037771b6e98a5425a683b25eb30d347adf85df2e377fc3b938dd8e82c086300a"; + +// CETUS OBJECTS +export const POOLS_REGISTRY = + "0x9257361c83803a30d6a73af133d92353668d9dae926b20ce1fce8c74d06421eb"; +export const REWARDS_GLOBAL_VAULT = + "0x7fab41d417de65b08adba76b013832d605109558c6e88413f241e6af04228add"; +export const CETUS_GLOBAL_CONFIG = + "0x34c896f9066b9acdeb8050165a6fe7eb95567e6e68823490c537b383bfce4722"; +export const ADMIN_CAP = + "0x14733e50730f8096bfef9c2f064c216fdd693730b49b990386db261aae116803"; + +export const CETUS_POOL = + "0x66019bc93fe73eddcdf584641c9c7ae414ef410c56ef752b5ee5c4092a8e1611"; + +// COIN TYPES +export const SUI_TYPE = + "0x67cf38b14fe8c056eae2660bc00b26e035cbd555af4bb095a6d872624f9857cf::sui::SUI"; +export const MSEND_TYPE = + "0x67cf38b14fe8c056eae2660bc00b26e035cbd555af4bb095a6d872624f9857cf::msend::MSEND"; +export const SEND_TYPE = + "0x67cf38b14fe8c056eae2660bc00b26e035cbd555af4bb095a6d872624f9857cf::send::SEND"; + +export const MSEND_TREASURY_CAP = + "0xf09ea5fdd7010312518bebaaba1d6637cc08c58618cdbf7cce23b987838ca102"; +export const SEND_TREASURY_CAP = + "0x3488c7793ded10259bea79c67424fb88fa50ff9ad83ccb270cdb7e17d9470380"; +export const SUI_TREASURY_CAP = + "0xe913be069641c21f667c61ef1e9cc7034f6ba57b97e74429eed71b657d290092"; + +export const MTOKEN_MANAGER = + "0x234c9653f3f449953afdc673cb8b79cd893f890c5fe2509b12ef83d413128301"; + +export const DECIMALS_SEND = 6; +export const DECIMALS_SUI = 9; +export const TICK_SPACING = 200; diff --git a/sdk/src/flashLoan.ts b/sdk/src/flashLoan.ts new file mode 100644 index 0000000..593399c --- /dev/null +++ b/sdk/src/flashLoan.ts @@ -0,0 +1,162 @@ +import { TickMath } from "@cetusprotocol/cetus-sui-clmm-sdk"; +import { Transaction } from "@mysten/sui/transactions"; +import Decimal from "decimal.js"; +import { + CETUS_GLOBAL_CONFIG, + CETUS_PKG, + DECIMALS_SEND, + DECIMALS_SUI, + MSEND_TYPE, + MTOKEN_PKG, + SEND_TYPE, + SUI_TYPE, +} from "./consts"; + +import { SUI_CLOCK_OBJECT_ID } from "@mysten/sui/utils"; + +export async function flashLoan(args: { + pool: string; + suiPenaltyAmount: number; + minPrice: number; // based on slippage + sourceMSendCoin: string; + burnAmount: number; + mTokenManager: string; + tickSpacing: number; + transaction: Transaction; +}) { + let { + pool, + suiPenaltyAmount, + minPrice, + sourceMSendCoin, + burnAmount, + mTokenManager, + tickSpacing, + transaction, + } = args; + + const mSendCoinToBurn = transaction.splitCoins(sourceMSendCoin, [burnAmount]); + + const minSqrtPrice = getClosestSqrtPriceFromPrice( + minPrice, + DECIMALS_SEND, + DECIMALS_SUI, + tickSpacing + ); + const [sendBal, suiBal, receipt] = transaction.moveCall({ + target: `${CETUS_PKG}::pool::flash_swap`, + typeArguments: [SEND_TYPE, SUI_TYPE], + arguments: [ + transaction.object(CETUS_GLOBAL_CONFIG), + transaction.object(pool), + transaction.pure.bool(true), // a2b, i.e. Get SUI, pay SEND later + transaction.pure.bool(false), // by_amount_in, false because we want to specify how much SUI we get which is equivalent to penalty amount + transaction.pure.u64(suiPenaltyAmount), + transaction.pure.u128(minSqrtPrice), + transaction.object(SUI_CLOCK_OBJECT_ID), + ], + }); + + const [penaltyCoin] = transaction.moveCall({ + target: `0x2::coin::from_balance`, + typeArguments: [SUI_TYPE], + arguments: [suiBal], + }); + + const [send] = transaction.moveCall({ + target: `${MTOKEN_PKG}::mtoken::redeem_mtokens`, + typeArguments: [MSEND_TYPE, SEND_TYPE, SUI_TYPE], + arguments: [ + transaction.object(mTokenManager), + transaction.object(mSendCoinToBurn), + penaltyCoin, + transaction.object(SUI_CLOCK_OBJECT_ID), + ], + }); + + const sendPayAmount = transaction.moveCall({ + target: `${CETUS_PKG}::pool::swap_pay_amount`, + typeArguments: [SEND_TYPE, SUI_TYPE], + arguments: [transaction.object(receipt)], + }); + + const sendCoinToPay = transaction.splitCoins(send, [sendPayAmount]); + + const sendBalToMerge = transaction.moveCall({ + target: `0x2::coin::into_balance`, + typeArguments: [SEND_TYPE], + arguments: [sendCoinToPay], + }); + + transaction.moveCall({ + target: `0x2::balance::join`, + typeArguments: [SEND_TYPE], + arguments: [sendBal, sendBalToMerge], + }); + + const emptySuiBalance = transaction.moveCall({ + target: `0x2::balance::zero`, + typeArguments: [SUI_TYPE], + arguments: [], + }); + + transaction.moveCall({ + target: `${CETUS_PKG}::pool::repay_flash_swap`, + typeArguments: [SEND_TYPE, SUI_TYPE], + arguments: [ + transaction.object(CETUS_GLOBAL_CONFIG), + transaction.object(pool), + transaction.object(sendBal), + transaction.object(emptySuiBalance), + receipt, + ], + }); +} + +export function getClosestTickFromPrice( + price: number, + decimalsA: number, + decimalsB: number, + tickSpacing: number +): number { + const priceDecimal = new Decimal(price); + const tick = TickMath.priceToTickIndex(priceDecimal, decimalsA, decimalsB); + + return closestLowerDivisibleByTickSpacing(tick, tickSpacing); +} + +export function getClosestSqrtPriceFromPrice( + price: number, + decimalsA: number, + decimalsB: number, + tickSpacing: number +): bigint { + const closestTick = getClosestTickFromPrice( + price, + decimalsA, + decimalsB, + tickSpacing + ); + + const closestSqrtPriceBN = TickMath.tickIndexToSqrtPriceX64(closestTick); + const closestSqrtPrice = BigInt(closestSqrtPriceBN.toString()); + return closestSqrtPrice; +} + +function closestLowerDivisibleByTickSpacing( + num: number, + tickSpacing: number +): number { + const divisor = tickSpacing; + const remainder = num % divisor; + + if (remainder === 0) { + return num; + } + + if (num > 0) { + return num - remainder; + } else { + return num - remainder - divisor; + } +} diff --git a/sdk/src/index.ts b/sdk/src/index.ts index e69de29..f4519b4 100644 --- a/sdk/src/index.ts +++ b/sdk/src/index.ts @@ -0,0 +1,56 @@ +import { Transaction } from "@mysten/sui/transactions"; +import { CETUS_POOL, MTOKEN_MANAGER, TICK_SPACING } from "./consts"; +import { getKeypair } from "./utils"; +import { + DevInspectResults, + getFullnodeUrl, + SuiClient, +} from "@mysten/sui/client"; +import { flashLoan } from "./flashLoan"; + +const keypair = getKeypair(); +const addy = keypair.getPublicKey().toSuiAddress(); + +const client = new SuiClient({ url: getFullnodeUrl("testnet") }); +const txb = new Transaction(); + +flashLoan({ + pool: CETUS_POOL, + suiPenaltyAmount: 100, // Without decimals - sui amount OUT + minPrice: 0.01, // based on slippage + sourceMSendCoin: + "0x4bd0d6fd7f186c2015f700ff267bc38f33db1b38af4bab3545c4745d1f4025df", + burnAmount: 1_000_000, // without decimals - msend amount to burn + mTokenManager: MTOKEN_MANAGER, + tickSpacing: TICK_SPACING, + transaction: txb, +}); + +const inspectResults: DevInspectResults = + await client.devInspectTransactionBlock({ + sender: addy, + transactionBlock: txb, + }); + +console.log(inspectResults); + +// if (inspectResults.effects.status.status === "success") { +// const result = await client.signAndExecuteTransaction({ +// transaction: txb, +// signer: keypair, +// options: { +// showEffects: true, +// showEvents: true, +// }, +// }); + +// console.log(result); +// if (result.errors) { +// throw new Error(`Transaction failed`); +// } else { +// console.log(`Transaction succeded`); +// } +// } else { +// console.log(inspectResults); +// throw new Error("Dry Run failed"); +// } diff --git a/sdk/src/mintMTokens.ts b/sdk/src/mintMTokens.ts new file mode 100644 index 0000000..4421a45 --- /dev/null +++ b/sdk/src/mintMTokens.ts @@ -0,0 +1,116 @@ +// import { GenericArg, generic, obj, pure } from "../../_framework/util"; +import { + DevInspectResults, + getFullnodeUrl, + SuiClient, +} from "@mysten/sui/client"; +import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519"; +import { + Transaction, + TransactionArgument, + TransactionObjectInput, +} from "@mysten/sui/transactions"; +import { bech32 } from "bech32"; +import { getKeypair } from "./utils"; +import { + MSEND_TREASURY_CAP, + MSEND_TYPE, + MTOKEN_PKG, + SEND_TYPE, + SUI_TYPE, +} from "./consts"; + +const SEND_COIN = + "0x780898dd623e1fb2844241cbd90e06132abcc57a33bda3bca23db012b6f300ae"; + +const START_PENALTY_NUMERATOR = 10; +const END_PENALTY_NUMERATOR = 10; +const PENALTY_DENOMINATOR = 100_000; +const START_TIME_TS_SECONDS = 1733311191; +const END_TIME_TS_SECONDS = 1734002391; + +export interface MintMtokensArgs { + treasuryCap: TransactionObjectInput; + vestingCoin: TransactionObjectInput; + startPenaltyNumerator: number; + endPenaltyNumerator: number; + penaltyDenominator: number; + startTimeS: number; + endTimeS: number; +} + +export function mintMtokens( + tx: Transaction, + sender: string, + pkgId: string, + typeArgs: [string, string, string], + args: MintMtokensArgs +) { + const [adminCap, vestingManager, msend] = tx.moveCall({ + target: `${pkgId}::mtoken::mint_mtokens`, + typeArguments: typeArgs, + arguments: [ + tx.object(args.treasuryCap), + tx.object(args.vestingCoin), + tx.pure.u64(args.startPenaltyNumerator), + tx.pure.u64(args.endPenaltyNumerator), + tx.pure.u64(args.penaltyDenominator), + tx.pure.u64(args.startTimeS), + tx.pure.u64(args.endTimeS), + ], + }); + + tx.transferObjects([adminCap, msend], sender); + tx.moveCall({ + target: `0x2::transfer::public_share_object`, + typeArguments: [ + `${pkgId}::mtoken::VestingManager<${MSEND_TYPE}, ${SEND_TYPE}, ${SUI_TYPE}>`, + ], + arguments: [vestingManager], + }); +} + +const keypair = getKeypair(); +const addy = keypair.getPublicKey().toSuiAddress(); + +const client = new SuiClient({ url: getFullnodeUrl("testnet") }); + +const txb = new Transaction(); + +mintMtokens(txb, addy, MTOKEN_PKG, [MSEND_TYPE, SEND_TYPE, SUI_TYPE], { + treasuryCap: MSEND_TREASURY_CAP, + vestingCoin: SEND_COIN, + startPenaltyNumerator: START_PENALTY_NUMERATOR, + endPenaltyNumerator: END_PENALTY_NUMERATOR, + penaltyDenominator: PENALTY_DENOMINATOR, + startTimeS: START_TIME_TS_SECONDS, + endTimeS: END_TIME_TS_SECONDS, +}); + +const inspectResults: DevInspectResults = + await client.devInspectTransactionBlock({ + sender: addy, + transactionBlock: txb, + }); + +// console.log(inspectResults); +if (inspectResults.effects.status.status === "success") { + const result = await client.signAndExecuteTransaction({ + transaction: txb, + signer: keypair, + options: { + showEffects: true, + showEvents: true, + }, + }); + + console.log(result); + if (result.errors) { + throw new Error(`Transaction failed`); + } else { + console.log(`Transaction succeded`); + } +} else { + console.log(inspectResults); + throw new Error("Dry Run failed"); +} diff --git a/sdk/src/setupTest.ts b/sdk/src/setupTest.ts new file mode 100644 index 0000000..be5237c --- /dev/null +++ b/sdk/src/setupTest.ts @@ -0,0 +1,119 @@ +import { Transaction } from "@mysten/sui/transactions"; +import { TickMath } from "@cetusprotocol/cetus-sui-clmm-sdk"; +import { + CETUS_GLOBAL_CONFIG, + CETUS_PKG, + POOLS_REGISTRY, + SEND_TREASURY_CAP, + SEND_TYPE, + SUI_TREASURY_CAP, + SUI_TYPE, + TICK_SPACING, +} from "./consts"; +import { SUI_CLOCK_OBJECT_ID } from "@mysten/sui/utils"; +import { getKeypair } from "./utils"; +import { + DevInspectResults, + getFullnodeUrl, + SuiClient, +} from "@mysten/sui/client"; + +function setupPool(sender: string, transaction: Transaction) { + const suiLiquidity = BigInt("859622001237312227"); + + // Mint test SUI coins + const [suiCoin] = transaction.moveCall({ + target: `0x2::coin::mint`, + typeArguments: [SUI_TYPE], + arguments: [ + transaction.object(SUI_TREASURY_CAP), + transaction.pure.u64(suiLiquidity), + ], + }); + + // Mint test SEND coins + const [sendCoin] = transaction.moveCall({ + target: `0x2::coin::mint`, + typeArguments: [SEND_TYPE], + arguments: [ + transaction.object(SEND_TREASURY_CAP), + transaction.pure.u64(20_000_000_000 * (10 ^ 6)), + ], + }); + + // Setup fee rate + transaction.moveCall({ + target: `${CETUS_PKG}::config::add_fee_tier`, + arguments: [ + transaction.object(CETUS_GLOBAL_CONFIG), + transaction.pure.u32(TICK_SPACING), + transaction.pure.u64(10000), // FEE RATE 10_000 BPS + ], + }); + + const initialSqrtPrice = BigInt( + TickMath.tickIndexToSqrtPriceX64(46000).toString() + ); // Price = 0.1 + + // Create pool + const [position, coinSend, coinSui] = transaction.moveCall({ + target: `${CETUS_PKG}::factory::create_pool_with_liquidity`, + typeArguments: [SEND_TYPE, SUI_TYPE], + arguments: [ + transaction.object(POOLS_REGISTRY), + transaction.object(CETUS_GLOBAL_CONFIG), + transaction.pure.u32(TICK_SPACING), + transaction.pure.u128(initialSqrtPrice), + transaction.pure.string("hello test"), + transaction.pure.u32(39000), // lower tick index = 0.05 + transaction.pure.u32(69000), // upper tick index = 1.0 + transaction.object(sendCoin), + transaction.object(suiCoin), + transaction.pure.u64(20_000_000_000 * (10 ^ 6)), // SEND liquidity amount + transaction.pure.u64(suiLiquidity), // SUI liquidity amount + transaction.pure.bool(true), // from_a + transaction.object(SUI_CLOCK_OBJECT_ID), + ], + }); + + transaction.transferObjects([position, coinSend, coinSui], sender); + // transaction.transferObjects([suiCoin, sendCoin], sender); +} + +const keypair = getKeypair(); +const addy = keypair.getPublicKey().toSuiAddress(); + +const client = new SuiClient({ url: getFullnodeUrl("testnet") }); + +const txb = new Transaction(); + +setupPool(addy, txb); + +const inspectResults: DevInspectResults = + await client.devInspectTransactionBlock({ + sender: addy, + transactionBlock: txb, + }); + +// console.log(inspectResults); + +if (inspectResults.effects.status.status === "success") { + const result = await client.signAndExecuteTransaction({ + transaction: txb, + signer: keypair, + options: { + showEffects: true, + showEvents: true, + }, + }); + + console.log(result); + if (result.errors) { + throw new Error(`Transaction failed`); + } else { + console.log(`Transaction succeded`); + } +} else { + console.log(inspectResults); + throw new Error("Dry Run failed"); +} diff --git a/sdk/src/utils.ts b/sdk/src/utils.ts new file mode 100644 index 0000000..1314203 --- /dev/null +++ b/sdk/src/utils.ts @@ -0,0 +1,34 @@ +import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519"; +import { bech32 } from "bech32"; +import dotenv from "dotenv"; + +dotenv.config(); + +export function getKeypair(): Ed25519Keypair { + return loadSuiKeypair(process.env.WALLET_KEY); +} + +export function loadSuiKeypair( + bech32String: string | undefined +): Ed25519Keypair { + if (!bech32String || !bech32String.startsWith("suiprivkey1")) { + throw new Error( + `Invalid private key format: Expected prefix 'suiprivkey1', but received '${bech32String}'` + ); + } + + // Decode the Bech32 encoded key + const decoded = bech32.decode(bech32String); + let privateKeyBytes = bech32.fromWords(decoded.words); + + // Ensure the private key is exactly 32 bytes (Ed25519 key size) + if (privateKeyBytes.length === 33) { + privateKeyBytes = privateKeyBytes.slice(1); // Remove the first extra byte + } else if (privateKeyBytes.length !== 32) { + throw new Error( + `Invalid private key length: Expected 32 bytes, got ${privateKeyBytes.length}` + ); + } + + return Ed25519Keypair.fromSecretKey(Uint8Array.from(privateKeyBytes)); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..6bd056f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "noImplicitReturns": true, + "noUnusedLocals": false, + "outDir": "dist", + "sourceMap": true, + "removeComments": false, + "strict": true, + "module": "ESNext", + "target": "ESNext", + "checkJs": false, + "esModuleInterop": true, + "skipLibCheck": true, + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "allowJs": true + }, + "compileOnSave": true, + "include": ["./sdk/src/**/*.ts"], + "exclude": ["demo"] + } \ No newline at end of file