See https://poa.gitbook.io/exit/ first to get the detailed info of the concept.
This prototype consists of three contracts:
-
Reward is a main contract which emulates a rewardable action (in this case - finishing staking epoch and minting EXIT tokens) and implements the rebalance mechanism of SoftETH tokens total supply. This contract is upgradeable by the
RewardProxy
contract. For upgradability we use OpenZeppelin solution. -
ExitToken is an ERC20 token contract representing EXIT token. It is mintable by the
Reward
contract. Initially, it's created with an empty supply. The supply is increased by theReward.finishStakingEpoch()
function (see below). No one else can mint the EXIT tokens. -
SoftETHToken is an ERC20 token contract representing SoftETH token. It is mintable and burnable by the
Reward
contract. Initially, it's created with an empty supply. The supply is changed by theReward.rebalance()
function (see below). No one else can mint or burn the SoftETH tokens.
These contracts are deployed in Ethereum Mainnet (see addresses). We use a public price oracle contract available on Mainnet to retrieve the current ETH/USD rate.
For ERC20 implementations we use the latest OpenZeppelin contracts.
These constants are supposed to be unchanged during prototype's life:
-
COLLATERAL_MULTIPLIER defines how many times the USD worth of SoftETH tokens must exceed the total supply of EXIT tokens. It's equal to 2.
-
EXIT_MINT_RATE defines the percent rate of how many EXIT tokens must be minted in relation to the USD worth of STAKE tokens totally staked. It's defined as 10%.
The Reward contract contains three setters:
-
finishStakingEpoch accepts
totalStakeAmount
as a single parameter and emulates finishing of staking epoch. ThetotalStakeAmount
defines the total amount of STAKE tokens staked by the moment of staking epoch end. This parameter is used along withSTAKE/USD
rate andEXIT_MINT_RATE
to calculate the amount of EXIT tokens needed to be minted as a reward. The function mints EXIT tokens and calls therebalance
function.finishStakingEpoch
can be called by anyone at any time. -
rebalance rebalances the
totalSupply
of SoftETH tokens so that it would exceed EXIT token supplyCOLLATERAL_MULTIPLIER
times in USD worth. This function doesn't accept any parameters and can be called by anyone at any time. -
setSTAKEUSD sets the current STAKE/USD rate in USD cents (for example,
10 USD
would be1000
). Can only be called by an address namedCurrency Rate Changer
(see below).
There are a few public getters which could be helpful:
-
ethUsdCurrent returns the current amount of USDTs in 1 ETH (in USD cents) provided by the price oracle. The returned value has 2 decimals.
-
usdEthCurrent returns the current amount of ETHs in 1 USDT (i.e. USDT/ETH rate) provided by the price oracle. The returned amount has 18 decimals.
-
exitCurrentSupply returns the current total supply of EXIT tokens.
-
softETHCurrentSupply returns the current total supply of SoftETH tokens.
-
softETHExpectedSupply returns the current expected supply of SoftETH tokens based on the current supply of EXIT tokens,
COLLATERAL_MULTIPLIER
, and the current USDT/ETH rate. -
ethUsd returns the latest known ETH/USD rate (in USD cents) set by
rebalance
function. The returned amount has 2 decimals. -
stakeUsd returns the STAKE/USD rate set by
setSTAKEUSD
function. The returned amount has 2 decimals.
The Reward
contract is well documented, so you can look into its code and get the detailed information about each function.
The ABIs are available in etherscan.io
as the contracts are verified (see contract addresses).
The Reward contract assumes to have three users:
-
Proxy admin
who can upgrade the code of theReward
contract through theRewardProxy
contract. The proxy admin cannot callReward
functions. -
Staker
is an arbitrary address which receives minted EXIT tokens. TheStaker
emulates the staking of STAKE tokens (as a single staker in the system). When theReward.finishStakingEpoch
function is called (by any address) with a non-zerototalStakeAmount
parameter, it's supposed that the staker had stakedtotalStakeAmount
STAKE tokens before staking epoch finished. This prototype doesn't have STAKE token contract - the tokens are only emulated by theReward.finishStakingEpoch
function. -
Currency Rate Changer
is an address that is allowed to call theReward.setSTAKEUSD
function. For simplicity, we assume this address is the same asStaker
.
-
Clone the repo and initialize it:
$ git clone https://github.com/xdaichain/exit-reward-prototype $ cd exit-reward-prototype $ npm i
-
Create
keys
file in the root of the repo which should contain private keys for theadmin
andstaker
/currencyRateChanger
addresses (one line for each).Example of the
keys
file content (the first is for theadmin
, the second is forstaker
/currencyRateChanger
):123a...bc45 678d...ef90
The
admin
address cannot be the same asstaker
/currencyRateChanger
.Make sure the
admin
address has at least 0.02 ETH and thestaker
/currencyRateChanger
has at least 0.001 ETH (for the gasPrice of 5 gwei). -
Set appropriate
gasPrice
intruffle-config.js
(the default is 5 gwei). -
Launch the deployment script as follows:
$ env STAKEUSD=1000 npm run deploy -- --network mainnet # STAKEUSD is STAKE/USD rate in USD cents
If the deployment is successful, you will see addresses.mainnet.json
file in the root of the repo. The file will contain all addresses needed to work with this prototype (contract addresses; admin, staker, currencyRateChanger).
To emulate the minting of EXIT tokens, call the Reward.finishStakingEpoch
function. This function cannot be called by the admin
, so please use another address for making the transaction. To ensure the supply of EXIT tokens is increased, use exitToken.totalSupply
getter.
To rebalance SoftETH supply after ETH/USD rate changing, call Reward.rebalance
. This function cannot be called by the admin
, so please use another address for making the transaction.
To change STAKE/USD rate, call the Reward.setSTAKEUSD
function by the Currency Rate Changer
address.
To compare the current SoftETH supply with the expected supply, use Reward.softETHCurrentSupply
and Reward.softETHExpectedSupply
getters. They should return almost the same value after rebalance
is called.
To know the current ETH/USD rate provided by the price oracle, use Reward.ethUsdCurrent
getter.
The Application for interaction with the contracts is available in the app
directory.