Security model
How the protocol protects funds: contract controls, node attestation, the node network and what to do if you find a bug.
Testnet. The contracts are internally audited. An independent third-party audit is planned for Q2 2027. Read the controls below as implemented and internally reviewed, not independently audited. See Testnet Status.
What exists and what is planned
| Control | Status |
|---|---|
| Internal security review and testnet testing | Current |
| Timelocked upgrades behind a multisig | Current |
| Emergency pause | Current |
| Independent third-party audit | Planned for Q2 2027 |
| Formal verification of critical functions | Planned before mainnet |
| Bug bounty program | Planned, launches with mainnet (Q4 2027) |
Testing so far: 24 of 24 automated tests pass, and fuzzing has run 10,000+ iterations. Findings are on the Audits page.
The path to mainnet: third-party audit in Q2 2027, airdrop in Q3 2027, mainnet in Q4 2027, full DAO governance in Q1 2028.
Contract controls
Upgrades and admin
Today a multisig behind a timelock is the only path that can upgrade the core contracts. See Governance. The delay leaves time to review a queued action and trigger incident response if it is hostile.
Core contracts use the UUPS (Universal Upgradeable Proxy Standard) pattern. The six vaults are EIP-2535 diamonds. Their facets change through diamondCut, which only the vault owner (the MultiSigTimelock) can call.
contract ERC7540VaultBase is
Initializable,
UUPSUpgradeable,
AccessControlUpgradeable,
PausableUpgradeable,
ReentrancyGuardUpgradeable
{
function _authorizeUpgrade(address newImplementation)
internal
override
onlyRole(UPGRADER_ROLE)
{}
}
Roles
All contracts use OpenZeppelin's AccessControlUpgradeable. The holders below are the intended mainnet configuration.
| Role | Description | Holders (mainnet target) |
|---|---|---|
DEFAULT_ADMIN_ROLE | Can grant/revoke all roles | Multi-sig (3/5) |
ADMIN_ROLE | Protocol configuration | Multi-sig (3/5) |
FULFILLER_ROLE | Execute ERC-7540 fulfillments | Validator nodes |
STRATEGY_ROLE | Execute strategy operations | Oracle nodes |
UPGRADER_ROLE | Upgrade proxy contracts | Multi-sig (3/5) |
PAUSER_ROLE | Emergency pause | 2-of-3 Safe (today) |
Pause
Any address holding PAUSER_ROLE can pause a contract in an emergency. Today the 2-of-3 Safe holds the role. Pausing by Guardians or by an emergency module is planned and not deployed.
function pause() external onlyRole(PAUSER_ROLE) {
_pause();
emit ProtocolPaused(msg.sender, block.timestamp);
}
Reentrancy and input checks
Every external function that changes state uses the nonReentrant modifier. All user inputs are validated.
function requestDeposit(uint256 assets, address controller, address owner)
external
nonReentrant
returns (uint256)
{
if (assets == 0) revert ZeroAssets();
if (controller == address(0)) revert InvalidController();
if (s.paused) revert E_BREAKER();
if (!(owner == msg.sender || s.isOperator[owner][msg.sender])) revert NotAuthorized();
if (assets < s.minDeposit) revert BelowMinDeposit(); // minDeposit is 0 on all six vaults
// ...
}
ERC-7540 requests
Deposits and redemptions are asynchronous. Four checks protect them:
- Request tracking. Each request has a unique ID.
- Fulfillment delay. At least 1 hour passes before fulfillment.
- Fulfillment. A keeper with
FULFILLER_ROLEfulfils requests. VRF based validator selection is planned, not live. - No double fulfillment. Fulfilled requests are tracked onchain.
mapping(uint256 => FulfillmentRequest) public fulfillmentRequests;
mapping(bytes32 => bool) public processedRequests;
function fulfillDeposit(uint256 requestId) external onlyRole(FULFILLER_ROLE) {
FulfillmentRequest storage request = fulfillmentRequests[requestId];
require(!request.fulfilled, "Already fulfilled");
require(block.timestamp >= request.requestTime + fulfillmentDelay, "Delay not passed");
// ...
}
Users can delegate claim operations to an operator:
mapping(address => mapping(address => bool)) public isOperator;
function setOperator(address operator, bool approved) external {
isOperator[msg.sender][operator] = approved;
emit OperatorSet(msg.sender, operator, approved);
}
Node attestation
Offchain results are not trusted at face value. That covers strategy performance, TrustFingerprint updates and reward epochs. The signature, quorum and Merkle proof mechanisms below are implemented and deployed on testnet.
- Oracle signatures. An oracle key signs each result with ECDSA over the secp256k1 curve, encoded with the EIP-191
personal_signscheme. The onchain verifier recovers the signer address before it accepts the payload. - Registration. Node and AI agent registration uses the same primitive. The server issues a single use, time limited nonce. The operator signs the full message with EIP-191, which binds the wallet to the identity onchain. A captured signature cannot be replayed.
- BFT quorum. No single oracle can move capital or finalize a result. The consensus contracts require 66% of the oracle signing set to agree before an attestation is final. The quorum counts signing weight, not keys.
- Merkle reward proofs. Reward distributions are published as a Merkle root, and each operator will claim with a Merkle proof. The
MerkleRewardDistributorcontract (0xCcDB471823C4F14Ffa4814641eafDa63fb526834on Base Sepolia) will verify the proof and pay out. Rewards will be transferred from funded reward pools, with no new tokens minted. Rewards are not being paid yet. - Hardware attestation. Where a Trusted Platform Module (TPM) or equivalent secure element is available, the node client produces an attestation quote. It is signed with an RSA device key and hashed with SHA-256, which binds the node identity to trusted hardware.
- Private strategies. Sensitive strategy logic handled by a Guardian or Oracle stays inside a secure enclave. Performance can be published and verified while the strategy stays private.
None of this depends on zero knowledge proofs. Performance privacy comes from secure enclaves and threshold handling, not ZK circuits. Third-party infrastructure named elsewhere in these docs, such as external rollup or data availability providers, is not part of this attestation path.
Node network
Each tier has a job:
- Oracle: price oracle updates. Planned: ML strategy generation, strategy execution through the ATE and governance proposal creation. Today one protocol keeper submits strategies.
- Guardian: strategy backtesting (1000+ Monte Carlo simulations), risk assessment and scoring, live strategy monitoring and, once deployed, emergency pause capability.
- Validator: monitors pending deposit and redeem requests, executes fulfillments when selected by lottery, governance vote execution and data availability.
- Micro: heartbeat reporting, network health monitoring and data replication.
Network targets are 15–50 Oracle, 25–100 Guardian and 100–1,000 Validator nodes. These are illustrative, not current figures. The initial paid node sale offers 425 nodes in total, and Micro nodes are unmetered. Hardware, stake and rewards are in Node Operators.
TrustFingerprint tracks node behavior. Guardian nodes monitor for threats, and emergency protocols activate automatically when a threat is detected.
The Guardian Chamber is designed to be the protocol's security council, made up of security focused node operators. Its membership and seat counts are set by governance and are being established as the network decentralizes.
Validator selection
Today selection uses keccak(timestamp, prevrandao, nonce). A Chainlink VRF lottery is planned and not live:
function selectValidator(uint256 requestId) internal returns (address) {
// Request random number from Chainlink VRF
uint256 randomWord = vrfCoordinator.requestRandomWords(...);
// Weight by reputation and stake
uint256 totalWeight = getTotalValidatorWeight();
uint256 selection = randomWord % totalWeight;
// Find selected validator
return getValidatorByWeight(selection);
}
Selection for task assignment is weighted by each Validator's fulfillment reputation in ValidatorFulfillmentManager. A successful fulfillment raises it by 1%, a failed one lowers it by 5%. This reputation is separate from the TrustFingerprint score.
Slashing
SlashingManager sets these penalties, as a share of stake:
| Violation | Validator | Guardian | Oracle |
|---|---|---|---|
| Downtime | 1% | 2% | 3% |
| Poor performance | 0.5% | 1% | 1.5% |
| Consensus violation | 15% | 30% | 50% |
| Malicious behavior | 25% | 50% | 75% |
Downtime counts after 48 hours without a heartbeat for a Validator, 24 hours for a Guardian and 12 hours for an Oracle.
Staking enforces a minimum stake, and unstaking has a delay. The amounts and the period are in the Staking guide.
// Stake tokens
function stake(uint256 amount) external {
require(amount >= minStake, "Below minimum");
nodrToken.transferFrom(msg.sender, address(this), amount);
stakes[msg.sender] += amount;
emit Staked(msg.sender, amount);
}
// Unstake (with delay)
function unstake(uint256 amount) external {
require(stakes[msg.sender] >= amount, "Insufficient stake");
unstakeRequests[msg.sender] = UnstakeRequest({
amount: amount,
unlockTime: block.timestamp + UNSTAKE_DELAY
});
emit UnstakeRequested(msg.sender, amount);
}
Threats and mitigations
| Threat | Mitigation |
|---|---|
| Smart contract vulnerabilities | Internal review (current), formal verification, third-party audit and bug bounty (all planned) |
| Node operator fraud | TrustFingerprint scoring, slashing, Guardian monitoring |
| Market manipulation | Risk limits, circuit breakers, diversified strategies |
| Governance attacks | Timelocks, quorum requirements, emergency controls |
| Oracle manipulation | Multiple oracle sources, outlier detection, validation |
Protect yourself
- Verify the official contract addresses before you interact.
- Keep significant assets in a hardware wallet.
- Review every transaction before you sign.
- Watch the official channels for security announcements.
Report a vulnerability
- Do not disclose it publicly.
- Email [email protected] immediately. A PGP key is available on request.
- Include a detailed description, steps to reproduce, the potential impact and a suggested fix if you have one.
- Allow reasonable time for remediation.
You can also report through the #security-reports channel in Discord. Reports will be eligible for bug bounty rewards once the program launches.