1

Prerequistes

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.
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 setup
const ethereumAccount = privateKeyToAccount('<YOUR_EVM_PRIVATE_KEY>');
const ethereumWalletClient = createWalletClient({
ethereumAccount,
chain: arbitrumSepolia,
transport: http(),
});

// Starknet wallet setup
const starknetProvider = new RpcProvider(); // Using default RPC URL
const starknetWallet = new Account(
    starknetProvider,
    '<YOUR_STARKNET_ADDRESS>',
    '<YOUR_STARKNET_PRIVATE_KEY>',
);

// Solana wallet setup
const 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 { Garden } from '@gardenfi/core';
import { Environment, DigestKey } from '@gardenfi/utils';

const digestKey = DigestKey.from('<YOUR_DIGEST_KEY>');

const garden = Garden.fromWallets({
    environment: Environment.TESTNET,
    digestKey: digestKey.val,
    wallets: {
        evm: ethereumWalletClient,
        starknet: starknetWallet,
        solana: solanaProvider,
    }
});
4

Create a swap

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 pair
const 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 pair
const 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 quote
const [_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 swap
const 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.
const order = swapResult.val;
const initRes = await garden.evmHTLC.initiate(order); // `garden.starknetHTLC` for Starknet

if (!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.
await garden.execute();

// Subscribe to Garden events to track transaction statuses
garden.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.