shll-policy-sdk
v1.0.0
Published
SDK for interacting with SHLL PolicyGuard — validate, execute, and manage on-chain safety policies
Readme
@shll/policy-sdk
SDK for interacting with SHLL's PolicyGuard — validate, execute, and manage on-chain safety policies.
Install
npm install @shll/policy-sdk viemQuick Start
import { PolicyClient } from "@shll/policy-sdk";
import { encodeFunctionData } from "viem";
// 1. Initialize
const client = new PolicyClient({
rpcUrl: "https://bsc-dataseed1.binance.org",
agentNfaAddress: "0xe98dcdbf370d7b52c9a2b88f79bef514a5375a2b",
policyGuardAddress: "0x25d17ea0e3bcb8ca08a2bfe917e817afc05dbbb3",
operatorPrivateKey: "0x...", // your runner's private key
});
// 2. Validate an action (off-chain — no gas cost)
const action = {
target: "0x10ED43C718714eb63d5aA57B78B54704E256024E", // PancakeSwap Router
value: 0n,
data: encodeFunctionData({
abi: pancakeRouterAbi,
functionName: "swapExactTokensForTokens",
args: [amountIn, amountOutMin, path, vaultAddress, deadline],
}),
};
const result = await client.validate(1n, action);
if (!result.ok) {
console.error("Policy rejected:", result.reason);
process.exit(1);
}
// 3. Execute (on-chain)
const tx = await client.execute(1n, action);
console.log("TX:", tx.hash);API Reference
new PolicyClient(config)
| Config Field | Type | Required | Description |
|---|---|---|---|
| rpcUrl | string | ✅ | BSC RPC endpoint |
| agentNfaAddress | Address | ✅ | AgentNFA contract address |
| policyGuardAddress | Address | ✅ | PolicyGuardV4 contract address |
| operatorPrivateKey | Hex | ❌ | Runner's private key (needed for write ops) |
| chainId | number | ❌ | 56 (mainnet, default) or 97 (testnet) |
Read Methods
| Method | Returns | Description |
|--------|---------|-------------|
| validate(tokenId, action) | ValidationResult | Off-chain policy simulation |
| getPolicies(tokenId) | PolicyInfo[] | Active policies with type info |
| getOperatorState(tokenId) | AgentOperatorState | Operator, renter, vault, nonce |
| getVault(tokenId) | Address | Agent vault address |
Write Methods (require operatorPrivateKey)
| Method | Returns | Description |
|--------|---------|-------------|
| execute(tokenId, action) | ExecutionResult | Simulate + execute single action |
| executeBatch(tokenId, actions) | ExecutionResult | Simulate + execute batch |
| setOperatorWithPermit(permit, sig) | ExecutionResult | Register operator on-chain |
| clearOperator(tokenId) | ExecutionResult | Remove operator authorization |
Batch Execution (approve + swap)
import { encodeFunctionData } from "viem";
const actions = [
{
target: tokenAddress,
value: 0n,
data: encodeFunctionData({
abi: erc20Abi,
functionName: "approve",
args: [routerAddress, amountIn],
}),
},
{
target: routerAddress,
value: 0n,
data: encodeFunctionData({
abi: pancakeRouterAbi,
functionName: "swapExactTokensForTokens",
args: [amountIn, amountOutMin, path, vaultAddress, deadline],
}),
},
];
const tx = await client.executeBatch(1n, actions);Query Active Policies
const policies = await client.getPolicies(1n);
for (const p of policies) {
console.log(`${p.policyTypeName} @ ${p.address} (renter configurable: ${p.renterConfigurable})`);
}
// Output:
// spending_limit @ 0x750f... (renter configurable: true)
// cooldown @ 0x1169... (renter configurable: true)
// receiver_guard @ 0x5480... (renter configurable: false)
// ...Operator Permit Flow
// 1. Get current nonce
const state = await client.getOperatorState(1n);
// 2. Renter signs EIP-712 permit off-chain (your frontend does this)
const permit = {
tokenId: 1n,
renter: state.renter,
operator: client.getOperatorAddress()!,
expires: state.renterExpires, // must be <= lease expiry
nonce: state.operatorNonce,
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), // 1 hour
};
// 3. Submit permit on-chain
const tx = await client.setOperatorWithPermit(permit, renterSignature);
console.log("Operator set:", tx.hash);Security Model
- Validate before execute —
execute()automatically simulates first (disable withskipValidation: true) - Fail-close — Unconfigured policies reject all operations
- Runner cannot withdraw — Only owner/renter can access vault funds
- Operator expiry — Permit cannot outlast the renter's lease
Further Reading
- Integration Guide — Architecture and full integration flow
- Policy Reference — Detailed documentation for each policy
