Skip to content
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
11 changes: 11 additions & 0 deletions .changeset/chilly-facts-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@reservoir0x/relay-bitcoin-wallet-adapter': minor
'@reservoir0x/relay-ethers-wallet-adapter': minor
'@reservoir0x/relay-sui-wallet-adapter': minor
'@reservoir0x/relay-svm-wallet-adapter': minor
'@reservoir0x/relay-kit-hooks': minor
'@reservoir0x/relay-sdk': minor
'@reservoir0x/relay-kit-ui': minor
---

Add websocket support and refactor executeSteps
27 changes: 24 additions & 3 deletions demo/components/providers/RelayKitProviderWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
import { LogLevel, RelayChain } from '@reservoir0x/relay-sdk'
import {
createClient,
LogLevel,
MAINNET_RELAY_WS,
RelayChain
} from '@reservoir0x/relay-sdk'
import { RelayKitProvider } from '@reservoir0x/relay-kit-ui'
import { useTheme } from 'next-themes'
import { FC, ReactNode } from 'react'
import { useRouter } from 'next/router'
import { FC, ReactNode, useEffect, useState } from 'react'

export const RelayKitProviderWrapper: FC<{
relayApi?: string
dynamicChains: RelayChain[]
children: ReactNode
}> = ({ relayApi, dynamicChains, children }) => {
const { theme } = useTheme()
const router = useRouter()
const [websocketsEnabled, setWebsocketsEnabled] = useState(false)

// Handle websocket configuration from query params
useEffect(() => {
const websocketParam = router.query.websockets as string
if (websocketParam !== undefined) {
setWebsocketsEnabled(websocketParam === 'true')
}
}, [router.query.websockets])

return (
<RelayKitProvider
options={{
Expand All @@ -25,7 +42,11 @@ export const RelayKitProviderWrapper: FC<{
useGasFeeEstimations: true,
pollingInterval: 1000,
confirmationPollingInterval: 1000,
themeScheme: theme === 'dark' ? 'dark' : 'light'
themeScheme: theme === 'dark' ? 'dark' : 'light',
websocket: {
enabled: websocketsEnabled,
url: MAINNET_RELAY_WS
}
}}
>
{children}
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/actions/execute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ let executeStepsSpy = vi
return Promise.resolve(clonedQuote)
}
)
vi.mock('../utils/executeSteps.js', () => {
vi.mock('../utils/executeSteps/index.js', () => {
return {
executeSteps: (...args: any[]) => {
return executeStepsSpy(...args)
Expand Down
32 changes: 28 additions & 4 deletions packages/sdk/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,25 @@ import type { RelayChain } from './types/index.js'
import { LogLevel, log as logUtil } from './utils/logger.js'
import * as actions from './actions/index.js'
import * as utils from './utils/index.js'
import { MAINNET_RELAY_API } from './constants/servers.js'
import { MAINNET_RELAY_API, MAINNET_RELAY_WS } from './constants/servers.js'
import { SDK_VERSION } from './version.js'

/**
* RelayClient Configuration Options
* @param source Used to manually override the source domain used to attribute local orders
* @param logLevel Log level from 0-4, the higher the more verbose.
* @param maxPollingAttemptsBeforeTimeout The maximum number of attempts the synced api is polled before timing out. The api is polled every 5 secs (default is 30)
*
* @property {string} [baseApiUrl] - The base URL for the Relay API. Defaults to the mainnet API if not provided.
* @property {string} [source] - The source to associate your onchain activity with, should be a domain.
* @property {LogLevel} [logLevel] - Log level from 0-4, the higher the more verbose. Defaults to LogLevel.None.
* @property {number} [pollingInterval] - Interval (in ms) for polling the API for status updates.
* @property {number} [maxPollingAttemptsBeforeTimeout] - The maximum number of polling attempts before timing out. The API is polled every 5 seconds by default (default is 30 attempts).
* @property {RelayChain[]} [chains] - List of supported chains. If not provided, defaults to all mainnet/testnet chains based on the API URL.
* @property {boolean} [useGasFeeEstimations] - Whether to use gas fee estimations. Defaults to true.
* @property {string} [uiVersion] - Optional UI version string for analytics/debugging.
* @property {(message: Parameters<typeof logUtil>[0], level: LogLevel) => void} [logger] - Custom logger function. If not provided, uses the default logger.
* @property {number} [confirmationPollingInterval] - Interval (in ms) for polling transaction confirmations.
* @property {Object} [websocket] - Websocket configuration options.
* @property {boolean} [websocket.enabled] - Whether to enable websocket support. Defaults to false.
* @property {string} [websocket.url] - Custom websocket URL. If not provided, falls back to the default.
*/
export type RelayClientOptions = {
baseApiUrl?: string
Expand All @@ -32,6 +43,10 @@ export type RelayClientOptions = {
uiVersion?: string
logger?: (message: Parameters<typeof logUtil>['0'], level: LogLevel) => void
confirmationPollingInterval?: number
websocket?: {
enabled?: boolean
url?: string
}
}

let _client: RelayClient
Expand All @@ -58,6 +73,8 @@ export class RelayClient {
maxPollingAttemptsBeforeTimeout?: number
useGasFeeEstimations: boolean
chains: RelayChain[]
websocketEnabled: boolean
websocketUrl: string
log(
message: Parameters<typeof logUtil>['0'],
level: LogLevel = LogLevel.Info
Expand All @@ -78,6 +95,8 @@ export class RelayClient {
this.maxPollingAttemptsBeforeTimeout =
options.maxPollingAttemptsBeforeTimeout
this.useGasFeeEstimations = options.useGasFeeEstimations ?? true
this.websocketEnabled = options.websocket?.enabled ?? false
this.websocketUrl = options.websocket?.url ?? MAINNET_RELAY_WS
if (options.chains) {
this.chains = options.chains
} else if (options.baseApiUrl?.includes('testnets')) {
Expand Down Expand Up @@ -121,6 +140,11 @@ export class RelayClient {
options.useGasFeeEstimations !== undefined
? options.useGasFeeEstimations
: this.useGasFeeEstimations
this.websocketEnabled =
options.websocket?.enabled !== undefined
? options.websocket.enabled
: this.websocketEnabled
this.websocketUrl = options.websocket?.url || this.websocketUrl

if (options.logger) {
this.log = options.logger
Expand Down
4 changes: 4 additions & 0 deletions packages/sdk/src/constants/servers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export const MAINNET_RELAY_API = 'https://api.relay.link'
export const TESTNET_RELAY_API = 'https://api.testnets.relay.link'
export const ASSETS_RELAY_API = 'https://assets.relay.link'

// WebSocket endpoints
export const MAINNET_RELAY_WS = 'wss://ws.relay.link'
export const DEV_RELAY_WS = 'wss://ws.dev.relay.link'
1 change: 1 addition & 0 deletions packages/sdk/src/types/Execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export type Execute = {
| 'waiting'
| 'failure'
| 'pending'
| 'submitted'
| 'success'
| 'unknown'
progressState?: TransactionStepState | SignatureStepState
Expand Down
10 changes: 9 additions & 1 deletion packages/sdk/src/types/SignatureStepItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@ import type { Execute } from './Execute.js'

export type SignatureStepItem = Pick<
NonNullable<Execute['steps'][0]['items']>[0],
'status' | 'orderIds' | 'orderIndexes' | 'orderData'
| 'status'
| 'orderIds'
| 'orderIndexes'
| 'orderData'
| 'progressState'
| 'txHashes'
| 'internalTxHashes'
| 'check'
| 'isValidatingSignature'
> & {
data?: {
sign?: {
Expand Down
12 changes: 11 additions & 1 deletion packages/sdk/src/types/TransactionStepItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@ import type { Execute } from './Execute.js'

export type TransactionStepItem = Pick<
NonNullable<Execute['steps'][0]['items']>[0],
'status' | 'orderIds' | 'orderIndexes' | 'orderData' | 'check'
| 'status'
| 'orderIds'
| 'orderIndexes'
| 'orderData'
| 'check'
| 'progressState'
| 'txHashes'
| 'internalTxHashes'
| 'receipt'
| 'checkStatus'
> & {
data: {
chainId?: number
data: any
from: `0x${string}`
to: `0x${string}`
Expand Down
Loading