Skip to content

Commit

Permalink
simplify fee calculations, remove priority fee limit
Browse files Browse the repository at this point in the history
  • Loading branch information
JonahGroendal committed Sep 23, 2022
1 parent a9fff9b commit fb61f1c
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 165 deletions.
50 changes: 22 additions & 28 deletions .openzeppelin/unknown-1337.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
},
{
"address": "0x82D50AD3C1091866E258Fd0f1a7cC9674609D254",
"txHash": "0x95efce8e43a1a6153d49177601b0f171055ad22cd961dd09d2cbe0e8a482f1a5",
"txHash": "0x0e86054bfa506da31a00d83825491f0bbc9f1fd624fd70095d407f538c4db1fd",
"kind": "uups"
}
],
Expand Down Expand Up @@ -485,9 +485,9 @@
}
}
},
"369a23fc4d42a3cfab4d793391d4cc292c3dcd1808c060d1212e134072f9cfb5": {
"ae04f5b4b3fd1da58e361903ccf516e586451c6f9ac5a35837deaf58229ab75d": {
"address": "0x75c35C980C0d37ef46DF04d31A140b65503c0eEd",
"txHash": "0x02f538627f216f44293f21990292f388197f1122d96531edd69303765bda15dd",
"txHash": "0xd5c36e1cf6a55608237e8cc9bed979458507129392aa04ec66193786e5a33692",
"layout": {
"storage": [
{
Expand Down Expand Up @@ -535,78 +535,72 @@
},
{
"contract": "Rates",
"label": "price",
"type": "t_contract(IPrice)9245",
"src": "../project:/contracts/Rates.sol:22"
"label": "fee",
"type": "t_uint256",
"src": "../project:/contracts/Rates.sol:24"
},
{
"contract": "Rates",
"label": "maxPriorityFee",
"label": "interest",
"type": "t_uint256",
"src": "../project:/contracts/Rates.sol:26"
"src": "../project:/contracts/Rates.sol:28"
},
{
"contract": "Rates",
"label": "tolerance",
"type": "t_uint256",
"label": "model",
"type": "t_contract(IModel)9237",
"src": "../project:/contracts/Rates.sol:31"
},
{
"contract": "Rates",
"label": "interest",
"type": "t_uint256",
"src": "../project:/contracts/Rates.sol:35"
"label": "price",
"type": "t_contract(IPrice)9245",
"src": "../project:/contracts/Rates.sol:34"
},
{
"contract": "Rates",
"label": "startTime",
"type": "t_uint256",
"src": "../project:/contracts/Rates.sol:39"
"src": "../project:/contracts/Rates.sol:38"
},
{
"contract": "Rates",
"label": "startValue",
"type": "t_uint256",
"src": "../project:/contracts/Rates.sol:42"
},
{
"contract": "Rates",
"label": "model",
"type": "t_contract(IModel)9237",
"src": "../project:/contracts/Rates.sol:45"
"src": "../project:/contracts/Rates.sol:41"
},
{
"contract": "Swap",
"label": "fixedLeg",
"type": "t_contract(IToken)9503",
"type": "t_contract(IToken)9457",
"src": "../project:/contracts/Swap.sol:16"
},
{
"contract": "Swap",
"label": "floatLeg",
"type": "t_contract(IToken)9503",
"type": "t_contract(IToken)9457",
"src": "../project:/contracts/Swap.sol:21"
},
{
"contract": "Swap",
"label": "underlying",
"type": "t_contract(IToken)9503",
"type": "t_contract(IToken)9457",
"src": "../project:/contracts/Swap.sol:25"
}
],
"types": {
"t_contract(IToken)9503": {
"t_contract(IToken)9457": {
"label": "contract IToken"
},
"t_contract(IPrice)9245": {
"label": "contract IPrice"
},
"t_uint256": {
"label": "uint256"
},
"t_contract(IModel)9237": {
"label": "contract IModel"
},
"t_contract(IPrice)9245": {
"label": "contract IPrice"
},
"t_array(t_uint256)50_storage": {
"label": "uint256[50]"
},
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ cons:


# TODO
- subtract the cost of gas from the premium so small transactions aren't disencentivized
- look into using super cheap exp() function
- consolidate premium rates functions
- make sure not vulnerable to erc 777 reentry
Expand Down
11 changes: 2 additions & 9 deletions contracts/IRates.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,12 @@ pragma solidity >=0.4.22 <0.9.0;

interface IRates {
function interest() external view returns (uint);
function maxPriorityFee() external view returns (uint);
function tolerance() external view returns (uint);
function fee() external view returns (uint);

function fixedValueNominal(uint amount) external view returns (uint);
function accIntMul() external view returns (uint);

function fixedBuyPremium(uint value) external view returns (uint);
function fixedSellPremium(uint value) external view returns (uint);
function floatBuyPremium(uint value, uint fixedTotalValue, uint floatTotalValue) external view returns (uint);
function floatSellPremium(uint value, uint fixedTotalValue, uint floatTotalValue) external view returns (uint);

function setMaxPriorityFee(uint _maxPriorityFee) external;
function setTolerance(uint _tolerance) external;
function setFee(uint _tolerance) external;
function setPrice(address _price) external;
function setModel(address _model) external;
}
74 changes: 15 additions & 59 deletions contracts/Rates.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,41 @@ contract Rates is IRates, Initializable, OwnableUpgradeable, UUPSUpgradeable {
uint constant ONE_8 = 10**8;
uint constant COMPOUNDING_PERIOD = 3600; // 1 hour

/// @notice Price of underlying in target asset
IPrice internal price;

/// @notice Maximum allowed priority fee for trades
/// @dev Prevents fruntrunning price oracle
uint public maxPriorityFee;

/// @notice Amount the price feed can safely deviate from the actual exchange rate due to latency
/// @dev Used to calculate buy/sell premiums.
/// @dev 18-decimal fixed-point percentage
uint public tolerance;
/// @notice Fee rate applied to notional value of trade.
/// @notice Prevents soft frontrunning.
/// @dev 18-decimal fixed-point
uint public fee;

/// @notice 1 + hourly interest rate. Rate can be negative
/// @dev 18-decimal fixed-point
uint public interest;

/// @notice Interest rate model
IModel public model;

/// @notice Price of underlying in target asset
IPrice internal price;

/// @notice Timestamp of when interest began accrewing
/// @dev start at a perfect multiple of COMPOUNDING_PERIOD so all contracts are syncronized
uint internal startTime;

/// @notice Value of accumulated interest multiplier when interest began accrewing
uint internal startValue;

/// @notice Interest rate model
IModel public model;

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

event PriceFeedChanged(address indexed priceFeed);
event MaxPriorityFeeChanged(uint maxPriorityFee);
event ToleranceChanged(uint tolerance);
event FeeChanged(uint tolerance);
event InterestModelChanged(address indexed model);

function initialize(address _price, address _model) public onlyInitializing {
__Ownable_init();
__UUPSUpgradeable_init();
maxPriorityFee = 3000000000;
interest = ONE;
startTime = (block.timestamp / COMPOUNDING_PERIOD) * COMPOUNDING_PERIOD;
startValue = ONE_26;
Expand All @@ -81,48 +76,9 @@ contract Rates is IRates, Initializable, OwnableUpgradeable, UUPSUpgradeable {
}
}

/// @return Fee required to buy `amount` fixedLeg tokens
/// @param value Value of trade in underlying
function fixedBuyPremium(uint value) public view returns (uint) {
return (value * ONE / (ONE - tolerance)) - value;
}

/// @return Fee required to sell `amount` fixedLeg tokens
/// @param value Value of trade in underlying
function fixedSellPremium(uint value) public view returns (uint) { // remove this and just use fixedBuyPremium with a negative value
return value - (value * ONE / (ONE + tolerance));
}

/// @return Fee required to buy `amount` floatLeg tokens
/// @param value Value of trade in underlying
/// @param fixedTotalValue Value in underlying of all fixedLeg tokens
/// @param floatTotalValue Value in underlying of all floatLeg tokens
function floatBuyPremium(uint value, uint fixedTotalValue, uint floatTotalValue) public view returns (uint) {
if (floatTotalValue <= 0) {
return 0;
}
return (value - (value * ONE / (ONE + tolerance))) * fixedTotalValue / floatTotalValue;
}

/// @return Fee required to sell `amount` floatLeg tokens
/// @param value Value of trade in underlying
/// @param fixedTotalValue Value in underlying of all fixedLeg tokens
/// @param floatTotalValue Value in underlying of all floatLeg tokens
function floatSellPremium(uint value, uint fixedTotalValue, uint floatTotalValue) public view returns (uint) {
if (floatTotalValue <= 0) {
return 0;
}
return ((value * ONE / (ONE - tolerance)) - value) * fixedTotalValue / floatTotalValue;
}

function setMaxPriorityFee(uint _maxPriorityFee) public onlyOwner {
maxPriorityFee = _maxPriorityFee;
emit MaxPriorityFeeChanged(_maxPriorityFee);
}

function setTolerance(uint _tolerance) public onlyOwner {
tolerance = _tolerance;
emit ToleranceChanged(_tolerance);
function setFee(uint _fee) public onlyOwner {
fee = _fee;
emit FeeChanged(_fee);
}

function setPrice(address _price) public onlyOwner {
Expand Down Expand Up @@ -156,7 +112,7 @@ contract Rates is IRates, Initializable, OwnableUpgradeable, UUPSUpgradeable {
/// @notice Change the hourly interest rate. May represent a negative rate.
/// @param _interest 18-decimal fixed-point. 1 + hourly interest rate.
function _setInterest(uint _interest, uint _accIntMul) internal {
startValue = _accIntMul;//accIntMul();
startValue = _accIntMul;
startTime = startTime + (((block.timestamp - startTime) / COMPOUNDING_PERIOD) * COMPOUNDING_PERIOD);
interest = _interest;
}
Expand Down
45 changes: 20 additions & 25 deletions contracts/Swap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,68 +58,63 @@ contract Swap is ISwap, Rates {
event BuyFloat (address indexed buyer, uint amount, uint value);
event SellFloat(address indexed seller, uint amount, uint value);


/// @notice limit TX priority to prevent fruntrunning price oracle updates
/// @notice Also should delay trades to prevent trading on advanced price knowledge.
/// @dev A selfish block producer could defeat this protection
modifier limitedPriority {
require(tx.gasprice - block.basefee <= maxPriorityFee, "Priority fee too high");
_;
}

/// @notice Buy into fixed leg, minting `amount` tokens
function buyFixed(uint amount, address to) public limitedPriority {
function buyFixed(uint amount, address to) public {
uint potValue = _potValue();
uint _accIntMul = accIntMul();
(uint value, uint tv) = _fixedValue(amount, potValue, _accIntMul);
require(value > 0, "Zero value trade");
uint cost = value + fixedBuyPremium(value);
underlying.transferFrom(msg.sender, address(this), cost);
value += value * fee / ONE;
underlying.transferFrom(msg.sender, address(this), value);
fixedLeg.mint(to, amount);
_updateInterest(potValue + cost, tv, _accIntMul);
_updateInterest(potValue + value, tv, _accIntMul);
emit BuyFixed(to, amount, value);
}

/// @notice Sell out of fixed leg, burning `amount` tokens
function sellFixed(uint amount, address to) public limitedPriority {
function sellFixed(uint amount, address to) public {
uint potValue = _potValue();
uint _accIntMul = accIntMul();
(uint value, uint tv) = _fixedValue(amount, potValue, _accIntMul);
require(value > 0, "Zero value trade");
uint cost = value - fixedSellPremium(value);
underlying.transfer(to, cost);
value -= value * fee / ONE;
underlying.transfer(to, value);
fixedLeg.burnFrom(msg.sender, amount);
_updateInterest(potValue - cost, tv, _accIntMul);
_updateInterest(potValue - value, tv, _accIntMul);
emit SellFixed(to, amount, value);
}

/// @notice Buy into floating leg, minting `amount` tokens
function buyFloat(uint amount, address to) public limitedPriority {
function buyFloat(uint amount, address to) public {
uint potValue = _potValue();
uint _accIntMul = accIntMul();
uint fixedTV = _fixedTV(potValue, _accIntMul);
uint floatTV = potValue - fixedTV;
uint value = _floatValue(amount, floatTV);
require(value > 0, "Zero value trade");
uint cost = value + floatBuyPremium(value, fixedTV, floatTV);
underlying.transferFrom(msg.sender, address(this), cost);
if (floatTV > 0) {
value += (value * fee / ONE) * fixedTV / floatTV;
}
underlying.transferFrom(msg.sender, address(this), value);
floatLeg.mint(to, amount);
_updateInterest(potValue + cost, fixedTV, _accIntMul);
_updateInterest(potValue + value, fixedTV, _accIntMul);
emit BuyFloat(to, amount, value);
}

/// @notice Sell out of floating leg, burning `amount` tokens
function sellFloat(uint amount, address to) public limitedPriority {
function sellFloat(uint amount, address to) public {
uint potValue = _potValue();
uint _accIntMul = accIntMul();
uint fixedTV = _fixedTV(potValue, _accIntMul);
uint floatTV = potValue - fixedTV;
uint value = _floatValue(amount, floatTV);
require(value > 0, "Zero value trade");
uint cost = value - floatSellPremium(value, fixedTV, floatTV);
underlying.transfer(to, cost);
if (floatTV > 0) {
value -= (value * fee / ONE) * fixedTV / floatTV;
}
underlying.transfer(to, value);
floatLeg.burnFrom(msg.sender, amount);
_updateInterest(potValue - cost, fixedTV, _accIntMul);
_updateInterest(potValue - value, fixedTV, _accIntMul);
emit SellFloat(to, amount, value);
}

Expand Down
Loading

0 comments on commit fb61f1c

Please sign in to comment.