diff --git a/projects/sdk/src/classes/Workflow.ts b/projects/sdk/src/classes/Workflow.ts index 7ef8a76b24..dd877fcd1f 100644 --- a/projects/sdk/src/classes/Workflow.ts +++ b/projects/sdk/src/classes/Workflow.ts @@ -289,8 +289,10 @@ export abstract class Workflow< if (input instanceof StepClass) { input.setSDK(Workflow.sdk); } + const depositOptions = { tag: "depositAmount" } + const validInput = input.name === "pipelineDeposit"; this._generators.push(input); - this._options.push(options || null); // null = no options set + this._options.push(validInput ? depositOptions : options || null); // null = no options set } return this; // allow chaining } diff --git a/projects/sdk/src/lib/farm/LibraryPresets.ts b/projects/sdk/src/lib/farm/LibraryPresets.ts index 19c8803c17..a3c11b6887 100644 --- a/projects/sdk/src/lib/farm/LibraryPresets.ts +++ b/projects/sdk/src/lib/farm/LibraryPresets.ts @@ -277,7 +277,7 @@ export class LibraryPresets { this.wellAddLiquidity = (well: BasinWell, tokenIn: ERC20Token, account: string, from?: FarmFromMode, to?: FarmToMode) => { const result = []; - const advancedPipe = sdk.farm.createAdvancedPipe("Pipeline"); + const advancedPipe = sdk.farm.createAdvancedPipe("pipelineDeposit"); const transferBack = to === FarmToMode.INTERNAL; const recipient = transferBack ? sdk.contracts.pipeline.address : account; @@ -289,19 +289,29 @@ export class LibraryPresets { const addLiquidity = new sdk.farm.actions.WellSync(well, tokenIn, recipient); // This approves the transferToBeanstalk operation. - const approveBack = new sdk.farm.actions.ApproveERC20(well.lpToken, sdk.contracts.beanstalk.address); + const approveBack = new sdk.farm.actions.ApproveERC20(well.lpToken, sdk.contracts.beanstalk.address, true); // Transfers the output token back to Beanstalk, from PIPELINE. - const transferToBeanstalk = new sdk.farm.actions.TransferToken(well.address, account, FarmFromMode.EXTERNAL, FarmToMode.INTERNAL); + const transferToBeanstalk = new sdk.farm.actions.TransferToken(well.address, account, FarmFromMode.EXTERNAL, FarmToMode.INTERNAL, true); result.push(transfer); - advancedPipe.add(addLiquidity, { tag: "wellSync" }); + advancedPipe.add(addLiquidity); + advancedPipe.add( + async function getBalance() { + return { + target: well.lpToken.address, + callData: well.lpToken.getContract().interface.encodeFunctionData("balanceOf", [ + sdk.contracts.pipeline.address + ]) + }; + }, + { tag: "amountToDeposit" } + ); if (transferBack) { advancedPipe.add(approveBack); advancedPipe.add(transferToBeanstalk); } - result.push(advancedPipe); return result; diff --git a/projects/sdk/src/lib/farm/actions/ApproveERC20.ts b/projects/sdk/src/lib/farm/actions/ApproveERC20.ts index 8ddbd65923..fb2cc82e58 100644 --- a/projects/sdk/src/lib/farm/actions/ApproveERC20.ts +++ b/projects/sdk/src/lib/farm/actions/ApproveERC20.ts @@ -1,20 +1,23 @@ import { ethers } from "ethers"; import { ERC20Token } from "src/classes/Token"; import { RunContext, Step, StepClass } from "src/classes/Workflow"; +import { Clipboard } from "src/lib/depot"; import { AdvancedPipePreparedResult } from "src/lib/depot/pipe"; export class ApproveERC20 extends StepClass { public name: string = "approve"; public token: ERC20Token; public spender: string; + public useClipboard?: boolean; - constructor(token: ERC20Token, spender: string) { + constructor(token: ERC20Token, spender: string, useClipboard?: boolean) { super(); if (!token) throw new Error("ApproveERC20 action requires a token"); if (!spender) throw new Error("ApproveERC20 action requires a spender"); this.token = token; this.spender = spender; + this.useClipboard = useClipboard; } async run(_amountInStep: ethers.BigNumber, context: RunContext): Promise> { @@ -23,9 +26,16 @@ export class ApproveERC20 extends StepClass { amountOut: _amountInStep, value: ethers.BigNumber.from(0), prepare: () => { + ApproveERC20.sdk.debug(`[${this.name}.encode()]`, { + token: this.token, + spender: this.spender, + amountInStep: _amountInStep, + useClipboard: this.useClipboard + }); return { target: this.token.address, - callData: this.token.getContract().interface.encodeFunctionData("approve", [this.spender, _amountInStep]) + callData: this.token.getContract().interface.encodeFunctionData("approve", [this.spender, _amountInStep]), + clipboard: this.useClipboard ? Clipboard.encodeSlot(context.step.findTag("amountToDeposit"), 0, 1) : undefined }; }, decode: (data: string) => this.token.getContract().interface.decodeFunctionData("approve", data), diff --git a/projects/sdk/src/lib/farm/actions/Deposit.ts b/projects/sdk/src/lib/farm/actions/Deposit.ts index a5b8d8e7f2..a5326b9729 100644 --- a/projects/sdk/src/lib/farm/actions/Deposit.ts +++ b/projects/sdk/src/lib/farm/actions/Deposit.ts @@ -1,7 +1,8 @@ -import { BasicPreparedResult, RunContext, Step, StepClass } from "src/classes/Workflow"; +import { BasicPreparedResult, RunContext, StepClass } from "src/classes/Workflow"; import { ethers } from "ethers"; import { FarmFromMode, FarmToMode } from "../types"; import { Token } from "src/classes/Token"; +import { Clipboard } from "src/lib/depot"; export class Deposit extends StepClass { public name: string = "deposit"; @@ -22,15 +23,17 @@ export class Deposit extends StepClass { context }); if (!_amountInStep) throw new Error("Deposit: Missing _amountInStep"); + const wellDeposit = this.token.symbol === "BEANETH"; return { target: Deposit.sdk.contracts.beanstalk.address, callData: Deposit.sdk.contracts.beanstalk.interface.encodeFunctionData("deposit", [ this.token.address, _amountInStep, this.fromMode - ]) + ]), + clipboard: wellDeposit ? Clipboard.encodeSlot(context.step.findTag("depositAmount"), 9, 1) : undefined }; - }, + }, decode: (data: string) => Deposit.sdk.contracts.beanstalk.interface.decodeFunctionData("deposit", data), decodeResult: (result: string) => Deposit.sdk.contracts.beanstalk.interface.decodeFunctionResult("deposit", result) }; diff --git a/projects/sdk/src/lib/farm/actions/TransferToken.ts b/projects/sdk/src/lib/farm/actions/TransferToken.ts index b8e9e06dfb..f7dd83fd75 100644 --- a/projects/sdk/src/lib/farm/actions/TransferToken.ts +++ b/projects/sdk/src/lib/farm/actions/TransferToken.ts @@ -1,17 +1,21 @@ import { ethers } from "ethers"; import { BasicPreparedResult, RunContext, Step, StepClass } from "src/classes/Workflow"; import { FarmFromMode, FarmToMode } from "../types"; +import { Clipboard } from "src/lib/depot"; export class TransferToken extends StepClass { public name: string = "transferToken"; + public useClipboard?: boolean; constructor( public readonly _tokenIn: string, public readonly _recipient: string, public readonly _fromMode: FarmFromMode = FarmFromMode.INTERNAL_TOLERANT, - public readonly _toMode: FarmToMode = FarmToMode.INTERNAL + public readonly _toMode: FarmToMode = FarmToMode.INTERNAL, + useClipboard?: boolean ) { super(); + this.useClipboard = useClipboard; } async run(_amountInStep: ethers.BigNumber, context: RunContext) { @@ -24,7 +28,8 @@ export class TransferToken extends StepClass { recipient: this._recipient, amountInStep: _amountInStep, fromMode: this._fromMode, - toMode: this._toMode + toMode: this._toMode, + useClipboard: this.useClipboard }); return { target: TransferToken.sdk.contracts.beanstalk.address, @@ -34,7 +39,8 @@ export class TransferToken extends StepClass { _amountInStep, // ignore minAmountOut since there is no slippage on transfer this._fromMode, // this._toMode // - ]) + ]), + clipboard: this.useClipboard ? Clipboard.encodeSlot(context.step.findTag("amountToDeposit"), 0, 2) : undefined }; }, decode: (data: string) => TransferToken.sdk.contracts.beanstalk.interface.decodeFunctionData("transferToken", data), diff --git a/projects/sdk/src/lib/farm/farm.ts b/projects/sdk/src/lib/farm/farm.ts index ae4dc9570c..0ddc565864 100644 --- a/projects/sdk/src/lib/farm/farm.ts +++ b/projects/sdk/src/lib/farm/farm.ts @@ -1,7 +1,7 @@ import { BeanstalkSDK } from "../BeanstalkSDK"; import * as ActionLibrary from "./actions"; import { LibraryPresets } from "./LibraryPresets"; -import { BasicPreparedResult, RunMode, Step, Workflow } from "src/classes/Workflow"; +import { RunMode, Workflow } from "src/classes/Workflow"; import { Beanstalk, Depot } from "src/constants/generated"; import { TokenValue } from "src/TokenValue"; import { CallOverrides, ethers } from "ethers"; @@ -94,7 +94,7 @@ export class AdvancedFarmWorkflow { + async execute(amountIn: ethers.BigNumber | TokenValue, data: RunData, overrides?: CallOverrides): Promise { const encoded = await this.estimateAndEncodeSteps(amountIn, RunMode.Execute, data); - return this.contract.advancedFarm(encoded, { value: this.value }); + if (overrides) { + overrides.value = this.value; + } else { + overrides = { value: this.value }; + } + Workflow.sdk.debug(`[Workflow][${this.name}][execute]`, encoded, overrides); + return this.contract.advancedFarm(encoded, overrides); } async callStatic(amountIn: ethers.BigNumber | TokenValue, data: RunData): Promise { @@ -165,4 +174,8 @@ export class Farm { createAdvancedPipe(name?: string) { return new AdvancedPipeWorkflow(Farm.sdk, name); } + + createAdvancedFarm(name?: string) { + return new AdvancedFarmWorkflow(Farm.sdk, name); + } } diff --git a/projects/sdk/src/lib/farm/index.ts b/projects/sdk/src/lib/farm/index.ts index 76c790dc08..ae69146398 100644 --- a/projects/sdk/src/lib/farm/index.ts +++ b/projects/sdk/src/lib/farm/index.ts @@ -1,2 +1,2 @@ -export { Farm, FarmWorkflow } from "./farm"; +export { Farm, FarmWorkflow, AdvancedFarmWorkflow } from "./farm"; export { FarmFromMode, FarmToMode } from "./types"; diff --git a/projects/sdk/src/lib/silo/DepositOperation.ts b/projects/sdk/src/lib/silo/DepositOperation.ts index cde57c306f..86f5a65394 100644 --- a/projects/sdk/src/lib/silo/DepositOperation.ts +++ b/projects/sdk/src/lib/silo/DepositOperation.ts @@ -4,7 +4,7 @@ import { Token } from "src/classes/Token"; import { ActionType } from "src/constants/actions"; import { TokenValue } from "src/TokenValue"; import { BeanstalkSDK } from "../BeanstalkSDK"; -import { FarmFromMode, FarmToMode, FarmWorkflow } from "../farm"; +import { AdvancedFarmWorkflow, FarmFromMode, FarmToMode, FarmWorkflow } from "../farm"; export class DepositOperation { static sdk: BeanstalkSDK; @@ -14,7 +14,7 @@ export class DepositOperation { inputToken: Token; inputAmount: TokenValue; readonly router: Router; - workflow: FarmWorkflow<{ slippage: number } & Record>; + workflow: AdvancedFarmWorkflow|FarmWorkflow<{ slippage: number } & Record>; lastAmountIn: TokenValue; constructor(sdk: BeanstalkSDK, router: Router, targetToken: Token, account: string) { @@ -37,7 +37,11 @@ export class DepositOperation { buildWorkflow() { const route = this.router.getRoute(this.inputToken.symbol, `${this.targetToken.symbol}:SILO`); - this.workflow = DepositOperation.sdk.farm.create(`Deposit`); + if (this.targetToken.symbol === "BEANETH") { + this.workflow = DepositOperation.sdk.farm.createAdvancedFarm(`Deposit`); + } else { + this.workflow = DepositOperation.sdk.farm.create(`Deposit`); + } for (let i = 0; i < route.length; i++) { let from, to; diff --git a/projects/ui/src/components/Silo/Actions/Deposit.tsx b/projects/ui/src/components/Silo/Actions/Deposit.tsx index 74b35269a2..412f148e6a 100644 --- a/projects/ui/src/components/Silo/Actions/Deposit.tsx +++ b/projects/ui/src/components/Silo/Actions/Deposit.tsx @@ -514,7 +514,8 @@ const DepositPropProvider: FC<{ depositTxn, amountIn, values.settings.slippage, - target.equals(BEAN_ETH_WELL_LP) ? 1.2 : undefined + target.equals(BEAN_ETH_WELL_LP) ? 1.2 : undefined, + target.equals(BEAN_ETH_WELL_LP) ); const txn = await execute(); diff --git a/projects/ui/src/lib/Txn/FormTxn/FormTxnBundler.ts b/projects/ui/src/lib/Txn/FormTxn/FormTxnBundler.ts index c86c94adea..49577eb792 100644 --- a/projects/ui/src/lib/Txn/FormTxn/FormTxnBundler.ts +++ b/projects/ui/src/lib/Txn/FormTxn/FormTxnBundler.ts @@ -128,9 +128,15 @@ export class FormTxnBundler { operation: FarmStep, amountIn: TokenValue, slippage: number, - gasMultiplier?: number + gasMultiplier?: number, + advancedFarm?: boolean ) { - const farm = this._sdk.farm.create(); + let farm: any; + if (advancedFarm) { + farm = this._sdk.farm.createAdvancedFarm(); + } else { + farm = this._sdk.farm.create(); + } Object.entries(this.before).forEach(([step, farmStep]) => { const farmInput = farmStep.getFarmInput();