Created
May 31, 2024 16:08
-
-
Save sambacha/e91e3a0f8a24436c98ea0e062018097c to your computer and use it in GitHub Desktop.
Solidity BigNumber Assertions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// SPDX-License-Identifier: GPL-2.0 | |
pragma solidity ^0.8.9; | |
import "forge-std/Test.sol"; | |
/// @title BigNumberAssertions | |
contract BigNumberAssertions is Test { | |
uint256 constant fullScale = 10**18; | |
/** | |
* @dev Asserts that two uint256 values are within a certain variance of each other. | |
* @param actual The actual value received | |
* @param expected The expected value | |
* @param variance The allowable variance | |
* @param reason An optional reason for the assertion | |
*/ | |
function assertBNClose( | |
uint256 actual, | |
uint256 expected, | |
uint256 variance, | |
string memory reason | |
) public { | |
uint256 actualDelta = actual > expected ? actual - expected : expected - actual; | |
string memory str = bytes(reason).length > 0 ? string(abi.encodePacked("\n\tReason: ", reason, "\n\t", uint2str(actual), " vs ", uint2str(expected))) : ""; | |
assertTrue(actual >= expected - variance, string(abi.encodePacked("Number is too small to be close (Delta between actual and expected is ", uint2str(actualDelta), ", but variance was only ", uint2str(variance), str))); | |
assertTrue(actual <= expected + variance, string(abi.encodePacked("Number is too large to be close (Delta between actual and expected is ", uint2str(actualDelta), ", but variance was only ", uint2str(variance), str))); | |
} | |
/** | |
* @dev Asserts that two uint256 values are within a certain percentage of each other. | |
* @param a The first value | |
* @param b The second value | |
* @param variance The allowable variance as a percentage | |
* @param reason An optional reason for the assertion | |
*/ | |
function assertBNClosePercent( | |
uint256 a, | |
uint256 b, | |
uint256 variance, | |
string memory reason | |
) public { | |
if (a == b) return; | |
uint256 diff = (a > b ? a - b : b - a) * 2 * fullScale / (a + b); | |
string memory str = bytes(reason).length > 0 ? string(abi.encodePacked("\n\tReason: ", reason, "\n\t", uint2str(a), " vs ", uint2str(b))) : ""; | |
assertTrue(diff <= variance, string(abi.encodePacked("Numbers exceed variance limit (Difference between actual and expected is ", uint2str(diff), ", but variance was only ", uint2str(variance), str))); | |
} | |
/** | |
* @dev Asserts that one uint256 value is greater than or equal to another, but not exceeding a certain percentage increase. | |
* @param actual The actual value received | |
* @param equator The expected value | |
* @param maxPercentIncrease The maximum allowable percentage increase | |
* @param mustBeGreater If true, actual must be strictly greater than equator | |
*/ | |
function assertBNSlightlyGTPercent( | |
uint256 actual, | |
uint256 equator, | |
uint256 maxPercentIncrease, | |
bool mustBeGreater | |
) public { | |
uint256 maxIncreaseUnits = equator * maxPercentIncrease / fullScale; | |
assertTrue(mustBeGreater ? actual > equator : actual >= equator, "Actual value should be greater than the expected value"); | |
assertTrue(actual <= equator + maxIncreaseUnits, string(abi.encodePacked("Actual value should not exceed ", uint2str(maxPercentIncrease), "% greater than expected"))); | |
} | |
/** | |
* @dev Find a contract event by address and event name. | |
* @param receipt The transaction receipt to search | |
* @param address The address of the contract | |
* @param eventName The name of the event | |
*/ | |
function findContractEvent( | |
ContractReceipt memory receipt, | |
address contractAddress, | |
string memory eventName | |
) public pure returns (Event memory) { | |
for (uint i = 0; i < receipt.events.length; i++) { | |
if (keccak256(abi.encodePacked(receipt.events[i].address)) == keccak256(abi.encodePacked(contractAddress)) && | |
keccak256(abi.encodePacked(receipt.events[i].event)) == keccak256(abi.encodePacked(eventName))) { | |
return receipt.events[i]; | |
} | |
} | |
revert("Event not found"); | |
} | |
//! FIXME: | |
/** | |
* @dev Custom matcher for any value. | |
*/ | |
function anyValue() public pure returns (bool) { | |
return true; | |
} | |
function uint2str(uint256 _i) internal pure returns (string memory _uintAsString) { | |
if (_i == 0) { | |
return "0"; | |
} | |
uint256 j = _i; | |
uint256 len; | |
while (j != 0) { | |
len++; | |
j /= 10; | |
} | |
bytes memory bstr = new bytes(len); | |
uint256 k = len; | |
while (_i != 0) { | |
k = k - 1; | |
uint8 temp = (48 + uint8(_i - _i / 10 * 10)); | |
bytes1 b1 = bytes1(temp); | |
bstr[k] = b1; | |
_i /= 10; | |
} | |
return string(bstr); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment