diff --git a/package.json b/package.json index ce0c1df8e..a63ebc2f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@paraswap/dex-lib", - "version": "2.22.2", + "version": "2.22.3", "main": "build/index.js", "types": "build/index.d.ts", "repository": "https://github.com/paraswap/paraswap-dex-lib", diff --git a/src/router/buy.ts b/src/router/buy.ts index a23e681cf..4bb1759f3 100644 --- a/src/router/buy.ts +++ b/src/router/buy.ts @@ -3,6 +3,7 @@ import { PayloadEncoder, encodeFeePercent, encodeFeePercentForReferrer, + encodePartnerAddressForFeeLogic, } from './payload-encoder'; import { Address, @@ -61,6 +62,22 @@ export class Buy extends PayloadEncoder implements IRouter { minMaxAmount, priceRoute.srcAmount, ); + + const [partner, feePercent] = referrerAddress + ? [referrerAddress, encodeFeePercentForReferrer(SwapSide.BUY)] + : [ + encodePartnerAddressForFeeLogic({ + partnerAddress, + partnerFeePercent, + positiveSlippageToUser, + }), + encodeFeePercent( + partnerFeePercent, + positiveSlippageToUser, + SwapSide.BUY, + ), + ]; + const buyData: ContractBuyData = { adapter, fromToken: priceRoute.srcToken, @@ -70,14 +87,8 @@ export class Buy extends PayloadEncoder implements IRouter { expectedAmount: priceRoute.srcAmount, beneficiary, route, - partner: referrerAddress || partnerAddress, - feePercent: referrerAddress - ? encodeFeePercentForReferrer(SwapSide.BUY) - : encodeFeePercent( - partnerFeePercent, - positiveSlippageToUser, - SwapSide.BUY, - ), + partner, + feePercent, permit, deadline, uuid: uuidToBytes16(uuid), diff --git a/src/router/directswap.ts b/src/router/directswap.ts index 377196e1d..2af9245bd 100644 --- a/src/router/directswap.ts +++ b/src/router/directswap.ts @@ -7,6 +7,7 @@ import { assert } from 'ts-essentials'; import { encodeFeePercent, encodeFeePercentForReferrer, + encodePartnerAddressForFeeLogic, } from './payload-encoder'; export class DirectSwap implements IRouter { @@ -69,6 +70,21 @@ export class DirectSwap implements IRouter { ? priceRoute.destAmount : priceRoute.srcAmount; + const [partner, feePercent] = referrerAddress + ? [referrerAddress, encodeFeePercentForReferrer(priceRoute.side)] + : [ + encodePartnerAddressForFeeLogic({ + partnerAddress, + partnerFeePercent, + positiveSlippageToUser, + }), + encodeFeePercent( + partnerFeePercent, + positiveSlippageToUser, + priceRoute.side, + ), + ]; + return dex.getDirectParam!( priceRoute.srcToken, priceRoute.destToken, @@ -79,15 +95,9 @@ export class DirectSwap implements IRouter { priceRoute.side, permit, uuid, - referrerAddress - ? encodeFeePercentForReferrer(priceRoute.side) - : encodeFeePercent( - partnerFeePercent, - positiveSlippageToUser, - priceRoute.side, - ), + feePercent, deadline, - referrerAddress || partnerAddress, + partner, beneficiary, priceRoute.contractMethod, ); diff --git a/src/router/megaswap.ts b/src/router/megaswap.ts index 5eba8738b..58433b270 100644 --- a/src/router/megaswap.ts +++ b/src/router/megaswap.ts @@ -3,6 +3,7 @@ import { PayloadEncoder, encodeFeePercent, encodeFeePercentForReferrer, + encodePartnerAddressForFeeLogic, } from './payload-encoder'; import { Address, @@ -50,6 +51,22 @@ export class MegaSwap extends PayloadEncoder implements IRouter { const { megaSwapPaths, networkFee } = this.getMegaSwapPathsWithNetworkFee( priceRoute.bestRoute, ); + + const [partner, feePercent] = referrerAddress + ? [referrerAddress, encodeFeePercentForReferrer(SwapSide.SELL)] + : [ + encodePartnerAddressForFeeLogic({ + partnerAddress, + partnerFeePercent, + positiveSlippageToUser, + }), + encodeFeePercent( + partnerFeePercent, + positiveSlippageToUser, + SwapSide.SELL, + ), + ]; + const sellData: ContractMegaSwapSellData = { fromToken: priceRoute.srcToken, fromAmount: priceRoute.srcAmount, @@ -57,14 +74,8 @@ export class MegaSwap extends PayloadEncoder implements IRouter { expectedAmount: priceRoute.destAmount, beneficiary, path: megaSwapPaths, - partner: referrerAddress || partnerAddress, - feePercent: referrerAddress - ? encodeFeePercentForReferrer(SwapSide.SELL) - : encodeFeePercent( - partnerFeePercent, - positiveSlippageToUser, - SwapSide.SELL, - ), + partner, + feePercent, permit, deadline, uuid: uuidToBytes16(uuid), diff --git a/src/router/multiswap.ts b/src/router/multiswap.ts index 03f7c94d4..d90695d0c 100644 --- a/src/router/multiswap.ts +++ b/src/router/multiswap.ts @@ -3,6 +3,7 @@ import { PayloadEncoder, encodeFeePercent, encodeFeePercentForReferrer, + encodePartnerAddressForFeeLogic, } from './payload-encoder'; import { Address, @@ -58,6 +59,22 @@ export class MultiSwap const { paths, networkFee } = this.getContractPathsWithNetworkFee( priceRoute.bestRoute[0].swaps, ); + + const [partner, feePercent] = referrerAddress + ? [referrerAddress, encodeFeePercentForReferrer(SwapSide.SELL)] + : [ + encodePartnerAddressForFeeLogic({ + partnerAddress, + partnerFeePercent, + positiveSlippageToUser, + }), + encodeFeePercent( + partnerFeePercent, + positiveSlippageToUser, + SwapSide.SELL, + ), + ]; + const sellData: ContractSellData = { fromToken: priceRoute.srcToken, fromAmount: priceRoute.srcAmount, @@ -65,14 +82,8 @@ export class MultiSwap expectedAmount: priceRoute.destAmount, beneficiary, path: paths, - partner: referrerAddress || partnerAddress, - feePercent: referrerAddress - ? encodeFeePercentForReferrer(SwapSide.SELL) - : encodeFeePercent( - partnerFeePercent, - positiveSlippageToUser, - SwapSide.SELL, - ), + partner, + feePercent, permit, deadline, uuid: uuidToBytes16(uuid), diff --git a/src/router/payload-encoder.ts b/src/router/payload-encoder.ts index 1801dbe72..3a9a9bc93 100644 --- a/src/router/payload-encoder.ts +++ b/src/router/payload-encoder.ts @@ -9,9 +9,10 @@ import { Address, Adapters, } from '../types'; -import { SwapSide } from '../constants'; +import { NULL_ADDRESS, SwapSide } from '../constants'; import { DexAdapterService } from '../dex'; import { convertToBasisPoints } from '../utils'; +import { assert } from 'ts-essentials'; const OneShift14 = 1n << 14n; const OneShift15 = 1n << 15n; @@ -25,6 +26,29 @@ const REFERRER_FEE = 2500n | OneShift14 | OneShift16 | OneShift248; const HALF_SPLIT = '5000'; +export function encodePartnerAddressForFeeLogic({ + partnerAddress, + partnerFeePercent, + positiveSlippageToUser, +}: { + partnerAddress: string; + partnerFeePercent: string; + positiveSlippageToUser: boolean; +}): string { + const isPartnerTakeNoFeeNoPos = + +partnerFeePercent === 0 && positiveSlippageToUser == true; + + // nullify partner address to fallback default circuit contract without partner/referrer (no harm as no fee taken at all) + const partner = isPartnerTakeNoFeeNoPos ? NULL_ADDRESS : partnerAddress; + + // invariant checks + if (+partnerFeePercent > 0 && partner !== partnerAddress) { + throw new Error('logic error: should return partner address if fee is set'); + } + + return partner; +} + export function encodeFeePercent( partnerFeePercent: string, positiveSlippageToUser: boolean, @@ -47,6 +71,7 @@ export function encodeFeePercent( } // Set 14th bit if positiveSlippageToUser is true + // Upd: not used onchain anymore but better to keep to prevent collisions and ensure continuity of analytics if (positiveSlippageToUser) fee |= OneShift14; // Set 15th bit to take fee from srcToken diff --git a/src/router/simpleswap.ts b/src/router/simpleswap.ts index 02af05ce8..1b8e9e108 100644 --- a/src/router/simpleswap.ts +++ b/src/router/simpleswap.ts @@ -17,6 +17,7 @@ import { DexAdapterService } from '../dex'; import { encodeFeePercent, encodeFeePercentForReferrer, + encodePartnerAddressForFeeLogic, } from './payload-encoder'; type SimpleSwapParam = [ConstractSimpleData]; @@ -285,6 +286,21 @@ export abstract class SimpleRouter extends SimpleRouterBase { minMaxAmount, ); + const [partner, feePercent] = referrerAddress + ? [referrerAddress, encodeFeePercentForReferrer(this.side)] + : [ + encodePartnerAddressForFeeLogic({ + partnerAddress, + partnerFeePercent, + positiveSlippageToUser, + }), + encodeFeePercent( + partnerFeePercent, + positiveSlippageToUser, + this.side, + ), + ]; + const sellData: ConstractSimpleData = { ...partialContractSimpleData, fromToken: priceRoute.srcToken, @@ -298,14 +314,8 @@ export abstract class SimpleRouter extends SimpleRouterBase { ? priceRoute.destAmount : priceRoute.srcAmount, beneficiary, - partner: referrerAddress || partnerAddress, - feePercent: referrerAddress - ? encodeFeePercentForReferrer(this.side) - : encodeFeePercent( - partnerFeePercent, - positiveSlippageToUser, - this.side, - ), + partner, + feePercent, permit, deadline, uuid: uuidToBytes16(uuid), diff --git a/src/router/simpleswapnft.ts b/src/router/simpleswapnft.ts index 9aba4ff63..1fce10a08 100644 --- a/src/router/simpleswapnft.ts +++ b/src/router/simpleswapnft.ts @@ -11,6 +11,7 @@ import { DexAdapterService } from '../dex'; import { encodeFeePercent, encodeFeePercentForReferrer, + encodePartnerAddressForFeeLogic, } from './payload-encoder'; import { PartialContractSimpleData, SimpleRouterBase } from './simpleswap'; import { BI_ADDR_MASK } from '../bigint-constants'; @@ -95,6 +96,21 @@ export class SimpleBuyNFT extends SimpleRouterBase { }; }; + const [partner, feePercent] = referrerAddress + ? [referrerAddress, encodeFeePercentForReferrer(SwapSide.BUY)] + : [ + encodePartnerAddressForFeeLogic({ + partnerAddress, + partnerFeePercent, + positiveSlippageToUser, + }), + encodeFeePercent( + partnerFeePercent, + positiveSlippageToUser, + SwapSide.BUY, + ), + ]; + const buyData: ContractSimpleBuyNFTData = { ...partialContractSimpleData, fromToken: priceRoute.srcToken, @@ -104,14 +120,8 @@ export class SimpleBuyNFT extends SimpleRouterBase { fromAmount: minMaxAmount, expectedAmount: priceRoute.srcAmount, beneficiary, - partner: referrerAddress || partnerAddress, - feePercent: referrerAddress - ? encodeFeePercentForReferrer(SwapSide.BUY) - : encodeFeePercent( - partnerFeePercent, - positiveSlippageToUser, - SwapSide.BUY, - ), + partner, + feePercent, permit, deadline, uuid: uuidToBytes16(uuid),