import { Env } from '@lombard.finance/sdk-common'; import type { Meta, StoryObj } from '@storybook/react'; import { useState } from 'react'; import { envToNetwork, getConfig } from '../../const/getConfig'; import { Button, CodeBlock, ConnectButton, ErrorDisplay, ResultDisplay, SectionCard, } from '../../stories/components'; import { functionType } from '../../stories/decorators/function-type'; import { useConnect } from '../../stories/hooks/useConnect'; import useQuery from '../../stories/hooks/useQuery'; import { redeem } from './redeem'; interface RedeemStoryArgs { environment: Env; amount: string; recipient: string; tokenMint: string; toLchainId: string; toTokenAddress: string; } export const StoryView = ({ environment, amount, recipient, tokenMint, toLchainId, toTokenAddress, }: RedeemStoryArgs) => { const network = envToNetwork[environment]; const config = getConfig(environment); const [transactionLogs, setTransactionLogs] = useState(null); const { data: connectionData, error: connectError, isLoading: isConnecting, connect, disconnect, } = useConnect(); const isConnected = !!connectionData; const address = connectionData?.address; const provider = connectionData?.provider; const effectiveMint = tokenMint || config.lbtcTokenMint; const effectiveToToken = toTokenAddress || config.btcbTokenMint; const request = async () => { if (!provider || !address) throw new Error('Wallet not connected.'); if (!recipient) throw new Error('Recipient address is required (set in args).'); const parsedAmount = parseFloat(amount); if (!amount || isNaN(parsedAmount) || parsedAmount <= 0) throw new Error('Amount must be a positive number in BTC (set in args).'); const amountSats = Math.round(parsedAmount * 1e8).toString(); setTransactionLogs(null); try { const result = await redeem(provider, { amount: amountSats, recipient, tokenMint: tokenMint || undefined, toLchainId: toLchainId || undefined, toTokenAddress: toTokenAddress || undefined, network, env: environment, debug: true, }); return result; } catch (err: unknown) { if (err instanceof Error && err.message.includes('Debug logs:')) { const parts = err.message.split('Debug logs:\n'); setTransactionLogs(parts[1]?.split('\n') || []); } throw err; } }; const { data: txHash, error, isLoading, refetch: handleRedeem, } = useQuery( request, [ provider, address, amount, recipient, tokenMint, toLchainId, toTokenAddress, environment, ], false, ); return ( <> {isConnected && ( <>

Environment: {environment}

Network: {network}

Amount: {amount} BTC

Recipient: {recipient || Not set}

Source token mint:{' '} {effectiveMint || Not configured}

Destination token:{' '} {effectiveToToken || Not configured}

{txHash && ( )} {(error || connectError) && ( )} {transactionLogs && transactionLogs.length > 0 && ( )} )} ); }; const meta: Meta = { title: 'write/redeem (Asset Router)', component: StoryView, tags: ['autodocs'], decorators: [functionType('write')], parameters: { docs: { description: { component: `Demonstrates generic token redemption via the Asset Router's \`redeem\` instruction. **Flow:** 1. Connect a Solana wallet holding the source token (defaults to LBTC) 2. Enter the recipient address and amount (in BTC) 3. Optionally override source mint, destination chain ID, and destination token 4. Call \`redeem\` — burns the source token and sends a GMP message through the Mailbox 5. The destination token is routed to the recipient's ATA for Asset Router \`native_mint\` (payload carries that token account address)`, }, }, }, args: { environment: Env.stage, amount: '0.0002', recipient: '', tokenMint: '', toLchainId: '', toTokenAddress: '', }, argTypes: { environment: { control: { type: 'select' }, options: Object.values(Env), }, amount: { control: { type: 'text' }, description: 'Amount to redeem in BTC (e.g. 0.0002)', }, recipient: { control: { type: 'text' }, description: 'Recipient wallet (owner); SDK uses the associated token account for on-chain native_mint in the redeem payload (Solana base58)', }, tokenMint: { control: { type: 'text' }, description: 'Source token mint override (defaults to LBTC from config)', }, toLchainId: { control: { type: 'text' }, description: 'Destination Lombard routing chain ID (hex). Defaults to Solana routing chain ID', }, toTokenAddress: { control: { type: 'text' }, description: 'Destination token address/mint override (defaults to BTC.b from config)', }, }, }; export default meta; type Story = StoryObj;