DeFi Position Yield View Implementation in Mobile Wallet
DeFi positions — liquidity in Uniswap v3, staking in Lido, lending in Aave — each protocol has its smart contracts, its methods of calculating yield and its logic for determining current balance. Aggregating this into a single "your positions" screen without a ready aggregator is complex: need protocol contract addresses, ABI interfaces, APY calculation formulas.
Data Sources for DeFi Positions
DeFi Llama API — free protocol aggregator. Endpoint /tvl/{protocol} returns TVL, /yields — current APY by pools. Good for market data, but doesn't give specific address positions.
Zapper API / Zerion API — portfolio aggregators. One request with wallet address returns all DeFi positions across supported protocols with current balance and P&L. Zerion supports 400+ protocols on 10+ networks. Paid but save a month of development.
Direct smart contract calls via eth_call — for specific protocols or custom data not in aggregators.
Read Position Directly from Contract: Aave v3
For Aave v3, main contract is UiPoolDataProviderV3. One eth_call returns all data on all user reserves:
// Call via web3dart
final contract = DeployedContract(
ContractAbi.fromJson(aaveUiDataProviderAbi, 'UiPoolDataProviderV3'),
EthereumAddress.fromHex('0x91c0eA31b49B69Ea18607702c5d9aC360bf3dE7d'), // Ethereum mainnet
);
final result = await ethClient.call(
contract: contract,
function: contract.function('getUserReservesData'),
params: [
EthereumAddress.fromHex(poolAddressProvider), // Aave pool address provider
EthereumAddress.fromHex(userAddress),
],
);
// result[0] — List<UserReserveData>: token, currentATokenBalance, currentVariableDebt, ...
UserReserveData structure contains currentATokenBalance (deposited amount with accrued interest) and currentVariableDebt (variable debt). APY calculated from reserve liquidityRate via formula APY = (1 + liquidityRate/10^27 / secondsPerYear)^secondsPerYear - 1.
Uniswap v3: Positions with Price Range
Uniswap v3 is more complex because each position is an NFT with individual concentrated liquidity range. NFT positions stored in NonfungiblePositionManager (address 0xC36442b4a4522E871399CD717aBDD847Ab11FE88 on mainnet).
To get user positions:
-
balanceOf(userAddress)— number of NFT positions -
tokenOfOwnerByIndex(userAddress, index)— token IDs for each position -
positions(tokenId)— position parameters: token0/token1, fee tier, tickLower, tickUpper, liquidity
Current amount of token0/token1 from liquidity and current sqrtPriceX96 — non-trivial math per Uniswap v3 whitepaper formulas. Better to use ready @uniswap/v3-sdk on JS via WebView bridge or port formulas to Dart/Kotlin/Swift.
Easier: Uniswap Subgraph on The Graph returns position with already calculated collectedFeesToken0, collectedFeesToken1, depositedToken0, depositedToken1.
Calculating P&L on DeFi Position
P&L = (current position value in USD) - (initially invested value in USD)
Hidden pitfall: impermanent loss. If invested 1 ETH + 1000 USDC in Uniswap v3 pool and ETH rose — pool will have less ETH and more USDC. Simply comparing current balance to initial in USD isn't enough — need to account for IL relative to hold strategy.
For displaying P&L to user: show "fees earned" separately from "price change of underlying assets" — clearer than single P&L number.
Data Update and Caching
DeFi data changes every block (~12 seconds on Ethereum). Requesting on every screen open is sufficient, pull-to-refresh is standard UX pattern. Cache with 60 second TTL: users don't expect real-time precision for lending.
For staking positions with slow yield accumulation (Lido stETH) — locally calculate accumulated yield by current APY and time since last update, show optimistic estimate without extra requests.
Scope of Work
- Data source selection and integration (aggregators or direct contracts)
- Position display for priority protocols (Aave, Uniswap, Compound, Lido etc.)
- Current balance and APY calculation
- Fees earned and P&L display
- Caching with proper TTL
- Multi-network support (Ethereum, Arbitrum, Optimism, Base)
Timeframe
Aggregator integration (Zerion/Zapper) with position display: 1–2 weeks. Direct 3–5 protocol integration with custom P&L calculation: 4–6 weeks. Cost calculated individually.







