What is the Optimizer?
The Giza Optimizer is a stateless service that calculates optimal capital allocation across DeFi lending protocols. It analyzes current APRs, gas costs, and constraints to determine the best distribution of capital for maximum net returns.
How It Works
Two Integration Patterns
1. Automatic (Agentic)
Agents use the optimizer automatically:
// You just activate the agent
await giza . agent . activate ({
wallet: smartAccountAddress ,
origin_wallet: userWallet ,
initial_token: USDC_ADDRESS ,
selected_protocols: [ 'aave' , 'compound' , 'moonwell' ],
});
// Agent internally calls optimizer, then executes the plan
Behind the scenes:
Agent calls optimizer with current allocations
Optimizer returns optimal allocation + action plan
Agent executes the rebalancing transactions
Repeat on regular optimization cycles
2. Manual (IaaS)
Call the optimizer directly for custom implementations:
const result = await giza . optimizer . optimize ({
chainId: Chain . BASE ,
total_capital: "1000000000" , // 1000 USDC (6 decimals)
token_address: USDC_ADDRESS ,
current_allocations: {
aave: "500000000" ,
compound: "500000000"
},
protocols: [ "aave" , "compound" , "moonwell" , "seamless" ],
});
console . log ( 'Optimal allocation:' , result . optimization_result . allocations );
console . log ( 'Action plan:' , result . action_plan );
console . log ( 'Execution calldata:' , result . calldata );
Use this for:
Partners with existing execution infrastructure
Custom rebalancing schedules and strategies
Integration with your own capital management systems
Full control over execution while leveraging Giza’s optimization intelligence
Stateless Design
The optimizer is completely stateless :
✅ No storage of historical data
✅ Each call is independent
✅ Same inputs always return same outputs (for same market conditions)
✅ No side effects
✅ Can be called from anywhere
This stateless design enables:
Predictable : Results depend only on inputs
Testable : Easy to unit test scenarios
Composable : Integrate with any system
Scalable : No state to manage
Private : Giza doesn’t store your data
IaaS-Ready : Perfect for Intelligence as a Service consumption
Required Parameters
Chain to optimize for (Base or Arbitrum)
Total capital to allocate (bigint as string, in token’s smallest unit) Example: "1000000000" for 1000 USDC (6 decimals)
Token to optimize (e.g., USDC address)
current_allocations
Record<string, string>
required
Current distribution across protocols (bigint as string) Example: {
aave : "500000000" ,
compound : "300000000" ,
moonwell : "200000000"
}
Protocols to consider in optimization Example: ["aave", "compound", "moonwell", "seamless"]
Optional Parameters
Constraints to respect during optimization Example: [
{
kind: WalletConstraints . MIN_PROTOCOLS ,
params: { min_protocols: 2 }
},
{
kind: WalletConstraints . MAX_AMOUNT_PER_PROTOCOL ,
params: { max_amount: "5000000000" }
}
]
Optimizer Output
Optimization Result
interface OptimizationResult {
// Optimal allocation for each protocol
allocations : ProtocolAllocation [];
// Total gas costs for rebalancing
total_costs : number ;
// Initial weighted APR (before optimization)
weighted_apr_initial : number ;
// Final weighted APR (after optimization)
weighted_apr_final : number ;
// Improvement in APR (percentage points)
apr_improvement : number ;
}
Example:
{
allocations : [
{
protocol: "moonwell" ,
allocation: "450000000" ,
apr: 8.5
},
{
protocol: "aave" ,
allocation: "350000000" ,
apr: 7.2
},
{
protocol: "compound" ,
allocation: "200000000" ,
apr: 6.8
}
],
total_costs : 0.45 , // USD
weighted_apr_initial : 7.1 ,
weighted_apr_final : 7.8 ,
apr_improvement : 0.7 // +0.7% APR
}
Action Plan
Step-by-step instructions to achieve the optimal allocation:
interface ActionDetail {
action_type : 'deposit' | 'withdraw' ;
protocol : string ;
amount : string ;
underlying_amount ?: string ; // For withdrawals
}
Example:
[
{
action_type: "withdraw" ,
protocol: "compound" ,
amount: "300000000" ,
underlying_amount: "301234567" // Amount + accrued interest
},
{
action_type: "deposit" ,
protocol: "moonwell" ,
amount: "450000000"
},
{
action_type: "deposit" ,
protocol: "aave" ,
amount: "100000000"
}
]
Execution Calldata
Ready-to-execute transaction data:
interface CalldataInfo {
contract_address : string ; // Target contract
function_name : string ; // Function to call
parameters : string []; // ABI-encoded parameters
value : string ; // Native token value (usually "0")
protocol : string ; // Protocol name
description : string ; // Human-readable description
}
Example:
[
{
contract_address: "0xCompoundComet..." ,
function_name: "withdraw" ,
parameters: [ "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" , "300000000" ],
value: "0" ,
protocol: "compound" ,
description: "Withdraw 300 USDC from Compound"
},
{
contract_address: "0xMoonwellMarket..." ,
function_name: "supply" ,
parameters: [ "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" , "450000000" ],
value: "0" ,
protocol: "moonwell" ,
description: "Deposit 450 USDC to Moonwell"
}
]
Optimization Algorithm
Factors Considered
Real-time APRs from each protocol for the specific token. Weighted by allocation size.
Estimated gas for each rebalancing transaction. Optimization only proceeds if APR improvement exceeds gas costs.
Available liquidity in each protocol. Won’t allocate more than what the protocol can efficiently handle.
Price impact of large deposits/withdrawals, especially for smaller protocols.
User-defined constraints (min protocols, max per protocol, exclusions, etc.).
Prefer fewer, larger transactions over many small ones to save gas.
Optimization Goals
The optimizer uses a constraint-based optimization approach:
Fetch Data : Get current APRs, gas prices, liquidity
Apply Constraints : Filter out invalid allocations
Calculate Scores : Score each possible allocation
Select Optimal : Choose highest net return allocation
Generate Plan : Create minimal set of transactions
Validate : Ensure plan respects all constraints
Constraints
Available Constraint Types
enum WalletConstraints {
MIN_PROTOCOLS = 'min_protocols' ,
MAX_ALLOCATION_AMOUNT_PER_PROTOCOL = 'max_allocation_amount_per_protocol' ,
MAX_AMOUNT_PER_PROTOCOL = 'max_amount_per_protocol' ,
MIN_AMOUNT = 'min_amount' ,
EXCLUDE_PROTOCOL = 'exclude_protocol' ,
MIN_ALLOCATION_AMOUNT_PER_PROTOCOL = 'min_allocation_amount_per_protocol' ,
}
Constraint Examples
Min Protocols
Max Per Protocol
Max Specific Protocol
Exclude Protocol
Min Amount
{
kind : WalletConstraints . MIN_PROTOCOLS ,
params : { min_protocols : 2 }
}
// Always diversify across at least 2 protocols
Combining Constraints
await giza . optimizer . optimize ({
chainId: Chain . BASE ,
total_capital: "10000000000" , // 10k USDC
token_address: USDC_ADDRESS ,
current_allocations: { aave: "10000000000" },
protocols: [ "aave" , "compound" , "moonwell" , "seamless" ],
constraints: [
// Diversify
{
kind: WalletConstraints . MIN_PROTOCOLS ,
params: { min_protocols: 3 }
},
// Cap newer protocols
{
kind: WalletConstraints . MAX_ALLOCATION_AMOUNT_PER_PROTOCOL ,
params: { protocol: "seamless" , max_amount: "2000000000" }
},
// Avoid dust allocations
{
kind: WalletConstraints . MIN_AMOUNT ,
params: { min_amount: "500000000" }
}
]
});
Using the Optimizer
Basic Usage
import { GizaAgent , Chain , WalletConstraints } from '@giza/agent-sdk' ;
const giza = new GizaAgent ({ chainId: Chain . BASE });
const result = await giza . optimizer . optimize ({
chainId: Chain . BASE ,
total_capital: "1000000000" ,
token_address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" ,
current_allocations: {
aave: "600000000" ,
compound: "400000000"
},
protocols: [ "aave" , "compound" , "moonwell" ],
});
console . log ( `APR improvement: + ${ result . optimization_result . apr_improvement } %` );
console . log ( `From ${ result . optimization_result . weighted_apr_initial } % to ${ result . optimization_result . weighted_apr_final } %` );
console . log ( `Actions needed: ${ result . action_plan . length } ` );
console . log ( `Gas cost: $ ${ result . optimization_result . total_costs } ` );
// Execute the plan (if using IaaS)
for ( const calldata of result . calldata ) {
console . log ( `Execute: ${ calldata . description } ` );
// Send transaction to calldata.contract_address
// Call calldata.function_name with calldata.parameters
}
Dry Run Scenarios
Test different scenarios without executing:
// Scenario 1: Current allocation
const current = await giza . optimizer . optimize ({
chainId: Chain . BASE ,
total_capital: "1000000000" ,
token_address: USDC_ADDRESS ,
current_allocations: { aave: "1000000000" },
protocols: [ "aave" , "compound" , "moonwell" ],
});
// Scenario 2: Add more protocols
const expanded = await giza . optimizer . optimize ({
chainId: Chain . BASE ,
total_capital: "1000000000" ,
token_address: USDC_ADDRESS ,
current_allocations: { aave: "1000000000" },
protocols: [ "aave" , "compound" , "moonwell" , "seamless" , "fluid" ],
});
// Compare
console . log ( `Current APR: ${ current . optimization_result . weighted_apr_final } %` );
console . log ( `With more protocols: ${ expanded . optimization_result . weighted_apr_final } %` );
console . log ( `Potential gain: + ${ expanded . optimization_result . weighted_apr_final - current . optimization_result . weighted_apr_final } %` );
Best Practices
Calling the optimizer too frequently wastes gas. Let APR differences accumulate before rebalancing. Good: Every 6-24 hours
Bad: Every 5 minutes
Set minimum APR improvement threshold
Only rebalance if APR improvement exceeds a threshold (e.g., 0.3%). if ( result . optimization_result . apr_improvement > 0.3 ) {
// Execute rebalancing
}
Use constraints for risk management
Always set constraints to match your risk tolerance and diversification requirements.
During high gas periods, higher APR improvement may be needed to justify rebalancing.
Next Steps