This guide assumes that you have completed the Setup guide.
2
Initialize wallets and providers
Initialize wallets and providers only for the chains you need.
Copy
Ask AI
import { BitcoinProvider, BitcoinNetwork, BitcoinWallet,} from '@catalogfi/wallets';import { createWalletClient, http } from 'viem';import { privateKeyToAccount } from 'viem/accounts';import { arbitrumSepolia } from 'viem/chains';import { RpcProvider, Account } from 'starknet';// Ethereum wallet setupconst ethereumAccount = privateKeyToAccount('<YOUR_EVM_PRIVATE_KEY>');const ethereumWalletClient = createWalletClient({ethereumAccount,chain: arbitrumSepolia,transport: http(),});// Starknet wallet setupconst starknetProvider = new RpcProvider(); // Using default RPC URLconst starknetWallet = new Account( starknetProvider, '<YOUR_STARKNET_ADDRESS>', '<YOUR_STARKNET_PRIVATE_KEY>',);// Solana wallet setupconst solanaPrivKeyBytes = new Uint8Array('<YOUR_SOLANA_PRIVATE_KEY_BYTES>');const solanaUser = web3.Keypair.fromSecretKey(solanaPrivKeyBytes);const solanaConnection = new web3.Connection(RPC_URL, { commitment: 'confirmed' });const solanaWallet = new anchor.Wallet(solanaUser);const solanaProvider = new anchor.AnchorProvider(solanaConnection, solanaWallet);
3
Configure Garden instance
A digest key is a 32-byte key that serves as a unique identifier, used for generating secrets (preimages for HTLCs). It functions as a Garden account, but it is strictly non-custodial, with no funds ever being associated with it or moved through it.
import { Quote, SwapParams } from '@gardenfi/core';import { Asset, SupportedAssets } from '@gardenfi/orderbook';const fromAsset = SupportedAssets.testnet.ethereum_sepolia_WBTC;const toAsset = SupportedAssets.testnet.bitcoin_testnet_BTC;const sendAmount = '1000000'; // 0.01 WBTC// Helper function to construct an order pairconst constructOrderpair = (fromAsset: Asset, toAsset: Asset) => `${fromAsset.chain}:${fromAsset.atomicSwapAddress}::${toAsset.chain}:${toAsset.atomicSwapAddress}`;const orderPair = constructOrderpair( fromAsset, toAsset,);// Get the quote for the send amount and order pairconst quoteResult = await garden.quote.getQuote( orderPair, Number(sendAmount), false, // Set this to true if you wish to specify the output (receive) amount);if (!quoteResult.ok) { throw new Error(quoteResult.error);}// Choose a quoteconst [_strategyId, quoteAmount] = Object.entries(quoteResult.val.quotes)[0];const swapParams: SwapParams = { fromAsset, toAsset, sendAmount, receiveAmount: quoteAmount, additionalData: { strategyId: _strategyId, btcAddress?: '<YOUR_BITCOIN_ADDRESS>', },};// Create the swapconst swapResult = await garden.swap(swapParams);if (!swapResult.ok) { throw new Error(swapResult.error);}const order = swapResult.val;console.log('✅ Order created:', order.create_order.create_id);
5
Initiate the swap
The first swap requires gas for token approval. Subsequent swaps will be gasless.
Copy
Ask AI
const order = swapResult.val;const initRes = await garden.evmHTLC.initiate(order); // `garden.starknetHTLC` for Starknetif (!initRes.ok) { throw new Error(initRes.error);}
6
Settle the swap
Garden handles swap settlement automatically. The execute function continuously polls for the order status and calls redeem when the status becomes redeemable.
Copy
Ask AI
await garden.execute();// Subscribe to Garden events to track transaction statusesgarden.on('error', (order, error) => { console.error(`Error occurred for order ID ${order.create_order.create_id}:`, error);});garden.on('success', (order, action, txHash) => { console.log(`${order} ${action} ${txHash}`);});
It is important to keep the service running until completion of the swap. If the instance is stopped, restarting it will ensure Garden checks the status of the order and resubmits the redeem if necessary.