The Vault is an escrow contract that holds intent rewards until they can be claimed by solvers or refunded to creators. Each intent has its own dedicated vault, deployed deterministically using CREATE2 for predictable addressing.Documentation Index
Fetch the complete documentation index at: https://eco.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
Architecture
Vaults use a minimal proxy pattern (ERC-1167) for gas-efficient deployment:- One vault per intent, deployed on-demand
- Deterministic addresses computed from intent hash
- Only the Portal can manage vault operations
- No persistent state between intents (stateless implementation)
Deployment
CREATE2 Determinism
Vault addresses are computed using CREATE2 with the intent hash as salt:On-Demand Deployment
Vaults are deployed lazily when first needed:- Intent Publishing: Address is computed but not deployed
- First Funding: Vault deployed if not already exists
- Withdrawal/Refund: Vault deployed if not already exists
Chain Compatibility
The CREATE2 prefix adapts to different chains:- Standard EVM Chains:
0xffprefix - TRON Mainnet (728126428):
0x41prefix - TRON Testnet (2494104990):
0x41prefix
Access Control
- Only validated intents can withdraw funds
- Refunds require proper deadline checks
- Token recovery follows protocol rules
Funding
Standard Funding
Called duringPortal.publishAndFund() or Portal.fund():
- Check native token balance against
reward.nativeAmount - For each ERC20 token:
- Attempt permit-based transfer first (if permit contract provided)
- Fall back to standard
transferFromwith allowance
- Return true only if all tokens fully funded
- Funder’s token balance
- Funder’s allowance/permit to vault
- Existing vault balance
Permit-Based Funding
Vaults support gasless approvals via permit contracts (e.g., Permit2): Permit Transfer:approve() call.
Standard Transfer (Fallback):
transferFrom based on existing allowance.
Funding Strategy:
- Check current vault balance
- Try permit transfer if permit contract provided
- Fall back to standard transfer for any remaining amount
- Return unfunded amount
Withdrawal
Solvers claim rewards after intent fulfillment and proof verification:- Transfer all reward ERC20 tokens to claimant (up to reward amounts)
- Transfer native tokens to claimant (up to reward amount)
- Use actual balance (may be less than reward if partially funded)
- Uses
SafeERC20.safeTransferfor token transfers - Minimum of reward amount and actual balance prevents over-withdrawal
- Native transfers use low-level call with success check
- Reverts on failed native transfer with
NativeTransferFailederror
Refund
Creators reclaim rewards after intent expiry:- Transfer all ERC20 token balances to
reward.creator - Transfer all native token balance to
reward.creator - No amount restrictions (returns full vault contents)
- Returns actual balance, not limited to reward amounts
- Always transfers to
reward.creator - Portal validates deadline before calling
Token Recovery
Recover tokens mistakenly sent to vault:- User accidentally sent tokens directly to vault address
- Tokens sent to wrong vault
- Extra tokens beyond reward amounts
- Cannot recover zero address (native tokens)
- Cannot recover any token in
reward.tokensarray - Intent must have zero native rewards OR already be claimed/refunded
Fund Flow
Publishing Flow
Withdrawal Flow
Refund Flow
Security Model
Immutable Portal
The portal address is set at construction and cannot be changed:- Unauthorized withdrawals
- Fake refunds before expiry
- Bypassing protocol validation
Balance-Based Logic
All transfers use actual balance rather than storing state:- No accounting variables to manipulate
- Always transfers real tokens held by vault
- Cannot withdraw more than vault contains
SafeERC20 Integration
Uses OpenZeppelin’s SafeERC20 for all token transfers:- Handles non-standard ERC20 returns
- Prevents silent transfer failures
- Reverts on insufficient balance
Minimal Proxy Pattern
Using ERC-1167 minimal proxies provides:- Gas Efficiency: ~2,500 gas to deploy vs ~200,000 for full contract
- Security: Implementation cannot be changed after proxy deployment
- Predictability: Deterministic addresses enable pre-funding
Integration Examples
Computing Vault Address
Pre-Funding Vault
Users can send tokens directly to the computed vault address before publishing:Funded status check, so verify funding manually with portal.isIntentFunded().
Partial Funding
Using Permit for Gasless Funding
Error Handling
NotPortalCaller(address): Caller is not the authorized Portal contractNativeTransferFailed(address, uint256): Failed to send native tokens to recipientZeroRecoverTokenBalance(address): Attempted to recover token with zero balance
Gas Considerations
Deployment Costs
- Full Vault Contract: ~200,000 gas
- Minimal Proxy: ~2,500 gas (98.75% savings)
- Implementation: One-time cost, shared across all vaults
Operation Costs
Funding:- Native transfer: ~21,000 gas
- ERC20 transfer: ~50,000 gas per token
- Permit transfer: ~70,000 gas per token (includes permit verification)
- Per token: ~50,000 gas
- Native transfer: ~21,000 gas
- Similar to withdrawal costs
- No amount validation overhead
Optimization Strategies
- Batch Operations: Use
Portal.batchWithdraw()to amortize vault deployment costs - Pre-Funding: Send tokens to vault address before publishing to skip funding transaction
- Single Token Rewards: Minimize token array length in rewards
- Standard Transfers: Use regular approvals instead of permits when possible (lower gas)
Cross-Chain Considerations
Address Consistency
Vault addresses are deterministic across chains with same:- Portal deployment address
- Intent parameters (destination, route, reward)
- CREATE2 prefix (chain-specific)
Native Token Handling
Each chain’s native token is handled uniformly:- Ethereum: ETH
- Polygon: MATIC
- Arbitrum: ETH
- TRON: TRX
reward.nativeAmount.
Best Practices
For Intent Creators
- Verify Funding: Call
portal.isIntentFunded()before expecting fulfillment - Adequate Approvals: Ensure sufficient allowance for all reward tokens
- Gas Budgeting: Include native amount for destination chain execution
- Deadline Buffer: Set
reward.deadlinewith buffer for proof verification time
For Solvers
- Check Vault Balance: Verify vault is fully funded before fulfilling
- Gas Estimation: Account for withdrawal transaction costs in profitability calculations
- Claimant Address: Ensure claimant address is correct and can receive tokens
- Token Compatibility: Verify all reward tokens are standard ERC20
For Integrators
- Address Prediction: Compute vault addresses off-chain to display to users
- Event Monitoring: Watch
IntentFundedevents to track funding progress - Error Handling: Handle partial funding scenarios gracefully
- Permit Integration: Support gasless approvals for better UX
