MetaMaskのSpending capとは?approve・revoke・Permitを安全に確認
MetaMaskのSpending cap、ERC-20 approve、allowance、revoke、Permitを区別し、token・spender・amount・chainを確認する手順を解説します。

MetaMaskにSpending cap requestと表示されたら、送金額だけを見る画面ではありません。多くの場合は、特定のtokenを、特定のspenderが、いくらまで使えるかをERC-20 token contractへ記録するapproveの確認画面です。
先に記録するのは、account、chain、token contract、spender、amountの5項目です。サイト名やボタン名だけでは、この5項目を確定できません。
dappのDisconnectとrevokeは別
Disconnectはサイトからaccount情報を切り離す操作です。すでにchain上へ記録されたallowanceは消えません。tokenを動かす権限を止めるには、対象のallowanceを別に確認してrevokeします。
この記事ではERC-20のtoken approvalを対象に、署名前、既存権限の確認、revoke後の確認までを順に整理します。contract addressやABIから確認したい場合は、先に直コンの安全確認手順を参照してください。
approval・Spending cap・allowance・revokeの違い
| 表示・用語 | 何を指すか | 確認する場所 |
|---|---|---|
approval / approve |
spenderへ利用上限を設定するon-chain transaction | walletのfunction詳細、token contract、receipt |
| Spending cap | MetaMaskが表示する利用上限。通常はapproveのamountに対応する |
MetaMaskのEstimated changes、Spender、Method |
| allowance | token contractが保持するowner → spenderの残り上限 |
allowance(owner, spender)、Approval Checker |
| revoke | 同じtoken・spenderの上限を0などへ更新するon-chain transaction | revoke画面、receipt、更新後のallowance |
ERC-20では、approve(spender, value)を再度実行すると、そのowner・spenderのallowanceをvalueへ更新します。spenderはtransferFromを使い、allowanceの範囲でownerのtokenを移動できます。
approvalは「サイト全体への包括的な許可」ではありません。少なくとも次の組み合わせごとに別のstateです。
chain + token contract + owner + spender = allowance
同じdappでもrouterのversionやchainが変わればspenderは別addressになり得ます。反対に、画面上のサイト名が違っても、共通のspender contractを使う場合があります。
署名前に固定する5項目
1. account
approvalを出すowner accountです。複数accountを使っている場合、別accountのallowanceを見ても署名対象の確認にはなりません。
2. chain
Ethereum、Base、Arbitrumなど、現在のnetworkを記録します。同じ形式のaddressでも、chainが違えば別のstateです。revokeに必要なnetwork fee用のnative tokenもchainごとに異なります。
3. token contract
token名やsymbolだけでなくcontract addressを確認します。偽tokenや同名tokenを避けるため、project公式資料とExplorerの両方で照合します。
4. spender
実際にtransferFromを呼べるaddressです。dappのドメイン、transactionのto、spenderは同じとは限りません。通常のERC-20 approveでは、transactionのtoはtoken contract、calldataの引数がspenderです。
5. amount
人が読むtoken数量と、decimals()を反映したraw valueを分けます。Maxやサイト提案値が、今使う予定量と同じとは限りません。
functionと引数をさらに確認する場合は、ABI・calldata・event logsの読み方でtoと引数を分けてください。
MetaMaskのSpending cap requestを読む
画面では、少なくとも次を照合します。
- 上部のaccountとnetwork
Spending capの数量SpenderのaddressRequest fromのdomainInteracting withのtoken contractMethodがApproveか- Estimated changesやsecurity warning
Request fromは「どのWebサイトが要求を開いたか」の手掛かりです。権限を持つ主体は、chain上のspender addressで確認します。domainが正しく見えても、spenderのcodeやupgrade権限まで安全と証明するものではありません。
unlimited approvalは即時被害ではないが、将来残高も範囲に入る
ExplorerやwalletがUnlimitedと表示するapprovalは、非常に大きな上限を設定している状態です。承認した瞬間にtokenが移動するとは限りませんが、spenderが呼び出せる状態なら、新しい署名なしでallowanceの範囲を利用できます。
リスクを判断するときは、現在残高だけでなく次を確認します。
- 今後同じaddressへ入るtokenも対象になり得るか
- spenderがproxyか、implementationを変更できるか
- dappを今も使うか
- 必要量に対して上限が過大ではないか
- allowanceに期限がある仕組みか
- token・spenderの両方を公式情報で照合できるか
unlimited approvalは正規dappでも使われます。一方で、spenderの脆弱性、鍵の侵害、悪意あるupgradeがあれば影響範囲が大きくなります。「Unlimitedだから詐欺」「有名dappだから無条件に安全」のどちらにも決めつけません。
既存allowanceをPortfolioとExplorerで確認する
MetaMask PortfolioのSpending Caps画面では、token、account、spender、Spending Capを同じ行で確認し、対象ごとにRevokeへ進めます。
ExplorerのApproval Checkerは、walletを接続しなくても公開addressを検索できます。読み取りだけなら署名は不要です。
一覧では、表示名だけでなく次を記録します。
- chainとowner address
- token contract
- approved spender address
- current allowanceとoriginal allowanceの区別
- 最後に更新したtransaction hashと時刻
- spenderのverification、proxy、現在のimplementation
Explorerのname tagは便利ですが、それだけで公式性や安全性は確定しません。project公式資料のaddressと照合します。
revokeは同じtoken・spenderのallowanceを更新する
通常のERC-20では、revoke UIがapprove(spender, 0)を送る形が一般的です。実行前後を次の順で確認します。
- 対象accountとchainを固定する
- token contractと正確なspenderを記録する
- 現在の
allowance(owner, spender)を読む - revokeのcallが同じtoken・spenderと0を対象にしているか確認する
- network feeとシミュレーション結果を確認する
- 署名・送信後にreceiptの
statusを見る - 更新後の
allowance(owner, spender)を読み、0になったか確認する
現在値は次のようにread-onlyで確認できます。
import { erc20Abi, formatUnits } from 'viem'
const [allowance, decimals] = await Promise.all([
publicClient.readContract({
address: token,
abi: erc20Abi,
functionName: 'allowance',
args: [owner, spender],
}),
publicClient.readContract({
address: token,
abi: erc20Abi,
functionName: 'decimals',
}),
])
console.log({
chainId: await publicClient.getChainId(),
token,
owner,
spender,
rawAllowance: allowance.toString(),
displayAllowance: formatUnits(allowance, decimals),
})
このreadはrevoke transactionを送りません。実際に書き込む場合は、token固有の実装、0へ変更してから別amountへ更新する必要性、proxyの現在ABIも確認します。シミュレーションが成功しても、contractの安全性や本番成功を保証しません。
receiptの確認はreceipt・calldata・logsを追う手順へ進みます。revokeがpending・failed・replacedのどれか分からない場合は、transaction状態の判定フローで元hashとreplacement hashの両方を残してください。
revokeが反映されないときの確認順
| 症状 | 最初に確認すること | 次に見る証拠 |
|---|---|---|
| Revokeボタンを押せない | wallet接続、account、chain、native token残高 | 対応network、walletのerror |
| 送信したが一覧に残る | receipt.status、block、transaction hash | index遅延を避けてallowanceを直接読む |
| allowanceが0にならない | token、owner、spenderの組み合わせ | calldata、Approval event、別spender |
| transactionがpending | nonce、gas、同じnonceの別hash | pending / replaced / dropped候補を分ける |
| transactionがfailed | revert reason、token固有制約 | シミュレーション、current implementation |
| dappをDisconnectしたのに残る | Disconnectとrevokeの取り違え | on-chain allowanceを確認する |
| 1件消しても権限が見える | routerやversionごとの複数spender | すべてのtoken・spender行を確認する |
Revokeは将来の利用上限を変える操作です。すでに移動したtokenを取り戻す処理ではありません。被害が疑われる場合は、追加署名を止め、hash、署名要求、token、spender、時刻を保存します。
PermitとPermit2は通常のapproveと分ける
gas feeが表示されない署名でも、token利用権限に関係する場合があります。
| 方式 | 署名・transaction | 確認する主な値 |
|---|---|---|
ERC-20 approve |
ownerがtoken contractへon-chain transaction | chain、token、spender、value |
ERC-2612 permit |
ownerがEIP-712 typed dataへ署名し、別accountでもtoken contractへ提出可能 | domain、chainId、verifyingContract、owner、spender、value、nonce、deadline |
| Permit2 AllowanceTransfer | tokenからPermit2へのapprovalに加え、指定spender・amount・expirationの権限 | token、Permit2 address、downstream spender、amount、expiration、nonce |
| Permit2 SignatureTransfer | 署名を使う1回のtransfer。Uniswap実装では使用transactionの間だけ有効 | token、amount、spender、nonce、deadline。recipientなどを拘束するwitnessの有無 |
ERC-2612のpermitは、署名が正しく、nonceとdeadlineが条件を満たすとallowanceを更新します。tokenがERC-2612を実装しているか、同名の独自permitではないかも確認が必要です。
Permit2はAllowanceTransferとSignatureTransferを持ちます。統合前には、token側からPermit2 contractへapprovalする層もあります。そのため、通常のApproval CheckerでspenderがPermit2と表示されても、実際のdapp側spenderや署名の期限まで一行で分かるとは限りません。
署名だけでchain上にtransactionが残らない場合もあります。署名画面では、少なくともdomain、verifying contract、spender、token、amount、nonce、deadlineを読み、理解できないtyped dataは拒否します。
最終チェックリスト
- signing accountとchainを確認した
- token名ではなくcontract addressを照合した
- dappのdomainとspender addressを分けた
- Spending capの人間向け数量とraw valueを確認した
- Maxやサイト提案値をそのまま選んでいない
- unlimited approvalの対象tokenと将来残高を確認した
- Disconnectとrevokeを混同していない
- revoke前のallowanceを記録した
- revoke transactionのtoken、spender、0、feeを確認した
- receipt成功後にallowanceを読み直した
- Permitならdomain、nonce、deadlineを確認した
- Permit2ならtoken→Permit2とPermit2→spenderの層を分けた
最短の確認方法は、画面の「Approve」「Revoke」という動詞を信じ切ることではありません。chain、token、owner、spender、allowanceを同じ組み合わせで署名前後に読み直すことです。
確認した一次情報
- MetaMask What is a token approval確認日: 2026/08/28
- MetaMask Customize token approvals確認日: 2026/08/28
- MetaMask Portfolio Spending Caps確認日: 2026/08/28
- MetaMask Revoke token approvals確認日: 2026/08/28
- MetaMask Signature phishing確認日: 2026/08/28
- ERC-20 Token Standard確認日: 2026/08/28
- ERC-2612 Permit Extension確認日: 2026/08/28
- Uniswap Permit2確認日: 2026/08/28
- Etherscan Token Approvals確認日: 2026/08/28
- Etherscan Safe Contract Interaction確認日: 2026/08/28



