Skip to content

Commit b011440

Browse files
authored
Merge pull request #706 from reservoirprotocol/ted/fe-7691-implement-sdk-websocket-connection
Add websocket support to sdk for real-time transaction status updates
2 parents 299952b + 561c55b commit b011440

File tree

17 files changed

+1756
-720
lines changed

17 files changed

+1756
-720
lines changed

.changeset/chilly-facts-press.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@reservoir0x/relay-bitcoin-wallet-adapter': minor
3+
'@reservoir0x/relay-ethers-wallet-adapter': minor
4+
'@reservoir0x/relay-sui-wallet-adapter': minor
5+
'@reservoir0x/relay-svm-wallet-adapter': minor
6+
'@reservoir0x/relay-kit-hooks': minor
7+
'@reservoir0x/relay-sdk': minor
8+
'@reservoir0x/relay-kit-ui': minor
9+
---
10+
11+
Add websocket support and refactor executeSteps

demo/components/providers/RelayKitProviderWrapper.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,31 @@
1-
import { LogLevel, RelayChain } from '@reservoir0x/relay-sdk'
1+
import {
2+
createClient,
3+
LogLevel,
4+
MAINNET_RELAY_WS,
5+
RelayChain
6+
} from '@reservoir0x/relay-sdk'
27
import { RelayKitProvider } from '@reservoir0x/relay-kit-ui'
38
import { useTheme } from 'next-themes'
4-
import { FC, ReactNode } from 'react'
9+
import { useRouter } from 'next/router'
10+
import { FC, ReactNode, useEffect, useState } from 'react'
511

612
export const RelayKitProviderWrapper: FC<{
713
relayApi?: string
814
dynamicChains: RelayChain[]
915
children: ReactNode
1016
}> = ({ relayApi, dynamicChains, children }) => {
1117
const { theme } = useTheme()
18+
const router = useRouter()
19+
const [websocketsEnabled, setWebsocketsEnabled] = useState(false)
20+
21+
// Handle websocket configuration from query params
22+
useEffect(() => {
23+
const websocketParam = router.query.websockets as string
24+
if (websocketParam !== undefined) {
25+
setWebsocketsEnabled(websocketParam === 'true')
26+
}
27+
}, [router.query.websockets])
28+
1229
return (
1330
<RelayKitProvider
1431
options={{
@@ -25,7 +42,11 @@ export const RelayKitProviderWrapper: FC<{
2542
useGasFeeEstimations: true,
2643
pollingInterval: 1000,
2744
confirmationPollingInterval: 1000,
28-
themeScheme: theme === 'dark' ? 'dark' : 'light'
45+
themeScheme: theme === 'dark' ? 'dark' : 'light',
46+
websocket: {
47+
enabled: websocketsEnabled,
48+
url: MAINNET_RELAY_WS
49+
}
2950
}}
3051
>
3152
{children}

packages/sdk/src/actions/execute.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ let executeStepsSpy = vi
3434
return Promise.resolve(clonedQuote)
3535
}
3636
)
37-
vi.mock('../utils/executeSteps.js', () => {
37+
vi.mock('../utils/executeSteps/index.js', () => {
3838
return {
3939
executeSteps: (...args: any[]) => {
4040
return executeStepsSpy(...args)

packages/sdk/src/client.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,25 @@ import type { RelayChain } from './types/index.js'
1212
import { LogLevel, log as logUtil } from './utils/logger.js'
1313
import * as actions from './actions/index.js'
1414
import * as utils from './utils/index.js'
15-
import { MAINNET_RELAY_API } from './constants/servers.js'
15+
import { MAINNET_RELAY_API, MAINNET_RELAY_WS } from './constants/servers.js'
1616
import { SDK_VERSION } from './version.js'
1717

1818
/**
1919
* RelayClient Configuration Options
20-
* @param source Used to manually override the source domain used to attribute local orders
21-
* @param logLevel Log level from 0-4, the higher the more verbose.
22-
* @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)
20+
*
21+
* @property {string} [baseApiUrl] - The base URL for the Relay API. Defaults to the mainnet API if not provided.
22+
* @property {string} [source] - The source to associate your onchain activity with, should be a domain.
23+
* @property {LogLevel} [logLevel] - Log level from 0-4, the higher the more verbose. Defaults to LogLevel.None.
24+
* @property {number} [pollingInterval] - Interval (in ms) for polling the API for status updates.
25+
* @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).
26+
* @property {RelayChain[]} [chains] - List of supported chains. If not provided, defaults to all mainnet/testnet chains based on the API URL.
27+
* @property {boolean} [useGasFeeEstimations] - Whether to use gas fee estimations. Defaults to true.
28+
* @property {string} [uiVersion] - Optional UI version string for analytics/debugging.
29+
* @property {(message: Parameters<typeof logUtil>[0], level: LogLevel) => void} [logger] - Custom logger function. If not provided, uses the default logger.
30+
* @property {number} [confirmationPollingInterval] - Interval (in ms) for polling transaction confirmations.
31+
* @property {Object} [websocket] - Websocket configuration options.
32+
* @property {boolean} [websocket.enabled] - Whether to enable websocket support. Defaults to false.
33+
* @property {string} [websocket.url] - Custom websocket URL. If not provided, falls back to the default.
2334
*/
2435
export type RelayClientOptions = {
2536
baseApiUrl?: string
@@ -32,6 +43,10 @@ export type RelayClientOptions = {
3243
uiVersion?: string
3344
logger?: (message: Parameters<typeof logUtil>['0'], level: LogLevel) => void
3445
confirmationPollingInterval?: number
46+
websocket?: {
47+
enabled?: boolean
48+
url?: string
49+
}
3550
}
3651

3752
let _client: RelayClient
@@ -58,6 +73,8 @@ export class RelayClient {
5873
maxPollingAttemptsBeforeTimeout?: number
5974
useGasFeeEstimations: boolean
6075
chains: RelayChain[]
76+
websocketEnabled: boolean
77+
websocketUrl: string
6178
log(
6279
message: Parameters<typeof logUtil>['0'],
6380
level: LogLevel = LogLevel.Info
@@ -78,6 +95,8 @@ export class RelayClient {
7895
this.maxPollingAttemptsBeforeTimeout =
7996
options.maxPollingAttemptsBeforeTimeout
8097
this.useGasFeeEstimations = options.useGasFeeEstimations ?? true
98+
this.websocketEnabled = options.websocket?.enabled ?? false
99+
this.websocketUrl = options.websocket?.url ?? MAINNET_RELAY_WS
81100
if (options.chains) {
82101
this.chains = options.chains
83102
} else if (options.baseApiUrl?.includes('testnets')) {
@@ -121,6 +140,11 @@ export class RelayClient {
121140
options.useGasFeeEstimations !== undefined
122141
? options.useGasFeeEstimations
123142
: this.useGasFeeEstimations
143+
this.websocketEnabled =
144+
options.websocket?.enabled !== undefined
145+
? options.websocket.enabled
146+
: this.websocketEnabled
147+
this.websocketUrl = options.websocket?.url || this.websocketUrl
124148

125149
if (options.logger) {
126150
this.log = options.logger
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
export const MAINNET_RELAY_API = 'https://api.relay.link'
22
export const TESTNET_RELAY_API = 'https://api.testnets.relay.link'
33
export const ASSETS_RELAY_API = 'https://assets.relay.link'
4+
5+
// WebSocket endpoints
6+
export const MAINNET_RELAY_WS = 'wss://ws.relay.link'
7+
export const DEV_RELAY_WS = 'wss://ws.dev.relay.link'

packages/sdk/src/types/Execute.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export type Execute = {
5757
| 'waiting'
5858
| 'failure'
5959
| 'pending'
60+
| 'submitted'
6061
| 'success'
6162
| 'unknown'
6263
progressState?: TransactionStepState | SignatureStepState

packages/sdk/src/types/SignatureStepItem.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@ import type { Execute } from './Execute.js'
22

33
export type SignatureStepItem = Pick<
44
NonNullable<Execute['steps'][0]['items']>[0],
5-
'status' | 'orderIds' | 'orderIndexes' | 'orderData'
5+
| 'status'
6+
| 'orderIds'
7+
| 'orderIndexes'
8+
| 'orderData'
9+
| 'progressState'
10+
| 'txHashes'
11+
| 'internalTxHashes'
12+
| 'check'
13+
| 'isValidatingSignature'
614
> & {
715
data?: {
816
sign?: {

packages/sdk/src/types/TransactionStepItem.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,19 @@ import type { Execute } from './Execute.js'
22

33
export type TransactionStepItem = Pick<
44
NonNullable<Execute['steps'][0]['items']>[0],
5-
'status' | 'orderIds' | 'orderIndexes' | 'orderData' | 'check'
5+
| 'status'
6+
| 'orderIds'
7+
| 'orderIndexes'
8+
| 'orderData'
9+
| 'check'
10+
| 'progressState'
11+
| 'txHashes'
12+
| 'internalTxHashes'
13+
| 'receipt'
14+
| 'checkStatus'
615
> & {
716
data: {
17+
chainId?: number
818
data: any
919
from: `0x${string}`
1020
to: `0x${string}`

0 commit comments

Comments
 (0)