Balance:
39,037.401289270863935565 MATIC
MATIC Value:
$35,910.51 (@ $0.92/MATIC)
Token:
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Latest 25 internal transaction
[ 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 Source Code Verified (Exact Match)
Contract Name:
Bank
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract KeeperBase { error OnlySimulatedBackend(); /** * @notice method that allows it to be simulated via eth_call by checking that * the sender is the zero address. */ function preventExecution() internal view { if (tx.origin != address(0)) { revert OnlySimulatedBackend(); } } /** * @notice modifier that allows it to be simulated via eth_call by checking * that the sender is the zero address. */ modifier cannotExecute() { preventExecution(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./KeeperBase.sol"; import "./interfaces/KeeperCompatibleInterface.sol"; abstract contract KeeperCompatible is KeeperBase, KeeperCompatibleInterface {}
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface KeeperCompatibleInterface { /** * @notice method that is simulated by the keepers to see if any work actually * needs to be performed. This method does does not actually need to be * executable, and since it is only ever simulated it can consume lots of gas. * @dev To ensure that it is never called, you may want to add the * cannotExecute modifier from KeeperBase to your implementation of this * method. * @param checkData specified in the upkeep registration so it is always the * same for a registered upkeep. This can easily be broken down into specific * arguments using `abi.decode`, so multiple upkeeps can be registered on the * same contract and easily differentiated by the contract. * @return upkeepNeeded boolean to indicate whether the keeper should call * performUpkeep or not. * @return performData bytes that the keeper should call performUpkeep with, if * upkeep is needed. If you would like to encode data to decode later, try * `abi.encode`. */ function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData); /** * @notice method that is actually executed by the keepers, via the registry. * The data returned by the checkUpkeep simulation will be passed into * this method to actually be executed. * @dev The input to this method should not be trusted, and the caller of the * method should not even be restricted to any single registry. Anyone should * be able call it, and the input should be validated, there is no guarantee * that the data passed in is the performData returned from checkUpkeep. This * could happen due to malicious keepers, racing keepers, or simply a state * change while the performUpkeep transaction is waiting for confirmation. * Always validate the data passed in. * @param performData is the data which was passed back from the checkData * simulation. If it is encoded, it can easily be decoded into other types by * calling `abi.decode`. This data should not be trusted, and should be * validated against the contract's current state. */ function performUpkeep(bytes calldata performData) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(uint160(account), 20), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControlEnumerable.sol"; import "./AccessControl.sol"; import "../utils/structs/EnumerableSet.sol"; /** * @dev Extension of {AccessControl} that allows enumerating the members of each role. */ abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { using EnumerableSet for EnumerableSet.AddressSet; mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) { return _roleMembers[role].at(index); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) { return _roleMembers[role].length(); } /** * @dev Overload {_grantRole} to track enumerable memberships */ function _grantRole(bytes32 role, address account) internal virtual override { super._grantRole(role, account); _roleMembers[role].add(account); } /** * @dev Overload {_revokeRole} to track enumerable memberships */ function _revokeRole(bytes32 role, address account) internal virtual override { super._revokeRole(role, account); _roleMembers[role].remove(account); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. */ interface IAccessControlEnumerable is IAccessControl { /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) external view returns (address); /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) external view returns (uint256); }
// 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 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// 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.5.0) (utils/Multicall.sol) pragma solidity ^0.8.0; import "./Address.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. * * _Available since v4.1._ */ abstract contract Multicall { /** * @dev Receives and executes a batch of function calls on this contract. */ function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { results[i] = Address.functionDelegateCall(address(this), data[i]); } return results; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_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) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @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] = _HEX_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: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol) pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import {AccessControlEnumerable} from "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {IERC20Metadata, IERC20} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Multicall} from "@openzeppelin/contracts/utils/Multicall.sol"; import {KeeperCompatibleInterface} from "@chainlink/contracts/src/v0.8/KeeperCompatible.sol"; interface IGame { function hasPendingBets(address token) external view returns (bool); function withdrawTokensVRFFees(address token) external; } // import "hardhat/console.sol"; /// @title BetSwirl's Bank /// @author Romuald Hog /// @notice The Bank contract holds the casino's funds, /// whitelist the games betting tokens, /// define the max bet amount based on a risk, /// payout the bet profit to user and collect the loss bet amount from the game's contract, /// split and allocate the house edge taken from each bet (won or loss). /// The admin role is transfered to a Timelock that execute administrative tasks, /// only the Games could payout the bet profit from the bank, and send the loss bet amount to the bank. /// @dev All rates are in basis point. contract Bank is AccessControlEnumerable, KeeperCompatibleInterface, Multicall { using SafeERC20 for IERC20; /// @notice Enum to identify the Chainlink Upkeep registration. enum UpkeepActions { DistributePartnerHouseEdge, DistributeOwnHouseEdge } /// @notice Token's house edge allocations struct. /// The games house edge is split into several allocations. /// The allocated amounts stays in the bank until authorized parties withdraw. They are subtracted from the balance. /// @param bank Rate to be allocated to the bank, on bet payout. /// @param dividend Rate to be allocated as staking rewards, on bet payout. /// @param partner Rate to be allocated to the partner, on bet payout. /// @param treasury Rate to be allocated to the treasury, on bet payout. /// @param team Rate to be allocated to the team, on bet payout. /// @param dividendAmount The number of tokens to be sent as staking rewards. /// @param partnerAmount The number of tokens to be sent to the partner. /// @param treasuryAmount The number of tokens to be sent to the treasury. /// @param teamAmount The number of tokens to be sent to the team. struct HouseEdgeSplit { uint16 bank; uint16 dividend; uint16 partner; uint16 treasury; uint16 team; uint256 dividendAmount; uint256 partnerAmount; uint256 treasuryAmount; uint256 teamAmount; } /// @notice Token struct. /// List of tokens to bet on games. /// @param allowed Whether the token is allowed for bets. /// @param paused Whether the token is paused for bets. /// @param balanceRisk Defines the maximum bank payout, used to calculate the max bet amount. /// @param VRFSubId Chainlink VRF v2 subscription ID. /// @param partner Address of the partner to manage the token and receive the house edge. /// @param minBetAmount Minimum bet amount. /// @param minHouseEdgeWithdrawAmount The minimum amount of token to trigger the distribution of the house edge. /// @param houseEdgeSplit House edge allocations. struct Token { bool allowed; bool paused; uint16 balanceRisk; uint64 VRFSubId; address partner; uint256 minBetAmount; uint256 minHouseEdgeWithdrawAmount; HouseEdgeSplit houseEdgeSplit; } /// @notice Token's metadata struct. It contains additional information from the ERC20 token. /// @dev Only used on the `getTokens` getter for the front-end. /// @param decimals Number of token's decimals. /// @param tokenAddress Contract address of the token. /// @param name Name of the token. /// @param symbol Symbol of the token. /// @param token Token data. struct TokenMetadata { uint8 decimals; address tokenAddress; string name; string symbol; Token token; } /// @notice Number of tokens added. uint8 private _tokensCount; /// @notice Treasury multi-sig wallet. address public immutable treasury; /// @notice Team wallet. address public teamWallet; /// @notice Role associated to Games smart contracts. bytes32 public constant GAME_ROLE = keccak256("GAME_ROLE"); /// @notice Role associated to harvester smart contract. bytes32 public constant HARVESTER_ROLE = keccak256("HARVESTER_ROLE"); /// @notice Maps tokens addresses to token configuration. mapping(address => Token) public tokens; /// @notice Maps tokens indexes to token address. mapping(uint8 => address) private _tokensList; /// @notice Emitted after the team wallet is set. /// @param teamWallet The team wallet address. event SetTeamWallet(address teamWallet); /// @notice Emitted after a token is added. /// @param token Address of the token. event AddToken(address token); /// @notice Emitted after the balance risk is set. /// @param balanceRisk Rate defining the balance risk. event SetBalanceRisk(address indexed token, uint16 balanceRisk); /// @notice Emitted after a token is allowed. /// @param token Address of the token. /// @param allowed Whether the token is allowed for betting. event SetAllowedToken(address indexed token, bool allowed); /// @notice Emitted after the minimum bet amount is set for a token. /// @param token Address of the token. /// @param minBetAmount Minimum bet amount. event SetTokenMinBetAmount(address indexed token, uint256 minBetAmount); /// @notice Emitted after the token's VRF subscription ID is set. /// @param token Address of the token. /// @param subId Subscription ID. event SetTokenVRFSubId(address indexed token, uint64 subId); /// @notice Emitted after a token is paused. /// @param token Address of the token. /// @param paused Whether the token is paused for betting. event SetPausedToken(address indexed token, bool paused); /// @notice Emitted after the Upkeep minimum transfer amount is set. /// @param token Address of the token. /// @param minHouseEdgeWithdrawAmount Minimum amount of token to allow transfer. event SetMinHouseEdgeWithdrawAmount( address indexed token, uint256 minHouseEdgeWithdrawAmount ); /// @notice Emitted after a token partner is set. /// @param token Address of the token. /// @param partner Address of the partner. event SetTokenPartner(address indexed token, address partner); /// @notice Emitted after a token deposit. /// @param token Address of the token. /// @param amount The number of token deposited. event Deposit(address indexed token, uint256 amount); /// @notice Emitted after a token withdrawal. /// @param token Address of the token. /// @param amount The number of token withdrawn. event Withdraw(address indexed token, uint256 amount); /// @notice Emitted after the token's house edge allocations for bet payout is set. /// @param token Address of the token. /// @param bank Rate to be allocated to the bank, on bet payout. /// @param dividend Rate to be allocated as staking rewards, on bet payout. /// @param partner Rate to be allocated to the partner, on bet payout. /// @param treasury Rate to be allocated to the treasury, on bet payout. /// @param team Rate to be allocated to the team, on bet payout. event SetTokenHouseEdgeSplit( address indexed token, uint16 bank, uint16 dividend, uint16 partner, uint16 treasury, uint16 team ); /// @notice Emitted after the token's treasury and team allocations are distributed. /// @param token Address of the token. /// @param treasuryAmount The number of tokens sent to the treasury. /// @param teamAmount The number of tokens sent to the team. event HouseEdgeDistribution( address indexed token, uint256 treasuryAmount, uint256 teamAmount ); /// @notice Emitted after the token's partner allocation is distributed. /// @param token Address of the token. /// @param partnerAmount The number of tokens sent to the partner. event HouseEdgePartnerDistribution( address indexed token, uint256 partnerAmount ); /// @notice Emitted after the token's dividend allocation is distributed. /// @param token Address of the token. /// @param amount The number of tokens sent to the Harvester. event HarvestDividend(address indexed token, uint256 amount); /// @notice Emitted after the token's house edge is allocated. /// @param token Address of the token. /// @param bank The number of tokens allocated to bank. /// @param dividend The number of tokens allocated as staking rewards. /// @param partner The number of tokens allocated to the partner. /// @param treasury The number of tokens allocated to the treasury. /// @param team The number of tokens allocated to the team. event AllocateHouseEdgeAmount( address indexed token, uint256 bank, uint256 dividend, uint256 partner, uint256 treasury, uint256 team ); /// @notice Emitted after the bet profit amount is sent to the user. /// @param token Address of the token. /// @param newBalance New token balance. /// @param profit Bet profit amount sent. event Payout(address indexed token, uint256 newBalance, uint256 profit); /// @notice Emitted after the bet amount is collected from the game smart contract. /// @param token Address of the token. /// @param newBalance New token balance. /// @param amount Bet amount collected. event CashIn(address indexed token, uint256 newBalance, uint256 amount); /// @notice Reverting error when trying to add an existing token. error TokenExists(); /// @notice Reverting error when setting the house edge allocations, but the sum isn't 100%. /// @param splitSum Sum of the house edge allocations rates. error WrongHouseEdgeSplit(uint16 splitSum); /// @notice Reverting error when sender isn't allowed. error AccessDenied(); /// @notice Reverting error when team wallet or treasury is the zero address. error WrongAddress(); /// @notice Reverting error when withdrawing a non paused token. error TokenNotPaused(); /// @notice Reverting error when token has pending bets on a game. error TokenHasPendingBets(); /// @notice Modifier that checks that an account is allowed to interact with a token. /// @param role The required role. /// @param token The token address. modifier onlyTokenOwner(bytes32 role, address token) { address partner = tokens[token].partner; if (partner == address(0)) { _checkRole(role, msg.sender); } else if (msg.sender != partner) { revert AccessDenied(); } _; } /// @notice Initialize the contract's admin role to the deployer, and state variables. /// @param treasuryAddress Treasury multi-sig wallet. /// @param teamWalletAddress Team wallet. constructor(address treasuryAddress, address teamWalletAddress) { if (treasuryAddress == address(0)) { revert WrongAddress(); } treasury = treasuryAddress; // The ownership should then be transfered to a multi-sig. _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); setTeamWallet(teamWalletAddress); } /// @notice Transfers a specific amount of token to an address. /// Uses native transfer or ERC20 transfer depending on the token. /// @dev The 0x address is considered the gas token. /// @param user Address of destination. /// @param token Address of the token. /// @param amount Number of tokens. function _safeTransfer( address user, address token, uint256 amount ) private { if (_isGasToken(token)) { Address.sendValue(payable(user), amount); } else { IERC20(token).safeTransfer(user, amount); } } /// @notice Check if the token has the 0x address. /// @param token Address of the token. /// @return Whether the token's address is the 0x address. function _isGasToken(address token) private pure returns (bool) { return token == address(0); } /// @notice Deposit funds in the bank to allow gamers to win more. /// ERC20 token allowance should be given prior to deposit. /// @param token Address of the token. /// @param amount Number of tokens. function deposit(address token, uint256 amount) external payable onlyTokenOwner(DEFAULT_ADMIN_ROLE, token) { if (_isGasToken(token)) { amount = msg.value; } else { IERC20(token).safeTransferFrom(msg.sender, address(this), amount); } emit Deposit(token, amount); } /// @notice Withdraw funds from the bank. Token has to be paused and no pending bet resolution on games. /// @param token Address of the token. /// @param amount Number of tokens. function withdraw(address token, uint256 amount) public onlyTokenOwner(DEFAULT_ADMIN_ROLE, token) { uint256 balance = getBalance(token); if (balance != 0) { if (!tokens[token].paused) { revert TokenNotPaused(); } uint256 roleMemberCount = getRoleMemberCount(GAME_ROLE); for (uint256 i; i < roleMemberCount; i++) { if (IGame(getRoleMember(GAME_ROLE, i)).hasPendingBets(token)) { revert TokenHasPendingBets(); } } if (amount > balance) { amount = balance; } _safeTransfer(msg.sender, token, amount); emit Withdraw(token, amount); } } /// @notice Sets the new token balance risk. /// @param token Address of the token. /// @param balanceRisk Risk rate. function setBalanceRisk(address token, uint16 balanceRisk) external onlyTokenOwner(DEFAULT_ADMIN_ROLE, token) { tokens[token].balanceRisk = balanceRisk; emit SetBalanceRisk(token, balanceRisk); } /// @notice Adds a new token that'll be enabled for the games' betting. /// Token shouldn't exist yet. /// @param token Address of the token. function addToken(address token) external onlyRole(DEFAULT_ADMIN_ROLE) { if (_tokensCount != 0) { for (uint8 i; i < _tokensCount; i++) { if (_tokensList[i] == token) { revert TokenExists(); } } } _tokensList[_tokensCount] = token; _tokensCount += 1; emit AddToken(token); } /// @notice Changes the token's bet permission. /// @param token Address of the token. /// @param allowed Whether the token is enabled for bets. function setAllowedToken(address token, bool allowed) external onlyRole(DEFAULT_ADMIN_ROLE) { tokens[token].allowed = allowed; emit SetAllowedToken(token, allowed); } /// @notice Changes the token's paused status. /// @param token Address of the token. /// @param paused Whether the token is paused. function setPausedToken(address token, bool paused) external onlyTokenOwner(DEFAULT_ADMIN_ROLE, token) { tokens[token].paused = paused; emit SetPausedToken(token, paused); } /// @notice Changes the token's Upkeep min transfer amount. /// @param token Address of the token. /// @param minHouseEdgeWithdrawAmount Minimum amount of token to allow transfer. function setMinHouseEdgeWithdrawAmount( address token, uint256 minHouseEdgeWithdrawAmount ) external onlyTokenOwner(DEFAULT_ADMIN_ROLE, token) { tokens[token].minHouseEdgeWithdrawAmount = minHouseEdgeWithdrawAmount; emit SetMinHouseEdgeWithdrawAmount(token, minHouseEdgeWithdrawAmount); } /// @notice Changes the token's partner address. /// It withdraw the available balance, the partner allocation, and the games' VRF fees. /// @param token Address of the token. /// @param partner Address of the partner. function setTokenPartner(address token, address partner) external onlyTokenOwner(DEFAULT_ADMIN_ROLE, token) { uint256 roleMemberCount = getRoleMemberCount(GAME_ROLE); for (uint256 i; i < roleMemberCount; i++) { IGame(getRoleMember(GAME_ROLE, i)).withdrawTokensVRFFees(token); } withdrawPartnerAmount(token); withdraw(token, getBalance(token)); tokens[token].partner = partner; emit SetTokenPartner(token, partner); } /// @notice Sets the token's house edge allocations for bet payout. /// @param token Address of the token. /// @param bank Rate to be allocated to the bank, on bet payout. /// @param dividend Rate to be allocated as staking rewards, on bet payout. /// @param partner Rate to be allocated to the partner, on bet payout. /// @param _treasury Rate to be allocated to the treasury, on bet payout. /// @param team Rate to be allocated to the team, on bet payout. /// @dev `bank`, `dividend`, `_treasury` and `team` rates sum must equals 10000. function setHouseEdgeSplit( address token, uint16 bank, uint16 dividend, uint16 partner, uint16 _treasury, uint16 team ) external onlyRole(DEFAULT_ADMIN_ROLE) { uint16 splitSum = bank + dividend + team + partner + _treasury; if (splitSum != 10000) { revert WrongHouseEdgeSplit(splitSum); } HouseEdgeSplit storage tokenHouseEdge = tokens[token].houseEdgeSplit; tokenHouseEdge.bank = bank; tokenHouseEdge.dividend = dividend; tokenHouseEdge.partner = partner; tokenHouseEdge.treasury = _treasury; tokenHouseEdge.team = team; emit SetTokenHouseEdgeSplit( token, bank, dividend, partner, _treasury, team ); } /// @notice Sets the minimum bet amount for a specific token. /// @param token Address of the token. /// @param tokenMinBetAmount Minimum bet amount. function setTokenMinBetAmount(address token, uint256 tokenMinBetAmount) external onlyTokenOwner(DEFAULT_ADMIN_ROLE, token) { tokens[token].minBetAmount = tokenMinBetAmount; emit SetTokenMinBetAmount(token, tokenMinBetAmount); } /// @notice Sets the Chainlink VRF subscription ID for a specific token. /// @param token Address of the token. /// @param subId Subscription ID. function setTokenVRFSubId(address token, uint64 subId) external onlyRole(DEFAULT_ADMIN_ROLE) { tokens[token].VRFSubId = subId; emit SetTokenVRFSubId(token, subId); } /// @notice Harvests tokens dividends. function harvestDividends() external onlyRole(HARVESTER_ROLE) { for (uint8 i; i < _tokensCount; i++) { address tokenAddress = _tokensList[i]; Token storage token = tokens[tokenAddress]; uint256 dividendAmount = token.houseEdgeSplit.dividendAmount; if (dividendAmount != 0) { delete token.houseEdgeSplit.dividendAmount; _safeTransfer(msg.sender, tokenAddress, dividendAmount); emit HarvestDividend(tokenAddress, dividendAmount); } } } /// @notice Splits the house edge fees and allocates them as dividends, to the partner, the bank, the treasury, and team. /// @param token Address of the token. /// @param fees Bet amount and bet profit fees amount. function _allocateHouseEdge(address token, uint256 fees) private { HouseEdgeSplit storage tokenHouseEdge = tokens[token].houseEdgeSplit; uint256 partnerAmount; if (tokenHouseEdge.partner != 0) { partnerAmount = ((fees * tokenHouseEdge.partner) / 10000); tokenHouseEdge.partnerAmount += partnerAmount; } uint256 dividendAmount = (fees * tokenHouseEdge.dividend) / 10000; tokenHouseEdge.dividendAmount += dividendAmount; // The bank also get allocated a share of the house edge. uint256 bankAmount = (fees * tokenHouseEdge.bank) / 10000; uint256 treasuryAmount = (fees * tokenHouseEdge.treasury) / 10000; tokenHouseEdge.treasuryAmount += treasuryAmount; uint256 teamAmount = (fees * tokenHouseEdge.team) / 10000; tokenHouseEdge.teamAmount += teamAmount; emit AllocateHouseEdgeAmount( token, bankAmount, dividendAmount, partnerAmount, treasuryAmount, teamAmount ); } /// @notice Payouts a winning bet, and allocate the house edge fee. /// @param user Address of the gamer. /// @param token Address of the token. /// @param profit Number of tokens to be sent to the gamer. /// @param fees Bet amount and bet profit fees amount. function payout( address user, address token, uint256 profit, uint256 fees ) external payable onlyRole(GAME_ROLE) { _allocateHouseEdge(token, fees); // Pay the user _safeTransfer(user, token, profit); emit Payout(token, getBalance(token), profit); } /// @notice Accounts a loss bet. /// @dev In case of an ERC20, the bet amount should be transfered prior to this tx. /// @dev In case of the gas token, the bet amount is sent along with this tx. /// @param tokenAddress Address of the token. /// @param amount Loss bet amount. /// @param fees Bet amount and bet profit fees amount. function cashIn( address tokenAddress, uint256 amount, uint256 fees ) external payable onlyRole(GAME_ROLE) { if (fees != 0) { _allocateHouseEdge(tokenAddress, fees); } emit CashIn(tokenAddress, getBalance(tokenAddress), amount); } /// @notice Executed by Chainlink Keepers when `upkeepNeeded` is true. /// @param performData Data which was passed back from `checkUpkeep`. function performUpkeep(bytes calldata performData) external override { (UpkeepActions upkeepAction, address tokenAddress) = abi.decode( performData, (UpkeepActions, address) ); Token memory token = tokens[tokenAddress]; if ( upkeepAction == UpkeepActions.DistributePartnerHouseEdge && token.houseEdgeSplit.partnerAmount > token.minHouseEdgeWithdrawAmount ) { withdrawPartnerAmount(tokenAddress); } else if ( upkeepAction == UpkeepActions.DistributeOwnHouseEdge && token.houseEdgeSplit.treasuryAmount + token.houseEdgeSplit.teamAmount > token.minHouseEdgeWithdrawAmount ) { withdrawHouseEdgeAmount(tokenAddress); } } /// @dev For the front-end function getTokens() external view returns (TokenMetadata[] memory) { TokenMetadata[] memory _tokens = new TokenMetadata[](_tokensCount); for (uint8 i; i < _tokensCount; i++) { address tokenAddress = _tokensList[i]; Token memory token = tokens[tokenAddress]; if (_isGasToken(tokenAddress)) { _tokens[i] = TokenMetadata({ decimals: 18, tokenAddress: tokenAddress, name: "ETH", symbol: "ETH", token: token }); } else { IERC20Metadata erc20Metadata = IERC20Metadata(tokenAddress); _tokens[i] = TokenMetadata({ decimals: erc20Metadata.decimals(), tokenAddress: tokenAddress, name: erc20Metadata.name(), symbol: erc20Metadata.symbol(), token: token }); } } return _tokens; } /// @notice Gets the token's min bet amount. /// @param token Address of the token. /// @return minBetAmount Min bet amount. /// @dev The min bet amount should be at least 10000 cause of the `getMaxBetAmount` calculation. function getMinBetAmount(address token) external view returns (uint256 minBetAmount) { minBetAmount = tokens[token].minBetAmount; if (minBetAmount < 10000) { minBetAmount = 10000; } } /// @notice Calculates the max bet amount based on the token balance, the balance risk, and the game multiplier. /// @param token Address of the token. /// @param multiplier The bet amount leverage determines the user's profit amount. 10000 = 100% = no profit. /// @return Maximum bet amount for the token. /// @dev The multiplier should be at least 10000. function getMaxBetAmount(address token, uint256 multiplier) external view returns (uint256) { return (getBalance(token) * tokens[token].balanceRisk) / multiplier; } /// @notice Gets the token's allow status used on the games smart contracts. /// @param tokenAddress Address of the token. /// @return Whether the token is enabled for bets. function isAllowedToken(address tokenAddress) external view returns (bool) { Token memory token = tokens[tokenAddress]; return token.allowed && !token.paused; } /// @notice Runs by Chainlink Keepers at every block to determine if `performUpkeep` should be called. /// @param checkData Fixed and specified at Upkeep registration. /// @return upkeepNeeded Boolean that when True will trigger the on-chain performUpkeep call. /// @return performData Bytes that will be used as input parameter when calling performUpkeep. /// @dev `checkData` and `performData` are encoded with types (uint8, address). function checkUpkeep(bytes calldata checkData) external view override returns (bool upkeepNeeded, bytes memory performData) { (UpkeepActions upkeepAction, address tokenAddressData) = abi.decode( checkData, (UpkeepActions, address) ); Token memory token = tokens[tokenAddressData]; if ( (upkeepAction == UpkeepActions.DistributePartnerHouseEdge && token.houseEdgeSplit.partnerAmount > token.minHouseEdgeWithdrawAmount) || (upkeepAction == UpkeepActions.DistributeOwnHouseEdge && token.houseEdgeSplit.treasuryAmount + token.houseEdgeSplit.teamAmount > token.minHouseEdgeWithdrawAmount) ) { upkeepNeeded = true; performData = abi.encode(upkeepAction, tokenAddressData); } } /// @notice Gets the token's Chainlink VRF v2 Subscription ID. /// @param token Address of the token. /// @return Chainlink VRF v2 Subscription ID. function getVRFSubId(address token) external view returns (uint64) { return tokens[token].VRFSubId; } /// @notice Gets the token's owner. /// @param token Address of the token. /// @return Address of the owner. function getTokenOwner(address token) external view returns (address) { address partner = tokens[token].partner; if (partner == address(0)) { return getRoleMember(DEFAULT_ADMIN_ROLE, 0); } else { return partner; } } /// @notice Sets the new team wallet. /// @param _teamWallet The team wallet address. function setTeamWallet(address _teamWallet) public onlyRole(DEFAULT_ADMIN_ROLE) { if (_teamWallet == address(0)) { revert WrongAddress(); } teamWallet = _teamWallet; emit SetTeamWallet(teamWallet); } /// @notice Distributes the token's treasury and team allocations amounts. /// @param tokenAddress Address of the token. function withdrawHouseEdgeAmount(address tokenAddress) public { HouseEdgeSplit storage tokenHouseEdge = tokens[tokenAddress] .houseEdgeSplit; uint256 treasuryAmount = tokenHouseEdge.treasuryAmount; uint256 teamAmount = tokenHouseEdge.teamAmount; if (treasuryAmount != 0) { delete tokenHouseEdge.treasuryAmount; _safeTransfer(treasury, tokenAddress, treasuryAmount); } if (teamAmount != 0) { delete tokenHouseEdge.teamAmount; _safeTransfer(teamWallet, tokenAddress, teamAmount); } if (treasuryAmount != 0 || teamAmount != 0) { emit HouseEdgeDistribution( tokenAddress, treasuryAmount, teamAmount ); } } /// @notice Distributes the token's partner amount. /// @param tokenAddress Address of the token. function withdrawPartnerAmount(address tokenAddress) public { Token storage token = tokens[tokenAddress]; uint256 partnerAmount = token.houseEdgeSplit.partnerAmount; if (partnerAmount != 0 && token.partner != address(0)) { delete token.houseEdgeSplit.partnerAmount; _safeTransfer(token.partner, tokenAddress, partnerAmount); emit HouseEdgePartnerDistribution(tokenAddress, partnerAmount); } } /// @notice Gets the token's balance. /// The token's house edge allocation amounts are subtracted from the balance. /// @param token Address of the token. /// @return The amount of token available for profits. function getBalance(address token) public view returns (uint256) { uint256 balance; if (_isGasToken(token)) { balance = address(this).balance; } else { balance = IERC20(token).balanceOf(address(this)); } HouseEdgeSplit memory tokenHouseEdgeSplit = tokens[token] .houseEdgeSplit; return balance - tokenHouseEdgeSplit.dividendAmount - tokenHouseEdgeSplit.partnerAmount - tokenHouseEdgeSplit.treasuryAmount - tokenHouseEdgeSplit.teamAmount; } }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 80000 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"treasuryAddress","type":"address"},{"internalType":"address","name":"teamWalletAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"TokenExists","type":"error"},{"inputs":[],"name":"TokenHasPendingBets","type":"error"},{"inputs":[],"name":"TokenNotPaused","type":"error"},{"inputs":[],"name":"WrongAddress","type":"error"},{"inputs":[{"internalType":"uint16","name":"splitSum","type":"uint16"}],"name":"WrongHouseEdgeSplit","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"AddToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"bank","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dividend","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"partner","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"treasury","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"team","type":"uint256"}],"name":"AllocateHouseEdgeAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CashIn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"HarvestDividend","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"treasuryAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"teamAmount","type":"uint256"}],"name":"HouseEdgeDistribution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"partnerAmount","type":"uint256"}],"name":"HouseEdgePartnerDistribution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"}],"name":"Payout","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"SetAllowedToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint16","name":"balanceRisk","type":"uint16"}],"name":"SetBalanceRisk","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"minHouseEdgeWithdrawAmount","type":"uint256"}],"name":"SetMinHouseEdgeWithdrawAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"SetPausedToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"teamWallet","type":"address"}],"name":"SetTeamWallet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint16","name":"bank","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"dividend","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"partner","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"treasury","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"team","type":"uint16"}],"name":"SetTokenHouseEdgeSplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"minBetAmount","type":"uint256"}],"name":"SetTokenMinBetAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"partner","type":"address"}],"name":"SetTokenPartner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint64","name":"subId","type":"uint64"}],"name":"SetTokenVRFSubId","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GAME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HARVESTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"addToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"fees","type":"uint256"}],"name":"cashIn","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"checkData","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"multiplier","type":"uint256"}],"name":"getMaxBetAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getMinBetAmount","outputs":[{"internalType":"uint256","name":"minBetAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTokenOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokens","outputs":[{"components":[{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"components":[{"internalType":"bool","name":"allowed","type":"bool"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"uint16","name":"balanceRisk","type":"uint16"},{"internalType":"uint64","name":"VRFSubId","type":"uint64"},{"internalType":"address","name":"partner","type":"address"},{"internalType":"uint256","name":"minBetAmount","type":"uint256"},{"internalType":"uint256","name":"minHouseEdgeWithdrawAmount","type":"uint256"},{"components":[{"internalType":"uint16","name":"bank","type":"uint16"},{"internalType":"uint16","name":"dividend","type":"uint16"},{"internalType":"uint16","name":"partner","type":"uint16"},{"internalType":"uint16","name":"treasury","type":"uint16"},{"internalType":"uint16","name":"team","type":"uint16"},{"internalType":"uint256","name":"dividendAmount","type":"uint256"},{"internalType":"uint256","name":"partnerAmount","type":"uint256"},{"internalType":"uint256","name":"treasuryAmount","type":"uint256"},{"internalType":"uint256","name":"teamAmount","type":"uint256"}],"internalType":"struct Bank.HouseEdgeSplit","name":"houseEdgeSplit","type":"tuple"}],"internalType":"struct Bank.Token","name":"token","type":"tuple"}],"internalType":"struct Bank.TokenMetadata[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getVRFSubId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"harvestDividends","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"isAllowedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"profit","type":"uint256"},{"internalType":"uint256","name":"fees","type":"uint256"}],"name":"payout","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"performUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setAllowedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint16","name":"balanceRisk","type":"uint16"}],"name":"setBalanceRisk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint16","name":"bank","type":"uint16"},{"internalType":"uint16","name":"dividend","type":"uint16"},{"internalType":"uint16","name":"partner","type":"uint16"},{"internalType":"uint16","name":"_treasury","type":"uint16"},{"internalType":"uint16","name":"team","type":"uint16"}],"name":"setHouseEdgeSplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minHouseEdgeWithdrawAmount","type":"uint256"}],"name":"setMinHouseEdgeWithdrawAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"paused","type":"bool"}],"name":"setPausedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_teamWallet","type":"address"}],"name":"setTeamWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenMinBetAmount","type":"uint256"}],"name":"setTokenMinBetAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"partner","type":"address"}],"name":"setTokenPartner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint64","name":"subId","type":"uint64"}],"name":"setTokenVRFSubId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"teamWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokens","outputs":[{"internalType":"bool","name":"allowed","type":"bool"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"uint16","name":"balanceRisk","type":"uint16"},{"internalType":"uint64","name":"VRFSubId","type":"uint64"},{"internalType":"address","name":"partner","type":"address"},{"internalType":"uint256","name":"minBetAmount","type":"uint256"},{"internalType":"uint256","name":"minHouseEdgeWithdrawAmount","type":"uint256"},{"components":[{"internalType":"uint16","name":"bank","type":"uint16"},{"internalType":"uint16","name":"dividend","type":"uint16"},{"internalType":"uint16","name":"partner","type":"uint16"},{"internalType":"uint16","name":"treasury","type":"uint16"},{"internalType":"uint16","name":"team","type":"uint16"},{"internalType":"uint256","name":"dividendAmount","type":"uint256"},{"internalType":"uint256","name":"partnerAmount","type":"uint256"},{"internalType":"uint256","name":"treasuryAmount","type":"uint256"},{"internalType":"uint256","name":"teamAmount","type":"uint256"}],"internalType":"struct Bank.HouseEdgeSplit","name":"houseEdgeSplit","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"withdrawHouseEdgeAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"withdrawPartnerAmount","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b50604051620051043803806200510483398101604081905262000034916200050c565b6001600160a01b0382166200005c57604051630d23cf4160e11b815260040160405180910390fd5b6001600160a01b0382166080526200007660003362000089565b620000818162000099565b5050620006a4565b6200009582826200012e565b5050565b6000620000a68162000171565b6001600160a01b038216620000ce57604051630d23cf4160e11b815260040160405180910390fd5b60028054610100600160a81b0319166101006001600160a01b038581168202929092179283905560405192041681527fc6a5dd316fe9d0339f2769deab7e31f64c8f5b101ffd85dfc9a83dbeaf2e69da9060200160405180910390a15050565b6200014582826200018060201b62002caa1760201c565b60008281526001602090815260409091206200016c91839062002d9a62000220821b17901c565b505050565b6200017d813362000240565b50565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1662000095576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001dc3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600062000237836001600160a01b038416620002e4565b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1662000095576200028a816001600160a01b031660146200033660201b62002dbc1760201c565b620002a083602062002dbc62000336821b17811c565b604051602001620002b39291906200056a565b60408051601f198184030181529082905262461bcd60e51b8252620002db91600401620005e3565b60405180910390fd5b60008181526001830160205260408120546200032d575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200023a565b5060006200023a565b60606000620003478360026200062e565b6200035490600262000648565b6001600160401b038111156200036e576200036e6200065e565b6040519080825280601f01601f19166020018201604052801562000399576020820181803683370190505b509050600360fc1b81600081518110620003b757620003b762000674565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110620003e957620003e962000674565b60200101906001600160f81b031916908160001a90535060006200040f8460026200062e565b6200041c90600162000648565b90505b60018111156200049e576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811062000454576200045462000674565b1a60f81b8282815181106200046d576200046d62000674565b60200101906001600160f81b031916908160001a90535060049490941c9362000496816200068a565b90506200041f565b508315620002375760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401620002db565b80516001600160a01b03811681146200050757600080fd5b919050565b600080604083850312156200052057600080fd5b6200052b83620004ef565b91506200053b60208401620004ef565b90509250929050565b60005b838110156200056157818101518382015260200162000547565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351620005a481601785016020880162000544565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351620005d781602884016020880162000544565b01602801949350505050565b60208152600082518060208401526200060481604085016020870162000544565b601f01601f19169190910160400192915050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176200023a576200023a62000618565b808201808211156200023a576200023a62000618565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000816200069c576200069c62000618565b506000190190565b608051614a3d620006c76000396000818161057d0152610a9a0152614a3d6000f3fe6080604052600436106102c65760003560e01c8063802ad8fb11610179578063ca15c873116100d6578063dc17c9ca1161008a578063f6b2a2f111610064578063f6b2a2f114610994578063f743b84c146109b4578063f8b2cb4f146109d457600080fd5b8063dc17c9ca14610832578063e486033914610852578063f3fef3a31461097457600080fd5b8063d41b8c6f116100bb578063d41b8c6f146107df578063d48bfca7146107f2578063d547741f1461081257600080fd5b8063ca15c8731461079f578063cbe230c3146107bf57600080fd5b8063aa6ca8081161012d578063ac9650d811610112578063ac9650d814610732578063bc3ec3831461075f578063c437afde1461077f57600080fd5b8063aa6ca808146106dc578063ab400706146106fe57600080fd5b80639010d07c1161015e5780639010d07c1461065657806391d1485414610676578063a217fddf146106c757600080fd5b8063802ad8fb146106215780638aaa22841461063657600080fd5b806338c64d2f1161022757806359927044116101db57806363a560ec116101c057806363a560ec1461059f5780636dfa8e52146105d35780636e04ff0d146105f357600080fd5b8063599270441461051457806361d027b31461056b57600080fd5b80634585e33b1161020c5780634585e33b146104c157806347e7ef24146104e157806356f0406d146104f457600080fd5b806338c64d2f146104815780634297dcbe146104a157600080fd5b8063278b39de1161027e5780632ee99d3e116102635780632ee99d3e146104215780632f2ff15d1461044157806336568abe1461046157600080fd5b8063278b39de14610393578063279e3415146103b357600080fd5b80631525ff7d116102af5780631525ff7d146103225780631f61502314610342578063248a9ca31461035557600080fd5b806301ffc9a7146102cb5780630ae30cb014610300575b600080fd5b3480156102d757600080fd5b506102eb6102e6366004613de4565b6109f4565b60405190151581526020015b60405180910390f35b34801561030c57600080fd5b5061032061031b366004613e48565b610a50565b005b34801561032e57600080fd5b5061032061033d366004613e48565b610b61565b610320610350366004613e65565b610c3e565b34801561036157600080fd5b50610385610370366004613eab565b60009081526020819052604090206001015490565b6040519081526020016102f7565b34801561039f57600080fd5b506103856103ae366004613ec4565b610cdd565b3480156103bf57600080fd5b506104086103ce366004613e48565b73ffffffffffffffffffffffffffffffffffffffff16600090815260036020526040902054640100000000900467ffffffffffffffff1690565b60405167ffffffffffffffff90911681526020016102f7565b34801561042d57600080fd5b5061032061043c366004613f02565b610d33565b34801561044d57600080fd5b5061032061045c366004613f78565b610f21565b34801561046d57600080fd5b5061032061047c366004613f78565b610f4b565b34801561048d57600080fd5b5061032061049c366004613e48565b610ffe565b3480156104ad57600080fd5b506103206104bc366004613ec4565b6110f1565b3480156104cd57600080fd5b506103206104dc366004613fa8565b6111ed565b6103206104ef366004613ec4565b6113c3565b34801561050057600080fd5b5061032061050f36600461401a565b6114ef565b34801561052057600080fd5b5060025461054690610100900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102f7565b34801561057757600080fd5b506105467f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b506103857f3fc733b4d20d27a28452ddf0e9351aced28242fe03389a653cdb783955316b9b81565b3480156105df57600080fd5b506103206105ee36600461404f565b61161b565b3480156105ff57600080fd5b5061061361060e366004613fa8565b6116bb565b6040516102f79291906140f8565b34801561062d57600080fd5b506103206118aa565b34801561064257600080fd5b50610320610651366004614121565b6119a2565b34801561066257600080fd5b5061054661067136600461414f565b611a30565b34801561068257600080fd5b506102eb610691366004613f78565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156106d357600080fd5b50610385600081565b3480156106e857600080fd5b506106f1611a48565b6040516102f791906141e9565b34801561070a57600080fd5b506103857f6a64baf327d646d1bca72653e2a075d15fd6ac6d8cbd7f6ee03fc55875e0fa8881565b34801561073e57600080fd5b5061075261074d366004614350565b611eee565b6040516102f791906143b3565b34801561076b57600080fd5b5061032061077a366004614433565b611fe3565b34801561078b57600080fd5b5061032061079a366004614121565b61221c565b3480156107ab57600080fd5b506103856107ba366004613eab565b612344565b3480156107cb57600080fd5b506102eb6107da366004613e48565b61235b565b6103206107ed366004614461565b6124a4565b3480156107fe57600080fd5b5061032061080d366004613e48565b612533565b34801561081e57600080fd5b5061032061082d366004613f78565b61269f565b34801561083e57600080fd5b5061054661084d366004613e48565b6126c4565b34801561085e57600080fd5b5061096061086d366004613e48565b6003602081815260009283526040928390208054600182015460028301548651610120810188529584015461ffff80821688526201000080830482169789019790975264010000000080830482169989019990995266010000000000008204811660608901526801000000000000000090910481166080880152600485015460a0880152600585015460c0880152600685015460e08801526007909401546101008088019190915260ff8085169891850416969584049094169493830467ffffffffffffffff16936c0100000000000000000000000090930473ffffffffffffffffffffffffffffffffffffffff169288565b6040516102f7989796959493929190614496565b34801561098057600080fd5b5061032061098f366004613ec4565b61270f565b3480156109a057600080fd5b506103856109af366004613e48565b6129d4565b3480156109c057600080fd5b506103206109cf366004613ec4565b612a11565b3480156109e057600080fd5b506103856109ef366004613e48565b612b0d565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610a4a5750610a4a82612fff565b92915050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600360208190526040909120600681015460078201549190920191908115610ac05760006003840155610ac07f00000000000000000000000000000000000000000000000000000000000000008584613096565b8015610af65760006004840155600254610af690610100900473ffffffffffffffffffffffffffffffffffffffff168583613096565b81151580610b0357508015155b15610b5b57604080518381526020810183905273ffffffffffffffffffffffffffffffffffffffff8616917f0146f1701c23c89f761280798d36d6c4e3acb349438456f5da8f83a2f5dd8cdc91015b60405180910390a25b50505050565b6000610b6c816130dc565b73ffffffffffffffffffffffffffffffffffffffff8216610bb9576040517f1a479e8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffff0000000000000000000000000000000000000000ff1661010073ffffffffffffffffffffffffffffffffffffffff8581168202929092179283905560405192041681527fc6a5dd316fe9d0339f2769deab7e31f64c8f5b101ffd85dfc9a83dbeaf2e69da906020015b60405180910390a15050565b7f6a64baf327d646d1bca72653e2a075d15fd6ac6d8cbd7f6ee03fc55875e0fa88610c68816130dc565b610c7284836130e9565b610c7d858585613096565b8373ffffffffffffffffffffffffffffffffffffffff167f634235fcf5af0adbca1a405ec65f6f6c08f55e1f379c2c45cd10f23cb29e0e31610cbe86612b0d565b6040805191825260208201879052015b60405180910390a25050505050565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260036020526040812054829062010000900461ffff16610d1885612b0d565b610d229190614535565b610d2c919061454c565b9392505050565b6000610d3e816130dc565b6000838584610d4d898b614587565b610d579190614587565b610d619190614587565b610d6b9190614587565b90508061ffff1661271014610db7576040517f6104384400000000000000000000000000000000000000000000000000000000815261ffff821660048201526024015b60405180910390fd5b6000600360008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003019050878160000160006101000a81548161ffff021916908361ffff160217905550868160000160026101000a81548161ffff021916908361ffff160217905550858160000160046101000a81548161ffff021916908361ffff160217905550848160000160066101000a81548161ffff021916908361ffff160217905550838160000160086101000a81548161ffff021916908361ffff1602179055508873ffffffffffffffffffffffffffffffffffffffff167f87512489f5b5226512d8f1bfede20d9e809ff4042f028da79c833ed04baa83978989898989604051610f0e95949392919061ffff95861681529385166020850152918416604084015283166060830152909116608082015260a00190565b60405180910390a2505050505050505050565b600082815260208190526040902060010154610f3c816130dc565b610f4683836132ce565b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610ff0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610dae565b610ffa82826132f0565b5050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526003602052604090206005810154801580159061105d575081546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615155b15610f465760006005830155815461109c906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff168483613096565b8273ffffffffffffffffffffffffffffffffffffffff167f1aa0fc6b9bc54a055d93b640b2c7313e0bd2944482e0b6b5fec7048bbdaacd81826040516110e491815260200190565b60405180910390a2505050565b73ffffffffffffffffffffffffffffffffffffffff808316600090815260036020526040812054909184916c01000000000000000000000000900416806111415761113c8333613312565b611190565b3373ffffffffffffffffffffffffffffffffffffffff821614611190576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff851660008181526003602052604090819020600101869055517f8b4a07860448b613116df3f175c837980eceaca7d1dc5143c46a20ab31ec00f990610cce9087815260200190565b6000806111fc838501856145a2565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260036020818152604080842081516101008082018452825460ff80821615158452828204161515838701526201000080820461ffff9081168588015264010000000080840467ffffffffffffffff166060808801919091526c01000000000000000000000000909404909b16608080870191909152600187015460a080880191909152600288015460c080890191909152895161012081018b529b8901548085168d5294850484169a8c019a909a529b83048216978a0197909752660100000000000082048116928901929092526801000000000000000090041693860193909352600482015496850196909652600581015492840192909252600682015460e0808501919091526007909201549083015283015292945090925090836001811115611347576113476145c4565b14801561135f57508060c001518160e0015160c00151115b156113725761136d82610ffe565b6113bc565b6001836001811115611386576113866145c4565b1480156113ae575060c081015160e0808301516101008101519101516113ac91906145f3565b115b156113bc576113bc82610a50565b5050505050565b73ffffffffffffffffffffffffffffffffffffffff808316600090815260036020526040812054909184916c01000000000000000000000000900416806114135761140e8333613312565b611462565b3373ffffffffffffffffffffffffffffffffffffffff821614611462576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8516611485573493506114a7565b6114a773ffffffffffffffffffffffffffffffffffffffff86163330876133e2565b8473ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c85604051610cce91815260200190565b73ffffffffffffffffffffffffffffffffffffffff808316600090815260036020526040812054909184916c010000000000000000000000009004168061153f5761153a8333613312565b61158e565b3373ffffffffffffffffffffffffffffffffffffffff82161461158e576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff851660008181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff166201000061ffff8a169081029190911790915591519182527f68288b0936dd994d19323ee940b2703e7bf46fae2552319d60dc1239ba52ec689101610cce565b6000611626816130dc565b73ffffffffffffffffffffffffffffffffffffffff831660008181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffff1664010000000067ffffffffffffffff88169081029190911790915591519182527fae367543cf47ca7e51a9f3f92711553aa33777847f719f7e2821ea8d846ed0e191016110e4565b6000606081806116cd858701876145a2565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260036020818152604080842081516101008082018452825460ff80821615158452828204161515838701526201000080820461ffff9081168588015264010000000080840467ffffffffffffffff166060808801919091526c01000000000000000000000000909404909b16608080870191909152600187015460a080880191909152600288015460c080890191909152895161012081018b529b8901548085168d5294850484169a8c019a909a529b83048216978a0197909752660100000000000082048116928901929092526801000000000000000090041693860193909352600482015496850196909652600581015492840192909252600682015460e0808501919091526007909201549083015283015292945090925090836001811115611818576118186145c4565b14801561183057508060c001518160e0015160c00151115b806118725750600183600181111561184a5761184a6145c4565b148015611872575060c081015160e08083015161010081015191015161187091906145f3565b115b156118a05760019450828260405160200161188e929190614606565b60405160208183030381529060405293505b5050509250929050565b7f3fc733b4d20d27a28452ddf0e9351aced28242fe03389a653cdb783955316b9b6118d4816130dc565b60005b60025460ff9081169082161015610ffa5760ff811660009081526004602081815260408084205473ffffffffffffffffffffffffffffffffffffffff16808552600390925290922090810154801561198c576000600483015561193b338483613096565b8273ffffffffffffffffffffffffffffffffffffffff167fca64dbcaf91abfb066e7a5163f1d135f8f48f2cbdb0395e3b35cc278ebbd340b8260405161198391815260200190565b60405180910390a25b505050808061199a90614666565b9150506118d7565b60006119ad816130dc565b73ffffffffffffffffffffffffffffffffffffffff831660008181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527fe589eb036e62c07e307aa4d441bd39c81e8bd86f349eaacb0caa06b1477f7f9a91016110e4565b6000828152600160205260408120610d2c90836134be565b60025460609060009060ff1667ffffffffffffffff811115611a6c57611a6c614685565b604051908082528060200260200182016040528015611aa557816020015b611a92613d1a565b815260200190600190039081611a8a5790505b50905060005b60025460ff9081169082161015611ee85760ff81811660009081526004602081815260408084205473ffffffffffffffffffffffffffffffffffffffff908116808652600380855295839020835161010080820186528254808b1615158352818104909a1615158288015262010000808b0461ffff90811684890152640100000000808d0467ffffffffffffffff166060808701919091526c01000000000000000000000000909d04909716608080860191909152600186015460a080870191909152600287015460c0808801919091528a5161012081018c529d8801548085168f5294850484169b8e019b909b529783048216988c01989098526601000000000000820481169b8b019b909b52680100000000000000009004909916948801949094529485015491860191909152600584015492850192909252600683015460e08086019190915260079093015494840194909452908301919091529081611cde576040518060a00160405280601260ff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020016040518060400160405280600381526020017f455448000000000000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600381526020017f4554480000000000000000000000000000000000000000000000000000000000815250815260200182815250848460ff1681518110611cce57611cce6146b4565b6020026020010181905250611ed3565b60008290506040518060a001604052808273ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d5d91906146e3565b60ff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015611dcc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611e129190810190614706565b81526020018273ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015611e62573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611ea89190810190614706565b815260200183815250858560ff1681518110611ec657611ec66146b4565b6020026020010181905250505b50508080611ee090614666565b915050611aab565b50919050565b60608167ffffffffffffffff811115611f0957611f09614685565b604051908082528060200260200182016040528015611f3c57816020015b6060815260200190600190039081611f275790505b50905060005b82811015611fdc57611fac30858584818110611f6057611f606146b4565b9050602002810190611f7291906147c6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506134ca92505050565b828281518110611fbe57611fbe6146b4565b60200260200101819052508080611fd490614832565b915050611f42565b5092915050565b73ffffffffffffffffffffffffffffffffffffffff808316600090815260036020526040812054909184916c01000000000000000000000000900416806120335761202e8333613312565b612082565b3373ffffffffffffffffffffffffffffffffffffffff821614612082576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006120ad7f6a64baf327d646d1bca72653e2a075d15fd6ac6d8cbd7f6ee03fc55875e0fa88612344565b905060005b8181101561217a576120e47f6a64baf327d646d1bca72653e2a075d15fd6ac6d8cbd7f6ee03fc55875e0fa8882611a30565b6040517f707cd55e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8981166004830152919091169063707cd55e90602401600060405180830381600087803b15801561214f57600080fd5b505af1158015612163573d6000803e3d6000fd5b50505050808061217290614832565b9150506120b2565b5061218486610ffe565b6121918661098f88612b0d565b73ffffffffffffffffffffffffffffffffffffffff86811660008181526003602090815260409182902080546bffffffffffffffffffffffff166c01000000000000000000000000958b16958602179055905192835290917fc991529379552af6d0789cc899d5180a270a4bc3b1a3892adcac3d95f93dda1d910160405180910390a2505050505050565b73ffffffffffffffffffffffffffffffffffffffff808316600090815260036020526040812054909184916c010000000000000000000000009004168061226c576122678333613312565b6122bb565b3373ffffffffffffffffffffffffffffffffffffffff8216146122bb576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8516600081815260036020526040908190208054871515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116179055517f624dd6809915867c3c11279c2699633040681f0e4efb0fa9a193217a11903c6090610cce90871515815260200190565b6000818152600160205260408120610a4a906134ef565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260036020818152604080842081516101008082018452825460ff80821615158452828204161515838701526201000080820461ffff9081168588015264010000000080840467ffffffffffffffff166060808801919091526c01000000000000000000000000909404909b16608080870191909152600187015460a080880191909152600288015460c080890191909152895161012081018b529b8901548085168d5294850484169a8c019a909a529b83048216978a0197909752660100000000000082048116928901929092526801000000000000000090041693860193909352600482015496850196909652600581015492840192909252600682015460e0808501919091526007909201549083015283015281519091908015610d2c5750602001511592915050565b7f6a64baf327d646d1bca72653e2a075d15fd6ac6d8cbd7f6ee03fc55875e0fa886124ce816130dc565b81156124de576124de84836130e9565b8373ffffffffffffffffffffffffffffffffffffffff167f812b76b477469edc716929cbf7ed54e3d9c1a68d8b9f8290dbabcda54d96fcbe61251f86612b0d565b604080519182526020820187905201610b52565b600061253e816130dc565b60025460ff16156125d55760005b60025460ff90811690821610156125d35760ff811660009081526004602052604090205473ffffffffffffffffffffffffffffffffffffffff8085169116036125c1576040517f55c7e8ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806125cb81614666565b91505061254c565b505b6002805460ff908116600090815260046020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905582546001939261263c9185911661486a565b92506101000a81548160ff021916908360ff1602179055507fe473c74f34be27c1464d6624f14a0d7fd4e301cbfa29c3eba425d378c8a7ebe082604051610c32919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6000828152602081905260409020600101546126ba816130dc565b610f4683836132f0565b73ffffffffffffffffffffffffffffffffffffffff80821660009081526003602052604081205490916c010000000000000000000000009091041680610a4a57610d2c600080611a30565b73ffffffffffffffffffffffffffffffffffffffff808316600090815260036020526040812054909184916c010000000000000000000000009004168061275f5761275a8333613312565b6127ae565b3373ffffffffffffffffffffffffffffffffffffffff8216146127ae576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006127b986612b0d565b905080156129cc5773ffffffffffffffffffffffffffffffffffffffff8616600090815260036020526040902054610100900460ff16612825576040517f93b3a85d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006128507f6a64baf327d646d1bca72653e2a075d15fd6ac6d8cbd7f6ee03fc55875e0fa88612344565b905060005b81811015612962576128877f6a64baf327d646d1bca72653e2a075d15fd6ac6d8cbd7f6ee03fc55875e0fa8882611a30565b6040517f594043fd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152919091169063594043fd90602401602060405180830381865afa1580156128f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129199190614883565b15612950576040517faa4256e000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061295a81614832565b915050612855565b508186111561296f578195505b61297a338888613096565b8673ffffffffffffffffffffffffffffffffffffffff167f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364876040516129c291815260200190565b60405180910390a2505b505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040902060010154612710811015612a0c57506127105b919050565b73ffffffffffffffffffffffffffffffffffffffff808316600090815260036020526040812054909184916c0100000000000000000000000090041680612a6157612a5c8333613312565b612ab0565b3373ffffffffffffffffffffffffffffffffffffffff821614612ab0576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff851660008181526003602052604090819020600201869055517f2c799d8bd0ce047a73ee6661740b3e780a2a13dd04c1201fca543f181bdff5ff90610cce9087815260200190565b60008073ffffffffffffffffffffffffffffffffffffffff8316612b32575047612bc3565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015612b9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc091906148a0565b90505b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360208181526040928390208351610120810185529281015461ffff80821685526201000082048116938501939093526401000000008104831694840194909452660100000000000084048216606084015268010000000000000000909304166080820152600482015460a08201819052600583015460c08301819052600684015460e084018190526007909401546101008401819052929391612c8490866148b9565b612c8e91906148b9565b612c9891906148b9565b612ca291906148b9565b949350505050565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610ffa5760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612d3c3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610d2c8373ffffffffffffffffffffffffffffffffffffffff84166134f9565b60606000612dcb836002614535565b612dd69060026145f3565b67ffffffffffffffff811115612dee57612dee614685565b6040519080825280601f01601f191660200182016040528015612e18576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612e4f57612e4f6146b4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612eb257612eb26146b4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000612eee846002614535565b612ef99060016145f3565b90505b6001811115612f96577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110612f3a57612f3a6146b4565b1a60f81b828281518110612f5057612f506146b4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93612f8f816148cc565b9050612efc565b508315610d2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610dae565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610a4a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610a4a565b73ffffffffffffffffffffffffffffffffffffffff82166130bb57610f468382613548565b610f4673ffffffffffffffffffffffffffffffffffffffff831684836136a2565b6130e68133613312565b50565b73ffffffffffffffffffffffffffffffffffffffff821660009081526003602081905260408220018054909190640100000000900461ffff16156131695781546127109061314390640100000000900461ffff1685614535565b61314d919061454c565b90508082600201600082825461316391906145f3565b90915550505b8154600090612710906131869062010000900461ffff1686614535565b613190919061454c565b9050808360010160008282546131a691906145f3565b90915550508254600090612710906131c29061ffff1687614535565b6131cc919061454c565b8454909150600090612710906131f0906601000000000000900461ffff1688614535565b6131fa919061454c565b90508085600301600082825461321091906145f3565b90915550508454600090612710906132389068010000000000000000900461ffff1689614535565b613242919061454c565b90508086600401600082825461325891906145f3565b90915550506040805184815260208101869052908101869052606081018390526080810182905273ffffffffffffffffffffffffffffffffffffffff8916907fc73e6f5bcd4395126567ead7e4c14b7c52a5f0b9eabd3335a05e631646a127e39060a00160405180910390a25050505050505050565b6132d88282612caa565b6000828152600160205260409020610f469082612d9a565b6132fa82826136f8565b6000828152600160205260409020610f4690826137af565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610ffa576133688173ffffffffffffffffffffffffffffffffffffffff166014612dbc565b613373836020612dbc565b604051602001613384929190614901565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610dae91600401614982565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610b5b9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526137d1565b6000610d2c83836138dd565b6060610d2c83836040518060600160405280602781526020016149e160279139613907565b6000610a4a825490565b600081815260018301602052604081205461354057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610a4a565b506000610a4a565b804710156135b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610dae565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461360c576040519150601f19603f3d011682016040523d82523d6000602084013e613611565b606091505b5050905080610f46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610dae565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610f469084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161343c565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610ffa5760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610d2c8373ffffffffffffffffffffffffffffffffffffffff8416613a2f565b6000613833826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613b229092919063ffffffff16565b805190915015610f4657808060200190518101906138519190614883565b610f46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610dae565b60008260000182815481106138f4576138f46146b4565b9060005260206000200154905092915050565b606073ffffffffffffffffffffffffffffffffffffffff84163b6139ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610dae565b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516139d59190614995565b600060405180830381855af49150503d8060008114613a10576040519150601f19603f3d011682016040523d82523d6000602084013e613a15565b606091505b5091509150613a25828286613b31565b9695505050505050565b60008181526001830160205260408120548015613b18576000613a536001836148b9565b8554909150600090613a67906001906148b9565b9050818114613acc576000866000018281548110613a8757613a876146b4565b9060005260206000200154905080876000018481548110613aaa57613aaa6146b4565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613add57613add6149b1565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610a4a565b6000915050610a4a565b6060612ca28484600085613b84565b60608315613b40575081610d2c565b825115613b505782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dae9190614982565b606082471015613c16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610dae565b73ffffffffffffffffffffffffffffffffffffffff85163b613c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610dae565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051613cbd9190614995565b60006040518083038185875af1925050503d8060008114613cfa576040519150601f19603f3d011682016040523d82523d6000602084013e613cff565b606091505b5091509150613d0f828286613b31565b979650505050505050565b6040518060a00160405280600060ff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016060815260200160608152602001613ddf604080516101008082018352600080835260208084018290528385018290526060808501839052608080860184905260a080870185905260c0808801869052885161012081018a528681529485018690529784018590529183018490528201839052810182905293840181905260e08481018290529184015290919082015290565b905290565b600060208284031215613df657600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610d2c57600080fd5b73ffffffffffffffffffffffffffffffffffffffff811681146130e657600080fd5b600060208284031215613e5a57600080fd5b8135610d2c81613e26565b60008060008060808587031215613e7b57600080fd5b8435613e8681613e26565b93506020850135613e9681613e26565b93969395505050506040820135916060013590565b600060208284031215613ebd57600080fd5b5035919050565b60008060408385031215613ed757600080fd5b8235613ee281613e26565b946020939093013593505050565b803561ffff81168114612a0c57600080fd5b60008060008060008060c08789031215613f1b57600080fd5b8635613f2681613e26565b9550613f3460208801613ef0565b9450613f4260408801613ef0565b9350613f5060608801613ef0565b9250613f5e60808801613ef0565b9150613f6c60a08801613ef0565b90509295509295509295565b60008060408385031215613f8b57600080fd5b823591506020830135613f9d81613e26565b809150509250929050565b60008060208385031215613fbb57600080fd5b823567ffffffffffffffff80821115613fd357600080fd5b818501915085601f830112613fe757600080fd5b813581811115613ff657600080fd5b86602082850101111561400857600080fd5b60209290920196919550909350505050565b6000806040838503121561402d57600080fd5b823561403881613e26565b915061404660208401613ef0565b90509250929050565b6000806040838503121561406257600080fd5b823561406d81613e26565b9150602083013567ffffffffffffffff81168114613f9d57600080fd5b60005b838110156140a557818101518382015260200161408d565b50506000910152565b600081518084526140c681602086016020860161408a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8215158152604060208201526000612ca260408301846140ae565b80151581146130e657600080fd5b6000806040838503121561413457600080fd5b823561413f81613e26565b91506020830135613f9d81614113565b6000806040838503121561416257600080fd5b50508035926020909101359150565b61ffff8082511683528060208301511660208401528060408301511660408401525060608101516141a8606084018261ffff169052565b5060808101516141be608084018261ffff169052565b5060a0818101519083015260c0808201519083015260e0808201519083015261010090810151910152565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015614342577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0898403018552815161028060ff825116855273ffffffffffffffffffffffffffffffffffffffff89830151168986015287820151818987015261427e828701826140ae565b9150506060808301518683038288015261429883826140ae565b925050608080840151935083511515818801528a84015160a0811515818a01528b860151915060c061ffff8316818b015284870151945060e092506142e8838b018667ffffffffffffffff169052565b9286015173ffffffffffffffffffffffffffffffffffffffff166101008a01528501516101208901529084015161014088015290920151915061432f610160860183614171565b9588019593505090860190600101614210565b509098975050505050505050565b6000806020838503121561436357600080fd5b823567ffffffffffffffff8082111561437b57600080fd5b818501915085601f83011261438f57600080fd5b81358181111561439e57600080fd5b8660208260051b850101111561400857600080fd5b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614426577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526144148583516140ae565b945092850192908501906001016143da565b5092979650505050505050565b6000806040838503121561444657600080fd5b823561445181613e26565b91506020830135613f9d81613e26565b60008060006060848603121561447657600080fd5b833561448181613e26565b95602085013595506040909401359392505050565b8815158152871515602082015261ffff8716604082015267ffffffffffffffff8616606082015273ffffffffffffffffffffffffffffffffffffffff8516608082015260a0810184905260c0810183905261020081016144f960e0830184614171565b9998505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610a4a57610a4a614506565b600082614582577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b61ffff818116838216019080821115611fdc57611fdc614506565b600080604083850312156145b557600080fd5b82356002811061445157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80820180821115610a4a57610a4a614506565b6040810160028410614641577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b92815273ffffffffffffffffffffffffffffffffffffffff9190911660209091015290565b600060ff821660ff810361467c5761467c614506565b60010192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156146f557600080fd5b815160ff81168114610d2c57600080fd5b60006020828403121561471857600080fd5b815167ffffffffffffffff8082111561473057600080fd5b818401915084601f83011261474457600080fd5b81518181111561475657614756614685565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561479c5761479c614685565b816040528281528760208487010111156147b557600080fd5b613d0f83602083016020880161408a565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126147fb57600080fd5b83018035915067ffffffffffffffff82111561481657600080fd5b60200191503681900382131561482b57600080fd5b9250929050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361486357614863614506565b5060010190565b60ff8181168382160190811115610a4a57610a4a614506565b60006020828403121561489557600080fd5b8151610d2c81614113565b6000602082840312156148b257600080fd5b5051919050565b81810381811115610a4a57610a4a614506565b6000816148db576148db614506565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161493981601785016020880161408a565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161497681602884016020880161408a565b01602801949350505050565b602081526000610d2c60208301846140ae565b600082516149a781846020870161408a565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212201cfe55b2a6ba42c2ec85ef4123f28d948622a1fed316f34ba36d711ab5cf42c264736f6c63430008110033000000000000000000000000fa695010bf9e757a1abcd2703259f419217aa756000000000000000000000000fdef3197980fb992ced40f5e0548725e2ab52b43
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000fa695010bf9e757a1abcd2703259f419217aa756000000000000000000000000fdef3197980fb992ced40f5e0548725e2ab52b43
-----Decoded View---------------
Arg [0] : treasuryAddress (address): 0xfa695010bf9e757a1abcd2703259f419217aa756
Arg [1] : teamWalletAddress (address): 0xfdef3197980fb992ced40f5e0548725e2ab52b43
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000fa695010bf9e757a1abcd2703259f419217aa756
Arg [1] : 000000000000000000000000fdef3197980fb992ced40f5e0548725e2ab52b43
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.