Skip to content

Commit

Permalink
Beanstalk arbitrum (#11887)
Browse files Browse the repository at this point in the history
  • Loading branch information
soilking authored Oct 14, 2024
1 parent 6b01515 commit 7297305
Showing 1 changed file with 140 additions and 70 deletions.
210 changes: 140 additions & 70 deletions projects/bean/index.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
const ADDRESSES = require('../helper/coreAssets.json')
const BEANSTALK = "0xc1e088fc1323b20bcbee9bd1b9fc9546db5624c5";

const BEAN_ERC20_V1 = "0xdc59ac4fefa32293a95889dc396682858d52e5db";
const BEANETH_V1 = "0x87898263b6c5babe34b4ec53f22d98430b91e371";
const BEAN3CRV_V1 = "0x3a70dfa7d2262988064a2d051dd47521e43c9bdd";
const BEANLUSD_V1 = "0xd652c40fbb3f06d6b58cb9aa9cff063ee63d465d";

const BEAN_ERC20 = "0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab";
const UNRIPE_BEAN_ERC20 = "0x1bea0050e63e05fbb5d8ba2f10cf5800b6224449";
const UNRIPE_LP_ERC20 = "0x1bea3ccd22f4ebd3d37d731ba31eeca95713716d";
const BEAN3CRV_V2 = "0xc9c32cd16bf7efb85ff14e0c8603cc90f6f2ee49";
const BEANETH_V2 = "0xbea0e11282e2bb5893bece110cf199501e872bad";

// Underlying non-bean tokens
const WETH = ADDRESSES.ethereum.WETH;
const CRV3 = "0x6c3f90f043a72fa612cbac8115ee7e52bde6e490";
const LUSD = ADDRESSES.ethereum.LUSD;
const ADDR = {
ethereum: {
BEANSTALK: "0xc1e088fc1323b20bcbee9bd1b9fc9546db5624c5",
BEAN_ERC20_V1: "0xdc59ac4fefa32293a95889dc396682858d52e5db",
BEANETH_V1: "0x87898263b6c5babe34b4ec53f22d98430b91e371",
BEAN3CRV_V1: "0x3a70dfa7d2262988064a2d051dd47521e43c9bdd",
BEANLUSD_V1: "0xd652c40fbb3f06d6b58cb9aa9cff063ee63d465d",
BEAN_ERC20: "0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab",
UNRIPE_BEAN_ERC20: "0x1bea0050e63e05fbb5d8ba2f10cf5800b6224449",
UNRIPE_LP_ERC20: "0x1bea3ccd22f4ebd3d37d731ba31eeca95713716d",
BEAN3CRV_V2: "0xc9c32cd16bf7efb85ff14e0c8603cc90f6f2ee49",
BEANETH_V2: "0xbea0e11282e2bb5893bece110cf199501e872bad",
// Underlying non-bean tokens
WETH: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
CRV3: "0x6c3f90f043a72fa612cbac8115ee7e52bde6e490",
LUSD: "0x5f98805a4e8be255a32880fdec7f6728c6568ba0"
},
arbitrum: {
BEANSTALK: "0xd1a0060ba708bc4bcd3da6c37efa8dedf015fb70",
BEAN_ERC20: "0xbea0005b8599265d41256905a9b3073d397812e4",
BEANWETH: "0xbea00aa8130acad047e137ec68693c005f8736ce",
BEANWSTETH: "0xbea00bbe8b5da39a3f57824a1a13ec2a8848d74f",
BEANWEETH: "0xbea00cc9f93e9a8ac0dfdff2d64ba38eb9c2e48c",
BEANWBTC: "0xbea00dde4b34acdcb1a30442bd2b39ca8be1b09c",
BEANUSDC: "0xbea00ee04d8289aed04f92ea122a96dc76a91bd7",
BEANUSDT: "0xbea00ff437ca7e8354b174339643b4d1814bed33",
UNRIPE_BEAN_ERC20: "0x1bea054dddbca12889e07b3e076f511bf1d27543",
UNRIPE_LP_ERC20: "0x1bea059c3ea15f6c10be1c53d70c75fd1266d788",
// Underlying non-bean tokens
WETH: "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
WSTETH: "0x5979d7b546e38e414f7e9822514be443a4800529",
WEETH: "0x35751007a407ca6feffe80b3cb397736d2cf4dbe",
WBTC: "0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f",
USDC: "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
USDT: "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9"
}
};

/// REFERENCE BLOCKS TIMESTAMPS
// Whitelist BEANETH_V1 12974075 1628288832
Expand All @@ -34,52 +53,96 @@ const LUSD = ADDRESSES.ethereum.LUSD;
const EXPLOIT_TIME = 1650198256;
const REPLANT_TIME = 1659657966;
const BIP12_TIME = 1645038020;
const ARB_MIGRATION_TIME = 1728529200;

// List of pools and time time periods they were valid within beanstalk
const ALL_POOLS = {
[BEANETH_V1]: {
startTime: 1628288832,
endTime: EXPLOIT_TIME,
underlying: [BEAN_ERC20_V1, WETH]
},
[BEAN3CRV_V1]: {
startTime: 1645038020,
endTime: EXPLOIT_TIME,
underlying: [BEAN_ERC20_V1, CRV3]
},
[BEANLUSD_V1]: {
startTime: 1649451979,
endTime: EXPLOIT_TIME,
underlying: [BEAN_ERC20_V1, LUSD]
},
[BEAN3CRV_V2]: {
startTime: 1659645914,
endTime: 999999999999,
// endTime: 1716407627, // Dewhitelisted upon BIP-45 deployment, but some tokens are still deposited and receive yield
underlying: [BEAN_ERC20, CRV3]
ethereum: {
[ADDR.ethereum.BEANETH_V1]: {
startTime: 1628288832,
endTime: EXPLOIT_TIME,
underlying: [ADDR.ethereum.BEAN_ERC20_V1, ADDR.ethereum.WETH]
},
[ADDR.ethereum.BEAN3CRV_V1]: {
startTime: 1645038020,
endTime: EXPLOIT_TIME,
underlying: [ADDR.ethereum.BEAN_ERC20_V1, ADDR.ethereum.CRV3]
},
[ADDR.ethereum.BEANLUSD_V1]: {
startTime: 1649451979,
endTime: EXPLOIT_TIME,
underlying: [ADDR.ethereum.BEAN_ERC20_V1, ADDR.ethereum.LUSD]
},
[ADDR.ethereum.BEAN3CRV_V2]: {
startTime: 1659645914,
endTime: ARB_MIGRATION_TIME,
underlying: [ADDR.ethereum.BEAN_ERC20, ADDR.ethereum.CRV3]
},
[ADDR.ethereum.BEANETH_V2]: {
startTime: 1693412759,
endTime: ARB_MIGRATION_TIME,
underlying: [ADDR.ethereum.BEAN_ERC20, ADDR.ethereum.WETH]
}
},
[BEANETH_V2]: {
startTime: 1693412759,
endTime: 999999999999,
underlying: [BEAN_ERC20, WETH]
arbitrum: {
[ADDR.arbitrum.BEANWETH]: {
startTime: ARB_MIGRATION_TIME,
endTime: 999999999999,
underlying: [ADDR.arbitrum.BEAN_ERC20, ADDR.arbitrum.WETH]
},
[ADDR.arbitrum.BEANWSTETH]: {
startTime: ARB_MIGRATION_TIME,
endTime: 999999999999,
underlying: [ADDR.arbitrum.BEAN_ERC20, ADDR.arbitrum.WSTETH]
},
[ADDR.arbitrum.BEANWEETH]: {
startTime: ARB_MIGRATION_TIME,
endTime: 999999999999,
underlying: [ADDR.arbitrum.BEAN_ERC20, ADDR.arbitrum.WEETH]
},
[ADDR.arbitrum.BEANWBTC]: {
startTime: ARB_MIGRATION_TIME,
endTime: 999999999999,
underlying: [ADDR.arbitrum.BEAN_ERC20, ADDR.arbitrum.WBTC]
},
[ADDR.arbitrum.BEANUSDC]: {
startTime: ARB_MIGRATION_TIME,
endTime: 999999999999,
underlying: [ADDR.arbitrum.BEAN_ERC20, ADDR.arbitrum.USDC]
},
[ADDR.arbitrum.BEANUSDT]: {
startTime: ARB_MIGRATION_TIME,
endTime: 999999999999,
underlying: [ADDR.arbitrum.BEAN_ERC20, ADDR.arbitrum.USDT]
},
}
};

function invalidTime(api) {
if (api.chain === 'ethereum') {
return (api.timestamp >= EXPLOIT_TIME && api.timestamp <= REPLANT_TIME) || api.timestamp >= ARB_MIGRATION_TIME;
} else if (api.chain === 'arbitrum') {
return false;
}
}

// Returns the relevant tokens for the given timestamp
function getBean(timestamp) {
if (timestamp <= EXPLOIT_TIME) {
return BEAN_ERC20_V1;
} else if (timestamp >= REPLANT_TIME) {
return BEAN_ERC20;
return ADDR.ethereum.BEAN_ERC20_V1;
} else if ( timestamp <= ARB_MIGRATION_TIME) {
return ADDR.ethereum.BEAN_ERC20;
} else {
return ADDR.arbitrum.BEAN_ERC20;
}
throw new Error("There was no Bean token during the requested timestamp");
}

// Returns the relevant pools for the given timestamp
function getPools(timestamp) {
function getPools(api) {
const { chain, timestamp } = api;
const pools = [];
for (const contract in ALL_POOLS) {
const pool = ALL_POOLS[contract];
for (const contract in ALL_POOLS[chain]) {
const pool = ALL_POOLS[chain][contract];
if (timestamp >= pool.startTime && timestamp <= pool.endTime) {
pools.push(contract);
}
Expand All @@ -100,14 +163,14 @@ async function getPoolReserves(api, pool) {

pool = pool.toLowerCase();
const poolBalances = await api.multiCall({
calls: (ALL_POOLS[pool] && ALL_POOLS[pool].underlying || []).map(token => ({
calls: ALL_POOLS[api.chain][pool].underlying.map(token => ({
target: token,
params: pool
})),
abi: 'erc20:balanceOf'
});

return poolBalances.map((balance, i) => ({ token: ALL_POOLS[pool].underlying[i], balance }));
return poolBalances.map((balance, i) => ({ token: ALL_POOLS[api.chain][pool].underlying[i], balance }));
}

// Returns the total silo'd amount of the requested token
Expand All @@ -118,15 +181,15 @@ async function getSiloDeposited(api, token) {
// Prior to BIP12, there was no generalized deposit getter
result = await api.call({
abi:
token === BEAN_ERC20_V1
token === ADDR.ethereum.BEAN_ERC20_V1
? "function totalDepositedBeans() public view returns (uint256)"
: "function totalDepositedLP() public view returns (uint256)",
target: BEANSTALK
target: ADDR[api.chain].BEANSTALK
});
} else {
result = await api.call({
abi: "function getTotalDeposited(address) external view returns (uint256)",
target: BEANSTALK,
target: ADDR[api.chain].BEANSTALK,
params: token
});
}
Expand Down Expand Up @@ -164,25 +227,26 @@ async function getRipePooledBalances(api, unripeToken) {
const [underlyingToken, underlyingPerUnripe, depositedUnripe] = await Promise.all([
api.call({
abi: "function getUnderlyingToken(address) external view returns (address)",
target: BEANSTALK,
target: ADDR[api.chain].BEANSTALK,
params: unripeToken
}),
api.call({
abi: "function getUnderlyingPerUnripeToken(address) external view returns (uint256)",
target: BEANSTALK,
target: ADDR[api.chain].BEANSTALK,
params: unripeToken
}),
getSiloDeposited(api, unripeToken),
]);

// Add the underlying pooled token balances
const underlyingAmount = underlyingPerUnripe * depositedUnripe / Math.pow(10, 6);
if (underlyingToken.toLowerCase() == BEAN_ERC20) {
ripePooledTokenBalances[BEAN_ERC20] = (ripePooledTokenBalances[BEAN_ERC20] ?? 0) + underlyingAmount;
const BEAN = ADDR[api.chain].BEAN_ERC20;
if (underlyingToken.toLowerCase() == BEAN) {
ripePooledTokenBalances[BEAN] = (ripePooledTokenBalances[BEAN] ?? 0) + underlyingAmount;
} else {
const underlyingSupply = await getTotalSupply(api, underlyingToken);
const ratio = underlyingAmount / underlyingSupply;
const balances = await getPooledBalances(api, [underlyingToken], [ratio]);
const balances = await getPooledBalances(api, [underlyingToken.toLowerCase()], [ratio]);
for (const token in balances) {
ripePooledTokenBalances[token] = (ripePooledTokenBalances[token] ?? 0) + balances[token];
}
Expand All @@ -192,31 +256,31 @@ async function getRipePooledBalances(api, unripeToken) {

// Beans deposited in the silo
async function staking(api) {
if (api.timestamp >= EXPLOIT_TIME && api.timestamp <= REPLANT_TIME) {
if (invalidTime(api)) {
return {};
}

// Bean deposits + ripe beans from unripe beans
const bean = getBean(api.timestamp);
const [siloBeans, unripeSiloBeans] = await Promise.all([
getSiloDeposited(api, bean),
getRipePooledBalances(api, UNRIPE_BEAN_ERC20)
getRipePooledBalances(api, ADDR[api.chain].UNRIPE_BEAN_ERC20)
]);
const totalStaked = siloBeans + unripeSiloBeans[BEAN_ERC20];
const totalStaked = siloBeans + unripeSiloBeans[ADDR[api.chain].BEAN_ERC20];

return {
[`ethereum:${bean.toLowerCase()}`]: totalStaked
[`${api.chain}:${bean.toLowerCase()}`]: totalStaked
}
}

// Tokens in liquidity pools corresponding to lp tokens that are deposited in the silo
async function pool2(api) {
if (api.timestamp >= EXPLOIT_TIME && api.timestamp <= REPLANT_TIME) {
if (invalidTime(api)) {
return {};
}

// Get the amount of lp tokens deposited in the silo
const pools = getPools(api.timestamp);
const pools = getPools(api);
const poolPromises = pools.map(pool => [
getSiloDeposited(api, pool),
getTotalSupply(api, pool)
Expand All @@ -231,7 +295,7 @@ async function pool2(api) {
// Gets the underlying token balances for both regular and unripe deposits
const balancesResults = await Promise.all([
getPooledBalances(api, pools, ratios),
getRipePooledBalances(api, UNRIPE_LP_ERC20)
getRipePooledBalances(api, ADDR[api.chain].UNRIPE_LP_ERC20)
]);

const pool2Balances = balancesResults[0];
Expand All @@ -242,21 +306,27 @@ async function pool2(api) {
// Add chain info
const retval = {};
for (const token in pool2Balances) {
retval[`ethereum:${token.toLowerCase()}`] = pool2Balances[token];
retval[`${api.chain}:${token.toLowerCase()}`] = pool2Balances[token];
}
return retval;
}

module.exports = {
methodology: "Counts the value of deposited Beans and LP tokens in the silo.",
start: 12974077,
start: 1628287657,
ethereum: {
tvl: () => ({}),
pool2,
staking
},
arbitrum: {
tvl: () => ({}),
pool2,
staking
},
hallmarks: [
[1650153600, "Governance Exploit"],
[1659602715, "Replant"]
[EXPLOIT_TIME, "Governance Exploit"],
[REPLANT_TIME, "Replant"],
[ARB_MIGRATION_TIME, "Migration to Arbitrum"],
]
};

0 comments on commit 7297305

Please sign in to comment.