Интеграция с Revoke.cash
Unlimited approve — стандартная практика в DeFi для экономии газа, и стандартный вектор атаки при компрометации протокола. Пользователь даёт approve(spender, type(uint256).max) один раз, и забывает об этом. Если протокол взломан — атакующий дренирует кошелёк полностью. Revoke.cash позволяет управлять allowances. Интеграция этого функционала в dApp — это один день работы, который существенно повышает уровень доверия к продукту.
Что такое интеграция с Revoke.cash
Revoke.cash предоставляет open-source компоненты и API. Интегрировать можно двумя способами:
-
Deeplink — кнопка «Manage Approvals» открывает
revoke.cash/address/<userAddress>с предзаполненным адресом - Embedded allowance list — отображение и управление allowances прямо в dApp через Revoke.cash SDK
Deeplink — 30 минут работы. Embedded — 1 день.
Deeplink интеграция
import { useAccount } from 'wagmi'
function ManageApprovalsButton() {
const { address, chainId } = useAccount()
const revokeUrl = address
? `https://revoke.cash/${address}?chainId=${chainId ?? 1}`
: 'https://revoke.cash'
return (
<a
href={revokeUrl}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 text-sm text-yellow-400 hover:text-yellow-300"
>
<ShieldAlert className="h-4 w-4" />
Управление разрешениями
</a>
)
}
Revoke.cash поддерживает параметр chainId — пользователь сразу попадает на нужную сеть.
Прямая работа с allowances через viem
Если нужно показывать allowances внутри dApp без редиректа — читаем напрямую через ERC-20 allowance():
import { createPublicClient, http, erc20Abi } from 'viem'
async function getAllowance(
tokenAddress: `0x${string}`,
owner: `0x${string}`,
spender: `0x${string}`,
chainId: number
): Promise<bigint> {
const client = createPublicClient({ chain: getChain(chainId), transport: http() })
return client.readContract({
address: tokenAddress,
abi: erc20Abi,
functionName: 'allowance',
args: [owner, spender],
})
}
Для revoke — approve(spender, 0):
import { useWriteContract } from 'wagmi'
import { erc20Abi } from 'viem'
function RevokeButton({ tokenAddress, spender }: { tokenAddress: `0x${string}`, spender: `0x${string}` }) {
const { writeContract, isPending } = useWriteContract()
return (
<button
onClick={() => writeContract({
address: tokenAddress,
abi: erc20Abi,
functionName: 'approve',
args: [spender, 0n],
})}
disabled={isPending}
>
{isPending ? 'Отзыв...' : 'Отозвать разрешение'}
</button>
)
}
Обратите внимание: 0n (BigInt ноль), не 0. viem строго типизирован и ожидает bigint для uint256.
Где разместить в интерфейсе
Логичные места для кнопки управления allowances:
- Settings / Security страница dApp
- После approve транзакции — всплывающая подсказка «Хотите ограничить разрешение?»
- Wallet dropdown — рядом с балансом и disconnect
- Transaction history — рядом с историческими approve операциями
Показывать это на главной странице не нужно — создаёт ненужный anxiety. Но возможность должна быть легко находимой.







