TGViewer
MVT MVT @isnomad · 347 subscribers
Post #535 589
Залился в пул, а один токен в паре поставили на паузу, как достать хоть что-то?

Столкнулся с такой проблемой на токене H где в позе было залито 95% USDC и не давало достать токены из-за паузы на трансферы самого H
Оказывается можно полностью отказаться от одного токена через контракт и забрать другой, в этом гайде пошагово расписаны шаги как это сделать:

Нужно собрать такие данные:
tokenId              = ID Uniswap v4 NFT позиции
liquidity = размер ликвидности позиции
recipient = адрес, куда вывести нормальный токен
goodToken = адрес токена, который нужно вывести
pausedToken = адрес токена, который нельзя перевести
goodTokenIsCurrency0 = true / false
amountMin = минимальная сумма нормального токена


Где взять tokenId
Открой адрес своего кошелька на Etherscan.
Перейди:
NFT Transfers / ERC-721 Token Txns

Ищи NFT от контракта:
Uniswap v4 Position Manager
0xbD216513d74C8cf14cf4747E6AaA6420FF64ee9e

В строке будет Token ID. Это и есть tokenId.

Где взять liquidity
Открой контракт Uniswap v4 Position Manager:
0xbD216513d74C8cf14cf4747E6AaA6420FF64ee9e

На Etherscan открой:
Read Proxy Contract

Вызови:
getPositionLiquidity(tokenId)

Ответ liquidity нужно вставить в encoder.

Где понять currency0 / currency1
На том же контракте вызови:
getPoolAndPositionInfo(tokenId)

В ответе будет:
currency0 = первый токен
currency1 = второй токен

Если выводимый токен — currency0, тогда:
amount0Min = amountMin
amount1Min = 0

Если выводимый токен — currency1, тогда:
amount0Min = 0
amount1Min = amountMin


Онлайн-способ: StackBlitz или Replit
Можно использовать любой онлайн Node.js runner:
StackBlitz
Replit Node.js
Можно залить инструкцию в гпт и он выполнит скрипт самостоятельно

Нельзя вставлять private key или seed phrase. Этот скрипт только генерирует calldata и ничего не подписывает.

encode.js
Создай файл encode.js:
import { AbiCoder, MaxUint256 } from "ethers";

const coder = AbiCoder.defaultAbiCoder();

/**
* ====== ЗАПОЛНИТЬ ЭТИ ПОЛЯ ======
*/

// ID NFT-позиции Uniswap v4
const tokenId = 123123;

// liquidity из getPositionLiquidity(tokenId)
const liquidity = 28680156276946644n;

// куда вывести нормальный токен
const recipient = "0xВАШ_КОШЕЛЕК";

// токен, который нужно достать
const goodToken = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; // example: USDC

// paused-токен, который нужно оставить/clear
const pausedToken = "0xcf5104D094e3864CfCBDa43B82e1cEFD26A016eB";

// true, если goodToken = currency0
// false, если goodToken = currency1
const goodTokenIsCurrency0 = true;

// минимальная сумма goodToken в raw units
// example: USDC 1490 = 1490 * 10^6 = 1490000000
const amountMin = 1490000000n;

/**
* ====== НИЖЕ НЕ ТРОГАТЬ ======
*/

// 0x01 = DECREASE_LIQUIDITY
// 0x0e = TAKE
// 0x13 = CLEAR_OR_TAKE
const actions = "0x010e13";

const amount0Min = goodTokenIsCurrency0 ? amountMin : 0n;
const amount1Min = goodTokenIsCurrency0 ? 0n : amountMin;

const params = [
// DECREASE_LIQUIDITY(tokenId, liquidity, amount0Min, amount1Min, hookData)
coder.encode(
["uint256", "uint256", "uint128", "uint128", "bytes"],
[
tokenId,
liquidity,
amount0Min,
amount1Min,
"0x"
]
),

// TAKE(goodToken, recipient, OPEN_DELTA)
// OPEN_DELTA = 0 means take all available positive delta
coder.encode(
["address", "address", "uint256"],
[
goodToken,
recipient,
0n
]
),

// CLEAR_OR_TAKE(pausedToken, MaxUint256)
// This forfeits the paused token delta instead of trying to transfer it.
coder.encode(
["address", "uint256"],
[
pausedToken,
MaxUint256
]
)
];

const unlockData = coder.encode(
["bytes", "bytes[]"],
[actions, params]
);

const deadline = Math.floor(Date.now() / 1000) + 3600;

console.log("unlockData:");
console.log(unlockData);

console.log("\ndeadline:");
console.log(deadline);


package.json
Если онлайн-редактор просит package.json, используй:
{
"type": "module",
"dependencies": {
"ethers": "^6.13.0"
},
"scripts": {
"start": "node encode.js"
}
}


Как запустить
В терминале онлайн-редактора:
npm install
node encode.js

На выходе будет:
unlockData:
0x...

deadline:
178...


Как вызвать на Etherscan
Открой контракт:
0xbD216513d74C8cf14cf4747E6AaA6420FF64ee9e

Перейди:
Write Proxy Contract

Подключи кошелек через:
Connect to Web3

Найди функцию:
modifyLiquidities(bytes unlockData, uint256 deadline)

Заполни:
unlockData = 0x... из скрипта
deadline = timestamp из скрипта
value = 0

Не используй:
modifyLiquiditiesWithoutUnlock


Что произойдет
Транзакция сделает:
DECREASE_LIQUIDITY
TAKE(goodToken)
CLEAR_OR_TAKE(pausedToken)

То есть нормальный токен будет отправлен на recipient.
Paused-токен не будет переведен. Его delta будет очищена через CLEAR_OR_TAKE.
Это не сохранение paused-токена. Это отказ от него ради вывода второго токена.

Примеры описаны на сети ETH, применимо и к другим EVM чейнам по аналогии
  • 👍 16
  • ❤ 5
  • 🔥 4
More from @isnomad
  1. Sep 13, 2026Расфлипался наконец то
  2. Sep 13, 2026Джитнул панду в х3 прямо перед полётом на атх 🥲
  3. Aug 3, 2026Post #542
  4. Jul 27, 2026Лягушка классная
  5. Jul 27, 2026Post #539
  6. Jul 23, 2026какие же интересные мувы на робингуде можно делать, классный чейн 🤑
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →