==== Source: ./contracts/base/Module.sol ==== pragma experimental SMTChecker; pragma solidity >=0.5.0; import "../common/SelfAuthorized.sol"; import "./ModuleManager.sol"; contract Module is SelfAuthorized { ModuleManager public manager; modifier authorized() override { require(msg.sender == address(manager), "Method can only be called from manager"); _; } } ==== Source: ./contracts/base/ModuleManager.sol ==== pragma experimental SMTChecker; pragma solidity >=0.5.0; import "../common/Enum.sol"; import "../common/SelfAuthorized.sol"; import "./Executor.sol"; import "./Module.sol"; contract ModuleManager is SelfAuthorized, Executor { event EnabledModule(Module module); event DisabledModule(Module module); event ExecutionFromModuleSuccess(address indexed module); event ExecutionFromModuleFailure(address indexed module); address internal constant SENTINEL_MODULES = address(0x1); mapping (address => address) internal modules; function enableModule(Module module) public authorized { require(address(module) != address(0) && address(module) != SENTINEL_MODULES, "Invalid module address provided"); require(modules[address(module)] == address(0), "Module has already been added"); modules[address(module)] = modules[SENTINEL_MODULES]; modules[SENTINEL_MODULES] = address(module); emit EnabledModule(module); } function disableModule(Module prevModule, Module module) public authorized { require(address(module) != address(0) && address(module) != SENTINEL_MODULES, "Invalid module address provided"); require(modules[address(prevModule)] == address(module), "Invalid prevModule, module pair provided"); modules[address(prevModule)] = modules[address(module)]; modules[address(module)] = address(0); emit DisabledModule(module); } function execTransactionFromModule(address to, uint256 value, bytes memory data, Enum.Operation operation) public returns (bool success) { require(msg.sender != SENTINEL_MODULES && modules[msg.sender] != address(0), "Method can only be called from an enabled module"); success = execute(to, value, data, operation, gasleft()); if (success) emit ExecutionFromModuleSuccess(msg.sender); else emit ExecutionFromModuleFailure(msg.sender); } function execTransactionFromModuleReturnData(address to, uint256 value, bytes memory data, Enum.Operation operation) public returns (bool success, bytes memory returnData) { success = execTransactionFromModule(to, value, data, operation); assembly { let ptr := mload(0x40) mstore(0x40, add(ptr, add(returndatasize(), 0x20))) mstore(ptr, returndatasize()) returndatacopy(add(ptr, 0x20), 0, returndatasize()) returnData := ptr } } function isModuleEnabled(Module module) public view returns (bool) { return SENTINEL_MODULES != address(module) && modules[address(module)] != address(0); } function getModulesPaginated(address start, uint256 pageSize) public view returns (address[] memory array, address next) { array = new address[](pageSize); uint256 moduleCount = 0; address currentModule = modules[start]; while(currentModule != address(0x0) && currentModule != SENTINEL_MODULES && moduleCount < pageSize) { array[moduleCount] = currentModule; currentModule = modules[currentModule]; moduleCount++; } next = currentModule; assembly { mstore(array, moduleCount) } } } ==== Source: ./contracts/base/OwnerManager.sol ==== pragma experimental SMTChecker; pragma solidity >=0.5.0; import "../common/SelfAuthorized.sol"; contract OwnerManager is SelfAuthorized { event AddedOwner(address owner); event RemovedOwner(address owner); event ChangedThreshold(uint256 threshold); address internal constant SENTINEL_OWNERS = address(0x1); mapping(address => address) internal owners; uint256 ownerCount; uint256 internal threshold; function setupOwners(address[] memory _owners, uint256 _threshold) internal { require(threshold == 0, "Owners have already been setup"); require(_threshold <= _owners.length, "Threshold cannot exceed owner count"); require(_threshold >= 1, "Threshold needs to be greater than 0"); address currentOwner = SENTINEL_OWNERS; for (uint256 i = 0; i < _owners.length; i++) { address owner = _owners[i]; require(owner != address(0) && owner != SENTINEL_OWNERS, "Invalid owner address provided"); require(owners[owner] == address(0), "Duplicate owner address provided"); owners[currentOwner] = owner; currentOwner = owner; } owners[currentOwner] = SENTINEL_OWNERS; ownerCount = _owners.length; threshold = _threshold; } function addOwnerWithThreshold(address owner, uint256 _threshold) public authorized { require(owner != address(0) && owner != SENTINEL_OWNERS, "Invalid owner address provided"); require(owners[owner] == address(0), "Address is already an owner"); owners[owner] = owners[SENTINEL_OWNERS]; owners[SENTINEL_OWNERS] = owner; ownerCount++; emit AddedOwner(owner); if (threshold != _threshold) changeThreshold(_threshold); } function removeOwner(address prevOwner, address owner, uint256 _threshold) public authorized { require(ownerCount - 1 >= _threshold, "New owner count needs to be larger than new threshold"); require(owner != address(0) && owner != SENTINEL_OWNERS, "Invalid owner address provided"); require(owners[prevOwner] == owner, "Invalid prevOwner, owner pair provided"); owners[prevOwner] = owners[owner]; owners[owner] = address(0); ownerCount--; emit RemovedOwner(owner); if (threshold != _threshold) changeThreshold(_threshold); } function swapOwner(address prevOwner, address oldOwner, address newOwner) public authorized { require(newOwner != address(0) && newOwner != SENTINEL_OWNERS, "Invalid owner address provided"); require(owners[newOwner] == address(0), "Address is already an owner"); require(oldOwner != address(0) && oldOwner != SENTINEL_OWNERS, "Invalid owner address provided"); require(owners[prevOwner] == oldOwner, "Invalid prevOwner, owner pair provided"); owners[newOwner] = owners[oldOwner]; owners[prevOwner] = newOwner; owners[oldOwner] = address(0); emit RemovedOwner(oldOwner); emit AddedOwner(newOwner); } function changeThreshold(uint256 _threshold) public authorized { require(_threshold <= ownerCount, "Threshold cannot exceed owner count"); require(_threshold >= 1, "Threshold needs to be greater than 0"); threshold = _threshold; emit ChangedThreshold(threshold); } function getThreshold() public view returns (uint256) { return threshold; } function isOwner(address owner) public view returns (bool) { return owner != SENTINEL_OWNERS && owners[owner] != address(0); } function getOwners() public view returns (address[] memory) { address[] memory array = new address[](ownerCount); uint256 index = 0; address currentOwner = owners[SENTINEL_OWNERS]; while(currentOwner != SENTINEL_OWNERS) { array[index] = currentOwner; currentOwner = owners[currentOwner]; index ++; } return array; } } ==== Source: ./contracts/base/Executor.sol ==== pragma experimental SMTChecker; pragma solidity >=0.5.0; import "../common/Enum.sol"; contract Executor { function execute(address to, uint256 value, bytes memory data, Enum.Operation operation, uint256 txGas) internal returns (bool success) { if (operation == Enum.Operation.Call) success = executeCall(to, value, data, txGas); else if (operation == Enum.Operation.DelegateCall) success = executeDelegateCall(to, data, txGas); else success = false; } function executeCall(address to, uint256 value, bytes memory data, uint256 txGas) internal returns (bool success) { assembly { success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0) } } function executeDelegateCall(address to, bytes memory data, uint256 txGas) internal returns (bool success) { assembly { success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0) } } } ==== Source: ./contracts/interfaces/ISignatureValidator.sol ==== pragma experimental SMTChecker; pragma solidity >=0.5.0; abstract contract ISignatureValidatorConstants { bytes4 constant internal EIP1271_MAGIC_VALUE = 0x20c13b0b; } abstract contract ISignatureValidator is ISignatureValidatorConstants { function isValidSignature( bytes memory _data, bytes memory _signature) public view virtual returns (bytes4); } ==== Source: ./contracts/common/SecuredTokenTransfer.sol ==== pragma experimental SMTChecker; pragma solidity >=0.5.0; contract SecuredTokenTransfer { function transferToken ( address token, address receiver, uint256 amount ) internal returns (bool transferred) { bytes memory data = abi.encodeWithSignature("transfer(address,uint256)", receiver, amount); assembly { let success := call(sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0) let ptr := mload(0x40) mstore(0x40, add(ptr, returndatasize())) returndatacopy(ptr, 0, returndatasize()) switch returndatasize() case 0 { transferred := success } case 0x20 { transferred := iszero(or(iszero(success), iszero(mload(ptr)))) } default { transferred := 0 } } } } ==== Source: ./contracts/common/SelfAuthorized.sol ==== pragma experimental SMTChecker; pragma solidity >=0.5.0; contract SelfAuthorized { modifier authorized() virtual { require(msg.sender == address(this), "Method can only be called from this contract"); _; } } ==== Source: ./contracts/common/SignatureDecoder.sol ==== pragma experimental SMTChecker; pragma solidity >=0.5.0; contract SignatureDecoder { function recoverKey ( bytes32 messageHash, bytes memory messageSignature, uint256 pos ) internal pure returns (address) { uint8 v; bytes32 r; bytes32 s; (v, r, s) = signatureSplit(messageSignature, pos); return ecrecover(messageHash, v, r, s); } function signatureSplit(bytes memory signatures, uint256 pos) internal pure returns (uint8 v, bytes32 r, bytes32 s) { assembly { let signaturePos := mul(0x41, pos) r := mload(add(signatures, add(signaturePos, 0x20))) s := mload(add(signatures, add(signaturePos, 0x40))) v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff) } } } ==== Source: ./contracts/common/Enum.sol ==== pragma experimental SMTChecker; pragma solidity >=0.5.0; contract Enum { enum Operation { Call, DelegateCall } } ==== Source: ./contracts/external/GnosisSafeMath.sol ==== pragma experimental SMTChecker; pragma solidity >=0.5.0; library GnosisSafeMath { function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0); // Solidity only automatically asserts when dividing by 0 uint256 c = a / b; return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a); uint256 c = a - b; return c; } function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a); return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0); return a % b; } function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } } ==== Source: ./contracts/GnosisSafe.sol ==== pragma experimental SMTChecker; pragma solidity >=0.5.0; import "./base/ModuleManager.sol"; import "./base/OwnerManager.sol"; import "./common/SignatureDecoder.sol"; import "./common/SecuredTokenTransfer.sol"; import "./interfaces/ISignatureValidator.sol"; import "./external/GnosisSafeMath.sol"; contract GnosisSafe is ModuleManager, OwnerManager, SignatureDecoder, SecuredTokenTransfer, ISignatureValidatorConstants { using GnosisSafeMath for uint256; bytes32 private constant SAFE_TX_TYPEHASH = 0xbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d8; bytes32 private constant SAFE_MSG_TYPEHASH = 0x60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca; event ExecutionFailure( bytes32 txHash, uint256 payment ); event ExecutionSuccess( bytes32 txHash, uint256 payment ); uint256 public nonce; bytes32 public domainSeparator; mapping(bytes32 => uint256) public signedMessages; mapping(address => mapping(bytes32 => uint256)) public approvedHashes; function execTransaction( address to, uint256 value, bytes calldata data, Enum.Operation operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address payable refundReceiver, bytes calldata signatures ) external payable returns (bool success) { bytes32 txHash; { bytes memory txHashData = encodeTransactionData( to, value, data, operation, // Transaction info safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, // Payment info nonce ); nonce++; txHash = keccak256(txHashData); checkSignatures(txHash, txHashData, signatures, true); } require(gasleft() >= (safeTxGas * 64 / 63).max(safeTxGas + 2500) + 500, "Not enough gas to execute safe transaction"); { uint256 gasUsed = gasleft(); success = execute(to, value, data, operation, gasPrice == 0 ? (gasleft() - 2500) : safeTxGas); gasUsed = gasUsed.sub(gasleft()); uint256 payment = 0; if (gasPrice > 0) { payment = handlePayment(gasUsed, baseGas, gasPrice, gasToken, refundReceiver); } if (success) emit ExecutionSuccess(txHash, payment); else emit ExecutionFailure(txHash, payment); } } function handlePayment( uint256 gasUsed, uint256 baseGas, uint256 gasPrice, address gasToken, address payable refundReceiver ) private returns (uint256 payment) { address payable receiver = refundReceiver == address(0) ? payable(tx.origin) : refundReceiver; if (gasToken == address(0)) { payment = gasUsed.add(baseGas).mul(gasPrice < tx.gasprice ? gasPrice : tx.gasprice); require(receiver.send(payment), "Could not pay gas costs with ether"); } else { payment = gasUsed.add(baseGas).mul(gasPrice); require(transferToken(gasToken, receiver, payment), "Could not pay gas costs with token"); } } function checkSignatures(bytes32 dataHash, bytes memory data, bytes memory signatures, bool consumeHash) internal { uint256 _threshold = threshold; require(_threshold > 0, "Threshold needs to be defined!"); require(signatures.length >= _threshold.mul(65), "Signatures data too short"); address lastOwner = address(0); address currentOwner; uint8 v; bytes32 r; bytes32 s; uint256 i; for (i = 0; i < _threshold; i++) { (v, r, s) = signatureSplit(signatures, i); if (v == 0) { currentOwner = address(uint160(uint256(r))); require(uint256(s) >= _threshold.mul(65), "Invalid contract signature location: inside static part"); require(uint256(s).add(32) <= signatures.length, "Invalid contract signature location: length not present"); uint256 contractSignatureLen; assembly { contractSignatureLen := mload(add(add(signatures, s), 0x20)) } require(uint256(s).add(32).add(contractSignatureLen) <= signatures.length, "Invalid contract signature location: data not complete"); bytes memory contractSignature; assembly { contractSignature := add(add(signatures, s), 0x20) } } else if (v == 1) { currentOwner = address(uint160(uint256(r))); require(msg.sender == currentOwner || approvedHashes[currentOwner][dataHash] != 0, "Hash has not been approved"); if (consumeHash && msg.sender != currentOwner) { approvedHashes[currentOwner][dataHash] = 0; } } else if (v > 30) { currentOwner = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)), v - 4, r, s); } else { currentOwner = ecrecover(dataHash, v, r, s); } require ( currentOwner > lastOwner && owners[currentOwner] != address(0) && currentOwner != SENTINEL_OWNERS, "Invalid owner provided" ); lastOwner = currentOwner; } } function isValidSignature(bytes calldata _data, bytes calldata _signature) external returns (bytes4) { bytes32 messageHash = getMessageHash(_data); if (_signature.length == 0) { require(signedMessages[messageHash] != 0, "Hash not approved"); } else { checkSignatures(messageHash, _data, _signature, false); } return EIP1271_MAGIC_VALUE; } function getMessageHash( bytes memory message ) public view returns (bytes32) { bytes32 safeMessageHash = keccak256( abi.encode(SAFE_MSG_TYPEHASH, keccak256(message)) ); return keccak256( abi.encodePacked(bytes1(0x19), bytes1(0x01), domainSeparator, safeMessageHash) ); } function encodeTransactionData( address to, uint256 value, bytes memory data, Enum.Operation operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address refundReceiver, uint256 _nonce ) public view returns (bytes memory) { bytes32 safeTxHash = keccak256( abi.encode(SAFE_TX_TYPEHASH, to, value, keccak256(data), operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce) ); return abi.encodePacked(bytes1(0x19), bytes1(0x01), domainSeparator, safeTxHash); } }