Rico Credit System 0
or RCS0
is a simplification of the Dai Stablecoin System with some new features. Users post collateral to mint new Rico
. To maintain adequate collateralization, the system detects when users’ positions are underwater and triggers liquidations. RCS can raise or lower collateral requirements reflexively to guard against rapid price movements. This has an added benefit of preventing unsustainable collateralization levels. We’ll discuss these mechanics further.
A CDP management module called vat
keeps track of CDPs. Users call frob
to evaluate and modify their positions and bail
to liquidate underwater positions. Vat collects fees on CDPs which are used to pay down bad debt and create a system surplus. Vat calls hook
to manage collateral. RCS Vat is designed intentionally to be flexible in collateral appraisal methods.
A debt/surplus balancing module called vow
balances the total system surplus/deficit. Vow mints new risk share tokens (Risk
) and sells them for Rico as a failsafe to cover system deficit. Vow auctions off surplus Rico tokens and sells them for Risk.
A price rate controller module called Vox
responds reflexively to market conditions by controlling collateral requirements. When the price of Rico rises, Vox lowers the price rate
, the rate of change in collateral requirements, to encourage users to borrow more Rico. When the price of Rico falls, Vox raises the price rate to encouraging CDP holders to buy circulating Rico to pay down their debts.
hooks
manage different collateral types, including ERC20 tokens but also types that aren’t easy to represent using DSS’s unsigned integer ink
or one-per-collateral type price feeds. This manual discusses one such non-ERC20 hook.
vat
vow
vox
rico:ref
price is low
rico:ref
price is high
hook
feed
This manual usually will not reference precisions outside of the precision section below. It will describe multiplications as A * B
even if A and B are both ray
s and their result is also a ray
.
In the code, art
and urn
are interchangeable. If urn
were a struct as in DSS, it would only have art
.
Core contract does not need Rico/RISK approve
. Instead, it uses mint
and burn
, where the rules for minting and burning are described solely by the controlling contract.
hook
s are delegatecall
ed.
Some minor details are omitted for simplicity. For example, the code might set some values to 1 instead of 0 to save gas. This manual focuses on giving a deep understanding of the mechanics without precisely specifying them.
A critical concept some might not be used to is mash
. The high-level idea is that whenever the system runs a collateral auction, it should factor its need to fill the auction into its asking price. That need is mash
. deal
is a precursor to mash
, and pep
, pop
, and pup
are parameters that adjust mash
’s sensitivity to deal
. So, in general:
auction_price ~= approx_market_price * mash
mash ~= pop * (deal ^ pep) + pup
The effect is:
pop
is a signed mash
-axis stretch that can be used to speed up mash
change
pep
is an exponent. Its purpose is similar to pop
, but it also can shape the curve in useful ways
flip
deal
is close to 1
pup
is a mash
-axis shift that tunes the mash
-axis and deal
-axis roots of the curve
par
and way
, the concept of reference price and reference rate
par
, art
and rack
is considered to be critical business logic and is grouped together with core CDP engine logic in the Vat
.
hook
s allow for advanced CDP types, potentially involving non-ERC20 tokens, ACLs, etc., without changing core Vat
logic
defensive line
/vsync
replaces DSS hole
mat
moved to hook
rate
-> rack
(per-ilk internal debt unit accumulator)
Art
-> tart
(total accumulated debt, in terms of internal debt unit)
Line
-> ceil
(debt ceiling)
duty
-> fee
(stability fee)
mat
-> liqr
(liquidation ratio)
Good to Know
wad
: 18 decimals. Used for debt amounts, token amounts, and Vow ramp rel
ray
: 27 decimals. Used for prices, multipliers, rates
rad
: 45 decimals. Used for internal denormalized debt calculations
file
: Change some configuration variable
filk
: Change some ilk’s configuration variable
ward
: Refers to permissions; permissioned functions are “warded”, for example
ref
: Reference asset
deal
: Precursor to mash
mash
: Auction price discount; used in hook
and vow
. Represents the risk in not filling the auction
pep
: mash
’s sensitivity exponent (e.g. pep == 2 means mash
changes quadratically with deal
)
pop
: mash
’s mash
-axis stretch
pup
: mash
’s mash
-axis shift
plx
: (uint, uint, int)
tuple representing (pep, pop, pup)
palm
: Event indicating a system variable change
rudd
: Feedbase (src, tag)
RCS
: Rico Credit System
RCS0
: Rico Credit System 0
Core Modules
vat
: Records and analyzes CDPs
vow
: Starts debt auctions, surplus auctions, and liquidations
vox
: Collateralization ratio controller
Auxiliary Modules
hook
: Module that manages collateral
feed
: Price feeds
Vat
rico
: The stable debt unit issued by RCSx
urn
: A CDP
art
: Normalized debt in an urn
ink
: Collateral
tab
: Denormalized debt; normalized debt * rack
ilk
: Collateral type
tart
: Per-ilk total art
rack
: Per-ilk accumulated rate; used to convert normalized debt to denormalized debt
dust
: Per-ilk urn debt floor
fee
: Per-ilk per-second compounding interest rate (together all ilks’ fee
s make up the q-rate)
rho
: Per-ilk time since last drip
sin
: Unbacked system debt; increases during liquidations and decreases on heal
debt
: Outstanding rico from this vat
ceil
: Vat debt ceiling
rest
: Rounding error from truncating denormalized debt internally represented as a rad
par
: Collateralization ratio multiplier; high par means high collateral requirement, low means low
frob
: Modify an urn
bail
: Liquidate a Sunk
urn
Safe
: Urn is not at risk of liquidation (collateral adequate)
Sunk
: Urn is at risk of liquidation (collateral inadequate)
Iffy
: tot
and cut
are out of date; urn may or may not be at risk of liquidation
drip
: Pay out pending interest
deal
: Ratio of collateral value:urn debt value, both denominated in ref
tot
: Collateral’s value in rad-precision denormalized debt
cut
: Collateral’s safety value; usually tot
with safety parameters (e.g. liqr
) applied
Hook
liqr
: Per-ilk liquidation ratio; urns with high liqr
need more collateral
Vow
flip
: Collateral auction
flap
: Surplus auction (selling surplus Rico for RISK)
flop
: Deficit auction (minting new RISK and selling for Rico to cover sin
)
keep
: Balance the system surplus/deficit by auctioning Rico (flap) or mint+selling RISK (flop)
ramp
: Four values describing RISK mint rate on flop (rel
, bel
, cel
, wel
)
rel
: RISK mint rate in fraction of RISK supply/second; actual mint rate will be min(vel rate, rel rate)
bel
: Last flop’s timestamp (prorated for clamped flops)
cel
: Maximum seconds a flop can ramp up before it’s clamped
wel
: Fraction of joy auctioned per flap
mcap
: RISK market cap, denominated in Rico
pex
: vow auction maximum price
dam
: vow auction decay rate per-second multiplier
earn
: RISK burned in flap, or Rico burned in flop, or Rico burned in flip
sell
: Rico minted in flap, or RISK minted in flop, or collateral sold in flip
loot
: Protocol fee factor. Owner makes (flap - sell) Rico in a flap
heal
: Pay down sin
by burning rico
deal
: mcap / (mcap + sin)
on flop, mcap / (mcap + joy)
on flap
Vox
mar
: Rico price quoted in an external reference asset
tip
: Feedbase (src, tag) for mar
way
: Price rate
how
: Sensitivity parameter; par
changes exponentially vs time with how
as the base
tau
: Time of last par
and way
update
cap
: way
‘s clamp. Way can’t go over cap
or under inverse(cap
)
Hook
ink
: Collateral
bailhook
: Manage auctioning off/writing off ink
frobhook
: Move collateral between system and user
safehook
: Calculate value of collateral in denormalized debt
vsync
: Sync joy
and line
with the proceeds from a flip
auction and the owed
Rico
defensive line
: The part of vsync
that lowers line defensively to limit sinny Rico
name | precision |
---|---|
mash
|
ray
|
pep
|
power
|
pop
|
ray
|
pup
|
signed ray
|
pex
|
ray
|
dam
|
ray
|
art
|
wad
|
tab
|
rad
|
tart
|
wad
|
dust
|
rad
|
fee
|
ray
|
rho
|
seconds
|
sin
|
rad
|
debt
|
wad
|
ceil
|
wad
|
rest
|
rad
|
par
|
ray
|
deal
|
ray
|
tot
|
rad
|
cut
|
rad
|
rel
|
ray
|
bel
|
seconds
|
cel
|
seconds
|
wel
|
ray
|
mcap
|
wad
|
earn
|
wad
|
sell
|
wad
|
loot
|
ray
|
mar
|
ray
|
way
|
ray
|
how
|
ray
|
tau
|
seconds
|
cap
|
ray
|
liqr
|
ray
|
name | type | description |
---|---|---|
Ilk
|
struct
|
per-collateral type parameter struct |
Ilk.tart
|
uint
|
total normalized debt |
Ilk.rack
|
uint
|
rate accumulator (similar to DSS rate )
|
Ilk.line
|
uint
|
sum of this ilk's urns' tab s can't exceed this
|
Ilk.dust
|
uint
|
urn debt floor; urn's tab can't go lower than this
|
Ilk.chop
|
uint
|
liquidation penalty; used to calculate bill
|
Ilk.hook
|
address
|
hook
|
urn
|
uint
|
CDP normalized debt, also known as art
|
joy
|
uint
|
accumulated Rico from fees and liquidations |
sin
|
uint
|
unbacked system debt |
rest
|
uint
|
rounding error, because debt is a wad and tab is a rad
|
debt
|
uint
|
backed system debt (sum of denormalized debt in all urns, plus sin , minus joy )
|
ceil
|
uint
|
system debt ceiling |
par
|
uint
|
collateral requirement multiplier |
lock
|
uint
|
frob /bail reentrancy lock
|
flock
|
uint
|
flash reentrancy lock
|
vat
keeps track of collateralized debt positions and delegates collateral management to hook
. vat
does not directly handle any tokens other than Rico. There is no DaiJoin or GemJoin equivalent - frobs
are immediately reflected in the caller’s Rico balance. To create a CDP, the user approves collateral to the collateral type’s hook
if necessary and calls frob
on one of the ilk
’s urn
s. frob
mints or burns Rico and calls hook
to manage the collateral.
Rico vat
determines urn safety with cut
, tab
, and, notably, par. par
is a multiplier for the urn’s collateral requirements. The effect is that par
increase encourages users to burn Rico and par
decrease encourages users to mint Rico.
Each collateral type, ilk
, has a rack
. rack
is an interest rate accumulator. It’s multiplied by fee
, the ilk’s interest rate, per second. rack
allows vat
to calculate pending interest in constant time. The pending interest is calculated by multiplying rack
‘s delta since the last update, by the ilk’s total normalized debt, summed over all of its urns. The amount of Rico minted or burned on frob
is proportional to the denormalized debt, art * rack
, so it’s the the caller’s responsibility to consider rack
when determining how much Rico frob
will mint or burn.
When rack
is updated on drip
, accumulated interest is optimistically minted to the vow
, the system surplus/deficit balance mechanism. If any of the minted Rico later turns out to be uncollateralized, it will be added to sin
.
hook
implements three functions: frobhook
, bailhook
, and safehook
. hook
makes vat
more flexible in the types of collateral it can accept.
frob(bytes32 i, address u, bytes calldata dink, int dart)
frob
modifies a CDP’s collateral and debt balances. It first drip
s ilk i
to accumulate any pending fees under that collateral type. It then modifies art
, the urn’s normalized debt, and tart
, the ilk’s total normalized debt, depending on dart
, the art
delta. It passes dink
to hook
to manage ink
. It applies the change in denormalized debt (normalized debt * rack
) to debt
, the total system debt, and rest
, the system debt rounding error.
Arguments:
i
: The ilk ID
u
: The urn address (primary “user” address)
dink
: Change in ink
(collateral), structure defined by hook
dart
: Change in art
, the debt, denominated in this ilk’s internal debt unit
Errors:
ErrDebtCeil
- debt increased and debt ceiling (line
or ceil
) exceeded
ErrUrnDust
- urn’s debt is nonzero but below dust limit
ErrNotSafe
- frob didn’t make the urn safer, and urn is not safe
ErrWrongUrn
- frob didn’t make urn safer, and u
is not the caller
Palms:
art
, tart
, debt
, rest
Notes:
frobhook
returns a bool that’s true if the CDP needs a safety check after.
dart
is change in normalized debt. This means that the amount of rico minted or burned is determined by the product of dart
and the rate accumulator, rack
. There is some rounding because this product is a rad
while debt
is a wad
. The rounding error is added to rest
, which later accrues to debt
.
bail(bytes32 ilk, address urn) returns (bytes memory);
bail
liquidates an underwater urn. It first drip
s ilk
. Then, if the CDP is unsafe, bail
records all of the urn’s tab
as sin
, sets the urn’s art
to 0, and calls bailhook
to try to auction off ink
to cover the position.
Arguments:
i
: The urn’s collateral type
u
: The urn’s owner
Palms:
art
, tart
, sin
Returns:
bytes memory
: data returned from hook
, typically some data representing the auctioned ink
.
Errors:
ErrSafeBail
: urn is Safe
or Iffy
(i.e. not clearly underwater)
Notes:
bail
creates sin
. vow
heal
s sin
with joy
safe(bytes32 i, address u) view returns (Spot spot, uint deal, uint tot)
safe
checks whether a CDP is underwater. It considers cut
, par
, rack
, and art
to determine the urn’s safety. safe
gets cut
from hook
. cut
is the collateral’s value with safety parameters (e.g. liquidation ratios) applied.
Arguments:
i
: The urn’s collateral type
u
: The urn’s owner
Return Value:
spot
: Sunk
if underwater, Iffy
if collateral’s price data is outdated and art != 0
, Safe
otherwise
deal
: cut
:tab
ratio. Measure of how underwater the urn is, if applicable
tot
: total collateral value in denormalized debt, calculated by hook
Notes:
Sunk == 0
, Iffy == 1
, Safe == 2
safehook
to determine value of collateral in denormalized debt
Safe
urn, the collateral covers the urn’s art
multiplied by par
, rack
, and liqr
par
acts as a controlled liqr
tot
is defined by hook
. Current hooks use it as an appraisal value.
art
are safe
. This ensures that users can always retrieve collateral by paying down the entire urn.
drip(bytes32 ilk)
drip
calculates interest since last drip
(rho
) per collateral type using fee
(per-second compounded interest rate) and rack
(accumulated rate). It optimistically assumes that the “dripped” Rico is sufficiently collateralized, so it does not modify sin
. It accumulates the pending interest to joy
.
debt
is a wad
and denormalized debt is a rad
. So, rounding error is kept in rest
and accrues to debt
when it’s greater than RAY.
If rest >= RAY
, it accrues to debt
.
Arguments:
ilk
: The collateral type
Palms:
rho
, rack
, debt
, rest
, joy
Notes:
tab
by fee
per second and accrues the difference between old tab
and new
tab`
vow
may later convert joy
to minted Rico.
rho
to current timestamp
keep
, and wraps an internal _drip
that’s called by frob
and bail
flash(address code, bytes calldata data) returns (bytes memory result);
flash
flash loans Rico to sender with no fee.
Arguments:
code
: Address of contract to call after borrowing Rico
data
: Encoded calldata and selector of the function to call in code
Errors:
code
if code
call failed
Gem.ErrUnderflow
: Failed to pay back Rico
Notes:
flash
does not implement ERC3156, a wrapper can be used to allow targets designed for the
ERC3156 standard, an example wrapping an earlier version of flash
is available at ricobank/flashutils.
init(bytes32 ilk, address hook) onlyOwner
init
initializes a new ilk
.
Initial Values:
rho
: block.timestamp
. rack
and fee
are both set to RAY
.
rack
: RAY
fee
: RAY
hook
: same as argument
Arguments:
ilk
: Collateral type identifier
hook
: Collateral type’s hook
contract
Palms:
rack
, fee
, hook
, rho
, tart
, chop
, line
, dust
Errors:
ErrMultiIlk
: ilk
already initialized
Notes:
chop
and line
are set by calling filk
filk(bytes32 ilk, bytes32 key, uint val) onlyOwner
filk
is like file
, but per-ilk instead of per-vat.
Arguments:
ilk
: The collateral configuration to modify
key
: The name of the parameter
val
: The value of the parameter, converted to uint
if necessary
Keys supported:
line
: debt ceiling
dust
: urn debt floor
hook
: hook
contract address (cast address->uint)
liqr
: liquidation ratio
chop
: liquidation penalty
fee
: per-second compounding rate
Palms:
Errors:
ErrBound
: tried to set fee < 10 ** 27
ErrWrongKey
: key
not supported
filh(bytes32 ilk, bytes32 key, bytes32[] calldata xs, bytes32 val) onlyOwner
filh
modifies a configuration parameter for ilk
’s hook
. It fetches ilk
’s hook
address and calls hook.file(key, ilk, xs, val)
.
Arguments:
ilk
: the ilk
ID
key
: the name of the hook
configuration parameter
xs
: additional indices for the hook
configuration parameter, e.g. if it’s in a nested mapping
val
: the new value of the hook
configuration parameter, cast to bytes32
geth(bytes32 ilk, bytes32 key, bytes32[] calldata xs) view returns (bytes32)
geth
fetches a configuration parameter from ilk
’s hook
. It calls hook.get(key, ilk, xs, val)
.
Arguments:
ilk
: the ilk
ID
key
: the name of the hook
configuration parameter
xs
: additional indices for the hook
configuration parameter, e.g. if it’s in a nested mapping
Returns:
hook
ink(bytes32 i, address u) view returns (bytes memory)
Arguments:
i
: collateral type ID
u
: urn owner’s address
Returns:
ink
left in urn (i, u)
name | type | description |
---|---|---|
risk
|
Gem
|
RISK token contract |
ramp.bel
|
uint
|
last flop timestamp (prorated if last flop was clamped) |
ramp.cel
|
uint
|
maximum time a flop can charge up |
ramp.rel
|
uint
|
fraction of RISK supply charged up for flop per second |
ramp.wel
|
uint
|
way fraction of surplus auctioned off per flap
|
loot
|
uint
|
way protocol fee, expressed as a fraction of surplus flapped
|
dam
|
uint
|
vow auction per-second decay multiplier |
pex
|
uint
|
vow auction maximum price |
vow
balances the system surplus and system deficit. It cancels joy
with sin
and vice versa (heal
). If there is surplus left over, vow
auctions it off for RISK (flap
). If there is deficit left over, vow
auctions new RISK for Rico (flop
) to cover the deficit. The Rico received accrues to joy
.
vow
allows the system to quickly and automatically respond to undercollateralization in bad market conditions. For example, if a collateral type suddenly crashes, flip
might not be able to cover the unbacked debt, drip
might take some time if fee
is low, but flop
can quickly act as an extra failsafe.
keep(bytes32[] calldata ilks)
keep
first drips each ilk
in ilks
. Then, on surplus or deficit, it heal
s so that either joy ~= surplus
or sin ~= deficit
. Finally, it balances the systems surplus or deficit. In deficit, it mints new RISK to msg.sender
and burns msg.sender
’s Rico to pay down sin
– this is a flop
auction. In surplus, it mints Rico to msg.sender
and burns msg.sender
’s RISK – this is a flap
auction.
Minted or burned Rico accrues to joy
. flap
s lower joy
and flop
s raise joy
.
keep
prices Rico and RISK depending on pex * dam ^ (current_time - bel)
, where dam
is a decay and pex
is a constant maximum price.
dam < 1
, so on flap
and flop
the offered price decreases as time passes.
flop
RISK minting is rate limited. flop
s can charge up for cel
seconds, accumulating rel
RISK/s to be minted on the next flop. flop
s attempt to cover the deficit and nothing more, clamping the minted amount if it would create a surplus otherwise. Normally bel
is set to block.timestamp
. If the flop is clamped, bel
is prorated relative to the amount of accumulated RISK used.
The protocol fee on flap
is determined by loot
. loot
is the fraction of the flapped joy
that gets sent to the keeper. The rest is sent to the owner
address.
The portion of surplus auctioned off per flap
is determined by wel
. wel
is a fraction of the post-heal
joy
that is minted to msg.sender
. wel
provides an extra level of control over flap
price; otherwise with aggressive pep
and pop
we can easily encounter situations where big flap
s are cheaper overall than small flap
s.
Arguments:
ilks
: IDs of all ilks to drip
before balancing budget
Errors:
ErrReflop()
: nothing to flop (usually when trying to flop multiple times per second)
name | type | description |
---|---|---|
tip
|
rudd
|
Feedbase (src, tag) for rico:ref` feed
|
way
|
uint
|
par rate of change, expressed as a fraction per second
|
how
|
uint
|
sensitivity; way is multiplied or divided by how every second
|
tau
|
uint
|
last poke timestamp |
cap
|
uint
|
way maximum is cap , and way minimum is 1/cap
|
vox
is the system’s price rate controller, also known as the redemption rate adjustment mechanism, also known as the par
price adjustment mechanism. It responds to spikes and dips in Rico’s price vs a reference asset by modifying the price rate, par
’s per-second rate of change. When Rico price spikes, the price rate decreases to encourage borrowing. When Rico price dips, the price rate increases to discourage borrowing.
vox
implements a type of integral controller called a tick controller. Short-term stimuli will not have a noticeable effect on vox
, but long-term stimuli will.
poke()
Updates the collateralization ratio multiplier, par
, and its first derivative, way
, also known as the price rate. poke
has two important steps:
par
by way
per second since the last poke
, thereby modifying the vat
’s collateral requirements by the price rate per second.
way
by how
per second since the last poke
if the mar
is less than par
, and divide way
by how
per second since the last poke
if the mar
is greater than par
, thereby multiplying or dividing the price rate by a constant per second. This has the medium-term effect of pushing mar
closer to par
.
When way < RAY
the price rate is negative. This is how the system can effectively create negative borrowing rates – as vox
lowers collateral requirements by lowering par
, Rico supply increases, Rico price decreases, and Rico borrowers can short.
way
is clamped. It can’t go above cap
or below the inverse of cap
. For example, if cap is 1.5, par
will not increase by more than 50%/second or decrease by more than 33% per second.
par
moves smoothly even when mar
’s feed fails. If mar
is stale, poke
still updates par
and tau
but leaves way
unchanged.
If poke
is called twice in the same second, the second poke
does nothing.
Notes:
way
changes exponentially with time when not clamped. This is what we mean when we say vox
is “log-scale”.
File
is used to modify system-wide configuration parameters.
file(bytes32 key, bytes32 val) onlyOwner
file
modifies a vat
-wide (i.e. not per-ilk) configuration parameter.
Arguments:
key
: The name of the parameter
val
: The value of the parameter, converted to bytes32 if necessary
Keys supported:
ceil
: The vat
’s debt ceiling
Errors:
ErrWrongKey
: key
not supported
hook
manages collateral. It’s removed from vat
for flexibility. Urns are now represented between two contracts: the vat
for art
, and the hook
for ink
. ink
’s type varies between hooks
. Each hook
implements a common interface of four methods: frobhook
, bailhook
, safehook
, and ink
, and possibly file
and get
.
name | type | description |
---|---|---|
sender
|
address
|
frob caller |
i
|
bytes32
|
collateral type id |
u
|
address
|
urn owner |
dink
|
bytes
|
collateral change |
dart
|
int
|
denormalized debt change |
name | type | description |
---|---|---|
i
|
bytes32
|
collateral type id |
u
|
address
|
urn owner |
bill
|
uint
|
Rico amount billed to hook |
owed
|
uint
|
Rico needed to cover new `sin` |
keeper
|
address
|
liquidator's address |
deal
|
uint
|
urn underwater-ness |
tot
|
uint
|
total collateral value in denormalized debt |
frobhook(FHParams p) returns (bool safer)
Called on frob
to move ink
between hook
and frob
caller. Returns true
if urn is no less safe after frob
than before frob
. We will often (but not necessarily always) see that removing ink
or adding art
makes an urn less safe.
Arguments:
p
: frobhook
parameter struct
Returns:
safer
: false if frob
should check this urn’s safety after calling frobhook
bailhook(BHParams p) returns (bytes memory sell)
Called on bail
to liquidate urn (i, u)
and move its ink
accordingly. Uses deal
, tot
, and bill
to determine a discounted price for the ink
and burns an appropriate amount of keeper
‘s Rico. Uses owed
to determine how much to lower line
if the liquidation doesn’t cover the urn’s debt.
bailhook
calls vsync
to accumulate auction proceeds to joy
and lower line
if there is sin
.
Arguments:
p
: bailhook
parameter struct
Returns:
sell
: bytes array describing the sold ink
safehook(bytes32 i, address u) view returns (uint tot, uint cut, uint ttl)
Called on safe
for urn (i, u)
to calculate ink's
value in denormalized debt.
Arguments:
i
: collateral type ID
u
: urn owner’s address
Returns:
tot
: the value in denormalized debt
cut
: the safety value in denormalized debt
ttl
: expiry
Notes:
tot
is implementation-dependent. It does not necessarily have to be the value in denormalized debt, but that’s what we’ve used it for so far.
ink(bytes32 i, address u) view returns (bytes memory)
Arguments:
i
: collateral type ID
u
: urn owner’s address
Returns:
ink
left in urn (i, u)
file(bytes32 key, bytes32 i, bytes32[] calldata xs, bytes32 val)
file
modifies a hook
configuration parameter.
Arguments:
key
: the name of the hook
configuration parameter
i
: the ilk
ID
xs
: additional indices for the hook
configuration parameter, e.g. if it’s in a nested mapping
val
: the new value of the hook
configuration parameter, cast to bytes32
Notes:
ilk
s can use the same hook
, so their storages are separated by i
.
get(bytes32 key, bytes32 i, bytes32[] calldata xs) view
get
returns a configuration parameter.
Arguments:
key
: the name of the hook
configuration parameter
i
: the ilk
ID
xs
: additional indices for the hook
configuration parameter, e.g. if it’s in a nested mapping
Returns:
hook
name | type | description |
---|---|---|
gem
|
address
|
ERC20 token address |
liqr
|
uint
|
liquidation ratio; multiplied in safehook to get cut
|
rudd
|
rudd
|
Feedbase (src, tag) for gem:ref price feed
|
plot
|
plx
|
(pep, pop, pup) for calculating bail discount
|
ERC20Hook
handles ERC20 token collateral.
frobhook
p.dink
is interpreted as a single ABI-encoded int256
, representing the amount to increase/decrease this urn’s balance in its corresponding ERC20 token.
Special case: if p.dink
is an empty bytes array, it’s interpreted as int256(0)
.
safer
iff p.dink >= 0
Errors:
ErrDinkSize
: dink
length is not 32 or 0
ErrTransfer
: failed to transfer collateral tokens between sender
and hook
ErrWrongUrn
: removing collateral or borrowing Rico from someone else’s urn
bailhook
Attempts to burn bill
Rico from keeper
. If covered with excess, the auctioned ink
amount is clamped to just cover bill
, with the excess left in the urn.
If burned Rico is less than owed
, bailhook
lowers the ilk
’s line
by the difference.
earn ~= min(bill, (tot * (pop * (deal ^ pep) + pup)))
Errors:
ErrTransfer
: collateral token transfer failed
Returns:
uint
amount of the collateral token sold to keeper
safehook
Returns:
tot
: the total ink
tokens in the urn, times their price
cut
: tot
, times liqr
ttl
: time to live
ink
Returns:
uint
representing amount of collateral token left in the urn
name | type | description |
---|---|---|
source
|
(uint,rudd)
|
per-gem liqr and gem:ref rudd
|
wrap
|
IUniWrapper
|
UniswapV3 library wrapper, for calling libraries that use an earlier compiler version. In particular, hook needs token0 and token1 amounts for each NFPM position. |
room
|
uint
|
maximum number of NFPM positions per urn |
plot
|
plx
|
(pep, pop, pup) for calculating bail discount
|
UniNFTHook
collateralizes UniswapV3 NonfungiblePositionManager positions. Each NFPM position is an NFT, and ink
is an array of NFPM position tokenIds. Each NFPM position represents a position in a (token0, token1) pool, so unlike ERC20Hook
, in this hook
a single urn can hold two or more different ERC20 tokens.
frobhook
p.dink
is interpreted as an ABI-encoded uint
array. The first uint
is dir
, which is either LOCK
(for adding ink
) or FREE
(for removing ink
). The following uint
s are NFPM tokenIds to lock or free.
Special case: if p.dink
is an empty bytes array, dir == LOCK
.
safer
iff dir == LOCK
and p.dart <= 0
.
LOCK == 1
and FREE == uint(int(-1))
.
Examples:
[LOCK, 1, 3]
[FREE, 1, 3]
Errors:
ErrFull
: too many tokenIds added
ErrDir
: dir
is not LOCK
or FREE
ErrWrongUrn
: removing collateral or borrowing Rico from someone else’s urn
Returns:
safer
: true if dink == LOCK
, false otherwise
bailhook
Attempts to burn bill
Rico from keeper
. If covered with excess, the excess Rico is sent to the urn’s owner. Note that this behavior is different from ERC20 bailhook
’s.
If burned Rico is less than owed
, bailhook
lowers the ilk
’s line
by the difference.
earn ~= tot * (pop * (deal ^ pep) + pup)
Errors:
Returns:
uint[]
of ink
tokenIds sent to keeper
safehook
Returns:
tot
: sum_over_tokenIds(sum_over_token0_and_token1(token amt * token:ref price))
cut
: sum_over_tokenIds(sum_over_token0_and_token1(token amt * token:ref price * token0 liqr))
ttl
: time to live
Notes:
token1_feed_price/token0_feed_price
, converted to tick
ink
Returns:
uint[]
representing list of NFPM tokenIds in CDP
Feedbase implements two functions: push
for pushing new data, and pull
for retrieving the latest data.
Each feed
has (bytes32 val, uint ttl)
. val
is the feed data and ttl
is its time-to-live (though could be used for other purposes).
(address src, bytes32 tag)
addresses a feed
. Only src
can push new data to (src,tag)
.
Combinators can use feedbase to compose other feeds, e.g. Divider
Adapters adapt data from external sources to feedbase
, e.g. Chainlink adapter
READ == 0
. On feedbase.pull
, if ttl == READ
, feedbase
deduces that src
is a contract that implements the Read
interface. Read
has one function:
read(bytes32 tag) view
Read
is best when prioritizing the latest data. For example, a divider’s output is equally exposed to all of its source feeds, so it makes sense to fetch the latest values on each pull
. Read
also avoids excessive storage writes that can’t be amortized effectively. For example, there’s no reason to push Chainlink data if the aggregator’s heartbeat is one hour and the data is only pull
ed once per hour.
push(bytes32 tag, bytes32 val, uint ttl)
Write (val, ttl)
to the feed at (msg.sender, tag)
.
Errors:
ErrTTL
: ttl == READ
; feed fetches new data on every read and should never be written
pull(address src, bytes32 tag) view
Read (val, ttl)
from the feed at (src, tag)
.
Errors:
Will fail if ttl == READ
and src
does not implement Read
interface.