Skip to content

Commit 53ce9ab

Browse files
committed
ottersec fixes
1 parent 4d26641 commit 53ce9ab

6 files changed

Lines changed: 500 additions & 18 deletions

File tree

liquid_staking/sources/cert.move

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module liquid_staking::cert {
2424

2525
// Track the current version of the module, iterate each upgrade
2626
const VERSION: u64 = 1;
27+
const DECIMALS: u8 = 9;
2728

2829
/* Constants */
2930

@@ -49,7 +50,7 @@ module liquid_staking::cert {
4950
fun init(witness: CERT, ctx: &mut TxContext) {
5051
// create coin with metadata
5152
let (treasury_cap, metadata) = coin::create_currency<CERT>(
52-
witness, 9, b"voloSUI", b"Volo Staked SUI",
53+
witness, DECIMALS, b"voloSUI", b"Volo Staked SUI",
5354
b"Volo's SUI staking solution provides the best user experience and highest level of decentralization, security, combined with an attractive reward mechanism and instant staking liquidity through a bond-like synthetic token called voloSUI.",
5455
option::some<Url>(url::new_unsafe_from_bytes(b"https://volo.fi/voloSUI.png")),
5556
ctx
@@ -159,4 +160,4 @@ module liquid_staking::cert {
159160
public fun test_init(ctx: &mut TxContext) {
160161
init(CERT {}, ctx)
161162
}
162-
}
163+
}

liquid_staking/sources/native_pool.move

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ module liquid_staking::native_pool {
4646
const E_REWARD_NOT_IN_THRESHOLD: u64 = 107;
4747
const E_BAD_SHARES: u64 = 108;
4848
const E_TOO_BIG_PERCENT: u64 = 109;
49+
const E_NOT_ENOUGH_BALANCE: u64 = 110;
4950

5051
/* Events */
5152
struct StakedEvent has copy, drop {
@@ -188,16 +189,18 @@ module liquid_staking::native_pool {
188189
*table::borrow(&self.total_staked, self.staked_update_epoch) + pending
189190
}
190191

191-
// returns total staked for active epoch
192+
/// returns total staked for active epoch
193+
/// active stake can be unstaked
192194
public fun get_total_active_stake(self: &NativePool, ctx: &mut TxContext): u64 {
193195
let last_active_epoch = self.staked_update_epoch;
194196
let current_epoch = tx_context::epoch(ctx);
195197

196198
if (last_active_epoch > current_epoch) {
197199
last_active_epoch = current_epoch;
198200
};
199-
200-
*table::borrow(&self.total_staked, last_active_epoch)
201+
202+
let pending = get_pending(self);
203+
*table::borrow(&self.total_staked, last_active_epoch) + pending
201204
}
202205

203206
public fun get_total_rewards(self: &NativePool): u64 {
@@ -235,7 +238,7 @@ module liquid_staking::native_pool {
235238
// we can allow to stake less than 1 SUI
236239
public entry fun change_min_stake(self: &mut NativePool, _owner_cap: &OwnerCap, value: u64) {
237240
assert_version(self);
238-
assert!(value > 0, E_LIMIT_TOO_LOW);
241+
assert!(value > 1000, E_LIMIT_TOO_LOW);
239242

240243
event::emit(MinStakeChangedEvent {
241244
prev_value: self.min_stake,
@@ -474,6 +477,11 @@ module liquid_staking::native_pool {
474477
fun stake_pool(self: &mut NativePool, wrapper: &mut SuiSystemState, ctx: &mut TxContext) {
475478
let pending_value = coin::value(&self.pending);
476479

480+
let tickets_supply = unstake_ticket::get_total_supply(&self.ticket_metadata);
481+
if (pending_value < tickets_supply) {
482+
return
483+
};
484+
pending_value = pending_value - tickets_supply;
477485
if (pending_value < ONE_SUI) {
478486
return
479487
};
@@ -581,10 +589,12 @@ module liquid_staking::native_pool {
581589
ctx: &mut TxContext
582590
): Coin<SUI> {
583591

592+
assert!(vector::length(&validators) > 0, E_NOTHING_TO_UNSTAKE);
584593
let i = vector::length(&validators) - 1;
585594

586-
let total_removed_balance = balance::zero<SUI>();
587-
let total_removed_value = 0;
595+
let total_removed_value = coin::value(&self.pending);
596+
let total_removed_balance = coin::into_balance(coin::split(&mut self.pending, total_removed_value, ctx));
597+
588598
let collectable_reward = 0;
589599

590600
while (total_removed_value < amount_to_unstake) {
@@ -624,6 +634,7 @@ module liquid_staking::native_pool {
624634
};
625635

626636
// extract our fees
637+
assert!(balance::value(&total_removed_balance) >= fee + collectable_reward, E_NOT_ENOUGH_BALANCE);
627638
let fee_balance = balance::split(&mut total_removed_balance, fee + collectable_reward);
628639
coin::join(&mut self.collectable_fee, coin::from_balance(fee_balance, ctx));
629640

@@ -651,6 +662,9 @@ module liquid_staking::native_pool {
651662

652663
// unstake validators with zero priority and stake to top validator
653664
public entry fun rebalance(self: &mut NativePool, wrapper: &mut SuiSystemState, ctx: &mut TxContext) {
665+
assert_version(self);
666+
when_not_paused(self);
667+
654668
// calculate total stake of validators
655669
let validators = validator_set::get_bad_validators(&self.validator_set);
656670
let unstaked_sui = unstake_amount_from_validators(self, wrapper, MAX_UINT_64, 0, validators, ctx);

liquid_staking/sources/validator_set.move

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ module liquid_staking::validator_set {
145145
self.sorted_validators = sorted;
146146
}
147147

148+
// @dev add or update validator and priority
148149
public(friend) fun update_validators(self: &mut ValidatorSet, validators: vector<address>, priorities: vector<u64>) {
149150
let length = vector::length(&validators);
150151
assert!(length < MAX_VLDRS_UPDATE, E_TOO_MANY_VLDRS);
@@ -227,7 +228,10 @@ module liquid_staking::validator_set {
227228

228229
let staked_sui_to_withdraw;
229230
let rest_requested_amount = requested_amount - balance::value(&total_withdrawn);
230-
if (rest_requested_amount >= MIST_PER_SUI && principal_value > rest_requested_amount && principal_value - rest_requested_amount >= MIST_PER_SUI) {
231+
if (rest_requested_amount < MIST_PER_SUI) {
232+
rest_requested_amount = MIST_PER_SUI
233+
};
234+
if (principal_value > rest_requested_amount && principal_value - rest_requested_amount >= MIST_PER_SUI) {
231235
// it's possible to split StakedSui
232236
staked_sui_to_withdraw = staking_pool::split(staked_sui_mut_ref, rest_requested_amount, ctx);
233237
principal_value = rest_requested_amount;

liquid_staking/tests/native_pool_tests.move

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ module liquid_staking::native_pool_tests {
174174
// Stake SUI, epoch = 1
175175
next_tx(&mut scenario, SENDER);
176176
{
177-
let sui = coin::mint_for_testing<SUI>(MIST_PER_SUI, ctx(&mut scenario)); // 1 SUI
177+
let sui = coin::mint_for_testing<SUI>(MIST_PER_SUI * 2, ctx(&mut scenario)); // 1 SUI
178178
let pool = test_scenario::take_shared<NativePool>(&scenario);
179179
let metadata = test_scenario::take_shared<Metadata<CERT>>(&scenario);
180180
let system_state = test_scenario::take_shared<SuiSystemState>(&scenario);
@@ -193,16 +193,16 @@ module liquid_staking::native_pool_tests {
193193
let pool = test_scenario::take_shared<NativePool>(&scenario);
194194

195195
let total_staked = native_pool::get_total_staked(&pool);
196-
test_utils::assert_eq(total_staked, MIST_PER_SUI * 101);
196+
test_utils::assert_eq(total_staked, MIST_PER_SUI * 102);
197197
let total_active_stake = native_pool::get_total_active_stake(&pool, ctx(&mut scenario));
198-
test_utils::assert_eq(total_active_stake, MIST_PER_SUI * 100);
198+
test_utils::assert_eq(total_active_stake, MIST_PER_SUI * 101);
199199

200200
advance_epoch(&mut scenario);
201201

202202
let total_staked = native_pool::get_total_staked(&pool);
203-
test_utils::assert_eq(total_staked, MIST_PER_SUI * 101);
203+
test_utils::assert_eq(total_staked, MIST_PER_SUI * 102);
204204
let total_active_stake = native_pool::get_total_active_stake(&pool, ctx(&mut scenario));
205-
test_utils::assert_eq(total_active_stake, MIST_PER_SUI * 101);
205+
test_utils::assert_eq(total_active_stake, MIST_PER_SUI * 102);
206206

207207
test_scenario::return_shared(pool);
208208
};
@@ -223,9 +223,9 @@ module liquid_staking::native_pool_tests {
223223
coin::burn_for_testing(sui);
224224

225225
let total_staked = native_pool::get_total_staked(&pool);
226-
test_utils::assert_eq(total_staked, MIST_PER_SUI * 100);
226+
test_utils::assert_eq(total_staked, MIST_PER_SUI * 101);
227227
let total_active_stake = native_pool::get_total_active_stake(&pool, ctx);
228-
test_utils::assert_eq(total_active_stake, MIST_PER_SUI * 100);
228+
test_utils::assert_eq(total_active_stake, MIST_PER_SUI * 101);
229229

230230
let ticket_supply = native_pool::get_ticket_supply(&pool);
231231
test_utils::assert_eq(ticket_supply, MIST_PER_SUI);
@@ -436,9 +436,9 @@ module liquid_staking::native_pool_tests {
436436
let owner_cap = test_scenario::take_from_sender<OwnerCap>(&scenario);
437437
let pool = test_scenario::take_shared<NativePool>(&scenario);
438438

439-
native_pool::change_min_stake(&mut pool, &owner_cap, 2);
439+
native_pool::change_min_stake(&mut pool, &owner_cap, 2002);
440440
let min_stake = native_pool::get_min_stake(&pool);
441-
test_utils::assert_eq(min_stake, 2);
441+
test_utils::assert_eq(min_stake, 2002);
442442

443443
test_scenario::return_to_address<OwnerCap>(SENDER, owner_cap);
444444
test_scenario::return_shared(pool);

0 commit comments

Comments
 (0)