packages/contracts-core/test/suite/libs/stack/Tips.t.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {SynapseLibraryTest, MemViewLib} from "../../../utils/SynapseLibraryTest.t.sol";
import {Tips, TipsHarness} from "../../../harnesses/libs/stack/TipsHarness.t.sol";
import {TipsOverflow, TipsValueTooLow} from "../../../../contracts/libs/Errors.sol";
import {TIPS_MULTIPLIER, TIPS_LENGTH} from "../../../../contracts/libs/Constants.sol";
import {RawTips} from "../../../utils/libs/SynapseStructs.t.sol";
// solhint-disable func-name-mixedcase
contract TipsLibraryTest is SynapseLibraryTest {
using MemViewLib for bytes;
TipsHarness internal libHarness;
function setUp() public {
libHarness = new TipsHarness();
}
function test_encodeTips(RawTips memory rt) public {
uint256 totalTips = uint256(rt.summitTip) + rt.attestationTip + rt.executionTip + rt.deliveryTip;
vm.assume(totalTips <= type(uint64).max);
// Test encoding
uint256 encodedTips = libHarness.encodeTips(rt.summitTip, rt.attestationTip, rt.executionTip, rt.deliveryTip);
uint256 expected = uint256(rt.summitTip) * 2 ** 192 + uint256(rt.attestationTip) * 2 ** 128
+ uint256(rt.executionTip) * 2 ** 64 + uint256(rt.deliveryTip);
assertEq(encodedTips, expected, "!encodeTips");
assertEq(libHarness.wrapPadded(encodedTips), expected, "!wrapPadded");
// Test getters
assertEq(libHarness.summitTip(encodedTips), rt.summitTip, "!summitTip");
assertEq(libHarness.attestationTip(encodedTips), rt.attestationTip, "!attestationTip");
assertEq(libHarness.executionTip(encodedTips), rt.executionTip, "!executionTip");
assertEq(libHarness.deliveryTip(encodedTips), rt.deliveryTip, "!deliveryTip");
assertEq(libHarness.value(encodedTips), totalTips * TIPS_MULTIPLIER, "!totalTips");
// Test hashing
assertEq(libHarness.leaf(encodedTips), keccak256(abi.encode(expected)), "!leaf");
}
function test_encodeTips256(uint96 summitTip, uint96 attestationTip, uint96 executionTip, uint96 deliveryTip)
public
{
uint256 encodedTips256 = libHarness.encodeTips256(summitTip, attestationTip, executionTip, deliveryTip);
uint256 encodedTips = libHarness.encodeTips(
uint64(summitTip / TIPS_MULTIPLIER),
uint64(attestationTip / TIPS_MULTIPLIER),
uint64(executionTip / TIPS_MULTIPLIER),
uint64(deliveryTip / TIPS_MULTIPLIER)
);
assertEq(encodedTips256, encodedTips, "!encodeTips256");
}
function test_matchTips(RawTips memory rt, uint256 newValue) public {
uint256 totalTips = uint256(rt.summitTip) + rt.attestationTip + rt.executionTip + rt.deliveryTip;
vm.assume(totalTips <= type(uint64).max);
uint256 maxNewTotalTips = uint256(rt.summitTip) + rt.attestationTip + rt.executionTip + type(uint64).max;
newValue = bound(newValue, totalTips * TIPS_MULTIPLIER, maxNewTotalTips * TIPS_MULTIPLIER);
Tips newTips = libHarness.matchValue(rt.castToTips(), newValue);
// Should not exceed newValue
assertLe(newTips.value(), newValue);
// Increasing the delivery tip by one should exceed newValue
if (newTips.deliveryTip() < type(uint64).max) {
newTips = Tips.wrap(Tips.unwrap(newTips) + 1);
assertGt(newTips.value(), newValue);
}
}
function test_matchTips_revert_newValueTooLow(RawTips memory rt, uint256 newValue) public {
uint256 totalTips = uint256(rt.summitTip) + rt.attestationTip + rt.executionTip + rt.deliveryTip;
vm.assume(totalTips != 0 && totalTips <= type(uint64).max);
newValue = bound(newValue, 0, totalTips * TIPS_MULTIPLIER - 1);
vm.expectRevert(TipsValueTooLow.selector);
libHarness.matchValue(rt.castToTips(), newValue);
}
function test_matchTips_revert_tipsOverflow(RawTips memory rt, uint256 newValue) public {
uint256 totalTips = uint256(rt.summitTip) + rt.attestationTip + rt.executionTip + rt.deliveryTip;
vm.assume(totalTips <= type(uint64).max);
uint256 overflowTotalTips = uint256(rt.summitTip) + rt.attestationTip + rt.executionTip + 1 << 64;
newValue = bound(newValue, overflowTotalTips * TIPS_MULTIPLIER, type(uint256).max);
vm.expectRevert(TipsOverflow.selector);
libHarness.matchValue(rt.castToTips(), newValue);
}
function test_emptyTips() public {
test_encodeTips(RawTips(0, 0, 0, 0));
assertEq(libHarness.emptyTips(), 0, "!emptyTips");
}
function test_tipsLength(RawTips memory rt) public {
assertEq(
abi.encodePacked(libHarness.encodeTips(rt.summitTip, rt.attestationTip, rt.executionTip, rt.deliveryTip))
.length,
TIPS_LENGTH
);
}
}