Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions contracts/mtoken/sources/mtoken.move
Original file line number Diff line number Diff line change
Expand Up @@ -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 =====

Expand Down Expand Up @@ -118,6 +124,43 @@ module mtoken::mtoken {
): Coin<MToken> {
mint_mtokens_internal(manager, admin_cap, coin, ctx)
}

public fun admin_close_vesting<MToken, Vesting, Penalty>(
mut manager: VestingManager<MToken, Vesting, Penalty>,
admin_cap: AdminCap<MToken, Vesting, Penalty>,
ctx: &mut TxContext,
): (Coin<Vesting>, Coin<Penalty>, TreasuryCap<MToken>) {
manager.assert_version_and_upgrade();

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<MToken: drop, Vesting, Penalty>(
manager: &mut VestingManager<MToken, Vesting, Penalty>,
Expand Down
48 changes: 48 additions & 0 deletions contracts/mtoken/tests/mtoken_tests.move
Original file line number Diff line number Diff line change
Expand Up @@ -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<VEST, UNDERLYING, SUI>(
create_one_time_witness<VEST>(),
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<VEST, UNDERLYING, SUI>(
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() {
Expand Down