Skip to content

Commit

Permalink
differential fuzzing of lib
Browse files Browse the repository at this point in the history
  • Loading branch information
0xgregthedev committed Oct 25, 2023
1 parent f013dd4 commit 739c10c
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 171 deletions.
64 changes: 64 additions & 0 deletions src/lib/RefStarPortLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
pragma solidity ^0.8.17;

import {ItemType, ReceivedItem, SpentItem} from "seaport-types/src/lib/ConsiderationStructs.sol";

import {LoanManager} from "starport-core/LoanManager.sol";
import "forge-std/console.sol";

enum Actions {
Nothing,
Origination,
Refinance,
Repayment,
Settlement
}

library RefStarPortLib {
error InvalidSalt();

uint256 internal constant ONE_WORD = 0x20;
uint256 internal constant CUSTODIAN_WORD_OFFSET = 0x40;

function getAction(bytes calldata data) internal pure returns (Actions action) {
assembly {
action := calldataload(data.offset)
}
}

function getCustodian(bytes calldata data) internal pure returns (address custodian) {
assembly {
custodian := calldataload(add(data.offset, CUSTODIAN_WORD_OFFSET))
}
}

function toReceivedItems(SpentItem[] calldata spentItems, address recipient)
internal
pure
returns (ReceivedItem[] memory consideration)
{
consideration = new ReceivedItem[](spentItems.length);
for (uint256 i = 0; i < spentItems.length;) {
consideration[i] = ReceivedItem({
itemType: spentItems[i].itemType,
token: spentItems[i].token,
identifier: spentItems[i].identifier,
amount: spentItems[i].amount,
recipient: payable(recipient)
});
unchecked {
++i;
}
}
}

function validateSalt(
mapping(address => mapping(bytes32 => bool)) storage usedSalts,
address borrower,
bytes32 salt
) internal {
if (usedSalts[borrower][salt]) {
revert InvalidSalt();
}
usedSalts[borrower][salt] = true;
}
}
16 changes: 2 additions & 14 deletions src/lib/StarPortLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -117,17 +117,6 @@ library StarPortLib {
}
}

function validateSaltRef(
mapping(address => mapping(bytes32 => bool)) storage usedSalts,
address borrower,
bytes32 salt
) internal {
if (usedSalts[borrower][salt]) {
revert InvalidSalt();
}
usedSalts[borrower][salt] = true;
}

function validateSalt(
mapping(address => mapping(bytes32 => bool)) storage usedSalts,
address borrower,
Expand All @@ -138,13 +127,12 @@ library StarPortLib {
mstore(0x20, usedSalts.slot)

//usedSalts[borrower]
let loc := keccak256(0x0, 0x40)

mstore(0x20, keccak256(0x0, 0x40))
mstore(0x0, salt)
mstore(0x20, loc)

//usedSalts[borrower][salt]
loc := keccak256(0x0, 0x40)
let loc := keccak256(0x0, 0x40)

//if (usedSalts[borrower][salt] == true)
if iszero(iszero(sload(loc))) {
Expand Down
140 changes: 140 additions & 0 deletions test/fuzz-testing/differential-fuzzing/TestStarPortLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
pragma solidity =0.8.17;

import "forge-std/Test.sol";
import {Vm} from "forge-std/Vm.sol";

import {ItemType, ReceivedItem, SpentItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {
ConsiderationItem,
AdvancedOrder,
CriteriaResolver,
OrderType
} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {Conduit} from "seaport-core/src/conduit/Conduit.sol";
import {ConduitController} from "seaport-core/src/conduit/ConduitController.sol";
import {StarPortLib} from "starport-core/lib/StarPortLib.sol";
import {RefStarPortLib} from "starport-core/lib/RefStarPortLib.sol";
import "starport-test/utils/FuzzStructs.sol" as Fuzz;
import {Bound} from "starport-test/utils/Bound.sol";
import {DeepEq} from "starport-test/utils/DeepEq.sol";

contract DiffFuzzTestStarPortLib is Test, Bound, DeepEq {
StarPortLibImpl testContract;
RefStarPortLibImpl refContract;

function setUp() public {
testContract = new StarPortLibImpl();
refContract = new RefStarPortLibImpl();
}

function testSpentToReceived(Fuzz.SpentItem[] memory unbSpentItems) public view {
SpentItem[] memory spentItems = _boundSpentItems(unbSpentItems);

ReceivedItem[] memory consideration0 = testContract.toReceivedItems(spentItems, address(1));
ReceivedItem[] memory consideration1 = refContract.toReceivedItems(spentItems, address(1));

_deepEq(consideration0, consideration1);
}

function testUnboundSpentToReceived(Fuzz.SpentItem[] memory unbSpentItems) public {
console.log("testUnboundSpentToReceived");
(bool success,) = address(refContract).call(
abi.encodeWithSelector(RefStarPortLibImpl.toReceivedItems.selector, unbSpentItems, address(1))
);
bool expectRevert = !success;

(success,) = address(testContract).call(
abi.encodeWithSelector(StarPortLibImpl.toReceivedItems.selector, unbSpentItems, address(1))
);
if (expectRevert) {
assertTrue(!success, "expected revert");
} else {
assertTrue(success, "expected success");
}
}

}

abstract contract BaseTestStarPortLib is Test {
StarPortLibImpl testContract;

function _setUp(address testImpl) internal {
testContract = StarPortLibImpl(testImpl);
}

function testValidateSalt(address user, bytes32 salt) public {
testContract.validateSalt(user, salt);

assert(testContract.usedSalts(user, salt));

vm.expectRevert(abi.encodeWithSelector(StarPortLib.InvalidSalt.selector));
testContract.validateSalt(user, salt);
}

function testSpentToReceived() public {
SpentItem[] memory spentItems = new SpentItem[](2);
spentItems[0] = SpentItem({itemType: ItemType.ERC20, token: address(2), identifier: 3, amount: 4});

spentItems[1] = SpentItem({itemType: ItemType.ERC20, token: address(2), identifier: 3, amount: 4});

address recipient = address(1);
ReceivedItem[] memory consideration0 = testContract.toReceivedItems(spentItems, recipient);

assertEq(consideration0.length, spentItems.length);
for (uint256 i = 0; i < consideration0.length; i++) {
assert(consideration0[i].itemType == spentItems[i].itemType);
assertEq(consideration0[i].token, spentItems[i].token);
assertEq(consideration0[i].identifier, spentItems[i].identifier);
assertEq(consideration0[i].amount, spentItems[i].amount);
assertEq(consideration0[i].recipient, recipient);
}
}
}

contract TestStarPortLib is BaseTestStarPortLib {
function setUp() public {
_setUp(address(new StarPortLibImpl()));
}
}

contract TestRefStarPortLib is BaseTestStarPortLib {
function setUp() public {
_setUp(address(new RefStarPortLibImpl()));
}
}

contract StarPortLibImpl {
using RefStarPortLib for *;

mapping(address => mapping(bytes32 => bool)) public usedSalts;

function toReceivedItems(SpentItem[] calldata spentItems, address recipient)
external
pure
returns (ReceivedItem[] memory consideration)
{
return spentItems.toReceivedItems(recipient);
}

function validateSalt(address user, bytes32 salt) external {
usedSalts.validateSalt(user, salt);
}
}

contract RefStarPortLibImpl {
using RefStarPortLib for *;

mapping(address => mapping(bytes32 => bool)) public usedSalts;

function toReceivedItems(SpentItem[] calldata spentItems, address recipient)
external
pure
returns (ReceivedItem[] memory consideration)
{
return spentItems.toReceivedItems(recipient);
}

function validateSalt(address user, bytes32 salt) external {
usedSalts.validateSalt(user, salt);
}
}
157 changes: 0 additions & 157 deletions test/fuzz-testing/differential-fuzzing/TestUtils.sol

This file was deleted.

0 comments on commit 739c10c

Please sign in to comment.