トークン承認:あなたが与え続けている権限

·8 分で読める·SSP Editorial Team 著
スマートコントラクトに手渡される鍵としてのトークン承認権限の山のイラスト

トークン承認:あなたが与え続けている権限

DeFi アプリと関わるたび――DEX でのスワップ、レンディング市場への預け入れ、ERC-20 のブリッジ――あなたはほぼ間違いなく トークン承認 を一度与えている。多くのユーザーは数秒で署名し、その存在を忘れてしまう。しかしその一回の approve トランザクションは、Ethereum 上で行うことの中でも最も重大な部類に入る:それは smart contract に対して、あなたのトークンを動かす恒常的な許可を、しばしば追加確認なしに引き渡すからだ。本ガイドでは、トークン承認とは何か、なぜ dApp が要求するのか、"無制限 allowance" パターンのリスク、そして SSP で承認に署名するときそれが何を意味するのかを整理する。

なぜ承認が存在するのか

ERC-20 トークンは、ETH と同じように "ウォレットの中" に保存されているわけではない。ERC-20 のトークンコントラクトは台帳である:アドレスから残高への対応表だ。あなたが 1,000 USDC を保有しているとき、オンチェーンに実際に存在しているのは USDC コントラクト内の一行、「このアドレスは 1,000 単位を所有している」という記録である。

残高がトークンコントラクトの中に住んでいるため、それを動かせるのはそのコントラクトだけだ。あなたが USDC を友人に送るとき、ウォレットはトークンの transfer 関数を直接呼び出している。

しかし DEX のように、別のコントラクト(router)があなたのアドレスから USDC を引き出してスワップを実行する必要がある場合、router はトークンコントラクトに手を突っ込んで残高を取ることはできない。ERC-20 はこれを二段階の委任パターンで解決する:

  1. あなた がトークンコントラクトの approve(spender, amount) を呼び出す。これにより allowance が設定される:spender はあなたのトークンを amount まで動かすことを許可されている、という記録だ。
  2. spender はその後、トークンコントラクトの transferFrom(yourAddress, destination, amount) を呼び出す。コントラクトは allowance を確認し、減算し、トークンを動かす。

承認は鍵である。それがなければ、router はそもそもあなたの USDC に触れることすらできない。

実際に何を与えているのか

approve(spender, amount) を文字通りに読んでみてほしい。あなたは ERC-20 コントラクトにこう告げている:「このアドレスは、私が変更するまで、いつでも、何回でも、私のトークンをこの量まで引き出すことができる」。

ここからいくつかのことが導かれる:

  • 恒常的な許可であり、一度きりの行為ではない。 一度与えれば、allowance を使い切るか取り消すまで、spender はあなたの署名を再度必要とせずにトークンを引っ張ることができる。
  • トークンごと。 DEX router に USDC を承認しても、DAI には触れさせない;DAI には別途承認が要る。
  • spender ごと。 別のコントラクトは――同じ dApp 由来であっても――独自の allowance を持つ。
  • 期限なし。 ERC-20 には組み込みの期限がない。2023 年に設定した allowance は、使い切られるか取り消されない限り 2026 年も生きている。

任意の allowance は、ブロックエクスプローラーの etherscan などで、トークンコントラクトの allowance(owner, spender) ビュー関数を読むことで確認できる。

無限 allowance パターン

承認が金額単位だとして、ではなぜほとんどの DEX は、たった今スワップしようとしている金額ではなく、巨大な数字――通常は 2^256 - 1、UI 上は "unlimited" や MaxUint256 と表示される――をあなたに求めてくるのか?

答えは UX と gas だ。DEX が毎回のスワップでトレードサイズに等しい新しい allowance を要求するとしたら、毎回 approve トランザクション分の gas を払うことになり、ひとつの操作に感じるものを 2 件のトランザクション確認に分けることになる。一度だけ無限 allowance を要求しておけば、その後はトレードあたり 1 件のトランザクションで自由にスワップできる。

これは本当に便利である。同時に、本当によりリスクが高い。無限 allowance とは、spender コントラクトがあなたのそのトークンの現在残高すべて――そして将来保有するあらゆる残高――を、あなたが追加で何も署名しなくても、任意のタイミングで吸い取れる権限を持つ、ということだ。

広く知られ、監査済みで、アップグレード不可能なコントラクトに対しては、実務上のリスクは通常小さい。デプロイされたばかりの dApp、アップグレード可能な proxy、聞いたこともないコントラクトに対しては、無限 allowance はあなたが意図したトレードよりはるかに広い攻撃面となる。

本当のリスク:あなたのトークンへの常駐の鍵

承認の危険は、承認トランザクションそのものにあるのではない。その後に起きることにある。いくつかのシナリオを考えてみよう:

  • spender コントラクトにバグがある。攻撃者がその transferFrom ロジックを悪用し、非ゼロの allowance を持つすべてのウォレットが空にされる。
  • spender コントラクトがアップグレード可能だ。アップグレード鍵を握る者が、有効な allowance を持つ全員からトークンを引く新しいロジックを公開する。
  • あなたは悪意あるクローンを承認していた。フィッシングサイトが本物の dApp の URL を真似ており、承認していたコントラクトは最初から攻撃者の管理下にあった。
  • spender の署名鍵が漏れた。公式コントラクト自体は問題ないが、運営側のウォレットがやられ、allowance が侵入者によって実行されている。

いずれの場合も、抜かれる瞬間にあなたは何も署名していない。攻撃者が必要とする唯一の許可は、あなたが数週間前あるいは数か月前に与えた承認である。「必要なものだけを承認し、もう使わないものは取り消す」というのは妄想ではない。雇ったすべての職人に自宅の合鍵を渡したままにしないのと、同じ原理である。

承認はどう静かに積もるのか

DeFi で 1~2 年活発に動いてきたウォレットは、すでに数十件の承認を積み上げている:使ってきたすべての DEX、新しいコントラクト経由でルーティングしたすべての aggregator、レンディング市場への預け入れ、NFT マーケットプレイス、ブリッジ、すべてだ。ユーザーはほとんど取り消しに戻らない。結果として、その多くが無制限の、しかも今ではもうやり取りもしていないコントラクト宛ての、長い尾の常駐許可が残る。

これが沈黙の攻撃面である。単一のトランザクションには現れない。通常使用の累積残渣だ。このリストを監査し剪定することは、自己保管における最も有効なセキュリティ習慣のひとつ――次回の記事では、その手順を SSP からトークン承認を取り消す で具体的に追っていく。

より新しいパターン:EIP-2612 permit

ERC-20 は現代 DeFi の大部分より古く、approve してから swap という二段階トランザクションの踊りは、長らくぎこちないと認識されてきた。EIP-2612 はそれを受け入れるトークン向けに別の選択肢を導入した:オンチェーンに approve を送る代わりに、ユーザーはオフチェーンのメッセージ(permit)に署名し、特定の spender・金額・期限を承認する。dApp はその署名をスワップとともに、1 件のトランザクションで提出する。

permit は gas 効率が良く、範囲が限定され(明示的な金額と期限を持つ)、期限があるおかげで放置されにくい。すべての ERC-20 が対応しているわけではない――USDC と DAI は対応している、古いトークンの多くは未対応――が、利用できる場面では、長寿命の approve allowance より一般に安全である。とはいえ permit 署名自体もフィッシングされうる:あなたに「ログイン」を促す悪意あるサイトが、その下に permit を忍ばせていることがある。署名するものをよく読むこと。

SSP の中ではどう意味するのか

SSP は自己保管型の 2-of-2 マルチシグウォレットである:すべてのオンチェーン取引は、SSP ブラウザ拡張と SSP Key モバイルアプリの両方によって共同署名される。Ethereum および SSP が対応する EVM ネットワーク(Polygon、Base、BNB Smart Chain、Avalanche)では、これは Schnorr 集約署名を使う ERC-4337 smart account として実装されている――しかしアプリケーション層では、承認は他のどんなトランザクションとも同じように見える。

留意しておきたいことがいくつかある:

  • 承認は、あなたの 2-of-2 が共同署名しなければならないトランザクションだ。 dApp が approve を要求するとき、SSP はそれを通常の tx と同じように示す。確認前に、両方の端末で spender アドレスと要求量が確認できる。
  • 一度与えれば、spender は再び動くのに SSP を必要としない。 マルチシグが守るのは承認の瞬間であって、その後の常駐許可ではない。悪意あるコントラクトに無限 allowance を与えてしまえば、その後の引き抜きからマルチシグは救ってくれない。
  • spender アドレスから目を離さない。 dApp はときどき router をアップグレードする;承認画面上の spender が想定するコントラクトと一致しないなら、止まって確認すること。
  • WalletConnect 経由の承認も見た目は同じ。 dApp がページ内で求めるにせよ WalletConnect 経由で求めるにせよ、フローもリスクも同一である。

育てるべき習慣

いくつかの具体的な実践で、承認面はちゃんと管理可能な範囲に収まる:

  • 可能なかぎり小さな allowance を選ぶ。 dApp が「正確な額」と「unlimited」のどちらかを選ばせるなら、日常的には使わないコントラクトに対しては「正確な額」の方が安全なデフォルトだ。
  • 無制限の承認をコミットメントとして扱う。 信頼していてしょっちゅう使う少数のコントラクトに限定する。それ以外はすべて範囲を絞る。
  • 定期的に監査する。 四半期に一度、各チェーン上のアクティブな承認を一覧にして、もう使わないものはすべて取り消す。revoke.cash のようなツールがそれをルーチン化してくれる。
  • 見知らぬ dApp には注意する。 監査履歴のない新しいプロトコルが無限 allowance を求めてくる――これは DeFi で最もリスクの高い組み合わせの一つだ。
  • 承認を与える鍵を守る。 SSP のマルチシグはハードルを大きく上げてくれるが、基本的な衛生は今も適用される――シードフレーズのベストプラクティス を参照。

持ち帰るメンタルモデル

トークン承認はクリックではなく、鍵である。それぞれはあなたが抜くまで錠の中に残り、それぞれが持ち主に対して、あなたがまだ稼いでもいないトークンを動かす能力を与える。注意して使えば、allowance は DeFi を動かしている配管そのものだ。使い捨てのクリックのように扱えば、それは引き受けたことすら忘れたリスクの、ゆっくりとした積み上げになる。

何を許可しているのかを理解し、dApp が許す場面では範囲を絞った付与を選び、常駐している承認を一定のリズムで剪定すること。プロトコルの詳細は ethereum.org の ERC-20 標準ドキュメント が標準的なリファレンスである。Ethereum 上で SSP を使い始めたばかりなら、私たちの SSP 上の Ethereum ガイドが基本を押さえてくれる。

この記事をシェアする

関連記事