Contract Reference
Solidity sources live in the contracts/ folder of the monorepo. Built with Foundry + OpenZeppelin; the V4 line uses a frozen toolchain (solc 0.8.36, optimizer_runs = 50, evm_version = cancun, via_ir = true) so the CREATE2 addresses stay deterministic.
Deployed addresses
Deterministic CREATE2 — the factories and both registries have the same address on every network:
| Contract | Address |
|---|---|
BVCCSmartWalletFactoryV4 | 0xfd105197109244483b5f870501326E6faec9F93c |
BVCCAgentWalletFactoryV4 | 0xf3A61F9d64d45362E149A111289546523BCd26a6 |
BVCCValidatorRegistry | 0x5e371D54AC97a57B0a99145Ed04A3c9fA07850C2 |
BVCCHookRegistry | 0x551C6e7ABdA04a110790888e711198f25621b066 |
| EntryPoint (OpenZeppelin v0.9) | 0x433709009B8330FDa32311DF1C2AFA402eD8D009 |
Live on Arbitrum One, Base, BNB Chain, Ethereum, Polygon and Arbitrum Sepolia (testnet). The per-chain validators (BVCCUniversalRouterValidator, BVCCPositionManagerValidator) are bound to each chain’s router / position manager, so their addresses differ per network — see the monorepo’s contracts/deployments/. Previous V2 factories (0x230b…BdEf1 / 0x8D9e…054c) are deprecated.
BVCCSmartWalletV4 — personal wallet (walletType 0)
One contract per user, deployed by the factory. No proxies, no upgradability.
- ●Signer: WebAuthn / P-256 public key (passkey), fixed at deployment. Every
execute()is authenticated via ERC-4337 UserOp signature validation. - ●Execution: ERC-7821 batched execution (
execute(bytes32 mode, bytes executionData)withExecution[]batches). - ●Fee: 0.05% per operation to the BVCC fee wallet (
0x3e3eb089169a7315a994947465ce5f5FC3A307D4), three cases — (1) ETH send: fee deducted from the sent value; (2) ERC-20 transfer: fee charged on top, the wallet must holdamount + fee; (3) DeFi/swap: balance snapshot before/after, fee on detected token balance increases. - ●Recovery: 3 guardian addresses, set once at creation. Replacing the WebAuthn signer requires 2-of-3 guardian signatures + a 48-hour timelock. Recovery functions bypass
execute()and pay no fee.
BVCCAgentWalletV4 — AI agent wallet (walletType 1)
Extends BVCCSmartWalletV4; adds delegated execution for authorized agent EOAs. Fee is 0.15%. On top of the whitelists below, V3 introduced per-selector call policies for DeFi calls (see Call policies).
AuthorizeParams (input to authorizeAgent)
| Field | Type | Meaning (`0` = unlimited/disabled) |
|---|---|---|
agent | address | agent EOA (must have no code) |
maxPerTxWei | uint128 | max ETH per single Execution item |
dailyLimitWei | uint128 | max ETH per UTC day |
totalBudgetWei | uint128 | lifetime ETH budget |
periodBudgetWei | uint128 | max ETH per rolling period |
periodDuration | uint64 | period length in seconds |
expiry | uint64 | unix timestamp; agent disabled after |
allowedTokens | address[] | ERC-20 whitelist; empty = deny all token ops |
tokenMaxAmounts | uint128[] | parallel: token cap per batch |
tokenDailyLimits | uint128[] | parallel: token cap per UTC day |
tokenTotalBudgets | uint128[] | parallel: lifetime token budget |
allowedProtocols | address[] | DeFi target whitelist; empty reverts (NoProtocolsWhitelisted) |
allowedRecipients | address[] | unified destination whitelist (ETH recipients, token recipients, approve spenders); empty = allow any |
Whitelists max 20 entries each. The four token arrays must have equal length.
Owner functions (callable only via the wallet’s own execute(), i.e. biometrics / WebAuthn)
Agent functions
See the Agent Integration Guide for call encoding, validation order and error reference.
Call policies
For DeFi calls (case 3), whitelisting a protocol in allowedProtocols is necessary but no longer sufficient: the call’s selector must also have a policy registered by the owner, or it reverts with SelectorNotAllowed. A policy is a packed uint256:
- ●PIN_WALLET — a fixed calldata word must equal the wallet (recipient at a known offset: SwapRouter02, Aave Pool supply/withdraw/borrow/repay). A mismatch reverts with
PinnedArgMismatch. - ●PIN_PROTOCOL — a calldata word must be an already-whitelisted protocol (e.g. the spender in
Permit2.approve). - ●DEEP — defers to the on-chain validator registry, which decodes variable-length calldata and checks every recipient (Universal Router
execute, v4 PositionManagermodifyLiquidities). Fail-closed: no validator, false, or a revert denies the call (PolicyValidationFailed).
Allowing a validator is timelocked 48h; denying one is immediate. The biometric owner is never subject to call policies — they apply only to agents. Policies are set with setCallPolicy, usually bundled into the same biometric signature that authorizes the agent.
Getters
Factories
Both factories share the same shape:
- ●Deterministic address: salt =
keccak256(abi.encode(pubKeyX, pubKeyY))— derived only from the passkey’s P-256 public key. Same key → same wallet address on every network. Guardians don’t affect the address: the factory only deploys, and the owner registers them afterwards withsetGuardians, callable only by the wallet itself (a passkey-signed self-call). Whoever deploys an address therefore cannot choose who can rotate its owner. The set is replaceable by the owner, except while a recovery is in flight. - ●Counterfactual:
getWalletAddressis a view — you can receive funds at the address before deploying. - ●Idempotent:
createWalletreturns the existing wallet if already deployed. - ●Kill switch:
kill()stops new creations only; existing wallets are independent contracts and keep working with their funds. - ●V4 addresses differ from V3: the wallet bytecode changed, so the same passkey resolves to a different address. V3 users recreate their wallet and move funds (same playbook as every generation before). The app shows a banner on wallets that are behind.
Registries & validators
- ●
BVCCValidatorRegistry— fixed dispatch point, compiled as a constant inside the wallet so a forged validator can’t be injected. Maps a protocol target to its validator. - ●
BVCCUniversalRouterValidator/BVCCPositionManagerValidator— per-chain, each bound to that chain’s router / position manager; addresses differ per network (seecontracts/deployments/). - ●
BVCCHookRegistry— allowlist of approved Uniswap v4 hooks, gated by the same 48h governance. - ●
IBVCCValidator— the sharedvalidate(...)view interface. It is an interface, not a deployed contract; the concrete validators implement it and are staticcalled fail-closed.
Security notes
- ●Internal security review, bilingual report in the monorepo’s
audits/folder and linked from these docs. Four review rounds so far, thirteen findings with identifiers (BVCC-01…BVCC-13): 2 critical, 3 high, 5 medium, 1 low, 2 informational. Nine are remediated and live on all six networks — including a cross-function reentrancy that let a compromised agent bypass every limit, and guardian squatting through the factory. Four stay open or accepted by decision, each documented with its mitigation; the one that should change your behaviour isBVCC-03. The V4 suite is 312 Foundry tests (unit, fork & fuzz). No independent party has audited this code. - ●V2 (June 2026) fixed a gas-griefing edge on Arbitrum: balance probes are capped at 100k gas (
PROBE_GAS_CAP) so calldata that happens to contain a precompile address can’t burn the transaction’s gas. V3 keeps this fix. - ●V3 (July 2026) closes an agent fund-exfiltration path: a stolen agent key could previously name its own address as the recipient/
toof a swap orPool.withdrawand move funds without touching the ETH/token budget. V3 makes case-3 calls default-deny per selector and pins the recipient to the wallet (or validates it on-chain). The owner’s biometric path is unaffected.