Oikos¶
Description¶
Source: Oikos.sol
Architecture¶
Inheritance Graph¶
Related Contracts¶
Details
Depot
: The depot trades OKS and therefore knows the Oikos address. *ArbRewarder
: The ArbRewarder knows the Synthetix address because it exchanges OKS.Exchanger
The helper contract that performs the heavy lifting forexchange()
andsettle()
.ExchangeRates
: The Oikos contract fetches prices from the exchange rates contract to facilitate synth exchange and to determine the value of various quantities of synths.FeePool
: The Oikos contract remits exchange fees as oUSD to the fee pool, and also uses it to keep track of historical issuance records for each issuer.Issuer
The helper contract that performs the heavy lifting forissueSynths()
,issueMaxSynths()
andburnSynths()
.Proxy
: The Oikos contract, which isProxyable
, exists behind aCALL
-style proxy for upgradeability.RewardEscrow
: This is similar to the OikosEscrow contract, but it is where the OKS inflationary supply is kept before it is released to Synth issuers.RewardsDistribution
: This contract works closely with RewardEscrow to release portions of the inflationary supply to different recipients.SupplySchedule
: The supply schedule determines the rate at which OKS are released from the inflationary supply.Synth
: Oikos manages the supply of synths. It keeps track of which ones exist, and they are all issued and burnt from the Synthetix contract. The Synthetix contract is also responsible for exchange between different synth flavours.OikosEscrow
: The escrow contract keeps track of OKS owed to participants in the initial token sale, and releases them according to specified vesting schedules.OikosState
: This state contract stores the debt ledger and the current issuance information for synth issuers.
Constants¶
TOKEN_NAME
¶
A constant used to initialise the ERC20 ExternStateToken.name
field upon construction.
Type: string constant
Value: "Oikos Network Token"
TOKEN_SYMBOL
¶
A constant used to initialise the ERC20 ExternStateToken.symbol
field upon construction.
Type: string constant
Value: "OKS"
DECIMALS
¶
A constant used to initialise the ERC20 ExternStateToken.decimals
field upon construction.
Type: uint8 constant
Value: 18
Variables¶
availableSynths
¶
List of the active Synths
. Used to compute the total value of issued synths.
Type: Synth[] public
exchangeEnabled
¶
Allows the contract owner to disable synth exchanges, for example during system upgrades.
Type: bool public
synths
¶
A mapping from currency keys (three letter descriptors) to Synth
token contract addresses.
Type: mapping(bytes32 => Synth) public
Constructor¶
The constructor initialises the inherited ExternStateToken
instance and MixinResolver
.
Details
Signature
constructor(address _proxy, TokenState _tokenState, address _owner, uint _totalSupply, address _resolver) public
Superconstructors
Views¶
availableCurrencyKeys
¶
Returns the currency key for each synth in availableSynths
.
Details
Signature
availableCurrencyKeys() public view returns (bytes32[])
availableSynthCount
¶
Returns the number of synths in the system, that is availableSynths.length
.
Details
Signature
availableSynthCount() public view returns (uint)
collateral
¶
Returns the total OKS owned by the given account, locked and unlocked, escrowed and unescrowed. This is the quantity of OKS synths can be issued against.
This is computed as the sum of Oikos.balanceOf(account)
, SynthetixEscrow.balanceOf(account)
, and RewardEscrow.balanceOf(account)
; so an account may issue synths against both its active balance and its unclaimed escrow funds.
Details
Signature
collateral(address account) public view returns (uint)
collateralisationRatio
¶
The ratio between value of synths that an account has issued and the value of the collateral they control. That is, this is just debtBalanceOf(issuer, "OKS") /
collateral(issuer)
.
Ideally, issuers should maintain their collateralisation ratio at a level less than the global issuance ratio, and they are incentivised to do this by the fees they can claim if they do so.
Details
Signature
collateralisationRatio(address issuer) public view returns (uint)
debtBalanceOf
¶
Reports the quantity of a given currency required to free up all OKS locked in given account.
If \mathrm{X} is the total value of all issued synths, and \check{\omega} is fraction of that value currently accounted for by this account's locked OKS, then the result is simply:
In order to account for fluctuations in synth prices and supply, the current ownership fraction is computed as the adjusted value:
Where \omega is the account's debt ownership fraction at the time it last issued or burnt synths, which produced the \Delta_\text{entry} item in the debt ledger. \Delta_\text{last} is the latest value on the ledger. This logic is much the same as that found in FeePool._effectiveDebtRatioForPeriod
. The actual value of \omega is set in _addToDebtRegister
and _removeFromDebtRegister
.
Details
Signature
debtBalanceOf(address issuer, bytes32 currencyKey) public view returns (uint)
effectiveValue
¶
Reports an equivalent value of a quantity of one synth in terms of another at current exchange rates. This is a simple wrapper for ExchangeRates.effectiveValue
Details
Signature
effectiveValue(bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey) public view returns (uint)
maxIssuableSynths
¶
The maximum number of a given synth that is issuable against the issuer's collateral. This is simply issuanceRatio *
collateral(issuer)
, priced in the requested currency.
Details
Signature
maxIssuableSynths(address issuer, bytes32 currencyKey) public view returns (uint)
remainingIssuableSynths
¶
The remaining oUSD synths this account can issue.
If \text{maxIssuable} is maxIssuableSynths(issuer)
and \text{debt} is debtBalanceOf(issuer, currencyKey)
, then the result of this function is max(0, \text{maxIssuable} - \text{debt}).
If prices fluctuate then the account's issued synth debt may exceed its current maximum issuable synths, in which case it may not issue any more synths until more collateral is added.
Details
Signature
remainingIssuableSynths(address issuer) public view returns (uint)
totalIssuedSynths
¶
Returns the total value of Synths in the system, priced in terms of a given currency.
This value is equivalent to:
Where \sigma_s and \pi_s are the total supply and price of synth s, and \pi_d is the price of the denominating synth flavour.
Details
Signature
totalIssuedSynths(bytes32 currencyKey) public view returns (uint)
Modifiers
Preconditions
- No rate for any of the currently available currencies can be stale.
transferableOikos
¶
The quantity of OKS this account can transfer given that a portion of it may be locked due to issuance.
If \text{balance} is balanceOf(account)
, and \text{lockedSnx} is debtBalanceOf(account, "OKS") / OikosState.issuanceRatio
, the function returns max(0, \text{balance} - \text{lockedSnx}). Escrowed tokens are not taken into account in this computation, so unescrowed tokens are locked immediately.
A Note on Price Motion
The value of \text{lockedSnx} depends on the current (\pi) and previous (\pi') prices being reported by the oracle, and the issuance ratio (\rho).
If we consider a situation where the synth supply has not changed in the time period under consideration, then ownership fractions do not change even if prices do. Further assuming that there is only a single synth circulating, debt balances correspond to the same number of synths, although perhaps not the same value.
In such a situation, we can think of each user having issued a particular quantity of synths. This quantity depends on the prices of synths and OKS at the time of issuance.
Whose value at the present time priced in terms of OKS, which is what debtBalanceOf(account, "OKS")
returns, is:
Note that this computation has a factor of \rho in it, and this must be divided out in order to ascertain the quantity of OKS which are presently locked.
Which is to say that the quantity of OKS locked in this situation depends on the price.
Extend this to the multicurrency case
Consider a two synth system, one primary synth and a secondary one which represents the price/supply of all other synths. Use the total issued value function to derive the behaviour for multiple currencies, and then examine a single currency as a special case.
Details
Signature
transferableOikos(address account) public view returns (uint)
Modifiers
isWaitingPeriod
¶
Whether or not the waiting period is ongoing for the given synth. If so, no exchanges into this synth will be allowed, nor will that synth be able to be transferred.
Details
Signature
isWaitingPeriod(bytes32 currencyKey) external view returns (bool)
Mutative Functions¶
burnSynths
¶
Burns a quantity of oUSD
in the calling address, in order to free up its locked OKS supply.
If the caller attempts to burn more synths than their OKS debt is worth, this function will only burn sufficiently many tokens to cover the debt and leave the rest untouched.
The new debt position of the caller is recorded with _appendAccountIssuanceRecord
, and the adjustment to global debt recorded with _removeFromDebtRegister
.
See Issuer
for further details.
Details
Signature
burnSynths(uint amount) external
Modifiers
Preconditions
- The existing debt the caller must be nonzero.
exchange
¶
Exchanges one synth flavour for an equivalent value of another at current exchange rates and transfers the converted quantity to a destination address. An exchange fee is charged on the way.
See Exchanger
for further details.
Details
Signature
exchange(bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address destinationAddress) external returns (bool)
Modifiers
Preconditions
- The source and destination currencies must be distinct.
- The exchanged quantity must be nonzero.
settle
¶
Settles any amounts oustanding for previous exchanges into the given synth.
See Exchanger
for further details.
Details
Signature
settle(bytes32 currencyKey) external returns (uint reclaimed, uint refunded)
Modifiers
Preconditions
- That the waiting period (see
Exchanger
) for this synth is0
issueSynths
¶
Issues a new quantity of oUSD
into the calling address. The new debt issuance is recorded with _addToDebtRegister
, and the account's issuance records are updated with _appendAccountIssuanceRecord
.
See Issuer
for further details.
Details
Signature
issueSynths(uint amount) public
Modifiers
Preconditions
- The quantity of new synths to be minted must be no greater than the remaining issuable for that account.
issueMaxSynths
¶
Issues the maximum quantity oUSD
issuable by the caller of a particular synth flavour. Otherwise, this operates exactly as issueSynths
does.
See Issuer
for further details.
mint
¶
This function is responsible for creating the inflationary OKS supply. It is a public function, so any address can ensure new tokens are released on schedule. When a new quantity is minted, the calling address is rewarded with a small incentive of OKS tokens, defined by SupplySchedule.minterReward
.
The supply is released according to the schedule defined in SupplySchedule.schedules
, being sent to the RewardsDistribution
contract for distribution and escrow. The total supply OKS supply is thus increased by the quantity specified by the schedule.
This function always returns true if the transaction did not revert.
Details
Signature
mint() external returns (bool)
Preconditions
- The
rewardsDistribution
address must be initialised. - The supply to mint retrieved from
SupplySchedule.mintableSupply
must be nonzero.
Emits
transfer
¶
This is a ERC20 transfer functions.
A successful transfer requires the message sender to have sufficient balance, accounting for locked OKS.
Implemented based on ExternStateToken._transfer_byProxy
.
Details
Signatures
transfer(address to, uint value) public returns (bool)
Modifiers
Preconditions and Events
value
must not exceedtransferableOikos(messageSender)
Otherwise, function behaves as per ExternStateToken._internalTransfer
.
transferFrom
¶
This is a ERC20 transferFrom functions.
A successful transfer requires the token owner to have sufficient balance, accounting for locked OKS.
Implemented based on ExternStateToken._transferFrom_byProxy
.
Details
Signatures
transferFrom(address from, address to, uint value) public returns (bool)
transfer(address from, address to, uint value) public returns (bool)
Modifiers
Preconditions and Events
value
must not exceedtransferableOikos(from)
Otherwise, the these functions behave as per ExternStateToken._internalTransfer
.
Owner Functions¶
addSynth
¶
Allows the owner to add a new Synth
to the system, inserting it into availableSynths
and synths
. The new synth's currency key must be unique.
Details
Signature
addSynth(Synth synth) external
Modifiers
Preconditions
- The new synth's currency key must not be taken already in the
synths
address mapping.
removeSynth
¶
Allows the owner to remove a Synth
from the system.
Upon removal it is also deleted from availableSynths
and synths
, which frees that currency key to be reused.
A Synth cannot be removed if it has outstanding issued tokens.
Details
Signature
removeSynth(bytes32 currencyKey) external
Modifiers
Preconditions
- The synth's currency key must exist in the
synths
address mapping. - The synth's total supply must be zero.
- The oUSD synth cannot be removed.
setExchangeEnabled
¶
Allows the owner to disable synth exchanges.
Details
Signature
setExchangeEnabled(bool _exchangeEnabled) external
Modifiers
Internal & Restricted Functions¶
synthInitiatedExchange
¶
Allows a synth to perform a free exchange into a different flavour.
This is only used by PurgeableSynth.purge
in order to convert outstanding synths into oUSD. No exchange fee is charged on such liquidations.
Details
Signature
synthInitiatedExchange(address from, bytes32 sourceCurrencyKey, sourceAmount, bytes32 destinationCurrencyKey, address destinationAddress) external returns (bool)
Modifiers
Proxyable.optionalProxy
through_onlySynth
Preconditions
- The message sender must be a synth (
_onlySynth
). - The source and destination currencies must be distinct.
- The exchanged quantity must be nonzero.
_internalExchange
¶
Implements synth exchanges for exchange
and synthInitiatedExchange
.
Conversion is performed by burning the specified quantity of the source currency from the from
address, and issuing an equivalent value of the destination currency into the destination address, minus a fee if chargeFee
is true. This fee is issued into the fee address in oUSD, and the fee pool is notified.
This function can be disabled by the owner.
Details
Signature
_internalExchange(address from, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address destinationAddress, bool chargeFee) internal returns (bool)
Preconditions
exchangeEnabled
must be true.- The destination address must not be the zero address.
- The destination address must not be the Oikos contract itself.
- The destination address must not be the Oikos proxy.
- The
from
address must have at leastsourceAmount
of the source currency.
_internalLiquidation
¶
This simply burns a quantity of the given synth from the specified account. This always returns true if the transaction was not reverted.
Details
Signature
_internalLiquidation(address from, bytes32 sourceCurrencyKey, uint sourceAmount) internal returns (bool)
_addToDebtRegister
¶
Whenever synths are issued, this function is invoked to update the debt ledger. It computes the factor the issuance changes the overall supply by and appends the resulting entry to the debt ledger. This entry is saved as a 27-decimal fixed point number.
In addition, the caller's current issuance data is updated and, if they haven't issued before, the total issuer count is incremented.
This function performs the same operation as _removeFromDebtRegister
, but a quantity of debt is added rather than removed from the total pool.
Debt Ledger and Issuance Data
The following holds for both addition and removal of debt; the logic of the latter is nearly identical to that of the former, but with a negative value of \chi.
Definitions
Term | Definition | Description |
---|---|---|
\Delta | See the Ledger Updates section below. | The debt ledger: an array of debt movement factors, indicating the size of the issued system debt over time. \Delta_n is the n^{th} entry in the ledger. |
X | \frac{1}{\pi_\text{oUSD}}\sum_{c}{\pi_c \sigma_c} | The oUSD value of all issued synths (totalIssuedSynths ) at current prices. |
\widehat{\chi} | \omega \frac{\Delta_\text{last}}{\Delta_{entry}} X | The XDR value of the account's existing issuance debt at current prices (debtBalanceOf ). \omega is the calling account's last recorded owership fraction of the total system debt. We will also refer to the adjusted current ownership fraction \check{\omega} = \omega \frac{\Delta_\text{last}}{\Delta_{entry}}. |
\chi | The XDR value of the newly-issued synth debt; the new total debt will be X + \chi. | |
\omega' | \frac{\chi}{X + \chi} | The fraction of the new total debt accounted for by \chi. |
\delta | 1 - \omega' \ = \ \frac{X}{X + \chi} | The factor to multiply existing debt ownership positions by to obtain their new fraction of the total after adding in \chi; that is, the ratio of the old total debt to the new total debt. |
Ledger Updates
After this function is invoked, the user's ownership fraction \omega and their debt entry index \text{entry} are updated to new values as follows:
That is, the updated ownership fraction includes both the old debt and the new debt, adjusted to current prices. The updated debt ledger entry index is the length of the debt ledger, because that will be the index of the new ledger entry that is about to be added.
The new entry is appended to the debt ledger, growing it by one element. The new last element of the ledger takes the value:
Hence each element of the ledger incorporates the value of the previous entry, noting that \Delta_0 = 1.
This gives us a recurrence defining the n^{th} debt ledger entry \Delta_n, corresponding to the n^{th} issuance or burning event.
As a result we can conclude that:
So a given debt ledger entry is the cumulative debt movement up to that point, and the division of one entry by another is the debt movement between them.
Note that, due to price movements in the tokens the system tracks, in general it is not the case that X_n = X_{n-1} + \chi_{n-1}. However, if it is assumed that this is the case, one obtains a telescoping series that yields \Delta_n = \frac{X_1}{X_{n+1}}. Consequently, the debt ledger measures the overall system growth, as the reciprocal of a particular debt ledger entry is the factor the total system debt had expanded by since the system's inception at the time it was generated.
Details
Signature
_addToDebtRegister(bytes32 currencyKey, uint amount) internal
Modifiers
_appendAccountIssuanceRecord
¶
Whenever synths are issued or burnt, the calling account's new issuance data (debt ownership and ledger index) is appended to its historical issuance ledger.
This operates by calling FeePool.appendAccountIssuanceRecord
thence FeePoolState.appendAccountIssuanceRecord
.
Details
Signature
_appendAccountIssuanceRecord() internal
_removeFromDebtRegister
¶
Whenever synths are burnt, this function is invoked to update the debt ledger. It computes the factor the burning changes the overall supply by and appends the resulting entry to the debt ledger. This entry is saved as a 27-decimal fixed point number.
In addition, the caller's current issuance data is updated and, if they are burning all their tokens, the total issuer count is decremented.
This function performs the same operation as _addToDebtRegister
, but a quantity of debt is removed rather than added to the total pool.
Relationship With _addToDebtRegister
If debt removal is considered as the addition of a negative quantity of debt, then the functions perform a largely identical function (and could perhaps be merged). The only difference here is that the new total debt is expressed as X - \chi. In particular, we have, explicitly computed within this function:
Which are all the same as in _addToDebtRegister
with \chi's sign flipped. See that function's notes for further discussion and definitions.
Details
Signature
_removeFromDebtRegister(uint amount) internal
Modifiers¶
notFeeAddress
¶
The transaction is reverted if the given account is the fee address.
Signature: notFeeAddress(address account)
onlyOracle
¶
The transaction is reverted if msg.sender
is not the exchange rates oracle.
rateNotStale
¶
The transaction is reverted if the given currency's latest exchange rate is stale. This will also revert if the currency key is unknown to the exchange rates contract.
Events¶
SynthExchange
¶
Records that an exchange between two flavours of synths occurred.
This event is emitted from the Oikos proxy with the emitSynthExchange
function.
Signature: SynthExchange(address indexed account, bytes32 fromCurrencyKey, uint256 fromAmount, bytes32 toCurrencyKey, uint256 toAmount, address toAddress)