Skip to main content
Glama
axdvdv

wwall

by axdvdv

wwall

Eine Policy-Wächterin, die zwischen einem KI-Agenten und einer Wallet sitzt.

Aleph Hackathon 2026 · WDK-Track · Tether

Gib einem Agenten eine Wallet, und du hast ihm dein Geld gegeben. wwall ist ein MCP-Server, der sich dazwischenstellt: Der Agent kann eine Zahlung vorschlagen, aber eine lokale, von Menschen verfasste Policy entscheidet, ob sie stattfindet, ob zuerst eine Person sie genehmigen muss oder ob sie rundweg abgelehnt wird. Jede Entscheidung wird in ein signiertes, append-only Ledger geschrieben.

Der Agent berührt @tetherto/wdk nie. Er berührt wwall, und wwall berührt WDK.

┌─────────────┐   MCP/stdio   ┌──────────────────────────┐        ┌──────────┐
│  AI agent   │──────────────▶│  wwall                   │───────▶│   WDK    │──▶ Polygon
│ (Claude…)   │  propose_     │  ├ predicates.ts (guard) │ only   │  wallet  │
│             │   payment     │  ├ ledger.jsonl (signed) │ if     └──────────┘
└─────────────┘◀──────────────│  └ policy.json           │ allowed
                 verdict      └──────────────────────────┘
                                          │ holds NEEDS_CONFIRM
                                          ▼
                                   ┌─────────────┐
                                   │   human     │  wwall pending / confirm / reject
                                   └─────────────┘

Die eine Invariante

Kein Tool-Aufruf kann wallet.send() erreichen, ohne vorher durch evaluatePredicates() zu gehen.

Alles andere ist darauf ausgelegt, das wahr zu machen:

  • Der Server registriert genau drei Tools — propose_payment, get_balance, get_pending. Es gibt kein Send-, Transfer-, Sign- oder Raw-Transaction-Tool, und ein Test prüft die Tool-Liste nach Name und Muster.

  • Die Wallet wird lazy geöffnet, nur auf einem Pfad, der bereits erlaubt wurde. Ein abgelehnter Vorschlag konstruiert überhaupt keine WDK-Instanz — die Token-Konfiguration, die zur Beantwortung nötig ist, wird genau aus diesem Grund separat übergeben.

  • Das Auszahlungs-Token ist durch die Konfiguration festgelegt. Ein Agent, der ein anderes Token nennt, wird abgelehnt, bevor irgendeine Regel läuft. (Ohne dies würde SPEND_CAP{token:"USDT0"} einfach nicht auf token:"MONOPOLY" zutreffen, die Policy würde es erlauben, und die Wallet würde trotzdem echte USD₮0 bewegen. Ein Ausgabenlimit darf nicht mit einem String umgehbar sein.)

  • Eine Ablehnung ist ein normales Tool-Ergebnis, nie ein geworfener Fehler, damit der Agent den Grund lesen und einer Person erklären kann.

  • Dieselben Prädikate sind auch in WDK selbst registriert, sodass die Wallet ebenfalls ablehnt — siehe unten.

Zwei Ebenen, ein Satz Prädikate

wwall entscheidet, ob transfer aufgerufen wird. Das ist eine Aussage über diesen Prozess. Die eigene Policy-Engine von WDK entscheidet, ob die Wallet sie ausführen wird, was eine Eigenschaft des Kontos ist:

wdk.registerPolicy({
  id: 'wwall-guard', scope: 'project', wallet: 'polygon',
  rules: [{ operation: 'transfer', action: 'ALLOW',
            conditions: [ctx => evaluate(policy, intentFrom(ctx.args), context(), 'ignore-confirm')] }]
})

Eine ALLOW-Regel, gesteuert durch dasselbe evaluatePredicates, das auch alles andere verwendet. Der Hebel liegt in dem, was nicht geschrieben ist: WDK ist default-deny auf verwalteten Konten, sodass ab dem Moment, in dem eine Policy greift, jede Methode in OPERATIONS umhüllt wird und alles ohne passende ALLOW-Regel PolicyViolationError wirft. Das schließt die Wege um ein Ausgabenlimit herum, die transfer gar nicht berühren:

Route

Warum eine transfer-förmige Wächterin sie übersieht

sendTransaction({to: token, data: <ERC-20 transfer calldata>})

Gleiche Wirkung, andere Methode

approve(spender, MAX) und dann transferFrom von jemand anderem

Gelder verlassen später, durch eine andere Hand

signTypedData eines EIP-2612-Permits

Vollständig off-chain; nichts wird „gesendet“

delegate(...) unter ERC-7702

Übergibt das Konto an einen Vertrag

wwall tut nichts davon. Das ist der Punkt: Es waren Dinge, die ihre Wächterin nicht sehen konnte. test/wdk-policy.test.ts treibt eine echte WDK-Instanz gegen einen toten RPC und behauptet, dass jede dieser Aktionen PolicyViolationError wirft, bevor irgendein Netzwerkaufruf erfolgt — während ein erlaubter Transfer stattdessen am Netzwerk scheitert, was beweist, dass er an der Wächterin vorbeikam und nicht von ihr gestoppt wurde.

Die Bedingung fragt „ist das überhaupt erlaubt“ (ignore-confirm-Modus). Die Trennung zwischen ausgeführt und gehalten gehört zur Ebene darüber: Wenn eine gehaltene Zahlung transfer erreicht, hat ein Mensch sie genehmigt, und diese Ebene darf sie nicht ein zweites Mal ablehnen.

Eine Bedingung, die bei einer ALLOW-Regel wirft, gilt als „nicht übereinstimmend“, was unter default-deny Ablehnung bedeutet — ein Fehler in dieser Ebene schlägt also fehl.

Schnellstart aus einem frischen Klon

git clone <this repo> && cd wwall
npm install
cp .env.example .env        # then edit it — see below
npm run build
npm test                    # 295 tests, no network, no money
npm run try                 # walk the guard through a dozen proposals, fake wallet

.env braucht genau eine Zeile. Alles andere hat einen Standardwert:

WARDEN_SEED="…twelve words…"
# WARDEN_ARMED=1            # leave unset until you mean to move real funds

Chain, RPC und Auszahlungs-Token standardmäßig auf Polygon und USD₮0; Policy, Ledger und Audit-Schlüssel liegen in ~/.wwall/. Siehe .env.example für jede Variable und was das Überschreiben bewirkt.

Prüfe die Wallet, ohne etwas auszugeben:

npm run check:wallet

Das liest symbol() und decimals() direkt vom Token-Vertrag und vergleicht sie mit deiner Konfiguration. Ein falsches decimals ist keine Fehlermeldung, sondern eine Auszahlung, die um einen Faktor 10ⁿ danebenliegt.

Die Sicherheitsfalle

WARDEN_ARMED ist standardmäßig aus. Bis es exakt 1 ist, wird eine von der Policy erlaubte Zahlung gemeldet, aber nicht gesendet — der Vorschlag kommt als rejected mit code: "not_armed" zurück. Bewaffne es bewusst.

Installation über Desktop Extension (empfohlen)

wwall wird als MCP-Bundle ausgeliefert — eine einzelne .mcpb-Datei, die Claude Desktop mit einem Klick installiert, mit einem Formular für die Einstellungen statt handbearbeitetem JSON.

npm install && npm run build
npm run bundle          # → build/wwall.mcpb

Dann in Claude Desktop: Einstellungen → Erweiterungen → Erweiterung installieren… und build/wwall.mcpb auswählen.

Das Formular fragt nach einer Sache: der Seed-Phrase. Sie ist im Manifest als "sensitive": true deklariert, sodass Claude Desktop sie maskiert und im OS-Schlüsselbund aufbewahrt, statt in einer Konfigurationsdatei, die du später vielleicht in einen Bugreport einfügst.

Alles andere hat einen Standardwert und wird nicht abgefragt:

Einstellung

Standard

Chain und RPC

Polygon, über einen öffentlichen Endpunkt

Auszahlungs-Token

USD₮0 — 0xc2132D05…, 6 Dezimalstellen, on-chain verifiziert

Policy, Ledger, Audit-Schlüssel

~/.wwall/

~/.wwall ist bewusst nicht das Arbeitsverzeichnis: Eine Erweiterung wird mit einem unvorhersehbaren cwd gestartet, sodass ein cwd-relatives Ledger der CLI und dem MCP-Server unterschiedliche Ausgabenverläufe geben würde — und ein Tageslimit, das aus dem falschen Ledger berechnet wird, ist kein Limit. Beide Hälften lesen jetzt dasselbe, sodass wwall pending aus jedem Verzeichnis sieht, was die Erweiterung geschrieben hat.

Beim ersten Start schreibt wwall eine Start-~/.wwall/policy.json mit einer leeren Allowlist, sodass jede Zahlung abgelehnt wird, bis du einen Empfänger benennst:

REJECTED — nothing was sent.
ALLOWLIST: list is empty, no recipient is allowed

Öffne wwall ui, um einen hinzuzufügen. Eine Erweiterung, die jemanden bezahlen könnte, von dem sie nie erfahren hat, wäre keine Wächterin, und eine Allowlist ist nichts, das man für dich erraten sollte.

Es gibt bewusst keinen zweiten Schalter. Eine installierte Erweiterung ist bewaffnet, und das Einzige, was zwischen einem Agenten und deinem Geld steht, ist die Policy — das ist der ganze Anspruch des Produkts, und ein Master-Toggle darüber würde ihn untergraben. Das Hinzufügen eines Empfängers zur Allowlist ist die bewusste Handlung; ein globales Ein/Aus wäre nur ein zweiter Ort, an dem man nachsieht, wenn eine Zahlung abgelehnt wird, und eine zweite Art von Ablehnung, die das Audit-Log verunreinigt.

WARDEN_ARMED existiert weiterhin für die CLI und die handgeschriebene Konfiguration, wo es als Einfrieren nützlich ist: Eine Zeile in .env stoppt die Wallet, ohne die Policy zu berühren.

Jeder Standardwert kann weiterhin auf die alte Weise überschrieben werden — jede WARDEN_*-Variable aus .env.example funktioniert, egal ob wwall von der CLI oder von einer Erweiterung gestartet wurde.

Das Erstellen des Bundles benötigt die Packaging-CLI, die bereits eine Dev-Abhängigkeit ist:

npx mcpb validate manifest.json   # check the manifest against the schema
npx mcpb pack build/mcpb build/wwall.mcpb

Das Format hieß .dxt und wurde als @anthropic-ai/dxt ausgeliefert; dieses Paket ist veraltet und zeigt jetzt auf @anthropic-ai/mcpb. Die Spezifikation liegt in MANIFEST.md; dieses Bundle zielt auf manifest_version 0.4.

Manuelles Einbinden in Claude Desktop

Der manuelle Weg funktioniert weiterhin und ist es wert, beibehalten zu werden: Er legt jede Einstellung in eine Datei, die du auf einen Blick lesen kannst, was manchmal genau das ist, was du willst, wenn du überprüfst, was eine Wächterin zu tun konfiguriert ist.

claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/):

{
  "mcpServers": {
    "wwall": {
      "command": "node",
      "args": ["/absolute/path/to/wwall/dist/src/bin/wwall-mcp.js"],
      "env": {
        "WARDEN_SEED": "…twelve words…",
        "WARDEN_CHAIN": "polygon",
        "WARDEN_RPC_URL": "https://polygon-bor-rpc.publicnode.com",
        "WARDEN_TOKEN_ADDRESS": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
        "WARDEN_TOKEN_SYMBOL": "USDT0",
        "WARDEN_TOKEN_DECIMALS": "6",
        "WARDEN_POLICY": "/absolute/path/to/wwall/policy.json",
        "WARDEN_LEDGER": "/absolute/path/to/wwall/ledger.jsonl"
      }
    }
  }
}

Starte Claude Desktop neu, und die drei Tools erscheinen. Ohne Client spricht der Server einfaches JSON-RPC auf stdio:

printf '%s\n%s\n%s\n' \
 '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"x","version":"0"}}}' \
 '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
 '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
 | node dist/src/bin/wwall-mcp.js

Oder richte den MCP Inspector darauf: npx @modelcontextprotocol/inspector node dist/src/bin/wwall-mcp.js

Tools

Tool

Was es tut

propose_payment(to, amount, token, reason?)

Der einzige Weg zur Wallet. Gibt executed + txHash, rejected + reason oder pending_confirmation + confirmationId zurück.

get_balance(token?)

Gas-Balance und Auszahlungs-Token-Balance. Nur lesend.

get_pending()

Zahlungen, die für einen Menschen gehalten werden. Sie wurden nicht gesendet.

Beträge sind überall dezimale Strings"12.50", nie 12.5. Eine JSON-Zahl auf dem Geldpfad ist ein Float, und ein Float ist ein Rundungsfehler, der auf eine ausreichend große Zahl wartet.

Die menschliche Hälfte

Der Agent kann eine Zahlung in pending_confirmation setzen. Nur eine Person kann sie herausnehmen:

wwall pending                     # what is waiting, and which rule held it
wwall confirm <id> --by alex      # approve and send
wwall reject  <id> --note "…"     # refuse; nothing is ever sent
wwall ui                          # policy builder in the browser

Beide Hälften lesen und schreiben dasselbe ledger.jsonl, sodass wwall pending genau das zeigt, was get_pending des Agenten zeigt.

wwall confirm bewertet die Policy vor dem Senden neu. Das Urteil wurde gefällt, als der Agent die Zahlung vorschlug, möglicherweise Stunden und mehrere Zahlungen zuvor; die Ausgabenlimits haben sich seitdem verschoben. Es prüft erneut im „ignore-confirm“-Modus — fragt nur ist das immer noch erlaubt, denn der Mensch an der Tastatur ist die Bestätigung.

Policy

policy.json ist ein Prädikatenbaum. Neun Opcodes:

Opcode

Felder

Bedeutung

AND / OR

rules[]

Leeres AND erlaubt (vakuöse Wahrheit); leeres OR lehnt ab.

NOT

rule

Kehrt um.

SPEND_CAP

token, amount, window: tx|day

Inklusiv. day ist ein rollierendes 24-Stunden-Fenster, kein Kalendertag — ein Kalenderfenster kann umgangen werden, indem man das Limit um 23:59 und erneut um 00:01 ausgibt.

ALLOWLIST

addresses[]

Eine leere Allowlist erlaubt niemandem. Eine Liste, die du vergessen hast auszufüllen, darf nicht stillschweigend alle erlauben.

DENYLIST

addresses[]

Leer lehnt niemanden ab.

TIME_WINDOW

from, to

"HH:MM" an beiden Enden = tägliches UTC-Fenster, inklusiv, über Mitternacht hinausgehend, wenn from > to. Zwei Zeitstempel = ein absoluter Bereich.

CONFIRM_THRESHOLD

amount

Keine Ablehnung — Beträge ab diesem Wert werden für einen Menschen gehalten.

VELOCITY

maxTxCount, window: hour|day

Rollierend, wie SPEND_CAP.

CONFIRM_THRESHOLD ist der Grund, warum die Policy pro Vorschlag zweimal ausgewertet wird: einmal mit jedem Schwellenwert als erfüllt behandelt (ist das überhaupt erlaubt?) und einmal strikt (kann es unbeaufsichtigt durchgehen?). Das ermöglicht es einem Schwellenwert, innerhalb eines AND, OR oder NOT zu funktionieren, statt nur auf der obersten Ebene — ein einfaches Flag „Genehmigung erforderlich“ könnte das nicht.

Nur bestätigte Sendungen zählen auf ein Cap an. Eine Zahlung, die übermittelt, aber noch nicht bestätigt ist, ist für SPEND_CAP und VELOCITY unsichtbar; siehe Bekannte Grenzen.

Der No-Code-Builder

wwall ui          # → http://127.0.0.1:4478/

Eine flache Liste von Regelkarten plus eines Umschalters für „alle erfüllen/beliebige erfüllen“, eine Live-Vorschau von policy.json und ein Testformular, das das Urteil während der Eingabe zeigt. Die Schaltfläche „Speichern“ schreibt policy.json über den lokalen Server.

Die Seite enthält keine Kopie der Guard-Logik. Ihr Urteil stammt von POST /api/evaluate, das dieselben evaluatePredicates aufruft, die auch der MCP-Server und die CLI aufrufen — eine zweite Implementierung in Browser-JavaScript würde von dieser abweichen und unmerklich abweichende Antworten liefern. Ein Test stellt sicher, dass die Seite keine clientseitige Betragsarithmetik ausliefert.

Der Builder kann bewusst keine verschachtelte Komposition zeichnen (NOT, Gruppen in Gruppen). Eine Policy, die sie verwendet, wird schreibgeschützt geöffnet, mit einem Hinweis auf policy.json. Die vollständige Komposition ist weiterhin durch Bearbeitung der Datei verfügbar.

Audit-Log

Jeder Datensatz — Urteile, Sendeversuche, Ergebnisse, Entscheidungen von Menschen — wird an ledger.jsonl angehängt, mit einem lokalen Ed25519-Schlüssel signiert und mit dem Datensatz davor verknüpft.

npm run verify:audit
records   3  (3 signed, 3 verified)
pinned to MCowBQYDK2VwAyEAKcjUin18… from audit-key.json

✓ every record is signed and the chain is unbroken

Signaturen beweisen, dass ein Datensatz nicht bearbeitet wurde. Sie beweisen nicht, dass ein Datensatz nicht entfernt wurde — das Löschen einer Zeile lässt jede verbleibende Signatur gültig. Das ist der Zweck von prev. Zusammen decken sie unwissentliches Bearbeiten, Löschen aus der Mitte und Umsortieren auf.

Die Zeile pinned to ist entscheidend: Ohne Audit-Schlüssel als Vergleichsbasis funktioniert ein Log, das mit dem Schlüssel eines Angreifers vollständig neu geschrieben wurde, einwandfrei. Verifikation ist nur gegen einen Schlüssel sinnvoll, dem Sie vertrauen.

Szenarien

36 Szenarien laufen über den echten MCP-Server über einen echten Transport — nicht durch direkten Aufruf des Evaluators, denn die interessanten Fehlschläge liegen in den Vorprüfungen, im Ledger-Roundtrip und an der Tool-Grenze.

npm run report:scenarios            # print
npm run report:scenarios -- --write # splice the table into this README

Szenario-Ergebnisse

Kategorie

Szenarien

Ausgeführt

Für Menschen zurückgehalten

Abgelehnt

Wie vorgegeben verhalten

Legitim

6

5 (83%)

1 (17%)

0 (0%)

6/6

Grenzfall

1 2

4 (33%)

3 (25%)

20 (??)

12/12

Dezimalstellen-Fallen

10

0 (0%)

0 (0%)

10 (100%)

10/10

Prompt-Injection

8

0 (0%)

1 (13%)

7 (88%)

8/8

Alle

36

9

5

22

36/36

#

Kategorie

Szenario

Ergebnis

Warum

L1

Legitim

Kleine Auszahlung an eine Adresse auf der Zulassungsliste

ausgeführt

unter jedem Cap und unter dem cap.

L2

Legitim

Kleinster darstellbarer Betrag

ausgeführt

genau eine Basiseinheit eines Tokens mit 6 Dezimalstellen.

L3

Legitim

Token über Vertragsadresse statt Symbol angegeben

ausgeführt

das Auszahlungs-Token wird in beiden Fällen erkannt.

L4

Legitim

Adresse mit Checksumme gegen eine Allowlist in Kleinschreibung

ausgeführt

EVM-Adressen vergrößern ohne Berücksichtigung von Groß-/Kleinschreibung.

L5

Legitim

Auszahlung, die einen Menschen braucht, und wird dafür zurückgehalten

zurückgehalten

über dem Bestätigungsbudget des 2-USDT0-Schellenwerts, aber innerhalb der Caps.

L6

Legitim

Zweite kleine Zahlung in der Stunde

ausgeführt

deutlich innerhalb der 5/Stunde-Geschwindigkeitsgrenze.

B1

Grenzfall

Genau am Cap pro Transaktion

zurückgehalten

das Cap ist inklusiv, also wird es gegenüber – aber es liegt über dem Bestätigungskriterium.

B2

Grenzfall

Eine Basiseinheit über dem Cap pro Transaktion

abgehrochen

Ein Millionstel Dollar über dem Cap ist immer noch über dem Cap.

B3

Grenzfall

Genau am Bestätigungsschwellenwert

zurückgehalten

der Schwellenwert löst bei >=, also ein Betrag davor benötigt einen Menschen.

B4

Grenzfall

Eine Basiseinheit unter dem Bestätigungsschwellenwert

ausgeführt

streng unterhalb des Schwellenwerts läuft es unvorhergesehen durch.

B5

Grenzfall

Zahlung, die das Tagesbudget genau ausschöpft

zurückgehalten

20 bereits ausgegeben + 5 = genau das Limit von 25/Tag, das inklusiv ist.

B6

Grenzfall

Zahlung, die das Tagesbudget um eine Einheit überschreitet

abgelehnt

gemessen wird der Verbrauch seit des Caps, nicht der einzelne Betrag.

B7

Grenzfall

Sechste Zahlung innerhalb der Stunde

abgelehnt

bereits fünf Zahlungen in dieser Stunde, und das Limit ist fünf.

B8

Grenzfall

Fünfte Zahlung innerhalb der Stunde

ausgeführt

vier bis jetzt gesendet, also bleibt diese Zahlung innerhalb des Limits.

B9

Grenzfall

Denylist-Empfänger, der auch auf der Allowlist vollständig

abgelehnt

überhaupt nicht auf der Zulassungsliste, und die Denylist lehnt es ohnehin ab.

B10

Grenzfall

Nullwert-Zahlung

ausgeführt

Null ist unter jedem Cap eine gültige Menge; nichts in der Policy verbietet es.

B11

Grenzfall

Adresse, die einer Zulassungslisten-Adresse fast gleicht

abgelehnt

ein anderes Zeichen ist eine andere Adresse, kein annähernd passender Treffer.

B12

Grenzfall

Empfängeradresse mit umgebenden Leerzeichen

ausgeführt

kopierte Leerzeichen werden abgeschnitten, nicht als andere Adresse behandelt.

D1

Dezimalstellen-Fallen

Mehr Dezimalstellen als das Token hat

abgelehnt

wäre ein Abschneiden auf 1.123456 eine kaum bemerkte Unterzahlung.

D2

Dezimalstellen-Fallen

Betrag kleiner als die kleinste darstellbare Einheit

abgelehnt

Was

Wo

Importe

src/wdk.ts:14-15

new WDK(seed).registerWallet(chain, WalletManagerEvm, {provider, transferMaxFee})

src/wdk.ts:216

wdk.registerPolicy(…) — wwalls Prädikate als WDK-Policy

src/wdk.ts:218, erstellt in src/wdk-policy.ts:55

Die ALLOW-Bedingung, die evaluate(…, 'ignore-confirm') aufruft

src/wdk-policy.ts:85

account.simulate.transfer(…) — die Engine fragen, ohne es auszuführen

src/wdk.ts:250

wdk.getAccount(chain, index)

src/wdk.ts:228

account.getBalance() → natives wei

src/wdk.ts:260

account.getTokenBalance(address) → Basiseinheiten

src/wdk.ts:261

account.quoteTransfer({token, recipient, amount})

src/wdk.ts:281

account.transfer({token, recipient, amount})die einzige Stelle, an der Geld bewegt wird

src/wdk.ts:304

account.waitForTransaction(hash, {target: 'confirmed'})

src/wdk.ts:328

wdk.dispose()

src/wdk.ts:364

MCP SDK: new McpServer in src/mcp-server.ts:97, die drei registerTool-Aufrufe bei 113, 169 und 209, sowie StdioServerTransport in src/bin/wwall-mcp.ts:52.

Die Signaturen wurden aus den eigenen .d.ts-Dateien der installierten Pakete gelesen, nicht aus dem Gedächtnis — und tsc --strict prüft die Typen dagegen, was der Beweis ist.

Pakete

Paket

Version

Warum

@tetherto/wdk

1.0.0-beta.16

Wallet-Manager, Kontenableitung

@tetherto/wdk-wallet-evm

1.0.0-beta.17

EVM-Konto: Guthaben, ERC-20-Transfer, Bestätigung

@tetherto/wdk-wallet

1.0.0-beta.17

Gemeinsame Ergebnistypen (transitiv)

@modelcontextprotocol/sdk

1.30.0

MCP-Server, Stdio-Transport

zod

4.4.3

Tool-Eingabe-/Ausgabeschemata

typescript

5.7.2

strict, noUncheckedIndexedAccess, exactOptionalPropertyTypes

vitest

2.1.8

Tests

Keine Abhängigkeit für Geldmathematik, Signierung, HTTP oder die UI: BigInt-Festkomma, node:crypto Ed25519, node:http und eine einzige handgeschriebene HTML-Datei.

Aufbau

Datei

Was

src/predicates.ts

Der Wächter. Rein — keine I/O, keine Uhr, kein Netzwerk.

src/amount.ts

BigInt-Festkomma. number erscheint nirgends auf dem Geldpfad.

src/context.ts

Ausgaben und Geschwindigkeit im gleitenden Fenster, aus dem Ledger gelesen.

src/ledger.ts

Nur-anhängbares JSONL, fsynced, optional signiert und verkettet.

src/audit.ts

Ed25519-Signierung und -Verifizierung.

src/policy.ts

Laden und Validierung, mit JSON-Pfad-Fehlern.

src/wdk.ts

Der WDK-Wrapper. Jedes Ergebnis ist JSON-serialisierbar.

src/wdk-policy.ts

Dieselben Prädikate, registriert bei WDKs Policy-Engine.

src/mcp-server.ts

Die drei Tools und der geschützte Pfad.

src/cli.ts

pending / confirm / reject / ui.

src/ui-server.ts

Nur-Loopback-API hinter dem Builder.

ui/index.html

Der Builder. Eine Datei, kein Bundler, kein Framework.

Bekannte Grenzen

Offen gesagt, denn ein Sicherheitstool, das seine Grenzen verbirgt, ist schlimmer als eines, das keine hat.

  • Nur bestätigte Sendungen zählen auf ein Limit. Ein Batch, der schneller ausgelöst wird, als er bestätigt, kann ein Tageslimit überschreiten. LedgerEvalContext.pendingInWindow() existiert, damit ein Bericht den ausstehenden Betrag zeigen kann, den kein Limit sehen kann.

  • Das Abschneiden am Ende ist nicht erkennbar. Die Hash-Kette läuft rückwärts, sodass das Löschen der letzten N Datensätze ein gültiges Präfix hinterlässt. Das zu erkennen erfordert einen externen Anker — eine anderswo geführte Datensatzzahl oder den außerhalb der Datei veröffentlichten Spitzen-Digest.

  • Der Seed bleibt der Seed. Die WDK-Policy regelt Konten, die über diese WDK-Instanz erhalten wurden. Jeder, der dieselbe Seed-Phrase in einem anderen Prozess besitzt — ein anderes Skript, eine Wallet-App, eine durchgesickerte .env — bewegt die Gelder, ohne dass eine Policy im Weg steht. Das abzusichern erfordert einen Schlüssel, der nicht abfließen kann, keine Policy: einen Signierer in einer Enklave, einen Smart Account mit On-Chain-Limits oder einen Co-Signer. wwall beschränkt einen Agenten; es beschränkt keinen Schlüsselinhaber.

  • USD₮ auf Polygon ist USDT0. Polygons altes PoS-gebrücktes USDT wurde in-place zu nativem USD₮0 migriert, Tether's Omnichain-Token, 1:1 in einem Ethereum-Tresor hinterlegt. On-Chain verifiziert: name()="USDT0", symbol()="USDT0", decimals()=6. Die BNB-Chain-Adresse 0x55d398… nicht wiederverwenden — sie ist Binance-Peg, nicht von Tether ausgegeben, und hat 18 Dezimalstellen statt 6.

  • policy.json ist vertrauenswürdige Eingabe. Jeder, der diese Datei schreiben kann, kann den Wächter neu schreiben. Sie wird einmal beim Start geladen und ihr sha256 wird bei jedem Urteil aufgezeichnet, sodass eine Änderung im Nachhinein im Audit-Protokoll sichtbar ist — aber nicht verhindert wird.

-
license - not tested
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Runtime permission, approval, and audit layer for AI agent tool execution.

  • Bitcoin-anchored, tamper-evident audit log for AI agents — record, disclose and verify actions.

  • Six-gate governance for AI agents: PROCEED/PAUSE/HALT decisions with hash-chained audit trails.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/axdvdv/wwall-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server