Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Treasury support KTON Proposal #306

Merged
merged 19 commits into from
Mar 3, 2020
Merged
Show file tree
Hide file tree
Changes from 2 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
9 changes: 9 additions & 0 deletions frame/balances/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Balances

Balances currently contains **RING** and **KTON**.

**RING** is system token of Darwinia Network, the initial supply before Darwinia network mainnet release is 2 billion.

**KTON** is the staking and governance credential of Darwinia Network, KTON can **only obtained by locking RING**, the initial supply is 0.

At present, some **RING** and **KTON** exist in the Ethereum network and the Tron network in the form of **ERC-20** and **TRC-20**. These TOKENs will be transferred to the Darwinia main network by 1:1 cross-chain conversion after the Darwinia main online.
31 changes: 31 additions & 0 deletions frame/balances/kton/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Kton

To encourage users to make long term commitments and pledge, users can choose to lock RING for 3 - 36 months in the process of Staking, and the system will offer a KTON token as reward for users participating in Staking. During the committed pledge period, users can not unlock their RING. (Unless pay triple amounts of KTON as penalty)

As a result, during RING staking process, user can choose to **lock RING for a period to receive KTON**. The initial supply amount of KTON should be zero, yet before Darwinia Mainnet launch, some users have already started locking their RING in Evolution Land, so there will be some KTON supply at the time of mainnet launch. The earliest design to obtain the KTON by locking the RING appears in the Gringotts of Evolution Land. The related introduction can refer to the Gringotts KTON model [5].

KTON can be pledged to receive Staking power, so as to participate POS mining as well. User may Staking via pledge KTON, if user take back their staking KTON, then related POS mining is stopped, and it takes 14 days for unpledged KTON to arrive.

## FAQ

### What is Kton?

**KTON** is the staking and governance credential of Darwinia Network, KTON can **only obtained by locking RING**, the initial supply is 0.

### Where Kton from?

Users can choose to lock RING for 3 - 36 months in the process of Staking, and the system will offer a KTON token as reward for users participating in Staking.

### When Kton spends?

1. Transfer to other accounts.

2. Burned by slashed.

### What will happen after slashing?

Slashed token goes to tresure.


---
(5): https://forum.evolution.land/topics/55
3 changes: 3 additions & 0 deletions frame/balances/ring/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# RING

**RING** is system token of Darwinia Network, the initial supply before Darwinia network mainnet release is 2 billion.
116 changes: 93 additions & 23 deletions frame/treasury/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ mod types {
pub type RingBalance<T> = <RingCurrency<T> as Currency<AccountId<T>>>::Balance;
pub type RingPositiveImbalance<T> = <RingCurrency<T> as Currency<AccountId<T>>>::PositiveImbalance;
pub type RingNegativeImbalance<T> = <RingCurrency<T> as Currency<AccountId<T>>>::NegativeImbalance;

pub type StakingBalanceT<T> = StakingBalance<RingBalance<T>, KtonBalance<T>>;
pub type KtonBalance<T> = <KtonCurrency<T> as Currency<AccountId<T>>>::Balance;
pub type KtonNegativeImbalance<T> = <KtonCurrency<T> as Currency<AccountId<T>>>::NegativeImbalance;

Expand All @@ -83,7 +83,7 @@ use frame_system::{self as system, ensure_signed};
use serde::{Deserialize, Serialize};
use sp_runtime::{
traits::{AccountIdConversion, EnsureOrigin, Saturating, StaticLookup, Zero},
ModuleId, Permill,
ModuleId, Permill, RuntimeDebug,
};
use sp_std::prelude::*;

Expand All @@ -95,6 +95,7 @@ const MODULE_ID: ModuleId = ModuleId(*b"py/trsry");
pub trait Trait: frame_system::Trait {
/// The staking *RING*.
type RingCurrency: Currency<Self::AccountId> + ReservableCurrency<Self::AccountId>;

/// The staking *Kton*.
type KtonCurrency: Currency<Self::AccountId> + ReservableCurrency<Self::AccountId>;

Expand All @@ -115,7 +116,7 @@ pub trait Trait: frame_system::Trait {
type ProposalBond: Get<Permill>;

/// Minimum amount of funds that should be placed in a deposit for making a proposal.
type ProposalBondMinimum: Get<RingBalance<Self>>;
type ProposalBondMinimum: Get<StakingBalanceT<Self>>;
clearloop marked this conversation as resolved.
Show resolved Hide resolved

/// Period between successive spends.
type SpendPeriod: Get<Self::BlockNumber>;
Expand All @@ -126,14 +127,23 @@ pub trait Trait: frame_system::Trait {

type ProposalIndex = u32;

/// To unify *Ring* and *Kton* balances. Ref to the solution at
/// [`darwinia_staking`](../darwinia_staking/enum.StakingBalance.html),
/// keep the `StakingBalance` name for upgrade usages.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Ord, PartialOrd)]
pub enum StakingBalance<RingBalance, KtonBalance> {
RingBalance(RingBalance),
KtonBalance(KtonBalance),
}
clearloop marked this conversation as resolved.
Show resolved Hide resolved

decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
/// Fraction of a proposal's value that should be bonded in order to place the proposal.
/// An accepted proposal gets these back. A rejected proposal does not.
const ProposalBond: Permill = T::ProposalBond::get();

/// Minimum amount of funds that should be placed in a deposit for making a proposal.
const ProposalBondMinimum: RingBalance<T> = T::ProposalBondMinimum::get();
const ProposalBondMinimum: StakingBalanceT<T> = T::ProposalBondMinimum::get();

/// Period between successive spends.
const SpendPeriod: T::BlockNumber = T::SpendPeriod::get();
Expand All @@ -157,21 +167,52 @@ decl_module! {
#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
fn propose_spend(
origin,
#[compact] value: RingBalance<T>,
value: StakingBalanceT<T>,
beneficiary: <T::Lookup as StaticLookup>::Source
) {
let proposer = ensure_signed(origin)?;
let beneficiary = T::Lookup::lookup(beneficiary)?;

let bond = Self::calculate_bond(value);
T::RingCurrency::reserve(&proposer, bond)
.map_err(|_| <Error<T>>::InsufficientProposersBalance)?;

let c = Self::proposal_count();
ProposalCount::put(c + 1);
<Proposals<T>>::insert(c, Proposal { proposer, value, beneficiary, bond });

Self::deposit_event(RawEvent::Proposed(c));
match value {
StakingBalance::RingBalance(value) => {
let proposer = ensure_signed(origin)?;
let beneficiary = T::Lookup::lookup(beneficiary)?;

// TODO: must be true, error handling.
if let StakingBalance::RingBalance(bond) = Self::calculate_bond(
StakingBalance::RingBalance(value)
) {
T::RingCurrency::reserve(&proposer, bond)
.map_err(|_| <Error<T>>::InsufficientProposersBalance)?;

let c = Self::proposal_count();
ProposalCount::put(c + 1);
<Proposals<T>>::insert(c, Proposal { proposer, value, beneficiary, bond });

Self::deposit_event(RawEvent::Proposed(c));
}
},
StakingBalance::KtonBalance(value) => {
// unimplemented!();
let proposer = ensure_signed(origin)?;
let _beneficiary = T::Lookup::lookup(beneficiary)?;

// TODO: must be true, error handling.
if let StakingBalance::KtonBalance(bond) = Self::calculate_bond(
StakingBalance::KtonBalance(value)
) {
T::KtonCurrency::reserve(&proposer, bond)
.map_err(|_| <Error<T>>::InsufficientProposersBalance)?;

let c = Self::proposal_count();
ProposalCount::put(c + 1);

// TODO: @clearloop
//
// This line requires completing StakingBalance store
// <Proposals<T>>::insert(c, Proposal { proposer, value, beneficiary, bond });

Self::deposit_event(RawEvent::Proposed(c));
}
}
clearloop marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// Reject a proposed spend. The original deposit will be slashed.
Expand All @@ -189,8 +230,22 @@ decl_module! {
let value = proposal.bond;
let imbalance = T::RingCurrency::slash_reserved(&proposal.proposer, value).0;
T::ProposalRejection::on_unbalanced(imbalance);

Self::deposit_event(Event::<T>::Rejected(proposal_id, value));


// match value {
// StakingBalance::KtonBalance(value) => {
// let imbalance = T::KtonCurrency::slash_reserved(&proposal.proposer, value).0;
// T::ProposalRejection::on_unbalanced(imbalance);
// Self::deposit_event(Event::<T>::Rejected(proposal_id, StakingBalance::KtonBalance(value)));
// },
// StakingBalance::RingBalance(value) => {
// let imbalance = T::RingCurrency::slash_reserved(&proposal.proposer, value).0;
// T::ProposalRejection::on_unbalanced(imbalance);
// Self::deposit_event(Event::<T>::Rejected(proposal_id, StakingBalance::RingBalance(value)));
// }
// }

}

/// Approve a proposal. At a later time, the proposal will be allocated to the beneficiary
Expand Down Expand Up @@ -222,11 +277,11 @@ decl_module! {
/// A spending proposal.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(Encode, Decode, Clone, PartialEq, Eq, sp_runtime::RuntimeDebug)]
pub struct Proposal<AccountId, RingBalance> {
pub struct Proposal<AccountId, StakingBalance> {
clearloop marked this conversation as resolved.
Show resolved Hide resolved
proposer: AccountId,
value: RingBalance,
value: StakingBalance,
beneficiary: AccountId,
bond: RingBalance,
bond: StakingBalance,
}

decl_storage! {
Expand All @@ -247,11 +302,19 @@ decl_storage! {
&<Module<T>>::account_id(),
T::RingCurrency::minimum_balance(),
);

// TODO: how to init both Ring and Kton in genesis?
//
// let _ = T::KtonCurrency::make_free_balance_be(
// &<Module<T>>::account_id(),
// T::KtonCurrency::minimum_balance(),
// );
clearloop marked this conversation as resolved.
Show resolved Hide resolved
});
}
}

decl_event!(
/// TODO: Events below needs to replace RingBalance to StakingBalance
clearloop marked this conversation as resolved.
Show resolved Hide resolved
pub enum Event<T>
where
<T as frame_system::Trait>::AccountId,
Expand Down Expand Up @@ -299,8 +362,15 @@ impl<T: Trait> Module<T> {
}

/// The needed bond for a proposal whose spend is `value`.
fn calculate_bond(value: RingBalance<T>) -> RingBalance<T> {
T::ProposalBondMinimum::get().max(T::ProposalBond::get() * value)
fn calculate_bond(value: StakingBalanceT<T>) -> StakingBalanceT<T> {
match value {
StakingBalance::KtonBalance(value) => {
T::ProposalBondMinimum::get().max(StakingBalance::KtonBalance(T::ProposalBond::get() * value))
}
StakingBalance::RingBalance(value) => {
T::ProposalBondMinimum::get().max(StakingBalance::RingBalance(T::ProposalBond::get() * value))
}
}
}

// Spend some money!
Expand Down