import { FC, useState } from 'react';
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { isTempoWallet } from '@dynamic-labs/tempo';
import { encodeFunctionData, Hex, parseUnits } from 'viem';
// TIP-20 ABI with transferWithMemo
const tip20Abi = [
{
inputs: [
{ name: 'to', type: 'address' },
{ name: 'amount', type: 'uint256' },
{ name: 'memo', type: 'string' },
],
name: 'transferWithMemo',
outputs: [{ name: '', type: 'bool' }],
stateMutability: 'nonpayable',
type: 'function',
},
] as const;
const TransferWithMemoButton: FC = () => {
const { primaryWallet } = useDynamicContext();
const [txHash, setTxHash] = useState<string | null>(null);
const onTransferWithMemo = async () => {
if (!primaryWallet || !isTempoWallet(primaryWallet)) {
throw new Error('Tempo wallet not found');
}
const publicClient = await primaryWallet.getPublicClient();
const walletClient = await primaryWallet.getWalletClient();
const fromAddress = primaryWallet.address as Hex;
const toAddress = '0xRecipient...' as Hex;
const tokenAddress = '0xToken...' as Hex;
const feeTokenAddress = '0xFeeToken...' as Hex;
const amount = parseUnits('100', 6); // 100 tokens with 6 decimals
const memo = 'Payment for invoice #12345';
// Encode transferWithMemo call
const callData = encodeFunctionData({
abi: tip20Abi,
functionName: 'transferWithMemo',
args: [toAddress, amount, memo],
});
// Get nonce and gas
const nonce = await publicClient.getTransactionCount({
address: fromAddress,
});
const gasPrice = await publicClient.getGasPrice();
// Build transaction
const tempoTx = {
calls: [
{
data: callData,
to: tokenAddress,
value: BigInt(0),
},
],
chainId: await publicClient.getChainId(),
gas: BigInt(300000),
maxFeePerGas: gasPrice,
maxPriorityFeePerGas: gasPrice / BigInt(10),
nonce,
feeToken: feeTokenAddress,
};
const hash = await walletClient.sendTransaction(tempoTx);
setTxHash(hash);
};
return (
<div>
<button onClick={onTransferWithMemo}>Transfer with Memo</button>
{txHash && <p>Transaction: {txHash}</p>}
</div>
);
};