Smart Contract Architecture
Overview
Karpous smart contracts are deployed on Base (Ethereum L2) and implement a security-first design pattern inspired by BoringVault and Maple Finance.
Contract Descriptions
Core Layer
KarpousVault
The vault is the central entry point for all deposits. It implements a passthrough-only design.
| Property | Value |
|---|---|
| Pattern | BoringVault (modified) |
| Fund Storage | NEVER - immediate forwarding |
| Ledger Address | Immutable at deployment |
| Authorization | Portal-based access control |
Key Functions:
// Forward deposit to Ledger (NO STORAGE)
function passthrough(
address from,
address token,
uint256 amount,
bytes32 depositId,
ProductType product
) external;
// Admin: authorize/revoke portals
function setPortal(address portal, bool authorized) external;
KarpousAccountant
Central configuration management for all platform parameters.
Manages:
- Lock period configurations (1/3/6/12 months)
- Boost multipliers (1.25x - 2x)
- Asset configurations (price, yield, supply caps)
- Fee settings (deposit, withdrawal, claim)
- Supported token whitelist
Key Data:
struct LockConfig {
uint40 lockSeconds; // Lock duration
uint40 boostSeconds; // Boost period
uint16 boostMultiplierBps; // Multiplier (basis points)
}
struct AssetConfig {
bool active;
uint16 baseYieldBps; // APY in basis points
uint256 currentPrice;
uint256 minDeposit;
uint256 maxSupply;
}
Portal Layer
FTokenPortalV2
Manages fractional asset token deposits and mints ERC20 fTokens.
| Feature | Description |
|---|---|
| Token Type | ERC20 (real tokens) |
| Fee | 1% deposit fee |
| Supply Cap | Per-asset maximum |
| Sale Period | Configurable start/end times |
Deposit Flow:
EarnPortal
Time-locked staking with yield boost multipliers.
| Feature | Description |
|---|---|
| Lock Periods | 1, 3, 6, 12 months |
| Boost Multiplier | 1.25x - 2x (early deposit) |
| Auto-Renewal | Optional with yield compounding |
| Grace Period | 24 hours (configurable) |
Lock Configuration:
| Duration | Lock Days | Boost Period | Boost Multiplier |
|---|---|---|---|
| 1 month | 30 | 7 days | 1.25x |
| 3 months | 90 | 7 days | 1.25x |
| 6 months | 180 | 15 days | 1.5x |
| 12 months | 365 | 30 days | 2x |
Position Structure:
struct EarnPosition {
address user;
uint128 amount;
address token;
uint8 lockDuration; // 0=1mo, 1=3mo, 2=6mo, 3=12mo
uint40 depositTime;
uint40 lockExpiry;
uint40 boostExpiry;
uint16 boostMultiplierBps;
bool withdrawn;
bool autoRenew;
uint24 gracePeriodHours;
}
DirectPurchasePortal
Whole-unit asset purchases (not fractional).
| Feature | Description |
|---|---|
| Unit Type | Whole units (1, 2, 3...) |
| Per-User Limit | Optional maximum |
| Supply Cap | Total units available |
| Fee | Variable per asset |
Withdrawal Layer
EarnWithdrawalQueue
Manages withdrawal requests with admin approval workflow.
Status Lifecycle:
Roles:
| Role | Permissions |
|---|---|
| OPERATOR | Approve/reject requests |
| SOLVER | Fulfill matured requests |
| User | Request/cancel own withdrawals |
ProductYieldQueue
Manages yield distribution and claim processing.
| Feature | Description |
|---|---|
| Update Frequency | Weekly batch |
| Claim Fee | 1% |
| Maturity Period | 1 hour |
| Per-Product | Separate tracking per asset/lock type |
Yield Flow:
Token Contracts
FToken (ERC20)
Each real-world asset has its own FToken contract.
| Property | Value |
|---|---|
| Standard | ERC20 |
| Decimals | 18 |
| Transfer Lock | Enabled by default |
| Minting | Only FTokenPortalV2 |
| Burning | Not supported (one-way) |
Access Control:
MINTER_ROLE → FTokenPortalV2 (can mint)
ADMIN_ROLE → Multisig (can toggle transfers)
Contract Interactions
Deposit Interaction
Withdrawal Interaction
Event System
All contracts emit events for backend synchronization:
Vault Events
event Passthrough(
address indexed from,
address indexed token,
uint256 amount,
bytes32 indexed depositId,
ProductType product,
uint256 timestamp
);
Portal Events
event FTokenDeposit(bytes32 indexed depositId, address indexed user, ...);
event EarnPositionCreated(bytes32 indexed positionId, address indexed user, ...);
event DirectPurchaseCompleted(bytes32 indexed purchaseId, address indexed user, ...);
Withdrawal Events
event WithdrawalRequested(bytes32 indexed requestId, ...);
event WithdrawalApproved(bytes32 indexed requestId, ...);
event WithdrawalFulfilled(bytes32 indexed requestId, ...);
Deployment Architecture
Contract Deployment Order
Configuration Steps:
1. vault.setPortal(ftokenPortal, true)
2. vault.setPortal(earnPortal, true)
3. vault.setPortal(directPurchasePortal, true)
4. Grant OPERATOR_ROLE to operators
5. Grant SOLVER_ROLE to solvers
6. Grant MINTER_ROLE to FTokenPortalV2
Network Configuration
| Network | Chain ID | Use Case |
|---|---|---|
| Base Mainnet | 8453 | Production |
| Base Sepolia | 84532 | Testnet |
Gas Optimization
Techniques Used
| Technique | Implementation |
|---|---|
| Packed Structs | uint40, uint128 for timestamps and amounts |
| EnumerableSet | Efficient iteration for active requests |
| Batch Operations | Arrays for approvals/fulfillments |
| Custom Errors | Gas-efficient error handling |
| Immutables | Ledger address, portal address |
Gas Estimates
| Operation | Gas Cost |
|---|---|
| Deposit (FToken) | ~150,000 |
| Deposit (Earn) | ~180,000 |
| Request Withdrawal | ~120,000 |
| Fulfill Withdrawal | ~80,000 per request |
| Claim Yield | ~100,000 |