Разработка UI для миграции токенов
Миграция токенов — это один из немногих случаев в Web3 где UX критичен с точки зрения безопасности. Пользователь апрувит контракт, которому он, возможно, не доверяет полностью. Задача UI: сделать каждый шаг прозрачным, показать что именно происходит с токенами, и не дать пользователю нажать «Approve» не понимая последствий.
Поток миграции
Стандартная схема: старый токен (v1) → новый токен (v2) через контракт-мигратор. Контракт принимает v1, сжигает или блокирует его, минтит v2 в соотношении 1:1 (или другом).
UI должен покрыть три транзакции:
-
approve(migratorContract, amount)на v1 токене -
migrate(amount)на контракте-мигратор - (опционально) добавить v2 в MetaMask через
wallet_watchAsset
async function migrateTokens(amount: bigint) {
// Шаг 1: проверяем текущий allowance
const currentAllowance = await v1Token.allowance(userAddress, MIGRATOR_ADDRESS);
if (currentAllowance < amount) {
const approveTx = await v1Token.approve(MIGRATOR_ADDRESS, amount);
await approveTx.wait();
}
// Шаг 2: миграция
const migrateTx = await migrator.migrate(amount);
const receipt = await migrateTx.wait();
return receipt;
}
Ключевые UI компоненты
Баланс-дисплей до/после
Показываем пользователю явно, что произойдёт: сколько v1 спишется, сколько v2 получится. Если курс не 1:1 — особенно важно.
function MigrationPreview({ amount, exchangeRate }: Props) {
const v2Amount = (BigInt(amount) * BigInt(exchangeRate * 100)) / 100n;
return (
<div className="migration-preview">
<div className="from">
<span>Отдаёте: {formatEther(amount)} {V1_SYMBOL}</span>
</div>
<ArrowIcon />
<div className="to">
<span>Получаете: {formatEther(v2Amount)} {V2_SYMBOL}</span>
</div>
</div>
);
}
Stepper с состояниями транзакций
Каждый шаг — approve, migrate, done — отображается с явным статусом: ожидание, pending, confirmed, error.
type MigrationStep = 'idle' | 'approving' | 'approved' | 'migrating' | 'done' | 'error';
const stepConfig = {
idle: { label: 'Готов к миграции', icon: 'clock' },
approving: { label: 'Подтверждаем апрув...', icon: 'spinner' },
approved: { label: 'Апрув подтверждён', icon: 'check' },
migrating: { label: 'Мигрируем токены...', icon: 'spinner' },
done: { label: 'Миграция завершена', icon: 'check-circle' },
error: { label: 'Ошибка', icon: 'x-circle' },
};
Ссылка на Etherscan для каждой транзакции, как только получен txHash — не ждём подтверждения.
Infinite approve предупреждение
Если контракт запрашивает type(uint256).max approve — явно сообщить пользователю. Предложить выбор: exact amount или unlimited. Для миграции правильнее exact amount — пользователь мигрирует конкретное количество.
Обработка edge cases
Частичная миграция: пользователь мигрировал часть токенов, вернулся позже. Показываем текущие балансы v1 и v2, остаток для миграции.
Дедлайн миграции: контракты-мигратор часто имеют deadline после которого миграция невозможна. Если дедлайн задан — показываем countdown, предупреждаем заранее (за 7 дней, 24 часа).
Revert причины: если транзакция reverted — пытаемся декодировать причину через parseRevertReason и показать человекочитаемое сообщение вместо «Transaction failed».
function parseRevertReason(error: any): string {
const message = error?.info?.error?.message || error?.message || '';
if (message.includes('Migration ended')) return 'Период миграции завершён';
if (message.includes('Insufficient balance')) return 'Недостаточно токенов';
if (message.includes('user rejected')) return 'Транзакция отменена пользователем';
return 'Неизвестная ошибка. Попробуйте позже.';
}
Ориентиры по срокам
Полный UI миграции с stepper, балансами, транзакциями и обработкой ошибок — 2-3 дня.







