Token Utilities
approveTokenIfNeeded
async approveTokenIfNeeded(
walletClient: WalletClient,
token: Address,
spender: Address,
amount: bigint
): Promise<Hex | null>
Checks the current token allowance and only sends an approval transaction if needed. Returns null if approval is already sufficient.
This is used internally by deposit() and createEscrowAndDeposit(), but you can call it manually for custom flows.
Parameters
walletClient: WalletClient– The token owner's wallettoken: Address– The ERC20 token contract addressspender: Address– The address to approve (usually escrow contract)amount: bigint– The required approval amount
Returns
Promise<Hex | null> – Transaction hash if approval was sent, null if already approved
import { createPalindromeSDK } from '@/lib/createSDK';
const { sdk, walletClient } = await connectAndInitSDK();
const USDT = "0x337610d27c682E347C9cD60BD4b3b107C9d34dDd"; // Base Sepolia USDT
const amount = 1000000000000000000000n; // 1000 USDT
// Approve if needed
const txHash = await sdk.approveTokenIfNeeded(
walletClient,
USDT,
sdk.contractAddress,
amount
);
if (txHash) {
console.log("Approval sent:", txHash);
} else {
console.log("Already approved — no transaction needed");
}
How It Works
// Pseudocode of internal logic:
async function approveTokenIfNeeded(wallet, token, spender, amount) {
const currentAllowance = await getTokenAllowance(wallet.address, spender, token);
if (currentAllowance >= amount) {
return null; // Already approved enough
}
// Send approval transaction
const hash = await wallet.writeContract({
address: token,
functionName: "approve",
args: [spender, amount],
});
await waitForReceipt(hash);
return hash;
}
With USDT Pattern
USDT on some chains requires resetting allowance to 0 before setting a new value:
// For tokens that require reset (like USDT on Ethereum mainnet)
async function approveWithReset(wallet, token, spender, amount) {
const current = await sdk.getTokenAllowance(wallet.address, spender, token);
// If current > 0 and < amount, reset first
if (current > 0n && current < amount) {
await wallet.writeContract({
address: token,
functionName: "approve",
args: [spender, 0n],
});
}
// Now approve the new amount
return await sdk.approveTokenIfNeeded(wallet, token, spender, amount);
}
UI Pattern
function DepositButton({ escrowId }: { escrowId: bigint }) {
const [approving, setApproving] = useState(false);
const [depositing, setDepositing] = useState(false);
const handleDeposit = async () => {
const escrow = await sdk.getEscrowByIdParsed(escrowId);
// Step 1: Approve if needed
setApproving(true);
const approveTx = await sdk.approveTokenIfNeeded(
walletClient,
escrow.token,
sdk.contractAddress,
escrow.amount
);
if (approveTx) {
console.log("Approved:", approveTx);
}
setApproving(false);
// Step 2: Deposit
setDepositing(true);
const depositTx = await sdk.deposit(walletClient, escrowId);
console.log("Deposited:", depositTx);
setDepositing(false);
};
return (
<button onClick={handleDeposit} disabled={approving || depositing}>
{approving ? "Approving..." : depositing ? "Depositing..." : "Deposit"}
</button>
);
}
See also → getTokenAllowance() · deposit()
