Skip to content

Commit

Permalink
feat: accept skippable actions in order planner (#298)
Browse files Browse the repository at this point in the history
  • Loading branch information
robercano authored May 27, 2024
1 parent 41d579c commit b3c3877
Show file tree
Hide file tree
Showing 63 changed files with 519 additions and 863 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export class OrderPlanner implements IOrderPlanner {
addressBookManager,
step,
protocolsRegistry,
actionBuildersMap,
})
}

Expand Down
12 changes: 1 addition & 11 deletions sdk/order-planner-common/src/utils/EncodeStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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],
})
}

Expand Down
12 changes: 0 additions & 12 deletions sdk/order-planner-common/src/utils/GenerateStrategyName.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
import { ISimulation, SimulationType } from '@summerfi/sdk-common/simulation'

export function generateStrategyName(simulation: ISimulation<SimulationType>): 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}`
}
2 changes: 2 additions & 0 deletions sdk/order-planner-service/src/config/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ReturnFundsActionBuilder,
SwapActionBuilder,
OpenPositionActionBuilder,
SkippedStepActionBuilder,
} from '@summerfi/protocol-plugins/plugins/common'

export const ActionBuildersConfig: ActionBuildersMap = {
Expand All @@ -24,4 +25,5 @@ export const ActionBuildersConfig: ActionBuildersMap = {
[SimulationSteps.NewPositionEvent]: PositionCreatedActionBuilder,
[SimulationSteps.Import]: ImportPositionActionBuilder,
[SimulationSteps.OpenPosition]: OpenPositionActionBuilder,
[SimulationSteps.Skipped]: SkippedStepActionBuilder,
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions sdk/protocol-plugins-common/src/actions/BaseAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export abstract class BaseAction<
name: this.config.name,
targetHash,
callData: calldata,
skipped: false,
} as ActionCall
}

Expand Down
40 changes: 40 additions & 0 deletions sdk/protocol-plugins-common/src/actions/SkippedAction.ts
Original file line number Diff line number Diff line change
@@ -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<typeof SkippedAction.Config> {
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()
}
}
6 changes: 4 additions & 2 deletions sdk/protocol-plugins-common/src/actions/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) */
Expand All @@ -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
}

/**
Expand Down
13 changes: 3 additions & 10 deletions sdk/protocol-plugins-common/src/actions/index.ts
Original file line number Diff line number Diff line change
@@ -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'
13 changes: 13 additions & 0 deletions sdk/protocol-plugins-common/src/context/StepBuilderContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -33,7 +34,19 @@ export class StepBuilderContext implements IStepBuilderContext {
arguments: Parameters<Action['encodeCall']>[0]
connectedInputs: Partial<StorageInputsMapType<Step, Config>>
connectedOutputs: Partial<StorageOutputsMapType<Step, Config>>
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type ActionBuilderParams<Step extends steps.Steps> = {
addressBookManager: IAddressBookManager
protocolsRegistry: IProtocolPluginsRegistry
step: Step
actionBuildersMap: ActionBuildersMap
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -38,6 +39,7 @@ export interface IStepBuilderContext {
arguments: Parameters<Action['encodeCall']>[0]
connectedInputs: Partial<StorageInputsMapType<Step, Config>>
connectedOutputs: Partial<StorageOutputsMapType<Step, Config>>
skip?: boolean
}): void

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,19 @@ export class AaveV3DepositBorrowActionBuilder extends BaseActionBuilder<steps.De
})

const borrowAmount = getValueFromReference(step.inputs.borrowAmount)

if (!borrowAmount.toBN().isZero()) {
context.addActionCall({
step: step,
action: new AaveV3BorrowAction(),
arguments: {
borrowAmount: borrowAmount,
borrowTo: await this._getBorrowTargetAddress(params),
},
connectedInputs: {},
connectedOutputs: {
borrowAmount: 'borrowedAmount',
},
})
}
context.addActionCall({
step: step,
action: new AaveV3BorrowAction(),
arguments: {
borrowAmount: borrowAmount,
borrowTo: await this._getBorrowTargetAddress(params),
},
connectedInputs: {},
connectedOutputs: {
borrowAmount: 'borrowedAmount',
},
skip: borrowAmount.toBN().isZero(),
})
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,54 +35,53 @@ export class AaveV3PaybackWithdrawActionBuilder extends BaseActionBuilder<steps.

const paybackAmount = getValueFromReference(step.inputs.paybackAmount)

if (!paybackAmount.toBN().isZero()) {
context.addActionCall({
step: step,
action: new SetApprovalAction(),
arguments: {
approvalAmount: getValueFromReference(step.inputs.paybackAmount),
delegate: sparkLendingPoolAddress,
sumAmounts: false,
},
connectedInputs: {
paybackAmount: 'approvalAmount',
},
connectedOutputs: {},
})
context.addActionCall({
step: step,
action: new SetApprovalAction(),
arguments: {
approvalAmount: getValueFromReference(step.inputs.paybackAmount),
delegate: sparkLendingPoolAddress,
sumAmounts: false,
},
connectedInputs: {
paybackAmount: 'approvalAmount',
},
connectedOutputs: {},
skip: paybackAmount.toBN().isZero(),
})

context.addActionCall({
step: params.step,
action: new AaveV3PaybackAction(),
arguments: {
paybackAmount: getValueFromReference(step.inputs.paybackAmount),
paybackAll: getValueFromReference(step.inputs.paybackAmount)
.toBN()
.gt(step.inputs.position.debtAmount.toBN()),
onBehalf: Address.ZeroAddressEthereum,
},
connectedInputs: {},
connectedOutputs: {
paybackAmount: 'paybackedAmount',
},
})
}
context.addActionCall({
step: params.step,
action: new AaveV3PaybackAction(),
arguments: {
paybackAmount: getValueFromReference(step.inputs.paybackAmount),
paybackAll: getValueFromReference(step.inputs.paybackAmount)
.toBN()
.gt(step.inputs.position.debtAmount.toBN()),
onBehalf: Address.ZeroAddressEthereum,
},
connectedInputs: {},
connectedOutputs: {
paybackAmount: 'paybackedAmount',
},
skip: paybackAmount.toBN().isZero(),
})

const withdrawAmount = getValueFromReference(step.inputs.withdrawAmount)

if (!withdrawAmount.toBN().isZero()) {
context.addActionCall({
step: step,
action: new AaveV3WithdrawAction(),
arguments: {
withdrawAmount: withdrawAmount,
withdrawTo: await this._getWithdrawTargetAddress(params),
},
connectedInputs: {},
connectedOutputs: {
withdrawAmount: 'withdrawnAmount',
},
})
}
context.addActionCall({
step: step,
action: new AaveV3WithdrawAction(),
arguments: {
withdrawAmount: withdrawAmount,
withdrawTo: await this._getWithdrawTargetAddress(params),
},
connectedInputs: {},
connectedOutputs: {
withdrawAmount: 'withdrawnAmount',
},
skip: withdrawAmount.toBN().isZero(),
})
}

/**
Expand Down
Loading

0 comments on commit b3c3877

Please sign in to comment.