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

cowprotocol / cow-sdk / 14001954831

21 Mar 2025 10:26PM UTC coverage: 73.659% (-3.4%) from 77.101%
14001954831

Pull #253

github

anxolin
chore: improve signatures
Pull Request #253: feat(bridging): get quote + post cross-chain swap

392 of 552 branches covered (71.01%)

Branch coverage included in aggregate %.

41 of 126 new or added lines in 16 files covered. (32.54%)

23 existing lines in 5 files now uncovered.

844 of 1126 relevant lines covered (74.96%)

16.39 hits per line

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

0.0
/src/bridging/BridgingSdk/getQuoteWithBridging.ts
1
import { latest } from '@cowprotocol/app-data'
2
import { MetadataApi } from '@cowprotocol/app-data'
3
import { getHookMockForCostEstimation } from '../../hooks/utils'
4
import {
5
  generateAppDataFromDoc,
6
  postSwapOrderFromQuote,
7
  QuoteResults,
8
  SwapAdvancedSettings,
9
  TradeParameters,
10
  TradingSdk,
11
} from '../../trading'
12
import {
13
  BridgeHook,
14
  BridgeProvider,
15
  BridgeQuoteAndPost,
16
  BridgeQuoteResult,
17
  BridgeQuoteResults,
18
  GetErc20Decimals,
19
  QuoteBridgeRequest,
20
  QuoteBridgeRequestWithoutAmount,
21
} from '../types'
22
import { Signer } from '@ethersproject/abstract-signer'
23
import { getSigner } from '../../common/utils/wallet'
24

25
export async function getQuoteWithBridge<T extends BridgeQuoteResult>(params: {
26
  quoteBridgeRequest: QuoteBridgeRequest
27
  advancedSettings?: SwapAdvancedSettings
28
  provider: BridgeProvider<T>
29
  tradingSdk: TradingSdk
30
  getErc20Decimals: GetErc20Decimals
31
}): Promise<BridgeQuoteAndPost> {
NEW
32
  const { provider, quoteBridgeRequest, advancedSettings, getErc20Decimals, tradingSdk } = params
×
NEW
33
  const { sellTokenAddress, amount, signer: signerLike, ...rest } = quoteBridgeRequest
×
34

35
  // Get the mocked hook (for estimating the additional swap costs)
NEW
36
  const bridgeQuoteRequestWithoutAmount = await getBaseBridgeQuoteRequest({
×
37
    quoteBridgeRequest,
38
    provider,
39
    getErc20Decimals,
40
  })
41

42
  // Get the hook mock for cost estimation
NEW
43
  const gasLimit = provider.getGasLimitEstimationForHook(bridgeQuoteRequestWithoutAmount)
×
NEW
44
  const mockedHook = getHookMockForCostEstimation(gasLimit)
×
45

46
  const { sellTokenAddress: intermediateToken, sellTokenDecimals: intermediaryTokenDecimals } =
NEW
47
    bridgeQuoteRequestWithoutAmount
×
48

49
  // Estimate the expected amount of intermediate tokens received in CoW Protocol's swap
NEW
50
  const swapParams: TradeParameters = {
×
51
    ...rest,
52
    sellToken: sellTokenAddress,
53
    buyToken: intermediateToken,
54
    buyTokenDecimals: intermediaryTokenDecimals,
55
    amount: amount.toString(),
56
  }
NEW
57
  const { result: swapResult, orderBookApi } = await tradingSdk.getQuoteResults(swapParams, {
×
58
    ...advancedSettings,
59
    appData: {
60
      metadata: {
61
        hooks: mockedHook,
62
      },
63
    },
64
  })
NEW
65
  const intermediateTokenAmount = swapResult.amountsAndCosts.afterSlippage.buyAmount // Estimated, as it will likely have surplus
×
66

67
  // Get the bridge result
NEW
68
  const signer = getSigner(signerLike)
×
NEW
69
  const { bridgeResult, bridgeHook, appData } = await getBridgeResult({
×
70
    quoteBridgeRequest,
71
    swapResult,
72
    bridgeQuoteRequestWithoutAmount,
73
    provider,
74
    intermediateTokenAmount,
75
    signer,
76
  })
77

78
  // Update the receiver and appData (both were mocked before we had the bridge hook)
NEW
79
  swapResult.tradeParameters.receiver = bridgeHook.recipient
×
NEW
80
  const { fullAppData, appDataKeccak256 } = await generateAppDataFromDoc(appData)
×
NEW
81
  swapResult.appDataInfo = {
×
82
    fullAppData,
83
    appDataKeccak256,
84
    doc: appData,
85
  }
86

87
  // Return the quote results with the post swap order function
NEW
88
  return {
×
89
    swap: swapResult,
90
    bridge: bridgeResult,
91
    async postSwapOrderFromQuote() {
NEW
92
      const quoteResults = {
×
93
        result: {
94
          ...swapResult,
95
          signer,
96
        },
97
        orderBookApi,
98
      }
99

NEW
100
      return postSwapOrderFromQuote(quoteResults, { ...advancedSettings, appData })
×
101
    },
102
  }
103
}
104

105
/**
106
 * Ge the base params (without the amount) for the bridge quote request
107
 */
108
async function getBaseBridgeQuoteRequest<T extends BridgeQuoteResult>(params: {
109
  quoteBridgeRequest: QuoteBridgeRequest
110
  provider: BridgeProvider<T>
111
  getErc20Decimals: GetErc20Decimals
112
}): Promise<QuoteBridgeRequestWithoutAmount> {
NEW
113
  const { provider, getErc20Decimals, quoteBridgeRequest } = params
×
NEW
114
  const { sellTokenChainId } = quoteBridgeRequest
×
115

NEW
116
  const intermediateTokens = await provider.getIntermediateTokens(quoteBridgeRequest)
×
117

NEW
118
  if (intermediateTokens.length === 0) {
×
NEW
119
    throw new Error('No path found')
×
120
  }
121

122
  // We just pick the first intermediate token for now
NEW
123
  const intermediateTokenAddress = intermediateTokens[0]
×
124

125
  // Get intermediate token decimals
NEW
126
  const intermediaryTokenDecimals = await getErc20Decimals(sellTokenChainId, intermediateTokenAddress)
×
127

128
  // Get the gas limit estimation for the hook
NEW
129
  const bridgeQuoteRequestWithoutAmount: QuoteBridgeRequestWithoutAmount = {
×
130
    ...quoteBridgeRequest,
131
    sellTokenAddress: intermediateTokenAddress,
132
    sellTokenDecimals: intermediaryTokenDecimals,
133
  }
134

NEW
135
  return bridgeQuoteRequestWithoutAmount
×
136
}
137

138
interface GetBridgeResultResult {
139
  bridgeResult: BridgeQuoteResults
140
  bridgeHook: BridgeHook
141
  appData: latest.AppDataRootSchema
142
}
143

144
async function getBridgeResult(params: {
145
  quoteBridgeRequest: QuoteBridgeRequest
146
  swapResult: QuoteResults
147
  intermediateTokenAmount: bigint
148
  bridgeQuoteRequestWithoutAmount: QuoteBridgeRequestWithoutAmount
149
  provider: BridgeProvider<BridgeQuoteResult>
150
  signer: Signer
151
}): Promise<GetBridgeResultResult> {
152
  const { swapResult, bridgeQuoteRequestWithoutAmount, provider, quoteBridgeRequest, intermediateTokenAmount, signer } =
NEW
153
    params
×
154

155
  // Get the quote for the bridging of the intermediate token to the final token
NEW
156
  const bridgingQuote = await provider.getQuote({
×
157
    ...bridgeQuoteRequestWithoutAmount,
158
    amount: intermediateTokenAmount,
159
  })
160

161
  // Get the bridging call
NEW
162
  const unsignedBridgeCall = await provider.getUnsignedBridgeCall(quoteBridgeRequest, bridgingQuote)
×
163

164
  // Get the pre-authorized hook
NEW
165
  const bridgeHook = await provider.getSignedHook(quoteBridgeRequest.sellTokenChainId, unsignedBridgeCall, signer)
×
166

167
  // Generate the app data for the hook
NEW
168
  const metadataApi = new MetadataApi()
×
NEW
169
  const appData = await metadataApi.generateAppDataDoc({
×
170
    ...swapResult.appDataInfo.doc,
171
    metadata: {
172
      hooks: {
173
        post: [bridgeHook.postHook],
174
      },
175
    },
176
  })
177

178
  // Prepare the bridge result
NEW
179
  const bridgeResult: BridgeQuoteResults = {
×
180
    ...bridgingQuote,
181
    providerInfo: provider.info,
182
    tradeParameters: quoteBridgeRequest,
183
    bridgeCallDetails: {
184
      unsignedBridgeCall: unsignedBridgeCall,
185
      preAuthorizedBridgingHook: bridgeHook,
186
    },
187
  }
188

NEW
189
  return { bridgeResult, bridgeHook, appData }
×
190
}
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

© 2025 Coveralls, Inc