Skip to content

Commit

Permalink
improve naming, update README
Browse files Browse the repository at this point in the history
  • Loading branch information
JonahGroendal committed Sep 29, 2022
1 parent 0cfdf6c commit f200ca6
Show file tree
Hide file tree
Showing 15 changed files with 352 additions and 337 deletions.
6 changes: 3 additions & 3 deletions .openzeppelin/unknown-1337.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
},
{
"address": "0xdDA6327139485221633A1FcD65f4aC932E60A2e1",
"txHash": "0x5aa4875b29d47808bc743f748fce799a3c9224660ae849d74947f236b7e0224c",
"txHash": "0x06de3dde6acfd6fa0bc4f82599d78f45986d7aa80ab9e48a2af53635ed3cd183",
"kind": "uups"
}
],
Expand Down Expand Up @@ -634,9 +634,9 @@
}
}
},
"7d2a76f3d9396e587cd59c0e5a7d94977db58c7ba3baf7f585d32236f551f483": {
"dab3517c4791065b5e923c7eeec2f60033cf940413a639563f03ebd4c2453223": {
"address": "0x82D50AD3C1091866E258Fd0f1a7cC9674609D254",
"txHash": "0xb36fbd522ccdbdf1c19e010abfbd8cc97369400f3c704dcaa8db2585478dc145",
"txHash": "0x58d7f50d9c892e44df36f598348ba11cb2b6d05f8f9eb8d6b138794d9de08569",
"layout": {
"storage": [
{
Expand Down
178 changes: 87 additions & 91 deletions README.md

Large diffs are not rendered by default.

6 changes: 0 additions & 6 deletions contractAddrs-goerli-fork.json

This file was deleted.

6 changes: 0 additions & 6 deletions contractAddrs-goerli.json

This file was deleted.

6 changes: 0 additions & 6 deletions contractAddrs-test.json

This file was deleted.

14 changes: 7 additions & 7 deletions contracts/ISwap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ pragma solidity ^0.8.11;
import "./IToken.sol";

interface ISwap {
function buyFloat (uint amount, address to) external;
function sellFloat (uint amount, address to) external;
function buyEquity (uint amount, address to) external;
function sellEquity(uint amount, address to) external;
function buyHedge(uint amount, address to) external;
function sellHedge(uint amount, address to) external;
function buyLeverage(uint amount, address to) external;
function sellLeverage(uint amount, address to) external;

function equityValue(uint amount) external view returns (uint);
function floatValue (uint amount) external view returns (uint, uint);
function floatValueNominal(uint amount) external view returns (uint);
function leverageValue(uint amount) external view returns (uint);
function hedgeValue(uint amount) external view returns (uint, uint);
function hedgeValueNominal(uint amount) external view returns (uint);

function updateInterestRate() external;

Expand Down
24 changes: 12 additions & 12 deletions contracts/Model.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ abstract contract Model is IModel {
int constant ONE = 10**18;
int constant STEP = ONE / 8765820; // 0.1% annually, compounded hourly

function getInterestRate(uint potValue, uint floatTV) external pure returns (int) {
return(f(potValue, floatTV) / STEP) * STEP;
function getInterestRate(uint potValue, uint hedgeTV) external pure returns (int) {
return(f(potValue, hedgeTV) / STEP) * STEP;
}

function f(uint potValue, uint floatTV) internal virtual pure returns (int);
function f(uint potValue, uint hedgeTV) internal virtual pure returns (int);
}

/// @notice Interest rate changes linearly wrt collateral ratio
Expand All @@ -21,28 +21,28 @@ contract LinearModel is Model {
int constant B = -28 * ONE / 876582;

/// @notice M * collateral ratio + B
/// @dev collateral ratio = pot value / float-leg total value
function f(uint potValue, uint floatTV) internal override pure returns (int) {
if (floatTV == 0) {
/// @dev collateral ratio = pot value / hedge total value
function f(uint potValue, uint hedgeTV) internal override pure returns (int) {
if (hedgeTV == 0) {
return 0;
}
unchecked {
return ((M * int(potValue)) / int(floatTV)) + B;
return ((M * int(potValue)) / int(hedgeTV)) + B;
}
}
}

/// @notice Maintain a constant interest rate wrt value of equity-leg tokens
/// @notice Maintain a constant interest rate wrt value of leverage tokens
contract ConstantFloatModel is Model {
// there are 8765.82 hours in a year
int constant FLOAT_RATE = 4 * ONE / 876582; // 4% APR, compounded hourly

function f(uint potValue, uint floatTV) internal override pure returns (int) {
if (floatTV == 0) {
function f(uint potValue, uint hedgeTV) internal override pure returns (int) {
if (hedgeTV == 0) {
return 0;
}
unchecked {
return ((FLOAT_RATE * int(potValue)) / int(floatTV)) - FLOAT_RATE;
return ((FLOAT_RATE * int(potValue)) / int(hedgeTV)) - FLOAT_RATE;
}
}
}
Expand All @@ -53,7 +53,7 @@ contract NonlinearModel is Model {
// current idea:
// (.001 / (x - 1)) + Mx + B
// verticle asymtote at x = 1 and is about linear when x is larger
// also a plus: interest rate wrt value of equity-leg tokens is monotonically increasing with x
// also a plus: interest rate wrt value of leverage tokens is monotonically increasing with x
// would need a minimum interest rate to avoid exploits
}
*/
20 changes: 10 additions & 10 deletions contracts/Parameters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,37 @@ contract Parameters is IParameters {
/// @notice Price of underlying in target asset
IPrice immutable price;

/// @notice Tokens comprising the swap's float leg
/// @notice Tokens representing the swap's protection buyers
/// @notice Pegged to denominating asset + accrewed interest
/// @dev Must use 18 decimals
IToken immutable floatLeg;
IToken immutable hedge;

/// @notice Tokens comprising the swap's equity leg
/// @notice Tokens representing the swap's protection sellers
/// @notice Pegged to [R/(R-1)]x leveraged underlying
/// @dev Must use 18 decimals
IToken immutable equityLeg;
IToken immutable leverage;

/// @notice Token collateralizing floatLeg / underlying equityLeg
/// @notice Token collateralizing hedge / underlying leverage
/// @dev Must use 18 decimals
IToken immutable underlying;

constructor(
uint _fee,
IModel _model,
IPrice _price,
IToken _floatLeg,
IToken _equityLeg,
IToken _hedge,
IToken _leverage,
IToken _underlying)
{
fee = _fee;
model = _model;
price = _price;
floatLeg = _floatLeg;
equityLeg = _equityLeg;
hedge = _hedge;
leverage = _leverage;
underlying = _underlying;
}

function get() public view returns (uint, IModel, IPrice, IToken, IToken, IToken) {
return (fee, model, price, floatLeg, equityLeg, underlying);
return (fee, model, price, hedge, leverage, underlying);
}
}
124 changes: 62 additions & 62 deletions contracts/Swap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

contract Swap is ISwap, Interest, OwnableUpgradeable, UUPSUpgradeable {
// /// @notice Minimum allowed value of equityLeg in underlying
// /// @dev prevents equityLeg `totalSupply` from growing too quickly and overflowing
// /// @notice Minimum allowed value of `leverage` in underlying
// /// @dev prevents `leverage` `totalSupply` from growing too quickly and overflowing
// uint constant MIN_EQUITY_TV = 10**13;

IParameters public params;

event BuyFloat (address indexed buyer, uint amount, uint value);
event SellFloat (address indexed seller, uint amount, uint value);
event BuyEquity (address indexed buyer, uint amount, uint value);
event SellEquity(address indexed seller, uint amount, uint value);
event BuyHedge (address indexed buyer, uint amount, uint value);
event SellHedge (address indexed seller, uint amount, uint value);
event BuyLeverage (address indexed buyer, uint amount, uint value);
event SellLeverage(address indexed seller, uint amount, uint value);
event ParametersChanged(address params);

/// @custom:oz-upgrades-unsafe-allow constructor
Expand All @@ -32,132 +32,132 @@ contract Swap is ISwap, Interest, OwnableUpgradeable, UUPSUpgradeable {
setParameters(_params);
}

/// @notice Buy into floating leg, minting `amount` tokens
function buyFloat(uint amount, address to) external {
(uint fee, IModel model, IPrice price, IToken floatLeg, , IToken underlying) = params.get();
/// @notice Buy into the protection buyer pool, minting `amount` hedge tokens
function buyHedge(uint amount, address to) external {
(uint fee, IModel model, IPrice price, IToken hedge, , IToken underlying) = params.get();
uint potValue = underlying.balanceOf(address(this));
uint _accrewedMul = accrewedMul();
(uint value, uint tv) = _floatValue(
amount, price.get(), floatLeg.totalSupply(), potValue, _accrewedMul
(uint value, uint tv) = _hedgeValue(
amount, price.get(), hedge.totalSupply(), potValue, _accrewedMul
);
require(value > 0, "Zero value trade");
value += value * fee / ONE;
underlying.transferFrom(msg.sender, address(this), value);
floatLeg.mint(to, amount);
hedge.mint(to, amount);
_updateRate(model, potValue + value, tv, _accrewedMul);
emit BuyFloat(to, amount, value);
emit BuyHedge(to, amount, value);
}

/// @notice Sell out of floating leg, burning `amount` tokens
function sellFloat(uint amount, address to) external {
(uint fee, IModel model, IPrice price, IToken floatLeg, , IToken underlying) = params.get();
/// @notice Sell out of the protection buyer pool, burning `amount` hedge tokens
function sellHedge(uint amount, address to) external {
(uint fee, IModel model, IPrice price, IToken hedge, , IToken underlying) = params.get();
uint potValue = underlying.balanceOf(address(this));
uint _accrewedMul = accrewedMul();
(uint value, uint tv) = _floatValue(
amount, price.get(), floatLeg.totalSupply(), potValue, _accrewedMul
(uint value, uint tv) = _hedgeValue(
amount, price.get(), hedge.totalSupply(), potValue, _accrewedMul
);
require(value > 0, "Zero value trade");
value -= value * fee / ONE;
underlying.transfer(to, value);
floatLeg.burnFrom(msg.sender, amount);
hedge.burnFrom(msg.sender, amount);
_updateRate(model, potValue - value, tv, _accrewedMul);
emit SellFloat(to, amount, value);
emit SellHedge(to, amount, value);
}

/// @notice Buy into equity leg, minting `amount` tokens
function buyEquity(uint amount, address to) external {
(uint fee, IModel model, IPrice price, IToken floatLeg, IToken equityLeg, IToken underlying) = params.get();
/// @notice Buy into the protection seller pool, minting `amount` leverage tokens
function buyLeverage(uint amount, address to) external {
(uint fee, IModel model, IPrice price, IToken hedge, IToken leverage, IToken underlying) = params.get();
uint potValue = underlying.balanceOf(address(this));
uint _accrewedMul = accrewedMul();
uint floatTV = _floatTV(potValue, floatLeg.totalSupply(), price.get(), _accrewedMul);
uint equityTV = potValue - floatTV;
uint value = _equityValue(amount, equityLeg.totalSupply(), equityTV);
uint hedgeTV = _hedgeTV(potValue, hedge.totalSupply(), price.get(), _accrewedMul);
uint leverageTV = potValue - hedgeTV;
uint value = _leverageValue(amount, leverage.totalSupply(), leverageTV);
require(value > 0, "Zero value trade");
if (equityTV > 0) {
value += (value * fee / ONE) * floatTV / equityTV;
if (leverageTV > 0) {
value += (value * fee / ONE) * hedgeTV / leverageTV;
}
underlying.transferFrom(msg.sender, address(this), value);
equityLeg.mint(to, amount);
_updateRate(model, potValue + value, floatTV, _accrewedMul);
emit BuyEquity(to, amount, value);
leverage.mint(to, amount);
_updateRate(model, potValue + value, hedgeTV, _accrewedMul);
emit BuyLeverage(to, amount, value);
}

/// @notice Sell out of equity leg, burning `amount` tokens
function sellEquity(uint amount, address to) external {
(uint fee, IModel model, IPrice price, IToken floatLeg, IToken equityLeg, IToken underlying) = params.get();
/// @notice Sell out of the protection seller pool, burning `amount` leverage tokens
function sellLeverage(uint amount, address to) external {
(uint fee, IModel model, IPrice price, IToken hedge, IToken leverage, IToken underlying) = params.get();
uint potValue = underlying.balanceOf(address(this));
uint _accrewedMul = accrewedMul();
uint floatTV = _floatTV(potValue, floatLeg.totalSupply(), price.get(), _accrewedMul);
uint equityTV = potValue - floatTV;
uint value = _equityValue(amount, equityLeg.totalSupply(), equityTV);
uint hedgeTV = _hedgeTV(potValue, hedge.totalSupply(), price.get(), _accrewedMul);
uint leverageTV = potValue - hedgeTV;
uint value = _leverageValue(amount, leverage.totalSupply(), leverageTV);
require(value > 0, "Zero value trade");
if (equityTV > 0) {
value -= (value * fee / ONE) * floatTV / equityTV;
if (leverageTV > 0) {
value -= (value * fee / ONE) * hedgeTV / leverageTV;
}
underlying.transfer(to, value);
equityLeg.burnFrom(msg.sender, amount);
_updateRate(model, potValue - value, floatTV, _accrewedMul);
emit SellEquity(to, amount, value);
leverage.burnFrom(msg.sender, amount);
_updateRate(model, potValue - value, hedgeTV, _accrewedMul);
emit SellLeverage(to, amount, value);
}

/// @notice Value in underlying of `amount` floatLeg tokens
function floatValue(uint amount) external view returns (uint, uint) {
(, , IPrice price, IToken floatLeg, , IToken underlying) = params.get();
/// @notice Value in underlying of `amount` hedge tokens
function hedgeValue(uint amount) external view returns (uint, uint) {
(, , IPrice price, IToken hedge, , IToken underlying) = params.get();
uint _accrewedMul = accrewedMul();
return _floatValue(amount, price.get(), floatLeg.totalSupply(), underlying.balanceOf(address(this)), _accrewedMul);
return _hedgeValue(amount, price.get(), hedge.totalSupply(), underlying.balanceOf(address(this)), _accrewedMul);
}

/// @notice Value in underlying of `amount` equityLeg tokens
function equityValue(uint amount) external view returns (uint) {
(, , IPrice price, IToken floatLeg, IToken equityLeg, IToken underlying) = params.get();
/// @notice Value in underlying of `amount` leverage tokens
function leverageValue(uint amount) external view returns (uint) {
(, , IPrice price, IToken hedge, IToken leverage, IToken underlying) = params.get();
uint potValue = underlying.balanceOf(address(this));
uint _accrewedMul = accrewedMul();
return _equityValue(amount, equityLeg.totalSupply(), potValue - _floatTV(potValue, floatLeg.totalSupply(), price.get(), _accrewedMul));
return _leverageValue(amount, leverage.totalSupply(), potValue - _hedgeTV(potValue, hedge.totalSupply(), price.get(), _accrewedMul));
}

/// @notice Nominal value of 1 floatLeg token in underlying
/// @notice Nominal value of 1 hedge token in underlying
/// @dev underlying exchange rate + accrewed interest
function floatValueNominal(uint amount) external view returns (uint) {
function hedgeValueNominal(uint amount) external view returns (uint) {
(, , IPrice price, , , ) = params.get();
return _floatValueNominal(amount, accrewedMul(), price.get());
return _hedgeValueNominal(amount, accrewedMul(), price.get());
}

/// @dev Would behoove some stakeholders to call this after a price change
function updateInterestRate() external {
(, IModel model, IPrice price, IToken floatLeg, , IToken underlying) = params.get();
(, IModel model, IPrice price, IToken hedge, , IToken underlying) = params.get();
uint potValue = underlying.balanceOf(address(this));
uint _accrewedMul = accrewedMul();
_updateRate(model, potValue, _floatTV(potValue, floatLeg.totalSupply(), price.get(), _accrewedMul), _accrewedMul);
_updateRate(model, potValue, _hedgeTV(potValue, hedge.totalSupply(), price.get(), _accrewedMul), _accrewedMul);
}

function setParameters(address _params) public onlyOwner {
params = IParameters(_params);
emit ParametersChanged(_params);
}

function _equityValue(uint amount, uint supply, uint totalValue) internal pure returns (uint) {
function _leverageValue(uint amount, uint supply, uint totalValue) internal pure returns (uint) {
if (supply == 0) {
return amount;
}
return amount*totalValue/supply;
}

function _floatValue(uint amount, uint price, uint supply, uint potValue, uint _accrewedMul) internal pure returns (uint, uint) {
uint nomValue = _floatValueNominal(amount, _accrewedMul, price);
uint nomTV = _floatValueNominal(supply, _accrewedMul, price);
function _hedgeValue(uint amount, uint price, uint supply, uint potValue, uint _accrewedMul) internal pure returns (uint, uint) {
uint nomValue = _hedgeValueNominal(amount, _accrewedMul, price);
uint nomTV = _hedgeValueNominal(supply, _accrewedMul, price);
if (potValue < nomTV)
return (amount*potValue/supply, potValue);
return (nomValue, nomTV);
}

function _floatTV(uint potValue, uint supply, uint price, uint _accrewedMul) internal pure returns (uint) {
uint nomValue = _floatValueNominal(supply, _accrewedMul, price);
function _hedgeTV(uint potValue, uint supply, uint price, uint _accrewedMul) internal pure returns (uint) {
uint nomValue = _hedgeValueNominal(supply, _accrewedMul, price);
if (potValue < nomValue)
return potValue;
return nomValue;
}

function _floatValueNominal(uint amount, uint _accrewedMul, uint price) internal pure returns (uint) {
function _hedgeValueNominal(uint amount, uint _accrewedMul, uint price) internal pure returns (uint) {
return amount * (_accrewedMul / ONE_8) / price;
}

Expand Down
Loading

0 comments on commit f200ca6

Please sign in to comment.