|
* |
|
* Requirements: |
|
* |
|
* - The divisor cannot be zero. |
|
*/ |
|
function div(uint256 a, uint256 b) internal pure returns (uint256) { |
|
require(b > 0, "SafeMath: division by zero"); |
|
return a / b; |
|
} |
|
|
|
/** |
|
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), |
|
* reverting when dividing by zero. |
|
* |
|
* Counterpart to Solidity's `%` operator. This function uses a `revert` |
|
* opcode (which leaves remaining gas untouched) while Solidity uses an |
|
* invalid opcode to revert (consuming all remaining gas). |
|
* |
|
* Requirements: |
|
* |
|
* - The divisor cannot be zero. |
|
*/ |
|
function mod(uint256 a, uint256 b) internal pure returns (uint256) { |
|
require(b > 0, "SafeMath: modulo by zero"); |
|
return a % b; |
|
} |
|
|
|
/** |
|
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on |
|
* overflow (when the result is negative). |
|
* |
|
* CAUTION: This function is deprecated because it requires allocating memory for the error |
|
* message unnecessarily. For custom revert reasons use {trySub}. |
|
* |
|
* Counterpart to Solidity's `-` operator. |
|
* |
|
* Requirements: |
|
* |
|
* - Subtraction cannot overflow. |
|
*/ |
|
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { |
|
require(b <= a, errorMessage); |
|
return a - b; |
|
} |
|
|
|
/** |
|
* @dev Returns the integer division of two unsigned integers, reverting with custom message on |
|
* division by zero. The result is rounded towards zero. |
|
* |
|
* CAUTION: This function is deprecated because it requires allocating memory for the error |
|
* message unnecessarily. For custom revert reasons use {tryDiv}. |
|
* |
|
* Counterpart to Solidity's `/` operator. Note: this function uses a |
|
* `revert` opcode (which leaves remaining gas untouched) while Solidity |
|
* uses an invalid opcode to revert (consuming all remaining gas). |
|
* |
|
* Requirements: |
|
* |
|
* - The divisor cannot be zero. |
|
*/ |
|
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { |
|
require(b > 0, errorMessage); |
|
return a / b; |
|
} |
|
|
|
/** |
|
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), |
|
* reverting with custom message when dividing by zero. |
|
* |
|
* CAUTION: This function is deprecated because it requires allocating memory for the error |
|
* message unnecessarily. For custom revert reasons use {tryMod}. |
|
* |
|
* Counterpart to Solidity's `%` operator. This function uses a `revert` |
|
* opcode (which leaves remaining gas untouched) while Solidity uses an |
|
* invalid opcode to revert (consuming all remaining gas). |
|
* |
|
* Requirements: |
|
* |
|
* - The divisor cannot be zero. |
|
*/ |
|
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { |
|
require(b > 0, errorMessage); |
|
return a % b; |
|
} |
|
} |
|
|
|
|
|
// File @openzeppelin/contracts/token/ERC20/[email protected] |
|
|
|
// SPDX-License-Identifier: MIT |
|
|
|
pragma solidity >=0.6.0 <0.8.0; |
|
|
|
|
|
|
|
/** |
|
* @dev Implementation of the {IERC20} interface. |
|
* |
|
* This implementation is agnostic to the way tokens are created. This means |
|
* that a supply mechanism has to be added in a derived contract using {_mint}. |
|
* For a generic mechanism see {ERC20PresetMinterPauser}. |
|
* |
|
* TIP: For a detailed writeup see our guide |
|
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How |
|
* to implement supply mechanisms]. |
|
* |
|
* We have followed general OpenZeppelin guidelines: functions revert instead |
|
* of returning `false` on failure. This behavior is nonetheless conventional |
|
* and does not conflict with the expectations of ERC20 applications. |
|
* |
|
* Additionally, an {Approval} event is emitted on calls to {transferFrom}. |
|
* This allows applications to reconstruct the allowance for all accounts just |
|
* by listening to said events. Other implementations of the EIP may not emit |
|
* these events, as it isn't required by the specification. |
|
* |
|
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance} |
|
* functions have been added to mitigate the well-known issues around setting |
|
* allowances. See {IERC20-approve}. |
|
*/ |
|
contract ERC20 is Context, IERC20 { |
|
using SafeMath for uint256; |
|
|
|
mapping (address => uint256) private _balances; |
|
|
|
mapping (address => mapping (address => uint256)) private _allowances; |
|
|
|
uint256 private _totalSupply; |
|
|
|
string private _name; |
|
string private _symbol; |
|
uint8 private _decimals; |
|
|
|
/** |
|
* @dev Sets the values for {name} and {symbol}, initializes {decimals} with |
|
* a default value of 18. |
|
* |
|
* To select a different value for {decimals}, use {_setupDecimals}. |
|
* |
|
* All three of these values are immutable: they can only be set once during |
|
* construction. |
|
*/ |
|
constructor (string memory name_, string memory symbol_) public { |
|
_name = name_; |
|
_symbol = symbol_; |
|
_decimals = 18; |
|
} |
|
|
|
/** |
|
* @dev Returns the name of the token. |
|
*/ |
|
function name() public view virtual returns (string memory) { |
|
return _name; |
|
} |
|
|
|
/** |
|
* @dev Returns the symbol of the token, usually a shorter version of the |
|
* name. |
|
*/ |
|
function symbol() public view virtual returns (string memory) { |
|
return _symbol; |
|
} |
|
|
|
/** |
|
* @dev Returns the number of decimals used to get its user representation. |
|
* For example, if `decimals` equals `2`, a balance of `505` tokens should |
|
* be displayed to a user as `5,05` (`505 / 10 ** 2`). |
|
* |
|
* Tokens usually opt for a value of 18, imitating the relationship between |
|
* Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is |
|
* called. |
|
* |
|
* NOTE: This information is only used for _display_ purposes: it in |
|
* no way affects any of the arithmetic of the contract, including |
|
* {IERC20-balanceOf} and {IERC20-transfer}. |
|
*/ |
|
function decimals() public view virtual returns (uint8) { |
|
return _decimals; |
|
} |
|
|
|
/** |
|
* @dev See {IERC20-totalSupply}. |
|
*/ |
|
function totalSupply() public view virtual override returns (uint256) { |
|
return _totalSupply; |
|
} |
|
|
|
/** |
|
* @dev See {IERC20-balanceOf}. |
|
*/ |
|
function balanceOf(address account) public view virtual override returns (uint256) { |
|
return _balances[account]; |
|
} |
|
|
|
/** |
|
* @dev See {IERC20-transfer}. |
|
* |
|
* Requirements: |
|
* |
|
* - `recipient` cannot be the zero address. |
|
* - the caller must have a balance of at least `amount`. |
|
*/ |
|
function transfer(address recipient, uint256 amount) public virtual override returns (bool) { |
|
_transfer(_msgSender(), recipient, amount); |
|
return true; |
|
} |
|
|
|
/** |
|
* @dev See {IERC20-allowance}. |
|
*/ |
|
function allowance(address owner, address spender) public view virtual override returns (uint256) { |
|
return _allowances[owner][spender]; |
|
} |
|
|
|
/** |
|
* @dev See {IERC20-approve}. |
|
* |
|
* Requirements: |
|
* |
|
* - `spender` cannot be the zero address. |
|
*/ |
|
function approve(address spender, uint256 amount) public virtual override returns (bool) { |
|
_approve(_msgSender(), spender, amount); |
|
return true; |
|
} |
|
|
|
/** |
|
* @dev See {IERC20-transferFrom}. |
|
* |
|
* Emits an {Approval} event indicating the updated allowance. This is not |
|
* required by the EIP. See the note at the beginning of {ERC20}. |
|
* |
|
* Requirements: |
|
* |
|
* - `sender` and `recipient` cannot be the zero address. |
|
* - `sender` must have a balance of at least `amount`. |
|
* - the caller must have allowance for ``sender``'s tokens of at least |
|
* `amount`. |
|
*/ |
|
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { |
|
_transfer(sender, recipient, amount); |
|
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); |
|
return true; |
|
} |
|
|
|
/** |
|
* @dev Atomically increases the allowance granted to `spender` by the caller. |
|
* |
|
* This is an alternative to {approve} that can be used as a mitigation for |
|
* problems described in {IERC20-approve}. |
|
* |
|
* Emits an {Approval} event indicating the updated allowance. |
|
* |
|
* Requirements: |
|
* |
|
* - `spender` cannot be the zero address. |
|
*/ |
|
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { |
|
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); |
|
return true; |
|
} |
|
|
|
/** |
|
* @dev Atomically decreases the allowance granted to `spender` by the caller. |
|
* |
|
* This is an alternative to {approve} that can be used as a mitigation for |
|
* problems described in {IERC20-approve}. |
|
* |
|
* Emits an {Approval} event indicating the updated allowance. |
|
* |
|
* Requirements: |
|
* |
|
* - `spender` cannot be the zero address. |
|
* - `spender` must have allowance for the caller of at least |
|
* `subtractedValue`. |
|
*/ |
|
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { |
|
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); |
|
return true; |
|
} |
|
|
|
/** |
|
* @dev Moves tokens `amount` from `sender` to `recipient`. |
|
* |
|
* This is internal function is equivalent to {transfer}, and can be used to |
|
* e.g. implement automatic token fees, slashing mechanisms, etc. |
|
* |
|
* Emits a {Transfer} event. |
|
* |
|
* Requirements: |
|
* |
|
* - `sender` cannot be the zero address. |
|
* - `recipient` cannot be the zero address. |
|
* - `sender` must have a balance of at least `amount`. |
|
*/ |
|
function _transfer(address sender, address recipient, uint256 amount) internal virtual { |
|
require(sender != address(0), "ERC20: transfer from the zero address"); |
|
require(recipient != address(0), "ERC20: transfer to the zero address"); |
|
|
|
_beforeTokenTransfer(sender, recipient, amount); |
|
|
|
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); |
|
_balances[recipient] = _balances[recipient].add(amount); |
|
emit Transfer(sender, recipient, amount); |
|
} |
|
|
|
/** @dev Creates `amount` tokens and assigns them to `account`, increasing |
|
* the total supply. |
|
* |
|
* Emits a {Transfer} event with `from` set to the zero address. |
|
* |
|
* Requirements: |
|
* |
|
* - `to` cannot be the zero address. |
|
*/ |
|
function _mint(address account, uint256 amount) internal virtual { |
|
require(account != address(0), "ERC20: mint to the zero address"); |
|
|
|
_beforeTokenTransfer(address(0), account, amount); |
|
|
|
_totalSupply = _totalSupply.add(amount); |
|
_balances[account] = _balances[account].add(amount); |
|
emit Transfer(address(0), account, amount); |
|
} |
|
|
|
/** |
|
* @dev Destroys `amount` tokens from `account`, reducing the |
|
* total supply. |
|
* |
|
* Emits a {Transfer} event with `to` set to the zero address. |
|
* |
|
* Requirements: |
|
* |
|
* - `account` cannot be the zero address. |
|
* - `account` must have at least `amount` tokens. |
|
*/ |
|
function _burn(address account, uint256 amount) internal virtual { |
|
require(account != address(0), "ERC20: burn from the zero address"); |
|
|
|
_beforeTokenTransfer(account, address(0), amount); |
|
|
|
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); |
|
_totalSupply = _totalSupply.sub(amount); |
|
emit Transfer(account, address(0), amount); |
|
} |
|
|
|
/** |
|
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. |
|
* |
|
* This internal function is equivalent to `approve`, and can be used to |
|
* e.g. set automatic allowances for certain subsystems, etc. |
|
* |
|
* Emits an {Approval} event. |
|
* |
|
* Requirements: |
|
* |
|
* - `owner` cannot be the zero address. |
|
* - `spender` cannot be the zero address. |
|
*/ |
|
function _approve(address owner, address spender, uint256 amount) internal virtual { |
|
require(owner != address(0), "ERC20: approve from the zero address"); |
|
require(spender != address(0), "ERC20: approve to the zero address"); |
|
|
|
_allowances[owner][spender] = amount; |
|
emit Approval(owner, spender, amount); |
|
} |
|
|
|
/** |
|
* @dev Sets {decimals} to a value other than the default one of 18. |
|
* |
|
* WARNING: This function should only be called from the constructor. Most |
|
* applications that interact with token contracts will not expect |
|
* {decimals} to ever change, and may work incorrectly if it does. |
|
*/ |
|
function _setupDecimals(uint8 decimals_) internal virtual { |
|
_decimals = decimals_; |
|
} |
|
|
|
/** |
|
* @dev Hook that is called before any transfer of tokens. This includes |
|
* minting and burning. |
|
* |
|
* Calling conditions: |
|
* |
|
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens |
|
* will be to transferred to `to`. |
|
* - when `from` is zero, `amount` tokens will be minted for `to`. |
|
* - when `to` is zero, `amount` of ``from``'s tokens will be burned. |
|
* - `from` and `to` are never both zero. |
|
* |
|
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. |
|
*/ |
|
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } |
|
} |
|
|
|
|
|
// File contracts/test/ERC20Token.sol |
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only |
|
pragma solidity >=0.6.0 <0.8.0; |
|
|
|
contract ERC20Token is ERC20 { |
|
constructor() public ERC20("TestToken", "TT") { |
|
_mint(msg.sender, 1000000000000000); |
|
} |
|
} |
|
|
|
|
|
// File contracts/handler/HandlerContext.sol |
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only |
|
pragma solidity >=0.7.0 <0.9.0; |
|
|
|
/// @title Handler Context - allows to extract calling context |
|
/// @author Richard Meissner - <[email protected]> |
|
/// @notice based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/f8cc8b844a9f92f63dc55aa581f7d643a1bc5ac1/contracts/metatx/ERC2771Context.sol |
|
contract HandlerContext { |
|
// This function does not rely on a trusted forwarder. Use the returned value only to check information against the calling manager. |
|
/// @notice This is only reliable in combination with a FallbackManager that supports this (e.g. Safe contract >=1.3.0). |
|
/// When using this functionality make sure that the linked _manager (aka msg.sender) supports this. |
|
function _msgSender() internal pure returns (address sender) { |
|
// The assembly code is more direct than the Solidity version using `abi.decode`. |
|
// solhint-disable-next-line no-inline-assembly |
|
assembly { |
|
sender := shr(96, calldataload(sub(calldatasize(), 20))) |
|
} |
|
} |
|
|
|
// Function do differentiate more clearly between msg.sender and the calling manager |
|
function _manager() internal view returns (address) { |
|
return msg.sender; |
|
} |
|
} |
|
|
|
|
|
// File contracts/test/TestHandler.sol |
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only |
|
pragma solidity >=0.7.0 <0.9.0; |
|
|
|
contract TestHandler is HandlerContext { |
|
function dudududu() external view returns (address sender, address manager) { |
|
return (_msgSender(), _manager()); |
|
} |
|
} |
|
|
|
|
|
// File @gnosis.pm/mock-contract/contracts/[email protected] |
|
|
|
pragma solidity ^0.6.0; |
|
|
|
interface MockInterface { |
|
/** |
|
* @dev After calling this method, the mock will return `response` when it is called |
|
* with any calldata that is not mocked more specifically below |
|
* (e.g. using givenMethodReturn). |
|
* @param response ABI encoded response that will be returned if method is invoked |
|
*/ |
|
function givenAnyReturn(bytes calldata response) external; |
|
function givenAnyReturnBool(bool response) external; |
|
function givenAnyReturnUint(uint response) external; |
|
function givenAnyReturnAddress(address response) external; |
|
|
|
function givenAnyRevert() external; |
|
function givenAnyRevertWithMessage(string calldata message) external; |
|
function givenAnyRunOutOfGas() external; |
|
|
|
/** |
|
* @dev After calling this method, the mock will return `response` when the given |
|
* methodId is called regardless of arguments. If the methodId and arguments |
|
* are mocked more specifically (using `givenMethodAndArguments`) the latter |
|
* will take precedence. |
|
* @param method ABI encoded methodId. It is valid to pass full calldata (including arguments). The mock will extract the methodId from it |
|
* @param response ABI encoded response that will be returned if method is invoked |
|
*/ |
|
function givenMethodReturn(bytes calldata method, bytes calldata response) external; |
|
function givenMethodReturnBool(bytes calldata method, bool response) external; |
|
function givenMethodReturnUint(bytes calldata method, uint response) external; |
|
function givenMethodReturnAddress(bytes calldata method, address response) external; |
|
|
|
function givenMethodRevert(bytes calldata method) external; |
|
function givenMethodRevertWithMessage(bytes calldata method, string calldata message) external; |
|
function givenMethodRunOutOfGas(bytes calldata method) external; |
|
|
|
/** |
|
* @dev After calling this method, the mock will return `response` when the given |
|
* methodId is called with matching arguments. These exact calldataMocks will take |
|
* precedence over all other calldataMocks. |
|
* @param call ABI encoded calldata (methodId and arguments) |
|
* @param response ABI encoded response that will be returned if contract is invoked with calldata |
|
*/ |
|
function givenCalldataReturn(bytes calldata call, bytes calldata response) external; |
|
function givenCalldataReturnBool(bytes calldata call, bool response) external; |
|
function givenCalldataReturnUint(bytes calldata call, uint response) external; |
|
function givenCalldataReturnAddress(bytes calldata call, address response) external; |
|
|
|
function givenCalldataRevert(bytes calldata call) external; |
|
function givenCalldataRevertWithMessage(bytes calldata call, string calldata message) external; |
|
function givenCalldataRunOutOfGas(bytes calldata call) external; |
|
|
|
/** |
|
* @dev Returns the number of times anything has been called on this mock since last reset |
|
*/ |
|
function invocationCount() external returns (uint); |
|
|
|
/** |
|
* @dev Returns the number of times the given method has been called on this mock since last reset |
|
* @param method ABI encoded methodId. It is valid to pass full calldata (including arguments). The mock will extract the methodId from it |
|
*/ |
|
function invocationCountForMethod(bytes calldata method) external returns (uint); |
|
|
|
/** |
|
* @dev Returns the number of times this mock has been called with the exact calldata since last reset. |
|
* @param call ABI encoded calldata (methodId and arguments) |
|
*/ |
|
function invocationCountForCalldata(bytes calldata call) external returns (uint); |
|
|
|
/** |
|
* @dev Resets all mocked methods and invocation counts. |
|
*/ |
|
function reset() external; |
|
} |
|
|
|
/** |
|
* Implementation of the MockInterface. |
|
*/ |
|
contract MockContract is MockInterface { |
|
enum MockType { Return, Revert, OutOfGas } |
|
|
|
bytes32 public constant MOCKS_LIST_START = hex"01"; |
|
bytes public constant MOCKS_LIST_END = "0xff"; |
|
bytes32 public constant MOCKS_LIST_END_HASH = keccak256(MOCKS_LIST_END); |
|
bytes4 public constant SENTINEL_ANY_MOCKS = hex"01"; |
|
bytes public constant DEFAULT_FALLBACK_VALUE = abi.encode(false); |
|
|
|
// A linked list allows easy iteration and inclusion checks |
|
mapping(bytes32 => bytes) calldataMocks; |
|
mapping(bytes => MockType) calldataMockTypes; |
|
mapping(bytes => bytes) calldataExpectations; |
|
mapping(bytes => string) calldataRevertMessage; |
|
mapping(bytes32 => uint) calldataInvocations; |
|
|
|
mapping(bytes4 => bytes4) methodIdMocks; |
|
mapping(bytes4 => MockType) methodIdMockTypes; |
|
mapping(bytes4 => bytes) methodIdExpectations; |
|
mapping(bytes4 => string) methodIdRevertMessages; |
|
mapping(bytes32 => uint) methodIdInvocations; |
|
|
|
MockType fallbackMockType; |
|
bytes fallbackExpectation = DEFAULT_FALLBACK_VALUE; |
|
string fallbackRevertMessage; |
|
uint invocations; |
|
uint resetCount; |
|
|
|
constructor() public { |
|
calldataMocks[MOCKS_LIST_START] = MOCKS_LIST_END; |
|
methodIdMocks[SENTINEL_ANY_MOCKS] = SENTINEL_ANY_MOCKS; |
|
} |
|
|
|
function trackCalldataMock(bytes memory call) private { |
|
bytes32 callHash = keccak256(call); |
|
if (calldataMocks[callHash].length == 0) { |
|
calldataMocks[callHash] = calldataMocks[MOCKS_LIST_START]; |
|
calldataMocks[MOCKS_LIST_START] = call; |
|
} |
|
} |
|
|
|
function trackMethodIdMock(bytes4 methodId) private { |
|
if (methodIdMocks[methodId] == 0x0) { |
|
methodIdMocks[methodId] = methodIdMocks[SENTINEL_ANY_MOCKS]; |
|
methodIdMocks[SENTINEL_ANY_MOCKS] = methodId; |
|
} |
|
} |
|
|
|
function _givenAnyReturn(bytes memory response) internal { |
|
fallbackMockType = MockType.Return; |
|
fallbackExpectation = response; |
|
} |
|
|
|
function givenAnyReturn(bytes calldata response) override external { |
|
_givenAnyReturn(response); |
|
} |
|
|
|
function givenAnyReturnBool(bool response) override external { |
|
uint flag = response ? 1 : 0; |
|
_givenAnyReturn(uintToBytes(flag)); |
|
} |
|
|
|
function givenAnyReturnUint(uint response) override external { |
|
_givenAnyReturn(uintToBytes(response)); |
|
} |
|
|
|
function givenAnyReturnAddress(address response) override external { |
|
_givenAnyReturn(uintToBytes(uint(response))); |
|
} |
|
|
|
function givenAnyRevert() override external { |
|
fallbackMockType = MockType.Revert; |
|
fallbackRevertMessage = ""; |
|
} |
|
|
|
function givenAnyRevertWithMessage(string calldata message) override external { |
|
fallbackMockType = MockType.Revert; |
|
fallbackRevertMessage = message; |
|
} |
|
|
|
function givenAnyRunOutOfGas() override external { |
|
fallbackMockType = MockType.OutOfGas; |
|
} |
|
|
|
function _givenCalldataReturn(bytes memory call, bytes memory response) private { |
|
calldataMockTypes[call] = MockType.Return; |
|
calldataExpectations[call] = response; |
|
trackCalldataMock(call); |
|
} |
|
|
|
function givenCalldataReturn(bytes calldata call, bytes calldata response) override external { |
|
_givenCalldataReturn(call, response); |
|
} |
|
|
|
function givenCalldataReturnBool(bytes calldata call, bool response) override external { |
|
uint flag = response ? 1 : 0; |
|
_givenCalldataReturn(call, uintToBytes(flag)); |
|
} |
|
|
|
function givenCalldataReturnUint(bytes calldata call, uint response) override external { |
|
_givenCalldataReturn(call, uintToBytes(response)); |
|
} |
|
|
|
function givenCalldataReturnAddress(bytes calldata call, address response) override external { |
|
_givenCalldataReturn(call, uintToBytes(uint(response))); |
|
} |
|
|
|
function _givenMethodReturn(bytes memory call, bytes memory response) private { |
|
bytes4 method = bytesToBytes4(call); |
|
methodIdMockTypes[method] = MockType.Return; |
|
methodIdExpectations[method] = response; |
|
trackMethodIdMock(method); |
|
} |
|
|
|
function givenMethodReturn(bytes calldata call, bytes calldata response) override external { |
|
_givenMethodReturn(call, response); |
|
} |
|
|
|
function givenMethodReturnBool(bytes calldata call, bool response) override external { |
|
uint flag = response ? 1 : 0; |
|
_givenMethodReturn(call, uintToBytes(flag)); |
|
} |
|
|
|
function givenMethodReturnUint(bytes calldata call, uint response) override external { |
|
_givenMethodReturn(call, uintToBytes(response)); |
|
} |
|
|
|
function givenMethodReturnAddress(bytes calldata call, address response) override external { |
|
_givenMethodReturn(call, uintToBytes(uint(response))); |
|
} |
|
|
|
function givenCalldataRevert(bytes calldata call) override external { |
|
calldataMockTypes[call] = MockType.Revert; |
|
calldataRevertMessage[call] = ""; |
|
trackCalldataMock(call); |
|
} |
|
|
|
function givenMethodRevert(bytes calldata call) override external { |
|
bytes4 method = bytesToBytes4(call); |
|
methodIdMockTypes[method] = MockType.Revert; |
|
trackMethodIdMock(method); |
|
} |
|
|
|
function givenCalldataRevertWithMessage(bytes calldata call, string calldata message) override external { |
|
calldataMockTypes[call] = MockType.Revert; |
|
calldataRevertMessage[call] = message; |
|
trackCalldataMock(call); |
|
} |
|
|
|
function givenMethodRevertWithMessage(bytes calldata call, string calldata message) override external { |
|
bytes4 method = bytesToBytes4(call); |
|
methodIdMockTypes[method] = MockType.Revert; |
|
methodIdRevertMessages[method] = message; |
|
trackMethodIdMock(method); |
|
} |
|
|
|
function givenCalldataRunOutOfGas(bytes calldata call) override external { |
|
calldataMockTypes[call] = MockType.OutOfGas; |
|
trackCalldataMock(call); |
|
} |
|
|
|
function givenMethodRunOutOfGas(bytes calldata call) override external { |
|
bytes4 method = bytesToBytes4(call); |
|
methodIdMockTypes[method] = MockType.OutOfGas; |
|
trackMethodIdMock(method); |
|
} |
|
|
|
function invocationCount() override external returns (uint) { |
|
return invocations; |
|
} |
|
|
|
function invocationCountForMethod(bytes calldata call) override external returns (uint) { |
|
bytes4 method = bytesToBytes4(call); |
|
return methodIdInvocations[keccak256(abi.encodePacked(resetCount, method))]; |
|
} |
|
|
|
function invocationCountForCalldata(bytes calldata call) override external returns (uint) { |
|
return calldataInvocations[keccak256(abi.encodePacked(resetCount, call))]; |
|
} |
|
|
|
function reset() override external { |
|
// Reset all exact calldataMocks |
|
bytes memory nextMock = calldataMocks[MOCKS_LIST_START]; |
|
bytes32 mockHash = keccak256(nextMock); |
|
// We cannot compary bytes |
|
while(mockHash != MOCKS_LIST_END_HASH) { |
|
// Reset all mock maps |
|
calldataMockTypes[nextMock] = MockType.Return; |
|
calldataExpectations[nextMock] = hex""; |
|
calldataRevertMessage[nextMock] = ""; |
|
// Set next mock to remove |
|
nextMock = calldataMocks[mockHash]; |
|
// Remove from linked list |
|
calldataMocks[mockHash] = ""; |
|
// Update mock hash |
|
mockHash = keccak256(nextMock); |
|
} |
|
// Clear list |
|
calldataMocks[MOCKS_LIST_START] = MOCKS_LIST_END; |
|
|
|
// Reset all any calldataMocks |
|
bytes4 nextAnyMock = methodIdMocks[SENTINEL_ANY_MOCKS]; |
|
while(nextAnyMock != SENTINEL_ANY_MOCKS) { |
|
bytes4 currentAnyMock = nextAnyMock; |
|
methodIdMockTypes[currentAnyMock] = MockType.Return; |
|
methodIdExpectations[currentAnyMock] = hex""; |
|
methodIdRevertMessages[currentAnyMock] = ""; |
|
nextAnyMock = methodIdMocks[currentAnyMock]; |
|
// Remove from linked list |
|
methodIdMocks[currentAnyMock] = 0x0; |
|
} |
|
// Clear list |
|
methodIdMocks[SENTINEL_ANY_MOCKS] = SENTINEL_ANY_MOCKS; |
|
|
|
fallbackExpectation = DEFAULT_FALLBACK_VALUE; |
|
fallbackMockType = MockType.Return; |
|
invocations = 0; |
|
resetCount += 1; |
|
} |
|
|
|
function useAllGas() private { |
|
while(true) { |
|
bool s; |
|
assembly { |
|
//expensive call to EC multiply contract |
|
s := call(sub(gas(), 2000), 6, 0, 0x0, 0xc0, 0x0, 0x60) |
|
} |
|
} |
|
} |
|
|
|
function bytesToBytes4(bytes memory b) private pure returns (bytes4) { |
|
bytes4 out; |
|
for (uint i = 0; i < 4; i++) { |
|
out |= bytes4(b[i] & 0xFF) >> (i * 8); |
|
} |
|
return out; |
|
} |
|
|
|
function uintToBytes(uint256 x) private pure returns (bytes memory b) { |
|
b = new bytes(32); |
|
assembly { mstore(add(b, 32), x) } |
|
} |
|
|
|
function updateInvocationCount(bytes4 methodId, bytes memory originalMsgData) public { |
|
require(msg.sender == address(this), "Can only be called from the contract itself"); |
|
invocations += 1; |
|
methodIdInvocations[keccak256(abi.encodePacked(resetCount, methodId))] += 1; |
|
calldataInvocations[keccak256(abi.encodePacked(resetCount, originalMsgData))] += 1; |
|
} |
|
|
|
fallback () payable external { |
|
bytes4 methodId; |
|
assembly { |
|
methodId := calldataload(0) |
|
} |
|
|
|
// First, check exact matching overrides |
|
if (calldataMockTypes[msg.data] == MockType.Revert) { |
|
revert(calldataRevertMessage[msg.data]); |
|
} |
|
if (calldataMockTypes[msg.data] == MockType.OutOfGas) { |
|
useAllGas(); |
|
} |
|
bytes memory result = calldataExpectations[msg.data]; |
|
|
|
// Then check method Id overrides |
|
if (result.length == 0) { |
|
if (methodIdMockTypes[methodId] == MockType.Revert) { |
|
revert(methodIdRevertMessages[methodId]); |
|
} |
|
if (methodIdMockTypes[methodId] == MockType.OutOfGas) { |
|
useAllGas(); |
|
} |
|
result = methodIdExpectations[methodId]; |
|
} |
|
|
|
// Last, use the fallback override |
|
if (result.length == 0) { |
|
if (fallbackMockType == MockType.Revert) { |
|
revert(fallbackRevertMessage); |
|
} |
|
if (fallbackMockType == MockType.OutOfGas) { |
|
useAllGas(); |
|
} |
|
result = fallbackExpectation; |
|
} |
|
|
|
// Record invocation as separate call so we don't rollback in case we are called with STATICCALL |
|
(, bytes memory r) = address(this).call{gas: 100000}(abi.encodeWithSignature("updateInvocationCount(bytes4,bytes)", methodId, msg.data)); |
|
assert(r.length == 0); |
|
|
|
assembly { |
|
return(add(0x20, result), mload(result)) |
|
} |
|
} |
|
} |
|
|
|
|
|
// File contracts/test/Token.sol |
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only |
|
pragma solidity >=0.6.0 <0.7.0; |
|
|
|
interface Token { |
|
function transfer(address _to, uint256 value) external returns (bool); |
|
} |
|
|
|
|
|
// File contracts/interfaces/ViewStorageAccessible.sol |
|
|
|
pragma solidity >=0.5.0 <0.6.0; |
|
|
|
/// @title ViewStorageAccessible - Interface on top of StorageAccessible base class to allow simulations from view functions |
|
/// @notice Adjusted version of https://github.com/gnosis/util-contracts/blob/3db1e531cb243a48ea91c60a800d537c1000612a/contracts/StorageAccessible.sol |
|
interface ViewStorageAccessible { |
|
/** |
|
* @dev Same as `simulate` on StorageAccessible. Marked as view so that it can be called from external contracts |
|
* that want to run simulations from within view functions. Will revert if the invoked simulation attempts to change state. |
|
*/ |
|
function simulate(address targetContract, bytes calldata calldataPayload) external view returns (bytes memory); |
|
} |
|
|
|
|
|
// File contracts/libraries/CreateCall.sol |
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only |
|
pragma solidity >=0.7.0 <0.9.0; |
|
|
|
/// @title Create Call - Allows to use the different create opcodes to deploy a contract |
|
/// @author Richard Meissner - <[email protected]> |
|
contract CreateCall { |
|
event ContractCreation(address newContract); |
|
|
|
function performCreate2( |
|
uint256 value, |
|
bytes memory deploymentData, |
|
bytes32 salt |
|
) public returns (address newContract) { |
|
// solhint-disable-next-line no-inline-assembly |
|
assembly { |
|
newContract := create2(value, add(0x20, deploymentData), mload(deploymentData), salt) |
|
} |
|
require(newContract != address(0), "Could not deploy contract"); |
|
emit ContractCreation(newContract); |
|
} |
|
|
|
function performCreate(uint256 value, bytes memory deploymentData) public returns (address newContract) { |
|
// solhint-disable-next-line no-inline-assembly |
|
assembly { |
|
newContract := create(value, add(deploymentData, 0x20), mload(deploymentData)) |
|
} |
|
require(newContract != address(0), "Could not deploy contract"); |
|
emit ContractCreation(newContract); |
|
} |
|
} |
|
|
|
|
|
// File contracts/libraries/MultiSend.sol |
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only |
|
pragma solidity >=0.7.0 <0.9.0; |
|
|
|
/// @title Multi Send - Allows to batch multiple transactions into one. |
|
/// @author Nick Dodson - <[email protected]> |
|
/// @author Gonçalo Sá - <[email protected]> |
|
/// @author Stefan George - <[email protected]> |
|
/// @author Richard Meissner - <[email protected]> |
|
contract MultiSend { |
|
address private immutable multisendSingleton; |
|
|
|
constructor() { |
|
multisendSingleton = address(this); |
|
} |
|
|
|
/// @dev Sends multiple transactions and reverts all if one fails. |
|
/// @param transactions Encoded transactions. Each transaction is encoded as a packed bytes of |
|
/// operation as a uint8 with 0 for a call or 1 for a delegatecall (=> 1 byte), |
|
/// to as a address (=> 20 bytes), |
|
/// value as a uint256 (=> 32 bytes), |
|
/// data length as a uint256 (=> 32 bytes), |
|
/// data as bytes. |
|
/// see abi.encodePacked for more information on packed encoding |
|
/// @notice This method is payable as delegatecalls keep the msg.value from the previous call |
|
/// If the calling method (e.g. execTransaction) received ETH this would revert otherwise |
|
function multiSend(bytes memory transactions) public payable { |
|
require(address(this) != multisendSingleton, "MultiSend should only be called via delegatecall"); |
|
// solhint-disable-next-line no-inline-assembly |
|
assembly { |
|
let length := mload(transactions) |
|
let i := 0x20 |
|
for { |
|
// Pre block is not used in "while mode" |
|
} lt(i, length) { |
|
// Post block is not used in "while mode" |
|
} { |
|
// First byte of the data is the operation. |
|
// We shift by 248 bits (256 - 8 [operation byte]) it right since mload will always load 32 bytes (a word). |
|
// This will also zero out unused data. |
|
let operation := shr(0xf8, mload(add(transactions, i))) |
|
// We offset the load address by 1 byte (operation byte) |
|
// We shift it right by 96 bits (256 - 160 [20 address bytes]) to right-align the data and zero out unused data. |
|
let to := shr(0x60, mload(add(transactions, add(i, 0x01)))) |
|
// We offset the load address by 21 byte (operation byte + 20 address bytes) |
|
let value := mload(add(transactions, add(i, 0x15))) |
|
// We offset the load address by 53 byte (operation byte + 20 address bytes + 32 value bytes) |
|
let dataLength := mload(add(transactions, add(i, 0x35))) |
|
// We offset the load address by 85 byte (operation byte + 20 address bytes + 32 value bytes + 32 data length bytes) |
|
let data := add(transactions, add(i, 0x55)) |
|
let success := 0 |
|
switch operation |
|
case 0 { |
|
success := call(gas(), to, value, data, dataLength, 0, 0) |
|
} |
|
case 1 { |
|
success := delegatecall(gas(), to, data, dataLength, 0, 0) |
|
} |
|
if eq(success, 0) { |
|
revert(0, 0) |
|
} |
|
// Next entry starts at 85 byte + data length |
|
i := add(i, add(0x55, dataLength)) |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
// File contracts/libraries/MultiSendCallOnly.sol |
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only |
|
pragma solidity >=0.7.0 <0.9.0; |
|
|
|
/// @title Multi Send Call Only - Allows to batch multiple transactions into one, but only calls |
|
/// @author Stefan George - <[email protected]> |
|
/// @author Richard Meissner - <[email protected]> |
|
/// @notice The guard logic is not required here as this contract doesn't support nested delegate calls |
|
contract MultiSendCallOnly { |
|
/// @dev Sends multiple transactions and reverts all if one fails. |
|
/// @param transactions Encoded transactions. Each transaction is encoded as a packed bytes of |
|
/// operation has to be uint8(0) in this version (=> 1 byte), |
|
/// to as a address (=> 20 bytes), |
|
/// value as a uint256 (=> 32 bytes), |
|
/// data length as a uint256 (=> 32 bytes), |
|
/// data as bytes. |
|
/// see abi.encodePacked for more information on packed encoding |
|
/// @notice The code is for most part the same as the normal MultiSend (to keep compatibility), |
|
/// but reverts if a transaction tries to use a delegatecall. |
|
/// @notice This method is payable as delegatecalls keep the msg.value from the previous call |
|
/// If the calling method (e.g. execTransaction) received ETH this would revert otherwise |
|
function multiSend(bytes memory transactions) public payable { |
|
// solhint-disable-next-line no-inline-assembly |
|
assembly { |
|
let length := mload(transactions) |
|
let i := 0x20 |
|
for { |
|
// Pre block is not used in "while mode" |
|
} lt(i, length) { |
|
// Post block is not used in "while mode" |
|
} { |
|
// First byte of the data is the operation. |
|
// We shift by 248 bits (256 - 8 [operation byte]) it right since mload will always load 32 bytes (a word). |
|
// This will also zero out unused data. |
|
let operation := shr(0xf8, mload(add(transactions, i))) |
|
// We offset the load address by 1 byte (operation byte) |
|
// We shift it right by 96 bits (256 - 160 [20 address bytes]) to right-align the data and zero out unused data. |
|
let to := shr(0x60, mload(add(transactions, add(i, 0x01)))) |
|
// We offset the load address by 21 byte (operation byte + 20 address bytes) |
|
let value := mload(add(transactions, add(i, 0x15))) |
|
// We offset the load address by 53 byte (operation byte + 20 address bytes + 32 value bytes) |
|
let dataLength := mload(add(transactions, add(i, 0x35))) |
|
// We offset the load address by 85 byte (operation byte + 20 address bytes + 32 value bytes + 32 data length bytes) |
|
let data := add(transactions, add(i, 0x55)) |
|
let success := 0 |
|
switch operation |
|
case 0 { |
|
success := call(gas(), to, value, data, dataLength, 0, 0) |
|
} |
|
// This version does not allow delegatecalls |
|
case 1 { |
|
revert(0, 0) |
|
} |
|
if eq(success, 0) { |
|
revert(0, 0) |
|
} |
|
// Next entry starts at 85 byte + data length |
|
i := add(i, add(0x55, dataLength)) |
|
} |
|
} |
|
} |
|
} |
|
~/development/fuse/safe-contracts on #v1.3.0 !3 ?1 ❯ took 6s at 14:39:45 |