Dissecting the Overlay protocol
A cryptocurrency that lets you long or short DeFi data streams.
Overlay is a protocol for trading data streams. Users can go long or short with leverage on any data streams Overlay supports using price oracles. You might ask, how is different from the gazillion derivative protocols out there already? The major difference between Overlay and other derivative protocols is that existing protocols use stablecoins such as USDC as collateral and settle and Overlay uses its own native token OVL for the same purpose. Existing derivative protocols face liquidity issues as there might not be enough liquidity to pay winning positions. Overlay solves this issue by minting OVL to give winners. Overlay has a yield farming program that incentivizes people to provide liquidity to OVL-ETH on Uniswap, which creates a price feed for Overlay to calculate OVL’s price in ETH. By knowing the current OVL price during settlement, Overlay knows how much OVL to mint for a winning position. Since OVL is Overlay’s own token and the protocol can mint as much as it needs, there can never be a liquidity issue. Its mechanism is similar to algo-stablecoins’ mint and burn mechanism.
The ability to mint unlimited OVL comes with inflationary risk. This can become a real issue if every trader is making winning bets even though it is very unlikely to happen. Overlay addresses this issue by burning OVL. OVL is burned when
a trader opens/settles a position, trading fees are charged and partially burned.
a trader settles a losing position, the difference between the opening and closing price is burned.
a trader settles a winning position, the protocol charges a fee and partially burns it.
a trader gets liquidated, the margin is partially burned.
Overlay protocol’s hypothesis is that with a large enough user base, traders will take on different positions. The long and short positions should cancel each other out and reduces OVL’s inflation risk. Overlay’s team members discussed different mechanisms to act as insurance in case the price of OVL collapses, such as performing certain on-chain or OTC actions to maintain price stability. For now, they will rely on the market and burning OVL to maintain price stability.
(Disclaimer: this mechanism is highly experimental and we’ve seen many algorithmic protocols spiralled out of control in the past. DYOR)
Overlay’s smart contracts live here. We will now take a look at how the protocol works.
OverlayV1Market
An Overlay market, such as OVL-ETH, ETH-DAI and OVL-DAI, is deployed by calling OverlayV1UniswapV3Factory#createMarket
, which creates a OverlayV1UniswapV3Market
with the market’s parameters. After the market is deployed, the market is added to the factory’s registry and the factory grants the newly created market the minter and burner role of the OVL token.
OverlayToken(ovl).grantRole(OverlayToken(ovl).MINTER_ROLE(), market);
OverlayToken(ovl).grantRole(OverlayToken(ovl).BURNER_ROLE(), market);
By granting these two roles to the market, it can mint/burn OVL tokens when a trader opens or settles a position. If one day the market is to be discontinued, OverlayV1UniswapV3Factory#disableMarket
can be called by the contract owner to revoke the market’s OVL minter and burner role so that it can no longer mint/burn OVL tokens.
OverlayToken(ovl).revokeRole(OverlayToken(ovl).MINTER_ROLE(), market);
OverlayToken(ovl).revokeRole(OverlayToken(ovl).BURNER_ROLE(), market);
Building a position
A trader can open a position by calling OverlayV1OVLCollateral#build
. The function takes the OVL collateral from the trader, calculates the open interest, charges a fee and creates a new position.
Open interest is collateral x leverage.
uint _oi = _collateral * _leverage;
Fee percentage is defined in the factory. The open interest, collateral and debt are fee adjusted. Fees are being accumulated.
uint _fee = ( _oi * factory.fee() ) / RESOLUTION;
_oiAdjusted = _oi - _fee;
uint _collateralAdjusted = _oiAdjusted / _leverage;
_debtAdjusted = _oiAdjusted - _collateralAdjusted;
fees += _fee;
The position’s open interest shares, cost and debt are added.
position.oiShares += _oiAdjusted;
position.cost += _collateralAdjusted;
position.debt += _debtAdjusted;
After creating the position, it queues the position’s open interest to OverlayV1OI
and makes sure the new total open interest has not reached the cap. Open interest is “queued” for T+1 price settlement. The queued open interest will be settled during OverlayV1Market#update
, after funding payment and price fetch from the oracle in order to prevent funding payment harvesting with 0 price risk.
if (isLong) {
queuedOiLong += oi;
require(oiLong + queuedOiLong <= oiCap, "OVLV1: breached oi cap");
} else {
queuedOiShort += oi;
require(oiShort + queuedOiShort <= oiCap, "OVLV1: breached oi cap");
}
Finally, the OVL collateral is transferred to the collateral contract and the contract mints ERC-1155 shares that represents the trader’s position.
ovl.transferFrom(msg.sender, address(this), _collateral);
mint(msg.sender, _positionId, _oiAdjusted, "");
Unwinding a position
This is where things get interesting. OVL is minted or burned in OverlayV1OVLCollateral#unwind
. At first, it does the usual, calculates user shares, notional value, debt, cost and open interest for unwinding and then remove them from the position.
uint _userOiShares = _shares * pos.oiShares / _totalPosShares;
uint _userNotional = _shares * pos.notional(_priceFrame, _oi, _oiShares) / _totalPosShares;
uint _userDebt = _shares * pos.debt / _totalPosShares;
uint _userCost = _shares * pos.cost / _totalPosShares;
uint _userOi = _shares * pos.openInterest(_oi, _oiShares) / _totalPosShares;
pos.debt -= _userDebt;
pos.cost -= _userCost;
pos.oiShares -= _userOiShares;
Then a fee is charged on the share’s notional value. Position value is also adjusted based on the position’s debt.
uint _feeAmount = ( _userNotional * factory.fee() ) / RESOLUTION;
uint _userValueAdjusted = _userNotional - _feeAmount;
if (_userValueAdjusted > _userDebt) _userValueAdjusted -= _userDebt;
else _userValueAdjusted = 0;
fees += _feeAmount;
Here is the core of the protocol, mint OVL if the unwinded shares’ value is greater than the cost, burn OVL otherwise. The amount to mint or burn is the absolute difference between the unwinded shares’ value and the cost. If the hypothesis is correct, the burned amount should be able to offset the minted amount. The unwinded shares’ value is then transferred to the trader.
if (_userCost < _userValueAdjusted) ovl.mint(address(this), _userValueAdjusted - _userCost);
else ovl.burn(address(this), _userCost - _userValueAdjusted);
ovl.transfer(msg.sender, _userValueAdjusted);
Finally, the exited open interest and shares are removed from the market and the shares are burned.
IOverlayV1Market(pos.market).exitOI(_isLong, _userOi, _userOiShares);
burn(msg.sender, _positionId, _shares);
Liquidation
An under water position can be liquidated by calling OverlayV1OVLCollateral#liquidate
. The function liquidates a position if it does not meet the current margin maintenance requirement. The position’s margin is added to the accumulated liquidations so that it can be burned and forwarded during protocol update. The liquidator gets rewarded for calling the function.
require(pos.isLiquidatable(
_priceFrame,
_oi,
_oiShares,
_marginMaintenance
), "OverlayV1: position not liquidatable");
_oi -= pos.openInterest(_oi, _oiShares);
_oiShares -= pos.oiShares;
IOverlayV1Market(pos.market).exitOI(_isLong, _oi, _oiShares);
pos.oiShares = 0;
uint _toForward = pos.cost;
uint _toReward = ( _toForward * _marginRewardRate ) / RESOLUTION;
liquidations += _toForward - _toReward;
ovl.transfer(_rewardsTo, _toReward);
Market update
OverlayV1OVLCollateral#update
can be called for regular protocol updates. It updates the funding payments, price from the TWAP oracle and open interests. It also burns and forwards fees.
Funding payments
If long’s open interest is greater than short’s open interest, then longs pay shorts. Otherwise, shorts pay longs. The funding amount is equal to the difference between the two sides’ open interests times the funding rate, divided by 2. oiLong
and oiShort
are updated accordingly, which will affect individual trader positions when they settle.
uint256 oiImbNow = fundingFactor.mul(funding - funded).decode144();
uint256 total = funding + funded;
funding = ( total + oiImbNow ) / 2;
funded = ( total - oiImbNow ) / 2;
fundingPaid = int( oiImbNow / 2 );
if (paidByShorts) ( oiShort = funding, oiLong = funded );
else ( oiLong = funding, oiShort = funded, fundingPaid = -fundingPaid );
Price
Overlay fetches asset price from Uniswap V3’s oracle and the price is stored in the pricePoints
array.
int24 tick = OracleLibrary.consult(feed, uint32(windowSize));
price_ = OracleLibrary.getQuoteAtTick(
tick,
uint128(amountIn),
isPrice0 ? token0 : token1,
isPrice0 ? token1 : token0
);
Open interests
Queued open interests are added to the current open interests.
oiLong += queuedOiLong;
oiShort += queuedOiShort;
oiLongShares += queuedOiLong;
oiShortShares += queuedOiShort;
queuedOiLong = 0;
queuedOiShort = 0;
Fees and liquidated margins
The protocol has a fee burn rate and a margin burn rate. Portions of the accumulated fees and liquidated margins will be burned by the protocol to control inflation. Portion of the accumulated fees will also be given to the market updater. The rest of the fees and liquidated margins will be sent to the protocol’s fee address.
uint _feeForward = fees;
uint _feeBurn = ( _feeForward * _feeBurnRate ) / RESOLUTION;
uint _feeReward = ( _feeForward * _feeRewardsRate ) / RESOLUTION;
_feeForward = _feeForward - _feeBurn - _feeReward;
uint _liqForward = liquidations;
uint _liqBurn = ( _liqForward * _marginBurnRate ) / RESOLUTION;
_liqForward -= _liqBurn;
fees = 0;
ovl.burn(address(this), _feeBurn + _liqBurn);
ovl.transfer(_feeTo, _feeForward + _liqForward);
ovl.transfer(_rewardsTo, _feeReward);
Closing Thoughts
Overlay is an interesting protocol because it is *really* not like other derivatives protocol. I have covered a few other derivative protocols so far (Perpetual, Qilin, Complifi) and all of them use stablecoins as margins. It is difficult to say if this mint and burn mechanism will really work. Once Overlay is launched on the mainnet with more users trading on it, we will have to observe whether longs and shorts’ open interests are balanced and whether OVL will suffer from hyperinflation.
For now you can test the dapp on the Kovan testnet at https://kovan.overlay.exchange