Skip to content

Commit

Permalink
refactored to use total loan value and have calcs in oracle
Browse files Browse the repository at this point in the history
  • Loading branch information
jpick713 committed Mar 29, 2024
1 parent f22af37 commit 7ced3d9
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@ pragma solidity 0.8.19;

interface IMysoTokenManager {
/**
* @notice gets Myso token price from MysoTokenManager
* @param ethPriceInUsd price of eth in usd
* @return mysotoken price in eth
* @notice gets Myso token loan amount from MysoTokenManager
* @return total Myso loan amount up until now
*/
function getMysoPriceInEth(
uint256 ethPriceInUsd
) external view returns (uint256);
function totalMysoLoanAmount() external view returns (uint256);
}
61 changes: 57 additions & 4 deletions contracts/peer-to-peer/oracles/custom/MysoOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,24 @@ import {IANKRETH} from "../../interfaces/oracles/IANKRETH.sol";
import {IMETH} from "../../interfaces/oracles/IMETH.sol";
import {IMysoTokenManager} from "../../interfaces/oracles/IMysoTokenManager.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {LogExpMath} from "./utils/LogExpMath.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

/**
* @dev supports oracles which are compatible with v2v3 or v3 interfaces
*/
contract MysoOracle is ChainlinkBase, Ownable {
struct PriceParams {
// maxPrice is in 8 decimals for chainlink consistency
uint96 maxPrice;
// k is in 18 decimals
// e.g. 8e17 is 0.8 in decimal
uint96 k;
// a and b are in terms of 1000
// e.g. 1770 is 1.77 in decimal
uint32 a;
uint32 b;
}
// solhint-disable var-name-mixedcase
address internal constant MYSO = 0x00000000000000000000000000000000DeaDBeef; // TODO: put in real myso address
address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
Expand All @@ -38,6 +50,8 @@ contract MysoOracle is ChainlinkBase, Ownable {

address public mysoTokenManager;

PriceParams public mysoPriceParams;

event MysoTokenManagerUpdated(address newMysoTokenManager);

error NoMyso();
Expand All @@ -53,12 +67,17 @@ contract MysoOracle is ChainlinkBase, Ownable {
address[] memory _tokenAddrs,
address[] memory _oracleAddrs,
address _owner,
address _mysoTokenManager
address _mysoTokenManager,
uint96 _maxPrice,
uint96 _k,
uint32 _a,
uint32 _b
)
ChainlinkBase(_tokenAddrs, _oracleAddrs, MYSO_IOO_BASE_CURRENCY_UNIT)
Ownable()
{
mysoTokenManager = _mysoTokenManager;
mysoPriceParams = PriceParams(_maxPrice, _k, _a, _b);
_transferOwnership(_owner);
}

Expand All @@ -74,6 +93,22 @@ contract MysoOracle is ChainlinkBase, Ownable {
emit MysoTokenManagerUpdated(_newMysoTokenManager);
}

/**
* @dev updates myso price params
* @param _maxPrice max price in 8 decimals
* @param _k k in 18 decimals
* @param _a a in terms of 1000
* @param _b b in terms of 1000
*/
function setMysoPriceParams(
uint96 _maxPrice,
uint96 _k,
uint32 _a,
uint32 _b
) external onlyOwner {
mysoPriceParams = PriceParams(_maxPrice, _k, _a, _b);
}

function getPrice(
address collToken,
address loanToken
Expand Down Expand Up @@ -149,9 +184,27 @@ contract MysoOracle is ChainlinkBase, Ownable {
uint256 ethPriceInUsd = _checkAndReturnLatestRoundData(
ETH_USD_CHAINLINK
);
mysoPriceInEth = IMysoTokenManager(mysoTokenManager).getMysoPriceInEth(
ethPriceInUsd
);
uint256 _totalMysoLoanAmount = IMysoTokenManager(mysoTokenManager)
.totalMysoLoanAmount();
uint256 mysoPriceInUsd = _getMysoPriceInUsd(_totalMysoLoanAmount);
mysoPriceInEth = Math.mulDiv(mysoPriceInUsd, 1e18, ethPriceInUsd);
}

function _getMysoPriceInUsd(
uint256 totalMysoLoanAmount
) internal view returns (uint256 mysoPriceInUsd) {
PriceParams memory params = mysoPriceParams;
uint256 maxPrice = uint256(params.maxPrice);
uint256 k = uint256(params.k);
uint256 a = uint256(params.a);
uint256 b = uint256(params.b);
uint256 numerator = k * b;
uint256 denominator = uint256(
LogExpMath.exp(
int256(Math.mulDiv(totalMysoLoanAmount, a, 1000000000))
)
) + (2 * b - 1000) * 1e15;
mysoPriceInUsd = maxPrice - Math.mulDiv(numerator, 1e5, denominator);
}

function _getRPLPriceInEth() internal view returns (uint256 rplPriceRaw) {
Expand Down
File renamed without changes.
21 changes: 0 additions & 21 deletions contracts/test/TestnetTokenManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import {DataTypesPeerToPeer} from "../peer-to-peer/DataTypesPeerToPeer.sol";
import {DataTypesPeerToPool} from "../peer-to-pool/DataTypesPeerToPool.sol";
import {Errors} from "../Errors.sol";
import {IMysoTokenManager} from "../interfaces/IMysoTokenManager.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {LogExpMath} from "./LogExpMath.sol";

contract TestnetTokenManager is ERC20, Ownable2Step, IMysoTokenManager {
uint8 internal _decimals;
Expand Down Expand Up @@ -130,26 +128,7 @@ contract TestnetTokenManager is ERC20, Ownable2Step, IMysoTokenManager {
super._transferOwnership(_newOwnerProposal);
}

function getMysoPriceInEth(
uint256 ethPriceInUsd
) public view returns (uint256) {
uint256 mysoPriceInUsd = _getMysoPriceInUsd();
return Math.mulDiv(mysoPriceInUsd, 1e18, ethPriceInUsd);
}

function decimals() public view override returns (uint8) {
return _decimals;
}

function _getMysoPriceInUsd() internal view returns (uint256) {
uint256 k1 = 63 * 1e8;
uint256 k2 = 80 * 1e18;
uint256 a = 1770;
uint256 denominator = uint256(
LogExpMath.exp(
int256(Math.mulDiv(totalMysoLoanAmount, a, 1000 * 1e18))
)
) + 1e18;
return k1 + Math.mulDiv(k2, 1e8, denominator);
}
}
33 changes: 8 additions & 25 deletions test/peer-to-peer/mainnet-myso-oracle-forked-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,22 +193,19 @@ describe('Peer-to-Peer: Myso Recent Forked Mainnet Tests', function () {
usdtToEthChainlinkAddr
],
team.address,
borrowerGateway.address
borrowerGateway.address,
63000000,
800000000000000000,
1770,
5300
)
await mysoOracle.deployed()

const mysoPriceData = await mysoOracle.mysoPrice()

expect(mysoPriceData.prePrice).to.equal(50000000)
expect(mysoPriceData.postPrice).to.equal(50000000)
const timestampAtDeployment = mysoPriceData.switchTime

const mysoPriceData = await mysoOracle.mysoPriceParams()
const mysoOracleOwner = await mysoOracle.owner()

expect(mysoOracleOwner).to.equal(team.address)

await expect(mysoOracle.connect(lender).setMysoPrice(80000000)).to.be.revertedWith('Ownable: caller is not the owner')

await expect(mysoOracle.getPrice(weth.address, cbeth)).to.be.revertedWithCustomError(mysoOracle, 'NoMyso')

const wethCollMysoLoanPrice = await mysoOracle.getPrice(weth.address, myso)
Expand Down Expand Up @@ -279,22 +276,8 @@ describe('Peer-to-Peer: Myso Recent Forked Mainnet Tests', function () {
console.log(ethers.utils.formatUnits(mysoCollDaiLoanPrice, 18))
}

await mysoOracle.connect(team).setMysoPrice(100000000)
const newMysoPriceData = await mysoOracle.mysoPrice()
expect(newMysoPriceData.prePrice).to.equal(50000000)
expect(newMysoPriceData.postPrice).to.equal(100000000)
expect(newMysoPriceData.switchTime).to.be.gte(ethers.BigNumber.from(timestampAtDeployment).add(ONE_HOUR.div(12)))
const newWethCollMysoLoanPrice = await mysoOracle.getPrice(weth.address, myso)
expect(newWethCollMysoLoanPrice).to.equal(wethCollMysoLoanPrice)
await ethers.provider.send('evm_mine', [ethers.BigNumber.from(newMysoPriceData.switchTime).add(10).toNumber()])
const wethCollMysoLoanPostPrice = await mysoOracle.getPrice(weth.address, myso)
// difference is very small less than the order of 10^-13
expect(
wethCollMysoLoanPostPrice
.sub(wethCollMysoLoanPrice.div(2))
.mul(ethers.BigNumber.from(10).pow(13))
.div(wethCollMysoLoanPostPrice)
).to.be.equal(0)
await mysoOracle.connect(team).setMysoPriceParams(70000000, 800000000000000000, 1770, 1000)
const newMysoPriceData = await mysoOracle.mysoPriceParams()

const wstEthCollMysoLoanPostPrice = await mysoOracle.getPrice(wsteth.address, myso)
const rethCollMysoLoanPostPrice = await mysoOracle.getPrice(reth, myso)
Expand Down

0 comments on commit 7ced3d9

Please sign in to comment.