Skip to content

Hugo0/signthat

Repository files navigation

SignThat

Zero-trust Ethereum signing via URL. For AI agents and humans.

  • Review and sign EIP-712 typed data — orders, permits, attestations
  • Review and send transactions — approvals, transfers, contract calls
  • 39KB single HTML file — no backend, no tracking, no cookies, IPFS-hosted

How It Works

  1. A service, script, or AI agent builds an unsigned payload and encodes it in a URL
  2. The user opens the link, reviews the decoded fields (human-readable, not raw hex)
  3. Connects their wallet (MetaMask, Rabby, Ledger, Trezor via EIP-6963)
  4. Signs on-device — private key never leaves the hardware wallet

The payload lives in the URL fragment (after #) — it's never sent to any server.

Quick Start

Python SDK:

from signthat import generate_signing_url

url = generate_signing_url("tx", {
    "to": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
    "data": "0x095ea7b3" + spender[2:].zfill(64) + hex(amount)[2:].zfill(64),
    "chainId": 137
})
# Send this URL to the user

TypeScript SDK:

import { generateSigningUrl } from 'signthat';

const url = generateSigningUrl('712', {
  primaryType: 'Order',
  types: { /* ... */ },
  domain: { name: 'Exchange', chainId: 137 },
  message: { maker: '0x...', amount: '1000000', side: '0' }
});

REST API:

curl -X POST https://api.signthat.org/api/v1/generate \
  -H "Content-Type: application/json" \
  -d '{"format": "tx", "payload": {"to": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", "chainId": 137, "data": "0x095ea7b3..."}}'

MCP Server (for Claude Code, Cursor, etc.):

{
  "mcpServers": {
    "signthat": {
      "command": "uvx",
      "args": ["signthat-mcp"]
    }
  }
}

Then your AI agent can call generate_signing_url("tx", payload) directly.

URL Format

https://<host>/#<format>/<base64url-json>.<checksum>
Component Description
format 712 (EIP-712 signing) or tx (transaction broadcast)
base64url-json JSON payload, base64url-encoded (RFC 4648 §5, no padding)
checksum First 6 hex chars of SHA-256 of the base64url string

For AI Agents

To propose a transaction to a human user, generate a SignThat URL and send it to them (via chat, notification, or any channel). The user opens the link in their browser, reviews the decoded transaction details, connects their wallet, and confirms.

  • EIP-712 signing: the user copies the resulting signature back to you
  • Transactions: broadcast happens automatically; the user shares the tx hash

No API keys. No wallet connection sessions. No private key access required.

Security Model

  • Fragment-only URLs — the server never sees the payload (fragments aren't sent in HTTP requests)
  • Single static HTML — all code inlined, no external scripts, no CDN
  • IPFS-hosted — content hash (CID) guarantees the page hasn't been tampered with
  • URL checksums — 6-char integrity check detects corruption or truncation
  • Verifiable builds — git commit hash and SHA-256 displayed in footer

Supported Chains

Ethereum, Polygon, Optimism, Arbitrum, Base, Sepolia (with block explorer links). Any EVM chain works — known chains get human-readable names and explorer integration.

Smart Decoding

  • ERC-20 function calls decoded: approve(), transfer(), transferFrom()
  • Known tokens labeled (USDC, USDC.e, USDT)
  • Addresses linked to block explorers with copy buttons
  • Token amounts formatted with correct decimals
  • Unlimited approvals detected and labeled

Development

# Build
bash build.sh

# Test (34 Playwright e2e tests)
npx playwright test

# Deploy to IPFS
bash deploy.sh

# Run API locally
cd api && pip install -r requirements.txt && uvicorn server:app --reload

License

MIT

Built by @uwwgo.

About

Zero-trust Ethereum signing via URL. For AI agents and humans.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors