Tokenを送れない・売れない原因|transfer fee・blacklist・rebasingを確認
ERC-20の送金・swap失敗をfee-on-transfer、rebasing、pause、blacklist、maxTx、sell restriction、liquidity、slippageへ分けてread-onlyで確認します。

tokenを送れない、受取額が減った、買えたのに売れない、swapの見積もりだけ失敗する。これらを全部「slippage」や「walletの不具合」にまとめると、原因が分からないままapprovalや失敗transactionを重ねることになります。
最初に分けるのは、token contract自身のtransfer条件、poolのliquidityとprice impact、routerのminimum received・deadline、walletやindexerの表示です。Explorerのverified表示、過去のbuy成功、symbol、detectorの単独判定は、現在のsellや送金が成功する証明になりません。
この記事は公式仕様とローカルの合成contractだけを使います。実在tokenの売買、wallet接続、approval、署名、送金、swap、bridge、公開transactionは行いません。
原因が分かるまで止める操作
次の操作は、調査ではなく新しいriskを増やします。
- 失敗のたびにslippageを上げる
- 別routerや未知の「sell専用site」へwalletを接続する
- contractを直接callすれば回避できるという案内に従う
- approvalを取り消しては付け直す操作を繰り返す
- token名やerror messageに書かれたURLを開く
- 「tax」「unlock fee」「回収用gas」を先払いする
- seed phrase、private key、remote-control、screen sharingを渡す
まず公開情報だけを保存し、どの層で止まったかを分類します。秘密情報、署名、追加送金は証拠に含めません。
一つの調査メモへ固定する値
| 層 | 保存する値 | 混同しないもの |
|---|---|---|
| identity | chain ID、full token contract、確認block number / hash | symbol、name、icon |
| account | full sender / recipient、raw balance、decimals | walletの丸めた表示だけ |
| transaction | tx hash、receipt status、called address、calldata selector、revert data | 一覧の「失敗」表示だけ |
| transfer accounting | sender減少、recipient増加、fee collector / burn、Transfer logs | swapのslippage |
| authority | proxy、implementation、owner、roles、admin、timelock、upgrade event | verified badge |
| market | pair / pool、route、active liquidity、price impact | token contractのblacklist |
| router | exact input / output、minimum received、deadline、allowance | tokenのtransferability |
| observation | RPC、block、from、to、amount、route、確認時刻 |
将来のtransaction保証 |
tokenがwalletへ出ないだけなら、先にchain・contract・decimalsから表示を確認する手順を使います。balanceOfはあるのに一覧へ出ない問題と、transfer自体がrevertする問題は別です。
standard ERC-20を基準に差を見る
ERC-20は、transferとtransferFromがboolを返すinterface、残高、allowance、Transfer / Approval eventを定めています。呼び出し側はfalseを無視してはいけません。
ただしERC-20という名前だけで、次の機能がないことまでは保証されません。
- transfer時のfeeやburn
- balanceを伸縮させるrebase / shares accounting
- pause、blacklist、allowlist
- 1回の最大量、cooldown、holding period
- 特定pool、router、sender、recipientだけを対象にする条件
- proxy upgradeで後から変わる実装
基準にする観測は単純です。固定blockの前後で、senderがamount減り、recipientが同じamount増え、成功を示すreturnと対応するeventがあるかを見ます。一つでも違えば、すぐに悪意や詐欺と断定せず、差の説明へ進みます。
6種類のtoken挙動を分ける
| case | decisive evidence | 主な影響 | 一つのsignalで断定しないこと |
|---|---|---|---|
| standard | sender debitとrecipient creditがamountに一致 | 通常のintegration前提 | 安全・公式・十分なliquidity |
| fee-on-transfer | debit、credit、collector / burnが同じtransferで説明できる | 受取減、quote差、router非対応 | 差額はすべて既知fee |
| rebasing / shares | sharesやindexは固定・変化し、表示balanceがtransfer外で変わる | wallet / indexer差、pool accounting差 | eventがないから資産消失 |
| pause / blacklist | current state、role、specific revert、対象account | 全体停止またはaccount別停止 | revert文字列だけで対象contractを特定 |
| maxTx / cooldown | threshold、last action、block / time条件 | amountや時点で結果が変わる | 小額成功なら将来も成功 |
| sell restriction | configured pool / recipientでだけ条件が変わる | buyと通常transferは通ってもsell失敗 | 1回の失敗だけでhoneypot確定 |
「honeypot」は市場やdetectorで広く使われますが、この記事では一つのlabelにしません。pool宛だけのrestriction、可変fee、owner変更可能なstate、router非対応、浅いliquidityを別々に保存します。
fee-on-transferはamount・受取・feeを3列にする
fee-on-transferでは、1,000を指定してもrecipientが975、collectorまたはburnが25になるような実装があります。確認式は次の形です。
sender debit = recipient credit + explained fee or burn + unexplained difference
ローカル例では1,000 = 975 + 25 + 0となりました。ところがrecipientが950で、確認できるfeeが25しかなければ、残る25を「たぶんtax」と補完しません。fee率、対象address、除外list、collector、burn、event、block-specific stateを読み、未説明差として止めます。
token feeとDEX pool feeも別です。token contractがtransfer時に徴収するfeeを、poolが価格曲線やprotocol feeとして取る額と合算しないでください。
Uniswap V2 Router02にはfee-on-transfer向けの別functionがありますが、どのtoken実装も扱える保証ではありません。Uniswap V3 coreはsender減少とrecipient増加がtransfer amountに一致するtokenを前提としており、Uniswap Labsはfee-on-transfer、rebase、reflection tokenをV3 / V4で非対応と案内しています。routerを変える前に、対象protocolとversionの公式support境界を確認します。
rebasingはshareと表示balanceを分ける
rebasing tokenには複数の設計があります。ローカル例ではaccountがshareを持ち、次の式で表示balanceを計算しました。
visible balance = shares × scaling factor
同じ1,000 sharesでもfactorが変わると、表示balanceが1,250または800になります。この例ではuser transferを実行しなくてもbalanceが変わります。すべてのrebase、reflection、interest-bearing tokenがこの式やevent設計を使うわけではありません。
確認するのはtotal supplyだけではなく、accountのshares / credits、scaling factor / index、rebase event、walletとindexerの更新時点、pool contractが保持するbalanceです。Transfer eventがない変化を即座に盗難とみなさず、逆にwallet表示だけをon-chain balanceの正本にしません。
pause・blacklist・maxTx・cooldownをstateへ対応させる
OpenZeppelinのERC20Pausableはtransfer、mint、burnをpause条件へ結び付けますが、公開pause関数と権限設計は利用側contractが定義します。Ownable、AccessControl、custom modifierでは、同じ「admin」に見えても変更できる項目が異なります。
次の順でspecific stateとfailureを対応させます。
- call先がtoken、router、proxyのどれかを確認する
- proxyならcurrent implementationを固定blockで解決する
- revert dataをdecodeし、source内の条件へ対応させる
- pause、blacklist、allowlist、maxTx、cooldown、pool設定を同じblockで読む
- owner、role admin、timelock、upgrade authorityが誰かを確認する
- 過去eventから、設定がいつ変更されたかを確認する
「pause functionがABIにない」だけでは、pause相当のcustom条件がない証拠になりません。反対にpaused()が存在しても、それが今回通ったtransfer pathへ適用されるかはsourceとcall pathで確認します。
buyできてもsellできる証明にはならない
buyとsellでは、token transferのsenderとrecipientが逆になります。custom logicがconfigured pool、router、recipient、sender、amount、blockを条件にすると、poolからuserへのbuyは通り、userからpoolへのsellだけrevertすることがあります。
同様に、wallet間の小額transferが通っても、pool宛、取引所deposit contract宛、bridge contract宛が通る保証にはなりません。過去成功を安全証明にせず、現在のimplementationとstateを固定します。
ただしsell失敗一回だけで、malicious honeypot、違法、回収不能と断定もしません。allowance不足、deadline、minimum output、route変更、liquidity不足、network fee不足、paused poolなど別layerの失敗もあります。detectorの結果は調査候補であり、contract identityとraw evidenceの代わりではありません。
liquidity・price impact・slippage・deadlineはmarket / router層
| signal | layer | 確認する値 | token restrictionとの違い |
|---|---|---|---|
| insufficient liquidity | market | pool、active liquidity、route、pair identity | token transfer前にquoteが成立しない場合がある |
| high price impact | market | input size、mid-price、average execution price | 注文自身がquoteを動かす |
| minimum received | router | quote、許容差、expected / minimum output | 実行時outputが境界を下回る |
| deadline | router | signed requestのdeadline、block timestamp | 時間条件でrouterが止める |
| pause / blacklist / maxTx | token | implementation state、account、amount、revert | slippageを変えても条件自体は直らない |
| transfer fee | token + integration | debit、credit、fee、router対応 | quote計算と実受取の前提が変わる |
Price impactとslippageの計算、minimum output、MEVはDEXのPrice impactとslippageを分ける手順で確認できます。oracleやTWAPがtoken transfer制限を示すわけでもないため、価格sourceを調べる場合はdecimals・staleness・TWAP・L2停止の検証へ分けます。
false・empty return・revertは同じ失敗ではない
EVM callの結果には少なくとも次の違いがあります。
- callがrevertし、revert dataやcustom errorを返す
- call自体はrevertしないが、ERC-20の
boolとしてfalseを返す - callはrevertせずreturn dataが空で、古いnon-standard tokenとしてintegration側が扱う
trueを返しても、受取balanceやeventが想定と一致しない
ERC-20はcallerがfalseを処理するよう求めます。OpenZeppelinのSafeERC20はfalseをfailureとして扱い、return dataが空でrevertしないtokenもsupportします。したがって「transaction statusがsuccess」「EVMがrevertしなかった」「returnがtrue」「recipient balanceが増えた」を別々に保存します。
custom errorの名前も、信頼できるsourceとselector対応があって初めて意味を持ちます。walletやsiteが整形した文字列だけで、どのcontractがどの条件を判定したか決めません。
verified sourceからproxy・権限・upgradeを追う順番
Explorerのverified sourceが直接示すのは、提示sourceとdeployed bytecodeの対応です。売却可能、安全、公式、upgrade不能という保証ではありません。再構築とmatchの境界はcompiler・constructor・proxyまで確認する手順で扱っています。
調査順は次のとおりです。
- chain ID、full token address、block number / hashを固定する
eth_getCodeでproxyかdirect implementationかを確認する- ERC-1967ならimplementation、beacon、admin slotとupgrade eventを読む
- implementationのverified source、compiler、runtime bytecodeを照合する
- transfer / transferFromから内部update path、fee、restrictionを追う
- owner、roles、role admin、timelock、multisig、upgrade authorityを列挙する
- pool / router address、liquidity、price impact、minimum outputを別recordへ分ける
- fixed inputのread-onlyシミュレーションを行い、block identityとreturn / revertを保存する
proxyのstorageはproxy側にあり、logicはimplementation側にあります。implementation sourceだけを読み、proxy stateやadminを見ない調査は不完全です。upgrade後は、以前のシミュレーションやsource reviewを現在の保証として使いません。
シミュレーション成功は将来のtransaction成功ではない
eth_callは公開transactionを送らずに、指定blockのstateに対してcallを評価できます。再現条件には次を含めます。
chainId / RPC identity / block number / block hash
from / to / value / calldata / gas assumptions
token implementation / token state / balance / allowance
pool / route / input / minimum output / deadline
raw return data or raw revert data
同じinputでも、ownerがfeeやblacklistを変更した、proxyがupgradeされた、balanceやallowanceが変わった、pool priceが動いた、deadlineを過ぎた、別block producer環境になった場合は結果が変わります。シミュレーション成功は、記録した条件でrevertしなかったという証拠であり、mempoolへの受理、block inclusion、実行順、最終成功、受取額を保証しません。
シミュレーションfailureも原因を自動確定しません。RPCのstate、from、gas、block parameter、router、calldataが本番requestと違う可能性を先に排除します。
ローカルの合成contractで再現した範囲
Solidity 0.8.36、Prague EVMの自己完結したlocal contractをcompileし、次を分けました。
| case | local observation | 記事で使う境界 |
|---|---|---|
| standard | debit 1,000 / credit 1,000 |
基準であって安全評価ではない |
| fee-on-transfer | debit 1,000 / credit 975 / fee 25 |
差額をaccountingで説明する |
| shares rebase | shares一定、visible balance 1,250または800 |
一つの設計例に限定する |
| restricted | pause、blacklist、maxTx、cooldown、pool宛sellを別custom error | restriction同士を混ぜない |
| non-standard return | empty returnとfalseを別contractで再現 |
EVM revertとreturn valueを分ける |
この検証は実在token detectorではありません。公開RPC、real token、wallet、account、asset、approval、signature、broadcast、swapを使わず、攻撃的deploymentやrestriction回避方法も含みません。
公式supportやsecurity reviewerへ渡すevidence package
checked at and timezone:
chain name / chain ID:
token full contract address:
block number / block hash:
proxy / implementation / beacon / admin:
owner / roles / timelock / recent upgrade:
sender / recipient or pool role, without secrets:
raw amount / decimals:
sender debit / recipient credit / explained fee / difference:
receipt status / called address / function selector:
raw return or revert data:
pause / blacklist / maxTx / cooldown / pool state:
pool / route / active liquidity / price impact:
expected output / minimum received / deadline:
simulation conditions: RPC identity / from / to / calldata / block:
wallet, app, and browser versions if a UI was involved:
public addressやtransactionもticketの公開範囲を確認します。seed phrase、private key、password、2FA code、session cookie、API key、full device backup、remote accessは渡しません。
症状別の停止条件
| 症状 | 次のread-only確認 | 停止する操作 |
|---|---|---|
| 受取額が少ない | debit / credit / collector / burn / events | feeと決めつけて再送しない |
| balanceが勝手に変わった | shares / index / rebase / fixed-block balance | eventなしを盗難確定にしない |
| 全送金がrevert | implementation / pause / role / recent upgrade | direct callで回避しない |
| 特定accountだけrevert | blacklist / allowlist / sender・recipient条件 | 別accountで試してrestrictionを回避しない |
| 大きなamountだけrevert | maxTx / limit unit / current state | 小分け送金を自動推奨しない |
| sellだけrevert | pool設定 / fee / router support / allowance / liquidity | slippageや未知routerを反復しない |
| quoteが出ない | pair identity / route / active liquidity | 同symbolの別tokenを選ばない |
| シミュレーションだけ成功 | fixed inputs / block / mutable state | 実transaction成功と表示しない |
「売却代行」「凍結解除」「税金を払えばunlock」「必ず回収できる」という未依頼DMは二次被害のsignalです。この記事にはtoken detector、wallet、DEX、取引所、audit、回収serviceのaffiliateやsponsor導線を置いていません。
最終チェックリスト
- chain IDとfull token contractを固定した
- symbol、name、iconをidentityにしていない
- wallet表示とfixed-block
balanceOfを分けた - sender debit、recipient credit、fee / burn、未説明差を保存した
- rebaseのshares / index / event設計を対象sourceで確認した
- pause、blacklist、maxTx、cooldown、pool restrictionを別stateとして読んだ
- liquidity、price impact、minimum received、deadlineをtoken restrictionと分けた
- false、empty return、revert、balance変化を別結果として扱った
- proxy、implementation、owner / roles、upgrade eventを同じblockへ対応させた
- シミュレーションの
from、to、calldata、block、routeを保存した - シミュレーションを将来のtransaction成功保証にしていない
- approval、署名、送金、swap、別router、direct callを追加していない
- detector一つで詐欺・honeypot・回収不能と断定していない
- secret、remote access、解除料、回収代行を渡していない
tokenを送れない・売れないときの最短経路は、設定を緩めることではありません。chainとcontractを固定し、transfer accounting、restriction state、market、router、シミュレーションを順番に分け、最初の未説明差で追加操作を止めることです。
確認した一次情報
- ERC-20 Token Standard確認日: 2026/09/02
- OpenZeppelin Contracts 5.x ERC20 API確認日: 2026/09/02
- OpenZeppelin Contracts 5.x Access Control確認日: 2026/09/02
- OpenZeppelin SafeERC20 v5.6.1 source確認日: 2026/09/02
- Uniswap V2 Router02 source確認日: 2026/09/02
- Uniswap V3 core token assumptions確認日: 2026/09/02
- Uniswap fee-on-transfer and rebase token support boundary確認日: 2026/09/02
- Uniswap transaction failure guidance確認日: 2026/09/02
- ERC-1967 Proxy Storage Slots確認日: 2026/09/02
- Ethereum JSON-RPC API確認日: 2026/09/02
- Solidity 0.8.36 errors and revert確認日: 2026/09/02



