0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TypeScriptでEVMの判定分岐を再現する:HTTP 200・SUCCESS・ALLOWの違い

0
Last updated at Posted at 2026-11-02

TypeScriptでEVMの判定分岐を再現する

HTTP 200を見て処理を続行する前に、レスポンス内のdecisionを確認します。TxGuardでは、simulation成功とpolicy上の許可は別の状態です。本稿では4つの合成ケースを実行し、SDK利用時の分岐まで確認します。

EVMトランザクションを組み立てるエージェントでは、送信前に「callが成功するか」と「アプリの方針として進めてよいか」を分けて扱う必要があります。

TxGuardの判定層を使って、同じsimulation成功でもALLOW・WARN・BLOCKが変わる例をローカルで再現します。対象は、すでにEVM callを作っているTypeScript開発者です。ウォレット接続や送信は行いません。

この記事では、TxGuardの判定層とSDKの動作をローカルで検証しています。公開APIの稼働、SDKのnpm公開、顧客利用や収益は今回確認していません。以下の出力は合成fixtureであり、実際のチェーンでの成功を示しません。

外部RPCなしで再現する

確認環境はNode.js v24.19.0です。以下は記事だけで実行できるJavaScriptの最小モデルです。editorial-example.mjs として保存してください。非公開リポジトリやnpmパッケージへのアクセスは不要です。

このモデルは無制限approvalの3設定と結果不明の4ケースに絞った説明用コードです。TxGuard本体が持つチェーン・アドレス・value等の検査は省いているので、実運用の判定器には使わないでください。4ケースの出力が、本体の evaluateDecision に合成fixtureを渡した結果と一致することを確認しました。

import assert from 'node:assert/strict';

// 記事用の最小モデル。TxGuard全体の実装ではない。
// 外部通信なし。calldataはcanonicalなapproveを模した合成データ。
const data = `0x095ea7b3${'0'.repeat(24)}${'33'.repeat(20)}${'f'.repeat(64)}`;
function decideApproval(data, mode, simulationStatus) {
  if (!['allow', 'warn', 'block'].includes(mode)) throw new Error('Invalid mode');
  if (simulationStatus !== 'SUCCESS') {
    return { simulation: 'UNKNOWN', decision: 'BLOCK', warnings: [] };
  }
  if (!/^0x095ea7b30{24}[0-9a-f]{104}$/i.test(data)) {
    throw new Error('This example accepts canonical approve calldata only');
  }
  const amount = BigInt(`0x${data.slice(74)}`);
  const unlimited = amount === (1n << 256n) - 1n;
  return {
    simulation: 'SUCCESS',
    decision: unlimited ? { allow: 'ALLOW', warn: 'WARN', block: 'BLOCK' }[mode] : 'ALLOW',
    warnings: unlimited ? ['UNLIMITED_APPROVAL'] : [],
  };
}
for (const [mode, expected] of [['allow', 'ALLOW'], ['warn', 'WARN'], ['block', 'BLOCK']]) {
  const result = decideApproval(data, mode, 'SUCCESS');
  assert.equal(result.decision, expected);
  assert.equal(result.warnings[0], 'UNLIMITED_APPROVAL');
  console.log(`${mode}: ${result.simulation} / ${result.decision} / ${result.warnings[0]}`);
}
const missing = decideApproval(data, 'block', null);
assert.equal(missing.decision, 'BLOCK');
console.log(`missing: ${missing.simulation} / ${missing.decision}`);

保存したディレクトリで実行します。

node editorial-example.mjs

確認した出力です。

allow: SUCCESS / ALLOW / UNLIMITED_APPROVAL
warn: SUCCESS / WARN / UNLIMITED_APPROVAL
block: SUCCESS / BLOCK / UNLIMITED_APPROVAL
missing: UNKNOWN / BLOCK

calldataとsimulationのSUCCESSは説明用fixtureです。EVMやRPCには問い合わせていません。本体との比較ではブロック42・gas 21000を含む合成成功結果を使いましたが、上の最小モデルはそれらの値を利用しません。最後のケースでは成功結果そのものがないため、UNKNOWN / BLOCKになります。実際のHTTPサービスではpolicyはサーバー管理であり、クライアントが任意のpolicyをリクエストに混ぜて上書きするAPIではありません。

無制限approvalを題材にする

ERC-20の approve(spender, amount) は、spenderに指定量までの利用を認めるインターフェースです。[ERC-20仕様]

ここでは approve(address,uint256) のcanonicalなcalldataに最大uint256を入れます。TxGuardはこれを UNLIMITED_APPROVAL として検出し、設定に応じて扱いを変えます。

tokenApproval.unlimited simulation fixture decision warnings
allow SUCCESS ALLOW UNLIMITED_APPROVAL
warn SUCCESS WARN UNLIMITED_APPROVAL
block SUCCESS BLOCK UNLIMITED_APPROVAL

ALLOWでもwarningsが空とは限りません。 明示的にallowしたfindingは、情報として残ります。反対にSUCCESSでもpolicy違反ならBLOCKです。

これはcalldataの検査です。宛先が本当にERC-20を実装している証明ではなく、permitやmulticall、他の権限付与形式は対象外です。maxTransactionValue もnative通貨のweiを制限する値であり、ERC-20数量やドル建て損失の上限ではありません。

3つの成功を分ける

観測するもの 分かること それだけでは分からないこと
HTTP 200 /v1/check が完了した判定を返した 判定がALLOWかどうか
simulation.status: SUCCESS 判定層が有効な成功結果として受け取った プロジェクトのpolicyに適合するか
decision: ALLOW 設定されたチェックが停止条件を出さなかった 安全性、将来の成功、経済的な妥当性

Ethereumの eth_call は、指定したブロックの状態を使ってcallを実行し、チェーンにトランザクションを作らずに戻り値を返します。送信後の実行を予約する仕組みではありません。[Ethereum JSON-RPC仕様]

TxGuardの判定層では、成功結果に対して許可チェーン、送信元・送信先・approval spenderの禁止アドレス、native value上限、対応するapprovalの設定を適用します。停止理由があればBLOCK、それがなく対応が必要な警告があればWARN、それもなければALLOWです。RPC失敗や結果不明を「警告だけ」にして先へ進める設計ではありません。

guard()の戻り値も確認する

以下は未公開SDKの実装上の契約を説明するものです。npmから取得できる公開チュートリアルではありません。SDKの check() はBLOCKを含む判定を返し、guard() はBLOCKで TxGuardBlockedError を投げます。ただし、guard() はWARNでは例外を投げません。

警告時に自動処理を保留したいアプリなら、次のような分岐を別途設けます。これは接続済みの txguard と検査対象の tx を受け取る組み込み方の例であり、上のオフライン再現コードとは別です。

// SDKをローカルtarball等で導入済みのアプリ内で使用する型
import type { TxGuard, Transaction } from '@txguard/sdk';

async function mayContinue(txguard: TxGuard, tx: Transaction) {
  try {
    const result = await txguard.guard(tx);
    if (result.decision !== 'ALLOW') {
      return { next: 'REVIEW', result }; // WARNはアプリ側でレビュー
    }
    return { next: 'APP_CHECKS', result }; // 追加の業務条件へ
  } catch {
    return { next: 'STOP' }; // BLOCK・通信障害などで送信へ進まない
  }
}

ここでは送信関数を呼びません。ALLOWの後も、アプリ固有の承認条件を確認します。検査後に to、value、data などを変えたトランザクションへ結果を流用してはいけません。状態変化により、検査時と送信時の結果が違う場合もあります。

通信失敗、タイムアウト、認証失敗、不正なレスポンスはSDKの例外経路です。HTTP 200だけを見て送信したり、catch後に送信処理へ落ちたりしない構造にします。

このコードと画面デモ、APIの違い

対象 契約・役割 今回の確認範囲
Webのdemoモード 選んだscenarioでfixtureを返す 実RPC simulationではないことをソース確認
既存 POST /preflight schemaVersion / chain / calldata を受けるx402系統 今回は決済も実行も検証しない
SaaS POST /v1/check chainId / from / to / value / data とBearer認証、サーバーpolicyによる判定 ソースで契約を確認。公開サービスの稼働確認ではない
@txguard/sdk /v1/check の型付きHTTPクライアント ローカルテスト。npm公開を前提にしない

/preflight の入力をそのまま /v1/check に渡すことはできません。またSDK自体はsimulationエンジンではなく、署名や送信も行いません。画面で成功例を選べることを、実トランザクションが成功した証拠には使えません。

検証した範囲

今回のローカル実行では、判定層12件、SDK60件が成功し、失敗・skipは0件でした。両パッケージのtypecheckも成功しています。記事の4ケースは別途実行し、assertと出力を確認しました。

以下は開発者側で実行した検証コマンドの記録です。リポジトリは非公開のため、読者の再現手順は上の単体JavaScriptを利用してください。

npm test --prefix packages/firewall
npm run typecheck --prefix packages/firewall
npm ci --cache /tmp/txguard-editorial-sdk-cache --prefix packages/sdk
npm test --prefix packages/sdk
npm run typecheck --prefix packages/sdk

これは判定分岐とクライアント契約の検証です。HTTP API全体、外部RPC、本番デプロイ、課金、コントラクトの安全性を検証した結果ではありません。

判定層とSDKの実装・テスト、HTTP APIの仕様、画面デモの実装を照合して確認しています。

自分のエージェントで評価するなら

まず、既知の成功・revert・結果不明に加え、「simulationは成功しても止めたいcall」を一つ選びます。秘密鍵や実資金を使わず、公開可能な合成fixtureで期待decisionを書いてから、実際の出力と比較してください。

見るのは判定の正答率だけではありません。「このreason codeで次の処理を決められるか」「WARN時の担当者や再確認条件を決められるか」「今のRPCエラー処理に比べて何が簡単になったか」を記録すると、導入価値を判断できます。

共有する場合は、秘密や個人情報を含まないfixture、期待したdecision、実際のdecision、不足した項目に絞ってください。公開APIへの有料利用をお願いする段階ではありません。運営者が用意した評価環境の提供範囲を確認したうえで、具体的な失敗ケースを評価するための材料です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?