Technical Background of Balancer V2 Composable Stable Pools Spesifikasi Balancer V2 Composable Stable Pools : : Pool Structure and How It Works Composable Stable Pools dibangun pada matematika terinspirasi oleh model StableSwap Curve. What is a Composable Stable Pool? Pool ini dirancang untuk memungkinkan aset dengan nilai yang hampir identik, seperti USDC dan DAI, atau stETH dan ETH, berdagang dengan slipage minimal. **What makes them “composable”? \ The pool’s LP token (BPT) is a standard ERC-20 token that can be reused across the ecosystem, for example, in other pools or as collateral. This allows liquidity to be seamlessly composed throughout the system. **How it works \ A Composable Stable Pool can hold multiple tokens, and its invariant DDD is calculated using the following polynomial equation: Untuk Balancer (terinspirasi oleh Curve), swap dihitung dengan menjaga (D) sesekali mungkin. ketika swap terjadi, saldo token bergerak ke keadaan baru yang mempertahankan invariant ini. persamaan di atas adalah Anda memutuskan untuk mendapatkan dari token yang Anda selesaikan, karena (D) tetap tetap tetap. stable invariant quadratic new balance (x) istilah (x): saldo baru (post-swap) dari token yang Anda selesaikan. (S): jumlah saldo token lainnya (tidak termasuk (x) ) (P): produk dari saldo token lainnya (tidak termasuk (x) ) (D): pulau invariant (ditargetkan untuk tetap konstan di seluruh swap). (A): parameter amplifikasi (menyejukkan kurva → meluncur lebih rendah untuk aset bernilai sama). (n): jumlah token dalam kolam. Intuisi: kita mengompres “semua token lainnya” menjadi dua agregat, (S) dan (P). . quadratic in (x) Kenapa harus quadratic? Setelah mengisolasi keseimbangan baru token yang tidak diketahui dan melipatgandakan sisanya menjadi (S) dan (P), kondisi invariant dikurangi menjadi polinom tingkat kedua dalam (x). memecahkannya Pilihlah akar yang dan (Dalam kisaran keseimbangan yang mungkin). akar yang lain biasanya negatif atau tidak masuk akal. Which root? positive economically valid Contoh sederhana Setup (2 tokens, large A → very low slippage) Internal (upscale) start balance: token0 = 1.000.000; token1 = 1.000.000 Jumlah token: n = 2 Amplifikasi A = 1000 Dengan besar A, D ≈ 2.000.000 Action Anda menambahkan 10.000 unit token0 (EXACT_IN). Quadratic to solve x^2 + (S - D/(A*n^n) - D)*x - D^(n+1)/(A*n^(2n)*P) = 0 di mana : , yang dan adalah saldo post-swap token1. S = 1,010,000 P = 1,010,000 x Solution x ≈ 990,999.546 Amount out amountOut = 1,000,000 - 990,999.546 ≈ 9,000.454 Interpretation Anda memasukkan 10.000 token0 dan menerima ~9,000.45 token1 → slappage rendah dengan A besar. Semua matematika menggunakan unit internal 18 desimal; implementasi bulat ke bawah untuk keamanan. Di mana ia digunakan (tingkat tinggi) EXACT_IN: Anda meningkatkan token input; menyelesaikan untuk saldo baru counter-token (x); perbedaan dari saldo lama adalah jumlah keluar. EXACT_OUT: Anda menargetkan jumlah yang diterima; menyelesaikan untuk yang dibutuhkan (x) (dan dengan demikian input yang dibutuhkan). Catatan praktis Semua keseimbangan diproses secara internal pada 18 desimal (dalam skala); perhitungan biasanya bulat ke bawah untuk aman. Kurva yang lebih besar (A) membuat kurva lebih konstan-sum-seperti (slip kecil untuk pasangan yang stabil); yang lebih kecil (A) lebih dekat dengan perilaku produk konstan. TL;DR: Persamaan ini adalah kuadrat workhorse yang, di bawah invariant tetap (D), memberi Anda keseimbangan token baru (x) setelah swap. koefisien mengkodekan “beberapa pool” melalui (S) dan (P), sementara (A) dan (n) menetapkan bentuk / ketebalan kurva stabil. TL;DR: Persamaan ini adalah kuadrat workhorse yang, di bawah invariant tetap (D), memberi Anda keseimbangan token baru (x) setelah swap. koefisien mengkodekan “beberapa pool” melalui (S) dan (P), sementara (A) dan (n) menetapkan bentuk / ketebalan kurva stabil. The pool memaksakan a Di antara perhitungan-perhitungan yang ditempuh oleh suatu . balance relationship invariant D Ketika Anda bertukar, satu keseimbangan naik, yang lain turun, dan kolam menemukan Itulah cara harga muncul. new balance that keeps D as constant as possible Pool menggunakan faktor skala untuk menormalkan token hingga 18 desimal. Operasi Upscale menyesuaikan keseimbangan dengan akurasi internal dan menggunakan pengeringan ke bawah. Swap Types EXACT_IN (GIVEN_IN): Jumlah input tetap, menghitung output. EXACT_OUT (GIVEN_OUT): Jumlah output tetap, menghitung input. Vault and BatchSwapBalancer Vault manages all operations. BatchSwap combines multiple swaps in one transaction and uses "deferred settlement" like flashloans. BPTs act like normal tokens, bypassing min pool supply limit to drop liquidity very low. 1) Analisis Eksploitasi 1.1 Serangan Pada 3 November 2025, sekitar pukul 7:40 UTC, pool stabil Balancer v2 tertentu ditargetkan dengan serangan canggih yang mengakibatkan kerugian kumulatif lebih dari $ 120 juta di seluruh Balancer dan forknya. The attack leveraged several circumstances: Sebagian besar pool yang ditargetkan adalah instansi dari kontrak ComposableStablePool. pool khusus yang dirancang untuk aset yang diharapkan untuk secara konsisten bertukar di dekat paritas atau pada nilai tukar yang diketahui. Fungsi batchSwap dari kontrak Balancer Vault memungkinkan swap transisi untuk terjadi sebelum kebutuhan untuk menyelesaikan delta yang tersisa. Serangan itu menguntungkan dalam skenario likuiditas rendah. penyerang harus mempersiapkan swap besar sehingga saldo kolam dapat dibawa ke likuiditas rendah dari satu atau token lainnya. cara yang paling banyak digunakan untuk mencapai ini adalah untuk menukar token LP untuk token kolam, meninggalkan kolam dalam keadaan likuiditas rendah. Semua yang disebutkan di atas hanyalah keadaan yang diperlukan tetapi tidak menyimpulkan, dengan satu-satunya keadaan yang diperlukan untuk ini terjadi adalah penyebab utama masalah, perilaku bulat dalam fungsi _upscale. Vektor serangan pertama kali diperkenalkan pada 16 Juli 2021, ketika MetaStablePool mengalahkan Perubahan yang sama kemudian diterapkan pada tanggal 1 September 2021, untuk pool linear di commit 4e9e70a dan pada tanggal 20 September 2021, pada commit f450760 untuk StablePhantomPool, kemudian diubah nama menjadi ComposableStablePool. _scalingFactors Dalam deskripsi masalah di bawah ini, kami menjelaskan mengapa pengenalan override ini berada di inti serangan. 1.2 Masalah Fungsi batchSwap dari kontrak Vault adalah titik masuk untuk serangan ini. Penyerang membuat panggilan untuk itu, menargetkan instansi ComposableStablePool. Logika yang relevan dalam kontrak Vault yang membawa ke interaksi ComposableStablePool didefinisikan oleh aliran ini: batchSwaps → secara internal memanggil _swapWithPools → yang secara internal memanggil kolam untuk setiap swap di _swapWithPool → _processGeneralPoolSwapRequest → akhirnya memanggil onSwap pada ComposableStablePool. Setelah mendarat di ComposableStablePool, eksekusi berlanjut di dalam hook onSwap, di mana dua hal terjadi: Panggilan ke fungsi _scalingFactors. Transfer ke _swapGivenOut seperti yang didefinisikan dalam contoh transaksi yang diberikan di atas. Perhatikan bahwa penyerang mungkin telah memutuskan untuk mengambil pola _swapGivenIn, tetapi input yang diberikan dalam transaksi serangan dengan jelas menunjukkan pilihan. Mari kita lihat dua fungsi tersebut. Skala faktor function _scalingFactors() internal view virtual override returns(uint256[] memory) { uint256 totalTokens = _getTotalTokens(); uint256[] memory scalingFactors = new uint256[](totalTokens); for (uint256 i = 0; i < totalTokens; ++i) { scalingFactors[i] = _getScalingFactor(i).mulDown(_getTokenRate(i)); } return scalingFactors; } Fungsi ini melakukan dua hal: Ini mengukur jumlah apa pun ke jumlah desimal yang tetap seperti yang disarankan oleh fungsi _getScalingFactor dan apa yang dikembalikan. Ini faktor dalam nilai tukar token dengan melipatgandakan dengan faktor skala dan membagi dengan 1e18. Meningkatkan function _upscale(uint256 amount, uint256 scalingFactor) pure returns (uint256) { /* Upscale rounding wouldn't necessarily always go in the same direction: in a swap for example the balance of token in should be rounded up, and that of token out rounded down. This is the only place where we round in the same direction for all amounts, as the impact of this rounding is expected to be minimal. */ return FixedPoint.mulDown(amount, scalingFactor); } Ini hanya melakukan multiplikasi jumlah dengan faktor skala, membagi dengan 1e18 di akhir. Masalahnya terletak pada dua fakta: Fungsi ini selalu bulat ke bawah (mulDown) terlepas dari arah swap. Jika jumlah adalah urutan ukuran yang lebih kecil dari yang scalingFactors, kerugian presisi menjadi tidak dapat diabaikan. Dalam transaksi penyerang, nilai khas dari jumlah dan faktor scaling adalah: jumlah: "17"scalingFactor: "1058132408689971699" Jika kita menghitung Kami mendapatkan , tetapi karena Solidity mengecilkan desimal, ini menjadi yang mengakibatkan a Di dalam Fungsi yang amount * scalingFactor / 1e18 17.98 17 0% net change _upscale Sekarang, pertimbangkan jumlah (sebuah token dengan 18 desimal). hasilnya adalah yang mewakili a yang benar mencerminkan tingkat. 17,000000000000000000 17.988250950000000000 5.8% increase Selain itu, untuk sebuah token dengan (seperti kebanyakan stablecoins memiliki), menggunakan sejumlah Perolehan yang hampir sama persis dengan yang . 6 decimals 17,000000 17.988250 5.8% positive change Truncation dimaksimalkan dengan membuat sebanyak mungkin, sehingga produk kehilangan akurasi maksimum ketika dibagi dengan 1e18. amount*scalingFactor mod 1e18 Misalnya, dalam tabel di bawah ini, jumlah=17 dan jumlah=50 keduanya menghasilkan kerugian putar mutlak sekitar 0,90. namun, kesalahan sebagai persentase dari jumlah ini bervariasi secara signifikan, dan persentase peningkatan kehilangan bervariasi bahkan lebih banyak, karena kerugian mutlak yang sama jauh lebih besar dibandingkan dengan 17 daripada 50. Contohnya Contoh kesalahan bulat lantai saat scaling dengan faktor 1.058132408689971699 amount upscale error %error %increase lost 17 17 0.98 5.76% 100% 50 52 0.90 1.80% 17% ... ... ... ... ... 17 17 0.98 5.76% dari 100 persen 50 52 0.90 1.80% dari 17% dari ... ... ... ... ... yang fungsi akan kemudian menggunakan nilai-nilai bulat ini untuk menghitung jumlah yang harus oleh penyerang ke kolam setelah swap. nilai ini secara buatan deflated, membuat swap lebih murah. ini kompleks, dan mereka juga membenarkan mengapa ini dapat dicapai di pulau-pulau di mana keadaan likuiditas rendah dapat diperoleh dengan sukarela. ini disebabkan oleh cek invariant yang menjamin konvergensi sampai batas tertentu. _swapGivenOut _swapGivenOut Pada akhirnya, dengan jumlah iterasi yang tinggi, delta setelah batchSwap membengkak, mengkreditkan penyerang dengan mayoritas dana di kolam. Selain itu, ada pengamatan yang relevan untuk dilakukan tentang doktrin _upscale dalam baris: /* Upscale rounding wouldn't necessarily always go in the same direction: in a swap for example the balance of token in should be rounded up, and that of token out rounded down. This is the only place where we round in the same direction for all amounts, as the impact of this rounding is expected to be minimal. */ Versi sebelumnya dari komentar ini memiliki catatan tambahan: /* …as the impact of this rounding is expected to be minimal (and there's no rounding error unless `_scalingFactor()` is overriden). */ Hal ini penting karena diperkenalkan pada Dan kemudian diubah menjadi dan menerapkan persis yang yang dibahas di atas. StablePhantomPool September 20, 2021 ComposableStablePool _scalingFactor Dalam versi sebelumnya dari , yang fungsi hanya memperhitungkan perbedaan dalam desimal token. dalam implementasi yang lebih baru, bagaimanapun, ia juga menggabungkan Menandai perubahan fundamental. StablePool _scalingFactor exchange rate Seperti yang dinyatakan dalam fungsi, kode yang dikembangkan dari penggunaan (Sebagai contoh a) Dua Perubahan ini, meskipun secara fungsional diperlukan, memperkenalkan potensi Bersama dengan mereka, sebuah . _upscale unitary scaling factors 1e12 non-unitary exchange rates rounding errors attack vector Sementara memungkinkan kesalahan rounding adalah penyebab utama, mengeksploitasi itu membutuhkan memanfaatkan mekanika protokol tambahan dan langkah-langkah serangan spesifik. Balancer’s batchSwap memungkinkan saldo internal sementara yang hanya net-settled pada akhir batch. berkat ini, penyerang secara efektif “meminjam” BPT dalam batch untuk memanipulasi kolam tanpa harus mengakhiri transaksi yang memegang BPT. BPT (Balancer Pool Token) adalah ERC-20 yang mewakili proporsional saham dari pool Balancer. Dalam beberapa desain pool, termasuk ComposableStablePools yang ditargetkan, BPT juga dapat muncul sebagai aset pool dan dapat diperdagangkan / ditukar. Fase pertama mendorong saldo token pool (misalnya, WETH / osETH) ke tingkat yang sangat rendah (hampir 100k) dengan berulang kali bertukar BPT ke token1 dan BPT ke token2. Dengan keseimbangan kecil, putaran titik tetap menjadi dominan. Tujuan adalah untuk memaksimalkan bagian fraksi yang dibuang dalam aritmatika lantai, yaitu, memaksimalkan jumlah*scalingFactor mod 1e18 sehingga produk kehilangan presisi sebanyak mungkin ketika dibagi oleh 1e18. Eksploit berjalan dalam pengulangan triplets swap: Prime: memindahkan kolam ke keadaan di mana truncation akan terjadi pada operasi berikutnya. Dalam screenshot di bawah ini, swap dari WETH ke osETH Eksploit: melakukan swap yang menyadari kerugian bulat. Dalam screenshot, swap 17 WETH untuk osETH. Reset: mengembalikan keseimbangan sehingga triplet dapat diputar ulang. Dalam screenshot adalah swap dari osETH ke WETH. Seperti yang ditunjukkan dalam jejak di bawah ini, swap kritis sering menggunakan jumlah=17 terhadap saldo kotak 18. Anda dapat melihat jumlah yang diulang 17 dalam swap kedua setiap triplet. Meningkatkan Praktek Terbaik Keamanan: Pelajaran untuk Industri Insiden ini telah memicu perdebatan tentang efektivitas audit keamanan kontrak cerdas, dengan beberapa komentator mempertanyakan apakah mereka memberikan nilai.Meskipun perasaan ini mungkin dapat dimengerti pada saat frustrasi, itu tidak mengakui mengapa audit keamanan telah menjadi praktik terbaik industri dan dampak besar praktik audit keamanan telah memiliki pada mengurangi risiko dan melindungi pengguna selama dekade terakhir. Perusahaan keamanan secara kolektif mencegah ratusan potensi eksploitasi setiap tahun. OpenZeppelin saja telah mengidentifikasi lebih dari 700 kerentanan kritis dan berat sebelum mereka mencapai produksi di semua audit kami. bencana yang dihindari ini tidak membuat judul, tetapi mereka mewakili miliaran nilai yang dilindungi dan banyak pengguna yang diselamatkan dari kerugian. audit keamanan berkualitas tinggi juga membantu tim pengembangan meningkatkan sikap keamanan mereka sepanjang siklus hidup pengembangan, menghasilkan pengurangan eksponensial dalam kemungkinan kesalahan lebih lanjut yang diperkenalkan ke dalam aplikasi blockchain. Pelajaran yang sebenarnya bukan bahwa audit tidak efektif – itu adalah bahwa praktik audit industri belum menyadari seberapa cepat protokol kompleks yang menjamin nilai yang signifikan berkembang.Karena audit sering dikelompokkan sebagai ulasan terpisah daripada komitmen berkelanjutan, konteks dapat hilang saat basis kode berkembang. 2.1 Menetapkan Keamanan Berkelanjutan sebagai Standar Industri The Balancer v2 exploit illustrates why we've been advocating for a fundamental shift in how the industry approaches security. Since pioneering the practice of smart contract auditing in 2016, we've seen how the most successful security outcomes come from ongoing security partnerships that cover entire protocol codebases and all of their changes over time, rather than ad hoc code reviews of major upgrades, which are often limited in scope to only those changes. Ketika peneliti keamanan bekerja dengan protokol secara berkelanjutan, mereka mengembangkan pengetahuan yang mendalam tentang arsitektur protokol, proses rekayasa, dan mengapa keputusan desain spesifik dibuat. Meskipun basis kode Balancer v2 telah ditinjau oleh empat firma audit independen, masing-masing perusahaan berkomitmen untuk fokus pada lingkup protokol yang berbeda.Penglibatan beberapa auditor membantu mengurangi kemungkinan kerentanan yang hilang, tetapi mempertahankan setidaknya satu mitra keamanan jangka panjang memberikan pemahaman yang lebih mendalam dan berkelanjutan tentang bagaimana basis kode berkembang dan bagaimana perubahan baru berinteraksi dengan logika yang ada. 2.2 Membangun kerangka kerja keamanan yang lebih baik OpenZeppelin Contracts telah menjadi standar de facto untuk membangun kontrak cerdas yang aman, saat ini memungkinkan lebih dari $ 30 triliun dalam nilai total yang ditransfer ke seluruh ekosistem. Sebagai contoh, OpenZeppelin berkontribusi pada badan-badan pengaturan standar industri, seperti Dewan Standar Keamanan Blockchain, Enterprise Ethereum Alliance, dan Organisasi Standar Internasional (ISO), untuk memastikan bahwa praktik terbaik keamanan tim dan komunitas kami telah membantu perintis tersedia untuk seluruh industri. Kami juga berkolaborasi dengan regulator dan pembuat kebijakan di seluruh dunia untuk memastikan praktik terbaik keamanan blockchain dipromosikan dalam rezim regulasi yang relevan. Secara khusus, OpenZeppelin telah berkolaborasi dengan Departemen Keuangan AS, Komisi Sekuritas dan Pertukaran AS, Otoritas Perilaku Keuangan Inggris, dan ACPR Perancis dan AMF mengenai manfaat melakukan audit keamanan yang komprehensif secara teratur. Selain itu, kami telah mengeksplorasi potensi untuk menciptakan organisasi regulasi mandiri khusus yang mirip dengan auditor di bidang lain yang kami percaya dapat membantu merumuskan standar dan metodologi audit keamanan untuk teknologi blockchain, menetapkan persyaratan kualitas dan etika untuk auditor, dan mengelola akreditasi untuk sertifikasi auditor yang berkualitas, yang dapat meningkatkan hasil keamanan dan meningkatkan kepercayaan konsumen. 2.3 Memperkuat ekosistem keamanan blockchain bersama-sama Setiap insiden keamanan memberikan wawasan berharga yang mendorong perbaikan di seluruh industri kami. eksploit Balancer v2 memperkuat bahwa seiring protokol menjadi lebih berharga dan canggih, menjadi penting bagi tim protokol untuk berinvestasi dalam keamanan yang berkelanjutan, serta untuk mengaudit perusahaan untuk membangun kerangka kerja yang mendukungnya.