Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/add-proofgate-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@goat-sdk/plugin-proofgate": minor
---

Add ProofGate transaction guardrails plugin for AI agent security
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ GOAT is free software, MIT licensed.
| Orca | Create positions on Orca | [@goat-sdk/plugin-orca](https://www.npmjs.com/package/@goat-sdk/plugin-orca) |
| PlunderSwap | Currency exchange on Zilliqa | [@goat-sdk/plugin-plunderswap](https://www.npmjs.com/package/@goat-sdk/plugin-plunderswap) |
| Polymarket | Bet on Polymarket | [@goat-sdk/plugin-polymarket](https://www.npmjs.com/package/@goat-sdk/plugin-polymarket) |
| ProofGate | Transaction guardrails for AI agents | [@goat-sdk/plugin-proofgate](https://www.npmjs.com/package/@goat-sdk/plugin-proofgate) |
| Pump.fun | Launch a token on Pump.fun | [@goat-sdk/plugin-pump-fun](https://www.npmjs.com/package/@goat-sdk/plugin-pump-fun) |
| Renzo | Create a position on Renzo | [@goat-sdk/plugin-renzo](https://www.npmjs.com/package/@goat-sdk/plugin-renzo) |
| Rugcheck | Check SPL token validity on Rugcheck | [@goat-sdk/plugin-rugcheck](https://www.npmjs.com/package/@goat-sdk/plugin-rugcheck) | [goat-sdk-plugin-rugcheck](https://github.com/goat-sdk/goat/tree/main/python/src/plugins/rugcheck) |
Expand Down
156 changes: 156 additions & 0 deletions typescript/packages/plugins/proofgate/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<div align="center">
<a href="https://github.com/goat-sdk/goat">

<img src="https://github.com/user-attachments/assets/5fc7f121-259c-492c-8bca-f15fe7eb830c" alt="GOAT" width="100px" height="auto" style="object-fit: contain;">
</a>
</div>

# ProofGate GOAT Plugin

Transaction guardrails for AI agents. Validate and block unsafe DeFi transactions before they execute. Protect against infinite approvals, contract exploits, and policy violations with on-chain cryptographic proofs.

## Features

- **19 EVM Chains** - Ethereum, Base, Arbitrum, Optimism, Polygon, and more
- **Auto-blocking** - Optionally block unsafe transactions automatically
- **On-chain Proofs** - Every validation recorded on Base mainnet
- **Custom Guardrails** - Define your own validation policies
- **DeFi-Focused** - Built specifically for AI agent DeFi operations

## Requirements

- ProofGate API key (get one at [proofgate.xyz/dashboard](https://www.proofgate.xyz/dashboard))

## Installation

```bash
npm install @goat-sdk/plugin-proofgate
yarn add @goat-sdk/plugin-proofgate
pnpm add @goat-sdk/plugin-proofgate
```

## Basic Setup

```typescript
import { proofgate } from "@goat-sdk/plugin-proofgate";

const tools = await getOnChainTools({
wallet: viem(walletClient),
plugins: [
proofgate({
apiKey: process.env.PROOFGATE_API_KEY,
autoBlock: true, // Block unsafe transactions (default)
}),
],
});
```

## With Other DeFi Plugins

```typescript
import { proofgate } from "@goat-sdk/plugin-proofgate";
import { uniswap } from "@goat-sdk/plugin-uniswap";
import { erc20 } from "@goat-sdk/plugin-erc20";

const tools = await getOnChainTools({
wallet: viem(walletClient),
plugins: [
proofgate({ apiKey: process.env.PROOFGATE_API_KEY }),
uniswap({ ... }),
erc20(),
],
});

// Now all DeFi transactions are validated before execution
```

## Tools

### 1. Validate Transaction
Detailed validation with full response including checks, severity, and evidence.

```typescript
// Tool: proofgate_validate_transaction
const result = await tools.proofgate_validate_transaction({
chainId: 8453, // Base
from: "0x...",
to: "0x...",
data: "0x...",
value: "0",
});
// Returns: { safe, result, reason, validationId, checks, evidenceUri }
```

### 2. Quick Safety Check
Simple boolean check for pass/fail decisions.

```typescript
// Tool: proofgate_is_safe
const { safe, reason } = await tools.proofgate_is_safe({
chainId: 8453,
from: "0x...",
to: "0x...",
data: "0x...",
value: "0",
});
// Returns: { safe: boolean, reason: string }
```

### 3. Get Evidence
Retrieve on-chain proof for a previous validation.

```typescript
// Tool: proofgate_get_evidence
const evidence = await tools.proofgate_get_evidence({
validationId: "val_xxx_xxx",
});
```

## Supported Chains

| Chain | ID | Type |
|-------|------|------|
| Ethereum | 1 | Mainnet |
| Base | 8453 | Mainnet |
| Arbitrum | 42161 | Mainnet |
| Optimism | 10 | Mainnet |
| Polygon | 137 | Mainnet |
| BNB Chain | 56 | Mainnet |
| Avalanche | 43114 | Mainnet |
| zkSync Era | 324 | Mainnet |
| Linea | 59144 | Mainnet |
| Scroll | 534352 | Mainnet |
| Fantom | 250 | Mainnet |
| Gnosis | 100 | Mainnet |
| Celo | 42220 | Mainnet |
| Mantle | 5000 | Mainnet |
| Polygon zkEVM | 1101 | Mainnet |
| Base Sepolia | 84532 | Testnet |
| Sepolia | 11155111 | Testnet |
| Polygon Amoy | 80002 | Testnet |
| BSC Testnet | 97 | Testnet |

## What Gets Validated

- **Infinite Approvals** - Blocked by default (dangerous pattern)
- **Contract Whitelists** - Only interact with trusted protocols
- **Value Limits** - Max transaction amounts per tx or daily
- **Balance Checks** - Ensure sufficient funds before tx
- **Custom Policies** - Define your own guardrail rules

## Links

- **Website:** [proofgate.xyz](https://www.proofgate.xyz)
- **Documentation:** [proofgate.xyz/docs](https://www.proofgate.xyz/docs)
- **Dashboard:** [proofgate.xyz/dashboard](https://www.proofgate.xyz/dashboard)
- **Guardrails:** [proofgate.xyz/guardrails](https://www.proofgate.xyz/guardrails)

<footer>
<br/>
<br/>
<div>
<a href="https://github.com/goat-sdk/goat">
<img src="https://github.com/user-attachments/assets/59fa5ddc-9d47-4d41-a51a-64f6798f94bd" alt="GOAT" width="100%" height="auto" style="object-fit: contain; max-width: 800px;">
</a>
</div>
</footer>
32 changes: 32 additions & 0 deletions typescript/packages/plugins/proofgate/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "@goat-sdk/plugin-proofgate",
"version": "0.1.0",
"description": "ProofGate transaction guardrails for AI agents - validate and block unsafe DeFi transactions",
"files": ["dist/**/*", "README.md", "package.json"],
"scripts": {
"build": "tsup",
"clean": "rm -rf dist",
"test": "vitest run --passWithNoTests"
},
"sideEffects": false,
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"dependencies": {
"@goat-sdk/core": "workspace:*",
"zod": "catalog:"
},
"peerDependencies": {
"@goat-sdk/core": "workspace:*"
},
"homepage": "https://www.proofgate.xyz",
"repository": {
"type": "git",
"url": "git+https://github.com/goat-sdk/goat.git"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/goat-sdk/goat/issues"
},
"keywords": ["ai", "agents", "web3", "security", "guardrails", "defi", "proofgate"]
}
69 changes: 69 additions & 0 deletions typescript/packages/plugins/proofgate/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const PROOFGATE_API_URL = "https://www.proofgate.xyz/api";

export interface ValidationRequest {
chainId: number;
from: string;
to: string;
data: string;
value: string;
guardrailId?: string;
}

export interface ValidationResponse {
result: "PASS" | "FAIL";
reason: string;
validationId: string;
checks?: Array<{
check: string;
passed: boolean;
message: string;
severity: "info" | "warning" | "critical";
}>;
severity?: "info" | "warning" | "critical";
evidenceUri?: string;
chainId?: number;
chainName?: string;
}

export interface ProofGateAPIError {
error: string;
code?: string;
}

export class ProofGateAPI {
constructor(private apiKey: string) {}

async validate(request: ValidationRequest): Promise<ValidationResponse> {
const response = await fetch(`${PROOFGATE_API_URL}/validate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.apiKey}`,
},
body: JSON.stringify(request),
});

const data = await response.json();

if (!response.ok) {
const error = data as ProofGateAPIError;
throw new Error(error.error || `ProofGate API error: ${response.status}`);
}

return data as ValidationResponse;
}

async getEvidence(validationId: string): Promise<{ uri: string; data: unknown }> {
const response = await fetch(`${PROOFGATE_API_URL}/evidence/${validationId}`, {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
});

if (!response.ok) {
throw new Error(`Failed to get evidence: ${response.status}`);
}

return response.json();
}
}
2 changes: 2 additions & 0 deletions typescript/packages/plugins/proofgate/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./proofgate.plugin";
export * from "./parameters";
47 changes: 47 additions & 0 deletions typescript/packages/plugins/proofgate/src/parameters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { createToolParameters } from "@goat-sdk/core";
import { z } from "zod";

export class ValidateTransactionParameters extends createToolParameters(
z.object({
chainId: z.number().describe("The chain ID of the network (e.g., 1 for Ethereum, 8453 for Base)"),
from: z
.string()
.regex(/^0x[a-fA-F0-9]{40}$/)
.describe("The sender wallet address (0x...)"),
to: z
.string()
.regex(/^0x[a-fA-F0-9]{40}$/)
.describe("The recipient/contract address (0x...)"),
data: z.string().describe("The transaction calldata (hex string starting with 0x)"),
value: z.string().default("0").describe("The transaction value in wei"),
guardrailId: z
.string()
.optional()
.describe("Optional guardrail/policy ID to validate against specific rules"),
}),
) {}

export class IsSafeParameters extends createToolParameters(
z.object({
chainId: z.number().describe("The chain ID of the network"),
from: z
.string()
.regex(/^0x[a-fA-F0-9]{40}$/)
.describe("The sender wallet address"),
to: z
.string()
.regex(/^0x[a-fA-F0-9]{40}$/)
.describe("The recipient/contract address"),
data: z.string().describe("The transaction calldata"),
value: z.string().default("0").describe("The transaction value in wei"),
guardrailId: z.string().optional().describe("Optional guardrail/policy ID"),
}),
) {}

export class GetEvidenceParameters extends createToolParameters(
z.object({
validationId: z
.string()
.describe("The validation ID returned from a previous validation (e.g., val_xxx_xxx)"),
}),
) {}
58 changes: 58 additions & 0 deletions typescript/packages/plugins/proofgate/src/proofgate.plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { type Chain, PluginBase } from "@goat-sdk/core";
import { ProofGateAPI } from "./api";
import { ProofGateService } from "./proofgate.service";

// Supported EVM chains (19 total)
const SUPPORTED_CHAIN_IDS = new Set([
// Layer 1
1, // Ethereum
56, // BNB Chain
43114, // Avalanche
250, // Fantom
42220, // Celo
100, // Gnosis
// Layer 2
8453, // Base
42161, // Arbitrum
10, // Optimism
137, // Polygon
324, // zkSync Era
59144, // Linea
534352, // Scroll
5000, // Mantle
1101, // Polygon zkEVM
// Testnets
84532, // Base Sepolia
11155111, // Sepolia
80002, // Polygon Amoy
97, // BSC Testnet
]);

export interface ProofGatePluginOptions {
/** ProofGate API key (starts with pg_live_) */
apiKey: string;
/** Automatically throw error on unsafe transactions (default: true) */
autoBlock?: boolean;
}

export class ProofGatePlugin extends PluginBase {
constructor({ apiKey, autoBlock = true }: ProofGatePluginOptions) {
const api = new ProofGateAPI(apiKey);
const service = new ProofGateService(api, autoBlock);

super("proofgate", [service]);
}

supportsChain(chain: Chain): boolean {
// Only support EVM chains
if (chain.type !== "evm") {
return false;
}
// Check if chain ID is in our supported list
return SUPPORTED_CHAIN_IDS.has(chain.id);
}
}

export function proofgate(options: ProofGatePluginOptions) {
return new ProofGatePlugin(options);
}
Loading