Skip to content

feat: add PriceUtils#657

Merged
robercano merged 2 commits intomainfrom
rcano/add-price-utils
Feb 6, 2026
Merged

feat: add PriceUtils#657
robercano merged 2 commits intomainfrom
rcano/add-price-utils

Conversation

@robercano
Copy link
Collaborator

@robercano robercano commented Jan 22, 2026

Description

Adapting PriceUtils.sol from monorepo to the new version of PRB. Also bumping up the interface to make it more efficient and easy to use.

Changes

  • Ported PRB usage from 2.5 to 4.1
  • Rewritten PriceUtils to include a custom Price type
  • Added overloads for Price to invert it and quote an amount
  • Added overload for uint256 to be able to multiply it or divide it by a Price
  • Added convenience function toPrice to create Price instances

Benefits

  1. Optimized version of Price: decimals scaling is built-in into the arithmetic and the price can be inverted cheaply
  2. Easier interface that aids in using the library correctly

Testing

Added unit tests with several test cases to demonstrate that the library works properly. Particularle I've added tests cases to check for the decimal conversion

Next steps

  • invert() could be optimized further by including a flag in the Price structure to indicate if the value is inverted or not, and use the flag to know which value is base and which one is quote

Please review and provide any feedback or suggestions for improvement.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a Solidity price utility library with support for converting between base and quote asset values
    • Introduced price type and functions for price inversion, amount quoting, and chained price calculations
    • Added comprehensive test coverage for price conversion operations
  • Chores

    • Added project configuration, development tooling, and documentation for the new price utilities package

✏️ Tip: You can customize this high-level summary in your review settings.

@robercano robercano self-assigned this Jan 22, 2026
@robercano robercano requested a review from halaprix January 22, 2026 10:59
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

Walkthrough

Introduces a new Solidity library package (@summerfi/price-solidity) under packages/price-utils providing price utilities for base/quote conversions. Includes type definitions, constructors, helper functions, and comprehensive test coverage with supporting configuration files.

Changes

Cohort / File(s) Summary
Configuration & Build
.editorconfig, .gitpod.yml, .solhint.json, foundry.toml, remappings.txt
Editor, development environment, linter, compiler, and import remapping configurations.
Documentation & Metadata
LICENSE.md, README.md, package.json
MIT license, library documentation with examples, and npm package manifest.
Core Library
contracts/Types.sol, contracts/Constants.sol, contracts/Constructor.sol, contracts/Helpers.sol, contracts/Utils.sol, contracts/PriceUtils.sol
Price struct definition, default decimals constant, price constructor, amount normalization helper, and price conversion utilities (invert, quote, mul, div).
Testing & Coverage
test/PriceUtils.t.sol, lcov.info
11 comprehensive test functions covering quote, invert, compound prices, and chaining operations; coverage report artifact.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A price library blooms, so neat,
Base and quote amounts now meet,
Conversion magic, decimals flow,
Tests ensure the functions glow! 🌸✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main feature addition of the PriceUtils library.
Description check ✅ Passed Description matches template structure with complete sections: Description, Changes, Benefits, Testing, and Next steps. All required information is provided.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch rcano/add-price-utils

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@packages/price-utils/contracts/Helpers.sol`:
- Around line 17-22: The exponentiation 10 ** exp can overflow for exp > 77; add
a guard that requires exp <= 77 (or a safe max) before computing 10 ** exp and
revert with a clear error message; apply this check in both branches where exp
is computed (the branch comparing amountDecimals and targetDecimals, referencing
the local variable exp and the surrounding function in Helpers.sol) so the
function validates the bound before performing the multiplication/division.

In `@packages/price-utils/foundry.toml`:
- Line 24: The TOML contains a deprecated goerli network entry (goerli = { key =
"${API_KEY_ETHERSCAN}" }); remove or replace it with the current Holesky network
entry (e.g., holesky = { key = "${API_KEY_ETHERSCAN}" }) and update any other
identical occurrences mentioned (the second occurrence at the other location) so
references and env usage remain consistent; ensure you only change the network
name(s) and preserve the API key variable name unless you also plan to rename
the env var.
🧹 Nitpick comments (3)
packages/price-utils/test/PriceUtils.t.sol (1)

15-245: Consider adding fuzz tests.

Good coverage of fixed cases. Add fuzz tests to catch edge cases (overflow, zero values, extreme decimals).

function testFuzz_quote(uint256 baseAmount, uint256 quoteAmount, uint256 input) public pure {
    vm.assume(baseAmount > 0 && quoteAmount > 0);
    vm.assume(input < type(uint256).max / baseAmount); // prevent overflow
    Price memory price = toPrice(baseAmount, quoteAmount);
    price.quote(input); // should not revert
}
packages/price-utils/contracts/Utils.sol (2)

97-102: div() allocates intermediate Price on every call.

As noted in PR for future optimization - invert() creates new memory struct. Consider lazy inversion flag later.


53-61: Zero quoteAmount causes opaque revert.

PRB Math will revert on division by zero but error message won't indicate price context. Consider explicit check if better UX needed.

Comment on lines +17 to +22
if (amountDecimals > targetDecimals) {
uint8 exp = amountDecimals - targetDecimals;
return amount / (10 ** exp);
} else if (amountDecimals < targetDecimals) {
uint8 exp = targetDecimals - amountDecimals;
return amount * (10 ** exp);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard exponent overflow in scaling.
10 ** exp overflows for exp > 77, causing revert. Add a bound check with a clear error.

Proposed fix
+error DecimalsOverflow(uint8 amountDecimals, uint8 targetDecimals);
+
 function _normalizeAmount(
     uint256 amount,
     uint8 amountDecimals,
     uint8 targetDecimals
 ) pure returns (uint256) {
     if (amountDecimals > targetDecimals) {
         uint8 exp = amountDecimals - targetDecimals;
+        if (exp > 77) revert DecimalsOverflow(amountDecimals, targetDecimals);
         return amount / (10 ** exp);
     } else if (amountDecimals < targetDecimals) {
         uint8 exp = targetDecimals - amountDecimals;
+        if (exp > 77) revert DecimalsOverflow(amountDecimals, targetDecimals);
         return amount * (10 ** exp);
     } else {
         return amount;
     }
 }
🤖 Prompt for AI Agents
In `@packages/price-utils/contracts/Helpers.sol` around lines 17 - 22, The
exponentiation 10 ** exp can overflow for exp > 77; add a guard that requires
exp <= 77 (or a safe max) before computing 10 ** exp and revert with a clear
error message; apply this check in both branches where exp is computed (the
branch comparing amountDecimals and targetDecimals, referencing the local
variable exp and the surrounding function in Helpers.sol) so the function
validates the bound before performing the multiplication/division.

avalanche = { key = "${API_KEY_SNOWTRACE}" }
base = { key = "${API_KEY_BASESCAN}" }
gnosis_chain = { key = "${API_KEY_GNOSISSCAN}" }
goerli = { key = "${API_KEY_ETHERSCAN}" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Goerli testnet deprecated.

Goerli reached EOL in March 2023. Consider removing these references or replacing with Holesky.

Also applies to: 46-46

🤖 Prompt for AI Agents
In `@packages/price-utils/foundry.toml` at line 24, The TOML contains a deprecated
goerli network entry (goerli = { key = "${API_KEY_ETHERSCAN}" }); remove or
replace it with the current Holesky network entry (e.g., holesky = { key =
"${API_KEY_ETHERSCAN}" }) and update any other identical occurrences mentioned
(the second occurrence at the other location) so references and env usage remain
consistent; ensure you only change the network name(s) and preserve the API key
variable name unless you also plan to rename the env var.

@robercano robercano merged commit 6746a13 into main Feb 6, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant