Prerequisites
This guide assumes that you have completed the Setup guide.
Setup your React app
For API key, reach out to us in the Townhall or raise a support ticket.
The Starknet and Solana configurations are only necessary if you choose to support those chains in your app.
import { GardenProvider } from '@gardenfi/react-hooks';
import { Network } from '@gardenfi/utils';
import { useAccount } from 'starknet-react/core';
import { useWalletClient } from 'wagmi';
import { useAnchorWallet, useConnection } from "@solana/wallet-adapter-react";
import { AnchorProvider } from "@coral-xyz/anchor";
function App() {
// EVM
const { data: walletClient } = useWalletClient();
// Starknet
const { account: starknetWallet } = useAccount();
// Solana
const { connection } = useConnection();
const anchorWallet = useAnchorWallet();
const solanaAnchorProvider = new AnchorProvider(connection, anchorWallet, {});
return (
<GardenProvider
config={{
environment: Network.TESTNET,
apiKey: <YOUR_API_KEY>,
wallets: {
evm: walletClient,
starknet: starknetWallet,
solana: solanaAnchorProvider
}
}}
store={localStorage}
>
{/* Your swap component */}
</GardenProvider>
);
}
export default App;
import React from 'react';
import ReactDOM from 'react-dom/client';
import { WagmiProvider } from 'wagmi';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
import { wagmiConfig } from 'wagmi.ts';
import { StarknetConfig } from '@starknet-react/core';
import { starknetChains, connectors as starknetConnectors, starknetProviders } from './starknetConfig.ts';
import { SolanaProvider } from "./solanaProvider.tsx";
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<WagmiProvider config={wagmiConfig}>
<QueryClientProvider client={new QueryClient()}>
<StarknetConfig
chains={starknetChains}
provider={starknetProviders}
connectors={starknetConnectors}
autoConnect
>
<SolanaProvider>
<App />
</SolanaProvider>
</StarknetConfig>
</QueryClientProvider>
</WagmiProvider>
</React.StrictMode>
);
export const network = import.meta.env.NETWORK
import { createConfig, http } from 'wagmi';
import { arbitrum, arbitrumSepolia, mainnet, sepolia } from 'wagmi/chains';
import { injected, metaMask, safe } from 'wagmi/connectors';
export const wagmiConfig = createConfig({
chains: [mainnet, arbitrum, sepolia, arbitrumSepolia], // All EVM chains you choose to support
connectors: [injected(), metaMask(), safe()],
transports: {
[mainnet.id]: http(),
[arbitrum.id]: http(),
[sepolia.id]: http(),
[arbitrumSepolia.id]: http(),
},
});
import { publicProvider } from '@starknet-react/core';
import { sepolia, mainnet } from '@starknet-react/chains';
import { argent } from '@starknet-react/core';
import { braavos } from '@starknet-react/core';
import { InjectedConnector } from 'starknetkit/injected';
export const connectors = [
new InjectedConnector({ options: { id: 'argentX' } }),
new InjectedConnector({ options: { id: 'braavos' } }),
new InjectedConnector({ options: { id: 'keplr' } }),
];
export const starknetChains = [mainnet, sepolia];
export const starknetProviders = publicProvider();
import { FC, ReactNode } from "react";
import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react";
import { network } from "./constants";
import { Network } from "@gardenfi/utils";
interface SolanaProviderProps {
children: ReactNode;
}
export const SolanaProvider: FC<SolanaProviderProps> = ({ children }) => {
const rpcEndpoint =
network === Network.MAINNET
? "https://solana-rpc.publicnode.com"
: "https://api.devnet.solana.com";
return (
<ConnectionProvider endpoint={rpcEndpoint}>
<WalletProvider wallets={[]} autoConnect>
{ children }
</WalletProvider>
</ConnectionProvider>
);
};
Create a swap component
The lifecycle of a swap is as follows:
- Get a quote
- Pick the best quote
- Initiate the transaction to complete the swap
swap.tsx
import { useState } from 'react';
import { useGarden } from '@gardenfi/react-hooks';
import { Assets } from '@gardenfi/orderbook';
import BigNumber from 'bignumber.js';
import { useAccount } from "wagmi";
export const Swap = () => {
const [quoteAmount, setQuoteAmount] = useState<string>();
const [solverId, setSolverId] = useState<string>();
const { swap, getQuote } = useGarden();
const { address: evmAddress } = useAccount();
// Define the assets involved in the swap
const inputAsset = Assets.arbitrum_sepolia.WBTC;
const outputAsset = Assets.bitcoin_testnet.BTC;
// Amount to be swapped, converted to the smallest unit of the input asset
const amount = new BigNumber(0.01).multipliedBy(10 ** inputAsset.decimals);
// User's Bitcoin address to receive funds
const btcAddress = 'tb1q25q3632323232323232323232323232323232';
const handleGetQuote = async () => {
if (!getQuote) return;
// Fetch a quote for the swap
const quote = await getQuote({
fromAsset: inputAsset,
toAsset: outputAsset,
amount: amount.toNumber(),
isExactOut: false, // Set to `true` if you wish to specify the output (receive) amount
});
if (!quote.ok) {
return alert(quote.error);
}
// Select a quote and save it (the user will confirm this quote before the swap is executed)
const quoteAmount = quote.val[0].destination.amount
const solverId = quote.val[0].solver_id
setQuoteAmount(quoteAmount);
setSolverId(solverId)
};
const handleSwap = async () => {
if (!swap || !quote) return;
// Initiate the swap with the selected quote and user's details
const order = await swap({
fromAsset: inputAsset,
toAsset: outputAsset,
sendAmount: amount.toString(),
receiveAmount: quoteAmount,
solverId,
sourceAddress: evmAddress,
destinationAddress: btcAddress,
});
if (!order.ok) {
return alert(order.error);
}
console.log('✅ Order created:', order.val);
};
return (
<div>
{/* Fetch swap quote */}
<button onClick={handleGetQuote}>Get Quote</button>
{/* Initiate the swap */}
<button onClick={handleSwap}>Swap</button>
</div>
);
}
To include affiliate fees in your swap flow, refer to the implementation here.