cowprotocol / services

Off-chain services for CoW Protocol
https://cow.fi/
Other
186 stars 72 forks source link

bug: Incorrect score calculation for partially-fillable trades #3077

Closed kana-sama closed 3 hours ago

kana-sama commented 4 hours ago

Problem

In some cases score is not 0 for:

  1. Order is Sell and partial fillable
  2. order.computed_buy_amount = trade.out_amount (it means that score should be equal to zero)
  3. Rounding issues in surplus_over function

Example: https://etherscan.io/tx/0x2d5a6f593cdc44a9ca46e9c8cc62a89ce55497b68f7102dabaa264cfc647f3a2 tx with real score = 0 but driver reported score: 1305051573483203

original order: "sellAmount": "514566789239999872", "buyAmount": "376", "partiallyFillable": true, "kind": "sell", So the output amount should be 376 * 45566789239999872 / 514566789239999872 = 33.29618839090851 =round because on 0 decimals=> 34

But, real calculations in driver:

reference prices:
"0x30ae41d5f9988d359c733232c6c693c0e645c77e": {
  "symbol": "WAAC",
  "trusted": false,
  "decimals": 0,
  "referencePrice": "1305051573483203635350678416654336",
  "availableBalance": "58"
},
"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": {
  "symbol": null,
  "trusted": true,
  "decimals": null,
  "referencePrice": "1000000000000000000",
  "availableBalance": "0"
},

clearing: prices: {
  "0x30aE41D5f9988D359c733232C6c693c0e645C77E": "44681665420184319",
  "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": "34"
 }

trade:      {
  "fee": "885123819815553",
  "kind": "fulfillment",
  "order": "0x0ca05899527076ccb83c52a1d3bc5f8ebbdb50addd76e19d2e6254d4d4c6cada7499003740393bec0ece8745e099c2eb3f59dc9d671ed010",
  "executedAmount": "44681665420184319"
 }

from clearin prices reported bu solver:
clearing_sell = 34
cleating_buy = 44681665420184319

from reference pices from auction:
ref_sell = 1000000000000000000
ref_buy = 1305051573483203635350678416654336

from original order:
limit_sell = 514566789239999872
limit_buy = 376

executed = fee + exec_am = 885123819815553 + 44681665420184319 = 45566789239999872

surplus = executed * clearing_price_sell / clearing_price_buy - executed * buy_limit_price / sell_limit_price
from code https://github.com/cowprotocol/services/blob/main/crates/driver/src/domain/competition/solution/scoring.rs#L109

using real values:
((45566789239999872 * 34) / 44681665420184319) - ((45566789239999872 * 376) / 514566789239999872) = 1.3773364115070734 (round to 1) in buy token

convert surplus to eth using ref price
1 * 1305051573483203635350678416654336 / 1000000000000000000 = 1305051573483203.8

score from driver (fork of original driver) who submitted tx: 1305051573483203

Impact

Indicate how significant you believe the impact of the bug is. Bugs that lead to data loss or corruption would be considered critical. In such cases, please also add the critical label.

To reproduce

Trade partially fillable order with target token with decimal = 0

Expected behaviour

Expected to return score=0 Actual: score isn't zero so transaction submitted onchain and solver blacklisted

services version/commit hash and environment

Environment: production

Additional context

This issue appears in forked driver code, so it seems issue should be also in original cow-services master

sunce86 commented 4 hours ago

Can you check if your forked code contains the latest fixes for score calculation? I just glanced over the example and it seems to me that this ceil_div should make sure that

376 * 45566789239999872 / 514566789239999872 = 33.29618839090851 =round because on 0 decimals=> 34

which is what you expect.

kana-sama commented 3 hours ago

Thanks!