Specification
About this project
How do you turn your volatile crypto assets into a stable store of value? How do you leverage your digital holdings for access to a new, secure form of money?
EOSDT’s core components work in concert to let users generate stablecoins pegged to the US dollar and backed by their own crypto holdings. The EOSDT stablecoin is a useful store of value with a variety of applications, like hedging against market turmoil, providing fiat-like quotes for currency pairs on decentralized exchanges, and even making online payments with merchants that accept cryptocurrency. It allows for more intuitive crypto transactions — one EOSDT always equals one USD.
There are four main smart contracts, operating as follow:
The market data smart contract references cryptocurrency prices from the external market through a trustline provided by Oraclize.it, Delphioracle, and LiquidApps.
The Position Smart Contract receives a user’s cryptocurrency and holds it without any human involvement or custody risk.
The Liquidation Smart Contract lets “guardians” and market participants make money by liquidating under-collateralized user positions. This happens automatically when their collateral drops below the critical level of 130%. Guardians can claim liquidated collateral or surplus EOSDT at a markdown from current market prices, an associated fee will be payable in NUT tokens, which are then redistributed back to the system.
The Governance Smart Contract lets users who hold NUT tokens submit proposals to change the EOSDT parameters on risk and stability. NUT holders can also vote for a list of EOS block producers they want to support with system’s EOS collateral. This feature drives the growth, development, and maturity of the entire EOS ecosystem.
EOS uses a delegated proof-of-stake concept, which grants the community lots of flexibility in making instant high-level decisions, like rollbacks and bug fixes, by majority among designated stakeholders. This approval voting system stakes the top 21 EOS block producers to produce blocks — EOS token holders must stake tokens for three days in order to vote. The top 21 candidates form the block-producing core, and the rest become backup block producers. Their priority is also determined by the number of votes they get.
Staking an EOS coin is like paying an opportunity cost — you can't unstake it until three days later, and you don’t have any access to it until then. This little cost grants you access to the entire EOS system. If you stake them for bandwidth, it means you can send transactions, and the size of transaction will consume your bandwidth.
EOSDT uses the EOS blockchain because it is faster than Ethereum, has near-zero transaction fees, and offers great infrastructure for implementing cross-chain solutions. It presently supports the EOS cryptocurrency as a collateral and is ready to support other collateral assets.
Technology review
The best decentralized applications not only offer fast transaction processing times, but an infrastructure robust enough to offer a high-quality experience to lots of users at once. EOSDT is the first stablecoin built on Equilibrium, which is an EOS-based multichain framework for crypto-backed stablecoins and DeFi products. Equilibrium in turn is built on the EOSIO technology stack because it offers decentralized storage and general purpose infrastructure for running EOS dApps more effectively than competitors. Transaction fees are effectively zero here, there’s a thoughtful resource balancing process, and transaction processing times are faster. These features substantially distinguish EOSIO technology from other second-generation blockchains currently on the market.
Stability
EOSDT’s stability comes from backing the EOSDT supply with the equivalent amount of USD collateral at minimum. EOSDT is pegged to the value of $1 USD to achieve this. An external price feed values the collateral, and the system constantly monitors the ratio of collateral to the total EOSDT supply to make sure it always meets the minimum threshold
There are several external actors and internal mechanisms that help maintain market equilibrium.
Market-makers
These are large actors who generate a lot of EOSDT for their massive collateral stakes. They’re willing to make the market at various exchanges by profiting on the price spread between EOSDT and USD.
Guardians
These are actors willing to profit on EOSDT’s price deviations from the $1 USD peg. The mechanics behind arbitrage are pretty straightforward: when the price of EOSDT rises above $1 USD, there’s added incentive to generate it by supplying collateral and selling it on the market. This increases the supply of EOSDT and brings its price down to $1 USD.
When price of EOSDT falls below $1 USD, there’s an incentive for position holders to buy EOSDT on the open market and pay back their positions. This reduces the supply of EOSDT and brings its price up to $1 USD.
Equilibrium fee
Changes to the equilibrium fee incentivize position holders repay or expand their EOSDT holdings, consequently pushing EOSDT price up or down until it finds equilibrium. The system applies the Equilibrium fee every time a user takes an action, and calculates this fee based on an annual percentage rate defined by governance smart contract. Since launch, the Equilibrium fee has been set to 0.0% APR.
If there’s an excess market supply of EOSDT, governance may decide to raise the applicable fee to induce position holders to sell off their “expensive” positions, lowering the supply of the stablecoins. If there’s excess demand for EOSDT, governance may lower the interest rate to induce users to enter more “cheap” positions, increasing the total supply. This is reminiscent of how central banks adjust short-term interest rates to control the economy’s supply of money.
A bundle of smart contracts
This documentation serves as an introduction to the EOSDT, giving you an understanding of how it was designed.
EOSDT’s core logic consists of the following smart contracts:
Account name | Source Contract Name | Description |
---|---|---|
eosdtcntract | eosdtcntract | This contract implements the position management logic for EOSDT users |
eosdtsttoken | eosio.token + temporary burn | The stablecoin contract is based on the native eosio.token contract, but has additional burn and issue methods to help control the system’s supply. It also lists all the issuing (positions) contracts which are allowed to generate EOSDT stablecoins |
eosdtnutoken | eosio.token + permanent burn | This utility token contract manages the Native Utility Token (NUT). It’s based on the native eosio.token contract, but has an additional permanent burn method for controlling the utility token’s supply mechanics. |
eosdtorclize | eosdtorclize | This contract stores and refreshes exchange rates for user collateral and utility tokens. It gets its data from three different oracles: Rovable, Delphioracle and Liquidapps DSP node. Oraclize.it (now known as Provable). |
eosdtliqdatr | eosdtliqdatr | This contract handles the liquidation of undercollateralized user positions. |
eosdtgovernc | eosdtgovernc | The framework’s governance contract provides a means for NUT token holders to vote on changing the framework’s parameters. |
eosdtbpproxy | eosdtbpproxy | The block producer voting proxy account. It will be used for REX staking. |
Positions contract
The positions contract sets the logic for a user’s position management. It also stores the framework’s global risk parameters, which specify how the system behaves and govern the position creation process and a user’s position management. EOSDT’s global risk parameters are configured by a governance mechanism, which means that NUT holders get to vote on proposals to change the framework’s parameters. If the majority agree on new parameters, those become the norm.
ctrsettings table:
Settings | On-Chain Name | Description |
---|---|---|
Global lock | global_lock | Indicator of the state of shutdown, will be set to one if entire system gets undercollateralized |
Time shift | time_shift | Used for testing when we shift time to accrue fees. |
Liquidator account | liquidator_account | Reference to liquidator contract |
Oraclize account | oraclize_account | Reference to rates provider contract |
EOSDT token | sttoken_account | Reference to EOSDT token contract |
NUT token | nutoken_account | Reference to NUT token contract |
Admin fee | governance_fee | This is set to 0% per year by default, payable in NUT utility tokens. This mechanism permanently reduces the NUT supply when EOSDT is repaid. |
Equilibrium fee | stability_fee | This is 1% per year by default, payable in EOSDT stablecoins as an interest rate on EOSDT. |
Critical collateralization ratio | critical_ltv | The minimum acceptable ratio of pledged collateral to loan value. This is set to 130% by default. |
Liquidation penalty | liquidation_penalty | The system charges a 15% liquidation penalty by default, taking that percentage of the position’s collateral. |
Liquidator discount | liquidator_discount | Liquidated EOSDT and collateral gets a 3% discount to incentivize arbitrators to redeem it from the liquidation contract. |
Liquidation price | liquidation_price | The final price set when the system undergoes global settlement and the position contract is locked for further user fund settlements. |
NUT liquidation weight | nut_auct_ratio | This parameter defines what fraction of the liquidation penalty will go to separate collateral balance on the liquidator for buying out with NUT. This parameter is set to 12% currently. |
NUT discount | nut_discount | Liquidated collateral and profit from REX is available to buy from the liquidator for NUT at a 6% discount from the current NUT oracle price. |
REX Profit Factor | profit_factor | This parameter defines the profit distribution from REX. Currently, 88% of REX profit goes to collateral holders and another 12% goes to the liquidator contract to buy NUT. Applicable only for EOS-collateral contract. |
Voting period | vote_period | The number of seconds the system votes to reset vote decay. Will be used in BP voting/REX functionality. Currently not used, as voting happens in real-time. This is 10 days (in seconds) by default. Applicable only for EOS-collateral contract. |
Stake period | stake_period | This specifies the interval at which the system stakes collateral to the REX, as well as collects profit from REX. It’s set to 5 days (in seconds) by default. |
Reserve ratio | reserve_ratio | Shows what percentage of total EOS collateral ends up inside the REX. Applicable only for EOS-collateral contract. |
Staking weight | staking_weight | Defines the fraction of total system collateral being staked every stake period into the REX. Applicable only for EOS-collateral contract. |
Proxy account | bpproxy_account | Reference to voting proxy account. Applicable only for EOS-collateral contract. |
Governance account | governc_account | Reference to governance contract. |
Referral stake | referral_min_stake | This parameter specifies the amount of NUT tokens participants in our referral program need to stake to positions contract to be able to funnel users to the contract on their behalf and get fraction of equilibrium fees. |
Referral ratio | referral_ratio | Fraction of equilibrium fee attributable to referrals when users terminate positions through their web interfaces. By default = 50% |
Collateral token account | collateral_account | Specifies the account of the collateral token. For EOS its eosio.token. |
Collateral token | collateral_token | Specifies the ticker and precision of collateral token. For example, “4,EOS” means that collateral is EOS token with 4 digits of precision. |
Actions and methods for position contracts
Method name | Parameter | Description |
---|---|---|
User invoked actions | ||
positionadd | Create an empty position entity and set the caller to be the owner. |
|
posandrefadd | Create a position used by referrals. |
|
positiondel | Check that a position is EOSDT-free. Return collateral to a position owner. Close the position. |
|
positiongive | Transfer position ownership to a new account. |
|
collateral add (transfer) | Add collateral to the position. |
|
colateraldel | Remove collateral from the position. |
|
debtgenerate | Generate stablecoins on the position. |
|
debtburnback (transfer) | Pay back and burn EOSDT |
|
close | Close existing position |
|
margincall | Close an undercollateralized position, move a position’s EOSDT, and transfer collateral with a penalty to the liquidator. |
|
margincallde | A method that gets called when the oracle service calls our contract with a rates update. If there are positions to be liquidated, deferred margin calls will be created and positions will be liquidated in the next blockchain transaction. |
|
Internal system actions | ||
margincalpos | Close multiple positions by sorting ltvratios table in order of ascending ltv_ratio | N/A |
reinit | This private system function calculates the accrued fees between consecutive calls before transferring it to the liquidator contract. This function is called every time a position method is called. | N/A |
receivecolat | This authenticates a liquidator account and transfers a requested quantity of collateral token to the liquidator contract. | N/A |
receivestable | This authenticates a liquidator account and transfers a requested quantity of EOSDT to the liquidator contract. (used in surplus auctions when the equilibrium fee isn’t zero) | N/A |
fillltvratio | Populate ctrltvratios contract table | N/A |
delltvratio | Clean ctrltvratios table | N/A |
contractinit | deprecated | N/A |
currentver | Returns current build version for debug purposes | N/A |
globallock | This locks the positions contract, disabling all methods related to position management except close(). It also fixes the Collateral/USD price, which facilitates user reimbursements. It sets the liquidation penalty and discount to 0%, and the critical collateralization ratio to 1. This method is used in global shutdown mechanics. | N/A |
settingsset | Used to set liquidator contract settings when contract deployment happens. | N/A |
unstakeall unstakeback withdrawall | Unstake and withdraw all collateral from REX (manually in case of emergency with REX) | N/A |
voteproducer | Action that every voting_period votes for eosdtbpproxy. Applicable only for EOS-collateral contract. | N/A |
Web application (self-service gateway)
EOSDT users may visit https://equilibrium.io/eosdt to generate collateral-backed stablecoins. All communication with the positions contract is supported via several desktop and mobile wallets. The full list of supported wallets is available at https://equilibrium.io/
Liquidator contract
This contract manages the balance between surplus EOSDT and collateral. It also tracks the total amount of EOSDT liability from liquidated positions.
Surplus EOSDT accumulates on the liquidator contract, accruing from the total system EOSDT supply based on the current equilibrium fee. That EOSDT is sold for collateral — a so-called “debt auction.” Debt auctions help distribute the system’s surplus EOSDT.
Collateral balance accumulates on the liquidator contract from positions that were subject to a margin call. This collateral is sold in exchange for EOSDT — a so-called “collateral auction.” Collateral auctions cover EOSDT liability originating from positions that got a margin call.
Liquidator contract actions and methods
Method / Transfer | Description | Example |
---|---|---|
Transfer EOS | This transfer buys surplus EOSDT from the liquidator contract at a discount on the peg price by supplying collateral. |
|
Transfer EOSDT | This transfer lets you buy collateral from the liquidator contract at a discount on the current market price. It supplies surplus EOSDT to the liquidator contract. |
|
Transfer NUT | This transfer buys EOS collateral from the liquidator nut_collat_balance pool for NUT at a discount. |
|
Transfer NUT | This transfer buys collateral from the liquidator nut_collat_balance pool for NUT at a discount. |
|
Internal system actions | ||
reducedebts | This action burns a minimum current “bad” EOSDT and surplus EOSDT on the liquidator contract. This internal function cancels out bad EOSDT by burning it and decreasing its supply. |
|
settingset | Used to set liquidator contract settings when contract deployment happens. |
|
transbaddebt | When any position gets liquidated, the positions contract calls this method to increase the amount of “bad debt” on the liquidator contract. |
|
unlockliqdtr | This method checks that there are no positions left and it calculates a final auction price, the liquidator contract’s bad EOSDT divided by its EOS balance. It unlocks liquidator methods. |
|
currentver | Returns current build version for debug purposes. |
|
paraminit | Initializes empty parameters table |
|
Guardian bot
The liquidator contract’s design lets EOSDT users compete for arbitrage opportunities. The liquidator contract constantly offers EOSDT and collateral for sale. A guardian bot can margin call risky positions and buy their bad EOSDT or collateral from the contract. Any user may run the bot to compete with other users, and they’ll be buying surplus EOSDT and/or liquidated collateral at an incentivizing liquidation discount.
There are also opportunities for buying out all the excess collateral, which accumulates on liquidator contract from various fees: liquidations, rex profits, and block producer rewards. The bot allows for buying this collateral with NUT tokens at a discount. NUT tokens then get partially redistributed back to the governance contract and partially get burned, reducing the total supply.
The guardian bot works in conjunction with the guardian contract and on-chain liquidations
Rates contract
EOSDT’s stability hinges on the real-time pricing for collateral, so that the system knows when to trigger margin calls for undercollateralized positions. Outside of accurately knowing collateral values, the system also needs a price for the NUT utility token to calculate the corresponding admin fee when users repay their stablecoins.
The system uses three different oracles for redundancy (Provable, Delphi Oracle, and Liquid Apps) and calculates the median rate based on the data provided by these oracles. That median value is a final reference price used in all on-chain calculations.
For a more detailed explanation of the rates contract, please visit Equilibrium framework knowledgebase and read about the rates contract there
Governance contract
EOSDT uses the native eosio.forum contract structure for system governance, but with the following modifications:
There are two types of proposals: parameter change proposals and general proposals.
Only NUT holders can create proposals.
Proposals are valid for a maximum of 30 days.
Expired proposals are frozen for three days.
For a proposal to successfully pass, it requires:
A minimum of 51% of the current NUT supply to have been cast in the voting process, like a simple majority shareholder vote.
At least 55% of all votes were "Yes."
NUT holders can generate proposals and change system parameters, effectively governing how EOSDT develops and operates
Apart from parameter changes and system governance, the contract allows NUT holders to vote for EOS Block Producers. In exchange for Equilibrium’s EOS collateral contract stake Block Producers pay a reward which amounts to 90% of profits they generate from the entire EOS collateral available for them. This reward is redistributed back to collateral holders and NUT holders. The absolute amount of the reward is calculated dynamically based on overall EOS collateral and corresponding vote weight of Equilibrium proxy.
Govsettings table:
Setting | On-Chain Name | Description |
---|---|---|
Minimum proposal theshold | min_proposal_weigh | Only users with NUT holdings of more than min_proposal_weigh may submit proposals to the governance contract. |
Freeze period | freeze_period | Freeze time for expired / finished proposals, by default = 3 days. |
Minimum participation rate | min_participation_rate | A minimum of 51% of the current NUT supply to have been cast in the voting process for a proposal to be valid, like a simple majority shareholder vote. |
Succes margin | success_margin | At least 55% of all votes were "Yes” for a proposal to pass. |
Top holders count | top_holders_amount | Top 10 holders of NUT by token count should participate in proposal voting for it to be a valid proposal. |
Maximum number of block producers | max_bp_count | Number of Block Producers equilibrium proxy is voting for. Currently 30 BPs get Equilibrium votes. |
Maximum BP votes | max_bp_votes | Maximum number of block producers one user may vote with his stake. By default = 3 |
Minimum vote | min_vote_stake | Minimum amount of NUT required to vote for Block Producers. By default = 2 NUT. |
Unstake period | unstake_period | The time voter has to wait before unstaking his NUT tokens from the governance contract. By default = 10 days. |
Reward sharing percent | reward_weight | 88% of profits from BP rewards goes to collateral holders, 12% goes to NUT holders |
Staking reward | stake_reward | Shows what fraction of profits from Equilibrium proxy block producers will share with collateral and NUT holders. |
Actions and methods for governance contract
Method name | Description | Example |
---|---|---|
User invoked actions | ||
bpregister | Register block producer on governance contract to participate in reward sharing program |
|
bpunregister | Unregister block producer from reward sharing program |
|
bpsetparams | Change reward amount for a particular BP, can’t be less than a govparams.min_reward number. |
|
propose | Propose a new proposal to the eosdtgovernc contract. There are 3 general proposal types: 0 - parameter change proposal 1 - general proposal 2 - BP voting 2nd type is reserved for BP voting and is never used by external proposers. |
|
expire | Expires proposal. Only the creator of the proposal may expire it. |
|
transfer | Transfer(stake) NUT to the contract to vote for proposals (voter entity is created in govvoters table) |
|
unstake | Unstake NUT tokens from the governance contract |
|
vote | Vote for given proposal 0 - means "NO!" 1 - means "YES!" |
|
unvote | Remove vote from a given proposal |
|
Internal/Private system actions | ||
addposcntr | Add positions contract of additional collateral type to the governance contract reference table so it may govern its parameters |
|
remposcntr | Remove positions contract of additional collateral type. |
|
reinit | This private system function calculates the accrued rewards between consecutive calls before transferring it to collateral holders and liquidator contract. This function is called every time vote/unvote action is called and also is called regularly by an external cron service |
|
clnproposal | Clean proposals table - removes expired proposals |
|
currentver | Returns current build version for debug purposes |
|
settingsset | Used to set liquidator contract settings when contract deployment happens |
|
apply | Applies changes in proposal that has been voted for and approved. |
|
applybpproxy | Re-votes with eosdtbpproxy for block producers on each reinit on positions contract (this is done to keep vote_weight intact) |
|
bpvotescount | Service action for debug purposes (deprecated) |
|
calcnutbal | Service action for debug purposes (deprecated) |
|
voterreborn | Service action for debug purposes (deprecated) |
|
Global shutdown
The system can lock itself down to let EOSDT holders redeem their collateral. This global shutdown mechanism exists in case of black swan events or other unforeseen circumstances that bring sudden negative price movement to reality. When the system becomes undercollateralized and the system’s loan-to-value ratio drops below 1, it can automatically cease operation. When there are crucial updates to the system’s logic and it needs to migrate to new code, it can safely pause.
The global shutdown mechanism is a part of the positions contract. There is a separate emergency fund (the eosdtstfund contract bundle) whose main purpose is to ensure users receive their full collateral in the event of system insolvency. At the time of global shutdown, any positions with a collateralization ratio of less than 100% will be funded directly from these contracts.
Global shutdown actions and methods
Method name | Description | Example |
---|---|---|
globallock | This locks the positions contract, disabling all
methods related to position management except close(). |
|
close | This method only works when the system is locked. It transfers bad EOSDT and position collateral after winding down all positions to a collateralization ratio of 1. |
|
unlockliqdtr | This checks that there are no positions left and it calculates a final auction price, the liquidator contract’s bad EOSDT divided by its EOS balance. It unlocks liquidator methods. |
|
generatedebt | An auxiliary method to generate EOSDT at auction price when that EOSDT is needed to fulfill obligations elsewhere. |
|
Emergency Fund Contract
essettings table:
Parameter | Description |
---|---|
unstake_period | This parameter governs how long a user must wait before withdrawing EOS from the funds contract. This is set to 30 days (in seconds) by default. |
mindeposit | Minimum deposit acceptable by the fund contract. By default = 10 EOS. |
maxdepositors | Number of depositors per contract. By default = 1000 |
Actions and Methods:
Method / Transfer | Description | Example |
---|---|---|
deposit / Transfer EOS | deposits EOS into the emergency fund contract. |
|
withdraw | Withdraws EOS from the emergency fund contract. Withdrawals are subject to a 30-day lockup period. |
|
sendeos | Calculates how much EOS needs to be transferred to the liquidator contract to align the liquidator’s auction_price with liquidation_price. Reduces each position on the funds contract based on its relative weight. |
|
settingsset | Used to set contract settings when contract deployment happens. |
|
paraminit | Initializes empty parameters table |
|