Skip to content

Commit

Permalink
[sui-system] minimum staking threshold of 1 SUI (#9961)
Browse files Browse the repository at this point in the history
## Description 

Took over the work @dmitri-perelman started (and almost finished) in
#9825 because I can't push to his fork of the repo.

## Test Plan 

Added some tests.

---
If your changes are not user-facing and not a breaking change, you can
skip the following section. Otherwise, please indicate what changed, and
then add to the Release Notes section as highlighted during the release
process.

### Type of Change (Check all that apply)

- [x] user-visible impact
- [ ] breaking change for a client SDKs
- [ ] breaking change for FNs (FN binary must upgrade)
- [ ] breaking change for validators or node operators (must upgrade
binaries)
- [ ] breaking change for on-chain data layout
- [ ] necessitate either a data wipe or data migration

### Release notes

---------

Co-authored-by: Dmitri Perelman <dmitrip@Dmitris-MacBook-Pro.local>
  • Loading branch information
emmazzz and Dmitri Perelman committed Mar 28, 2023
1 parent 976d3e1 commit 15eae36
Show file tree
Hide file tree
Showing 18 changed files with 359 additions and 213 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -240,56 +240,56 @@ validators:
next_epoch_worker_address: ~
extra_fields:
id:
id: "0xf64a2f2782984f7b7a36a99c9d77a83b3b6b5ebecf6ee0eaf118a37d74925c00"
id: "0x5e311ba6292362f225da9c71cf52097ca86b95fe6f4863a88c8e34a262a01193"
size: 0
voting_power: 10000
operation_cap_id: "0x62a99cd4412cb992da5a1035d6021db91e041704625a4010af68d1b0100a3177"
operation_cap_id: "0x669f5c0b0ca9066ace330aba5135ea3d5bbfdd4da5733574d0c596c8787d92de"
gas_price: 1
staking_pool:
id: "0xa110faecebe16b6d167929f7ee40acb2c8c1341eb80c5a24e92fe8dc1cd85015"
id: "0x2a6e996bd69665ad4b2e880c60ec497fb38ca17cc282264222f5ba00ea5d25c8"
activation_epoch: 0
deactivation_epoch: ~
sui_balance: 20000000000000000
rewards_pool:
value: 0
pool_token_balance: 20000000000000000
exchange_rates:
id: "0x77dbaaae503d2664c5e6dfdd01d0bc46b1edf85fc927be9ece5cfd5f0c7a48ef"
id: "0x34c71362a7bfbbd2f2e1ddc116e22834185f8e84635dd819e5432b35bca560aa"
size: 1
pending_stake: 0
pending_total_sui_withdraw: 0
pending_pool_token_withdraw: 0
extra_fields:
id:
id: "0x4898c94bc523d09495c8f9f0947785a3d27e6fbc904c7aa13f48bd90b3032ac7"
id: "0x9540bb52b6eb64682154ab9f190069b2f65408326ca1cde6879bcd22f41ea436"
size: 0
commission_rate: 0
next_epoch_stake: 20000000000000000
next_epoch_gas_price: 1
next_epoch_commission_rate: 0
extra_fields:
id:
id: "0x6daf7eb399ff05a5c2567b7bbb125c9451433af8b425904ab54debbdd28b38df"
id: "0x32da93ecef6352085e4a98e8fdc6ef53f58a87867735e5963e2862da4ca7ebf4"
size: 0
pending_active_validators:
contents:
id: "0x66748b0af8b5eb3e9414d0fd7b424031ec634dc036b8a7a16d17b59e48c514f4"
id: "0x2c9d0fce0e485143215ddf9b3bad49a90faaa08abbe603d6268064e0fa11de63"
size: 0
pending_removals: []
staking_pool_mappings:
id: "0x8091ccc40b81fafe63c18b385bef35ca34f86dc8ce03b14a5c5bd2ecc764dfcc"
id: "0x0e8b457d90c99717d5deafde80d2e6c2c930ededf359d0dde79488fae9d2c70d"
size: 1
inactive_validators:
id: "0xd2427484e7572464744d5ac7805d36e083ab262fef2f8c8cb16e4bf80eeba28e"
id: "0xe5e4e20e15059e13633058858aa474a3d50e647ba500b6ab2eab85a1ffd31ac2"
size: 0
validator_candidates:
id: "0x575efc4d1aa2dac9276de776fe85bab09f1dcde06481d19309094b460d4666d5"
id: "0xc7bb461afa1ee2ca919443255525031ccf3dfafd6aabca790053afffaef11258"
size: 0
at_risk_validators:
contents: []
extra_fields:
id:
id: "0x341985f35823807fb3acf0a34c0b8bf152b355c3638dca24a3222701324eafe7"
id: "0x89b6475302daabe7d012b2f70b706551cbe84e6c4f23ae4713e472af36bcb239"
size: 0
storage_fund:
total_object_storage_rebates:
Expand All @@ -306,7 +306,7 @@ parameters:
validator_low_stake_grace_period: 7
extra_fields:
id:
id: "0xfcfc2dd968cefbf2e4d4679d06ac311ad5eb58fc4ea7d2e988eec89b8e1ec85f"
id: "0xa95d9ca79ae9361d0fa0086c09d61818a4c95926d4ff8873af54fa7c3d033288"
size: 0
reference_gas_price: 1
validator_report_records:
Expand All @@ -320,7 +320,7 @@ stake_subsidy:
stake_subsidy_decrease_rate: 10000
extra_fields:
id:
id: "0x08d8bb5dcbae6e7e0cff0ba0aa23ec8998794cb8e465dd0db6c45cf84752b25b"
id: "0x7590e21a4280f3e5b567da3338e491df195f724b7f908e6cf543717dbbaf3040"
size: 0
safe_mode: false
safe_mode_storage_rewards:
Expand All @@ -332,6 +332,6 @@ safe_mode_non_refundable_storage_fee: 0
epoch_start_timestamp_ms: 10
extra_fields:
id:
id: "0x1f79bdc6d1399738cc06184895e2bc41c76b3c06ddb3d3ece4549f45bf0de724"
id: "0x139f148cc3a7ad72f792389ed8d63875c594fbd59bd7c65a6c4bb01c1a28be49"
size: 0

31 changes: 28 additions & 3 deletions crates/sui-framework/docs/staking_pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,15 @@ A self-custodial object holding the staked SUI tokens.



<a name="0x3_staking_pool_EStakedSuiBelowThreshold"></a>



<pre><code><b>const</b> <a href="staking_pool.md#0x3_staking_pool_EStakedSuiBelowThreshold">EStakedSuiBelowThreshold</a>: u64 = 18;
</code></pre>



<a name="0x3_staking_pool_ETokenBalancesDoNotMatchExchangeRate"></a>


Expand Down Expand Up @@ -397,6 +406,16 @@ A self-custodial object holding the staked SUI tokens.



<a name="0x3_staking_pool_MIN_STAKING_THRESHOLD"></a>

StakedSui objects cannot be split to below this amount.


<pre><code><b>const</b> <a href="staking_pool.md#0x3_staking_pool_MIN_STAKING_THRESHOLD">MIN_STAKING_THRESHOLD</a>: u64 = 1000000000;
</code></pre>



<a name="0x3_staking_pool_new"></a>

## Function `new`
Expand Down Expand Up @@ -1049,7 +1068,7 @@ Split the given StakedSui to the two parts, one with principal <code>split_amoun
transfer the newly split part to the sender address.


<pre><code><b>public</b> entry <b>fun</b> <a href="staking_pool.md#0x3_staking_pool_split_staked_sui">split_staked_sui</a>(c: &<b>mut</b> <a href="staking_pool.md#0x3_staking_pool_StakedSui">staking_pool::StakedSui</a>, split_amount: u64, ctx: &<b>mut</b> <a href="_TxContext">tx_context::TxContext</a>)
<pre><code><b>public</b> entry <b>fun</b> <a href="staking_pool.md#0x3_staking_pool_split_staked_sui">split_staked_sui</a>(stake: &<b>mut</b> <a href="staking_pool.md#0x3_staking_pool_StakedSui">staking_pool::StakedSui</a>, split_amount: u64, ctx: &<b>mut</b> <a href="_TxContext">tx_context::TxContext</a>)
</code></pre>


Expand All @@ -1058,8 +1077,14 @@ transfer the newly split part to the sender address.
<summary>Implementation</summary>


<pre><code><b>public</b> entry <b>fun</b> <a href="staking_pool.md#0x3_staking_pool_split_staked_sui">split_staked_sui</a>(c: &<b>mut</b> <a href="staking_pool.md#0x3_staking_pool_StakedSui">StakedSui</a>, split_amount: u64, ctx: &<b>mut</b> TxContext) {
<a href="_transfer">transfer::transfer</a>(<a href="staking_pool.md#0x3_staking_pool_split">split</a>(c, split_amount, ctx), <a href="_sender">tx_context::sender</a>(ctx));
<pre><code><b>public</b> entry <b>fun</b> <a href="staking_pool.md#0x3_staking_pool_split_staked_sui">split_staked_sui</a>(stake: &<b>mut</b> <a href="staking_pool.md#0x3_staking_pool_StakedSui">StakedSui</a>, split_amount: u64, ctx: &<b>mut</b> TxContext) {
<b>let</b> original_amount = <a href="_value">balance::value</a>(&stake.principal);
<b>assert</b>!(split_amount &lt;= original_amount, <a href="staking_pool.md#0x3_staking_pool_EInsufficientSuiTokenBalance">EInsufficientSuiTokenBalance</a>);
<b>let</b> remaining_amount = original_amount - split_amount;
// Both resulting parts should have at least <a href="staking_pool.md#0x3_staking_pool_MIN_STAKING_THRESHOLD">MIN_STAKING_THRESHOLD</a>.
<b>assert</b>!(remaining_amount &gt;= <a href="staking_pool.md#0x3_staking_pool_MIN_STAKING_THRESHOLD">MIN_STAKING_THRESHOLD</a>, <a href="staking_pool.md#0x3_staking_pool_EStakedSuiBelowThreshold">EStakedSuiBelowThreshold</a>);
<b>assert</b>!(split_amount &gt;= <a href="staking_pool.md#0x3_staking_pool_MIN_STAKING_THRESHOLD">MIN_STAKING_THRESHOLD</a>, <a href="staking_pool.md#0x3_staking_pool_EStakedSuiBelowThreshold">EStakedSuiBelowThreshold</a>);
<a href="_transfer">transfer::transfer</a>(<a href="staking_pool.md#0x3_staking_pool_split">split</a>(stake, split_amount, ctx), <a href="_sender">tx_context::sender</a>(ctx));
}
</code></pre>

Expand Down
21 changes: 21 additions & 0 deletions crates/sui-framework/docs/validator_set.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,15 @@ The epoch value corresponds to the first epoch this change takes place.
## Constants


<a name="0x3_validator_set_MIN_STAKING_THRESHOLD"></a>



<pre><code><b>const</b> <a href="validator_set.md#0x3_validator_set_MIN_STAKING_THRESHOLD">MIN_STAKING_THRESHOLD</a>: u64 = 1000000000;
</code></pre>



<a name="0x3_validator_set_EInvalidCap"></a>


Expand Down Expand Up @@ -477,6 +486,15 @@ The epoch value corresponds to the first epoch this change takes place.



<a name="0x3_validator_set_EStakingBelowThreshold"></a>



<pre><code><b>const</b> <a href="validator_set.md#0x3_validator_set_EStakingBelowThreshold">EStakingBelowThreshold</a>: u64 = 10;
</code></pre>



<a name="0x3_validator_set_EValidatorNotCandidate"></a>


Expand Down Expand Up @@ -743,6 +761,7 @@ Only an active validator can request to be removed.
Called by <code><a href="sui_system.md#0x3_sui_system">sui_system</a></code>, to add a new stake to the validator.
This request is added to the validator's staking pool's pending stake entries, processed at the end
of the epoch.
Aborts in case the staking amount is smaller than MIN_STAKING_THRESHOLD


<pre><code><b>public</b>(<b>friend</b>) <b>fun</b> <a href="validator_set.md#0x3_validator_set_request_add_stake">request_add_stake</a>(self: &<b>mut</b> <a href="validator_set.md#0x3_validator_set_ValidatorSet">validator_set::ValidatorSet</a>, validator_address: <b>address</b>, stake: <a href="_Balance">balance::Balance</a>&lt;<a href="_SUI">sui::SUI</a>&gt;, ctx: &<b>mut</b> <a href="_TxContext">tx_context::TxContext</a>)
Expand All @@ -760,6 +779,8 @@ of the epoch.
stake: Balance&lt;SUI&gt;,
ctx: &<b>mut</b> TxContext,
) {
<b>let</b> sui_amount = <a href="_value">balance::value</a>(&stake);
<b>assert</b>!(sui_amount &gt;= <a href="validator_set.md#0x3_validator_set_MIN_STAKING_THRESHOLD">MIN_STAKING_THRESHOLD</a>, <a href="validator_set.md#0x3_validator_set_EStakingBelowThreshold">EStakingBelowThreshold</a>);
<b>let</b> <a href="validator.md#0x3_validator">validator</a> = <a href="validator_set.md#0x3_validator_set_get_candidate_or_active_validator_mut">get_candidate_or_active_validator_mut</a>(self, validator_address);
<a href="validator.md#0x3_validator_request_add_stake">validator::request_add_stake</a>(<a href="validator.md#0x3_validator">validator</a>, stake, <a href="_sender">tx_context::sender</a>(ctx), ctx);
}
Expand Down
14 changes: 12 additions & 2 deletions crates/sui-framework/packages/sui-system/sources/staking_pool.move
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ module sui_system::staking_pool {
friend sui_system::validator;
friend sui_system::validator_set;

/// StakedSui objects cannot be split to below this amount.
const MIN_STAKING_THRESHOLD: u64 = 1_000_000_000; // 1 SUI

const EInsufficientPoolTokenBalance: u64 = 0;
const EWrongPool: u64 = 1;
const EWithdrawAmountCannotBeZero: u64 = 2;
Expand All @@ -35,6 +38,7 @@ module sui_system::staking_pool {
const EPoolNotPreactive: u64 = 15;
const EActivationOfInactivePool: u64 = 16;
const EDelegationOfZeroSui: u64 = 17;
const EStakedSuiBelowThreshold: u64 = 18;

/// A staking pool embedded in each validator struct in the system state object.
struct StakingPool has key, store {
Expand Down Expand Up @@ -342,8 +346,14 @@ module sui_system::staking_pool {

/// Split the given StakedSui to the two parts, one with principal `split_amount`,
/// transfer the newly split part to the sender address.
public entry fun split_staked_sui(c: &mut StakedSui, split_amount: u64, ctx: &mut TxContext) {
transfer::transfer(split(c, split_amount, ctx), tx_context::sender(ctx));
public entry fun split_staked_sui(stake: &mut StakedSui, split_amount: u64, ctx: &mut TxContext) {
let original_amount = balance::value(&stake.principal);
assert!(split_amount <= original_amount, EInsufficientSuiTokenBalance);
let remaining_amount = original_amount - split_amount;
// Both resulting parts should have at least MIN_STAKING_THRESHOLD.
assert!(remaining_amount >= MIN_STAKING_THRESHOLD, EStakedSuiBelowThreshold);
assert!(split_amount >= MIN_STAKING_THRESHOLD, EStakedSuiBelowThreshold);
transfer::transfer(split(stake, split_amount, ctx), tx_context::sender(ctx));
}

/// Consume the staked sui `other` and add its value to `self`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ module sui_system::validator_set {
const ANY_VALIDATOR: u8 = 3;

const BASIS_POINT_DENOMINATOR: u128 = 10000;
const MIN_STAKING_THRESHOLD: u64 = 1_000_000_000; // 1 SUI

// Errors
const ENonValidatorInReportRecords: u64 = 0;
Expand All @@ -120,7 +121,7 @@ module sui_system::validator_set {
const EValidatorNotCandidate: u64 = 7;
const ENotValidatorCandidate: u64 = 8;
const ENotActiveOrPendingValidator: u64 = 9;

const EStakingBelowThreshold: u64 = 10;
const EInvalidCap: u64 = 101;


Expand Down Expand Up @@ -265,12 +266,15 @@ module sui_system::validator_set {
/// Called by `sui_system`, to add a new stake to the validator.
/// This request is added to the validator's staking pool's pending stake entries, processed at the end
/// of the epoch.
/// Aborts in case the staking amount is smaller than MIN_STAKING_THRESHOLD
public(friend) fun request_add_stake(
self: &mut ValidatorSet,
validator_address: address,
stake: Balance<SUI>,
ctx: &mut TxContext,
) {
let sui_amount = balance::value(&stake);
assert!(sui_amount >= MIN_STAKING_THRESHOLD, EStakingBelowThreshold);
let validator = get_candidate_or_active_validator_mut(self, validator_address);
validator::request_add_stake(validator, stake, tx_context::sender(ctx), ctx);
}
Expand Down
Loading

3 comments on commit 15eae36

@vercel
Copy link

@vercel vercel bot commented on 15eae36 Mar 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

explorer – ./apps/explorer

explorer-git-main-mysten-labs.vercel.app
explorer-topaz.vercel.app
explorer.sui.io
explorer-mysten-labs.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 15eae36 Mar 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

wallet-adapter – ./sdk/wallet-adapter/example

wallet-adapter-git-main-mysten-labs.vercel.app
sui-wallet-adapter.vercel.app
wallet-adapter-mysten-labs.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 15eae36 Mar 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

explorer-storybook – ./apps/explorer

explorer-storybook.vercel.app
explorer-storybook-git-main-mysten-labs.vercel.app
explorer-storybook-mysten-labs.vercel.app

Please sign in to comment.