Unveiling Hidden Precision Errors in Cryptocurrency

Introduction

Hello everyone! recently I embarked on a fascinating journey into the world of decentralized finance and smart contract development. This adventure began when I stumbled upon an intriguing discrepancy in token swap outputs, which sparked a deep dive into the realms of mathematics and computer science. I'd like to share my experience with you, highlighting how a simple anomaly piqued my curiosity and led me to explore the underlying mechanisms of how computers and blockchains handle numbers.

The Beginning: Collaborating on a DeFi Project

Our team at Block Apex was working on a DeFi application that involved both smart contract development and an aggregator service to calculate the best price quotes for token swaps. A colleague was responsible for developing the aggregator, which determined the most favorable exchange rates by analyzing various liquidity pools.

My role was to implement the smart contract side, specifically executing token swaps based on the quotes provided by the aggregator. To ensure accuracy and reliability, we benchmarked our work against Ref Finance, a well-respected DeFi platform on the NEAR blockchain.

The Discovery: A Curious Discrepancy

As I began testing the execution of transactions in the smart contract using the price quotes from the aggregator, I noticed something odd: the quotes provided by our aggregator were consistently higher than those from Ref Finance for the same swap inputs.

Observations

I conducted several tests swapping between wrap.testnet (a wrapped NEAR token) and usdt.fakes.testnet (a mock USDT token on NEAR testnet). Here are the results:

Input Swap Amount (yoctoNEAR)Aggregator Quote (USDT)Ref Finance Quote (USDT)Difference (USDT)
100,0000.00000326097813900.000003260978139
10,000,0000.000326097813900.0003260978139
100,000,000,000,0003,260.9779073,2600.977907
10,000,000,000,000,000,000326,097,790.6326,097,7900.6
100,000,000,000,000,000,0003,260,977,8963,260,977,8951.0

Note: 1 yoctoNEAR is 10^{-24} NEAR

The discrepancies, though seemingly small, were consistent and significant enough to warrant investigation. This anomaly piqued my curiosity. Was there an error in the aggregator's calculations? Or was there a deeper reason behind these differences?

Diving Deep: Investigating the Cause

Determined to uncover the root of the discrepancy, I embarked on a thorough investigation.

Recreating the Calculations in Excel

To isolate the issue, I recreated the swap calculations in Excel using the constant product formula, incorporating fees.

Excel Formula:

ΔY = Y * [ΔX * (Fee Divisor - Fee) / Fee Divisor] / [X + ΔX * (Fee Divisor - Fee) / Fee Divisor]

Variables:

  • X: Token A liquidity (input reserves)
  • Y: Token B liquidity (output reserves)
  • ΔX: Swap amount (input amount)
  • ΔY: Amount of Token B to receive (output amount)
  • Fee: Total fee (e.g., 20)
  • Fee Divisor: Scaling factor (e.g., 10000)

Using the same input values as in the tests, the Excel calculations matched the aggregator's quotes but differed from Ref Finance's. This suggested that the aggregator's calculations were mathematically correct, so why was there still a discrepancy?

Comparing with Ref Finance's Implementation

I examined Ref Finance's approach to understand how they handle swap calculations. Their implementation uses integer arithmetic and truncates any fractional parts, ensuring that only whole tokens are considered in the output.

Unveiling the Core Issue: How Computers Handle Numbers

At this point, I realized that the discrepancy was due to how numbers are represented and handled in computers, especially within blockchain environments.

Understanding Number Representation in Computers

Computers represent numbers using binary (base-2), and there are different methods for representing numbers, depending on whether they are integers (whole numbers) or floating-point numbers (numbers with fractions).

  • Integer Numbers: Whole numbers without fractional parts.
  • Floating-Point Numbers: Numbers that can represent fractions, using a format similar to scientific notation in binary.

Floating-Point Representation:

  • Uses a fixed number of bits to represent a wide range of values.
  • Consists of a sign bit, exponent, and mantissa (fractional part).
  • Cannot represent some decimal fractions exactly due to binary limitations (e.g., 0.1 in decimal is a repeating binary fraction in binary).

Floating-Point Precision Errors

Floating-point arithmetic allows for the representation of very large or very small numbers, including fractions, but at the cost of precision due to rounding errors and the limitations of binary representation.

Example:

let a = 0.1 + 0.2;
println!("{}", a); // Output 0.30000000000000004

This small error occurs because 0.1 and 0.2 cannot be represented exactly in binary floating-point.

Why Cryptocurrencies Use Integer Arithmetic

In blockchain environments, smart contracts typically use integer arithmetic for several reasons:

  1. Determinism: All nodes in the network must reach the same result for the same computation to maintain consensus. Floating-point arithmetic can lead to non-deterministic results due to differences in hardware or software implementations.
  2. Precision and Accuracy: Floating-point arithmetic can introduce rounding errors, which are unacceptable in financial applications where precise calculations are critical.
  3. Security: Avoiding floating-point arithmetic reduces the attack surface for certain types of exploits that rely on rounding errors or inconsistencies.

Understanding Integer Division and Truncation

In integer arithmetic, when you divide two integers, the result is an integer, and any fractional part is discarded (truncated). For example:

let result = 7 / 2; // result is 3, not 3.5

This means that any calculation resulting in a fraction will be rounded down to the nearest whole number.

The Role of Fractional Tokens in Blockchain

In most blockchain systems, tokens are represented in their smallest indivisible units (e.g., wei in Ethereum, satoshi in Bitcoin, or yoctoNEAR in NEAR). Fractions of these units cannot exist on the blockchain.

Thus, any calculation resulting in a fractional token amount must handle the fractional part appropriately—usually by truncating it.

Connecting the Dots: The Cause of the Discrepancy

Realizing this, I understood that the aggregator's calculations included fractional tokens, whereas Ref Finance's calculations did not.

The Aggregator's Calculations Included Fractional Tokens

  • Mathematically Precise: The calculations were accurate in terms of pure mathematics.
  • Practically Impractical: Blockchain tokens cannot be divided beyond their smallest unit; fractional tokens cannot exist on-chain.
  • Result: The aggregator provided slightly higher output amounts because it included fractions of tokens that cannot actually be transacted.

Ref Finance's Calculations Truncated Fractions

  • Integer Arithmetic: By using integer division, any fractional parts are discarded.
  • Blockchain-Compatible: Ensures that only whole units of the smallest token denomination are used.
  • Result: Outputs are slightly lower but reflect the actual amount of tokens that can be transferred.

Reflecting on Mathematical and Computational Concepts

This realization led me to explore deeper into how computers handle numbers and the implications for financial calculations.

The Fascinating World of Number Systems

Understanding how numbers are represented and manipulated in computers is crucial, especially when dealing with applications like DeFi where precision is paramount.

  • Binary Numbers: The fundamental language of computers, using bits (0s and 1s).
  • Decimal Numbers: Our everyday number system, base-10.
  • Hexadecimal and Other Systems: Used in computing for various purposes.

Floating-Point vs. Fixed-Point Arithmetic

  • Floating-Point Arithmetic: Allows for a wide range of values but can introduce rounding errors.
  • Fixed-Point Arithmetic: Represents numbers with a fixed number of decimal places, offering more predictability in calculations.

Importance of Precision in Financial Applications

  • Accuracy Matters: Even small errors can accumulate and have significant financial implications.
  • Consistency: Using integer arithmetic ensures that all computations are consistent across different systems.

The Impact on DeFi Applications

Understanding these concepts is critical for anyone involved in DeFi or smart contract development.

  • Smart Contract Calculations: Must use integer arithmetic to ensure security and determinism.
  • Aggregators and Price Feeds: Need to account for the limitations of blockchain number representations to provide accurate and usable data.

Lessons Learned

This journey taught me several valuable lessons:

  1. The Importance of Investigating Anomalies: A small discrepancy can lead to significant insights when investigated thoroughly.
  2. Understanding the Underlying Mechanics: Grasping how numbers are represented and computed in programming languages is essential, especially for financial applications.
  3. Blockchain Constraints: Recognizing that blockchains have specific requirements and limitations, such as the inability to handle fractions of the smallest token unit.
  4. Practicality Over Mathematical Perfection: In some cases, it's more important to have practical solutions that work within system constraints than to have mathematically perfect calculations.
  5. Continuous Learning: Curiosity can lead to a deeper understanding of complex topics and improve problem-solving skills.

Conclusion

What began as a small discrepancy in token swap outputs led me on a journey through the intricacies of computer arithmetic, number representation, and blockchain mechanics. I learned that in blockchain environments, practicality and security often take precedence over mathematical precision.

By truncating fractional tokens, DeFi platforms ensure that they do not attempt to distribute tokens that cannot exist on the blockchain, maintaining the integrity and consistency of transactions.

This experience not only helped me understand the importance of integer arithmetic in smart contracts and aggregators but also sparked a deeper appreciation for the mathematical and computational principles that underpin the technology we use every day.


Thank you for joining me on this journey! I hope my experience provides valuable insights for developers, enthusiasts, and anyone curious about the fascinating intersection of math, computing, and blockchain technology. If you have any questions or thoughts, feel free to share them. Let's continue learning and exploring together.

Additional Resources

More Reading

Post navigation

Leave a Comment

Leave a Reply

Your email address will not be published. Required fields are marked *