Smart Contract Security
Architecture Overview
Karpous smart contracts implement a security-first design pattern derived from battle-tested DeFi protocols, specifically combining elements from BoringVault and Maple Finance.
KarpousVault (BoringVault Pattern)
Design Philosophy
The vault is intentionally minimal - approximately 100 lines of Solidity code. This extreme simplicity is a security feature:
- Fewer lines of code = fewer bugs
- No complex state = no state manipulation attacks
- Passthrough only = no fund accumulation risk
Contract Code Analysis
contract KarpousVault is Auth {
// IMMUTABLE: Cannot be changed after deployment
address public immutable LEDGER;
// Only authorized portals can trigger passthrough
mapping(address => bool) public isPortal;
function passthrough(
address from,
address token,
uint256 amount,
bytes32 depositId,
ProductType product
) external {
if (!isPortal[msg.sender]) revert UnauthorizedPortal();
// Pull from user
ERC20(token).safeTransferFrom(from, address(this), amount);
// IMMEDIATELY forward to Ledger - NO STORAGE
ERC20(token).safeTransfer(LEDGER, amount);
}
}
Security Properties
| Property | Guarantee |
|---|---|
| Fund Storage | NEVER - always 0 balance |
| Ledger Address | IMMUTABLE - set at deployment |
| Portal Authorization | Multisig controlled |
| Upgrade Risk | NONE - not upgradeable |
Attack Resistance
| Attack Type | Protection |
|---|---|
| Re-entrancy | No callbacks, immediate transfer |
| Flash Loans | No funds to borrow |
| Price Manipulation | No price dependencies |
| Admin Rug Pull | Cannot change Ledger destination |
| Contract Compromise | Empty vault = nothing to steal |
Access Control Implementation
Role-Based Access Control (RBAC)
We use OpenZeppelin AccessControl for granular permission management:
Permission Matrix
| Function | Admin | Operator | Solver | User |
|---|---|---|---|---|
| Grant Roles | Y | - | - | - |
| Set Configuration | Y | - | - | - |
| Approve Withdrawals | - | Y | - | - |
| Update Prices | - | Y | - | - |
| Fulfill Withdrawals | - | - | Y | - |
| Fulfill Claims | - | - | Y | - |
| Request Withdrawal | - | - | - | Y |
| Request Claim | - | - | - | Y |
| Deposit | - | - | - | Y |
Reentrancy Protection
Implementation
All state-modifying functions use ReentrancyGuard:
Protected Functions
| Contract | Protected Functions |
|---|---|
| FTokenPortal | deposit() |
| FTokenPortalV2 | deposit() |
| EarnPortal | deposit() |
| DirectPurchasePortal | purchase() |
| EarnWithdrawalQueue | requestWithdrawal(), cancelWithdrawal(), fulfillWithdrawals() |
| ProductYieldQueue | requestClaim(), fulfillClaims() |
| YieldClaimQueue | requestClaim(), fulfillClaims() |
Time-Lock Mechanisms
Maturity Periods
All sensitive operations include mandatory waiting periods:
Purpose
| Attack Type | Mitigation |
|---|---|
| Flash Loan Attacks | Cannot borrow and withdraw in same tx |
| MEV Exploitation | Time window reduces profitability |
| Rushed Approvals | Forces manual review period |
| Social Engineering | Time for detection and response |
Configuration
| Operation | Maturity Period | Rationale |
|---|---|---|
| Withdrawal | 1 minute | Flash attack prevention |
| Yield Claim | 1 hour | Higher security for yields |
| Auto-Renewal | 24 hours grace | User opt-out window |
Withdrawal Security Model
Maple Finance-Inspired Approval Flow
Why This Design?
- Human Review: Every withdrawal is manually reviewed
- No Direct Contract Access: Solver pays from own wallet (refilled from Ledger)
- Cancellation Option: Users can cancel pending requests
- Batch Efficiency: Multiple fulfillments in single transaction
Supply Cap Protection
Asset Supply Limits
Each asset has a maximum supply cap to prevent over-concentration:
struct AssetConfig {
bool active;
uint16 baseYieldBps;
uint256 currentPrice;
uint256 minDeposit;
uint256 maxSupply; // Maximum USDT that can be deposited
}
Input Validation
Comprehensive Checks
Error Handling
Custom errors for gas efficiency and clarity:
error InvalidLedgerAddress();
error UnauthorizedPortal();
error ZeroAmount();
error TokenNotSupported();
error AssetNotActive();
error AssetSupplyCapExceeded();
error PositionNotUnlocked();
error PositionAlreadyWithdrawn();
error NotPositionOwner();
Event Logging
Comprehensive Audit Trail
All significant actions emit events for off-chain tracking:
Dependency Security
Trusted Libraries
| Library | Version | Purpose | Audit Status |
|---|---|---|---|
| Solmate | 6.x | Gas-optimized primitives | Extensively reviewed |
| OpenZeppelin | 5.x | Access control, utilities | Formally audited |
Minimal Dependencies
We deliberately minimize dependencies to reduce supply chain risk:
- No complex DeFi integrations
- No oracle dependencies for core functions
- No upgradeable proxy patterns for vault
Testing Coverage
Test Statistics
| Metric | Value |
|---|---|
| Total Tests | 211 |
| Passing | 211 (100%) |
| Coverage | Core functions fully tested |
Test Types
| Type | Description | Count |
|---|---|---|
| Unit Tests | Individual function testing | 150+ |
| Integration Tests | Full flow testing | 40+ |
| Edge Cases | Boundary conditions | 20+ |
Tested Scenarios
- Normal deposit/withdrawal flows
- Lock period expiration
- Access control violations
- Reentrancy attempts
- Supply cap enforcement
- Fee calculations
- Auto-renewal mechanics