Polygon Sponsored slots available. Book your slot here!
Contract Overview
Balance:
0 MATIC
MATIC Value:
$0.00
My Name Tag:
Not Available, login to update
Txn Hash |
Method
|
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0x7f1006a1b483b76e7cfff5c35ba58dde30394961329ed4db7f3fcb90af4ed56f | FACTORY | 34010756 | 173 days 14 hrs ago | 0xb70d2e30b2d2f8af8b657f5da5b305ec533f6dc2 | IN | 0xd01f11855bccb95f88d7a48492f66410d4637313 | 0 MATIC | 0.000753379445 | |
0xe245ffee60f786c34d0aa28a0261642405e5b67562257001b0fd1aa541e9b898 | Execute | 28102227 | 324 days 14 mins ago | 0x0474e22fa791c86c91ca66bcafda7dd519b407e1 | IN | 0xd01f11855bccb95f88d7a48492f66410d4637313 | 0 MATIC | 0.003533705 | |
0xa82890bd68b5b60ebaa66592d36fd0bbb423b4510a7d26cf2702d3e5c58f843e | Execute | 27521611 | 338 days 16 hrs ago | 0x6c9244d2f9febf230f7be9de2d185b330e431261 | IN | 0xd01f11855bccb95f88d7a48492f66410d4637313 | 0 MATIC | 0.0014001615 |
[ Download CSV Export ]
Latest 1 internal transaction
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0xfeb7212605a592ba5e22065be53a7c2628383c5a33ba7aede51928972e6b275e | 12171826 | 740 days 14 hrs ago | 0x8a5bc19e22d6ad55a2c763b93a75d09f321fe764 | Contract Creation | 0 MATIC |
[ Download CSV Export ]
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:
MainModule
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 999999 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; pragma experimental ABIEncoderV2; import "../utils/SignatureValidator.sol"; import "./commons/Implementation.sol"; import "./commons/ModuleAuthFixed.sol"; import "./commons/ModuleHooks.sol"; import "./commons/ModuleCalls.sol"; import "./commons/ModuleUpdate.sol"; import "./commons/ModuleCreator.sol"; import "../interfaces/receivers/IERC1155Receiver.sol"; import "../interfaces/receivers/IERC721Receiver.sol"; import "../interfaces/IERC1271Wallet.sol"; /** * @notice Contains the core functionality arcadeum wallets will inherit. * @dev If using a new main module, developpers must ensure that all inherited * contracts by the mainmodule don't conflict and are accounted for to be * supported by the supportsInterface method. */ contract MainModule is ModuleAuthFixed, ModuleCalls, ModuleUpdate, ModuleHooks, ModuleCreator { constructor( address _factory ) public ModuleAuthFixed( _factory ) { } /** * @notice Query if a contract implements an interface * @param _interfaceID The interface identifier, as specified in ERC-165 * @return `true` if the contract implements `_interfaceID` */ function supportsInterface( bytes4 _interfaceID ) public override( ModuleAuth, ModuleCalls, ModuleUpdate, ModuleHooks, ModuleCreator ) pure returns (bool) { return super.supportsInterface(_interfaceID); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; import "../interfaces/IERC1271Wallet.sol"; import "./LibBytes.sol"; /** * @dev Contains logic for signature validation. * Signatures from wallet contracts assume ERC-1271 support (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1271.md) * Notes: Methods are strongly inspired by contracts in https://github.com/0xProject/0x-monorepo/blob/development/ */ contract SignatureValidator { using LibBytes for bytes; /***********************************| | Variables | |__________________________________*/ // bytes4(keccak256("isValidSignature(bytes,bytes)")) bytes4 constant internal ERC1271_MAGICVALUE = 0x20c13b0b; // bytes4(keccak256("isValidSignature(bytes32,bytes)")) bytes4 constant internal ERC1271_MAGICVALUE_BYTES32 = 0x1626ba7e; // Allowed signature types. uint256 private constant SIG_TYPE_EIP712 = 1; uint256 private constant SIG_TYPE_ETH_SIGN = 2; uint256 private constant SIG_TYPE_WALLET_BYTES32 = 3; /***********************************| | Signature Functions | |__________________________________*/ /** * @notice Recover the signer of hash, assuming it's an EOA account * @dev Only for SignatureType.EIP712 and SignatureType.EthSign signatures * @param _hash Hash that was signed * encoded as (bytes32 r, bytes32 s, uint8 v, ... , SignatureType sigType) */ function recoverSigner( bytes32 _hash, bytes memory _signature ) internal pure returns (address signer) { require(_signature.length == 66, "SignatureValidator#recoverSigner: invalid signature length"); uint256 signatureType = uint8(_signature[_signature.length - 1]); // Variables are not scoped in Solidity. uint8 v = uint8(_signature[64]); bytes32 r = _signature.readBytes32(0); bytes32 s = _signature.readBytes32(32); // 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 (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): 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. // // Source OpenZeppelin // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { revert("SignatureValidator#recoverSigner: invalid signature 's' value"); } if (v != 27 && v != 28) { revert("SignatureValidator#recoverSigner: invalid signature 'v' value"); } // Signature using EIP712 if (signatureType == SIG_TYPE_EIP712) { signer = ecrecover(_hash, v, r, s); // Signed using web3.eth_sign() or Ethers wallet.signMessage() } else if (signatureType == SIG_TYPE_ETH_SIGN) { signer = ecrecover( keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)), v, r, s ); } else { // Anything other signature types are illegal (We do not return false because // the signature may actually be valid, just not in a format // that we currently support. In this case returning false // may lead the caller to incorrectly believe that the // signature was invalid.) revert("SignatureValidator#recoverSigner: UNSUPPORTED_SIGNATURE_TYPE"); } // Prevent signer from being 0x0 require( signer != address(0x0), "SignatureValidator#recoverSigner: INVALID_SIGNER" ); return signer; } /** * @notice Returns true if the provided signature is valid for the given signer. * @dev Supports SignatureType.EIP712, SignatureType.EthSign, and ERC1271 signatures * @param _hash Hash that was signed * @param _signer Address of the signer candidate * @param _signature Signature byte array */ function isValidSignature( bytes32 _hash, address _signer, bytes memory _signature ) internal view returns (bool valid) { uint256 signatureType = uint8(_signature[_signature.length - 1]); if (signatureType == SIG_TYPE_EIP712 || signatureType == SIG_TYPE_ETH_SIGN) { // Recover signer and compare with provided valid = recoverSigner(_hash, _signature) == _signer; } else if (signatureType == SIG_TYPE_WALLET_BYTES32) { // Remove signature type before calling ERC1271, restore after call uint256 prevSize; assembly { prevSize := mload(_signature) mstore(_signature, sub(prevSize, 1)) } valid = ERC1271_MAGICVALUE_BYTES32 == IERC1271Wallet(_signer).isValidSignature(_hash, _signature); assembly { mstore(_signature, prevSize) } } else { // Anything other signature types are illegal (We do not return false because // the signature may actually be valid, just not in a format // that we currently support. In this case returning false // may lead the caller to incorrectly believe that the // signature was invalid.) revert("SignatureValidator#isValidSignature: UNSUPPORTED_SIGNATURE_TYPE"); } } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; /** * @dev Allows modules to access the implementation slot */ contract Implementation { /** * @notice Updates the Wallet implementation * @param _imp New implementation address * @dev The wallet implementation is stored on the storage slot * defined by the address of the wallet itself * WARNING updating this value may break the wallet and users * must be confident that the new implementation is safe. */ function _setImplementation(address _imp) internal { assembly { sstore(address(), _imp) } } /** * @notice Returns the Wallet implementation * @return _imp The address of the current Wallet implementation */ function _getImplementation() internal view returns (address _imp) { assembly { _imp := sload(address()) } } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; import "./ModuleAuth.sol"; import "../../Wallet.sol"; /** * Implements ModuleAuth by validating the signature image against * the salt used to deploy the contract * * This module allows wallets to be deployed with a default configuration * without using any aditional contract storage */ abstract contract ModuleAuthFixed is ModuleAuth { bytes32 public immutable INIT_CODE_HASH; address public immutable FACTORY; constructor(address _factory) { // Build init code hash of the deployed wallets using that module bytes32 initCodeHash = keccak256(abi.encodePacked(Wallet.creationCode, uint256(address(this)))); INIT_CODE_HASH = initCodeHash; FACTORY = _factory; } /** * @notice Validates the signature image with the salt used to deploy the contract * @param _imageHash Hash image of signature * @return true if the signature image is valid */ function _isValidImage(bytes32 _imageHash) internal override view returns (bool) { return address( uint256( keccak256( abi.encodePacked( byte(0xff), FACTORY, _imageHash, INIT_CODE_HASH ) ) ) ) == address(this); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; import "./interfaces/IModuleHooks.sol"; import "./ModuleSelfAuth.sol"; import "./ModuleStorage.sol"; import "./ModuleERC165.sol"; import "../../interfaces/receivers/IERC1155Receiver.sol"; import "../../interfaces/receivers/IERC721Receiver.sol"; import "../../interfaces/receivers/IERC223Receiver.sol"; contract ModuleHooks is IERC1155Receiver, IERC721Receiver, IModuleHooks, ModuleERC165, ModuleSelfAuth { // HOOKS_KEY = keccak256("org.arcadeum.module.hooks.hooks"); bytes32 private constant HOOKS_KEY = bytes32(0xbe27a319efc8734e89e26ba4bc95f5c788584163b959f03fa04e2d7ab4b9a120); /** * @notice Reads the implementation hook of a signature * @param _signature Signature function * @return The address of the implementation hook, address(0) if none */ function readHook(bytes4 _signature) external override view returns (address) { return _readHook(_signature); } /** * @notice Adds a new hook to handle a given function selector * @param _signature Signature function linked to the hook * @param _implementation Hook implementation contract * @dev Can't overwrite hooks that are part of the mainmodule (those defined below) */ function addHook(bytes4 _signature, address _implementation) external override onlySelf { require(_readHook(_signature) == address(0), "ModuleHooks#addHook: HOOK_ALREADY_REGISTERED"); _writeHook(_signature, _implementation); } /** * @notice Removes a registered hook * @param _signature Signature function linked to the hook * @dev Can't remove hooks that are part of the mainmodule (those defined below) * without upgrading the wallet */ function removeHook(bytes4 _signature) external override onlySelf { require(_readHook(_signature) != address(0), "ModuleHooks#removeHook: HOOK_NOT_REGISTERED"); _writeHook(_signature, address(0)); } /** * @notice Reads the implementation hook of a signature * @param _signature Signature function * @return The address of the implementation hook, address(0) if none */ function _readHook(bytes4 _signature) private view returns (address) { return address(uint256(ModuleStorage.readBytes32Map(HOOKS_KEY, _signature))); } /** * @notice Writes the implementation hook of a signature * @param _signature Signature function * @param _implementation Hook implementation contract */ function _writeHook(bytes4 _signature, address _implementation) private { ModuleStorage.writeBytes32Map(HOOKS_KEY, _signature, bytes32(uint256(_implementation))); } /** * @notice Handle the receipt of a single ERC1155 token type. * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` */ function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external override returns (bytes4) { return ModuleHooks.onERC1155Received.selector; } /** * @notice Handle the receipt of multiple ERC1155 token types. * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` */ function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external override returns (bytes4) { return ModuleHooks.onERC1155BatchReceived.selector; } /** * @notice Handle the receipt of a single ERC721 token. * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` */ function onERC721Received(address, address, uint256, bytes calldata) external override returns (bytes4) { return ModuleHooks.onERC721Received.selector; } /** * @notice Routes fallback calls through hooks */ fallback() external payable { address target = _readHook(msg.sig); if (target != address(0)) { (bool success, bytes memory result) = target.delegatecall(msg.data); assembly { if iszero(success) { revert(add(result, 0x20), mload(result)) } return(add(result, 0x20), mload(result)) } } } /** * @notice Allows the wallet to receive ETH */ receive() external payable { } /** * @notice Query if a contract implements an interface * @param _interfaceID The interface identifier, as specified in ERC-165 * @return `true` if the contract implements `_interfaceID` */ function supportsInterface(bytes4 _interfaceID) public override virtual pure returns (bool) { if ( _interfaceID == type(IModuleHooks).interfaceId || _interfaceID == type(IERC1155Receiver).interfaceId || _interfaceID == type(IERC721Receiver).interfaceId || _interfaceID == type(IERC223Receiver).interfaceId ) { return true; } return super.supportsInterface(_interfaceID); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; pragma experimental ABIEncoderV2; import "./ModuleSelfAuth.sol"; import "./ModuleStorage.sol"; import "./ModuleERC165.sol"; import "./interfaces/IModuleCalls.sol"; import "./interfaces/IModuleAuth.sol"; abstract contract ModuleCalls is IModuleCalls, IModuleAuth, ModuleERC165, ModuleSelfAuth { // NONCE_KEY = keccak256("org.arcadeum.module.calls.nonce"); bytes32 private constant NONCE_KEY = bytes32(0x8d0bf1fd623d628c741362c1289948e57b3e2905218c676d3e69abee36d6ae2e); uint256 private constant NONCE_BITS = 96; bytes32 private constant NONCE_MASK = bytes32((1 << NONCE_BITS) - 1); /** * @notice Returns the next nonce of the default nonce space * @dev The default nonce space is 0x00 * @return The next nonce */ function nonce() external override virtual view returns (uint256) { return readNonce(0); } /** * @notice Returns the next nonce of the given nonce space * @param _space Nonce space, each space keeps an independent nonce count * @return The next nonce */ function readNonce(uint256 _space) public override virtual view returns (uint256) { return uint256(ModuleStorage.readBytes32Map(NONCE_KEY, bytes32(_space))); } /** * @notice Changes the next nonce of the given nonce space * @param _space Nonce space, each space keeps an independent nonce count * @param _nonce Nonce to write on the space */ function _writeNonce(uint256 _space, uint256 _nonce) private { ModuleStorage.writeBytes32Map(NONCE_KEY, bytes32(_space), bytes32(_nonce)); } /** * @notice Allow wallet owner to execute an action * @dev Relayers must ensure that the gasLimit specified for each transaction * is acceptable to them. A user could specify large enough that it could * consume all the gas available. * @param _txs Transactions to process * @param _nonce Signature nonce (may contain an encoded space) * @param _signature Encoded signature */ function execute( Transaction[] memory _txs, uint256 _nonce, bytes memory _signature ) public override virtual { // Validate and update nonce _validateNonce(_nonce); // Hash transaction bundle bytes32 txHash = _subDigest(keccak256(abi.encode(_nonce, _txs))); // Verify that signatures are valid require( _signatureValidation(txHash, _signature), "ModuleCalls#execute: INVALID_SIGNATURE" ); // Execute the transactions _execute(txHash, _txs); } /** * @notice Allow wallet to execute an action * without signing the message * @param _txs Transactions to execute */ function selfExecute( Transaction[] memory _txs ) public override virtual onlySelf { // Hash transaction bundle bytes32 txHash = _subDigest(keccak256(abi.encode('self:', _txs))); // Execute the transactions _execute(txHash, _txs); } /** * @notice Executes a list of transactions * @param _txHash Hash of the batch of transactions * @param _txs Transactions to execute */ function _execute( bytes32 _txHash, Transaction[] memory _txs ) private { // Execute transaction for (uint256 i = 0; i < _txs.length; i++) { Transaction memory transaction = _txs[i]; bool success; bytes memory result; require(gasleft() >= transaction.gasLimit, "ModuleCalls#_execute: NOT_ENOUGH_GAS"); if (transaction.delegateCall) { (success, result) = transaction.target.delegatecall{ gas: transaction.gasLimit == 0 ? gasleft() : transaction.gasLimit }(transaction.data); } else { (success, result) = transaction.target.call{ value: transaction.value, gas: transaction.gasLimit == 0 ? gasleft() : transaction.gasLimit }(transaction.data); } if (success) { emit TxExecuted(_txHash); } else { _revertBytes(transaction, _txHash, result); } } } /** * @notice Verify if a nonce is valid * @param _rawNonce Nonce to validate (may contain an encoded space) * @dev A valid nonce must be above the last one used * with a maximum delta of 100 */ function _validateNonce(uint256 _rawNonce) private { // Retrieve current nonce for this wallet (uint256 space, uint256 providedNonce) = _decodeNonce(_rawNonce); uint256 currentNonce = readNonce(space); // Verify if nonce is valid require( providedNonce == currentNonce, "MainModule#_auth: INVALID_NONCE" ); // Update signature nonce uint256 newNonce = providedNonce + 1; _writeNonce(space, newNonce); emit NonceChange(space, newNonce); } /** * @notice Logs a failed transaction, reverts if the transaction is not optional * @param _tx Transaction that is reverting * @param _txHash Hash of the transaction * @param _reason Encoded revert message */ function _revertBytes( Transaction memory _tx, bytes32 _txHash, bytes memory _reason ) internal { if (_tx.revertOnError) { assembly { revert(add(_reason, 0x20), mload(_reason)) } } else { emit TxFailed(_txHash, _reason); } } /** * @notice Decodes a raw nonce * @dev A raw nonce is encoded using the first 160 bits for the space * and the last 96 bits for the nonce * @param _rawNonce Nonce to be decoded * @return _space The nonce space of the raw nonce * @return _nonce The nonce of the raw nonce */ function _decodeNonce(uint256 _rawNonce) private pure returns (uint256 _space, uint256 _nonce) { _nonce = uint256(bytes32(_rawNonce) & NONCE_MASK); _space = _rawNonce >> NONCE_BITS; } /** * @notice Query if a contract implements an interface * @param _interfaceID The interface identifier, as specified in ERC-165 * @return `true` if the contract implements `_interfaceID` */ function supportsInterface(bytes4 _interfaceID) public override virtual pure returns (bool) { if (_interfaceID == type(IModuleCalls).interfaceId) { return true; } return super.supportsInterface(_interfaceID); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; import "./interfaces/IModuleUpdate.sol"; import "./Implementation.sol"; import "./ModuleSelfAuth.sol"; import "./ModuleERC165.sol"; import "../../utils/LibAddress.sol"; contract ModuleUpdate is IModuleUpdate, ModuleERC165, ModuleSelfAuth, Implementation { using LibAddress for address; event ImplementationUpdated(address newImplementation); /** * @notice Updates the implementation of the base wallet * @param _implementation New main module implementation * @dev WARNING Updating the implementation can brick the wallet */ function updateImplementation(address _implementation) external override onlySelf { require(_implementation.isContract(), "ModuleUpdate#updateImplementation: INVALID_IMPLEMENTATION"); _setImplementation(_implementation); emit ImplementationUpdated(_implementation); } /** * @notice Query if a contract implements an interface * @param _interfaceID The interface identifier, as specified in ERC-165 * @return `true` if the contract implements `_interfaceID` */ function supportsInterface(bytes4 _interfaceID) public override virtual pure returns (bool) { if (_interfaceID == type(IModuleUpdate).interfaceId) { return true; } return super.supportsInterface(_interfaceID); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; import "./interfaces/IModuleCreator.sol"; import "./ModuleSelfAuth.sol"; import "./ModuleERC165.sol"; contract ModuleCreator is IModuleCreator, ModuleERC165, ModuleSelfAuth { event CreatedContract(address _contract); /** * @notice Creates a contract forwarding eth value * @param _code Creation code of the contract * @return addr The address of the created contract */ function createContract(bytes memory _code) public override payable onlySelf returns (address addr) { assembly { addr := create(callvalue(), add(_code, 32), mload(_code)) } emit CreatedContract(addr); } /** * @notice Query if a contract implements an interface * @param _interfaceID The interface identifier, as specified in ERC-165 * @return `true` if the contract implements `_interfaceID` */ function supportsInterface(bytes4 _interfaceID) public override virtual pure returns (bool) { if (_interfaceID == type(IModuleCreator).interfaceId) { return true; } return super.supportsInterface(_interfaceID); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; interface IERC1155Receiver { function onERC1155Received(address, address, uint256, uint256, bytes calldata) external returns (bytes4); function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) external returns (bytes4); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; interface IERC721Receiver { function onERC721Received(address, address, uint256, bytes calldata) external returns (bytes4); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; interface IERC1271Wallet { /** * @notice Verifies whether the provided signature is valid with respect to the provided data * @dev MUST return the correct magic value if the signature provided is valid for the provided data * > The bytes4 magic value to return when signature is valid is 0x20c13b0b : bytes4(keccak256("isValidSignature(bytes,bytes)") * > This function MAY modify Ethereum's state * @param _data Arbitrary length data signed on the behalf of address(this) * @param _signature Signature byte array associated with _data * @return magicValue Magic value 0x20c13b0b if the signature is valid and 0x0 otherwise */ function isValidSignature( bytes calldata _data, bytes calldata _signature) external view returns (bytes4 magicValue); /** * @notice Verifies whether the provided signature is valid with respect to the provided hash * @dev MUST return the correct magic value if the signature provided is valid for the provided hash * > The bytes4 magic value to return when signature is valid is 0x20c13b0b : bytes4(keccak256("isValidSignature(bytes,bytes)") * > This function MAY modify Ethereum's state * @param _hash keccak256 hash that was signed * @param _signature Signature byte array associated with _data * @return magicValue Magic value 0x20c13b0b if the signature is valid and 0x0 otherwise */ function isValidSignature( bytes32 _hash, bytes calldata _signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; library LibBytes { using LibBytes for bytes; /***********************************| | Read Bytes Functions | |__________________________________*/ /** * @dev Read firsts uint16 value. * @param data Byte array to be read. * @return a uint16 value of data at index zero. * @return newIndex Updated index after reading the values. */ function readFirstUint16( bytes memory data ) internal pure returns ( uint16 a, uint256 newIndex ) { assembly { let word := mload(add(32, data)) a := shr(240, word) newIndex := 2 } require(2 <= data.length, "LibBytes#readFirstUint16: OUT_OF_BOUNDS"); } /** * @dev Reads consecutive bool (8 bits) and uint8 values. * @param data Byte array to be read. * @param index Index in byte array of uint8 and uint8 values. * @return a uint8 value of data at given index. * @return b uint8 value of data at given index + 8. * @return newIndex Updated index after reading the values. */ function readUint8Uint8( bytes memory data, uint256 index ) internal pure returns ( uint8 a, uint8 b, uint256 newIndex ) { assembly { let word := mload(add(index, add(32, data))) a := shr(248, word) b := and(shr(240, word), 0xff) newIndex := add(index, 2) } assert(newIndex > index); require(newIndex <= data.length, "LibBytes#readUint8Uint8: OUT_OF_BOUNDS"); } /** * @dev Reads an address value from a position in a byte array. * @param data Byte array to be read. * @param index Index in byte array of address value. * @return a address value of data at given index. * @return newIndex Updated index after reading the value. */ function readAddress( bytes memory data, uint256 index ) internal pure returns ( address a, uint256 newIndex ) { assembly { let word := mload(add(index, add(32, data))) a := and(shr(96, word), 0xffffffffffffffffffffffffffffffffffffffff) newIndex := add(index, 20) } assert(newIndex > index); require(newIndex <= data.length, "LibBytes#readAddress: OUT_OF_BOUNDS"); } /** * @dev Reads 66 bytes from a position in a byte array. * @param data Byte array to be read. * @param index Index in byte array of 66 bytes value. * @return a 66 bytes bytes array value of data at given index. * @return newIndex Updated index after reading the value. */ function readBytes66( bytes memory data, uint256 index ) internal pure returns ( bytes memory a, uint256 newIndex ) { a = new bytes(66); assembly { let offset := add(32, add(data, index)) mstore(add(a, 32), mload(offset)) mstore(add(a, 64), mload(add(offset, 32))) mstore(add(a, 66), mload(add(offset, 34))) newIndex := add(index, 66) } assert(newIndex > index); require(newIndex <= data.length, "LibBytes#readBytes66: OUT_OF_BOUNDS"); } /** * @dev Reads a bytes32 value from a position in a byte array. * @param b Byte array containing a bytes32 value. * @param index Index in byte array of bytes32 value. * @return result bytes32 value from byte array. */ function readBytes32( bytes memory b, uint256 index ) internal pure returns (bytes32 result) { require( b.length >= index + 32, "LibBytes#readBytes32: GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED" ); // Arrays are prefixed by a 256 bit length parameter uint256 pos = index + 32; // Read the bytes32 from array memory assembly { result := mload(add(b, pos)) } return result; } /** * @dev Reads an uint16 value from a position in a byte array. * @param data Byte array to be read. * @param index Index in byte array of uint16 value. * @return a uint16 value of data at given index. * @return newIndex Updated index after reading the value. */ function readUint16( bytes memory data, uint256 index ) internal pure returns (uint16 a, uint256 newIndex) { assembly { let word := mload(add(index, add(32, data))) a := and(shr(240, word), 0xffff) newIndex := add(index, 2) } assert(newIndex > index); require(newIndex <= data.length, "LibBytes#readUint16: OUT_OF_BOUNDS"); } /** * @dev Reads bytes from a position in a byte array. * @param data Byte array to be read. * @param index Index in byte array of bytes value. * @param size Number of bytes to read. * @return a bytes bytes array value of data at given index. * @return newIndex Updated index after reading the value. */ function readBytes( bytes memory data, uint256 index, uint256 size ) internal pure returns (bytes memory a, uint256 newIndex) { a = new bytes(size); assembly { let offset := add(32, add(data, index)) let i := 0 let n := 32 // Copy each word, except last one for { } lt(n, size) { i := n n := add(n, 32) } { mstore(add(a, n), mload(add(offset, i))) } // Load word after new array let suffix := add(a, add(32, size)) let suffixWord := mload(suffix) // Copy last word, overwrites after array mstore(add(a, n), mload(add(offset, i))) // Restore after array mstore(suffix, suffixWord) newIndex := add(index, size) } assert(newIndex >= index); require(newIndex <= data.length, "LibBytes#readBytes: OUT_OF_BOUNDS"); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; import "../../utils/LibBytes.sol"; import "../../utils/SignatureValidator.sol"; import "../../interfaces/IERC1271Wallet.sol"; import "./interfaces/IModuleAuth.sol"; import "./ModuleERC165.sol"; abstract contract ModuleAuth is IModuleAuth, ModuleERC165, SignatureValidator, IERC1271Wallet { using LibBytes for bytes; uint256 private constant FLAG_SIGNATURE = 0; uint256 private constant FLAG_ADDRESS = 1; uint256 private constant FLAG_DYNAMIC_SIGNATURE = 2; bytes4 private constant SELECTOR_ERC1271_BYTES_BYTES = 0x20c13b0b; bytes4 private constant SELECTOR_ERC1271_BYTES32_BYTES = 0x1626ba7e; /** * @notice Verify if signer is default wallet owner * @param _hash Hashed signed message * @param _signature Array of signatures with signers ordered * like the the keys in the multisig configs * * @dev The signature must be solidity packed and contain the total number of owners, * the threshold, the weight and either the address or a signature for each owner. * * Each weight & (address or signature) pair is prefixed by a flag that signals if such pair * contains an address or a signature. The aggregated weight of the signatures must surpass the threshold. * * Flag types: * 0x00 - Signature * 0x01 - Address * * E.g: * abi.encodePacked( * uint16 threshold, * uint8 01, uint8 weight_1, address signer_1, * uint8 00, uint8 weight_2, bytes signature_2, * ... * uint8 01, uint8 weight_5, address signer_5 * ) */ function _signatureValidation( bytes32 _hash, bytes memory _signature ) internal override view returns (bool) { ( uint16 threshold, // required threshold signature uint256 rindex // read index ) = _signature.readFirstUint16(); // Start image hash generation bytes32 imageHash = bytes32(uint256(threshold)); // Acumulated weight of signatures uint256 totalWeight; // Iterate until the image is completed while (rindex < _signature.length) { // Read next item type and addrWeight uint256 flag; uint256 addrWeight; address addr; (flag, addrWeight, rindex) = _signature.readUint8Uint8(rindex); if (flag == FLAG_ADDRESS) { // Read plain address (addr, rindex) = _signature.readAddress(rindex); } else if (flag == FLAG_SIGNATURE) { // Read single signature and recover signer bytes memory signature; (signature, rindex) = _signature.readBytes66(rindex); addr = recoverSigner(_hash, signature); // Acumulate total weight of the signature totalWeight += addrWeight; } else if (flag == FLAG_DYNAMIC_SIGNATURE) { // Read signer (addr, rindex) = _signature.readAddress(rindex); // Read signature size uint256 size; (size, rindex) = _signature.readUint16(rindex); // Read dynamic size signature bytes memory signature; (signature, rindex) = _signature.readBytes(rindex, size); require(isValidSignature(_hash, addr, signature), "ModuleAuth#_signatureValidation: INVALID_SIGNATURE"); // Acumulate total weight of the signature totalWeight += addrWeight; } else { revert("ModuleAuth#_signatureValidation INVALID_FLAG"); } // Write weight and address to image imageHash = keccak256(abi.encode(imageHash, addrWeight, addr)); } return totalWeight >= threshold && _isValidImage(imageHash); } /** * @notice Validates the signature image * @param _imageHash Hashed image of signature * @return true if the signature image is valid */ function _isValidImage(bytes32 _imageHash) internal virtual view returns (bool); /** * @notice Will hash _data to be signed (similar to EIP-712) * @param _digest Pre-final digest * @return hashed data for this wallet */ function _subDigest(bytes32 _digest) internal override view returns (bytes32) { uint256 chainId; assembly { chainId := chainid() } return keccak256( abi.encodePacked( "\x19\x01", chainId, address(this), _digest ) ); } /** * @notice Verifies whether the provided signature is valid with respect to the provided data * @dev MUST return the correct magic value if the signature provided is valid for the provided data * > The bytes4 magic value to return when signature is valid is 0x20c13b0b : bytes4(keccak256("isValidSignature(bytes,bytes)")) * @param _data Arbitrary length data signed on the behalf of address(this) * @param _signatures Signature byte array associated with _data. * Encoded as abi.encode(Signature[], Configs) * @return magicValue Magic value 0x20c13b0b if the signature is valid and 0x0 otherwise */ function isValidSignature( bytes calldata _data, bytes calldata _signatures ) external override view returns (bytes4) { // Validate signatures if (_signatureValidation(_subDigest(keccak256(_data)), _signatures)) { return SELECTOR_ERC1271_BYTES_BYTES; } } /** * @notice Verifies whether the provided signature is valid with respect to the provided hash * @dev MUST return the correct magic value if the signature provided is valid for the provided hash * > The bytes4 magic value to return when signature is valid is 0x1626ba7e : bytes4(keccak256("isValidSignature(bytes32,bytes)")) * @param _hash keccak256 hash that was signed * @param _signatures Signature byte array associated with _data. * Encoded as abi.encode(Signature[], Configs) * @return magicValue Magic value 0x1626ba7e if the signature is valid and 0x0 otherwise */ function isValidSignature( bytes32 _hash, bytes calldata _signatures ) external override view returns (bytes4) { // Validate signatures if (_signatureValidation(_subDigest(_hash), _signatures)) { return SELECTOR_ERC1271_BYTES32_BYTES; } } /** * @notice Query if a contract implements an interface * @param _interfaceID The interface identifier, as specified in ERC-165 * @return `true` if the contract implements `_interfaceID` */ function supportsInterface(bytes4 _interfaceID) public override virtual pure returns (bool) { if ( _interfaceID == type(IModuleAuth).interfaceId || _interfaceID == type(IERC1271Wallet).interfaceId ) { return true; } return super.supportsInterface(_interfaceID); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; /** Minimal upgradeable proxy implementation, delegates all calls to the address defined by the storage slot matching the wallet address. Inspired by EIP-1167 Implementation (https://eips.ethereum.org/EIPS/eip-1167) deployed code: 0x00 0x36 0x36 CALLDATASIZE cds 0x01 0x3d 0x3d RETURNDATASIZE 0 cds 0x02 0x3d 0x3d RETURNDATASIZE 0 0 cds 0x03 0x37 0x37 CALLDATACOPY 0x04 0x3d 0x3d RETURNDATASIZE 0 0x05 0x3d 0x3d RETURNDATASIZE 0 0 0x06 0x3d 0x3d RETURNDATASIZE 0 0 0 0x07 0x36 0x36 CALLDATASIZE cds 0 0 0 0x08 0x3d 0x3d RETURNDATASIZE 0 cds 0 0 0 0x09 0x30 0x30 ADDRESS addr 0 cds 0 0 0 0x0A 0x54 0x54 SLOAD imp 0 cds 0 0 0 0x0B 0x5a 0x5a GAS gas imp 0 cds 0 0 0 0x0C 0xf4 0xf4 DELEGATECALL suc 0 0x0D 0x3d 0x3d RETURNDATASIZE rds suc 0 0x0E 0x82 0x82 DUP3 0 rds suc 0 0x0F 0x80 0x80 DUP1 0 0 rds suc 0 0x10 0x3e 0x3e RETURNDATACOPY suc 0 0x11 0x90 0x90 SWAP1 0 suc 0x12 0x3d 0x3d RETURNDATASIZE rds 0 suc 0x13 0x91 0x91 SWAP2 suc 0 rds 0x14 0x60 0x18 0x6018 PUSH1 0x18 suc 0 rds /-- 0x16 0x57 0x57 JUMPI 0 rds | 0x17 0xfd 0xfd REVERT \-> 0x18 0x5b 0x5b JUMPDEST 0 rds 0x19 0xf3 0xf3 RETURN flat deployed code: 0x363d3d373d3d3d363d30545af43d82803e903d91601857fd5bf3 deploy function: 0x00 0x60 0x3a 0x603a PUSH1 0x3a 0x02 0x60 0x0e 0x600e PUSH1 0x0e 0x3a 0x04 0x3d 0x3d RETURNDATASIZE 0 0x0e 0x3a 0x05 0x39 0x39 CODECOPY 0x06 0x60 0x1a 0x601a PUSH1 0x1a 0x08 0x80 0x80 DUP1 0x1a 0x1a 0x09 0x51 0x51 MLOAD imp 0x1a 0x0A 0x30 0x30 ADDRESS addr imp 0x1a 0x0B 0x55 0x55 SSTORE 0x1a 0x0C 0x3d 0x3d RETURNDATASIZE 0 0x1a 0x0D 0xf3 0xf3 RETURN [...deployed code] flat deploy function: 0x603a600e3d39601a805130553df3363d3d373d3d3d363d30545af43d82803e903d91601857fd5bf3 */ library Wallet { bytes internal constant creationCode = hex"603a600e3d39601a805130553df3363d3d373d3d3d363d30545af43d82803e903d91601857fd5bf3"; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; abstract contract IModuleAuth { /** * @notice Hashed _data to be signed * @param _digest Pre-final digest * @return hashed data for this wallet */ function _subDigest( bytes32 _digest ) internal virtual view returns (bytes32); /** * @notice Verify if signer is default wallet owner * @param _hash Hashed signed message * @param _signature Encoded signature * @return True is the signature is valid */ function _signatureValidation( bytes32 _hash, bytes memory _signature ) internal virtual view returns (bool); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; pragma experimental ABIEncoderV2; abstract contract ModuleERC165 { /** * @notice Query if a contract implements an interface * @param _interfaceID The interface identifier, as specified in ERC-165 * @dev Adding new hooks will not lead to them being reported by this function * without upgrading the wallet. In addition, developpers must ensure that * all inherited contracts by the mainmodule don't conflict and are accounted * to be supported by the supportsInterface method. * @return `true` if the contract implements `_interfaceID` */ function supportsInterface(bytes4 _interfaceID) virtual public pure returns (bool) { return _interfaceID == this.supportsInterface.selector; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; interface IModuleHooks { /** * @notice Reads the implementation hook of a signature * @param _signature Signature function * @return The address of the implementation hook, address(0) if none */ function readHook(bytes4 _signature) external view returns (address); /** * @notice Adds a new hook to handle a given function selector * @param _signature Signature function linked to the hook * @param _implementation Hook implementation contract */ function addHook(bytes4 _signature, address _implementation) external; /** * @notice Removes a registered hook * @param _signature Signature function linked to the hook */ function removeHook(bytes4 _signature) external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; contract ModuleSelfAuth { modifier onlySelf() { require(msg.sender == address(this), "ModuleSelfAuth#onlySelf: NOT_AUTHORIZED"); _; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; library ModuleStorage { function writeBytes32(bytes32 _key, bytes32 _val) internal { assembly { sstore(_key, _val) } } function readBytes32(bytes32 _key) internal view returns (bytes32 val) { assembly { val := sload(_key) } } function writeBytes32Map(bytes32 _key, bytes32 _subKey, bytes32 _val) internal { bytes32 key = keccak256(abi.encode(_key, _subKey)); assembly { sstore(key, _val) } } function readBytes32Map(bytes32 _key, bytes32 _subKey) internal view returns (bytes32 val) { bytes32 key = keccak256(abi.encode(_key, _subKey)); assembly { val := sload(key) } } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; interface IERC223Receiver { function tokenFallback(address, uint256, bytes calldata) external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; pragma experimental ABIEncoderV2; interface IModuleCalls { // Events event NonceChange(uint256 _space, uint256 _newNonce); event TxFailed(bytes32 _tx, bytes _reason); event TxExecuted(bytes32 _tx) anonymous; // Transaction structure struct Transaction { bool delegateCall; // Performs delegatecall bool revertOnError; // Reverts transaction bundle if tx fails uint256 gasLimit; // Maximum gas to be forwarded address target; // Address of the contract to call uint256 value; // Amount of ETH to pass with the call bytes data; // calldata to pass } /** * @notice Returns the next nonce of the default nonce space * @dev The default nonce space is 0x00 * @return The next nonce */ function nonce() external view returns (uint256); /** * @notice Returns the next nonce of the given nonce space * @param _space Nonce space, each space keeps an independent nonce count * @return The next nonce */ function readNonce(uint256 _space) external view returns (uint256); /** * @notice Allow wallet owner to execute an action * @param _txs Transactions to process * @param _nonce Signature nonce (may contain an encoded space) * @param _signature Encoded signature */ function execute( Transaction[] calldata _txs, uint256 _nonce, bytes calldata _signature ) external; /** * @notice Allow wallet to execute an action * without signing the message * @param _txs Transactions to execute */ function selfExecute( Transaction[] calldata _txs ) external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; interface IModuleUpdate { /** * @notice Updates the implementation of the base wallet * @param _implementation New main module implementation * @dev WARNING Updating the implementation can brick the wallet */ function updateImplementation(address _implementation) external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; library LibAddress { /** * @notice Will return true if provided address is a contract * @param account Address to verify if contract or not * @dev This contract will return false if called within the constructor of * a contract's deployment, as the code is not yet stored on-chain. */ function isContract(address account) internal view returns (bool) { uint256 csize; // solhint-disable-next-line no-inline-assembly assembly { csize := extcodesize(account) } return csize != 0; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.7.6; interface IModuleCreator { /** * @notice Creates a contract forwarding eth value * @param _code Creation code of the contract * @return addr The address of the created contract */ function createContract(bytes calldata _code) external payable returns (address addr); }
{ "optimizer": { "enabled": true, "runs": 999999, "details": { "yul": true } }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_factory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_contract","type":"address"}],"name":"CreatedContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newImplementation","type":"address"}],"name":"ImplementationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_space","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newNonce","type":"uint256"}],"name":"NonceChange","type":"event"},{"anonymous":true,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_tx","type":"bytes32"}],"name":"TxExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_tx","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"_reason","type":"bytes"}],"name":"TxFailed","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"FACTORY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INIT_CODE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_signature","type":"bytes4"},{"internalType":"address","name":"_implementation","type":"address"}],"name":"addHook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_code","type":"bytes"}],"name":"createContract","outputs":[{"internalType":"address","name":"addr","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"delegateCall","type":"bool"},{"internalType":"bool","name":"revertOnError","type":"bool"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IModuleCalls.Transaction[]","name":"_txs","type":"tuple[]"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"},{"internalType":"bytes","name":"_signatures","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_signatures","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_signature","type":"bytes4"}],"name":"readHook","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_space","type":"uint256"}],"name":"readNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_signature","type":"bytes4"}],"name":"removeHook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"delegateCall","type":"bool"},{"internalType":"bool","name":"revertOnError","type":"bool"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IModuleCalls.Transaction[]","name":"_txs","type":"tuple[]"}],"name":"selfExecute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_implementation","type":"address"}],"name":"updateImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60c06040523480156200001157600080fd5b5060405162002d6338038062002d638339810160408190526200003491620000e2565b80600060405180606001604052806028815260200162002d3b60289139306001600160a01b03166040516020018083805190602001908083835b602083106200008f5780518252601f1990920191602091820191016200006e565b51815160209384036101000a60001901801990921691161790529201938452506040805180850381529382019052825192019190912060805250505060601b6001600160601b03191660a0525062000112565b600060208284031215620000f4578081fd5b81516001600160a01b03811681146200010b578182fd5b9392505050565b60805160a05160601c612bf862000143600039806106d55280611baa5250806106b15280611bdb5250612bf86000f3fe6080604052600436106101125760003560e01c80634fcf3eca116100a557806390042baf11610074578063b93ea7ad11610059578063b93ea7ad146103c5578063bc197c81146103e5578063f23a6e611461040557610119565b806390042baf1461039d578063affed0e0146103b057610119565b80634fcf3eca1461031d57806361c2926c1461033d5780637a9a16281461035d5780638c3f55631461037d57610119565b80631a9b2337116100e15780631a9b23371461029957806320c13b0b146102c6578063257671f5146102e65780632dd310001461030857610119565b806301ffc9a7146101f4578063025b22bc1461022a578063150b7a021461024c5780631626ba7e1461027957610119565b3661011957005b60006101486000357fffffffff0000000000000000000000000000000000000000000000000000000016610425565b905073ffffffffffffffffffffffffffffffffffffffff8116156101f1576000808273ffffffffffffffffffffffffffffffffffffffff166000366040518083838082843760405192019450600093509091505080830381855af49150503d80600081146101d2576040519150601f19603f3d011682016040523d82523d6000602084013e6101d7565b606091505b5091509150816101e957805160208201fd5b805160208201f35b50005b34801561020057600080fd5b5061021461020f366004612401565b61047b565b6040516102219190612633565b60405180910390f35b34801561023657600080fd5b5061024a610245366004612166565b610486565b005b34801561025857600080fd5b5061026c610267366004612237565b6105a7565b6040516102219190612660565b34801561028557600080fd5b5061026c6102943660046123b7565b6105d1565b3480156102a557600080fd5b506102b96102b4366004612401565b61064a565b6040516102219190612612565b3480156102d257600080fd5b5061026c6102e136600461244d565b610655565b3480156102f257600080fd5b506102fb6106af565b604051610221919061263e565b34801561031457600080fd5b506102b96106d3565b34801561032957600080fd5b5061024a610338366004612401565b6106f7565b34801561034957600080fd5b5061024a61035836600461231a565b6107d5565b34801561036957600080fd5b5061024a61037836600461234d565b61086e565b34801561038957600080fd5b506102fb6103983660046124e9565b6108ea565b6102b96103ab3660046124b6565b610916565b3480156103bc57600080fd5b506102fb6109ca565b3480156103d157600080fd5b5061024a6103e036600461241b565b6109db565b3480156103f157600080fd5b5061026c610400366004612180565b610ab4565b34801561041157600080fd5b5061026c6104203660046122a4565b610ae1565b60006104737fbe27a319efc8734e89e26ba4bc95f5c788584163b959f03fa04e2d7ab4b9a1207fffffffff000000000000000000000000000000000000000000000000000000008416610b0c565b90505b919050565b600061047382610b39565b3330146104de576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526027815260200180612b9c6027913960400191505060405180910390fd5b6104fd8173ffffffffffffffffffffffffffffffffffffffff16610b96565b610552576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526039815260200180612a826039913960400191505060405180910390fd5b61055b81610b9c565b6040805173ffffffffffffffffffffffffffffffffffffffff8316815290517f310ba5f1d2ed074b51e2eccd052a47ae9ab7c6b800d1fca3db3999d6a592ca039181900360200190a150565b7f150b7a020000000000000000000000000000000000000000000000000000000095945050505050565b600061061b6105df85610ba0565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c0092505050565b1561064357507f1626ba7e000000000000000000000000000000000000000000000000000000005b9392505050565b600061047382610425565b600061067f6105df86866040518083838082843760405192018290039091209350610ba092505050565b156106a757507f20c13b0b000000000000000000000000000000000000000000000000000000005b949350505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b33301461074f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526027815260200180612b9c6027913960400191505060405180910390fd5b600061075a82610425565b73ffffffffffffffffffffffffffffffffffffffff1614156107c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b8152602001806128e0602b913960400191505060405180910390fd5b6107d2816000610df8565b50565b33301461082d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526027815260200180612b9c6027913960400191505060405180910390fd5b600061085e82604051602001610843919061277e565b60405160208183030381529060405280519060200120610ba0565b905061086a8183610e5b565b5050565b6108778261102a565b600061088f83856040516020016108439291906127c5565b905061089b8183610c00565b6108da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108d190612721565b60405180910390fd5b6108e48185610e5b565b50505050565b60006104737f8d0bf1fd623d628c741362c1289948e57b3e2905218c676d3e69abee36d6ae2e83610b0c565b6000333014610970576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526027815260200180612b9c6027913960400191505060405180910390fd5b81516020830134f06040805173ffffffffffffffffffffffffffffffffffffffff8316815290519192507fa506ad4e7f05eceba62a023c3219e5bd98a615f4fa87e2afb08a2da5cf62bf0c919081900360200190a1919050565b60006109d660006108ea565b905090565b333014610a33576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526027815260200180612b9c6027913960400191505060405180910390fd5b6000610a3e83610425565b73ffffffffffffffffffffffffffffffffffffffff1614610aaa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806129f4602c913960400191505060405180910390fd5b61086a8282610df8565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b60408051602080820194909452808201929092528051808303820181526060909201905280519101205490565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f90042baf000000000000000000000000000000000000000000000000000000001415610b8d57506001610476565b610473826110ce565b3b151590565b3055565b604080517f19010000000000000000000000000000000000000000000000000000000000006020808301919091524660228301523060601b6042830152605680830194909452825180830390940184526076909101909152815191012090565b6000806000610c0e8461120f565b909250905061ffff821660005b8551831015610dd55760008080610c32898761127d565b975060ff91821694501691506001831415610c5a57610c5189876112fe565b96509050610d7e565b82610c86576060610c6b8a88611376565b97509050610c798b82611427565b9150828501945050610d7e565b6002831415610d2d57610c9989876112fe565b965090506000610ca98a886117b1565b975061ffff1690506060610cbe8b8984611822565b98509050610ccd8c8483611911565b610d22576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001806129c26032913960400191505060405180910390fd5b505092810192610d7e565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806128b4602c913960400191505060405180910390fd5b848282604051602001808481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019350505050604051602081830303815290604052805190602001209450505050610c1b565b8361ffff168110158015610ded5750610ded82611b59565b979650505050505050565b61086a7fbe27a319efc8734e89e26ba4bc95f5c788584163b959f03fa04e2d7ab4b9a1207fffffffff00000000000000000000000000000000000000000000000000000000841673ffffffffffffffffffffffffffffffffffffffff8416611c37565b60005b8151811015611025576000828281518110610e7557fe5b602002602001015190506000606082604001515a1015610ec1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108d1906126c4565b825115610f5957826060015173ffffffffffffffffffffffffffffffffffffffff168360400151600014610ef9578360400151610efb565b5a5b8460a00151604051610f0d91906125f6565b6000604051808303818686f4925050503d8060008114610f49576040519150601f19603f3d011682016040523d82523d6000602084013e610f4e565b606091505b509092509050610fee565b826060015173ffffffffffffffffffffffffffffffffffffffff1683608001518460400151600014610f8f578460400151610f91565b5a5b908560a00151604051610fa491906125f6565b600060405180830381858888f193505050503d8060008114610fe2576040519150601f19603f3d011682016040523d82523d6000602084013e610fe7565b606091505b5090925090505b811561100f5785604051611002919061263e565b60405180910390a061101a565b61101a838783611c65565b505050600101610e5e565b505050565b60008061103683611cb5565b915091506000611045836108ea565b9050808214611080576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108d19061268d565b6001820161108e8482611cce565b7f1f180c27086c7a39ea2a7b25239d1ab92348f07ca7bb59d1438fcf527568f88184826040516110bf9291906127de565b60405180910390a15050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fec6aba5000000000000000000000000000000000000000000000000000000000148061116157507fffffffff0000000000000000000000000000000000000000000000000000000082167f4e2312e000000000000000000000000000000000000000000000000000000000145b806111ad57507fffffffff0000000000000000000000000000000000000000000000000000000082167f150b7a0200000000000000000000000000000000000000000000000000000000145b806111f957507fffffffff0000000000000000000000000000000000000000000000000000000082167fc0ee0b8a00000000000000000000000000000000000000000000000000000000145b1561120657506001610476565b61047382611cf9565b6020810151815160f09190911c90600290811115611278576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061292e6027913960400191505060405180910390fd5b915091565b8082016020015160f881901c9060f01c60ff166002830183811161129d57fe5b84518111156112f7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180612af76026913960400191505060405180910390fd5b9250925092565b8082016020015160601c6014820182811161131557fe5b835181111561136f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602381526020018061290b6023913960400191505060405180910390fd5b9250929050565b6040805160428082526080820190925260609160009190602082018180368337019050509150828401602001805160208401526020810151604084015260228101516042840152506042830190508281116113cd57fe5b835181111561136f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180612a5f6023913960400191505060405180910390fd5b60008151604214611483576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603a81526020018061287a603a913960400191505060405180910390fd5b60008260018451038151811061149557fe5b602001015160f81c60f81b60f81c60ff1690506000836040815181106114b757fe5b016020015160f81c905060006114cd8582611d56565b905060006114dc866020611d56565b90507f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0811115611557576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603d81526020018061283d603d913960400191505060405180910390fd5b8260ff16601b1415801561156f57508260ff16601c14155b156115c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603d815260200180612955603d913960400191505060405180910390fd5b60018414156116395760018784848460405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015611628573d6000803e3d6000fd5b50505060206040510351945061173b565b60028414156116ea5760018760405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c018281526020019150506040516020818303038152906040528051906020012084848460405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015611628573d6000803e3d6000fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603c815260200180612abb603c913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff85166117a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260308152602001806129926030913960400191505060405180910390fd5b5050505092915050565b8082016020015160f01c600282018281116117c857fe5b835181111561136f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180612b3e6022913960400191505060405180910390fd5b606060008267ffffffffffffffff8111801561183d57600080fd5b506040519080825280601f01601f191660200182016040528015611868576020820181803683370190505b509150838501602001600060205b8581101561188f57908201518482015260208101611876565b84860160200180519390920151908501525250828201838110156118af57fe5b8451811115611909576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612b1d6021913960400191505060405180910390fd5b935093915050565b6000808260018451038151811061192457fe5b016020015160f81c9050600181148061193d5750600281145b15611981578373ffffffffffffffffffffffffffffffffffffffff166119638685611427565b73ffffffffffffffffffffffffffffffffffffffff16149150611b51565b6003811415611b005782517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81018452604080517f1626ba7e000000000000000000000000000000000000000000000000000000008152600481018881526024820192835286516044830152865173ffffffffffffffffffffffffffffffffffffffff891693631626ba7e938b938a9390929160640190602085019080838360005b83811015611a3b578181015183820152602001611a23565b50505050905090810190601f168015611a685780820380516001836020036101000a031916815260200191505b50935050505060206040518083038186803b158015611a8657600080fd5b505afa158015611a9a573d6000803e3d6000fd5b505050506040513d6020811015611ab057600080fd5b50519084527fffffffff00000000000000000000000000000000000000000000000000000000167f1626ba7e00000000000000000000000000000000000000000000000000000000149150611b51565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603f815260200180612a20603f913960400191505060405180910390fd5b509392505050565b604080517fff000000000000000000000000000000000000000000000000000000000000006020808301919091527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000060601b166021830152603582018490527f0000000000000000000000000000000000000000000000000000000000000000605580840191909152835180840390910181526075909201909252805191012073ffffffffffffffffffffffffffffffffffffffff163014919050565b6040805160208082019590955280820193909352805180840382018152606090930190528151919092012055565b826020015115611c7757805160208201fd5b7f3dbd1590ea96dd3253a91f24e64e3a502e1225d602a5731357bc12643070ccd78282604051611ca8929190612647565b60405180910390a1505050565b606081901c916bffffffffffffffffffffffff90911690565b61086a7f8d0bf1fd623d628c741362c1289948e57b3e2905218c676d3e69abee36d6ae2e8383611c37565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f025b22bc000000000000000000000000000000000000000000000000000000001415611d4d57506001610476565b61047382611dbe565b60008160200183511015611db5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603c815260200180612b60603c913960400191505060405180910390fd5b50016020015190565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f389901c7000000000000000000000000000000000000000000000000000000001415611e1257506001610476565b6104738260007fffffffff0000000000000000000000000000000000000000000000000000000082161580611e8857507fffffffff0000000000000000000000000000000000000000000000000000000082167f36e7817500000000000000000000000000000000000000000000000000000000145b15611e9557506001610476565b7f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610473565b803573ffffffffffffffffffffffffffffffffffffffff8116811461047657600080fd5b600082601f830112611f13578081fd5b8135602067ffffffffffffffff80831115611f2a57fe5b611f3782838502016127ec565b83815282810190868401865b86811015612013578135890160c0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0838e03011215611f8157898afd5b604080518281018181108a82111715611f9657fe5b8252611fa3848b01612063565b8152611fb0828501612063565b8a8201526060808501358383015260809250611fcd838601611edf565b9082015260a08481013583830152928401359289841115611fec578c8dfd5b611ffa8f8c868801016120e3565b9082015287525050509285019290850190600101611f43565b509098975050505050505050565b60008083601f840112612032578182fd5b50813567ffffffffffffffff811115612049578182fd5b602083019150836020808302850101111561136f57600080fd5b8035801515811461047657600080fd5b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461047657600080fd5b60008083601f8401126120b4578182fd5b50813567ffffffffffffffff8111156120cb578182fd5b60208301915083602082850101111561136f57600080fd5b600082601f8301126120f3578081fd5b813567ffffffffffffffff81111561210757fe5b61213860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016127ec565b81815284602083860101111561214c578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215612177578081fd5b61064382611edf565b60008060008060008060008060a0898b03121561219b578384fd5b6121a489611edf565b97506121b260208a01611edf565b9650604089013567ffffffffffffffff808211156121ce578586fd5b6121da8c838d01612021565b909850965060608b01359150808211156121f2578586fd5b6121fe8c838d01612021565b909650945060808b0135915080821115612216578384fd5b506122238b828c016120a3565b999c989b5096995094979396929594505050565b60008060008060006080868803121561224e578081fd5b61225786611edf565b945061226560208701611edf565b935060408601359250606086013567ffffffffffffffff811115612287578182fd5b612293888289016120a3565b969995985093965092949392505050565b60008060008060008060a087890312156122bc578182fd5b6122c587611edf565b95506122d360208801611edf565b94506040870135935060608701359250608087013567ffffffffffffffff8111156122fc578283fd5b61230889828a016120a3565b979a9699509497509295939492505050565b60006020828403121561232b578081fd5b813567ffffffffffffffff811115612341578182fd5b6106a784828501611f03565b600080600060608486031215612361578283fd5b833567ffffffffffffffff80821115612378578485fd5b61238487838801611f03565b94506020860135935060408601359150808211156123a0578283fd5b506123ad868287016120e3565b9150509250925092565b6000806000604084860312156123cb578283fd5b83359250602084013567ffffffffffffffff8111156123e8578283fd5b6123f4868287016120a3565b9497909650939450505050565b600060208284031215612412578081fd5b61064382612073565b6000806040838503121561242d578182fd5b61243683612073565b915061244460208401611edf565b90509250929050565b60008060008060408587031215612462578182fd5b843567ffffffffffffffff80821115612479578384fd5b612485888389016120a3565b9096509450602087013591508082111561249d578384fd5b506124aa878288016120a3565b95989497509550505050565b6000602082840312156124c7578081fd5b813567ffffffffffffffff8111156124dd578182fd5b6106a7848285016120e3565b6000602082840312156124fa578081fd5b5035919050565b6000815180845260208085018081965082840281019150828601855b8581101561259f5782840389528151805115158552858101511515868601526040808201519086015260608082015173ffffffffffffffffffffffffffffffffffffffff16908601526080808201519086015260a09081015160c09186018290529061258b818701836125ac565b9a87019a955050509084019060010161251d565b5091979650505050505050565b600081518084526125c4816020860160208601612810565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60008251612608818460208701612810565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b901515815260200190565b90815260200190565b6000838252604060208301526106a760408301846125ac565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b6020808252601f908201527f4d61696e4d6f64756c65235f617574683a20494e56414c49445f4e4f4e434500604082015260600190565b60208082526024908201527f4d6f64756c6543616c6c73235f657865637574653a204e4f545f454e4f55474860408201527f5f47415300000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526026908201527f4d6f64756c6543616c6c7323657865637574653a20494e56414c49445f53494760408201527f4e41545552450000000000000000000000000000000000000000000000000000606082015260800190565b600060408252600560408301527f73656c663a0000000000000000000000000000000000000000000000000000006060830152608060208301526106436080830184612501565b6000838252604060208301526106a76040830184612501565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561280857fe5b604052919050565b60005b8381101561282b578181015183820152602001612813565b838111156108e4575050600091015256fe5369676e617475726556616c696461746f72237265636f7665725369676e65723a20696e76616c6964207369676e6174757265202773272076616c75655369676e617475726556616c696461746f72237265636f7665725369676e65723a20696e76616c6964207369676e6174757265206c656e6774684d6f64756c6541757468235f7369676e617475726556616c69646174696f6e20494e56414c49445f464c41474d6f64756c65486f6f6b732372656d6f7665486f6f6b3a20484f4f4b5f4e4f545f524547495354455245444c696242797465732372656164416464726573733a204f55545f4f465f424f554e44534c696242797465732372656164466972737455696e7431363a204f55545f4f465f424f554e44535369676e617475726556616c696461746f72237265636f7665725369676e65723a20696e76616c6964207369676e6174757265202776272076616c75655369676e617475726556616c696461746f72237265636f7665725369676e65723a20494e56414c49445f5349474e45524d6f64756c6541757468235f7369676e617475726556616c69646174696f6e3a20494e56414c49445f5349474e41545552454d6f64756c65486f6f6b7323616464486f6f6b3a20484f4f4b5f414c52454144595f524547495354455245445369676e617475726556616c696461746f7223697356616c69645369676e61747572653a20554e535550504f525445445f5349474e41545552455f545950454c696242797465732372656164427974657336363a204f55545f4f465f424f554e44534d6f64756c6555706461746523757064617465496d706c656d656e746174696f6e3a20494e56414c49445f494d504c454d454e544154494f4e5369676e617475726556616c696461746f72237265636f7665725369676e65723a20554e535550504f525445445f5349474e41545552455f545950454c69624279746573237265616455696e743855696e74383a204f55545f4f465f424f554e44534c69624279746573237265616442797465733a204f55545f4f465f424f554e44534c69624279746573237265616455696e7431363a204f55545f4f465f424f554e44534c696242797465732372656164427974657333323a20475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f52455155495245444d6f64756c6553656c6641757468236f6e6c7953656c663a204e4f545f415554484f52495a4544a2646970667358221220b34deca9dd75815e4ef8a9279e45750ec5554b22c673e160bdba849d80f5888564736f6c63430007060033603a600e3d39601a805130553df3363d3d373d3d3d363d30545af43d82803e903d91601857fd5bf3000000000000000000000000f9d09d634fb818b05149329c1dccfaea53639d96
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f9d09d634fb818b05149329c1dccfaea53639d96
-----Decoded View---------------
Arg [0] : _factory (address): 0xf9d09d634fb818b05149329c1dccfaea53639d96
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000f9d09d634fb818b05149329c1dccfaea53639d96
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.