A minimal on-chain guard contract that enforces policy constraints before execution. Commonly used in multisigs, DAOs, and protocol risk management systems.
Smart contract systems need explicit policy enforcement before executing sensitive operations:
- π° Rate limiting - Prevent excessive withdrawals
- β° Cooldown periods - Time-based restrictions
- π Role-based access - Who can do what
- π Amount limits - Maximum transaction sizes
This pattern separates policy validation from execution logic, reducing blast radius and simplifying security audits.
- π― Simple Policy Enforcement -
ActionGuard.sol - π§ Advanced Multi-Policy Support -
AdvancedActionGuard.sol - βοΈ Signed Approvals - Off-chain signature verification
- π§ͺ Comprehensive Tests - Full Foundry test suite
- π Well Documented - Clear architecture and security model
- π OpenZeppelin Based - Battle-tested access control
- Foundry installed
# Clone the repo
git clone https://github.com/kelpejol/on-chain-action-guard.git
cd on-chain-action-guard
# Install dependencies
forge install
# Build contracts
forge build
# Run tests
forge test# Run all tests
forge test
# Run with verbosity
forge test -vvv
# Run specific test
forge test --match-test testAllowsExecution
# Run with gas reporting
forge test --gas-reportSimple guard with single global policy.
// Deploy
ActionGuard guard = new ActionGuard(100 ether, 1 days);
// Check policy
guard.check(msg.sender, 10 ether); // β
Passes
// Record execution
guard.recordExecution(msg.sender);
// Cooldown enforced
guard.check(msg.sender, 10 ether); // β RevertsMulti-policy support with signed approvals.
// Set policy
bytes32 policyId = keccak256("TREASURY_WITHDRAWAL");
guard.setPolicy(caller, policyId, 100 ether, 1 days);
// Check with policy ID
guard.check(caller, policyId, 50 ether); // β
// Or use signed approval
guard.checkWithApproval(
caller,
policyId,
50 ether,
nonce,
signature
);Example integration showing guard usage.
contract ProtectedVault {
ActionGuard public guard;
function withdraw(uint256 amount) external {
guard.check(msg.sender, amount);
guard.recordExecution(msg.sender);
// ... transfer logic
}
}Caller
β
ActionGuard (Policy Validation)
β
Protected Contract (Execution)
- Control Plane / Execution Plane Split - Policy separate from logic
- Fail Fast - Invalid requests rejected immediately
- Explicit Authorization - No implicit trust
- Composability - Works with any contract
DEFAULT_ADMIN_ROLEis trustedPOLICY_ADMIN_ROLEis trusted to set valid policies- Callers may be adversarial
Protected Against:
- β Replay attacks (nonce-based)
- β Privilege escalation (role-based access)
- β Policy bypass (must call guard explicitly)
- β Rate limit violations (per-caller cooldowns)
Not Protected Against:
- β Smart contract bypassing the guard entirely
- β Admin key compromise
- β Flash loan attacks (no economic security)
See SECURITY.md for complete threat model.
| Operation | Gas Cost |
|---|---|
check() |
~25,000 |
recordExecution() |
~45,000 |
checkWithApproval() |
~75,000 |
Gas costs approximate, may vary
# Run all tests
forge test
# Run with coverage
forge coverage
# Run with gas snapshots
forge snapshot
# Run specific test file
forge test --match-path test/ActionGuard.t.soltest/
βββ ActionGuard.t.sol # Basic guard tests
βββ AdvancedActionGuard.t.sol # Advanced features
# Start local node
anvil
# Deploy (in another terminal)
forge script script/Deploy.s.sol --rpc-url http://localhost:8545 --broadcast# Deploy to Sepolia
forge script script/Deploy.s.sol \
--rpc-url $SEPOLIA_RPC_URL \
--private-key $PRIVATE_KEY \
--broadcast \
--verify# Deploy to mainnet (use hardware wallet!)
forge script script/Deploy.s.sol \
--rpc-url $MAINNET_RPC_URL \
--ledger \
--broadcast \
--verify[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc_version = "0.8.20"
optimizer = true
optimizer_runs = 200Contributions welcome! Please see CONTRIBUTING.md.
- Fork the repo
- Create a branch (
git checkout -b feature/amazing) - Make changes
- Run tests (
forge test) - Commit (
git commit -m 'Add feature') - Push and open PR
MIT License - see LICENSE file.
- OpenZeppelin Contracts
- Foundry
- Inspired by real-world DAO treasury management patterns
- π Report Issues
- π¬ Discussions
- π Documentation
- Multi-signature requirement support
- Time-weighted voting integration
- Cross-chain policy enforcement
- Emergency pause mechanism
- Policy composition and inheritance
- Formal verification with Certora
Built with β€οΈ using Foundry