/**
* useStealthTransfer - Mobile-optimized private transfer hook
*
* Handles shielded SPL token transfers on Solana from mobile devices.
*
* @example
* ```tsx
* import { useStealthTransfer } from '@sip-protocol/react-native'
*
* function SendScreen() {
* const { transfer, status, error, isLoading } = useStealthTransfer({
* connection,
* wallet: walletAdapter,
* })
*
* const handleSend = async () => {
* const result = await transfer({
* recipientMetaAddress: 'sip:solana:...',
* amount: 1000000n, // 1 USDC
* mint: USDC_MINT,
* })
* if (result.success) {
* Alert.alert('Success', 'Payment sent privately!')
* }
* }
*
* return (
*
* {isLoading ? 'Sending...' : 'Send Private Payment'}
*
* )
* }
* ```
*/
import { useState, useCallback } from 'react'
/**
* Wallet adapter interface for mobile wallets
*/
export interface MobileWalletAdapter {
publicKey: { toBase58(): string } | null
signTransaction: (transaction: T) => Promise
signAllTransactions?: (transactions: T[]) => Promise
}
/**
* Transfer status enum
*/
export type TransferStatus =
| 'idle'
| 'preparing'
| 'signing'
| 'sending'
| 'confirming'
| 'success'
| 'error'
/**
* Parameters for stealth transfer
*/
export interface TransferParams {
/** Recipient's stealth meta-address */
recipientMetaAddress: string
/** Amount in smallest units */
amount: bigint
/** SPL token mint address */
mint: string
}
/**
* Result of stealth transfer
*/
export interface TransferResult {
success: boolean
signature?: string
stealthAddress?: string
error?: Error
}
/**
* Connection interface (subset of @solana/web3.js Connection)
*/
export interface SolanaConnection {
confirmTransaction(
signature: string,
commitment?: string
): Promise<{ value: { err: unknown } }>
}
/**
* Parameters for useStealthTransfer hook
*/
export interface UseStealthTransferParams {
/** Solana connection */
connection: SolanaConnection
/** Wallet adapter */
wallet: MobileWalletAdapter
}
/**
* Return type for useStealthTransfer hook
*/
export interface UseStealthTransferReturn {
/** Execute a private transfer */
transfer: (params: TransferParams) => Promise
/** Current transfer status */
status: TransferStatus
/** Error if any occurred */
error: Error | null
/** Whether a transfer is in progress */
isLoading: boolean
/** Reset the hook state */
reset: () => void
}
/**
* Mobile-optimized stealth transfer hook
*
* @param params - Hook parameters
*/
export function useStealthTransfer(
params: UseStealthTransferParams
): UseStealthTransferReturn {
const { connection, wallet } = params
const [status, setStatus] = useState('idle')
const [error, setError] = useState(null)
const transfer = useCallback(
async (transferParams: TransferParams): Promise => {
const { recipientMetaAddress, amount, mint } = transferParams
// Validate wallet connected
if (!wallet.publicKey) {
const err = new Error('Wallet not connected')
setError(err)
setStatus('error')
return { success: false, error: err }
}
try {
setStatus('preparing')
setError(null)
// Dynamic import SDK functions to avoid bundling issues
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const sdk: any = await import('@sip-protocol/sdk')
// Check if sendPrivateSPLTransfer is available
if (!sdk.sendPrivateSPLTransfer) {
throw new Error(
'sendPrivateSPLTransfer not available. Install @sip-protocol/sdk with Solana support.'
)
}
const sendPrivateSPLTransfer = sdk.sendPrivateSPLTransfer as (params: {
connection: unknown
sender: unknown
senderTokenAccount: unknown
recipientMetaAddress: string
mint: unknown
amount: bigint
signTransaction: unknown
}) => Promise<{ signature: string; stealthAddress: string }>
// Dynamic import Solana libraries
const { PublicKey } = await import('@solana/web3.js')
const { getAssociatedTokenAddress } = await import('@solana/spl-token')
// Get sender's token account
const mintPubkey = new PublicKey(mint)
const senderTokenAccount = await getAssociatedTokenAddress(
mintPubkey,
new PublicKey(wallet.publicKey.toBase58())
)
setStatus('signing')
// Execute private transfer
const result = await sendPrivateSPLTransfer({
connection,
sender: new PublicKey(wallet.publicKey.toBase58()),
senderTokenAccount,
recipientMetaAddress,
mint: mintPubkey,
amount,
signTransaction: wallet.signTransaction,
})
setStatus('confirming')
// Wait for confirmation
const confirmation = await connection.confirmTransaction(
result.signature,
'confirmed'
)
if (confirmation.value.err) {
throw new Error(`Transaction failed: ${confirmation.value.err}`)
}
setStatus('success')
setError(null)
return {
success: true,
signature: result.signature,
stealthAddress: result.stealthAddress,
}
} catch (err) {
const error = err instanceof Error ? err : new Error('Transfer failed')
setError(error)
setStatus('error')
return { success: false, error }
}
},
[connection, wallet]
)
const reset = useCallback(() => {
setStatus('idle')
setError(null)
}, [])
return {
transfer,
status,
error,
isLoading: status !== 'idle' && status !== 'success' && status !== 'error',
reset,
}
}
/**
* Get associated token address helper
*
* Dynamically imports from @solana/spl-token
*
* @param mint - Token mint address string
* @param owner - Owner address string
* @returns Associated token address
*/
export async function getAssociatedTokenAddress(
mint: string,
owner: string
): Promise {
const { PublicKey } = await import('@solana/web3.js')
const { getAssociatedTokenAddress: getATA } = await import('@solana/spl-token')
const ata = await getATA(new PublicKey(mint), new PublicKey(owner))
return ata.toBase58()
}