Skip to content

Commit

Permalink
BIP38 UI + Maintenance mode (#661)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xalecks authored Oct 20, 2023
2 parents 6dfc7a9 + fb704b3 commit 7108a7b
Show file tree
Hide file tree
Showing 68 changed files with 21,697 additions and 16,470 deletions.
4 changes: 4 additions & 0 deletions .yarn/versions/118d26de.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
undecided:
- "@beanstalk/sdk"
- ui
- "@beanstalk/protocol"
2 changes: 1 addition & 1 deletion projects/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@beanstalk/cli",
"version": "0.0.9",
"version": "0.0.10",
"description": "Beanstalk protocol development cli tool",
"license": "MIT",
"repository": {
Expand Down
6 changes: 5 additions & 1 deletion projects/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { setbalance } from "./commands/setbalance.js";
import { sunrise } from "./commands/sunrise.js";
import { setPrice } from "./commands/setprice.js";
import { help } from "./commands/help.js";
import { mineBlocks } from "./commands/mine.js";

main().catch((e) => {
console.log("FAILED:");
Expand All @@ -22,7 +23,7 @@ async function main() {
{ name: "amount", alias: "m", defaultValue: "50000" },
{ name: "rpcUrl", alias: "r", defaultValue: "http://127.0.0.1:8545" },
{ name: "no-imp", type: Boolean },
{ name: "force", alias: "f", type: Boolean}
{ name: "force", alias: "f", type: Boolean }
];
const args = commandLineArgs(commands, { partial: true });

Expand All @@ -41,6 +42,9 @@ async function main() {
case "setprice":
await setPrice(sdk, chain, { params: args._unknown });
break;
case "mine":
await mineBlocks(sdk, args.amount);
break;
case "help":
default:
await help();
Expand Down
17 changes: 14 additions & 3 deletions projects/cli/src/commands/balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,20 @@ export const balance = async (sdk, { account, symbol }) => {
res.push(await getBal(sdk, symbol, account));
} else {
const bals = await Promise.all(
["ETH", "WETH", "BEAN", "USDT", "USDC", "DAI", "CRV3", "UNRIPE_BEAN", "UNRIPE_BEAN_CRV3", "BEAN_CRV3_LP", "ROOT"].map((s) =>
getBal(sdk, s, account)
)
[
"ETH",
"WETH",
"BEAN",
"USDT",
"USDC",
"DAI",
"CRV3",
"UNRIPE_BEAN",
"UNRIPE_BEAN_WETH",
"BEAN_CRV3_LP",
"BEAN_ETH_WELL_LP",
"ROOT"
].map((s) => getBal(sdk, s, account))
);
res.push(...bals);
}
Expand Down
18 changes: 18 additions & 0 deletions projects/cli/src/commands/mine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { BeanstalkSDK } from "@beanstalk/sdk";
import chalk from "chalk";
import { table } from "table";

export const mineBlocks = async (sdk: BeanstalkSDK, amount) => {
const numBlocks = amount === "50000" ? 1 : amount;

async function mineBlocks(blockNumber) {
while (blockNumber > 0) {
blockNumber--;
await sdk.provider.send("evm_mine", []);
}
}

await mineBlocks(numBlocks);

console.log(`${chalk.bold.whiteBright("Mined ")} ${chalk.greenBright(numBlocks)} block(s)`);
};
5 changes: 3 additions & 2 deletions projects/cli/src/commands/setbalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ export const setbalance = async (sdk, chain, { account, symbol, amount }) => {
if (!symbol) {
await chain.setAllBalances(account, amount);
} else {
const symbols = ["ETH", "WETH", "BEAN", "USDT", "USDC", "DAI", "3CRV", "BEAN3CRV", "urBEAN", "urBEAN3CRV", "ROOT"];
const symbols = ["ETH", "WETH", "BEAN", "USDT", "USDC", "DAI", "3CRV", "BEAN3CRV", "BEANWETH", "urBEAN", "urBEANWETH", "ROOT"];
if (!symbols.includes(symbol)) {
console.log(`${chalk.bold.red("Error")} - ${chalk.bold.white(symbol)} is not a valid token. Valid options are: `);
console.log(symbols.map((s) => chalk.green(s)).join(", "));
process.exit(-1);
}
let t = sdk.tokens[symbol] as Token;
if (symbol === "urBEAN") t = sdk.tokens.UNRIPE_BEAN;
if (symbol === "urBEAN3CRV") t = sdk.tokens.UNRIPE_BEAN_CRV3;
if (symbol === "urBEANWETH") t = sdk.tokens.UNRIPE_BEAN_WETH;
if (symbol === "BEAN3CRV") t = sdk.tokens.BEAN_CRV3_LP;
if (symbol === "BEANWETH") t = sdk.tokens.BEAN_ETH_WELL_LP;
if (typeof chain[`set${symbol}Balance`] !== "function")
throw new Error(`${symbol} is not a valid token or the method ${chalk.bold.whiteBright("")}`);

Expand Down
4 changes: 2 additions & 2 deletions projects/sdk/src/classes/Workflow.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ethers } from "ethers";
import { CallOverrides, ethers } from "ethers";
import { Token } from "src/classes/Token";
import { BeanstalkSDK } from "src/lib/BeanstalkSDK";
import { TokenValue } from "src/TokenValue";
Expand Down Expand Up @@ -593,7 +593,7 @@ export abstract class Workflow<
* @param slippage A human readable percent value. Ex: 0.1 would mean 0.1% slippage
* @returns Promise of a Transaction
*/
abstract execute(amountIn: ethers.BigNumber | TokenValue, data: RunData): Promise<ethers.ContractTransaction>;
abstract execute(amountIn: ethers.BigNumber | TokenValue, data: RunData, overrides?: CallOverrides): Promise<ethers.ContractTransaction>;

/**
* CallStatic version of the execute method. Allows testing the execution of the workflow.
Expand Down
4 changes: 2 additions & 2 deletions projects/sdk/src/constants/addresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export const addresses = {
UNRIPE_BEAN:
// "Unripe Bean": Unripe vesting asset for the Bean token, Localhost
Address.make("0x1BEA0050E63e05FBb5D8BA2f10cf5800B6224449"),
UNRIPE_BEAN_CRV3:
// "Unripe BEAN:CRV3 LP": Unripe vesting asset for the BEAN:CRV3 LP token, Localhost
UNRIPE_BEAN_WETH:
// "Unripe BEAN:WETH LP": Unripe vesting asset for the BEAN:WETH LP token, Localhost
Address.make("0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716D"),

// ----------------------------------------
Expand Down
22 changes: 18 additions & 4 deletions projects/sdk/src/lib/farm/LibraryPresets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export class LibraryPresets {

public readonly weth2bean: ActionBuilder;
public readonly bean2weth: ActionBuilder;
public readonly weth2bean3crv: ActionBuilder;
public readonly wellWethBean;
public readonly wellAddLiquidity;

Expand All @@ -37,6 +38,7 @@ export class LibraryPresets {
public readonly dai2weth: ActionBuilder;
public readonly usdc2weth: ActionBuilder;

public readonly usdt23crv: ActionBuilder;
public readonly usdc2beaneth;
public readonly usdt2beaneth;
public readonly dai2beaneth;
Expand Down Expand Up @@ -176,6 +178,20 @@ export class LibraryPresets {
this.usdt2weth(FarmFromMode.INTERNAL, toMode) as StepGenerator
];

///////// WETH -> 3CRV ///////////
this.weth2bean3crv = (fromMode?: FarmFromMode, toMode?: FarmToMode) => [
this.weth2usdt(fromMode, FarmToMode.INTERNAL) as StepGenerator,
this.usdt23crv(fromMode, FarmToMode.INTERNAL) as StepGenerator
];

//////// USDT -> 3CRV ////////
this.usdt23crv = (fromMode?: FarmFromMode, toMode?: FarmToMode) => {
const pool = sdk.contracts.curve.pools.pool3.address;
const registry = sdk.contracts.curve.registries.poolRegistry.address;
// [0 ,0 , 1] is for USDT; [DAI, USDC, USDT]
return new sdk.farm.actions.AddLiquidity(pool, registry, [0, 0, 1], fromMode, toMode);
};

///////// DAI -> USDT ///////////
this.dai2usdt = (fromMode?: FarmFromMode, toMode?: FarmToMode) =>
new Exchange(
Expand All @@ -197,7 +213,7 @@ export class LibraryPresets {
fromMode,
toMode
);

///////// DAI -> WETH ///////////
this.dai2weth = (fromMode?: FarmFromMode, toMode?: FarmToMode) => [
this.dai2usdt(fromMode, FarmToMode.INTERNAL) as StepGenerator,
Expand All @@ -210,7 +226,6 @@ export class LibraryPresets {
this.usdt2weth(FarmFromMode.INTERNAL, toMode) as StepGenerator
];


///////// [ USDC, USDT, DAI ] -> BEANETH ///////////
this.usdc2beaneth = (well: BasinWell, account: string, fromMode?: FarmFromMode, toMode?: FarmToMode) => [
this.usdc2weth(fromMode, FarmToMode.INTERNAL) as StepGenerator,
Expand Down Expand Up @@ -275,7 +290,6 @@ export class LibraryPresets {
};

this.wellAddLiquidity = (well: BasinWell, tokenIn: ERC20Token, account: string, from?: FarmFromMode, to?: FarmToMode) => {

const result = [];
const advancedPipe = sdk.farm.createAdvancedPipe("pipelineDeposit");

Expand Down Expand Up @@ -304,13 +318,13 @@ export class LibraryPresets {
}
const transferToBeanstalk = new sdk.farm.actions.TransferToken(well.address, account, FarmFromMode.EXTERNAL, FarmToMode.INTERNAL, transferClipboard);


result.push(transfer);
advancedPipe.add(addLiquidity, { tag: "amountToDeposit" });
if (transferBack) {
advancedPipe.add(approveBack);
advancedPipe.add(transferToBeanstalk);
}

result.push(advancedPipe);

return result;
Expand Down
3 changes: 3 additions & 0 deletions projects/sdk/src/lib/farm/actions/WellShift.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { Token } from "src/classes/Token";
import { RunContext, RunMode, Step, StepClass, Workflow } from "src/classes/Workflow";
import { AdvancedPipePreparedResult } from "src/lib/depot/pipe";

/**
* Swap tokens in a Well by using the shift() method
*/
export class WellShift extends StepClass<AdvancedPipePreparedResult> {
public name: string = "shift";

Expand Down
22 changes: 11 additions & 11 deletions projects/sdk/src/lib/farm/actions/WellSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { Token } from "src/classes/Token";
import { RunContext, RunMode, Step, StepClass } from "src/classes/Workflow";
import { AdvancedPipePreparedResult } from "src/lib/depot/pipe";

/**
* Add liqudity to a well using the Sync method, which transfers tokens directly to the well first
* which does not require an approval
*/
export class WellSync extends StepClass<AdvancedPipePreparedResult> {
public name: string = "wellSync";

Expand All @@ -31,7 +35,7 @@ export class WellSync extends StepClass<AdvancedPipePreparedResult> {
throw new Error("Reverse direction is not supported by wellSync");
}

let amounts: TokenValue[] = []
let amounts: TokenValue[] = [];
for (let i = 0; i < this._well.tokens.length; i++) {
if (i === tokenIndex) {
amounts[i] = this.tokenIn.fromBlockchain(_amountInStep);
Expand All @@ -47,23 +51,19 @@ export class WellSync extends StepClass<AdvancedPipePreparedResult> {
amountOut: quote.toBigNumber(),
value: ethers.BigNumber.from(0),
prepare: () => {

const minLP = quote.subSlippage(context.data.slippage || 0.1);

WellSync.sdk.debug(`>[${this.name}.prepare()]`, {
well: well.name,
recipient: this.recipient,
quoteAmountLessSlippage: minLP,
method: "sync",
context
well: well.name,
recipient: this.recipient,
quoteAmountLessSlippage: minLP,
method: "sync",
context
});

return {
target: well.address,
callData: well.contract.interface.encodeFunctionData("sync", [
this.recipient,
minLP.toBigNumber().toString(),
])
callData: well.contract.interface.encodeFunctionData("sync", [this.recipient, minLP.toBigNumber().toString()])
};
},
decode: (data: string) => well.contract.interface.decodeFunctionData("sync", data),
Expand Down
2 changes: 1 addition & 1 deletion projects/sdk/src/lib/silo/Convert.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe("Silo Convert", function () {
const BEAN = sdk.tokens.BEAN;
const BEANLP = sdk.tokens.BEAN_CRV3_LP;
const urBEAN = sdk.tokens.UNRIPE_BEAN;
const urBEANLP = sdk.tokens.UNRIPE_BEAN_CRV3;
const urBEANLP = sdk.tokens.UNRIPE_BEAN_WETH;
const whitelistedTokens = [BEAN, BEANLP, urBEAN, urBEANLP];

beforeAll(async () => {
Expand Down
16 changes: 8 additions & 8 deletions projects/sdk/src/lib/silo/Convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,24 @@ export class Convert {
BeanCrv3: Token;
BeanEth: Token;
urBean: Token;
urBeanCrv3: Token;
urBeanWeth: Token;
paths: Map<Token, Token>;

constructor(sdk: BeanstalkSDK) {
Convert.sdk = sdk;
this.Bean = Convert.sdk.tokens.BEAN;
this.BeanCrv3 = Convert.sdk.tokens.BEAN_CRV3_LP;
this.BeanCrv3 = Convert.sdk.tokens.BEAN_CRV3_LP;
this.BeanEth = Convert.sdk.tokens.BEAN_ETH_WELL_LP;
this.urBean = Convert.sdk.tokens.UNRIPE_BEAN;
this.urBeanCrv3 = Convert.sdk.tokens.UNRIPE_BEAN_CRV3;
this.urBeanWeth = Convert.sdk.tokens.UNRIPE_BEAN_WETH;

this.paths = new Map<Token, Token>();
this.paths.set(this.Bean, this.BeanCrv3);
this.paths.set(this.BeanCrv3, this.Bean);
this.paths.set(this.Bean, this.BeanEth);
this.paths.set(this.BeanEth, this.Bean);
this.paths.set(this.urBean, this.urBeanCrv3);
this.paths.set(this.urBeanCrv3, this.urBean);
this.paths.set(this.urBean, this.urBeanWeth);
this.paths.set(this.urBeanWeth, this.urBean);
}

async convert(fromToken: Token, toToken: Token, fromAmount: TokenValue, slippage: number = 0.1): Promise<ContractTransaction> {
Expand Down Expand Up @@ -117,12 +117,12 @@ export class Convert {
calculateEncoding(fromToken: Token, toToken: Token, amountIn: TokenValue, minAmountOut: TokenValue) {
let encoding;

if (fromToken.address === this.urBean.address && toToken.address === this.urBeanCrv3.address) {
if (fromToken.address === this.urBean.address && toToken.address === this.urBeanWeth.address) {
encoding = ConvertEncoder.unripeBeansToLP(
amountIn.toBlockchain(), // amountBeans
minAmountOut.toBlockchain() // minLP
);
} else if (fromToken.address === this.urBeanCrv3.address && toToken.address === this.urBean.address) {
} else if (fromToken.address === this.urBeanWeth.address && toToken.address === this.urBean.address) {
encoding = ConvertEncoder.unripeLPToBeans(
amountIn.toBlockchain(), // amountLP
minAmountOut.toBlockchain() // minBeans
Expand Down Expand Up @@ -178,7 +178,7 @@ export class Convert {
const deltaB = await Convert.sdk.bean.getDeltaB();

if (deltaB.gte(TokenValue.ZERO)) {
if (fromToken.equals(this.BeanCrv3) || fromToken.equals(this.urBeanCrv3) || fromToken.equals(this.BeanEth)) {
if (fromToken.equals(this.BeanCrv3) || fromToken.equals(this.urBeanWeth) || fromToken.equals(this.BeanEth)) {
throw new Error("Cannot convert this token when deltaB is >= 0");
}
} else if (deltaB.lt(TokenValue.ZERO)) {
Expand Down
47 changes: 47 additions & 0 deletions projects/sdk/src/lib/silo/Deposit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,41 @@ const { sdk, account, utils } = getTestUtils();

jest.setTimeout(30000);

const happyPaths: Record<string, string> = {
"ETH:BEAN": "ETH -> WETH -> BEAN -> BEAN:SILO",
"ETH:BEAN3CRV": "ETH -> WETH -> 3CRV -> BEAN3CRV -> BEAN3CRV:SILO",
"ETH:BEANWETH": "ETH -> WETH -> BEANWETH -> BEANWETH:SILO",

"WETH:BEAN": "WETH -> BEAN -> BEAN:SILO",
"WETH:BEAN3CRV": "WETH -> 3CRV -> BEAN3CRV -> BEAN3CRV:SILO",
"WETH:BEANWETH": "WETH -> BEANWETH -> BEANWETH:SILO",

"BEAN:BEAN": "BEAN -> BEAN:SILO",
"BEAN:BEAN3CRV": "BEAN -> BEAN3CRV -> BEAN3CRV:SILO",
"BEAN:BEANWETH": "BEAN -> BEANWETH -> BEANWETH:SILO",

"3CRV:BEAN": "3CRV -> USDC -> WETH -> BEAN -> BEAN:SILO", // TODO: Fix this path
"3CRV:BEAN3CRV": "3CRV -> BEAN3CRV -> BEAN3CRV:SILO",
"3CRV:BEANWETH": "3CRV -> USDC -> BEANWETH -> BEANWETH:SILO",

"DAI:BEAN": "DAI -> WETH -> BEAN -> BEAN:SILO",
"DAI:BEAN3CRV": "DAI -> 3CRV -> BEAN3CRV -> BEAN3CRV:SILO",
"DAI:BEANWETH": "DAI -> BEANWETH -> BEANWETH:SILO",

"USDC:BEAN": "USDC -> WETH -> BEAN -> BEAN:SILO",
"USDC:BEAN3CRV": "USDC -> 3CRV -> BEAN3CRV -> BEAN3CRV:SILO",
"USDC:BEANWETH": "USDC -> BEANWETH -> BEANWETH:SILO",

"USDT:BEAN": "USDT -> WETH -> BEAN -> BEAN:SILO",
"USDT:BEAN3CRV": "USDT -> 3CRV -> BEAN3CRV -> BEAN3CRV:SILO",
"USDT:BEANWETH": "USDT -> BEANWETH -> BEANWETH:SILO"
};

describe("Silo Deposit", function () {
const builder = new DepositBuilder(sdk);

const whiteListedTokens = Array.from(sdk.tokens.siloWhitelist);
const whiteListedTokensRipe = whiteListedTokens.filter((t) => !t.isUnripe);
const bean3CrvDepositable = [
sdk.tokens.ETH,
sdk.tokens.WETH,
Expand All @@ -29,6 +60,22 @@ describe("Silo Deposit", function () {
await utils.setAllBalances(account, "20000");
});

describe("Routes correctly", () => {
describe.each(bean3CrvDepositable)("Whitelist Token", (token: Token) => {
it.each(whiteListedTokensRipe.map((t) => [t.symbol, t]))(`Deposit ${token.symbol} into %s`, async (symbol: string, silo: Token) => {
const op = builder.buildDeposit(silo, account);
op.setInputToken(token);

// need to run an estimate first to generate the route
await op.estimate(token.amount(10));
const path = op.route.toString();

const goodPath = happyPaths[`${token.symbol}:${silo.symbol}`];
expect(path).toBe(goodPath);
});
});
});

it("Estimates", async () => {
const op = builder.buildDeposit(sdk.tokens.BEAN_CRV3_LP, account);
op.setInputToken(sdk.tokens.USDC);
Expand Down
Loading

0 comments on commit 7108a7b

Please sign in to comment.