Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bean Eth Price #589

Merged
merged 15 commits into from
Aug 7, 2023
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