Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/bridging/src/BridgingSdk/mock/bridgeRequestMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ export const amountsAndCosts: QuoteAmountsAndCosts = {
amount: BigInt('100000000'),
bps: 100,
},
protocolFee: {
amount: 0n,
bps: 0
}
},
beforeNetworkCosts: {
sellAmount: BigInt('100000000'),
Expand Down
4 changes: 2 additions & 2 deletions packages/order-book/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cowprotocol/sdk-order-book",
"version": "0.2.0",
"version": "0.2.1",
"description": "CowProtocol Order Book package",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
Expand All @@ -20,7 +20,7 @@
"test": "jest",
"test:coverage": "jest --coverage --json --outputFile=jest.results.json && npx coveralls < ./coverage/lcov.info",
"test:coverage:html": "jest --silent=false --coverage --coverageReporters html",
"swagger:codegen": "openapi --input https://raw.githubusercontent.com/cowprotocol/services/v2.291.0/crates/orderbook/openapi.yml --output src/generated --exportServices false --exportCore false",
"swagger:codegen": "openapi --input https://raw.githubusercontent.com/cowprotocol/services/dfb50cb4a103e8f949f5a7145beb6be63ef41c85/crates/orderbook/openapi.yml --output src/generated --exportServices false --exportCore false",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify if this commit hash corresponds to a released version.

Using a commit hash instead of a version tag makes it harder to track which API version is in use. Before merging, ensure this commit is part of a stable release and consider using a version tag instead.


🏁 Script executed:

#!/bin/bash
# Check if the commit is tagged with a version
cd /tmp
git clone --filter=blob:none --no-checkout https://github.com/cowprotocol/services.git 2>/dev/null || true
cd services
git fetch origin dfb50cb4a103e8f949f5a7145beb6be63ef41c85 2>/dev/null
git tag --contains dfb50cb4a103e8f949f5a7145beb6be63ef41c85 2>/dev/null | head -5

Length of output: 0


Let me try alternative verification approaches to check if this commit is tagged or part of a release:


---

🏁 Script executed:

```shell
#!/bin/bash
# Try using GitHub API to check the commit and its tags
COMMIT="dfb50cb4a103e8f949f5a7145beb6be63ef41c85"
REPO="cowprotocol/services"

# Check if commit exists
echo "Checking if commit exists..."
curl -s "https://api.github.com/repos/${REPO}/commits/${COMMIT}" | jq -r '.sha // empty' | head -1

# Try to find tags associated with this commit
echo "Searching for associated tags..."
curl -s "https://api.github.com/repos/${REPO}/git/refs/tags" | jq -r ".[] | select(.object.sha == \"${COMMIT}\") | .ref" 2>/dev/null | head -5

Length of output: 102



---

🏁 Script executed:

```shell
#!/bin/bash
COMMIT="dfb50cb4a103e8f949f5a7145beb6be63ef41c85"
REPO="cowprotocol/services"

# Get commit details
echo "=== Commit Details ==="
curl -s "https://api.github.com/repos/${REPO}/commits/${COMMIT}" | jq -r '.commit.message, .commit.author.date, .commit.committer.date' 2>/dev/null

# Get v2.291.0 tag info
echo ""
echo "=== v2.291.0 Tag Details ==="
curl -s "https://api.github.com/repos/${REPO}/git/refs/tags/v2.291.0" | jq -r '.object' 2>/dev/null

# Get the commit date for v2.291.0
echo ""
echo "=== v2.291.0 Commit Date ==="
curl -s "https://api.github.com/repos/${REPO}/tags" | jq -r '.[] | select(.name == "v2.291.0") | .commit.url' 2>/dev/null | head -1 | xargs -I {} curl -s {} | jq -r '.commit.author.date' 2>/dev/null

Length of output: 362


Do not merge with this unreleased commit hash. Use a stable version tag instead.

The commit dfb50cb4a103e8f949f5a7145beb6be63ef41c85 is a recent feature branch merge from 2025-11-12, not a released version. It's not tagged and differs from the previous stable version v2.291.0. Using an unreleased commit introduces maintenance risk and makes dependency tracking difficult. Before merging, switch to a stable version tag (e.g., v2.291.0 or a newer release if available).

🤖 Prompt for AI Agents
In packages/order-book/package.json around line 23, the swagger:codegen script
references an unreleased commit hash (dfb50cb4a103e8f949f5a7145beb6be63ef41c85)
in the OpenAPI input URL; replace that commit hash with a stable release tag
(for example v2.291.0 or a newer official release) so the codegen points to a
released version, then update the repository (or CI) to regenerate the
src/generated output with the chosen tag and run tests/linters to ensure no
regressions.

"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
"typecheck": "tsc --noEmit",
"prepublishOnly": "npm run build"
Expand Down
6 changes: 6 additions & 0 deletions packages/order-book/src/quoteAmountsAndCostsUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ describe('Calculation of before/after fees amounts', () => {
buyDecimals,
slippagePercentBps: 0,
partnerFeeBps: undefined,
protocolFeeBps: undefined,
})

expect(result.afterNetworkCosts.sellAmount.toString()).toBe(
Expand All @@ -74,6 +75,7 @@ describe('Calculation of before/after fees amounts', () => {
buyDecimals,
slippagePercentBps: 0,
partnerFeeBps: undefined,
protocolFeeBps: undefined,
})

expect(result.beforeNetworkCosts.buyAmount.toString()).toBe(
Expand All @@ -99,6 +101,7 @@ describe('Calculation of before/after fees amounts', () => {
buyDecimals,
partnerFeeBps,
slippagePercentBps: 0,
protocolFeeBps: undefined,
})

const buyAmountBeforeNetworkCosts =
Expand All @@ -120,6 +123,7 @@ describe('Calculation of before/after fees amounts', () => {
buyDecimals,
partnerFeeBps,
slippagePercentBps: 0,
protocolFeeBps: undefined,
})

const partnerFeeAmount = Math.floor((+orderParams.sellAmount * partnerFeeBps) / 100 / 100)
Expand All @@ -141,6 +145,7 @@ describe('Calculation of before/after fees amounts', () => {
buyDecimals,
partnerFeeBps: undefined,
slippagePercentBps,
protocolFeeBps: undefined,
})

const buyAmountAfterNetworkCosts = +orderParams.buyAmount
Expand All @@ -160,6 +165,7 @@ describe('Calculation of before/after fees amounts', () => {
buyDecimals,
partnerFeeBps: undefined,
slippagePercentBps,
protocolFeeBps: undefined,
})

const sellAmountAfterNetworkCosts = +orderParams.sellAmount + +orderParams.feeAmount
Expand Down
77 changes: 63 additions & 14 deletions packages/order-book/src/quoteAmountsAndCostsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface QuoteAmountsAndCostsParams {
buyDecimals: number
slippagePercentBps: number
partnerFeeBps: number | undefined
protocolFeeBps: number | undefined
}

const ONE_HUNDRED_BPS = BigInt(100 * 100)
Expand Down Expand Up @@ -85,10 +86,10 @@ function _getQuoteAmountsWithCosts(params: {
}

function getQuoteAmountsWithPartnerFee(params: {
sellAmountAfterNetworkCosts: BigNumber
buyAmountAfterNetworkCosts: BigNumber
buyAmountBeforeNetworkCosts: BigNumber
sellAmountBeforeNetworkCosts: BigNumber
sellAmountAfterNetworkCosts: bigint
buyAmountAfterNetworkCosts: bigint
buyAmountBeforeNetworkCosts: bigint
sellAmountBeforeNetworkCosts: bigint
isSell: boolean
partnerFeeBps: number
}) {
Expand All @@ -104,20 +105,20 @@ function getQuoteAmountsWithPartnerFee(params: {
/**
* Partner fee is always added on the surplus amount, for sell-orders it's buy amount, for buy-orders it's sell amount
*/
const surplusAmount = isSell ? buyAmountBeforeNetworkCosts.big : sellAmountBeforeNetworkCosts.big
const partnerFeeAmount = partnerFeeBps > 0 ? (surplusAmount * BigInt(partnerFeeBps)) / ONE_HUNDRED_BPS : BigInt(0)
const surplusAmount = isSell ? buyAmountBeforeNetworkCosts : sellAmountBeforeNetworkCosts
const partnerFeeAmount = partnerFeeBps > 0 ? (surplusAmount * BigInt(partnerFeeBps)) / ONE_HUNDRED_BPS : 0n

/**
* Partner fee is always added on the surplus token, for sell-orders it's buy token, for buy-orders it's sell token
*/
const afterPartnerFees = isSell
? {
sellAmount: sellAmountAfterNetworkCosts.big,
buyAmount: buyAmountAfterNetworkCosts.big - partnerFeeAmount,
sellAmount: sellAmountAfterNetworkCosts,
buyAmount: buyAmountAfterNetworkCosts - partnerFeeAmount,
}
: {
sellAmount: sellAmountAfterNetworkCosts.big + partnerFeeAmount,
buyAmount: buyAmountAfterNetworkCosts.big,
sellAmount: sellAmountAfterNetworkCosts + partnerFeeAmount,
buyAmount: buyAmountAfterNetworkCosts,
}

return {
Expand All @@ -126,6 +127,40 @@ function getQuoteAmountsWithPartnerFee(params: {
}
}

function getProtocolFeeAmount(params: {
sellAmountAfterNetworkCosts: bigint
buyAmountAfterNetworkCosts: bigint
networkCostAmount: bigint
isSell: boolean
protocolFeeBps: number
}) {
const { sellAmountAfterNetworkCosts, buyAmountAfterNetworkCosts, networkCostAmount, isSell, protocolFeeBps } = params

if (protocolFeeBps <= 0) {
return 0n
}

const protocolFeeBpsBig = BigInt(protocolFeeBps)

if (isSell) {
/**
* SELL orders formula: protocolFeeInBuy = quoteBuyAmount * protocolFeeBps / (1 - protocolFeeBps)
*
* The buyAmountAfterNetworkCosts already includes the protocol fee (it was deducted from buyAmount by the API).
* We need to reconstruct the original buyAmount and calculate the fee amount.
*/
const ONE_MINUS_PROTOCOL_FEE_BPS = ONE_HUNDRED_BPS - protocolFeeBpsBig
return (buyAmountAfterNetworkCosts * protocolFeeBpsBig) / ONE_MINUS_PROTOCOL_FEE_BPS
} else {
/**
* BUY orders formula: protocolFeeInSell = (quoteSellAmount + feeAmount) * proto colFeeBps / (1 + protocolFeeBps)
*/
const ONE_PLUS_PROTOCOL_FEE_BPS = ONE_HUNDRED_BPS + protocolFeeBpsBig
const sellAmountWithNetworkFee = sellAmountAfterNetworkCosts + networkCostAmount
return (sellAmountWithNetworkFee * protocolFeeBpsBig) / ONE_PLUS_PROTOCOL_FEE_BPS
}
}

function getQuoteAmountsWithSlippage(params: {
afterPartnerFees: { sellAmount: bigint; buyAmount: bigint }
isSell: boolean
Expand Down Expand Up @@ -155,6 +190,7 @@ function getQuoteAmountsWithSlippage(params: {
export function getQuoteAmountsAndCosts(params: QuoteAmountsAndCostsParams): QuoteAmountsAndCosts {
const { orderParams, sellDecimals, buyDecimals, slippagePercentBps } = params
const partnerFeeBps = params.partnerFeeBps ?? 0
const protocolFeeBps = params.protocolFeeBps ?? 0

// Get amounts including network costs
const {
Expand All @@ -167,12 +203,21 @@ export function getQuoteAmountsAndCosts(params: QuoteAmountsAndCostsParams): Quo
quotePrice,
} = _getQuoteAmountsWithCosts({ sellDecimals, buyDecimals, orderParams })


const protocolFeeAmount = getProtocolFeeAmount({
sellAmountAfterNetworkCosts: sellAmountAfterNetworkCosts.big,
buyAmountAfterNetworkCosts: buyAmountAfterNetworkCosts.big,
networkCostAmount: networkCostAmount.big,
isSell,
protocolFeeBps,
})

// Get amounts including partner fees
const { afterPartnerFees, partnerFeeAmount } = getQuoteAmountsWithPartnerFee({
sellAmountAfterNetworkCosts,
buyAmountAfterNetworkCosts,
buyAmountBeforeNetworkCosts,
sellAmountBeforeNetworkCosts,
sellAmountAfterNetworkCosts: sellAmountAfterNetworkCosts.big,
buyAmountAfterNetworkCosts: buyAmountAfterNetworkCosts.big,
buyAmountBeforeNetworkCosts: buyAmountBeforeNetworkCosts.big,
sellAmountBeforeNetworkCosts: sellAmountBeforeNetworkCosts.big,
isSell,
partnerFeeBps,
})
Expand All @@ -195,6 +240,10 @@ export function getQuoteAmountsAndCosts(params: QuoteAmountsAndCostsParams): Quo
amount: partnerFeeAmount,
bps: partnerFeeBps,
},
protocolFee: {
amount: protocolFeeAmount,
bps: protocolFeeBps,
},
},
beforeNetworkCosts: {
sellAmount: sellAmountBeforeNetworkCosts.big,
Expand Down
5 changes: 5 additions & 0 deletions packages/order-book/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export interface Costs<T> {
amount: T
bps: number
}
protocolFee: {
amount: T
bps: number
}
}

/**
Expand All @@ -32,6 +36,7 @@ export interface Costs<T> {
* The order of adding fees and costs is as follows:
* 1. Network fee is always added to the sell amount
* 2. Partner fee is added to the surplus amount (sell amount for sell-orders, buy amount for buy-orders)
* 3. Protocol fee --- need to clarify this one
*
* For sell-orders the partner fee is subtracted from the buy amount after network costs.
* For buy-orders the partner fee is added on top of the sell amount after network costs.
Expand Down
4 changes: 3 additions & 1 deletion packages/trading/src/getOrderToSign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ interface OrderToSignParams {
from: string
networkCostsAmount?: string
applyCostsSlippageAndFees?: boolean
protocolFeeBps?: number
}

export function getOrderToSign(
{ chainId, from, networkCostsAmount = '0', isEthFlow, applyCostsSlippageAndFees = true }: OrderToSignParams,
{ chainId, from, networkCostsAmount = '0', isEthFlow, applyCostsSlippageAndFees = true, protocolFeeBps }: OrderToSignParams,
limitOrderParams: LimitTradeParameters,
appDataKeccak256: string,
): UnsignedOrder {
Expand Down Expand Up @@ -63,6 +64,7 @@ export function getOrderToSign(
orderParams,
slippagePercentBps: slippageBps,
partnerFeeBps: getPartnerFeeBps(partnerFee),
protocolFeeBps,
sellDecimals: sellTokenDecimals,
buyDecimals: buyTokenDecimals,
})
Expand Down
3 changes: 2 additions & 1 deletion packages/trading/src/getQuote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,13 @@ export async function getQuote(
orderParams: quote.quote,
slippagePercentBps: slippageBps,
partnerFeeBps: getPartnerFeeBps(partnerFee),
protocolFeeBps: quote.protocolFeeBps ? Number(quote.protocolFeeBps) : undefined,
sellDecimals: sellTokenDecimals,
buyDecimals: buyTokenDecimals,
})

const orderToSign = getOrderToSign(
{ chainId, from, networkCostsAmount: quote.quote.feeAmount, isEthFlow },
{ chainId, from, networkCostsAmount: quote.quote.feeAmount, isEthFlow, protocolFeeBps: quote.protocolFeeBps ? Number(quote.protocolFeeBps) : undefined },
swapParamsToLimitOrderParams(tradeParameters, quote),
appDataInfo.appDataKeccak256,
)
Expand Down
1 change: 1 addition & 0 deletions packages/trading/src/resolveSlippageSuggestion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export async function resolveSlippageSuggestion(
orderParams: quote.quote,
slippagePercentBps: 0,
partnerFeeBps: getPartnerFeeBps(tradeParameters.partnerFee),
protocolFeeBps: quote.protocolFeeBps ? Number(quote.protocolFeeBps) : undefined,
sellDecimals: tradeParameters.sellTokenDecimals,
buyDecimals: tradeParameters.buyTokenDecimals,
})
Expand Down
6 changes: 5 additions & 1 deletion packages/trading/src/utils/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function mapQuoteAmountsAndCosts<T, R>(
mapper: (value: T) => R,
): QuoteAmountsAndCosts<R> {
const {
costs: { networkFee, partnerFee },
costs: { networkFee, partnerFee, protocolFee },
} = value

function serializeAmounts(value: { sellAmount: T; buyAmount: T }): { sellAmount: R; buyAmount: R } {
Expand All @@ -56,6 +56,10 @@ export function mapQuoteAmountsAndCosts<T, R>(
...partnerFee,
amount: mapper(partnerFee.amount),
},
protocolFee: {
...protocolFee,
amount: mapper(protocolFee.amount),
},
},
beforeNetworkCosts: serializeAmounts(value.beforeNetworkCosts),
afterNetworkCosts: serializeAmounts(value.afterNetworkCosts),
Expand Down