From 0028ac3eccad359216774a9f17de34a048e019c1 Mon Sep 17 00:00:00 2001 From: 0xxgen1 <0xxgen@solend.fi> Date: Tue, 13 May 2025 00:41:29 +0100 Subject: [PATCH 1/2] admin function to withdraw vesting --- contracts/mtoken/sources/mtoken.move | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/contracts/mtoken/sources/mtoken.move b/contracts/mtoken/sources/mtoken.move index 0cb9a12..8018b6c 100644 --- a/contracts/mtoken/sources/mtoken.move +++ b/contracts/mtoken/sources/mtoken.move @@ -118,6 +118,18 @@ module mtoken::mtoken { ): Coin { mint_mtokens_internal(manager, admin_cap, coin, ctx) } + + public fun admin_withdraw_vesting( + manager: &mut VestingManager, + _admin_cap: &AdminCap, + amount: u64, + ctx: &mut TxContext, + ): Coin { + manager.assert_version_and_upgrade(); + let vesting_coin = coin::from_balance(manager.vesting_balance.split(amount), ctx); + + vesting_coin + } entry fun set_params( manager: &mut VestingManager, From 803d926cb349bd7b74f06b753bbdcabe1f76a0d8 Mon Sep 17 00:00:00 2001 From: 0xxgen1 <0xxgen@solend.fi> Date: Wed, 14 May 2025 10:48:22 +0100 Subject: [PATCH 2/2] admin function to close vesting --- contracts/mtoken/sources/mtoken.move | 45 ++++++++++++++++++---- contracts/mtoken/tests/mtoken_tests.move | 48 ++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 7 deletions(-) diff --git a/contracts/mtoken/sources/mtoken.move b/contracts/mtoken/sources/mtoken.move index 8018b6c..ce9d42e 100644 --- a/contracts/mtoken/sources/mtoken.move +++ b/contracts/mtoken/sources/mtoken.move @@ -66,6 +66,12 @@ module mtoken::mtoken { vesting_type: TypeName, penalty_type: TypeName, } + + public struct CloseVestingEvent has store, copy, drop { + manager_id: ID, + underlying_balance: u64, + penalty_balance: u64, + } // ===== Public functions ===== @@ -119,16 +125,41 @@ module mtoken::mtoken { mint_mtokens_internal(manager, admin_cap, coin, ctx) } - public fun admin_withdraw_vesting( - manager: &mut VestingManager, - _admin_cap: &AdminCap, - amount: u64, + public fun admin_close_vesting( + mut manager: VestingManager, + admin_cap: AdminCap, ctx: &mut TxContext, - ): Coin { + ): (Coin, Coin, TreasuryCap) { manager.assert_version_and_upgrade(); - let vesting_coin = coin::from_balance(manager.vesting_balance.split(amount), ctx); - vesting_coin + let VestingManager { + id, + version: _, + vesting_balance, + penalty_balance, + mtoken_treasury_cap, + start_penalty_numerator: _, + end_penalty_numerator: _, + penalty_denominator: _, + start_time_s: _, + end_time_s: _, + } = manager; + + emit(CloseVestingEvent { + manager_id: id.to_inner(), + underlying_balance: vesting_balance.value(), + penalty_balance: penalty_balance.value(), + }); + + object::delete(id); + + let AdminCap { id, manager: _ } = admin_cap; + object::delete(id); + + let underlying = coin::from_balance(vesting_balance, ctx); + let penalty = coin::from_balance(penalty_balance, ctx); + + (underlying, penalty, mtoken_treasury_cap) } entry fun set_params( diff --git a/contracts/mtoken/tests/mtoken_tests.move b/contracts/mtoken/tests/mtoken_tests.move index f79da90..43ce318 100644 --- a/contracts/mtoken/tests/mtoken_tests.move +++ b/contracts/mtoken/tests/mtoken_tests.move @@ -54,6 +54,54 @@ module mtoken::mtoken_tests { (admin_cap, manager, mtoken_coin) } + + #[test] + fun test_admin_withdraw_vesting() { + let owner = @0x10; + let mut scenario = test_scenario::begin(owner); + let clock = clock::create_for_testing(ctx(&mut scenario)); + + let (mut treasury_cap, metadata) = underlying::create_currency(ctx(&mut scenario)); + let underlying_coin = treasury_cap.mint(8_000, ctx(&mut scenario)); + + let (admin_cap, manager, vesting_coin) = mint_mtokens_for_test( + create_one_time_witness(), + underlying_coin, + &metadata, + 10, + 0, + 100, + clock.timestamp_ms() / 1_000, + (clock.timestamp_ms() / 1_000) + 100, + ctx(&mut scenario), + ); + + transfer::public_share_object(manager); + + scenario.next_tx(owner); + + let manager = scenario.take_shared(); + + // Admin withdraws from vesting + let (withdrawn_coin, penalty_coin, cap) = mtoken::admin_close_vesting( + manager, + admin_cap, + ctx(&mut scenario), + ); + + assert!(vesting_coin.value() == 8_000, 0); + assert!(penalty_coin.value() == 0, 0); + + destroy(withdrawn_coin); + destroy(vesting_coin); + destroy(cap); + destroy(penalty_coin); + destroy(clock); + destroy(metadata); + destroy(treasury_cap); + + test_scenario::end(scenario); + } #[test] fun test_create_mtoken_coin() {