Skip to content

Commit

Permalink
feat(utils): more utils
Browse files Browse the repository at this point in the history
  • Loading branch information
re1ro committed Sep 29, 2023
1 parent cd1da16 commit 6056c8b
Show file tree
Hide file tree
Showing 17 changed files with 493 additions and 61 deletions.
37 changes: 37 additions & 0 deletions contracts/interfaces/IDistributable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IDistributable {
error NotDistributor();
error NotProposedDistributor();

event DistributorshipTransferred(address indexed distributor);
event DistributorshipTransferStarted(address indexed distributor);

/**
* @notice Get the address of the distributor
* @return distributor of the distributor
*/
function distributor() external view returns (address distributor);

/**
* @notice Change the distributor of the contract
* @dev Can only be called by the current distributor
* @param distributor The address of the new distributor
*/
function transferDistributorship(address distributor) external;

/**
* @notice Proposed a change of the distributor of the contract
* @dev Can only be called by the current distributor
* @param distributor_ The address of the new distributor
*/
function proposeDistributorship(address distributor_) external;

/**
* @notice Accept a change of the distributor of the contract
* @dev Can only be called by the proposed distributor
*/
function acceptDistributorship() external;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ pragma solidity ^0.8.0;
* @notice This contract provides a mechanism to halt the execution of specific functions
* if a pause condition is activated.
*/
interface INoReEntrancy {
error ReEntrancy();
interface INoReentrancy {
error Reentrancy();
}
37 changes: 37 additions & 0 deletions contracts/interfaces/IOperatable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IOperatable {
error NotOperator();
error NotProposedOperator();

event OperatorshipTransferred(address indexed operator);
event OperatorChangeProposed(address indexed operator);

/**
* @notice Get the address of the operator
* @return operator_ of the operator
*/
function operator() external view returns (address operator_);

/**
* @notice Change the operator of the contract
* @dev Can only be called by the current operator
* @param operator_ The address of the new operator
*/
function transferOperatorship(address operator_) external;

/**
* @notice Proposed a change of the operator of the contract
* @dev Can only be called by the current operator
* @param operator_ The address of the new operator
*/
function proposeOperatorship(address operator_) external;

/**
* @notice Accept a proposed change of operatorship
* @dev Can only be called by the proposed operator
*/
function acceptOperatorship() external;
}
20 changes: 20 additions & 0 deletions contracts/interfaces/IPausable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
* @title Pausable
* @notice This contract provides a mechanism to halt the execution of specific functions
* if a pause condition is activated.
*/
interface IPausable {
event PausedSet(bool indexed paused);

error Paused();

/**
* @notice Check if the contract is paused
* @return paused A boolean representing the pause status. True if paused, false otherwise.
*/
function isPaused() external view returns (bool);
}
3 changes: 0 additions & 3 deletions contracts/interfaces/IUpgradable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ interface IUpgradable is IOwnable, IContractIdentifier {
error InvalidCodeHash();
error InvalidImplementation();
error SetupFailed();
error NotProxy();

event Upgraded(address indexed newImplementation);

Expand All @@ -21,6 +20,4 @@ interface IUpgradable is IOwnable, IContractIdentifier {
bytes32 newImplementationCodeHash,
bytes calldata params
) external;

function setup(bytes calldata data) external;
}
38 changes: 38 additions & 0 deletions contracts/libs/AddressBytesUtils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
* @title AddressBytesUtils
* @dev This library provides utility functions to convert between `address` and `bytes`.
*/
library AddressBytesUtils {
error InvalidBytesLength(bytes bytesAddress);

/**
* @dev Converts a bytes address to an address type.
* @param bytesAddress The bytes representation of an address
* @return addr The converted address
*/
function toAddress(bytes memory bytesAddress) internal pure returns (address addr) {
if (bytesAddress.length != 20) revert InvalidBytesLength(bytesAddress);

assembly {
addr := mload(add(bytesAddress, 20))
}
}

/**
* @dev Converts an address to bytes.
* @param addr The address to be converted
* @return bytesAddress The bytes representation of the address
*/
function toBytes(address addr) internal pure returns (bytes memory bytesAddress) {
bytesAddress = new bytes(20);
// we can test if using a single 32 byte variable that is the address with the length together and using one mstore would be slightly cheaper.
assembly {
mstore(add(bytesAddress, 20), addr)
mstore(bytesAddress, 20)
}
}
}
17 changes: 17 additions & 0 deletions contracts/test/utils/DistributableTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { Distributable } from '../../utils/Distributable.sol';

contract DistributableTest is Distributable {
uint256 public nonce;

constructor(address distributor) {
_setDistributor(distributor);
}

function testDistributable() external onlyDistributor {
nonce++;
}
}
13 changes: 13 additions & 0 deletions contracts/test/utils/ImplementationTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { Implementation } from '../../upgradable/Implementation.sol';

contract ImplementationTest is Implementation {
uint256 public val;

function setup(bytes calldata params) external override onlyProxy {
val = abi.decode(params, (uint256));
}
}
32 changes: 32 additions & 0 deletions contracts/test/utils/MulticallTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { Multicall } from '../../utils/Multicall.sol';

contract MulticallTest is Multicall {
uint256 public nonce;
bytes[] public lastMulticallReturns;
event Function1Called(uint256 nonce_);
event Function2Called(uint256 nonce_);

function function1() external returns (uint256) {
uint256 nonce_ = nonce++;
emit Function1Called(nonce_);
return nonce_;
}

function function2() external returns (uint256) {
uint256 nonce_ = nonce++;
emit Function2Called(nonce_);
return nonce_;
}

function multicallTest(bytes[] calldata data) external {
lastMulticallReturns = multicall(data);
}

function getLastMulticallReturns() external view returns (bytes[] memory r) {
return lastMulticallReturns;
}
}
17 changes: 17 additions & 0 deletions contracts/test/utils/OperatorableTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { Operatable } from '../../utils/Operatable.sol';

contract OperatorableTest is Operatable {
uint256 public nonce;

constructor(address operator) {
_setOperator(operator);
}

function testOperatorable() external onlyOperator {
nonce++;
}
}
17 changes: 17 additions & 0 deletions contracts/test/utils/Pausable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { Pausable } from '../../utils/Pausable.sol';

contract PausableTest is Pausable {
event TestEvent();

function setPaused(bool paused) external {
_setPaused(paused);
}

function testPaused() external notPaused {
emit TestEvent();
}
}
12 changes: 2 additions & 10 deletions contracts/upgradable/Upgradable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ pragma solidity ^0.8.0;

import { IUpgradable } from '../interfaces/IUpgradable.sol';
import { Ownable } from '../utils/Ownable.sol';
import {Implementation} from "./Implementation.sol";

/**
* @title Upgradable Contract
* @notice This contract provides an interface for upgradable smart contracts and includes the functionality to perform upgrades.
*/
abstract contract Upgradable is Ownable, IUpgradable {
abstract contract Upgradable is Ownable, Implementation, IUpgradable {
// bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
address internal immutable implementationAddress;
Expand All @@ -25,15 +26,6 @@ abstract contract Upgradable is Ownable, IUpgradable {
implementationAddress = address(this);
}

/**
* @notice Modifier to ensure that a function can only be called by the proxy
*/
modifier onlyProxy() {
// Prevent setup from being called on the implementation
if (address(this) == implementationAddress) revert NotProxy();
_;
}

/**
* @notice Returns the address of the current implementation
* @return implementation_ Address of the current implementation
Expand Down
83 changes: 83 additions & 0 deletions contracts/utils/Distributable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IDistributable } from '../interfaces/IDistributable.sol';

/**
* @title Distributable Contract
* @dev A contract module which provides a basic access control mechanism, where
* there is an account (a distributor) that can be granted exclusive access to
* specific functions. This module is used through inheritance.
*/
contract Distributable is IDistributable {
// uint256(keccak256('distributor')) - 1
uint256 internal constant DISTRIBUTOR_SLOT = 0x71c5a35e45a25c49e8f747acd4bcb869814b3d104c492d2554f4c46e12371f56;

// uint256(keccak256('proposed-distributor')) - 1
uint256 internal constant PROPOSED_DISTRIBUTOR_SLOT = 0xbb1aa7d30971a97896e14e460c5ace030e39b624cf8f7c1ce200eeb378d7dcf1;

/**
* @dev Throws a NotDistributor custom error if called by any account other than the distributor.
*/
modifier onlyDistributor() {
if (distributor() != msg.sender) revert NotDistributor();
_;
}

/**
* @notice Get the address of the distributor
* @return distributor_ of the distributor
*/
function distributor() public view returns (address distributor_) {
assembly {
distributor_ := sload(DISTRIBUTOR_SLOT)
}
}

/**
* @dev Internal function that stores the new distributor address in the correct storage slot
* @param distributor_ The address of the new distributor
*/
function _setDistributor(address distributor_) internal {
assembly {
sstore(DISTRIBUTOR_SLOT, distributor_)
}
emit DistributorshipTransferred(distributor_);
}

/**
* @notice Change the distributor of the contract
* @dev Can only be called by the current distributor
* @param distributor_ The address of the new distributor
*/
function transferDistributorship(address distributor_) external onlyDistributor {
_setDistributor(distributor_);
}

/**
* @notice Proposed a change of the distributor of the contract
* @dev Can only be called by the current distributor
* @param distributor_ The address of the new distributor
*/
function proposeDistributorship(address distributor_) external onlyDistributor {
assembly {
sstore(PROPOSED_DISTRIBUTOR_SLOT, distributor_)
}
emit DistributorshipTransferStarted(distributor_);
}

/**
* @notice Accept a change of the distributor of the contract
* @dev Can only be called by the proposed distributor
*/
function acceptDistributorship() external {
address proposedDistributor;
assembly {
proposedDistributor := sload(PROPOSED_DISTRIBUTOR_SLOT)
sstore(PROPOSED_DISTRIBUTOR_SLOT, 0)
}
if (msg.sender != proposedDistributor) revert NotProposedDistributor();
_setDistributor(proposedDistributor);
}
}
Loading

0 comments on commit 6056c8b

Please sign in to comment.