From d2371f2c8e21a51c7aa98b7427a5c0890fadf41b Mon Sep 17 00:00:00 2001 From: Flocqst Date: Mon, 25 Mar 2024 16:20:10 +0100 Subject: [PATCH 1/4] =?UTF-8?q?=E2=9C=85=20Test=20Signature=20Checker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/SignatureCheckerLib.t.sol | 178 +++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/test/SignatureCheckerLib.t.sol b/test/SignatureCheckerLib.t.sol index aba8028a..0b6884af 100644 --- a/test/SignatureCheckerLib.t.sol +++ b/test/SignatureCheckerLib.t.sol @@ -20,4 +20,182 @@ contract SignatureCheckerLibTest is Test { } /// @custom:reference github.com/Vectorized/solady/blob/main/test/SignatureCheckerLib.t.sol + function testSignatureChecker(bytes32 digest) public { + (address signer, uint256 privateKey) = _randomSigner(); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); + + if (_random() % 8 == 0) { + assertEq( + this.isValidSignatureNowCalldata(signer, digest, abi.encodePacked(r, s, v)), true + ); + } + + if (_random() % 8 == 0) { + bytes32 vs; + /// @solidity memory-safe-assembly + assembly { + vs := or(shl(255, sub(v, 27)), s) + } + assertEq(this.isValidSignatureNowCalldata(signer, digest, abi.encode(r, vs)), true); + } + + if (_random() % 8 == 0) { + bytes32 vsc; // Corrupted `vs`. + /// @solidity memory-safe-assembly + assembly { + vsc := or(shl(255, xor(1, sub(v, 27))), s) + } + assertEq(this.isValidSignatureNowCalldata(signer, digest, abi.encode(r, vsc)), false); + } + + if (_random() % 8 == 0) { + uint8 vc = uint8(_random()); // Corrupted `v`. + while (vc == 28 || vc == 27) vc = uint8(_random()); + assertEq( + this.isValidSignatureNowCalldata(signer, digest, abi.encodePacked(r, s, vc)), false + ); + } + } + + function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature) + external + view + returns (bool result) + { + result = SignatureCheckerLib.isValidSignatureNowCalldata(signer, hash, signature); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* SIGNATURE CHECKING TEST UTILS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns a pseudorandom random number from [0 .. 2**256 - 1] (inclusive). + /// For usage in fuzz tests, please ensure that the function has an unnamed uint256 argument. + /// e.g. `testSomething(uint256) public`. + function _random() internal returns (uint256 r) { + /// @solidity memory-safe-assembly + assembly { + // This is the keccak256 of a very long string I randomly mashed on my keyboard. + let sSlot := 0xd715531fe383f818c5f158c342925dcf01b954d24678ada4d07c36af0f20e1ee + let sValue := sload(sSlot) + + mstore(0x20, sValue) + r := keccak256(0x20, 0x40) + + // If the storage is uninitialized, initialize it to the keccak256 of the calldata. + if iszero(sValue) { + sValue := sSlot + let m := mload(0x40) + calldatacopy(m, 0, calldatasize()) + r := keccak256(m, calldatasize()) + } + sstore(sSlot, add(r, 1)) + + // Do some biased sampling for more robust tests. + // prettier-ignore + for {} 1 {} { + let d := byte(0, r) + // With a 1/256 chance, randomly set `r` to any of 0,1,2. + if iszero(d) { + r := and(r, 3) + break + } + // With a 1/2 chance, set `r` to near a random power of 2. + if iszero(and(2, d)) { + // Set `t` either `not(0)` or `xor(sValue, r)`. + let t := xor(not(0), mul(iszero(and(4, d)), not(xor(sValue, r)))) + // Set `r` to `t` shifted left or right by a random multiple of 8. + switch and(8, d) + case 0 { + if iszero(and(16, d)) { t := 1 } + r := add(shl(shl(3, and(byte(3, r), 0x1f)), t), sub(and(r, 7), 3)) + } + default { + if iszero(and(16, d)) { t := shl(255, 1) } + r := add(shr(shl(3, and(byte(3, r), 0x1f)), t), sub(and(r, 7), 3)) + } + // With a 1/2 chance, negate `r`. + if iszero(and(0x20, d)) { r := not(r) } + break + } + // Otherwise, just set `r` to `xor(sValue, r)`. + r := xor(sValue, r) + break + } + } + } + + /// @dev Returns a random signer and its private key. + function _randomSigner() internal returns (address signer, uint256 privateKey) { + uint256 privateKeyMax = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140; + privateKey = _hem(_random(), 1, privateKeyMax); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, 0xffa18649) // `addr(uint256)`. + mstore(0x20, privateKey) + if iszero(call(gas(), 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, 0, 0x1c, 0x24, 0x00, 0x20)) { revert(0, 0) } + signer := mload(0x00) + } + } + + /// @dev Adapted from `bound`: + /// https://github.com/foundry-rs/forge-std/blob/ff4bf7db008d096ea5a657f2c20516182252a3ed/src/StdUtils.sol#L10 + /// Differentially fuzzed tested against the original implementation. + function _hem(uint256 x, uint256 min, uint256 max) + internal + pure + virtual + returns (uint256 result) + { + require(min <= max, "Max is less than min."); + + /// @solidity memory-safe-assembly + assembly { + // prettier-ignore + for {} 1 {} { + // If `x` is between `min` and `max`, return `x` directly. + // This is to ensure that dictionary values + // do not get shifted if the min is nonzero. + // More info: https://github.com/foundry-rs/forge-std/issues/188 + if iszero(or(lt(x, min), gt(x, max))) { + result := x + break + } + + let size := add(sub(max, min), 1) + if and(iszero(gt(x, 3)), gt(size, x)) { + result := add(min, x) + break + } + + let w := not(0) + if and(iszero(lt(x, sub(0, 4))), gt(size, sub(w, x))) { + result := sub(max, sub(w, x)) + break + } + + // Otherwise, wrap x into the range [min, max], + // i.e. the range is inclusive. + if iszero(lt(x, max)) { + let d := sub(x, max) + let r := mod(d, size) + if iszero(r) { + result := max + break + } + result := add(add(min, r), w) + break + } + let d := sub(min, x) + let r := mod(d, size) + if iszero(r) { + result := min + break + } + result := add(sub(max, r), 1) + break + } + } + } } From a68d403e5721fc0168c98988c335639e63e14299 Mon Sep 17 00:00:00 2001 From: Flocqst Date: Wed, 27 Mar 2024 15:45:58 +0100 Subject: [PATCH 2/4] =?UTF-8?q?=E2=9C=85=20Add=20tests=20for=20EIP712?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/EIP712.t.sol | 215 +++++++++++++++++++++++++++++--- test/utils/mocks/MockEIP712.sol | 75 +++++++++++ 2 files changed, 272 insertions(+), 18 deletions(-) create mode 100644 test/utils/mocks/MockEIP712.sol diff --git a/test/EIP712.t.sol b/test/EIP712.t.sol index 151c7208..4f789fa5 100644 --- a/test/EIP712.t.sol +++ b/test/EIP712.t.sol @@ -3,11 +3,13 @@ pragma solidity 0.8.20; import {Test} from "lib/forge-std/src/Test.sol"; import {EIP712} from "src/utils/EIP712.sol"; +import {MockEIP712} from "./utils/mocks/MockEIP712.sol"; contract EIP712Test is Test, EIP712 { - function test_constructor() public pure { - /// @custom:write-test-here - assert(true); + MockEIP712 mock; + + function setUp() public { + mock = new MockEIP712(); } function test_domainNameAndVersion() public pure { @@ -22,30 +24,207 @@ contract EIP712Test is Test, EIP712 { ); } - function test_DOMAIN_SEPARATOR() public pure { - /// @custom:write-test-here - assert(true); + function test_DOMAIN_SEPARATOR() public { + bytes32 expectedDomainSeparator = keccak256( + abi.encode( + keccak256( + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + ), + keccak256("SMv3: OrderBook"), + keccak256("1"), + block.chainid, + address(mock) + ) + ); + assertEq(mock.DOMAIN_SEPARATOR(), expectedDomainSeparator); } - function test_hashTypedData() public pure { - /// @custom:write-test-here - assert(true); + + function test_hashTypedData() public { + (address signer, uint256 privateKey) = _randomSigner(); + + (address to,) = _randomSigner(); + + string memory message = "Test SMv3"; + + bytes32 structHash = + keccak256(abi.encode("Message(address to,string message)", to, message)); + bytes32 expectedDigest = + keccak256(abi.encodePacked("\x19\x01", mock.DOMAIN_SEPARATOR(), structHash)); + + assertEq(mock.hashTypedData(structHash), expectedDigest); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, expectedDigest); + + address recoveredAddress = ecrecover(expectedDigest, v, r, s); + + assertEq(recoveredAddress, signer); } - function test_eip712Domain() public pure { - /// @custom:write-test-here - assert(true); + struct _testEIP5267Variables { + bytes1 fields; + string name; + string version; + uint256 chainId; + address verifyingContract; + bytes32 salt; + uint256[] extensions; } + function test_eip712Domain() public { + _testEIP5267Variables memory t; + (t.fields, t.name, t.version, t.chainId, t.verifyingContract, t.salt, t.extensions) = + mock.eip712Domain(); - function test_buildDomainSeparator() public pure { - /// @custom:write-test-here - assert(true); + assertEq(t.fields, hex"0f"); + assertEq(t.name, "SMv3: OrderBook"); + assertEq(t.version, "1"); + assertEq(t.chainId, block.chainid); + assertEq(t.verifyingContract, address(mock)); + assertEq(t.salt, bytes32(0)); + assertEq(t.extensions, new uint256[](0)); } - function test_cachedDomainSeparatorInvalidated() public pure { - /// @custom:write-test-here - assert(true); + function test_buildDomainSeparator() public { + bytes32 separator = mock.buildDomainSeparator(); + assertEq(separator, mock._cachedDomainSeparator()); + } + + function test_cachedDomainSeparatorInvalidated() public { + assertFalse(mock.cachedDomainSeparatorInvalidated()); } /// @custom:reference github.com/Vectorized/solady/blob/main/test/EIP712.t.sol + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* SIGNATURE CHECKING TEST UTILS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns a pseudorandom random number from [0 .. 2**256 - 1] (inclusive). + /// For usage in fuzz tests, please ensure that the function has an unnamed uint256 argument. + /// e.g. `testSomething(uint256) public`. + function _random() internal returns (uint256 r) { + /// @solidity memory-safe-assembly + assembly { + // This is the keccak256 of a very long string I randomly mashed on my keyboard. + let sSlot := 0xd715531fe383f818c5f158c342925dcf01b954d24678ada4d07c36af0f20e1ee + let sValue := sload(sSlot) + + mstore(0x20, sValue) + r := keccak256(0x20, 0x40) + + // If the storage is uninitialized, initialize it to the keccak256 of the calldata. + if iszero(sValue) { + sValue := sSlot + let m := mload(0x40) + calldatacopy(m, 0, calldatasize()) + r := keccak256(m, calldatasize()) + } + sstore(sSlot, add(r, 1)) + + // Do some biased sampling for more robust tests. + // prettier-ignore + for {} 1 {} { + let d := byte(0, r) + // With a 1/256 chance, randomly set `r` to any of 0,1,2. + if iszero(d) { + r := and(r, 3) + break + } + // With a 1/2 chance, set `r` to near a random power of 2. + if iszero(and(2, d)) { + // Set `t` either `not(0)` or `xor(sValue, r)`. + let t := xor(not(0), mul(iszero(and(4, d)), not(xor(sValue, r)))) + // Set `r` to `t` shifted left or right by a random multiple of 8. + switch and(8, d) + case 0 { + if iszero(and(16, d)) { t := 1 } + r := add(shl(shl(3, and(byte(3, r), 0x1f)), t), sub(and(r, 7), 3)) + } + default { + if iszero(and(16, d)) { t := shl(255, 1) } + r := add(shr(shl(3, and(byte(3, r), 0x1f)), t), sub(and(r, 7), 3)) + } + // With a 1/2 chance, negate `r`. + if iszero(and(0x20, d)) { r := not(r) } + break + } + // Otherwise, just set `r` to `xor(sValue, r)`. + r := xor(sValue, r) + break + } + } + } + + /// @dev Returns a random signer and its private key. + function _randomSigner() internal returns (address signer, uint256 privateKey) { + uint256 privateKeyMax = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140; + privateKey = _hem(_random(), 1, privateKeyMax); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, 0xffa18649) // `addr(uint256)`. + mstore(0x20, privateKey) + if iszero(call(gas(), 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, 0, 0x1c, 0x24, 0x00, 0x20)) { revert(0, 0) } + signer := mload(0x00) + } + } + + /// @dev Adapted from `bound`: + /// https://github.com/foundry-rs/forge-std/blob/ff4bf7db008d096ea5a657f2c20516182252a3ed/src/StdUtils.sol#L10 + /// Differentially fuzzed tested against the original implementation. + function _hem(uint256 x, uint256 min, uint256 max) + internal + pure + virtual + returns (uint256 result) + { + require(min <= max, "Max is less than min."); + + /// @solidity memory-safe-assembly + assembly { + // prettier-ignore + for {} 1 {} { + // If `x` is between `min` and `max`, return `x` directly. + // This is to ensure that dictionary values + // do not get shifted if the min is nonzero. + // More info: https://github.com/foundry-rs/forge-std/issues/188 + if iszero(or(lt(x, min), gt(x, max))) { + result := x + break + } + + let size := add(sub(max, min), 1) + if and(iszero(gt(x, 3)), gt(size, x)) { + result := add(min, x) + break + } + + let w := not(0) + if and(iszero(lt(x, sub(0, 4))), gt(size, sub(w, x))) { + result := sub(max, sub(w, x)) + break + } + + // Otherwise, wrap x into the range [min, max], + // i.e. the range is inclusive. + if iszero(lt(x, max)) { + let d := sub(x, max) + let r := mod(d, size) + if iszero(r) { + result := max + break + } + result := add(add(min, r), w) + break + } + let d := sub(min, x) + let r := mod(d, size) + if iszero(r) { + result := min + break + } + result := add(sub(max, r), 1) + break + } + } + } } diff --git a/test/utils/mocks/MockEIP712.sol b/test/utils/mocks/MockEIP712.sol new file mode 100644 index 00000000..15f3a4e2 --- /dev/null +++ b/test/utils/mocks/MockEIP712.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import "../../../src/utils/EIP712.sol"; + +/// @dev WARNING! This mock is strictly intended for testing purposes only. +/// Do NOT copy anything here into production code unless you really know what you are doing. +contract MockEIP712 is EIP712 { + + uint256 public immutable _cachedThis; + uint256 public immutable _cachedChainId; + bytes32 public immutable _cachedNameHash; + bytes32 public immutable _cachedVersionHash; + bytes32 public immutable _cachedDomainSeparator; + + constructor() { + _cachedThis = uint256(uint160(address(this))); + _cachedChainId = block.chainid; + + (string memory name, string memory version) = _domainNameAndVersion(); + bytes32 nameHash = keccak256(bytes(name)); + bytes32 versionHash = keccak256(bytes(version)); + _cachedNameHash = nameHash; + _cachedVersionHash = versionHash; + + bytes32 separator; + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Load the free memory pointer. + mstore(m, _DOMAIN_TYPEHASH) + mstore(add(m, 0x20), nameHash) + mstore(add(m, 0x40), versionHash) + mstore(add(m, 0x60), chainid()) + mstore(add(m, 0x80), address()) + separator := keccak256(m, 0xa0) + } + _cachedDomainSeparator = separator; + } + + function hashTypedData(bytes32 structHash) external view returns (bytes32) { + return _hashTypedData(structHash); + } + + /// @dev Returns the EIP-712 domain separator. + function buildDomainSeparator() public view returns (bytes32 separator) { + // We will use `separator` to store the name hash to save a bit of gas. + separator = _cachedNameHash; + bytes32 versionHash = _cachedVersionHash; + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Load the free memory pointer. + mstore(m, _DOMAIN_TYPEHASH) + mstore(add(m, 0x20), separator) + mstore(add(m, 0x40), versionHash) + mstore(add(m, 0x60), chainid()) + mstore(add(m, 0x80), address()) + separator := keccak256(m, 0xa0) + } + } + + /// @dev Returns if the cached domain separator has been invalidated. + function cachedDomainSeparatorInvalidated() + public + view + returns (bool result) + { + uint256 cachedChainId = _cachedChainId; + uint256 cachedThis = _cachedThis; + /// @solidity memory-safe-assembly + assembly { + result := + iszero(and(eq(chainid(), cachedChainId), eq(address(), cachedThis))) + } + } +} From dd75d566ffb09169d897f3a250be4b03bc414354 Mon Sep 17 00:00:00 2001 From: Flocqst Date: Wed, 27 Mar 2024 15:54:18 +0100 Subject: [PATCH 3/4] =?UTF-8?q?=E2=9C=85=20refactor=20randomSigner=20metho?= =?UTF-8?q?ds?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/EIP712.t.sol | 161 ++++------------------------- test/SignatureCheckerLib.t.sol | 174 ++++++-------------------------- test/utils/RandomSigner.sol | 157 ++++++++++++++++++++++++++++ test/utils/mocks/MockEIP712.sol | 7 +- 4 files changed, 210 insertions(+), 289 deletions(-) create mode 100644 test/utils/RandomSigner.sol diff --git a/test/EIP712.t.sol b/test/EIP712.t.sol index 4f789fa5..11180c3c 100644 --- a/test/EIP712.t.sol +++ b/test/EIP712.t.sol @@ -4,8 +4,9 @@ pragma solidity 0.8.20; import {Test} from "lib/forge-std/src/Test.sol"; import {EIP712} from "src/utils/EIP712.sol"; import {MockEIP712} from "./utils/mocks/MockEIP712.sol"; +import {RandomSigner} from "./utils/RandomSigner.sol"; -contract EIP712Test is Test, EIP712 { +contract EIP712Test is Test, RandomSigner, EIP712 { MockEIP712 mock; function setUp() public { @@ -39,7 +40,6 @@ contract EIP712Test is Test, EIP712 { assertEq(mock.DOMAIN_SEPARATOR(), expectedDomainSeparator); } - function test_hashTypedData() public { (address signer, uint256 privateKey) = _randomSigner(); @@ -47,10 +47,12 @@ contract EIP712Test is Test, EIP712 { string memory message = "Test SMv3"; - bytes32 structHash = - keccak256(abi.encode("Message(address to,string message)", to, message)); - bytes32 expectedDigest = - keccak256(abi.encodePacked("\x19\x01", mock.DOMAIN_SEPARATOR(), structHash)); + bytes32 structHash = keccak256( + abi.encode("Message(address to,string message)", to, message) + ); + bytes32 expectedDigest = keccak256( + abi.encodePacked("\x19\x01", mock.DOMAIN_SEPARATOR(), structHash) + ); assertEq(mock.hashTypedData(structHash), expectedDigest); @@ -70,10 +72,18 @@ contract EIP712Test is Test, EIP712 { bytes32 salt; uint256[] extensions; } + function test_eip712Domain() public { _testEIP5267Variables memory t; - (t.fields, t.name, t.version, t.chainId, t.verifyingContract, t.salt, t.extensions) = - mock.eip712Domain(); + ( + t.fields, + t.name, + t.version, + t.chainId, + t.verifyingContract, + t.salt, + t.extensions + ) = mock.eip712Domain(); assertEq(t.fields, hex"0f"); assertEq(t.name, "SMv3: OrderBook"); @@ -92,139 +102,4 @@ contract EIP712Test is Test, EIP712 { function test_cachedDomainSeparatorInvalidated() public { assertFalse(mock.cachedDomainSeparatorInvalidated()); } - - /// @custom:reference github.com/Vectorized/solady/blob/main/test/EIP712.t.sol - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* SIGNATURE CHECKING TEST UTILS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev Returns a pseudorandom random number from [0 .. 2**256 - 1] (inclusive). - /// For usage in fuzz tests, please ensure that the function has an unnamed uint256 argument. - /// e.g. `testSomething(uint256) public`. - function _random() internal returns (uint256 r) { - /// @solidity memory-safe-assembly - assembly { - // This is the keccak256 of a very long string I randomly mashed on my keyboard. - let sSlot := 0xd715531fe383f818c5f158c342925dcf01b954d24678ada4d07c36af0f20e1ee - let sValue := sload(sSlot) - - mstore(0x20, sValue) - r := keccak256(0x20, 0x40) - - // If the storage is uninitialized, initialize it to the keccak256 of the calldata. - if iszero(sValue) { - sValue := sSlot - let m := mload(0x40) - calldatacopy(m, 0, calldatasize()) - r := keccak256(m, calldatasize()) - } - sstore(sSlot, add(r, 1)) - - // Do some biased sampling for more robust tests. - // prettier-ignore - for {} 1 {} { - let d := byte(0, r) - // With a 1/256 chance, randomly set `r` to any of 0,1,2. - if iszero(d) { - r := and(r, 3) - break - } - // With a 1/2 chance, set `r` to near a random power of 2. - if iszero(and(2, d)) { - // Set `t` either `not(0)` or `xor(sValue, r)`. - let t := xor(not(0), mul(iszero(and(4, d)), not(xor(sValue, r)))) - // Set `r` to `t` shifted left or right by a random multiple of 8. - switch and(8, d) - case 0 { - if iszero(and(16, d)) { t := 1 } - r := add(shl(shl(3, and(byte(3, r), 0x1f)), t), sub(and(r, 7), 3)) - } - default { - if iszero(and(16, d)) { t := shl(255, 1) } - r := add(shr(shl(3, and(byte(3, r), 0x1f)), t), sub(and(r, 7), 3)) - } - // With a 1/2 chance, negate `r`. - if iszero(and(0x20, d)) { r := not(r) } - break - } - // Otherwise, just set `r` to `xor(sValue, r)`. - r := xor(sValue, r) - break - } - } - } - - /// @dev Returns a random signer and its private key. - function _randomSigner() internal returns (address signer, uint256 privateKey) { - uint256 privateKeyMax = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140; - privateKey = _hem(_random(), 1, privateKeyMax); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, 0xffa18649) // `addr(uint256)`. - mstore(0x20, privateKey) - if iszero(call(gas(), 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, 0, 0x1c, 0x24, 0x00, 0x20)) { revert(0, 0) } - signer := mload(0x00) - } - } - - /// @dev Adapted from `bound`: - /// https://github.com/foundry-rs/forge-std/blob/ff4bf7db008d096ea5a657f2c20516182252a3ed/src/StdUtils.sol#L10 - /// Differentially fuzzed tested against the original implementation. - function _hem(uint256 x, uint256 min, uint256 max) - internal - pure - virtual - returns (uint256 result) - { - require(min <= max, "Max is less than min."); - - /// @solidity memory-safe-assembly - assembly { - // prettier-ignore - for {} 1 {} { - // If `x` is between `min` and `max`, return `x` directly. - // This is to ensure that dictionary values - // do not get shifted if the min is nonzero. - // More info: https://github.com/foundry-rs/forge-std/issues/188 - if iszero(or(lt(x, min), gt(x, max))) { - result := x - break - } - - let size := add(sub(max, min), 1) - if and(iszero(gt(x, 3)), gt(size, x)) { - result := add(min, x) - break - } - - let w := not(0) - if and(iszero(lt(x, sub(0, 4))), gt(size, sub(w, x))) { - result := sub(max, sub(w, x)) - break - } - - // Otherwise, wrap x into the range [min, max], - // i.e. the range is inclusive. - if iszero(lt(x, max)) { - let d := sub(x, max) - let r := mod(d, size) - if iszero(r) { - result := max - break - } - result := add(add(min, r), w) - break - } - let d := sub(min, x) - let r := mod(d, size) - if iszero(r) { - result := min - break - } - result := add(sub(max, r), 1) - break - } - } - } } diff --git a/test/SignatureCheckerLib.t.sol b/test/SignatureCheckerLib.t.sol index 0b6884af..d548abd7 100644 --- a/test/SignatureCheckerLib.t.sol +++ b/test/SignatureCheckerLib.t.sol @@ -3,8 +3,9 @@ pragma solidity 0.8.20; import {Test} from "lib/forge-std/src/Test.sol"; import {SignatureCheckerLib} from "src/libraries/SignatureCheckerLib.sol"; +import {RandomSigner} from "./utils/RandomSigner.sol"; -contract SignatureCheckerLibTest is Test { +contract SignatureCheckerLibTest is Test, RandomSigner { /// @dev following test is an example of how to use the library; no functionality is tested function test_isValidSignatureNowCalldata( address signer, @@ -27,7 +28,10 @@ contract SignatureCheckerLibTest is Test { if (_random() % 8 == 0) { assertEq( - this.isValidSignatureNowCalldata(signer, digest, abi.encodePacked(r, s, v)), true + this.isValidSignatureNowCalldata( + signer, digest, abi.encodePacked(r, s, v) + ), + true ); } @@ -37,7 +41,12 @@ contract SignatureCheckerLibTest is Test { assembly { vs := or(shl(255, sub(v, 27)), s) } - assertEq(this.isValidSignatureNowCalldata(signer, digest, abi.encode(r, vs)), true); + assertEq( + this.isValidSignatureNowCalldata( + signer, digest, abi.encode(r, vs) + ), + true + ); } if (_random() % 8 == 0) { @@ -46,156 +55,33 @@ contract SignatureCheckerLibTest is Test { assembly { vsc := or(shl(255, xor(1, sub(v, 27))), s) } - assertEq(this.isValidSignatureNowCalldata(signer, digest, abi.encode(r, vsc)), false); + assertEq( + this.isValidSignatureNowCalldata( + signer, digest, abi.encode(r, vsc) + ), + false + ); } if (_random() % 8 == 0) { uint8 vc = uint8(_random()); // Corrupted `v`. while (vc == 28 || vc == 27) vc = uint8(_random()); assertEq( - this.isValidSignatureNowCalldata(signer, digest, abi.encodePacked(r, s, vc)), false + this.isValidSignatureNowCalldata( + signer, digest, abi.encodePacked(r, s, vc) + ), + false ); } } - function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature) - external - view - returns (bool result) - { - result = SignatureCheckerLib.isValidSignatureNowCalldata(signer, hash, signature); - } - - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* SIGNATURE CHECKING TEST UTILS */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - /// @dev Returns a pseudorandom random number from [0 .. 2**256 - 1] (inclusive). - /// For usage in fuzz tests, please ensure that the function has an unnamed uint256 argument. - /// e.g. `testSomething(uint256) public`. - function _random() internal returns (uint256 r) { - /// @solidity memory-safe-assembly - assembly { - // This is the keccak256 of a very long string I randomly mashed on my keyboard. - let sSlot := 0xd715531fe383f818c5f158c342925dcf01b954d24678ada4d07c36af0f20e1ee - let sValue := sload(sSlot) - - mstore(0x20, sValue) - r := keccak256(0x20, 0x40) - - // If the storage is uninitialized, initialize it to the keccak256 of the calldata. - if iszero(sValue) { - sValue := sSlot - let m := mload(0x40) - calldatacopy(m, 0, calldatasize()) - r := keccak256(m, calldatasize()) - } - sstore(sSlot, add(r, 1)) - - // Do some biased sampling for more robust tests. - // prettier-ignore - for {} 1 {} { - let d := byte(0, r) - // With a 1/256 chance, randomly set `r` to any of 0,1,2. - if iszero(d) { - r := and(r, 3) - break - } - // With a 1/2 chance, set `r` to near a random power of 2. - if iszero(and(2, d)) { - // Set `t` either `not(0)` or `xor(sValue, r)`. - let t := xor(not(0), mul(iszero(and(4, d)), not(xor(sValue, r)))) - // Set `r` to `t` shifted left or right by a random multiple of 8. - switch and(8, d) - case 0 { - if iszero(and(16, d)) { t := 1 } - r := add(shl(shl(3, and(byte(3, r), 0x1f)), t), sub(and(r, 7), 3)) - } - default { - if iszero(and(16, d)) { t := shl(255, 1) } - r := add(shr(shl(3, and(byte(3, r), 0x1f)), t), sub(and(r, 7), 3)) - } - // With a 1/2 chance, negate `r`. - if iszero(and(0x20, d)) { r := not(r) } - break - } - // Otherwise, just set `r` to `xor(sValue, r)`. - r := xor(sValue, r) - break - } - } - } - - /// @dev Returns a random signer and its private key. - function _randomSigner() internal returns (address signer, uint256 privateKey) { - uint256 privateKeyMax = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140; - privateKey = _hem(_random(), 1, privateKeyMax); - /// @solidity memory-safe-assembly - assembly { - mstore(0x00, 0xffa18649) // `addr(uint256)`. - mstore(0x20, privateKey) - if iszero(call(gas(), 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, 0, 0x1c, 0x24, 0x00, 0x20)) { revert(0, 0) } - signer := mload(0x00) - } - } - - /// @dev Adapted from `bound`: - /// https://github.com/foundry-rs/forge-std/blob/ff4bf7db008d096ea5a657f2c20516182252a3ed/src/StdUtils.sol#L10 - /// Differentially fuzzed tested against the original implementation. - function _hem(uint256 x, uint256 min, uint256 max) - internal - pure - virtual - returns (uint256 result) - { - require(min <= max, "Max is less than min."); - - /// @solidity memory-safe-assembly - assembly { - // prettier-ignore - for {} 1 {} { - // If `x` is between `min` and `max`, return `x` directly. - // This is to ensure that dictionary values - // do not get shifted if the min is nonzero. - // More info: https://github.com/foundry-rs/forge-std/issues/188 - if iszero(or(lt(x, min), gt(x, max))) { - result := x - break - } - - let size := add(sub(max, min), 1) - if and(iszero(gt(x, 3)), gt(size, x)) { - result := add(min, x) - break - } - - let w := not(0) - if and(iszero(lt(x, sub(0, 4))), gt(size, sub(w, x))) { - result := sub(max, sub(w, x)) - break - } - - // Otherwise, wrap x into the range [min, max], - // i.e. the range is inclusive. - if iszero(lt(x, max)) { - let d := sub(x, max) - let r := mod(d, size) - if iszero(r) { - result := max - break - } - result := add(add(min, r), w) - break - } - let d := sub(min, x) - let r := mod(d, size) - if iszero(r) { - result := min - break - } - result := add(sub(max, r), 1) - break - } - } + function isValidSignatureNowCalldata( + address signer, + bytes32 hash, + bytes calldata signature + ) external view returns (bool result) { + result = SignatureCheckerLib.isValidSignatureNowCalldata( + signer, hash, signature + ); } } diff --git a/test/utils/RandomSigner.sol b/test/utils/RandomSigner.sol new file mode 100644 index 00000000..24aac2a6 --- /dev/null +++ b/test/utils/RandomSigner.sol @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity 0.8.20; + +contract RandomSigner { + /// @dev Returns a pseudorandom random number from [0 .. 2**256 - 1] (inclusive). + /// For usage in fuzz tests, please ensure that the function has an unnamed uint256 argument. + /// e.g. `testSomething(uint256) public`. + function _random() internal returns (uint256 r) { + /// @solidity memory-safe-assembly + assembly { + // This is the keccak256 of a very long string I randomly mashed on my keyboard. + let sSlot := + 0xd715531fe383f818c5f158c342925dcf01b954d24678ada4d07c36af0f20e1ee + let sValue := sload(sSlot) + + mstore(0x20, sValue) + r := keccak256(0x20, 0x40) + + // If the storage is uninitialized, initialize it to the keccak256 of the calldata. + if iszero(sValue) { + sValue := sSlot + let m := mload(0x40) + calldatacopy(m, 0, calldatasize()) + r := keccak256(m, calldatasize()) + } + sstore(sSlot, add(r, 1)) + + // Do some biased sampling for more robust tests. + // prettier-ignore + for {} 1 {} { + let d := byte(0, r) + // With a 1/256 chance, randomly set `r` to any of 0,1,2. + if iszero(d) { + r := and(r, 3) + break + } + // With a 1/2 chance, set `r` to near a random power of 2. + if iszero(and(2, d)) { + // Set `t` either `not(0)` or `xor(sValue, r)`. + let t := + xor(not(0), mul(iszero(and(4, d)), not(xor(sValue, r)))) + // Set `r` to `t` shifted left or right by a random multiple of 8. + switch and(8, d) + case 0 { + if iszero(and(16, d)) { t := 1 } + r := + add( + shl(shl(3, and(byte(3, r), 0x1f)), t), + sub(and(r, 7), 3) + ) + } + default { + if iszero(and(16, d)) { t := shl(255, 1) } + r := + add( + shr(shl(3, and(byte(3, r), 0x1f)), t), + sub(and(r, 7), 3) + ) + } + // With a 1/2 chance, negate `r`. + if iszero(and(0x20, d)) { r := not(r) } + break + } + // Otherwise, just set `r` to `xor(sValue, r)`. + r := xor(sValue, r) + break + } + } + } + + /// @dev Returns a random signer and its private key. + function _randomSigner() + internal + returns (address signer, uint256 privateKey) + { + uint256 privateKeyMax = + 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140; + privateKey = _hem(_random(), 1, privateKeyMax); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, 0xffa18649) // `addr(uint256)`. + mstore(0x20, privateKey) + if iszero( + call( + gas(), + 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, + 0, + 0x1c, + 0x24, + 0x00, + 0x20 + ) + ) { revert(0, 0) } + signer := mload(0x00) + } + } + + /// @dev Adapted from `bound`: + /// https://github.com/foundry-rs/forge-std/blob/ff4bf7db008d096ea5a657f2c20516182252a3ed/src/StdUtils.sol#L10 + /// Differentially fuzzed tested against the original implementation. + function _hem(uint256 x, uint256 min, uint256 max) + internal + pure + virtual + returns (uint256 result) + { + require(min <= max, "Max is less than min."); + + /// @solidity memory-safe-assembly + assembly { + // prettier-ignore + for {} 1 {} { + // If `x` is between `min` and `max`, return `x` directly. + // This is to ensure that dictionary values + // do not get shifted if the min is nonzero. + // More info: https://github.com/foundry-rs/forge-std/issues/188 + if iszero(or(lt(x, min), gt(x, max))) { + result := x + break + } + + let size := add(sub(max, min), 1) + if and(iszero(gt(x, 3)), gt(size, x)) { + result := add(min, x) + break + } + + let w := not(0) + if and(iszero(lt(x, sub(0, 4))), gt(size, sub(w, x))) { + result := sub(max, sub(w, x)) + break + } + + // Otherwise, wrap x into the range [min, max], + // i.e. the range is inclusive. + if iszero(lt(x, max)) { + let d := sub(x, max) + let r := mod(d, size) + if iszero(r) { + result := max + break + } + result := add(add(min, r), w) + break + } + let d := sub(min, x) + let r := mod(d, size) + if iszero(r) { + result := min + break + } + result := add(sub(max, r), 1) + break + } + } + } +} diff --git a/test/utils/mocks/MockEIP712.sol b/test/utils/mocks/MockEIP712.sol index 15f3a4e2..3e429b1b 100644 --- a/test/utils/mocks/MockEIP712.sol +++ b/test/utils/mocks/MockEIP712.sol @@ -6,7 +6,6 @@ import "../../../src/utils/EIP712.sol"; /// @dev WARNING! This mock is strictly intended for testing purposes only. /// Do NOT copy anything here into production code unless you really know what you are doing. contract MockEIP712 is EIP712 { - uint256 public immutable _cachedThis; uint256 public immutable _cachedChainId; bytes32 public immutable _cachedNameHash; @@ -37,7 +36,11 @@ contract MockEIP712 is EIP712 { _cachedDomainSeparator = separator; } - function hashTypedData(bytes32 structHash) external view returns (bytes32) { + function hashTypedData(bytes32 structHash) + external + view + returns (bytes32) + { return _hashTypedData(structHash); } From 1a66951dfbabbf261f51f5146adc77e942eaef39 Mon Sep 17 00:00:00 2001 From: Flocqst Date: Wed, 27 Mar 2024 15:56:59 +0100 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=93=B8=20Update=20gas-snapshot/lcov?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 28 +++--- lcov.info | 236 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 157 insertions(+), 107 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index aef63bb5..99babd14 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -25,10 +25,10 @@ Conditions:test_isPriceAbove() (gas: 175814) Conditions:test_isPriceBelow() (gas: 175643) Conditions:test_isTimestampAfter() (gas: 13288) Conditions:test_isTimestampBefore() (gas: 13376) -Credit:test_credit(uint256) (runs: 256, μ: 94496, ~: 105108) +Credit:test_credit(uint256) (runs: 256, μ: 94630, ~: 105108) Credit:test_credit_event() (gas: 88151) Credit:test_credit_zap() (gas: 677111) -Debit:test_debit(uint256) (runs: 256, μ: 136670, ~: 147259) +Debit:test_debit(uint256) (runs: 256, μ: 136580, ~: 147259) Debit:test_debit_InsufficientBalance() (gas: 122814) Debit:test_debit_Unauthorized() (gas: 122831) Debit:test_debit_event() (gas: 104507) @@ -45,13 +45,12 @@ DepositCollateral:test_depositCollateral_collateralAmount() (gas: 433843) DepositCollateral:test_depositCollateral_insufficient_balance() (gas: 61158) DepositCollateral:test_depositCollateral_totalCollateralValue() (gas: 435519) DepositCollateral:test_depositCollateral_zap() (gas: 940531) -EIP712Test:test_DOMAIN_SEPARATOR() (gas: 165) -EIP712Test:test_buildDomainSeparator() (gas: 165) -EIP712Test:test_cachedDomainSeparatorInvalidated() (gas: 144) -EIP712Test:test_constructor() (gas: 164) +EIP712Test:test_DOMAIN_SEPARATOR() (gas: 5729) +EIP712Test:test_buildDomainSeparator() (gas: 6363) +EIP712Test:test_cachedDomainSeparatorInvalidated() (gas: 5454) EIP712Test:test_domainNameAndVersion() (gas: 1261) -EIP712Test:test_eip712Domain() (gas: 187) -EIP712Test:test_hashTypedData() (gas: 187) +EIP712Test:test_eip712Domain() (gas: 10831) +EIP712Test:test_hashTypedData() (gas: 37085) Execute:test_execute_CannotExecuteOrder_invalid_acceptablePrice() (gas: 322478) Execute:test_execute_CannotExecuteOrder_invalid_settlementStrategyId() (gas: 103691) Execute:test_execute_CannotExecuteOrder_too_leveraged() (gas: 469124) @@ -65,9 +64,9 @@ FulfillOracleQuery:test_fulfillOracleQuery_refund(bytes) (runs: 256, μ: 40303, FulfillOracleQuery:test_fulfillOracleQuery_revert(bytes) (runs: 256, μ: 32927, ~: 32919) MathLibTest:test_abs128() (gas: 448) MathLibTest:test_abs256() (gas: 458) -MathLibTest:test_fuzz_abs128(int128) (runs: 256, μ: 577, ~: 603) -MathLibTest:test_fuzz_abs256(int256) (runs: 256, μ: 449, ~: 436) -MathLibTest:test_fuzz_toInt256(uint256) (runs: 256, μ: 989, ~: 438) +MathLibTest:test_fuzz_abs128(int128) (runs: 256, μ: 578, ~: 603) +MathLibTest:test_fuzz_abs256(int256) (runs: 256, μ: 451, ~: 436) +MathLibTest:test_fuzz_toInt256(uint256) (runs: 256, μ: 1000, ~: 438) MathLibTest:test_isSameSign() (gas: 999) MathLibTest:test_toInt256() (gas: 3347) MathLibTest:test_toInt256_overflow() (gas: 3251) @@ -79,11 +78,11 @@ Multicall:testMulticallableBenchmark() (gas: 29229) Multicall:testMulticallableOriginalBenchmark() (gas: 38452) Multicall:testMulticallablePreservesMsgSender() (gas: 11116) Multicall:testMulticallableReturnDataIsProperlyEncoded() (gas: 11637) -Multicall:testMulticallableReturnDataIsProperlyEncoded(string,string,uint256) (runs: 256, μ: 9797, ~: 9409) +Multicall:testMulticallableReturnDataIsProperlyEncoded(string,string,uint256) (runs: 256, μ: 9680, ~: 7435) Multicall:testMulticallableReturnDataIsProperlyEncoded(uint256,uint256,uint256,uint256) (runs: 256, μ: 11695, ~: 11695) Multicall:testMulticallableRevertWithCustomError() (gas: 11746) Multicall:testMulticallableRevertWithMessage() (gas: 13451) -Multicall:testMulticallableRevertWithMessage(string) (runs: 256, μ: 14035, ~: 13883) +Multicall:testMulticallableRevertWithMessage(string) (runs: 256, μ: 14138, ~: 14177) Multicall:testMulticallableRevertWithNothing() (gas: 11655) Multicall:testMulticallableWithNoData() (gas: 6311) MulticallFulfillOracleQuery:test_fulfillOracleQuery_multicall(bytes) (runs: 256, μ: 34608, ~: 34543) @@ -102,7 +101,8 @@ ReduceOnly:test_reduce_only_truncate_size_up() (gas: 614783) ReduceOnly:test_reduce_only_when_position_doesnt_exist() (gas: 166346) ReduceOnly:test_reduce_only_zero_size_delta() (gas: 166380) RemoveUpgradability:test_removeUpgradability() (gas: 4537931) -SignatureCheckerLibTest:test_isValidSignatureNowCalldata(address,bytes32,bytes) (runs: 256, μ: 3496, ~: 3474) +SignatureCheckerLibTest:testSignatureChecker(bytes32) (runs: 256, μ: 31623, ~: 28584) +SignatureCheckerLibTest:test_isValidSignatureNowCalldata(address,bytes32,bytes) (runs: 256, μ: 35465847065546046, ~: 3451) StorageLayout:test_credit_slot() (gas: 5584) StorageLayout:test_nonceBitmap_slot() (gas: 5520) VerifyConditions:test_max_condition_size_exceeded() (gas: 51317) diff --git a/lcov.info b/lcov.info index ab971ff1..df0b6ded 100644 --- a/lcov.info +++ b/lcov.info @@ -6,30 +6,42 @@ DA:210,0 DA:211,0 DA:213,0 DA:222,0 +FN:101,DeployBaseGoerli_Synthetix.run +FNDA:0,DeployBaseGoerli_Synthetix.run +DA:102,0 +DA:103,0 +DA:105,0 +DA:114,0 +FN:59,DeployBase_Synthetix.run +FNDA:0,DeployBase_Synthetix.run +DA:60,0 +DA:61,0 +DA:63,0 +DA:72,0 +FN:143,DeployBaseSepolia_Andromeda.run +FNDA:0,DeployBaseSepolia_Andromeda.run +DA:144,0 +DA:145,0 +DA:147,0 +DA:156,0 FN:80,DeployBase_Andromeda.run FNDA:0,DeployBase_Andromeda.run DA:81,0 DA:82,0 DA:84,0 DA:93,0 -FN:188,DeployOptimism_Synthetix.run -FNDA:0,DeployOptimism_Synthetix.run -DA:189,0 -DA:190,0 -DA:192,0 -DA:201,0 FN:167,DeployBaseGoerli_KwentaFork.run FNDA:0,DeployBaseGoerli_KwentaFork.run DA:168,0 DA:169,0 DA:171,0 DA:180,0 -FN:59,DeployBase_Synthetix.run -FNDA:0,DeployBase_Synthetix.run -DA:60,0 -DA:61,0 -DA:63,0 -DA:72,0 +FN:188,DeployOptimism_Synthetix.run +FNDA:0,DeployOptimism_Synthetix.run +DA:189,0 +DA:190,0 +DA:192,0 +DA:201,0 FN:122,DeployBaseGoerli_Andromeda.run FNDA:0,DeployBaseGoerli_Andromeda.run DA:123,0 @@ -38,21 +50,9 @@ DA:126,0 DA:135,0 FN:30,Setup.deploySystem FNDA:4,Setup.deploySystem -DA:38,103 -DA:48,100 -DA:51,100 -FN:143,DeployBaseSepolia_Andromeda.run -FNDA:0,DeployBaseSepolia_Andromeda.run -DA:144,0 -DA:145,0 -DA:147,0 -DA:156,0 -FN:101,DeployBaseGoerli_Synthetix.run -FNDA:0,DeployBaseGoerli_Synthetix.run -DA:102,0 -DA:103,0 -DA:105,0 -DA:114,0 +DA:38,4 +DA:48,1 +DA:51,1 FNF:9 FNH:1 LF:35 @@ -62,30 +62,15 @@ BRH:0 end_of_record TN: SF:script/Upgrade.s.sol +FN:25,Setup.deployImplementation +FNDA:0,Setup.deployImplementation +DA:33,0 FN:69,DeployBaseGoerli_Synthetix.run FNDA:0,DeployBaseGoerli_Synthetix.run DA:70,0 DA:71,0 DA:73,0 DA:82,0 -FN:135,DeployOptimism_Synthetix.run -FNDA:0,DeployOptimism_Synthetix.run -DA:136,0 -DA:137,0 -DA:139,0 -DA:148,0 -FN:93,DeployBaseGoerli_KwentaFork.run -FNDA:0,DeployBaseGoerli_KwentaFork.run -DA:94,0 -DA:95,0 -DA:97,0 -DA:106,0 -FN:114,DeployBaseGoerli_Andromeda.run -FNDA:0,DeployBaseGoerli_Andromeda.run -DA:115,0 -DA:116,0 -DA:118,0 -DA:127,0 FN:156,DeployOptimismGoerli_Synthetix.run FNDA:0,DeployOptimismGoerli_Synthetix.run DA:157,0 @@ -98,9 +83,24 @@ DA:49,0 DA:50,0 DA:52,0 DA:61,0 -FN:25,Setup.deployImplementation -FNDA:0,Setup.deployImplementation -DA:33,0 +FN:93,DeployBaseGoerli_KwentaFork.run +FNDA:0,DeployBaseGoerli_KwentaFork.run +DA:94,0 +DA:95,0 +DA:97,0 +DA:106,0 +FN:135,DeployOptimism_Synthetix.run +FNDA:0,DeployOptimism_Synthetix.run +DA:136,0 +DA:137,0 +DA:139,0 +DA:148,0 +FN:114,DeployBaseGoerli_Andromeda.run +FNDA:0,DeployBaseGoerli_Andromeda.run +DA:115,0 +DA:116,0 +DA:118,0 +DA:127,0 FNF:7 FNH:0 LF:25 @@ -155,12 +155,12 @@ DA:298,13 BRDA:298,3,0,- BRDA:298,3,1,13 FN:306,Engine.modifyCollateral -FNDA:60,Engine.modifyCollateral -DA:311,60 -DA:313,60 -BRDA:313,4,0,57 +FNDA:13,Engine.modifyCollateral +DA:311,13 +DA:313,13 +BRDA:313,4,0,10 BRDA:313,4,1,3 -DA:314,57 +DA:314,10 DA:318,3 BRDA:318,5,0,- BRDA:318,5,1,3 @@ -180,17 +180,17 @@ DA:346,1 DA:353,1 DA:356,1 FN:360,Engine._depositCollateral -FNDA:57,Engine._depositCollateral -DA:369,57 -DA:371,56 -DA:373,56 +FNDA:10,Engine._depositCollateral +DA:369,10 +DA:371,9 +DA:373,9 FN:376,Engine._withdrawCollateral FNDA:3,Engine._withdrawCollateral DA:383,3 DA:387,1 FN:395,Engine._getSynthAddress -FNDA:60,Engine._getSynthAddress -DA:400,60 +FNDA:13,Engine._getSynthAddress +DA:400,13 FN:410,Engine.commitOrder FNDA:4,Engine.commitOrder DA:426,4 @@ -205,7 +205,7 @@ FN:468,Engine.creditAccount FNDA:776,Engine.creditAccount DA:473,776 DA:476,776 -DA:478,656 +DA:478,661 FN:482,Engine.creditAccountZap FNDA:3,Engine.creditAccountZap DA:488,3 @@ -217,7 +217,7 @@ DA:501,259 BRDA:501,9,0,1 BRDA:501,9,1,258 DA:503,258 -DA:505,140 +DA:505,143 FN:509,Engine.debitAccountZap FNDA:3,Engine.debitAccountZap DA:514,3 @@ -233,10 +233,10 @@ DA:527,1 FN:530,Engine._debit FNDA:259,Engine._debit DA:533,259 -BRDA:533,12,0,104 -BRDA:533,12,1,155 -DA:536,155 -DA:539,155 +BRDA:533,12,0,105 +BRDA:533,12,1,154 +DA:536,154 +DA:539,154 FN:547,Engine.execute FNDA:15,Engine.execute DA:563,15 @@ -485,8 +485,8 @@ SF:src/utils/MulticallablePayable.sol FN:24,MulticallablePayable.multicall FNDA:1288,MulticallablePayable.multicall DA:33,1288 -BRDA:33,0,0,124 -DA:43,1164 +BRDA:33,0,0,121 +DA:43,1167 FNF:1 FNH:1 LF:2 @@ -620,6 +620,11 @@ BRH:0 end_of_record TN: SF:test/utils/Bootstrap.sol +FN:207,BootstrapOptimism.init +FNDA:0,BootstrapOptimism.init +DA:220,0 +DA:229,0 +DA:238,0 FN:65,Bootstrap.initializeOptimism FNDA:0,Bootstrap.initializeOptimism DA:66,0 @@ -696,16 +701,11 @@ DA:194,0 DA:195,0 DA:200,0 DA:202,0 -FN:207,BootstrapOptimism.init -FNDA:0,BootstrapOptimism.init -DA:220,0 -DA:229,0 -DA:238,0 FN:297,BootstrapBase.init -FNDA:99,BootstrapBase.init -DA:310,99 -DA:319,99 -DA:328,99 +FNDA:0,BootstrapBase.init +DA:310,0 +DA:319,0 +DA:328,0 FN:252,BootstrapOptimismGoerli.init FNDA:0,BootstrapOptimismGoerli.init DA:265,0 @@ -717,9 +717,9 @@ DA:355,0 DA:364,0 DA:373,0 FNF:8 -FNH:1 +FNH:0 LF:80 -LH:3 +LH:0 BRF:0 BRH:0 end_of_record @@ -782,14 +782,42 @@ BRF:0 BRH:0 end_of_record TN: +SF:test/utils/RandomSigner.sol +FN:8,RandomSigner._random +FNDA:0,RandomSigner._random +DA:17,0 +DA:20,0 +BRDA:20,0,0,- +DA:21,0 +DA:24,0 +FN:72,RandomSigner._randomSigner +FNDA:0,RandomSigner._randomSigner +DA:76,0 +DA:78,0 +DA:83,0 +BRDA:83,1,0,- +DA:94,0 +FN:101,RandomSigner._hem +FNDA:0,RandomSigner._hem +DA:107,0 +BRDA:107,2,0,- +BRDA:107,2,1,- +FNF:3 +FNH:0 +LF:9 +LH:0 +BRF:4 +BRH:0 +end_of_record +TN: SF:test/utils/SynthMinter.sol FN:18,SynthMinter.mint_sUSD -FNDA:142,SynthMinter.mint_sUSD -DA:19,142 +FNDA:0,SynthMinter.mint_sUSD +DA:19,0 FNF:1 -FNH:1 +FNH:0 LF:1 -LH:1 +LH:0 BRF:0 BRH:0 end_of_record @@ -813,6 +841,15 @@ BRH:0 end_of_record TN: SF:test/utils/mocks/EIP7412Mock.sol +FN:24,EIP7412MockRevert.fulfillOracleQuery +FNDA:256,EIP7412MockRevert.fulfillOracleQuery +DA:25,256 +FN:9,EIP7412Mock.fulfillOracleQuery +FNDA:769,EIP7412Mock.fulfillOracleQuery +DA:10,769 +BRDA:10,0,0,- +BRDA:10,0,1,769 +DA:11,769 FN:16,EIP7412MockRefund.fulfillOracleQuery FNDA:256,EIP7412MockRefund.fulfillOracleQuery DA:17,256 @@ -822,15 +859,6 @@ DA:18,256 DA:19,256 BRDA:19,1,0,256 BRDA:19,1,1,- -FN:9,EIP7412Mock.fulfillOracleQuery -FNDA:769,EIP7412Mock.fulfillOracleQuery -DA:10,769 -BRDA:10,0,0,- -BRDA:10,0,1,769 -DA:11,769 -FN:24,EIP7412MockRevert.fulfillOracleQuery -FNDA:256,EIP7412MockRevert.fulfillOracleQuery -DA:25,256 FNF:3 FNH:3 LF:6 @@ -839,6 +867,28 @@ BRF:6 BRH:3 end_of_record TN: +SF:test/utils/mocks/MockEIP712.sol +FN:39,MockEIP712.hashTypedData +FNDA:0,MockEIP712.hashTypedData +DA:44,0 +FN:48,MockEIP712.buildDomainSeparator +FNDA:0,MockEIP712.buildDomainSeparator +DA:50,0 +DA:51,0 +DA:60,0 +FN:65,MockEIP712.cachedDomainSeparatorInvalidated +FNDA:0,MockEIP712.cachedDomainSeparatorInvalidated +DA:70,0 +DA:71,0 +DA:74,0 +FNF:3 +FNH:0 +LF:7 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: SF:test/utils/mocks/MockEngineUpgrade.sol FN:27,MockEngineUpgrade.echo FNDA:1,MockEngineUpgrade.echo @@ -865,8 +915,8 @@ FN:29,MockMulticallablePayable.returnsTuple FNDA:534,MockMulticallablePayable.returnsTuple DA:34,534 FN:37,MockMulticallablePayable.returnsString -FNDA:133,MockMulticallablePayable.returnsString -DA:42,133 +FNDA:136,MockMulticallablePayable.returnsString +DA:42,136 FN:47,MockMulticallablePayable.pay FNDA:0,MockMulticallablePayable.pay DA:48,0