Skip to content

Commit

Permalink
Bean Eth Price (#589)
Browse files Browse the repository at this point in the history
  • Loading branch information
publiuss committed Aug 7, 2023
2 parents 893c99d + f4de22d commit 76a4c61
Show file tree
Hide file tree
Showing 12 changed files with 600 additions and 79 deletions.
120 changes: 60 additions & 60 deletions protocol/abi/Beanstalk.json
Original file line number Diff line number Diff line change
Expand Up @@ -4375,9 +4375,9 @@
},
{
"indexed": false,
"internalType": "int128",
"internalType": "int96",
"name": "stem",
"type": "int128"
"type": "int96"
},
{
"indexed": false,
Expand Down Expand Up @@ -4484,6 +4484,59 @@
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenIn",
"type": "address"
},
{
"internalType": "address",
"name": "tokenOut",
"type": "address"
},
{
"internalType": "uint256",
"name": "amountIn",
"type": "uint256"
}
],
"name": "getAmountOut",
"outputs": [
{
"internalType": "uint256",
"name": "amountOut",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenIn",
"type": "address"
},
{
"internalType": "address",
"name": "tokenOut",
"type": "address"
}
],
"name": "getMaxAmountIn",
"outputs": [
{
"internalType": "uint256",
"name": "amountIn",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [
Expand Down Expand Up @@ -4570,59 +4623,6 @@
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenIn",
"type": "address"
},
{
"internalType": "address",
"name": "tokenOut",
"type": "address"
},
{
"internalType": "uint256",
"name": "amountIn",
"type": "uint256"
}
],
"name": "getAmountOut",
"outputs": [
{
"internalType": "uint256",
"name": "amountOut",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenIn",
"type": "address"
},
{
"internalType": "address",
"name": "tokenOut",
"type": "address"
}
],
"name": "getMaxAmountIn",
"outputs": [
{
"internalType": "uint256",
"name": "amountIn",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -5692,7 +5692,7 @@
"type": "address"
}
],
"name": "getLastStem",
"name": "getLastMowedStem",
"outputs": [
{
"internalType": "int96",
Expand Down Expand Up @@ -6025,9 +6025,9 @@
"name": "seasonToStem",
"outputs": [
{
"internalType": "int128",
"internalType": "int96",
"name": "stem",
"type": "int128"
"type": "int96"
}
],
"stateMutability": "view",
Expand Down Expand Up @@ -6057,9 +6057,9 @@
"name": "stemTipForToken",
"outputs": [
{
"internalType": "int128",
"internalType": "int96",
"name": "_stemTip",
"type": "int128"
"type": "int96"
}
],
"stateMutability": "view",
Expand Down
1 change: 1 addition & 0 deletions protocol/contracts/beanstalk/init/InitDiamond.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ contract InitDiamond {
s.season.withdrawSeasons = 25;
s.season.period = C.getSeasonPeriod();
s.season.timestamp = block.timestamp;
s.season.stemStartSeason = 0;
s.season.start = s.season.period > 0 ?
(block.timestamp / s.season.period) * s.season.period :
block.timestamp;
Expand Down
13 changes: 8 additions & 5 deletions protocol/contracts/ecosystem/price/BeanstalkPrice.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import "./CurvePrice.sol";
import {WellPrice, C, SafeMath} from "./WellPrice.sol";

contract BeanstalkPrice is CurvePrice {
contract BeanstalkPrice is CurvePrice, WellPrice {
using SafeMath for uint256;

struct Prices {
uint256 price;
Expand All @@ -14,15 +16,16 @@ contract BeanstalkPrice is CurvePrice {
}

function price() external view returns (Prices memory p) {
p.ps = new P.Pool[](1);
p.ps = new P.Pool[](2);
p.ps[0] = getCurve();
p.ps[1] = getConstantProductWell(C.BEAN_ETH_WELL);


// assumes that liquidity and prices on all pools uses the same precision.
for (uint256 i = 0; i < p.ps.length; i++) {
p.price += p.ps[i].price * p.ps[i].liquidity;
p.price += p.ps[i].price.mul(p.ps[i].liquidity);
p.liquidity += p.ps[i].liquidity;
p.deltaB += p.ps[i].deltaB;
}
p.price /= p.liquidity;
p.price = p.price.div(p.liquidity);
}
}
98 changes: 98 additions & 0 deletions protocol/contracts/ecosystem/price/WellPrice.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//SPDX-License-Identifier: MIT
pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import {P} from "./P.sol";
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {Call, IWell, IERC20} from "../../interfaces/basin/IWell.sol";
import {IBeanstalkWellFunction} from "../../interfaces/basin/IBeanstalkWellFunction.sol";
import {LibUsdOracle} from "../../libraries/Oracle/LibUsdOracle.sol";
import {LibWellMinting} from "../../libraries/Minting/LibWellMinting.sol";
import {LibWell} from "../../libraries/Well/LibWell.sol";
import {C} from "../../C.sol";

interface IBeanstalk {
function bdv(address token, uint256 amount) external view returns (uint256);

function poolDeltaB(address pool) external view returns (int256);
}

interface dec{
function decimals() external view returns (uint256);
}

contract WellPrice {

using SafeMath for uint256;

IBeanstalk private constant BEANSTALK = IBeanstalk(0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5);
uint256 private constant WELL_DECIMALS = 1e18;
uint256 private constant PRICE_PRECISION = 1e6;

struct Pool {
address pool;
address[2] tokens;
uint256[2] balances;
uint256 price;
uint256 liquidity;
int256 deltaB;
uint256 lpUsd;
uint256 lpBdv;
}

function getConstantProductWell(address wellAddress) public view returns (P.Pool memory pool) {
IWell well = IWell(wellAddress);
pool.pool = wellAddress;

IERC20[] memory wellTokens = well.tokens();
pool.tokens = [address(wellTokens[0]), address(wellTokens[1])];

uint256[] memory wellBalances = well.getReserves();
pool.balances = [wellBalances[0], wellBalances[1]];

uint256 beanIndex = LibWell.getBeanIndex(wellTokens);
uint256 tknIndex = beanIndex == 0 ? 1 : 0;

// swap 1 bean of the opposite asset to get the usd price
// price = amtOut/tknOutPrice
uint256 assetPrice = LibUsdOracle.getUsdPrice(pool.tokens[tknIndex]);
if(assetPrice > 0) {
pool.price =
well.getSwapOut(wellTokens[beanIndex], wellTokens[tknIndex], 1e6)
.mul(PRICE_PRECISION)
.div(assetPrice);
} else {
// cannnot determine a price for bean if the other asset that bean is trading against is 0.
pool.price = 0;
}

// liquidity is calculated by getting the usd value of the bean portion of the pool,
// and multiplying by 2 to get the total liquidity of the pool.
pool.liquidity =
pool.balances[beanIndex]
.mul(pool.price)
.mul(2)
.div(PRICE_PRECISION);

pool.deltaB = getDeltaB(wellAddress, wellTokens, wellBalances);
pool.lpUsd = pool.liquidity.mul(WELL_DECIMALS).div(IERC20(wellAddress).totalSupply());
pool.lpBdv = BEANSTALK.bdv(wellAddress, WELL_DECIMALS);
}

function getDeltaB(address well, IERC20[] memory tokens, uint256[] memory reserves) internal view returns (int256 deltaB) {
Call memory wellFunction = IWell(well).wellFunction();
(uint256[] memory ratios, uint256 beanIndex, bool success) = LibWell.getRatiosAndBeanIndex(tokens);
// If the USD Oracle oracle call fails, we can't compute deltaB
if(!success) return 0;

uint256 beansAtPeg = IBeanstalkWellFunction(wellFunction.target).calcReserveAtRatioLiquidity(
reserves,
beanIndex,
ratios,
wellFunction.data
);

deltaB = int256(beansAtPeg) - int256(reserves[beanIndex]);
}

}
4 changes: 4 additions & 0 deletions protocol/contracts/mocks/well/MockSetComponentsWell.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ contract MockSetComponentsWell is MockToken {
_reserves = new uint256[](2);
}

function init() external {
_reserves = new uint256[](2);
}

Call[] public _pumps;
Call public _wellFunction;

Expand Down
18 changes: 17 additions & 1 deletion protocol/scripts/impersonate.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ const {
ETH_USDC_UNISWAP_V3,
ETH_USDT_UNISWAP_V3,
USDT,
ETH_USD_CHAINLINK_AGGREGATOR
ETH_USD_CHAINLINK_AGGREGATOR,
BEAN_ETH_WELL
} = require('../test/utils/constants');
const { deployWell } = require('../utils/well.js');
const { impersonateSigner, mintEth } = require('../utils');

const { getSigner } = '../utils'
Expand Down Expand Up @@ -95,6 +97,8 @@ async function weth() {
WETH,
JSON.parse(tokenJson).deployedBytecode,
]);
const weth = await ethers.getContractAt("MockToken", WETH);
await weth.setDecimals(18);
}

async function router() {
Expand Down Expand Up @@ -268,6 +272,15 @@ async function ethUsdtUniswap() {
]);
}

async function beanEthWell() {
const well = await deployWell([BEAN, WETH]);
const bytecode = await ethers.provider.getCode(well.address)
await network.provider.send("hardhat_setCode", [
BEAN_ETH_WELL,
bytecode,
]);
}

async function ethUsdChainlinkAggregator() {
let chainlinkAggregatorJson = fs.readFileSync(`./artifacts/contracts/mocks/chainlink/MockChainlinkAggregator.sol/MockChainlinkAggregator.json`);

Expand All @@ -279,6 +292,8 @@ async function ethUsdChainlinkAggregator() {
await ethUsdChainlinkAggregator.setDecimals(6)
}



exports.impersonateRouter = router
exports.impersonateBean = bean
exports.impersonateCurve = curve
Expand All @@ -295,3 +310,4 @@ exports.impersonateEthUsdcUniswap = ethUsdcUniswap
exports.impersonateEthUsdtUniswap = ethUsdtUniswap
exports.impersonateBeanstalk = impersonateBeanstalk
exports.impersonateEthUsdChainlinkAggregator = ethUsdChainlinkAggregator
exports.impersonateBeanEthWell = beanEthWell
3 changes: 0 additions & 3 deletions protocol/test/LegacyClaim.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ const { upgradeWithNewFacets } = require("../scripts/diamond");

describe("Legacy Claim", async function () {
before(async function () {
console.log("startup stuff");

try {
await network.provider.request({
method: "hardhat_reset",
Expand Down Expand Up @@ -47,7 +45,6 @@ describe("Legacy Claim", async function () {


this.diamond = BEANSTALK;
console.log("this.diamond: ", this.diamond);

// this.season = await ethers.getContractAt("MockSeasonFacet", this.diamond);

Expand Down
7 changes: 4 additions & 3 deletions protocol/test/Silo.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,10 @@ describe('Silo', function () {
depositID4 = '0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716DFFF000000000000000000111';
expect(await this.metadata.uri(depositID4)).to.eq(depositmetadata);

depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageBeanEth.txt', 'utf-8');
depositID5 = '0x9bAaB117304f7D6517048e371025dB8f89a8DbE5FFFFFFFFFFFFF00000000002';
expect(await this.metadata.uri(depositID5)).to.eq(depositmetadata);
// TODO: reimplement once basin addresses are deployed.
// depositmetadata = await fs.readFileSync(__dirname + '/data/base64EncodedImageBeanEth.txt', 'utf-8');
// depositID5 = '0x9bAaB117304f7D6517048e371025dB8f89a8DbE5FFFFFFFFFFFFF00000000002';
// expect(await this.metadata.uri(depositID5)).to.eq(depositmetadata);

});

Expand Down
Loading

0 comments on commit 76a4c61

Please sign in to comment.