Skip to content

Commit

Permalink
Merge pull request #96 from Zarfsec/main
Browse files Browse the repository at this point in the history
Pausable huff implementation
  • Loading branch information
devtooligan authored Feb 21, 2023
2 parents 26d8f73 + 36d92fa commit 2b4013a
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 0 deletions.
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ fs_permissions = [
{ access = "read", path = "./test/utils/mocks/MerkleProofLibWrappers.huff" },
{ access = "read", path = "./test/utils/mocks/MulticallableWrappers.huff" },
{ access = "read", path = "./test/utils/mocks/Create3Wrappers.huff" },
{ access = "read", path = "./test/utils/mocks/PausableWrappers.huff" },
{ access = "read", path = "./test/utils/mocks/ReentrancyGuardWrappers.huff" },
{ access = "read", path = "./test/utils/mocks/RefundedWrappers.huff" },
{ access = "read", path = "./test/utils/mocks/SafeTransferLibWrappers.huff" },
Expand Down
93 changes: 93 additions & 0 deletions src/utils/Pausable.huff
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/// @title Pausable
/// @notice SPDX-License-Identifier: MIT
/// @author zarf.eth <https://github.com/zarfsec>
/// @notice A Pausable implementation


// Interface

/// @notice returns whether the contract is paused
#define function isPaused() view returns (bool)

/// @notice Pauses the contract
/// @dev Only callable when the contract is unpaused.
#define function pause() nonpayable returns ()

/// @notice Unpauses the contract
/// @dev Only callable when the contract is paused.
#define function unpause() nonpayable returns ()

/// @notice Emitted when contract is paused.
#define event Paused(address)

/// @notice Emitted when contract is unpaused.
#define event Unpaused(address)



// Storage

/// @notice Paused Storage Slot
#define constant PAUSED_SLOT = FREE_STORAGE_POINTER()

/// @notice Unpaused representation
#define constant _UNPAUSED = 0x01

/// @notice Paused representation
#define constant _PAUSED = 0x02


/// @notice Pausable constructor
#define macro PAUSABLE_CONSTRUCTOR() = takes (0) returns (0) {
[_UNPAUSED] [PAUSED_SLOT] sstore // []
}

/// @notice whenNotPaused modifier
#define macro WHEN_NOT_PAUSED_MODIFIER() = takes (0) returns (0) {
[PAUSED_SLOT] sload // [isPaused]
[_UNPAUSED] eq when_not_paused jumpi // []
0x00 dup1 revert // []
when_not_paused: // []
}

/// @notice whenPaused modifier
#define macro WHEN_PAUSED_MODIFIER() = takes (0) returns (0) {
[PAUSED_SLOT] sload // [isPaused]
[_PAUSED] eq when_paused jumpi // []
0x00 dup1 revert // []
when_paused: // []
}

/// @notice return whether contract is paused
#define macro PAUSABLE_IS_PAUSED() = takes (0) returns (0) {
0x01 // [1]
[PAUSED_SLOT] sload // [isPaused, 1]
sub // [bool]
0x00 mstore // []
0x20 0x00 return // []
}


/// @notice Pause the contract
#define macro PAUSABLE_PAUSE() = takes (0) returns (0) {
WHEN_NOT_PAUSED_MODIFIER() // []

//emit Paused(address)
caller __EVENT_HASH(Paused) 0x00 dup1 // [0, 0, EVENT_PAUSED, msg.sender]
log2 // []

[_PAUSED] [PAUSED_SLOT] sstore // []
stop
}

/// @notice Unpause the contract
#define macro PAUSABLE_UNPAUSE() = takes (0) returns (0) {
WHEN_PAUSED_MODIFIER() // []

//emit Unpaused(address)
caller __EVENT_HASH(Unpaused) 0x00 dup1 // [0, 0, EVENT_UNPAUSED, msg.sender]
log2 // []

[_UNPAUSED] [PAUSED_SLOT] sstore // []
stop
}
52 changes: 52 additions & 0 deletions test/utils/Pausable.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import "foundry-huff/HuffDeployer.sol";
import "forge-std/Test.sol";


interface IPausable {
function isPaused() external view returns (bool);
function pause() external;
function unpause() external;
}



contract PausableTest is Test {
IPausable pausable;

function setUp() public {
string memory wrapper_code = vm.readFile("test/utils/mocks/PausableWrappers.huff");
pausable = IPausable(HuffDeployer.deploy_with_code("utils/Pausable", wrapper_code));
}

function testIsPausedByDefault() public {
assertEq(pausable.isPaused(), false);
}

function testPauseUnPause() public {
pausable.pause();
assertEq(pausable.isPaused(), true);

pausable.unpause();
assertEq(pausable.isPaused(), false);
}

function testUnpauseWhenUnpaused() public {
assertEq(pausable.isPaused(), false);

vm.expectRevert();
pausable.unpause();
}

function testPauseWhenPaused() public {
pausable.pause();
assertEq(pausable.isPaused(), true);

vm.expectRevert();
pausable.pause();
}


}
39 changes: 39 additions & 0 deletions test/utils/mocks/PausableWrappers.huff
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#define function isPaused() view returns (bool)
#define function pause() nonpayable returns ()
#define function unpause() nonpayable returns ()


#define macro CONSTRUCTOR() = takes (0) returns (0) {
PAUSABLE_CONSTRUCTOR()
}


#define macro IS_PAUSED_WRAPPER() = takes (0) returns (0) {
PAUSABLE_IS_PAUSED()
}

#define macro PAUSE_WRAPPER() = takes (0) returns (0) {
PAUSABLE_PAUSE()
}

#define macro UNPAUSE_WRAPPER() = takes (0) returns (0) {
PAUSABLE_UNPAUSE()
}


#define macro MAIN() = takes (0) returns (0) {
pc calldataload 0xe0 shr // [sig]

dup1 __FUNC_SIG(pause) eq pause jumpi
dup1 __FUNC_SIG(unpause) eq unpause jumpi
dup1 __FUNC_SIG(isPaused) eq is_paused jumpi

0x00 dup1 revert

pause:
PAUSE_WRAPPER()
unpause:
UNPAUSE_WRAPPER()
is_paused:
IS_PAUSED_WRAPPER()
}

0 comments on commit 2b4013a

Please sign in to comment.