• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cowprotocol / cow-sdk / #1693

14 May 2025 06:27PM UTC coverage: 76.468% (+0.9%) from 75.588%
#1693

push

anxolin
fix: don't treat slippage 0 as AUTO

450 of 640 branches covered (70.31%)

Branch coverage included in aggregate %.

1009 of 1268 relevant lines covered (79.57%)

18.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.83
/src/composable/utils.ts
1
import { utils, providers, BigNumber } from 'ethers'
2
import { SupportedChainId } from '../chains'
3
import { COMPOSABLE_COW_CONTRACT_ADDRESS, EXTENSIBLE_FALLBACK_HANDLER_CONTRACT_ADDRESS } from '../common'
4
import { ExtensibleFallbackHandler__factory } from '../common/generated'
5
import { BlockInfo, ConditionalOrderParams, IsValid, IsValidResult } from './types'
6
import { Order, OrderBalance, OrderKind } from '@cowprotocol/contracts'
7
import { GPv2Order } from '../common/generated/ComposableCoW'
8

9
const ERC20_BALANCE_VALUES = ['erc20', '0x5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9']
4✔
10
const EXTERNAL_BALANCE_VALUES = ['external', '0xabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea0632']
4✔
11
const INTERNAL_BALANCE_VALUES = ['internal', '0x4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce']
4✔
12
const SELL_KIND_VALUES = ['sell', '0xf3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775']
4✔
13
const BUY_KIND_VALUES = ['buy', '0x6ed88e868af0a1983e3886d5f3e95a2fafbd6c3450bc229e27342283dc429ccc']
4✔
14

15
// Define the ABI tuple for the ConditionalOrderParams struct
16
export const CONDITIONAL_ORDER_PARAMS_ABI = ['tuple(address handler, bytes32 salt, bytes staticInput)']
4✔
17

18
export const DEFAULT_TOKEN_FORMATTER = (address: string, amount: BigNumber) => `${amount}@${address}`
4✔
19

20
export function isExtensibleFallbackHandler(handler: string, chainId: SupportedChainId): boolean {
21
  return handler === EXTENSIBLE_FALLBACK_HANDLER_CONTRACT_ADDRESS[chainId]
×
22
}
23

24
export function isComposableCow(handler: string, chainId: SupportedChainId): boolean {
25
  return handler === COMPOSABLE_COW_CONTRACT_ADDRESS[chainId]
×
26
}
27

28
export async function getDomainVerifier(
29
  safe: string,
30
  domain: string,
31
  chainId: SupportedChainId,
32
  provider: providers.Provider,
33
): Promise<string> {
34
  const contract = ExtensibleFallbackHandler__factory.connect(
×
35
    EXTENSIBLE_FALLBACK_HANDLER_CONTRACT_ADDRESS[chainId],
36
    provider,
37
  )
38
  return await contract.callStatic.domainVerifiers(safe, domain)
×
39
}
40

41
export function createSetDomainVerifierTx(domain: string, verifier: string): string {
42
  return ExtensibleFallbackHandler__factory.createInterface().encodeFunctionData('setDomainVerifier', [
×
43
    domain,
44
    verifier,
45
  ])
46
}
47

48
/**
49
 * Encode the `ConditionalOrderParams` for the conditional order.
50
 *
51
 * @param params The `ConditionalOrderParams` struct representing the conditional order as taken from a merkle tree.
52
 * @returns The ABI-encoded conditional order.
53
 * @see ConditionalOrderParams
54
 */
55
export function encodeParams(params: ConditionalOrderParams): string {
56
  return utils.defaultAbiCoder.encode(CONDITIONAL_ORDER_PARAMS_ABI, [params])
91✔
57
}
58

59
/**
60
 * Decode the `ConditionalOrderParams` for the conditional order.
61
 *
62
 * @param encoded The encoded conditional order.
63
 * @returns The decoded conditional order.
64
 */
65
export function decodeParams(encoded: string): ConditionalOrderParams {
66
  const { handler, salt, staticInput } = utils.defaultAbiCoder.decode(CONDITIONAL_ORDER_PARAMS_ABI, encoded)[0]
9✔
67
  return { handler, salt, staticInput }
6✔
68
}
69

70
/**
71
 * Helper method for validating ABI types.
72
 * @param types ABI types to validate against.
73
 * @param values The values to validate.
74
 * @returns {boolean} Whether the values are valid ABI for the given types.
75
 */
76
// eslint-disable-next-line @typescript-eslint/no-explicit-any
77
export function isValidAbi(types: readonly (string | utils.ParamType)[], values: any[]): boolean {
78
  try {
43✔
79
    utils.defaultAbiCoder.encode(types, values)
43✔
80
  } catch {
81
    return false
3✔
82
  }
83
  return true
40✔
84
}
85

86
export async function getBlockInfo(provider: providers.Provider): Promise<BlockInfo> {
87
  const block = await provider.getBlock('latest')
2✔
88

89
  return {
2✔
90
    blockNumber: block.number,
91
    blockTimestamp: block.timestamp,
92
  }
93
}
94

95
export function formatEpoch(epoch: number): string {
96
  return new Date(epoch * 1000).toISOString()
20✔
97
}
98

99
/**
100
 * Convert a balance source/destination hash to a string
101
 *
102
 * @param balance balance source/destination hash
103
 * @returns string representation of the balance
104
 * @throws if the balance is not recognized
105
 */
106
function balanceToString(balance: string) {
107
  if (ERC20_BALANCE_VALUES.includes(balance)) {
8!
108
    return OrderBalance.ERC20
8✔
109
  } else if (EXTERNAL_BALANCE_VALUES.includes(balance)) {
×
110
    return OrderBalance.EXTERNAL
×
111
  } else if (INTERNAL_BALANCE_VALUES.includes(balance)) {
×
112
    return OrderBalance.INTERNAL
×
113
  } else {
114
    throw new Error(`Unknown balance type: ${balance}`)
×
115
  }
116
}
117

118
/**
119
 * Convert an order kind hash to a string
120
 * @param kind of order in hash format
121
 * @returns string representation of the order kind
122
 */
123
function kindToString(kind: string) {
124
  if (SELL_KIND_VALUES.includes(kind)) {
4✔
125
    return OrderKind.SELL
1✔
126
  } else if (BUY_KIND_VALUES.includes(kind)) {
3!
127
    return OrderKind.BUY
3✔
128
  } else {
129
    throw new Error(`Unknown kind: ${kind}`)
×
130
  }
131
}
132

133
export function fromStructToOrder(order: GPv2Order.DataStruct): Order {
134
  const {
135
    sellToken,
136
    sellAmount,
137
    buyToken,
138
    buyAmount,
139
    buyTokenBalance,
140
    sellTokenBalance,
141
    feeAmount,
142
    kind,
143
    receiver,
144
    validTo,
145
    partiallyFillable,
146
    appData,
147
  } = order
4✔
148

149
  return {
4✔
150
    sellToken,
151
    sellAmount,
152
    buyToken,
153
    buyAmount,
154
    feeAmount,
155
    receiver,
156
    partiallyFillable,
157
    appData,
158
    validTo: Number(validTo),
159
    kind: kindToString(kind.toString()),
160
    sellTokenBalance: balanceToString(sellTokenBalance.toString()),
161
    buyTokenBalance: balanceToString(buyTokenBalance.toString()),
162
  }
163
}
164

165
export function getIsValidResult(result: IsValidResult): result is IsValid {
166
  return result.isValid
49✔
167
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc