From d588da343721686806f0d584d23dcb0c4bc9f522 Mon Sep 17 00:00:00 2001 From: Roberto Cano <3525807+robercano@users.noreply.github.com> Date: Tue, 30 Apr 2024 18:00:00 +0200 Subject: [PATCH] fix: correct swap amount --- .../common/builders/SwapActionBuilder.ts | 8 ++-- sdk/sdk-common/src/simulation/Steps.ts | 19 +++++++--- .../tests/refinanceMakerSparkAnyPair.test.ts | 38 +++++++++++-------- .../simulator-engine/reducer/swapReducer.ts | 31 ++++++--------- .../stepProcessor/swapOutputProcessor.ts | 2 +- .../implementation/utils/GetSwapStepData.ts | 22 +++++++++-- .../RefinanceLendingToLendingAnyPair.ts | 5 +-- 7 files changed, 73 insertions(+), 52 deletions(-) diff --git a/sdk/protocol-plugins/src/plugins/common/builders/SwapActionBuilder.ts b/sdk/protocol-plugins/src/plugins/common/builders/SwapActionBuilder.ts index 754169ac91..d04170acaf 100644 --- a/sdk/protocol-plugins/src/plugins/common/builders/SwapActionBuilder.ts +++ b/sdk/protocol-plugins/src/plugins/common/builders/SwapActionBuilder.ts @@ -11,8 +11,8 @@ export const SwapActionBuilder: ActionBuilder = async (params): const swapData = await swapManager.getSwapDataExactInput({ chainInfo: params.user.chainInfo, - fromAmount: step.inputs.amountAfterFee, - toToken: step.inputs.toTokenAmount.token, + fromAmount: step.inputs.inputAmountAfterFee, + toToken: step.inputs.minimumReceivedAmount.token, recipient: Address.createFromEthereum({ value: swapContractInfo.address as HexData }), slippage: step.inputs.slippage, }) @@ -21,8 +21,8 @@ export const SwapActionBuilder: ActionBuilder = async (params): step: step, action: new SwapAction(), arguments: { - fromAmount: step.inputs.fromTokenAmount, - toMinimumAmount: step.inputs.toTokenAmount, + fromAmount: step.inputs.inputAmount, + toMinimumAmount: step.inputs.minimumReceivedAmount, fee: step.inputs.summerFee, withData: swapData.calldata, collectFeeInFromToken: true, diff --git a/sdk/sdk-common/src/simulation/Steps.ts b/sdk/sdk-common/src/simulation/Steps.ts index 7308ac40ff..f330857f59 100644 --- a/sdk/sdk-common/src/simulation/Steps.ts +++ b/sdk/sdk-common/src/simulation/Steps.ts @@ -64,16 +64,25 @@ export interface SwapStep { provider: SwapProviderType routes: SwapRoute[] + /** Spot price of the token being traded */ spotPrice: Price - // Amount that will be send to our Swap service which then deducts our fee - fromTokenAmount: TokenAmount - // This amount has our fee already dedducted, and it will be send to exchange provider - amountAfterFee: TokenAmount - toTokenAmount: TokenAmount + /** Offer price of the token being traded, derived from the swap quote */ + offerPrice: Price + /** Full amount sent to the swap contract, before deducting the Summer fee */ + inputAmount: TokenAmount + /** Amount to be swapped after deducting the Summer fee */ + inputAmountAfterFee: TokenAmount + /** Amount estimated by the swap service to be received, equal to `inputAmountAfterFee / offerPrice` */ + estimatedReceivedAmount: TokenAmount + /** Minimum amount to be received from the swap service, equal to `inputAmountAfterFee / offerPrice * (1 - slippage)` */ + minimumReceivedAmount: TokenAmount + /** Maximum slippage accepted for the swap */ slippage: Percentage + /** Fee charged by Summer */ summerFee: Percentage }, { + /** Effective amount received after the actual swap */ received: TokenAmount } > {} diff --git a/sdk/sdk-e2e/tests/refinanceMakerSparkAnyPair.test.ts b/sdk/sdk-e2e/tests/refinanceMakerSparkAnyPair.test.ts index e49b6634a1..66efc3a66f 100644 --- a/sdk/sdk-e2e/tests/refinanceMakerSparkAnyPair.test.ts +++ b/sdk/sdk-e2e/tests/refinanceMakerSparkAnyPair.test.ts @@ -22,17 +22,25 @@ import assert from 'assert' import { EmodeType } from '@summerfi/protocol-plugins/plugins/common' import { ILKType, MakerPoolId } from '@summerfi/protocol-plugins/plugins/maker' import { SparkPoolId, isSparkPoolId } from '@summerfi/protocol-plugins/plugins/spark' +import { AddressValue } from '@summerfi/sdk-common' jest.setTimeout(300000) -const SDKAPiUrl = 'https://zmjmtfsocb.execute-api.us-east-1.amazonaws.com/api/sdk' -const TenderlyForkUrl = - 'https://virtual.mainnet.rpc.tenderly.co/ea4060f8-c16d-49ba-84dd-2c12afb98cdd' - -describe.skip('Refinance Maker Spark | SDK', () => { +/** 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', +} + +describe('Refinance Maker Spark | SDK', () => { it('should allow refinance Maker -> Spark with same pair', async () => { // SDK - const sdk = makeSDK({ apiURL: SDKAPiUrl }) + const sdk = makeSDK({ apiURL: config.SDKAPiUrl }) // Chain const chain: Maybe = await sdk.chains.getChain({ @@ -43,7 +51,7 @@ describe.skip('Refinance Maker Spark | SDK', () => { // User const walletAddress = Address.createFromEthereum({ - value: '0x34314adbfBb5d239bb67f0265c9c45EB8b834412', + value: config.walletAddress as AddressValue, }) const user: User = await sdk.users.getUser({ chainInfo: chain.chainInfo, @@ -56,7 +64,7 @@ describe.skip('Refinance Maker Spark | SDK', () => { // Positions Manager const positionsManager: IPositionsManager = { address: Address.createFromEthereum({ - value: '0xd1edd5ff690a83e9a1ebcd0ac1c3f7e231b72f76', + value: config.DPMAddress as AddressValue, }), } @@ -88,7 +96,7 @@ describe.skip('Refinance Maker Spark | SDK', () => { chainInfo: chain.chainInfo, }, ilkType: ILKType.ETH_C, - vaultId: '31717', + vaultId: config.makerVaultId, } const makerPool = await maker.getPool({ @@ -103,14 +111,14 @@ describe.skip('Refinance Maker Spark | SDK', () => { // Source position const makerPosition: Position = Position.createFrom({ type: PositionType.Multiply, - positionId: PositionId.createFrom({ id: '31717' }), - debtAmount: TokenAmount.createFromBaseUnit({ + positionId: PositionId.createFrom({ id: config.makerVaultId }), + debtAmount: TokenAmount.createFrom({ token: DAI, - amount: '0', + amount: config.debtAmount, }), - collateralAmount: TokenAmount.createFromBaseUnit({ + collateralAmount: TokenAmount.createFrom({ token: WETH, - amount: '10000000000000000000', + amount: config.collateralAmount, }), pool: makerPool, }) @@ -168,7 +176,7 @@ describe.skip('Refinance Maker Spark | SDK', () => { const privateKey = process.env.DEPLOYER_PRIVATE_KEY as Hex const transactionUtils = new TransactionUtils({ - rpcUrl: TenderlyForkUrl, + rpcUrl: config.TenderlyForkUrl, walletPrivateKey: privateKey, }) diff --git a/sdk/simulator-service/src/implementation/simulator-engine/reducer/swapReducer.ts b/sdk/simulator-service/src/implementation/simulator-engine/reducer/swapReducer.ts index 08230ab2b3..b98f6adb3b 100644 --- a/sdk/simulator-service/src/implementation/simulator-engine/reducer/swapReducer.ts +++ b/sdk/simulator-service/src/implementation/simulator-engine/reducer/swapReducer.ts @@ -4,21 +4,12 @@ import { addBalance, subtractBalance } from '../../utils' import { ISimulationState } from '../../../interfaces/simulation' export function swapReducer(step: steps.SwapStep, state: ISimulationState): ISimulationState { - const balanceWithoutFromToken = subtractBalance(step.inputs.fromTokenAmount, state.balances) - const balanceWithToToken = addBalance(step.outputs.received, balanceWithoutFromToken) - - const baseToken = step.inputs.toTokenAmount.token - const quoteToken = step.inputs.fromTokenAmount.token + const balanceWithoutFromToken = subtractBalance(step.inputs.inputAmount, state.balances) + console.log('step inputs', JSON.stringify(step.inputs, null, 2)) + console.log('step outputs', JSON.stringify(step.outputs, null, 2)) - // We require both from & to be at similar decimal precisions - const offerPrice = Price.createFrom({ - value: step.inputs.fromTokenAmount.divide(step.inputs.toTokenAmount.amount).amount, - baseToken, - quoteToken, - }) - - const spotPrice = step.inputs.spotPrice - const fromAmountPreSummerFee = step.inputs.fromTokenAmount.divide( + const balanceWithToToken = addBalance(step.outputs.received, balanceWithoutFromToken) + const fromAmountPreSummerFee = step.inputs.inputAmount.divide( Percentage.createFrom({ value: 1 }).subtract(step.inputs.summerFee), ) @@ -36,14 +27,14 @@ export function swapReducer(step: steps.SwapStep, state: ISimulationState): ISim // routes: step.inputs.routes, // SummerFee should already have been subtracted by this stage // Should be subtracted from `from` amount when getting swap quote in simulator - fromTokenAmount: step.inputs.fromTokenAmount, - toTokenAmount: step.inputs.toTokenAmount, + fromTokenAmount: step.inputs.inputAmount, + toTokenAmount: step.inputs.estimatedReceivedAmount, slippage: Percentage.createFrom({ value: step.inputs.slippage.value }), - offerPrice, - spotPrice, - priceImpact: calculatePriceImpact(spotPrice, offerPrice), + offerPrice: step.inputs.offerPrice, + spotPrice: step.inputs.spotPrice, + priceImpact: calculatePriceImpact(step.inputs.spotPrice, step.inputs.offerPrice), summerFee: TokenAmount.createFrom({ - token: step.inputs.fromTokenAmount.token, + token: step.inputs.inputAmount.token, amount: fromAmountPreSummerFee.multiply(step.inputs.summerFee.toProportion()).amount, }), }, diff --git a/sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/swapOutputProcessor.ts b/sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/swapOutputProcessor.ts index 602fd3bae5..3b8aac7dc8 100644 --- a/sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/swapOutputProcessor.ts +++ b/sdk/simulator-service/src/implementation/simulator-engine/stepProcessor/swapOutputProcessor.ts @@ -5,7 +5,7 @@ export const swapOutputProcessor: StepOutputProcessor = async (s return { ...step, outputs: { - received: step.inputs.toTokenAmount, + received: step.inputs.minimumReceivedAmount, }, } } diff --git a/sdk/simulator-service/src/implementation/utils/GetSwapStepData.ts b/sdk/simulator-service/src/implementation/utils/GetSwapStepData.ts index bb28d4a7d7..026c451312 100644 --- a/sdk/simulator-service/src/implementation/utils/GetSwapStepData.ts +++ b/sdk/simulator-service/src/implementation/utils/GetSwapStepData.ts @@ -1,3 +1,4 @@ +import { Price } from '@summerfi/sdk-common' import type { ChainInfo, Percentage, @@ -46,12 +47,25 @@ export async function getSwapStepData(params: { }), ]) + // Actual price offered by the swap service + const offerPrice = Price.createFrom({ + value: params.fromAmount.divide(quote.toTokenAmount.amount).amount, + baseToken: params.toToken, + quoteToken: params.fromAmount.token, + }) + + const minimumReceivedAmount = quote.toTokenAmount.multiply(1.0 - params.slippage.toProportion()) + return { - ...quote, - fromTokenAmount: params.fromAmount, - amountAfterFee: amountAfterSummerFee, - summerFee, + provider: quote.provider, + routes: quote.routes, spotPrice: spotPrice.price, + offerPrice: offerPrice, + inputAmount: params.fromAmount, + inputAmountAfterFee: amountAfterSummerFee, + estimatedReceivedAmount: quote.toTokenAmount, + minimumReceivedAmount: minimumReceivedAmount, slippage: params.slippage, + summerFee: summerFee, } } diff --git a/sdk/simulator-service/src/strategies/refinanceAnyPair/RefinanceLendingToLendingAnyPair.ts b/sdk/simulator-service/src/strategies/refinanceAnyPair/RefinanceLendingToLendingAnyPair.ts index 987e3c385c..7a9057d689 100644 --- a/sdk/simulator-service/src/strategies/refinanceAnyPair/RefinanceLendingToLendingAnyPair.ts +++ b/sdk/simulator-service/src/strategies/refinanceAnyPair/RefinanceLendingToLendingAnyPair.ts @@ -8,7 +8,7 @@ import { getValueFromReference, } from '@summerfi/sdk-common/simulation' import { Simulator } from '../../implementation/simulator-engine' -import { Position, TokenAmount, Percentage, Token } from '@summerfi/sdk-common/common' +import { Position, TokenAmount, Percentage, Token, isSameTokens } from '@summerfi/sdk-common/common' import { newEmptyPositionFromPool } from '@summerfi/sdk-common/common/utils' import { IRefinanceParameters } from '@summerfi/sdk-common/orders' import { isLendingPool } from '@summerfi/sdk-common/protocols' @@ -16,8 +16,7 @@ import { refinanceLendingToLendingAnyPairStrategy } from './Strategy' import { type IRefinanceDependencies } from '../common/Types' import { getSwapStepData } from '../../implementation/utils/GetSwapStepData' import { ISwapManager } from '@summerfi/swap-common/interfaces' -import { isSameTokens } from '@summerfi/sdk-common/common' -import BigNumber from 'bignumber.js' +import { BigNumber } from 'bignumber.js' export async function refinanceLendingToLendingAnyPair( args: IRefinanceParameters,