Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/extensions/recovery/Recovery.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ contract Recovery is ISapientCompact {
uint256 internal constant FLAG_BRANCH = 4;

/// @notice Emitted when a new payload is queued
event NewQueuedPayload(address _wallet, address _signer, bytes32 _payloadHash, uint256 _timestamp);
event NewQueuedPayload(address indexed _wallet, address indexed _signer, bytes32 _payloadHash, uint256 _timestamp);

/// @notice Error thrown when the signature is invalid
error InvalidSignature(address _wallet, address _signer, Payload.Decoded _payload, bytes _signature);
Expand All @@ -37,7 +37,10 @@ contract Recovery is ISapientCompact {
/// @notice Error thrown when the signature flag is invalid
error InvalidSignatureFlag(uint256 _flag);

function domainSeparator(bool _noChainId, address _wallet) internal view returns (bytes32 _domainSeparator) {
function domainSeparator(
bool _noChainId,
address _wallet
) internal view returns (bytes32 _domainSeparator) {
return keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
Expand All @@ -61,7 +64,10 @@ contract Recovery is ISapientCompact {
/// @param _wallet The wallet to get the total number of queued payloads for
/// @param _signer The signer to get the total number of queued payloads for
/// @return The total number of queued payloads
function totalQueuedPayloads(address _wallet, address _signer) public view returns (uint256) {
function totalQueuedPayloads(
address _wallet,
address _signer
) public view returns (uint256) {
return queuedPayloadHashes[_wallet][_signer].length;
}

Expand Down Expand Up @@ -140,7 +146,10 @@ contract Recovery is ISapientCompact {
/// @param _wallet The wallet to get the recovery payload hash for
/// @param _payload The payload to get the recovery payload hash for
/// @return The recovery payload hash
function recoveryPayloadHash(address _wallet, Payload.Decoded calldata _payload) public view returns (bytes32) {
function recoveryPayloadHash(
address _wallet,
Payload.Decoded calldata _payload
) public view returns (bytes32) {
bytes32 domain = domainSeparator(_payload.noChainId, _wallet);
bytes32 structHash = Payload.toEIP712(_payload);
return keccak256(abi.encodePacked("\x19\x01", domain, structHash));
Expand Down
19 changes: 13 additions & 6 deletions src/modules/Calls.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import { IDelegatedExtension } from "./interfaces/IDelegatedExtension.sol";
abstract contract Calls is ReentrancyGuard, BaseAuth, Nonce {

/// @notice Emitted when a call succeeds
event CallSucceeded(bytes32 _opHash, uint256 _index);
event CallSucceeded(bytes32 indexed _opHash, uint256 _index);
/// @notice Emitted when a call fails
event CallFailed(bytes32 _opHash, uint256 _index, bytes _returnData);
event CallFailed(bytes32 indexed _opHash, uint256 _index, bytes _returnData);
/// @notice Emitted when a call is aborted
event CallAborted(bytes32 _opHash, uint256 _index, bytes _returnData);
event CallAborted(bytes32 indexed _opHash, uint256 _index, bytes _returnData);
/// @notice Emitted when a call is skipped
event CallSkipped(bytes32 _opHash, uint256 _index);
event CallSkipped(bytes32 indexed _opHash, uint256 _index);

/// @notice Error thrown when a call reverts
error Reverted(Payload.Decoded _payload, uint256 _index, bytes _returnData);
Expand All @@ -33,7 +33,10 @@ abstract contract Calls is ReentrancyGuard, BaseAuth, Nonce {
/// @notice Execute a call
/// @param _payload The payload
/// @param _signature The signature
function execute(bytes calldata _payload, bytes calldata _signature) external payable virtual nonReentrant {
function execute(
bytes calldata _payload,
bytes calldata _signature
) external payable virtual nonReentrant {
uint256 startingGas = gasleft();
Payload.Decoded memory decoded = Payload.fromPackedCalls(_payload);

Expand All @@ -59,7 +62,11 @@ abstract contract Calls is ReentrancyGuard, BaseAuth, Nonce {
_execute(startingGas, opHash, decoded);
}

function _execute(uint256 _startingGas, bytes32 _opHash, Payload.Decoded memory _decoded) private {
function _execute(
uint256 _startingGas,
bytes32 _opHash,
Payload.Decoded memory _decoded
) private {
bool errorFlag = false;

uint256 numCalls = _decoded.calls.length;
Expand Down
47 changes: 30 additions & 17 deletions test/Guest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,6 @@ contract GuestTest is AdvTest {

Guest public guest;

event CallSucceeded(bytes32 _opHash, uint256 _index);
event CallFailed(bytes32 _opHash, uint256 _index, bytes _returnData);
event CallAborted(bytes32 _opHash, uint256 _index, bytes _returnData);
event CallSkipped(bytes32 _opHash, uint256 _index);

function setUp() external {
guest = new Guest();
}
Expand All @@ -57,18 +52,21 @@ contract GuestTest is AdvTest {
for (uint256 i = 0; i < decoded.calls.length; i++) {
if (decoded.calls[i].onlyFallback) {
vm.expectEmit(true, true, true, true);
emit CallSkipped(opHash, i);
emit Calls.CallSkipped(opHash, i);
} else {
vm.expectCall(decoded.calls[i].to, decoded.calls[i].data);
// vm.expectEmit(true, true, true, true);
// emit CallSucceeded(opHash, i);
// emit Calls.CallSucceeded(opHash, i);
}
}
(bool ok,) = address(guest).call(packed);
assertTrue(ok);
}

function test_notEnoughGas(GuestPayload memory p, uint256 callIndex) external {
function test_notEnoughGas(
GuestPayload memory p,
uint256 callIndex
) external {
vm.assume(p.calls.length > 0);
callIndex = bound(callIndex, 0, p.calls.length - 1);

Expand Down Expand Up @@ -98,7 +96,10 @@ contract GuestTest is AdvTest {
assertTrue(ok);
}

function test_delegateCallNotAllowed(GuestPayload memory p, uint256 callIndex) external {
function test_delegateCallNotAllowed(
GuestPayload memory p,
uint256 callIndex
) external {
vm.assume(p.calls.length > 0);
callIndex = bound(callIndex, 0, p.calls.length - 1);

Expand Down Expand Up @@ -126,7 +127,10 @@ contract GuestTest is AdvTest {
assertTrue(ok);
}

function test_callFailsWithIgnoreBehavior(GuestPayload memory p, uint256 callIndex) external {
function test_callFailsWithIgnoreBehavior(
GuestPayload memory p,
uint256 callIndex
) external {
vm.assume(p.calls.length > 0);
callIndex = bound(callIndex, 0, p.calls.length - 1);

Expand Down Expand Up @@ -163,12 +167,12 @@ contract GuestTest is AdvTest {
vm.expectEmit(true, true, true, true);

if (!errorFlag && decoded.calls[i].onlyFallback) {
emit CallSkipped(opHash, i);
emit Calls.CallSkipped(opHash, i);
} else if (decoded.calls[i].to == failureAddress && keccak256(decoded.calls[i].data) == failureDataHash) {
emit CallFailed(opHash, i, revertData);
emit Calls.CallFailed(opHash, i, revertData);
errorFlag = true;
} else {
emit CallSucceeded(opHash, i);
emit Calls.CallSucceeded(opHash, i);
vm.expectCall(decoded.calls[i].to, decoded.calls[i].data);
errorFlag = false;
}
Expand All @@ -178,7 +182,10 @@ contract GuestTest is AdvTest {
assertTrue(ok);
}

function test_callFailsWithRevertBehavior(GuestPayload memory p, uint256 callIndex) external {
function test_callFailsWithRevertBehavior(
GuestPayload memory p,
uint256 callIndex
) external {
vm.assume(p.calls.length > 0);
callIndex = bound(callIndex, 0, p.calls.length - 1);

Expand Down Expand Up @@ -216,7 +223,10 @@ contract GuestTest is AdvTest {
assertTrue(ok);
}

function test_callFailsWithAbortBehavior(GuestPayload memory p, uint256 callIndex) external {
function test_callFailsWithAbortBehavior(
GuestPayload memory p,
uint256 callIndex
) external {
vm.assume(p.calls.length > 0);
callIndex = bound(callIndex, 0, p.calls.length - 1);

Expand Down Expand Up @@ -250,13 +260,16 @@ contract GuestTest is AdvTest {

// Expect the abort event
vm.expectEmit(true, true, true, true);
emit CallAborted(opHash, callIndex, revertData);
emit Calls.CallAborted(opHash, callIndex, revertData);

(bool ok,) = address(guest).call(packed);
assertTrue(ok);
}

function test_forwardPayment(uint256 _value1, uint256 _value2) external {
function test_forwardPayment(
uint256 _value1,
uint256 _value2
) external {
address to1 = address(0x100001);
address to2 = address(0x100002);

Expand Down
56 changes: 37 additions & 19 deletions test/modules/Calls.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ contract CallsImp is Calls {
expectedOpHash = _opHash;
}

function writeNonce(uint256 _space, uint256 _nonce) external {
function writeNonce(
uint256 _space,
uint256 _nonce
) external {
_writeNonce(_space, _nonce);
}

Expand All @@ -52,7 +55,9 @@ contract CallsImp is Calls {

}

contract MockDelegatecall { // extends IDelegatedExtension (but we make it payable for the test)
contract MockDelegatecall {

// extends IDelegatedExtension (but we make it payable for the test)

event OpHash(bytes32 _opHash);
event StartingGas(uint256 _startingGas);
Expand Down Expand Up @@ -102,11 +107,6 @@ contract CallsTest is AdvTest {

CallsImp public calls = new CallsImp();

event CallSucceeded(bytes32 _opHash, uint256 _index);
event CallSkipped(bytes32 _opHash, uint256 _index);
event CallFailed(bytes32 _opHash, uint256 _index, bytes _returnData);
event CallAborted(bytes32 _opHash, uint256 _index, bytes _returnData);

function preparePayload(
Payload.Decoded memory decoded
) internal {
Expand All @@ -131,7 +131,11 @@ contract CallsTest is AdvTest {
vm.deal(address(calls), totalEther);
}

function test_execute(bytes32 _opHash, CallsPayload memory _payload, bytes calldata _signature) external {
function test_execute(
bytes32 _opHash,
CallsPayload memory _payload,
bytes calldata _signature
) external {
vm.assume(_payload.calls.length < 3);
address mockDelegatecall = address(new MockDelegatecall());
Payload.Decoded memory decoded = toDecodedPayload(_payload);
Expand All @@ -147,7 +151,7 @@ contract CallsTest is AdvTest {
for (uint256 i = 0; i < decoded.calls.length; i++) {
if (decoded.calls[i].onlyFallback) {
vm.expectEmit(true, true, true, true, address(calls));
emit CallSkipped(_opHash, i);
emit Calls.CallSkipped(_opHash, i);
} else {
vm.deal(decoded.calls[i].to, 0);

Expand All @@ -169,7 +173,7 @@ contract CallsTest is AdvTest {
vm.expectCall(decoded.calls[i].to, decoded.calls[i].data);
}

emit CallSucceeded(_opHash, i);
emit Calls.CallSucceeded(_opHash, i);
}
}

Expand Down Expand Up @@ -215,7 +219,7 @@ contract CallsTest is AdvTest {
for (uint256 i = 0; i < decoded.calls.length; i++) {
if (decoded.calls[i].onlyFallback) {
vm.expectEmit(true, true, true, true, address(calls));
emit CallSkipped(opHash, i);
emit Calls.CallSkipped(opHash, i);
} else {
vm.deal(decoded.calls[i].to, 0);
if (decoded.calls[i].delegateCall) {
Expand All @@ -235,7 +239,7 @@ contract CallsTest is AdvTest {
vm.expectCall(decoded.calls[i].to, decoded.calls[i].data);
}
vm.expectEmit(true, true, true, true, address(calls));
emit CallSucceeded(opHash, i);
emit Calls.CallSucceeded(opHash, i);
}
}

Expand Down Expand Up @@ -325,16 +329,19 @@ contract CallsTest is AdvTest {

// First call should fail and emit CallFailed
vm.expectEmit(true, true, true, true, address(calls));
emit CallFailed(opHash, 0, revertData);
emit Calls.CallFailed(opHash, 0, revertData);

// Second call should succeed as the previous error makes the fallback execute
vm.expectEmit(true, true, true, true, address(calls));
emit CallSucceeded(opHash, 1);
emit Calls.CallSucceeded(opHash, 1);

calls.execute(packed, _signature);
}

function test_revert_on_error(Payload.Call calldata call, bytes calldata _signature) external {
function test_revert_on_error(
Payload.Call calldata call,
bytes calldata _signature
) external {
CallsPayload memory _payload;
_payload.calls = new Payload.Call[](1);

Expand Down Expand Up @@ -369,7 +376,10 @@ contract CallsTest is AdvTest {
calls.execute(packed, _signature);
}

function test_abort_on_error(Payload.Call calldata call, bytes calldata _signature) external {
function test_abort_on_error(
Payload.Call calldata call,
bytes calldata _signature
) external {
CallsPayload memory _payload;
_payload.calls = new Payload.Call[](1);

Expand Down Expand Up @@ -400,12 +410,16 @@ contract CallsTest is AdvTest {

// Call should fail and emit CallAborted
vm.expectEmit(true, true, true, true, address(calls));
emit CallAborted(opHash, 0, revertData);
emit Calls.CallAborted(opHash, 0, revertData);

calls.execute(packed, _signature);
}

function test_not_enough_gas(Payload.Call calldata call, uint256 txGasLimit, bytes calldata _signature) external {
function test_not_enough_gas(
Payload.Call calldata call,
uint256 txGasLimit,
bytes calldata _signature
) external {
CallsPayload memory _payload;
_payload.calls = new Payload.Call[](1);

Expand Down Expand Up @@ -437,7 +451,11 @@ contract CallsTest is AdvTest {
calls.execute{ gas: txGasLimit }(packed, _signature);
}

function test_empty_payload_consumes_nonce(uint256 space, uint256 nonce, bytes calldata signature) external {
function test_empty_payload_consumes_nonce(
uint256 space,
uint256 nonce,
bytes calldata signature
) external {
Payload.Decoded memory decoded;
decoded.kind = Payload.KIND_TRANSACTIONS;
decoded.space = space;
Expand Down