diff --git a/pallets/dapp-staking-v3/README.md b/pallets/dapp-staking-v3/README.md index 9022056568..98a68c5be5 100644 --- a/pallets/dapp-staking-v3/README.md +++ b/pallets/dapp-staking-v3/README.md @@ -44,8 +44,63 @@ Neither stakers nor dApps earn rewards during this subperiod - no new rewards ar `Build&Earn` subperiod consits of one or more eras, therefore its length is expressed in eras. -After each _era_ end, eligible stakers and dApps can claim the rewards they earned. Rewards are only claimable for the finished eras. +After each _era_ ends, eligible stakers and dApps can claim the rewards they earned. Rewards are **only** claimable for the finished eras. It is still possible to _stake_ during this period, and stakers are encouraged to do so since this will increase the rewards they earn. -The only exemption is the **final era** of the `build&earn` subperiod - it's not possible to _stake_ then since the stake would be invalid anyhow (stake is only valid from the next era). +The only exemption is the **final era** of the `build&earn` subperiod - it's not possible to _stake_ then since the stake would be invalid anyhow (stake is only valid from the next era which would be in the next period). +### dApps & Smart Contracts + +Protocol is called dApp staking, but internally it essentially works with smart contracts, or even more precise, smart contract addresses. + +Throughout the code, when addressing a particular dApp, it's addressed as `smart contract`. Naming of the types & storage more closely follows `dApp` nomenclature. + +#### Registration + +Projects, or _dApps_, must be registered into protocol to participate. +Only a privileged `ManagerOrigin` can perform dApp registration. +The pallet itself does not make assumptions who the privileged origin is, and it can differ from runtime to runtime. + +There is a limit of how many smart contracts can be registered at once. Once the limit is reached, any additional attempt to register a new contract will fail. + +#### Reward Beneficiary & Ownership + +When contract is registered, it is assigned a unique compact numeric Id - 16 bit unsigned integer. This is important for the inner workings of the pallet, and is not directly exposed to the users. + +After a dApp has been registered, it is possible to modify reward beneficiary or even the owner of the dApp. The owner can perform reward delegation and can further transfer ownership. + +#### Unregistration + +dApp can be removed from the procotol by unregistering it. +This is a privileged action that only `ManagerOrigin` can perform. + +After a dApp has been unregistered, it's no longer eligible to receive rewards. +It's still possible however to claim past unclaimed rewards. + +Important to note that even if dApp has been unregistered, it still occupies a _slot_ +in the dApp staking protocol and counts towards maximum number of registered dApps. +This will be improved in the future when dApp data will be cleaned up after the period ends. + +### Stakers + +#### Locking Funds + +In order for users to participate in dApp staking, the first step they need to take is lock some native currency. Reserved tokens cannot be locked, but tokens locked by another lock can be re-locked into dApp staking (double locked). + +**NOTE:** Locked funds cannot be used for paying fees, or for transfer. + +In order to participate, user must have a `MinimumLockedAmount` of native currency locked. This doesn't mean that they cannot lock _less_ in a single call, but total locked amount must always be equal or greater than `MinimumLockedAmount`. + +In case amount specified for locking is greater than what user has available, only what's available will be locked. + +#### Unlocking Funds + +User can at any time decide to unlock their tokens. However, it's not possible to unlock tokens which are staked, so user has to unstake them first. + +Once _unlock_ is successfully executed, the tokens aren't immediately unlocked, but instead must undergo the unlocking process. Once unlocking process has finished, user can _claim_ their unlocked tokens into their free balance. + +There is a limited number of `unlocking chunks` a user can have at any point in time. If limit is reached, user must claim existing unlocked chunks, or wait for them to be unlocked before claiming them to free up space for new chunks. + +In case calling unlocking some amount would take the user below the `MinimumLockedAmount`, **everything** will be unlocked. + +For users who decide they would rather re-lock their tokens then wait for the unlocking process to finish, there's an option to do so. All currently unlocking chunks are consumed, and added back into locked amount. \ No newline at end of file diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 654c53b28d..cd63dff29e 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -819,9 +819,6 @@ pub mod pallet { /// /// In case caller account doesn't have sufficient balance to cover the specified amount, everything is locked. /// After adjustment, lock amount must be greater than zero and in total must be equal or greater than the minimum locked amount. - /// - /// It is possible for call to fail due to caller account already having too many locked balance chunks in storage. To solve this, - /// caller should claim pending rewards, before retrying to lock additional funds. #[pallet::call_index(5)] #[pallet::weight(Weight::zero())] pub fn lock(origin: OriginFor, #[pallet::compact] amount: Balance) -> DispatchResult { diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index 61a45152a9..8f48239666 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -86,10 +86,6 @@ pub type AccountLedgerFor = AccountLedger, ::M pub type DAppTierRewardsFor = DAppTierRewards, ::NumberOfTiers>; -// TODO: temp experimental type, don't review -pub type ContractEntriesFor = - ExperimentalContractStakeEntries, ::NumberOfTiers>; - // Helper struct for converting `u16` getter into `u32` #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct MaxNumberOfContractsU32(PhantomData); @@ -357,10 +353,6 @@ pub struct AccountLedger< /// Number of contract stake entries in storage. #[codec(compact)] pub contract_stake_count: u32, - // TODO: introduce a variable which keeps track of the latest era for which the rewards have been calculated. - // This is needed since in case we break up reward calculation into multiple blocks, we should prohibit staking until - // reward calculation has finished. - // >>> Only if we decide to break calculation into multiple steps. } impl Default for AccountLedger @@ -1695,7 +1687,7 @@ pub trait RewardPoolProvider { fn bonus_reward_pool() -> Balance; } -// TODO: this is experimental, don't review +// TODO: these are experimental, don't review #[derive(Encode, Decode, MaxEncodedLen, Copy, Clone, Debug, PartialEq, Eq, TypeInfo)] pub struct ExperimentalContractStakeEntry { #[codec(compact)] @@ -1706,7 +1698,6 @@ pub struct ExperimentalContractStakeEntry { pub build_and_earn: Balance, } -// TODO: this is experimental, don't review #[derive( Encode, Decode, @@ -1727,3 +1718,7 @@ pub struct ExperimentalContractStakeEntries, NT: Get> { #[codec(compact)] pub period: PeriodNumber, } + +// TODO: temp experimental type, don't review +pub type ContractEntriesFor = + ExperimentalContractStakeEntries, ::NumberOfTiers>;