Skip to content

Commit

Permalink
Full test coverage for trust contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
Agusx1211 committed Nov 28, 2023
1 parent 17091b5 commit 744e142
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 13 deletions.
7 changes: 2 additions & 5 deletions contracts/trust/Trust.sol
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,8 @@ contract Trust is IERC1271Wallet {
_signature
);

if (res == SELECTOR_ERC1271_BYTES32_BYTES) {
return SELECTOR_ERC1271_BYTES_BYTES;
}

return bytes4(0);
assert(res == SELECTOR_ERC1271_BYTES32_BYTES);
return SELECTOR_ERC1271_BYTES_BYTES;
}

function isValidSignature(
Expand Down
10 changes: 2 additions & 8 deletions contracts/trust/TrustFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,7 @@ contract TrustFactory {
address _owner,
address _beneficiary,
uint256 _duration
) external returns (address) {
Trust trust = new Trust{ salt: bytes32(0) }( _owner, _beneficiary, _duration);

if (address(trust) == address(0)) {
revert ErrorDeployingTrust(_owner, _beneficiary, _duration);
}

return address(trust);
) external returns (Trust) {
return new Trust{ salt: bytes32(0) }( _owner, _beneficiary, _duration);
}
}
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ src = 'contracts'
out = 'foundry_artifacts'
libs = ["node_modules", "lib"]
test = 'foundry_test'

max_test_rejects = 2048000
105 changes: 105 additions & 0 deletions foundry_test/trust/Trust.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ contract MockFail {
contract TrustTest is AdvTest {
Trust private trust;

function test_define_initial_parameters(uint256 _ownerPk, uint256 _beneficiaryPk, uint256 _duration) external {
trust = new Trust(vm.addr(boundPk(_ownerPk)), vm.addr(boundPk(_beneficiaryPk)), _duration);
assertEq(trust.owner(), vm.addr(boundPk(_ownerPk)));
assertEq(trust.beneficiary(), vm.addr(boundPk(_beneficiaryPk)));
assertEq(trust.duration(), _duration);
}

function test_start_locked(uint256 _ownerPk, uint256 _beneficiaryPk, uint256 _duration) external {
trust = new Trust(vm.addr(boundPk(_ownerPk)), vm.addr(boundPk(_beneficiaryPk)), _duration);
assertEq(trust.isLocked(), true);
Expand Down Expand Up @@ -397,4 +404,102 @@ contract TrustTest is AdvTest {
vm.expectRevert(abi.encodeWithSignature('InvalidSignatureFlag(bytes,bytes1)', sig, bytes1(_signerFlag)));
t.isValidSignature(keccak256(_message), sig);
}

function test_fail_isValidSignature_pre_unlock_as_beneficiary(
uint256 _ownerPk,
uint256 _beneficiaryPk,
uint256 _duration,
uint256 _unlockAt,
bytes calldata _message
) external {
_duration = bound(_duration, 1, type(uint256).max - block.timestamp);
_unlockAt = bound(_unlockAt, block.timestamp + _duration, type(uint256).max);

vm.assume(boundPk(_ownerPk) != boundPk(_beneficiaryPk));
Trust t = new Trust(vm.addr(boundPk(_ownerPk)), vm.addr(boundPk(_beneficiaryPk)), _duration);

vm.prank(vm.addr(boundPk(_beneficiaryPk)));
t.setUnlocksAt(_unlockAt);

bytes32 rawHash = keccak256(_message);
bytes32 finalHash = keccak256(abi.encodePacked(address(t), rawHash));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(boundPk(_beneficiaryPk), finalHash);

bytes memory sig = abi.encodePacked(r, s, v, uint8(1), bytes1(0x01));

vm.expectRevert(abi.encodeWithSignature('NotUnlocked(uint256)', _unlockAt));
t.isValidSignature(rawHash, sig);

vm.expectRevert(abi.encodeWithSignature('NotUnlocked(uint256)', _unlockAt));
t.isValidSignature(_message, sig);
}

struct MemoryStruct1 {
bytes32 rawHash;
bytes32 finalHash;
uint8 v;
bytes32 r;
bytes32 s;
}

function test_fail_isValidSignature_invalid_signature(
uint256 _ownerPk,
uint256 _beneficiaryPk,
uint256 _badSignerPk,
bool _signsOwner,
uint256 _duration,
uint256 _unlockAt,
bytes calldata _message
) external {
_ownerPk = boundPk(_ownerPk);
_beneficiaryPk = boundPk(_beneficiaryPk);
_badSignerPk = boundPk(_badSignerPk);

address expectedSigner = _signsOwner ? vm.addr(_ownerPk) : vm.addr(_beneficiaryPk);

_duration = bound(_duration, 0, type(uint256).max - block.timestamp);
_unlockAt = bound(_unlockAt, block.timestamp + _duration, type(uint256).max);

Trust t = new Trust(vm.addr(_ownerPk), vm.addr(_beneficiaryPk), _duration);

vm.prank(vm.addr(_beneficiaryPk));
t.setUnlocksAt(_unlockAt);

if (_signsOwner) {
vm.assume(_ownerPk != _badSignerPk);
} else {
vm.assume(_beneficiaryPk != _badSignerPk);
// Advance clock to unlock
vm.warp(_unlockAt);
}

MemoryStruct1 memory m;
{
// Stack too deep manual workaround
bytes32 rawHash = keccak256(_message);
bytes32 finalHash = keccak256(abi.encodePacked(address(t), rawHash));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(_badSignerPk, finalHash);
m.rawHash = rawHash;
m.finalHash = finalHash;
m.v = v;
m.r = r;
m.s = s;
}

bytes memory sig = abi.encodePacked(m.r, m.s, m.v, uint8(1), _signsOwner ? bytes1(0x00) : bytes1(0x01));

bytes memory revertErr = abi.encodeWithSignature(
'InvalidSignature(bytes32,bytes32,address,bytes)',
m.rawHash,
m.finalHash,
expectedSigner,
abi.encodePacked(m.r, m.s, m.v, uint8(1))
);

vm.expectRevert(revertErr);
t.isValidSignature(m.rawHash, sig);

vm.expectRevert(revertErr);
t.isValidSignature(_message, sig);
}
}
51 changes: 51 additions & 0 deletions foundry_test/trust/TrustFactory.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "contracts/trust/TrustFactory.sol";

import "foundry_test/base/AdvTest.sol";

contract TrustFactoryTest is AdvTest {
TrustFactory private factory;

function setUp() external {
factory = new TrustFactory();
}

function test_create_trust(address _owner, address _beneficiary, uint256 _duration) external {
Trust trust = factory.deploy(_owner, _beneficiary, _duration);
address trustAddress = address(trust);

assertEq(trust.owner(), _owner);
assertEq(trust.beneficiary(), _beneficiary);
assertEq(trust.duration(), _duration);

uint256 codeSize; assembly { codeSize := extcodesize(trustAddress) }
assertGt(codeSize, 0);
}

function test_predict_address(address _owner, address _beneficiary, uint256 _duration) external {
address expected = factory.addressOf(_owner, _beneficiary, _duration);
address actual = address(factory.deploy(_owner, _beneficiary, _duration));
assertEq(actual, expected);
}

function test_fail_deploy_twice(address _owner, address _beneficiary, uint256 _duration) external {
factory.deploy(_owner, _beneficiary, _duration);
vm.expectRevert();
factory.deploy(_owner, _beneficiary, _duration);
}

function test_fail_deploy_low_gas(address _owner, address _beneficiary, uint256 _duration, uint256 _gas) external {
_gas = bound(_gas, 21000, block.gaslimit);
try factory.deploy{ gas: _gas }(_owner, _beneficiary, _duration) returns (Trust trust) {
address trustAddress = address(trust);
// The address should have code, and never be the zero address
assertNotEq(trustAddress, address(0));
uint256 codeSize; assembly { codeSize := extcodesize(trustAddress) }
assertGt(codeSize, 0);
} catch {
// Ignore errors from low gas
}
}
}

0 comments on commit 744e142

Please sign in to comment.