Mathematical Modeling with Floating Point Numbers in Solidity
I built a thing...
I've been writing code off and on for more than 30 years now, but never considered myself a developer. I am a scientist turned technical founder. Writing code was always a means to implement some numerical model I created myself.
The most beautiful model I've built in my life so far is the Multiswap. Multiswap is not just a product. Multiswap represents a new foundation for decentralized capital markets.
The first implementation of Multiswap was deployed on Ethereum's Ropsten testnet in April 2022 and later on Avalanche mainnet in September 2023. Both implementations were written in the Solidity programming language for the Ethereum Virtual Machine (EVM).
Fixed-Decimal Arithmetic
As someone who has built numerical models my entire adult life, building in Solidity is by far the most painful due to the lack of a proper floating-point number. The EVM is a programmable ledger and account balances are stored in a 256-bit unsigned integer type: uint256. The native token uses 18 decimals so in order to represent the simple number "1", we are actually dealing with a giant integer
ONE = 1_000_000_000_000_000_000
i.e. a "1" followed by 18 zeros!
Multiplying 2.5 times 3.0 is accomplished horrendously like
2_500_000_000_000_000_000 x 3_000_000_000_000_000_000 / 1_000_000_000_000_000_000
Because each number has 18 extra zeros, when we multiply two numbers we need to divide the result by ONE (1 with 18 zeros). If that makes your eyes hurt, you're not alone!
This is called "fixed-decimal" arithmetic and there are plenty of good fixed-decimal libraries out there for Solidity. I like Solady.
Fixed-decimal numbers are fine for accounting and I often say that 90% of finance is getting the accounting right. BUT... I've never seen anyone building financial models using fixed-decimal numbers until I started working with smart contracts in Solidity. Frankly, this is nuts.
Mixed-Decimal Arithmetic? ??
Although using fixed decimals is already a bit of a head scratcher for mathematical modeling, I haven't even touched on the most painful point of using fixed-decimal arithmetic in Solidity. That is, different tokens use different decimals so it isn't really fixed. It is more like a bastardized "mixed-decimal" arithmetic and that has tripped up more than a few smart contracts. Don't ask me how I know.
领英推荐
For example, as I mentioned, native EVM tokens such as ETH and AVAX use 18 decimals and 18 is the default number of decimals for most ERC20 tokens with some important exceptions. The biggest exceptions are US dollar denominated stablecoins, i.e. ERC20 tokens that are intended to represent $1 ,such as USDt, USDC and DAI. These use 6 decimals. Other exceptions include ERC20 versions of Bitcon such as WBTC and BTC.b. These use 8 decimals.
Having different tokens with different decimals creates real headaches for smart contract developers. Many protocols deal with this by converting balances to some internal number format and perform the mathematics on that format. However, in all cases I am aware of, this internal format is again some form of fixed decimal.
Fuzz Tests
I deployed the Beta 1.0 version of Multiswap, essentially a prototype, in September 2023 on Avalanche mainnet. The Beta had a number of training wheels that impeded its commercial success, but it was a tremendous learning experience having a product onchain. Two major issues with the Beta included:
In November 2023, I deployed and seeded the "Beta 1.1" contract that fixes both these issues. As I was updating the web application to interface with the new contract, I noticed a very small unintended approximation that had an extremely minor impact on an extreme corner case that probably no one would ever hit. It was tempting to ignore it. I am almost 100% sure the tiny approximation would not lead a vulnerability, but I didn't feel good announcing a product with a known mathematical error.
Fixing the error was simple and I could have immediately deployed a fix and moved the seed funds to the new contract, but it bugged me that my tests did not catch that tiny mathematical error so I tightened down my tests. A lot.
In the process, I found more issues that were not particular to Multiswap. I was seeing basic weaknesses resulting just from the use of fixed-decimal arithmetic for mathematical modeling. Numerical approximation errors creep in for extremely small and extremely large trades. These extremes are unrealistic and it would be pragmatic and acceptable to most reasonable people to ignore them. Every other protocol on the planet ignores them. Why shouldn't I? After all, that's the way it's always been done around here.
Combatting this kind of lazy attitude was always a motivation for me when I worked in traditional finance and you can be sure I am not going to accept it in this new world of decentralized finance.
Floating-Point Arithmetic
The solution is simple. Use fixed-decimal arithmetic for accounting and use floating-point arithmetic for the numerical models. Every first-year finance person knows this. As mentioned, Solidity does not have native support even for fixed-decimal arithmetic so we need to rely on external libraries. Not surprisingly, I could not find an acceptable open-source floating-point math library in Solidity so I built one myself:
This is open sourced with MIT license. I hope others can find it useful and PRs are welcome!
Using this new floating-point math library, I have been able to quote swaps for amounts as small and smaller than 10^-1000 and for swaps as large and larger than 10^1000. Multiswap is now the most robust protocol on the planet with the largest range of input values with no loss in accuracy.
tech for good l crypto l ai l quantum
10 个月Excellent. Nerds unite.
CTO @ infobud.ai - Chief of Vectors and Data
10 个月Wow! This is truly amazing, Eric, and so necessary. So far, every SmartContract engineer has either built their own solution or bypassed the problem somehow. Thank you for open-sourcing it. Have you discussed it with the guys from OpenZeppelin? It (c/sh)ould be part of their libraries as well.
Technology | MIT Sloan-Columbia-Tuck | NUS | Ex-Accenture | CEO @ CloudSwyft - the global leader in hyper-scaler labs technology & future-ready skills solutions for the education and enterprise sector. ALWAYS HIRING! ??
10 个月Good stuff Eric Forgy
Nice Eric used to have trouble calculating greeks via finite difference because of fp arithmetic particularly in excel. This looks interesting!