10000 feat: SDK new chains [SYN-45] by ChiTimesChi · Pull Request #3535 · synapsecns/sanguine · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: SDK new chains [SYN-45] #3535

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Mar 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/rest-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ To run locally:
yarn dev
```

## Environment Variables

The REST API supports the following environment variables:

| Variable | Description | Default Value |
|----------|-------------|---------------|
| RFQ_API_URL | URL for the RFQ API | https://rfq-api.omnirpc.io |
| RFQ_INDEXER_URL | URL for the RFQ Indexer API | https://rfq-indexer.synapseprotocol.com/api |

# Documentation
[Swagger Documentation](https://api.synapseprotocol.com/api-docs/)

Expand Down
4 changes: 2 additions & 2 deletions packages/rest-api/src/constants/bridgeMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -943,8 +943,8 @@ export const BRIDGE_MAP = {
'0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': {
decimals: 18,
symbol: 'HYPE',
origin: ['Gas.zip'],
destination: ['Gas.zip'],
origin: ['Gas.zip', 'RFQ.ETH', 'RFQ.USDC'],
destination: ['Gas.zip', 'RFQ.ETH', 'RFQ.USDC'],
swappable: [],
},
},
Expand Down
8000
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe('destinatonTokens Route', () => {

expect(response.status).toBe(200)
expect(Array.isArray(response.body)).toBe(true)
expect(response.body.length).toBe(8)
expect(response.body.length).toBe(9)
expect(response.body[0]).toHaveProperty('symbol')
expect(response.body[0]).toHaveProperty('address')
expect(response.body[0]).toHaveProperty('chainId')
Expand Down
9 changes: 7 additions & 2 deletions packages/rest-api/src/utils/isGatewayRoute.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { createProxyMiddleware } from 'http-proxy-middleware'

// Environment variables for RFQ API and Indexer URLs
const RFQ_API_URL = process.env.RFQ_API_URL || 'https://rfq-api.omnirpc.io'
const RFQ_INDEXER_URL =
process.env.RFQ_INDEXER_URL || 'https://rfq-indexer.synapseprotocol.com/api'

export const isRFQIndexerRequest = (route: string): boolean => {
return (
route.includes('/conflicting-proofs') ||
Expand All @@ -24,11 +29,11 @@ export const isRFQAPIRequest = (route: string): boolean => {
}

export const rfqApiProxy = createProxyMiddleware({
target: 'https://rfq-api.omnirpc.io',
target: RFQ_API_URL,
changeOrigin: true,
})

export const rfqIndexerProxy = createProxyMiddleware({
target: 'https://rfq-indexer.synapseprotocol.com/api',
target: RFQ_INDEXER_URL,
changeOrigin: true,
})
8 changes: 8 additions & 0 deletions packages/sdk-router/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ This package contains the Synapse Protocol Cross-Chain Swap and Bridging SDK.

[See the Docs](https://synapse-3.gitbook.io/synapse-protocol/developers/bridge-sdk)

## Environment Variables

The SDK Router supports the following environment variables:

| Variable | Description | Default Value |
| ----------- | ------------------- | -------------------------- |
| RFQ_API_URL | URL for the RFQ API | https://rfq-api.omnirpc.io |

# Synapse SDK

The Synapse SDK allows you to interact with [Synapse Protocol](https://synapseprotocol.com/) router contracts deployed on 19 chains. It handles:
Expand Down
3 changes: 3 additions & 0 deletions packages/sdk-router/src/constants/chainIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export enum SupportedChainId {
FANTOM = 250,
BOBA = 288,
WORLDCHAIN = 480,
HYPEREVM = 999,
METIS = 1088,
MOONBEAM = 1284,
MOONRIVER = 1285,
Expand Down Expand Up @@ -35,6 +36,7 @@ const UNSUPPORTED_BRIDGE_CHAIN_IDS: number[] = [
SupportedChainId.WORLDCHAIN,
SupportedChainId.UNICHAIN,
SupportedChainId.BERACHAIN,
SupportedChainId.HYPEREVM,
]

/**
Expand Down Expand Up @@ -89,6 +91,7 @@ export const RFQ_SUPPORTED_CHAIN_IDS: number[] = [
SupportedChainId.SCROLL,
SupportedChainId.UNICHAIN,
SupportedChainId.BERACHAIN,
SupportedChainId.HYPEREVM,
].filter((chainId) => !PAUSED_CHAIN_IDS.includes(chainId))

/**
Expand Down
1 change: 1 addition & 0 deletions packages/sdk-router/src/constants/medianTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,5 @@ export const MEDIAN_TIME_RFQ = {
[SupportedChainId.WORLDCHAIN]: 15,
[SupportedChainId.UNICHAIN]: 15,
[SupportedChainId.BERACHAIN]: 15,
[SupportedChainId.HYPEREVM]: 15,
}
87 changes: 80 additions & 7 deletions packages/sdk-router/src/rfq/api.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,45 @@
import { getWithTimeout } from '../utils/api'
import { logger } from '../utils/logger'
import { marshallTicker } from './ticker'
import {
FastBridgeQuote,
FastBridgeQuoteAPI,
unmarshallFastBridgeQuote,
} from './quote'

const API_URL = 'https://rfq-api.omnirpc.io'
const DEFAULT_API_URL = 'https://rfq-api.omnirpc.io'
const CUSTOM_API_URL = process.env.RFQ_API_URL
const API_TIMEOUT = 2000

/**
* Hits Quoter API /quotes endpoint to get all quotes.
* Get all API endpoints to query.
* Uses both the default API endpoint and custom API endpoint if defined and different.
*
* @returns A promise that resolves to the list of quotes.
* Will return an empty list if the request fails or times out.
* @returns Array of API endpoints to query
*/
export const getAllQuotes = async (): Promise<FastBridgeQuote[]> => {
const getApiEndpoints = (): string[] => {
return CUSTOM_API_URL && CUSTOM_API_URL !== DEFAULT_API_URL
? [DEFAULT_API_URL, CUSTOM_API_URL]
: [DEFAULT_API_URL]
}

/**
* Fetch quotes from a specific API endpoint
*
* @param endpoint The API endpoint URL to query
* @returns Array of unmarshalled FastBridgeQuote objects or empty array if request fails
*/
const getQuotesFromEndpoint = async (
endpoint: string
): Promise<FastBridgeQuote[]> => {
try {
const response = await getWithTimeout(
'RFQ API',
`${API_URL}/quotes`,
`${endpoint}/quotes`,
API_TIMEOUT
)
if (!response) {
logger.info({ endpoint }, 'No response from endpoint')
return []
}
// The response is a list of quotes in the FastBridgeQuoteAPI format
Expand All @@ -32,11 +49,67 @@
try {
return unmarshallFastBridgeQuote(quote)
} catch (error) {
logger.error({ quote, error }, 'Could not unmarshall quote')
logger.error({ endpoint, quote, error }, 'Could not unmarshall quote')

Check warning on line 52 in packages/sdk-router/src/rfq/api.ts

View check run for this annotation

Codecov / codecov/patch

packages/sdk-router/src/rfq/api.ts#L52

Added line #L52 was not covered by tests
return null
}
})
.filter((quote): quote is FastBridgeQuote => quote !== null)
} catch (error) {
logger.error({ endpoint, error }, 'Failed to fetch quotes from endpoint')
return []

Check warning on line 59 in packages/sdk-router/src/rfq/api.ts

View check run for this annotation

Codecov / codecov/patch

packages/sdk-router/src/rfq/api.ts#L58-L59

Added lines #L58 - L59 were not covered by tests
}
}

/**
* Create a unique key for a quote based on relayer address and ticker
*
* @param quote The quote to create a key for
* @returns A unique string key
*/
const createQuoteKey = (quote: FastBridgeQuote): string => {
return `${quote.relayerAddr}-${marshallTicker(quote.ticker)}`
}

/**
* Merges quotes from multiple arrays, avoiding duplicates based on relayer + ticker.
*
* @param quotesArrays Arrays of quotes to merge
* @returns Merged array of unique quotes
*/
const mergeQuotes = (quotesArrays: FastBridgeQuote[][]): FastBridgeQuote[] => {
// Use a Map to track unique quotes by a string key representing the relayer + ticker key.
const uniqueQuotes = new Map<string, FastBridgeQuote>()

quotesArrays.forEach((quotes) => {
quotes.forEach((quote) => {
const key = createQuoteKey(quote)
// If we haven't seen this ticker by this relayer before, or if this quote is newer, keep it
const existingQuote = uniqueQuotes.get(key)
if (!existingQuote || quote.updatedAt > existingQuote.updatedAt) {
uniqueQuotes.set(key, quote)
}
})
})

return Array.from(uniqueQuotes.values())
}

/**
* Hits all available Quoter API /quotes endpoints to get quotes.
* Merges quotes from all endpoints, preferring the most recently updated quotes.
*
* @returns A promise that resolves to the list of quotes.
* Will return an empty list if all requests fail or time out.
*/
export const getAllQuotes = async (): Promise<FastBridgeQuote[]> => {
try {
const endpoints = getApiEndpoints()
// Fetch quotes from all endpoints in parallel
const quotesArrays = await Promise.all(
endpoints.map((endpoint) => getQuotesFromEndpoint(endpoint))
)
// Merge all quotes, keeping the most recent ones
return mergeQuotes(quotesArrays)
} catch (error) {
logger.error({ error }, 'Failed to fetch all quotes')
return []
Expand Down
14 changes: 10 additions & 4 deletions packages/sdk-router/src/rfq/fastBridgeRouterSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,17 @@
feeAmount: BigNumber
feeConfig: FeeConfig
}> {
// Origin Out vs Dest Out is the effective fee
// TODO: do we actually need to return non-zero alues here?
// Origin Out vs Dest Out is the effective fee if amountOut is within 1% of amountIn.
// Otherwise origin and destination tokens are different, so the SDK has no means to determine the effective fee.
const amountIn = bridgeRoute.originQuery.minAmountOut
const amountOut = bridgeRoute.destQuery.minAmountOut

Check warning on line 159 in packages/sdk-router/src/rfq/fastBridgeRouterSet.ts

View check run for this annotation

Codecov / codecov/patch

packages/sdk-router/src/rfq/fastBridgeRouterSet.ts#L158-L159

Added lines #L158 - L159 were not covered by tests
const feeAmount =
amountOut.gte(amountIn.mul(99).div(100)) && amountOut.lte(amountIn)
? amountIn.sub(amountOut)
: Zero
return {
feeAmount: bridgeRoute.originQuery.minAmountOut.sub(
bridgeRoute.destQuery.minAmountOut
),
feeAmount,
feeConfig: {
bridgeFee: 0,
minFee: BigNumber.from(0),
Expand Down
4 changes: 2 additions & 2 deletions packages/synapse-interface/constants/bridgeMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -943,8 +943,8 @@ export const BRIDGE_MAP = {
'0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': {
decimals: 18,
symbol: 'HYPE',
origin: ['Gas.zip'],
destination: ['Gas.zip'],
origin: ['Gas.zip', 'RFQ.ETH', 'RFQ.USDC'],
destination: ['Gas.zip', 'RFQ.ETH', 'RFQ.USDC'],
swappable: [],
},
},
Expand Down
2 changes: 1 addition & 1 deletion packages/synapse-interface/scripts/generateMaps.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require('dotenv').config()

// TODO: handle HYPE-ETH, HYPE-USDC pairs from the RFQ API
const { ethers } = require('ethers')

const { prettyPrintTS } = require('./utils/prettyPrintTs')
Expand Down
Loading
0