Skip to content

Commit 1ff7aef

Browse files
authored
chore: do not rely on src libraries in test libraries (#210)
## Description We define a broad set of library functions to make testing the contracts in `src` easier. However, these libraries themselves rely on the tested contracts. This could lead to issues when the tests pass because both the libraries and the files in `src` are broken in the same way. To guarantee that tests are independent of the tested libraries, all use of `src` libraries has been removed. ## What I really wanted Unfortunately, it's still possible that we forget about this and use some function in, e.g., `GPv2Order` in the test library, especially since we need to import this library to get related types and constants. I tried to create a Solidity file that reexports everything we need from the libraries without the functions themselves (this would, for example, allow us to define a custom linting rule asserting that there's no import from `src` in any test file) but I was unsuccessful. It was very easy to reexport contracts (e.g., `GPv2Settlement`) and interfaces (e.g., `IERC20`), and it was also easy to reexport constants (e.g., `GPv2Order.KIND_SELL`), The issue was with reexporting type structs: to my understanding, this is impossible in Solidity ≤0.8.26, confirmed by the fact that there is no statement that appears to enable this use case in the [language grammar](https://docs.soliditylang.org/en/v0.8.26/grammar.html). Since neither reexporting everything but the structs nor reexporting the entire libraries make sense, I decided to keep everything as it is without further reexporting. ## Test Plan Nothing broken in CI.
1 parent 5957d67 commit 1ff7aef

File tree

4 files changed

+36
-24
lines changed

4 files changed

+36
-24
lines changed

test/libraries/Order.sol

+27-17
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22
pragma solidity ^0.8;
33

44
import {GPv2Order, IERC20} from "src/contracts/libraries/GPv2Order.sol";
5-
import {GPv2Trade} from "src/contracts/libraries/GPv2Trade.sol";
65

7-
library Order {
8-
using GPv2Order for GPv2Order.Data;
9-
using GPv2Order for bytes;
10-
using GPv2Trade for uint256;
6+
import {Eip712} from "./Eip712.sol";
117

8+
library Order {
129
/// Order flags
1310
struct Flags {
1411
bytes32 kind;
@@ -134,10 +131,24 @@ library Order {
134131
}
135132
}
136133

137-
/// @dev Given a GPv2Trade encoded flags, decode them into a `Flags` struct
138-
function toFlags(uint256 encodedFlags) internal pure returns (Flags memory flags) {
139-
(flags.kind, flags.partiallyFillable, flags.sellTokenBalance, flags.buyTokenBalance,) =
140-
encodedFlags.extractFlags();
134+
/// @dev Given a GPv2Trade encoded flags, decode them into a `Flags` struct.
135+
/// See GPv2Trade.extractFlags for a complete definition of each flag.
136+
function toFlags(uint256 encodedFlags) internal pure returns (Flags memory) {
137+
bytes32 sellTokenBalance;
138+
if (encodedFlags & 0x08 == 0) {
139+
sellTokenBalance = GPv2Order.BALANCE_ERC20;
140+
} else if (encodedFlags & 0x04 == 0) {
141+
sellTokenBalance = GPv2Order.BALANCE_EXTERNAL;
142+
} else {
143+
sellTokenBalance = GPv2Order.BALANCE_INTERNAL;
144+
}
145+
146+
return Flags({
147+
kind: (encodedFlags & 0x01 == 0) ? GPv2Order.KIND_SELL : GPv2Order.KIND_BUY,
148+
partiallyFillable: encodedFlags & 0x02 != 0,
149+
sellTokenBalance: sellTokenBalance,
150+
buyTokenBalance: (encodedFlags & 0x10 == 0) ? GPv2Order.BALANCE_ERC20 : GPv2Order.BALANCE_INTERNAL
151+
});
141152
}
142153

143154
/// @dev Computes the order UID for an order and the given owner
@@ -146,17 +157,16 @@ library Order {
146157
pure
147158
returns (bytes memory)
148159
{
149-
return computeOrderUid(order.hash(domainSeparator), owner, order.validTo);
160+
return computeOrderUid(hash(order, domainSeparator), owner, order.validTo);
150161
}
151162

152163
/// @dev Computes the order UID for its base components
153-
function computeOrderUid(bytes32 orderHash, address owner, uint32 validTo)
154-
internal
155-
pure
156-
returns (bytes memory orderUid)
157-
{
158-
orderUid = new bytes(GPv2Order.UID_LENGTH);
159-
orderUid.packOrderUidParams(orderHash, owner, validTo);
164+
function computeOrderUid(bytes32 orderHash, address owner, uint32 validTo) internal pure returns (bytes memory) {
165+
return abi.encodePacked(orderHash, owner, validTo);
166+
}
167+
168+
function hash(GPv2Order.Data memory order, bytes32 domainSeparator) internal pure returns (bytes32) {
169+
return Eip712.typedDataHash(Eip712.toEip712SignedStruct(order), domainSeparator);
160170
}
161171

162172
function fuzz(Fuzzed memory params) internal pure returns (GPv2Order.Data memory) {

test/libraries/Sign.sol

+9-5
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ pragma solidity ^0.8;
33

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

6-
import {EIP1271Verifier, GPv2Order, GPv2Signing, GPv2Trade} from "src/contracts/mixins/GPv2Signing.sol";
6+
import {EIP1271Verifier, GPv2Order, GPv2Signing} from "src/contracts/mixins/GPv2Signing.sol";
77

88
import {Bytes} from "./Bytes.sol";
9+
import {Order} from "./Order.sol";
910

1011
type PreSignSignature is address;
1112

1213
library Sign {
13-
using GPv2Order for GPv2Order.Data;
14-
using GPv2Trade for uint256;
1514
using Bytes for bytes;
15+
using Order for GPv2Order.Data;
1616

1717
// Copied from GPv2Signing.sol
1818
uint256 internal constant PRE_SIGNED = uint256(keccak256("GPv2Signing.Scheme.PreSign"));
@@ -123,8 +123,12 @@ library Sign {
123123
}
124124

125125
/// @dev Given a GPv2Trade encoded flags, decode them into a `GPv2Signing.Scheme`
126-
function toSigningScheme(uint256 encodedFlags) internal pure returns (GPv2Signing.Scheme signingScheme) {
127-
(,,,, signingScheme) = encodedFlags.extractFlags();
126+
function toSigningScheme(uint256 encodedFlags) internal pure returns (GPv2Signing.Scheme) {
127+
uint256 encodedScheme = (encodedFlags >> 5);
128+
if (encodedScheme >= 4) {
129+
revert("invalid flag encoding, trying to use invalid signature scheme");
130+
}
131+
return GPv2Signing.Scheme(encodedScheme);
128132
}
129133

130134
/// @dev Internal helper function for EthSign signatures (non-EIP-712)

test/libraries/Trade.sol

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {Sign} from "./Sign.sol";
66
import {GPv2Order, GPv2Signing, GPv2Trade, IERC20} from "src/contracts/mixins/GPv2Signing.sol";
77

88
library Trade {
9-
using GPv2Trade for uint256;
109
using Order for Order.Flags;
1110
using Order for uint256;
1211
using Sign for GPv2Signing.Scheme;

test/libraries/encoders/SettlementEncoder.sol

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {Trade} from "../Trade.sol";
1818
import {Registry, TokenRegistry} from "./TokenRegistry.sol";
1919

2020
library SettlementEncoder {
21-
using GPv2Order for GPv2Order.Data;
2221
using Trade for GPv2Order.Data;
2322
using Sign for Vm;
2423
using TokenRegistry for TokenRegistry.State;

0 commit comments

Comments
 (0)