11import { NextPage } from 'next'
2- import { useMemo , useState } from 'react'
3- import { useWalletClient } from 'wagmi'
2+ import { useEffect , useMemo , useState } from 'react'
43import { useRelayClient } from '@relayprotocol/relay-kit-ui'
54import { ConnectButton } from 'components/ConnectButton'
65import {
7- adaptViemWallet ,
86 type QuoteBody ,
97 type AdaptedWallet ,
108 type Execute ,
11- type TransactionStepItem
9+ adaptViemWallet
1210} from '@relayprotocol/relay-sdk'
11+ import { createFastFillWallet } from 'utils/createFastFillWallet'
12+ import { useDynamicContext } from '@dynamic-labs/sdk-react-core'
13+ import { isEthereumWallet } from '@dynamic-labs/ethereum'
14+ import { isSolanaWallet } from '@dynamic-labs/solana'
15+ import { isBitcoinWallet } from '@dynamic-labs/bitcoin'
16+ import { isSuiWallet } from '@dynamic-labs/sui'
17+ import { isTronWallet , type TronWallet } from '@dynamic-labs/tron'
18+ import { adaptSolanaWallet } from '@relayprotocol/relay-svm-wallet-adapter'
19+ import { adaptBitcoinWallet } from '@relayprotocol/relay-bitcoin-wallet-adapter'
20+ import { adaptSuiWallet } from '@relayprotocol/relay-sui-wallet-adapter'
21+ import { adaptTronWallet } from '@relayprotocol/relay-tron-wallet-adapter'
1322
1423const FastFillPage : NextPage = ( ) => {
15- const { data : wallet } = useWalletClient ( )
1624 const client = useRelayClient ( )
25+ const { primaryWallet } = useDynamicContext ( )
1726 const [ quoteParams , setQuoteParams ] = useState < string > ( '' )
1827 const [ quote , setQuote ] = useState < Execute | null > ( null )
1928 const [ result , setResult ] = useState < any > ( null )
2029 const [ progress , setProgress ] = useState < any > ( null )
2130 const [ loading , setLoading ] = useState ( false )
2231 const [ error , setError ] = useState < string | null > ( null )
2332 const [ fastFillPassword , setFastFillPassword ] = useState < string > ( '' )
33+ const [ solverInputCurrencyAmount , setSolverInputCurrencyAmount ] = useState < string > ( '' )
34+ const [ adaptedWallet , setAdaptedWallet ] = useState < AdaptedWallet | null > ( null )
2435
25- // Create a custom wallet adapter that wraps the viemWallet adapter
26- // and intercepts handleSendTransactionStep to call fastFill
27- const createFastFillWalletAdapter = (
28- originalWallet : AdaptedWallet ,
29- password : string
30- ) : AdaptedWallet => {
31- return {
32- ...originalWallet ,
33- handleSendTransactionStep : async (
34- chainId : number ,
35- stepItem : TransactionStepItem ,
36- step : Execute [ 'steps' ] [ 0 ]
37- ) => {
38- const txHash = await originalWallet . handleSendTransactionStep (
39- chainId ,
40- stepItem ,
41- step
42- )
43- // Call fastFill proxy API if requestId is available
44- if ( step . requestId && step . id === 'deposit' ) {
45- try {
46- console . log ( 'Calling fastFill proxy for requestId:' , step . requestId )
47- const response = await fetch ( '/api/fast-fill' , {
48- method : 'POST' ,
49- headers : {
50- 'Content-Type' : 'application/json'
51- } ,
52- body : JSON . stringify ( {
53- requestId : step . requestId ,
54- password
55- } )
56- } )
57-
58- if ( response . ok ) {
59- const data = await response . json ( )
60- console . log ( 'FastFill called successfully:' , data )
61- } else {
62- const error = await response . json ( )
63- console . warn (
64- 'FastFill error (continuing with transaction):' ,
65- error . error || error . message
66- )
36+ // Adapt wallet whenever primaryWallet changes
37+ useEffect ( ( ) => {
38+ const adaptWallet = async ( ) => {
39+ if ( ! primaryWallet ) {
40+ setAdaptedWallet ( null )
41+ return
42+ }
43+
44+ try {
45+ let wallet : AdaptedWallet | null = null
46+
47+ if ( isEthereumWallet ( primaryWallet ) ) {
48+ const walletClient = await primaryWallet . getWalletClient ( )
49+ wallet = adaptViemWallet ( walletClient )
50+ } else if ( isSolanaWallet ( primaryWallet ) ) {
51+ const connection = await primaryWallet . getConnection ( )
52+ const signer = await primaryWallet . getSigner ( )
53+
54+ if ( ! connection || ! signer ?. signTransaction ) {
55+ throw new Error ( 'Unable to setup Solana wallet' )
56+ }
57+
58+ wallet = adaptSolanaWallet (
59+ primaryWallet . address ,
60+ 792703809 , // Solana chain ID
61+ connection ,
62+ signer . signAndSendTransaction
63+ )
64+ } else if ( isBitcoinWallet ( primaryWallet ) ) {
65+ wallet = adaptBitcoinWallet (
66+ primaryWallet . address ,
67+ async ( _address , _psbt , dynamicParams ) => {
68+ const response = await primaryWallet . signPsbt ( dynamicParams )
69+ if ( ! response ) {
70+ throw new Error ( 'Missing psbt response' )
71+ }
72+ return response . signedPsbt
6773 }
68- } catch ( e : any ) {
69- // Log error but don't fail the transaction
70- console . warn (
71- 'FastFill error (continuing with transaction):' ,
72- e ?. message || String ( e )
73- )
74+ )
75+ } else if ( isSuiWallet ( primaryWallet ) ) {
76+ const walletClient = await primaryWallet . getWalletClient ( )
77+
78+ if ( ! walletClient ) {
79+ throw new Error ( 'Unable to setup Sui wallet' )
7480 }
75- }
7681
77- return txHash
78- } ,
79- handleBatchTransactionStep : async ( chainId , items , step ) => {
80- const txHash = await originalWallet ?. handleBatchTransactionStep ?.(
81- chainId ,
82- items ,
83- step
84- )
85- // Call fastFill proxy API if requestId is available
86- if ( txHash ) {
87- try {
88- console . log ( 'Calling fastFill proxy for requestId:' , step . requestId )
89- const response = await fetch ( '/api/fast-fill' , {
90- method : 'POST' ,
91- headers : {
92- 'Content-Type' : 'application/json'
93- } ,
94- body : JSON . stringify ( {
95- requestId : step . requestId ,
96- password
82+ wallet = adaptSuiWallet (
83+ primaryWallet . address ,
84+ 784 , // Sui chain ID placeholder - will be updated based on quote params
85+ walletClient ,
86+ async ( tx ) => {
87+ const signedTransaction = await primaryWallet . signTransaction ( tx )
88+ const executionResult = await walletClient . executeTransactionBlock ( {
89+ options : { } ,
90+ signature : signedTransaction . signature ,
91+ transactionBlock : signedTransaction . bytes
9792 } )
98- } )
99-
100- if ( response . ok ) {
101- const data = await response . json ( )
102- console . log ( 'FastFill called successfully:' , data )
103- } else {
104- const error = await response . json ( )
105- console . warn (
106- 'FastFill error (continuing with transaction):' ,
107- error . error || error . message
108- )
93+ return executionResult
10994 }
110- } catch ( e : any ) {
111- // Log error but don't fail the transaction
112- console . warn (
113- 'FastFill error (continuing with transaction):' ,
114- e ?. message || String ( e )
115- )
95+ )
96+ } else if ( isTronWallet ( primaryWallet ) ) {
97+ const tronWeb = ( primaryWallet as TronWallet ) . getTronWeb ( )
98+ if ( ! tronWeb ) {
99+ throw new Error ( 'Unable to setup Tron wallet' )
116100 }
101+ wallet = adaptTronWallet (
102+ ( primaryWallet as TronWallet ) . address ,
103+ tronWeb
104+ )
117105 }
106+ // Note: Hyperliquid support can be added here following a similar pattern
118107
119- return txHash
108+ setAdaptedWallet ( wallet )
109+ } catch ( e : any ) {
110+ console . error ( 'Error adapting wallet:' , e )
111+ setError ( `Error adapting wallet: ${ e ?. message || String ( e ) } ` )
112+ setAdaptedWallet ( null )
120113 }
121114 }
122- }
115+
116+ adaptWallet ( )
117+ } , [ primaryWallet ] )
123118
124119 const handleExecute = async ( ) => {
125120 if ( ! client ) {
126121 setError ( 'Missing Client!' )
127122 return
128123 }
129- if ( ! wallet ) {
124+ if ( ! adaptedWallet ) {
130125 setError ( 'Please connect your wallet!' )
131126 return
132127 }
@@ -147,13 +142,11 @@ const FastFillPage: NextPage = () => {
147142 }
148143
149144 try {
150- // Adapt the wallet
151- const adaptedWallet = adaptViemWallet ( wallet )
152-
153- // Wrap it with our fastFill adapter
154- const fastFillWallet = createFastFillWalletAdapter (
145+ // Wrap the adapted wallet with our fastFill wrapper
146+ const fastFillWallet = createFastFillWallet (
155147 adaptedWallet ,
156- fastFillPassword
148+ fastFillPassword ,
149+ solverInputCurrencyAmount || undefined
157150 )
158151
159152 // Execute the quote with the fastFill wallet adapter
@@ -176,7 +169,7 @@ const FastFillPage: NextPage = () => {
176169 setError ( 'Missing Client!' )
177170 return
178171 }
179- if ( ! wallet ) {
172+ if ( ! adaptedWallet || ! primaryWallet ) {
180173 setError ( 'Please connect your wallet!' )
181174 return
182175 }
@@ -195,13 +188,13 @@ const FastFillPage: NextPage = () => {
195188 return
196189 }
197190
198- const userAddress = wallet . account ? .address
191+ const userAddress = primaryWallet . address
199192 if ( ! userAddress ) {
200193 setError ( 'Could not get address from connected wallet' )
201194 setLoading ( false )
202195 return
203196 }
204- const adaptedWallet = adaptViemWallet ( wallet )
197+
205198 const quoteResult = await client . actions . getQuote (
206199 {
207200 chainId : params . originChainId ,
@@ -231,7 +224,7 @@ const FastFillPage: NextPage = () => {
231224 } catch ( e ) {
232225 return ''
233226 }
234- } , [ result ] )
227+ } , [ progress ] )
235228
236229 return (
237230 < div
@@ -248,6 +241,20 @@ const FastFillPage: NextPage = () => {
248241 >
249242 < ConnectButton />
250243
244+ { adaptedWallet && (
245+ < div
246+ style = { {
247+ width : '100%' ,
248+ padding : '10px' ,
249+ background : '#e0f0ff' ,
250+ borderRadius : '8px' ,
251+ marginBottom : 10
252+ } }
253+ >
254+ < b > Connected Wallet VM Type:</ b > { adaptedWallet . vmType }
255+ </ div >
256+ ) }
257+
251258 < div style = { { width : '100%' } } >
252259 < label style = { { display : 'block' , marginBottom : 8 , fontWeight : 600 } } >
253260 Quote Parameters (JSON):
@@ -262,12 +269,13 @@ const FastFillPage: NextPage = () => {
262269 } }
263270 >
264271 Note that user/recipient are not required — they are taken from the
265- connected wallet.
272+ connected wallet. This demo now supports all wallet types: EVM, Solana
273+ (SVM), Bitcoin (BVM), Sui, Tron (TVM), and Hyperliquid.
266274 </ div >
267275 < textarea
268276 value = { quoteParams }
269277 onChange = { ( e ) => setQuoteParams ( e . target . value ) }
270- placeholder = '{"chainId ": 1, "toChainId ": 8453, "currency ": "0x0000000000000000000000000000000000000000", "toCurrency ": "0x0000000000000000000000000000000000000000", "amount": "1000000000000000000", "tradeType": "EXACT_INPUT"}'
278+ placeholder = '{"originChainId ": 1, "destinationChainId ": 8453, "originCurrency ": "0x0000000000000000000000000000000000000000", "destinationCurrency ": "0x0000000000000000000000000000000000000000", "amount": "1000000000000000000", "tradeType": "EXACT_INPUT"}'
271279 style = { {
272280 width : '100%' ,
273281 minHeight : 150 ,
@@ -292,7 +300,7 @@ const FastFillPage: NextPage = () => {
292300 cursor : 'pointer' ,
293301 width : '100%'
294302 } }
295- disabled = { ! wallet || loading || ! quoteParams . trim ( ) }
303+ disabled = { ! adaptedWallet || loading || ! quoteParams . trim ( ) }
296304 onClick = { handleGetQuote }
297305 >
298306 { loading && ! quote ? 'Getting Quote...' : 'Get Quote' }
@@ -308,9 +316,9 @@ const FastFillPage: NextPage = () => {
308316 marginTop : 10
309317 } }
310318 >
311- < b > Quote obtained! Request IDs :</ b >
319+ < b > Quote obtained! Request ID :</ b >
312320 < pre style = { { fontSize : 11 , overflow : 'auto' , maxHeight : 200 } } >
313- { quote . steps . find ( ( step ) => step . requestId ) ?. requestId ?? '' }
321+ { quote . steps . find ( ( step ) => step . requestId ) ?. requestId ?? 'No request ID found ' }
314322 </ pre >
315323 </ div >
316324 ) }
@@ -334,6 +342,25 @@ const FastFillPage: NextPage = () => {
334342 />
335343 </ div >
336344
345+ < div style = { { width : '100%' } } >
346+ < label style = { { display : 'block' , marginBottom : 8 , fontWeight : 600 } } >
347+ Solver Input Currency Amount (Optional):
348+ </ label >
349+ < input
350+ type = "text"
351+ value = { solverInputCurrencyAmount }
352+ onChange = { ( e ) => setSolverInputCurrencyAmount ( e . target . value ) }
353+ placeholder = "Enter solver input currency amount"
354+ style = { {
355+ width : '100%' ,
356+ padding : 12 ,
357+ fontSize : 14 ,
358+ border : '1px solid #ccc' ,
359+ borderRadius : 8
360+ } }
361+ />
362+ </ div >
363+
337364 < button
338365 style = { {
339366 marginTop : 20 ,
@@ -347,7 +374,7 @@ const FastFillPage: NextPage = () => {
347374 cursor : 'pointer' ,
348375 width : '100%'
349376 } }
350- disabled = { ! wallet || ! quote || loading || ! fastFillPassword . trim ( ) }
377+ disabled = { ! adaptedWallet || ! quote || loading || ! fastFillPassword . trim ( ) }
351378 onClick = { handleExecute }
352379 >
353380 { loading ? 'Executing with Fast Fill...' : 'Execute with Fast Fill' }
@@ -375,6 +402,23 @@ const FastFillPage: NextPage = () => {
375402 </ pre >
376403 </ div >
377404 ) }
405+
406+ { result && (
407+ < div
408+ style = { {
409+ marginTop : 20 ,
410+ padding : '10px' ,
411+ background : '#e0ffe0' ,
412+ borderRadius : '8px' ,
413+ width : '100%'
414+ } }
415+ >
416+ < b > Result:</ b >
417+ < pre style = { { fontSize : 11 , overflow : 'auto' , maxHeight : 300 } } >
418+ { JSON . stringify ( result , null , 2 ) }
419+ </ pre >
420+ </ div >
421+ ) }
378422 </ div >
379423 )
380424}
0 commit comments