Skip to content

Instantly share code, notes, and snippets.

@developerfred
Last active September 15, 2021 17:40
Show Gist options
  • Save developerfred/58cd98ffc2a77eafb2f9b25fc755d61c to your computer and use it in GitHub Desktop.
Save developerfred/58cd98ffc2a77eafb2f9b25fc755d61c to your computer and use it in GitHub Desktop.
Gnosis Safe Deploy - Fuse Network
*
* 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

Release

https://github.com/gnosis/safe-contracts/releases/tag/v1.3.0

Contracts

  • reusing "SimulateTxAccessor" at 0x59AD6735bCd8152B84860Cb256dD9e96b85F69Da
  • deploying "GnosisSafeProxyFactory" (tx: 0xd5dd2d7967d36ed923c1f4699d188ea3936600df2f554b60037c8405907450dc)...: deployed at 0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2 with 1050114 gas
  • reusing "DefaultCallbackHandler" at 0x1AC114C2099aFAf5261731655Dc6c306bFcd4Dbd
  • deploying "CompatibilityFallbackHandler" (tx: 0x5081d6beb3997abcf99628f9f6c944a6d08f2fbfb2548bfc4a004242cbdca5e7)...: deployed at 0xf48f2B2d2a534e402487b3ee7C18c33Aec0Fe5e4 with 1502931 gas
  • reusing "CreateCall" at 0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4
  • reusing "MultiSend" at 0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761
  • reusing "MultiSendCallOnly" at 0x40A2aCCbd92BCA938b02010E17A5b8929b49130D
  • deploying "GnosisSafeL2" (tx: 0xfec4c5ae8b52a798e67fa06a55a28f0267e2e8f24948e80cc04019cd19ea0bfa)...: deployed at 0x3E5c63644E683549055b9Be8653de26E0B4CD36E with 6298461 gas
  • deploying "GnosisSafe" (tx: 0xa3edfa01c6bade5e5434b13ebf002206e937b26f69ce01f83d2c03c1d4c03cdd)...: deployed at 0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552 with 6072685 gas```

✨ Done in 79.57s.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment