From b3c387706d19dc9841c69b692695a99b44c8edcd Mon Sep 17 00:00:00 2001 From: Roberto Cano <3525807+robercano@users.noreply.github.com> Date: Mon, 27 May 2024 13:48:30 +0200 Subject: [PATCH] feat: accept skippable actions in order planner (#298) --- .../src/implementation/OrderPlanner.ts | 1 + .../src/utils/EncodeStrategy.ts | 12 +- .../src/utils/GenerateStrategyName.ts | 12 -- .../src/config/Config.ts | 2 + .../tests/service/OrderPlannerService.spec.ts | 5 +- .../src/actions/BaseAction.ts | 1 + .../src/actions/SkippedAction.ts | 40 ++++++ .../src/actions/Types.ts | 6 +- .../src/actions/index.ts | 13 +- .../src/context/StepBuilderContext.ts | 13 ++ .../src/interfaces/IActionBuilder.ts | 1 + .../src/interfaces/IStepBuilderContext.ts | 2 + .../AaveV3DepositBorrowActionBuilder.ts | 28 ++-- .../AaveV3PaybackWithdrawActionBuilder.ts | 87 ++++++------ .../plugins/common/actions/FlashloanAction.ts | 16 +-- .../builders/SkippedStepActionBuilder.ts | 41 ++++++ .../src/plugins/common/builders/index.ts | 1 + .../MakerPaybackWithdrawActionBuilder.ts | 31 ++-- .../MorphoDepositBorrowActionBuilder.ts | 67 ++++----- .../MorphoPaybackWithdrawActionBuilder.ts | 62 ++++---- .../SparkDepositBorrowActionBuilder.ts | 27 ++-- .../SparkPaybackWithdrawActionBuilder.ts | 85 ++++++----- .../unit/actions/FlashloanAction.spec.ts | 2 + .../AaveV3DepositBorrowActionBuilder.spec.ts | 3 +- ...AaveV3PaybackWithdrawActionBuilder.spec.ts | 6 +- .../MakerPaybackWithdrawActionBuilder.spec.ts | 5 +- .../MorphoDepositBorrowActionBuilder.spec.ts | 7 +- ...MorphoPaybackWithdrawActionBuilder.spec.ts | 6 +- .../SparkDepositBorrowActionBuilder.spec.ts | 3 +- .../SparkPaybackWithdrawActionBuilder.spec.ts | 6 +- .../tests/utils/SetupBuilderParams.ts | 4 +- .../simulations/RefinanceSimulationManager.ts | 4 +- sdk/sdk-common/src/simulation/Enums.ts | 14 +- sdk/sdk-common/src/simulation/Steps.ts | 11 ++ sdk/sdk-e2e/tests/refinance.test.ts | 6 +- .../tests/refinanceAaveV3SparkAnyPair.test.ts | 15 +- ...refinanceMakerSparkAlreadyImported.test.ts | 4 +- .../tests/refinanceMakerSparkAnyPair.test.ts | 45 +++--- .../tests/refinanceMorphoSparkAnyPair.test.ts | 4 +- .../src/handlers/getRefinanceSimulation.ts | 17 +-- .../reducer/skippedStepReducer.ts | 12 ++ .../simulator-engine/reducer/stateReducers.ts | 2 + .../simulator-engine/simulator.ts | 19 ++- .../skippedStepOutputProcessor.ts | 9 ++ .../stepProcessor/stepOutputProcessors.ts | 2 + .../utils/GetRefinanceSimulationType.ts | 20 --- .../src/strategies/StrategyIndex.ts | 10 +- .../common/RefinanceStrategyRouter.ts | 45 ------ .../src/strategies/common/index.ts | 1 - sdk/simulator-service/src/strategies/index.ts | 4 +- .../RefinanceLendingToLendingAnyPair.ts | 117 ++++++++++------ .../Strategy.ts | 0 .../index.ts | 0 .../RefinanceLendingToLendingNoDebt.ts | 132 ------------------ .../strategies/refinanceNoDebt/Strategy.ts | 30 ---- .../src/strategies/refinanceNoDebt/index.ts | 2 - .../RefinanceLendingToLendingSamePair.ts | 129 ----------------- .../strategies/refinanceSamePair/Strategy.ts | 35 ----- .../src/strategies/refinanceSamePair/index.ts | 2 - sdk/simulator-service/tests/simulator.test.ts | 68 +-------- .../src/utils/StrategyExecutorDecoding.ts | 11 +- sdk/testing-utils/src/utils/index.ts | 11 +- sdk/tools/genStrategyDefinitions/src/index.ts | 6 +- 63 files changed, 519 insertions(+), 863 deletions(-) create mode 100644 sdk/protocol-plugins-common/src/actions/SkippedAction.ts create mode 100644 sdk/protocol-plugins/src/plugins/common/builders/SkippedStepActionBuilder.ts create mode 100644 sdk/simulator-service/src/implementation/simulator-engine/reducer/skippedStepReducer.ts create mode 100644 sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/skippedStepOutputProcessor.ts delete mode 100644 sdk/simulator-service/src/implementation/utils/GetRefinanceSimulationType.ts delete mode 100644 sdk/simulator-service/src/strategies/common/RefinanceStrategyRouter.ts rename sdk/simulator-service/src/strategies/{refinanceAnyPair => refinanceLendingToLending}/RefinanceLendingToLendingAnyPair.ts (71%) rename sdk/simulator-service/src/strategies/{refinanceAnyPair => refinanceLendingToLending}/Strategy.ts (100%) rename sdk/simulator-service/src/strategies/{refinanceAnyPair => refinanceLendingToLending}/index.ts (100%) delete mode 100644 sdk/simulator-service/src/strategies/refinanceNoDebt/RefinanceLendingToLendingNoDebt.ts delete mode 100644 sdk/simulator-service/src/strategies/refinanceNoDebt/Strategy.ts delete mode 100644 sdk/simulator-service/src/strategies/refinanceNoDebt/index.ts delete mode 100644 sdk/simulator-service/src/strategies/refinanceSamePair/RefinanceLendingToLendingSamePair.ts delete mode 100644 sdk/simulator-service/src/strategies/refinanceSamePair/Strategy.ts delete mode 100644 sdk/simulator-service/src/strategies/refinanceSamePair/index.ts diff --git a/sdk/order-planner-common/src/implementation/OrderPlanner.ts b/sdk/order-planner-common/src/implementation/OrderPlanner.ts index 8113c93dbf..f12f398b73 100644 --- a/sdk/order-planner-common/src/implementation/OrderPlanner.ts +++ b/sdk/order-planner-common/src/implementation/OrderPlanner.ts @@ -53,6 +53,7 @@ export class OrderPlanner implements IOrderPlanner { addressBookManager, step, protocolsRegistry, + actionBuildersMap, }) } diff --git a/sdk/order-planner-common/src/utils/EncodeStrategy.ts b/sdk/order-planner-common/src/utils/EncodeStrategy.ts index 3d1a9cd9ed..699e557359 100644 --- a/sdk/order-planner-common/src/utils/EncodeStrategy.ts +++ b/sdk/order-planner-common/src/utils/EncodeStrategy.ts @@ -3,10 +3,6 @@ import { Address, HexData, Maybe } from '@summerfi/sdk-common/common' import { IPositionsManager, TransactionInfo } from '@summerfi/sdk-common/orders' import { encodeFunctionData, parseAbi } from 'viem' -type SkippableActionCall = ActionCall & { - skipped: boolean -} - function encodeForExecutor(params: { strategyName: string; actions: ActionCall[] }): HexData { const { strategyName, actions } = params @@ -15,16 +11,10 @@ function encodeForExecutor(params: { strategyName: string; actions: ActionCall[] 'struct Call { bytes32 targetHash; bytes callData; bool skipped; }', ]) - // TODO: Hiding this here for now as we don't support skippable actions anymore in the new version - const skippableActions: SkippableActionCall[] = actions.map((action) => ({ - ...action, - skipped: false, - })) - return encodeFunctionData({ abi, functionName: 'executeOp', - args: [skippableActions, strategyName], + args: [actions, strategyName], }) } diff --git a/sdk/order-planner-common/src/utils/GenerateStrategyName.ts b/sdk/order-planner-common/src/utils/GenerateStrategyName.ts index 1006abf536..6cd3715765 100644 --- a/sdk/order-planner-common/src/utils/GenerateStrategyName.ts +++ b/sdk/order-planner-common/src/utils/GenerateStrategyName.ts @@ -1,17 +1,5 @@ import { ISimulation, SimulationType } from '@summerfi/sdk-common/simulation' export function generateStrategyName(simulation: ISimulation): string { - // TODO: temporary workaround to use the right simulation name - if ( - simulation.simulationType === SimulationType.Refinance || - simulation.simulationType === SimulationType.RefinanceDifferentPair || - simulation.simulationType === SimulationType.RefinanceDifferentCollateral || - simulation.simulationType === SimulationType.RefinanceDifferentDebt || - simulation.simulationType === SimulationType.RefinanceNoDebt || - simulation.simulationType === SimulationType.RefinanceNoDebtDifferentCollateral - ) { - return `Refinance${simulation.sourcePosition?.pool.id.protocol.name}${simulation.targetPosition.pool.id.protocol.name}` - } - return `${simulation.simulationType}${simulation.sourcePosition?.pool.id.protocol.name}${simulation.targetPosition?.pool.id.protocol.name}` } diff --git a/sdk/order-planner-service/src/config/Config.ts b/sdk/order-planner-service/src/config/Config.ts index 29b8af3e55..e64920cd8d 100644 --- a/sdk/order-planner-service/src/config/Config.ts +++ b/sdk/order-planner-service/src/config/Config.ts @@ -11,6 +11,7 @@ import { ReturnFundsActionBuilder, SwapActionBuilder, OpenPositionActionBuilder, + SkippedStepActionBuilder, } from '@summerfi/protocol-plugins/plugins/common' export const ActionBuildersConfig: ActionBuildersMap = { @@ -24,4 +25,5 @@ export const ActionBuildersConfig: ActionBuildersMap = { [SimulationSteps.NewPositionEvent]: PositionCreatedActionBuilder, [SimulationSteps.Import]: ImportPositionActionBuilder, [SimulationSteps.OpenPosition]: OpenPositionActionBuilder, + [SimulationSteps.Skipped]: SkippedStepActionBuilder, } diff --git a/sdk/order-planner-service/tests/service/OrderPlannerService.spec.ts b/sdk/order-planner-service/tests/service/OrderPlannerService.spec.ts index be9a7079fc..8a9275770d 100644 --- a/sdk/order-planner-service/tests/service/OrderPlannerService.spec.ts +++ b/sdk/order-planner-service/tests/service/OrderPlannerService.spec.ts @@ -15,14 +15,13 @@ import { getRefinanceSimulation } from '../utils/RefinanceSimulation/RefinanceSi import { OrderPlannerService } from '../../src/implementation/OrderPlannerService' import { decodeActionCalldata, - SkippableActionCall, decodePositionsManagerCalldata, decodeStrategyExecutorCalldata, getErrorMessage, } from '@summerfi/testing-utils' import assert from 'assert' import { IUser } from '@summerfi/sdk-common/user' -import { IProtocolPluginsRegistry } from '@summerfi/protocol-plugins-common' +import { ActionCall, IProtocolPluginsRegistry } from '@summerfi/protocol-plugins-common' import { http, createPublicClient } from 'viem' import { MakerPaybackAction, @@ -153,7 +152,7 @@ describe('Order Planner Service', () => { expect(flashloanCall.mapping).toEqual([0, 0, 0, 0]) /* Decode flashloan sub-calls */ - const flashloanSubcalls = flashloanCall.args[0].calls as SkippableActionCall[] + const flashloanSubcalls = flashloanCall.args[0].calls as ActionCall[] // PaybackWithdraw in Maker and DepositBorrow in Spark take 2 actions each expect(flashloanSubcalls.length).toBe(6) diff --git a/sdk/protocol-plugins-common/src/actions/BaseAction.ts b/sdk/protocol-plugins-common/src/actions/BaseAction.ts index 1625697c9d..b9f8dac4c0 100644 --- a/sdk/protocol-plugins-common/src/actions/BaseAction.ts +++ b/sdk/protocol-plugins-common/src/actions/BaseAction.ts @@ -75,6 +75,7 @@ export abstract class BaseAction< name: this.config.name, targetHash, callData: calldata, + skipped: false, } as ActionCall } diff --git a/sdk/protocol-plugins-common/src/actions/SkippedAction.ts b/sdk/protocol-plugins-common/src/actions/SkippedAction.ts new file mode 100644 index 0000000000..6d589884bc --- /dev/null +++ b/sdk/protocol-plugins-common/src/actions/SkippedAction.ts @@ -0,0 +1,40 @@ +import { BaseAction } from './BaseAction' +import { InputSlotsMapping } from '../types/InputSlotsMapping' +import { ActionCall } from './Types' +import { IAction } from '../interfaces/IAction' + +export class SkippedAction extends BaseAction { + static Config = { + name: 'SkippedAction', + version: 0, + parametersAbi: ['()'], + storageInputs: [], + storageOutputs: [], + } as const + + private _skippedAction: IAction + + public constructor(skippedAction: IAction) { + super() + + this._skippedAction = skippedAction + } + + /* eslint-disable @typescript-eslint/no-unused-vars */ + public encodeCall(paramsMapping?: InputSlotsMapping): ActionCall { + return { + name: this._skippedAction.config.name, + callData: '0x', + targetHash: this._skippedAction.getActionHash(), + skipped: true, + } + } + + public get config() { + return SkippedAction.Config + } + + public getVersionedName(): string { + return this._skippedAction.getVersionedName() + } +} diff --git a/sdk/protocol-plugins-common/src/actions/Types.ts b/sdk/protocol-plugins-common/src/actions/Types.ts index c4cc1dddbb..9636f62da6 100644 --- a/sdk/protocol-plugins-common/src/actions/Types.ts +++ b/sdk/protocol-plugins-common/src/actions/Types.ts @@ -15,7 +15,7 @@ export type ActionVersion = number */ export type ActionConfig = { /** The name of the action */ - readonly name: ActionNames + readonly name: ActionNames | 'SkippedAction' /** The version of the action */ readonly version: ActionVersion /** Human-readable ABI parameters (check `viem` documentation) */ @@ -32,11 +32,13 @@ export type ActionConfig = { */ export type ActionCall = { /** Name of the action for logging */ - readonly name: ActionNames + readonly name: ActionNames | 'SkippedAction' /** The hash of the action name plus its version */ readonly targetHash: HexData /** The call data to be sent to the smart contract */ readonly callData: HexData + /** If the action was skipped */ + readonly skipped: boolean } /** diff --git a/sdk/protocol-plugins-common/src/actions/index.ts b/sdk/protocol-plugins-common/src/actions/index.ts index 44dee35d96..ab2271f948 100644 --- a/sdk/protocol-plugins-common/src/actions/index.ts +++ b/sdk/protocol-plugins-common/src/actions/index.ts @@ -1,10 +1,3 @@ -export type { - ActionConfig, - ActionCall, - ActionCallBatch, - ActionStorageName, - ActionInputStorageNames, - ActionOutputStorageNames, - ActionVersion, -} from './Types' -export { BaseAction } from './BaseAction' +export type * from './Types' +export * from './BaseAction' +export * from './SkippedAction' diff --git a/sdk/protocol-plugins-common/src/context/StepBuilderContext.ts b/sdk/protocol-plugins-common/src/context/StepBuilderContext.ts index 3ecceeb500..d7414af88e 100644 --- a/sdk/protocol-plugins-common/src/context/StepBuilderContext.ts +++ b/sdk/protocol-plugins-common/src/context/StepBuilderContext.ts @@ -7,6 +7,7 @@ import { ActionCallBatch, ActionConfig } from '../actions/Types' import { ActionCallsStack } from './ActionCallsStack' import { ExecutionStorageMapper } from './ExecutionStorageMapper' import { TransactionInfo } from '@summerfi/sdk-common/orders' +import { SkippedAction } from '../actions/SkippedAction' /** * @name StepBuilderContext @@ -33,7 +34,19 @@ export class StepBuilderContext implements IStepBuilderContext { arguments: Parameters[0] connectedInputs: Partial> connectedOutputs: Partial> + skip?: boolean }) { + // TODO: temporary solution until we remove the Operations Registry + if (params.skip) { + const skipAction = new SkippedAction(params.action) + + this._calls.addCall({ + call: skipAction.encodeCall(), + }) + + return + } + const paramsMapping = this._storage.addStorageMap({ step: params.step, action: params.action, diff --git a/sdk/protocol-plugins-common/src/interfaces/IActionBuilder.ts b/sdk/protocol-plugins-common/src/interfaces/IActionBuilder.ts index 2b31de4f5b..f05e4a8266 100644 --- a/sdk/protocol-plugins-common/src/interfaces/IActionBuilder.ts +++ b/sdk/protocol-plugins-common/src/interfaces/IActionBuilder.ts @@ -18,6 +18,7 @@ export type ActionBuilderParams = { addressBookManager: IAddressBookManager protocolsRegistry: IProtocolPluginsRegistry step: Step + actionBuildersMap: ActionBuildersMap } /** diff --git a/sdk/protocol-plugins-common/src/interfaces/IStepBuilderContext.ts b/sdk/protocol-plugins-common/src/interfaces/IStepBuilderContext.ts index afb7e84beb..9260c715d1 100644 --- a/sdk/protocol-plugins-common/src/interfaces/IStepBuilderContext.ts +++ b/sdk/protocol-plugins-common/src/interfaces/IStepBuilderContext.ts @@ -27,6 +27,7 @@ export interface IStepBuilderContext { * will read from storage * @param connectedOutputs The connected outputs to the action, this is the values that the action * will write to storage + * @param skip If true, the action will be skipped and empty calldata will be added to the TX */ addActionCall< Step extends steps.Steps, @@ -38,6 +39,7 @@ export interface IStepBuilderContext { arguments: Parameters[0] connectedInputs: Partial> connectedOutputs: Partial> + skip?: boolean }): void /** diff --git a/sdk/protocol-plugins/src/plugins/aave-v3/builders/AaveV3DepositBorrowActionBuilder.ts b/sdk/protocol-plugins/src/plugins/aave-v3/builders/AaveV3DepositBorrowActionBuilder.ts index d050310b82..9182afb7d3 100644 --- a/sdk/protocol-plugins/src/plugins/aave-v3/builders/AaveV3DepositBorrowActionBuilder.ts +++ b/sdk/protocol-plugins/src/plugins/aave-v3/builders/AaveV3DepositBorrowActionBuilder.ts @@ -63,21 +63,19 @@ export class AaveV3DepositBorrowActionBuilder extends BaseActionBuilder { public static Config = { name: 'TakeFlashloan', @@ -26,15 +21,6 @@ export class FlashloanAction extends BaseAction { }, paramsMapping?: InputSlotsMapping, ): ActionCall { - const calls: OptionalActionCall[] = params.calls.map((call) => { - return { - name: call.name, - targetHash: call.targetHash, - callData: call.callData, - skipped: false, - } - }) - return this._encodeCall({ arguments: [ { @@ -43,7 +29,7 @@ export class FlashloanAction extends BaseAction { isProxyFlashloan: true, isDPMProxy: true, provider: params.provider, - calls: calls, + calls: params.calls, }, ], mapping: paramsMapping, diff --git a/sdk/protocol-plugins/src/plugins/common/builders/SkippedStepActionBuilder.ts b/sdk/protocol-plugins/src/plugins/common/builders/SkippedStepActionBuilder.ts new file mode 100644 index 0000000000..31eff868c3 --- /dev/null +++ b/sdk/protocol-plugins/src/plugins/common/builders/SkippedStepActionBuilder.ts @@ -0,0 +1,41 @@ +import { + ActionBuilderParams, + ActionBuilderUsedAction, + ActionConfig, + BaseAction, +} from '@summerfi/protocol-plugins-common' +import { steps } from '@summerfi/sdk-common/simulation' +import { BaseActionBuilder } from '../../../implementation/BaseActionBuilder' + +// TODO: temporary solution until we remove the Operations Registry +export class SkippedStepActionBuilder extends BaseActionBuilder { + readonly actions: ActionBuilderUsedAction[] = [] + + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ + async build(params: ActionBuilderParams): Promise { + const { context } = params + const BuilderClass = params.actionBuildersMap[params.step.inputs.type] + if (!BuilderClass) { + return + } + + const builder = new BuilderClass() + + for (const actionConfig of builder.actions) { + if (actionConfig.action === 'DelegatedToProtocol') { + throw new Error('DelegatedToProtocol is not supported in SkippedStepActionBuilder') + } + + const action = new actionConfig.action() + + context.addActionCall({ + step: params.step, + action: action as BaseAction, + arguments: {}, + connectedInputs: {}, + connectedOutputs: {}, + skip: true, + }) + } + } +} diff --git a/sdk/protocol-plugins/src/plugins/common/builders/index.ts b/sdk/protocol-plugins/src/plugins/common/builders/index.ts index d56f468f26..c2dbc80501 100644 --- a/sdk/protocol-plugins/src/plugins/common/builders/index.ts +++ b/sdk/protocol-plugins/src/plugins/common/builders/index.ts @@ -8,3 +8,4 @@ export * from './SwapActionBuilder' export * from './PositionCreatedActionBuilder' export * from './ImportPositionActionBuilder' export * from './OpenPositionActionBuilder' +export * from './SkippedStepActionBuilder' diff --git a/sdk/protocol-plugins/src/plugins/maker/builders/MakerPaybackWithdrawActionBuilder.ts b/sdk/protocol-plugins/src/plugins/maker/builders/MakerPaybackWithdrawActionBuilder.ts index 1c2073045f..fd01e7a9fb 100644 --- a/sdk/protocol-plugins/src/plugins/maker/builders/MakerPaybackWithdrawActionBuilder.ts +++ b/sdk/protocol-plugins/src/plugins/maker/builders/MakerPaybackWithdrawActionBuilder.ts @@ -30,22 +30,21 @@ export class MakerPaybackWithdrawActionBuilder extends BaseActionBuilder { name: 'SendToken', targetHash: '0x3434343434343434343434343434343456565656565656565656565656565656', callData: '0x1234567890123456789012345678901234', + skipped: false, }, { name: 'ReturnFunds', targetHash: '0x1212121212121212121212121212121278787878787878787878787878787878', callData: '0x9876543210987654321098765432109876', + skipped: false, }, ], }, diff --git a/sdk/protocol-plugins/tests/unit/builders/aaveV3/AaveV3DepositBorrowActionBuilder.spec.ts b/sdk/protocol-plugins/tests/unit/builders/aaveV3/AaveV3DepositBorrowActionBuilder.spec.ts index 37591bff59..3a777e7eb5 100644 --- a/sdk/protocol-plugins/tests/unit/builders/aaveV3/AaveV3DepositBorrowActionBuilder.spec.ts +++ b/sdk/protocol-plugins/tests/unit/builders/aaveV3/AaveV3DepositBorrowActionBuilder.spec.ts @@ -182,10 +182,11 @@ describe('AaveV3 Deposit Borrow Action Builder', () => { const { callsBatch } = builderParams.context.endSubContext() - expect(callsBatch.length).toEqual(2) + expect(callsBatch.length).toEqual(3) expect(callsBatch[0].name).toBe('SetApproval') expect(callsBatch[1].name).toBe('AaveV3Deposit') + expect(callsBatch[2].name).toBe('AaveV3Borrow') }) it('should add borrow but not send token when borrow target is positions manager', async () => { diff --git a/sdk/protocol-plugins/tests/unit/builders/aaveV3/AaveV3PaybackWithdrawActionBuilder.spec.ts b/sdk/protocol-plugins/tests/unit/builders/aaveV3/AaveV3PaybackWithdrawActionBuilder.spec.ts index 8c31b47a36..1e08e65d93 100644 --- a/sdk/protocol-plugins/tests/unit/builders/aaveV3/AaveV3PaybackWithdrawActionBuilder.spec.ts +++ b/sdk/protocol-plugins/tests/unit/builders/aaveV3/AaveV3PaybackWithdrawActionBuilder.spec.ts @@ -182,8 +182,10 @@ describe('AaveV3 Payback Withdraw Action Builder', () => { const { callsBatch } = builderParams.context.endSubContext() - expect(callsBatch.length).toEqual(1) + expect(callsBatch.length).toEqual(3) - expect(callsBatch[0].name).toBe('AaveV3Withdraw') + expect(callsBatch[0].name).toBe('SetApproval') + expect(callsBatch[1].name).toBe('AaveV3Payback') + expect(callsBatch[2].name).toBe('AaveV3Withdraw') }) }) diff --git a/sdk/protocol-plugins/tests/unit/builders/maker/MakerPaybackWithdrawActionBuilder.spec.ts b/sdk/protocol-plugins/tests/unit/builders/maker/MakerPaybackWithdrawActionBuilder.spec.ts index 1d7c045225..07a9f08744 100644 --- a/sdk/protocol-plugins/tests/unit/builders/maker/MakerPaybackWithdrawActionBuilder.spec.ts +++ b/sdk/protocol-plugins/tests/unit/builders/maker/MakerPaybackWithdrawActionBuilder.spec.ts @@ -187,8 +187,9 @@ describe('Maker Payback Withdraw Action Builder', () => { const { callsBatch } = builderParams.context.endSubContext() - expect(callsBatch.length).toEqual(1) + expect(callsBatch.length).toEqual(2) - expect(callsBatch[0].name).toBe('MakerWithdraw') + expect(callsBatch[0].name).toBe('MakerPayback') + expect(callsBatch[1].name).toBe('MakerWithdraw') }) }) diff --git a/sdk/protocol-plugins/tests/unit/builders/morpho/MorphoDepositBorrowActionBuilder.spec.ts b/sdk/protocol-plugins/tests/unit/builders/morpho/MorphoDepositBorrowActionBuilder.spec.ts index 6d63b4a36e..3dd9eb142d 100644 --- a/sdk/protocol-plugins/tests/unit/builders/morpho/MorphoDepositBorrowActionBuilder.spec.ts +++ b/sdk/protocol-plugins/tests/unit/builders/morpho/MorphoDepositBorrowActionBuilder.spec.ts @@ -190,10 +190,12 @@ describe('Morpho Deposit Borrow Action Builder', () => { const { callsBatch } = builderParams.context.endSubContext() - expect(callsBatch.length).toEqual(2) + expect(callsBatch.length).toEqual(4) expect(callsBatch[0].name).toBe('SetApproval') expect(callsBatch[1].name).toBe('MorphoBlueDeposit') + expect(callsBatch[2].name).toBe('MorphoBlueBorrow') + expect(callsBatch[3].name).toBe('SendToken') }) it('should add borrow but not send token when borrow target is positions manager', async () => { @@ -213,10 +215,11 @@ describe('Morpho Deposit Borrow Action Builder', () => { const { callsBatch } = builderParams.context.endSubContext() - expect(callsBatch.length).toEqual(3) + expect(callsBatch.length).toEqual(4) expect(callsBatch[0].name).toBe('SetApproval') expect(callsBatch[1].name).toBe('MorphoBlueDeposit') expect(callsBatch[2].name).toBe('MorphoBlueBorrow') + expect(callsBatch[3].name).toBe('SendToken') }) }) diff --git a/sdk/protocol-plugins/tests/unit/builders/morpho/MorphoPaybackWithdrawActionBuilder.spec.ts b/sdk/protocol-plugins/tests/unit/builders/morpho/MorphoPaybackWithdrawActionBuilder.spec.ts index 0b71224781..f258c72097 100644 --- a/sdk/protocol-plugins/tests/unit/builders/morpho/MorphoPaybackWithdrawActionBuilder.spec.ts +++ b/sdk/protocol-plugins/tests/unit/builders/morpho/MorphoPaybackWithdrawActionBuilder.spec.ts @@ -187,8 +187,10 @@ describe('Morpho Payback Withdraw Action Builder', () => { const { callsBatch } = builderParams.context.endSubContext() - expect(callsBatch.length).toEqual(1) + expect(callsBatch.length).toEqual(3) - expect(callsBatch[0].name).toBe('MorphoBlueWithdraw') + expect(callsBatch[0].name).toBe('SetApproval') + expect(callsBatch[1].name).toBe('MorphoBluePayback') + expect(callsBatch[2].name).toBe('MorphoBlueWithdraw') }) }) diff --git a/sdk/protocol-plugins/tests/unit/builders/spark/SparkDepositBorrowActionBuilder.spec.ts b/sdk/protocol-plugins/tests/unit/builders/spark/SparkDepositBorrowActionBuilder.spec.ts index 6e9e5a2356..9cb115d17d 100644 --- a/sdk/protocol-plugins/tests/unit/builders/spark/SparkDepositBorrowActionBuilder.spec.ts +++ b/sdk/protocol-plugins/tests/unit/builders/spark/SparkDepositBorrowActionBuilder.spec.ts @@ -182,10 +182,11 @@ describe('Spark Deposit Borrow Action Builder', () => { const { callsBatch } = builderParams.context.endSubContext() - expect(callsBatch.length).toEqual(2) + expect(callsBatch.length).toEqual(3) expect(callsBatch[0].name).toBe('SetApproval') expect(callsBatch[1].name).toBe('SparkDeposit') + expect(callsBatch[2].name).toBe('SparkBorrow') }) it('should add borrow but not send token when borrow target is positions manager', async () => { diff --git a/sdk/protocol-plugins/tests/unit/builders/spark/SparkPaybackWithdrawActionBuilder.spec.ts b/sdk/protocol-plugins/tests/unit/builders/spark/SparkPaybackWithdrawActionBuilder.spec.ts index 7f247571e6..8a8ffd164a 100644 --- a/sdk/protocol-plugins/tests/unit/builders/spark/SparkPaybackWithdrawActionBuilder.spec.ts +++ b/sdk/protocol-plugins/tests/unit/builders/spark/SparkPaybackWithdrawActionBuilder.spec.ts @@ -182,8 +182,10 @@ describe('Spark Payback Withdraw Action Builder', () => { const { callsBatch } = builderParams.context.endSubContext() - expect(callsBatch.length).toEqual(1) + expect(callsBatch.length).toEqual(3) - expect(callsBatch[0].name).toBe('SparkWithdraw') + expect(callsBatch[0].name).toBe('SetApproval') + expect(callsBatch[1].name).toBe('SparkPayback') + expect(callsBatch[2].name).toBe('SparkWithdraw') }) }) diff --git a/sdk/protocol-plugins/tests/utils/SetupBuilderParams.ts b/sdk/protocol-plugins/tests/utils/SetupBuilderParams.ts index 2962f2a715..b18466abdf 100644 --- a/sdk/protocol-plugins/tests/utils/SetupBuilderParams.ts +++ b/sdk/protocol-plugins/tests/utils/SetupBuilderParams.ts @@ -3,7 +3,7 @@ import { IPositionsManager } from '@summerfi/sdk-common/orders' import { Address, ChainInfo } from '@summerfi/sdk-common/common' import { SetupDeployments } from './SetupDeployments' import { IUser } from '@summerfi/sdk-common/user' -import { IProtocolPluginsRegistry } from '@summerfi/protocol-plugins-common' +import { ActionBuildersMap, IProtocolPluginsRegistry } from '@summerfi/protocol-plugins-common' import { createEmptyBuildersProtocolPluginsRegistry, createEmptyProtocolPluginsRegistry, @@ -25,6 +25,7 @@ export type SetupBuilderReturnType = { swapManager: SwapManagerMock addressBookManager: IAddressBookManager protocolsRegistry: IProtocolPluginsRegistry + actionBuildersMap: ActionBuildersMap emptyProtocolsRegistry: IProtocolPluginsRegistry emptyBuildersProtocolRegistry: IProtocolPluginsRegistry noCheckpointProtocolsRegistry: IProtocolPluginsRegistry @@ -50,6 +51,7 @@ export function setupBuilderParams(params: { chainInfo: ChainInfo }): SetupBuild swapManager: new SwapManagerMock(), addressBookManager: new AddressBookManagerMock(), protocolsRegistry: protocolsRegistry, + actionBuildersMap: {} as ActionBuildersMap, emptyProtocolsRegistry: emptyProtocolsRegistry, noCheckpointProtocolsRegistry: noCheckpointProtocolsRegistry, emptyBuildersProtocolRegistry: emptyBuildersProtocolRegistry, diff --git a/sdk/sdk-client/src/implementation/simulations/RefinanceSimulationManager.ts b/sdk/sdk-client/src/implementation/simulations/RefinanceSimulationManager.ts index a595fcd787..599f6baba5 100644 --- a/sdk/sdk-client/src/implementation/simulations/RefinanceSimulationManager.ts +++ b/sdk/sdk-client/src/implementation/simulations/RefinanceSimulationManager.ts @@ -1,5 +1,5 @@ import { IRefinanceParameters } from '@summerfi/sdk-common/orders' -import { ISimulation, RefinanceSimulationTypes } from '@summerfi/sdk-common/simulation' +import { ISimulation, SimulationType } from '@summerfi/sdk-common/simulation' import { RPCClientType } from '../../rpc/SDKClient' import { IRPCClient } from '../../interfaces/IRPCClient' @@ -10,7 +10,7 @@ export class RefinanceSimulationManager extends IRPCClient { public async simulateRefinancePosition( refinanceParameters: IRefinanceParameters, - ): Promise> { + ): Promise> { return this.rpcClient.simulation.refinance.query(refinanceParameters) } } diff --git a/sdk/sdk-common/src/simulation/Enums.ts b/sdk/sdk-common/src/simulation/Enums.ts index 72e9232d8f..a81fd394e0 100644 --- a/sdk/sdk-common/src/simulation/Enums.ts +++ b/sdk/sdk-common/src/simulation/Enums.ts @@ -7,11 +7,6 @@ export enum SimulationType { Migrate = 'Migrate', CreatePosition = 'CreatePosition', Refinance = 'Refinance', - RefinanceDifferentPair = 'RefinanceDifPair', - RefinanceDifferentDebt = 'RefinanceDifDebt', - RefinanceDifferentCollateral = 'RefinanceDifCol', - RefinanceNoDebt = 'RefinanceNoDebt', - RefinanceNoDebtDifferentCollateral = 'RefNoDebtDifCol', } export enum SimulationSteps { @@ -25,6 +20,7 @@ export enum SimulationSteps { Import = 'Import', NewPositionEvent = 'NewPositionEvent', OpenPosition = 'OpenPosition', + Skipped = 'Skipped', } export enum FlashloanProvider { @@ -36,11 +32,3 @@ export enum TokenTransferTargetType { StrategyExecutor = 0, PositionsManager = 1, } - -export type RefinanceSimulationTypes = - | SimulationType.Refinance - | SimulationType.RefinanceDifferentPair - | SimulationType.RefinanceDifferentCollateral - | SimulationType.RefinanceDifferentDebt - | SimulationType.RefinanceNoDebt - | SimulationType.RefinanceNoDebtDifferentCollateral diff --git a/sdk/sdk-common/src/simulation/Steps.ts b/sdk/sdk-common/src/simulation/Steps.ts index a0092b1e62..046d268403 100644 --- a/sdk/sdk-common/src/simulation/Steps.ts +++ b/sdk/sdk-common/src/simulation/Steps.ts @@ -8,6 +8,7 @@ import { IPrice } from '../common/interfaces/IPrice' import { IPosition } from '../common/interfaces/IPosition' import { IToken } from '../common/interfaces/IToken' import { ILendingPool } from '../protocols/interfaces/ILendingPool' +import { ProtocolName } from '../protocols' export interface Step { type: T @@ -60,6 +61,15 @@ export interface PaybackWithdrawStep } > {} +export interface SkippedStep + extends Step< + SimulationSteps.Skipped, + { + type: SimulationSteps + protocol?: ProtocolName + } + > {} + export interface SwapStep extends Step< SimulationSteps.Swap, @@ -124,3 +134,4 @@ export type Steps = | NewPositionEventStep | ImportStep | OpenPosition + | SkippedStep diff --git a/sdk/sdk-e2e/tests/refinance.test.ts b/sdk/sdk-e2e/tests/refinance.test.ts index 41aa6a2611..a3b08dfedf 100644 --- a/sdk/sdk-e2e/tests/refinance.test.ts +++ b/sdk/sdk-e2e/tests/refinance.test.ts @@ -11,13 +11,13 @@ import { import { ProtocolName, isLendingPool } from '@summerfi/sdk-common/protocols' import { ProtocolClient, makeSDK, type Chain, type User } from '@summerfi/sdk-client' import { PositionsManager, IRefinanceParameters, Order } from '@summerfi/sdk-common/orders' -import { ISimulation } from '@summerfi/sdk-common/simulation' +import { ISimulation, SimulationType } from '@summerfi/sdk-common/simulation' import { TransactionUtils } from './utils/TransactionUtils' import { Hex } from 'viem' import assert from 'assert' import { EmodeType } from '@summerfi/protocol-plugins/plugins/common' -import { AddressValue, CommonTokenSymbols, RefinanceSimulationTypes } from '@summerfi/sdk-common' +import { AddressValue, CommonTokenSymbols } from '@summerfi/sdk-common' import { SparkLendingPoolId, isSparkLendingPoolId, @@ -176,7 +176,7 @@ describe.skip('Refinance All | SDK', () => { assert(false, 'Spark pool type is not lending') } - const refinanceSimulation: ISimulation = + const refinanceSimulation: ISimulation = await sdk.simulator.refinance.simulateRefinancePosition({ sourcePosition: makerPosition, targetPool: sparkPool, diff --git a/sdk/sdk-e2e/tests/refinanceAaveV3SparkAnyPair.test.ts b/sdk/sdk-e2e/tests/refinanceAaveV3SparkAnyPair.test.ts index 40a9d85d3b..1cee33c628 100644 --- a/sdk/sdk-e2e/tests/refinanceAaveV3SparkAnyPair.test.ts +++ b/sdk/sdk-e2e/tests/refinanceAaveV3SparkAnyPair.test.ts @@ -4,7 +4,6 @@ import { EmodeType } from '@summerfi/protocol-plugins/plugins/common' import { AddressValue, CommonTokenSymbols, - RefinanceSimulationTypes, ISimulation, Percentage, TokenAmount, @@ -13,6 +12,7 @@ import { ChainFamilyMap, PositionType, IToken, + SimulationType, } from '@summerfi/sdk-common' import { PositionsManager, Order, RefinanceParameters } from '@summerfi/sdk-common/orders' import { @@ -37,13 +37,13 @@ jest.setTimeout(300000) /** TEST CONFIG */ const config = { SDKAPiUrl: 'https://zmjmtfsocb.execute-api.us-east-1.amazonaws.com/api/sdk', - TenderlyForkUrl: 'https://virtual.mainnet.rpc.tenderly.co/cc7432cd-f037-4aa8-a05f-ae6d8cefba39', + TenderlyForkUrl: 'https://virtual.mainnet.rpc.tenderly.co/5eea57de-3dc2-4cae-b7ed-24b16b0cbde0', DPMAddress: '0x551eb8395093fde4b9eef017c93593a3c7a75138', walletAddress: '0xbEf4befb4F230F43905313077e3824d7386E09F8', collateralTokenSymbol: CommonTokenSymbols.WETH, collateralAmount: '0.0198', debtTokenSymbol: CommonTokenSymbols.DAI, - debtAmount: '26', + debtAmount: '34', sendTransactionEnabled: true, } @@ -166,7 +166,7 @@ describe.skip('Refinance AaveV3 Spark | SDK', () => { slippage: Percentage.createFrom({ value: 0.2 }), }) - const refinanceSimulation: ISimulation = + const refinanceSimulation: ISimulation = await sdk.simulator.refinance.simulateRefinancePosition(refinanceParameters) expect(refinanceSimulation).toBeDefined() @@ -181,10 +181,11 @@ describe.skip('Refinance AaveV3 Spark | SDK', () => { assert(refinanceOrder, 'Order not found') - // Send transaction - console.log('Sending transaction...') - + console.log('Order:', JSON.stringify(refinanceOrder, null, 2)) if (config.sendTransactionEnabled) { + // Send transaction + console.log('Sending transaction...') + const privateKey = process.env.DEPLOYER_PRIVATE_KEY as Hex const transactionUtils = new TransactionUtils({ rpcUrl: config.TenderlyForkUrl, diff --git a/sdk/sdk-e2e/tests/refinanceMakerSparkAlreadyImported.test.ts b/sdk/sdk-e2e/tests/refinanceMakerSparkAlreadyImported.test.ts index d9d551f404..2c265eaa7b 100644 --- a/sdk/sdk-e2e/tests/refinanceMakerSparkAlreadyImported.test.ts +++ b/sdk/sdk-e2e/tests/refinanceMakerSparkAlreadyImported.test.ts @@ -14,7 +14,7 @@ import { ProtocolName } from '@summerfi/sdk-common/protocols' import { makeSDK, type Chain, type User, ProtocolClient } from '@summerfi/sdk-client' import { CommonTokenSymbols } from '@summerfi/sdk-common/common/enums' import { PositionsManager, Order, RefinanceParameters } from '@summerfi/sdk-common/orders' -import { ISimulation, RefinanceSimulationTypes } from '@summerfi/sdk-common/simulation' +import { ISimulation, SimulationType } from '@summerfi/sdk-common/simulation' import { TransactionUtils } from './utils/TransactionUtils' import { decodeActionCalldata, @@ -187,7 +187,7 @@ describe.skip('Refinance Maker Spark | SDK', () => { slippage: Percentage.createFrom({ value: 0.2 }), }) - const refinanceSimulation: ISimulation = + const refinanceSimulation: ISimulation = await sdk.simulator.refinance.simulateRefinancePosition(refinanceParameters) expect(refinanceSimulation).toBeDefined() diff --git a/sdk/sdk-e2e/tests/refinanceMakerSparkAnyPair.test.ts b/sdk/sdk-e2e/tests/refinanceMakerSparkAnyPair.test.ts index 579a6d4478..7abb09fe87 100644 --- a/sdk/sdk-e2e/tests/refinanceMakerSparkAnyPair.test.ts +++ b/sdk/sdk-e2e/tests/refinanceMakerSparkAnyPair.test.ts @@ -11,13 +11,13 @@ import { import { ProtocolName, isLendingPool } from '@summerfi/sdk-common/protocols' import { ProtocolClient, makeSDK, type Chain, type User } from '@summerfi/sdk-client' import { PositionsManager, Order, RefinanceParameters } from '@summerfi/sdk-common/orders' -import { ISimulation } from '@summerfi/sdk-common/simulation' +import { ISimulation, SimulationType } from '@summerfi/sdk-common/simulation' import { TransactionUtils } from './utils/TransactionUtils' import { Hex } from 'viem' import assert from 'assert' import { EmodeType } from '@summerfi/protocol-plugins/plugins/common' -import { AddressValue, CommonTokenSymbols, RefinanceSimulationTypes } from '@summerfi/sdk-common' +import { AddressValue, CommonTokenSymbols } from '@summerfi/sdk-common' import { SparkLendingPoolId, isSparkLendingPoolId, @@ -37,12 +37,13 @@ jest.setTimeout(300000) /** TEST CONFIG */ const config = { SDKAPiUrl: 'https://zmjmtfsocb.execute-api.us-east-1.amazonaws.com/api/sdk', - TenderlyForkUrl: 'https://virtual.mainnet.rpc.tenderly.co/4711dc9f-76a4-4f6c-9464-6f8c7369df61', - makerVaultId: '31709', - DPMAddress: '0xc1475b2735fb9130a4701ee9e2215b6305dd501b', - walletAddress: '0xbEf4befb4F230F43905313077e3824d7386E09F8', - collateralAmount: '5000.0', - debtAmount: '5000000.0', + TenderlyForkUrl: 'https://virtual.mainnet.rpc.tenderly.co/5eea57de-3dc2-4cae-b7ed-24b16b0cbde0', + makerVaultId: '31722', + DPMAddress: '0x2e0515d7A3eA0276F28c94C426c5d2D1d85FD4d5', + walletAddress: '0xDDc68f9dE415ba2fE2FD84bc62Be2d2CFF1098dA', + collateralAmount: '2.5', + debtAmount: '3501.0', + sendTransaction: true, } describe.skip('Refinance Maker Spark | SDK', () => { @@ -133,7 +134,7 @@ describe.skip('Refinance Maker Spark | SDK', () => { // Source position const makerPosition: MakerPosition = MakerPosition.createFrom({ type: PositionType.Multiply, - id: MakerPositionId.createFrom({ id: '31697', vaultId: '31697' }), + id: MakerPositionId.createFrom({ id: config.makerVaultId, vaultId: config.makerVaultId }), debtAmount: TokenAmount.createFrom({ token: DAI, amount: config.debtAmount, @@ -182,7 +183,7 @@ describe.skip('Refinance Maker Spark | SDK', () => { slippage: Percentage.createFrom({ value: 0.2 }), }) - const refinanceSimulation: ISimulation = + const refinanceSimulation: ISimulation = await sdk.simulator.refinance.simulateRefinancePosition(refinanceParameters) expect(refinanceSimulation).toBeDefined() @@ -197,19 +198,21 @@ describe.skip('Refinance Maker Spark | SDK', () => { assert(refinanceOrder, 'Order not found') - // Send transaction - console.log('Sending transaction...') + if (config.sendTransaction) { + // Send transaction + console.log('Sending transaction...') - const privateKey = process.env.DEPLOYER_PRIVATE_KEY as Hex - const transactionUtils = new TransactionUtils({ - rpcUrl: config.TenderlyForkUrl, - walletPrivateKey: privateKey, - }) + const privateKey = process.env.DEPLOYER_PRIVATE_KEY as Hex + const transactionUtils = new TransactionUtils({ + rpcUrl: config.TenderlyForkUrl, + walletPrivateKey: privateKey, + }) - const receipt = await transactionUtils.sendTransaction({ - transaction: refinanceOrder.transactions[0].transaction, - }) + const receipt = await transactionUtils.sendTransaction({ + transaction: refinanceOrder.transactions[0].transaction, + }) - console.log('Transaction sent:', receipt) + console.log('Transaction sent:', receipt) + } }) }) diff --git a/sdk/sdk-e2e/tests/refinanceMorphoSparkAnyPair.test.ts b/sdk/sdk-e2e/tests/refinanceMorphoSparkAnyPair.test.ts index f45914dcde..3dbbe93b66 100644 --- a/sdk/sdk-e2e/tests/refinanceMorphoSparkAnyPair.test.ts +++ b/sdk/sdk-e2e/tests/refinanceMorphoSparkAnyPair.test.ts @@ -4,7 +4,6 @@ import { EmodeType } from '@summerfi/protocol-plugins/plugins/common' import { AddressValue, CommonTokenSymbols, - RefinanceSimulationTypes, ISimulation, Percentage, TokenAmount, @@ -13,6 +12,7 @@ import { ChainFamilyMap, PositionType, IToken, + SimulationType, } from '@summerfi/sdk-common' import { PositionsManager, Order, RefinanceParameters } from '@summerfi/sdk-common/orders' import { @@ -164,7 +164,7 @@ describe.skip('Refinance Morpho Spark | SDK', () => { slippage: Percentage.createFrom({ value: 0.2 }), }) - const refinanceSimulation: ISimulation = + const refinanceSimulation: ISimulation = await sdk.simulator.refinance.simulateRefinancePosition(refinanceParameters) expect(refinanceSimulation).toBeDefined() diff --git a/sdk/sdk-server/src/handlers/getRefinanceSimulation.ts b/sdk/sdk-server/src/handlers/getRefinanceSimulation.ts index fac12c1ab8..1a67ec2800 100644 --- a/sdk/sdk-server/src/handlers/getRefinanceSimulation.ts +++ b/sdk/sdk-server/src/handlers/getRefinanceSimulation.ts @@ -1,22 +1,19 @@ -import type { ISimulation, RefinanceSimulationTypes } from '@summerfi/sdk-common/simulation' -import { refinanceStrategyRouter } from '@summerfi/simulator-service/strategies' +import type { ISimulation, SimulationType } from '@summerfi/sdk-common/simulation' +import { refinanceLendingToLending } from '@summerfi/simulator-service/strategies' import { publicProcedure } from '../TRPC' import { isRefinanceParameters } from '@summerfi/sdk-common/orders' import { z } from 'zod' export const getRefinanceSimulation = publicProcedure .input(z.any()) - .query(async (opts): Promise> => { + .query(async (opts): Promise> => { if (!isRefinanceParameters(opts.input)) { throw new Error('Invalid refinance parameters') } - return refinanceStrategyRouter({ - refinanceParameters: opts.input, - refinanceDependencies: { - swapManager: opts.ctx.swapManager, - oracleManager: opts.ctx.oracleManager, - protocolManager: opts.ctx.protocolManager, - }, + return refinanceLendingToLending(opts.input, { + swapManager: opts.ctx.swapManager, + oracleManager: opts.ctx.oracleManager, + protocolManager: opts.ctx.protocolManager, }) }) diff --git a/sdk/simulator-service/src/implementation/simulator-engine/reducer/skippedStepReducer.ts b/sdk/simulator-service/src/implementation/simulator-engine/reducer/skippedStepReducer.ts new file mode 100644 index 0000000000..a8f97ddaac --- /dev/null +++ b/sdk/simulator-service/src/implementation/simulator-engine/reducer/skippedStepReducer.ts @@ -0,0 +1,12 @@ +import { steps } from '@summerfi/sdk-common/simulation' +import { ISimulationState } from '../../../interfaces/simulation' + +export function skippedStepReducer( + step: steps.SkippedStep, + state: ISimulationState, +): ISimulationState { + return { + ...state, + steps: [...state.steps, step], + } +} diff --git a/sdk/simulator-service/src/implementation/simulator-engine/reducer/stateReducers.ts b/sdk/simulator-service/src/implementation/simulator-engine/reducer/stateReducers.ts index daef596a5a..6baed637f0 100644 --- a/sdk/simulator-service/src/implementation/simulator-engine/reducer/stateReducers.ts +++ b/sdk/simulator-service/src/implementation/simulator-engine/reducer/stateReducers.ts @@ -11,6 +11,7 @@ import { pullTokenReducer } from './pullTokenReducer' import { importReducer } from './importReducer' import { newPositionEventReducer } from './newPositionEventReducer' import { openPositionReducer } from './openPositionReducer' +import { skippedStepReducer } from './skippedStepReducer' const stateReducers: StateReducers = { [SimulationSteps.Flashloan]: flashloanReducer, @@ -23,6 +24,7 @@ const stateReducers: StateReducers = { [SimulationSteps.Import]: importReducer, [SimulationSteps.NewPositionEvent]: newPositionEventReducer, [SimulationSteps.OpenPosition]: openPositionReducer, + [SimulationSteps.Skipped]: skippedStepReducer, } export function stateReducer(step: steps.Steps, state: ISimulationState): ISimulationState { diff --git a/sdk/simulator-service/src/implementation/simulator-engine/simulator.ts b/sdk/simulator-service/src/implementation/simulator-engine/simulator.ts index 74899968d5..e3a6900615 100644 --- a/sdk/simulator-service/src/implementation/simulator-engine/simulator.ts +++ b/sdk/simulator-service/src/implementation/simulator-engine/simulator.ts @@ -5,7 +5,7 @@ import { processStepOutput } from './stepProcessor/stepOutputProcessors' import { stateReducer } from './reducer/stateReducers' import type { SimulationStrategy } from '@summerfi/sdk-common/simulation' import { steps } from '@summerfi/sdk-common/simulation' -import { Maybe } from '@summerfi/sdk-common' +import { Maybe, ProtocolName, SimulationSteps } from '@summerfi/sdk-common' import { GetReferencedValue, NextFunction, @@ -83,24 +83,31 @@ export class Simulator, - skip?: boolean, + skipData?: { skip: boolean; type: SimulationSteps; protocol?: ProtocolName }, ): Simulator, [...AddedSteps, ProccessedStep]> { const schemaHead = head(this.schema) const schemaTail = tail(this.schema) - const nextArray = [...this.nextArray, next] - if (skip) { + if (skipData && skipData.skip) { if (schemaHead.optional === false) { throw new Error(`Step is required: ${schemaHead.step}`) } + const skippedNext = [ + ...this.nextArray, + async () => ({ + type: SimulationSteps.Skipped, + inputs: skipData, + }), + ] + return new Simulator, [...AddedSteps, ProccessedStep]>( schemaTail, this.originalSchema, this.state, // TODO: We should not use any here /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - this.nextArray as any, + skippedNext as any, ) } @@ -108,6 +115,8 @@ export class Simulator, [...AddedSteps, ProccessedStep]>( schemaTail, this.originalSchema, diff --git a/sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/skippedStepOutputProcessor.ts b/sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/skippedStepOutputProcessor.ts new file mode 100644 index 0000000000..5b3e859f6c --- /dev/null +++ b/sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/skippedStepOutputProcessor.ts @@ -0,0 +1,9 @@ +import { steps } from '@summerfi/sdk-common/simulation' +import type { StepOutputProcessor } from '../../../interfaces/steps' + +export const skippedStepOutputProcessor: StepOutputProcessor = async (step) => { + return { + ...step, + outputs: undefined, + } +} diff --git a/sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/stepOutputProcessors.ts b/sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/stepOutputProcessors.ts index 7f175ced45..66f3898969 100644 --- a/sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/stepOutputProcessors.ts +++ b/sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/stepOutputProcessors.ts @@ -14,6 +14,7 @@ import { repayFlashloanOutputProcessor } from './repayFlashloanOutputProcessor' import { importPositionProcessor } from './importPositionProcessor' import { newPositionEventProcessor } from './newPositionEvent' import { openPositionProcessor } from './openPositionProcessor' +import { skippedStepOutputProcessor } from './skippedStepOutputProcessor' const stepOutputProcessors: StepOutputProcessors = { [SimulationSteps.Flashloan]: flashloanOutputProcessor, @@ -26,6 +27,7 @@ const stepOutputProcessors: StepOutputProcessors = { [SimulationSteps.Import]: importPositionProcessor, [SimulationSteps.NewPositionEvent]: newPositionEventProcessor, [SimulationSteps.OpenPosition]: openPositionProcessor, + [SimulationSteps.Skipped]: skippedStepOutputProcessor, } export async function processStepOutput(step: StepsWithoutOutputs): Promise { diff --git a/sdk/simulator-service/src/implementation/utils/GetRefinanceSimulationType.ts b/sdk/simulator-service/src/implementation/utils/GetRefinanceSimulationType.ts deleted file mode 100644 index 1f4ba198e9..0000000000 --- a/sdk/simulator-service/src/implementation/utils/GetRefinanceSimulationType.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { RefinanceSimulationTypes, SimulationType } from '@summerfi/sdk-common/simulation' - -export function getRefinanceSimulationType( - hasCollateralSwap: boolean, - hasDebtSwap: boolean, -): RefinanceSimulationTypes { - if (hasCollateralSwap && hasDebtSwap) { - return SimulationType.RefinanceDifferentPair - } - - if (hasCollateralSwap) { - return SimulationType.RefinanceDifferentCollateral - } - - if (hasDebtSwap) { - return SimulationType.RefinanceDifferentDebt - } - - return SimulationType.Refinance -} diff --git a/sdk/simulator-service/src/strategies/StrategyIndex.ts b/sdk/simulator-service/src/strategies/StrategyIndex.ts index 6b2369429a..b020a38f1c 100644 --- a/sdk/simulator-service/src/strategies/StrategyIndex.ts +++ b/sdk/simulator-service/src/strategies/StrategyIndex.ts @@ -1,12 +1,6 @@ -import { refinanceLendingToLendingSamePairStrategy } from './refinanceSamePair/Strategy' -import { refinanceLendingToLendingAnyPairStrategy } from './refinanceAnyPair/Strategy' -import { refinanceLendingToLendingNoDebtStrategy } from './refinanceNoDebt/Strategy' +import { refinanceLendingToLending } from './refinanceLendingToLending/RefinanceLendingToLendingAnyPair' /** * List of all strategies so the strategy definition generation tool can use them */ -export const StrategyIndex = [ - refinanceLendingToLendingSamePairStrategy, - refinanceLendingToLendingAnyPairStrategy, - refinanceLendingToLendingNoDebtStrategy, -] +export const StrategyIndex = [refinanceLendingToLending] diff --git a/sdk/simulator-service/src/strategies/common/RefinanceStrategyRouter.ts b/sdk/simulator-service/src/strategies/common/RefinanceStrategyRouter.ts deleted file mode 100644 index c13bcd9d20..0000000000 --- a/sdk/simulator-service/src/strategies/common/RefinanceStrategyRouter.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { IRefinanceParameters } from '@summerfi/sdk-common/orders' -import { refinanceLendingToLendingAnyPair } from '../refinanceAnyPair/RefinanceLendingToLendingAnyPair' -import { refinanceLendingToLendingNoDebt } from '../refinanceNoDebt/RefinanceLendingToLendingNoDebt' -import { refinanceLendingToLendingSamePair } from '../refinanceSamePair/RefinanceLendingToLendingSamePair' -import { ISwapManager } from '@summerfi/swap-common/interfaces' -import { IOracleManager } from '@summerfi/oracle-common' -import { IProtocolManager } from '@summerfi/protocol-manager-common' - -function isToSamePair(parameters: IRefinanceParameters): boolean { - const { sourcePosition, targetPool } = parameters - - return ( - sourcePosition.debtAmount.token.equals(targetPool.debtToken) && - sourcePosition.collateralAmount.token.equals(targetPool.collateralToken) - ) -} - -/** - * Choses the correct refinance strategy based on the parameters - * @param refinanceParameters Parameters for the refinance simulation - * @param refinanceDependencies Dependencies for the simulation - * @returns The simulation result - */ -export function refinanceStrategyRouter(params: { - refinanceParameters: IRefinanceParameters - refinanceDependencies: { - swapManager: ISwapManager - oracleManager: IOracleManager - protocolManager: IProtocolManager - } -}) { - if (params.refinanceParameters.sourcePosition.debtAmount.amount === '0') { - return refinanceLendingToLendingNoDebt(params.refinanceParameters, params.refinanceDependencies) - } - - // TODO: in the end we should use just any pair - if (isToSamePair(params.refinanceParameters)) { - return refinanceLendingToLendingSamePair( - params.refinanceParameters, - params.refinanceDependencies, - ) - } - - return refinanceLendingToLendingAnyPair(params.refinanceParameters, params.refinanceDependencies) -} diff --git a/sdk/simulator-service/src/strategies/common/index.ts b/sdk/simulator-service/src/strategies/common/index.ts index f85330ef32..cf701220bd 100644 --- a/sdk/simulator-service/src/strategies/common/index.ts +++ b/sdk/simulator-service/src/strategies/common/index.ts @@ -1,2 +1 @@ export * from './Types' -export * from './RefinanceStrategyRouter' diff --git a/sdk/simulator-service/src/strategies/index.ts b/sdk/simulator-service/src/strategies/index.ts index 31de16f64e..c7990e6a82 100644 --- a/sdk/simulator-service/src/strategies/index.ts +++ b/sdk/simulator-service/src/strategies/index.ts @@ -1,5 +1,3 @@ -export * from './refinanceSamePair' -export * from './refinanceAnyPair' -export * from './refinanceNoDebt' +export * from './refinanceLendingToLending' export * from './common' export * from './import' diff --git a/sdk/simulator-service/src/strategies/refinanceAnyPair/RefinanceLendingToLendingAnyPair.ts b/sdk/simulator-service/src/strategies/refinanceLendingToLending/RefinanceLendingToLendingAnyPair.ts similarity index 71% rename from sdk/simulator-service/src/strategies/refinanceAnyPair/RefinanceLendingToLendingAnyPair.ts rename to sdk/simulator-service/src/strategies/refinanceLendingToLending/RefinanceLendingToLendingAnyPair.ts index 752d6f866c..30ef7f6ab7 100644 --- a/sdk/simulator-service/src/strategies/refinanceAnyPair/RefinanceLendingToLendingAnyPair.ts +++ b/sdk/simulator-service/src/strategies/refinanceLendingToLending/RefinanceLendingToLendingAnyPair.ts @@ -1,8 +1,8 @@ import { FlashloanProvider, ISimulation, - RefinanceSimulationTypes, SimulationSteps, + SimulationType, TokenTransferTargetType, getValueFromReference, } from '@summerfi/sdk-common/simulation' @@ -13,13 +13,12 @@ import { isLendingPool } from '@summerfi/sdk-common/protocols' import { refinanceLendingToLendingAnyPairStrategy } from './Strategy' import { type IRefinanceDependencies } from '../common/Types' import { getSwapStepData } from '../../implementation/utils/GetSwapStepData' -import { getRefinanceSimulationType } from '../../implementation/utils/GetRefinanceSimulationType' import { estimateSwapFromAmount } from '../../implementation/utils/EstimateSwapFromAmount' -export async function refinanceLendingToLendingAnyPair( +export async function refinanceLendingToLending( args: IRefinanceParameters, dependencies: IRefinanceDependencies, -): Promise> { +): Promise> { // args validation if (!isLendingPool(args.sourcePosition.pool)) { throw new Error('Source pool is not a lending pool') @@ -46,27 +45,36 @@ export async function refinanceLendingToLendingAnyPair( const isCollateralSwapSkipped = targetPool.collateralToken.equals(sourcePool.collateralToken) const isDebtSwapSkipped = targetPool.debtToken.equals(sourcePool.debtToken) + const isDebtAmountZero = position.debtAmount.toBaseUnit() === '0' + + const maxDebtAmount = TokenAmount.createFrom({ + token: position.debtAmount.token, + amount: Number.MAX_SAFE_INTEGER.toString(), + }) const simulation = await simulator - .next(async () => ({ - name: 'Flashloan', - type: SimulationSteps.Flashloan, - inputs: { - amount: flashloanAmount, - provider: - flashloanAmount.token.symbol === CommonTokenSymbols.DAI - ? FlashloanProvider.Maker - : FlashloanProvider.Balancer, + .next( + async () => ({ + name: 'Flashloan', + type: SimulationSteps.Flashloan, + inputs: { + amount: flashloanAmount, + provider: + flashloanAmount.token.symbol === CommonTokenSymbols.DAI + ? FlashloanProvider.Maker + : FlashloanProvider.Balancer, + }, + }), + { + skip: isDebtAmountZero, + type: SimulationSteps.Flashloan, }, - })) + ) .next(async () => ({ name: 'PaybackWithdrawFromSourcePosition', type: SimulationSteps.PaybackWithdraw, inputs: { - paybackAmount: TokenAmount.createFrom({ - amount: Number.MAX_SAFE_INTEGER.toString(), - token: position.debtAmount.token, - }), + paybackAmount: isDebtAmountZero ? position.debtAmount : maxDebtAmount, withdrawAmount: position.collateralAmount, position: position, withdrawTargetType: TokenTransferTargetType.PositionsManager, @@ -85,7 +93,10 @@ export async function refinanceLendingToLendingAnyPair( oracleManager: dependencies.oracleManager, }), }), - isCollateralSwapSkipped, + { + skip: isCollateralSwapSkipped, + type: SimulationSteps.Swap, + }, ) .next(async () => ({ name: 'OpenTargetPosition', @@ -98,7 +109,9 @@ export async function refinanceLendingToLendingAnyPair( name: 'DepositBorrowToTargetPosition', type: SimulationSteps.DepositBorrow, inputs: { - // refactor + depositAmount: isCollateralSwapSkipped + ? position.collateralAmount + : ctx.getReference(['SwapCollateralFromSourcePosition', 'received']), borrowAmount: isDebtSwapSkipped ? position.debtAmount : await estimateSwapFromAmount({ @@ -108,9 +121,7 @@ export async function refinanceLendingToLendingAnyPair( swapManager: dependencies.swapManager, oracleManager: dependencies.oracleManager, }), - depositAmount: isCollateralSwapSkipped - ? position.collateralAmount - : ctx.getReference(['SwapCollateralFromSourcePosition', 'received']), + position: getValueFromReference(ctx.getReference(['OpenTargetPosition', 'position'])), borrowTargetType: TokenTransferTargetType.PositionsManager, }, @@ -130,30 +141,44 @@ export async function refinanceLendingToLendingAnyPair( oracleManager: dependencies.oracleManager, }), }), - isDebtSwapSkipped, + { + skip: isDebtSwapSkipped, + type: SimulationSteps.Swap, + }, ) - .next(async () => ({ - name: 'RepayFlashloan', - type: SimulationSteps.RepayFlashloan, - inputs: { - amount: flashloanAmount, + .next( + async () => ({ + name: 'RepayFlashloan', + type: SimulationSteps.RepayFlashloan, + inputs: { + amount: flashloanAmount, + }, + }), + { + skip: isDebtAmountZero, + type: SimulationSteps.RepayFlashloan, }, - })) - .next(async () => ({ - name: 'ReturnFunds', - type: SimulationSteps.ReturnFunds, - inputs: { - /* - * We swap back to the original position's debt in order to repay the flashloan. - * Therefore, the dust amount will be in the original position's debt - * */ - token: position.debtAmount.token, + ) + .next( + async () => ({ + name: 'ReturnFunds', + type: SimulationSteps.ReturnFunds, + inputs: { + /* + * We swap back to the original position's debt in order to repay the flashloan. + * Therefore, the dust amount will be in the original position's debt + * */ + token: position.debtAmount.token, + }, + }), + { + skip: isDebtAmountZero || isDebtSwapSkipped, + type: SimulationSteps.ReturnFunds, }, - })) + ) .next(async (ctx) => { - // TODO: we should have a way to get the target position more easily and realiably, - const targetPosition = Object.values(ctx.state.positions).find((p) => - p.pool.id.protocol.equals(targetPool.id.protocol), + const targetPosition = getValueFromReference( + ctx.getReference(['OpenTargetPosition', 'position']), ) if (!targetPosition) { throw new Error('Target position not found') @@ -181,10 +206,10 @@ export async function refinanceLendingToLendingAnyPair( } return { - simulationType: getRefinanceSimulationType(!isCollateralSwapSkipped, !isDebtSwapSkipped), + simulationType: SimulationType.Refinance, sourcePosition: position, - targetPosition, + targetPosition: targetPosition, swaps: simulation.swaps, steps: simulation.steps, - } satisfies ISimulation + } satisfies ISimulation } diff --git a/sdk/simulator-service/src/strategies/refinanceAnyPair/Strategy.ts b/sdk/simulator-service/src/strategies/refinanceLendingToLending/Strategy.ts similarity index 100% rename from sdk/simulator-service/src/strategies/refinanceAnyPair/Strategy.ts rename to sdk/simulator-service/src/strategies/refinanceLendingToLending/Strategy.ts diff --git a/sdk/simulator-service/src/strategies/refinanceAnyPair/index.ts b/sdk/simulator-service/src/strategies/refinanceLendingToLending/index.ts similarity index 100% rename from sdk/simulator-service/src/strategies/refinanceAnyPair/index.ts rename to sdk/simulator-service/src/strategies/refinanceLendingToLending/index.ts diff --git a/sdk/simulator-service/src/strategies/refinanceNoDebt/RefinanceLendingToLendingNoDebt.ts b/sdk/simulator-service/src/strategies/refinanceNoDebt/RefinanceLendingToLendingNoDebt.ts deleted file mode 100644 index d56c51a195..0000000000 --- a/sdk/simulator-service/src/strategies/refinanceNoDebt/RefinanceLendingToLendingNoDebt.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { - ISimulation, - SimulationSteps, - SimulationType, - TokenTransferTargetType, - getValueFromReference, -} from '@summerfi/sdk-common/simulation' -import { Simulator } from '../../implementation/simulator-engine' -import { Percentage, TokenAmount } from '@summerfi/sdk-common/common' -import { IRefinanceParameters } from '@summerfi/sdk-common/orders' -import { isLendingPool } from '@summerfi/sdk-common/protocols' -import { refinanceLendingToLendingNoDebtStrategy } from './Strategy' -import { type IRefinanceDependencies } from '../common/Types' -import { getSwapStepData } from '../../implementation/utils/GetSwapStepData' - -export async function refinanceLendingToLendingNoDebt( - args: IRefinanceParameters, - dependencies: IRefinanceDependencies, -): Promise< - ISimulation -> { - // args validation - if (!isLendingPool(args.sourcePosition.pool)) { - throw new Error('Source pool is not a lending pool') - } - if (!isLendingPool(args.targetPool)) { - throw new Error('Target pool is not a lending pool') - } - - const position = args.sourcePosition - const sourcePool = args.sourcePosition.pool - const targetPool = args.targetPool - - if (!isLendingPool(targetPool)) { - throw new Error('Target pool is not a lending pool') - } - const simulator = Simulator.create(refinanceLendingToLendingNoDebtStrategy) - - const zeroAmount = TokenAmount.createFromBaseUnit({ - token: position.debtAmount.token, - amount: '0', - }) - - const isCollateralSwapSkipped = targetPool.collateralToken.equals(sourcePool.collateralToken) - - const simulation = await simulator - .next(async () => ({ - name: 'PaybackWithdrawFromSourcePosition', - type: SimulationSteps.PaybackWithdraw, - inputs: { - paybackAmount: zeroAmount, - withdrawAmount: position.collateralAmount, - position: position, - withdrawTargetType: TokenTransferTargetType.PositionsManager, - }, - })) - .next( - async () => ({ - name: 'SwapCollateralFromSourcePosition', - type: SimulationSteps.Swap, - inputs: await getSwapStepData({ - chainInfo: position.pool.id.protocol.chainInfo, - fromAmount: position.collateralAmount, - toToken: targetPool.collateralToken, - slippage: Percentage.createFrom({ value: args.slippage.value }), - swapManager: dependencies.swapManager, - oracleManager: dependencies.oracleManager, - }), - }), - isCollateralSwapSkipped, - ) - .next(async () => ({ - name: 'OpenTargetPosition', - type: SimulationSteps.OpenPosition, - inputs: { - pool: targetPool, - }, - })) - .next(async (ctx) => ({ - name: 'DepositBorrowToTargetPosition', - type: SimulationSteps.DepositBorrow, - inputs: { - depositAmount: isCollateralSwapSkipped - ? position.collateralAmount - : ctx.getReference(['SwapCollateralFromSourcePosition', 'received']), - borrowAmount: TokenAmount.createFrom({ - amount: '0', - token: targetPool.debtToken, - }), - position: getValueFromReference(ctx.getReference(['OpenTargetPosition', 'position'])), - borrowTargetType: TokenTransferTargetType.PositionsManager, - }, - })) - .next(async (ctx) => { - const targetPosition = getValueFromReference( - ctx.getReference(['OpenTargetPosition', 'position']), - ) - if (!targetPosition) { - throw new Error('Target position not found') - } - - return { - name: 'NewPositionEvent', - type: SimulationSteps.NewPositionEvent, - inputs: { - position: targetPosition, - }, - } - }) - .run() - - const targetPositionId = getValueFromReference( - simulation.getReference(['OpenTargetPosition', 'position']), - ) - const targetPosition = Object.values(simulation.positions).find( - (p) => p.id.id === targetPositionId.id.id, - ) - - if (!targetPosition) { - throw new Error('Target position not found') - } - - return { - simulationType: isCollateralSwapSkipped - ? SimulationType.RefinanceNoDebt - : SimulationType.RefinanceNoDebtDifferentCollateral, - sourcePosition: position, - targetPosition, - swaps: Object.values(simulation.swaps), - steps: Object.values(simulation.steps), - } -} diff --git a/sdk/simulator-service/src/strategies/refinanceNoDebt/Strategy.ts b/sdk/simulator-service/src/strategies/refinanceNoDebt/Strategy.ts deleted file mode 100644 index b95a1fe56e..0000000000 --- a/sdk/simulator-service/src/strategies/refinanceNoDebt/Strategy.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { SimulationSteps } from '@summerfi/sdk-common/simulation' -import { makeStrategy } from '../../implementation/utils' - -export const refinanceLendingToLendingNoDebtStrategy = makeStrategy([ - { - name: 'PaybackWithdrawFromSourcePosition', - step: SimulationSteps.PaybackWithdraw, - optional: false, - }, - { - name: 'SwapCollateralFromSourcePosition', - step: SimulationSteps.Swap, - optional: true, - }, - { - name: 'OpenTargetPosition', - step: SimulationSteps.OpenPosition, - optional: false, - }, - { - name: 'DepositBorrowToTargetPosition', - step: SimulationSteps.DepositBorrow, - optional: false, - }, - { - name: 'NewPositionEvent', - step: SimulationSteps.NewPositionEvent, - optional: false, - }, -] as const) diff --git a/sdk/simulator-service/src/strategies/refinanceNoDebt/index.ts b/sdk/simulator-service/src/strategies/refinanceNoDebt/index.ts deleted file mode 100644 index cd0d1e4d72..0000000000 --- a/sdk/simulator-service/src/strategies/refinanceNoDebt/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './RefinanceLendingToLendingNoDebt' -export * from './Strategy' diff --git a/sdk/simulator-service/src/strategies/refinanceSamePair/RefinanceLendingToLendingSamePair.ts b/sdk/simulator-service/src/strategies/refinanceSamePair/RefinanceLendingToLendingSamePair.ts deleted file mode 100644 index 1f32eef744..0000000000 --- a/sdk/simulator-service/src/strategies/refinanceSamePair/RefinanceLendingToLendingSamePair.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { - FlashloanProvider, - ISimulation, - SimulationSteps, - SimulationType, - TokenTransferTargetType, - getValueFromReference, -} from '@summerfi/sdk-common/simulation' -import { Simulator } from '../../implementation/simulator-engine' -import { TokenAmount } from '@summerfi/sdk-common/common' -import { IRefinanceParameters } from '@summerfi/sdk-common/orders' -import { isLendingPool } from '@summerfi/sdk-common/protocols' -import { refinanceLendingToLendingSamePairStrategy } from './Strategy' -import { type IRefinanceDependencies } from '../common/Types' - -export async function refinanceLendingToLendingSamePair( - args: IRefinanceParameters, - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - dependencies: IRefinanceDependencies, -): Promise> { - // args validation - if (!isLendingPool(args.sourcePosition.pool)) { - throw new Error('Source pool is not a lending pool') - } - if (!isLendingPool(args.targetPool)) { - throw new Error('Target pool is not a lending pool') - } - - const position = args.sourcePosition - const targetPool = args.targetPool - - if (!isLendingPool(targetPool)) { - throw new Error('Target pool is not a lending pool') - } - - const FLASHLOAN_MARGIN = 1.001 - const flashloanAmount = position.debtAmount.multiply(FLASHLOAN_MARGIN) - const simulator = Simulator.create(refinanceLendingToLendingSamePairStrategy) - - // TODO: read debt amount from chain (special step: ReadDebtAmount) - // TODO: the swap quote should also include the summer fee, in this case we need to know when we are taking the fee, - // before or after the swap, it influences actual call to oneInch api - const simulation = await simulator - .next(async () => ({ - name: 'Flashloan', - type: SimulationSteps.Flashloan, - inputs: { - amount: flashloanAmount, - provider: - flashloanAmount.token.symbol === 'DAI' - ? FlashloanProvider.Maker - : FlashloanProvider.Balancer, - }, - })) - .next(async () => ({ - name: 'PaybackWithdrawFromSourcePosition', - type: SimulationSteps.PaybackWithdraw, - inputs: { - paybackAmount: TokenAmount.createFrom({ - amount: Number.MAX_SAFE_INTEGER.toString(), - token: position.debtAmount.token, - }), - withdrawTargetType: TokenTransferTargetType.PositionsManager, - withdrawAmount: position.collateralAmount, - position: position, - }, - })) - .next(async () => ({ - name: 'OpenTargetPosition', - type: SimulationSteps.OpenPosition, - inputs: { - pool: targetPool, - }, - })) - .next(async (ctx) => ({ - name: 'DepositBorrowToTargetPosition', - type: SimulationSteps.DepositBorrow, - inputs: { - depositAmount: position.collateralAmount, - borrowAmount: position.debtAmount, // TODO figure the debt amount - position: getValueFromReference(ctx.getReference(['OpenTargetPosition', 'position'])), - borrowTargetType: TokenTransferTargetType.PositionsManager, - }, - })) - .next(async () => ({ - name: 'RepayFlashloan', - type: SimulationSteps.RepayFlashloan, - inputs: { - amount: flashloanAmount, - }, - })) - .next(async (ctx) => { - // TODO: we should have a way to get the target position more easily and realiably, - const targetPosition = Object.values(ctx.state.positions).find( - (p) => p.pool.id.protocol === targetPool.id.protocol, - ) - if (!targetPosition) { - throw new Error('Target position not found') - } - - return { - name: 'NewPositionEvent', - type: SimulationSteps.NewPositionEvent, - inputs: { - position: targetPosition, - }, - } - }) - .run() - - const targetPositionId = getValueFromReference( - simulation.getReference(['OpenTargetPosition', 'position']), - ) - const targetPosition = Object.values(simulation.positions).find( - (p) => p.id.id === targetPositionId.id.id, - ) - - if (!targetPosition) { - throw new Error('Target position not found') - } - - return { - simulationType: SimulationType.Refinance, - sourcePosition: position, - targetPosition, - swaps: Object.values(simulation.swaps), - steps: Object.values(simulation.steps), - } as ISimulation -} diff --git a/sdk/simulator-service/src/strategies/refinanceSamePair/Strategy.ts b/sdk/simulator-service/src/strategies/refinanceSamePair/Strategy.ts deleted file mode 100644 index 9645f4fb5a..0000000000 --- a/sdk/simulator-service/src/strategies/refinanceSamePair/Strategy.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { SimulationSteps } from '@summerfi/sdk-common/simulation' -import { makeStrategy } from '../../implementation/utils' - -export const refinanceLendingToLendingSamePairStrategy = makeStrategy([ - { - name: 'Flashloan', - step: SimulationSteps.Flashloan, - optional: false, - }, - { - name: 'PaybackWithdrawFromSourcePosition', - step: SimulationSteps.PaybackWithdraw, - optional: false, - }, - { - name: 'OpenTargetPosition', - step: SimulationSteps.OpenPosition, - optional: false, - }, - { - name: 'DepositBorrowToTargetPosition', - step: SimulationSteps.DepositBorrow, - optional: false, - }, - { - name: 'RepayFlashloan', - step: SimulationSteps.RepayFlashloan, - optional: false, - }, - { - name: 'NewPositionEvent', - step: SimulationSteps.NewPositionEvent, - optional: false, - }, -] as const) diff --git a/sdk/simulator-service/src/strategies/refinanceSamePair/index.ts b/sdk/simulator-service/src/strategies/refinanceSamePair/index.ts deleted file mode 100644 index df1f26236a..0000000000 --- a/sdk/simulator-service/src/strategies/refinanceSamePair/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './RefinanceLendingToLendingSamePair' -export * from './Strategy' diff --git a/sdk/simulator-service/tests/simulator.test.ts b/sdk/simulator-service/tests/simulator.test.ts index eb767a27bc..33cfb78e09 100644 --- a/sdk/simulator-service/tests/simulator.test.ts +++ b/sdk/simulator-service/tests/simulator.test.ts @@ -1,79 +1,19 @@ -import { ISimulation, SimulationSteps, steps } from '@summerfi/sdk-common/simulation' -import { - refinanceLendingToLendingAnyPair, - refinanceLendingToLendingSamePair, -} from '../src/strategies' +import { ISimulation, SimulationSteps, SimulationType } from '@summerfi/sdk-common/simulation' +import { refinanceLendingToLending } from '../src/strategies' import { Percentage } from '@summerfi/sdk-common/common' import { otherTestCollateral, otherTestDebt, testSourcePosition, - testTargetLendingPool, testTargetLendingPoolRequiredSwaps, } from './mocks/testSourcePosition' import { mockRefinanceContext, mockRefinanceContextRequiredSwaps } from './mocks/contextMock' -import assert from 'assert' -import { RefinanceSimulationTypes } from '@summerfi/sdk-common' describe('Refinance', () => { - describe('to the position with the same collateral and debt (no swaps)', () => { - let simulation: ISimulation - beforeAll(async () => { - simulation = await refinanceLendingToLendingSamePair( - { - sourcePosition: testSourcePosition, - targetPool: testTargetLendingPool, - slippage: Percentage.createFrom({ value: 1 }), - }, - mockRefinanceContext, - ) - }) - - it('should not include swap steps', async () => { - const steps = simulation.steps.filter((step) => !step.skip).map((step) => step.type) - - expect(steps).not.toContain(SimulationSteps.Swap) - }) - - it('should open position with the same collateral', async () => { - const targetPosition = simulation.targetPosition - - expect(targetPosition.collateralAmount).toEqual(testSourcePosition.collateralAmount) - }) - - it('should open position with the same debt', async () => { - const targetPosition = simulation.targetPosition - - expect(targetPosition.debtAmount).toEqual(testSourcePosition.debtAmount) - }) - - it('should open position as required target pool', async () => { - const targetPosition = simulation.targetPosition - - expect(targetPosition.pool).toEqual(testTargetLendingPool) - expect(targetPosition.id).toBeDefined() - }) - - it('should open position with id', async () => { - const targetPosition = simulation.targetPosition - - expect(targetPosition.id).toBeDefined() - }) - - it('should include a new position event step', async () => { - const newPositionStep = simulation.steps.find( - (step) => step.type === SimulationSteps.NewPositionEvent, - ) as steps.NewPositionEventStep - - assert(newPositionStep, 'New position event step not found') - expect(newPositionStep.inputs.position).toEqual(simulation.targetPosition) - }) - }) - describe('to the position with the different collateral and debt (with swaps)', () => { - let simulation: ISimulation + let simulation: ISimulation beforeAll(async () => { - simulation = await refinanceLendingToLendingAnyPair( + simulation = await refinanceLendingToLending( { sourcePosition: testSourcePosition, targetPool: testTargetLendingPoolRequiredSwaps, diff --git a/sdk/testing-utils/src/utils/StrategyExecutorDecoding.ts b/sdk/testing-utils/src/utils/StrategyExecutorDecoding.ts index 2d79e74a90..293dda7e25 100644 --- a/sdk/testing-utils/src/utils/StrategyExecutorDecoding.ts +++ b/sdk/testing-utils/src/utils/StrategyExecutorDecoding.ts @@ -2,10 +2,6 @@ import { ActionCall } from '@summerfi/protocol-plugins-common' import { HexData } from '@summerfi/sdk-common/common' import { decodeFunctionData, parseAbi } from 'viem' -export type SkippableActionCall = ActionCall & { - skipped: boolean -} - export function decodeStrategyExecutorCalldata(calldata: HexData | string): | { actionCalls: ActionCall[] @@ -26,13 +22,8 @@ export function decodeStrategyExecutorCalldata(calldata: HexData | string): return undefined } - const actionCalls: ActionCall[] = (decoded.args[0] as SkippableActionCall[]).map( - /* eslint-disable @typescript-eslint/no-unused-vars */ - ({ skipped, ...rest }) => rest, - ) - return { - actionCalls, + actionCalls: decoded.args[0] as ActionCall[], strategyName: decoded.args[1] as string, } } diff --git a/sdk/testing-utils/src/utils/index.ts b/sdk/testing-utils/src/utils/index.ts index 38ac213782..de3debca51 100644 --- a/sdk/testing-utils/src/utils/index.ts +++ b/sdk/testing-utils/src/utils/index.ts @@ -1,7 +1,4 @@ -export { decodeActionCalldata, getTargetHash } from './ActionDecoding' -export { getErrorMessage } from './ErrorMessage' -export { - type SkippableActionCall, - decodeStrategyExecutorCalldata, -} from './StrategyExecutorDecoding' -export { decodePositionsManagerCalldata } from './PositionsManagerDecoding' +export * from './ActionDecoding' +export * from './ErrorMessage' +export * from './StrategyExecutorDecoding' +export * from './PositionsManagerDecoding' diff --git a/sdk/tools/genStrategyDefinitions/src/index.ts b/sdk/tools/genStrategyDefinitions/src/index.ts index 052b6bb844..7526a5bf37 100644 --- a/sdk/tools/genStrategyDefinitions/src/index.ts +++ b/sdk/tools/genStrategyDefinitions/src/index.ts @@ -27,7 +27,7 @@ async function main() { }) .option('format', { alias: 'f', - description: 'Output format (safe, tenderly)', + description: 'Output format (safe, tenderly, debug)', default: 'safe', type: 'string', }) @@ -51,8 +51,10 @@ async function main() { // Write to file if (args.format === 'safe') { fs.writeFileSync(args.output, JSON.stringify(safeBatch, null, 2)) - } else { + } else if (args.format === 'tenderly') { fs.writeFileSync(args.output, JSON.stringify(operationDefinitions, null, 2)) + } else { + fs.writeFileSync(args.output, JSON.stringify(strategyDefinitions, null, 2)) } } else { console.log('--------------------')