token-antiflash について
token-antiflashは、ERC20トークンコントラクト内のフラッシュローン対策を設計するスキルで、トークン層の脅威を評価するスマートコントラクト開発者向けです。実装前に脅威モデル、対策のトレードオフ、パラメーターを確認します。
主な機能
- 01トークンの脅威モデルと攻撃経路の評価
- 02防御策とトレードオフの比較
- 03コスト追跡、クールダウン、取引上限の提示
- 04転送時の状態伝播に関する設計要点
- 05OpenZeppelin 4.xと5.xのフックを区別
活用シーン
- 01ERC20トークンのフラッシュローン対策設計
- 02攻撃経路に応じた防御策の選択
- 03上限、税率、クールダウンの設定
- 04転送状態の伝播における回避リスクの確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ 0xlayerghost/ solidity-agent-kit --skill token-antiflashインストール後、Claude Code で/token-antiflashを入力して読み込まれたか確認します。
詳細
トークンレベルのフラッシュローン防止設計パターン
言語ルール
- 常にユーザーが使用している言語で応答してください。 ユーザーが中国語で質問した場合は、中国語で応答してください。英語の場合は英語で応答してください。
対象範囲:トークンコントラクトレベルでフラッシュローン攻撃への保護が必要な ERC20 トークンコントラクトに適用されます。
defi-securityスキル(プロトコルレベル)を補完する、トークン内部の防御メカニズムです。以下に示すすべてのパラメーターは設計上の参考値であり、実際の値はプロジェクトの要件、トークノミクス、市場状況に基づいて決定してください。
ワークフロールール
このスキルが呼び出された場合、すべての戦略を直接実装してはいけません。次のワークフローに従ってください。
- 評価:プロジェクトの脅威モデルを特定します。トークンの種類(ミーム、コミュニティ、DeFi エコシステム)、リスクにさらされる価値、現実的な攻撃ベクトルを確認してください
- 提示:Strategy Decision Matrix と Combination Guide を開発者に提示します。各戦略のトレードオフ(ガスコスト、UX 上の摩擦、実装の複雑さ)を明確に説明してください
- 開発者に選択してもらう:希望する保護レベル(Basic/Standard/Advanced/Maximum)、または具体的な戦略を開発者に尋ねてください。保護レベルを推測してはいけません
- パラメーターを確認する:選択された各戦略について、コードを書く前に主要な設計パラメーター(税率区分、取引量制限の割合、クールダウンの細かさなど)を開発者に確認してください
- 実装:開発者の確認後に限り、合意したパラメーターで選択された戦略を実装してください
例外:開発者が明示的に「すべて実装」または「最大限の保護」と指示した場合は、手順 2〜4 を省略し、Maximum の組み合わせを実装してください。開発者が番号で具体的な戦略を指定した場合は、それらの戦略について手順 4 に進んでください。
バージョン互換性
| OpenZeppelin バージョン | オーバーライドするフック | 備考 |
|---|---|---|
| OZ 5.x (Solidity ≥0.8.20) | _update(address from, address to, uint256 amount) | フックの実行時には状態がすでに更新されています |
| OZ 4.x (Solidity <0.8.20) | _beforeTokenTransfer(address from, address to, uint256 amount) | 状態はまだ更新されていません。読み取り値は転送前のものです |
// OZ 5.x — preferred for new projects
function _update(address from, address to, uint256 amount) internal override {
super._update(from, to, amount);
// ... defense logic here
}
// OZ 4.x — for existing projects
function _beforeTokenTransfer(address from, address to, uint256 amount) internal override {
super._beforeTokenTransfer(from, to, amount);
// ... defense logic here (balances not yet changed)
}
コア設計原則
フラッシュローン攻撃は、単一トランザクション内でのアトミックな実行に依存します。借入 → 操作 → 利益獲得 → 返済という流れです。トークンレベルの防御では、トークンコントラクト自体にコスト、時間、本人確認の障壁を導入し、このアトミック性を打ち破ります。
戦略選択マトリックス
フラッシュローン対策を備えたトークンを設計する際は、脅威モデルに基づいて適用する戦略を評価してください。
| 脅威ベクトル | 推奨戦略 | 優先度 |
|---|---|---|
| 同一ブロック内の購入→売却アービトラージ | 同一ブロックのクールダウン + コントラクトアドレスのチェック | 高 |
| コストゼロでのトークン悪用(エアドロップ/脆弱性の悪用) | コスト追跡 + 段階的な売却税 | 高 |
| 大量取引による操作 | アドレスごとの取引量制限 + 基本取引手数料 | 中 |
| 複数アドレスによるシビル攻撃の回避 | 紹介者の紐付け + 転送時の状態伝播 | 中 |
| ボットによる先回り/サンドイッチ攻撃 | 先回り売却の保護 + 動的手数料 | 状況に応じて |
戦略 1:コストの追跡
設計の考え方:アドレスごとにトークンの取得原価を追跡します。実現利益を取得原価に対する設定可能な倍率に制限します。取得原価がゼロのトークン(エアドロップ、エクスプロイト、フラッシュローン)は取得原価がゼロとなるため、利益の上限はゼロになるか、売却時にトークンがバーンされます。
主な設計ポイント:
- アドレスごとの取得原価状態を保持し、すべての
_transfer/_updateで更新する - 転送時:コストはトークンに追随する — 送信元から受信先へ、割合に応じてコストを引き継ぐ
- コストゼロのトークンにはフラグを設定し、別途処理する(バーンまたは売却制限)
- 利益上限の倍率は、妥当な上限を設けたうえで、所有者が設定可能なパラメーターにする
- 追加マッピングを維持する際のガスコストを考慮する — 転送時のガスへの影響を測定する
フラッシュローンへの効果:フラッシュローンで借り入れたトークンは、本質的に取得原価がゼロです。取得原価に応じて利益が制限されるため、攻撃を実行する経済的な動機がなくなります。
実装:
struct CostBasis {
uint256 totalCost; // total acquisition cost in quote token units
uint256 totalAmount; // total token amount held
}
mapping(address => CostBasis) private _costBasis;
function _propagateCostBasis(address from, address to, uint256 amount) private {
CostBasis storage senderCost = _costBasis[from];
if (senderCost.totalAmount == 0) return;
// proportional cost transfer
uint256 transferredCost = (senderCost.totalCost * amount) / senderCost.totalAmount;
senderCost.totalCost -= transferredCost;
senderCost.totalAmount -= amount;
_costBasis[to].totalCost += transferredCost;
_costBasis[to].totalAmount += amount;
}
// call this when a buy is detected (from == AMM pair)
function _recordBuy(address buyer, uint256 amount, uint256 costInQuote) private {
_costBasis[buyer].totalCost += costInQuote;
_costBasis[buyer].totalAmount += amount;
}
戦略 2:コントラクトアドレスのチェック(EIP-7702 対応)
設計の考え方:スマートコントラクト(フラッシュローンのコントラクトも該当)からのインタラクションをブロックしつつ、EIP-7702 で委任された EOA を適切に扱います。
主な設計ポイント:
- EIP-7702 の委任デジグネーターは、特定のコード長を持つ(23 バイト:
0xef0100+ 20 バイトのアドレス) - この正確なコード長を持つアドレスは許可する(コントラクトではなく、委任された EOA)
- それ以外のゼロ以外のコード長を持つアドレスはブロックする(通常のスマートコントラクト)
- 二次的なガードとして、
msg.sender == tx.originのチェックも検討する - 必要なコントラクトをホワイトリストに登録する:LP ペア、ルーター、ステーキングコントラクト
フラッシュローンへの効果:フラッシュローンの実行は、コントラクトの呼び出しチェーン内で行われます。コントラクトからの呼び出し元をブロックすれば、EOA 経由でのインタラクションが必要になり、アトミックな実行を阻止できます。
実装:
// EIP-7702 delegation designator format:
// byte[0..2] = 0xef0100 (magic prefix, 3 bytes)
// byte[3..22] = target contract address (20 bytes)
// total: 23 bytes
// Plain EOA has extcodesize = 0.
// Regular contract has extcodesize > 0 (and != 23 for the magic prefix case).
bytes3 private constant EIP7702_MAGIC = 0xef0100;
/// @dev Classifies an address into three types:
/// - size == 0 → plain EOA → return false (allow)
/// - size == 23 AND prefix matches 0xef0100 → EIP-7702 delegated EOA → return false (allow)
/// - anything else → real deployed contract → return true (block)
///
/// EIP-7702 delegated EOAs are allowed because:
/// 1. They are user-controlled accounts (smart wallets), not attack contracts
/// 2. They cannot execute atomic flash loan buy→sell (Strategy 3 still blocks same-block ops)
/// 3. Blocking them would break smart wallet UX for legitimate holders
///
/// extcodecopy gas note: ~700 gas cold read. Only runs when size == 23, which is rare.
function _isRealContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
// fast path: most addresses are plain EOA or regular contract
if (size == 0) return false; // plain EOA → allow
if (size != 23) return true; // regular contract (size > 23 or 1..22) → block
// slow path: exactly 23 bytes → read prefix to distinguish 7702 from an exotic 23-byte contract
bytes3 prefix;
assembly {
// extcodecopy(addr, destMemPtr, srcOffset, length)
// write 3 bytes starting at offset 0 of the account's code into `prefix`
extcodecopy(account, prefix, 0, 3)
}
if (prefix == EIP7702_MAGIC) return false; // confirmed EIP-7702 delegated EOA → allow
return true; // exotic 23-byte contract → block
}
/// @dev Call at the top of _update (or _beforeTokenTransfer) to block contract interactions.
/// Whitelisted addresses (LP pair, router, staking) bypass this check entirely.
function _checkNotContract(address addr) internal view {
if (_isWhitelisted[addr]) return;
require(!_isRealContract(addr), "AntiFlash: contract caller blocked");
}
戦略 3:同一ブロック内のクールダウン
設計の考え方:同じブロック内での購入と売却(または受け取りと売却)を防ぎます。フラッシュローンは1つのトランザクション(1ブロック)内で完了する必要があるため、これは最も直接的な対策です。
主な設計ポイント:
- アドレスごとに、最後にトークンを受け取ったブロック番号を追跡する
- 売却時(LP ペアへの転送時)には、追跡しているブロック番号が現在の
block.numberより小さいことを必須とする - 重要:転送による回避にも対処する — 同一ブロック内での「A が購入 → A が B に転送 → B が売却」を防ぐ
- ウォレット間の転送時には、状態のロンダリングを防ぐため、
max(lastBlock[to], lastBlock[from])を使ってブロック制限を引き継ぐ - 同一ブロックの追跡に
block.timestampを使用しない — 正しい指標はblock.number
フラッシュローンへの効果:フラッシュローンは1つのトランザクション(1ブロック)内で実行・返済されます。同一ブロック内のクールダウンにより、購入から売却までのサイクルを完全に防げます。
_update 統合ハブ
すべての戦略状態の引き継ぎは、単一の _update オーバーライドにまとめる必要があります。これは最も見落とされやすい脆弱性です — 一部しか組み込まないと、転送による回避経路が残ります。
function _update(address from, address to, uint256 amount) internal override {
// ── Guard: call super first so balances are updated before our checks ──
super._update(from, to, amount);
bool fromPair = _isAMMPair[from]; // buy: tokens flow from pair → user
bool toPair = _isAMMPair[to]; // sell: tokens flow from user → pair
bool isTransfer = !fromPair && !toPair && from != address(0) && to != address(0);
// ── Strategy 2: Block real contracts ──
// Only check non-whitelisted, non-pair addresses
if (from != address(0) && !fromPair) {
_checkNotContract(from);
}
// ── Strategy 3: Same-block cooldown ──
if (toPair && from != address(0)) {
// sell path: seller must not have received tokens this block
require(
block.number > _lastInteractionBlock[from],
"AntiFlash: same-block sell"
);
}
if (fromPair) {
// buy path: record the block so this address cannot sell same-block
_lastInteractionBlock[to] = block.number;
}
if (isTransfer) {
// ★ transfer path: propagate the stricter (larger) block number
// using max() ensures restriction only extends, never shortens
// prevents: buy → transfer to fresh address → sell same-block
if (_lastInteractionBlock[from] > _lastInteractionBlock[to]) {
_lastInteractionBlock[to] = _lastInteractionBlock[from];
}
}
// ── Strategy 1: Cost basis propagation ──
if (useCostTracking && isTransfer) {
_propagateCostBasis(from, to, amount);
}
if (useCostTracking && fromPair) {
// record buy cost using current price from oracle or passed-in value
// (exact cost recording depends on your price feed integration)
_recordBuy(to, amount, _getCurrentCostBasis(amount));
}
// ── Strategy 7: Progressive tax timestamp propagation ──
if (useProgressiveTax && isTransfer) {
// propagate the older (more restrictive) timestamp so receiver
// cannot launder holding time by receiving a fresh transfer
if (_firstBuyTimestamp[from] > 0) {
if (_firstBuyTimestamp[to] == 0 || _firstBuyTimestamp[from] > _firstBuyTimestamp[to]) {
_firstBuyTimestamp[to] = _firstBuyTimestamp[from];
}
}
}
if (useProgressiveTax && fromPair && _firstBuyTimestamp[to] == 0) {
_firstBuyTimestamp[to] = block.timestamp;
}
// ── Strategy 4: Per-address daily volume ──
if (useDailyLimit && !fromPair && from != address(0)) {
uint256 today = block.timestamp / 1 days;
_dailyVolume[from][today] += amount;
require(_dailyVolume[from][today] <= _dailyLimit, "AntiFlash: daily limit");
}
}
すべての状態引き継ぎにおける重要なルール:
max()のセマンティクスを使用する — 制限は延長するだけで、短縮してはなりません。直接代入(state[to] = state[from])は悪用される可能性があります。クールダウンが短い送信元が、受信先のより長いクールダウンを上書きできてしまいます。
戦略 4:アドレスごとの取引量制限
設計の考え方:取引ごとと期間ごとの両方で、個々の取引量を制限し、攻撃による経済的規模を抑えます。
主な設計ポイント:
- 取引ごとの制限:総供給量に対する割合として設定可能
- 期間ごと(例:日次)のアドレスごとの累積制限
block.timestamp / period_lengthをマッピングキーとして期間を追跡- LP ペア、ステーキングコントラクト、運用アドレスを制限の対象外としてホワイトリストに登録
- パラメーターは上限を定めたうえで、オーナーが調整できるようにする
フラッシュローンへの効果:攻撃者が1回の取引で移動できる量を制限します。他の防御策を回避された場合でも、損害を抑えられます。
戦略 5:最低残高の維持
設計の考え方:全額引き出しを認めず、すべての送金後に送信者のアカウントへ少額の最低残高が残るようにします。
主な設計ポイント:
- 設定可能な最低維持残高(少額のダスト)を定義
_update/_transferで次の条件を適用:balanceOf(from) - amount >= minBalance- 特定の操作は例外とする:許可されたバーン、コントラクトの移行
- 副次的な効果:保有者数の指標を維持できる(アドレスの残高がゼロにならない)
- 通常のユーザー体験に影響しない程度に最低額を小さく保つ
戦略 6:フロントランによる売却への保護
設計の考え方:大規模な売り注文を検知した際に、パラメーターを調整するか保護メカニズムを作動させ、価格への影響を和らげます。
主な設計ポイント:
- 保護を作動させるしきい値(例:LP リザーブに対する割合)を定義
- 選択肢:売却手数料の一時的な引き上げ、徴収した税金を使った買い戻し、LP パラメーターの調整
- トークンコントラクト内ではなく、ビジネス/ルーターレイヤーで実装するのが最適です
- ネイティブな LP 統合には Uniswap V4 hooks の利用を検討
- 時間枠ごとの売り/買い比率を監視し、売りが大幅に優勢な場合は手数料を引き上げる
- この戦略は複雑であり、すべてのプロジェクトに適しているとは限りません
戦略 7:段階的な売却税(税率ラダー)
設計の考え方:取得したばかりのトークンには高い売却税を適用し、保有期間が長くなるほど税率を下げます。保有を促し、短期売買を抑制します。
主な設計ポイント:
- アドレスごとに初回購入時刻を追跡
- 設定可能な税率スケジュールを定義:保有期間が最も短い場合に最高税率を適用し、段階的に基準税率まで下げる
- 税金は売却額から差し引き、指定された手数料受取先へ送る
- 重要:ウォレット間の送金では、タイムスタンプの引き継ぎが必要です。タイムスタンプのロンダリングを防ぐため、送信者に制限がある場合、受信者に「新しい」タイムスタンプを設定しないでください
- 税率パラメーターはオーナーが調整できるようにする
- ガス効率を高めるため、連続的な計算式ではなく、時間の段階(時間/日)を使うことを検討
フラッシュローンへの効果:フラッシュローンで借りたトークンの保有時間は実質ゼロになるため、最高税率が適用され、利益幅がなくなります。
実装:
struct TaxTier {
uint32 maxAge; // max holding time in seconds for this tier to apply
uint16 taxBps; // tax rate in basis points (e.g. 2000 = 20%)
}
TaxTier[] public sellTaxSchedule;
/// @dev Returns the sell tax rate (bps) for `seller` based on their holding time.
/// Tiers must be ordered ascending by maxAge. Returns BASE_TAX_BPS if all tiers exceeded.
function _getSellTaxRate(address seller) internal view returns (uint256) {
uint256 holdTime = block.timestamp - _firstBuyTimestamp[seller];
uint256 len = sellTaxSchedule.length;
for (uint256 i; i < len; ) {
if (holdTime < sellTaxSchedule[i].maxAge) return sellTaxSchedule[i].taxBps;
unchecked { ++i; }
}
return BASE_TAX_BPS; // long-term holder baseline rate
}
/// @dev Example schedule — owner should configure via setter with an upper-bound guard
function _initDefaultTaxSchedule() internal {
sellTaxSchedule.push(TaxTier(1 hours, 4000)); // < 1h → 40%
sellTaxSchedule.push(TaxTier(1 days, 2500)); // < 1d → 25%
sellTaxSchedule.push(TaxTier(7 days, 1500)); // < 7d → 15%
sellTaxSchedule.push(TaxTier(30 days, 500)); // < 30d → 5%
// > 30d → BASE_TAX_BPS
}
/// @dev Owner setter — enforce upper bound to prevent rug via tax
function setSellTaxSchedule(TaxTier[] calldata tiers) external onlyOwner {
for (uint256 i; i < tiers.length; ) {
require(tiers[i].taxBps <= 5000, "AntiFlash: tax exceeds 50%");
unchecked { ++i; }
}
delete sellTaxSchedule;
for (uint256 i; i < tiers.length; ) {
sellTaxSchedule.push(tiers[i]);
unchecked { ++i; }
}
}
ガスに関する注意:段階が8以下であれば、線形探索で問題ありません。段階を増やす場合は、二分探索またはハードコードした
if-elseチェーンに置き換えてください。
戦略 8:エコシステム利益税
設計の考え方:売却税を追加し、その税収をエコシステムの価値蓄積に振り向けます。例として、NFT 保有者への配当、子トークンのバーン、その他のエコシステムコントラクトへの配分があります。
主な設計ポイント:
- 売却時に基本手数料に上乗せする追加税を課し、指定されたエコシステムコントラクト間で分配
- 税額は実現利益に基づいて算出可能(戦略 1 のコスト追跡が必要)。または定額税率を使用
- 配当の分配にはプッシュ型ではなく、プル型(請求)パターンを使用し、ガスを使った妨害を回避
- 戦略 7 と組み合わせて、多層的な税制を構築可能
- 税金の受取先となるコントラクトは検証済みかつ不変であること(またはタイムロックの管理下にあること)を確認
戦略 9:基本取引手数料
設計の考え方:すべての売買に標準的な基本手数料を適用し、AMM の自然なスリッページと組み合わせることで、往復取引に最低コストを設けます。
主な設計ポイント:
- 買いと売りの両方に設定可能な手数料を適用します
- 手数料を開発資金/LP への追加/バーンに分配します(設定可能)
- AMM のスリッページと組み合わせて、往復取引の最低コストを確保します
- これだけではフラッシュローン対策として不十分です — 他の戦略と組み合わせて機能する基本レイヤーです
- 通常の取引を妨げない妥当な手数料にします
戦略 10:紹介バインディングシステム
設計の考え方:アドレスが取引する前に紹介関係の設定を必須にし、匿名のフラッシュローンコントラクトが回避できない本人確認の壁を設けます。
主な設計ポイント:
- 新しいアドレスは、初回取引の前に既存の紹介者による「有効化」が必要です
- 紹介関係は一度設定すると、アドレスごとに変更できません
- 取引手数料から複数階層の紹介報酬を支払います(階層数と料率は設定可能)
- フラッシュローンコントラクトには紹介者がいないため、取引できません
- ある程度の Sybil 耐性を確保できます(有効化済みアドレスを短時間に多数作成するのが困難になります)
- UX への影響を考慮してください — 正規の新規ユーザーにとって手間が増える可能性があります
組み合わせガイド
プロジェクトのニーズに応じて戦略を選択してください。戦略を増やすほど保護は強化されますが、ガスコストと実装の複雑さも増します。
| 保護レベル | 戦略 | 適した用途 |
|---|---|---|
| 基本 | 3 + 4 + 9 | 基本的な保護が必要な標準的なトークン |
| 標準 | 2 + 3 + 4 + 5 + 7 + 9 | 中程度の価値が関わるコミュニティトークン |
| 高度 | 1 + 2 + 3 + 4 + 5 + 7 + 8 + 9 | エコシステムを持つ高価値の DeFi トークン |
| 最大 | すべての戦略 | NFT エコシステム、子トークン、高い TVL を持つトークン |
ガス最適化:構造体のパッキング
複数の戦略を有効にすると、個別の mapping(address => uint256) ごとに、各フィールドの転送あたり SLOAD/SSTORE が必要になります。アドレスごとの状態をすべて 1 つの構造体にまとめることで、読み書きを 1 スロットに減らせます。
// ❌ Scattered storage — up to 4 separate SLOAD/SSTORE per transfer
mapping(address => uint256) private _lastInteractionBlock; // slot A
mapping(address => uint256) private _firstBuyTimestamp; // slot B
mapping(address => uint256) private _dailyVolume; // slot C
mapping(address => uint256) private _cooldownUntil; // slot D
// ✅ Packed storage — 1 SLOAD + 1 SSTORE covers all four fields
// uint64 block number: safe until block ~1.8×10^19 (far future)
// uint64 timestamp: safe until year ~584 billion
// uint96 daily volume: up to ~79 billion tokens with 18 decimals
struct UserState {
uint64 lastBlock; // Strategy 3: last interaction block
uint64 firstBuyTime; // Strategy 7: first buy timestamp
uint96 dailyVolume; // Strategy 4: today's traded volume
uint32 cooldownUntil; // optional: unix timestamp cooldown end
// total: 8+8+12+4 = 32 bytes → exactly 1 storage slot
}
mapping(address => UserState) private _userState;
// Example read — one SLOAD fetches all fields
function _getSellTaxRatePacked(address seller) internal view returns (uint256) {
uint256 holdTime = block.timestamp - uint256(_userState[seller].firstBuyTime);
// ... same tier lookup as Strategy 7
}
// Example write — one SSTORE updates all touched fields
function _updateOnBuy(address buyer) internal {
UserState storage s = _userState[buyer];
s.lastBlock = uint64(block.number);
s.firstBuyTime = s.firstBuyTime == 0 ? uint64(block.timestamp) : s.firstBuyTime;
// dailyVolume and cooldownUntil updated separately as needed
}
使用するタイミング:3 つ以上の戦略が有効で、転送時のガスコストが懸念される場合は、構造体のパッキングを有効にしてください。適用前後を測定してください。スロットがコールドかウォームかによって異なりますが、通常は転送あたり 10,000~40,000 ガスを節約できます。
実装チェックリスト
フラッシュローン対策を備えたトークンをデプロイする前に、次の項目を確認してください。
- コスト基準、ブロック追跡、タイムスタンプなど、すべての保護状態が
_transfer/_updateを含むすべての転送経路で正しく引き継がれている - ウォレット間転送でも制限状態を引き継ぐ — ペアとのやり取りだけではありません(最も見落とされやすい脆弱性です)
- LP ペア、ルーター、ステーキングコントラクト、デプロイヤーのマルチシグについて、ホワイトリストが正しく設定されている
- 設定可能なすべてのパラメーターに、上限と下限を定めたオーナー用セッターがある
- コントラクトアドレスのチェックを使用する場合、EIP-7702 の委任デジグネーター(23 バイト)を正しく処理している
- 同一ブロックのクールダウンが、直接の売却と、転送後に売却するパターンの両方をカバーしている
- 段階的な税率のタイムスタンプが、新しいアドレスへの転送によってリセットされない
- すべての手数料/税金の徴収に、プッシュ方式ではなくプル方式(請求)を使用している
- 追加の追跡マッピングによるガスへの影響を測定し、
_transferのガス使用量が許容範囲内に収まっている - ファジーテストで、コスト基準がゼロのトークンの売却、同一ブロック内のマルチホップ、アドレスの巡回、複数アドレスによる Sybil 回避の試みを検証している
- オラクルに依存する価格設定を行う場合、ビジネスレイヤーでの TWAP 統合を検討している(トークンコントラクト内での直接実装は困難なため、ルーター/ビジネスコントラクトを推奨)