Smart Contract Security
Noderr Protocol implements multiple layers of security to protect user funds and ensure protocol integrity.
Security Architecture
Access Control
All contracts use OpenZeppelin's AccessControlUpgradeable with role-based permissions:
| Role | Description | Holders |
|---|---|---|
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 | Governance contract (GovernanceManager) |
Multi-Signature Requirements
Critical operations require multi-sig approval:
- Contract Upgrades: 3/5 signatures
- Parameter Changes: 2/5 signatures
- Emergency Pause: Any address holding
PAUSER_ROLE(granted toGovernanceManagercontract at deployment) - Unpause: 3/5 signatures via MultiSigTimelock
Upgradeability
Contracts use the UUPS (Universal Upgradeable Proxy Standard) pattern:
contract ERC7540VaultBase is
Initializable,
UUPSUpgradeable,
AccessControlUpgradeable,
PausableUpgradeable,
ReentrancyGuardUpgradeable
{
function _authorizeUpgrade(address newImplementation)
internal
override
onlyRole(UPGRADER_ROLE)
{}
}
Security Features
Reentrancy Protection
All external functions that modify state use nonReentrant modifier:
function deposit(uint256 assets, address receiver)
external
nonReentrant
whenNotPaused
returns (uint256 shares)
{
// ...
}
Pausability
Contracts can be paused in emergencies:
function pause() external onlyRole(PAUSER_ROLE) {
_pause();
emit ProtocolPaused(msg.sender, block.timestamp);
}
Input Validation
All user inputs are validated:
function requestDeposit(uint256 assets, address receiver, address owner)
external
returns (uint256 requestId)
{
require(assets >= minDeposit, "Below minimum deposit");
require(assets <= maxDeposit, "Exceeds maximum deposit");
require(receiver != address(0), "Invalid receiver");
require(owner != address(0), "Invalid owner");
// ...
}
Slippage Protection
Vault operations include slippage protection:
function withdraw(
uint256 assets,
address receiver,
address owner,
uint256 maxSharesBurned
) external returns (uint256 shares) {
shares = previewWithdraw(assets);
require(shares <= maxSharesBurned, "Slippage exceeded");
// ...
}
ERC-7540 Security
Async Operation Safety
The ERC-7540 implementation includes:
- Request Tracking: Each request has unique ID
- Fulfillment Delay: Minimum 1-hour delay before fulfillment
- Validator Selection: Chainlink VRF for fair selection
- Double-Fulfillment Prevention: On-chain tracking
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");
// ...
}
Operator Permissions
Users can delegate claim operations to operators:
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);
}
Audit Status
Testnet (Current)
- Internal security review: β Complete
- Automated testing: β 24/24 tests passing
- Fuzzing: β 10,000+ iterations
Mainnet (Planned)
- Third-party audit: π Scheduled Q3-Q4 2026
- Bug bounty program: π Launch with mainnet
- Formal verification: π Critical functions
Bug Bounty Program
Coming with Mainnet Launch
| Severity | Reward |
|---|---|
| Critical | $50,000 - $100,000 |
| High | $10,000 - $50,000 |
| Medium | $2,500 - $10,000 |
| Low | $500 - $2,500 |
Security Contacts
- Security Email: [email protected]
- Bug Reports:https://github.com/Noderrxyz/noderr-protocol/security
- Discord: #security-reports channel
Known Limitations
- Testnet Only: Current deployment is on Base Sepolia testnet
- Single Admin Key: Testnet uses single admin for convenience (multi-sig for mainnet)
- No Formal Verification: Planned for mainnet critical paths
Last Updated: December 2025