├── .gitignore ├── README.md └── sui ├── cetus_clmm ├── Move.lock ├── Move.toml ├── README.md └── sources │ ├── acl.move │ ├── config.move │ ├── factory.move │ ├── math │ ├── clmm_math.move │ └── tick_math.move │ ├── partner.move │ ├── pool.move │ ├── pool_creator.move │ ├── position.move │ ├── rewarder.move │ ├── tick.move │ └── utils.move ├── dca ├── .gitignore ├── Move.lock ├── Move.toml ├── README.md ├── dca.png └── sources │ ├── acl.move │ ├── config.move │ └── order.move ├── limit-order ├── .gitignore ├── Move.lock ├── Move.toml ├── README.md └── sources │ ├── acl.move │ ├── config.move │ └── order.move ├── lp_burn ├── Move.lock ├── Move.toml ├── README.md └── sources │ └── lp_burn.move ├── stable_farming ├── Move.lock ├── Move.toml ├── README.md └── sources │ ├── acl.move │ ├── config.move │ ├── pool.move │ ├── rewarder.move │ └── router.move ├── token ├── .gitignore ├── README.md ├── cetus │ ├── Move.lock │ ├── Move.toml │ └── sources │ │ └── cetus.move ├── dividends │ ├── Move.lock │ ├── Move.toml │ ├── README.md │ └── sources │ │ ├── dividend.move │ │ └── router.move └── xcetus │ ├── Move.lock │ ├── Move.toml │ ├── README.md │ └── sources │ ├── lock_coin.move │ ├── locking.move │ ├── router.move │ └── xcetus.move └── vaults ├── .gitignore ├── Move.lock ├── Move.toml ├── README.md └── sources ├── acl.move ├── fetcher.move ├── router.move └── vaults.move /.gitignore: -------------------------------------------------------------------------------- 1 | sui/cetus_clmm/build 2 | sui/cetus_clmm/.idea/ 3 | sui/lp_burn/build 4 | sui/stable_farming/build 5 | sui/.idea/ 6 | .idea/ 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cetus clmm interface 2 | 3 | 4 | ![GitHub Repo stars](https://img.shields.io/github/stars/CetusProtocol/cetus-clmm-interface?logo=github) 5 | 6 | 7 |
8 |
9 |

Cetus-CLMM-INTERFACE

10 | 11 |

12 | Integrating Cetus-CLMMPOOL: A Comprehensive Guide 13 |
14 | Explore the docs » 15 |
16 |
17 | · 18 | Report Bug 19 | · 20 | Request Feature 21 |

22 |
23 | 24 | ## Projects 25 | 26 | ### Latest Published At Table 27 | 28 | - **Mainnet** 29 | 30 | | Contract | Latest published at address | 31 | | -------------- | ------------------------------------------------------------------ | 32 | | cetusclmm | 0xc6faf3703b0e8ba9ed06b7851134bbbe7565eb35ff823fd78432baa4cbeaa12e | 33 | | lp_burn | 0xb6ec861eec8c550269dc29a1662008a816ac4756df723af5103075b665e32e65 | 34 | | dca | 0x587614620d0d30aed66d86ffd3ba385a661a86aa573a4d579017068f561c6d8f | 35 | | limitorder | 0x533fab9a116080e2cb1c87f1832c1bf4231ab4c32318ced041e75cc28604bba9 | 36 | | stable_farming | 0x7e4ca066f06a1132ab0499c8c0b87f847a0d90684afa902e52501a44dbd81992 | 37 | | xcetus | 0x9e69acc50ca03bc943c4f7c5304c2a6002d507b51c11913b247159c60422c606 | 38 | | dividends | 0xcec352932edc6663a118e8d64ed54da6b8107e8719603bf728f80717592cd9e8 | 39 | | vaults | 0x58e5de6e425397eeaf952d55c0f94637bee91b25d6138ce222f89cda0aefec03 | 40 | 41 | - **Testnet** 42 | 43 | | Contract | Latest published at address | 44 | | -------------- | ------------------------------------------------------------------ | 45 | | cetusclmm | 0xb2a1d27337788bda89d350703b8326952413bd94b35b9b573ac8401b9803d018 | 46 | | lp_burn | 0x9c751fccc633f3ebad2becbe7884e5f38b4e497127689be0d404b24f79d95d71 | 47 | | dca | 0xacd0ab94883a8785c5258388618b6252f0c2e9384b23f91fc23f6c8ef44d445c | 48 | | limitorder | 0xc65bc51d2bc2fdbce8c701f8d812da80fb37dba9cdf97ce38f60ab18c5202b17 | 49 | | stable_farming | 0x3c4582ee27a09f7e6c091022d0d279fdc8e54c1f782916bf135a71a8e8006aa5 | 50 | | xcetus | 0xdebaab6b851fd3414c0a62dbdf8eb752d6b0d31f5cfce5e38541bc6c6daa8966 | 51 | | dividends | 0x20d948d640edd0c749f533d41efc5f843f212d441220324ad7959c6e1d281828 | 52 | | vaults | 0x04df17a109336491867f04df40ca8a77277bc6e382139e88ae0d0d267ac07905 | 53 | 54 | ### Cetus CLMM 55 | 56 | The Cetus CLMM Interface provider all core features function interface of CLMM, allowing users to easily connect with CLMM by contract. For more detailed information, please refer to the CLMM README document. [CLMM README Document](./sui/cetus_clmm/README.md) 57 | 58 | ### LP Burn 59 | 60 | The Cetus LP Burn integrate all core lp burn interface of Stable Farming, For more detailed information, please refer to the LP Burn README document. [LP Burn README Document](./sui/lp_burn/README.md) 61 | 62 | ### Stable Farming 63 | 64 | The Cetus Stable Farming integrate all core features function interface of Stable Farming, For more detailed information, please refer to the Stable Farming README document. [Stable Farming README Document](./sui/stable_farming/README.md) 65 | 66 | ### Token 67 | 68 | The Cetus Token Interface integrates cetus, xcetus, dividends. For more detailed information, please refer to the Token README document. [Token README Document](./sui/token/README.md) 69 | 70 | ### Limit Order 71 | 72 | The Cetus Limit Order seamlessly integrates all core functionalities of the Limit Order interface. For more detailed information, please refer to the Limit Order README document. [Limit Order README Document](./sui/limitorder/README.md) 73 | 74 | ### DCA 75 | 76 | The Cetus DCA integrates all core functionalities of the DCA interface. For more detailed information, please refer to the DCA README document. [DCA README Document](./sui/dca/README.md) 77 | 78 | ### Vaults 79 | 80 | The Cetus vaults integrates all core functionalities of the vaults interface. For more detailed information, please refer to the Vaults README document. [Vaults README Document](./sui/vaults/README.md) 81 | 82 | ## How to migrate to the latest version? 83 | 84 | ### Why need to migrate? 85 | 86 | Cetus has already updated to the new CLMM contract and will disable the old version of the CLMM contract. The following contracts will need to be updated simultaneously: 87 | integrate, stable farming, vault, aggregator, lp burn. 88 | 89 | ### Clmm contract update details 90 | 91 | This update introduces new methods for pool creation, with the primary change being mandatory liquidity provision for new pools. To create a new pool, you can use either: 92 | 93 | - **pool_creator.create_pool_v2** on the cetus_clmm contract 94 | - **pool_creator_v2.create_pool_v2** on the integrate contract 95 | 96 | **Note**: The previous creation method `factory.create_pool` is permissioned, and `factory.create_pool_with_liquidity` is deprecated in this update. The `pool_creator.create_pool_v2_by_creation_cap` method is deprecated, please use `pool_creator.create_pool_v2_with_creation_cap`. 97 | 98 | ```rust 99 | // cetus_clmm.pool_creator.create_pool_v2 100 | public fun create_pool_v2( 101 | config: &GlobalConfig, 102 | pools: &mut Pools, 103 | tick_spacing: u32, 104 | initialize_price: u128, 105 | url: String, 106 | tick_lower_idx: u32, 107 | tick_upper_idx: u32, 108 | coin_a: Coin, 109 | coin_b: Coin, 110 | metadata_a: &CoinMetadata, 111 | metadata_b: &CoinMetadata, 112 | fix_amount_a: bool, 113 | clock: &Clock, 114 | ctx: &mut TxContext 115 | ): (Position, Coin, Coin) 116 | 117 | // integrate.pool_creator_v2.create_pool_v2 118 | public entry fun create_pool_v2( 119 | config: &GlobalConfig, 120 | pools: &mut Pools, 121 | tick_spacing: u32, 122 | initialize_price: u128, 123 | url: String, 124 | tick_lower_idx: u32, 125 | tick_upper_idx: u32, 126 | coin_a: &mut Coin, 127 | coin_b: &mut Coin, 128 | metadata_a: &CoinMetadata, 129 | metadata_b: &CoinMetadata, 130 | fix_amount_a: bool, 131 | clock: &Clock, 132 | ctx: &mut TxContext 133 | ) 134 | ``` 135 | 136 | In these two methods, you can use the fix_amount_a parameter to control which coin amount remains fixed: 137 | 138 | If `fix_amount_a` is true: The amount of coin_a will be fixed. You should provide the exact amount of coin_a you want to deposit, and the required amount of coin_b will be calculated automatically. 139 | If `fix_amount_a` is false: The amount of coin_b will be fixed. You should provide the exact amount of coin_b you want to deposit, and the required amount of coin_a will be calculated automatically. 140 | 141 | In some situations, coin issuers may want to reclaim the capability to create pools, so the protocol implements a `PoolCreationCap` mechanism for coin issuers. Here's how it works: 142 | Prerequisites: 143 | 144 | - You must hold the `TreasuryCap` of the coin 145 | - The `TreasuryCap` must not be frozen 146 | - Only one `PoolCreationCap` can be minted per coin 147 | 148 | Steps to create a restricted pool: 149 | 150 | 1. Mint a `PoolCreationCap` using your coin's `TreasuryCap` 151 | 152 | 2. Register a pool by specifying: **Quote coin** and **Tick spacing**. 153 | 154 | The protocol controls which quote coins and tick_spacing values are permitted for pool registration. 155 | Currently, only pools with the SUI-200 can be registered. 156 | 157 | ```rust 158 | let pool_creator_cap = factory::mint_pool_creation_cap( 159 | clmm_global_config, 160 | clmm_pools, 161 | &mut treasury_cap, 162 | ctx 163 | ); 164 | 165 | factory::register_permission_pair( 166 | clmm_global_config, 167 | clmm_pools, 168 | 200, 169 | &pool_creator_cap, 170 | ctx 171 | ); 172 | 173 | 174 | let (lp_position, return_coin_a, return_coin_b) = pool_creator::create_pool_v2_with_creation_cap( 175 | clmm_global_config, 176 | clmm_pools, 177 | pool_creator_cap, 178 | 200, 179 | current_sqrt_price, 180 | string::utf8(b""), 181 | coin_a, 182 | coin_b, 183 | metadata_a, 184 | metadata_b, 185 | is_fix_a, 186 | clk, 187 | ctx 188 | ); 189 | ``` 190 | 191 | Additionally, a new event `CollectRewardV2Event` has been added to the pool module. 192 | 193 | **Important Notice**: Mandatory Contract Upgrade 194 | The Cetus CLMM core contract will undergo a mandatory upgrade in the near future. Upon completion, previous versions of the contract will be deprecated and no longer accessible 195 | All dependent protocols will require updates, including: 196 | 197 | - [Vaults](sui/vaults/) 198 | - [StableFarming](sui/stable_farming/) 199 | - [LPBurn](sui/lp_burn/) 200 | - Aggregator 201 | - Integrate 202 | 203 | Please ensure all necessary preparations are made before the upgrade takes effect. 204 | 205 | # More About Cetus 206 | 207 | Use the following links to learn more about Cetus: 208 | 209 | Learn more about working with Cetus in the [Cetus Documentation](https://cetus-1.gitbook.io/cetus-docs). 210 | 211 | Join the Cetus community on [Cetus Discord](https://discord.com/channels/1009749448022315008/1009751382783447072). 212 | -------------------------------------------------------------------------------- /sui/cetus_clmm/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "393CAC9FD2CE651E98C22D27B26BDBD698224B1D87473FF260D31C0C440E0097" 6 | deps_digest = "52B406A7A21811BEF51751CF88DA0E76DAEFFEAC888D4F4060B1A72BBE7D8D35" 7 | dependencies = [ 8 | { id = "Bridge", name = "Bridge" }, 9 | { id = "IntegerMate", name = "IntegerMate" }, 10 | { id = "MoveSTL", name = "MoveSTL" }, 11 | { id = "MoveStdlib", name = "MoveStdlib" }, 12 | { id = "Sui", name = "Sui" }, 13 | { id = "SuiSystem", name = "SuiSystem" }, 14 | ] 15 | 16 | [[move.package]] 17 | id = "Bridge" 18 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/bridge" } 19 | 20 | dependencies = [ 21 | { id = "MoveStdlib", name = "MoveStdlib" }, 22 | { id = "Sui", name = "Sui" }, 23 | { id = "SuiSystem", name = "SuiSystem" }, 24 | ] 25 | 26 | [[move.package]] 27 | id = "IntegerMate" 28 | source = { git = "https://github.com/CetusProtocol/integer-mate.git", rev = "sui-v1.1.2", subdir = "sui" } 29 | 30 | dependencies = [ 31 | { id = "Sui", name = "Sui" }, 32 | ] 33 | 34 | [[move.package]] 35 | id = "MoveSTL" 36 | source = { git = "https://github.com/CetusProtocol/move-stl.git", rev = "mainnet-v1.48.2", subdir = "sui" } 37 | 38 | dependencies = [ 39 | { id = "Bridge", name = "Bridge" }, 40 | { id = "MoveStdlib", name = "MoveStdlib" }, 41 | { id = "Sui", name = "Sui" }, 42 | { id = "SuiSystem", name = "SuiSystem" }, 43 | ] 44 | 45 | [[move.package]] 46 | id = "MoveStdlib" 47 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/move-stdlib" } 48 | 49 | [[move.package]] 50 | id = "Sui" 51 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-framework" } 52 | 53 | dependencies = [ 54 | { id = "MoveStdlib", name = "MoveStdlib" }, 55 | ] 56 | 57 | [[move.package]] 58 | id = "SuiSystem" 59 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-system" } 60 | 61 | dependencies = [ 62 | { id = "MoveStdlib", name = "MoveStdlib" }, 63 | { id = "Sui", name = "Sui" }, 64 | ] 65 | 66 | [move.toolchain-version] 67 | compiler-version = "1.48.2" 68 | edition = "2024" 69 | flavor = "sui" 70 | 71 | [env] 72 | 73 | [env.mainnet] 74 | chain-id = "35834a8a" 75 | original-published-id = "0x1eabed72c53feb3805120a081dc15963c204dc8d091542592abaf7a35689b2fb" 76 | latest-published-id = "0x687e4b27fd88de55f2d7023dc7a3ec07ccd28b6a45a35ac88e95b6c387a3e338" 77 | published-version = "11" 78 | -------------------------------------------------------------------------------- /sui/cetus_clmm/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "CetusClmm" 3 | version = "0.0.1" 4 | 5 | [dependencies] 6 | MoveSTL = { git = "https://github.com/CetusProtocol/move-stl.git", subdir = "sui", rev = "mainnet-v1.48.2", override = true } 7 | IntegerMate = { git = "https://github.com/CetusProtocol/integer-mate.git", subdir = "sui", rev = "sui-v1.1.2", override = true } 8 | 9 | [addresses] 10 | cetusclmm = "0x1eabed72c53feb3805120a081dc15963c204dc8d091542592abaf7a35689b2fb" 11 | -------------------------------------------------------------------------------- /sui/cetus_clmm/sources/acl.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | #[allow(unused_field)] 4 | /// Fork @https://github.com/pentagonxyz/movemate.git 5 | /// 6 | /// `acl` is a simple access control module, where `member` represents a member and `role` represents a type 7 | /// of permission. A member can have multiple permissions. 8 | module cetusclmm::acl { 9 | use sui::tx_context::TxContext; 10 | 11 | use move_stl::linked_table::LinkedTable; 12 | 13 | struct ACL has store { 14 | permissions: LinkedTable 15 | } 16 | 17 | struct Member has store, drop, copy { 18 | address: address, 19 | permission: u128 20 | } 21 | 22 | /// @notice Create a new ACL (access control list). 23 | public fun new(_ctx: &mut TxContext): ACL { 24 | abort 0 25 | } 26 | 27 | /// @notice Check if a member has a role in the ACL. 28 | public fun has_role(_acl: &ACL, _member: address, _role: u8): bool { 29 | abort 0 30 | } 31 | 32 | /// @notice Set all roles for a member in the ACL. 33 | /// @param permissions Permissions for a member, represented as a `u128` with each bit representing the presence of (or lack of) each role. 34 | public fun set_roles(_acl: &mut ACL, _member: address, _permissions: u128) { 35 | abort 0 36 | } 37 | 38 | /// @notice Add a role for a member in the ACL. 39 | public fun add_role(_acl: &mut ACL, _member: address, _role: u8) { 40 | abort 0 41 | } 42 | 43 | /// @notice Revoke a role for a member in the ACL. 44 | public fun remove_role(_acl: &mut ACL, _member: address, _role: u8) { 45 | abort 0 46 | } 47 | 48 | /// Remove all roles of member. 49 | public fun remove_member(_acl: &mut ACL, _member: address) { 50 | abort 0 51 | } 52 | 53 | /// Get all members. 54 | public fun get_members(_acl: &ACL): vector { 55 | abort 0 56 | } 57 | 58 | /// Get the permission of member by addresss. 59 | public fun get_permission(_acl: &ACL, _address: address): u128 { 60 | abort 0 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /sui/cetus_clmm/sources/config.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | #[allow(unused_type_parameter, unused_field)] 4 | /// The global config module is used for manage the `protocol_fee`, acl roles, fee_tiers and package version of the cetus clmmpool protocol. 5 | /// The `protocol_fee` is the protocol fee rate, it will be charged when user swap token. 6 | /// The `fee_tiers` is a map, the key is the tick spacing, the value is the fee rate. the fee_rate can be same for 7 | /// different tick_spacing and can be updated. 8 | /// For different types of pair, we can use different tick spacing. Basically, for stable pair we can use small tick 9 | /// spacing, for volatile pair we can use large tick spacing. 10 | /// the fee generated of a swap is calculated by the following formula: 11 | /// total_fee = fee_rate * swap_in_amount. 12 | /// protocol_fee = total_fee * protocol_fee_rate / 1000000 13 | /// lp_fee = total_fee - protocol_fee 14 | /// Also, the acl roles is managed by this module, the roles is used for control the access of the cetus clmmpool 15 | /// protocol. 16 | /// Currently, we have 5 roles: 17 | /// 1. PoolManager: The pool manager can update pool fee rate, pause and unpause the pool. 18 | /// 2. FeeTierManager: The fee tier manager can add/remove fee tier, update fee tier fee rate. 19 | /// 3. ClaimProtocolFee: The claim protocol fee can claim the protocol fee. 20 | /// 4. PartnerManager: The partner manager can add/remove partner, update partner fee rate. 21 | /// 5. RewarderManager: The rewarder manager can add/remove rewarder, update rewarder fee rate. 22 | /// The package version is used for upgrade the package, when upgrade the package, we need increase the package version. 23 | module cetusclmm::config { 24 | use sui::object::{UID, ID}; 25 | use sui::tx_context::TxContext; 26 | use sui::vec_map::VecMap; 27 | 28 | use cetusclmm::acl; 29 | 30 | /// Clmmpools acl roles 31 | #[allow(unused_const)] 32 | const ACL_POOL_MANAGER: u8 = 0; 33 | #[allow(unused_const)] 34 | const ACL_FEE_TIER_MANAGER: u8 = 1; 35 | #[allow(unused_const)] 36 | const ACL_CLAIM_PROTOCOL_FEE: u8 = 2; 37 | #[allow(unused_const)] 38 | const ACL_PARTNER_MANAGER: u8 = 3; 39 | #[allow(unused_const)] 40 | const ACL_REWARDER_MANAGER: u8 = 4; 41 | 42 | // === Structs === 43 | struct AdminCap has key, store { 44 | id: UID, 45 | } 46 | 47 | 48 | struct ProtocolFeeClaimCap has key, store { 49 | id: UID, 50 | } 51 | 52 | 53 | /// The clmmpools fee tier data 54 | struct FeeTier has store, copy, drop { 55 | /// The tick spacing 56 | tick_spacing: u32, 57 | 58 | /// The default fee rate 59 | fee_rate: u64, 60 | } 61 | 62 | 63 | struct GlobalConfig has key, store { 64 | id: UID, 65 | /// `protocol_fee_rate` The protocol fee rate 66 | protocol_fee_rate: u64, 67 | /// 'fee_tiers' The Clmmpools fee tire map 68 | fee_tiers: VecMap, 69 | /// `acl` The Clmmpools ACL 70 | acl: acl::ACL, 71 | 72 | /// The current package version 73 | package_version: u64 74 | } 75 | 76 | 77 | // === Events === 78 | 79 | 80 | /// Emit when init the `GlobalConfig` and `AdminCap` 81 | struct InitConfigEvent has copy, drop { 82 | admin_cap_id: ID, 83 | global_config_id: ID, 84 | } 85 | 86 | 87 | /// Emit when update the protocol fee rate 88 | struct UpdateFeeRateEvent has copy, drop { 89 | old_fee_rate: u64, 90 | new_fee_rate: u64, 91 | } 92 | 93 | 94 | /// Emit when add fee_tier 95 | struct AddFeeTierEvent has copy, drop { 96 | tick_spacing: u32, 97 | fee_rate: u64, 98 | } 99 | 100 | 101 | /// Emit when update fee_tier 102 | struct UpdateFeeTierEvent has copy, drop { 103 | tick_spacing: u32, 104 | old_fee_rate: u64, 105 | new_fee_rate: u64, 106 | } 107 | 108 | 109 | /// Emit when delete fee_tier 110 | struct DeleteFeeTierEvent has copy, drop { 111 | tick_spacing: u32, 112 | fee_rate: u64, 113 | } 114 | 115 | 116 | /// Emit when set roles 117 | struct SetRolesEvent has copy, drop { 118 | member: address, 119 | roles: u128, 120 | } 121 | 122 | 123 | /// Emit when add member a role 124 | struct AddRoleEvent has copy, drop { 125 | member: address, 126 | role: u8, 127 | } 128 | 129 | 130 | /// Emit when remove member a role 131 | struct RemoveRoleEvent has copy, drop { 132 | member: address, 133 | role: u8 134 | } 135 | 136 | 137 | /// Emit when add member 138 | struct RemoveMemberEvent has copy, drop { 139 | member: address, 140 | } 141 | 142 | 143 | /// Emit when update package version. 144 | struct SetPackageVersion has copy, drop { 145 | new_version: u64, 146 | old_version: u64 147 | } 148 | 149 | // === Functions === 150 | 151 | /// Update the protocol fee rate 152 | /// Params 153 | /// - config: The global config 154 | /// - protocol_fee_rate: The new protocol fee rate 155 | public fun update_protocol_fee_rate( 156 | _config: &mut GlobalConfig, 157 | _protocol_fee_rate: u64, 158 | _ctx: &TxContext 159 | ) { 160 | abort 0 161 | } 162 | 163 | /// Add a fee tier 164 | /// Params 165 | /// - config: The global config 166 | /// - tick_spacing: The tick spacing 167 | /// - fee_rate: The fee rate 168 | public fun add_fee_tier( 169 | _config: &mut GlobalConfig, 170 | _tick_spacing: u32, 171 | _fee_rate: u64, 172 | _ctx: &TxContext, 173 | ) { 174 | abort 0 175 | } 176 | 177 | //// Delete a fee tier by `tick_spacing`. 178 | /// Params 179 | /// - config: The global config 180 | /// - tick_spacing: The tick spacing 181 | public fun delete_fee_tier( 182 | _config: &mut GlobalConfig, 183 | _tick_spacing: u32, 184 | _ctx: &TxContext 185 | ) { 186 | abort 0 187 | } 188 | 189 | /// Update the fee rate of a FeeTier by `tick_spacing`. 190 | /// Params 191 | /// - config: The global config 192 | /// - tick_spacing: The tick spacing 193 | /// - new_fee_rate: The new fee rate 194 | public fun update_fee_tier( 195 | _config: &mut GlobalConfig, 196 | _tick_spacing: u32, 197 | _new_fee_rate: u64, 198 | _ctx: &TxContext 199 | ) { 200 | abort 0 201 | } 202 | 203 | /// Set role for member. 204 | /// Params 205 | /// - admin_cap: The admin cap 206 | /// - config: The global config 207 | /// - _member: The member address 208 | /// - roles: The roles 209 | public fun set_roles(_: &AdminCap, _config: &mut GlobalConfig, _member: address, _roles: u128) { 210 | abort 0 211 | } 212 | 213 | /// Add a role for member. 214 | /// Params 215 | /// - admin_cap: The admin cap 216 | /// - config: The global config 217 | /// - _member: The member address 218 | /// - role: The role 219 | public fun add_role(_: &AdminCap, _config: &mut GlobalConfig, _member: address, _role: u8) { 220 | abort 0 221 | } 222 | 223 | /// Remove a role for member. 224 | /// Params 225 | /// - admin_cap: The admin cap 226 | /// - config: The global config 227 | /// - _member: The member address 228 | /// - role: The role 229 | public fun remove_role(_: &AdminCap, _config: &mut GlobalConfig, _member: address, _role: u8) { 230 | abort 0 231 | } 232 | 233 | /// Remove a member from ACL. 234 | /// Params 235 | /// - admin_cap: The admin cap 236 | /// - config: The global config 237 | /// - _member: The member address 238 | public fun remove_member(_: &AdminCap, _config: &mut GlobalConfig, _member: address) { 239 | abort 0 240 | } 241 | 242 | public fun is_pool_manager(_config: &GlobalConfig, _member: address): bool { 243 | abort 0 244 | } 245 | 246 | /// Get all members in ACL. 247 | public fun get_members(_config: &GlobalConfig): vector { 248 | abort 0 249 | } 250 | 251 | /// Get the protocol fee rate 252 | public fun get_protocol_fee_rate(_global_config: &GlobalConfig): u64 { 253 | abort 0 254 | } 255 | 256 | /// Get fee rate by tick spacing 257 | public fun get_fee_rate( 258 | _tick_spacing: u32, 259 | _global_config: &GlobalConfig 260 | ): u64 { 261 | abort 0 262 | } 263 | 264 | /// Get the max fee rate 265 | public fun max_fee_rate(): u64 { 266 | abort 0 267 | } 268 | 269 | /// Get the max protocol fee rate 270 | public fun max_protocol_fee_rate(): u64 { 271 | abort 0 272 | } 273 | 274 | /// Check member has pool manager role 275 | public fun check_pool_manager_role(_config: &GlobalConfig, _member: address) { 276 | abort 0 277 | } 278 | 279 | /// Check member has fee tier manager role 280 | public fun check_fee_tier_manager_role(_config: &GlobalConfig, _member: address) { 281 | abort 0 282 | } 283 | 284 | /// Check member has protocol fee claim role 285 | public fun check_protocol_fee_claim_role(_config: &GlobalConfig, _member: address) { 286 | abort 0 287 | } 288 | 289 | /// Check member has partner manager role. 290 | public fun check_partner_manager_role(_config: &GlobalConfig, _member: address) { 291 | abort 0 292 | } 293 | 294 | /// Check member has rewarder manager role. 295 | public fun check_rewarder_manager_role(_config: &GlobalConfig, _member: address) { 296 | abort 0 297 | } 298 | 299 | /// Get tick_spacing of FeeTier. 300 | public fun tick_spacing(_fee_tier: &FeeTier): u32 { 301 | abort 0 302 | } 303 | 304 | /// Get fee_rate of FeeTier. 305 | public fun fee_rate(_fee_tier: &FeeTier): u64 { 306 | abort 0 307 | } 308 | 309 | /// Get the protocol_fee_rate from `GlobalConfig`. 310 | public fun protocol_fee_rate(_config: &GlobalConfig): u64 { 311 | abort 0 312 | } 313 | 314 | /// Get the fee tiers from `GlobalConfig`. 315 | public fun fee_tiers(_config: &GlobalConfig): &VecMap { 316 | abort 0 317 | } 318 | 319 | /// Get the ACL from `GlobalConfig`. 320 | public fun acl(_config: &GlobalConfig): &acl::ACL { 321 | abort 0 322 | } 323 | 324 | /// Check package version of the package_version in `GlobalConfig` and VERSION in current package. 325 | public fun checked_package_version(_config: &GlobalConfig) { 326 | abort 0 327 | } 328 | 329 | /// Update the package version. 330 | public fun update_package_version(_: &AdminCap, _config: &mut GlobalConfig, _version: u64) { 331 | abort 0 332 | } 333 | 334 | public fun package_version(): u64 { 335 | abort 0 336 | } 337 | 338 | #[test_only] 339 | use sui::object; 340 | #[test_only] 341 | use sui::vec_map; 342 | #[test_only] 343 | use sui::tx_context; 344 | 345 | // === Functions only for test === 346 | #[test_only] 347 | public fun new_global_config_for_test(ctx: &mut TxContext, protocol_fee_rate: u64): (AdminCap, GlobalConfig) { 348 | let (global_config, admin_cap) = ( 349 | GlobalConfig { 350 | id: object::new(ctx), 351 | protocol_fee_rate, 352 | fee_tiers: vec_map::empty(), 353 | acl: acl::new(ctx), 354 | package_version: 1, 355 | }, 356 | AdminCap { 357 | id: object::new(ctx) 358 | } 359 | ); 360 | 361 | let sender = tx_context::sender(ctx); 362 | let roles = 0u128 | 363 | (1 << ACL_POOL_MANAGER) | 364 | (1 << ACL_FEE_TIER_MANAGER) | 365 | (1 << ACL_REWARDER_MANAGER) | 366 | (1 << ACL_CLAIM_PROTOCOL_FEE) | 367 | (1 << ACL_PARTNER_MANAGER); 368 | set_roles(&admin_cap, &mut global_config, sender, roles); 369 | (admin_cap, global_config) 370 | } 371 | } 372 | -------------------------------------------------------------------------------- /sui/cetus_clmm/sources/factory.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | #[allow(unused_type_parameter, unused_field)] 4 | // The factory module is provided to create and manage pools. 5 | // The `Pools` is a singleton, and the `Pools` is initialized when the contract is deployed. 6 | // The pools are organized in a linked list, and the key is generate by hash([coin_type_a + coin_type_b]). The details can be found in `new_pool_key` function. 7 | // When create a pool, the `CoinTypeA` and `CoinTypeB` must be different, and the `CoinTypeA` must be the bigger one(string order). 8 | module cetusclmm::factory { 9 | use std::string::String; 10 | use std::type_name::TypeName; 11 | 12 | use sui::clock::Clock; 13 | use sui::tx_context::TxContext; 14 | use sui::object::{ID, UID}; 15 | use sui::coin::{Coin, TreasuryCap}; 16 | use sui::table::{Table}; 17 | use sui::vec_set::{VecSet}; 18 | use sui::coin::CoinMetadata; 19 | 20 | use move_stl::linked_table::LinkedTable; 21 | 22 | use cetusclmm::config::{GlobalConfig}; 23 | use cetusclmm::position::Position; 24 | 25 | // === Structs === 26 | 27 | struct PoolSimpleInfo has store, copy, drop { 28 | pool_id: ID, 29 | pool_key: ID, 30 | coin_type_a: TypeName, 31 | coin_type_b: TypeName, 32 | tick_spacing: u32, 33 | } 34 | 35 | 36 | /// hold the pool list, and the pool list is organized in a linked list. 37 | /// index is the max index used by pools. 38 | struct Pools has key, store { 39 | id: UID, 40 | list: LinkedTable, 41 | index: u64, 42 | } 43 | 44 | // === Events === 45 | 46 | 47 | /// Emit when init factory. 48 | struct InitFactoryEvent has copy, drop { 49 | pools_id: ID, 50 | } 51 | 52 | 53 | /// Emit when create pool. 54 | struct CreatePoolEvent has copy, drop { 55 | pool_id: ID, 56 | coin_type_a: String, 57 | coin_type_b: String, 58 | tick_spacing: u32, 59 | } 60 | 61 | struct DenyCoinList has key, store { 62 | id: UID, 63 | denied_list: Table, 64 | allowed_list: Table, 65 | } 66 | 67 | struct PoolKey has store, copy, drop { 68 | coin_a: TypeName, 69 | coin_b: TypeName, 70 | tick_spacing: u32, 71 | } 72 | 73 | struct PermissionPairManager has key, store { 74 | id: UID, 75 | allowed_pair_config: Table>, 76 | pool_key_to_cap: Table, 77 | // pool_key -> cap_id 78 | cap_to_pool_key: Table>, 79 | // cap_id -> pool_key -> PoolKey 80 | coin_type_to_cap: Table, 81 | } 82 | 83 | struct PoolCreationCap has key, store { 84 | id: UID, 85 | coin_type: TypeName, 86 | } 87 | 88 | public fun pool_id(_info: &PoolSimpleInfo): ID { 89 | abort 0 90 | } 91 | 92 | public fun pool_key(_info: &PoolSimpleInfo): ID { 93 | abort 0 94 | } 95 | 96 | public fun coin_types(_info: &PoolSimpleInfo): (TypeName, TypeName) { 97 | abort 0 98 | } 99 | 100 | public fun tick_spacing(_info: &PoolSimpleInfo): u32 { 101 | abort 0 102 | } 103 | 104 | public fun index(_pools: &Pools): u64 { 105 | abort 0 106 | } 107 | 108 | public fun pool_simple_info(_pools: &Pools, _pool_key: ID): &PoolSimpleInfo { 109 | abort 0 110 | } 111 | 112 | public fun in_allowed_list(_pools: &Pools): bool { 113 | abort 0 114 | } 115 | 116 | public fun in_denied_list(_pools: &Pools): bool { 117 | abort 0 118 | } 119 | 120 | public fun is_allowed_coin(_pools: &mut Pools, _metadata: &CoinMetadata): bool { 121 | abort 0 122 | } 123 | 124 | public fun is_permission_pair(_pools: &Pools, _tick_spacing: u32): bool { 125 | abort 0 126 | } 127 | 128 | public fun permission_pair_cap(_pools: &Pools, _tick_spacing: u32): ID { 129 | abort 0 130 | } 131 | 132 | public fun add_allowed_list(_config: &GlobalConfig, _pools: &mut Pools, _ctx: &TxContext) { 133 | abort 0 134 | } 135 | 136 | public fun remove_allowed_list(_config: &GlobalConfig, _pools: &mut Pools, _ctx: &TxContext) { 137 | abort 0 138 | } 139 | 140 | public fun add_denied_list(_config: &GlobalConfig, _pools: &mut Pools, _ctx: &TxContext) { 141 | abort 0 142 | } 143 | 144 | public fun remove_denied_list(_config: &GlobalConfig, _pools: &mut Pools, _ctx: &TxContext) { 145 | abort 0 146 | } 147 | 148 | public fun add_allowed_pair_config( 149 | _config: &GlobalConfig, 150 | _pools: &mut Pools, 151 | _tick_spacing: u32, 152 | _ctx: &TxContext 153 | ) { 154 | abort 0 155 | } 156 | 157 | public fun remove_allowed_pair_config( 158 | _config: &GlobalConfig, 159 | _pools: &mut Pools, 160 | _tick_spacing: u32, 161 | _ctx: &TxContext 162 | ) { 163 | abort 0 164 | } 165 | 166 | public fun mint_pool_creation_cap( 167 | _config: &GlobalConfig, 168 | _pools: &mut Pools, 169 | _treasury_cap: &mut TreasuryCap, 170 | _ctx: &mut TxContext 171 | ): PoolCreationCap { 172 | abort 0 173 | } 174 | 175 | public fun mint_pool_creation_cap_by_admin( 176 | _config: &GlobalConfig, 177 | _pools: &mut Pools, 178 | _ctx: &mut TxContext 179 | ): PoolCreationCap { 180 | abort 0 181 | } 182 | 183 | public fun register_permission_pair( 184 | _config: &GlobalConfig, 185 | _pools: &mut Pools, 186 | _tick_spacing: u32, 187 | _pool_creation_cap: &PoolCreationCap, 188 | _ctx: &mut TxContext 189 | ) { 190 | abort 0 191 | } 192 | 193 | public fun unregister_permission_pair( 194 | _config: &GlobalConfig, 195 | _pools: &mut Pools, 196 | _tick_spacing: u32, 197 | _cap: &PoolCreationCap, 198 | ) { 199 | abort 0 200 | } 201 | 202 | 203 | #[allow(unused_type_parameter)] 204 | public fun create_pool( 205 | _pools: &mut Pools, 206 | _config: &GlobalConfig, 207 | _tick_spacing: u32, 208 | _initialize_price: u128, 209 | _url: String, 210 | _clock: &Clock, 211 | _ctx: &mut TxContext 212 | ) { 213 | abort 0 214 | } 215 | 216 | public fun create_pool_with_liquidity( 217 | _pools: &mut Pools, 218 | _config: &GlobalConfig, 219 | _tick_spacing: u32, 220 | _initialize_price: u128, 221 | _url: String, 222 | _tick_lower_idx: u32, 223 | _tick_upper_idx: u32, 224 | _coin_a: Coin, 225 | _coin_b: Coin, 226 | _amount_a: u64, 227 | _amount_b: u64, 228 | _fix_amount_a: bool, 229 | _clock: &Clock, 230 | _ctx: &mut TxContext 231 | ): (Position, Coin, Coin) { 232 | abort 0 233 | } 234 | 235 | public fun fetch_pools( 236 | _pools: &Pools, 237 | _start: vector, 238 | _limit: u64 239 | ): vector { 240 | abort 0 241 | } 242 | 243 | #[allow(unused_type_parameter)] 244 | public fun new_pool_key(_tick_spacing: u32): ID { 245 | abort 0 246 | } 247 | 248 | #[test_only] 249 | use move_stl::linked_table; 250 | #[test_only] 251 | use sui::object; 252 | 253 | #[test_only] 254 | public fun new_pools_for_test(ctx: &mut TxContext): Pools { 255 | Pools { 256 | id: object::new(ctx), 257 | list: linked_table::new(ctx), 258 | index: 0 259 | } 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /sui/cetus_clmm/sources/math/tick_math.move: -------------------------------------------------------------------------------- 1 | module cetusclmm::tick_math { 2 | use integer_mate::full_math_u128; 3 | use integer_mate::i32::{Self, I32}; 4 | use integer_mate::i128; 5 | 6 | const TICK_BOUND: u32 = 443636; 7 | const MAX_SQRT_PRICE_X64: u128 = 79226673515401279992447579055; 8 | const MIN_SQRT_PRICE_X64: u128 = 4295048016; 9 | 10 | /// Errors 11 | const EINVALID_TICK: u64 = 1; 12 | const EINVALID_SQRT_PRICE: u64 =2; 13 | 14 | public fun max_sqrt_price(): u128 { 15 | MAX_SQRT_PRICE_X64 16 | } 17 | 18 | public fun min_sqrt_price(): u128 { 19 | MIN_SQRT_PRICE_X64 20 | } 21 | 22 | public fun max_tick(): i32::I32 { 23 | i32::from(TICK_BOUND) 24 | } 25 | 26 | public fun min_tick(): i32::I32 { 27 | i32::neg_from(TICK_BOUND) 28 | } 29 | 30 | public fun tick_bound(): u32 { 31 | TICK_BOUND 32 | } 33 | 34 | public fun get_sqrt_price_at_tick(tick: i32::I32): u128 { 35 | assert!(i32::gte(tick, min_tick()) && i32::lte(tick, max_tick()), EINVALID_TICK); 36 | if (i32::is_neg(tick)) { 37 | get_sqrt_price_at_negative_tick(tick) 38 | } else { 39 | get_sqrt_price_at_positive_tick(tick) 40 | } 41 | } 42 | 43 | public fun is_valid_index(index: I32, tick_spacing: u32): bool { 44 | let in_range = i32::gte(index, min_tick()) && i32::lte(index, max_tick()); 45 | in_range && (i32::mod(index, i32::from(tick_spacing)) == i32::from(0)) 46 | } 47 | 48 | public fun get_tick_at_sqrt_price(sqrt_price: u128): i32::I32 { 49 | assert!(sqrt_price >= MIN_SQRT_PRICE_X64 && sqrt_price <= MAX_SQRT_PRICE_X64, EINVALID_SQRT_PRICE); 50 | let r = sqrt_price; 51 | let msb = 0; 52 | 53 | let f: u8 = as_u8(r >= 0x10000000000000000) << 6; // If r >= 2^64, f = 64 else 0 54 | msb = msb | f; 55 | r = r >> f; 56 | f = as_u8(r >= 0x100000000) << 5; // 2^32 57 | msb = msb | f; 58 | r = r >> f; 59 | f = as_u8(r >= 0x10000) << 4; // 2^16 60 | msb = msb | f; 61 | r = r >> f; 62 | f = as_u8(r >= 0x100) << 3; // 2^8 63 | msb = msb | f; 64 | r = r >> f; 65 | f = as_u8(r >= 0x10) << 2; // 2^4 66 | msb = msb | f; 67 | r = r >> f; 68 | f = as_u8(r >= 0x4) << 1; // 2^2 69 | msb = msb | f; 70 | r = r >> f; 71 | f = as_u8(r >= 0x2) << 0; // 2^0 72 | msb = msb | f; 73 | 74 | let log_2_x32 = i128::shl(i128::sub(i128::from((msb as u128)), i128::from(64)), 32); 75 | 76 | r = if (msb >= 64) { 77 | sqrt_price >> (msb - 63) 78 | } else { 79 | sqrt_price << (63 - msb) 80 | }; 81 | 82 | let shift = 31; 83 | while (shift >= 18) { 84 | r = ((r * r) >> 63); 85 | f = ((r >> 64) as u8); 86 | log_2_x32 = i128::or(log_2_x32, i128::shl(i128::from((f as u128)), shift)); 87 | r = r >> f; 88 | shift = shift - 1; 89 | }; 90 | 91 | let log_sqrt_10001 = i128::mul(log_2_x32, i128::from(59543866431366u128)); 92 | 93 | let tick_low = i128::as_i32(i128::shr(i128::sub(log_sqrt_10001, i128::from(184467440737095516u128)), 64)); 94 | let tick_high = i128::as_i32(i128::shr(i128::add(log_sqrt_10001, i128::from(15793534762490258745u128)), 64)); 95 | 96 | if (i32::eq(tick_low, tick_high)) { 97 | return tick_low 98 | } else if (get_sqrt_price_at_tick(tick_high) <= sqrt_price) { 99 | return tick_high 100 | } else { 101 | return tick_low 102 | } 103 | } 104 | 105 | fun as_u8(b: bool): u8 { 106 | if (b) { 107 | 1 108 | } else { 109 | 0 110 | } 111 | } 112 | 113 | fun get_sqrt_price_at_negative_tick(tick: i32::I32): u128 { 114 | let abs_tick = i32::as_u32(i32::abs(tick)); 115 | let ratio = if (abs_tick & 0x1 != 0) { 116 | 18445821805675392311u128 117 | } else { 118 | 18446744073709551616u128 119 | }; 120 | if (abs_tick & 0x2 != 0) { 121 | ratio = full_math_u128::mul_shr(ratio, 18444899583751176498u128, 64u8) 122 | }; 123 | if (abs_tick & 0x4 != 0) { 124 | ratio = full_math_u128::mul_shr(ratio, 18443055278223354162u128, 64u8); 125 | }; 126 | if (abs_tick & 0x8 != 0) { 127 | ratio = full_math_u128::mul_shr(ratio, 18439367220385604838u128, 64u8); 128 | }; 129 | if (abs_tick & 0x10 != 0) { 130 | ratio = full_math_u128::mul_shr(ratio, 18431993317065449817u128, 64u8); 131 | }; 132 | if (abs_tick & 0x20 != 0) { 133 | ratio = full_math_u128::mul_shr(ratio, 18417254355718160513u128, 64u8); 134 | }; 135 | if (abs_tick & 0x40 != 0) { 136 | ratio = full_math_u128::mul_shr(ratio, 18387811781193591352u128, 64u8); 137 | }; 138 | if (abs_tick & 0x80 != 0) { 139 | ratio = full_math_u128::mul_shr(ratio, 18329067761203520168u128, 64u8); 140 | }; 141 | if (abs_tick & 0x100 != 0) { 142 | ratio = full_math_u128::mul_shr(ratio, 18212142134806087854u128, 64u8); 143 | }; 144 | if (abs_tick & 0x200 != 0) { 145 | ratio = full_math_u128::mul_shr(ratio, 17980523815641551639u128, 64u8); 146 | }; 147 | if (abs_tick & 0x400 != 0) { 148 | ratio = full_math_u128::mul_shr(ratio, 17526086738831147013u128, 64u8); 149 | }; 150 | if (abs_tick & 0x800 != 0) { 151 | ratio = full_math_u128::mul_shr(ratio, 16651378430235024244u128, 64u8); 152 | }; 153 | if (abs_tick & 0x1000 != 0) { 154 | ratio = full_math_u128::mul_shr(ratio, 15030750278693429944u128, 64u8); 155 | }; 156 | if (abs_tick & 0x2000 != 0) { 157 | ratio = full_math_u128::mul_shr(ratio, 12247334978882834399u128, 64u8); 158 | }; 159 | if (abs_tick & 0x4000 != 0) { 160 | ratio = full_math_u128::mul_shr(ratio, 8131365268884726200u128, 64u8); 161 | }; 162 | if (abs_tick & 0x8000 != 0) { 163 | ratio = full_math_u128::mul_shr(ratio, 3584323654723342297u128, 64u8); 164 | }; 165 | if (abs_tick & 0x10000 != 0) { 166 | ratio = full_math_u128::mul_shr(ratio, 696457651847595233u128, 64u8); 167 | }; 168 | if (abs_tick & 0x20000 != 0) { 169 | ratio = full_math_u128::mul_shr(ratio, 26294789957452057u128, 64u8); 170 | }; 171 | if (abs_tick & 0x40000 != 0) { 172 | ratio = full_math_u128::mul_shr(ratio, 37481735321082u128, 64u8); 173 | }; 174 | 175 | ratio 176 | } 177 | 178 | fun get_sqrt_price_at_positive_tick(tick: i32::I32): u128 { 179 | let abs_tick = i32::as_u32(i32::abs(tick)); 180 | let ratio = if (abs_tick & 0x1 != 0) { 181 | 79232123823359799118286999567u128 182 | } else { 183 | 79228162514264337593543950336u128 184 | }; 185 | 186 | if (abs_tick & 0x2 != 0) { 187 | ratio = full_math_u128::mul_shr(ratio, 79236085330515764027303304731u128, 96u8) 188 | }; 189 | if (abs_tick & 0x4 != 0) { 190 | ratio = full_math_u128::mul_shr(ratio, 79244008939048815603706035061u128, 96u8) 191 | }; 192 | if (abs_tick & 0x8 != 0) { 193 | ratio = full_math_u128::mul_shr(ratio, 79259858533276714757314932305u128, 96u8) 194 | }; 195 | if (abs_tick & 0x10 != 0) { 196 | ratio = full_math_u128::mul_shr(ratio, 79291567232598584799939703904u128, 96u8) 197 | }; 198 | if (abs_tick & 0x20 != 0) { 199 | ratio = full_math_u128::mul_shr(ratio, 79355022692464371645785046466u128, 96u8) 200 | }; 201 | if (abs_tick & 0x40 != 0) { 202 | ratio = full_math_u128::mul_shr(ratio, 79482085999252804386437311141u128, 96u8) 203 | }; 204 | if (abs_tick & 0x80 != 0) { 205 | ratio = full_math_u128::mul_shr(ratio, 79736823300114093921829183326u128, 96u8) 206 | }; 207 | if (abs_tick & 0x100 != 0) { 208 | ratio = full_math_u128::mul_shr(ratio, 80248749790819932309965073892u128, 96u8) 209 | }; 210 | if (abs_tick & 0x200 != 0) { 211 | ratio = full_math_u128::mul_shr(ratio, 81282483887344747381513967011u128, 96u8) 212 | }; 213 | if (abs_tick & 0x400 != 0) { 214 | ratio = full_math_u128::mul_shr(ratio, 83390072131320151908154831281u128, 96u8) 215 | }; 216 | if (abs_tick & 0x800 != 0) { 217 | ratio = full_math_u128::mul_shr(ratio, 87770609709833776024991924138u128, 96u8) 218 | }; 219 | if (abs_tick & 0x1000 != 0) { 220 | ratio = full_math_u128::mul_shr(ratio, 97234110755111693312479820773u128, 96u8) 221 | }; 222 | if (abs_tick & 0x2000 != 0) { 223 | ratio = full_math_u128::mul_shr(ratio, 119332217159966728226237229890u128, 96u8) 224 | }; 225 | if (abs_tick & 0x4000 != 0) { 226 | ratio = full_math_u128::mul_shr(ratio, 179736315981702064433883588727u128, 96u8) 227 | }; 228 | if (abs_tick & 0x8000 != 0) { 229 | ratio = full_math_u128::mul_shr(ratio, 407748233172238350107850275304u128, 96u8) 230 | }; 231 | if (abs_tick & 0x10000 != 0) { 232 | ratio = full_math_u128::mul_shr(ratio, 2098478828474011932436660412517u128, 96u8) 233 | }; 234 | if (abs_tick & 0x20000 != 0) { 235 | ratio = full_math_u128::mul_shr(ratio, 55581415166113811149459800483533u128, 96u8) 236 | }; 237 | if (abs_tick & 0x40000 != 0) { 238 | ratio = full_math_u128::mul_shr(ratio, 38992368544603139932233054999993551u128, 96u8) 239 | }; 240 | 241 | ratio >> 32 242 | } 243 | 244 | #[test] 245 | fun test_get_sqrt_price_at_tick() { 246 | // min tick 247 | assert!(get_sqrt_price_at_tick(i32::neg_from(TICK_BOUND)) == 4295048016u128, 2); 248 | // max tick 249 | assert!(get_sqrt_price_at_tick(i32::from(TICK_BOUND)) == 79226673515401279992447579055u128, 1); 250 | assert!(get_sqrt_price_at_tick(i32::neg_from(435444u32)) == 6469134034u128, 3); 251 | assert!(get_sqrt_price_at_tick(i32::from(408332u32)) == 13561044167458152057771544136u128, 4); 252 | } 253 | 254 | #[test] 255 | fun test_get_tick_at_sqrt_price_1() { 256 | assert!(i32::eq(get_tick_at_sqrt_price(6469134034u128), i32::neg_from(435444)) == true, 0); 257 | assert!(i32::eq(get_tick_at_sqrt_price(13561044167458152057771544136u128), i32::from(408332u32)) == true, 0); 258 | } 259 | 260 | #[test] 261 | #[expected_failure] 262 | fun test_get_sqrt_price_at_invalid_upper_tick() { 263 | get_sqrt_price_at_tick(i32::add(max_tick(), i32::from(1))); 264 | } 265 | 266 | #[test] 267 | #[expected_failure] 268 | fun test_get_sqrt_price_at_invalid_lower_tick() { 269 | get_sqrt_price_at_tick(i32::sub(min_tick(), i32::from(1))); 270 | } 271 | 272 | #[test] 273 | #[expected_failure] 274 | fun test_get_tick_at_invalid_lower_sqrt_price() { 275 | get_tick_at_sqrt_price(MAX_SQRT_PRICE_X64 + 1); 276 | } 277 | 278 | #[test] 279 | #[expected_failure] 280 | fun test_get_tick_at_invalid_upper_sqrt_price() { 281 | get_tick_at_sqrt_price(MIN_SQRT_PRICE_X64 - 1); 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /sui/cetus_clmm/sources/partner.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | #[allow(unused_type_parameter, unused_field)] 4 | /// "Partner" is a module of "clmmpool" that defines a "Partner" object. When a partner participates in a swap 5 | /// transaction, they pass this object and will receive a share of the swap fee that belongs to them. 6 | module cetusclmm::partner { 7 | use sui::object::{UID, ID}; 8 | use sui::vec_map::VecMap; 9 | use std::string::String; 10 | use sui::bag::Bag; 11 | use sui::balance::Balance; 12 | use sui::tx_context::TxContext; 13 | use sui::clock::Clock; 14 | 15 | use cetusclmm::config::GlobalConfig; 16 | 17 | // =============== Structs ================= 18 | 19 | 20 | struct Partners has key { 21 | id: UID, 22 | partners: VecMap 23 | } 24 | 25 | 26 | struct PartnerCap has key, store { 27 | id: UID, 28 | name: String, 29 | partner_id: ID, 30 | } 31 | 32 | 33 | struct Partner has key, store { 34 | id: UID, 35 | name: String, 36 | ref_fee_rate: u64, 37 | start_time: u64, 38 | end_time: u64, 39 | balances: Bag, 40 | } 41 | 42 | 43 | // ============= Events ================= 44 | 45 | 46 | /// Emit when publish the module. 47 | struct InitPartnerEvent has copy, drop { 48 | partners_id: ID, 49 | } 50 | 51 | 52 | /// Emit when create partner. 53 | struct CreatePartnerEvent has copy, drop { 54 | recipient: address, 55 | partner_id: ID, 56 | partner_cap_id: ID, 57 | ref_fee_rate: u64, 58 | name: String, 59 | start_time: u64, 60 | end_time: u64, 61 | } 62 | 63 | 64 | /// Emit when update partner ref fee rate. 65 | struct UpdateRefFeeRateEvent has copy, drop { 66 | partner_id: ID, 67 | old_fee_rate: u64, 68 | new_fee_rate: u64, 69 | } 70 | 71 | 72 | /// Emit when update partner time range. 73 | struct UpdateTimeRangeEvent has copy, drop { 74 | partner_id: ID, 75 | start_time: u64, 76 | end_time: u64, 77 | } 78 | 79 | 80 | /// Emit when receive ref fee. 81 | struct ReceiveRefFeeEvent has copy, drop { 82 | partner_id: ID, 83 | amount: u64, 84 | type_name: String, 85 | } 86 | 87 | 88 | /// Emit when claim ref fee. 89 | struct ClaimRefFeeEvent has copy, drop { 90 | partner_id: ID, 91 | amount: u64, 92 | type_name: String, 93 | } 94 | 95 | /// Create one partner. 96 | /// Params 97 | /// - name: the partner name. 98 | /// - ref_fee_rate: the partner ref fee rate. 99 | /// - start_time: the partner valid start time. 100 | /// - end_time: the partner valid end time. 101 | /// - recipient: the partner cap recipient. 102 | public fun create_partner( 103 | _config: &GlobalConfig, 104 | _partners: &mut Partners, 105 | _name: String, 106 | _ref_fee_rate: u64, 107 | _start_time: u64, 108 | _end_time: u64, 109 | _recipient: address, 110 | _clock: &Clock, 111 | _ctx: &mut TxContext 112 | ) { 113 | abort 0 114 | } 115 | 116 | /// Get partner name. 117 | public fun name(_partner: &Partner): String { 118 | abort 0 119 | } 120 | 121 | /// get partner ref_fee_rate. 122 | public fun ref_fee_rate(_partner: &Partner): u64 { 123 | abort 0 124 | } 125 | 126 | /// get partner start_time. 127 | public fun start_time(_partner: &Partner): u64 { 128 | abort 0 129 | } 130 | 131 | /// get partner end_time. 132 | public fun end_time(_partner: &Partner): u64 { 133 | abort 0 134 | } 135 | 136 | /// get partner balances. 137 | public fun balances(_partner: &Partner): &Bag { 138 | abort 0 139 | } 140 | 141 | /// check the parter is valid or not, and return the partner ref_fee_rate. 142 | public fun current_ref_fee_rate( 143 | _partner: &Partner, 144 | _current_time: u64 145 | ): u64 { 146 | abort 0 147 | } 148 | 149 | /// Update partner ref fee rate. 150 | public fun update_ref_fee_rate( 151 | _config: &GlobalConfig, 152 | _partner: &mut Partner, 153 | _new_fee_rate: u64, 154 | _ctx: &TxContext 155 | ) { 156 | abort 0 157 | } 158 | 159 | /// Update partner time range. 160 | public fun update_time_range( 161 | _config: &GlobalConfig, 162 | _partner: &mut Partner, 163 | _start_time: u64, 164 | _end_time: u64, 165 | _clock: &Clock, 166 | _ctx: &mut TxContext 167 | ) { 168 | abort 0 169 | } 170 | 171 | /// Receive ref fee. 172 | /// This method is called when swap and partner is provided. 173 | public fun receive_ref_fee( 174 | _partner: &mut Partner, 175 | _fee: Balance 176 | ) { 177 | abort 0 178 | } 179 | 180 | /// The `PartnerCap` owner claim the parter fee by CoinType. 181 | public fun claim_ref_fee( 182 | _config: &GlobalConfig, 183 | _partner_cap: &PartnerCap, 184 | _partner: &mut Partner, 185 | _ctx: &mut TxContext 186 | ) { 187 | abort 0 188 | } 189 | 190 | #[test_only] 191 | public fun create_partner_for_test( 192 | _name: String, 193 | _ref_fee_rate: u64, 194 | _start_time: u64, 195 | _end_time: u64, 196 | _clock: &Clock, 197 | _ctx: &mut TxContext 198 | ): (PartnerCap, Partner) { 199 | abort 0 200 | } 201 | 202 | #[test_only] 203 | public fun create_partners_for_test(_ctx: &mut TxContext): Partners { 204 | abort 0 205 | } 206 | 207 | #[test_only] 208 | public fun return_partners(_partners: Partners) { 209 | abort 0 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /sui/cetus_clmm/sources/pool_creator.move: -------------------------------------------------------------------------------- 1 | module cetusclmm::pool_creator { 2 | use std::string::String; 3 | use sui::coin::{Coin, CoinMetadata}; 4 | use sui::clock::Clock; 5 | use sui::tx_context::TxContext; 6 | 7 | use cetusclmm::factory::Pools; 8 | use cetusclmm::config:: GlobalConfig; 9 | use cetusclmm::position::Position; 10 | use cetusclmm::factory::PoolCreationCap; 11 | 12 | public fun create_pool_v2_by_creation_cap( 13 | _config: &GlobalConfig, 14 | _pools: &mut Pools, 15 | _cap: &PoolCreationCap, 16 | _tick_spacing: u32, 17 | _initialize_price: u128, 18 | _url: String, 19 | _coin_a: Coin, 20 | _coin_b: Coin, 21 | _metadata_a: &CoinMetadata, 22 | _metadata_b: &CoinMetadata, 23 | _fix_amount_a: bool, 24 | _clock: &Clock, 25 | _ctx: &mut TxContext 26 | ): (Position, Coin, Coin) { 27 | abort 0 28 | } 29 | 30 | public fun create_pool_v2_with_creation_cap( 31 | _config: &GlobalConfig, 32 | _pools: &mut Pools, 33 | _cap: &PoolCreationCap, 34 | _tick_spacing: u32, 35 | _initialize_price: u128, 36 | _url: String, 37 | _tick_lower_idx: u32, 38 | _tick_upper_idx: u32, 39 | _coin_a: Coin, 40 | _coin_b: Coin, 41 | _metadata_a: &CoinMetadata, 42 | _metadata_b: &CoinMetadata, 43 | _fix_amount_a: bool, 44 | _clock: &Clock, 45 | _ctx: &mut TxContext 46 | ): (Position, Coin, Coin){ 47 | abort 0 48 | } 49 | 50 | public fun create_pool_v2( 51 | _config: &GlobalConfig, 52 | _pools: &mut Pools, 53 | _tick_spacing: u32, 54 | _initialize_price: u128, 55 | _url: String, 56 | _tick_lower_idx: u32, 57 | _tick_upper_idx: u32, 58 | _coin_a: Coin, 59 | _coin_b: Coin, 60 | _metadata_a: &CoinMetadata, 61 | _metadata_b: &CoinMetadata, 62 | _fix_amount_a: bool, 63 | _clock: &Clock, 64 | _ctx: &mut TxContext 65 | ): (Position, Coin, Coin) { 66 | abort 0 67 | } 68 | 69 | public fun full_range_tick_range(_tick_spacing: u32): (u32, u32) { 70 | abort 0 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /sui/cetus_clmm/sources/position.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | #[allow(unused_type_parameter, unused_field)] 4 | /// The `position` module is designed for the convenience of the `Pool`'s position and all `position` related 5 | /// operations are completed by this module. Regarding the `position` of `clmmpool`, 6 | /// there are several points that need to be explained: 7 | /// 8 | /// 1. `clmmpool` specifies the ownership of the `position` through an `Object` named `position_nft`, 9 | /// rather than a wallet address. This means that whoever owns the `position_nft` owns the position it holds. 10 | /// This also means that `clmmpool`'s `position` can be transferred between users freely. 11 | /// 2. `position_nft` records some basic information about the position, but these data do not participate in the 12 | /// related calculations of the position, they are only used for display. The data that actually participates in the 13 | /// calculation is stored in `position_info`, which corresponds one-to-one with `position_nft` and is stored in 14 | /// `PositionManager`. The reason for this design is that in our other contracts, we need to read the information of 15 | /// multiple positions in the `Pool`. 16 | module cetusclmm::position { 17 | use std::string::String; 18 | use std::type_name::TypeName; 19 | 20 | use sui::package::{Publisher}; 21 | use sui::object::{UID, ID}; 22 | use sui::tx_context::TxContext; 23 | 24 | use integer_mate::i32::{I32}; 25 | 26 | use move_stl::linked_table; 27 | 28 | use cetusclmm::config::{GlobalConfig}; 29 | 30 | /// The Cetus clmmpool's position manager, which has only store ability. 31 | /// The `PositionInfo` is organized into a linked table. 32 | struct PositionManager has store { 33 | tick_spacing: u32, 34 | position_index: u64, 35 | positions: linked_table::LinkedTable 36 | } 37 | 38 | struct POSITION has drop {} 39 | 40 | 41 | /// The Cetus clmmpool's position NFT. 42 | struct Position has key, store { 43 | id: UID, 44 | pool: ID, 45 | index: u64, 46 | coin_type_a: TypeName, 47 | coin_type_b: TypeName, 48 | name: String, 49 | description: String, 50 | url: String, 51 | tick_lower_index: I32, 52 | tick_upper_index: I32, 53 | liquidity: u128, 54 | } 55 | 56 | 57 | /// The Cetus clmmpool's position information. 58 | struct PositionInfo has store, drop, copy { 59 | position_id: ID, 60 | liquidity: u128, 61 | tick_lower_index: I32, 62 | tick_upper_index: I32, 63 | fee_growth_inside_a: u128, 64 | fee_growth_inside_b: u128, 65 | fee_owned_a: u64, 66 | fee_owned_b: u64, 67 | points_owned: u128, 68 | points_growth_inside: u128, 69 | rewards: vector, 70 | } 71 | 72 | 73 | /// The Position's rewarder 74 | struct PositionReward has drop, copy, store { 75 | growth_inside: u128, 76 | amount_owned: u64, 77 | } 78 | 79 | fun init(_otw: POSITION, _ctx: &mut TxContext) { 80 | abort 0 81 | } 82 | 83 | /// Set `Display` for the position NFT. 84 | public fun set_display( 85 | _config: &GlobalConfig, 86 | _publisher: &Publisher, 87 | _description: String, 88 | _link: String, 89 | _website: String, 90 | _creator: String, 91 | _ctx: &mut TxContext 92 | ) { 93 | abort 0 94 | } 95 | 96 | /// New `PositionManager` 97 | public(friend) fun new( 98 | _tick_spacing: u32, 99 | _ctx: &mut TxContext 100 | ): PositionManager { 101 | abort 0 102 | } 103 | 104 | /// the inited reward count in `PositionInfo`. 105 | public fun inited_rewards_count(_manager: &PositionManager, _position_id: ID): u64 { 106 | abort 0 107 | } 108 | 109 | /// Fetch `PositionInfo` List. 110 | /// Params 111 | /// - manager: PositionManager 112 | /// - start: start position id 113 | /// - limit: max count of `PositionInfo` to fetch 114 | public fun fetch_positions( 115 | _manager: &PositionManager, _start: vector, _limit: u64 116 | ): vector { 117 | abort 0 118 | } 119 | 120 | /// Get the pool_id of a position. 121 | public fun pool_id(_position_nft: &Position): ID { 122 | abort 0 123 | } 124 | 125 | /// Get the tick range tuple of position. 126 | public fun tick_range(_position_nft: &Position): (I32, I32) { 127 | abort 0 128 | } 129 | 130 | /// Get the index of position. 131 | public fun index(_position_nft: &Position): u64 { 132 | abort 0 133 | } 134 | 135 | /// Get the name of position. 136 | public fun name(_position_nft: &Position): String { 137 | abort 0 138 | } 139 | 140 | /// Get the description of position. 141 | public fun description(_position_nft: &Position): String { 142 | abort 0 143 | } 144 | 145 | /// Get the url of position. 146 | public fun url(_position_nft: &Position): String { 147 | abort 0 148 | } 149 | 150 | /// Get the liquidity of position. 151 | public fun liquidity(_position_nft: &Position): u128 { 152 | abort 0 153 | } 154 | 155 | /// Get the position_id of `PositionInfo`. 156 | public fun info_position_id(_info: &PositionInfo): ID { 157 | abort 0 158 | } 159 | 160 | /// Get the liquidity of `PositionInfo`. 161 | public fun info_liquidity(_info: &PositionInfo): u128 { 162 | abort 0 163 | } 164 | 165 | /// Get the tick range tuple of `PositionInfo`. 166 | public fun info_tick_range(_info: &PositionInfo): (I32, I32) { 167 | abort 0 168 | } 169 | 170 | /// Get the fee_growth_inside tuple of `PositionInfo`. 171 | public fun info_fee_growth_inside(_info: &PositionInfo): (u128, u128) { 172 | abort 0 173 | } 174 | 175 | /// Get the fee_owned tuple of `PositionInfo`. 176 | public fun info_fee_owned(_info: &PositionInfo): (u64, u64) { 177 | abort 0 178 | } 179 | 180 | /// Get the points_owned of `PositionInfo`. 181 | public fun info_points_owned(_info: &PositionInfo): u128 { 182 | abort 0 183 | } 184 | 185 | /// Get the points_growth_inside of `PositionInfo`. 186 | public fun info_points_growth_inside(_info: &PositionInfo): u128 { 187 | abort 0 188 | } 189 | 190 | /// Get the rewards of `PositionInfo`. 191 | public fun info_rewards(_info: &PositionInfo): &vector { 192 | abort 0 193 | } 194 | 195 | /// Returns the reward growth by `PositionReward`. 196 | public fun reward_growth_inside(_reward: &PositionReward): u128 { 197 | abort 0 198 | } 199 | 200 | /// Returns the reward owned by `PositionReward`. 201 | public fun reward_amount_owned(_reward: &PositionReward): u64 { 202 | abort 0 203 | } 204 | 205 | /// Returns the amount of rewards owned by the position. 206 | public(friend) fun rewards_amount_owned( 207 | _manager: &PositionManager, 208 | _postion_id: ID, 209 | ): vector { 210 | abort 0 211 | } 212 | 213 | /// Borrow `PositionInfo` by position_id. 214 | public fun borrow_position_info( 215 | _manager: &PositionManager, 216 | _position_id: ID, 217 | ): &PositionInfo { 218 | abort 0 219 | } 220 | 221 | /// Check if a position is empty 222 | /// 1. liquidity == 0 223 | /// 2. fee_owned_a == 0 224 | /// 3. fee_owned_b == 0 225 | /// 4. [reward.amount_owned == 0 for reward in position_info.rewards] 226 | public fun is_empty(_position_info: &PositionInfo): bool { 227 | abort 0 228 | } 229 | 230 | /// Check if a position tick range is valid. 231 | /// 1. lower < upper 232 | /// 2. (lower >= min_tick) && (upper <= max_tick) 233 | /// 3. (lower % tick_spacing == 0) && (upper % tick_spacing == 0) 234 | public fun check_position_tick_range(_lower: I32, _upper: I32, _tick_spacing: u32) { 235 | abort 0 236 | } 237 | 238 | /// check if the position exists in `PositionManager` by position_id. 239 | public fun is_position_exist(_manager: &PositionManager, _position_id: ID): bool { 240 | abort 0 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /sui/cetus_clmm/sources/rewarder.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | #[allow(unused_type_parameter, unused_field)] 4 | /// `Rewarder` is the liquidity incentive module of `clmmpool`, which is commonly known as `farming`. In `clmmpool`, 5 | /// liquidity is stored in a price range, so `clmmpool` uses a reward allocation method based on effective liquidity. 6 | /// The allocation rules are roughly as follows: 7 | /// 8 | /// 1. Each pool can configure multiple `Rewarders`, and each `Rewarder` releases rewards at a uniform speed according 9 | /// to its configured release rate. 10 | /// 2. During the time period when the liquidity price range contains the current price of the pool, the liquidity 11 | /// position can participate in the reward distribution for this time period (if the pool itself is configured with 12 | /// rewards), and the proportion of the distribution depends on the size of the liquidity value of the position. 13 | /// Conversely, if the price range of a position does not include the current price of the pool during a certain period 14 | /// of time, then this position will not receive any rewards during this period of time. This is similar to the 15 | /// calculation of transaction fees. 16 | module cetusclmm::rewarder { 17 | use std::option::Option; 18 | use std::type_name::TypeName; 19 | use sui::bag::Bag; 20 | use sui::balance::Balance; 21 | use sui::object::{UID, ID}; 22 | use sui::tx_context::TxContext; 23 | 24 | use cetusclmm::config::{GlobalConfig, AdminCap}; 25 | 26 | friend cetusclmm::pool; 27 | 28 | /// Manager the Rewards and Points. 29 | struct RewarderManager has store { 30 | rewarders: vector, 31 | points_released: u128, 32 | points_growth_global: u128, 33 | last_updated_time: u64, 34 | } 35 | 36 | 37 | /// Rewarder store the information of a rewarder. 38 | /// `reward_coin` is the type of reward coin. 39 | /// `emissions_per_second` is the amount of reward coin emit per second. 40 | /// `growth_global` is Q64.X64, is reward emited per liquidity. 41 | struct Rewarder has copy, drop, store { 42 | reward_coin: TypeName, 43 | emissions_per_second: u128, 44 | growth_global: u128, 45 | } 46 | 47 | 48 | /// RewarderGlobalVault store the rewarder `Balance` in Bag globally. 49 | struct RewarderGlobalVault has key, store { 50 | id: UID, 51 | balances: Bag 52 | } 53 | 54 | 55 | /// Emit when `RewarderManager` is initialized. 56 | struct RewarderInitEvent has copy, drop { 57 | global_vault_id: ID, 58 | } 59 | 60 | 61 | /// Emit when deposit reward. 62 | struct DepositEvent has copy, drop, store { 63 | reward_type: TypeName, 64 | deposit_amount: u64, 65 | after_amount: u64 66 | } 67 | 68 | 69 | /// Emit when withdraw reward. 70 | struct EmergentWithdrawEvent has copy, drop, store { 71 | reward_type: TypeName, 72 | withdraw_amount: u64, 73 | after_amount: u64 74 | } 75 | 76 | /// init the `RewarderGlobalVault 77 | fun init(_ctx: &mut TxContext) { 78 | abort 0 79 | } 80 | 81 | /// initialize the `RewarderManager`. 82 | public(friend) fun new(): RewarderManager { 83 | abort 0 84 | } 85 | 86 | /// get the rewarders 87 | public fun rewarders(_manager: &RewarderManager): vector { 88 | abort 0 89 | } 90 | 91 | /// get the reward_growth_globals 92 | public fun rewards_growth_global(_manager: &RewarderManager): vector { 93 | abort 0 94 | } 95 | 96 | /// get the points_released 97 | public fun points_released(_manager: &RewarderManager): u128 { 98 | abort 0 99 | } 100 | 101 | /// get the points_growth_global 102 | public fun points_growth_global(_manager: &RewarderManager): u128 { 103 | abort 0 104 | } 105 | 106 | /// get the last_updated_time 107 | public fun last_update_time(_manager: &RewarderManager): u64 { 108 | abort 0 109 | } 110 | 111 | /// get the rewarder coin Type. 112 | public fun reward_coin(_rewarder: &Rewarder): TypeName { 113 | abort 0 114 | } 115 | 116 | /// get the rewarder emissions_per_second. 117 | public fun emissions_per_second(_rewarder: &Rewarder): u128 { 118 | abort 0 119 | } 120 | 121 | /// get the rewarder growth_global. 122 | public fun growth_global(_rewarder: &Rewarder): u128 { 123 | abort 0 124 | } 125 | 126 | /// Get index of CoinType in `RewarderManager`, if not exists, return `None` 127 | public fun rewarder_index(_manager: &RewarderManager): Option { 128 | abort 0 129 | } 130 | 131 | /// Borrow `Rewarder` from `RewarderManager` 132 | public fun borrow_rewarder(_manager: &RewarderManager): &Rewarder { 133 | abort 0 134 | } 135 | 136 | /// Deposit Reward into `RewarderGlobalVault` 137 | /// Params 138 | /// - `config`: GlobalConfig 139 | /// - `vault`: RewarderGlobalVault 140 | /// - `balance`: Balance of CoinType 141 | public fun deposit_reward( 142 | _config: &GlobalConfig, 143 | _vault: &mut RewarderGlobalVault, 144 | _balance: Balance 145 | ): u64 { 146 | abort 0 147 | } 148 | 149 | /// Withdraw reward Balance of CoinType from vault by the protocol `AdminCap`. 150 | /// This function is only used for emergency. 151 | /// Params 152 | /// - config: GlobalConfig. 153 | /// - amount: the amount of reward Balance to withdraw. 154 | /// - vault: RewarderGlobalVault. 155 | public fun emergent_withdraw( 156 | _: &AdminCap, 157 | _config: &GlobalConfig, 158 | _vault: &mut RewarderGlobalVault, 159 | _amount: u64 160 | ): Balance { 161 | abort 0 162 | } 163 | 164 | /// Get the balances in vault. 165 | public fun balances( 166 | _vault: & RewarderGlobalVault 167 | ): &Bag { 168 | abort 0 169 | } 170 | 171 | /// Get the balance value of CoinType in vault. 172 | public fun balance_of( 173 | _vault: &RewarderGlobalVault 174 | ): u64 { 175 | abort 0 176 | } 177 | 178 | #[test_only] 179 | use sui::object; 180 | #[test_only] 181 | use std::type_name; 182 | #[test_only] 183 | use sui::bag; 184 | 185 | #[test_only] 186 | public fun new_vault_for_test(ctx: &mut TxContext): RewarderGlobalVault { 187 | RewarderGlobalVault { 188 | id: object::new(ctx), 189 | balances: bag::new(ctx) 190 | } 191 | } 192 | 193 | #[test_only] 194 | public fun new_rewarder_for_test( 195 | emissions_per_second: u128, 196 | growth_global: u128, 197 | ): Rewarder { 198 | Rewarder { 199 | reward_coin: type_name::get(), 200 | emissions_per_second, 201 | growth_global 202 | } 203 | } 204 | 205 | 206 | #[test_only] 207 | public fun update_for_swap_test( 208 | manager: &mut RewarderManager, 209 | rewarders: vector, 210 | points_released: u128, 211 | points_growth_global: u128, 212 | last_updated_time: u64, 213 | ) { 214 | manager.rewarders = rewarders; 215 | manager.points_released = points_released; 216 | manager.points_growth_global = points_growth_global; 217 | manager.last_updated_time = last_updated_time; 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /sui/cetus_clmm/sources/tick.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | #[allow(unused_field)] 4 | /// The `tick` module is a module that is designed to facilitate the management of `tick` owned by `Pool`. 5 | /// All `tick` related operations of `Pool` are handled by this module. 6 | module cetusclmm::tick { 7 | use std::option::Option; 8 | 9 | use sui::tx_context::TxContext; 10 | 11 | use integer_mate::i32::I32; 12 | use integer_mate::i128::I128; 13 | 14 | use move_stl::skip_list::SkipList; 15 | use move_stl::option_u64::OptionU64; 16 | 17 | 18 | friend cetusclmm::pool; 19 | 20 | /// Manager ticks of a pool, ticks is organized into SkipList. 21 | struct TickManager has store { 22 | tick_spacing: u32, 23 | ticks: SkipList 24 | } 25 | 26 | 27 | /// Tick infos. 28 | struct Tick has copy, drop, store { 29 | index: I32, 30 | sqrt_price: u128, 31 | liquidity_net: I128, 32 | liquidity_gross: u128, 33 | fee_growth_outside_a: u128, 34 | fee_growth_outside_b: u128, 35 | points_growth_outside: u128, 36 | rewards_growth_outside: vector, 37 | } 38 | 39 | /// init the TickManager. 40 | public(friend) fun new(_tick_spacing: u32, _seed: u64, _ctx: &mut TxContext): TickManager { 41 | abort 0 42 | } 43 | 44 | /// return the next tick index for swap. 45 | public fun first_score_for_swap( 46 | _manager: &TickManager, 47 | _current_tick_idx: I32, 48 | _a2b: bool, 49 | ): OptionU64 { 50 | abort 0 51 | } 52 | 53 | /// Borrow Tick by score and return the next tick score for swap. 54 | public fun borrow_tick_for_swap(_manager: &TickManager, _score: u64, _a2b: bool): (&Tick, OptionU64) { 55 | abort 0 56 | } 57 | 58 | /// Get tick_spacing. 59 | public fun tick_spacing(_manager: &TickManager): u32 { 60 | abort 0 61 | } 62 | 63 | /// Get tick index 64 | public fun index(_tick: &Tick): I32 { 65 | abort 0 66 | } 67 | 68 | /// Get tick sqrt_price 69 | public fun sqrt_price(_tick: &Tick): u128 { 70 | abort 0 71 | } 72 | 73 | /// Get tick liquidity_net 74 | public fun liquidity_net(_tick: &Tick): I128 { 75 | abort 0 76 | } 77 | 78 | /// Get tick liquidity_gross 79 | public fun liquidity_gross(_tick: &Tick): u128 { 80 | abort 0 81 | } 82 | 83 | /// Get tick fee_growth_insides 84 | public fun fee_growth_outside(_tick: &Tick): (u128, u128) { 85 | abort 0 86 | } 87 | 88 | /// Get tick points_growth_outside 89 | public fun points_growth_outside(_tick: &Tick): u128 { 90 | abort 0 91 | } 92 | 93 | /// Get tick rewards_growth_outside 94 | public fun rewards_growth_outside(_tick: &Tick): &vector { 95 | abort 0 96 | } 97 | 98 | /// Borrow Tick by index 99 | public fun borrow_tick(_manager: &TickManager, _idx: I32): &Tick { 100 | abort 0 101 | } 102 | 103 | /// Get the tick reward_growth_outside by index. 104 | public fun get_reward_growth_outside(_tick: &Tick, _idx: u64): u128 { 105 | abort 0 106 | } 107 | 108 | /// Get the fee inside in tick range. 109 | public fun get_fee_in_range( 110 | _pool_current_tick_index: I32, 111 | _fee_growth_global_a: u128, 112 | _fee_growth_global_b: u128, 113 | _op_tick_lower: Option, 114 | _op_tick_upper: Option 115 | ): (u128, u128) { 116 | abort 0 117 | } 118 | 119 | /// Get the rewards inside in tick range. 120 | public fun get_rewards_in_range( 121 | _pool_current_tick_index: I32, 122 | _rewards_growth_globals: vector, 123 | _op_tick_lower: Option, 124 | _op_tick_upper: Option 125 | ): vector { 126 | abort 0 127 | } 128 | 129 | /// Get the points inside in tick range. 130 | public fun get_points_in_range( 131 | _pool_current_tick_index: I32, 132 | _points_growth_global: u128, 133 | _op_tick_lower: Option, 134 | _op_tick_upper: Option 135 | ): u128 { 136 | abort 0 137 | } 138 | 139 | 140 | /// Fetch Ticks 141 | /// Params 142 | /// -start: start tick index 143 | /// - limit: max number of ticks to fetch 144 | public fun fetch_ticks( 145 | _manager: &TickManager, 146 | _start: vector, 147 | _limit: u64 148 | ): vector { 149 | abort 0 150 | } 151 | 152 | /// For store Ticks in LinkedTable, convert the tick index of I32 to u64 153 | /// Convert tick range[-4423636, 443636] to [0, 443636*2]. 154 | #[allow(unused_function)] 155 | fun tick_score(_tick: I32): u64 { 156 | abort 0 157 | } 158 | 159 | 160 | #[test_only] 161 | use cetusclmm::tick_math; 162 | #[test_only] 163 | use move_stl::skip_list; 164 | #[test_only] 165 | use std::vector; 166 | 167 | #[test_only] 168 | public fun new_tick_for_test( 169 | index: I32, 170 | liquidity_net: I128, 171 | liquidity_gross: u128, 172 | fee_growth_outside_a: u128, 173 | fee_growth_outside_b: u128, 174 | points_growth_outside: u128, 175 | rewards_growth_outside: vector 176 | ): Tick { 177 | Tick { 178 | index, 179 | sqrt_price: tick_math::get_sqrt_price_at_tick(index), 180 | liquidity_net, 181 | liquidity_gross, 182 | fee_growth_outside_a, 183 | fee_growth_outside_b, 184 | points_growth_outside, 185 | rewards_growth_outside, 186 | } 187 | } 188 | 189 | #[test_only] 190 | public fun add_ticks_for_test( 191 | manager: &mut TickManager, 192 | ticks: vector 193 | ) { 194 | let idx = 0; 195 | while (idx < vector::length(&ticks)) { 196 | let tick = *vector::borrow(&ticks, idx); 197 | let score = tick_score(tick.index); 198 | if (skip_list::contains(&manager.ticks, score)) { 199 | skip_list::remove(&mut manager.ticks, score); 200 | }; 201 | skip_list::insert(&mut manager.ticks, score, tick); 202 | idx = idx + 1; 203 | } 204 | } 205 | 206 | #[test_only] 207 | public fun copy_tick_with_default( 208 | _manager: &TickManager, 209 | _tick_idx: I32 210 | ): Tick { 211 | abort 0 212 | } 213 | 214 | #[test_only] 215 | public fun insert_tick( 216 | manager: &mut TickManager, 217 | index: I32, 218 | sqrt_price: u128, 219 | liquidity_net: I128, 220 | liquidity_gross: u128, 221 | fee_growth_outside_a: u128, 222 | fee_growth_outside_b: u128, 223 | points_growth_outside: u128, 224 | rewards_growth_outside: vector 225 | ) { 226 | let tick = Tick { 227 | index, 228 | sqrt_price, 229 | liquidity_net, 230 | liquidity_gross, 231 | fee_growth_outside_a, 232 | fee_growth_outside_b, 233 | points_growth_outside, 234 | rewards_growth_outside, 235 | }; 236 | let score = tick_score(tick.index); 237 | if (skip_list::contains(&manager.ticks, score)) { 238 | skip_list::remove(&mut manager.ticks, score); 239 | }; 240 | skip_list::insert(&mut manager.ticks, score, tick); 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /sui/cetus_clmm/sources/utils.move: -------------------------------------------------------------------------------- 1 | module cetusclmm::utils { 2 | use std::string::String; 3 | 4 | /// Convert u64 to String. 5 | public fun str(_num: u64): String { 6 | abort 0 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /sui/dca/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.log 3 | /.vscode 4 | /.idea 5 | -------------------------------------------------------------------------------- /sui/dca/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "38C23E3FDFEE0048CEF856892AF2EDD467D223A82F36AFE575A5DAB4185D53BA" 6 | deps_digest = "397E6A9F7A624706DBDFEE056CE88391A15876868FD18A88504DA74EB458D697" 7 | dependencies = [ 8 | { id = "Bridge", name = "Bridge" }, 9 | { id = "MoveSTL", name = "MoveSTL" }, 10 | { id = "MoveStdlib", name = "MoveStdlib" }, 11 | { id = "Sui", name = "Sui" }, 12 | { id = "SuiSystem", name = "SuiSystem" }, 13 | ] 14 | 15 | [[move.package]] 16 | id = "Bridge" 17 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/bridge" } 18 | 19 | dependencies = [ 20 | { id = "MoveStdlib", name = "MoveStdlib" }, 21 | { id = "Sui", name = "Sui" }, 22 | { id = "SuiSystem", name = "SuiSystem" }, 23 | ] 24 | 25 | [[move.package]] 26 | id = "MoveSTL" 27 | source = { git = "https://github.com/CetusProtocol/move-stl.git", rev = "mainnet-v1.48.2", subdir = "sui" } 28 | 29 | dependencies = [ 30 | { id = "Bridge", name = "Bridge" }, 31 | { id = "MoveStdlib", name = "MoveStdlib" }, 32 | { id = "Sui", name = "Sui" }, 33 | { id = "SuiSystem", name = "SuiSystem" }, 34 | ] 35 | 36 | [[move.package]] 37 | id = "MoveStdlib" 38 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/move-stdlib" } 39 | 40 | [[move.package]] 41 | id = "Sui" 42 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-framework" } 43 | 44 | dependencies = [ 45 | { id = "MoveStdlib", name = "MoveStdlib" }, 46 | ] 47 | 48 | [[move.package]] 49 | id = "SuiSystem" 50 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-system" } 51 | 52 | dependencies = [ 53 | { id = "MoveStdlib", name = "MoveStdlib" }, 54 | { id = "Sui", name = "Sui" }, 55 | ] 56 | 57 | [move.toolchain-version] 58 | compiler-version = "1.48.2" 59 | edition = "2024.beta" 60 | flavor = "sui" 61 | 62 | [env] 63 | 64 | [env.mainnet] 65 | chain-id = "35834a8a" 66 | original-published-id = "0x587614620d0d30aed66d86ffd3ba385a661a86aa573a4d579017068f561c6d8f" 67 | latest-published-id = "0x587614620d0d30aed66d86ffd3ba385a661a86aa573a4d579017068f561c6d8f" 68 | published-version = "1" 69 | -------------------------------------------------------------------------------- /sui/dca/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "DCA" 3 | edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move 4 | 5 | [dependencies] 6 | MoveSTL = { git = "https://github.com/CetusProtocol/move-stl.git", subdir = "sui", rev = "mainnet-v1.48.2", override = true } 7 | 8 | [addresses] 9 | dca = "0x587614620d0d30aed66d86ffd3ba385a661a86aa573a4d579017068f561c6d8f" 10 | -------------------------------------------------------------------------------- /sui/dca/README.md: -------------------------------------------------------------------------------- 1 | # Cetus DCA 2 | 3 | ## What is Cetus DCA ? 4 | 5 | Cetus DCA(Dollar Cost Averaging) can help users achieve the goal of purchasing a specific token at fixed intervals with a fixed amount, regardless of how the market price fluctuates. 6 | 7 | ## What is Cetus DCA Interface ? 8 | 9 | The Cetus DCA Contract is used to record all user dca order information on our platform. 10 | 11 | The Cetus DCA Interface is designed to facilitate developers who wish to integrate dca orders at the contract level. With just one line of code, you can integrate Cetus DCA into your smart contracts. 12 | 13 | ## How to Use the Cetus DCA Interface ? 14 | 15 | ### Tags corresponding to different networks 16 | 17 | | Tag of Repo | Network | Latest published at address | 18 | | --------------- | ------- | ------------------------------------------------------------------ | 19 | | mainnet-v1.24.0 | mainnet | 0x587614620d0d30aed66d86ffd3ba385a661a86aa573a4d579017068f561c6d8f | 20 | | testnet-v1.24.0 | testnet | 0x484d2be08b58b8dc00a08c0ff8a2a9cd0542c4249ea2d5934ef9b15a10585d88 | 21 | 22 | eg: 23 | 24 | mainnet: 25 | 26 | ``` 27 | CetusDCA = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/dca", rev = "mainnet-v1.24.0", override = true } 28 | ``` 29 | 30 | testnet: 31 | 32 | ``` 33 | CetusDCA = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/dca", rev = "testnet-v1.24.0", override = true } 34 | ``` 35 | 36 | ## Usage 37 | 38 | Cetus DCA interface is not complete(just have function definition), so it will fails when sui client check the code version. However, this does not affect its actual functionality. Therefore, we need to add a `--dependencies-are-root` during the build. 39 | 40 | ```bash 41 | sui move build --dependencies-are-root && sui client publish --dependencies-are-root 42 | ``` 43 | 44 | ## Process 45 | 46 | Here is a complete workflow of the DCA process. 47 | ![DCA workflow](./dca.png) 48 | 49 | ## Function Description 50 | 51 | We describe all parameters only when they appear for the first time. 52 | 53 | ### 1. open_order 54 | 55 | First, the specified in coin type and out coin type uniquely determine the type of order. The orders indexer is used to index all orders of a certain type, similarly, creating a rate orders indexer is a prerequisite for placing a limit order. 56 | 57 | #### Params: 58 | 59 | - **config**: dca global config object. 60 | 61 | | Network | Global Config Object ID | 62 | | ------- | ------------------------------------------------------------------ | 63 | | mainnet | 0x5db218756f8486fa2ac26fab590c4be4e439be54e6d932c9a30b20573a5b706a | 64 | | testnet | 0xdac150723df0b51c1407ea942036d7f9d4e3b064ff35a4136dd31ffb397497e0 | 65 | 66 | - **in_coin**: The input coin object. 67 | - **cycle_frequency**: Frequency of order execution (in seconds). 68 | - **cycle_count**: Total cycle count of order execution. 69 | - **min_out_amount_per_cycle**: Minimum amount of out_coin obtained per transaction. 70 | - **max_out_amount_per_cycle**: Maximum amount of out_coin obtained per transaction. 71 | - **in_amount_per_cycle**: Amount of in_coin per transaction (in_deposited divided by in_amount_per_cycle gives the 72 | - **fee_rate**: Transaction fee rate (denominator is 1,000,000). 73 | - **timestamp**: Current timestamp when order created. 74 | - **signature**: Create by cetus quote service, it will check the `in_amount_per_cycle`,`fee_rate`, `timestamp`. 75 | - **indexer**: the indexer about dca order orders 76 | 77 | | Network | orders indexer | 78 | | ------- | ------------------------------------------------------------------ | 79 | | mainnet | 0x713f0968d042b48f4ec57e4e21bd7e346d06355f59776faedc9497ca990a9f77 | 80 | | testnet | 0xacd0ab94883a8785c5258388618b6252f0c2e9384b23f91fc23f6c8ef44d445c | 81 | 82 | #### Code Example: 83 | 84 | ``` 85 | public fun open_order( 86 | config: &GlobalConfig, 87 | in_coin: Coin, 88 | cycle_frequency: u64, 89 | cycle_count: u64, 90 | min_out_amount_per_cycle: u64, 91 | max_out_amount_per_cycle: u64, 92 | in_amount_limit_per_cycle: u64, 93 | fee_rate: u64, 94 | timestamp: u64, 95 | signature: String, 96 | clk: &Clock, 97 | indexer: &mut OrderIndexer, 98 | ctx: &mut TxContext 99 | ) { 100 | ... 101 | } 102 | ``` 103 | 104 | ### 2. withdraw 105 | 106 | As the function name suggests, users can withdraw already execute dca order. 107 | 108 | #### Code Example: 109 | 110 | ``` 111 | public fun withdraw( 112 | config: &GlobalConfig, 113 | order: &mut Order, 114 | clk: &Clock, 115 | ctx: &mut TxContext 116 | ): Coin { 117 | ... 118 | } 119 | ``` 120 | 121 | ### 3. cancle_order 122 | 123 | Users can cancel their orders at any time and return both the executed and unexecuted portions. 124 | 125 | ``` 126 | public fun cancle_order( 127 | config: &GlobalConfig, 128 | order: &mut Order, 129 | indexer: &mut OrderIndexer, 130 | clk: &Clock, 131 | ctx: &mut TxContext 132 | ): (Coin, Coin) { 133 | ... 134 | } 135 | ``` 136 | 137 | ## DCA Quote 138 | 139 | This is used to validate the user's input parameters for the DCA order and to sign these parameters. As introduced in the initial workflow, before creating an order, users need to request a quote to generate the signature. When creating the order, the signature must be provided, and the contract will verify whether the signature is valid. 140 | 141 | ### /dca/quote 142 | 143 | - Mainnet: http://api-sui.cetus.com/dca/quote 144 | - Testnet: http://api-sui.devcetus.com/dca/quote 145 | 146 | ``` 147 | curl http://api-sui.cetus.com/dca/quote?in_coin=0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI&freq=120&count=10&sender={user_address} 148 | { 149 | "code": 200, 150 | "data": { 151 | "amount_in_limit": 9744545921, 152 | "coin_type": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI", 153 | "signature": "00dee6e2fe5f0c5c1e703f6ae9ce8995fde7a4b88f994f2dd8f81fd0eae3ad7b339ff803cb8ab25630a0fc19351e8b7c13b5212df634b9bd361c7ac6f0bde31a079d14900643e10df9eb3b0fac154df75f1d38650b4a741f4fc6b70a3cf2a9f6be", 154 | "signer": "{user_address}", 155 | "fee_rate": 1000, 156 | "timestamp": 1723626105 157 | }, 158 | "msg": "Success" 159 | } 160 | ``` 161 | -------------------------------------------------------------------------------- /sui/dca/dca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CetusProtocol/cetus-clmm-interface/228ef93c2d0d32761a1c5036a0b75ca18e4680b7/sui/dca/dca.png -------------------------------------------------------------------------------- /sui/dca/sources/acl.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | #[allow(unused_field, unused_const)] 4 | /// Fork @https://github.com/pentagonxyz/movemate.git 5 | /// 6 | /// `acl` is a simple access control module, where `member` represents a member and `role` represents a type 7 | /// of permission. A member can have multiple permissions. 8 | module dca::acl { 9 | 10 | use move_stl::linked_table::LinkedTable; 11 | 12 | /// @dev When attempting to add/remove a role >= 128. 13 | const ERoleNumberTooLarge: u64 = 0; 14 | 15 | /// @dev Maps addresses to `u128`s with each bit representing the presence of (or lack of) each role. 16 | public struct ACL has store { 17 | permissions: LinkedTable 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /sui/dca/sources/config.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | #[allow(unused_type_parameter, unused_field, unused_const, unused_use)] 4 | module dca::config { 5 | use std::type_name; 6 | use std::type_name::TypeName; 7 | use sui::bag; 8 | use sui::bag::Bag; 9 | use sui::balance::Balance; 10 | use sui::coin; 11 | use sui::event::emit; 12 | use sui::table::{Self, Table}; 13 | use sui::transfer::{transfer, share_object, public_transfer}; 14 | use dca::acl; 15 | 16 | // Constructs 17 | const VERSION: u64 = 1; 18 | 19 | const ACL_KEEPER: u8 = 0; 20 | const ACL_MANAGER: u8 = 1; 21 | const ACL_ORACLE: u8 = 2; 22 | 23 | // === Errors === 24 | const EPackageVersionDeprecate: u64 = 0; 25 | const ENoKeeperPermission: u64 = 1; 26 | const ENoManagerPermision: u64 = 2; 27 | const ENoOraclePermission: u64 = 3; 28 | 29 | // === Structs === 30 | 31 | public struct GlobalConfig has key, store { 32 | id: UID, 33 | acl: acl::ACL, 34 | package_version: u64, 35 | oracle_valid_duration: u64, 36 | min_cycle_frequency: u64, 37 | min_cycle_count: u64, 38 | keeper_threshold: u64, 39 | whitelist_mode: u8, 40 | in_coin_whitelist: Table, 41 | out_coin_whitelist: Table, 42 | } 43 | 44 | public struct ProtocolFeeVault has key, store { 45 | id: UID, 46 | vault: Bag 47 | } 48 | 49 | // === Events === 50 | 51 | /// Emit when init dca config module 52 | public struct InitEvent has copy, drop { 53 | global_config_id: ID, 54 | admin_cap_id: ID, 55 | protocol_fee_vault_id: ID 56 | } 57 | 58 | /// Emit when set roles 59 | public struct SetRolesEvent has copy, drop { 60 | member: address, 61 | roles: u128, 62 | } 63 | 64 | /// Emit when add member 65 | public struct RemoveMemberEvent has copy, drop { 66 | member: address, 67 | } 68 | 69 | /// Emit when update package version. 70 | public struct SetPackageVersionEvent has copy, drop { 71 | new_version: u64, 72 | old_version: u64 73 | } 74 | 75 | /// Emit when set min cycle frequency 76 | public struct SetMinCycelFrequencyEvent has copy, drop { 77 | new_min_cycle_frequency: u64, 78 | old_min_cycle_frequency: u64 79 | } 80 | 81 | /// Emit when set oracle valid duration 82 | public struct SetOracleValidDuration has copy, drop { 83 | new_oracle_valid_duration: u64, 84 | old_oracle_valid_duration: u64 85 | } 86 | 87 | /// Emit when set keeper threshold 88 | public struct SetKeeperThreshold has copy, drop { 89 | new_keeper_threshold: u64, 90 | old_keeper_threshold: u64 91 | } 92 | 93 | /// Emit when set whilitelist mod 94 | public struct SetWhitelistModeEvent has copy, drop { 95 | new_whitelist_mode: u8, 96 | old_whitelist_mode: u8 97 | } 98 | 99 | /// Emit when add coin type to in coin whitelist 100 | public struct AddInCoinTypeEvent has copy, drop { 101 | coin_type: TypeName 102 | } 103 | 104 | /// Emit when remove coin type to in coin whitelist 105 | public struct RemoveInCoinTypeEvent has copy, drop { 106 | coin_type: TypeName 107 | } 108 | 109 | /// Emit when add coin type to out coin whitelist 110 | public struct AddOutCoinTypeEvent has copy, drop { 111 | coin_type: TypeName 112 | } 113 | 114 | /// Emit when remove coin type to out coin whitelist 115 | public struct RemoveOutCoinTypeEvent has copy, drop { 116 | coin_type: TypeName 117 | } 118 | 119 | /// Emit when claim protocol fee 120 | public struct ClaimProtocolFee has copy, drop { 121 | coin_type: TypeName, 122 | amount: u64 123 | } 124 | 125 | // === Functions === 126 | 127 | /// Check package version of the package_version in `GlobalConfig` and VERSION in current package. 128 | public fun checked_package_version(_config: &GlobalConfig) { 129 | abort 0 130 | } 131 | 132 | /// Claim the protocol fee 133 | public fun claim_fee( 134 | _config: &GlobalConfig, 135 | _vault: &mut ProtocolFeeVault, 136 | _ctx: &mut TxContext 137 | ) { 138 | abort 0 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /sui/dca/sources/order.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | #[allow(unused_type_parameter, unused_field, unused_const)] 4 | module dca::order { 5 | use std::string::String; 6 | use std::type_name::TypeName; 7 | use sui::balance::Balance; 8 | use sui::clock::Clock; 9 | use sui::coin::Coin; 10 | use sui::table::Table; 11 | use dca::config::GlobalConfig; 12 | 13 | // === Constans === 14 | const ED25519: u8 = 0; 15 | const FEE_RATE_DENOMINATOR: u128 = 1000000; 16 | 17 | const CHECK_ORACLE: u8 = 0; 18 | const CHECK_KEEPER: u8 = 1; 19 | 20 | const ORDER_STATUS_PENDING: u64 = 0; 21 | const ORDER_STATUS_FINISHED: u64 = 1; 22 | const ORDER_STATUS_CANCLED: u64 = 2; 23 | 24 | // === Errors === 25 | const ECycleCountLimit: u64 = 0; 26 | const ECycleFrequencyLimit: u64 = 1; 27 | const EOrderCycleAmountLeftIsZero: u64 = 2; 28 | const ENotYetTimeForMakeDeal: u64 = 3; 29 | const EOutAmountLtMinLimit: u64 = 4; 30 | const EOutAmountGtMaxLimit: u64 = 5; 31 | const EOutAmountLtPromise: u64 = 6; 32 | const EPerCycleMinInAmountLimit: u64 = 7; 33 | const EInvalidOrderId: u64 = 8; 34 | const EIsNotOrderOwner: u64 = 9; 35 | const ESchemeNotSupport: u64 = 10; 36 | const EOracleSignatureExpired: u64 = 11; 37 | const EInvalidOracleSignature: u64 = 12; 38 | const EOrderNotPending: u64 = 13; 39 | const EKeeperValidate: u64 = 14; 40 | const ETradePairUnSupported: u64 = 15; 41 | const EOutAmountLimitRange: u64 = 16; 42 | 43 | // === Structs === 44 | 45 | /// DCA Order struct 46 | public struct Order has key, store { 47 | id: UID, 48 | user: address, 49 | in_deposited: u64, 50 | in_withdrawn: u64, 51 | out_withdrawn: u64, 52 | in_balance: Balance, 53 | out_balance: Balance, 54 | cycle_frequency: u64, 55 | in_amount_per_cycle: u64, 56 | amount_left_next_cycle: u64, 57 | next_cycle_at: u64, 58 | min_out_amount_per_cycle: u64, 59 | max_out_amount_per_cycle: u64, 60 | fee_rate: u64, 61 | status: u64, 62 | created_at: u64 63 | } 64 | 65 | /// Order Indexer struct, used to store the open orders and user orders 66 | public struct OrderIndexer has key, store { 67 | id: UID, 68 | open_orders: Table, 69 | user_orders: Table>, 70 | } 71 | 72 | /// Make Deal Receipt struct, used to store the make deal receipt 73 | public struct MakeDealReceipt { 74 | order_id: ID, 75 | in_amount: u64, 76 | promise_out_amount: u64, 77 | fee_amount: u64, 78 | } 79 | 80 | // === Events === 81 | 82 | /// Emitted when a new order is opened. 83 | public struct OpenOrderEvent has copy, drop { 84 | order_id: ID, 85 | user: address, 86 | in_coin: TypeName, 87 | out_coin: TypeName, 88 | in_deposited: u64, 89 | cycle_count: u64, 90 | cycle_frequency: u64, 91 | in_amount_per_cycle: u64, 92 | in_amount_limit_per_cycle: u64, 93 | min_out_amount_per_cycle: u64, 94 | max_out_amount_per_cycle: u64, 95 | fee_rate: u64, 96 | created_at: u64 97 | } 98 | 99 | /// Emitted when a deal is made. 100 | public struct MakeDealEvent has copy, drop { 101 | order_id: ID, 102 | user: address, 103 | in_coin: TypeName, 104 | out_coin: TypeName, 105 | in_amount: u64, 106 | out_amount: u64, 107 | promise_out_amount: u64, 108 | after_in_balance: u64, 109 | after_out_balance: u64, 110 | fee_amount: u64, 111 | execution_at: u64 112 | } 113 | 114 | /// Emitted when a deal is made. 115 | public struct WithdrawEvent has copy, drop { 116 | order_id: ID, 117 | user: address, 118 | out_coin: TypeName, 119 | out_withdrawn: u64, 120 | withdrawn_at: u64 121 | } 122 | 123 | /// Emitted when an order is cancelled. 124 | public struct CancelOrderEvent has copy, drop { 125 | order_id: ID, 126 | user: address, 127 | in_coin: TypeName, 128 | out_coin: TypeName, 129 | in_withdrawn: u64, 130 | out_withdrawn: u64, 131 | closed_at: u64 132 | } 133 | 134 | /// Emitted when an order is closed. 135 | public struct CloseOrderEvent has copy, drop { 136 | order_id: ID, 137 | user: address, 138 | out_coin: TypeName, 139 | out_withdrawn: u64, 140 | closed_at: u64 141 | } 142 | 143 | // === functions === 144 | 145 | /// Open a new order 146 | /// Parameters: 147 | /// - `_config`: GlobalConfig struct 148 | /// - `_in_coin`: Input coin 149 | /// - `_cycle_frequency`: Frequency of order execution (in seconds) 150 | /// - `_cycle_count`: Total cycle count of order execution. 151 | /// - `_min_out_amount_per_cycle`: Minimum amount of out_coin obtained per transaction. 152 | /// - `_max_out_amount_per_cycle`: Maximum amount of out_coin obtained per transaction. 153 | /// - `_in_amount_limit_per_cycle`: Amount of in_coin per transaction (in_deposited divided by in_amount_per_cycle gives the number of cycles) 154 | /// - `_fee_rate`: Transaction fee rate (denominator is 1,000,000) 155 | /// - `_timestamp`: Current timestamp when order created. 156 | /// - `_signature`: Create by cetus quote service, it will check the `in_amount_per_cycle`,`fee_rate`, `timestamp`. 157 | /// - `_clk`: Clock 158 | /// - `_indexer`: OrderIndexer struct 159 | /// - `_ctx`: Transaction context 160 | public fun open_order( 161 | _config: &GlobalConfig, 162 | _in_coin: Coin, 163 | _cycle_frequency: u64, 164 | _cycle_count: u64, 165 | _min_out_amount_per_cycle: u64, 166 | _max_out_amount_per_cycle: u64, 167 | _in_amount_limit_per_cycle: u64, 168 | _fee_rate: u64, 169 | _timestamp: u64, 170 | _signature: String, 171 | _clk: &Clock, 172 | _indexer: &mut OrderIndexer, 173 | _ctx: &mut TxContext 174 | ) { 175 | abort 0 176 | } 177 | 178 | /// Withdraw out_coin from the order 179 | /// Parameters: 180 | /// - `_config`: GlobalConfig struct 181 | /// - `_order`: Order struct 182 | /// - `_clk`: Clock 183 | /// - `_ctx`: Transaction context 184 | public fun withdraw( 185 | _config: &GlobalConfig, 186 | _order: &mut Order, 187 | _clk: &Clock, 188 | _ctx: &mut TxContext 189 | ): Coin { 190 | abort 0 191 | } 192 | 193 | /// Cancle the order 194 | /// Parameters: 195 | /// - `_config`: GlobalConfig struct 196 | /// - `_order`: Order struct 197 | /// - `_indexer`: OrderIndexer struct 198 | /// - `_clk`: Clock 199 | /// - `_ctx`: Transaction context 200 | public fun cancle_order( 201 | _config: &GlobalConfig, 202 | _order: &mut Order, 203 | _indexer: &mut OrderIndexer, 204 | _clk: &Clock, 205 | _ctx: &mut TxContext 206 | ): (Coin, Coin) { 207 | abort 0 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /sui/limit-order/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.log 3 | /.vscode 4 | /.idea 5 | -------------------------------------------------------------------------------- /sui/limit-order/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "CFCDB106FC4B1533F60AB2D716F1C5D68F269D3D88E2C070C4731148968FD271" 6 | deps_digest = "52B406A7A21811BEF51751CF88DA0E76DAEFFEAC888D4F4060B1A72BBE7D8D35" 7 | dependencies = [ 8 | { id = "Bridge", name = "Bridge" }, 9 | { id = "IntegerMate", name = "IntegerMate" }, 10 | { id = "MoveSTL", name = "MoveSTL" }, 11 | { id = "MoveStdlib", name = "MoveStdlib" }, 12 | { id = "Sui", name = "Sui" }, 13 | { id = "SuiSystem", name = "SuiSystem" }, 14 | ] 15 | 16 | [[move.package]] 17 | id = "Bridge" 18 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/bridge" } 19 | 20 | dependencies = [ 21 | { id = "MoveStdlib", name = "MoveStdlib" }, 22 | { id = "Sui", name = "Sui" }, 23 | { id = "SuiSystem", name = "SuiSystem" }, 24 | ] 25 | 26 | [[move.package]] 27 | id = "IntegerMate" 28 | source = { git = "https://github.com/CetusProtocol/integer-mate.git", rev = "sui-v1.1.2", subdir = "sui" } 29 | 30 | dependencies = [ 31 | { id = "Sui", name = "Sui" }, 32 | ] 33 | 34 | [[move.package]] 35 | id = "MoveSTL" 36 | source = { git = "https://github.com/CetusProtocol/move-stl.git", rev = "mainnet-v1.48.2", subdir = "sui" } 37 | 38 | dependencies = [ 39 | { id = "Bridge", name = "Bridge" }, 40 | { id = "MoveStdlib", name = "MoveStdlib" }, 41 | { id = "Sui", name = "Sui" }, 42 | { id = "SuiSystem", name = "SuiSystem" }, 43 | ] 44 | 45 | [[move.package]] 46 | id = "MoveStdlib" 47 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/move-stdlib" } 48 | 49 | [[move.package]] 50 | id = "Sui" 51 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-framework" } 52 | 53 | dependencies = [ 54 | { id = "MoveStdlib", name = "MoveStdlib" }, 55 | ] 56 | 57 | [[move.package]] 58 | id = "SuiSystem" 59 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-system" } 60 | 61 | dependencies = [ 62 | { id = "MoveStdlib", name = "MoveStdlib" }, 63 | { id = "Sui", name = "Sui" }, 64 | ] 65 | 66 | [move.toolchain-version] 67 | compiler-version = "1.48.2" 68 | edition = "2024" 69 | flavor = "sui" 70 | 71 | [env] 72 | 73 | [env.mainnet] 74 | chain-id = "35834a8a" 75 | original-published-id = "0x533fab9a116080e2cb1c87f1832c1bf4231ab4c32318ced041e75cc28604bba9" 76 | latest-published-id = "0x533fab9a116080e2cb1c87f1832c1bf4231ab4c32318ced041e75cc28604bba9" 77 | published-version = "1" 78 | -------------------------------------------------------------------------------- /sui/limit-order/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "LimitOrder" 3 | version = "0.1.1" 4 | 5 | [dependencies] 6 | MoveSTL = { git = "https://github.com/CetusProtocol/move-stl.git", subdir = "sui", rev = "mainnet-v1.48.2", override = true } 7 | IntegerMate = { git = "https://github.com/CetusProtocol/integer-mate.git", subdir = "sui", rev = "sui-v1.1.2", override = true } 8 | 9 | 10 | [addresses] 11 | limit_order = "0x533fab9a116080e2cb1c87f1832c1bf4231ab4c32318ced041e75cc28604bba9" 12 | -------------------------------------------------------------------------------- /sui/limit-order/README.md: -------------------------------------------------------------------------------- 1 | # Cetus LimitOrder Interface 2 | 3 | ## What is Cetus LimitOrder ? 4 | 5 | Cetus LimitOrder offers a fast and convenient way to create limit orders on the Sui network, allowing users to flexibly buy and sell between any specified trading pairs at set prices. Cetus leverages the powerful capabilities of the Cetus Aggregator to monitor all available liquidity across the entire Sui chain in real-time, executing transactions as soon as market prices meet the user-defined order prices. 6 | 7 | ## What is Cetus LimitOrder Interface ? 8 | 9 | The Cetus Limit Order Contract is used to record all user limit order information on our platform. All orders placed by users are stored in a shared object, and flash loans are provided to enable limit order bots to quickly utilize the assets in these orders. Through the powerful routing capabilities provided by the Cetus Aggregator, the orders are matched with all liquidity on SUI network. 10 | 11 | The Cetus LimitOrder Interface is designed to facilitate developers who wish to integrate limit orders at the contract level. With just one line of code, you can integrate Cetus LimitOrder into your smart contracts. 12 | 13 | ## How to Use the Cetus LimitOrder Interface ? 14 | 15 | ### Tags corresponding to different networks 16 | 17 | | Tag of Repo | Network | Latest published at address | 18 | | --------------- | ------- | ------------------------------------------------------------------ | 19 | | mainnet-v1.24.0 | mainnet | 0x533fab9a116080e2cb1c87f1832c1bf4231ab4c32318ced041e75cc28604bba9 | 20 | | testnet-v1.24.0 | testnet | 0xc65bc51d2bc2fdbce8c701f8d812da80fb37dba9cdf97ce38f60ab18c5202b17 | 21 | 22 | eg: 23 | 24 | mainnet: 25 | 26 | ``` 27 | LimitOrder = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/limitorder", rev = "mainnet-v1.24.0", override = true } 28 | ``` 29 | 30 | testnet: 31 | 32 | ``` 33 | LimitOrder = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/limitorder", rev = "testnet-v1.24.0", override = true } 34 | ``` 35 | 36 | ## Usage 37 | 38 | Cetus limitorder interface is not complete(just have function definition), so it will fails when sui client check the code version. However, this does not affect its actual functionality. Therefore, we need to add a `--dependencies-are-root` during the build. 39 | 40 | ```bash 41 | sui move build --dependencies-are-root && sui client publish --dependencies-are-root 42 | ``` 43 | 44 | ## Function Description 45 | 46 | We describe all parameters only when they appear for the first time. 47 | 48 | ### 1. create_rate_orders_indexer 49 | 50 | First, the specified pay coin type and target coin type uniquely determine the type of order. The rate orders indexer is used to index all orders of a certain type and group them by price. A rate orders indexer is only needed when creating this type of order for the first time; similarly, creating a rate orders indexer is a prerequisite for placing a limit order. 51 | 52 | #### Params: 53 | 54 | - config: limitorder global config object. 55 | 56 | | Network | Global Config Object ID | 57 | | ------- | ------------------------------------------------------------------ | 58 | | mainnet | 0xd3403f23a053b52e5c4ef0c2a8be316120c435ec338f2596647b6befd569fd9c | 59 | | testnet | 0xd4d98f126233057b3a01f17adfb5bc77d7bdb0332fe982ab44c6c7a2f66443dc | 60 | 61 | - rate_orders_indexers: the indexer about limit order rate orders indexer 62 | 63 | | Network | Rate orders indexer | 64 | | ------- | ------------------------------------------------------------------ | 65 | | mainnet | 0x7de9db54893cd6f69aae7be7fa99362a820810278a234d87d109980e9cfce7c3 | 66 | | testnet | 0xeaa7dc3a4b70c14b434aed2cef0bdd272a781c630ea3c54c25fa53c72fb3cf96 | 67 | 68 | #### Code Example: 69 | 70 | ``` 71 | public entry fun create_rate_orders_indexer( 72 | config: &GlobalConfig, 73 | rate_orders_indexers: &mut RateOrdersIndexers, 74 | clock: &Clock, 75 | ctx: &mut TxContext, 76 | ) { 77 | ... 78 | } 79 | ``` 80 | 81 | ### 2. place_limit_order 82 | 83 | As the function name suggests, users can directly create a limit order through this method. 84 | 85 | #### Params: 86 | 87 | - config: limitorder global config object. 88 | 89 | - rate_orders_indexer: the indexer about one specific type limit orders, key is rate. every pay coin type and target coin type corresponds to a unique rate orders indexer. 90 | 91 | - user_orders_indexer: the indexer about limit orders, key is the owner address. 92 | 93 | | Network | User orders indexer | 94 | | ------- | ------------------------------------------------------------------ | 95 | | mainnet | 0x7f851ac19e438f97e78a5335eed4f12766a3a0ae94340bab7956a402f0e6212e | 96 | | testnet | 0x18ff28ae25ea50c703a0dfcc49653cc7dd7035207e26c8f86fa9e4aea49037d0 | 97 | 98 | - pay_coin: the all balance will be whole used to create limit order. 99 | 100 | - rate: [how to calculate rate by `pay_amount` and `target_amount`](#rate-and-target-amount-calcucalculation-formulaalte). 101 | 102 | - expire_ts: if this order will not be matched by limitorder bot utils expired time, it will auto be canceled, the coin will be send to owner. 103 | 104 | #### Code Example: 105 | 106 | ``` 107 | public entry fun place_limit_order( 108 | config: &GlobalConfig, 109 | rate_orders_indexer: &mut RateOrdersIndexer, 110 | user_orders_indexer: &mut UserOrdersIndexer, 111 | pay_coin: Coin, 112 | rate: u128, 113 | expire_ts: u64, 114 | clock: &Clock, 115 | ctx: &mut TxContext, 116 | ) { 117 | ... 118 | } 119 | ``` 120 | 121 | ### 3. create_indexer_and_place_limit_order 122 | 123 | This method combines the creation of a rate orders indexer with the placement of a limit order, applicable only when a certain type of order does not yet exist in the entire limit order system. 124 | 125 | ``` 126 | public entry fun create_indexer_and_place_limit_order( 127 | config: &GlobalConfig, 128 | rate_orders_indexers: &mut RateOrdersIndexers, 129 | user_orders_indexer: &mut UserOrdersIndexer, 130 | pay_coin: Coin, 131 | rate: u128, 132 | expire_ts: u64, 133 | clock: &Clock, 134 | ctx: &mut TxContext, 135 | ) { 136 | ... 137 | } 138 | ``` 139 | 140 | ### 4. claim_target_coin 141 | 142 | Due to the large quantity involved in some limit orders, our bots may need to transact multiple times to fully execute an order. When a part of the order is executed, we allow the owner of the order to claim the portion executed at the set price. 143 | 144 | ``` 145 | public fun claim_target_coin( 146 | config: &GlobalConfig, 147 | limit_order: &mut LimitOrder, 148 | ctx: &mut TxContext, 149 | ) { 150 | ... 151 | } 152 | ``` 153 | 154 | ### 5. cancel_order_by_owner 155 | 156 | For orders that have not been executed for a long time, we allow users to cancel them, and the assets in the order will be returned to the order's owner. 157 | 158 | ``` 159 | public fun cancel_order_by_owner( 160 | config: &GlobalConfig, 161 | rate_orders_indexer: &mut RateOrdersIndexer, 162 | limit_order: &mut LimitOrder, 163 | clock: &Clock, 164 | ctx: &mut TxContext, 165 | ) { 166 | ... 167 | } 168 | ``` 169 | 170 | ## View Function 171 | 172 | ### 1. get_orders_indexer_by_owner 173 | 174 | Users can quickly find orders created by a specific owner through the order indexer. 175 | 176 | ## Rate and target amount Calcucalculation formulaalte 177 | 178 | 1. expected target amount calculation formula: 179 | 180 | ``` 181 | expect target amount = pay amount * rate 182 | ``` 183 | 184 | 2. rate calculation formula 185 | 186 | ``` 187 | precision = 10 ^ 18 188 | ``` 189 | 190 | ``` 191 | rate = (pay amount * precision) / target amount 192 | ``` 193 | 194 | 3. explanation of the formula: 195 | 196 | - **pay amount** is the amount of coin paid by the user. 197 | - **rate** is the exchange rate for the currency conversion. 198 | - **expect target amount** is the anticipated amount to be received, calculated based on the pay amount and the exchange rate. 199 | - **target amount** is the amount of coin received by the user. 200 | -------------------------------------------------------------------------------- /sui/limit-order/sources/acl.move: -------------------------------------------------------------------------------- 1 | // Copyright © Cetus Technology Limited 2 | 3 | #[allow(unused_const, unused_field)] 4 | /// Fork @https://github.com/pentagonxyz/movemate.git 5 | /// 6 | /// `acl` is a simple access control module, where `member` represents a member and `role` represents a type 7 | /// of permission. A member can have multiple permissions. 8 | module limit_order::acl { 9 | 10 | /// @dev When attempting to add/remove a role >= 128. 11 | const ERoleNumberTooLarge: u64 = 0; 12 | 13 | /// @dev Maps addresses to `u128`s with each bit representing the presence of (or lack of) each role. 14 | struct ACL has store { 15 | permissions: vector // Changed to vector, as interfaces should not include specific implementations 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sui/limit-order/sources/config.move: -------------------------------------------------------------------------------- 1 | // Copyright (C) Cetus Technology Limited 2 | 3 | #[allow(unused_type_parameter, unused_field, unused_const, unused_use)] 4 | // The factory module is provided to create and manage limit order pools. 5 | // The `OrderPools` is a singleton, and it is initialized when the contract is deployed. 6 | // The pools are organized in a linked list, and the key is generated by hash([coin_type_a + coin_type_b]). The details can be found in `new_pool_key` function. 7 | // When creating a pool, the `CoinTypeA` and `CoinTypeB` must be different, and the `CoinTypeA` must be the bigger one (string order). 8 | module limit_order::config { 9 | use std::type_name::TypeName; 10 | use std::ascii::String; 11 | 12 | use sui::object::{ID, UID}; 13 | use sui::tx_context::TxContext; 14 | 15 | use limit_order::acl::ACL; 16 | 17 | // === Constants === 18 | 19 | // Package version 20 | const VERSION: u64 = 1; 21 | 22 | // Limit order ACL roles 23 | const ACL_TOKEN_WHITE_LIST_MANAGER: u8 = 0; 24 | const ACL_KEEPER: u8 = 1; 25 | 26 | // === Errors === 27 | const EPackageVersionDeprecate: u64 = 0; 28 | const ENoTokenWhiteListManagerPermission: u64 = 1; 29 | const ENoLoanManagerPermission: u64 = 2; 30 | const ENotInTokenWhiteList: u64 = 3; 31 | 32 | // === Structs === 33 | 34 | struct AdminCap has key, store { 35 | id: UID, 36 | } 37 | 38 | struct GlobalConfig has key, store { 39 | id: UID, 40 | acl: ACL, 41 | // Limit minimum trade quantity about one token when it used to pay. 42 | token_white_list: vector, // Simplified for interface 43 | deletion_grace_period: u64, 44 | // Manage the switch on flash loan auth 45 | require_flash_loan_auth: bool, 46 | require_check_token_white_list: bool, 47 | package_version: u64, 48 | } 49 | 50 | // === Functions === 51 | 52 | // Check package version of the `package_version` in `GlobalConfig` and `VERSION` in current package. 53 | public fun checked_package_version(_config: &GlobalConfig) { 54 | abort 0 55 | } 56 | 57 | // Get the current package version. 58 | public fun package_version(): u64 { 59 | abort 0 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /sui/lp_burn/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "889C9CDBEE36A0F36727113924727F663799D323CAA9195AF7E74741390FCC91" 6 | deps_digest = "397E6A9F7A624706DBDFEE056CE88391A15876868FD18A88504DA74EB458D697" 7 | dependencies = [ 8 | { id = "Bridge", name = "Bridge" }, 9 | { id = "CetusClmm", name = "CetusClmm" }, 10 | { id = "MoveStdlib", name = "MoveStdlib" }, 11 | { id = "Sui", name = "Sui" }, 12 | { id = "SuiSystem", name = "SuiSystem" }, 13 | ] 14 | 15 | [[move.package]] 16 | id = "Bridge" 17 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/bridge" } 18 | 19 | dependencies = [ 20 | { id = "MoveStdlib", name = "MoveStdlib" }, 21 | { id = "Sui", name = "Sui" }, 22 | { id = "SuiSystem", name = "SuiSystem" }, 23 | ] 24 | 25 | [[move.package]] 26 | id = "CetusClmm" 27 | source = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", rev = "mainnet-v1.48.3", subdir = "sui/cetus_clmm" } 28 | 29 | dependencies = [ 30 | { id = "Bridge", name = "Bridge" }, 31 | { id = "IntegerMate", name = "IntegerMate" }, 32 | { id = "MoveSTL", name = "MoveSTL" }, 33 | { id = "MoveStdlib", name = "MoveStdlib" }, 34 | { id = "Sui", name = "Sui" }, 35 | { id = "SuiSystem", name = "SuiSystem" }, 36 | ] 37 | 38 | [[move.package]] 39 | id = "IntegerMate" 40 | source = { git = "https://github.com/CetusProtocol/integer-mate.git", rev = "sui-v1.1.2", subdir = "sui" } 41 | 42 | dependencies = [ 43 | { id = "Sui", name = "Sui" }, 44 | ] 45 | 46 | [[move.package]] 47 | id = "MoveSTL" 48 | source = { git = "https://github.com/CetusProtocol/move-stl.git", rev = "mainnet-v1.48.2", subdir = "sui" } 49 | 50 | dependencies = [ 51 | { id = "Bridge", name = "Bridge" }, 52 | { id = "MoveStdlib", name = "MoveStdlib" }, 53 | { id = "Sui", name = "Sui" }, 54 | { id = "SuiSystem", name = "SuiSystem" }, 55 | ] 56 | 57 | [[move.package]] 58 | id = "MoveStdlib" 59 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/move-stdlib" } 60 | 61 | [[move.package]] 62 | id = "Sui" 63 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-framework" } 64 | 65 | dependencies = [ 66 | { id = "MoveStdlib", name = "MoveStdlib" }, 67 | ] 68 | 69 | [[move.package]] 70 | id = "SuiSystem" 71 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-system" } 72 | 73 | dependencies = [ 74 | { id = "MoveStdlib", name = "MoveStdlib" }, 75 | { id = "Sui", name = "Sui" }, 76 | ] 77 | 78 | [move.toolchain-version] 79 | compiler-version = "1.48.2" 80 | edition = "2024.beta" 81 | flavor = "sui" 82 | 83 | [env] 84 | 85 | [env.mainnet] 86 | chain-id = "35834a8a" 87 | original-published-id = "0x12d73de9a6bc3cb658ec9dc0fe7de2662be1cea5c76c092fcc3606048cdbac27" 88 | latest-published-id = "0xb6ec861eec8c550269dc29a1662008a816ac4756df723af5103075b665e32e65" 89 | published-version = "4" 90 | -------------------------------------------------------------------------------- /sui/lp_burn/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "LpBurn" 3 | version = "0.0.1" 4 | edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move 5 | 6 | [dependencies] 7 | # cetusclmm = { r.mvr = "@cetuspackages/clmm" } 8 | CetusClmm = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/cetus_clmm", rev = "mainnet-v1.48.3" } 9 | 10 | [addresses] 11 | lpburn = "0x12d73de9a6bc3cb658ec9dc0fe7de2662be1cea5c76c092fcc3606048cdbac27" 12 | 13 | [r.mvr] 14 | network = "mainnet" 15 | -------------------------------------------------------------------------------- /sui/lp_burn/README.md: -------------------------------------------------------------------------------- 1 | # Cetus LP Burn Docs 2 | 3 | The primary functionality of this project, nominally referred to as "LP Burn," is essentially designed for users who wish to permanently lock their liquidity positions. Once locked, the liquidity within these positions cannot be withdrawn, yet users retain the ability to claim any transaction fees and mining rewards generated from these positions. This locking mechanism is implemented by wrapping the original position, effectively sealing the liquidity while still allowing the accrual of rewards. The Cetus LP Burn contract is particularly tailored for projects that have established liquidity pools and wish to relinquish their liquidity rights. This feature allows these projects to commit to their community and ecosystem by locking liquidity permanently, thus providing stability and trust in the liquidity pool's longevity. 4 | 5 | ## Tags corresponding to different networks 6 | 7 | | Tag of Repo | Network | Latest published at address | Package ID | 8 | | --------------- | ------- | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 9 | | mainnet-v1.26.0 | mainnet | 0xb6ec861eec8c550269dc29a1662008a816ac4756df723af5103075b665e32e65 | 0x12d73de9a6bc3cb658ec9dc0fe7de2662be1cea5c76c092fcc3606048cdbac27 | 10 | | testnet-v1.26.0 | testnet | 0x9c751fccc633f3ebad2becbe7884e5f38b4e497127689be0d404b24f79d95d71 | 0x3b494006831b046481c8046910106e2dfbe0d1fa9bc01e41783fb3ff6534ed3a | 11 | 12 | eg: 13 | 14 | mainnet: 15 | 16 | ``` 17 | LpBurn = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/lp_burn", rev = "mainnet-v1.26.0", override = true } 18 | ``` 19 | 20 | testnet: 21 | 22 | ``` 23 | LpBurn = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/lp_burn", rev = "testnet-v1.26.0", override = true } 24 | ``` 25 | 26 | ## 1. Key Structures 27 | 28 | - **BurnManager**: Manager for burning LP. 29 | 30 | ```move 31 | public struct BurnManager has key { 32 | id: UID, 33 | position: Table>, 34 | must_full_range: bool, 35 | package_version: u64 36 | } 37 | ``` 38 | 39 | - **CetusLPBurnProof**: Proof of burning LP. 40 | 41 | ```move 42 | public struct CetusLPBurnProof has key, store { 43 | id: UID, 44 | name: String, 45 | description: String, 46 | image_url: String, 47 | position: Position 48 | } 49 | ``` 50 | 51 | - **BurnedPositionInfo**: Information of burned position. 52 | 53 | ```move 54 | public struct BurnedPositionInfo has store { 55 | burned_position_id: ID, 56 | position_id: ID, 57 | pool_id: ID 58 | } 59 | ``` 60 | 61 | ## 2. User Operations 62 | 63 | 1. Burn LP V2 (**Recommended**). 64 | 65 | When the position is burned, a `CetusLPBurnProof` will be returned. Compared to the `burn_lp` function, this V2 version does not require the pool object as a parameter, making it more convenient to use. The function will automatically verify the position's validity through the position object itself. This design also allows users to create a pool, add liquidity, and burn the position all within one transaction. 66 | 67 | ```move 68 | public fun burn_lp_v2( 69 | manager: &mut BurnManager, 70 | position: Position, 71 | ctx: &mut TxContext 72 | ): CetusLPBurnProof {} 73 | ``` 74 | 75 | 2. Entry Burn LP V2 (**Recommended**). 76 | 77 | The entry function to burn position v2, it will auto transfer `CetusLPBurnProof` to tx sender. 78 | 79 | ```move 80 | public entry fun burn_v2( 81 | manager: &mut BurnManager, 82 | position: Position, 83 | ctx: &mut TxContext 84 | ) {} 85 | ``` 86 | 87 | 3. Burn LP. 88 | 89 | When the position is burned, a `CetusLPBurnProof` will be returned. 90 | 91 | ```move 92 | public fun burn_lp( 93 | manager: &mut BurnManager, 94 | pool: &Pool, 95 | position: Position, 96 | ctx: &mut TxContext 97 | ): CetusLPBurnProof {} 98 | ``` 99 | 100 | 4. Entry Burn LP. 101 | 102 | The entry function to burn position, it will auto transfer `CetusLPBurnProof` to tx sender. 103 | 104 | ```move 105 | public entry fun burn( 106 | manager: &mut BurnManager, 107 | pool: &Pool, 108 | position: Position, 109 | ctx: &mut TxContext 110 | ) {} 111 | ``` 112 | 113 | 5. Collect fee. 114 | 115 | `CetusLPBurnProof` holder can collect lp fee. 116 | 117 | - `config`: This is clmm global config. 118 | 119 | ```move 120 | public fun collect_fee( 121 | m: &BurnManager, 122 | config: &GlobalConfig, 123 | pool: &mut Pool, 124 | position: &mut CetusLPBurnProof, 125 | ctx: &mut TxContext, 126 | ): (Coin, Coin) {} 127 | ``` 128 | 129 | 6. Collect reward. 130 | 131 | `CetusLPBurnProof` holder can collect reward. 132 | 133 | ```move 134 | public fun collect_reward( 135 | m: &BurnManager, 136 | config: &GlobalConfig, 137 | pool: &mut Pool, 138 | position_nft: &mut CetusLPBurnProof, 139 | vault: &mut RewarderGlobalVault, 140 | clock: &Clock, 141 | ctx: &mut TxContext, 142 | ): Coin {} 143 | ``` 144 | 145 | ## 4. OnChain Objects ID 146 | 147 | 1. Mainnet 148 | 149 | ```text 150 | BurnManager: 0x1d94aa32518d0cb00f9de6ed60d450c9a2090761f326752ffad06b2e9404f845 151 | GlobalConfig(clmm): 0xdaa46292632c3c4d8f31f23ea0f9b36a28ff3677e9684980e4438403a67a3d8f 152 | RewarderGlobalVault(clmm): 0xce7bceef26d3ad1f6d9b6f13a953f053e6ed3ca77907516481ce99ae8e588f2b 153 | ``` 154 | 155 | 2. Testnet 156 | 157 | ```text 158 | BurnManager: 0xd04529ef15b7dad6699ee905daca0698858cab49724b2b2a1fc6b1ebc5e474ef 159 | GlobalConfig(clmm): 0x9774e359588ead122af1c7e7f64e14ade261cfeecdb5d0eb4a5b3b4c8ab8bd3e 160 | RewarderGlobalVault(clmm): 0xf78d2ee3c312f298882cb680695e5e8c81b1d441a646caccc058006c2851ddea 161 | ``` 162 | -------------------------------------------------------------------------------- /sui/lp_burn/sources/lp_burn.move: -------------------------------------------------------------------------------- 1 | /// Module: burn_position 2 | #[allow(unused_type_parameter, unused_field)] 3 | module lpburn::lp_burn { 4 | use cetusclmm::config::GlobalConfig; 5 | use cetusclmm::pool::Pool; 6 | use cetusclmm::position::Position; 7 | use cetusclmm::rewarder::RewarderGlobalVault; 8 | use integer_mate::i32::I32; 9 | use std::string::String; 10 | use sui::clock::Clock; 11 | use sui::coin::Coin; 12 | use sui::table::Table; 13 | 14 | // === Structs === 15 | public struct AdminCap has key, store { 16 | id: UID, 17 | } 18 | 19 | public struct LP_BURN has drop {} 20 | 21 | public struct BurnManager has key { 22 | id: UID, 23 | position: Table>, 24 | must_full_range: bool, 25 | package_version: u64, 26 | } 27 | 28 | public struct CetusLPBurnProof has key, store { 29 | id: UID, 30 | name: String, 31 | description: String, 32 | image_url: String, 33 | position: Position, 34 | } 35 | 36 | public struct BurnedPositionInfo has store { 37 | burned_position_id: ID, 38 | position_id: ID, 39 | pool_id: ID, 40 | } 41 | 42 | public struct BurnPositionEvent has copy, drop { 43 | position_id: ID, 44 | burned_position_id: ID, 45 | pool_id: ID, 46 | } 47 | 48 | public struct InitEvent has copy, drop { 49 | manager_id: ID, 50 | cap_id: ID, 51 | } 52 | 53 | public fun burn_lp( 54 | _manager: &mut BurnManager, 55 | _pool: &Pool, 56 | _position: Position, 57 | _ctx: &mut TxContext, 58 | ): CetusLPBurnProof { 59 | abort 0 60 | } 61 | 62 | public entry fun burn( 63 | _manager: &mut BurnManager, 64 | _pool: &Pool, 65 | _position: Position, 66 | _ctx: &mut TxContext, 67 | ) { 68 | abort 0 69 | } 70 | 71 | public fun burn_lp_v2( 72 | _manager: &mut BurnManager, 73 | _position: Position, 74 | _ctx: &mut TxContext, 75 | ): CetusLPBurnProof { 76 | abort 0 77 | } 78 | 79 | public entry fun burn_v2( 80 | _manager: &mut BurnManager, 81 | _position: Position, 82 | _ctx: &mut TxContext, 83 | ) { 84 | abort 0 85 | } 86 | 87 | public fun collect_fee( 88 | _m: &BurnManager, 89 | _config: &GlobalConfig, 90 | _pool: &mut Pool, 91 | _position: &mut CetusLPBurnProof, 92 | _ctx: &mut TxContext, 93 | ): (Coin, Coin) { 94 | abort 0 95 | } 96 | 97 | public fun collect_reward( 98 | _m: &BurnManager, 99 | _config: &GlobalConfig, 100 | _pool: &mut Pool, 101 | _position_nft: &mut CetusLPBurnProof, 102 | _vault: &mut RewarderGlobalVault, 103 | _clock: &Clock, 104 | _ctx: &mut TxContext, 105 | ): Coin { 106 | abort 0 107 | } 108 | 109 | public fun package_version(): u64 { 110 | abort 0 111 | } 112 | 113 | public fun valid_full_range(_min_tick: I32, _max_tick: I32, _tick_spacing: u32) { 114 | abort 0 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /sui/stable_farming/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "79465A7D482A572469EF626DBEC977F45CEEA9279D978AA6EAA65A783A4E9154" 6 | deps_digest = "397E6A9F7A624706DBDFEE056CE88391A15876868FD18A88504DA74EB458D697" 7 | dependencies = [ 8 | { id = "Bridge", name = "Bridge" }, 9 | { id = "CetusClmm", name = "CetusClmm" }, 10 | { id = "MoveStdlib", name = "MoveStdlib" }, 11 | { id = "Sui", name = "Sui" }, 12 | { id = "SuiSystem", name = "SuiSystem" }, 13 | ] 14 | 15 | [[move.package]] 16 | id = "Bridge" 17 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/bridge" } 18 | 19 | dependencies = [ 20 | { id = "MoveStdlib", name = "MoveStdlib" }, 21 | { id = "Sui", name = "Sui" }, 22 | { id = "SuiSystem", name = "SuiSystem" }, 23 | ] 24 | 25 | [[move.package]] 26 | id = "CetusClmm" 27 | source = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", rev = "mainnet-v1.48.3", subdir = "sui/cetus_clmm" } 28 | 29 | dependencies = [ 30 | { id = "Bridge", name = "Bridge" }, 31 | { id = "IntegerMate", name = "IntegerMate" }, 32 | { id = "MoveSTL", name = "MoveSTL" }, 33 | { id = "MoveStdlib", name = "MoveStdlib" }, 34 | { id = "Sui", name = "Sui" }, 35 | { id = "SuiSystem", name = "SuiSystem" }, 36 | ] 37 | 38 | [[move.package]] 39 | id = "IntegerMate" 40 | source = { git = "https://github.com/CetusProtocol/integer-mate.git", rev = "sui-v1.1.2", subdir = "sui" } 41 | 42 | dependencies = [ 43 | { id = "Sui", name = "Sui" }, 44 | ] 45 | 46 | [[move.package]] 47 | id = "MoveSTL" 48 | source = { git = "https://github.com/CetusProtocol/move-stl.git", rev = "mainnet-v1.48.2", subdir = "sui" } 49 | 50 | dependencies = [ 51 | { id = "Bridge", name = "Bridge" }, 52 | { id = "MoveStdlib", name = "MoveStdlib" }, 53 | { id = "Sui", name = "Sui" }, 54 | { id = "SuiSystem", name = "SuiSystem" }, 55 | ] 56 | 57 | [[move.package]] 58 | id = "MoveStdlib" 59 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/move-stdlib" } 60 | 61 | [[move.package]] 62 | id = "Sui" 63 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-framework" } 64 | 65 | dependencies = [ 66 | { id = "MoveStdlib", name = "MoveStdlib" }, 67 | ] 68 | 69 | [[move.package]] 70 | id = "SuiSystem" 71 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-system" } 72 | 73 | dependencies = [ 74 | { id = "MoveStdlib", name = "MoveStdlib" }, 75 | { id = "Sui", name = "Sui" }, 76 | ] 77 | 78 | [move.toolchain-version] 79 | compiler-version = "1.48.2" 80 | edition = "2024" 81 | flavor = "sui" 82 | 83 | [env] 84 | 85 | [env.mainnet] 86 | chain-id = "35834a8a" 87 | original-published-id = "0x11ea791d82b5742cc8cab0bf7946035c97d9001d7c3803a93f119753da66f526" 88 | latest-published-id = "0x7e4ca066f06a1132ab0499c8c0b87f847a0d90684afa902e52501a44dbd81992" 89 | published-version = "5" 90 | -------------------------------------------------------------------------------- /sui/stable_farming/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Farming" 3 | version = "mainnet-v1.1.0" 4 | 5 | [dependencies] 6 | # cetusclmm = { r.mvr = "@cetuspackages/clmm/10" } 7 | CetusClmm = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/cetus_clmm", rev = "mainnet-v1.48.3" } 8 | 9 | [addresses] 10 | farming = "0x11ea791d82b5742cc8cab0bf7946035c97d9001d7c3803a93f119753da66f526" 11 | 12 | # [r.mvr] 13 | # network = "mainnet" 14 | -------------------------------------------------------------------------------- /sui/stable_farming/README.md: -------------------------------------------------------------------------------- 1 | # Cetus StableFarming Docs 2 | 3 | Farms supports the release of multiple rewarders; each rewarder has an emission speed represented by `emission_per_second` and distributes rewards among multiple clmmpools based on the pool's `pool_allocate_point`. 4 | The allocation of a single pool rewarder to staked clmm positions is determined by the position share, which is calculated at the time of staking into the pool. 5 | 6 | ## Tags corresponding to different networks 7 | 8 | | Tag of Repo | Network | Latest published at address | Package ID | 9 | |-----------------| ------- |---------------------------------------------------------------------| ------------------------------------------------------------------ | 10 | | mainnet-v1.25.0 | mainnet | 0x7e4ca066f06a1132ab0499c8c0b87f847a0d90684afa902e52501a44dbd81992 | 0x11ea791d82b5742cc8cab0bf7946035c97d9001d7c3803a93f119753da66f526 | 11 | | testnet-v1.25.0 | testnet | 0x3c4582ee27a09f7e6c091022d0d279fdc8e54c1f782916bf135a71a8e8006aa5 | 0xcc38686ca84d1dca949b6966dcdb66b698b58a4bba247d8db4d6a3a1dbeca26e | 12 | 13 | eg: 14 | 15 | mainnet: 16 | 17 | ``` 18 | StableFarming = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/stable_farming", rev = "mainnet-v1.25.0", override = true } 19 | ``` 20 | 21 | testnet: 22 | 23 | ``` 24 | StableFarming = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/stable_farming", rev = "testnet-v1.25.0", override = true } 25 | ``` 26 | 27 | ## 1. Key Structures 28 | 29 | - **RewarderManager**: Singleton that creates a global object when the contract is deployed, holds the rewarder balance, and manages multiple `Rewarder` information through LinkedTable. 30 | 31 | ```move 32 | struct RewarderManager has key, store { 33 | id: UID, 34 | vault: Bag, 35 | pool_shares: LinkedTable, 36 | rewarders: LinkedTable 37 | } 38 | ``` 39 | 40 | - **Rewarder** 41 | 42 | ```move 43 | struct Rewarder has store { 44 | reward_coin: TypeName, 45 | total_allocate_point: u64, 46 | emission_per_second: u128, 47 | last_reward_time: u64, 48 | total_reward_released: u128, 49 | total_reward_harvested: u64, 50 | pools: LinkedTable 51 | } 52 | 53 | struct PoolRewarderInfo has store { 54 | allocate_point: u64, 55 | acc_per_share: u128, 56 | last_reward_time: u64, 57 | reward_released: u128, 58 | reward_harvested: u64 59 | } 60 | ``` 61 | 62 | - **Pool** 63 | 64 | ```move 65 | struct Pool has key, store { 66 | id: UID, 67 | clmm_pool_id: ID, 68 | effective_tick_lower: I32, 69 | effective_tick_upper: I32, 70 | sqrt_price: u128, 71 | total_share: u128, 72 | rewarders: vector, 73 | positions: LinkedTable 74 | } 75 | 76 | struct WrappedPositionNFT has key, store { 77 | id: UID, 78 | pool_id: ID, 79 | clmm_postion: Position, 80 | url: String 81 | } 82 | 83 | /// Clmm Position 84 | struct Position has key, store { 85 | id: UID, 86 | pool: ID, // clmm pool id 87 | index: u64, 88 | coin_type_a: TypeName, 89 | coin_type_b: TypeName, 90 | name: String, 91 | description: String, 92 | url: String, 93 | tick_lower_index: I32, 94 | tick_upper_index: I32, 95 | liquidity: u128, 96 | } 97 | ``` 98 | 99 | ## 2. Contract Structure 100 | 101 | ```text 102 | acl.move: The ACL module 103 | config.move: Global Config module 104 | pool.move: Pool associated with clmmpool to record information about farming 105 | rewarder.move: Global RewarderManager to manage multiple Rewarders 106 | router.move: All Entry functions 107 | ``` 108 | 109 | ## 3. User Operations 110 | 111 | 1. Deposit Clmm Position into Farming Pool. 112 | When the clmmpool is staked, a `WrappedPositionNFT` is sent to the user. 113 | 114 | ```move 115 | public entry fun deposit( 116 | global_config: &GlobalConfig, 117 | rewarder_manager: &mut RewarderManager, 118 | pool: &mut Pool, 119 | clmm_position: CLMMPosition, 120 | clk: &Clock, 121 | ctx: &mut TxContext 122 | ) 123 | ``` 124 | 125 | 2. Withdraw Clmm Position from Farms Pool. All rewarders should be harvested before withdrawal. 126 | This instruction should work with the harvest instruction; the harvest move call should be organized before the withdrawal move call in a single transaction. 127 | If the clmmpool of this position has two rewarders, two move calls of harvest should be included in the transaction. 128 | 129 | ```move 130 | public entry fun withdraw( 131 | global_config: &GlobalConfig, 132 | rewarder_manager: &mut RewarderManager, 133 | pool: &mut Pool, 134 | wrapped_position: WrappedPositionNFT, 135 | clk: &Clock, 136 | ctx: &TxContext 137 | ) 138 | ``` 139 | 140 | 3. Harvest farm rewarders 141 | 142 | ```move 143 | public entry fun harvest( 144 | global_config: &GlobalConfig, 145 | rewarder_manager: &mut RewarderManager, 146 | pool: &mut Pool, 147 | wrapped_position: &WrappedPositionNFT, 148 | clk: &Clock, 149 | ctx: &mut TxContext 150 | ) 151 | ``` 152 | 153 | 4. Add liquidity into the clmmpool position staked in Farms pool 154 | 155 | ```move 156 | public entry fun add_liquidity( 157 | global_config: &GlobalConfig, 158 | clmm_global_config: &CLMMGlobalConfig, 159 | rewarder_manager: &mut RewarderManager, 160 | pool: &mut Pool, 161 | clmm_pool: &mut CLMMPool, 162 | wrapped_position: &mut WrappedPositionNFT, 163 | coin_a: Coin, 164 | coin_b: Coin, 165 | amount_limit_a: u64, 166 | amount_limit_b: u64, 167 | delta_liquidity: u128, 168 | clk: &Clock, 169 | ctx: &mut TxContext, 170 | ) 171 | ``` 172 | 173 | 5. Add fixed coin liquidity into the clmmpool position staked in Farms pool 174 | 175 | ```move 176 | public entry fun add_liquidity_fix_coin( 177 | global_config: &GlobalConfig, 178 | clmm_global_config: &CLMMGlobalConfig, 179 | rewarder_manager: &mut RewarderManager, 180 | pool: &mut Pool, 181 | clmm_pool: &mut CLMMPool, 182 | wrapped_position: &mut WrappedPositionNFT, 183 | coin_a: Coin, 184 | coin_b: Coin, 185 | amount_a: u64, 186 | amount_b: u64, 187 | fix_amount_a: bool, 188 | clk: &Clock, 189 | ctx: &mut TxContext 190 | ) 191 | ``` 192 | 193 | 6. Remove liquidity from the clmmpool position staked in Farms pool 194 | 195 | ```move 196 | public entry fun remove_liquidity( 197 | global_config: &GlobalConfig, 198 | clmm_global_config: &CLMMGlobalConfig, 199 | rewarder_manager: &mut RewarderManager, 200 | pool: &mut Pool, 201 | clmm_pool: &mut CLMMPool, 202 | wrapped_position: &mut WrappedPositionNFT, 203 | delta_liquidity: u128, 204 | min_amount_a: u64, 205 | min_amount_b: u64, 206 | clk: &Clock, 207 | ctx: &mut TxContext 208 | ) 209 | ``` 210 | 211 | 7. Collect clmm fee using `WrappedPositionNFT` 212 | 213 | ```move 214 | public entry fun collect_fee( 215 | global_config: &GlobalConfig, 216 | clmm_global_config: &CLMMGlobalConfig, 217 | clmm_pool: &mut CLMMPool, 218 | wrapped_position: &WrappedPositionNFT, 219 | ctx: &mut TxContext 220 | ) 221 | ``` 222 | 223 | 8. Collect clmm rewarder using `WrappedPositionNFT` 224 | 225 | ```move 226 | public entry fun collect_clmm_reward( 227 | global_config: &GlobalConfig, 228 | clmm_global_config: &CLMMGlobalConfig, 229 | clmm_pool: &mut CLMMPool, 230 | warped_position: &WrappedPositionNFT, 231 | vault: &mut RewarderGlobalVault, 232 | reward_coin: Coin, 233 | clock: &Clock, 234 | ctx: &mut TxContext 235 | ) 236 | ``` 237 | 238 | 9. Close clmm position 239 | Before calling this instruction to close the clmm position, the possible existing multiple clmm rewarders should be collected, and possible multiple Farms rewarders should be harvested. 240 | So the `collect_clmm_reward` and `harvest` move calls should be organized with `close_position` into a single transaction. 241 | 242 | ```move 243 | public fun close_position( 244 | global_config: &GlobalConfig, 245 | rewarder_manager: &mut RewarderManager, 246 | pool: &mut Pool, 247 | clmm_global_config: &CLMMGlobalConfig, 248 | clmm_pool: &mut CLMMPool, 249 | wrapped_position: WrappedPositionNFT, 250 | min_amount_a: u64, 251 | min_amount_b: u64, 252 | clk: &Clock, 253 | ctx: &mut TxContext 254 | ) 255 | ``` 256 | 257 | ## 4. OnChain Contracts and Objects 258 | 259 | 1. Testnet 260 | 261 | ```text 262 | package_id: 0xcc38686ca84d1dca949b6966dcdb66b698b58a4bba247d8db4d6a3a1dbeca26e 263 | published_at: 0x3c4582ee27a09f7e6c091022d0d279fdc8e54c1f782916bf135a71a8e8006aa5 264 | 265 | RewardManager: 0x960c7800e301fd1e47b79037927b426db57b643bd2934f7069d81c2dae092230 266 | GlobalConfig: 0x499132a4baf342a0fe9528a3666a77b2aece3be129f4a3ada469fef4b9c34fb4 267 | CLmmGlobalConfig: 0x9774e359588ead122af1c7e7f64e14ade261cfeecdb5d0eb4a5b3b4c8ab8bd3e 268 | ``` 269 | 270 | 2. Mainnet 271 | 272 | ```text 273 | package_id: 0x11ea791d82b5742cc8cab0bf7946035c97d9001d7c3803a93f119753da66f526 274 | published_at: 0x7e4ca066f06a1132ab0499c8c0b87f847a0d90684afa902e52501a44dbd81992 275 | 276 | RewardManager: 0xe0e155a88c77025056da08db5b1701a91b79edb6167462f768e387c3ed6614d5 277 | GlobalConfig: 0x21215f2f6de04b57dd87d9be7bb4e15499aec935e36078e2488f36436d64996e 278 | ClmmGlobalConfig: 0xdaa46292632c3c4d8f31f23ea0f9b36a28ff3677e9684980e4438403a67a3d8f 279 | ``` 280 | 281 | ## 5. How to Fetch All Farms Pools 282 | 283 | ```move 284 | struct CreatePoolEvent has drop, copy { 285 | pool_id: ID, 286 | clmm_pool_id: ID, 287 | sqrt_price: u128, 288 | effective_tick_lower: I32, 289 | effective_tick_upper: I32, 290 | } 291 | ``` 292 | 293 | Query all events of type "{package_id}::pool::CreatePoolEvent", and all related Farms pool_id and clmm_pool_id will be returned. 294 | 295 | ## 6. How to Fetch the Latest Rewarders for WrappedPositionNFT 296 | 297 | Simulate the `accumulated_position_rewards` instruction, which will emit the `AccumulatedPositionRewardsEvent`. Parsing the event will get multiple rewarders that the `WrappedPositionNFT` gets at the current time. 298 | 299 | ```move 300 | public fun accumulated_position_rewards( 301 | global_config: &GlobalConfig, 302 | rewarder_manager: &mut RewarderManager, 303 | pool: &mut Pool, 304 | wrapped_position_id: ID, 305 | clk: &Clock, 306 | ) { 307 | emit struct AccumulatedPositionRewardsEvent has drop, copy { 308 | pool_id: ID, 309 | wrapped_position_id: ID, 310 | clmm_position_id: ID, 311 | rewards: vec_map::VecMap 312 | } 313 | } 314 | ``` 315 | 316 | ## 7. Open Liquidity Position, Add Liquidity if Needed, and Deposit into Farms Pool in a Single Transaction 317 | 318 | Organize open position, add liquidity, and deposit move calls into a single transaction. 319 | 320 | ```move 321 | /// clmmpool::pool::open_position and get Clmm LP. 322 | public fun open_position( 323 | config: &GlobalConfig, 324 | pool: &mut Pool, 325 | tick_lower: u32, 326 | tick_upper: u32, 327 | ctx: &mut TxContext 328 | ): Position; 329 | 330 | /// integrate::pool_v2::add_liquidity_by_fix_coin. 331 | public entry fun add_liquidity_by_fix_coin( 332 | config: &GlobalConfig, 333 | pool: &mut Pool, 334 | position_nft: &mut Position, 335 | coin_a: Coin, 336 | coin_b: Coin, 337 | amount_a: u64, 338 | amount_b: u64, 339 | fix_amount_a: bool, 340 | clock: &Clock, 341 | ctx: &mut TxContext 342 | ); 343 | 344 | /// call farms::pool::deposit to deposit LP into Farms pool and get WrappedPositionNFT 345 | public fun deposit( 346 | global_config: &GlobalConfig, 347 | rewarder_manager: &mut RewarderManager, 348 | pool: &mut Pool, 349 | clmm_position: CLMMPosition, 350 | clk: &Clock, 351 | ctx: &mut TxContext 352 | ): WrappedPositionNFT 353 | ``` 354 | -------------------------------------------------------------------------------- /sui/stable_farming/sources/acl.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | /// Fork @https://github.com/pentagonxyz/movemate.git 4 | /// 5 | /// `acl` is a simple access control module, where `member` represents a member and `role` represents a type 6 | /// of permission. A member can have multiple permissions. 7 | #[allow(unused_type_parameter, unused_field, unused_function, unused_const)] 8 | module farming::acl { 9 | use sui::tx_context::TxContext; 10 | 11 | use move_stl::linked_table::{Self, LinkedTable}; 12 | 13 | const MAX_U128: u128 = 340282366920938463463374607431768211455; 14 | 15 | /// @dev When attempting to add/remove a role >= 128. 16 | const ERoleNumberTooLarge: u64 = 0; 17 | const EMemberNotExists: u64 = 1; 18 | 19 | /// @dev Maps addresses to `u128`s with each bit representing the presence of (or lack of) each role. 20 | struct ACL has store { 21 | _permissions: LinkedTable 22 | } 23 | 24 | struct Member has store, drop, copy { 25 | _address: address, 26 | _permission: u128 27 | } 28 | 29 | /// @notice Create a new ACL (access control list). 30 | public fun new(_ctx: &mut TxContext): ACL { 31 | ACL { _permissions: linked_table::new(_ctx) } 32 | } 33 | 34 | /// @notice Check if a member has a role in the ACL. 35 | public fun has_role(_acl: &ACL, _member: address, _role: u8): bool { 36 | abort 0 37 | } 38 | 39 | /// @notice Set all roles for a member in the ACL. 40 | /// @param _permissions Permissions for a member, represented as a `u128` with each bit representing the presence of (or lack of) each role. 41 | public fun set_roles(_acl: &mut ACL, _member: address, _permissions: u128) { 42 | abort 0 43 | } 44 | 45 | /// @notice Add a role for a member in the ACL. 46 | public fun add_role(_acl: &mut ACL, _member: address, _role: u8) { 47 | abort 0 48 | } 49 | 50 | /// @notice Revoke a role for a member in the ACL. 51 | public fun remove_role(_acl: &mut ACL, _member: address, _role: u8) { 52 | abort 0 53 | } 54 | 55 | /// Remove all roles of member. 56 | public fun remove_member(_acl: &mut ACL, _member: address) { 57 | abort 0 58 | } 59 | 60 | /// Get all members. 61 | public fun get_members(_acl: &ACL): vector { 62 | abort 0 63 | } 64 | 65 | /// Get the permission of member by address. 66 | public fun get_permission(_acl: &ACL, _address: address): u128 { 67 | abort 0 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /sui/stable_farming/sources/config.move: -------------------------------------------------------------------------------- 1 | #[allow(unused_type_parameter, unused_field, unused_const)] 2 | module farming::config { 3 | use sui::object::{ID, UID}; 4 | use sui::tx_context::TxContext; 5 | use sui::table::Table; 6 | 7 | use farming::acl; 8 | #[test_only] 9 | use sui::table; 10 | 11 | 12 | /// The acl roles of stable farming 13 | const ACL_POOL_MANAGER: u8 = 0; 14 | const ACL_REWARDER_MANAGER: u8 = 1; 15 | 16 | const VERSION: u64 = 1; 17 | 18 | // ========================= Errors ========================== 19 | const ENoPoolManagerPermission: u64 = 1; 20 | const ENoRewarderManagerPermission: u64 = 2; 21 | const EPackageVersionDeprecate: u64 = 3; 22 | 23 | // ========================= Structs ========================= 24 | /// The admin cap of stable farming module 25 | struct AdminCap has key, store { 26 | id: UID 27 | } 28 | 29 | /// The operator cap of stable farming module 30 | struct OperatorCap has key { 31 | id: UID 32 | } 33 | 34 | /// The global config of stable farming module 35 | struct GlobalConfig has key, store { 36 | id: UID, 37 | acl: acl::ACL, 38 | acceleration_factor: Table, 39 | package_version: u64 40 | } 41 | 42 | // ========================= Events =========================== 43 | /// Emit when module init 44 | struct InitConfigEvent has copy, drop { 45 | _admin_cap_id: ID, 46 | _global_config_id: ID 47 | } 48 | 49 | /// Emit when add a operator 50 | struct AddOperatorEvent has copy, drop { 51 | _operator_cap_id: ID, 52 | _recipient: address, 53 | _roles: u128 54 | } 55 | 56 | /// Emit when set roles 57 | struct SetRolesEvent has copy, drop { 58 | _member: address, 59 | _roles: u128, 60 | } 61 | 62 | /// Emit when add member a role 63 | struct AddRoleEvent has copy, drop { 64 | _member: address, 65 | _role: u8, 66 | } 67 | 68 | /// Emit when remove member a role 69 | struct RemoveRoleEvent has copy, drop { 70 | _member: address, 71 | _role: u8 72 | } 73 | 74 | /// Emit when add member 75 | struct RemoveMemberEvent has copy, drop { 76 | _member: address, 77 | } 78 | 79 | /// Emit when update package version. 80 | struct SetPackageVersion has copy, drop { 81 | _new_version: u64, 82 | _old_version: u64 83 | } 84 | 85 | #[allow(unused_function)] 86 | fun init(_ctx: &mut TxContext) { 87 | abort 0 88 | } 89 | 90 | /// Add a operator 91 | public fun add_operator( 92 | _: &AdminCap, 93 | _config: &mut GlobalConfig, 94 | _roles: u128, 95 | _recipient: address, 96 | _ctx: &mut TxContext 97 | ) { 98 | abort 0 99 | } 100 | 101 | public fun set_roles(_: &AdminCap, _config: &mut GlobalConfig, _member: address, _roles: u128) { 102 | abort 0 103 | } 104 | 105 | public fun add_role(_: &AdminCap, _config: &mut GlobalConfig, _member: address, _role: u8) { 106 | abort 0 107 | } 108 | 109 | public fun remove_role(_: &AdminCap, _config: &mut GlobalConfig, _member: address, _role: u8) { 110 | abort 0 111 | } 112 | 113 | public fun remove_member(_: &AdminCap, _config: &mut GlobalConfig, _member: address) { 114 | abort 0 115 | } 116 | 117 | public fun set_package_version(_: &AdminCap, _config: &mut GlobalConfig, _version: u64) { 118 | abort 0 119 | } 120 | 121 | public fun get_members(_config: &GlobalConfig): vector { 122 | abort 0 123 | } 124 | 125 | public fun check_pool_manager_role(_config: &GlobalConfig, _member: address) { 126 | abort 0 127 | } 128 | 129 | public fun check_rewarder_manager_role(_config: &GlobalConfig, _member: address) { 130 | abort 0 131 | } 132 | 133 | public fun checked_package_version(_config: &GlobalConfig) { 134 | abort 0 135 | } 136 | 137 | public fun package_version(): u64 { 138 | abort 0 139 | } 140 | 141 | #[test_only] 142 | use sui::object; 143 | 144 | #[test_only] 145 | public fun test_add_operator( 146 | _: &AdminCap, 147 | config: &mut GlobalConfig, 148 | roles: u128, 149 | ctx: &mut TxContext 150 | ): OperatorCap { 151 | let operator_cap = OperatorCap { 152 | id: object::new(ctx) 153 | }; 154 | let operator_cap_id = object::id(&operator_cap); 155 | 156 | acl::set_roles(&mut config.acl, object::id_to_address(&operator_cap_id), roles); 157 | operator_cap 158 | } 159 | 160 | #[test_only] 161 | public fun return_operator_cap(opcap: OperatorCap, addr: address) { 162 | sui::transfer::transfer(opcap, addr) 163 | } 164 | 165 | #[test_only] 166 | public fun new_config(ctx: &mut TxContext): (GlobalConfig, AdminCap) { 167 | let config = GlobalConfig { 168 | id: object::new(ctx), 169 | acl: acl::new(ctx), 170 | package_version: 0, 171 | acceleration_factor: table::new(ctx) 172 | }; 173 | let cap = AdminCap { 174 | id: object::new(ctx), 175 | }; 176 | (config, cap) 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /sui/stable_farming/sources/rewarder.move: -------------------------------------------------------------------------------- 1 | #[allow(unused_type_parameter, unused_field, unused_function, unused_const, unused_use)] 2 | module farming::rewarder { 3 | use std::type_name::{Self, TypeName}; 4 | use std::option; 5 | use std::vector; 6 | use sui::vec_map; 7 | 8 | use sui::object::{Self, ID, UID}; 9 | use sui::bag::{Self, Bag}; 10 | use sui::linked_table::{Self, LinkedTable}; 11 | use sui::transfer; 12 | use sui::event::{emit}; 13 | use sui::tx_context::TxContext; 14 | use sui::clock::{Self, Clock}; 15 | use sui::balance::{Self, Balance}; 16 | 17 | use integer_mate::full_math_u128; 18 | use farming::config::{Self, OperatorCap, GlobalConfig, checked_package_version, AdminCap}; 19 | friend farming::pool; 20 | 21 | const REWARD_PRECISION: u128 = 1000000000000; 22 | 23 | struct PoolRewarderInfo has store { 24 | _allocate_point: u64, 25 | _acc_per_share: u128, 26 | _last_reward_time: u64, 27 | _reward_released: u128, 28 | _reward_harvested: u64 29 | } 30 | 31 | struct Rewarder has store { 32 | _reward_coin: TypeName, 33 | _total_allocate_point: u64, 34 | _emission_per_second: u128, 35 | _last_reward_time: u64, 36 | _total_reward_released: u128, 37 | _total_reward_harvested: u64, 38 | _pools: LinkedTable 39 | } 40 | 41 | struct RewarderManager has key, store { 42 | id: UID, 43 | _vault: Bag, 44 | _pool_shares: LinkedTable, 45 | _rewarders: LinkedTable 46 | } 47 | 48 | struct InitRewarderManagerEvent has copy, drop { 49 | _id: ID, 50 | } 51 | 52 | struct CreateRewarderEvent has copy, drop { 53 | _reward_coin: TypeName, 54 | _emission_per_second: u128, 55 | } 56 | 57 | struct UpdateRewarderEvent has copy, drop { 58 | _reward_coin: TypeName, 59 | _emission_per_second: u128, 60 | } 61 | 62 | struct DepositEvent has copy, drop { 63 | _reward_type: TypeName, 64 | _deposit_amount: u64, 65 | _after_amount: u64 66 | } 67 | 68 | struct EmergentWithdrawEvent has copy, drop, store { 69 | _reward_type: TypeName, 70 | _withdraw_amount: u64, 71 | _after_amount: u64 72 | } 73 | 74 | #[allow(unused_function)] 75 | fun init(_ctx: &mut TxContext) { 76 | abort 0 77 | } 78 | 79 | public fun deposit_rewarder( 80 | _global_config: &GlobalConfig, 81 | _manager: &mut RewarderManager, 82 | _balance: Balance 83 | ) { 84 | abort 0 85 | } 86 | 87 | public fun emergent_withdraw( 88 | _: &AdminCap, 89 | _config: &GlobalConfig, 90 | _manager: &mut RewarderManager, 91 | _amount: u64 92 | ): Balance { 93 | abort 0 94 | } 95 | 96 | public fun create_rewarder( 97 | _cap: &OperatorCap, 98 | _config: &GlobalConfig, 99 | _manager: &mut RewarderManager, 100 | _emission_per_second: u128, 101 | _clock: &Clock, 102 | _ctx: &mut TxContext 103 | ) { 104 | abort 0 105 | } 106 | 107 | public(friend) fun register_pool(_manager: &mut RewarderManager, _clmm_pool_id: ID) { 108 | abort 0 109 | } 110 | 111 | public(friend) fun add_pool( 112 | _manager: &mut RewarderManager, 113 | _clmm_pool_id: ID, 114 | _allocate_point: u64, 115 | _clock: &Clock, 116 | ) { 117 | abort 0 118 | } 119 | 120 | public(friend) fun set_pool( 121 | _manager: &mut RewarderManager, 122 | _clmm_pool_id: ID, 123 | _allocate_point: u64, 124 | _clock: &Clock, 125 | ): u128 { 126 | abort 0 127 | } 128 | 129 | public(friend) fun pool_rewards_settle( 130 | _manager: &mut RewarderManager, 131 | _pool_reward_coins: vector, 132 | _clmm_pool_id: ID, 133 | _clock: &Clock, 134 | ): vec_map::VecMap { 135 | abort 0 136 | } 137 | 138 | public(friend) fun set_pool_share( 139 | _manager: &mut RewarderManager, 140 | _clmm_pool_id: ID, 141 | _pool_share: u128, 142 | ) { 143 | abort 0 144 | } 145 | 146 | public(friend) fun withdraw_reward( 147 | _manager: &mut RewarderManager, 148 | _clmm_pool_id: ID, 149 | _amount: u64, 150 | ): balance::Balance { 151 | abort 0 152 | } 153 | 154 | public fun borrow_rewarder( 155 | _manager: &RewarderManager, 156 | ): &Rewarder { 157 | abort 0 158 | } 159 | 160 | public fun borrow_pool_share(_manager: &RewarderManager, _pool: ID): u128 { 161 | abort 0 162 | } 163 | 164 | public fun borrow_pool_rewarder_info( 165 | _rewarder: &Rewarder, 166 | _clmm_pool_id: ID 167 | ): &PoolRewarderInfo { 168 | abort 0 169 | } 170 | 171 | public fun borrow_pool_allocate_point(_manager: &RewarderManager, _reward_coin: TypeName, _clmm_pool_id: ID): u64 { 172 | abort 0 173 | } 174 | 175 | public fun pool_share( 176 | _manager: &RewarderManager, 177 | _clmm_pool_id: ID 178 | ): u128 { 179 | abort 0 180 | } 181 | 182 | public fun emission_per_second(_rewarder: &Rewarder): u128 { 183 | abort 0 184 | } 185 | 186 | public fun vault_balance(_manager: &RewarderManager): u64 { 187 | abort 0 188 | } 189 | 190 | public fun total_allocate_point(_r: &Rewarder): u64 { 191 | abort 0 192 | } 193 | 194 | public fun last_reward_time(_m: &Rewarder): u64 { 195 | abort 0 196 | } 197 | 198 | public fun total_reward_released(_m: &Rewarder): u128 { 199 | abort 0 200 | } 201 | 202 | public fun total_reward_harvested(_m: &Rewarder): u64 { 203 | abort 0 204 | } 205 | 206 | public fun pool_last_reward_time(_p: &PoolRewarderInfo): u64 { 207 | abort 0 208 | } 209 | 210 | public fun pool_allocate_point(_p: &PoolRewarderInfo): u64 { 211 | abort 0 212 | } 213 | 214 | public fun pool_acc_per_share(_p: &PoolRewarderInfo): u128 { 215 | abort 0 216 | } 217 | 218 | public fun pool_reward_released(_p: &PoolRewarderInfo): u128 { 219 | abort 0 220 | } 221 | 222 | public fun pool_reward_harvested(_p: &PoolRewarderInfo): u64 { 223 | abort 0 224 | } 225 | 226 | fun is_pool_registered(_manager: &RewarderManager, _clmm_pool_id: ID): bool { 227 | abort 0 228 | } 229 | 230 | fun accumulate_rewarder_released( 231 | _rewarder: &mut Rewarder, 232 | _current_ts: u64 233 | ) { 234 | abort 0 235 | } 236 | 237 | fun accumulate_pools_reward( 238 | _manager: &mut RewarderManager, 239 | _current_ts: u64, 240 | ) { 241 | abort 0 242 | } 243 | 244 | fun accumulate_pool_reward( 245 | _rewarder: &mut Rewarder, 246 | _clmm_pool_id: ID, 247 | _pool_share: u128, 248 | _current_ts: u64, 249 | ): u128 { 250 | abort 0 251 | } 252 | 253 | fun is_pool_in_rewarder( 254 | _manager: &RewarderManager, 255 | _reward_coin: TypeName, 256 | _clmm_pool_id: ID 257 | ): bool { 258 | abort 0 259 | } 260 | 261 | #[test_only] 262 | public fun new_manager_for_test(_ctx: &mut TxContext): RewarderManager { 263 | abort 0 264 | } 265 | 266 | #[test_only] 267 | public fun register_pool_for_test(_manager: &mut RewarderManager, _clmm_pool_id: ID) { 268 | abort 0 269 | } 270 | 271 | #[test_only] 272 | public fun add_pool_for_test( 273 | _manager: &mut RewarderManager, 274 | _clmm_pool_id: ID, 275 | _allocate_point: u64, 276 | _clock: &Clock, 277 | ) { 278 | abort 0 279 | } 280 | 281 | #[test_only] 282 | public fun set_pool_for_test( 283 | _manager: &mut RewarderManager, 284 | _clmm_pool_id: ID, 285 | _allocate_point: u64, 286 | _clock: &Clock, 287 | ) { 288 | abort 0 289 | } 290 | 291 | #[test_only] 292 | public fun destory_rewarder_for_test( 293 | _rewarder: Rewarder 294 | ) { 295 | abort 0 296 | } 297 | 298 | #[test_only] 299 | public fun update_pool_share_for_test( 300 | _manager: &mut RewarderManager, 301 | _reward_coins: vector, 302 | _clmm_pool_id: ID, 303 | _pool_share: u128, 304 | _clock: &Clock, 305 | ): vec_map::VecMap { 306 | abort 0 307 | } 308 | 309 | #[test_only] 310 | public fun withdraw_reward_for_test( 311 | _manager: &mut RewarderManager, 312 | _clmm_pool_id: ID, 313 | _amount: u64, 314 | ): balance::Balance { 315 | abort 0 316 | } 317 | 318 | #[test_only] 319 | struct RewardCoinA {} 320 | 321 | #[test_only] 322 | public fun add_pool_to_rewarder_for_test( 323 | _rewarder: &mut Rewarder, 324 | _pool_id: ID, 325 | _allocate_point: u64, 326 | _clk: &Clock 327 | ) { 328 | abort 0 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /sui/stable_farming/sources/router.move: -------------------------------------------------------------------------------- 1 | #[allow(unused_type_parameter, unused_field, unused_function, unused_const, unused_use)] 2 | module farming::router { 3 | use sui::clock::Clock; 4 | use sui::tx_context::{Self, TxContext}; 5 | use sui::coin; 6 | use sui::coin::Coin; 7 | use sui::object::ID; 8 | use sui::transfer; 9 | use std::vector; 10 | use sui::pay; 11 | 12 | use cetusclmm::position::{Position as CLMMPosition}; 13 | use cetusclmm::pool::{Pool as CLMMPool}; 14 | use cetusclmm::config::{GlobalConfig as CLMMGlobalConfig}; 15 | use cetusclmm::rewarder::RewarderGlobalVault; 16 | use integer_mate::i32; 17 | 18 | use farming::rewarder::{Self, RewarderManager}; 19 | use farming::pool::{Self, Pool, WrappedPositionNFT}; 20 | use farming::config::{Self, AdminCap, GlobalConfig, OperatorCap}; 21 | 22 | public entry fun set_roles(_cap: &AdminCap, _config: &mut GlobalConfig, _member: address, _roles: u128) { 23 | abort 0 24 | } 25 | 26 | public entry fun add_role(_cap: &AdminCap, _config: &mut GlobalConfig, _member: address, _role: u8) { 27 | abort 0 28 | } 29 | 30 | public entry fun remove_role(_cap: &AdminCap, _config: &mut GlobalConfig, _member: address, _role: u8) { 31 | abort 0 32 | } 33 | 34 | public entry fun add_operator( 35 | _cap: &AdminCap, 36 | _config: &mut GlobalConfig, 37 | _roles: u128, 38 | _recipient: address, 39 | _ctx: &mut TxContext 40 | ) { 41 | abort 0 42 | } 43 | 44 | #[lint_allow(self_transfer)] 45 | public entry fun deposit_rewarder( 46 | _config: &GlobalConfig, 47 | _manager: &mut RewarderManager, 48 | _coins: vector>, 49 | _amount: u64, 50 | _ctx: &mut TxContext 51 | ) { 52 | abort 0 53 | } 54 | 55 | #[lint_allow(self_transfer)] 56 | public entry fun emergent_withdraw( 57 | _cap: &AdminCap, 58 | _config: &GlobalConfig, 59 | _manager: &mut RewarderManager, 60 | _amount: u64, 61 | _ctx: &mut TxContext, 62 | ) { 63 | abort 0 64 | } 65 | 66 | public entry fun create_rewarder( 67 | _cap: &OperatorCap, 68 | _config: &GlobalConfig, 69 | _manager: &mut RewarderManager, 70 | _emission_per_second: u128, 71 | _clock: &Clock, 72 | _ctx: &mut TxContext 73 | ) { 74 | abort 0 75 | } 76 | 77 | public entry fun update_rewarder( 78 | _cap: &OperatorCap, 79 | _config: &GlobalConfig, 80 | _manager: &mut RewarderManager, 81 | _emission_per_second: u128, 82 | _clock: &Clock, 83 | ) { 84 | abort 0 85 | } 86 | 87 | public entry fun create_pool( 88 | _cap: &OperatorCap, 89 | _global_config: &GlobalConfig, 90 | _rewarder_manager: &mut RewarderManager, 91 | _clmm_pool: &CLMMPool, 92 | _effective_tick_lower: u32, 93 | _effective_tick_upper: u32, 94 | _sqrt_price: u128, 95 | _ctx: &mut TxContext 96 | ) { 97 | abort 0 98 | } 99 | 100 | public entry fun update_effective_tick_range( 101 | _cap: &OperatorCap, 102 | _global_config: &GlobalConfig, 103 | _rewarder_manager: &mut RewarderManager, 104 | _pool: &mut Pool, 105 | _clmm_pool: &CLMMPool, 106 | _effective_tick_lower: u32, 107 | _effective_tick_upper: u32, 108 | _sqrt_price: u128, 109 | _start: vector, 110 | _limit: u64, 111 | _clk: &Clock 112 | ) { 113 | abort 0 114 | } 115 | 116 | public entry fun add_rewarder( 117 | _cap: &OperatorCap, 118 | _global_config: &GlobalConfig, 119 | _rewarder_manager: &mut RewarderManager, 120 | _pool: &mut Pool, 121 | _allocate_point: u64, 122 | _clk: &Clock, 123 | ) { 124 | abort 0 125 | } 126 | 127 | public entry fun update_pool_allocate_point( 128 | _cap: &OperatorCap, 129 | _global_config: &GlobalConfig, 130 | _rewarder_manager: &mut RewarderManager, 131 | _pool: &Pool, 132 | _allocate_point: u64, 133 | _clock: &Clock, 134 | ) { 135 | abort 0 136 | } 137 | 138 | #[lint_allow(self_transfer)] 139 | public entry fun deposit( 140 | _global_config: &GlobalConfig, 141 | _rewarder_manager: &mut RewarderManager, 142 | _pool: &mut Pool, 143 | _clmm_position: CLMMPosition, 144 | _clk: &Clock, 145 | _ctx: &mut TxContext 146 | ) { 147 | abort 0 148 | } 149 | 150 | #[lint_allow(self_transfer)] 151 | public entry fun withdraw( 152 | _global_config: &GlobalConfig, 153 | _rewarder_manager: &mut RewarderManager, 154 | _pool: &mut Pool, 155 | _wrapped_position: WrappedPositionNFT, 156 | _clk: &Clock, 157 | _ctx: &TxContext 158 | ) { 159 | abort 0 160 | } 161 | 162 | #[lint_allow(self_transfer)] 163 | public entry fun harvest( 164 | _global_config: &GlobalConfig, 165 | _rewarder_manager: &mut RewarderManager, 166 | _pool: &mut Pool, 167 | _wrapped_position: &WrappedPositionNFT, 168 | _clk: &Clock, 169 | _ctx: &mut TxContext 170 | ) { 171 | abort 0 172 | } 173 | 174 | public fun accumulated_position_rewards( 175 | _global_config: &GlobalConfig, 176 | _rewarder_manager: &mut RewarderManager, 177 | _pool: &mut Pool, 178 | _wrapped_position_id: ID, 179 | _clk: &Clock, 180 | ) { 181 | abort 0 182 | } 183 | 184 | public entry fun add_liquidity( 185 | _global_config: &GlobalConfig, 186 | _clmm_global_config: &CLMMGlobalConfig, 187 | _rewarder_manager: &mut RewarderManager, 188 | _pool: &mut Pool, 189 | _clmm_pool: &mut CLMMPool, 190 | _wrapped_position: &mut WrappedPositionNFT, 191 | _coin_a: Coin, 192 | _coin_b: Coin, 193 | _amount_limit_a: u64, 194 | _amount_limit_b: u64, 195 | _delta_liquidity: u128, 196 | _clk: &Clock, 197 | _ctx: &mut TxContext, 198 | ) { 199 | abort 0 200 | } 201 | 202 | public entry fun add_liquidity_fix_coin( 203 | _global_config: &GlobalConfig, 204 | _clmm_global_config: &CLMMGlobalConfig, 205 | _rewarder_manager: &mut RewarderManager, 206 | _pool: &mut Pool, 207 | _clmm_pool: &mut CLMMPool, 208 | _wrapped_position: &mut WrappedPositionNFT, 209 | _coin_a: Coin, 210 | _coin_b: Coin, 211 | _amount_a: u64, 212 | _amount_b: u64, 213 | _fix_amount_a: bool, 214 | _clk: &Clock, 215 | _ctx: &mut TxContext 216 | ) { 217 | abort 0 218 | } 219 | 220 | public entry fun remove_liquidity( 221 | _global_config: &GlobalConfig, 222 | _clmm_global_config: &CLMMGlobalConfig, 223 | _rewarder_manager: &mut RewarderManager, 224 | _pool: &mut Pool, 225 | _clmm_pool: &mut CLMMPool, 226 | _wrapped_position: &mut WrappedPositionNFT, 227 | _delta_liquidity: u128, 228 | _min_amount_a: u64, 229 | _min_amount_b: u64, 230 | _clk: &Clock, 231 | _ctx: &mut TxContext 232 | ) { 233 | abort 0 234 | } 235 | 236 | public entry fun collect_fee( 237 | _global_config: &GlobalConfig, 238 | _clmm_global_config: &CLMMGlobalConfig, 239 | _clmm_pool: &mut CLMMPool, 240 | _wrapped_position: &WrappedPositionNFT, 241 | _ctx: &mut TxContext 242 | ) { 243 | abort 0 244 | } 245 | 246 | public entry fun collect_clmm_reward( 247 | _global_config: &GlobalConfig, 248 | _clmm_global_config: &CLMMGlobalConfig, 249 | _clmm_pool: &mut CLMMPool, 250 | _warped_position: &WrappedPositionNFT, 251 | _vault: &mut RewarderGlobalVault, 252 | _reward_coin: Coin, 253 | _clock: &Clock, 254 | _ctx: &mut TxContext 255 | ) { 256 | abort 0 257 | } 258 | 259 | public fun close_position( 260 | _global_config: &GlobalConfig, 261 | _rewarder_manager: &mut RewarderManager, 262 | _pool: &mut Pool, 263 | _clmm_global_config: &CLMMGlobalConfig, 264 | _clmm_pool: &mut CLMMPool, 265 | _wrapped_position: WrappedPositionNFT, 266 | _min_amount_a: u64, 267 | _min_amount_b: u64, 268 | _clk: &Clock, 269 | _ctx: &mut TxContext 270 | ) { 271 | abort 0 272 | } 273 | 274 | public fun send_coin( 275 | _coin: Coin, 276 | _recipient: address 277 | ) { 278 | abort 0 279 | } 280 | 281 | public fun merge_coins(_coins: vector>, _ctx: &mut TxContext): Coin { 282 | abort 0 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /sui/token/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | */sui.log* 3 | */build/* 4 | sui.log* 5 | -------------------------------------------------------------------------------- /sui/token/README.md: -------------------------------------------------------------------------------- 1 | # Cetus Token Interface 2 | 3 | Cetus, xCetus, Dividends 4 | 5 | ## Concepts 6 | 7 | CETUS is the main token of the Cetus Protocol, while xCETUS is the Cetus escrowed token to unlock more utilities such as staking, governance, etc. CETUS can be converted into xCETUS instantly at any time, while xCETUS can be redeemed back to CETUS upon a vesting period. A different redemption ratio will be applied depending on the actual vesting duration selected. 8 | 9 | Details: https://cetus-1.gitbook.io/cetus-docs/tokenomics/cetus 10 | 11 | Dividends is the protocol to manage bonus about xcetus. User can use redeem_v2 to collect multi bonus. 12 | 13 | ### VeNFT 14 | 15 | VeNFT is used for holding the xCetus. 16 | 17 | ## Tags corresponding to different networks 18 | 19 | 1. XCetus 20 | 21 | | Tag of Repo | Network | Latest published at address | 22 | | --------------- | ------- | ------------------------------------------------------------------ | 23 | | mainnet-v1.24.0 | mainnet | 0x9e69acc50ca03bc943c4f7c5304c2a6002d507b51c11913b247159c60422c606 | 24 | | testnet-v1.24.0 | testnet | 0xdebaab6b851fd3414c0a62dbdf8eb752d6b0d31f5cfce5e38541bc6c6daa8966 | 25 | 26 | eg: 27 | 28 | mainnet: 29 | 30 | ``` 31 | xcetus = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/token/xcetus", rev = "mainnet-v1.24.0" } 32 | ``` 33 | 34 | testnet: 35 | 36 | ``` 37 | xcetus = { git = "https://github.com/CetusProtocol/cetus-token-interface.git", subdir = "sui/token/xcetus", rev = "testnet-v1.24.0" } 38 | ``` 39 | 40 | 2. Dividend 41 | 42 | | Tag of Repo | Network | Latest published at address | 43 | | --------------- | ------- | ------------------------------------------------------------------ | 44 | | mainnet-v1.24.0 | mainnet | 0xcec352932edc6663a118e8d64ed54da6b8107e8719603bf728f80717592cd9e8 | 45 | | testnet-v1.24.0 | testnet | 0x20d948d640edd0c749f533d41efc5f843f212d441220324ad7959c6e1d281828 | 46 | 47 | eg: 48 | 49 | mainnet: 50 | 51 | ``` 52 | dividend = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/token/dividend", rev = "mainnet-v1.24.0" } 53 | ``` 54 | 55 | testnet: 56 | 57 | ``` 58 | dividend = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/token/dividend", rev = "testnet-v1.24.0" } 59 | ``` 60 | -------------------------------------------------------------------------------- /sui/token/cetus/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "25A4E3A44F7ECF419FA4A74169B9D7F66D4DBD531704F52EE9F631276BCFFDFC" 6 | deps_digest = "F9B494B64F0615AED0E98FC12A85B85ECD2BC5185C22D30E7F67786BB52E507C" 7 | dependencies = [ 8 | { id = "Bridge", name = "Bridge" }, 9 | { id = "MoveStdlib", name = "MoveStdlib" }, 10 | { id = "Sui", name = "Sui" }, 11 | { id = "SuiSystem", name = "SuiSystem" }, 12 | ] 13 | 14 | [[move.package]] 15 | id = "Bridge" 16 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/bridge" } 17 | 18 | dependencies = [ 19 | { id = "MoveStdlib", name = "MoveStdlib" }, 20 | { id = "Sui", name = "Sui" }, 21 | { id = "SuiSystem", name = "SuiSystem" }, 22 | ] 23 | 24 | [[move.package]] 25 | id = "MoveStdlib" 26 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/move-stdlib" } 27 | 28 | [[move.package]] 29 | id = "Sui" 30 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-framework" } 31 | 32 | dependencies = [ 33 | { id = "MoveStdlib", name = "MoveStdlib" }, 34 | ] 35 | 36 | [[move.package]] 37 | id = "SuiSystem" 38 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-system" } 39 | 40 | dependencies = [ 41 | { id = "MoveStdlib", name = "MoveStdlib" }, 42 | { id = "Sui", name = "Sui" }, 43 | ] 44 | 45 | [move.toolchain-version] 46 | compiler-version = "1.48.2" 47 | edition = "2024" 48 | flavor = "sui" 49 | 50 | [env] 51 | 52 | [env.mainnet] 53 | chain-id = "35834a8a" 54 | original-published-id = "0x06864a6f921804860930db6ddbe2e16acdf8504495ea7481637a1c8b9a8fe54b" 55 | latest-published-id = "0x06864a6f921804860930db6ddbe2e16acdf8504495ea7481637a1c8b9a8fe54b" 56 | published-version = "1" 57 | -------------------------------------------------------------------------------- /sui/token/cetus/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Cetus" 3 | version = "1.0.0" 4 | 5 | [dependencies] 6 | 7 | [addresses] 8 | cetus = "0x6864a6f921804860930db6ddbe2e16acdf8504495ea7481637a1c8b9a8fe54b" 9 | -------------------------------------------------------------------------------- /sui/token/cetus/sources/cetus.move: -------------------------------------------------------------------------------- 1 | module cetus::cetus { 2 | use sui::tx_context::TxContext; 3 | use sui::object::ID; 4 | 5 | struct CETUS has drop {} 6 | 7 | #[allow(unused_field)] 8 | struct InitEvent has copy, drop { 9 | cap_id: ID, 10 | metadata_id: ID, 11 | } 12 | 13 | fun init(_witness: CETUS, _ctx: &mut TxContext) { 14 | abort 0 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sui/token/dividends/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "CD724DEE539C6CCBBCF9E502C2DF3B7263A817071092E1B6BB8E0E3E4831E3B9" 6 | deps_digest = "52B406A7A21811BEF51751CF88DA0E76DAEFFEAC888D4F4060B1A72BBE7D8D35" 7 | dependencies = [ 8 | { id = "Bridge", name = "Bridge" }, 9 | { id = "MoveSTL", name = "MoveSTL" }, 10 | { id = "MoveStdlib", name = "MoveStdlib" }, 11 | { id = "Sui", name = "Sui" }, 12 | { id = "SuiSystem", name = "SuiSystem" }, 13 | { id = "Xcetus", name = "Xcetus" }, 14 | ] 15 | 16 | [[move.package]] 17 | id = "Bridge" 18 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/bridge" } 19 | 20 | dependencies = [ 21 | { id = "MoveStdlib", name = "MoveStdlib" }, 22 | { id = "Sui", name = "Sui" }, 23 | { id = "SuiSystem", name = "SuiSystem" }, 24 | ] 25 | 26 | [[move.package]] 27 | id = "Cetus" 28 | source = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", rev = "mainnet-v1.48.2", subdir = "sui/token/cetus" } 29 | 30 | dependencies = [ 31 | { id = "Bridge", name = "Bridge" }, 32 | { id = "MoveStdlib", name = "MoveStdlib" }, 33 | { id = "Sui", name = "Sui" }, 34 | { id = "SuiSystem", name = "SuiSystem" }, 35 | ] 36 | 37 | [[move.package]] 38 | id = "MoveSTL" 39 | source = { git = "https://github.com/CetusProtocol/move-stl.git", rev = "mainnet-v1.48.2", subdir = "sui" } 40 | 41 | dependencies = [ 42 | { id = "Bridge", name = "Bridge" }, 43 | { id = "MoveStdlib", name = "MoveStdlib" }, 44 | { id = "Sui", name = "Sui" }, 45 | { id = "SuiSystem", name = "SuiSystem" }, 46 | ] 47 | 48 | [[move.package]] 49 | id = "MoveStdlib" 50 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/move-stdlib" } 51 | 52 | [[move.package]] 53 | id = "Sui" 54 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-framework" } 55 | 56 | dependencies = [ 57 | { id = "MoveStdlib", name = "MoveStdlib" }, 58 | ] 59 | 60 | [[move.package]] 61 | id = "SuiSystem" 62 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-system" } 63 | 64 | dependencies = [ 65 | { id = "MoveStdlib", name = "MoveStdlib" }, 66 | { id = "Sui", name = "Sui" }, 67 | ] 68 | 69 | [[move.package]] 70 | id = "Xcetus" 71 | source = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", rev = "mainnet-v1.48.2", subdir = "sui/token/xcetus/" } 72 | 73 | dependencies = [ 74 | { id = "Bridge", name = "Bridge" }, 75 | { id = "Cetus", name = "Cetus" }, 76 | { id = "MoveSTL", name = "MoveSTL" }, 77 | { id = "MoveStdlib", name = "MoveStdlib" }, 78 | { id = "Sui", name = "Sui" }, 79 | { id = "SuiSystem", name = "SuiSystem" }, 80 | ] 81 | 82 | [move.toolchain-version] 83 | compiler-version = "1.48.2" 84 | edition = "2024" 85 | flavor = "sui" 86 | 87 | [env] 88 | 89 | [env.mainnet] 90 | chain-id = "35834a8a" 91 | original-published-id = "0x785248249ac457dfd378bdc6d2fbbfec9d1daf65e9d728b820eb4888c8da2c10" 92 | latest-published-id = "0x5aa58e1623885bd93de2331d05c29bf4930e54e56beeabcab8fe5385de2d31dc" 93 | published-version = "4" 94 | -------------------------------------------------------------------------------- /sui/token/dividends/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Dividends" 3 | version = "1.0.3" 4 | 5 | [dependencies] 6 | MoveSTL = { git = "https://github.com/CetusProtocol/move-stl.git", subdir = "sui", rev = "mainnet-v1.48.2", override = true } 7 | xcetus = { r.mvr = "@cetuspackages/xcetus" } 8 | 9 | 10 | [addresses] 11 | dividends = "0x785248249ac457dfd378bdc6d2fbbfec9d1daf65e9d728b820eb4888c8da2c10" 12 | 13 | [r.mvr] 14 | network = "mainnet" 15 | -------------------------------------------------------------------------------- /sui/token/dividends/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | 1. Support multi bonus type. 4 | 2. Support different bonus type in every phase. 5 | 6 | ## Operations 7 | 8 | 1. Initialize `DividendManager` 9 | 2. Add bonus 10 | 3. Transfer Coin 11 | 4. Register bonus every phase. 12 | 5. Settle bonus every phase. -------------------------------------------------------------------------------- /sui/token/dividends/sources/dividend.move: -------------------------------------------------------------------------------- 1 | #[allow(unused_type_parameter, unused_field, unused_const, unused_use)] 2 | // This module is designed to dividend the bonus to venfts who hold the xCETUS. 3 | module dividends::dividend { 4 | use std::type_name::TypeName; 5 | use move_stl::linked_table; 6 | use sui::object::{UID, ID}; 7 | use sui::clock::Clock; 8 | use sui::tx_context::TxContext; 9 | use sui::bag::Bag; 10 | use sui::vec_map::VecMap; 11 | use sui::table::Table; 12 | use sui::vec_map; 13 | use xcetus::xcetus::VeNFT; 14 | 15 | 16 | const ONE_DAY_SECONDS: u64 = 24 * 3600; 17 | 18 | const EBONUS_TYPE_NOT_EXISTS: u64 = 0; 19 | const EALREADY_SETTLED: u64 = 1; 20 | const ELAST_PHASE_NOT_FINISH: u64 = 2; 21 | const EBONUS_TYPE_NOT_SUPPORT: u64 = 3; 22 | const EDIVIDEND_IS_CLOSE: u64 = 4; 23 | const EPHASE_NOT_REGISTERED: u64 = 5; 24 | const ESTART_ERROR: u64 = 6; 25 | const EPACKAGE_VERSION_DEPRECATE: u64 = 7; 26 | #[allow(unused_const)] 27 | const EVENFT_HAS_NO_DIVIDEND: u64 = 8; 28 | const EBALANCE_NOT_ENOUGH: u64 = 9; 29 | #[allow(unused_const)] 30 | const ESTART_TIME_ERROR: u64 = 10; 31 | const EBONUS_TYPE_EXISTS: u64 = 11; 32 | const EAMOUNT_NOT_CHANGE: u64 = 12; 33 | const EAMOUNT_NOT_ENOUGH: u64 = 13; 34 | const EMETHOD_DEPRECATED: u64 = 14; 35 | const EBONUS_IS_ZERO: u64 = 15; 36 | const EREGISTER_ALREADY: u64 = 16; 37 | 38 | /// 39 | struct AdminCap has key, store { 40 | id: UID 41 | } 42 | 43 | /// used for settle 44 | struct SettleCap has key, store { 45 | id: UID 46 | } 47 | 48 | /// DividendManager(only one instance) 49 | struct DividendManager has key { 50 | id: UID, 51 | /// Dividend info of every phase. 52 | dividends: linked_table::LinkedTable, 53 | /// Dividend info of every venft. 54 | venft_dividends: linked_table::LinkedTable, 55 | /// Current bonus type supported. 56 | bonus_types: vector, 57 | /// init time 58 | start_time: u64, 59 | /// interval day between each settlement phase 60 | interval_day: u8, 61 | /// hold the bonus of different types. 62 | balances: Bag, 63 | /// status 64 | is_open: bool, 65 | package_version: u64 66 | } 67 | 68 | struct VeNFTDividends has key { 69 | id: UID, 70 | venft_dividends: linked_table::LinkedTable 71 | } 72 | 73 | struct VeNFTDividendInfoV2 has store { 74 | /// bonus of every type of every phase. When the bonus is claimed, the record will remove from the vec_map. 75 | dividends: Table> 76 | } 77 | 78 | /// Record the dividend infos of a VeNFT 79 | struct VeNFTDividendInfo has store, drop { 80 | /// bonus of every type of every phase. When the bonus is claimed, the record will remove from the vec_map. 81 | dividends: vec_map::VecMap> 82 | } 83 | 84 | 85 | /// Global Dividend info. 86 | struct DividendInfo has store, drop { 87 | /// register time 88 | register_time: u64, 89 | // 90 | settled_num: u64, 91 | // is_settle 92 | is_settled: bool, 93 | /// bonus types of this phase 94 | bonus_types: vector, 95 | /// total bonus of this phase 96 | bonus: VecMap, 97 | // bonus redeemed of this phase 98 | redeemed_num: VecMap, 99 | } 100 | 101 | /// Events 102 | struct RedeemEvent has copy, drop, store { 103 | venft_id: ID, 104 | phases: vector, 105 | redeemed_nums: vec_map::VecMap, 106 | amount: u64 107 | } 108 | 109 | struct RedeemV2Event has copy, drop, store { 110 | venft_id: ID, 111 | type: TypeName, 112 | amount: u64 113 | } 114 | 115 | struct RedeemV3Event has copy, drop, store { 116 | venft_id: ID, 117 | type: TypeName, 118 | amount: u64 119 | } 120 | 121 | struct RedeemAllEvent has copy, drop, store { 122 | receiver: address, 123 | amount: u64 124 | } 125 | 126 | struct DividendInfoEvent has copy, drop, store { 127 | info: vec_map::VecMap> 128 | } 129 | 130 | public fun redeem_v2( 131 | _: &mut DividendManager, 132 | _: &mut VeNFT, 133 | _: &Clock, 134 | _: &mut TxContext 135 | ) { 136 | abort 0 137 | } 138 | 139 | public fun redeem_v3( 140 | _: &mut DividendManager, 141 | _: &mut VeNFTDividends, 142 | _: vector, 143 | _: &mut VeNFT, 144 | _: &Clock, 145 | _: &mut TxContext 146 | ) { 147 | abort 0 148 | } 149 | 150 | public fun fetch_dividend_info(_: &DividendManager, _: ID) { 151 | abort 0 152 | } 153 | 154 | public fun fetch_dividend_info_v2(_: &DividendManager, _: &VeNFTDividends, _: ID) { 155 | abort 0 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /sui/token/dividends/sources/router.move: -------------------------------------------------------------------------------- 1 | #[allow(unused_type_parameter, unused_field, unused_const, unused_use)] 2 | module dividends::router { 3 | 4 | use xcetus::locking::LockUpManager; 5 | use dividends::dividend::{DividendManager, VeNFTDividends}; 6 | use sui::tx_context::TxContext; 7 | use xcetus::xcetus::{XcetusManager, VeNFT}; 8 | use sui::clock::Clock; 9 | use sui::object::ID; 10 | 11 | /// Redeem 12 | /// args 13 | /// -`DividendManager` 14 | /// - Venft 15 | public entry fun redeem( 16 | _: &mut DividendManager, 17 | _: &mut VeNFT, 18 | _: &mut TxContext 19 | ) { 20 | abort 1 21 | } 22 | 23 | /// RedeemV2 24 | /// args 25 | /// -`DividendManager` 26 | /// - Venft 27 | public entry fun redeem_v2( 28 | _: &mut DividendManager, 29 | _: &mut VeNFT, 30 | _: &Clock, 31 | _: &mut TxContext 32 | ) { 33 | abort 1 34 | } 35 | 36 | /// RedeemV3 37 | public entry fun redeem_v3( 38 | _: &mut DividendManager, 39 | _: &mut VeNFTDividends, 40 | _: vector, 41 | _: &mut VeNFT, 42 | _: &Clock, 43 | _: &mut TxContext 44 | ) 45 | { 46 | abort 1 47 | } 48 | 49 | public entry fun fetch_dividend_info(_: &DividendManager, _: ID) { 50 | abort 1 51 | } 52 | 53 | public entry fun fetch_dividend_info_v2(_: &DividendManager, _: &VeNFTDividends, _: ID) { 54 | abort 1 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /sui/token/xcetus/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "D1E4C09610F24C289D2349608013D260C9765CACF9810143C845C2704B71EB0F" 6 | deps_digest = "52B406A7A21811BEF51751CF88DA0E76DAEFFEAC888D4F4060B1A72BBE7D8D35" 7 | dependencies = [ 8 | { id = "Bridge", name = "Bridge" }, 9 | { id = "Cetus", name = "Cetus" }, 10 | { id = "MoveSTL", name = "MoveSTL" }, 11 | { id = "MoveStdlib", name = "MoveStdlib" }, 12 | { id = "Sui", name = "Sui" }, 13 | { id = "SuiSystem", name = "SuiSystem" }, 14 | ] 15 | 16 | [[move.package]] 17 | id = "Bridge" 18 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/bridge" } 19 | 20 | dependencies = [ 21 | { id = "MoveStdlib", name = "MoveStdlib" }, 22 | { id = "Sui", name = "Sui" }, 23 | { id = "SuiSystem", name = "SuiSystem" }, 24 | ] 25 | 26 | [[move.package]] 27 | id = "Cetus" 28 | source = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", rev = "mainnet-v1.48.2", subdir = "sui/token/cetus" } 29 | 30 | dependencies = [ 31 | { id = "Bridge", name = "Bridge" }, 32 | { id = "MoveStdlib", name = "MoveStdlib" }, 33 | { id = "Sui", name = "Sui" }, 34 | { id = "SuiSystem", name = "SuiSystem" }, 35 | ] 36 | 37 | [[move.package]] 38 | id = "MoveSTL" 39 | source = { git = "https://github.com/CetusProtocol/move-stl.git", rev = "mainnet-v1.48.2", subdir = "sui" } 40 | 41 | dependencies = [ 42 | { id = "Bridge", name = "Bridge" }, 43 | { id = "MoveStdlib", name = "MoveStdlib" }, 44 | { id = "Sui", name = "Sui" }, 45 | { id = "SuiSystem", name = "SuiSystem" }, 46 | ] 47 | 48 | [[move.package]] 49 | id = "MoveStdlib" 50 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/move-stdlib" } 51 | 52 | [[move.package]] 53 | id = "Sui" 54 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-framework" } 55 | 56 | dependencies = [ 57 | { id = "MoveStdlib", name = "MoveStdlib" }, 58 | ] 59 | 60 | [[move.package]] 61 | id = "SuiSystem" 62 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-system" } 63 | 64 | dependencies = [ 65 | { id = "MoveStdlib", name = "MoveStdlib" }, 66 | { id = "Sui", name = "Sui" }, 67 | ] 68 | 69 | [move.toolchain-version] 70 | compiler-version = "1.48.2" 71 | edition = "2024" 72 | flavor = "sui" 73 | 74 | [env] 75 | 76 | [env.mainnet] 77 | chain-id = "35834a8a" 78 | original-published-id = "0x9e69acc50ca03bc943c4f7c5304c2a6002d507b51c11913b247159c60422c606" 79 | latest-published-id = "0x07d45ee8fc56ddce3232304c1191f3c0319fa8240305c5ee2231a2da7cbb49e6" 80 | published-version = "2" 81 | -------------------------------------------------------------------------------- /sui/token/xcetus/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Xcetus" 3 | version = "1.0.0" 4 | 5 | [dependencies] 6 | MoveSTL = { git = "https://github.com/CetusProtocol/move-stl.git", subdir = "sui", rev = "mainnet-v1.48.2", override = true } 7 | Cetus = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/token/cetus", rev = "mainnet-v1.48.2" } 8 | 9 | [addresses] 10 | xcetus = "0x9e69acc50ca03bc943c4f7c5304c2a6002d507b51c11913b247159c60422c606" 11 | -------------------------------------------------------------------------------- /sui/token/xcetus/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## operations 3 | 4 | > Step 1. initialize the LockManager. 5 | 6 | 7 | `initialize` function: 8 | 9 | ``` 10 | public entry fun initialize( 11 | cap: &AdminCap, 12 | min_lock_day: u64, 13 | max_lock_day: u64, 14 | min_percent_numerator: u64, 15 | max_percent_numerator: u64, 16 | ctx: &mut TxContext 17 | ) 18 | ``` 19 | 20 | -------------------------------------------------------------------------------- /sui/token/xcetus/sources/lock_coin.move: -------------------------------------------------------------------------------- 1 | #[allow(unused_type_parameter, unused_field)] 2 | // This module is used for locking coin in `LockedCoin` object which cannot be transferred. 3 | // When the lock time ends, the user can unwrap the `Balance` from `LockedCoin`. 4 | module xcetus::lock_coin { 5 | use std::type_name::TypeName; 6 | 7 | use sui::object::{UID, ID}; 8 | use sui::balance::Balance; 9 | use sui::tx_context::TxContext; 10 | use sui::coin::Coin; 11 | use sui::clock::Clock; 12 | 13 | /// A coin of type `T` locked until `timestamp`. 14 | struct LockedCoin has key { 15 | id: UID, 16 | balance: Balance, 17 | locked_start_time: u64, 18 | locked_until_time: u64 19 | } 20 | 21 | /// Events 22 | struct LockCoinEvent has copy, drop { 23 | type: TypeName, 24 | amount: u64, 25 | recipient: address, 26 | locked_until_time: u64, 27 | } 28 | 29 | struct UnlockCoinEvent has copy, drop { 30 | type: TypeName, 31 | amount: u64, 32 | locked_coin: ID, 33 | locked_until_time: u64, 34 | } 35 | 36 | /// Lock a coin up until `locked_until_time`. The input Coin is wrapped and a LockedCoin 37 | /// is transferred to the `recipient`. This function aborts if the `locked_until_time` is less than 38 | /// or equal to the current timestamp. 39 | public fun lock_coin( 40 | _: Coin, 41 | _: u64, 42 | _: u64, 43 | _: address, 44 | _: &mut TxContext 45 | ): ID { 46 | abort 0 47 | } 48 | 49 | /// Unlock a locked coin. The function aborts if the current timestamp is less than the `locked_until_time` 50 | /// of the coin. If the check is successful, the `LockedCoin` object is deleted and a Coin is transferred back 51 | /// to the sender. 52 | public fun unlock_coin( 53 | _: LockedCoin, 54 | _: &Clock, 55 | _: &mut TxContext 56 | ): ID { 57 | abort 0 58 | } 59 | 60 | /// Public getter for the `LockedCoin` value 61 | public fun value(_: &LockedCoin): u64 { 62 | abort 0 63 | } 64 | 65 | /// Public getter for the `LockedCoin` locked_until_time 66 | public fun lock_time(_: &LockedCoin): u64 { 67 | abort 0 68 | } 69 | 70 | /// Delete the `LockedCoin` object. 71 | public fun destory_lock(_: LockedCoin): (Balance, ID) { 72 | abort 0 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /sui/token/xcetus/sources/locking.move: -------------------------------------------------------------------------------- 1 | #[allow(unused_use, unused_field, unused_const)] 2 | // This module works with xcetus module to provide lock of xCETUS. 3 | // If you want to convert XCETUS back to CETUS, you have to lock it for some times. 4 | // If the lock time ends, you can redeem CETUS to your address, and the xCETUS will be burned. 5 | // You can also cancel the lock before lock time ends. 6 | // The convert of CETUS to xCETUS is provided. 7 | module xcetus::locking { 8 | use std::type_name::TypeName; 9 | use sui::object::{UID, ID}; 10 | use sui::balance::Balance; 11 | use sui::tx_context::TxContext; 12 | use sui::coin::Coin; 13 | use sui::clock::Clock; 14 | use move_stl::linked_table; 15 | use xcetus::xcetus::{VeNFT, XcetusManager}; 16 | use xcetus::lock_coin::LockedCoin; 17 | use cetus::cetus::CETUS; 18 | 19 | const ONE_DAY_SECONDS: u64 = 24 * 3600; 20 | const EXCHANGE_RATE_MULTIPER: u128 = 1000; 21 | const REDEEM_NUM_MULTIPER: u128 = 100000000000; 22 | const PACKAGE_VERSION: u64 = 1; 23 | 24 | // Errors 25 | const EINIT_CONFIG_ERROR: u64 = 0; 26 | const EBALANCE_NOT_ENOUGH: u64 = 1; 27 | const ELOCK_DAY_ERROR: u64 = 2; 28 | const EREDEMM_AMOUNT_ERROR: u64 = 3; 29 | const EVENFT_NOT_MATCH_WITH_LOCK: u64 = 4; 30 | const EALREADY_UNLOCK: u64 = 5; 31 | const EADMIN_REDEEM_ERROR: u64 = 6; 32 | const ETREASURY_MANAGER_ERROR: u64 = 7; 33 | const EPACKAGE_VERSION_DEPRECATE: u64 = 8; 34 | 35 | struct AdminCap has key, store { 36 | id: UID 37 | } 38 | 39 | /// Manager the lock to the xCETUS. 40 | struct LockUpManager has key { 41 | id: UID, 42 | balance: Balance, 43 | treasury_manager: address, 44 | extra_treasury: Balance, 45 | /// lock_id -> LockInfo 46 | lock_infos: linked_table::LinkedTable, 47 | type_name: TypeName, 48 | min_lock_day: u64, 49 | max_lock_day: u64, 50 | min_percent_numerator: u64, 51 | max_percent_numerator: u64, 52 | //package version 53 | package_version: u64, 54 | } 55 | 56 | /// The lock info. 57 | struct LockInfo has store, drop { 58 | venft_id: ID, 59 | lock_id: ID, 60 | xcetus_amount: u64, 61 | cetus_amount: u64, 62 | } 63 | 64 | /// Events 65 | struct ConvertEvent has copy, store, drop { 66 | venft_id: ID, 67 | amount: u64, 68 | lock_manager: ID, 69 | } 70 | 71 | struct RedeemLockEvent has copy, store, drop { 72 | lock_manager: ID, 73 | venft_id: ID, 74 | amount: u64, 75 | lock_day: u64, 76 | cetus_amount: u64, 77 | } 78 | 79 | struct CancelRedeemEvent has copy, drop, store { 80 | lock_manager: ID, 81 | venft_id: ID, 82 | locked_coin: ID, 83 | } 84 | 85 | struct RedeemEvent has copy, drop, store { 86 | lock_manager: ID, 87 | venft_id: ID, 88 | locked_coin: ID, 89 | cetus_amount: u64, 90 | xcetus_amount: u64 91 | } 92 | 93 | struct RedeemAllEvent has copy, drop, store { 94 | lock_manager: ID, 95 | receiver: address, 96 | amount: u64, 97 | } 98 | 99 | struct LOCKING has drop {} 100 | 101 | public fun checked_package_version(_m: &LockUpManager) { 102 | abort 0 103 | } 104 | 105 | /// Convert from CETUS to xCETUS. 106 | /// The mint of xCETUS needs to save same amount of CETUS in LockManager. 107 | public fun convert( 108 | _: &mut LockUpManager, 109 | _: &mut XcetusManager, 110 | _: vector>, 111 | _: u64, 112 | _: &mut VeNFT, 113 | _: &mut TxContext 114 | ) { 115 | abort 0 116 | } 117 | 118 | /// Convert xCETUS back to CETUS. 119 | /// The calculated amount of CETUS will wrap in LockedCoin object and give to user. 120 | /// the state of venftinfo will be updated. 121 | public fun redeem_lock( 122 | _: &mut LockUpManager, 123 | _: &mut XcetusManager, 124 | _: &mut VeNFT, 125 | _: u64, 126 | _: u64, 127 | _: &Clock, 128 | _: &mut TxContext 129 | ) { 130 | abort 0 131 | } 132 | 133 | 134 | /// Cancel the redeem lock. 135 | /// The CETUS will be send back to LockManger, LockedCoin will be destroyed. the state related to xCETUS will be updated. 136 | public fun cancel_redeem_lock( 137 | _: &mut LockUpManager, 138 | _: &mut XcetusManager, 139 | _: &mut VeNFT, 140 | _: LockedCoin, 141 | _: &Clock, 142 | ) { 143 | abort 0 144 | } 145 | 146 | /// When the lock time is ends, the CETUS can be redeemed. 147 | public fun redeem( 148 | _: &mut LockUpManager, 149 | _: &mut XcetusManager, 150 | _: &mut VeNFT, 151 | _: LockedCoin, 152 | _: &Clock, 153 | _: &mut TxContext 154 | ) { 155 | abort 0 156 | } 157 | 158 | /// Mint VeNFT and convert. 159 | public fun mint_and_convert( 160 | _: &mut LockUpManager, 161 | _: &mut XcetusManager, 162 | _: vector>, 163 | _: u64, 164 | _: &mut TxContext 165 | ) { 166 | abort 0 167 | } 168 | } 169 | 170 | -------------------------------------------------------------------------------- /sui/token/xcetus/sources/router.move: -------------------------------------------------------------------------------- 1 | // The router of the contract. 2 | module xcetus::router { 3 | 4 | use xcetus::locking::LockUpManager; 5 | use xcetus::xcetus::{XcetusManager, VeNFT}; 6 | use sui::coin::Coin; 7 | use sui::clock::Clock; 8 | use sui::tx_context::TxContext; 9 | use xcetus::lock_coin::LockedCoin; 10 | use sui::object::ID; 11 | use cetus::cetus::CETUS; 12 | 13 | 14 | /// convert. 15 | /// Convert CETUS to xCETUS. 16 | public entry fun convert( 17 | _: &mut LockUpManager, 18 | _: &mut XcetusManager, 19 | _: vector>, 20 | _: u64, 21 | _: &mut VeNFT, 22 | _: &mut TxContext 23 | ) { 24 | abort 1 25 | } 26 | 27 | public entry fun mint_and_convert( 28 | _: &mut LockUpManager, 29 | _: &mut XcetusManager, 30 | _: vector>, 31 | _: u64, 32 | _: &mut TxContext 33 | ) { 34 | abort 1 35 | } 36 | 37 | /// redeem_lock. 38 | /// Convert xCETUS to CETUS, first step is to lock the CETUS for a period. 39 | /// When the time is reach, xcetus can be redeem and xCETUS will be burned. 40 | public entry fun redeem_lock( 41 | _: &mut LockUpManager, 42 | _: &mut XcetusManager, 43 | _: &mut VeNFT, 44 | _: u64, 45 | _: u64, 46 | _: &Clock, 47 | _: &mut TxContext 48 | ) { 49 | abort 1 50 | } 51 | 52 | /// cancel_redeem_lock 53 | /// Cancel the redeem lock, the xcetus locked will be return back to the manager and the xCETUS will be available again. 54 | public entry fun cancel_redeem_lock( 55 | _: &mut LockUpManager, 56 | _: &mut XcetusManager, 57 | _: &mut VeNFT, 58 | _: LockedCoin, 59 | _: &Clock, 60 | ) { 61 | abort 1 62 | } 63 | 64 | /// redeem 65 | /// lock time is reach and the xcetus can be redeemed, the xCETUS will be burned. 66 | public entry fun redeem( 67 | _: &mut LockUpManager, 68 | _: &mut XcetusManager, 69 | _: &mut VeNFT, 70 | _: LockedCoin, 71 | _: &Clock, 72 | _: &mut TxContext 73 | ) { 74 | abort 1 75 | } 76 | 77 | /// burn_venft 78 | /// args 79 | /// - manager: XcetusManager share object. 80 | /// - venft: VeNFT 81 | public entry fun burn_venft(_: &mut XcetusManager, _: VeNFT, _: &mut TxContext) { 82 | abort 1 83 | } 84 | 85 | /// mint venft 86 | /// args 87 | /// - manager: XcetusManager share object. 88 | /// - venft: VeNFT 89 | public entry fun mint_venft(_: &mut XcetusManager, _: &mut TxContext): ID { 90 | abort 1 91 | } 92 | } 93 | 94 | -------------------------------------------------------------------------------- /sui/token/xcetus/sources/xcetus.move: -------------------------------------------------------------------------------- 1 | #[allow(unused_type_parameter, unused_field, unused_const)] 2 | // This module is about: 3 | // create the xcetus coin, 4 | // provide the management of `VeNFT`, 5 | // store the information about VeNFTs, and the update of these states of venfts. 6 | // The VenftInfo list info is used for supporting the activities of higher level contracts. 7 | // This module work with `locking` module. 8 | // A `AdminCap` exists in this module, which can mint, burn xcetus in some situations. 9 | module xcetus::xcetus { 10 | use sui::balance::Balance; 11 | use sui::tx_context::TxContext; 12 | use sui::coin::TreasuryCap; 13 | use sui::object::{UID, ID}; 14 | use sui::table::Table; 15 | use move_stl::linked_table; 16 | 17 | friend xcetus::locking; 18 | 19 | const EBALANCE_NOT_ZERO: u64 = 1; 20 | const EBALANCE_NOT_MATCH: u64 = 2; 21 | const EBALANCE_AMOUNT_ERROR: u64 = 3; 22 | const EAVAILABLE_BALANCE_NOT_ENOUGH: u64 = 4; 23 | const EHAS_VENFT_ALREADY: u64 = 5; 24 | 25 | /// The witness of XCETUS Coin. 26 | struct XCETUS has drop {} 27 | 28 | /// The capability of the xcetus module, can mint, burn, transfer xcetus if needed. 29 | struct AdminCap has key, store { 30 | id: UID 31 | } 32 | 33 | /// Store the `Treasury` object of xCETUS Coin, and record all venfts's info. 34 | struct XcetusManager has key { 35 | id: UID, 36 | index: u64, 37 | has_venft: Table, 38 | nfts: linked_table::LinkedTable, 39 | treasury: TreasuryCap, 40 | total_locked: u64, 41 | } 42 | 43 | /// The venft info stored in XcetusManager which is used for support dividends, maker-bonus and other future higher level activities. 44 | struct VeNftInfo has store, drop { 45 | id: ID, 46 | xcetus_amount: u64, 47 | lock_amount: u64, 48 | } 49 | 50 | /// The Venft Object which cannot be transfered, and holding the xCETUS. 51 | struct VeNFT has key { 52 | id: UID, 53 | index: u64, 54 | xcetus_balance: Balance 55 | } 56 | 57 | // ============= Events ================= 58 | struct MintVeNFTEvent has copy, drop, store { 59 | nft_id: ID, 60 | index: u64, 61 | } 62 | 63 | struct BurnVeNFTEvent has copy, drop, store { 64 | nft_id: ID, 65 | } 66 | 67 | struct MintEvent has copy, drop, store { 68 | nft_id: ID, 69 | amount: u64 70 | } 71 | 72 | struct BurnEvent has copy, drop, store { 73 | nft_id: ID, 74 | amount: u64 75 | } 76 | 77 | struct TransferEvent has copy, drop, store { 78 | from_venft: ID, 79 | to_venft: ID, 80 | amount: u64 81 | } 82 | 83 | /// Mint Venft. 84 | public fun mint_venft(_: &mut XcetusManager, _: &mut TxContext): ID { 85 | abort 0 86 | } 87 | 88 | /// Burn Venft when the xcetus balance owned is zero. 89 | public fun burn_venft(_: &mut XcetusManager, _: VeNFT, _: &mut TxContext) { 90 | abort 0 91 | } 92 | 93 | /// Getter `xcetus_amount` of VenftInfo. 94 | public fun xcetus_amount(_: &VeNftInfo): u64 { 95 | abort 0 96 | } 97 | 98 | /// Getter `lock_amount` of VenftInfo. 99 | public fun lock_amount(_: &VeNftInfo): u64 { 100 | abort 0 101 | } 102 | 103 | /// Getter the xCETUS amount of Venft. 104 | public fun value(_: &XcetusManager, _: &VeNFT): u64 { 105 | abort 0 106 | } 107 | 108 | /// Getter the unlocked xcetus amount of venft. 109 | public fun available_value(_: &XcetusManager, _: &VeNFT): u64 { 110 | abort 0 111 | } 112 | 113 | /// Getter total amount of xCETUS. 114 | public fun totol_amount(_: &XcetusManager): u64 { 115 | abort 0 116 | } 117 | 118 | /// Getter total locked xCETUS amount. 119 | public fun total_locked(_: &XcetusManager): u64 { 120 | abort 0 121 | } 122 | 123 | /// Getter total venfts 124 | public fun total_holder(_: &XcetusManager): u64 { 125 | abort 0 126 | } 127 | 128 | /// Getter all VenftInfo. 129 | public fun nfts(_: &XcetusManager): &linked_table::LinkedTable { 130 | abort 0 131 | } 132 | } 133 | 134 | -------------------------------------------------------------------------------- /sui/vaults/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.log 3 | /.vscode 4 | /.idea 5 | -------------------------------------------------------------------------------- /sui/vaults/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 3 5 | manifest_digest = "70EAEE861A0B5BFE3784C480D74CB819A405140F72FC81BCC3C620237F6CFB4E" 6 | deps_digest = "52B406A7A21811BEF51751CF88DA0E76DAEFFEAC888D4F4060B1A72BBE7D8D35" 7 | dependencies = [ 8 | { id = "Bridge", name = "Bridge" }, 9 | { id = "CetusClmm", name = "CetusClmm" }, 10 | { id = "Farming", name = "Farming" }, 11 | { id = "MoveStdlib", name = "MoveStdlib" }, 12 | { id = "Sui", name = "Sui" }, 13 | { id = "SuiSystem", name = "SuiSystem" }, 14 | ] 15 | 16 | [[move.package]] 17 | id = "Bridge" 18 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/bridge" } 19 | 20 | dependencies = [ 21 | { id = "MoveStdlib", name = "MoveStdlib" }, 22 | { id = "Sui", name = "Sui" }, 23 | { id = "SuiSystem", name = "SuiSystem" }, 24 | ] 25 | 26 | [[move.package]] 27 | id = "CetusClmm" 28 | source = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", rev = "aaa66c17098c8f91d0f27068089f84e1d3e9cf98", subdir = "sui/cetus_clmm/" } 29 | 30 | dependencies = [ 31 | { id = "Bridge", name = "Bridge" }, 32 | { id = "IntegerMate", name = "IntegerMate" }, 33 | { id = "MoveSTL", name = "MoveSTL" }, 34 | { id = "MoveStdlib", name = "MoveStdlib" }, 35 | { id = "Sui", name = "Sui" }, 36 | { id = "SuiSystem", name = "SuiSystem" }, 37 | ] 38 | 39 | [[move.package]] 40 | id = "Farming" 41 | source = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", rev = "mainnet-v1.48.2", subdir = "sui/stable_farming/" } 42 | 43 | dependencies = [ 44 | { id = "Bridge", name = "Bridge" }, 45 | { id = "CetusClmm", name = "CetusClmm" }, 46 | { id = "MoveStdlib", name = "MoveStdlib" }, 47 | { id = "Sui", name = "Sui" }, 48 | { id = "SuiSystem", name = "SuiSystem" }, 49 | ] 50 | 51 | [[move.package]] 52 | id = "IntegerMate" 53 | source = { git = "https://github.com/CetusProtocol/integer-mate.git", rev = "mainnet-v1.48.2", subdir = "sui" } 54 | 55 | dependencies = [ 56 | { id = "Bridge", name = "Bridge" }, 57 | { id = "MoveStdlib", name = "MoveStdlib" }, 58 | { id = "Sui", name = "Sui" }, 59 | { id = "SuiSystem", name = "SuiSystem" }, 60 | ] 61 | 62 | [[move.package]] 63 | id = "MoveSTL" 64 | source = { git = "https://github.com/CetusProtocol/move-stl.git", rev = "mainnet-v1.48.2", subdir = "sui" } 65 | 66 | dependencies = [ 67 | { id = "Bridge", name = "Bridge" }, 68 | { id = "MoveStdlib", name = "MoveStdlib" }, 69 | { id = "Sui", name = "Sui" }, 70 | { id = "SuiSystem", name = "SuiSystem" }, 71 | ] 72 | 73 | [[move.package]] 74 | id = "MoveStdlib" 75 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/move-stdlib" } 76 | 77 | [[move.package]] 78 | id = "Sui" 79 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-framework" } 80 | 81 | dependencies = [ 82 | { id = "MoveStdlib", name = "MoveStdlib" }, 83 | ] 84 | 85 | [[move.package]] 86 | id = "SuiSystem" 87 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "3802482bd4e3", subdir = "crates/sui-framework/packages/sui-system" } 88 | 89 | dependencies = [ 90 | { id = "MoveStdlib", name = "MoveStdlib" }, 91 | { id = "Sui", name = "Sui" }, 92 | ] 93 | 94 | [move.toolchain-version] 95 | compiler-version = "1.48.2" 96 | edition = "2024" 97 | flavor = "sui" 98 | 99 | [env] 100 | 101 | [env.mainnet] 102 | chain-id = "35834a8a" 103 | original-published-id = "0xd3453d9be7e35efe222f78a810bb3af1859fd1600926afced8b4936d825c9a05" 104 | latest-published-id = "0x5c35deb22849011d69456f37aaf4d90356e0829545d413039212dafa5b1d70b4" 105 | published-version = "7" 106 | -------------------------------------------------------------------------------- /sui/vaults/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vaults" 3 | version = "v1.0.0" 4 | 5 | [dependencies] 6 | # farming = { r.mvr = "@cetuspackages/farming" } 7 | # cetusclmm = { r.mvr = "@cetuspackages/clmm" } 8 | Farming = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/stable_farming", rev = "mainnet-v1.48.3" } 9 | # CetusClmm = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/cetus_clmm", rev = "mainnet-v1.48.3" } 10 | 11 | [addresses] 12 | vaults = "0xd3453d9be7e35efe222f78a810bb3af1859fd1600926afced8b4936d825c9a05" 13 | 14 | [r.mvr] 15 | network = "mainnet" 16 | -------------------------------------------------------------------------------- /sui/vaults/README.md: -------------------------------------------------------------------------------- 1 | ## Vaults 2 | 3 | Vaults is a system specifically designed to automatically manage user liquidity. It encompasses the timely reinvestment 4 | of fees and rewards, as well as rebalancing when necessary. 5 | 6 | Vaults possesses the Farms WrappedPositionNFT. When a user deposits tokens into Vaults, those tokens are utilized to 7 | provide liquidity within the positions held by Vaults. 8 | 9 | As tokens are added to the respective positions, LP (Liquidity Provider) tokens are minted and allocated to users. 10 | 11 | These LP tokens serve as a representation of the individual's share of liquidity within Vaults. 12 | 13 | ## Tags corresponding to different networks 14 | 15 | | Tag of Repo | Network | Latest published at address | 16 | |-----------------| ------- |---------------------------------------------------------------------| 17 | | mainnet-v1.25.0 | mainnet | 0x58e5de6e425397eeaf952d55c0f94637bee91b25d6138ce222f89cda0aefec03 | 18 | | testnet-v1.25.0 | testnet | 0x04df17a109336491867f04df40ca8a77277bc6e382139e88ae0d0d267ac07905 | 19 | 20 | mainnet: 21 | 22 | ``` 23 | vaults = { git = "https://github.com/CetusProtocol/cetus-clmm-interface.git", subdir = "sui/vaults", rev = "mainnet-v1.25.0", override = true } 24 | ``` 25 | 26 | testnet: 27 | 28 | ``` 29 | vaults = { git = "https://github.com/CetusProtocol/cetus-token-interface.git", subdir = "sui/vaults", rev = "testnet-v1.25.0", override = true } 30 | ``` 31 | 32 | ### How to calculate LP amount when deposit 33 | 34 | ``` 35 | 36 | total_lp_amount the_lp_amount_mint_to_user 37 | -------------------------------- = ------------------------------ 38 | total_liqudity_in_vault_position the_liqudiity_user_deposited 39 | 40 | the_lp_amount_mint_to_user = total_lp_amount * the_liqudiity_user_deposited / total_liqudity_in_vault_position 41 | ``` 42 | 43 | ### How to calculate the liquidity should remove to user given the lp amount user provided 44 | 45 | ``` 46 | 47 | total_lp_amount the_lp_amount_user_provided 48 | -------------------------------- = ---------------------------- 49 | total_liqudity_in_vault_position the_liquidity_give_to_user 50 | 51 | the_liquidity_give_to_user = total_liqudity_in_vault_position * the_lp_amount_user_provided / total_lp_amount 52 | 53 | ``` 54 | 55 | ### How to reinvest 56 | 57 | 1. collect_fee 58 | 2. collect clmm rewarders 59 | 3. swap clmm rewarders to vault token_a or token_b(flash loan way) 60 | 4. harvest farms rewarders 61 | 5. swap farms rewarders to vault token_a or token_b(flash loan way) 62 | 6. rebalance the token_a and token_b in vault bag 63 | 7. reinvest 64 | 65 | ### How to rebalance 66 | 67 | 1. collect clmm rewarders 68 | 2. harvest farms rewarders 69 | 3. remove all liquidity and collect fee, close position from farms `close_position` instruction 70 | 4. open position and deposit into farms pool 71 | 5. use `rebalance` to add liquidity into farms pool 72 | 6. use `finish_rebalance` to rebalance and add liquidity to farms pool; this operation can do multiple times if need, 73 | and the last time should set `is_finish` is true to finish rebalance 74 | 75 | ## ChangeLog 76 | 77 | 1. Fix bug 78 | Tue, 11 Jun 2024 18:28:08 +0800 79 | 80 | call collect_fee before deposit and remove. 81 | -------------------------------------------------------------------------------- /sui/vaults/sources/acl.move: -------------------------------------------------------------------------------- 1 | // Copyright (c) Cetus Technology Limited 2 | 3 | /// Fork @https://github.com/pentagonxyz/movemate.git 4 | /// 5 | /// `acl` is a simple access control module, where `member` represents a member and `role` represents a type 6 | /// of permission. A member can have multiple permissions. 7 | #[allow(unused_type_parameter, unused_field, unused_const)] 8 | module vaults::acl { 9 | 10 | use move_stl::linked_table::{LinkedTable}; 11 | 12 | const MAX_U128: u128 = 340282366920938463463374607431768211455; 13 | 14 | /// @dev When attempting to add/remove a role >= 128. 15 | const ERoleNumberTooLarge: u64 = 0; 16 | const EMemberNotExists: u64 = 1; 17 | 18 | /// @dev Maps addresses to `u128`s with each bit representing the presence of (or lack of) each role. 19 | struct ACL has store { 20 | permissions: LinkedTable 21 | } 22 | 23 | struct Member has store, drop, copy { 24 | address: address, 25 | permission: u128 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sui/vaults/sources/fetcher.move: -------------------------------------------------------------------------------- 1 | #[allow(unused_type_parameter, unused_field, unused_const)] 2 | module vaults::fetcher { 3 | 4 | use sui::object::ID; 5 | 6 | use cetusclmm::pool::Pool; 7 | 8 | use vaults::vaults::Vault; 9 | 10 | 11 | /// Events 12 | struct LpTokenValueEvent has copy, drop { 13 | lp_amount: u64, 14 | amount_a: u64, 15 | amount_b: u64, 16 | clmm_pool: ID, 17 | vault_id: ID, 18 | } 19 | 20 | /// Get the Coin amounts by Lp Token amount. 21 | public entry fun get_position_amounts( 22 | _: &Vault, 23 | _: &Pool, 24 | _: u64, 25 | ) { 26 | abort 1 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sui/vaults/sources/router.move: -------------------------------------------------------------------------------- 1 | #[allow(unused_type_parameter, unused_field, unused_const)] 2 | module vaults::router { 3 | 4 | use sui::clock::Clock; 5 | use sui::coin::{Coin}; 6 | use sui::tx_context::{TxContext}; 7 | 8 | use cetusclmm::config::GlobalConfig; 9 | use cetusclmm::pool::Pool; 10 | 11 | use farming::rewarder::RewarderManager; 12 | use farming::pool::Pool as SFarmingPool; 13 | use farming::config::GlobalConfig as SFarmingConfig; 14 | 15 | use vaults::vaults::{ 16 | VaultsManager, 17 | Vault, 18 | }; 19 | 20 | 21 | /// User deposit Asset into `Vault` 22 | public entry fun deposit( 23 | _: &VaultsManager, 24 | _: &mut Vault, 25 | _: &mut RewarderManager, 26 | _: &SFarmingConfig, 27 | _: &mut SFarmingPool, 28 | _: &GlobalConfig, 29 | _: &mut Pool, 30 | _: Coin, 31 | _: Coin, 32 | _: u64, 33 | _: u64, 34 | _: bool, 35 | _: &Clock, 36 | _: &mut TxContext 37 | ) 38 | { 39 | abort 0 40 | } 41 | 42 | /// User Remove Asset from `Vault` by Lp Token 43 | public entry fun remove( 44 | _: &VaultsManager, 45 | _: &mut Vault, 46 | _: &mut RewarderManager, 47 | _: &SFarmingConfig, 48 | _: &mut SFarmingPool, 49 | _: &GlobalConfig, 50 | _: &mut Pool, 51 | _: &mut Coin, 52 | _: u64, 53 | _: u64, 54 | _: u64, 55 | _: &Clock, 56 | _: &mut TxContext 57 | ) { 58 | abort 0 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /sui/vaults/sources/vaults.move: -------------------------------------------------------------------------------- 1 | #[allow(unused_type_parameter, unused_field, unused_const)] 2 | module vaults::vaults { 3 | 4 | use std::type_name::{TypeName}; 5 | 6 | use sui::bag::{Bag}; 7 | use sui::clock::Clock; 8 | use sui::coin::{TreasuryCap, Coin}; 9 | use sui::table::{Table}; 10 | use sui::tx_context::{TxContext}; 11 | use sui::object::{UID, ID}; 12 | 13 | use cetusclmm::config::GlobalConfig; 14 | use cetusclmm::pool::{Pool}; 15 | 16 | use farming::pool::{ 17 | WrappedPositionNFT, 18 | Pool as SFarmingPool, 19 | }; 20 | use farming::rewarder::RewarderManager; 21 | use farming::config::GlobalConfig as SFarmingConfig; 22 | 23 | use vaults::acl; 24 | 25 | 26 | /// Package verison which is need update when upgrade package 27 | const VERSION: u64 = 5; 28 | 29 | /// the denominator of `Vault` protocol_fee. 30 | const PROTOCOL_FEE_DENOMINATOR: u64 = 10000; 31 | /// Max protocol fee(2000/10000 = 20%) 32 | const MAX_PROTOCOL_FEE_RATE: u64 = 2000; 33 | 34 | const PRICE_MULTIPER: u256 = 100000000000000000000; 35 | 36 | const UINT64_MAX: u256 = 18446744073709551616; 37 | /// Range is (0 - 255 / 2000 = 12.75%) 38 | const SLIPPAGE_DENOMINATOR: u64 = 2000; 39 | 40 | 41 | /// Vaults Acl Roles 42 | const ACL_CLAIM_PROTOCOL_FEE: u8 = 0; 43 | const ACL_REINVEST_MANAGER: u8 = 1; 44 | const ACL_REBALANCE_MANAGER: u8 = 2; 45 | const ACL_POOL_MANAGER: u8 = 3; 46 | 47 | /// Vault Status 48 | const STATUS_RUNNING: u8 = 1; 49 | const STATUS_REBALANCING: u8 = 2; 50 | 51 | /// Errors 52 | const EAmountOutBelowMinLimit: u64 = 1; 53 | const EPositionSizeError: u64 = 2; 54 | const EPackageVersionDeprecate: u64 = 3; 55 | const ETokenAmountOverflow: u64 = 4; 56 | const ETokenAmountIsZero: u64 = 5; 57 | const EPoolIsPause: u64 = 6; 58 | const EInvalidCoinType: u64 = 7; 59 | const ERebalanceAddLiquidityError: u64 = 8; 60 | const ETokenAmountNotEnough: u64 = 9; 61 | const EInvalidProtocolFeeRate: u64 = 10; 62 | const ENoProtocolFeeClaimPermission: u64 = 11; 63 | const ENoOperationManagerPermission: u64 = 12; 64 | const ENoPoolManagerPemission: u64 = 13; 65 | const ETreausyCapIllegal: u64 = 14; 66 | const EWrongPackageVersion: u64 = 15; 67 | const EQuotaReached: u64 = 16; 68 | const EVaultNotRunning: u64 = 17; 69 | const EVaultNotRebalancing: u64 = 18; 70 | const EQuotaTypeNameError: u64 = 19; 71 | const ESameCoinType: u64 = 20; 72 | const EInvalidCoinTypeSequence: u64 = 21; 73 | const ECoinPairExisted: u64 = 22; 74 | const ECoinPairNonExisted: u64 = 23; 75 | const EIncorrectFlashLoanAmount: u64 = 24; 76 | const EIncorrentRepay: u64 = 25; 77 | const EOraclePoolError: u64 = 26; 78 | const EFlashloanCountNonzero: u64 = 27; 79 | const EFinishRebalanceThresholdNotMatch: u64 = 28; 80 | const EHarvestAssetNotEnough: u64 = 29; 81 | const EInvalidVaultOperation: u64 = 30; 82 | 83 | /// The Admin Cap of the protocol, manager the ACL. 84 | struct AdminCap has key, store { 85 | id: UID 86 | } 87 | 88 | /// The Vaults manager 89 | struct VaultsManager has key, store { 90 | id: UID, 91 | // Vault index created. 92 | index: u64, 93 | package_version: u64, 94 | // Store the pool ids. Map vault_id to clmm pool_id. 95 | vault_to_pool_maps: Table, 96 | // Store new_pool_key() -> OracleInfo 97 | // The OracleInfo is used when flash_loan assetA from vault to calculate the repay assetB amount. 98 | // The reinvest or rebalance is done by flash_loan way. 99 | price_oracles: Table, 100 | acl: acl::ACL 101 | } 102 | 103 | struct OracleInfo has store, drop { 104 | clmm_pool: ID, 105 | slippage: u8, 106 | } 107 | 108 | /// The Vault. 109 | struct Vault has key, store { 110 | id: UID, 111 | /// Clmm pool ID 112 | pool: ID, 113 | /// The liquidity in the Vault 114 | liquidity: u128, 115 | /// The protocol fee 116 | protocol_fee_rate: u64, 117 | /// Indicate if the vault is paused, the pool can be paused when in emergency 118 | is_pause: bool, 119 | /// The `WrappedPositionNFT` hold in vault. the size is always 1. 120 | positions: vector, 121 | /// The `TreasuryCap` of the associated LP Token to mint LP Token. 122 | lp_token_treasury: TreasuryCap, 123 | /// Store the fee and rewarders temporarily 124 | harvest_assets: Bag, 125 | /// Store the protocol fee 126 | protocol_fees: Bag, 127 | /// Max TVL based on quota_based_type can add to the vault 128 | max_quota: u128, 129 | /// status: STATUS_RUNNING | STATUS_REBALANCING 130 | /// Rebalancing operation can be divided into two steps: Open new Position and add liquidity as can as possible without swap, 131 | /// second step is rebalance the liquidity and add liquidity into position, this step can do multiple times if needed(when the liquidity is large), 132 | /// and the last time the status must be set to STATUS_RUNNING. 133 | status: u8, 134 | /// Quota based CoinType 135 | quota_based_type: TypeName, 136 | /// When finish rebalance and change vault status to STATUS_RUNNING, assets amount of coin_a and coin_b in harvest_assets based on `quota_based_type` must less then `finish_rebalance_threshold` 137 | finish_rebalance_threshold: u64, 138 | /// When finish rebalance and change vault status to STATUS_RUNNING, `flash_loan_count` must be 0. 139 | /// To avoid call flash_loan to satisfy `finish_rebalance_threshold` and then call rebalance to finishd the rebalance process. 140 | flash_loan_count: u8, 141 | } 142 | 143 | /// Emit when deposit 144 | struct DepositEvent has copy, drop { 145 | vault_id: ID, 146 | before_liquidity: u128, 147 | delta_liquidity: u128, 148 | before_supply: u64, 149 | lp_amount: u64, 150 | } 151 | 152 | /// Emit when remove 153 | struct RemoveEvent has copy, drop { 154 | vault_id: ID, 155 | lp_amount: u64, 156 | liquidity: u128, 157 | amount_a: u64, 158 | amount_b: u64, 159 | protocol_fee_a_amount: u64, 160 | protocol_fee_b_amount: u64 161 | } 162 | 163 | /// Deposit Token to `Vault` and return Lp Token to user. 164 | /// Params 165 | /// - manager: `VaultManger` 166 | /// - vault: `Vault` 167 | /// - rewarder_manager: RewarderManager 168 | /// - sfarming_config: FarmingConfig 169 | /// - sfarming_pool: FarmingPool 170 | /// - clmm_config: Clmm config 171 | /// - clmm_pool: the Clmm pool associated to Vault is needed here to add liquidity. 172 | /// - coin_a 173 | /// - coin_b 174 | /// - amount_a: work with fix_amount_a 175 | /// - amount_b: work with fix_amount_b 176 | /// - fix_amount_a: fix amount_a or amount_b 177 | /// - clk: Clock 178 | public fun deposit( 179 | _: &VaultsManager, 180 | _: &mut Vault, 181 | _: &mut RewarderManager, 182 | _: &SFarmingConfig, 183 | _: &mut SFarmingPool, 184 | _: &GlobalConfig, 185 | _: &mut Pool, 186 | _: Coin, 187 | _: Coin, 188 | _: u64, 189 | _: u64, 190 | _: bool, 191 | _: &Clock, 192 | _: &mut TxContext 193 | ): Coin { 194 | abort 0 195 | } 196 | 197 | /// Remove liquidity: burn the Lp Token and remove asset to user. 198 | /// Params 199 | /// - manager: `VaultManger` 200 | /// - vault: `Vault` 201 | /// - rewarder_manager: RewarderManager 202 | /// - sfarming_config: FarmingConfig 203 | /// - sfarming_pool: FarmingPool 204 | /// - clmm_config: Clmm config 205 | /// - clmm_pool: the Clmm pool associated to Vault is needed here to remove liquidity. 206 | /// - coins: The Lp Token to burn 207 | /// - lp_token_amount: The amount of lp Token to remove 208 | /// - min_amount_a: the minimum coin_a return 209 | /// - min_amount_b: the minimum coin_b return 210 | /// - clk: Clock 211 | public fun remove( 212 | _: &VaultsManager, 213 | _: &mut Vault, 214 | _: &mut RewarderManager, 215 | _: &SFarmingConfig, 216 | _: &mut SFarmingPool, 217 | _: &GlobalConfig, 218 | _: &mut Pool, 219 | _: &mut Coin, 220 | _: u64, 221 | _: u64, 222 | _: u64, 223 | _: &Clock, 224 | _: &mut TxContext 225 | ): (Coin, Coin) { 226 | abort 0 227 | } 228 | 229 | /// Get Coin amounts by Lp Token amount 230 | /// 1. Calculate the delta_liquidity the lp_amount share deserved 231 | /// 2. Calculate the amount_a and amount_b from the delta_liquidity in clmm. 232 | /// Params 233 | /// - vault: `Vault` 234 | /// - pool: `CLmmpool` 235 | /// - lp_amount: Lp Token amount 236 | public fun get_position_amounts( 237 | _: &Vault, 238 | _: &Pool, 239 | _: u64, 240 | ): (u64, u64) { 241 | abort 0 242 | } 243 | 244 | 245 | /// The total_supply of Lp Token 246 | /// Params 247 | /// - vault: Vault 248 | public fun total_token_amount(_: &Vault): u64 { 249 | abort 0 250 | } 251 | 252 | } 253 | --------------------------------------------------------------------------------