Sei uno sviluppatore che vuole costruire una dApp con liquidità decentrata o prestiti on‑chain. Conosci già Solidity e sai interagire con una blockchain. Ma quando si tratta di implementare uno scambio automatico o un pool di prestito, ti trovi davanti a concetti come constant product formula, impermanent loss, utilization rate. Non sono solo termini da whitepaper – sono meccanismi che determinano se la tua applicazione funziona o brucia capitale.
Noi, di Meteora Web, abbiamo integrato DEX e lending pool in progetti reali per clienti. Abbiamo visto cosa fanno gli smart contract quando vengono stressati da liquidazioni e arbitraggi. E come sviluppatore, devi saperlo prima di scrivere una riga di codice.
Cosa sono i liquidity pool e come funzionano realmente?
Partiamo dal cuore: un liquidity pool è un insieme di token bloccati in uno smart contract che consente scambi automatici. Nessun order book, nessuna controparte. La formula che regola il prezzo è la constant product market maker (CPMM): x * y = k. Semplice, elegante, ma con conseguenze precise per chi sviluppa.
La formula che non puoi ignorare
Immagina un pool ETH/USDC con 100 ETH e 200.000 USDC. k = 100 * 200.000 = 20.000.000. Un trader compra 10 ETH. Il pool deve mantenere k costante, quindi la quantità di USDC aumenta. Il prezzo dopo lo scambio è dato da prezzo = x / y (dopo l'aggiornamento delle riserve). Ecco la mutazione in JavaScript con ethers.js:
const { ethers } = require("ethers");
async function calculateOutput(reserveIn, reserveOut, amountIn) {
const amountInWithFee = amountIn.mul(997); // 0.3% fee
const numerator = amountInWithFee.mul(reserveOut);
const denominator = reserveIn.mul(1000).add(amountInWithFee);
return numerator.div(denominator);
}
// Esempio: pool ETH/USDC
const reserveEth = ethers.utils.parseEther("100");
const reserveUsdc = ethers.utils.parseUnits("200000", 6);
const amountIn = ethers.utils.parseEther("1");
const output = await calculateOutput(reserveEth, reserveUsdc, amountIn);
console.log(`Ricevi ${ethers.utils.formatUnits(output, 6)} USDC`);Errore comune da evitare: dimenticare lo 0.3% di fee. La fee finisce ai fornitori di liquidità, non al protocollo. Se stai costruendo un DEX custom, devi decidere dove va la commissione – una decisione che incide direttamente sulla sostenibilità del pool.
Sponsored Protocol
Fornire liquidità: cosa accade realmente
Quando un utente deposita token in un pool, ottiene LP token (Liquidity Provider token). Quei token rappresentano la sua quota del pool. Il prezzo degli LP token non è statico – varia con le commissioni accumulate e con le variazioni di prezzo. Ecco uno snippet per ottenere il valore di un LP token in un pool Uniswap V2:
function getLPValue(address pair, address token0, address token1) external view returns (uint256) {
IUniswapV2Pair _pair = IUniswapV2Pair(pair);
(uint112 reserve0, uint112 reserve1, ) = _pair.getReserves();
uint256 totalSupply = _pair.totalSupply();
uint256 price0 = getPrice(token0); // da un oracolo esterno
uint256 price1 = getPrice(token1);
return (reserve0 * price0 + reserve1 * price1) / totalSupply;
}Operativo: la prossima volta che interagisci con un DEX su testnet, prendi un pair come WETH / USDC su Sepolia, chiama getReserves e calcola il prezzo medio. Vedrai lo spread tra il prezzo di previsione della formula e quello di mercato – è lì che si annida l'arbitraggio.
Sponsored Protocol
Come uno sviluppatore può interagire con un protocollo di lending?
I protocolli di lending (Aave, Compound) permettono di depositare un asset come garanzia e prendere in prestito un altro. Il meccanismo si basa su tre parametri: loan‑to‑value (LTV), liquidation threshold e health factor. Se il health factor scende sotto 1, lo smart contract liquida la posizione.
Depositare e prendere a prestito con Aave V3
L'interazione avviene via Pool contract. Ecco un esempio con ethers.js:
const poolAddress = "0x...AaveV3Pool";
const pool = new ethers.Contract(poolAddress, AAVE_POOL_ABI, signer);
// Depositare 10 ETH (come aEthWETH)
const amountDeposit = ethers.utils.parseEther("10");
await pool.supply("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", amountDeposit, userAddress, 0);
// Prendere a prestito USDC fino al 75% del LTV (esempio)
const amountBorrow = ethers.utils.parseUnits("7500", 6); // 7500 USDC
await pool.borrow("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", amountBorrow, 2, 0, userAddress);Attenzione: il parametro referralCode (0 per default) e interestRateMode (1 = stable, 2 = variable). Noi consigliamo sempre l'interesse variabile a meno di contratti fissi – il tasso stabile può diventare penalizzante se il mercato sale.
Leggere i tassi di interesse in tempo reale
Il PoolDataProvider di Aave espone getReserveData. Con questo puoi calcolare il tasso di fornitura e di prestito corrente.
Sponsored Protocol
const dataProvider = new ethers.Contract(providerAddress, DATA_PROVIDER_ABI, provider);
const reserveData = await dataProvider.getReserveData(usdcAddress);
console.log(`Utilization rate: ${reserveData.utilizationRate}`);
console.log(`Borrow rate variable: ${reserveData.variableBorrowRate}`);Perché importa: il tasso di utilizzazione (utilization = totalBorrows / totalSupply) determina i tassi. Quando la domanda sale, i tassi salgono. Se stai costruendo un frontend per un lending pool, devi mostrare in tempo reale questi dati – non fare mai cache di più di 15 secondi.
Quali sono i rischi concreti di una liquidity pool e come mitigarli?
Due rischi principali: impermanent loss (IL) e slippage.
Impermanent loss: quando la volatilità del pool ti mangia i profitti
L'IL si verifica quando il prezzo relativo dei due asset cambia rispetto al momento del deposito. Più volatile la coppia, più alto l'IL. La formula per calcolare la perdita percentuale in funzione del cambio di prezzo è:
IL = 2 * sqrt(priceRatio) / (1 + priceRatio) - 1Dove priceRatio = newPrice / oldPrice. Se il prezzo raddoppia (priceRatio = 2), IL = 5,7%. Se quadruplica (priceRatio = 4), IL = 20%.
Errore comune da evitare: molti sviluppatori ignorano l'IL quando progettano pool a bassa volatilità (es. stablecoin). Ma anche le stablecoin possono sganciarsi (vedi UST). Un semplice simulatore on‑chain può avvisare l'utente prima del deposito.
Slippage e front‑running
Ogni swap ha uno slippage implicito dovuto alla profondità del pool. Come sviluppatore, devi calcolare lo slippage stimato e permettere all'utente di impostare un limite. Ecco come farlo in un frontend:
Sponsored Protocol
// Stimato da quote di Uniswap
const amountOut = await pair.getAmountOut(amountIn);
const slippageLimit = 0.01; // 1%
const minAmountOut = amountOut.mul(100 - slippageLimit * 100).div(100);
// E poi nella transazione
await pair.swap(amountIn, minAmountOut, to, bytes);Operativo: implementa un controllo di minAmountOut in ogni funzione di swap. Senza, il tuo contratto è vulnerabile a front‑running che ruba lo slippage.
Come misurare il rendimento di un liquidity pool o di un prestito?
Non ti puoi fermare al tasso nominale. Devi calcolare il rendimento effettivo considerando commissioni, frequenza di reinvestimento e IL.
APY di un pool con reinvestimento automatico
I pool con fee automatiche (es. Uniswap V3) richiedono il calcolo del rendimento composto. In Solidity puoi usare il modello di interesse continuo:
function calculateAPY(uint256 feePerBlock, uint256 totalLiquidity, uint256 blocksPerYear) external pure returns (uint256) {
// feePerBlock = commissioni accumulate in un blocco
uint256 growthPerBlock = (totalLiquidity + feePerBlock) * 1e18 / totalLiquidity;
// compound annual
uint256 result = _pow(growthPerBlock, blocksPerYear);
return result - 1e18;
}Nota: questo è un calcolo semplificato. La realtà include variazioni di volume, IL e fee variabili. Per una stima realistica, integra un oracolo come Chainlink che fornisce il volume storico.
Sponsored Protocol
Rendimento di un prestito: supply vs borrow spread
Se stai fornendo liquidità a un lending pool, il tuo APY è il supply APY. Se stai prendendo a prestito, paghi il borrow APY. Lo spread è il margine del protocollo. Per calcolare il tuo effettivo rendimento come fornitore:
effetiveAPY = supplyAPY * (1 - utilizationRate * reserveFactor)Dove reserveFactor è la percentuale trattenuta dal protocollo (es. 10%).
Operativo: usa un dashboard come DeFiLlama per confrontare gli APY reali di pool e pool di lending. Ma scrivi anche un piccolo script che ogni ora si connette al contratto e salva i tassi – così puoi fare analisi storiche per il tuo progetto.
Cosa fare adesso
- Simula su testnet: scegli Sepolia, deploy di un pool Uniswap V2 fittizio (usa il factory di test) e interagisci via ethers.js. Calcola output, slippage e IL.
- Leggi il whitepaper di Aave V3: capisci la struttura degli interest rate curves e come influenzano la liquidazione. Documentazione ufficiale.
- Integra un oracolo: per ottenere prezzi reali nel tuo smart contract, usa Chainlink Data Feeds. Non usare mai price pool interni (susceptibili a manipolazione).
- Audita i tuoi contratti: se stai scrivendo uno smart contract custom per liquidity pool o lending, noleggia un revisore professionale. Un bug nella formula
x * y = kpuò cancellare milioni.
Noi, di Meteora Web, abbiamo accompagnato sviluppatori in questi passaggi. Se vuoi approfondire l'intero ecosistema, leggi la nostra pillar su Blockchain e Web3. La DeFi non è un gioco – è finanza programmabile. Trattala con la serietà che merita.