Architecture
Skrimples for Shibarium is comprised of four main components. 1) Skrimples Token
Skrimples Token
Skrimples is an ERC20 that powers the Skrimples ecosystem and has three primary uses:
Reward users who stake their $SKRIMP in the Boneyard
Register validators and determine their max delegation of $BONE
Governance of Ruffhouse Gang DAO
Skrimples has built in fees when traded on dexes. Fees are used to fund development, marketing, and for buybacks which can be redistributed as staking rewards.
Devs Bimpus and Snake have the ability to modify trading fees on $SKRIMP, but they fees cannot be raised over 5% on either buys or sells. While the contract is designed to allow the modification of fees, this is the only admin controlled function that could have any impact on the trading of the token.
The Boneyard
The Boneyard is a staking contract through which admins can create pools, and users can deposit their $SKRIMP (and other tokens) to earn rewards. Shibarium validators can secure a larger maximum delegation of $BONE from the protocol's LSD by staking $SKRIMP in pool 0.
The Boneyard is a fork of Sushiswap's MasterChef contract with some significant modifications. With the original contract it was impossible to create a staking pool for SUSHI, the reward token. The Boneyard allows the staking of $SKRIMP to be rewarded in $SKRIMP. Other changes are as follows:
Skrimples rewards per block is modifiable through an admin only function
ACL - Access Control used in favor of OpenZeppelin's Ownable contract
Removed the migrator and all related functions, along with the risk these posed to users
Skrimples is on a fixed supply, not mintable like SUSHI, so contract employs transferFrom function to move rewards from the treasury
stBONE
The stBONE contract is an ERC20 token contract which performs the following functions:
User interaction
Reward Distribution
Manage withdrawals
Manage reward fees
Delegate to validators
Mint and burn NFTs
ACL
Skrimples, stBONE, and the Boneyardcontract uses OpenZeppelin AccessControl to manage permissions.
User Interaction:
A user can interact only with the stBONE contract to:
Submit ERC20 BONE
Request Withdraw
Claim withdraw
call ERC20 functions
Users can submit BONE and get stBONE automatically by calling the submit function inside the StBone contract and passing the delegated amount.
Minting stBONE
The total amount of stBONE that a user will get when delegate his BONE tokens is calculated as follows:
sharePerUser = submittedBone * totalShares / totalPooledBone
The totalPooledBone is the total amount of the buffered tokens (submitted by the user but not yet delegated) plus the total delegated.
totalPooledBone = totalBufferedBone + totalDelegatedBones
Example:
Case 1
Initial states
totalShares | 0 |
---|---|
totalPooledBone | 0 |
User1 submit
submit ==> 1000 BONE
Gets ==> 1000 stBONE
Update states
totalShares | 1000 |
---|---|
totalPooledBONE | 1000 |
Users Shares
User | userP = userShares / totalShares | userBone = userP * totalPooledBone |
---|---|---|
1 | 1 = 1000 / 1000 | 1 * 1000 = 1000 |
Case 2
User2 submit
submit ==> 500 Bone
Gets ==> 500 * 1000 / 1000 = 500 stBone
Update states
totalShares | 1500 |
---|---|
totalPooledBone | 1500 |
Users Shares
User | userP = userShares / totalShares | userBone = userP * totalPooledBone |
---|---|---|
1 | 0.66 = 1000 / 1500 | 0.66 * 1500 = 1000 |
2 | 0.33 = 500/ 1500 | 0.33 * 1500 = 500 |
Case 3
The system was slashed => -100 BONE
Update states
totalShares | 1500 |
---|---|
totalPooledBone | 1500 - 100 = 1400 |
Users Shares
User | userP = userShares / totalShares | userBone = userP * totalPooledBone |
---|---|---|
1 | 0.66 = 1000 / 1500 | 0.66 * 1400 = 933.33 |
2 | 0.33 = 500/ 1500 | 0.33 * 1400 = 466.66 |
Case 4
User3 submit
submit ==> 500 Bone
Gets ==> 500 * 1500 / 1400 = 535.71 stBone
Update states
totalShares | 2035.71 |
---|---|
totalPooledBone | 1900 |
Users Shares
User | userP = userShares / totalShares | userBone= userP * totalPooledBone |
---|---|---|
1 | 0.4912= 1000 / 2035.71 | 0.4912 * 1900 = 933.33 |
2 | 0.2456= 500 / 2035.71 | 0.2456 * 1900 = 466.66 |
3 | 0.2631= 535.71 / 2035.71 | 0.2631 * 1900 = 500 |
Case 4
The system accumulates reward => +200 BONE
Update states
totalShares | 2035.71 |
---|---|
totalPooledBone | 1900 + 200 = 2100 |
Users Shares
User | userP = userShares / totalShares | userBone = userP * totalPooledBone |
---|---|---|
1 | 0.4912= 1000 / 2035.71 | 0.4912 * 2100=1031.52 |
2 | 0.2456= 500 / 2035.71 | 0.2456 * 2100= 515.76 |
3 | 0.2631= 535.71 / 2035.71 | 0.2631 * 2100= 552.62 |
When the system gets slashed, the total pooled BONE decreases, and it increases when a user submits BONE again or the system gets rewarded.
Delegate to Validators
The StBone contract facilitates token delegation to validators.
The delegation process relies on the bufferedBone tokens stored within the StBone contract. Once the minDelegationAmount is reached, the delegation to all Staked operators begins. Each operator is assigned a maxDelegateLimit value, determined by the DAO. For instance, trusted operators will have larger values, while non-trusted validators will have lower values. This maxDelegateLimit allows us to distribute tokens among these operators.
Trusted validators with the greatest number of shares of staked $SKRIMP in the Boneyard will receive the highest maxDelegateLimit.
Manage Withdrawals
Withdrawals are processed using the new validatorShare exit API, which introduces a unique nonce for each user request. The Bone contract keeps track of each validatorShare nonce, which increments with every new withdrawal request.
When a user requests to withdraw their BONE tokens, a fresh ERC721 token is minted and associated with the request. This newly minted token can be traded, sold, or used to redeem the user's BONE tokens.
The withdrawal process involves the following steps:
The user initiates the withdrawal request.
An NFT is minted, and its identifier is linked to the withdrawal request.
The request nonce of the validatorShare and validatorShare address are stored.
The sellVoucher_new function is invoked.
Claim tokens:
The user calls the claim token function and passes the tokenId.
A check is made to ensure that the msg.sender (caller) is the owner of this NFT.
Call the claim unstake tokens function on the validatorShare contract.
Transfer tokens to the user
Burn the NFT.
Distribute Rewards
BONE tokens are accumulated and stored inside the StBone contract upon 2 events:
Each time a user requests to withdraw, the validatorShare contract transfers the rewards
Scheduled job (explained below)
TOTAL_REWARDS = accumulated rewards on Skrimples + accumulated rewards on all validators
As we are going to allow the operator to stake a max number of BONE tokens, the accumulated rewards on all validator's sides are ignored. We are going to use Chainlink Keeper or Gelato to distribute rewards. We regularly check if the amount is greater than a lower bound (a variable that can be set). If that requirement is fulfilled, StBone calculates the amount that the Node Operators and the treasury get, transfers tokens to them immediately. Finally, the remaining BONE tokens are added as a buffered and re-delegated which increases totalPooledBone value. 5% of the staking rewards go to Skrimples treasury, and 5% goes to Node Operators, whereas 90% goes to the stBONE value using re-delegation.
The operator's rewards are distributed between all the staked operators using a ratio. A validator has a ratio of 100% if he was not slashed during the last period. Else if the validator was slashed his ratio is 80% of his total reward part the remainder will be distributed to the other validators.
withdrawTotalDelegated
When an operator was unstaked, the nodeOperator contract called withdrawTotalDelegated function which claims all the delegated Bone from the unstacked validator an NFT token is mint and mapped with this request later a cron job can call claimTokens2StBone to withdraw the Bone from the validatorShare.
ValidatorShare Behaviour
When a user requests withdrawal, the validatorShare contract transfers the total rewards accumulated automatically. The same thing happens when buying new vouchers. So the idea is to consider all the tokens that are not submitted (not buffered) using the submit function as rewards, and they should be distributed.
Manage reward fees:
We can manage the rewards fees using the StBone contract.
ValidatorShare API
The StBone implements the validatorShare contract API
BuyVoucher_new: buy shares from a validator link.
SellVouchernew: sell an amount of shares link. Also, it has a good feature that allows us to track each sell request using a nonce.
unstakeClaimTokens_new: claim the token by a nonce link.
getTotalStake: get the total staked amount link.
getLiquidRewards: get the accumulated rewards link
SkrimplesNFT
The SkrimplesNFT contract is an ERC721 contract used by the StBone contract to manage withdrawal requests.
Each time a user calls the requestWithdraw function inside the StBonecontract a new NFT is minted and mapped with the request.
When a user owns an NFT he can:
Claim a tokens from the withdraw request
Trade NFT to someone else, who will then be able to claim
Approve it to someone else who willl then also be able to claim
This ERC721 is slightly modified so it returns a list of owned tokens of an address by using the public mapping owner2Tokens. Same goes for retrieving the list of approved tokens by using the mapping address2Approved.
Validator Registry
The Validatory Registry is Skrimples' system for onboarding eligible validators and determining their maximum delegation of BONE from the Skrimples protocol.
Validators are incentivized to stake their Skrimples tokens in Skrimples' Boneyard. The greater the stake, the greater their maximum delegation of Skrimples.
Validators are added by the registry by holding Skrimples and by applying to be added by the Ruffhouse Gang DAO.
Operator contract
Manage operators
The validator contract is used to stake on the polygon stake manager. Each operator gets a new validatorProxy contract created each time the addOperator function is called, this validatorProxy is used as the owner of the validator on the Polygon stakeManager.Thought it an operator’s owner can interact with the stakeManager API to:
stakeFor: stake a validator link.
unstake: unstake a validator link.
topUpForFee: topUpHeimdallFees for a validator link.
validatorStake: get the total staked by a validator link.
restake: restake amount link.
getValidatorContract: get validator share contract link.
updateSIgner: allows to update signer pubkey
claimFee: allows to withdraw heimdall fees
updateCommisionRate: allows to update commision
withdrawRewards: withdraw rewards link
Manage Operators
Add an operator
A new Operator expresses their interest to join the Skrimples protocol.
The DAO votes to include the new operator. After successful voting for inclusion, the Node Operator becomes active:
A new validator contract is created.
Set the status to NotStaked.
A default max delegation value is set that means the system will delegate this amount (at max) each time the delegate function is called.
Each operator owner can interact with his operator using the reward address to do the following actions:
stake
join
Unstake
topUpHeimdallFees
unjail
restake
update signer pub key
unstake claim.
claim fee.
Stake an operator
The operator calls the stake function, including the amount of BONE and heimdallFees.
The operator is switched to staked status and becomes ready to accept delegation.
Join
Allows already staked validators to join the Skrimples protocol.
They have first to approve the NFT token to the specific validatorProxy contract.
Call this function to join the system.
Unstake an Operator
When an operator is ongoing to be unstaked, the NodeOperator contract calls the StBone contract in his turn calls the validatorShare contract and withdraws the total delegated BONE tokens. After the withdrawal delay the lido contract can claim those tokens. This last step claiming the tokens can be done using a cron job.
Remove an Operator
Remove an operator is the last step after it was unstaked and he claimed his staked tokens. The DAO can call this function to remove the operator and delete the validatorProxy contract.
Top Up Heimdall Fees
A validator has the possibility to topup the heimdall fees used by the heimdall and the Bor node for validating new blocks
Unjail
Allows a validator to switch his status from locked to ative.
Restake
Allows a validator to stake more BONE, by default this feature is disabled.
Update Signer Public Key
Allows the operator to update the Signer Public key used by the heimdall.
Unstake Claim
Allows the operator owner to claim his staked BONE tokens.
Claim Fee
Allows the operator owner to claim his heimdall fees.
Update Operator Commision Rate
Update the operator's commission rate.
Set Stake Amount And Fees
Set the min and max amount and heimdall fees an operator can use to stake or topup heimdall fees.
Validator Factory
The validator Factory is used to deploy new validatorProxy that is later added to an array of validators.
create
permission:
OPERATOR
description:
Creates a new ValidatorProxy and appends it to array of validators
remove
permission:
OPERATOR
description:
Removes a ValidatorProxy determined by its address from the array of validators
Last updated