DeFi Basics untuk Devs — Web3

DeFi Basics untuk Devs DeFi (Decentralized Finance) adalah ekosistem aplikasi keuangan yang berjalan di blockchain tanpa perantara (bank, broker). Sebagai…

DeFi (Decentralized Finance) adalah layanan keuangan (tukar token, pinjam-meminjam, menyimpan nilai) yang berjalan di smart contract, tanpa perantara terpusat yang memegang dana atau mencocokkan order. Bayangin kotak tukar di depan Toko Kaos Raka: isinya POIN dan uang mainan, dan siapa pun boleh menukar tanpa kasir. Harganya gak ditentukan orang, tapi oleh aturan tertulis di kotak itu: makin banyak POIN di kotak, makin murah POIN. Sebagai developer, kamu perlu paham aturan itu untuk memanggilnya dengan aman, dan untuk tahu kapan angka dari kotak itu gak boleh dipercaya.

🧪 Tebakan cepat: kolam berisi 10.000 POIN dan 500.000 RPU, jadi 1 POIN = 50 RPU. Dinda menjual 100 POIN. Berapa RPU yang ia terima: tepat 5.000, sedikit kurang dari 5.000, atau lebih dari 5.000? Tebak dulu, jawabannya ada di bagian "Swap pertama Dinda".

Kolam mainan di chain lokal

Semua angka di lesson ini dari chain lokal Hardhat dan token mainan: RPU (Rupiah Uji, ERC-20 OpenZeppelin, 1 RPU dianggap Rp 1) dan PoinRaka. Bukan token sungguhan, bukan saran investasi. Raka mengisi kolam dengan 10.000 POIN dan 500.000 RPU, sesuai nilai POIN di toko (100 POIN = Rp 5.000).

AMM: harga dari rumus x · y = k

AMM (Automated Market Maker) adalah algoritma yang menentukan harga token dari rasio isi liquidity pool, tanpa order book. Yang paling sederhana memakai constant product: x · y = k. x = cadangan POIN, y = cadangan RPU, dan k gak boleh turun setelah swap. Harga spot = y / x = 500.000 / 10.000 = 50 RPU per POIN. Ini inti kontraknya (rumus yang sama dipakai Uniswap v2, fee 0,3%):

function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) public pure returns (uint256) {
    uint256 inWithFee = amountIn * 997;                                 // 0,3% fee tinggal di kolam
    return (inWithFee * reserveOut) / (reserveIn * 1000 + inWithFee);
}

function jualPoin(uint256 amountIn, uint256 minOut) external returns (uint256 out) {
    out = getAmountOut(amountIn, cadanganPoin, cadanganRpu);
    if (out < minOut) revert Slippage(out, minOut);                     // perlindungan slippage
    cadanganPoin += amountIn;
    cadanganRpu -= out;
    poin.safeTransferFrom(msg.sender, address(this), amountIn);
    rpu.safeTransfer(msg.sender, out);
}

Swap pertama Dinda

await kolam.read.getAmountOut([parseUnits('100', 18), parseUnits('10000', 18), parseUnits('500000', 18)])
// 4935790171985306494252n
await kolam.write.jualPoin([parseUnits('100', 18), parseUnits('4900', 18)], { account: dinda.account })
// receipt: status 'success', gasUsed 84917n
await kolam.read.cadanganPoin() // 10100000000000000000000n
await kolam.read.cadanganRpu()  // 495064209828014693505748n

Dinda menerima 4.935,79 RPU, sedikit kurang dari 5.000. Itu jawaban tebakannya. Selisih 64,21 RPU punya dua sebab: fee 0,3% (tanpa fee hasilnya 4.950,50) dan price impact: tiap POIN yang masuk membuat POIN berikutnya lebih murah. k malah naik dari 5.000.000.000 ke sekitar 5.000.148.519, karena fee tertinggal di kolam. Jual 2.000 POIN sekaligus? Hasilnya 83.124,90 RPU, bukan 100.000: hampir 17% hilang karena kolamnya terlalu kecil untuk ukuran trade itu.

Slippage dan minOut

Antara Dinda menandatangani dan transaksinya masuk block, orang lain bisa menukar duluan. Yoga menjual 2.000 POIN lebih dulu, dan 100 POIN Dinda sekarang cuma bernilai 3.434,99 RPU. Karena Dinda memasang minOut 1% di bawah perkiraan (4.886,43 RPU), contract menolak:

The contract function "jualPoin" reverted.

Error: Slippage(uint256 out, uint256 minOut)
               (3434998214055883422976, 4886432270265453429309)

Tanpa minOut (atau minOut = 0), Dinda tetap kehilangan 30% diam-diam. Selalu hitung minOut dari perkiraan yang baru dibaca, dan beri batas waktu (deadline) di aplikasi sungguhan.

Penyedia likuiditas dan impermanent loss

Isi kolam datang dari liquidity provider (LP): Raka menyetor 10.000 POIN + 500.000 RPU (nilai 1.000.000 RPU) dan mendapat fee dari tiap swap. Risikonya impermanent loss. Kalau harga POIN di luar naik jadi 100 RPU, arbitrase membeli POIN dari kolam sampai harga kolam ikut 100. Tanpa menghitung fee, isinya jadi √(k/100) = 7.071,07 POIN dan √(k·100) = 707.106,78 RPU:

Isi Nilai di harga 100
Tetap di kolam 7.071,07 POIN + 707.106,78 RPU 1.414.213,56 RPU
Disimpan saja (HODL) 10.000 POIN + 500.000 RPU 1.500.000 RPU

Selisihnya 5,72%: rumus 2√r / (1 + r) - 1 dengan r = 2. Harga ×4 atau ×¼ memberi 20%. "Impermanent" karena kalau harga kembali ke 50, selisihnya hilang; kalau LP menarik dana saat harga sudah bergeser, rugi itu jadi nyata. Fee harus lebih besar dari itu supaya LP untung.

Oracle: jangan percaya harga kolam

Contract gak bisa melihat harga di luar blockchain. Oracle membawa data itu ke chain. Godaan termudah: pakai harga spot kolam (cadanganRpu / cadanganPoin). Ini berbahaya. Di chain lokal, satu transaksi pembelian POIN dengan 500.000 RPU menggeser harga dari 50 ke 199,70 RPU per POIN. Contract pinjaman yang menilai jaminan dengan harga itu akan menghargai 100 POIN hampir 20.000 RPU, padahal nilai wajarnya 5.000. Dengan flash loan (pinjaman yang dipinjam dan dilunasi dalam satu transaksi), modal sebesar itu bisa didapat sesaat, jadi kerentanan ini nyata. Pertahanannya:

Lending dan likuidasi

Protokol pinjam-meminjam menerima jaminan (collateral) dan meminjamkan aset lain sampai batas tertentu. Misalnya Dinda menjaminkan 1.000 POIN (50.000 RPU) dan meminjam 25.000 RPU. Kalau POIN turun ke 30 RPU, jaminannya cuma 30.000; dengan batas likuidasi 80% (24.000 RPU) utangnya sudah melewati batas, dan siapa pun boleh melikuidasi: melunasi utang itu dan mengambil jaminan Dinda plus bonus. Itu sebabnya harga dari oracle harus benar: harga yang salah bisa melikuidasi orang yang sebenarnya aman.

⚠️ Jebakan yang sering ketemu

TL;DR: DeFi adalah layanan keuangan yang berjalan di smart contract tanpa perantara terpusat. AMM menentukan harga dari rasio isi liquidity pool, tanpa order book: x · y = k, harga spot y / x, fee 0,3% (amountIn * 997). Di kolam mainan 10.000 POIN / 500.000 RPU, menjual 100 POIN memberi 4.935,79 RPU (fee + price impact), menjual 2.000 memberi 83.124,90 (hampir 17% lebih buruk). minOut membuat swap revert dengan Slippage(out, minOut) kalau harga bergeser. LP mendapat fee tapi menanggung impermanent loss (5,72% kalau harga ×2). Harga spot kolam bisa digeser dalam satu transaksi (50 jadi 199,70), jadi pakai oracle atau TWAP. Lending butuh jaminan dan bisa dilikuidasi. Semua di sini token mainan di chain lokal: DeFi sungguhan berisiko, dan ini bukan saran investasi.

Yang akan kamu pelajari