Skip to content

Commit

Permalink
feat: misc updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Space-Bean committed Sep 19, 2024
1 parent dc79a22 commit f6f74a2
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 180 deletions.
2 changes: 1 addition & 1 deletion projects/examples/src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const RPC_URL = "http://127.0.0.1:8545";
const network = {
name: "local",
chainId: ChainId.LOCALHOST,
_defaultProvider: () => new ethers.providers.JsonRpcProvider(RPC_URL, network)
_defaultProvider: () => new ethers.providers.JsonRpcProvider(RPC_URL)
};

export const provider = new ethers.providers.StaticJsonRpcProvider(RPC_URL, network);
Expand Down
100 changes: 15 additions & 85 deletions projects/sdk/src/classes/Pool/BasinWell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,10 @@ import { BasinWell__factory, BasinWell as BasinWellContract } from "src/constant
import { TokenValue } from "src/TokenValue";
import Pool, { Reserves } from "./Pool";
import { ERC20Token } from "../Token";
import { BeanstalkSDK } from "src/lib/BeanstalkSDK";

export class BasinWell extends Pool {
public readonly contract: BasinWellContract;

constructor(
sdk: BeanstalkSDK,
address: string,
lpToken: ERC20Token,
tokens: ERC20Token[],
metadata: {
name: string;
symbol: string;
logo: string;
color: string;
}
) {
super(sdk, address, lpToken, tokens, metadata);
this.contract = BasinWell__factory.connect(address, sdk.providerOrSigner);
}

public getContract() {
return this.contract;
return BasinWell__factory.connect(this.address, Pool.sdk.providerOrSigner);
}

public getReserves() {
Expand All @@ -43,80 +24,29 @@ export class BasinWell extends Pool {
);
}

async getAddLiquidityOut(amounts: TokenValue[]) {
return this.contract
async getAddLiquidityOut(amounts: TokenValue[]): Promise<TokenValue> {
return this.getContract()
.getAddLiquidityOut(amounts.map((a) => a.toBigNumber()))
.then((result) => this.lpToken.fromBlockchain(result));
}

async getRemoveLiquidityOutEqual(amount: TokenValue) {
return this.contract
async getRemoveLiquidityOutEqual(amount: TokenValue): Promise<TokenValue[]> {
return this.getContract()
.getRemoveLiquidityOut(amount.toBigNumber())
.then((result) => this.tokens.map((token, i) => token.fromBlockchain(result[i])));
}

async getRemoveLiquidityOutOneToken(lpAmountIn: TokenValue, tokenOut: ERC20Token) {
return this.contract
async getRemoveLiquidityOutOneToken(
lpAmountIn: TokenValue,
tokenOut: ERC20Token
): Promise<TokenValue> {
const tokenIndex = this.tokens.findIndex((token) => token.equals(tokenOut));
if (tokenIndex < 0) {
throw new Error(`Token ${tokenOut.symbol} does not underly ${this.name}`);
}

return this.getContract()
.getRemoveLiquidityOneTokenOut(lpAmountIn.toBigNumber(), tokenOut.address)
.then((result) => tokenOut.fromBlockchain(result));
}

/**
* Get the @wagmi/core multicall params for removing liquidity
* @param lpAmountIn The amount of LP tokens to remove
* @returns @wagmi/core multicall calls for
* - removing equal amounts of liquidity
* - removing single sided liquidity as well.tokens[0]
* - removing single sided liquidity as well.tokens[1]
*/
static getRemoveLiquidityOutMulticallParams(well: BasinWell, lpAmountIn: TokenValue) {
const contract = {
address: well.address as `0x${string}`,
abi: removeLiquidityPartialABI
};

const removeEqual = {
...contract,
method: "getRemoveLiquidityOut",
args: [lpAmountIn.toBigNumber()]
};

const removeSingleSided0 = {
...contract,
method: "getRemoveLiquidityOneTokenOut",
args: [lpAmountIn.toBigNumber(), well.tokens[0].address as `0x${string}`]
};

const removeSingleSided1 = {
...contract,
method: "getRemoveLiquidityOneTokenOut",
args: [lpAmountIn.toBigNumber(), well.tokens[1].address as `0x${string}`]
};

return {
equal: removeEqual,
side0: removeSingleSided0,
side1: removeSingleSided1
};
}
}

const removeLiquidityPartialABI = [
{
inputs: [
{ internalType: "uint256", name: "lpAmountIn", type: "uint256" },
{ internalType: "contract IERC20", name: "tokenOut", type: "address" }
],
name: "getRemoveLiquidityOneTokenOut",
outputs: [{ internalType: "uint256", name: "tokenAmountOut", type: "uint256" }],
stateMutability: "view",
type: "function"
},
{
inputs: [{ internalType: "uint256", name: "lpAmountIn", type: "uint256" }],
name: "getRemoveLiquidityOut",
outputs: [{ internalType: "uint256[]", name: "tokenAmountsOut", type: "uint256[]" }],
stateMutability: "view",
type: "function"
}
] as const;
30 changes: 14 additions & 16 deletions projects/sdk/src/constants/addresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,20 @@ export const addresses = {
[ChainId.ARBITRUM_MAINNET]: "0x6985884C4392D348587B19cb9eAAf157F13271cd"
}),

// ----------------------------------------
// Uniswap V3
// ----------------------------------------
UNISWAP_V3_ROUTER: Address.make({
[ChainId.ETH_MAINNET]: "0xE592427A0AEce92De3Edee1F18E0157C05861564",
[ChainId.ARBITRUM_MAINNET]: "0xE592427A0AEce92De3Edee1F18E0157C05861564"
}),

UNISWAP_V3_QUOTER_V2: Address.make({
[ChainId.ETH_MAINNET]: "0x61fFE014bA17989E743c5F6cB21bF9697530B21e",
[ChainId.ARBITRUM_MAINNET]: "0x61fFE014bA17989E743c5F6cB21bF9697530B21e"
}),
// ----------------------------------------

// ----------------------------------------
// Curve Pools: Other
// ----------------------------------------
Expand Down Expand Up @@ -255,22 +269,6 @@ export const addresses = {
[ChainId.ETH_MAINNET]: "0xA79828DF1850E8a3A3064576f380D90aECDD3359"
}),

/**
* @deprecated
* Uniswap V3 Router
*/
UNISWAP_V3_ROUTER: Address.make({
[ChainId.ETH_MAINNET]: "0xE592427A0AEce92De3Edee1F18E0157C05861564"
}),

/**
* @deprecated
* Uniswap V3 Quoter V2
*/
UNISWAP_V3_QUOTER_V2: Address.make({
[ChainId.ETH_MAINNET]: "0x61fFE014bA17989E743c5F6cB21bF9697530B21e"
}),

/**
* @deprecated
*/
Expand Down
29 changes: 8 additions & 21 deletions projects/sdk/src/lib/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,7 @@ export class Contracts {
*/
public readonly root: Root | null = null;

/**
* @deprecated as of Beanstalk 3.0 L2 migration
* @description mainnet only
*/
public readonly uniswapV3Router: UniswapV3Router;

/**
* @deprecated as of Beanstalk 3.0 L2 migration
* @description mainnet only
*/
public readonly uniswapV3QuoterV2: UniswapV3QuoterV2;

constructor(sdk: BeanstalkSDK) {
Expand Down Expand Up @@ -150,18 +141,14 @@ export class Contracts {
};

// Uniswap
if (uniswapV3RouterAddress) {
this.uniswapV3Router = UniswapV3Router__factory.connect(
uniswapV3RouterAddress,
sdk.providerOrSigner
);
}
this.uniswapV3Router = UniswapV3Router__factory.connect(
uniswapV3RouterAddress,
sdk.providerOrSigner
);

if (uniswapV3QuoterV2Address) {
this.uniswapV3QuoterV2 = UniswapV3QuoterV2__factory.connect(
uniswapV3QuoterV2Address,
sdk.providerOrSigner
);
}
this.uniswapV3QuoterV2 = UniswapV3QuoterV2__factory.connect(
uniswapV3QuoterV2Address,
sdk.providerOrSigner
);
}
}
10 changes: 8 additions & 2 deletions projects/sdk/src/lib/pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import Pool from "src/classes/Pool/Pool";
import { BasinWell } from "src/classes/Pool/BasinWell";
import { Token } from "src/classes/Token";
import { BeanstalkSDK } from "src/lib/BeanstalkSDK";
import { Address, ChainId, ChainResolver } from "@beanstalk/sdk-core";
import { pool } from "src/constants/generated/projects/sdk/src/constants/abi/Curve";
import { ChainResolver } from "@beanstalk/sdk-core";

export class Pools {
static sdk: BeanstalkSDK;
Expand Down Expand Up @@ -142,6 +141,13 @@ export class Pools {
return this.lpAddressMap.get(token.address);
}

getWellByLPToken(token: Token | string): BasinWell | undefined {
if (typeof token === "string") {
return this.wellAddressMap.get(token.toLowerCase());
}
return this.wellAddressMap.get(token.address);
}

getWells(): readonly BasinWell[] {
return Array.from(this.wellAddressMap.values()) as ReadonlyArray<BasinWell>;
}
Expand Down
74 changes: 48 additions & 26 deletions projects/sdk/src/lib/silo/Convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ERC20Token, Token } from "src/classes/Token";
import { BeanstalkSDK } from "../BeanstalkSDK";
import { ConvertEncoder } from "./ConvertEncoder";
import { Deposit } from "./types";
import { pickCrates, sortCratesByBDVRatio, sortCratesByStem } from "./utils";
import { normaliseERC20, pickCrates, sortCratesByBDVRatio, sortCratesByStem } from "./utils";

export type ConvertDetails = {
amount: TokenValue;
Expand All @@ -17,35 +17,48 @@ export type ConvertDetails = {

export class Convert {
static sdk: BeanstalkSDK;
Bean: Token;
BeanCrv3: Token;
BeanEth: Token;
beanWstETH: Token;
urBean: Token;
urBeanWstETH: Token;
paths: Map<Token, ERC20Token[]>;
readonly paths: Map<Token, ERC20Token[]>;

constructor(sdk: BeanstalkSDK) {
Convert.sdk = sdk;
this.Bean = Convert.sdk.tokens.BEAN;
this.BeanCrv3 = Convert.sdk.tokens.BEAN_CRV3_LP;
this.BeanEth = Convert.sdk.tokens.BEAN_ETH_WELL_LP;
this.beanWstETH = Convert.sdk.tokens.BEAN_WSTETH_WELL_LP;
this.urBean = Convert.sdk.tokens.UNRIPE_BEAN;
this.urBeanWstETH = Convert.sdk.tokens.UNRIPE_BEAN_WSTETH;

// TODO: Update me for lambda to lambda converts

this.paths = new Map<Token, ERC20Token[]>();

// BEAN<>LP
this.paths.set(Convert.sdk.tokens.BEAN, [
// Convert.sdk.tokens.BEAN_CRV3_LP, // Deprecated.
Convert.sdk.tokens.BEAN,
Convert.sdk.tokens.BEAN_WSTETH_WELL_LP,
Convert.sdk.tokens.BEAN_ETH_WELL_LP,
Convert.sdk.tokens.BEAN_WBTC_WELL_LP,
Convert.sdk.tokens.BEAN_WEETH_WELL_LP,
Convert.sdk.tokens.BEAN_USDC_WELL_LP,
Convert.sdk.tokens.BEAN_USDT_WELL_LP
]);

this.paths.set(Convert.sdk.tokens.BEAN_ETH_WELL_LP, [
Convert.sdk.tokens.BEAN,
Convert.sdk.tokens.BEAN_ETH_WELL_LP
]);
this.paths.set(Convert.sdk.tokens.BEAN_CRV3_LP, [Convert.sdk.tokens.BEAN]);
this.paths.set(Convert.sdk.tokens.BEAN_ETH_WELL_LP, [Convert.sdk.tokens.BEAN]);
this.paths.set(Convert.sdk.tokens.BEAN_WSTETH_WELL_LP, [Convert.sdk.tokens.BEAN]);
this.paths.set(Convert.sdk.tokens.BEAN_WSTETH_WELL_LP, [
Convert.sdk.tokens.BEAN,
Convert.sdk.tokens.BEAN_WSTETH_WELL_LP
]);
this.paths.set(Convert.sdk.tokens.BEAN_WBTC_WELL_LP, [
Convert.sdk.tokens.BEAN,
Convert.sdk.tokens.BEAN_WBTC_WELL_LP
]);
this.paths.set(Convert.sdk.tokens.BEAN_WEETH_WELL_LP, [
Convert.sdk.tokens.BEAN,
Convert.sdk.tokens.BEAN_WEETH_WELL_LP
]);
this.paths.set(Convert.sdk.tokens.BEAN_USDC_WELL_LP, [
Convert.sdk.tokens.BEAN,
Convert.sdk.tokens.BEAN_USDC_WELL_LP
]);
this.paths.set(Convert.sdk.tokens.BEAN_USDT_WELL_LP, [
Convert.sdk.tokens.BEAN,
Convert.sdk.tokens.BEAN_USDT_WELL_LP
]);

// URBEAN<>(URBEAN_WSTETH_LP & RIPE BEAN)
this.paths.set(Convert.sdk.tokens.UNRIPE_BEAN, [
Expand Down Expand Up @@ -166,13 +179,24 @@ export class Convert {

const tks = Convert.sdk.tokens;

const deprecatedLPs = new Set([Convert.sdk.tokens.BEAN_CRV3_LP]);

const whitelistedWellLPs = new Set([
Convert.sdk.tokens.BEAN_ETH_WELL_LP.address.toLowerCase(),
Convert.sdk.tokens.BEAN_WSTETH_WELL_LP.address.toLowerCase()
]);
const isFromWlLP = Boolean(whitelistedWellLPs.has(fromToken.address.toLowerCase()));
const isToWlLP = Boolean(whitelistedWellLPs.has(toToken.address.toLowerCase()));

if (deprecatedLPs.has(fromToken as ERC20Token) || deprecatedLPs.has(toToken as ERC20Token)) {
throw new Error("SDK: Deprecated conversion pathway");
}

// BS3TODO: is this encoding correct ?
if (fromToken.equals(toToken)) {
return ConvertEncoder.lambdaLambda(amountIn.toBlockchain(), fromToken.address);
}

if (
fromToken.address === tks.UNRIPE_BEAN.address &&
toToken.address === tks.UNRIPE_BEAN_WSTETH.address
Expand Down Expand Up @@ -242,7 +266,10 @@ export class Convert {
return encoding;
}

async validateTokens(fromToken: Token, toToken: Token) {
async validateTokens(_fromToken: Token, _toToken: Token) {
const fromToken = normaliseERC20(_fromToken, Convert.sdk);
const toToken = normaliseERC20(_toToken, Convert.sdk);

if (!Convert.sdk.tokens.isWhitelisted(fromToken)) {
throw new Error("fromToken is not whitelisted");
}
Expand All @@ -251,10 +278,6 @@ export class Convert {
throw new Error("toToken is not whitelisted");
}

if (fromToken.equals(toToken)) {
throw new Error("Cannot convert between the same token");
}

const path = this.getConversionPaths(fromToken as ERC20Token);
const found = path.find((tk) => tk.address.toLowerCase() === toToken.address.toLowerCase());

Expand All @@ -267,5 +290,4 @@ export class Convert {
const token = Convert.sdk.tokens.findByAddress(fromToken.address);
return token ? this.paths.get(token) || [] : [];
}

}
Loading

0 comments on commit f6f74a2

Please sign in to comment.