Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x60806040 | 22116579 | 3 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 22085654 | 7 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 22005950 | 18 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21992548 | 20 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21970727 | 23 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21954906 | 25 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21952617 | 26 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21943491 | 27 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21935328 | 28 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21911889 | 31 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21862021 | 38 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21856825 | 39 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21838614 | 42 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21830597 | 43 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21808631 | 46 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21776795 | 50 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21759181 | 53 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21737172 | 56 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21714691 | 59 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21698350 | 61 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21681891 | 63 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21663572 | 66 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21614430 | 73 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21578714 | 78 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 21519524 | 86 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
SmartAccountProxyFactory
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "@openzeppelin/contracts/utils/Create2.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./SmartAccount.sol"; import "./SmartAccountProxy.sol"; /** * A wrapper factory contract to deploy SmartAccount as an Account-Abstraction wallet contract. */ contract SmartAccountProxyFactory is Ownable { event ProxyCreation(SmartAccountProxy proxy, address singleton); event SafeSingletonSet(address safeSingleton, bool value); mapping(address => bool) public safeSingleton; mapping(address => bool) public walletWhiteList; constructor(address _safeSingleton, address _owner) { safeSingleton[_safeSingleton] = true; _transferOwnership(_owner); } function setSafeSingleton( address _safeSingleton, bool value ) public onlyOwner { safeSingleton[_safeSingleton] = value; emit SafeSingletonSet(_safeSingleton, value); } /// @dev Allows to retrieve the runtime code of a deployed Proxy. This can be used to check that the expected Proxy was deployed. function proxyRuntimeCode() public pure returns (bytes memory) { return type(SmartAccountProxy).runtimeCode; } /// @dev Allows to retrieve the creation code used for the Proxy deployment. With this it is easily possible to calculate predicted address. function proxyCreationCode() public pure returns (bytes memory) { return type(SmartAccountProxy).creationCode; } /// @dev Allows to create new proxy contact using CREATE2 but it doesn't run the initializer. /// This method is only meant as an utility to be called from other methods /// @param _singleton Address of singleton contract. /// @param initializer Payload for message call sent to new proxy contract. /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract. function deployProxyWithNonce( address _singleton, bytes memory initializer, uint256 saltNonce ) internal returns (SmartAccountProxy proxy) { // If the initializer changes the proxy address should change too. Hashing the initializer data is cheaper than just concatinating it bytes32 salt = keccak256( abi.encodePacked(keccak256(initializer), saltNonce) ); bytes memory deploymentData = abi.encodePacked( type(SmartAccountProxy).creationCode ); // solhint-disable-next-line no-inline-assembly assembly { proxy := create2( 0x0, add(0x20, deploymentData), mload(deploymentData), salt ) } require(address(proxy) != address(0), "Create2 call failed"); walletWhiteList[address(proxy)] = true; } /// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction. /// @param _singleton Address of singleton contract. /// @param initializer Payload for message call sent to new proxy contract. /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract. function createProxyWithNonce( address _singleton, bytes memory initializer, uint256 saltNonce ) internal returns (SmartAccountProxy proxy) { proxy = deployProxyWithNonce(_singleton, initializer, saltNonce); if (initializer.length > 0) { // solhint-disable-next-line no-inline-assembly bytes memory initdata = abi.encodeWithSelector( SmartAccountProxy.initialize.selector, _singleton, initializer ); assembly { if eq( call( gas(), proxy, 0, add(initdata, 0x20), mload(initdata), 0, 0 ), 0 ) { revert(0, 0) } } } emit ProxyCreation(proxy, _singleton); } function createAccount( address _safeSingleton, bytes memory initializer, uint256 salt ) public returns (address) { require(safeSingleton[_safeSingleton], "Invalid singleton"); address addr = getAddress(_safeSingleton, initializer, salt); uint256 codeSize = addr.code.length; if (codeSize > 0) { return addr; } return address(createProxyWithNonce(_safeSingleton, initializer, salt)); } /** * calculate the counterfactual address of this account as it would be returned by createAccount() * (uses the same "create2 signature" used by SmartAccountProxyFactory.createProxyWithNonce) */ function getAddress( address _safeSingleton, bytes memory initializer, uint256 salt ) public view returns (address) { //copied from deployProxyWithNonce bytes32 salt2 = keccak256( abi.encodePacked(keccak256(initializer), salt) ); bytes memory deploymentData = abi.encodePacked( type(SmartAccountProxy).creationCode ); return Create2.computeAddress( bytes32(salt2), keccak256(deploymentData), address(this) ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Create2.sol) pragma solidity ^0.8.0; /** * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. * `CREATE2` can be used to compute in advance the address where a smart * contract will be deployed, which allows for interesting new mechanisms known * as 'counterfactual interactions'. * * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more * information. */ library Create2 { /** * @dev Deploys a contract using `CREATE2`. The address where the contract * will be deployed can be known in advance via {computeAddress}. * * The bytecode for a contract can be obtained from Solidity with * `type(contractName).creationCode`. * * Requirements: * * - `bytecode` must not be empty. * - `salt` must have not been used for `bytecode` already. * - the factory must have a balance of at least `amount`. * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. */ function deploy( uint256 amount, bytes32 salt, bytes memory bytecode ) internal returns (address addr) { require(address(this).balance >= amount, "Create2: insufficient balance"); require(bytecode.length != 0, "Create2: bytecode length is zero"); /// @solidity memory-safe-assembly assembly { addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) } require(addr != address(0), "Create2: Failed on deploy"); } /** * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the * `bytecodeHash` or `salt` will result in a new destination address. */ function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) { return computeAddress(salt, bytecodeHash, address(this)); } /** * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. */ function computeAddress( bytes32 salt, bytes32 bytecodeHash, address deployer ) internal pure returns (address addr) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) // Get free memory pointer // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... | // |-------------------|---------------------------------------------------------------------------| // | bytecodeHash | CCCCCCCCCCCCC...CC | // | salt | BBBBBBBBBBBBB...BB | // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA | // | 0xFF | FF | // |-------------------|---------------------------------------------------------------------------| // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC | // | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ | mstore(add(ptr, 0x40), bytecodeHash) mstore(add(ptr, 0x20), salt) mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff mstore8(start, 0xff) addr := keccak256(start, 85) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "../library/UserOperation.sol"; interface IAccount { /** * Validate user's signature and nonce * the entryPoint will make the call to the recipient only if this validation call returns successfully. * signature failure should be reported by returning SIG_VALIDATION_FAILED (1). * This allows making a "simulation call" without a valid signature * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure. * * @dev Must validate caller is the entryPoint. * Must validate the signature and nonce * @param userOp the operation that is about to be executed. * @param userOpHash hash of the user's request data. can be used as the basis for signature. * @param aggregator the aggregator used to validate the signature. NULL for non-aggregated signature accounts. * @param missingAccountFunds missing funds on the account's deposit in the entrypoint. * This is the minimum amount to transfer to the sender(entryPoint) to be able to make the call. * The excess is left as a deposit in the entrypoint, for future calls. * can be withdrawn anytime using "entryPoint.withdrawTo()" * In case there is a paymaster in the request (or the current deposit is high enough), this value will be zero. * @return deadline the last block timestamp this operation is valid, or zero if it is valid indefinitely. * signature failure is returned as SIG_VALIDATION_FAILED value (1) * Note that the validation code cannot use block.timestamp (or block.number) directly. */ function validateUserOp( UserOperation calldata userOp, bytes32 userOpHash, address aggregator, uint256 missingAccountFunds ) external returns (uint256 deadline); function validateUserOpWithoutSig( UserOperation calldata userOp, bytes32 userOpHash, address aggregator, uint256 missingAccountFunds ) external returns (uint256 deadline); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; contract ISignatureValidatorConstants { // bytes4(keccak256("isValidSignature(bytes,bytes)") bytes4 internal constant EIP1271_MAGIC_VALUE = 0x20c13b0b; } abstract contract ISignatureValidator is ISignatureValidatorConstants { /** * @dev Should return whether the signature provided is valid for the provided data * @param _data Arbitrary length data signed on the behalf of address(this) * @param _signature Signature byte array associated with _data * * MUST return the bytes4 magic value 0x20c13b0b when function passes. * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5) * MUST allow external calls */ function isValidSignature( bytes memory _data, bytes memory _signature ) public view virtual returns (bytes4); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /** * A wrapper factory contract to deploy SmartAccount as an Account-Abstraction wallet contract. */ interface ISmartAccountProxy { function masterCopy() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; interface IStorage { struct bundlerInformation { address bundler; uint256 registeTime; } event UnrestrictedWalletSet(bool allowed); event UnrestrictedBundlerSet(bool allowed); event UnrestrictedModuleSet(bool allowed); event WalletFactoryWhitelistSet(address walletProxyFactory); event BundlerWhitelistSet(address indexed bundler, bool allowed); event ModuleWhitelistSet(address indexed module, bool allowed); function officialBundlerWhiteList( address bundler ) external view returns (bool); function moduleWhiteList(address module) external view returns (bool); function setUnrestrictedWallet(bool allowed) external; function setUnrestrictedBundler(bool allowed) external; function setUnrestrictedModule(bool allowed) external; function setBundlerOfficialWhitelist( address bundler, bool allowed ) external; function setWalletProxyFactoryWhitelist(address walletFactory) external; function setModuleWhitelist(address module, bool allowed) external; function validateModuleWhitelist(address module) external; function validateWalletWhitelist(address sender) external view; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /* solhint-disable no-inline-assembly */ /** * User Operation struct * @param sender the sender account of this request * @param nonce unique value the sender uses to verify it is not a replay. * @param initCode if set, the account contract will be created by this constructor * @param callData the method call to execute on this account. * @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp * @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead. * @param maxFeePerGas same as EIP-1559 gas parameter * @param maxPriorityFeePerGas same as EIP-1559 gas parameter * @param paymasterAndData if set, this field hold the paymaster address and "paymaster-specific-data". the paymaster will pay for the transaction instead of the sender * @param signature sender-verified signature over the entire request, the EntryPoint address and the chain ID. */ struct UserOperation { address sender; uint256 nonce; bytes initCode; bytes callData; uint256 callGasLimit; uint256 verificationGasLimit; uint256 preVerificationGas; uint256 maxFeePerGas; uint256 maxPriorityFeePerGas; bytes paymasterAndData; bytes signature; } library UserOperationLib { function getSender( UserOperation calldata userOp ) internal pure returns (address) { address data; //read sender from userOp, which is first userOp member (saves 800 gas...) assembly { data := calldataload(userOp) } return address(uint160(data)); } //relayer/block builder might submit the TX with higher priorityFee, but the user should not // pay above what he signed for. function gasPrice( UserOperation calldata userOp ) internal view returns (uint256) { unchecked { uint256 maxFeePerGas = userOp.maxFeePerGas; uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; if (maxFeePerGas == maxPriorityFeePerGas) { //legacy mode (for networks that don't support basefee opcode) return maxFeePerGas; } return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee); } } function pack( UserOperation calldata userOp ) internal pure returns (bytes memory ret) { address sender = getSender(userOp); uint256 nonce = userOp.nonce; bytes32 hashInitCode = calldataKeccak(userOp.initCode); bytes32 hashCallData = calldataKeccak(userOp.callData); uint256 callGasLimit = userOp.callGasLimit; uint256 verificationGasLimit = userOp.verificationGasLimit; uint256 preVerificationGas = userOp.preVerificationGas; uint256 maxFeePerGas = userOp.maxFeePerGas; uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData); return abi.encode( sender, nonce, hashInitCode, hashCallData, callGasLimit, verificationGasLimit, preVerificationGas, maxFeePerGas, maxPriorityFeePerGas, hashPaymasterAndData ); } function calldataKeccak( bytes calldata data ) internal pure returns (bytes32 ret) { assembly { let mem := mload(0x40) let len := data.length calldatacopy(mem, data.offset, len) ret := keccak256(mem, len) } } function hash( UserOperation calldata userOp ) internal pure returns (bytes32) { return keccak256(pack(userOp)); } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; import "../common/Enum.sol"; /// @title Executor - A contract that can execute transactions contract Executor { struct ExecuteParams { bool allowFailed; address to; uint256 value; bytes data; bytes nestedCalls; // ExecuteParams encoded as bytes } event HandleSuccessExternalCalls(); event HandleFailedExternalCalls(bytes revertReason); function execute( ExecuteParams memory params, Enum.Operation operation, uint256 txGas ) internal returns (bool success) { bytes memory result; if (operation == Enum.Operation.DelegateCall) { // solhint-disable-next-line no-inline-assembly (success, result) = params.to.delegatecall{gas: txGas}(params.data); } else { // solhint-disable-next-line no-inline-assembly (success, result) = payable(params.to).call{ gas: txGas, value: params.value }(params.data); } if (!success) { if (!params.allowFailed) { assembly { revert(add(result, 32), mload(result)) } } } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; import "../common/SelfAuthorized.sol"; /// @title Fallback Manager - A contract that manages fallback calls made to this contract contract FallbackManager is SelfAuthorized { event ChangedFallbackHandler(address handler); // keccak256("fallback_manager.handler.address") bytes32 internal constant FALLBACK_HANDLER_STORAGE_SLOT = 0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5; function getFallbackHandler() public view returns (address fallbackHandler) { bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT; // solhint-disable-next-line no-inline-assembly assembly { let encoded := sload(slot) fallbackHandler := shr(96, encoded) } } /// @dev Allows to add a contract to handle fallback calls. /// Only fallback calls without value and with data will be forwarded. /// This can only be done via a Safe transaction. /// @param handler contract to handle fallbacks calls. function setFallbackHandler(address handler) external authorized { setFallbackHandler(handler, false); emit ChangedFallbackHandler(handler); } function setFallbackHandler(address handler, bool delegate) internal { bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT; // solhint-disable-next-line no-inline-assembly assembly { let encoded := or(shl(96, handler), delegate) sstore(slot, encoded) } } function initializeFallbackHandler(address handler) internal { bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT; // solhint-disable-next-line no-inline-assembly assembly { let encoded := shl(96, handler) sstore(slot, encoded) } } // solhint-disable-next-line payable-fallback,no-complex-fallback fallback() external { assembly { // Load handler and delegate flag from storage let encoded := sload(FALLBACK_HANDLER_STORAGE_SLOT) let handler := shr(96, encoded) let delegate := and(encoded, 1) // Copy calldata to memory calldatacopy(0, 0, calldatasize()) // If delegate flag is set, delegate the call to the handler switch delegate case 0 { mstore(calldatasize(), shl(96, caller())) let success := call( gas(), handler, 0, 0, add(calldatasize(), 20), 0, 0 ) returndatacopy(0, 0, returndatasize()) if iszero(success) { revert(0, returndatasize()) } return(0, returndatasize()) } case 1 { let result := delegatecall( gas(), handler, 0, calldatasize(), 0, 0 ) returndatacopy(0, 0, returndatasize()) switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; import "../common/Enum.sol"; import "../common/SelfAuthorized.sol"; import "./Executor.sol"; interface Guard { function checkTransaction( address to, uint256 value, bytes memory data, Enum.Operation operation ) external; function checkAfterExecution(bool success) external; } /// @title Fallback Manager - A contract that manages fallback calls made to this contract contract GuardManager is SelfAuthorized, Executor { event ChangedGuard(address guard); // keccak256("guard_manager.guard.address") bytes32 internal constant GUARD_STORAGE_SLOT = 0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8; function getGuard() public view returns (address guard) { bytes32 slot = GUARD_STORAGE_SLOT; // solhint-disable-next-line no-inline-assembly assembly { guard := sload(slot) } } function setGuard(address guard) external authorized { bytes32 slot = GUARD_STORAGE_SLOT; // solhint-disable-next-line no-inline-assembly assembly { sstore(slot, guard) } emit ChangedGuard(guard); } // execute from this contract function execTransactionBatch( bytes memory executeParamBytes ) external authorized { executeWithGuardBatch(abi.decode(executeParamBytes, (ExecuteParams[]))); } function execTransactionRevertOnFail( bytes memory executeParamBytes ) external authorized { execTransactionBatchRevertOnFail( abi.decode(executeParamBytes, (ExecuteParams[])) ); } function executeWithGuard( address to, uint256 value, bytes calldata data ) internal { address guard = getGuard(); if (guard != address(0)) { Guard(guard).checkTransaction(to, value, data, Enum.Operation.Call); Guard(guard).checkAfterExecution( execute( ExecuteParams(false, to, value, data, ""), Enum.Operation.Call, gasleft() ) ); } else { execute( ExecuteParams(false, to, value, data, ""), Enum.Operation.Call, gasleft() ); } } function execTransactionBatchRevertOnFail( ExecuteParams[] memory _params ) internal { address guard = getGuard(); uint256 length = _params.length; if (guard == address(0)) { for (uint256 i = 0; i < length; ) { ExecuteParams memory param = _params[i]; execute(param, Enum.Operation.Call, gasleft()); if (param.nestedCalls.length > 0) { try this.execTransactionRevertOnFail(param.nestedCalls) {} catch (bytes memory returnData) { revert(string(returnData)); } } unchecked { ++i; } } } else { for (uint256 i = 0; i < length; ) { ExecuteParams memory param = _params[i]; Guard(guard).checkTransaction( param.to, param.value, param.data, Enum.Operation.Call ); Guard(guard).checkAfterExecution( execute(param, Enum.Operation.Call, gasleft()) ); if (param.nestedCalls.length > 0) { try this.execTransactionRevertOnFail(param.nestedCalls) {} catch (bytes memory returnData) { revert(string(returnData)); } } unchecked { ++i; } } } } function executeWithGuardBatch(ExecuteParams[] memory _params) internal { address guard = getGuard(); uint256 length = _params.length; if (guard == address(0)) { for (uint256 i = 0; i < length; ) { ExecuteParams memory param = _params[i]; bool success = execute(param, Enum.Operation.Call, gasleft()); if (success) { emit HandleSuccessExternalCalls(); } if (param.nestedCalls.length > 0) { try this.execTransactionBatch(param.nestedCalls) {} catch ( bytes memory returnData ) { emit HandleFailedExternalCalls(returnData); } } unchecked { ++i; } } } else { for (uint256 i = 0; i < length; ) { ExecuteParams memory param = _params[i]; Guard(guard).checkTransaction( param.to, param.value, param.data, Enum.Operation.Call ); bool success = execute(param, Enum.Operation.Call, gasleft()); if (success) { emit HandleSuccessExternalCalls(); } Guard(guard).checkAfterExecution(success); if (param.nestedCalls.length > 0) { try this.execTransactionBatch(param.nestedCalls) {} catch ( bytes memory returnData ) { emit HandleFailedExternalCalls(returnData); } } unchecked { ++i; } } } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; import "../common/Enum.sol"; import "../common/SelfAuthorized.sol"; import "./Executor.sol"; /// @title Module Manager - A contract that manages modules that can execute transactions via this contract contract ModuleManager is SelfAuthorized, Executor { event EnabledModule(address module); event DisabledModule(address module); event ExecutionFromModuleSuccess(address module); event ExecutionFromModuleFailure(address module); address internal constant SENTINEL_MODULES = address(0x1); mapping(address => address) internal modules; function initializeModules() internal { modules[SENTINEL_MODULES] = SENTINEL_MODULES; } function enableModule(address module) public authorized { // Module address cannot be null or sentinel. require(module != address(0) && module != SENTINEL_MODULES, "GS101"); // Module cannot be added twice. require(modules[module] == address(0), "GS102"); modules[module] = modules[SENTINEL_MODULES]; modules[SENTINEL_MODULES] = module; emit EnabledModule(module); } /// @dev Allows to remove a module from the whitelist. /// This can only be done via a Safe transaction. /// @notice Disables the module `module` for the Safe. /// @param prevModule Module that pointed to the module to be removed in the linked list /// @param module Module to be removed. function disableModule( address prevModule, address module ) public authorized { // Validate module address and check that it corresponds to module index. require(module != address(0) && module != SENTINEL_MODULES, "GS101"); require(modules[prevModule] == module, "GS103"); modules[prevModule] = modules[module]; modules[module] = address(0); emit DisabledModule(module); } /// @dev Returns if an module is enabled /// @return True if the module is enabled function isModuleEnabled(address module) public view returns (bool) { return SENTINEL_MODULES != module && modules[module] != address(0); } /// @dev Allows a Module to execute a Safe transaction without any further confirmations. /// @param to Destination address of module transaction. /// @param value Ether value of module transaction. /// @param data Data payload of module transaction. /// @param operation Operation type of module transaction. function execTransactionFromModule( address to, uint256 value, bytes calldata data, Enum.Operation operation ) public virtual { // Only whitelisted modules are allowed. require(modules[msg.sender] != address(0), "GS104"); // Execute transaction without further confirmations. if ( execute( ExecuteParams(false, to, value, data, ""), operation, gasleft() ) ) emit ExecutionFromModuleSuccess(msg.sender); else emit ExecutionFromModuleFailure(msg.sender); } /// @dev Allows a Module to execute a Safe transaction without any further confirmations and return data /// @param to Destination address of module transaction. /// @param value Ether value of module transaction. /// @param data Data payload of module transaction. /// @param operation Operation type of module transaction. function execTransactionFromModuleReturnData( address to, uint256 value, bytes calldata data, Enum.Operation operation ) public returns (bytes memory returnData) { execTransactionFromModule(to, value, data, operation); // solhint-disable-next-line no-inline-assembly assembly { // Load free memory location let ptr := mload(0x40) // We allocate memory for the return data by setting the free memory location to // current free memory location + data size + 32 bytes for data size value mstore(0x40, add(ptr, add(returndatasize(), 0x20))) // Store the size mstore(ptr, returndatasize()) // Store the data returndatacopy(add(ptr, 0x20), 0, returndatasize()) // Point the return data to the correct memory location returnData := ptr } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; contract OwnerManager { event AAOwnerSet(address owner); address internal owner; uint256 public nonce; modifier onlyOwner() { require(isOwner(msg.sender), "not call by owner"); _; } function initializeOwners(address _owner) internal { owner = _owner; emit AAOwnerSet(_owner); } function isOwner(address _owner) public view returns (bool) { return owner == _owner; } function getOwner() public view returns (address) { return owner; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../../interfaces/ISignatureValidator.sol"; import "../../interfaces/IAccount.sol"; import "../common/Enum.sol"; import "../common/SignatureDecoder.sol"; import "./OwnerManager.sol"; contract SignatureManager is IAccount, ISignatureValidatorConstants, Enum, OwnerManager, SignatureDecoder { using UserOperationLib for UserOperation; uint256 internal constant NONCE_VALIDATION_FAILED = 2; bytes32 internal immutable HASH_NAME; bytes32 internal immutable HASH_VERSION; bytes32 internal immutable TYPE_HASH; address internal immutable ADDRESS_THIS; bytes32 internal immutable EIP712_ORDER_STRUCT_SCHEMA_HASH; uint256 internal constant SIG_VALIDATION_FAILED = 1; struct SignMessage { address sender; uint256 nonce; bytes initCode; bytes callData; uint256 callGasLimit; uint256 verificationGasLimit; uint256 preVerificationGas; uint256 maxFeePerGas; uint256 maxPriorityFeePerGas; bytes paymasterAndData; address EntryPoint; uint256 sigTime; } /* solhint-enable var-name-mixedcase */ constructor(string memory name, string memory version) { HASH_NAME = keccak256(bytes(name)); HASH_VERSION = keccak256(bytes(version)); TYPE_HASH = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); ADDRESS_THIS = address(this); EIP712_ORDER_STRUCT_SCHEMA_HASH = keccak256( abi.encodePacked( "SignMessage(", "address sender,", "uint256 nonce,", "bytes initCode,", "bytes callData,", "uint256 callGasLimit,", "uint256 verificationGasLimit,", "uint256 preVerificationGas,", "uint256 maxFeePerGas,", "uint256 maxPriorityFeePerGas,", "bytes paymasterAndData,", "address EntryPoint,", "uint256 sigTime", ")" ) ); } function getUOPHash( SignatureType sigType, address EntryPoint, UserOperation calldata userOp ) public view returns (bytes32) { return keccak256( abi.encode( sigType == SignatureType.EIP712Type ? EIP712_ORDER_STRUCT_SCHEMA_HASH : bytes32(block.chainid), userOp.getSender(), userOp.nonce, keccak256(userOp.initCode), keccak256(userOp.callData), userOp.callGasLimit, userOp.verificationGasLimit, userOp.preVerificationGas, userOp.maxFeePerGas, userOp.maxPriorityFeePerGas, keccak256(userOp.paymasterAndData), EntryPoint, uint256(bytes32(userOp.signature[1:33])) ) ); } function getUOPSignedHash( SignatureType sigType, address EntryPoint, UserOperation calldata userOp ) public view returns (bytes32) { return sigType == SignatureType.EIP712Type ? ECDSA.toTypedDataHash( keccak256( abi.encode( TYPE_HASH, HASH_NAME, HASH_VERSION, block.chainid, ADDRESS_THIS ) ), keccak256( abi.encode( EIP712_ORDER_STRUCT_SCHEMA_HASH, userOp.getSender(), userOp.nonce, keccak256(userOp.initCode), keccak256(userOp.callData), userOp.callGasLimit, userOp.verificationGasLimit, userOp.preVerificationGas, userOp.maxFeePerGas, userOp.maxPriorityFeePerGas, keccak256(userOp.paymasterAndData), EntryPoint, uint256(bytes32(userOp.signature[1:33])) ) ) ) : ECDSA.toEthSignedMessageHash( keccak256( abi.encode( bytes32(block.chainid), userOp.getSender(), userOp.nonce, keccak256(userOp.initCode), keccak256(userOp.callData), userOp.callGasLimit, userOp.verificationGasLimit, userOp.preVerificationGas, userOp.maxFeePerGas, userOp.maxPriorityFeePerGas, keccak256(userOp.paymasterAndData), EntryPoint, uint256(bytes32(userOp.signature[1:33])) ) ) ); } function validateUserOp( UserOperation calldata userOp, bytes32, address, uint256 missingAccountFunds ) public virtual returns (uint256) { if (missingAccountFunds != 0) { payable(msg.sender).call{ value: missingAccountFunds, gas: type(uint256).max }(""); } unchecked { if (userOp.nonce != nonce++) { return NONCE_VALIDATION_FAILED; } } if ( ECDSA.recover( getUOPSignedHash( SignatureType(uint8(bytes1(userOp.signature[0:1]))), msg.sender, userOp ), userOp.signature[33:] ) != owner ) { return SIG_VALIDATION_FAILED; } else { return uint256(bytes32(userOp.signature[1:33])); } } function validateUserOpWithoutSig( UserOperation calldata userOp, bytes32, address, uint256 missingAccountFunds ) public virtual returns (uint256) { if (missingAccountFunds != 0) { payable(msg.sender).call{ value: missingAccountFunds, gas: type(uint256).max }(""); } unchecked { if (userOp.nonce != nonce++) { return NONCE_VALIDATION_FAILED; } } if ( ECDSA.recover( getUOPSignedHash( SignatureType(uint8(bytes1(userOp.signature[0:1]))), msg.sender, userOp ), userOp.signature[33:] ) != owner ) { return uint256(bytes32(userOp.signature[1:33])); } else { return uint256(bytes32(userOp.signature[1:33])); } } function isValidSignature( bytes32 _hash, bytes calldata _signature ) external view returns (bytes4) { if (isOwner(ECDSA.recover(_hash, _signature))) { return 0x1626ba7e; } else { return 0xffffffff; } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; /// @title Enum - Collection of enums contract Enum { enum Operation { Call, DelegateCall } enum SignatureType { EIP712Type, EIP191Type } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; /// @title EtherPaymentFallback - A contract that has a fallback to accept ether payments /// @author Richard Meissner - <[email protected]> contract EtherPaymentFallback { event SafeReceived(address indexed sender, uint256 value); /// @dev Fallback function accepts Ether transactions. receive() external payable { emit SafeReceived(msg.sender, msg.value); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; /// @title SecuredTokenTransfer - Secure token transfer /// @author Richard Meissner - <[email protected]> contract SecuredTokenTransfer { /// @dev Transfers a token and returns if it was a success /// @param token Token that should be transferred /// @param receiver Receiver to whom the token should be transferred /// @param amount The amount of tokens that should be transferred function transferToken( address token, address receiver, uint256 amount ) internal returns (bool transferred) { // 0xa9059cbb - keccack("transfer(address,uint256)") bytes memory data = abi.encodeWithSelector( 0xa9059cbb, receiver, amount ); // solhint-disable-next-line no-inline-assembly assembly { // We write the return value to scratch space. // See https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory let success := call( sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0x20 ) switch returndatasize() case 0 { transferred := success } case 0x20 { transferred := iszero(or(iszero(success), iszero(mload(0)))) } default { transferred := 0 } } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; import "../common/SelfAuthorized.sol"; /// @title SelfAuthorized - authorizes current contract to perform actions /// @author Richard Meissner - <[email protected]> contract SelfAuthorized { function requireSelfCall() private view { require(msg.sender == address(this), "GS031"); } modifier authorized() { // This is a function call as it minimized the bytecode size requireSelfCall(); _; } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; /// @title SignatureDecoder - Decodes signatures that a encoded as bytes /// @author Richard Meissner - <[email protected]> contract SignatureDecoder { /// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`. /// @notice Make sure to peform a bounds check for @param pos, to avoid out of bounds access on @param signatures /// @param pos which signature to read. A prior bounds check of this parameter should be performed, to avoid out of bounds access /// @param signatures concatenated rsv signatures function signatureSplit( bytes memory signatures, uint256 pos ) internal pure returns (uint8 v, bytes32 r, bytes32 s) { // The signature format is a compact form of: // {bytes32 r}{bytes32 s}{uint8 v} // Compact means, uint8 is not padded to 32 bytes. // solhint-disable-next-line no-inline-assembly assembly { let signaturePos := mul(0x41, pos) r := mload(add(signatures, add(signaturePos, 0x20))) s := mload(add(signatures, add(signaturePos, 0x40))) // Here we are loading the last 32 bytes, including 31 bytes // of 's'. There is no 'mload8' to do this. // // 'byte' is not working due to the Solidity parser, so lets // use the second best option, 'and' v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff) } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; import "./SelfAuthorized.sol"; /// @title Singleton - Base for singleton contracts (should always be first super contract) /// This contract is tightly coupled to our proxy contract contract Singleton is SelfAuthorized { event ImplementUpdated(address indexed implement); address internal singleton; function updateImplement(address implement) external authorized { singleton = implement; emit ImplementUpdated(implement); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; import "../interfaces/IStorage.sol"; import "./base/SignatureManager.sol"; import "./base/ModuleManager.sol"; import "./base/OwnerManager.sol"; import "./base/FallbackManager.sol"; import "./base/GuardManager.sol"; import "./common/EtherPaymentFallback.sol"; import "./common/Singleton.sol"; import "./common/SignatureDecoder.sol"; import "./common/SecuredTokenTransfer.sol"; contract SmartAccount is EtherPaymentFallback, Singleton, ModuleManager, OwnerManager, SignatureDecoder, SecuredTokenTransfer, FallbackManager, GuardManager, SignatureManager { address public immutable EntryPoint; address public immutable FallbackHandler; constructor( address _EntryPoint, address _FallbackHandler, string memory _name, string memory _version ) SignatureManager(_name, _version) { EntryPoint = _EntryPoint; FallbackHandler = _FallbackHandler; } modifier onlyEntryPoint() { require(msg.sender == EntryPoint, "Not from entrypoint"); _; } function Initialize(address _owner) external { require(getOwner() == address(0), "account: have set up"); initializeOwners(_owner); initializeFallbackHandler(FallbackHandler); initializeModules(); } function validateUserOp( UserOperation calldata userOp, bytes32 userOpHash, address aggregatorAddress, uint256 missingAccountFunds ) public override onlyEntryPoint returns (uint256 deadline) { deadline = super.validateUserOp( userOp, userOpHash, aggregatorAddress, missingAccountFunds ); } function validateUserOpWithoutSig( UserOperation calldata userOp, bytes32 userOpHash, address aggregatorAddress, uint256 missingAccountFunds ) public override onlyEntryPoint returns (uint256 deadline) { deadline = super.validateUserOpWithoutSig( userOp, userOpHash, aggregatorAddress, missingAccountFunds ); } function execTransactionFromEntrypoint( address to, uint256 value, bytes calldata data ) public onlyEntryPoint { executeWithGuard(to, value, data); } function execTransactionFromEntrypointBatch( ExecuteParams[] calldata _params ) external onlyEntryPoint { executeWithGuardBatch(_params); } function execTransactionFromEntrypointBatchRevertOnFail( ExecuteParams[] calldata _params ) external onlyEntryPoint { execTransactionBatchRevertOnFail(_params); } function execTransactionFromModule( address to, uint256 value, bytes calldata data, Enum.Operation operation ) public override { IStorage(EntryPoint).validateModuleWhitelist(msg.sender); if (operation == Enum.Operation.Call) { ModuleManager.execTransactionFromModule(to, value, data, operation); } else { address originalFallbackHandler = getFallbackHandler(); setFallbackHandler(msg.sender, true); ModuleManager.execTransactionFromModule(to, value, data, operation); setFallbackHandler(originalFallbackHandler, false); } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.12; import "../interfaces/ISmartAccountProxy.sol"; /// @title SmartAccountProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract. contract SmartAccountProxy is ISmartAccountProxy { // singleton always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated. // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt` address internal singleton; /// @dev Constructor function sets address of singleton contract. /// @param _singleton Singleton address. function initialize(address _singleton, bytes memory _initdata) external { require(singleton == address(0), "Initialized already"); require(_singleton != address(0), "Invalid singleton address provided"); singleton = _singleton; (bool success, ) = _singleton.delegatecall(_initdata); require(success, "init failed"); } function masterCopy() external view returns (address) { return singleton; } /// @dev Fallback function forwards all transactions and returns all received return data. fallback() external payable { // solhint-disable-next-line no-inline-assembly assembly { let _singleton := and( sload(0), 0xffffffffffffffffffffffffffffffffffffffff ) calldatacopy(0, 0, calldatasize()) let success := delegatecall( gas(), _singleton, 0, calldatasize(), 0, 0 ) returndatacopy(0, 0, returndatasize()) if eq(success, 0) { revert(0, returndatasize()) } return(0, returndatasize()) } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_safeSingleton","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract SmartAccountProxy","name":"proxy","type":"address"},{"indexed":false,"internalType":"address","name":"singleton","type":"address"}],"name":"ProxyCreation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"safeSingleton","type":"address"},{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"SafeSingletonSet","type":"event"},{"inputs":[{"internalType":"address","name":"_safeSingleton","type":"address"},{"internalType":"bytes","name":"initializer","type":"bytes"},{"internalType":"uint256","name":"salt","type":"uint256"}],"name":"createAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_safeSingleton","type":"address"},{"internalType":"bytes","name":"initializer","type":"bytes"},{"internalType":"uint256","name":"salt","type":"uint256"}],"name":"getAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxyCreationCode","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"proxyRuntimeCode","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"safeSingleton","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_safeSingleton","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"name":"setSafeSingleton","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"walletWhiteList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5060405161115238038061115283398101604081905261002f916100da565b6100383361006e565b6001600160a01b0382166000908152600160208190526040909120805460ff191690911790556100678161006e565b505061010d565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b03811681146100d557600080fd5b919050565b600080604083850312156100ed57600080fd5b6100f6836100be565b9150610104602084016100be565b90509250929050565b6110368061011c6000396000f3fe60806040523480156200001157600080fd5b5060043610620000ab5760003560e01c8063addacc0f116200006e578063addacc0f1462000152578063bf1652ae146200015c578063c8a7adf51462000182578063f2fde38b1462000199578063fb4424f414620001b057600080fd5b8063296601cd14620000b057806353e5d93514620000e45780635eb43cb514620000fd578063715018a614620001345780638da5cb5b1462000140575b600080fd5b620000c7620000c136600462000752565b620001c7565b6040516001600160a01b0390911681526020015b60405180910390f35b620000ee6200026e565b604051620000db91906200087d565b620001236200010e36600462000892565b60016020526000908152604090205460ff1681565b6040519015158152602001620000db565b6200013e6200029a565b005b6000546001600160a01b0316620000c7565b620000ee620002b2565b620001236200016d36600462000892565b60026020526000908152604090205460ff1681565b620000c76200019336600462000752565b620002c6565b6200013e620001aa36600462000892565b62000362565b6200013e620001c1366004620008b0565b620003e1565b6001600160a01b03831660009081526001602052604081205460ff16620002295760405162461bcd60e51b815260206004820152601160248201527024b73b30b634b21039b4b733b632ba37b760791b60448201526064015b60405180910390fd5b600062000238858585620002c6565b90506001600160a01b0381163b8015620002555750905062000267565b620002628686866200044e565b925050505b9392505050565b606060405180602001620002829062000703565b601f1982820381018352601f90910116604052919050565b620002a46200051f565b620002b060006200057b565b565b606060405180602001620002829062000711565b600080838051906020012083604051602001620002ed929190918252602082015260400190565b604051602081830303815290604052805190602001209050600060405180602001620003199062000703565b601f1982820381018352601f9091011660408190526200033d9190602001620008f0565b60405160208183030381529060405290506200026282828051906020012030620005cb565b6200036c6200051f565b6001600160a01b038116620003d35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000220565b620003de816200057b565b50565b620003eb6200051f565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527fe1185cd32427908d625dc06a30f72342f35f7f94bea383873794f7b140a36002910160405180910390a15050565b60006200045d848484620005f5565b835190915015620004d557600063d1f5789460e01b8585604051602401620004879291906200090e565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217825280519092506000918291829182875af103620004d357600080fd5b505b604080516001600160a01b038084168252861660208201527f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e235910160405180910390a19392505050565b6000546001600160a01b03163314620002b05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000220565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b6000808380519060200120836040516020016200061c929190918252602082015260400190565b604051602081830303815290604052805190602001209050600060405180602001620006489062000703565b601f1982820381018352601f9091011660408190526200066c9190602001620008f0565b6040516020818303038152906040529050818151826020016000f592506001600160a01b038316620006d75760405162461bcd60e51b815260206004820152601360248201527210dc99585d194c8818d85b1b0819985a5b1959606a1b604482015260640162000220565b50506001600160a01b0381166000908152600260205260409020805460ff191660011790559392505050565b610372806200093d83390190565b6103528062000caf83390190565b80356001600160a01b03811681146200073757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156200076857600080fd5b62000773846200071f565b9250602084013567ffffffffffffffff808211156200079157600080fd5b818601915086601f830112620007a657600080fd5b813581811115620007bb57620007bb6200073c565b604051601f8201601f19908116603f01168101908382118183101715620007e657620007e66200073c565b816040528281528960208487010111156200080057600080fd5b826020860160208301376000602084830101528096505050505050604084013590509250925092565b60005b83811015620008465781810151838201526020016200082c565b50506000910152565b600081518084526200086981602086016020860162000829565b601f01601f19169290920160200192915050565b6020815260006200026760208301846200084f565b600060208284031215620008a557600080fd5b62000267826200071f565b60008060408385031215620008c457600080fd5b620008cf836200071f565b915060208301358015158114620008e557600080fd5b809150509250929050565b600082516200090481846020870162000829565b9190910192915050565b6001600160a01b038316815260406020820181905260009062000934908301846200084f565b94935050505056fe608060405234801561001057600080fd5b50610352806100206000396000f3fe6080604052600436106100295760003560e01c8063a619486e14610055578063d1f5789414610081575b600080546001600160a01b03163682803781823684845af490503d82833e80610050573d82fd5b503d81f35b34801561006157600080fd5b50600054604080516001600160a01b039092168252519081900360200190f35b34801561008d57600080fd5b506100a161009c36600461021d565b6100a3565b005b6000546001600160a01b0316156100f75760405162461bcd60e51b8152602060048201526013602482015272496e697469616c697a656420616c726561647960681b60448201526064015b60405180910390fd5b6001600160a01b0382166101585760405162461bcd60e51b815260206004820152602260248201527f496e76616c69642073696e676c65746f6e20616464726573732070726f766964604482015261195960f21b60648201526084016100ee565b600080546001600160a01b0319166001600160a01b03841690811782556040516101839084906102ed565b600060405180830381855af49150503d80600081146101be576040519150601f19603f3d011682016040523d82523d6000602084013e6101c3565b606091505b50509050806102025760405162461bcd60e51b815260206004820152600b60248201526a1a5b9a5d0819985a5b195960aa1b60448201526064016100ee565b505050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561023057600080fd5b82356001600160a01b038116811461024757600080fd5b9150602083013567ffffffffffffffff8082111561026457600080fd5b818501915085601f83011261027857600080fd5b81358181111561028a5761028a610207565b604051601f8201601f19908116603f011681019083821181831017156102b2576102b2610207565b816040528281528860208487010111156102cb57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000825160005b8181101561030e57602081860181015185830152016102f4565b50600092019182525091905056fea26469706673582212204562a53397a5ec95ae3a45e3c739fc82314f87e701a71907f89ebfd3656322ef64736f6c634300081100336080604052600436106100295760003560e01c8063a619486e14610055578063d1f5789414610081575b600080546001600160a01b03163682803781823684845af490503d82833e80610050573d82fd5b503d81f35b34801561006157600080fd5b50600054604080516001600160a01b039092168252519081900360200190f35b34801561008d57600080fd5b506100a161009c36600461021d565b6100a3565b005b6000546001600160a01b0316156100f75760405162461bcd60e51b8152602060048201526013602482015272496e697469616c697a656420616c726561647960681b60448201526064015b60405180910390fd5b6001600160a01b0382166101585760405162461bcd60e51b815260206004820152602260248201527f496e76616c69642073696e676c65746f6e20616464726573732070726f766964604482015261195960f21b60648201526084016100ee565b600080546001600160a01b0319166001600160a01b03841690811782556040516101839084906102ed565b600060405180830381855af49150503d80600081146101be576040519150601f19603f3d011682016040523d82523d6000602084013e6101c3565b606091505b50509050806102025760405162461bcd60e51b815260206004820152600b60248201526a1a5b9a5d0819985a5b195960aa1b60448201526064016100ee565b505050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561023057600080fd5b82356001600160a01b038116811461024757600080fd5b9150602083013567ffffffffffffffff8082111561026457600080fd5b818501915085601f83011261027857600080fd5b81358181111561028a5761028a610207565b604051601f8201601f19908116603f011681019083821181831017156102b2576102b2610207565b816040528281528860208487010111156102cb57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000825160005b8181101561030e57602081860181015185830152016102f4565b50600092019182525091905056fea26469706673582212204562a53397a5ec95ae3a45e3c739fc82314f87e701a71907f89ebfd3656322ef64736f6c63430008110033a2646970667358221220c5c24787b256b81dd28db0cd575bf20219fb6866496bad6d02593de45af583fb64736f6c634300081100330000000000000000000000003dbeb76d9d9444d7db9dcf3799e17acd247f8fac000000000000000000000000794b93902449c524c3158f9e101204ecb2057f2e
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620000ab5760003560e01c8063addacc0f116200006e578063addacc0f1462000152578063bf1652ae146200015c578063c8a7adf51462000182578063f2fde38b1462000199578063fb4424f414620001b057600080fd5b8063296601cd14620000b057806353e5d93514620000e45780635eb43cb514620000fd578063715018a614620001345780638da5cb5b1462000140575b600080fd5b620000c7620000c136600462000752565b620001c7565b6040516001600160a01b0390911681526020015b60405180910390f35b620000ee6200026e565b604051620000db91906200087d565b620001236200010e36600462000892565b60016020526000908152604090205460ff1681565b6040519015158152602001620000db565b6200013e6200029a565b005b6000546001600160a01b0316620000c7565b620000ee620002b2565b620001236200016d36600462000892565b60026020526000908152604090205460ff1681565b620000c76200019336600462000752565b620002c6565b6200013e620001aa36600462000892565b62000362565b6200013e620001c1366004620008b0565b620003e1565b6001600160a01b03831660009081526001602052604081205460ff16620002295760405162461bcd60e51b815260206004820152601160248201527024b73b30b634b21039b4b733b632ba37b760791b60448201526064015b60405180910390fd5b600062000238858585620002c6565b90506001600160a01b0381163b8015620002555750905062000267565b620002628686866200044e565b925050505b9392505050565b606060405180602001620002829062000703565b601f1982820381018352601f90910116604052919050565b620002a46200051f565b620002b060006200057b565b565b606060405180602001620002829062000711565b600080838051906020012083604051602001620002ed929190918252602082015260400190565b604051602081830303815290604052805190602001209050600060405180602001620003199062000703565b601f1982820381018352601f9091011660408190526200033d9190602001620008f0565b60405160208183030381529060405290506200026282828051906020012030620005cb565b6200036c6200051f565b6001600160a01b038116620003d35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000220565b620003de816200057b565b50565b620003eb6200051f565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527fe1185cd32427908d625dc06a30f72342f35f7f94bea383873794f7b140a36002910160405180910390a15050565b60006200045d848484620005f5565b835190915015620004d557600063d1f5789460e01b8585604051602401620004879291906200090e565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217825280519092506000918291829182875af103620004d357600080fd5b505b604080516001600160a01b038084168252861660208201527f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e235910160405180910390a19392505050565b6000546001600160a01b03163314620002b05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000220565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b6000808380519060200120836040516020016200061c929190918252602082015260400190565b604051602081830303815290604052805190602001209050600060405180602001620006489062000703565b601f1982820381018352601f9091011660408190526200066c9190602001620008f0565b6040516020818303038152906040529050818151826020016000f592506001600160a01b038316620006d75760405162461bcd60e51b815260206004820152601360248201527210dc99585d194c8818d85b1b0819985a5b1959606a1b604482015260640162000220565b50506001600160a01b0381166000908152600260205260409020805460ff191660011790559392505050565b610372806200093d83390190565b6103528062000caf83390190565b80356001600160a01b03811681146200073757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156200076857600080fd5b62000773846200071f565b9250602084013567ffffffffffffffff808211156200079157600080fd5b818601915086601f830112620007a657600080fd5b813581811115620007bb57620007bb6200073c565b604051601f8201601f19908116603f01168101908382118183101715620007e657620007e66200073c565b816040528281528960208487010111156200080057600080fd5b826020860160208301376000602084830101528096505050505050604084013590509250925092565b60005b83811015620008465781810151838201526020016200082c565b50506000910152565b600081518084526200086981602086016020860162000829565b601f01601f19169290920160200192915050565b6020815260006200026760208301846200084f565b600060208284031215620008a557600080fd5b62000267826200071f565b60008060408385031215620008c457600080fd5b620008cf836200071f565b915060208301358015158114620008e557600080fd5b809150509250929050565b600082516200090481846020870162000829565b9190910192915050565b6001600160a01b038316815260406020820181905260009062000934908301846200084f565b94935050505056fe608060405234801561001057600080fd5b50610352806100206000396000f3fe6080604052600436106100295760003560e01c8063a619486e14610055578063d1f5789414610081575b600080546001600160a01b03163682803781823684845af490503d82833e80610050573d82fd5b503d81f35b34801561006157600080fd5b50600054604080516001600160a01b039092168252519081900360200190f35b34801561008d57600080fd5b506100a161009c36600461021d565b6100a3565b005b6000546001600160a01b0316156100f75760405162461bcd60e51b8152602060048201526013602482015272496e697469616c697a656420616c726561647960681b60448201526064015b60405180910390fd5b6001600160a01b0382166101585760405162461bcd60e51b815260206004820152602260248201527f496e76616c69642073696e676c65746f6e20616464726573732070726f766964604482015261195960f21b60648201526084016100ee565b600080546001600160a01b0319166001600160a01b03841690811782556040516101839084906102ed565b600060405180830381855af49150503d80600081146101be576040519150601f19603f3d011682016040523d82523d6000602084013e6101c3565b606091505b50509050806102025760405162461bcd60e51b815260206004820152600b60248201526a1a5b9a5d0819985a5b195960aa1b60448201526064016100ee565b505050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561023057600080fd5b82356001600160a01b038116811461024757600080fd5b9150602083013567ffffffffffffffff8082111561026457600080fd5b818501915085601f83011261027857600080fd5b81358181111561028a5761028a610207565b604051601f8201601f19908116603f011681019083821181831017156102b2576102b2610207565b816040528281528860208487010111156102cb57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000825160005b8181101561030e57602081860181015185830152016102f4565b50600092019182525091905056fea26469706673582212204562a53397a5ec95ae3a45e3c739fc82314f87e701a71907f89ebfd3656322ef64736f6c634300081100336080604052600436106100295760003560e01c8063a619486e14610055578063d1f5789414610081575b600080546001600160a01b03163682803781823684845af490503d82833e80610050573d82fd5b503d81f35b34801561006157600080fd5b50600054604080516001600160a01b039092168252519081900360200190f35b34801561008d57600080fd5b506100a161009c36600461021d565b6100a3565b005b6000546001600160a01b0316156100f75760405162461bcd60e51b8152602060048201526013602482015272496e697469616c697a656420616c726561647960681b60448201526064015b60405180910390fd5b6001600160a01b0382166101585760405162461bcd60e51b815260206004820152602260248201527f496e76616c69642073696e676c65746f6e20616464726573732070726f766964604482015261195960f21b60648201526084016100ee565b600080546001600160a01b0319166001600160a01b03841690811782556040516101839084906102ed565b600060405180830381855af49150503d80600081146101be576040519150601f19603f3d011682016040523d82523d6000602084013e6101c3565b606091505b50509050806102025760405162461bcd60e51b815260206004820152600b60248201526a1a5b9a5d0819985a5b195960aa1b60448201526064016100ee565b505050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561023057600080fd5b82356001600160a01b038116811461024757600080fd5b9150602083013567ffffffffffffffff8082111561026457600080fd5b818501915085601f83011261027857600080fd5b81358181111561028a5761028a610207565b604051601f8201601f19908116603f011681019083821181831017156102b2576102b2610207565b816040528281528860208487010111156102cb57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000825160005b8181101561030e57602081860181015185830152016102f4565b50600092019182525091905056fea26469706673582212204562a53397a5ec95ae3a45e3c739fc82314f87e701a71907f89ebfd3656322ef64736f6c63430008110033a2646970667358221220c5c24787b256b81dd28db0cd575bf20219fb6866496bad6d02593de45af583fb64736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003dbeb76d9d9444d7db9dcf3799e17acd247f8fac000000000000000000000000794b93902449c524c3158f9e101204ecb2057f2e
-----Decoded View---------------
Arg [0] : _safeSingleton (address): 0x3DbeB76d9d9444D7Db9DcF3799e17ACd247f8fac
Arg [1] : _owner (address): 0x794b93902449C524c3158f9e101204ECb2057f2e
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000003dbeb76d9d9444d7db9dcf3799e17acd247f8fac
Arg [1] : 000000000000000000000000794b93902449c524c3158f9e101204ecb2057f2e
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.