@cowprotocol/cow-sdk 6.3.2 → 7.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +276 -192
- package/dist/CHANGELOG.md +24 -0
- package/dist/README.md +276 -192
- package/dist/index.d.mts +73 -0
- package/dist/index.d.ts +73 -11
- package/dist/index.js +86 -27
- package/dist/index.mjs +49 -0
- package/dist/package.json +71 -91
- package/package.json +71 -91
- package/LICENSE-APACHE +0 -201
- package/LICENSE-MIT +0 -21
- package/dist/COPYRIGHT.md +0 -13
- package/dist/bridging/BridgingSdk/BridgingSdk.d.ts +0 -87
- package/dist/bridging/BridgingSdk/findBridgeProviderFromHook.d.ts +0 -2
- package/dist/bridging/BridgingSdk/getBridgeSignedHook.d.ts +0 -8
- package/dist/bridging/BridgingSdk/getCrossChainOrder.d.ts +0 -16
- package/dist/bridging/BridgingSdk/getQuoteWithBridge.d.ts +0 -3
- package/dist/bridging/BridgingSdk/getQuoteWithoutBridge.d.ts +0 -7
- package/dist/bridging/BridgingSdk/mock/bridgeRequestMocks.d.ts +0 -21
- package/dist/bridging/BridgingSdk/types.d.ts +0 -43
- package/dist/bridging/const.d.ts +0 -6
- package/dist/bridging/errors.d.ts +0 -22
- package/dist/bridging/index.d.ts +0 -8
- package/dist/bridging/providers/across/AcrossApi.d.ts +0 -30
- package/dist/bridging/providers/across/AcrossBridgeProvider.d.ts +0 -44
- package/dist/bridging/providers/across/abi.d.ts +0 -154
- package/dist/bridging/providers/across/const/contracts.d.ts +0 -3
- package/dist/bridging/providers/across/const/interfaces.d.ts +0 -3
- package/dist/bridging/providers/across/const/misc.d.ts +0 -2
- package/dist/bridging/providers/across/const/tokens.d.ts +0 -11
- package/dist/bridging/providers/across/createAcrossDepositCall.d.ts +0 -9
- package/dist/bridging/providers/across/getDepositParams.d.ts +0 -4
- package/dist/bridging/providers/across/types.d.ts +0 -242
- package/dist/bridging/providers/across/util.d.ts +0 -43
- package/dist/bridging/providers/bungee/BungeeApi.d.ts +0 -68
- package/dist/bridging/providers/bungee/BungeeBridgeProvider.d.ts +0 -45
- package/dist/bridging/providers/bungee/abi.d.ts +0 -203
- package/dist/bridging/providers/bungee/const/contracts.d.ts +0 -4
- package/dist/bridging/providers/bungee/const/misc.d.ts +0 -8
- package/dist/bridging/providers/bungee/createBungeeDepositCall.d.ts +0 -7
- package/dist/bridging/providers/bungee/getBridgingStatusFromEvents.d.ts +0 -3
- package/dist/bridging/providers/bungee/types.d.ts +0 -268
- package/dist/bridging/providers/bungee/util.d.ts +0 -62
- package/dist/bridging/providers/mock/MockBridgeProvider.d.ts +0 -26
- package/dist/bridging/providers/utils/getGasLimitEstimationForHook.d.ts +0 -10
- package/dist/bridging/types.d.ts +0 -333
- package/dist/bridging/utils.d.ts +0 -9
- package/dist/chains/const/index.d.ts +0 -25
- package/dist/chains/const/path.d.ts +0 -1
- package/dist/chains/details/arbitrum.d.ts +0 -7
- package/dist/chains/details/avalanche.d.ts +0 -2
- package/dist/chains/details/base.d.ts +0 -7
- package/dist/chains/details/bnb.d.ts +0 -2
- package/dist/chains/details/gnosis.d.ts +0 -7
- package/dist/chains/details/index.d.ts +0 -10
- package/dist/chains/details/lens.d.ts +0 -2
- package/dist/chains/details/mainnet.d.ts +0 -7
- package/dist/chains/details/optimism.d.ts +0 -2
- package/dist/chains/details/polygon.d.ts +0 -2
- package/dist/chains/details/sepolia.d.ts +0 -7
- package/dist/chains/index.d.ts +0 -4
- package/dist/chains/types.d.ts +0 -133
- package/dist/chains/utils.d.ts +0 -19
- package/dist/common/consts/config.d.ts +0 -9
- package/dist/common/consts/contracts.d.ts +0 -45
- package/dist/common/consts/ipfs.d.ts +0 -2
- package/dist/common/consts/order.d.ts +0 -1
- package/dist/common/consts/path.d.ts +0 -1
- package/dist/common/consts/tokens.d.ts +0 -9
- package/dist/common/generated/CoWShed.d.ts +0 -219
- package/dist/common/generated/CoWShedFactory.d.ts +0 -191
- package/dist/common/generated/ComposableCoW.d.ts +0 -340
- package/dist/common/generated/EthFlow.d.ts +0 -117
- package/dist/common/generated/ExtensibleFallbackHandler.d.ts +0 -282
- package/dist/common/generated/GPv2Settlement.d.ts +0 -107
- package/dist/common/generated/TWAP.d.ts +0 -141
- package/dist/common/generated/common.d.ts +0 -21
- package/dist/common/generated/factories/CoWShedFactory__factory.d.ts +0 -250
- package/dist/common/generated/factories/CoWShed__factory.d.ts +0 -254
- package/dist/common/generated/factories/ComposableCoW__factory.d.ts +0 -475
- package/dist/common/generated/factories/EthFlow__factory.d.ts +0 -124
- package/dist/common/generated/factories/ExtensibleFallbackHandler__factory.d.ts +0 -389
- package/dist/common/generated/factories/GPv2Settlement__factory.d.ts +0 -81
- package/dist/common/generated/factories/TWAP__factory.d.ts +0 -260
- package/dist/common/generated/factories/index.d.ts +0 -7
- package/dist/common/generated/index.d.ts +0 -15
- package/dist/common/index.d.ts +0 -12
- package/dist/common/types/config.d.ts +0 -70
- package/dist/common/types/cow-error.d.ts +0 -4
- package/dist/common/types/ethereum.d.ts +0 -5
- package/dist/common/types/tokens.d.ts +0 -12
- package/dist/common/types/wallets.d.ts +0 -5
- package/dist/common/utils/common.d.ts +0 -1
- package/dist/common/utils/config.d.ts +0 -4
- package/dist/common/utils/log.d.ts +0 -2
- package/dist/common/utils/math.d.ts +0 -19
- package/dist/common/utils/order.d.ts +0 -4
- package/dist/common/utils/serialize.d.ts +0 -1
- package/dist/common/utils/wallet.d.ts +0 -3
- package/dist/composable/ConditionalOrder.d.ts +0 -206
- package/dist/composable/ConditionalOrderFactory.d.ts +0 -19
- package/dist/composable/Multiplexer.d.ts +0 -174
- package/dist/composable/contracts.d.ts +0 -6
- package/dist/composable/generated/ComposableCoW.d.ts +0 -340
- package/dist/composable/generated/ExtensibleFallbackHandler.d.ts +0 -282
- package/dist/composable/generated/TWAP.d.ts +0 -141
- package/dist/composable/generated/common.d.ts +0 -21
- package/dist/composable/generated/factories/ComposableCoW__factory.d.ts +0 -475
- package/dist/composable/generated/factories/ExtensibleFallbackHandler__factory.d.ts +0 -389
- package/dist/composable/generated/factories/TWAP__factory.d.ts +0 -260
- package/dist/composable/generated/factories/index.d.ts +0 -3
- package/dist/composable/generated/index.d.ts +0 -7
- package/dist/composable/index.d.ts +0 -6
- package/dist/composable/orderTypes/Twap.d.ts +0 -242
- package/dist/composable/orderTypes/index.d.ts +0 -3
- package/dist/composable/orderTypes/test/TestConditionalOrder.d.ts +0 -25
- package/dist/composable/types.d.ts +0 -133
- package/dist/composable/utils.d.ts +0 -37
- package/dist/cow-shed/CowShedSdk.d.ts +0 -74
- package/dist/cow-shed/contracts/CoWShedHooks.d.ts +0 -46
- package/dist/cow-shed/contracts/utils.d.ts +0 -4
- package/dist/cow-shed/index.d.ts +0 -3
- package/dist/cow-shed/types.d.ts +0 -17
- package/dist/docs/architecture.md +0 -353
- package/dist/examples/cra/README.md +0 -21
- package/dist/hooks/utils.d.ts +0 -3
- package/dist/index-ba4aa036.js +0 -29
- package/dist/index-ba4aa036.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.modern.mjs +0 -2
- package/dist/index.modern.mjs.map +0 -1
- package/dist/index.module.js +0 -29
- package/dist/index.module.js.map +0 -1
- package/dist/order-book/api.d.ts +0 -235
- package/dist/order-book/generated/index.d.ts +0 -55
- package/dist/order-book/generated/models/Address.d.ts +0 -4
- package/dist/order-book/generated/models/AppData.d.ts +0 -7
- package/dist/order-book/generated/models/AppDataHash.d.ts +0 -6
- package/dist/order-book/generated/models/AppDataObject.d.ts +0 -7
- package/dist/order-book/generated/models/Auction.d.ts +0 -30
- package/dist/order-book/generated/models/AuctionOrder.d.ts +0 -92
- package/dist/order-book/generated/models/AuctionPrices.d.ts +0 -6
- package/dist/order-book/generated/models/BigUint.d.ts +0 -4
- package/dist/order-book/generated/models/BuyTokenDestination.d.ts +0 -7
- package/dist/order-book/generated/models/CallData.d.ts +0 -4
- package/dist/order-book/generated/models/CompetitionAuction.d.ts +0 -14
- package/dist/order-book/generated/models/CompetitionOrderStatus.d.ts +0 -29
- package/dist/order-book/generated/models/EcdsaSignature.d.ts +0 -4
- package/dist/order-book/generated/models/EcdsaSigningScheme.d.ts +0 -7
- package/dist/order-book/generated/models/EthflowData.d.ts +0 -20
- package/dist/order-book/generated/models/ExecutedAmounts.d.ts +0 -5
- package/dist/order-book/generated/models/ExecutedProtocolFee.d.ts +0 -8
- package/dist/order-book/generated/models/FeePolicy.d.ts +0 -7
- package/dist/order-book/generated/models/InteractionData.d.ts +0 -11
- package/dist/order-book/generated/models/NativePriceResponse.d.ts +0 -10
- package/dist/order-book/generated/models/OnchainOrderData.d.ts +0 -24
- package/dist/order-book/generated/models/Order.d.ts +0 -3
- package/dist/order-book/generated/models/OrderCancellation.d.ts +0 -14
- package/dist/order-book/generated/models/OrderCancellationError.d.ts +0 -15
- package/dist/order-book/generated/models/OrderCancellations.d.ts +0 -18
- package/dist/order-book/generated/models/OrderClass.d.ts +0 -8
- package/dist/order-book/generated/models/OrderCreation.d.ts +0 -80
- package/dist/order-book/generated/models/OrderKind.d.ts +0 -7
- package/dist/order-book/generated/models/OrderMetaData.d.ts +0 -100
- package/dist/order-book/generated/models/OrderParameters.d.ts +0 -53
- package/dist/order-book/generated/models/OrderPostError.d.ts +0 -35
- package/dist/order-book/generated/models/OrderQuoteRequest.d.ts +0 -58
- package/dist/order-book/generated/models/OrderQuoteResponse.d.ts +0 -27
- package/dist/order-book/generated/models/OrderQuoteSide.d.ts +0 -26
- package/dist/order-book/generated/models/OrderQuoteSideKindBuy.d.ts +0 -3
- package/dist/order-book/generated/models/OrderQuoteSideKindSell.d.ts +0 -3
- package/dist/order-book/generated/models/OrderQuoteValidity.d.ts +0 -14
- package/dist/order-book/generated/models/OrderStatus.d.ts +0 -10
- package/dist/order-book/generated/models/PreSignature.d.ts +0 -4
- package/dist/order-book/generated/models/PriceEstimationError.d.ts +0 -12
- package/dist/order-book/generated/models/PriceImprovement.d.ts +0 -12
- package/dist/order-book/generated/models/PriceQuality.d.ts +0 -16
- package/dist/order-book/generated/models/Quote.d.ts +0 -19
- package/dist/order-book/generated/models/SellTokenSource.d.ts +0 -8
- package/dist/order-book/generated/models/Signature.d.ts +0 -6
- package/dist/order-book/generated/models/SigningScheme.d.ts +0 -9
- package/dist/order-book/generated/models/SolverCompetitionResponse.d.ts +0 -30
- package/dist/order-book/generated/models/SolverSettlement.d.ts +0 -47
- package/dist/order-book/generated/models/Surplus.d.ts +0 -7
- package/dist/order-book/generated/models/TokenAmount.d.ts +0 -4
- package/dist/order-book/generated/models/TotalSurplus.d.ts +0 -10
- package/dist/order-book/generated/models/Trade.d.ts +0 -57
- package/dist/order-book/generated/models/TransactionHash.d.ts +0 -4
- package/dist/order-book/generated/models/UID.d.ts +0 -8
- package/dist/order-book/generated/models/Volume.d.ts +0 -6
- package/dist/order-book/index.d.ts +0 -5
- package/dist/order-book/mock.d.ts +0 -63
- package/dist/order-book/quoteAmountsAndCostsUtils.d.ts +0 -35
- package/dist/order-book/request.d.ts +0 -49
- package/dist/order-book/transformOrder.d.ts +0 -10
- package/dist/order-book/types.d.ts +0 -74
- package/dist/order-signing/index.d.ts +0 -2
- package/dist/order-signing/orderSigningUtils.d.ts +0 -97
- package/dist/order-signing/types.d.ts +0 -55
- package/dist/order-signing/utils.d.ts +0 -49
- package/dist/schemas/trading/LimitOrderAdvancedSettings.ts +0 -422
- package/dist/schemas/trading/LimitTradeParameters.ts +0 -229
- package/dist/schemas/trading/QuoteResultsSerialized.ts +0 -1151
- package/dist/schemas/trading/QuoterParameters.ts +0 -43
- package/dist/schemas/trading/SwapAdvancedSettings.ts +0 -708
- package/dist/schemas/trading/TradeParameters.ts +0 -217
- package/dist/src/bridging/PROVIDER_README.md +0 -796
- package/dist/src/bridging/README.md +0 -718
- package/dist/src/cow-shed/README.md +0 -60
- package/dist/src/trading/README.md +0 -544
- package/dist/src/weiroll/README.md +0 -58
- package/dist/subgraph/api.d.ts +0 -77
- package/dist/subgraph/graphql.d.ts +0 -3203
- package/dist/subgraph/index.d.ts +0 -1
- package/dist/subgraph/queries.d.ts +0 -14
- package/dist/test/getWallet.d.ts +0 -5
- package/dist/test/utils.d.ts +0 -1
- package/dist/trading/appDataUtils.d.ts +0 -5
- package/dist/trading/calculateUniqueOrderId.d.ts +0 -5
- package/dist/trading/consts.d.ts +0 -6
- package/dist/trading/getEthFlowTransaction.d.ts +0 -12
- package/dist/trading/getOrderToSign.d.ts +0 -11
- package/dist/trading/getOrderTypedData.d.ts +0 -4
- package/dist/trading/getPreSignTransaction.d.ts +0 -4
- package/dist/trading/getQuote.d.ts +0 -26
- package/dist/trading/index.d.ts +0 -21
- package/dist/trading/postCoWProtocolTrade.d.ts +0 -4
- package/dist/trading/postLimitOrder.d.ts +0 -3
- package/dist/trading/postSellNativeCurrencyOrder.d.ts +0 -4
- package/dist/trading/postSwapOrder.d.ts +0 -5
- package/dist/trading/suggestSlippageBps.d.ts +0 -13
- package/dist/trading/suggestSlippageFromFee.d.ts +0 -19
- package/dist/trading/suggestSlippageFromVolume.d.ts +0 -10
- package/dist/trading/tradingSdk.d.ts +0 -26
- package/dist/trading/types.d.ts +0 -221
- package/dist/trading/utils/getPartnerFeeBps.d.ts +0 -2
- package/dist/trading/utils/misc.d.ts +0 -27
- package/dist/trading/utils/slippage.d.ts +0 -16
- package/dist/utils-5a0554e7.js +0 -2
- package/dist/utils-5a0554e7.js.map +0 -1
- package/dist/utils-6b3b66e7.js +0 -2
- package/dist/utils-6b3b66e7.js.map +0 -1
- package/dist/utils-c9bb9a82.js +0 -2
- package/dist/utils-c9bb9a82.js.map +0 -1
- package/dist/utils.d.ts +0 -3
- package/dist/weiroll/index.d.ts +0 -23
|
@@ -1,796 +0,0 @@
|
|
|
1
|
-
# Bridge Provider Development Guide
|
|
2
|
-
|
|
3
|
-
This guide explains how to develop a new bridge provider for the `CoW Protocol` `BridgingSDK`.
|
|
4
|
-
Bridge providers integrate third-party bridging protocols into the `CoW ecosystem`, enabling cross-chain token swaps.
|
|
5
|
-
|
|
6
|
-
> You can see existing providers code in [`src/bridging/providers`](./providers) directory.
|
|
7
|
-
|
|
8
|
-
## Table of Contents
|
|
9
|
-
|
|
10
|
-
1. [Overview](#overview)
|
|
11
|
-
2. [Architecture](#architecture)
|
|
12
|
-
3. [Getting Started](#getting-started)
|
|
13
|
-
4. [BridgeProvider Interface](#bridgeprovider-interface)
|
|
14
|
-
5. [Implementation Guide](#implementation-guide)
|
|
15
|
-
6. [Required Components](#required-components)
|
|
16
|
-
7. [Testing Your Provider](#testing-your-provider)
|
|
17
|
-
8. [Best Practices](#best-practices)
|
|
18
|
-
9. [Integration Examples](#integration-examples)
|
|
19
|
-
10. [Troubleshooting](#troubleshooting)
|
|
20
|
-
|
|
21
|
-
## Overview
|
|
22
|
-
|
|
23
|
-
A bridge provider acts as an adapter between the BridgingSdk and external bridging protocols. It handles:
|
|
24
|
-
|
|
25
|
-
- **Quote Generation**: Fetching bridging quotes from external APIs
|
|
26
|
-
- **Transaction Building**: Creating unsigned bridge transactions
|
|
27
|
-
- **Hook Management**: Generating pre-authorized hooks for CoW settlement
|
|
28
|
-
- **Status Tracking**: Monitoring bridge transaction status
|
|
29
|
-
- **Token Support**: Managing supported tokens across chains
|
|
30
|
-
|
|
31
|
-
### Key Concepts
|
|
32
|
-
|
|
33
|
-
- **Intermediate Tokens**: Tokens on the source chain that can be bridged to the destination chain
|
|
34
|
-
- **CoW Shed**: Proxy contracts that hold user funds during bridging
|
|
35
|
-
- **Post Hooks**: Smart contract calls executed after order settlement to initiate bridging
|
|
36
|
-
- **Bridge Quotes**: Price and timing estimates for cross-chain transfers
|
|
37
|
-
|
|
38
|
-
## Getting Started
|
|
39
|
-
|
|
40
|
-
### 1. Create Provider Structure
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
src/bridging/providers/your-bridge/
|
|
44
|
-
├── YourBridgeProvider.ts # Main provider class
|
|
45
|
-
├── YourBridgeApi.ts # API client
|
|
46
|
-
├── types.ts # Type definitions
|
|
47
|
-
├── util.ts # Utility functions
|
|
48
|
-
├── createYourBridgeCall.ts # Transaction builder
|
|
49
|
-
└── const/
|
|
50
|
-
├── contracts.ts # Contract addresses
|
|
51
|
-
└── misc.ts # Constants
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### 2. Define Provider Options
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
import { JsonRpcProvider } from '@ethersproject/providers'
|
|
58
|
-
import { SupportedChainId, CowShedSdkOptions } from '../../../chains'
|
|
59
|
-
|
|
60
|
-
export interface YourBridgeProviderOptions {
|
|
61
|
-
getRpcProvider(chainId: SupportedChainId): JsonRpcProvider
|
|
62
|
-
|
|
63
|
-
// API configuration
|
|
64
|
-
apiOptions?: YourBridgeApiOptions
|
|
65
|
-
|
|
66
|
-
// CoW Shed configuration
|
|
67
|
-
cowShedOptions?: CowShedSdkOptions
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export interface YourBridgeApiOptions {
|
|
71
|
-
baseUrl?: string
|
|
72
|
-
apiKey?: string
|
|
73
|
-
// Add provider-specific options
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## BridgeProvider Interface
|
|
78
|
-
|
|
79
|
-
The [`BridgeProvider<Q extends BridgeQuoteResult>`](types.ts#L155) interface defines all methods your provider must implement:
|
|
80
|
-
|
|
81
|
-
### Core Properties
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
interface BridgeProvider<Q extends BridgeQuoteResult> {
|
|
85
|
-
// Provider metadata
|
|
86
|
-
info: BridgeProviderInfo
|
|
87
|
-
|
|
88
|
-
// RPC provider access
|
|
89
|
-
getRpcProvider(chainId: SupportedChainId): JsonRpcProvider
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Required Methods
|
|
94
|
-
|
|
95
|
-
| Method | Purpose | Required |
|
|
96
|
-
| -------------------------------- | ------------------------------------- | ---------- |
|
|
97
|
-
| `getNetworks()` | Get supported destination chains | ✅ |
|
|
98
|
-
| `getBuyTokens()` | Get supported tokens for a chain | ✅ |
|
|
99
|
-
| `getIntermediateTokens()` | Get bridgeable tokens on source chain | ✅ |
|
|
100
|
-
| `getQuote()` | Generate bridge quote | ✅ |
|
|
101
|
-
| `getUnsignedBridgeCall()` | Create unsigned bridge transaction | ✅ |
|
|
102
|
-
| `getGasLimitEstimationForHook()` | Estimate gas for hook execution | ✅ |
|
|
103
|
-
| `getSignedHook()` | Generate pre-authorized hook | ✅ |
|
|
104
|
-
| `getStatus()` | Check bridge transaction status | ✅ |
|
|
105
|
-
| `getBridgingParams()` | Extract bridge params from settlement | ✅ |
|
|
106
|
-
| `getExplorerUrl()` | Get bridge explorer URL | ✅ |
|
|
107
|
-
| `decodeBridgeHook()` | Decode hook data | Optional\* |
|
|
108
|
-
| `getCancelBridgingTx()` | Create cancel transaction | Optional\* |
|
|
109
|
-
| `getRefundBridgingTx()` | Create refund transaction | Optional\* |
|
|
110
|
-
|
|
111
|
-
\*Can throw "Not implemented" error if unsupported
|
|
112
|
-
|
|
113
|
-
## Implementation Guide
|
|
114
|
-
|
|
115
|
-
### Step 1: Basic Provider Class
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
import { BridgeProvider, BridgeProviderInfo, BridgeQuoteResult } from '../../types'
|
|
119
|
-
import { SupportedChainId, mainnet, polygon, arbitrumOne, optimism, ChainInfo } from '../../../chains'
|
|
120
|
-
import { CowShedSdk } from '../../../cow-shed'
|
|
121
|
-
import { JsonRpcProvider } from '@ethersproject/providers'
|
|
122
|
-
import { HOOK_DAPP_BRIDGE_PROVIDER_PREFIX } from '../../const'
|
|
123
|
-
|
|
124
|
-
export const YOUR_BRIDGE_HOOK_DAPP_ID = `${HOOK_DAPP_BRIDGE_PROVIDER_PREFIX}/your-bridge`
|
|
125
|
-
|
|
126
|
-
// Define supported networks
|
|
127
|
-
export const YOUR_BRIDGE_SUPPORTED_NETWORKS = [
|
|
128
|
-
mainnet,
|
|
129
|
-
polygon,
|
|
130
|
-
arbitrumOne,
|
|
131
|
-
optimism,
|
|
132
|
-
// Add your supported chains
|
|
133
|
-
// If there are no needed chains, add them to `src/chains`
|
|
134
|
-
]
|
|
135
|
-
|
|
136
|
-
export interface YourBridgeQuoteResult extends BridgeQuoteResult {
|
|
137
|
-
// Add provider-specific quote data
|
|
138
|
-
externalQuote: YourBridgeQuote
|
|
139
|
-
metadata: YourBridgeMetadata
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export class YourBridgeProvider implements BridgeProvider<YourBridgeQuoteResult> {
|
|
143
|
-
protected api: YourBridgeApi
|
|
144
|
-
protected cowShedSdk: CowShedSdk
|
|
145
|
-
public getRpcProvider: (chainId: SupportedChainId) => JsonRpcProvider
|
|
146
|
-
|
|
147
|
-
constructor(private options: YourBridgeProviderOptions) {
|
|
148
|
-
this.api = new YourBridgeApi(options.apiOptions)
|
|
149
|
-
this.cowShedSdk = new CowShedSdk(options.cowShedOptions)
|
|
150
|
-
this.getRpcProvider = options.getRpcProvider
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
info: BridgeProviderInfo = {
|
|
154
|
-
name: 'YourBridge',
|
|
155
|
-
logoUrl: `/your-bridge/logo.png`,
|
|
156
|
-
dappId: YOUR_BRIDGE_HOOK_DAPP_ID,
|
|
157
|
-
website: 'https://yourbridge.example',
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Implement all required methods...
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
> It's important to define valid `info.dappId`. It should always start with `HOOK_DAPP_BRIDGE_PROVIDER_PREFIX`
|
|
165
|
-
|
|
166
|
-
### Step 2: Network and Token Support
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
export class YourBridgeProvider implements BridgeProvider<YourBridgeQuoteResult> {
|
|
170
|
-
async getNetworks(): Promise<ChainInfo[]> {
|
|
171
|
-
// Return chains supported as destination
|
|
172
|
-
return YOUR_BRIDGE_SUPPORTED_NETWORKS
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
async getBuyTokens(params: BuyTokensParams): Promise<TokenInfo[]> {
|
|
176
|
-
// Get tokens available for purchase on target chain
|
|
177
|
-
try {
|
|
178
|
-
const tokens = await this.api.getSupportedTokens({
|
|
179
|
-
chainId: params.buyChainId,
|
|
180
|
-
sellChainId: params.sellChainId,
|
|
181
|
-
sellTokenAddress: params.sellTokenAddress,
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
return tokens.map((token) => ({
|
|
185
|
-
chainId: token.chainId,
|
|
186
|
-
address: token.address,
|
|
187
|
-
name: token.name,
|
|
188
|
-
symbol: token.symbol,
|
|
189
|
-
decimals: token.decimals,
|
|
190
|
-
logoUrl: token.logoUrl,
|
|
191
|
-
}))
|
|
192
|
-
} catch (error) {
|
|
193
|
-
console.error('Failed to fetch buy tokens:', error)
|
|
194
|
-
return []
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async getIntermediateTokens(request: QuoteBridgeRequest): Promise<TokenInfo[]> {
|
|
199
|
-
// Validate order kind
|
|
200
|
-
if (request.kind !== OrderKind.SELL) {
|
|
201
|
-
throw new BridgeProviderQuoteError(BridgeQuoteErrors.ONLY_SELL_ORDER_SUPPORTED, { kind: request.kind })
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Get tokens on source chain that can bridge to target token
|
|
205
|
-
const { sellTokenChainId, buyTokenChainId, buyTokenAddress } = request
|
|
206
|
-
|
|
207
|
-
const intermediateTokens = await this.api.getIntermediateTokens({
|
|
208
|
-
fromChainId: sellTokenChainId,
|
|
209
|
-
toChainId: buyTokenChainId,
|
|
210
|
-
toTokenAddress: buyTokenAddress,
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
// Return sorted by liquidity/priority
|
|
214
|
-
return intermediateTokens
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### Step 3: Quote Generation
|
|
220
|
-
|
|
221
|
-
```typescript
|
|
222
|
-
export class YourBridgeProvider implements BridgeProvider<YourBridgeQuoteResult> {
|
|
223
|
-
async getQuote(request: QuoteBridgeRequest): Promise<YourBridgeQuoteResult> {
|
|
224
|
-
const {
|
|
225
|
-
sellTokenAddress, // This is the intermediate token
|
|
226
|
-
sellTokenChainId,
|
|
227
|
-
buyTokenChainId,
|
|
228
|
-
buyTokenAddress,
|
|
229
|
-
amount,
|
|
230
|
-
receiver,
|
|
231
|
-
account,
|
|
232
|
-
owner,
|
|
233
|
-
} = request
|
|
234
|
-
|
|
235
|
-
// Get CoW Shed account for the owner
|
|
236
|
-
const ownerAddress = owner ?? account
|
|
237
|
-
const cowShedAccount = this.cowShedSdk.getCowShedAccount(sellTokenChainId, ownerAddress)
|
|
238
|
-
|
|
239
|
-
// Request quote from external bridge
|
|
240
|
-
const externalQuote = await this.api.getQuote({
|
|
241
|
-
fromChainId: sellTokenChainId,
|
|
242
|
-
toChainId: buyTokenChainId,
|
|
243
|
-
fromTokenAddress: sellTokenAddress,
|
|
244
|
-
toTokenAddress: buyTokenAddress,
|
|
245
|
-
amount: amount.toString(),
|
|
246
|
-
fromAddress: cowShedAccount,
|
|
247
|
-
toAddress: receiver ?? account,
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
// Validate quote
|
|
251
|
-
await this.validateQuote(externalQuote, request)
|
|
252
|
-
|
|
253
|
-
// Convert to standard BridgeQuoteResult format
|
|
254
|
-
return this.convertToBridgeQuote(externalQuote, request)
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
private async validateQuote(externalQuote: YourBridgeQuote, request: QuoteBridgeRequest): Promise<void> {
|
|
258
|
-
// Add validation logic
|
|
259
|
-
if (!externalQuote.isValid) {
|
|
260
|
-
throw new BridgeProviderQuoteError(BridgeQuoteErrors.NO_ROUTES_FOUND, { quote: externalQuote })
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
private convertToBridgeQuote(externalQuote: YourBridgeQuote, request: QuoteBridgeRequest): YourBridgeQuoteResult {
|
|
265
|
-
return {
|
|
266
|
-
isSell: true,
|
|
267
|
-
amountsAndCosts: {
|
|
268
|
-
costs: {
|
|
269
|
-
bridgingFee: {
|
|
270
|
-
feeBps: externalQuote.feeBps,
|
|
271
|
-
amountInSellCurrency: BigInt(externalQuote.bridgeFee),
|
|
272
|
-
amountInBuyCurrency: BigInt(externalQuote.bridgeFeeInBuyToken),
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
beforeFee: {
|
|
276
|
-
sellAmount: BigInt(request.amount),
|
|
277
|
-
buyAmount: BigInt(externalQuote.outputAmount),
|
|
278
|
-
},
|
|
279
|
-
afterFee: {
|
|
280
|
-
sellAmount: BigInt(request.amount),
|
|
281
|
-
buyAmount: BigInt(externalQuote.outputAmountAfterFee),
|
|
282
|
-
},
|
|
283
|
-
afterSlippage: {
|
|
284
|
-
sellAmount: BigInt(request.amount),
|
|
285
|
-
buyAmount: BigInt(externalQuote.minOutputAmount),
|
|
286
|
-
},
|
|
287
|
-
slippageBps: externalQuote.slippageBps,
|
|
288
|
-
},
|
|
289
|
-
quoteTimestamp: Date.now(),
|
|
290
|
-
expectedFillTimeSeconds: externalQuote.estimatedTime,
|
|
291
|
-
fees: {
|
|
292
|
-
bridgeFee: BigInt(externalQuote.bridgeFee),
|
|
293
|
-
destinationGasFee: BigInt(externalQuote.destinationGasFee),
|
|
294
|
-
},
|
|
295
|
-
limits: {
|
|
296
|
-
minDeposit: BigInt(externalQuote.minAmount),
|
|
297
|
-
maxDeposit: BigInt(externalQuote.maxAmount),
|
|
298
|
-
},
|
|
299
|
-
// Provider-specific data
|
|
300
|
-
externalQuote,
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### Step 4: Transaction Building
|
|
307
|
-
|
|
308
|
-
> It very depends on your smart-contract implementation.
|
|
309
|
-
> Basically, the smart-contract should:
|
|
310
|
-
>
|
|
311
|
-
> 1. Approve sell token spending from `CoW Shed proxy`
|
|
312
|
-
> 2. Transfer funds from `CoW Shed proxy` to your deposit smart-contract
|
|
313
|
-
>
|
|
314
|
-
> See `createBungeeDepositCall` as an example
|
|
315
|
-
|
|
316
|
-
```typescript
|
|
317
|
-
export class YourBridgeProvider implements BridgeProvider<YourBridgeQuoteResult> {
|
|
318
|
-
async getUnsignedBridgeCall(request: QuoteBridgeRequest, quote: YourBridgeQuoteResult): Promise<EvmCall> {
|
|
319
|
-
// Create the bridge transaction that will be executed by CoW Shed
|
|
320
|
-
return createYourBridgeCall({
|
|
321
|
-
request,
|
|
322
|
-
quote,
|
|
323
|
-
cowShedSdk: this.cowShedSdk,
|
|
324
|
-
})
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// In createYourBridgeCall.ts
|
|
329
|
-
import { ethers } from 'ethers'
|
|
330
|
-
import { QuoteBridgeRequest } from '../../types'
|
|
331
|
-
import { EvmCall } from '../../../common'
|
|
332
|
-
|
|
333
|
-
import { YourBridgeQuoteResult } from '../types'
|
|
334
|
-
import { YOUR_BRIDGE_CONTRACTS, YOUR_BRIDGE_ABI } from '../const'
|
|
335
|
-
|
|
336
|
-
export async function createYourBridgeCall({
|
|
337
|
-
request,
|
|
338
|
-
quote,
|
|
339
|
-
}: {
|
|
340
|
-
request: QuoteBridgeRequest
|
|
341
|
-
quote: YourBridgeQuoteResult
|
|
342
|
-
}): Promise<EvmCall> {
|
|
343
|
-
const { sellTokenChainId, sellTokenAddress, amount, owner, account } = request
|
|
344
|
-
const { externalQuote } = quote
|
|
345
|
-
|
|
346
|
-
// Get bridge contract address
|
|
347
|
-
const bridgeContract = YOUR_BRIDGE_CONTRACTS[sellTokenChainId]
|
|
348
|
-
if (!bridgeContract) {
|
|
349
|
-
throw new Error(`Bridge contract not found for chain ${sellTokenChainId}`)
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// Encode bridge function call
|
|
353
|
-
const bridgeInterface = new ethers.utils.Interface(YOUR_BRIDGE_ABI)
|
|
354
|
-
const callData = bridgeInterface.encodeFunctionData('bridge', [
|
|
355
|
-
sellTokenAddress, // token to bridge
|
|
356
|
-
amount, // amount to bridge
|
|
357
|
-
externalQuote.toChainId, // destination chain
|
|
358
|
-
externalQuote.toTokenAddress, // destination token
|
|
359
|
-
externalQuote.minOutputAmount, // minimum output
|
|
360
|
-
externalQuote.recipient, // recipient
|
|
361
|
-
externalQuote.deadline, // deadline
|
|
362
|
-
externalQuote.callData, // bridge-specific data
|
|
363
|
-
])
|
|
364
|
-
|
|
365
|
-
return {
|
|
366
|
-
to: bridgeContract,
|
|
367
|
-
data: callData,
|
|
368
|
-
value: BigInt(0), // or bridge fee if ETH
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
### Step 5: Hook Management
|
|
374
|
-
|
|
375
|
-
```typescript
|
|
376
|
-
import { BridgeHook, BridgeProvider, QuoteBridgeRequest } from '../../types'
|
|
377
|
-
import { SupportedChainId } from '../../../chains'
|
|
378
|
-
import { EvmCall } from '../../../common'
|
|
379
|
-
import { Signer } from 'ethers'
|
|
380
|
-
import { getGasLimitEstimationForHook } from '../utils/getGasLimitEstimationForHook'
|
|
381
|
-
|
|
382
|
-
export class YourBridgeProvider implements BridgeProvider<YourBridgeQuoteResult> {
|
|
383
|
-
async getGasLimitEstimationForHook(
|
|
384
|
-
request: Omit<QuoteBridgeRequest, 'amount'> & { extraGas?: number; extraGasProxyCreation?: number },
|
|
385
|
-
): Promise<number> {
|
|
386
|
-
// Use utility function or implement custom gas estimation
|
|
387
|
-
return getGasLimitEstimationForHook(
|
|
388
|
-
cowshed: this.cowShedSdk,
|
|
389
|
-
request: request as QuoteBridgeRequest, // cast needed due to omit
|
|
390
|
-
provider: this.getRpcProvider(request.sellTokenChainId),
|
|
391
|
-
extraGas: request.extraGas, // to add extra gas to the hook
|
|
392
|
-
extraGasProxyCreation: request.extraGasProxyCreation // to add extra gas to the hook and deploy proxy account
|
|
393
|
-
)
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
async getSignedHook(
|
|
397
|
-
chainId: SupportedChainId,
|
|
398
|
-
unsignedCall: EvmCall,
|
|
399
|
-
signer: Signer,
|
|
400
|
-
bridgeHookNonce: string,
|
|
401
|
-
deadline: bigint,
|
|
402
|
-
hookGasLimit: number,
|
|
403
|
-
): Promise<BridgeHook> {
|
|
404
|
-
// Sign the multicall using CoW Shed SDK
|
|
405
|
-
const { signedMulticall, cowShedAccount, gasLimit } = await this.cowShedSdk.signCalls({
|
|
406
|
-
calls: [
|
|
407
|
-
{
|
|
408
|
-
target: unsignedCall.to,
|
|
409
|
-
value: unsignedCall.value,
|
|
410
|
-
callData: unsignedCall.data,
|
|
411
|
-
allowFailure: false,
|
|
412
|
-
isDelegateCall: true,
|
|
413
|
-
},
|
|
414
|
-
],
|
|
415
|
-
chainId,
|
|
416
|
-
signer,
|
|
417
|
-
gasLimit: BigInt(hookGasLimit),
|
|
418
|
-
deadline,
|
|
419
|
-
nonce: bridgeHookNonce,
|
|
420
|
-
})
|
|
421
|
-
|
|
422
|
-
const { to, data } = signedMulticall
|
|
423
|
-
return {
|
|
424
|
-
postHook: {
|
|
425
|
-
target: to,
|
|
426
|
-
callData: data,
|
|
427
|
-
gasLimit: gasLimit.toString(),
|
|
428
|
-
dappId: YOUR_BRIDGE_HOOK_DAPP_ID,
|
|
429
|
-
},
|
|
430
|
-
recipient: cowShedAccount,
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
> Note: getGasLimitEstimationForHook() implies a post-hook estimation. But it might be not trivial, because it's assumed that hook will be called with a context of CoW Shed after swap execution. It means that we expect funds are already transfered to CoW Shed after swap. But in fact there are no funds on CoW Shed on the moment of an order creation.
|
|
437
|
-
|
|
438
|
-
### Step 6: Status Tracking
|
|
439
|
-
|
|
440
|
-
```typescript
|
|
441
|
-
import { ChainId, SupportedChainId } from '../../../chains'
|
|
442
|
-
import { BridgeProvider, BridgeStatus, BridgeStatusResult, BridgingDepositParams } from '../../types'
|
|
443
|
-
|
|
444
|
-
export class YourBridgeProvider implements BridgeProvider<YourBridgeQuoteResult> {
|
|
445
|
-
async getStatus(bridgingId: string, originChainId: SupportedChainId): Promise<BridgeStatusResult> {
|
|
446
|
-
try {
|
|
447
|
-
const status = await this.api.getBridgeStatus({
|
|
448
|
-
transactionId: bridgingId,
|
|
449
|
-
originChainId,
|
|
450
|
-
})
|
|
451
|
-
|
|
452
|
-
return {
|
|
453
|
-
status: this.mapStatusToBridgeStatus(status.status),
|
|
454
|
-
fillTimeInSeconds: status.fillTime,
|
|
455
|
-
depositTxHash: status.depositTxHash,
|
|
456
|
-
fillTxHash: status.fillTxHash,
|
|
457
|
-
}
|
|
458
|
-
} catch (error) {
|
|
459
|
-
console.error('Failed to get bridge status:', error)
|
|
460
|
-
return {
|
|
461
|
-
status: BridgeStatus.UNKNOWN,
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
private mapStatusToBridgeStatus(externalStatus: string): BridgeStatus {
|
|
467
|
-
// This an example code, do not use swich/case in such cases
|
|
468
|
-
// It's better to use Record<string, BridgeStatus> instead
|
|
469
|
-
switch (externalStatus.toLowerCase()) {
|
|
470
|
-
case 'pending':
|
|
471
|
-
case 'processing':
|
|
472
|
-
return BridgeStatus.IN_PROGRESS
|
|
473
|
-
case 'completed':
|
|
474
|
-
case 'filled':
|
|
475
|
-
return BridgeStatus.EXECUTED
|
|
476
|
-
case 'expired':
|
|
477
|
-
case 'timeout':
|
|
478
|
-
return BridgeStatus.EXPIRED
|
|
479
|
-
case 'refunded':
|
|
480
|
-
case 'cancelled':
|
|
481
|
-
return BridgeStatus.REFUND
|
|
482
|
-
default:
|
|
483
|
-
return BridgeStatus.UNKNOWN
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
async getBridgingParams(
|
|
488
|
-
chainId: ChainId,
|
|
489
|
-
orderUid: string,
|
|
490
|
-
txHash: string,
|
|
491
|
-
): Promise<{ params: BridgingDepositParams; status: BridgeStatusResult } | null> {
|
|
492
|
-
try {
|
|
493
|
-
// Get transaction receipt
|
|
494
|
-
const txReceipt = await this.getRpcProvider(chainId).getTransactionReceipt(txHash)
|
|
495
|
-
|
|
496
|
-
// Parse bridge events from transaction logs
|
|
497
|
-
const bridgeParams = await this.extractBridgeParams(orderUid, txReceipt)
|
|
498
|
-
|
|
499
|
-
if (!bridgeParams) return null
|
|
500
|
-
|
|
501
|
-
return {
|
|
502
|
-
params: bridgeParams,
|
|
503
|
-
status: await this.getStatus(bridgeParams.bridgingId, chainId),
|
|
504
|
-
}
|
|
505
|
-
} catch (error) {
|
|
506
|
-
console.error('Failed to get bridging params:', error)
|
|
507
|
-
return null
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
getExplorerUrl(bridgingId: string): string {
|
|
512
|
-
return `https://yourbridge.example/tx/${bridgingId}`
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
### Type Definitions
|
|
518
|
-
|
|
519
|
-
Define comprehensive types for your provider:
|
|
520
|
-
|
|
521
|
-
```typescript
|
|
522
|
-
// types.ts
|
|
523
|
-
export interface YourBridgeQuoteRequest {
|
|
524
|
-
fromChainId: number
|
|
525
|
-
toChainId: number
|
|
526
|
-
fromTokenAddress: string
|
|
527
|
-
toTokenAddress: string
|
|
528
|
-
amount: string
|
|
529
|
-
fromAddress: string
|
|
530
|
-
toAddress: string
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
export interface YourBridgeQuote {
|
|
534
|
-
isValid: boolean
|
|
535
|
-
outputAmount: string
|
|
536
|
-
outputAmountAfterFee: string
|
|
537
|
-
minOutputAmount: string
|
|
538
|
-
bridgeFee: string
|
|
539
|
-
bridgeFeeInBuyToken: string
|
|
540
|
-
destinationGasFee: string
|
|
541
|
-
feeBps: number
|
|
542
|
-
slippageBps: number
|
|
543
|
-
estimatedTime: number
|
|
544
|
-
minAmount: string
|
|
545
|
-
maxAmount: string
|
|
546
|
-
deadline: number
|
|
547
|
-
callData: string
|
|
548
|
-
// Add provider-specific fields
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
export interface YourBridgeStatusRequest {
|
|
552
|
-
transactionId: string
|
|
553
|
-
originChainId: SupportedChainId
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
export interface YourBridgeStatus {
|
|
557
|
-
status: string
|
|
558
|
-
fillTime?: number
|
|
559
|
-
depositTxHash?: string
|
|
560
|
-
fillTxHash?: string
|
|
561
|
-
}
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
### Constants
|
|
565
|
-
|
|
566
|
-
Define contract addresses and other constants:
|
|
567
|
-
|
|
568
|
-
```typescript
|
|
569
|
-
// const/contracts.ts
|
|
570
|
-
export const YOUR_BRIDGE_CONTRACTS: Record<SupportedChainId, string> = {
|
|
571
|
-
[SupportedChainId.MAINNET]: '0x...',
|
|
572
|
-
[SupportedChainId.POLYGON]: '0x...',
|
|
573
|
-
[SupportedChainId.ARBITRUM_ONE]: '0x...',
|
|
574
|
-
[SupportedChainId.OPTIMISM]: '0x...',
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
// const/misc.ts
|
|
578
|
-
export const HOOK_DAPP_BRIDGE_PROVIDER_PREFIX = 'cow-hooks.cow.fi'
|
|
579
|
-
export const YOUR_BRIDGE_SUPPORTED_TOKENS = {
|
|
580
|
-
// Define supported token lists
|
|
581
|
-
}
|
|
582
|
-
```
|
|
583
|
-
|
|
584
|
-
## Testing Your Provider
|
|
585
|
-
|
|
586
|
-
### Unit Tests
|
|
587
|
-
|
|
588
|
-
```typescript
|
|
589
|
-
// YourBridgeProvider.test.ts
|
|
590
|
-
import { YourBridgeProvider } from '../YourBridgeProvider'
|
|
591
|
-
import { MockBridgeProvider } from '../../mock/MockBridgeProvider'
|
|
592
|
-
import { SupportedChainId } from '../../../../chains'
|
|
593
|
-
|
|
594
|
-
describe('YourBridgeProvider', () => {
|
|
595
|
-
let provider: YourBridgeProvider
|
|
596
|
-
|
|
597
|
-
beforeEach(() => {
|
|
598
|
-
provider = new YourBridgeProvider({
|
|
599
|
-
getRpcProvider: jest.fn(),
|
|
600
|
-
apiOptions: {
|
|
601
|
-
baseUrl: 'https://test-api.yourbridge.example',
|
|
602
|
-
},
|
|
603
|
-
})
|
|
604
|
-
})
|
|
605
|
-
|
|
606
|
-
describe('getNetworks', () => {
|
|
607
|
-
it('should return supported networks', async () => {
|
|
608
|
-
const networks = await provider.getNetworks()
|
|
609
|
-
expect(networks).toHaveLength(4)
|
|
610
|
-
expect(networks[0].name).toBe('Ethereum')
|
|
611
|
-
})
|
|
612
|
-
})
|
|
613
|
-
|
|
614
|
-
describe('getQuote', () => {
|
|
615
|
-
it('should return valid quote', async () => {
|
|
616
|
-
const request = {
|
|
617
|
-
sellTokenChainId: SupportedChainId.MAINNET,
|
|
618
|
-
sellTokenAddress: '0x...',
|
|
619
|
-
// ... complete request
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
const quote = await provider.getQuote(request)
|
|
623
|
-
|
|
624
|
-
expect(quote.isSell).toBe(true)
|
|
625
|
-
expect(quote.fees.bridgeFee).toBeGreaterThan(0n)
|
|
626
|
-
})
|
|
627
|
-
|
|
628
|
-
it('should throw error for BUY orders', async () => {
|
|
629
|
-
const request = {
|
|
630
|
-
kind: OrderKind.BUY,
|
|
631
|
-
// ... rest of request
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
await expect(provider.getQuote(request)).rejects.toThrow('Only sell orders are supported')
|
|
635
|
-
})
|
|
636
|
-
})
|
|
637
|
-
|
|
638
|
-
// Add more tests...
|
|
639
|
-
})
|
|
640
|
-
```
|
|
641
|
-
|
|
642
|
-
## Best Practices
|
|
643
|
-
|
|
644
|
-
### Error Handling
|
|
645
|
-
|
|
646
|
-
```typescript
|
|
647
|
-
// Use specific error types
|
|
648
|
-
throw new BridgeProviderQuoteError(BridgeQuoteErrors.INSUFFICIENT_LIQUIDITY, {
|
|
649
|
-
availableLiquidity: '1000',
|
|
650
|
-
requestedAmount: '2000',
|
|
651
|
-
})
|
|
652
|
-
|
|
653
|
-
// Handle API failures gracefully
|
|
654
|
-
try {
|
|
655
|
-
return await this.api.getQuote(params)
|
|
656
|
-
} catch (error) {
|
|
657
|
-
if (error.status === 404) {
|
|
658
|
-
throw new BridgeProviderQuoteError(BridgeQuoteErrors.NO_ROUTES_FOUND, { params })
|
|
659
|
-
}
|
|
660
|
-
throw error
|
|
661
|
-
}
|
|
662
|
-
```
|
|
663
|
-
|
|
664
|
-
### Logging
|
|
665
|
-
|
|
666
|
-
```typescript
|
|
667
|
-
import { log } from '../../../common/utils/log'
|
|
668
|
-
|
|
669
|
-
async getQuote(request: QuoteBridgeRequest): Promise<YourBridgeQuoteResult> {
|
|
670
|
-
log('Getting quote for YourBridge:', {
|
|
671
|
-
fromChain: request.sellTokenChainId,
|
|
672
|
-
toChain: request.buyTokenChainId,
|
|
673
|
-
amount: request.amount.toString(),
|
|
674
|
-
})
|
|
675
|
-
|
|
676
|
-
// ... implementation
|
|
677
|
-
}
|
|
678
|
-
```
|
|
679
|
-
|
|
680
|
-
### Validation
|
|
681
|
-
|
|
682
|
-
```typescript
|
|
683
|
-
private validateRequest(request: QuoteBridgeRequest): void {
|
|
684
|
-
if (request.amount <= 0n) {
|
|
685
|
-
throw new BridgeProviderQuoteError(
|
|
686
|
-
BridgeQuoteErrors.INVALID_AMOUNT,
|
|
687
|
-
{ amount: request.amount.toString() }
|
|
688
|
-
)
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
if (!YOUR_BRIDGE_SUPPORTED_NETWORKS.some(n => n.chainId === request.buyTokenChainId)) {
|
|
692
|
-
throw new BridgeProviderQuoteError(
|
|
693
|
-
BridgeQuoteErrors.UNSUPPORTED_CHAIN,
|
|
694
|
-
{ chainId: request.buyTokenChainId }
|
|
695
|
-
)
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
```
|
|
699
|
-
|
|
700
|
-
### Performance
|
|
701
|
-
|
|
702
|
-
```typescript
|
|
703
|
-
// Cache frequently accessed data
|
|
704
|
-
private tokenCache = new Map<string, TokenInfo[]>()
|
|
705
|
-
|
|
706
|
-
async getBuyTokens(params: BuyTokensParams): Promise<TokenInfo[]> {
|
|
707
|
-
const cacheKey = `${params.buyChainId}-${params.sellChainId}`
|
|
708
|
-
|
|
709
|
-
if (this.tokenCache.has(cacheKey)) {
|
|
710
|
-
return this.tokenCache.get(cacheKey)!
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
const tokens = await this.api.getSupportedTokens(params)
|
|
714
|
-
this.tokenCache.set(cacheKey, tokens)
|
|
715
|
-
|
|
716
|
-
return tokens
|
|
717
|
-
}
|
|
718
|
-
```
|
|
719
|
-
|
|
720
|
-
## Integration Examples
|
|
721
|
-
|
|
722
|
-
### Adding Your Provider to BridgingSdk
|
|
723
|
-
|
|
724
|
-
```typescript
|
|
725
|
-
// Example usage
|
|
726
|
-
import { BridgingSdk, YourBridgeProvider } from '@cowprotocol/cow-sdk'
|
|
727
|
-
|
|
728
|
-
const yourBridgeProvider = new YourBridgeProvider({
|
|
729
|
-
getRpcProvider: (chainId) => new JsonRpcProvider(getRpcUrl(chainId)),
|
|
730
|
-
apiOptions: {
|
|
731
|
-
apiKey: process.env.YOUR_BRIDGE_API_KEY,
|
|
732
|
-
baseUrl: 'https://api.yourbridge.example',
|
|
733
|
-
},
|
|
734
|
-
})
|
|
735
|
-
|
|
736
|
-
const bridgingSdk = new BridgingSdk({
|
|
737
|
-
providers: [yourBridgeProvider],
|
|
738
|
-
enableLogging: true,
|
|
739
|
-
})
|
|
740
|
-
```
|
|
741
|
-
|
|
742
|
-
## Troubleshooting
|
|
743
|
-
|
|
744
|
-
### Common Issues
|
|
745
|
-
|
|
746
|
-
1. **Gas Estimation Failures**
|
|
747
|
-
|
|
748
|
-
```typescript
|
|
749
|
-
import { getGasLimitEstimationForHook } from '../utils/getGasLimitEstimationForHook'
|
|
750
|
-
|
|
751
|
-
// Provide fallback gas limits
|
|
752
|
-
async getGasLimitEstimationForHook(): Promise<number> {
|
|
753
|
-
try {
|
|
754
|
-
return await getGasLimitEstimationForHook(...)
|
|
755
|
-
} catch (error) {
|
|
756
|
-
console.warn('Gas estimation failed, using fallback:', error)
|
|
757
|
-
return 800_000 // Safe fallback
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
```
|
|
761
|
-
|
|
762
|
-
2. **API Rate Limiting**
|
|
763
|
-
|
|
764
|
-
```typescript
|
|
765
|
-
// Implement retry logic with exponential backoff
|
|
766
|
-
private async withRetry<T>(operation: () => Promise<T>, maxRetries = 3): Promise<T> {
|
|
767
|
-
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
768
|
-
try {
|
|
769
|
-
return await operation()
|
|
770
|
-
} catch (error) {
|
|
771
|
-
if (attempt === maxRetries || !this.isRetryableError(error)) {
|
|
772
|
-
throw error
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
const delay = Math.pow(2, attempt - 1) * 1000
|
|
776
|
-
await new Promise(resolve => setTimeout(resolve, delay))
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
throw new Error('Max retries exceeded')
|
|
780
|
-
}
|
|
781
|
-
```
|
|
782
|
-
|
|
783
|
-
3. **Token Address Mismatches**
|
|
784
|
-
```typescript
|
|
785
|
-
// Normalize addresses consistently
|
|
786
|
-
private normalizeAddress(address: string): string {
|
|
787
|
-
return address.toLowerCase()
|
|
788
|
-
}
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
### Debug Tips
|
|
792
|
-
|
|
793
|
-
- Enable detailed logging during development
|
|
794
|
-
- Test with small amounts first
|
|
795
|
-
- Validate against existing providers like `MockBridgeProvider`
|
|
796
|
-
- Monitor transaction status on both chains
|