@@ -221,7 +221,133 @@ Create `packages/swapper/src/swappers/[SwapperName]Swapper/`
221221
222222** Refer to** ` @examples.md ` for code templates. ** Copy patterns** from similar existing swappers.
223223
224- #### Step 3: Register the swapper
224+ #### Step 3: Add Swapper-Specific Metadata (ONLY if needed)
225+
226+ ** When is metadata needed?**
227+ - Deposit-to-address swappers (Chainflip, NEAR Intents) - need deposit address, swap ID for status polling
228+ - Order-based swappers (CowSwap) - need order ID for status tracking
229+ - Any swapper that requires tracking state between quote → execution → status polling
230+
231+ ** When is metadata NOT needed?**
232+ - Direct transaction swappers (Bebop, 0x, Portals) - transaction is built from quote, no async tracking needed
233+ - Same-chain aggregators where transaction hash is sufficient for status tracking
234+ - Most EVM-only swappers that return transaction data directly
235+
236+ ** If your swapper doesn't need async status polling or deposit addresses, skip this step!**
237+
238+ ** Three places to add metadata:**
239+
240+ ** a. Define types** (` packages/swapper/src/types.ts ` ):
241+
242+ Add to ` TradeQuoteStep ` type:
243+ ``` typescript
244+ export type TradeQuoteStep = {
245+ // ... existing fields
246+ [swapperName ]Specific? : {
247+ depositAddress: string
248+ swapId: number
249+ // ... other swapper-specific fields
250+ }
251+ }
252+ ` ` `
253+
254+ Add to ` SwapperSpecificMetadata ` type (for swap storage):
255+ ` ` ` typescript
256+ export type SwapperSpecificMetadata = {
257+ chainflipSwapId: number | undefined
258+ nearIntentsSpecific? : {
259+ depositAddress: string
260+ depositMemo? : string
261+ timeEstimate: number
262+ deadline: string
263+ }
264+ // Add your swapper's metadata here
265+ [swapperName ]Specific? : {
266+ // ... fields needed for status polling
267+ }
268+ // ... other fields
269+ }
270+ ` ` `
271+
272+ **b. Populate in quote** ( ` packages /swapper /src /swappers /[Swapper ]/swapperApi /getTradeQuote .ts ` ):
273+
274+ Store metadata in the TradeQuoteStep:
275+ ` ` ` typescript
276+ const tradeQuote: TradeQuote = {
277+ // ... other fields
278+ steps: [{
279+ // ... step fields
280+ [swapperName ]Specific: {
281+ depositAddress: response .depositAddress ,
282+ swapId: response .id ,
283+ // ... other data needed later
284+ }
285+ }]
286+ }
287+ ```
288+
289+ ** c. Extract into swap** (TWO places required!):
290+
291+ ** Place 1** : ` src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeButtonProps.tsx `
292+
293+ Add to metadata object around line 114-126:
294+ ``` typescript
295+ metadata : {
296+ chainflipSwapId : firstStep ?.chainflipSpecific ?.chainflipSwapId ,
297+ nearIntentsSpecific : firstStep ?.nearIntentsSpecific ,
298+ // Add your swapper's metadata extraction here:
299+ [swapperName ]Specific : firstStep ?.[swapperName ]Specific ,
300+ relayTransactionMetadata : firstStep ?.relayTransactionMetadata ,
301+ stepIndex : currentHopIndex ,
302+ quoteId : activeQuote .id ,
303+ streamingSwapMetadata : { ... }
304+ }
305+ ```
306+
307+ ** Place 2** : ` src/lib/tradeExecution.ts ` (CRITICAL - often forgotten!)
308+
309+ Add to metadata object around line 156-161:
310+ ``` typescript
311+ metadata : {
312+ ... swap .metadata ,
313+ chainflipSwapId : tradeQuote .steps [0 ]?.chainflipSpecific ?.chainflipSwapId ,
314+ nearIntentsSpecific : tradeQuote .steps [0 ]?.nearIntentsSpecific ,
315+ // Add your swapper's metadata extraction here:
316+ [swapperName ]Specific : tradeQuote .steps [0 ]?.[swapperName ]Specific ,
317+ relayTransactionMetadata : tradeQuote .steps [0 ]?.relayTransactionMetadata ,
318+ stepIndex ,
319+ }
320+ ```
321+
322+ ** Why both places?**
323+ - ` useTradeButtonProps ` creates the initial swap (before wallet signature)
324+ - ` tradeExecution ` updates the swap during execution (after wallet signature, with actual tradeQuote)
325+ - If you only add to one place, metadata will be missing!
326+
327+ ** d. Access in status check** (` packages/swapper/src/swappers/[Swapper]/endpoints.ts ` ):
328+
329+ ``` typescript
330+ checkTradeStatus : async ({ config , swap }) => {
331+ const { [swapperName]Specific } = swap ?.metadata ?? {}
332+
333+ if (! [swapperName ]Specific ?.swapId ) {
334+ throw new Error (' swapId is required for status check' )
335+ }
336+
337+ // Use metadata to poll API
338+ const status = await api .getStatus ([swapperName ]Specific .swapId )
339+ // ...
340+ }
341+ ```
342+
343+ ** Example: NEAR Intents metadata flow**
344+ ```
345+ 1. Quote: Store in step.nearIntentsSpecific.depositAddress
346+ 2. Swap creation: Extract to swap.metadata.nearIntentsSpecific
347+ 3. Status check: Read from swap.metadata.nearIntentsSpecific.depositAddress
348+ ```
349+
350+ #### Step 4: Register the swapper
225351
226352Update these files to register your new swapper:
227353
@@ -234,12 +360,26 @@ Update these files to register your new swapper:
234360 - Export new swapper
235361
2363623 . ** ` packages/swapper/src/types.ts ` **
237- - Add transaction metadata type if needed
238- - Add API config fields
363+ - Add API config fields (if not already done in metadata step)
239364
2403654 . ** CSP Headers** (if swapper calls external API):
241- - Add API domain to ` headers/csps/index.ts `
242- - Create ` headers/csps/defi/swappers/[SwapperName].ts ` with CSP rules
366+ - Create ` headers/csps/defi/swappers/[SwapperName].ts ` :
367+ ``` typescript
368+ import type { Csp } from ' ../../../types'
369+
370+ export const csp: Csp = {
371+ ' connect-src' : [' https://api.[swapper].com' ],
372+ }
373+ ```
374+ - Register in ` headers/csps/index.ts ` :
375+ ` ` ` typescript
376+ import { csp as [swapperName] } from './defi/swappers/[SwapperName]'
377+
378+ export const csps = [
379+ // ... other csps
380+ [swapperName],
381+ ]
382+ ` ` `
243383
2443845. ** UI Integration ** (` src/ ` ):
245385
@@ -277,11 +417,14 @@ Update these files to register your new swapper:
277417
278418 ** d . Wire up feature flag :**
279419 - File : ` src/state/helpers.ts `
280- - Add to ` isCrossAccountTradeSupported ` (if applicable )
281- - Add to ` getEnabledSwappers ` :
420+ - Add to ` isCrossAccountTradeSupported ` function parameter and switch statement (if swapper supports cross - account )
421+ - Add to `getEnabledSwappers` function :
282422 ```typescript
283423 export const getEnabledSwappers = (
284- { [SwapperName]Swap, ...otherFlags }: FeatureFlags,
424+ {
425+ [SwapperName ]Swap , // Add to destructured parameters
426+ ... otherFlags
427+ }: FeatureFlags ,
285428 ...
286429 ): Record <SwapperName , boolean > => {
287430 return {
@@ -292,9 +435,15 @@ Update these files to register your new swapper:
292435 }
293436 ```
294437
295- ** e . Update test mocks (if applicable ):**
438+ ** e . Update test mocks (REQUIRED ):**
296439 - File : ` src/test/mocks/store.ts `
297- - Add feature flag to mock state
440+ - Add feature flag to mock featureFlags object :
441+ ` ` ` typescript
442+ featureFlags: {
443+ // ... other flags
444+ [SwapperName]Swap: false,
445+ }
446+ ` ` `
298447
2994486. ** Configuration ** :
300449
0 commit comments