The Runtime Guard Wrapper is a Soroban smart contract designed to wrap other contracts and provide real-time validation, monitoring, and security guards during execution.
This contract enables:
- Pre-execution Validation - Verify system state before function execution
- Post-execution Verification - Confirm state invariants after execution
- Execution Monitoring - Track and record all contract calls
- Security Guards - Enforce runtime contracts and policies
- Metrics Collection - Gather performance and operational data
- Event Emission - Emit events for external monitoring systems
- Continuous Validation - Enable testnet continuous validation requirements
┌──────────────────────────────────────────────────────────────┐
│ Soroban Testnet │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Runtime Guard Wrapper Contract │ │
│ │ ┌──────────┐ │ │
│ │ │ A. Pre-Execution Guards │ │
│ │ │ - Verify wrapped contract set │ │
│ │ │ - Check storage integrity │ │
│ │ └──────────┘ │ │
│ │ ↓ │ │
│ │ ┌──────────┐ │ │
│ │ │ B. Execute with Monitoring │ │
│ │ │ - Record metrics │ │
│ │ │ - Track gas usage │ │
│ │ │ - Measure execution time │ │
│ │ └──────────┘ │ │
│ │ ↓ │ │
│ │ ┌──────────┐ │ │
│ │ │ C. Post-Execution Guards │ │
│ │ │ - Verify invariants │ │
│ │ │ - Check state consistency │ │
│ │ │ - Emit validation events │ │
│ │ └──────────┘ │ │
│ │ ↓ │ │
│ │ ┌──────────┐ │ │
│ │ │ D. Logging & Reporting │ │
│ │ │ - Record execution │ │
│ │ │ - Collect statistics │ │
│ │ │ - Update metrics │ │
│ │ └──────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
pub struct GuardConfig {
pub check_storage_invariants: bool, // Validate storage state
pub check_auth_guards: bool, // Verify authorization
pub check_overflow: bool, // Detect overflows
pub monitor_events: bool, // Track events
pub max_execution_time_ms: u32, // Execution timeout
}Initialize Wrapper
↓
Set Wrapped Contract Address
↓
Pre-Execution Checks
├─ Wrapped contract accessible?
├─ Storage integrity OK?
└─ Guards configured?
↓
Execute Guarded Function
├─ Record start time
├─ Monitor execution
├─ Handle errors
└─ Record metrics
↓
Post-Execution Checks
├─ Verify invariants
├─ Check consistency
└─ Emit events
↓
Log & Report
├─ Update call log
├─ Record metrics
└─ Update statistics
The contract uses three storage layers:
Instance Storage (Persistent):
- Wrapped contract address
- Guard configuration
Persistent Storage (Long-term):
- Call execution log (capped at 100 entries)
- Invariant check counter
- Guard failure records
- Execution metrics (capped at 1000 entries)
- Event logs
Initialize the wrapper with a target contract address.
pub fn init(env: Env, wrapped_contract: Address) {
// Set wrapped contract
// Initialize guard configuration
// Initialize logging
// Emit initialization event
}Retrieve the wrapped contract address.
pub fn get_wrapped_contract(env: Env) -> Address {
// Returns the address of the wrapped contract
}Execute a function with runtime guards enabled.
pub fn execute_guarded(
env: Env,
function_name: Symbol,
args: Vec<Val>
) -> Result<Val, Error> {
// Pre-execution guards
// Monitored execution
// Post-execution checks
// Logging
// Returns result or error
}Get contract statistics.
Returns tuple: (invariants_checked, execution_count, guard_failures)
pub fn get_stats(env: Env) -> (u32, u32, u32) {
// Returns statistics for monitoring
}Verify contract health and operational status.
pub fn health_check(env: Env) -> bool {
// Checks:
// - Wrapped contract is set
// - Metrics storage accessible
// Returns true if all systems operational
}Each execution generates metrics:
pub struct ExecutionMetrics {
pub call_hash: u32, // Hash of function call
pub success: bool, // Execution succeeded?
pub timestamp: u64, // Execution time
pub gas_used: u64, // Gas consumed (reserved)
}The contract emits events for monitoring:
Event: (Symbol, Symbol)
First: Event name (e.g., "guard_wrapper", "pre_exec_guard")
Second: Status (e.g., "success", "passed", "failure")
- All runtime-guard events use the
guard_wrappertopic. - Event name and status are emitted as symbol pairs and are intended to stay stable for downstream parsers.
- Failure paths emit
guard_failurewith a status that maps to the failure class (argument mismatch, missing function, wrapped-call error).
- Runtime state is segmented into instance and persistent storage namespaces.
- Fixed keys are intentionally centralized to avoid accidental key reuse across guard statistics and execution metadata.
- Health checks treat abnormal key growth as a fixture failure signal.
- Guarded execution returns Soroban
Errorvalues for invalid function names, argument mismatches, and wrapped-call decoding failures. - Wrapped-call conversion failures are explicitly recorded as guard failures before returning the error.
- Successful executions increment invariant counters and append execution log entries; failed executions do not mutate those success-only counters.
cargo build \
-p runtime-guard-wrapper \
--release \
--target wasm32-unknown-unknown# Using deployment script
bash scripts/deploy-soroban-testnet.sh --network testnet
# Or using CLI
sanctifier deploy ./contracts/runtime-guard-wrapper \
--network testnet \
--validateCONTRACT_ID="C1234567..."
WRAPPED_CONTRACT="GXXXXX..."
soroban contract invoke \
--id "$CONTRACT_ID" \
--network testnet \
-- init "$WRAPPED_CONTRACT"soroban contract invoke \
--id "$CONTRACT_ID" \
--network testnet \
-- execute_guarded function_name args# Get statistics
soroban contract invoke \
--id "$CONTRACT_ID" \
--network testnet \
-- get_stats
# Health check
soroban contract invoke \
--id "$CONTRACT_ID" \
--network testnet \
-- health_check
# Read events
soroban events read \
--network testnet \
--id "$CONTRACT_ID"The contract includes integration tests:
cd contracts/runtime-guard-wrapper
cargo testTest coverage:
- Wrapper initialization
- Pre-execution guards
- Post-execution guards
- Execution logging
- Metrics recording
- Health checks
- Event emission
- Storage validation
- Unhandled-
Resultfixture behavior - Event-emission fixture boundaries
A cargo fuzz harness drives execute_guarded and its accessors through
arbitrary byte sequences (random function names, argument counts/values, and
init ordering) to confirm the contract never panics and always resolves
unexpected input to a typed RuntimeGuardError.
cd contracts/runtime-guard-wrapper
cargo install cargo-fuzz
cargo +nightly fuzz run fuzz_execute_guarded- Keep event names/status values stable unless there is a migration note and consumer update.
- When adding new failure paths, record the failure category before returning
Err. - Prefer extending
tests/integration_tests.rswith fixture-style tests that assert both return value andget_stats()effects.
- Guard Immutability - Guards cannot be disabled after initialization
- Storage Integrity - Regular validation of critical storage
- Audit Trail - All operations are logged
- Fail-Safe - Errors prevent execution
- Bounded Growth - Logs and metrics are capped to prevent DoS
- ✅ Pre-execution: Verify system readiness
- ✅ Post-execution: Confirm state consistency
- ✅ Overflow: Detect arithmetic errors
⚠️ Authorization: Guard invocation restrictions⚠️ Events: Monitor critical operations
- Wrapped contract address cannot be changed after init
- Storage space is bounded (100 calls, 1000 metrics)
- Events are advisory only (not enforceable)
- No on-chain cryptographic verification
Estimated gas usage per operation:
| Operation | Approximate Gas |
|---|---|
| init | 15,000 |
| execute_guarded | 10,000-20,000 |
| get_stats | 5,000 |
| health_check | 8,000 |
| Item | Size |
|---|---|
| Wrapped address | 32 bytes |
| Config | 16 bytes |
| Call log entry | 32 bytes (×100 max) |
| Metrics entry | 32 bytes (×1000 max) |
| Total max | ~64 KB |
Potential improvements:
- Async invocation support
- Custom guard policies
- Per-function rate limiting
- Advanced metrics (percentiles, histograms)
- Replay protection
- Multi-wrapper composition
- Event filtering and sampling
# Verify contract is initialized
soroban contract invoke \
--id "$CONTRACT_ID" \
--network testnet \
-- get_wrapped_contract# Run health check
soroban contract invoke \
--id "$CONTRACT_ID" \
--network testnet \
-- health_check
# Check contract state
soroban contract read --id "$CONTRACT_ID" --network testnet- May indicate network congestion
- Increase timeout in guard config
- Check RPC endpoint health
Part of the Sanctifier project. See repository LICENSE.