Everything you need to understand, integrate, and build on the Bouclier protocol. From installation to deploying custom policies.
# Clone the monorepo git clone https://github.com/incyashraj/bouclier.git cd bouclier # Install dependencies npm install # Build contracts cd contracts forge build # Run tests forge test
# Set environment variables export BASE_SEPOLIA_RPC="https://sepolia.base.org" export PRIVATE_KEY="your-deployer-private-key" # Deploy the registry contract forge script script/DeployRegistry.s.sol \ --rpc-url $BASE_SEPOLIA_RPC \ --private-key $PRIVATE_KEY \ --broadcast # Deploy a sample policy forge script script/DeployTransferLimitPolicy.s.sol \ --rpc-url $BASE_SEPOLIA_RPC \ --private-key $PRIVATE_KEY \ --broadcast
┌─────────────────────────────────────────────┐
│ AI Agent (any framework) │
│ LangChain · AutoGPT · CrewAI · Custom │
└──────────────────┬──────────────────────────┘
│ action request
▼
┌─────────────────────────────────────────────┐
│ Bouclier SDK │
│ @bouclier/sdk · bouclier-rs · bouclier-py │
└──────────────────┬──────────────────────────┘
│ validate()
▼
┌─────────────────────────────────────────────┐
│ Sentinel Network │
│ Distributed policy verification nodes │
└──────────────────┬──────────────────────────┘
│ check policies
▼
┌─────────────────────────────────────────────┐
│ On-Chain Registry (Base L2) │
│ Agent IDs · Policy Bindings · Revocation │
└──────────────────┬──────────────────────────┘
│ settlement
▼
┌─────────────────────────────────────────────┐
│ Target Protocol / Contract │
│ DeFi · NFT · DAO · Any EVM Contract │
└─────────────────────────────────────────────┘On-chain identity and policy bindings on Base L2. Immutable contract state.
Sentinel nodes intercept and validate agent actions against registered policies.
Composable smart contract modules — each one defines a specific constraint.
A unique identifier derived from keccak256(abi.encodePacked(owner, metadata, salt)). This is the on-chain identity for an autonomous agent.
An immutable smart contract that implements a validate() function. Returns true if the agent action is permitted, false to block.
The on-chain link between an Agent ID and an array of policy contract addresses. All policies must pass for an action to proceed.
A verification node that monitors the Base L2 mempool, intercepts agent transactions, and runs policy checks before settlement.
A single-call operation (revokeAgent) that globally deactivates an agent. All sentinel nodes stop processing its transactions immediately.
The response from a policy check: { valid: bool, reason: string }. On failure, the sentinel node blocks the action and logs the reason.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IBouclierRegistry {
/// @notice Register a new agent with attached policies
/// @param agentId Unique bytes32 identifier for the agent
/// @param policies Array of policy contract addresses
function registerAgent(
bytes32 agentId,
address[] calldata policies
) external;
/// @notice Revoke an agent — stops all sentinel processing
/// @param agentId The agent to revoke
function revokeAgent(bytes32 agentId) external;
/// @notice Check if an agent is currently active
function isActive(bytes32 agentId) external view returns (bool);
/// @notice Get all policies attached to an agent
function getPolicies(
bytes32 agentId
) external view returns (address[] memory);
/// @notice Add a policy to an existing agent
function addPolicy(bytes32 agentId, address policy) external;
/// @notice Remove a policy from an agent
function removePolicy(bytes32 agentId, address policy) external;
event AgentRegistered(bytes32 indexed agentId, address indexed owner);
event AgentRevoked(bytes32 indexed agentId);
event PolicyAdded(bytes32 indexed agentId, address indexed policy);
event PolicyRemoved(bytes32 indexed agentId, address indexed policy);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IBouclierPolicy {
/// @notice Validate an agent action against this policy
/// @param agentId The registered agent identifier
/// @param target The contract being called
/// @param value The ETH value being sent
/// @param data The calldata being executed
/// @return valid Whether the action is permitted
function validate(
bytes32 agentId,
address target,
uint256 value,
bytes calldata data
) external view returns (bool valid);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {IBouclierPolicy} from "./IBouclierPolicy.sol";
/// @title TransferLimitPolicy
/// @notice Enforces a maximum ETH transfer per transaction
contract TransferLimitPolicy is IBouclierPolicy {
uint256 public immutable maxTransferWei;
constructor(uint256 _maxTransferWei) {
maxTransferWei = _maxTransferWei;
}
function validate(
bytes32, /* agentId */
address, /* target */
uint256 value,
bytes calldata /* data */
) external view override returns (bool valid) {
return value <= maxTransferWei;
}
}The TypeScript SDK is in active development. Install from the monorepo while the npm package is being prepared.
# From the monorepo root cd sdk npm install npm run build # Link for local development npm link
import { BouclierClient } from "@bouclier/sdk";
import { createWalletClient, http } from "viem";
import { baseSepolia } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
// Initialize the Bouclier client
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const bouclier = new BouclierClient({
chain: baseSepolia,
transport: http(process.env.BASE_SEPOLIA_RPC),
account,
});
// Generate an agent ID
const agentId = bouclier.generateAgentId({
name: "treasury-bot",
version: "1.0.0",
salt: "unique-salt-value",
});
// Register with policies
const tx = await bouclier.registerAgent({
agentId,
policies: [
"0x...TransferLimitPolicy",
"0x...ScopeRestrictionPolicy",
],
});
console.log("Agent registered:", tx.hash);
console.log("Agent ID:", agentId);// Validate an action before execution
const result = await bouclier.validate({
agentId,
target: "0x...TargetContract",
value: 0n,
data: encodedCalldata,
});
if (result.valid) {
// All policies passed — safe to execute
const tx = await walletClient.sendTransaction({
to: target,
value: 0n,
data: encodedCalldata,
});
} else {
console.error("Policy violation:", result.reason);
}
// Check agent status
const isActive = await bouclier.isActive(agentId);
// Get attached policies
const policies = await bouclier.getPolicies(agentId);
// Revoke in emergency
await bouclier.revokeAgent(agentId);// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {IBouclierPolicy} from "./IBouclierPolicy.sol";
/// @title ScopeRestrictionPolicy
/// @notice Restricts an agent to only interact with whitelisted contracts
contract ScopeRestrictionPolicy is IBouclierPolicy {
mapping(address => bool) public allowedTargets;
constructor(address[] memory _targets) {
for (uint i = 0; i < _targets.length; i++) {
allowedTargets[_targets[i]] = true;
}
}
function validate(
bytes32, /* agentId */
address target,
uint256, /* value */
bytes calldata /* data */
) external view override returns (bool valid) {
return allowedTargets[target];
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "forge-std/Test.sol";
import "../src/ScopeRestrictionPolicy.sol";
contract ScopeRestrictionPolicyTest is Test {
ScopeRestrictionPolicy policy;
address allowed = address(0xA);
address blocked = address(0xB);
function setUp() public {
address[] memory targets = new address[](1);
targets[0] = allowed;
policy = new ScopeRestrictionPolicy(targets);
}
function testAllowedTarget() public view {
bool valid = policy.validate(
bytes32(0), allowed, 0, ""
);
assertTrue(valid);
}
function testBlockedTarget() public view {
bool valid = policy.validate(
bytes32(0), blocked, 0, ""
);
assertFalse(valid);
}
function testFuzz(address target) public view {
bool valid = policy.validate(
bytes32(0), target, 0, ""
);
assertEq(valid, target == allowed);
}
}Scans the Base L2 mempool for transactions from registered agents
Runs each pending action through the agent's attached policy contracts
Blocks invalid transactions and logs violations to the on-chain audit trail
# Clone and build git clone https://github.com/incyashraj/bouclier.git cd bouclier/node cargo build --release # Initialize configuration ./target/release/bouclier-node init --network base-sepolia # Start the sentinel node ./target/release/bouclier-node start \ --rpc $BASE_SEPOLIA_RPC \ --registry 0x...RegistryAddress
| Method | Parameters | Returns |
|---|---|---|
| registerAgent | agentId, policies[] | TransactionHash |
| revokeAgent | agentId | TransactionHash |
| isActive | agentId | boolean |
| getPolicies | agentId | address[] |
| addPolicy | agentId, policy | TransactionHash |
| removePolicy | agentId, policy | TransactionHash |
| validate | agentId, target, value, data | { valid, reason } |
| generateAgentId | name, version, salt | bytes32 |
Clone the repo, deploy to testnet, and register your first agent.