Token Triple Confirmation Community
Overview ERC20
Price
$0.00 @ 0.000000 AVAX
Fully Diluted Market Cap
Total Supply:
1,420,069,000 TCC
Holders:
13 addresses
Transfers:
-
Contract:
Decimals:
6
[ Download CSV Export ]
[ Download CSV Export ]
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Source Code Verified (Exact Match)
Contract Name:
TCC
Compiler Version
v0.8.19+commit.7dd6d404
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2023-04-22 */ // SPDX-License-Identifier: WTFPL // = = = = = = = = = = = = = = = = = // // // // Written by Triple Confirmation // // // // 20 April 2023 // // = = = = = = = = = = = = = = = = = // pragma solidity ^0.8.19; /** * @dev OpenZeppelin's IERC20 interface with `value` -> `amount` */ interface IERC20 { // ### VIEW FUNCTIONS ### function name() external view returns (string memory name); function symbol() external view returns (string memory symbol); function decimals() external view returns (uint8 decimals); function totalSupply() external view returns (uint totalSupply); // ### CONTRACT INTERACTIONS ### /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint balance); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint amount) external returns (bool success); /** * @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 (uint allowance); /** * @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, uint amount) external returns (bool success); /** * @dev Moves `amount` tokens from `sender` to `recipient` 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, uint amount) external returns (bool success); // ### EVENTS ### /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `amount` may be zero. */ event Transfer(address indexed from, address indexed to, uint amount); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `amount` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint amount); } /** * @dev * File level variables are compiled into the contract as constant uints. * This method of variable management helps to reduce bytecode size while * reducing the likelihood of mistakes. Rather than writing out the exact * index or static numbers, we opt for referencing these file level constants * thereby making any adjustments immediate and ubiquitous across the entire * contract code. Having a central registry for constant numbers ensures * consistency across the codebase and is therefore good code management. */ /** * @dev Indices related to `allowances` and the `approve()` system. */ uint8 constant lenAMem = 4; // needs to include `aTimeRemaining` uint8 constant lenAStor = 3; uint8 constant aAllowance = 0; uint8 constant aTimestamp = 1; uint8 constant aPerpetual = 2; uint8 constant aTimeRemaining = 3; /** * @dev * All `uint8 constant` variables below at the file level are index identifiers * allowing certain variables to be grouped together in arrays for easier * storage, recall, mutability, and recursion. */ uint8 constant rAmount = 0; uint8 constant rAccountsToRain = 1; /** * @dev Indices related to the `delegationMem` pseudo-struct mapping. */ uint8 constant lenDelegationMem = 4; uint8 constant encodedDelegation = 0; uint8 constant startIndex = 1; uint8 constant total = 2; uint8 constant excluded = 3; /** * @dev * Indices related to recall of `bytes32` encodes of * supported Delegation `functionName`s given by a * user to identify the function delegated. */ uint8 constant lenDelegates = 5; uint8 constant dFuncSetId = 0; uint8 constant dFuncTransferMultiple = 1; uint8 constant dFuncRain = 2; uint8 constant dFuncRainList = 3; uint8 constant dFuncRainAll = 4; /** * @dev Indices related to the `errors` array of `string`s. */ uint8 constant lenErrors = 34; uint8 constant errSymbol = 0; uint8 constant errAdminAuth = 1; uint8 constant errTreasuryAdminAuth = 2; uint8 constant errGuardianTreasuryAdminAuth = 3; uint8 constant errInsufficientBalance = 4; uint8 constant errTransferContract = 5; uint8 constant errInsufficientAllowance = 6; uint8 constant errTransferMultiple = 7; uint8 constant errList = 8; uint8 constant errDelegateSetId = 9; uint8 constant errSetId = 10; uint8 constant errSetIdProtected = 11; uint8 constant errSetAdmin0 = 12; uint8 constant errSetAdmin1 = 13; uint8 constant errSetTreasury0 = 14; uint8 constant errSetTreasury1 = 15; uint8 constant errSetGasPerLoop = 16; uint8 constant errSetGasValues = 17; uint8 constant errSetBreakAtGasThres = 18; uint8 constant errSetRainMinBalance = 19; uint8 constant errPermit0 = 20; uint8 constant errPermitDeadline = 21; uint8 constant errPermitBadSig = 22; uint8 constant errGasPerLoopHeader = 23; uint8 constant errGasPerLoop = 24; uint8 constant errRainAmounts = 25; uint8 constant errRainNumAccounts = 26; uint8 constant errRunMyDelegation = 27; uint8 constant errAuthMyDelegation = 28; uint8 constant errDelegationDoesntMatch = 29; uint8 constant errInvalidDelegation = 30; uint8 constant errClaimERC20 = 31; uint8 constant errDecreaseAllowance = 32; uint8 constant errSetAllowanceTimeToLive = 33; /** * @dev * `__denominator` is copied to `denominator` in the TokenBase. * We opted to hardcode the `decimals` as 10 ** 6 to allow for * use in assembly{} operations. */ uint constant __denominator = 1000000; uint constant __denominatorBy10 = __denominator / 10; uint constant __maxRainThreshold = 4200690000; uint constant __minSecsAllowanceTimeToLive = 30; string constant __strPeriod = "."; string constant __strZero = "0"; /** * @notice * Disconnected library for deployment in a Web3xx VM such as in the * Remix IDE to allow us to easily harvest a array of error * strings to copy into TokenBase via repeated `setError()` executions. * This methodology doesn't import bytecode on construction and saves * an immense amount of bytecode compared to including the errors in * the TokenBase contract itself. */ abstract contract TokenBaseUtils { // ### UTILITY FUNCTIONS ### function _isContract(address _account) internal view returns (bool) { /** * @dev * According to EIP-1052, 0x0 is the value returned * for not-yet-created accounts and * 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 * is returned for accounts without code such as `keccak256('')`. */ bytes32 _codehash; bytes32 _accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; assembly { _codehash := extcodehash(_account) } /** * @dev * Return true if the `_account` in question has both: * # Been created, AND * # Is an address with bytecode. */ return _codehash != _accountHash && _codehash != 0x0; } /** * @return -> Raw number without consideration to decimal places. */ function __uintToString( uint __value ) internal pure returns ( string memory ) { // Save gas and return a constant string of "0" if the `_value` == 0. if (__value == 0) { return __strZero; } uint __temp = __value; uint __digits; while (__temp != 0) { ++__digits; __temp /= 10; } bytes memory __buffer = new bytes(__digits); while (__value != 0) { __buffer[--__digits] = bytes1(uint8(48 + uint(__value % 10))); __value /= 10; } return string(__buffer); } /** * @notice * `_divisor` is safely set to 1 if 0 is given in order to avoid * division-by-0 errors. Division by 1 is highly likely to * be the desired outcome since that simply returns the same * number as before the division operation. `divisor`s other * than 0 can be returned as-is without change since we only * need to protect against returning a 0 `_divisor`. Less than 0 * `_divisor`s are impossible to return since `uint`s are * by definition always 0 or positive. */ function _safeDivision(uint _divisor) internal pure returns (uint) { if (_divisor == 0) { return 1; } return _divisor; } /** * @dev Converts a `uint` to its ASCII `string` decimal representation. * @param _value -> Any number which the user desires to convert into `string`. * @return -> Nicely formatted string output WITH decimal places. */ function _uintToString( uint _value ) internal pure returns ( string memory ) { // Save gas and return a constant string of "0" if the `_value` == 0. if (_value == 0) { return __strZero; } /** * @dev * We need to use assembly to achieve a proper, * non-overflowing modulo. */ uint _decimalToShow; assembly { _decimalToShow := mod(_value, __denominator) } /** * @dev * Next generate the decimals string, * fixed to the number of `decimalToShow`. */ string memory _strDecimals = __uintToString(_decimalToShow); /** * @dev * Continue adding padded 0's to the beginning of the `strDecimals` * until the desired number of `decimalsToShow` is achieved. * If we didn't do this, then an expected output of * 1234.0056 would be outputted as 1234.56. */ if (_decimalToShow > 0) { for (; _decimalToShow < __denominatorBy10; _decimalToShow *= 10) { _strDecimals = string.concat(__strZero, _strDecimals); } } // Before returning, assemble the string. return string.concat( __uintToString(_value / __denominator), __strPeriod, _strDecimals ); } } /** * @dev * Got a strange error message from Etherscan about this being imported * when it's very clearly not. This library definitely isn't included * in TokenBase but is derivative and very much related, hence why * it's included in this source file. We'll leave uncommented for now * and simply re-comment if Snowtrace/Etherscan refuses to compile * and verify the bytecode after mainnet deployment. */ contract TokenBaseErrors is TokenBaseUtils { /** * @return _errors -> Formatted for recursively passing into `setError()`. * @dev Throw into Remix IDE to copy-paste the generated Errors. */ function generateErrors( string calldata _symbol ) external pure returns ( string[lenErrors] memory _errors ) { string memory __symbol = string.concat(" ", _symbol, "."); _errors = [ "", "AUTH: Sender must be the Admin Wallet.", "AUTH: Sender must be either the Treasury Wallet or the Admin Wallet.", "AUTH: Sender must be the Guardian Wallet, the Treasury Wallet, or the Admin Wallet.", "TRANSFER: Insufficient balance: ", "TRANSFER: Use `transferFrom()` to transfer tokens to a smart contract.", "TRANSFER-FROM: Insufficient `approve()` amount remaining: ", "TRANSFER-MULTIPLE: Count of recipients and amounts must be identical.", "LIST: First index cannot be greater than the last index.", "DELEGATE SET-ID: Count of recipients and amounts must be identical.", "SET: `id` disallowed for `account`.", "SET: `id` is protected.", "SET: New Admin Wallet cannot be set to a null address.", "SET: New Admin Wallet cannot be the same as the current one.", "SET: New Treasury Wallet cannot be set to a null address.", "SET: New Treasury Wallet cannot be the same as the current one.", "SET: `gasPerLoop` cannot be greater than 1/20 the `block.gaslimit`.", "SET: `breakAtGasThreshold` must be a greater value than `gasPerLoop`.", "SET: `breakAtGasThreshold` cannot be greater than 1/4 the `block.gaslimit`.", string.concat( "SET: Maximum possible value of ", _uintToString(__maxRainThreshold), __symbol ), "PERMIT ERROR: The 0 address cannot permit others.", "PERMIT ERROR: Expired deadline.", "PERMIT ERROR: Invalid signature.", "GAS: Submit with ", "", "RAIN: Invalid `amounts` provided.", "RAIN: Must rain on at least 1 account.", "DELEGATION: Null address are disallowed from execution.", "DELEGATION: You're not the delegate or owner.", "DELEGATION: No match found.", "DELEGATION: Unsupported function.", "CLAIM ERC-20: Failed transfer.", "DECREASE ALLOWANCE: Amount to deduct is greater than existing `approve()` amount: ", string.concat( "APPROVE DEADLINE: Minimum possible value is ", __uintToString(__minSecsAllowanceTimeToLive), " seconds. ", "Maximum possible value is 2^248." ) ]; for (uint8 i; i < lenErrors; ++i) { _errors[i] = string.concat(_symbol, " | ", _errors[i]); } // Two exceptions in the list. _errors[errSymbol] = __symbol; delete _errors[errGasPerLoop]; return _errors; } } /** * @notice * Everything in this comment box is related to generating the * error `string`s for saving during token deployment. * * @devnote * Outputted `_errors` array ready for use in TokenBase's `constructor()`. [ " TC.", "TC | AUTH: Sender must be the Admin Wallet.", "TC | AUTH: Sender must be either the Treasury Wallet or the Admin Wallet.", "TC | AUTH: Sender must be the Guardian Wallet, the Treasury Wallet, or the Admin Wallet.", "TC | TRANSFER: Insufficient balance: ", "TC | TRANSFER: Use `transferFrom()` to transfer tokens to a smart contract.", "TC | TRANSFER-FROM: Insufficient `approve()` amount remaining: ", "TC | TRANSFER-MULTIPLE: Count of recipients and amounts must be identical.", "TC | LIST: First index cannot be greater than the last index.", "TC | DELEGATE SET-ID: Count of recipients and amounts must be identical.", "TC | SET: `id` disallowed for `account`.", "TC | SET: `id` is protected.", "TC | SET: New Admin Wallet cannot be set to a null address.", "TC | SET: New Admin Wallet cannot be the same as the current one.", "TC | SET: New Treasury Wallet cannot be set to a null address.", "TC | SET: New Treasury Wallet cannot be the same as the current one.", "TC | SET: `gasPerLoop` cannot be greater than 1/20 the `block.gaslimit`.", "TC | SET: `breakAtGasThreshold` must be a greater value than `gasPerLoop`.", "TC | SET: `breakAtGasThreshold` cannot be greater than 1/4 the `block.gaslimit`.", "TC | SET: Maximum possible value of 4200.690000 TC.", "TC | PERMIT ERROR: The 0 address cannot permit others.", "TC | PERMIT ERROR: Expired deadline.", "TC | PERMIT ERROR: Invalid signature.", "TC | GAS: Submit with ", "", "TC | RAIN: Invalid `amounts` provided.", "TC | RAIN: Must rain on at least 1 account.", "TC | DELEGATION: Null address are disallowed from execution.", "TC | DELEGATION: You're not the delegate or owner.", "TC | DELEGATION: No match found.", "TC | DELEGATION: Unsupported function.", "TC | CLAIM ERC-20: Failed transfer.", "TC | DECREASE ALLOWANCE: Amount to deduct is greater than existing `approve()` amount: ", "TC | APPROVE DEADLINE: Minimum possible value is 30 seconds. Maximum possible value is 2^248." ]; [ " TCC.", "TCC | AUTH: Sender must be the Admin Wallet.", "TCC | AUTH: Sender must be either the Treasury Wallet or the Admin Wallet.", "TCC | AUTH: Sender must be the Guardian Wallet, the Treasury Wallet, or the Admin Wallet.", "TCC | TRANSFER: Insufficient balance: ", "TCC | TRANSFER: Use `transferFrom()` to transfer tokens to a smart contract.", "TCC | TRANSFER-FROM: Insufficient `approve()` amount remaining: ", "TCC | TRANSFER-MULTIPLE: Count of recipients and amounts must be identical.", "TCC | LIST: First index cannot be greater than the last index.", "TCC | DELEGATE SET-ID: Count of recipients and amounts must be identical.", "TCC | SET: `id` disallowed for `account`.", "TCC | SET: `id` is protected.", "TCC | SET: New Admin Wallet cannot be set to a null address.", "TCC | SET: New Admin Wallet cannot be the same as the current one.", "TCC | SET: New Treasury Wallet cannot be set to a null address.", "TCC | SET: New Treasury Wallet cannot be the same as the current one.", "TCC | SET: `gasPerLoop` cannot be greater than 1/20 the `block.gaslimit`.", "TCC | SET: `breakAtGasThreshold` must be a greater value than `gasPerLoop`.", "TCC | SET: `breakAtGasThreshold` cannot be greater than 1/4 the `block.gaslimit`.", "TCC | SET: Maximum possible value of 4200.690000 TCC.", "TCC | PERMIT ERROR: The 0 address cannot permit others.", "TCC | PERMIT ERROR: Expired deadline.", "TCC | PERMIT ERROR: Invalid signature.", "TCC | GAS: Submit with ", "", "TCC | RAIN: Invalid `amounts` provided.", "TCC | RAIN: Must rain on at least 1 account.", "TCC | DELEGATION: Null address are disallowed from execution.", "TCC | DELEGATION: You're not the delegate or owner.", "TCC | DELEGATION: No match found.", "TCC | DELEGATION: Unsupported function.", "TCC | CLAIM ERC-20: Failed transfer.", "TCC | DECREASE ALLOWANCE: Amount to deduct is greater than existing `approve()` amount: ", "TCC | APPROVE DEADLINE: Minimum possible value is 30 seconds. Maximum possible value is 2^248." ]; */ // ------------------------------------------------------------------------------------ // /** * @title TokenBase for deployment as the "Triple Confirmation" token. * @notice This token contract is ERC-20 and EIP-2612 compatible. * * @notice * The size of this TokenBase contract allows for up to * 42,000 optimizsation runs. More runs than this doesn't * seem to produce a meaningful difference in the bytecode * size and thus likely doesn't help reduce gas costs. * The bytecode remains the same at 4.2 billion runs. * * @notice * When the American spelling of a word may have a 'z' * in its suffix, we use 'zs' as a compromise with the * British 's' spelling. In other words: * "Optimization" + "Optimisation" = "Optimizsation". * Our project is based in the UK. Our Solidity devs are American. * We find the spelling compromise to be apropos. * * @notice * Choosing which ERC or EIP standards to support is one of the most * research-intensive tasks to perform when writing a token contract. * We chose to start with the ubiquitous ERC-20 standard as our base * platform and ultimately chose to only augment it with EIP-2612. * * @notice * We opted not to support ERC-223, ERC-777, EIP-1363, or EIP-3009 for * a variety of reasons. Most of all because none of those standards are * as widely accepted or expected as ERC-2ying 0 and EIP-2612. * # ERC-223: We were unable to verify the extent of its support amongst * popular DeFi platforms, and it's still in Draft as of 2023. * # ERC-777: Implementation is quite complicated and its verification of * functionality even more so. ERC-777 also has re-entry * complications, most famously with Uniswap. * # EIP-1363: We were unable to verify the extent of its support amongst * popular DeFi platforms. * # EIP-3009: Very similar to EIP-2612 but with the drawback of being * unable to easily burn previously signed `permit()` messages. * Considering the adoption of EIP-2612 by Uniswap, USDC, ARB token, and * others, we feel the `permit()` gasless approval system is much simpler * while largely solving the long-standing concerns regarding `approve()`. * * @notice * We chose to build on ERC-20 and EIP-2612 with optional automated * expiration of `allowance`s. Our automated expiration system is self-built * without relying or complying with any particular ERC or EIP standard. * Perhaps we will submit our system as an EIP in our attempt to further * improve the `approve()` + `transferFrom()` user experience while: * # Complying to the expected ERC-20 standard * # Providing greater security, and * # Offering approachable controls over existing `approve()`s. * * @dev * Variables are named without any prefix if the function is externally-facing * or with appended `_` prefix depending on how many layers deep. For example * the `__swapId()` function is itself nested inside the `_swapId()` function * but itself also has a nested function inside, thus there also exists * a named `___swapId()` function. The only exceptions to this rule are: * # `i` for a counter omits the `_` prefix unless there's multiple counters, * # and when the unprefixed variable name is already exists in global scope * and would thus be shadowed. Example: `account` -> `_account`. */ contract TCC is IERC20, TokenBaseUtils { // ------------------------------------------------------------------ // // ---------------------- GLOBAL VARIABLES ---------------------- // /** * @dev * We thought that tightly packing unsigned integers into a single * 32-byte storage slot (1 word) would be advantageous for bytecode * and/or gas efficiency. In our testing it cost both /more/ gas * AND /more/ bytecode to use tightly packed integers versus using * standard unsigned `uint` which is a full 256 bits and 32 bytes. * Originally we had the following initializsed first to tightly pack: * uint8 + uint32 + uint32 + uint40 + uint32 only used 0.5625 of a single * uint256's 32 bytes. While – per the Ethereum.org documentation – that * should've resulted in them all being tightly packed within a * single 32-byte storage slot (1 word) and thus using less bytecode * and less gas, the reality is the opposite. Using smaller `uint`s than * the standard 256 used /more/ bytecode and /more/ gas in all operations. * * @notice ERC-20 required variable -> `decimals` */ uint8 public constant decimals = 6; /** * @dev * Equal to 10 ** `decimals`. * Assembly compile error requires hard-coded, * real value not a computed value such as * `= 10 ** decimals` or even `= 10 ** 6`. * * @return denominator -> 1000000 */ uint public constant denominator = __denominator; /** * @dev 4,200 TC upper limit for `rain()` minimum balance eligibility. */ uint public rainMinimumBalance = 1 * denominator; /** * @dev * Default is 200% the gas cost of a standard `transfer()` execution. * In our testing that's approximately the cost of each loop * transferring to multiple accounts in a single Tx. */ uint public gasPerLoop = 31400; /** * @notice breakAtGasThreshold is used in: * # `addAccounts()` * # `updateErrorMsg_GasPerLoop()` * # `_verifyLoopGas()` * # `eraseAllApprovals()` * # `transferMultiple()` * # `rain()` * # `rainList()` * # `rainAll()` */ uint public breakAtGasThreshold = 50000; /** * @dev * Immutable is employed to enforce fixed supply tokenomics. * `supply` is whole tokens (no decimals). * `totalSupply` is ERC-20 required. Raw total token units. * * @notice ERC-20 required variable -> `totalSupply` */ uint public immutable supply; // Whole tokens. uint public immutable totalSupply; // Raw total number. /** * @dev * ERC-20 required variables. Immutable. * A commented `immutable` keyword for any `string` variable can be * interpreted hereafter to mean the variable is indeed set at * construction time and never again edited. As of this contract's * writing in 2023, the `immutable` keyword does not support `string`s. * * @dev * Until clarity is found around EIP-2612 about whether the * `version` can be a string other than "1" – which is required * by EIP-712 – we opt for two different variables: * # `version` -> "1" as required in EIP-712 on which EIP-2612 relies. * # `versionNotes` -> To give information about this deployment. * * @notice ERC-20 required variables -> `name` and `symbol` */ string public /* immutable */ name; string public /* immutable */ symbol; string public constant version = "1"; // Required per EIP-2612 -> EIP-712 string public constant versionNotes = "2023-04-20 | Final"; /** * @dev * Events unique to this token contract. * Not part of the ERC-20 standard. */ event Mint(address indexed origin, uint amount); event TransferMultiple(address indexed account, uint amount); event Rain(address indexed gifter, uint amountThisBlock); event RainList(address indexed account, uint total); event RainAll(address indexed account, uint total); event Claimed(address indexed token, uint amount, address indexed receiver); event AdminChange(address indexed from, address indexed to); event TreasuryChange(address indexed from, address indexed to); /** * @dev `string` error messages recalled out of storage via named-index. * @notice Can be grabbed as a full list via `getErrors()` `view` function. */ string[lenErrors] errors; uint public maxRecipientsPerBlock; /** * @return Give a list of `string` of all `errors`. */ function getErrors() external view returns (string[lenErrors] memory) { return errors; } /** * @dev * These addresses are primarily established for the purposes of * easily identifying and tracking the `treasuryWallet` across * the Triple Confirmation system of contracts. The `adminWallet` * and `treasuryWallet` both have the same authority level * EXCEPT that the `adminWallet` can change the `treasuryWallet` without * the latter's permission. Worth noting that while the `adminWallet` * can change the `treasuryWallet` address, the `adminWallet` * cannot transfer tokens away from the outgoing `treasuryWallet` * without being given permission via sufficient `allowance`. * * @notice * `guardianWallet` is created to assist `adminWallet` with routine * token contract management that are of low consequence. These are * parameters relating to highly recursive operations such as adjusting * error messages or setting team wallets to lower `id`s for easier * access and organizsation from `getAccountsList()` calls. * * @notice * `guardianWallet` is authorizsed by `adminWallet` to run only: * # `setId()` * # `setError()` * # `addAccounts()` * # `setProtected()` * # `setGasPerLoop()` */ address public adminWallet; address public treasuryWallet; address public guardianWallet; /** * @return circulatingSupply -> Raw value unsigned integer (uint) * of `totalSupply` not under the control of the `adminWallet` * or `treasuryWallet`. */ function getCirculatingSupply() external view returns (uint) { uint circulatingSupply = totalSupply - balance[adminWallet]; /** * @notice * The `circulatingSupply` is the amount of tokens * available to all accounts aside from the `adminWallet` * and `treasuryWallet`. To get the `circulatingSupply()` * we exclude these tokens from the `totalSupply` variable. * The difference is the amount "out in the wild." */ if (adminWallet != treasuryWallet) { circulatingSupply -= balance[treasuryWallet]; } return circulatingSupply; } /** * @notice * Account information. * We found the most efficient storage and execution gas costs to come * from utilizsing mappings of various primitive variable types as opposed * to packing all variables into a struct. Recalling and writing to a * struct appeared to cost significantly more gas – especially during * `for` loops – in our testing. * * @dev * - Unique mappings to our token contract: * # `id` * # `account` * # `protected` * # `rainAllNextId` * # `rainAllRunningTotal` * # `allowanceTimeToLive` * # `approvedSpenders`, and the * # `delegationMem` * These are all employed to provide: * # An improved `approve()` experience, * # For the execution of `transferMultiple()`, * # Various `rain()` functions, and * # Delegate certain looping transactions thereby allowing users to * employ scripted wallets via Web3xx on their behalf. * * @notice * The `protected` mapping allows the `adminWallet`, `treasuryWallet`, * or `guardianWallet` to lock a specific account to a specific `id`. * This potentially enables easier team management of the TC trading bot * and any potential rewards related and given out to promote its use. * * @dev * Be aware the `public` visibility gobbles up bytecode vs `private`. * * @dev * Largest handle-able `allowanceTimeToLive` value due to the need * to add with `block.timestamp`: * 115339776388732929035197660848497720713218148788040405586178452820382218977280 */ uint public numAccounts; mapping(address => uint) public id; mapping(uint => address) public account; /** * @dev * We trialed three different systems to store these account-specific values: * # Single mapping of `uint[]` list, * # Struct containing all values, and * # Primitive type mappings (current). * The other two methods – a single `uint[]` per address, and a single * struct containing all account values – both cost more in bytecode and * gas to use. Thus we settled on employing mappings of primitive types. */ mapping(address => uint) balance; mapping(address => bool) protected; mapping(address => uint) rainAllNextId; mapping(address => uint) rainAllRunningTotal; mapping(address => uint248) allowanceTimeToLive; mapping(address => address[]) approvedSpenders; mapping(address => mapping(address => uint[lenAStor])) allowances; mapping(address => uint[lenDelegationMem]) delegationMem; // ------------------------------------------------------------------ // // ------------------------ GET ACCOUNTS ------------------------ // /** * @dev * The Delegation struct is intended purely for input. Its execution * requires verification against an encoded `uint` stored in a * given account's `delegationMem` array. */ struct Delegation { address delegate; string functionName; address[] recipients; uint[] amounts; } /** * @dev * The following structs below here are intended purely for * `view` functions including `getAccountsList()`: * # RainStruct * # Approved * # Account */ struct RainStruct { bool excluded; uint allNextId; uint allRunningTotal; uint delegation; } struct Approved { address account; uint amount; uint timestamp; uint timeRemaining; uint perpetualSince; } struct Approves { uint248 timeToLive; Approved[] list; } struct Account { uint id; address account; uint balance; bool protected; Approves approvedSpenders; RainStruct rain; } /** * @notice * Converts an account's `address[]` held via `approvedSpenders` * to named-value (easier-to-read) `Approved[]` list. */ function _buildApprovedStructList( address _account, uint248 _allowanceTimeToLive ) private view returns ( Approved[] memory _approvedList ) { // Pull the account's list of `address` that have been approved. address[] memory _approves = approvedSpenders[_account]; /** * @notice * We like lots of info about approvedSpenders. Hence there's a * whole struct list dedicated to them. First grab how * many approved spenders exist for this account. Then we'll * start building the struct list. */ uint _numApproved = _approves.length; // Create an empty Approved struct list with the length identified above. _approvedList = new Approved[](_numApproved); // Loop through the empty Approved struct list and fill in // each approved address, including the amount and deadline. for (uint i; i < _numApproved; ++i) { // Grab the approved account at index `i` of the // address list obtained via the `approvedSpenders` mapping. address _spender = _approves[i]; /** * @dev * Grab the `allowances` out of storage setting the current * `allowance` to the proper index (0 which == `aAllowance`) * and then continue building the approve struct. */ uint[lenAMem] memory _allowance = _calcAllowance( _account, _spender, _allowanceTimeToLive ); /** * @dev * If the `_spender` still has an `allowance` of `_account`, * then give the actual time remaining to expiration. Otherwise * if the `_spender` has been set to perpetual then the * time remaining will be 0 but the `allowance` amount * will persist. * * @dev * Save data about this particular account to the * appropriate index `i` in the Approved struct list. */ _approvedList[i] = Approved( _spender, _allowance[aAllowance], _allowance[aTimestamp], _allowance[aTimeRemaining], _allowance[aPerpetual] ); } return _approvedList; } /** * @notice * Converts an account's mappings related to `rain()` and its two * derivative functions – `rainList()` and `rainAll()` – to a more * understandable named-value `RainStruct[]` list. */ function _buildRainStruct( address _account ) private view returns (RainStruct memory) { return RainStruct( _isContract(_account), rainAllNextId[_account], rainAllRunningTotal[_account], delegationMem[_account][encodedDelegation] ); } /** * @param _first -> First `id` of which to grab account information. * @param _last -> Last `id` of which to grab account information. * @return _accounts -> List of all accounts and their associated information. */ function _accountsList( uint _first, uint _last ) private view returns ( Account[] memory _accounts ) { _accounts = new Account[](1 + _last - _first); uint _i; // Loop over each account. for (uint i = _first; i <= _last; ++i) { /** * @dev * Build out the Account struct including the Approved[] list * and the RainStruct[] list. We use nested structs for easier * named-value reading on the Web3xx side. * * @notice * We employ a separate counter `_i` distinct from `i` * to fill in the `accounts` without worrying about * underflow, overflow, or out-of-index errors. * This `_i` counter is incremented by 1 after retrieval * from memory via the `++` suffix. Appending the `++` * as a prefix would instead increment by 1 before retrieval * which is not what we want, hence we append `++` as a suffix. * * @dev * Incrementing variables by 1 with the `++` as a prefix uses * less gas than incrementing by 1 with the `++` as a suffix. * For `view` functions there exists no functional gas limit * since we can always spin up our own node with no timeout. */ _accounts[_i++] = getAccount(account[i]); } return _accounts; } /** * @notice * External `view` wrapper to obtain a list of all accounts. * Costs around ≈ 20,000 gas per account meaning there's a * soft limit of ≈ 395 accounts supported by a gas-limited node. * * @notice * If there's no accounts, this will revert. We find this to be * an acceptable limitation. */ function getAccountsList() external view returns (Account[] memory) { return _accountsList(1, numAccounts); } /** * @notice * The same as above but with the added option of grabbing accounts only * between certain indices/values of `id`. * * @param first -> In reference to `id` NOT `getAccountsList()` indices. * @param last -> In reference to `id` NOT `getAccountsList()` indices. * * @notice * Submitting a larger number than `numAccounts` for `first` will force the * list to /start/ at the last account. * Submitting a larger number than `numAccounts` for `last` will force the * list to /terminate/ at the last account. */ function getAccountsListByIds( uint first, uint last ) external view returns ( Account[] memory ) { require( first <= last, errors[errList] ); /** * @dev * Purposefully omit the `0` index since that's a null user that * should always result in default, unset values. */ if (last > numAccounts) { last = numAccounts; if (first > numAccounts) { first = numAccounts; } } return _accountsList(first, last); } /** * @param _account -> Provide all relevant associated information. */ function getAccount( address _account ) public view returns ( Account memory ) { uint248 _allowanceTimeToLive = allowanceTimeToLive[_account]; return Account( id[_account], _account, balance[_account], protected[_account], Approves( _allowanceTimeToLive, _buildApprovedStructList(_account, _allowanceTimeToLive) ), _buildRainStruct(_account) ); } /** * @param _id -> Provide all relevant account info on account at `_id`. */ function getAccountById( uint _id ) external view returns ( Account memory ) { return getAccount(account[_id]); } // ------------------------------------------------------------------ // // ------------------------- CONSTRUCTOR ------------------------ // /** * @dev Constructor. * @param _deployer -> Address employed to disburse tokens. * @param _guardian -> Address entrusted to be Guardian. * @notice ERC-20 required variables -> `_name` and `_symbol` and `_supply`. */ constructor( string memory _name, string memory _symbol, uint _supply, address _deployer, address _guardian ) { name = _name; symbol = _symbol; supply = _supply; totalSupply = _supply * denominator; adminWallet = msg.sender; treasuryWallet = msg.sender; balance[_deployer] = totalSupply; guardianWallet = _guardian; /** * @dev * We purposefully do not add the `msg.sender` * or `_deployer` because neither the deploying * wallet nor the deployer should be remembered. _addAccount(msg.sender); */ emit Transfer(address(0), _deployer, totalSupply); emit Mint(_deployer, totalSupply); /** * @dev * Domain creation MUST occur either * after the storage of `name` or * not during the `constructor()`. */ saveDomainSeparatorAndChainId(); } // ------------------------------------------------------------------ // // ----------------- ADMIN-GUARDIAN HOUSEKEEPING ---------------- // /** * @notice * `adminWallet`, `treasuryWallet`, and `guardianWallet` are all unique * address slots that may be three unique entities. A situation can arise * where they do not see eye-to-eye on certain housekeeping duties such as * what a specific error message should read. In the case of a dispute, the * `adminWallet` is endowed with full credentials to strip the other two * of their authority and has the exclusive ability to arbitrate any and * all issues. */ /** * @dev * We tried setting the errors in the `constructor()` but that would cost * too much gas to deploy. We then tried to set all the strings in a single * function here but that added +0.3Kb to the bytecode. Instead, we've * chosen to implement the `guardianWallet` and allow it to loop over the * entire `errors` storage array to set each error one-at-a-time. * function setErrorList( string[lenErrors] calldata _errors ) external _adminTreasuryOrGuardianAuth { assert(id[msg.sender] == 0); for (uint8 i; i < lenErrors; ++i) { errors[i] = _errors[i]; } } */ /** * @notice Accepts a given `string` and sets it to the `index` in `errors`. */ function setError( string calldata _error, uint index ) external _adminTreasuryOrGuardianAuth { assert(index < lenErrors); errors[index] = _error; } /** * @dev Costs ≈ 85,000 gas per account. * @param accounts -> List of address to add as new accounts. * @param shouldBeProtected -> Attribute of `protected` for each given address. * @notice `accounts` and `shouldBeProtected` must be identical in length * and index-matched to each other. Entries should be linked by index. * @dev Increases bytecode by +0.1Kb to make a nested private exec function. */ function addAccounts( address[] calldata accounts, bool[] calldata shouldBeProtected ) external _adminTreasuryOrGuardianAuth { uint _end = accounts.length; assert(_end == shouldBeProtected.length); _verifyLoopGas(_end / 2); for (uint i; i < _end; ++i) { if (_hasInsufficientGasRemaining() && i > 0 && i + 1 < _end) { return; } _addAccount(accounts[i]); protected[accounts[i]] = shouldBeProtected[i]; } } /** * @notice * Allows certain wallets to remain at a static `id`. * * @notice * Set `address(0)` as a protected wallet to disable accounts * from being automatically erased during `rain()` functions. * * @notice * Be aware that setting the account at the current * `numAccounts` will also (temporarily) prevent accounts * from being erased during `rain()` functions until a * new un`protected` account joins. */ function setProtected( address wallet, bool shouldBeProtected ) external _adminTreasuryOrGuardianAuth { protected[wallet] = shouldBeProtected; } /** * @notice * Very minor exploits while running `rainAll()` with a mischievous * `adminWallet`, `treasuryWallet`, or `guardianWallet`: * # --> Set an already-rained-on `id` to a not-yet-rained `_id`. * * @notice * The above could result in a given account getting rained on two or more * times during `rainAll()` and disallowing someone else from being rained * on at all. This minor exploit can advantage certain accounts while * disadvantaging others and can be employed by third-parties who have * sway over any of the aforementioned administrative wallets without the * need to be one themselves. Ultimately what's most important is being * aware of this concern. This is a social issue, not an actual bug. * * @dev * Swapping the account at `id` == 0 which is expected to be a null account * of `address(0)` is intended to be avoided in all scenarios. */ function setId(address _account, uint _id) external _adminTreasuryOrGuardianAuth { require( !protected[account[_id]], errors[errSetIdProtected] ); _setId(_account, _id); } /** * @dev * Updating error strings with complex `string.concat()` logic eats up a * lot of bytecode. This particular one we find to be important since * requiring the `guardianWallet`, `treasuryWallet`, or `adminWallet` to * push a separate `setError()` transaction in addition to a * `setGasPerLoop()` transaction doesn't seem very well-conceived. This way * only the aforementioned `setGasPerLoop()` function need be called and * its associated error message will automatically be updated with all the * new values as calculated with the new `gasPerLoop` parameter. */ function updateErrorMsg_gasPerLoop() external { // Saves a little bytecode using a nested, private execution function. _updateErrorMsg_gasPerLoop(); } // ------------------------------------------------------------------ // // -------- INTERNAL ADMIN-GUARDIAN HOUSEKEEPING HELPERS -------- // /** * @dev Nested private execution function required for delegation use. * @param _account -> Set its `id` to `_id`. * @param _id -> Submit `0` to attempt to delete the `_account`. */ function _setId(address _account, uint _id) private { /** * @dev * We want to ensure the `_account` is a current account * so we run it through `_addAccount()` to verify its * registration or to register it in the case that it's * not yet an account of this token contract. If the * `_account` wasn't registered then we could accidentally * `__swapId()` with an unset entry which would result * in `address(0)` being registered. We want to avoid that * behaviour and we also want to only `__swapId()`s with * registered non-null accounts, hence we run `_account` * through `_addAccount()`. */ require( /** * @dev * Only allow the `__swapId()` to take place if the `_account` is * registered. If the `_account` has an `id` of 0 after the * `_addAccount` – such as if `address(0)` is submitted as the * `_account` – then the `require()` below will fail. */ _addAccount(_account) > 0 && ( ( /** * @dev * Only process a deletion if: * # The `_account`s `balance` is 0, AND * # The deletion was requested from `_id` == 0. */ balance[_account] == 0 && _id == 0 ) || // OR ( /** * @dev * Otherwise only allow the `__swapId()` * if the `_id` requested is less than * or equal to the `numAccounts` as * swapping outside of that would result * in `address(0)` becoming registered. * We do not want `address(0)` to ever * be registered. */ _id > 0 && _id <= numAccounts ) ), errors[errSetId] ); // Process the `id` swap. __swapId(_account, _id); } /** * @dev * Execute the actual swap of `_id`. * Do NOT call directly without verification * and `require()` checks beforehand. */ function ___swapId(address _account, uint _id) private { ( account[_id], account[id[_account]], id[_account], id[account[_id]] ) = ( account[id[_account]], account[_id], id[account[_id]], id[_account] ); } /** * @dev Call from the `_setId()` private function. */ function __swapId(address _account, uint _id) private { /** * @dev * If the wallet existing in the requested `_id` * is `protected` then do nothing. In order to * supplant that account, set its `id` to something * else or eliminate its `protected` attribute. * * @notice * To prevent any account from being erased, set * `address(0)` to `protected` == true. */ if (protected[account[_id]]) { return; } // Delete the account. if (_id == 0) { /** * @dev If the wallet is `protected` then do nothing. */ if (protected[_account]) { return; } /** * @dev * Execute the deletion by swapping the `_account` * to the end of the list of `id`s. Then delete * the `_account`s `id` link keeping in mind to * increment `numAccounts` down by 1 afterwards. */ ___swapId(_account, numAccounts); delete account[numAccounts--]; delete id[_account]; return; } /** * @dev * Note that we don't recursively verify that the account on the * receiving end of swap with `_account` is themselves ineligible for * deletion; such as having a 0 balance. Our intention is that should * the `adminWallet`, `treasuryWallet`, or `guardianWallet` desire to * cleanse the `rain()` list of 0 balance wallets, then they will loop * over all accounts with `_id` set to 0 and thus over time and many * swaps, reach the desired outcome of pruning ineligible accounts. * * Performing a simple swap of ID's this way without recursive * verification allows MetaMask and other Web3 providers to better * estimate the gas cost of the transaction, and ensures the cost of * any given `rain()` function isn't overly bloated by the calls to * this `_swapId()` function which itself is nested inside the * `_hasRainMinimumBalance()` function which is nested inside the * `rain()` functions. * * Our philosophy is to enable pruning of the accounts list in a * cost-effective manner, and to spread out such pruning over multiple * transactions by a somewhat random number of balance-holders. */ ___swapId(_account, _id); } /** * @dev Private executable to update the `gasPerLoop` error message. */ function _updateErrorMsg_gasPerLoop() private { maxRecipientsPerBlock = (block.gaslimit - breakAtGasThreshold) / _safeDivision(gasPerLoop); errors[errGasPerLoop] = string.concat( " gas. Required: ", __uintToString(gasPerLoop), " gas/recipient + ", __uintToString(breakAtGasThreshold), " gas/Tx. ", __uintToString(maxRecipientsPerBlock), " max recipients." ); } // ------------------------------------------------------------------ // // ------------------ AUTHORIZSATION MODIFIERS ------------------ // /** * @notice * Authorizsation is inherited such that `adminWallet` has full privileges, * `treasuryWallet` has a subset of those privileges, and `guardianWallet` * has a subset of `treasuryWallet`s privileges. Thus there is nothing * that `guardianWallet` can do that `treasuryWallet` cannot, and nothing * that `treasuryWallet` can do that `adminWallet` cannot. */ function _walletIsAdmin(address _wallet) private view returns (bool) { return _wallet == adminWallet; } modifier _adminAuth() { require( _walletIsAdmin(msg.sender), errors[errAdminAuth] ); _; } function _walletIsTreasury(address _wallet) private view returns (bool) { return _wallet == treasuryWallet; } function _walletIsTreasuryOrAdmin(address _wallet) private view returns (bool) { return _walletIsTreasury(_wallet) || _walletIsAdmin(_wallet); } modifier _adminOrTreasuryAuth() { require( _walletIsTreasuryOrAdmin(msg.sender), errors[errTreasuryAdminAuth] ); _; } function _walletIsGuardian(address _wallet) private view returns (bool) { return _wallet == guardianWallet; } function _walletIsGuardianTreasuryOrAdmin(address _wallet) private view returns (bool) { return _walletIsGuardian(_wallet) || _walletIsTreasuryOrAdmin(_wallet); } modifier _adminTreasuryOrGuardianAuth() { require( _walletIsGuardianTreasuryOrAdmin(msg.sender), errors[errGuardianTreasuryAdminAuth] ); _; } // ------------------------------------------------------------------ // // ---------------------- INTERNAL HELPERS ---------------------- // function _hasInsufficientGasRemaining() private view returns (bool) { return breakAtGasThreshold > gasleft(); } /** * @notice * Accounts who have a `balance` below the `rainMinimumBalance` * are deemed ineligible for `rain()` and `rainAll()` functions. * Since `rain()` operates on a random basis and `rainAll()` * operates on an all-accounts basis, we feel it makes sense to * set a low threshold above which an account's `balance` must land * in order to qualify. This functionality is invisible to senders. * Senders do not specific who they `rain()` or `rainAll()`, thus * we feel this functionality is fair to ensure tokens stay in * circulation – something very important for fixed supply * tokenomics – and to encourage accounts to hold a `balance` * thereby putting positive pressure on tokenomics. We also want to * keep gas costs reasonable while looping across many accounts. That's * only possible if set the threshold at such an amount that account * pollution doesn't occur; that is, we want to avoid people making * hundreds of accounts each with TC dust for the exclusive purpose of * reaping higher `rainAll()` rewards and a higher probability of * `rain()` rewards. The `rainMinimumBalance` is adjustable for that * very purpose: For the administrative team to discourage account * pollution while ensuring the fun execution of `rain()` functions. * * @notice * `rainList()` is explicitly exempted from the aforementioned `balance` * checks because if the sender provides a list to rain on then we can * logically assume the sender does intend and want to rain on each * address. If we did perform the same check on `rainList()` executions, * senders could very well become confused upon realizsing only * certain accounts received their rain while others in their list * did not. Without the ability to notify the sender of why certain * accounts were rained and others weren't, senders will simply * become frustrated at this obtuse functionality. * * @notice * `protected` wallets are excluded from being rained on – except in the * case of `rainList()` which bypasses the check – to avoid abuse by the * `adminWallet`, `treasuryWallet`, or `guardianWallet` setting their * personal wallets earlier in the `id` list and thus being more likely to * be hit in `rainAll()` executions than if they had a higher `id`. Should * the administrative wallets set their personal wallets to a lower `id` * and /not/ set them as `protected`, we feel the requirement to have * `rainMinimumBalance` to be sufficiently fair despite the slight * advantage gained by being earlier in the `rainAll()` list. Furthermore, * this minor advantage is limited to `rainAll()` exclusively. */ function _execRain( address _owner, address _recipient, uint _amount ) private returns ( bool _skip ) { if ( /** * @dev * Don't process the rain if: * # The same account raining is the one chosen to be rained on * # The `_recipient` is protected * # A null address is hit. */ _owner == _recipient || protected[_recipient] || _isNullAccount(_recipient) // Specifically avoid `_addAccount()`. ) { return _skip; } /** * @dev * Only if the `_recipient`s balance is 0 AND the `rainMinimumBalance` * is greater than 0 should accounts be eligible for deletion. * The deletion will be skipped if an account is `protected`. * Note though the flow of if{} statements prevents `protected` * accounts from reaching this logic block. */ uint _recipientBal = balance[_recipient]; if (_recipientBal == 0 && rainMinimumBalance > 0) { __swapId(_recipient, 0); // Delete the account. return _skip; } /** * @dev * Massively cheaper in gas costs to verify a given address * is a contract each time versus saving and recalling * a `bool` held in storage. */ if (_isContract(_recipient)) { return _skip; } /** * @dev * Reaching this logic block means the account is deemed eligible * to receive `rain()`ed tokens. Process a direct `_transfer()`. */ if (_recipientBal >= rainMinimumBalance) { return _transfer(_owner, _recipient, _amount); } /** * @dev For all other conditions, skip the account. */ return _skip; } /** * @dev * In order to implement a successful `rain()` function, * we need to store a list of all accounts. This list is * used and verified in `rain()` and `rainAll()` with * 0 balance accounts pruned unless `rainMinimumBalance` * is also set to 0. * * @return _id -> Lookup of `_newAccount` in the `id` mapping. * @dev For null accounts, `_id` should always return 0. */ function _addAccount(address _newAccount) private returns (uint _id) { _id = id[_newAccount]; if (_id > 0 || _isNullAccount(_newAccount)) { return _id; } /** * @dev * By incrementing `numAccounts` before setting * it in the `account` mapping we ensure that * `id` == 0 is also address(0). This is the * intended output since otherwise address(0) * would be eligible for `rain()` and would thus * burn tokens. We would much prefer to avoid * burning tokens since we have a fixed supply * and would rather manage the circulating supply * via the trading bot and its associated fees. */ _id = ++numAccounts; account[_id] = _newAccount; id[_newAccount] = _id; return _id; } /** * @return -> String with `_owner`s balance included. */ function _insufficientBalanceError( address _owner ) private view returns ( string memory ) { return string.concat( errors[errInsufficientBalance], _tokenValueAsString(balance[_owner]) ); } /** * @return -> String of `_value` in decimal form with `symbol` appended. */ function _tokenValueAsString( uint _value ) private view returns ( string memory ) { return string.concat( _uintToString(_value), errors[errSymbol] ); } /** * @notice * Nested `require()`s that verify the `sender` has a sufficient * `balance` to send the `totalRainAmount` tokens. The error * message is generated on-demand in a human-readable and * intuitively-understandable format with decimals shown. * * @notice * Named `_rainAndListChecks()` because this check applies * only to `rain()` and `rainList()`. * * @param _enforceGasRequired -> Should be true if actually executing. */ function _rainAndListChecks( address _owner, uint _amount, uint _accountsToRain, bool _enforceGasRequired ) private view { /** * @notice * Our intention is that only those who have an insufficient `balance` * pay extra gas for the error message to be generated. We feel * the need to return an easily understood error message to be * important for a good user experience when attempting to `rain()`. */ require( balance[_owner] >= _amount * _accountsToRain, /** * @notice * If the `sender` has an insufficient `balance`, * tell them how many tokens they must have in * order to run the function { `rain()` | `rainList()` } * they desire. */ string.concat( _insufficientBalanceError(_owner), " Required: ", _tokenValueAsString(_amount * _accountsToRain) ) ); /** * @dev * While raining on 0 accounts would not present any execution * issues, we feel the user experience is improved having a * revert occur with a clear error message that no `rain()` * took place. */ require( _accountsToRain > 0, errors[errRainNumAccounts] ); /** * @notice Parameter to optionally verify the submitted gas. */ if (_enforceGasRequired) { _verifyLoopGas(_accountsToRain); } } /** * @notice Ensure sufficient gas was given to run at least one loop. * * @dev * We could limit `_loops` to `maxRecipientsPerBlock` but decide that's * not as important or as guaranteed a check as directly limiting the * maximum amount of `_gasRequired` to 90% the `block.gaslimit` which * will always be possible to submit. */ function _verifyLoopGas(uint _loops) private view { /** * @dev * Ensure the `_gasRequired` isn't greater than 90% the `block.gaslimit` * otherwise a user may be unable to submit the given transaction. The * safest path to ensure this check doesn't return a value greater than * or too close to the `block.gaslimit` is to simply limit it after the * calculated `_gasRequired`. We want to ensure the requirement here is * some amount of gas that a user can reasonably produce. Thus, limit * the upper bound of `_gasRequired` to 90% the `block.gaslimit`. The * `++` prefix on `_loops` assists in ensuring sufficient gas is given * to run at least one loop before the `breakAtGasThreshold` is hit. */ uint _gasRequired = breakAtGasThreshold + (gasPerLoop * ++_loops); if (_gasRequired > 90 * block.gaslimit / 100) { _gasRequired = 90 * block.gaslimit / 100; } /** * @dev * If there is insufficient `gasleft()` then error with a message * explaining how much gas needs to be provided. */ require( gasleft() > _gasRequired, string.concat( errors[errGasPerLoopHeader], __uintToString(_gasRequired), errors[errGasPerLoop] ) ); } // ------------------------------------------------------------------ // // ------------------- INTERNAL ERC-20 HELPERS ------------------ // /** * @return Is the `_account` one of the null wallets, or (this) address? * * @notice * In order of likelihood to occur. * Prevent token burns by silently * re-routing to the `treasuryWallet`. */ function _isNullAccount(address _account) private view returns (bool) { // These are all eligible via `transferFrom()`. return _account == address(0) || _account == address(0xdead) || _account == address(this); } /** * @notice * Our assumption is that if someone sends tokens to this token contract * or to one of the above listed null accounts, they are intending to burn * them or get rid of them forever. Should they have transferred a mistake * then there exists the (social) potential for the `treasuryWallet` to * send the tokens back to their rightful owner. * * @dev Executes the requested balance transfer and emits the {Transfer} event. * @notice ERC-20 required execution function. */ function _transfer( address _from, address _to, uint _amount ) private returns ( bool ) { require( balance[_from] >= _amount, _insufficientBalanceError(_from) ); /** * @notice Redirect lost tokens to the `treasuryWallet`. * No reason to spend add'l gas adding `_from` accounts. */ if (_addAccount(_to) == 0 || _isNullAccount(_from)) { _to = treasuryWallet; } /** * @dev Execute the `balance` transfer. */ balance[_from] -= _amount; balance[_to] += _amount; emit Transfer(_from, _to, _amount); return true; } /** * @notice * By simply setting an `allowance` to a static `_amount`, there exists a * race condition exploit native to the ERC-20 standard where a `_spender` * can spend both the previous `allowance` AND this new `allowance` amount * being set. We attempt to nullify this race condition exploit inherent * to the ERC-20 standard by implementing EIP-2612 and its `permit()` * function. EIP-2612 adds support for gasless approvals and allows the * `allowance` to be set just before `transferFrom()` execution all in the * same transaction in the same block. If executed this way, two problems * are simultaneously solved: * # Race condition for double `allowance` spend, and * # Need to submit two transactions { `approve()` + `transferFrom()` } * and spend 50% more gas. This has systemic drawbacks as well since * a single, simple transfer costs twice as much blockchain bandwidth, * filling up crucial block space. * * @dev * Current blockchain technology is inherently throughput-restricted. * We feel a better system than the two transaction ERC-20 standard can * be implemented to transfer tokens to a dApp or smart contract. While * ERC-223, ERC-777, EIP-1363, and EIP-3009 all offer unique proposal, * we found EIP-2612 to be the most compelling due to its simplicity * and clear support across 1/3 of the top tokens, by market cap, in 2023. * * @dev * This function is the endpoint of: * # `approve()` * # `increaseAllowance()` * # `decreaseAllowance()` * # `permit()` * * @notice ERC-20 and EIP-2612 required private execution function. */ function _approve( address _owner, address _spender, uint _amount ) private returns ( bool ) { /** * @dev * Standard ERC-20: `approve()` sets the `aAllowance` amount * in our `allowances` `uint[3]` mapping. */ allowances[_owner][_spender][aAllowance] = _amount; /** * @dev * Save the `_spender` into the `_owner`s `approvedSpenders` list if * they're a new spender. The `approvedSpenders` list and all associated * `allowances` can be deleted via `eraseAllApprovals()` with * `onlyExpired` set to false. * * @dev * The same address can be pushed into the `approvedSpenders` list twice * if the `aTimestamp` of a given spender's allowance is reset to 0 * without first erasing the entire `approvedSpenders` list. Each address * in the `approvedSpenders` list for a given `_owner` should appear * only once. When queried via the `getAccount()` or its derivative * functions, each `_spender` in the `approvedSpenders` list should * appear with all relevant info including that `_spender`s `allowance`, * when it was last updated, and how many seconds it has until expiration. * We try to avoid duplicative entries in the `approvedSpenders` list * by not erasing the `aTimestamp` except when an `_owner` requests * a full `eraseAllApprovals()` with `onlyExpired` set to false. */ if (allowances[_owner][_spender][aTimestamp] == 0) { approvedSpenders[_owner].push(_spender); } // Non-standard ERC-20: Remember when the `allowances` was set. allowances[_owner][_spender][aTimestamp] = block.timestamp; /** * @dev * Finalizse the `approve()` by emitting the {Approval} event * and returning true as required by the ERC-20 standard. */ emit Approval(_owner, _spender, _amount); return true; } /** * @notice * Give the list of recipients the amount in the `_amounts` list * using the index as a link between the two. The lists * must be of identical length to avoid unintended transfers. * * @notice ERC-20 extended internal execution function. */ function _transferMultiple( address _owner, bool _delegated, address[] calldata _recipients, uint[] calldata _amounts ) private { uint _end = _recipients.length; _verifyLoopGas(_end); // Local variable setup. uint i; if (_delegated) { i = delegationMem[_owner][startIndex]; } uint _start = i; uint _total; // Sum of all transfers. // Loop through `_recipients` list. for (; i < _end; ++i) { if ( _delegated && _hasInsufficientGasRemaining() && i > _start && i + 1 < _end ) { break; } /** * @notice * No verification of if the `recipient` is a * smart contract where tokens may be irreversibly lost. */ _transfer(_owner, _recipients[i], _amounts[i]); /** * @dev * Must sum the individual amounts for an accurate total. * Can't multiply by `amount` because each recipient might * receive a different amount. */ _total += _amounts[i]; } if (_delegated) { delegationMem[_owner][total] += _total; delegationMem[_owner][startIndex] = i; } if (i >= _recipients.length) { emit TransferMultiple( _owner, _delegated ? delegationMem[_owner][total] : _total ); } } /** * @dev * Private executable to calculate the `allowance` taking into consideration * the `_owner`s set duration until expiration of `_spender`s `allowance`. */ function _calcAllowance( address _owner, address _spender, uint248 _allowanceTimeToLive ) private view returns ( uint[lenAMem] memory _allowances ) { /** * @dev * Grab and remember the `allowances` out of storage. * This doesn't cost any less gas than individual calls * but does help in centralizse the `allowance` calculation * logic and to return a fully set array of values for * easy parsing and management across the token contract. * The array itself is used most heavily in the `getAccount(s)` * functions. The first indexed value is the calculated * `allowance` taking into consideration the aforementioned * spoil/expiration time. */ for (uint8 i; i < lenAStor; ++i) { _allowances[i] = allowances[_owner][_spender][i]; } /** * @dev * 1 second added to allow an `allowance` to be used if the current time * and the `_deadline` are the same time. Thus transferring if the * current time is exactly `_deadline` is accepted but transferring one * second /after/ the `_deadline` is rejected. While we could use `>=` * here, when returned via the `getAccount()` or its derivative * functions the owner would see 0 seconds remaining when the * `allowance` really has 1 second remaining until expiration. */ uint _deadline = 1 + _allowanceTimeToLive + _allowances[aTimestamp]; if (_deadline > block.timestamp) { _allowances[aTimeRemaining] = _deadline - block.timestamp; } /** * @dev * If { * the user has set an `allowanceTimeToLive` * AND * the user has NOT set this `_spender` to perpetual * AND * the `allowance` has zero time remaining, * } * THEN * Return a 0 `allowance` by deleting the appropriate entry. * Note that `delete` REFUNDS some gas whereas `= 0` COSTS add'l gas. */ if ( _allowanceTimeToLive > 0 && _allowances[aPerpetual] == 0 && _allowances[aTimeRemaining] == 0 ) { delete _allowances[aAllowance]; } return _allowances; } /** * @dev Private executable to loop through revoking approvals. */ function _eraseAllApprovals( bool _onlyExpired, uint248 _allowanceTimeToLive ) private returns ( bool _completed ) { address[] memory _approves = approvedSpenders[msg.sender]; _verifyLoopGas(3 * _approves.length / 2); // 150% the expense of `rain()` /** * @dev `_revokeApproval()` will return false if the Tx ran out of gas. */ for (uint i; i < _approves.length; ++i) { if (!_revokeApproval(_approves[i], _onlyExpired, _allowanceTimeToLive)) { return _completed; // false } } _completed = true; // Full revokes should also delete the `approvedSpenders` list. if (!_onlyExpired) { delete approvedSpenders[msg.sender]; } return _completed; } /** * @dev Private executable to revoke an approval of one `_spender` only. */ function _revokeApproval( address _spender, bool _onlyExpired, uint248 _allowanceTimeToLive ) private returns ( bool _completed ) { // Returning to save progress is preferable to reverting. if (_hasInsufficientGasRemaining()) { return _completed; // false } _completed = true; /** * @dev * We thought we could save gas by calling the `_allowances[]` * array once out of storage rather than calling individual * values. Apparently Solidity charges a storage recall * /per index/ meaning grabbing a whole array is significantly * more expensive than calls of individual values as needed, provided * we don't call the same value out of storage more than once. uint[lenA] memory _allowances = _calcAllowance(msg.sender, _spender); */ /** * @dev * If the `allowance` is still active – that is, has not expired – * and `onlyExpired` is true, then don't delete this `allowance`. */ if (_onlyExpired) { /** * @dev * If the `allowance` is still active, leave it alone * and continue through the list of `approvedSpenders`. This * is because the sender desires only to destroy * `onlyExpired` approvals. * * @dev * If the `allowance` is perpetual with the sender having * explicitly having set the `_spender` as perpetual (having * no expiration date), then `continue` through the list. */ if ( allowances[msg.sender][_spender][aPerpetual] > 0 // `calcAllowance()` is higher in gas to calculate, hence second. || _calcAllowance( msg.sender, _spender, _allowanceTimeToLive )[aAllowance] > 0 ) { return _completed; // true } /** * @dev * Otherwise if the `_spender` has 0 allowance AND * was not previously registered by the sender as * having no expiration date then delete the allowance. */ delete allowances[msg.sender][_spender][aAllowance]; return _completed; // true } /** * @dev * If not `onlyExpired` then the sender desires to destroy * all data related to their `allowances`. */ delete allowances[msg.sender][_spender]; return _completed; // true } // ------------------------------------------------------------------ // // -------------------------- SETTERS --------------------------- // /** * @dev * Private executable for changing the `adminWallet` and/or `treasuryWallet`. * Saves bytecode to combine the functionality into a private exec function. */ function _execAdminTreasuryWalletChange( address _newWallet, address _existingWallet, bool _transferTokens, string[2] memory _errors ) private { require( _addAccount(_newWallet) > 0, _errors[0] // Invalid, null address. ); require( _newWallet != _existingWallet, _errors[1] // No change in address. ); if (_transferTokens) { // Enforces `allowance` if `adminWallet` != `treasuryWallet`. transferFrom( _existingWallet, _newWallet, balance[_existingWallet] ); } // Safest security measure is to erase stored Delegation. delete delegationMem[_existingWallet]; delete delegationMem[_newWallet]; } /** * @notice Only the `adminWallet` can replace itself and set a successor. */ function setAdminWallet( address newAdminWallet, bool transferTokens ) external _adminAuth { _execAdminTreasuryWalletChange( newAdminWallet, adminWallet, transferTokens, [errors[errSetAdmin0], errors[errSetAdmin1]] ); /** * @notice * Outgoing `adminWallet` can choose to allow the incoming `adminWallet` * to inherit its `balance` or not. */ if (adminWallet == treasuryWallet) { setTreasuryWallet(newAdminWallet, transferTokens); } emit AdminChange(adminWallet, newAdminWallet); adminWallet = newAdminWallet; } /** * @notice By default the `treasuryWallet` is set to the `adminWallet`. * * @notice * `transferFrom()` is used instead of `_transfer()` because otherwise * an exploit exists where the `adminWallet` can `setTreasuryWallet()` * to anyone, then `setTreasuryWallet()` again to itself to steal all * the tokens from the intermediate account. By requiring an `approve()` * function for `adminWallet` to move tokens that do not belong to it, * we solve this exploit and require the `treasuryWallet` to `approve()` * the `adminWallet` thereby giving authorizsation to move its tokens. * * @notice * `treasuryWallet` can replace itself and set a new `treasuryWallet`. * `adminWallet` can strip any `treasuryWallet` of its privileges at any time. */ function setTreasuryWallet( address newTreasuryWallet, bool transferTokens ) public _adminOrTreasuryAuth { _execAdminTreasuryWalletChange( newTreasuryWallet, treasuryWallet, transferTokens && adminWallet != treasuryWallet, [errors[errSetTreasury0], errors[errSetTreasury1]] ); /** * @notice * Requiring the outgoing `treasuryWallet` to `approve()` the * `adminWallet` in the case where the `adminWallet` is not also * the `treasuryWallet` ensures that `adminWallet` cannot rugpull * (steal tokens) by the exploit explained at this function's header. */ emit TreasuryChange(treasuryWallet, newTreasuryWallet); treasuryWallet = newTreasuryWallet; } /** * @dev * Allows `adminWallet` or `treasuryWallet` to set a `guardianWallet` * to execute basic housekeeping tasks on the former's behalf. No * verification of `address(0)` or other null addresses since that would * prohibit `adminWallet` and `treasuryWallet` from deleting the * `guardianWallet` should it choose to do so. */ function setGuardianWallet( address newGuardianWallet ) external _adminOrTreasuryAuth { guardianWallet = newGuardianWallet; } /** * @dev * EVM in 2023 doesn't easily permit looping across a wide battery of * accounts. Our workaround is to loop over the same elements across * multiple blocks. To ensure that millions of gas isn't wasted when * looping across multiple blocks, we set the minimum `gasPerLoop` and * `breakAtGasThreshold` variables. We do not see any exploit possible * here other than annoying users by artificially inflating the amount * of gas required to submit a looping transaction. Any unspent gas * is refunded on transaction completion regardless of the values of * `gasPerLoop` and `breakAtGasThreshold`. * * @notice * These two variables are changeable to allow the `adminWallet`, * `treasuryWallet`, or `guardianWallet` to adjust the required gas * parameters in the two cases: * # Blockchain parameters change. * # Looping transactions revert or run out of gas * instead of gracefully returning. */ function setGasPerLoop( uint newGasPerLoop, uint newBreakAtGasThreshold ) external _adminTreasuryOrGuardianAuth { /** * @dev * Ensure the new `gasPerLoop` would still allow at least a few * accounts to be looped over in the `rainAll()` function. */ require( newGasPerLoop <= block.gaslimit / 20, errors[errSetGasPerLoop] ); /** * @dev * Setting the `gasPerLoop` to the same as `breakAtGasThreshold` * could result in sufficient gas being given to run another loop * but insufficient to closing the transaction after breaking the * loop. For sure setting `breakAtGasThreshold` /below/ `gasPerLoop` * could easily result in reverting loops and millions of gas lost. */ require( newGasPerLoop < newBreakAtGasThreshold, errors[errSetGasValues] ); /** * @dev * Reasonable to allow a minimum of 3/4 the `block.gaslimit` * to be used for looping only before breaking and closing. */ require( newBreakAtGasThreshold <= block.gaslimit / 4, errors[errSetBreakAtGasThres] ); /** * @dev * Save the values into storage and update the relevant error message. */ gasPerLoop = newGasPerLoop; breakAtGasThreshold = newBreakAtGasThreshold; _updateErrorMsg_gasPerLoop(); } /** * @notice * Set a minimum balance required to qualify for * inclusion in `rain()` and `rainAll()` functions. * * @notice * Default is 1 whole token required. * Accounts with a fraction of a token, as in <= 0.999999, are excluded. */ function setRainMinimumBalance( uint newRainMinimumBalance ) external _adminOrTreasuryAuth { // Enforce a maximum required balance of 4200.69 tokens. require( newRainMinimumBalance <= __maxRainThreshold, errors[errSetRainMinBalance] ); rainMinimumBalance = newRainMinimumBalance; } // ------------------------------------------------------------------ // // ---------------------- ERC-20 FUNCTIONS ---------------------- // /** * @notice Section dedicated to externally-facing ERC-20 functions. */ /** * @dev * Prevent tokens from being irrevocably lost by requiring users to submit * `transferFrom()` transactions to transfer to a smart contract. While this * is unexpected ERC-20 functionality, it's also only applied when a * non-contract wallet – a person – transfers directly to an address at * which a contract exists. The only exclusions are the `guardianWallet`, * `treasuryWallet`, and `adminWallet` since our intent is for those * addresses to always be able to accept and manage any and all tokens * such as them being multi-sig wallet contracts. * * @notice * Be aware that `transferFrom()` transactions made by an account owner * themselves will bypass the `approve()` requirement and execute * as if they were a standard `transfer()` transaction. We consider this * acceptable functionality since account owners should always be free to * do with their tokens what they like without needing to authorizse * themselves. Furthermore, forcing users to call a different function will * almost assuredly prevent unintended transfers directly to contracts. * Most EVM contracts in 2023 cannot react to tokens sent directly via * ERC-20's standard `transfer()` method. By being forced to call a * separate function, users are made aware of the danger but may * still proceed should they desire to transfer directly to a contract. * * @notice ERC-20 required function. */ function transfer(address to, uint amount) external returns (bool) { /** * @dev * If sent directly to a smart contract, tell the user to use * `transferFrom()`. This check adds ≈ 3000 gas to a `transfer()` * transaction, increasing the cost from ≈ 37000 to ≈ 40000 total. */ require( _isContract(msg.sender) || !_isContract(to) || _walletIsGuardianTreasuryOrAdmin(to), errors[errTransferContract] ); return _transfer(msg.sender, to, amount); } /** * @return balance -> Of the provided `owner`. * @notice ERC-20 required function. */ function balanceOf(address owner) external view returns (uint) { return balance[owner]; } /** * @return allowance -> That the `_account` has granted the `_spender`. * @notice ERC-20 required function. */ function allowance( address owner, address spender ) public view returns ( uint ) { /** * @dev * If the `allowanceTimeToLive` set by the `_owner` is * 0 then the `allowance` is perpetual. Otherwise, * any non-zero number should be treated as the * number of seconds into the future the user intends * for their `_spender`s `allowance` to expire. * * @dev * If current time is in the future from the `owner`s * `allowanceTimeToLive` number of seconds plus when the * `approve()` AKA `allowance` was set, then show that the * `allowance` is 0 (expired). Otherwise, return the calculated * value based on the actual one stored in the `allowances` mapping. */ return _calcAllowance(owner, spender, allowanceTimeToLive[owner])[aAllowance]; } /** * @notice * 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. * * @notice * While the Ethereum community states, "One possible solution to mitigate * this race condition is to first reduce the spender's `allowance` to 0 * and set the desired value afterwards" we do not see how unfortunate * transaction ordering can't still spend the outgoing `allowance` before * it is set to 0. * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM * * @notice ERC-20 required function. */ function approve(address spender, uint amount) external returns (bool) { return _approve(msg.sender, spender, amount); } /** * @notice * Defined with `public` visibility to allow for use in `setTreasuryWallet()`. * Pre-requisite to use: Owner gives an `allowance` to the `sender`. * `sender` may now `transferFrom()` `owner` to any `recipient` of their * choosing for any amount up to `allowance[owner][recipient][aAllowance]`. * * @notice * Since the transfer may be called with the possibility of * `from` != `msg.sender` we opt for the variable name * `owner` instead of `from`, and `recipient` instead of `to`. * * @notice ERC-20 required function. */ function transferFrom( address owner, address recipient, uint amount ) public returns (bool) { uint _allowance = allowance(owner, msg.sender); /** * @notice * Always allow a transaction where the `msg.sender` is the `owner` * by adjusting `allowances`, essentially giving a token holder unlimited * `allowance` for themselves to mirror `transfer()` functionality. */ if (msg.sender == owner && _allowance <= amount) { /** * @dev * Costs less gas to check `if{}` statement than to `delete` if * already set to 0. Very likely a `msg.sender` won't ever set * their allowance at all meaning it'll be 0 most of the time. */ if (_allowance > 0) { delete allowances[msg.sender][msg.sender][aAllowance]; } } /** * @notice * Otherwise if the `msg.sender` is not the `owner` or if they provided * themselves with sufficient `allowance`, then continue into the * `else{}` statement. */ else { /** * @dev * Nesting the `require()` this way ensures lower gas cost since we * allow execution if `msg.sender` == `sender` with the special * case of a token holder wanting to directly call `transferFrom()` * themselves. That special case exists because of our desire to * prevent the extremely common user error of using `transfer()` * to send directly to a smart contract. These smart contracts * in 2023 EVM won't typically register they've received anything * and thus the tokens will be lost forever. The common exception * is a multi-sig wallet via smart contract which we have no ability * to identify and exempt from our checks. */ require( _allowance >= amount, string.concat( errors[errInsufficientAllowance], _tokenValueAsString(_allowance) ) ); /** * @dev * Disallow the subtraction of `allowance` by `amount` * if `_allowance != type(uint).max`. Saves ≈ 2k gas * in the case of an `owner` setting `spender`s * `allowance` to be effectively unlimited. While this * doesn't strictly adhere to the ERC-20 standard, this * functionality is quite common and saves gas when there * exists no materially significant outcome difference. */ if (_allowance != type(uint).max) { allowances[owner][msg.sender][aAllowance] -= amount; } /** * @dev * Important to note that we use `msg.sender` NOT `recipient` since * the former adheres to the ERC-20 standard whereas requiring * `msg.sender` == `recipient` or checking the `recipient`s * `allowance` is standard-breaking. Many protocols have a * higher-level contract administer – commonly known as a router – * to `transferFrom()` a user to a separate contract for actual * execution. This means the `msg.sender` will be approved but * a `recipient` may not be. */ } // Execute the transfer and emit a {Transfer} event. return _transfer(owner, recipient, amount); } // ------------------------------------------------------------------ // // ------------------ ERC-20 EXTENDED FUNCTIONS ----------------- // /** * @notice Section dedicated to extended EIP-2612 functionality. * * @notice * Function name uses "Approvals" instead of "Allowances" because its * purpose is to delete all information related a given spender on sender's * behalf. If we were only erasing the amount – as in the value stored at * the `aAllowance` index in the `allowances` array – then we would've opted * for "eraseAllAllowances()" as a function name. Instead this function * destroys all traces of all approvals if run with `_onlyExpired` == false. * * @notice EIP-2612 extended function. */ function eraseAllApprovals( bool onlyExpired ) external returns ( bool ) { return _eraseAllApprovals(onlyExpired, allowanceTimeToLive[msg.sender]); } /** * @dev * Setting an account's `allowanceTimeToLive` to less than * ≈ 30 seconds could very easily result in transfers * bricking. Can be set to 0 to remove the limit entirely. * * @notice ERC-20 extended function. */ function setAllowanceTimeToLive(uint newAllowanceTimeToLive) external { require( ( newAllowanceTimeToLive >= __minSecsAllowanceTimeToLive // 30 seconds && newAllowanceTimeToLive <= type(uint248).max ) || newAllowanceTimeToLive == 0, // Otherwise, give an error. errors[errSetAllowanceTimeToLive] ); /** * @dev * To ensure lingering `approve()`s don't suddenly appear, the best * course of action is to `eraseAllApprovals()` if the user is * setting their `allowanceTimeToLive` to: * # A different length of time than their current setting * # AND is either setting it to * # 0 (that being perpetual/indefinite `approve()`s) * # A longer duration of time than their current setting * In those scenarios we'd want to `eraseAllApprovals()`s. * Setting the `allowanceTimeToLive` to a /stricter/ setting such as * going from default 0 to 30 or from 60 to 45 seconds would not * need to invoke the `eraseAllApprovals()` since that would see * current `approve()`s become invalidated rather than previously * invalidated `approve()`s suddenly becoming valid again. */ uint248 _allowanceTimeToLive = allowanceTimeToLive[msg.sender]; if ( _allowanceTimeToLive != newAllowanceTimeToLive && ( newAllowanceTimeToLive == 0 || ( _allowanceTimeToLive > 0 && newAllowanceTimeToLive > _allowanceTimeToLive ) ) ) { /** * @dev * Stricter (shorter) time limits needn't * access and erase storage values since * they still get calculated as 0. */ if (!_eraseAllApprovals(true, _allowanceTimeToLive)) { return; } } allowanceTimeToLive[msg.sender] = uint248(newAllowanceTimeToLive); } /** * @dev * Allow the `msg.sender` to decide if they want to enable perpetual * approvals for the given `spender` or to delete/disable such setting. */ function setAllowancePerpetual(address spender, bool enable) external { /** * @dev * Prevent zombie `approve()`s from being revived. * No possible gas savings over accessing `aAllowance` * directly and then needing to fallback to * `_calcAllowance()` in most scenarios anyway. */ if (allowance(msg.sender, spender) == 0) { /** * @dev * Since we already know the allowance is 0 with the * current expiration, delete the `aAllowance` amount * to prevent it from being potentially revived after we * set the account to perpetual – unending – expiration. */ delete allowances[msg.sender][spender][aAllowance]; } /** * @dev Enable perpetual approvals by setting to non-zero. */ allowances[msg.sender][spender][aPerpetual] = enable ? block.timestamp : 0; } /** * @notice ERC-20 extended function. */ function increaseAllowance( address spender, uint amountToAdd ) external returns ( bool ) { uint _allowance = allowance(msg.sender, spender); return _approve(msg.sender, spender, _allowance + amountToAdd); } /** * @notice ERC-20 extended function. */ function decreaseAllowance( address spender, uint amountToDeduct ) external returns ( bool ) { uint _allowance = allowance(msg.sender, spender); require( _allowance >= amountToDeduct, string.concat( errors[errDecreaseAllowance], _tokenValueAsString(_allowance) ) ); return _approve(msg.sender, spender, _allowance - amountToDeduct); } /** * @notice Batch-transfer a list of index-linked recipients and amounts. * * @dev * Give the list of recipients the amount in the `amounts` list * using the index as a link between the two. The lists * must be of identical length to avoid unintended transfers. * * @notice ERC-20 extended function. */ function transferMultiple( address[] calldata recipients, uint[] calldata amounts ) external { require( recipients.length == amounts.length, errors[errTransferMultiple] ); _transferMultiple(msg.sender, false, recipients, amounts); } // ------------------------------------------------------------------ // // --------------------- EIP-2612 FUNCTIONS --------------------- // /** * @notice Section dedicated to all EIP-2612 logic. */ /** * @dev * This packed bytes may NOT be altered in any way * without completely breaking compatibility with * the EIP-2612 standard. EIP-2612 relies on * having a `PERMIT_TYPEHASH` that * returns an >> identical << result in Web3xx. * * @notice EIP-2612 required variable. */ bytes32 private constant PERMIT_TYPEHASH = keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ); // == 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9 /** * @notice Estimated gas cost ≈ 250,000. * @notice EIP-2612 required function. * * @dev Helpful links related to gasless approvals: * https://eips.ethereum.org/EIPS/eip-2612 * https://soliditydeveloper.com/erc20-permit * https://github.com/Uniswap/v3-periphery/blob/main/test/shared/permit.ts * https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2ERC20.sol#L81 * https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol#L112 * https://github.com/soliditylabs/ERC20-Permit/blob/main/contracts/ERC20Permit.sol#L33 * https://anettrolikova.medium.com/permits-as-free-approval-messages-for-signing-transactions-6f9b7c1b7ee0 * https://github.com/ethereum/EIPs/pull/5987#issuecomment-1351327168 * https://twitter.com/dmihal/status/1251505379391004672 * https://eips.ethereum.org/EIPS/eip-777 * https://www.blockchain-council.org/ethereum/ethereum-tokens-erc-20-vs-erc-223-vs-erc-777/ * * @dev * Executing with the `++` as a suffix on `nonces` will grab the current * `nonces` value, then increment by 1 after resolution of the `keccak256()` * calculation. We could of course write `++nonces[owner]` on a new line * after the function execution. However, writing the logic this way makes * it clear the nonce is used then incremented after its use. */ function permit( address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s ) external { require( deadline >= block.timestamp, errors[errPermitDeadline] ); bytes32 _digest = keccak256( abi.encodePacked( hex"1901", // == "\x19\x01" _getAndSaveDomainSeparator(), keccak256( abi.encode( PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline ) ) ) ); /** * @dev * Verify the `owner` matches the signature. VERY important. * This entire `permit()` and EIP-2612 gasless approval * system hinges on the ability to recover the `owner` * from the `v`, `r`, and `s` values given, and then for * those values to match the `_digest` calculated based * on the other arguments provided. */ require( owner == ecrecover(_digest, v, r, s), errors[errPermitBadSig] ); /** * @dev * `require()`s placed in order of * most likely to least likely to fail * to save gas on invalid executions. */ require( owner != address(0), errors[errPermit0] ); /** * @dev Execute the approval. */ _approve(owner, spender, value); } /** * @dev * Ideally we'd create a nested mapping to ensure any particular user * can create permits across multiple dApps without a nonce collision * occurring. Since there is only a single nonce, then each user could * only `permit()` one dApp at a time rather than being able to * simultaneously interact with multiple. On the plus side, ensuring a * user's `nonce` is the same across their entire account does enable the * ability to burn previous `permit()`s more easily and allows dApps * to more easily create signatures in Web3xx. * * @notice EIP-2612 required variable. */ mapping (address => uint) public nonces; /** * @notice EIP-2612 extended function. * * @notice * Allows a user to burn the oldest unused and previously-signed message, * thereby burning a previous `permit()` --> `approve()` they created. */ function permitBurn() external { ++nonces[msg.sender]; } /** * @notice EIP-2612 required variable. */ bytes32 private constant EIP712_DOMAIN = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); /** * @notice EIP-2612 required variable. */ bytes32 public DOMAIN_SEPARATOR; /** * @notice EIP-2612 derivative required variable. */ uint public chainId; /** * @notice EIP-2612 required function. */ function saveDomainSeparatorAndChainId() public { chainId = block.chainid; /** * @dev * From EIP-712. * https://eips.ethereum.org/EIPS/eip-712 * None of these fields can be altered in any way * without completely breaking compatibility with * the EIP-2612 standard, which itself relies on * having a `DOMAIN_SEPARATOR` per EIP-712 that * returns an >> identical << result in Web3xx. */ DOMAIN_SEPARATOR = keccak256( abi.encode( EIP712_DOMAIN, // EIP-712 required: Defined keccak256(bytes(name)), // EIP-712 required: Generated keccak256(bytes(version)), // EIP-712 required: Defined block.chainid, // EIP-712 required: Generated address(this) // EIP-712 required: Generated ) ); } /** * @dev * Grabs the `DOMAIN_SEPARATOR` and updates only * if the `block.chainid` changes. * * @notice * MUST be run during `constructor()` AFTER `name` is saved. * * @notice EIP-2612 extended function. */ function _getAndSaveDomainSeparator() private returns (bytes32) { if (block.chainid != chainId) { saveDomainSeparatorAndChainId(); } return DOMAIN_SEPARATOR; } // --------- EIP-2612 support ending --------- // ------------------------------------------------------------------ // // ----------------------------- RAIN --------------------------- // /** * @notice * The operation herein is identical to `rainAll()`. The `_amount` * applies to each account rained such that the total spend per `rain()` * is equal to { `_accountsToRain` x `_amount` }. If someone `rain()`s * 10 on 10 accounts, they will have `_transfer()`d away 100 tokens. */ function _rain( address _owner, uint _amount, uint _accountsToRain ) private { _rainAndListChecks(_owner, _amount, _accountsToRain, true); // Attempted randomness. uint _firstId = uint( keccak256( abi.encodePacked( tx.gasprice, block.timestamp, block.number, _amount, _accountsToRain ) ) ) % (numAccounts + 1); // Prevent modulo by 0. uint _increment = uint( keccak256( abi.encodePacked( blockhash(block.number - 1), block.timestamp % (_firstId + 1), gasleft(), _accountsToRain ) ) ) % (_accountsToRain + 1); // Prevent modulo by 0. uint _randomNumber = uint( keccak256( abi.encodePacked( blockhash(block.number - 2), _owner, account[numAccounts], gasleft() / 2, _firstId, _increment ) ) ); // Increase randomness. if (_randomNumber % 2 == 0) { ++_firstId; } if (_randomNumber % 6 == 0) { ++_increment; } if (_randomNumber % 7 == 0) { ++_firstId; } if (_randomNumber % 13 == 0) { ++_increment; } if (_firstId > numAccounts) { _firstId %= numAccounts; } if (_increment > numAccounts) { _increment %= numAccounts; } // Ensure no 0 values at the start. if (_firstId == 0) { ++_firstId; } if (_increment == 0) { ++_increment; } uint _startId = _firstId; uint _randomId = _startId; uint i; uint _excluded; for (; i < _accountsToRain; ++i) { // Close the `rain()` if gas is running out. if ( _hasInsufficientGasRemaining() && i > 0 && i + 1 < _accountsToRain ) { break; } /** * @notice * If the end of the accounts list has been reached, * wrap around and continue. */ if (_randomId > numAccounts) { _randomId -= numAccounts; } /** * @notice * If the current user to rain has already been rained, * since they were the `_startId` and `i` is no longer 0, * then seek forward by increments of 1 until the end of the * list is reached. If the rain is still ongoing, reset `_startId` * to one account before the `_firstId` and traverse backwards to * the 0 index. If the rain is /still/ ongoing after the `_startId` * hitting every single member in the accounts list, which will * occur when `_startId` == 0, then restart from * the original `_firstId`. */ if (_randomId == _startId && i > 0) { if (_startId >= _firstId) { ++_startId; } else { --_startId; } if (_startId == 0) { _startId = _firstId; } if (_startId > numAccounts) { _startId = _firstId - 1; /** * @dev * `_firstId` will always start at 1 or greater * since above we evaluate `_firstId == 0` * to result in `++_firstId`. */ } _randomId = _startId; /** This `_startId` should * be different from the one compared at the beginning * of this entire `if{}` flow. */ } /** * @dev * If this loop results in a skip, whether or not the `_randomId` * had their `id` set to 0 doesn't matter since we'll increment * `_excluded` even for a delete. Furthermore `_randomId` is * verified to be not greater than `numAccounts` at the start * of each loop. When compared to `i`, `_excluded` will be * an accurate number of loops in which no rain took place. */ if ( !_execRain( _owner, account[_randomId], _amount ) ) { /** * @dev * Make sure to continue for one additional loop * if this one was an unsuccessful rain transfer. * This should ensure that at the end of the * function, `i` - `_excluded` == the `_owner`s * originally intended number of accounts to rain. */ ++_excluded; ++_accountsToRain; } _randomId += _increment; } /** * @param _delegated -> `false` submitted since this function * should never run across multiple blocks and therefore * we needn't remember any info into `delegationMem`. */ _rainEnd(_owner, false, 0, 0, _amount * (i - _excluded)); } /** * @notice Externally facing for anyone to use on their own behalf. */ function rain(uint amount, uint accountsToRain) external { _rain(msg.sender, amount, accountsToRain); } /** * @notice Give `_amount` to each `_recipient` in the list. */ function _rainList( address _owner, bool _delegated, uint _amount, address[] calldata _recipients ) private { uint _end = _recipients.length; _rainAndListChecks(_owner, _amount, _end, true); uint _firstId; uint i; if (_delegated) { i = delegationMem[_owner][startIndex]; _firstId = i; } for (; i < _end; ++i) { if ( _delegated && _hasInsufficientGasRemaining() && i > _firstId && i + 1 < _end ) { break; } /** * @notice * No verification of `rainMinimumBalance` * nor if the `recipient` is a smart contract * where tokens may be irreversibly lost. */ _transfer(_owner, _recipients[i], _amount); } _rainEnd(_owner, _delegated, 0, i, _amount * (i - _firstId)); if (i >= _recipients.length) { emit RainList(_owner, _amount * _recipients.length); } } /** * @notice Give `amount` to each `_recipient` in the list. */ function rainList(uint amount, address[] calldata recipients) external { _rainList(msg.sender, false, amount, recipients); } /** * @notice * This will revert if there are 0 accounts. * This will skip raining on the owner's address. * Rains `_amount` to every single `account` * that qualifies inside `_execRain()`. */ function _rainAll( address _owner, bool _delegated, uint _amount ) private { _verifyLoopGas(maxRecipientsPerBlock); // Go for calculated max per block. uint _firstId = _delegated ? delegationMem[_owner][startIndex] : rainAllNextId[_owner]; /** * @dev * Avoid `rainAll()` on address(0). * Ensure this check occurs /after/ the `_delegated` if{} statement * above which sets `_firstId` to `delegationMem[startIndex]`. */ if (_firstId == 0) { ++_firstId; } // Slightly more gas efficient to create variables outside a `for` loop. uint i = _firstId; uint _lastIdToRain = i + (balance[_owner] / _safeDivision(_amount)); uint _excluded; address _recipient; // Time to loop until we run out of gas or reach `_lastIdToRain`. for (; i <= _lastIdToRain;) { /** * @dev * Don't break unless at least one account has been rained on * and also don't break if there's only one account remaining. */ if ( _hasInsufficientGasRemaining() && i < numAccounts && i > _firstId && i < _lastIdToRain ) { break; } /** * @dev * `numAccounts` can be incremented down * by `_execRain()`s `_setId()` function. * Thus we need a verification on each * loop to ensure we don't start looping * across null accounts beyond the ones * that exist. */ if (_lastIdToRain > numAccounts) { /** * @dev * If `i` has become greater than `numAccounts` * then break to avoid an infinite loop * going up through default values of `address(0)`. */ if (i > numAccounts) { break; } _lastIdToRain = numAccounts; } /** * @notice Skips if the `_owner` is the token `_recipient`. * @dev If `lastIdToRain` becomes larger than `numAccounts` * from this interaction, it'll get fixed on the next loop * before hitting any user. In case the `_owner` is the last * account registered, the loop will break above( inside the * `lastIdToRain` > `numAccounts` if{} flow). */ _recipient = account[i]; if ( !_execRain( _owner, _recipient, _amount ) ) { /** * @dev * If the account was not deleted (in which case `numAccounts` * would be incremented down), then permit an extra loop. */ if (id[_recipient] > 0) { ++_excluded; ++i; /** * @dev * Since this rain transfer was unsuccessful and the * account was not deleted (meaning it `_isContract()`), * then increment `lastIdToRain` up by 1 on the condition * that it isn't already a value of `numAccounts` or greater. */ if (_lastIdToRain < numAccounts) { ++_lastIdToRain; } } continue; } ++i; } /** * @dev * Prevent a revert if we make a simple math error in how many tokens * were rained during this `rainAll()` execution. */ uint _rainedAmount; if (i > _excluded + _firstId) { _rainedAmount = _amount * (i - _excluded - _firstId); } _rainEnd( _owner, _delegated, 0, i, _rainedAmount ); /** * @notice * Save the progress of the `rainAll()` if the `_owner` == `msg.sender` * where the rained tokens came from the account calling this function. */ if (!_delegated) { // Nested if{} with additional variable `rainAllNextId` set to `i`. if (_rainedAmount > 0) { rainAllRunningTotal[_owner] += _rainedAmount; } rainAllNextId[_owner] = i; } /** * @dev * If not every account was rained on, emit a standard {Rain} event * then return to prevent further logic execution and to ensure * the `rainAllNextId` and `rainAllRunningTotal` are both * properly saved for future completion. */ if (i < numAccounts) { return; } /** * @dev * If `_delegated` == true and completed – as evidenced by * `i` >= `numAccounts` – then emit a {RainAll} event and * return to avoid overwriting `msg.sender`s self-made progress * of `rainAllNextId` and `rainAllRunningTotal`. The * `delegationMem` structure should be deleted in the parent * `runMyDelegation()` function if this event is hit. */ if (_delegated) { emit RainAll(_owner, delegationMem[_owner][total]); return; } /** * @dev * All logic below here should only run if the `msg.sender` * is the account out of which the rain is paid. */ emit RainAll(_owner, rainAllRunningTotal[_owner]); // Reset the _owner's next account to rain variable. rainAllNextId[_owner] = 1; // Erase the running total number of tokens the `_owner` has rained. delete rainAllRunningTotal[_owner]; } /** * @dev * Costs ≈ 40,000 gas per recipient * for a soft cap of 198 recipients per block. */ function rainAll(uint amount) external { _rainAll(msg.sender, false, amount); } /** * @dev Saves info if `_delegated` and emits a {Rain} event. */ function _rainEnd( address _owner, bool _delegated, uint _excluded, uint _i, uint _rainedAmount ) private returns ( uint ) { if (_delegated) { if (_rainedAmount > 0) { delegationMem[_owner][total] += _rainedAmount; } if (_excluded > 0) { delegationMem[_owner][excluded] += _excluded; } delegationMem[_owner][startIndex] = _i; _excluded = delegationMem[_owner][excluded]; } emit Rain(_owner, _rainedAmount); return _excluded; } // ------------------------------------------------------------------ // // ------------------------- DELEGATION ------------------------- // /** * @notice * Our intent behind delegations is to enable users – most especially the * `adminWallet`, `treasuryWallet`, and `guardianWallet` – to execute * functions via an external, (likely) scripted wallet that may loop * across multiple blocks. This allows all the security that comes with * `address`-specific authentication with the flexibility and loop-ability * of scriptable software wallets. */ /** * @notice * Might be worthwhile for someone submitting a delegation to see the * encoded output to compare with what the `owner` actually set. * If the outputs don't match, don't bother sending the transaction. * Explain to the `owner` that the provided Delegation `input` * is invalid and doesn't match what they set. */ function encodeDelegation( address owner, Delegation calldata input ) public pure returns ( uint, bytes32 ) { return ( uint( keccak256( abi.encode( owner, input ) ) ), keccak256( abi.encodePacked( input.functionName ) ) ); } /* uint8 constant lenDelegates = 5; uint8 constant dFuncSetId = 0; uint8 constant dFuncTransferMultiple = 1; uint8 constant dFuncRain = 2; uint8 constant dFuncRainList = 3; uint8 constant dFuncRainAll = 4; */ bytes32[lenDelegates] delegateFunctions = [ keccak256(abi.encodePacked("setId()")), keccak256(abi.encodePacked("transferMultiple()")), keccak256(abi.encodePacked("rain()")), keccak256(abi.encodePacked("rainList()")), keccak256(abi.encodePacked("rainAll()")) ]; /** * @dev Verification of the Delegation struct being valid is performed * before saving the struct's info to storage. * * @param input.delegate -> submit `address(0)` to delete your delegation */ function setMyDelegation( Delegation calldata input ) external { delete delegationMem[msg.sender]; /** * @dev Return if the user only intends to delete their delegation. */ if (input.delegate == address(0)) { return; } /* mapping(address => uint[4]) public delegationMem; uint8 constant lenDelegationMem = 4; uint8 constant encodedDelegation = 0; uint8 constant startIndex = 1; uint8 constant total = 2; uint8 constant excluded = 3; struct Delegation { address delegate; string functionName; address[] recipients; uint[] amounts; } */ bytes32 _functionNameEncoded; ( delegationMem[msg.sender][encodedDelegation], _functionNameEncoded ) = encodeDelegation(msg.sender, input); /** * @dev * An alternative way to verify the delegate function is valid * written below. Downside of this one is that it doesn't * verify that any of the other arguments inside the provided * Delegation are valid for the function chosen. * for (uint8 i; i < lenDelegates; ++i) { if ( _functionNameEncoded == delegateFunctions[i] ) { return; } } revert(error_invalidDelegation); * */ // Copied requires from `setId()` if ( _functionNameEncoded == delegateFunctions[dFuncSetId] ) { require( _walletIsGuardianTreasuryOrAdmin(msg.sender), errors[errGuardianTreasuryAdminAuth] ); require( input.recipients.length == input.amounts.length, errors[errDelegateSetId] ); } // Copied requires from `transferMultiple()` else if ( _functionNameEncoded == delegateFunctions[dFuncTransferMultiple] ) { require( input.recipients.length == input.amounts.length, errors[errTransferMultiple] ); } // Copied requires from `rainList()` else if ( _functionNameEncoded == delegateFunctions[dFuncRainList] ) { require( input.amounts.length == 1, errors[errRainAmounts] ); _rainAndListChecks( msg.sender, input.amounts[rAmount], input.recipients.length, false ); } // Copied requires from `rain()` else if ( _functionNameEncoded == delegateFunctions[dFuncRain] ) { require( input.amounts.length == 2, errors[errRainAmounts] ); /** * @dev * In `rain()`: * `amounts[0]` --> `amount` --> `rAmount` * `amounts[1]` --> `accountsToRain` --> `rAccountsToRain` */ _rainAndListChecks( msg.sender, input.amounts[rAmount], input.amounts[rAccountsToRain], false ); } else { // Prevent invalid delegations being set if none of the above hit. require( _functionNameEncoded == delegateFunctions[dFuncRainAll], errors[errInvalidDelegation] ); // Copied requires from `rainAll()` require( input.amounts.length == 1, errors[errRainAmounts] ); } } /** * @notice Must have the exact parameters set by the `owner`. * * @dev * Run the delegation entrusted to me. * `owner` can run their own delegation even if they chose * a different delegate at `input.delegate`. */ function runMyDelegation( address owner, Delegation calldata input ) external { require( msg.sender != address(0), errors[errRunMyDelegation] ); /** * @dev * Only you or the `delegate` you chose can execute your * stored Delegation. */ require( msg.sender == input.delegate || msg.sender == owner, errors[errAuthMyDelegation] ); ( uint _encodedDelegation, bytes32 _functionNameEncoded ) = encodeDelegation(owner, input); /** * @dev After encoding the delegation, verify it matches what is stored. */ require( _encodedDelegation == delegationMem[owner][encodedDelegation], errors[errDelegationDoesntMatch] ); // `setId()` delegation if ( _functionNameEncoded == delegateFunctions[dFuncSetId] ) { /** * @dev * We ran into an issue where neither Remix nor Hardhat * would actually push the transaction through the loop * with sufficient gas for each account. To get around * this limitation of incorrect gas estimation, we simply * spoof another few `_accounts` into the gas `require()` * to ensure the Tx is pushed with sufficient gas. * * @dev * Swapping `id`s costs ≈ 50k gas whereas we enforce ≈ 23k per loop. * Therefore setting this value to 2x `rain()` ≈ 46k per loop should * be sufficient to loop through all the `setId()`s provided. * * @dev * Should the `gasPerLoop` value increase the worst that happens * is users push their Tx with additional gas and are refunded * on Tx completion. At least they ensure their gas was * spent on actually achieving the action(s) they desired. */ uint _accounts = input.recipients.length; /** * @dev * Somewhat more expensive than `rain()` due to our requirement * to verify the delegation before running. We estimate that'll * cost the same as 2x `rain()` execution loop. */ _verifyLoopGas(_accounts * 2); /** * @dev * Go through the entire list of `_accounts`, starting at * the remembered index in the `delegationMem` mapping. * By default this index starts at 0. */ uint i = delegationMem[owner][startIndex]; uint _start = i; for (; i < _accounts; ++i) { /** * @dev * Insufficient gas remaining? * Remember the current index and return to save progress. */ if ( _hasInsufficientGasRemaining() && i > _start && i + 1 < _accounts ) { delegationMem[owner][startIndex] = i; return; } /** * @dev Execute the `setId()` on the given account. */ _setId(input.recipients[i], input.amounts[i]); } } // `transferMultiple()` delegation else if ( _functionNameEncoded == delegateFunctions[dFuncTransferMultiple] ) { /** * @dev * Looping occurs inside the `_transferMultiple()` * private executable. */ _transferMultiple(owner, true, input.recipients, input.amounts); if (delegationMem[owner][startIndex] < input.recipients.length) { return; } } // `rainList()` delegation else if ( _functionNameEncoded == delegateFunctions[dFuncRainList] ) { /** * @dev * Looping occurs inside the `_rainList()` * private executable. */ _rainList( owner, true, input.amounts[rAmount], input.recipients ); if (delegationMem[owner][startIndex] < input.recipients.length) { return; } } // `rain()` delegation else if ( _functionNameEncoded == delegateFunctions[dFuncRain] ) { /** * @dev * In `_rain()` private executable: * `amounts[0]` --> `amount` --> `rAmount` * `amounts[1]` --> `accountsToRain` --> `rAccountsToRain` */ _rain( owner, input.amounts[rAmount], input.amounts[rAccountsToRain] ); } // `rainAll()` delegation else if ( _functionNameEncoded == delegateFunctions[dFuncRainAll] ) { /** * @dev * Looping occurs inside the `_rainAll()` * private executable. */ _rainAll( owner, true, input.amounts[rAmount] ); if (delegationMem[owner][startIndex] < numAccounts) { return; } } // Invalid or unknown delegation. else { revert(errors[errInvalidDelegation]); } /** * @dev * If delegation is successfully run, * delete the delegation to prevent * unintended expenditures. */ delete delegationMem[owner]; } // ------------------------------------------------------------------ // // ---------------------- CLAIM LOST ERC-20 --------------------- // /** * @notice * Our token contract has no way of knowing if it's received tokens. * Instead of implementing an ERC-223's `tokenFallback()` functionality * or ERC-777's `tokensReceived()` functionality, we opted for a custom * and much less complicated approach: Anyone can claim any outside tokens * sent to this token contract. * * @notice * Should tokens be sent to `address(this)` then in `_transfer()` * we re-route them to the `treasuryWallet`, thereby ensuring the tokens * this contract creates won't ever exist at `address(this)` and thus * won't be claimable via the below function. */ function claimERC20(address token) external { IERC20 _token = IERC20(token); uint tokenBalance = _token.balanceOf(address(this)); // costs 3000 gas emit Claimed(token, tokenBalance, msg.sender); if (tokenBalance > 0) { require( _token.transfer(msg.sender, tokenBalance), errors[errClaimERC20] ); } } } // ------------------------------------------------------------------------------------ // // = = = = = = = = = = = = = = = = = // // // // [email protected] // // [email protected] // // [email protected] // // // // 20 April 2023 // // = = = = = = = = = = = = = = = = = //
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_supply","type":"uint256"},{"internalType":"address","name":"_deployer","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"AdminChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"origin","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"gifter","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountThisBlock","type":"uint256"}],"name":"Rain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"total","type":"uint256"}],"name":"RainAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"total","type":"uint256"}],"name":"RainList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferMultiple","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"TreasuryChange","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"account","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"bool[]","name":"shouldBeProtected","type":"bool[]"}],"name":"addAccounts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"adminWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"breakAtGasThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"claimERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amountToDeduct","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"denominator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"components":[{"internalType":"address","name":"delegate","type":"address"},{"internalType":"string","name":"functionName","type":"string"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct TCC.Delegation","name":"input","type":"tuple"}],"name":"encodeDelegation","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bool","name":"onlyExpired","type":"bool"}],"name":"eraseAllApprovals","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gasPerLoop","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getAccount","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"bool","name":"protected","type":"bool"},{"components":[{"internalType":"uint248","name":"timeToLive","type":"uint248"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"timeRemaining","type":"uint256"},{"internalType":"uint256","name":"perpetualSince","type":"uint256"}],"internalType":"struct TCC.Approved[]","name":"list","type":"tuple[]"}],"internalType":"struct TCC.Approves","name":"approvedSpenders","type":"tuple"},{"components":[{"internalType":"bool","name":"excluded","type":"bool"},{"internalType":"uint256","name":"allNextId","type":"uint256"},{"internalType":"uint256","name":"allRunningTotal","type":"uint256"},{"internalType":"uint256","name":"delegation","type":"uint256"}],"internalType":"struct TCC.RainStruct","name":"rain","type":"tuple"}],"internalType":"struct TCC.Account","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getAccountById","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"bool","name":"protected","type":"bool"},{"components":[{"internalType":"uint248","name":"timeToLive","type":"uint248"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"timeRemaining","type":"uint256"},{"internalType":"uint256","name":"perpetualSince","type":"uint256"}],"internalType":"struct TCC.Approved[]","name":"list","type":"tuple[]"}],"internalType":"struct TCC.Approves","name":"approvedSpenders","type":"tuple"},{"components":[{"internalType":"bool","name":"excluded","type":"bool"},{"internalType":"uint256","name":"allNextId","type":"uint256"},{"internalType":"uint256","name":"allRunningTotal","type":"uint256"},{"internalType":"uint256","name":"delegation","type":"uint256"}],"internalType":"struct TCC.RainStruct","name":"rain","type":"tuple"}],"internalType":"struct TCC.Account","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAccountsList","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"bool","name":"protected","type":"bool"},{"components":[{"internalType":"uint248","name":"timeToLive","type":"uint248"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"timeRemaining","type":"uint256"},{"internalType":"uint256","name":"perpetualSince","type":"uint256"}],"internalType":"struct TCC.Approved[]","name":"list","type":"tuple[]"}],"internalType":"struct TCC.Approves","name":"approvedSpenders","type":"tuple"},{"components":[{"internalType":"bool","name":"excluded","type":"bool"},{"internalType":"uint256","name":"allNextId","type":"uint256"},{"internalType":"uint256","name":"allRunningTotal","type":"uint256"},{"internalType":"uint256","name":"delegation","type":"uint256"}],"internalType":"struct TCC.RainStruct","name":"rain","type":"tuple"}],"internalType":"struct TCC.Account[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"first","type":"uint256"},{"internalType":"uint256","name":"last","type":"uint256"}],"name":"getAccountsListByIds","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"bool","name":"protected","type":"bool"},{"components":[{"internalType":"uint248","name":"timeToLive","type":"uint248"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"timeRemaining","type":"uint256"},{"internalType":"uint256","name":"perpetualSince","type":"uint256"}],"internalType":"struct TCC.Approved[]","name":"list","type":"tuple[]"}],"internalType":"struct TCC.Approves","name":"approvedSpenders","type":"tuple"},{"components":[{"internalType":"bool","name":"excluded","type":"bool"},{"internalType":"uint256","name":"allNextId","type":"uint256"},{"internalType":"uint256","name":"allRunningTotal","type":"uint256"},{"internalType":"uint256","name":"delegation","type":"uint256"}],"internalType":"struct TCC.RainStruct","name":"rain","type":"tuple"}],"internalType":"struct TCC.Account[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCirculatingSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getErrors","outputs":[{"internalType":"string[34]","name":"","type":"string[34]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardianWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"id","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amountToAdd","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxRecipientsPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numAccounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"permitBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"accountsToRain","type":"uint256"}],"name":"rain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rainAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address[]","name":"recipients","type":"address[]"}],"name":"rainList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rainMinimumBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"components":[{"internalType":"address","name":"delegate","type":"address"},{"internalType":"string","name":"functionName","type":"string"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct TCC.Delegation","name":"input","type":"tuple"}],"name":"runMyDelegation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"saveDomainSeparatorAndChainId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdminWallet","type":"address"},{"internalType":"bool","name":"transferTokens","type":"bool"}],"name":"setAdminWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"bool","name":"enable","type":"bool"}],"name":"setAllowancePerpetual","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newAllowanceTimeToLive","type":"uint256"}],"name":"setAllowanceTimeToLive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_error","type":"string"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"setError","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newGasPerLoop","type":"uint256"},{"internalType":"uint256","name":"newBreakAtGasThreshold","type":"uint256"}],"name":"setGasPerLoop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGuardianWallet","type":"address"}],"name":"setGuardianWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"setId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"delegate","type":"address"},{"internalType":"string","name":"functionName","type":"string"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct TCC.Delegation","name":"input","type":"tuple"}],"name":"setMyDelegation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"bool","name":"shouldBeProtected","type":"bool"}],"name":"setProtected","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRainMinimumBalance","type":"uint256"}],"name":"setRainMinimumBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasuryWallet","type":"address"},{"internalType":"bool","name":"transferTokens","type":"bool"}],"name":"setTreasuryWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"transferMultiple","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasuryWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updateErrorMsg_gasPerLoop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"versionNotes","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c060405262000014620f42406001620003ac565b600055617aa860015561c3506002556040805160a081018252667365744964282960c81b60c0820152815160a781830301815260c782018352805160209182012082529151717472616e736665724d756c7469706c65282960701b818401529091820190603201604051602081830303815290604052805190602001208152602001604051602001620000b390657261696e282960d01b815260060190565b604051602081830303815290604052805190602001208152602001604051602001620000ef90697261696e4c697374282960b01b8152600a0190565b6040516020818303038152906040528051906020012081526020016040516020016200012a90687261696e416c6c282960b81b815260090190565b60408051601f19818403018152919052805160209091012090526200015490603990600562000352565b503480156200016257600080fd5b5060405162006582380380620065828339810160408190526200018591620004ba565b6003620001938682620005e2565b506004620001a28582620005e2565b506080839052620001b7620f424084620003ac565b60a081905260288054336001600160a01b031991821681179092556029805482169092179091556001600160a01b038481166000818152602e60209081526040808320879055602a80549096169488169490941790945591519384529290917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3816001600160a01b03167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688560a0516040516200027f91815260200190565b60405180910390a2620002916200029c565b50505050506200072c565b466038556040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f90620002d390600390620006ae565b60408051918290038220828201825260018352603160f81b6020938401528151928301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160408051601f198184030181529190528051602090910120603755565b826005810192821562000383579160200282015b828111156200038357825182559160200191906001019062000366565b506200039192915062000395565b5090565b5b8082111562000391576000815560010162000396565b8082028115828204841417620003d257634e487b7160e01b600052601160045260246000fd5b92915050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200040057600080fd5b81516001600160401b03808211156200041d576200041d620003d8565b604051601f8301601f19908116603f01168101908282118183101715620004485762000448620003d8565b816040528381526020925086838588010111156200046557600080fd5b600091505b838210156200048957858201830151818301840152908201906200046a565b600093810190920192909252949350505050565b80516001600160a01b0381168114620004b557600080fd5b919050565b600080600080600060a08688031215620004d357600080fd5b85516001600160401b0380821115620004eb57600080fd5b620004f989838a01620003ee565b965060208801519150808211156200051057600080fd5b506200051f88828901620003ee565b9450506040860151925062000537606087016200049d565b915062000547608087016200049d565b90509295509295909350565b600181811c908216806200056857607f821691505b6020821081036200058957634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620005dd57600081815260208120601f850160051c81016020861015620005b85750805b601f850160051c820191505b81811015620005d957828155600101620005c4565b5050505b505050565b81516001600160401b03811115620005fe57620005fe620003d8565b62000616816200060f845462000553565b846200058f565b602080601f8311600181146200064e5760008415620006355750858301515b600019600386901b1c1916600185901b178555620005d9565b600085815260208120601f198616915b828110156200067f578886015182559484019460019091019084016200065e565b50858210156200069e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000808354620006be8162000553565b60018281168015620006d95760018114620006ef5762000720565b60ff198416875282151583028701945062000720565b8760005260208060002060005b85811015620007175781548a820152908401908201620006fc565b50505082870194505b50929695505050505050565b60805160a051615e2962000759600039600081816104560152610f62015260006103b60152615e296000f3fe608060405234801561001057600080fd5b506004361061038e5760003560e01c8063870a633d116101de578063ad469eb61161010f578063d505accf116100ad578063f02e4b041161007c578063f02e4b0414610898578063f506d635146108a0578063fbcbc0f1146108b3578063fe924c1e146108c657600080fd5b8063d505accf14610823578063dd62ed3e14610836578063e307e1bb14610849578063e520b83f1461085c57600080fd5b8063c4bdb06d116100e9578063c4bdb06d146107d5578063c8427b43146107dd578063d11d8779146107fd578063d2df3e0f1461081057600080fd5b8063ad469eb6146107a6578063b43f06ad146107b9578063c18a7485146107cc57600080fd5b806395d89b411161017c5780639f89090a116101565780639f89090a1461075a578063a05fccef1461076d578063a457c2d714610780578063a9059cbb1461079357600080fd5b806395d89b411461073f57806396ce0795146107475780639a8a05921461075157600080fd5b80638b49f6ee116101b85780638b49f6ee146106f05780638ce25a931461070357806391d6b5851461070c578063957e3fae1461071f57600080fd5b8063870a633d146106955780638955defb146106bd5780638a7f997c146106dd57600080fd5b8063313ce567116102c35780634626402b1161026157806370a082311161023057806370a0823114610623578063719e24c0146106595780637a0ea3fe1461066c5780637ecebe001461067557600080fd5b80634626402b146105a15780634f9fc267146105c157806350261a95146105d457806354fd4d50146105e757600080fd5b806336b19cd71161029d57806336b19cd7146105485780633950935114610568578063426ef74e1461057b5780634540709d1461058e57600080fd5b8063313ce5671461051257806333fd1fe21461052c5780633644e5151461053f57600080fd5b806318160ddd1161033057806323b872dd1161030a57806323b872dd1461049457806324ccc1ba146104a75780632b112e49146104af5780632dd7c658146104b757600080fd5b806318160ddd146104515780631c519ba61461047857806321b2d6c81461048157600080fd5b806306fdde031161036c57806306fdde0314610406578063095ea7b31461041b5780630ea4a9d21461043e57806314de9baa1461044857600080fd5b80630146844f14610393578063047fc9aa146103b157806305aca141146103e6575b600080fd5b61039b6108d9565b6040516103a89190614c03565b60405180910390f35b6103d87f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016103a8565b6103f96103f4366004614c6f565b6109a1565b6040516103a89190614db0565b61040e6109dd565b6040516103a89190614dc3565b61042e610429366004614dfa565b610a6b565b60405190151581526020016103a8565b610446610a7f565b005b6103d860025481565b6103d87f000000000000000000000000000000000000000000000000000000000000000081565b6103d860275481565b61044661048f366004614e32565b610b6d565b61042e6104a2366004614e69565b610dc9565b610446610f0f565b6103d8610f32565b6104ed6104c5366004614c6f565b602d6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103a8565b61051a600681565b60405160ff90911681526020016103a8565b61044661053a366004614c6f565b610fe8565b6103d860375481565b6028546104ed9073ffffffffffffffffffffffffffffffffffffffff1681565b61042e610576366004614dfa565b611073565b61042e610589366004614ea5565b61109e565b61044661059c366004614eda565b6110da565b6029546104ed9073ffffffffffffffffffffffffffffffffffffffff1681565b6104466105cf366004614e32565b611552565b6104466105e2366004614f28565b6115db565b61040e6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b6103d8610631366004614fa0565b73ffffffffffffffffffffffffffffffffffffffff166000908152602e602052604090205490565b610446610667366004614e32565b611651565b6103d860005481565b6103d8610683366004614fa0565b60366020526000908152604090205481565b6106a86106a3366004614eda565b611831565b604080519283526020830191909152016103a8565b6103d86106cb366004614fa0565b602c6020526000908152604090205481565b6104466106eb366004614e32565b6118bd565b6104466106fe366004615000565b611957565b6103d8602b5481565b61044661071a36600461506c565b611ae6565b602a546104ed9073ffffffffffffffffffffffffffffffffffffffff1681565b61040e611e0e565b6103d8620f424081565b6103d860385481565b610446610768366004614fa0565b611e1b565b61044661077b366004615000565b611ea6565b61042e61078e366004614dfa565b611ef2565b61042e6107a1366004614dfa565b611f78565b6104466107b4366004614c6f565b611fe9565b6104466107c7366004614dfa565b611ff8565b6103d860015481565b6104466120b7565b6107f06107eb3660046150a1565b6120c1565b6040516103a891906150c3565b61044661080b3660046150a1565b612128565b61044661081e366004614fa0565b61224d565b610446610831366004615143565b612420565b6103d86108443660046151b6565b6126d0565b610446610857366004614c6f565b61272c565b61040e6040518060400160405280601281526020017f323032332d30342d3230207c2046696e616c000000000000000000000000000081525081565b6107f06128ad565b6104466108ae3660046151e9565b6128c1565b6103f96108c1366004614fa0565b6128cf565b6104466108d43660046150a1565b612997565b6108e1614aac565b604080516104408101909152600560226000835b8282101561099857838201805461090b90615235565b80601f016020809104026020016040519081016040528092919081815260200182805461093790615235565b80156109845780601f1061095957610100808354040283529160200191610984565b820191906000526020600020905b81548152906001019060200180831161096757829003601f168201915b5050505050815260200190600101906108f5565b50505050905090565b6109a9614ad4565b6000828152602d60205260409020546109d79073ffffffffffffffffffffffffffffffffffffffff166128cf565b92915050565b600380546109ea90615235565b80601f0160208091040260200160405190810160405280929190818152602001828054610a1690615235565b8015610a635780601f10610a3857610100808354040283529160200191610a63565b820191906000526020600020905b815481529060010190602001808311610a4657829003601f168201915b505050505081565b6000610a783384846129a2565b9392505050565b466038556040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f90610ab490600390615313565b604080519182900382208282018252600183527f31000000000000000000000000000000000000000000000000000000000000006020938401528151928301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120603755565b610b7633612abf565b600790610bb9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b60405180910390fd5b50602954610d3a90839073ffffffffffffffffffffffffffffffffffffffff16838015610c04575060295460285473ffffffffffffffffffffffffffffffffffffffff908116911614155b60408051808201909152806005600e018054610c1f90615235565b80601f0160208091040260200160405190810160405280929190818152602001828054610c4b90615235565b8015610c985780601f10610c6d57610100808354040283529160200191610c98565b820191906000526020600020905b815481529060010190602001808311610c7b57829003601f168201915b50505091835250506020016005600f5b018054610cb490615235565b80601f0160208091040260200160405190810160405280929190818152602001828054610ce090615235565b8015610d2d5780601f10610d0257610100808354040283529160200191610d2d565b820191906000526020600020905b815481529060010190602001808311610d1057829003601f168201915b5050505050815250612b0f565b60295460405173ffffffffffffffffffffffffffffffffffffffff8085169216907f803605f0e28534cba577fd3b24b497857b9d8fd1b4105ce6b37c5c33b83ef76b90600090a350602980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600080610dd685336126d0565b90503373ffffffffffffffffffffffffffffffffffffffff8616148015610dfd5750828111155b15610e26578015610e21573360009081526034602090815260408083209091528120555b610efb565b82811015600b610e3583612c29565b604051602001610e469291906153f7565b60405160208183030381529060405290610e8d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb09190614dc3565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610efb5773ffffffffffffffffffffffffffffffffffffffff8516600090815260346020908152604080832033845290915281208054859290610ef590849061544b565b90915550505b610f06858585612c5d565b95945050505050565b3360009081526036602052604081208054909190610f2c9061545e565b90915550565b60285473ffffffffffffffffffffffffffffffffffffffff166000908152602e60205260408120548190610f86907f000000000000000000000000000000000000000000000000000000000000000061544b565b60295460285491925073ffffffffffffffffffffffffffffffffffffffff918216911614610fe35760295473ffffffffffffffffffffffffffffffffffffffff166000908152602e6020526040902054610fe0908261544b565b90505b919050565b610ff133612abf565b60079061102b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50601863fa61715082111561106d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50600055565b60008061108033856126d0565b905061109633856110918685615496565b6129a2565b949350505050565b336000908152603260205260408120546109d79083907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16612dd7565b602033611114576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b506111226020820182614fa0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061117057503373ffffffffffffffffffffffffffffffffffffffff8316145b6021906111aa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b506000806111b88484611831565b73ffffffffffffffffffffffffffffffffffffffff86166000908152603560205260409020549193509150602290831461121f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50603954810361135957600061123860408501856154a9565b915061124f905061124a826002615511565b612eda565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260356020526040902060010154805b828210156113515761128a612fa5565b801561129557508082115b80156112aa5750826112a8836001615496565b105b156112e35773ffffffffffffffffffffffffffffffffffffffff8716600090815260356020526040902082906001015550505050505050565b6113416112f360408801886154a9565b848181106113035761130361531f565b90506020020160208101906113189190614fa0565b61132560608901896154a9565b858181106113355761133561531f565b90506020020135612fb1565b61134a8261545e565b915061127a565b505050611511565b603a5481036113d25761138784600161137560408701876154a9565b61138260608901896154a9565b613052565b61139460408401846154a9565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260356020526040902090915060015b015410156113cd5750505050565b611511565b603c548103611419576113878460016113ee60608701876154a9565b6000816113fd576113fd61531f565b9050602002013586806040019061141491906154a9565b613251565b603b548103611476576113cd8461143360608601866154a9565b6000816114425761144261531f565b9050602002013585806060019061145991906154a9565b600181811061146a5761146a61531f565b9050602002013561339a565b603d5481036114dc576114ad84600161149260608701876154a9565b6000816114a1576114a161531f565b9050602002013561376e565b602b5473ffffffffffffffffffffffffffffffffffffffff8516600090815260356020526040902060016113bf565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152610bb09060239060040161534e565b73ffffffffffffffffffffffffffffffffffffffff841660009081526035602052604081208181556001810182905560028101829055600301555b50505050565b61155c33836126d0565b6000036115955733600090815260346020908152604080832073ffffffffffffffffffffffffffffffffffffffff861684529091528120555b806115a15760006115a3565b425b33600090815260346020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091529020600201555050565b6115e433613af5565b60089061161e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b506022811061162f5761162f615528565b8282600583602281106116445761164461531f565b019161154c9190836155cc565b60285473ffffffffffffffffffffffffffffffffffffffff1633146006906116a6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b506028546040805180820190915261177391849173ffffffffffffffffffffffffffffffffffffffff909116908490806005600c0180546116e690615235565b80601f016020809104026020016040519081016040528092919081815260200182805461171290615235565b801561175f5780601f106117345761010080835404028352916020019161175f565b820191906000526020600020905b81548152906001019060200180831161174257829003601f168201915b50505091835250506020016005600d610ca8565b60295460285473ffffffffffffffffffffffffffffffffffffffff9182169116036117a2576117a28282610b6d565b60285460405173ffffffffffffffffffffffffffffffffffffffff8085169216907f38b1065e0d088f6eda3cb9f0efc7bbb9b145907ab0deb0dbfb700d2bb21599e990600090a350602880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000808383604051602001611847929190615836565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020918201209061188a9085018561595a565b60405160200161189b9291906159bf565b60405160208183030381529060405280519060200120915091505b9250929050565b6118c633613af5565b600890611900576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152602f6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b61196033613af5565b60089061199a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50828181146119ab576119ab615528565b6119b961124a6002836159fe565b60005b81811015611ade576119cc612fa5565b80156119d85750600081115b80156119ed5750816119eb826001615496565b105b156119f957505061154c565b611a28868683818110611a0e57611a0e61531f565b9050602002016020810190611a239190614fa0565b613b2b565b50838382818110611a3b57611a3b61531f565b9050602002016020810190611a509190614ea5565b602f6000888885818110611a6657611a6661531f565b9050602002016020810190611a7b9190614fa0565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055611ad78161545e565b90506119bc565b505050505050565b3360009081526035602052604081208181556001810182905560028101829055600301556000611b196020830183614fa0565b73ffffffffffffffffffffffffffffffffffffffff1603611b375750565b6000611b433383611831565b336000908152603560205260409020919091556039549091508103611c0b57611b6b33613af5565b600890611ba5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50611bb360608301836154a9565b9050611bc260408401846154a9565b919091149050600560095b0190611c06576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b505050565b603a548103611c3f57611c2160608301836154a9565b9050611c3060408401846154a9565b91909114905060056007611bcd565b603c548103611cd857611c5560608301836154a9565b601e9150600114611c93576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50611cd433611ca560608501856154a9565b600081611cb457611cb461531f565b90506020020135848060400190611ccb91906154a9565b90506000613be6565b5050565b603b548103611d8357611cee60608301836154a9565b601e9150600214611d2c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50611cd433611d3e60608501856154a9565b600081611d4d57611d4d61531f565b90506020020135848060600190611d6491906154a9565b6001818110611d7557611d7561531f565b905060200201356000613be6565b603d546023908214611dc2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50611dd060608301836154a9565b601e9150600114611c06576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b600480546109ea90615235565b611e2433612abf565b600790611e5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50602a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600c818414611ee2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b5061154c33600086868686613052565b600080611eff33856126d0565b9050828110156025611f1083612c29565b604051602001611f219291906153f7565b60405160208183030381529060405290611f68576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb09190614dc3565b506110963385611091868561544b565b6000611f8333613cd6565b80611f945750611f9283613cd6565b155b80611fa35750611fa383613af5565b600a90611fdd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50610a78338484612c5d565b611ff53360008361376e565b50565b61200133613af5565b60089061203b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b506000818152602d602090815260408083205473ffffffffffffffffffffffffffffffffffffffff168352602f90915290205460109060ff16156120ac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50611cd48282612fb1565b6120bf613d0f565b565b6060600d82841115612100576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50602b5482111561211e57602b5491508183111561211e57602b5492505b610a788383613da3565b61213133613af5565b60089061216b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b506121776014456159fe565b6015908311156121b4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b5060168183106121f1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b506121fd6004456159fe565b60179082111561223a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b5060018290556002819055611cd4613d0f565b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152819060009073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa1580156122bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e09190615a12565b90503373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f7e6632ca16a0ac6cf28448500b1a17d96c8b8163ad4c4a9b44ef5386cc02779e8360405161234191815260200190565b60405180910390a38015611c06576040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810182905273ffffffffffffffffffffffffffffffffffffffff83169063a9059cbb906044016020604051808303816000875af11580156123c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123e69190615a2b565b60249061154c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b601a4285101561245d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b506000612468613e89565b73ffffffffffffffffffffffffffffffffffffffff8916600090815260366020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928c928c928c929091906124c38361545e565b9091555060408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810187905260e001604051602081830303815290604052805190602001206040516020016125649291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201206000845290830180835281905260ff8716918301919091526060820185905260808201849052915060019060a0016020604051602081039080840390855afa1580156125ea573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151601b915073ffffffffffffffffffffffffffffffffffffffff8a8116911614612668576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50601973ffffffffffffffffffffffffffffffffffffffff89166126b9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b506126c58888886129a2565b505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff821660009081526032602052604081205461272490849084907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16613ea3565b519392505050565b601e811015801561275c57507effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8111155b80612765575080155b60269061279f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50336000908152603260205260409020547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16818114801590612835575081158061283557506000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161180156128355750807effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1682115b1561284d57612845600182612dd7565b61284d575050565b5033600090815260326020526040902080547fff00000000000000000000000000000000000000000000000000000000000000167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60606128bc6001602b54613da3565b905090565b611c06336000858585613251565b6128d7614ad4565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260326020908152604080832054815160c081018352602c8452828520548152808401869052858552602e84528285205481840152948452602f8352928190205460ff161515606085015280518082019091527effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921680835292916080830191810161297e8786613fd8565b9052815260200161298e856141b8565b90529392505050565b611cd433838361339a565b73ffffffffffffffffffffffffffffffffffffffff83811660009081526034602090815260408083209386168352929052908120828155600101548103612a475773ffffffffffffffffffffffffffffffffffffffff84811660009081526033602090815260408220805460018101825590835291200180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169185169190911790555b73ffffffffffffffffffffffffffffffffffffffff8481166000818152603460209081526040808320948816808452948252918290204260019091015590518581527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a35060019392505050565b6000612ae68260295473ffffffffffffffffffffffffffffffffffffffff91821691161490565b806109d7575060285473ffffffffffffffffffffffffffffffffffffffff8381169116146109d7565b6000612b1a85613b2b565b82519110612b55576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb09190614dc3565b50602081015173ffffffffffffffffffffffffffffffffffffffff84811690861603612bae576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb09190614dc3565b508115612bea5773ffffffffffffffffffffffffffffffffffffffff83166000908152602e6020526040902054612be89084908690610dc9565b505b73ffffffffffffffffffffffffffffffffffffffff83166000908152603560205260408120818155600181018290556002810182905560030155611511565b6060612c3482614251565b604051612c479190600590602001615a48565b6040516020818303038152906040529050919050565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602e6020526040812054821115612c8f856143c3565b90612cc7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb09190614dc3565b50612cd183613b2b565b1580612ce15750612ce184614409565b15612d025760295473ffffffffffffffffffffffffffffffffffffffff1692505b73ffffffffffffffffffffffffffffffffffffffff84166000908152602e602052604081208054849290612d3790849061544b565b909155505073ffffffffffffffffffffffffffffffffffffffff83166000908152602e602052604081208054849290612d71908490615496565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051612aad91815260200190565b33600090815260336020908152604080832080548251818502810185019093528083528493830182828015612e4257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612e17575b50505050509050612e66600282516003612e5c9190615511565b61124a91906159fe565b60005b8151811015612eb157612e96828281518110612e8757612e8761531f565b6020026020010151868661446a565b612ea15750506109d7565b612eaa8161545e565b9050612e69565b506001915083612ed357336000908152603360205260408120612ed391614b44565b5092915050565b6000612ee58261545e565b915081600154612ef59190615511565b600254612f029190615496565b90506064612f1145605a615511565b612f1b91906159fe565b811115612f3c576064612f2f45605a615511565b612f3991906159fe565b90505b805a11601c612f4a83614549565b604051612f5e929190601d90602001615a66565b60405160208183030381529060405290611c06576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb09190614dc3565b60005a60025411905090565b6000612fbc83613b2b565b11801561300d575073ffffffffffffffffffffffffffffffffffffffff82166000908152602e6020526040902054158015612ff5575080155b8061300d575060008111801561300d5750602b548111155b600f90613047576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50611cd48282614679565b8261305c81612eda565b6000861561308f575073ffffffffffffffffffffffffffffffffffffffff87166000908152603560205260409020600101545b8060005b8383101561314f578880156130ab57506130ab612fa5565b80156130b657508183115b80156130cb5750836130c9846001615496565b105b61314f576131188a8989868181106130e5576130e561531f565b90506020020160208101906130fa9190614fa0565b88888781811061310c5761310c61531f565b90506020020135612c5d565b5085858481811061312b5761312b61531f565b905060200201358161313d9190615496565b90506131488361545e565b9250613093565b88156131bf5773ffffffffffffffffffffffffffffffffffffffff8a1660009081526035602052604090208190600201600082825461318e9190615496565b909155505073ffffffffffffffffffffffffffffffffffffffff8a1660009081526035602052604090208390600101555b868310613245578973ffffffffffffffffffffffffffffffffffffffff167fc9a1d560030214e7b5a46c36acf49151dc9dd436da71f508b44ca9f9dae6198a8a6132095782613233565b73ffffffffffffffffffffffffffffffffffffffff8c166000908152603560205260409020600201545b60405190815260200160405180910390a25b50505050505050505050565b8061325f8685836001613be6565b600080861561329557505073ffffffffffffffffffffffffffffffffffffffff8616600090815260356020526040902060010154805b82811015613313578680156132ad57506132ad612fa5565b80156132b857508181115b80156132cd5750826132cb826001615496565b105b61331357613302888686848181106132e7576132e761531f565b90506020020160208101906132fc9190614fa0565b88612c5d565b5061330c8161545e565b9050613295565b6133348888600084613325878261544b565b61332f908c615511565b614888565b508381106133905773ffffffffffffffffffffffffffffffffffffffff88167f53df978d4ae97f179e7d856b810e8cd7bd5bfd929a20e9e0051eecd88205347261337e8689615511565b60405190815260200160405180910390a25b5050505050505050565b6133a78383836001613be6565b6000602b5460016133b89190615496565b604080513a602082015242918101919091524360608201526080810185905260a0810184905260c0016040516020818303038152906040528051906020012060001c6134049190615a8e565b90506000613413836001615496565b61341e60014361544b565b4061342a846001615496565b6134349042615a8e565b5a60408051602081019490945283019190915260608201526080810185905260a0016040516020818303038152906040528051906020012060001c6134799190615a8e565b9050600061348860024361544b565b602b546000908152602d6020526040902054904090879073ffffffffffffffffffffffffffffffffffffffff1660025a6134c291906159fe565b6040805160208101959095527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606094851b8116918601919091529190921b16605483015260688201526088810184905260a8810183905260c801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209050613560600282615a8e565b600003613573576135708361545e565b92505b61357e600682615a8e565b6000036135915761358e8261545e565b91505b61359c600782615a8e565b6000036135af576135ac8361545e565b92505b6135ba600d82615a8e565b6000036135cd576135ca8261545e565b91505b602b548311156135e757602b546135e49084615a8e565b92505b602b5482111561360157602b546135fe9083615a8e565b91505b82600003613615576136128361545e565b92505b81600003613629576136268261545e565b91505b82806000805b878210156137455761363f612fa5565b801561364b5750600082115b801561366057508761365e836001615496565b105b61374557602b5483111561367e57602b5461367b908461544b565b92505b838314801561368d5750600082115b156136dd578684106136a9576136a28461545e565b93506136b5565b6136b284615aa2565b93505b836000036136c1578693505b602b548411156136d9576136d660018861544b565b93505b8392505b6000838152602d602052604090205461370e908b9073ffffffffffffffffffffffffffffffffffffffff168b6149a7565b6137295761371b8161545e565b90506137268861545e565b97505b6137338684615496565b925061373e8261545e565b915061362f565b6137618a60008080613757868861544b565b61332f908f615511565b5050505050505050505050565b613779602754612eda565b6000826137ab5773ffffffffffffffffffffffffffffffffffffffff84166000908152603060205260409020546137d5565b73ffffffffffffffffffffffffffffffffffffffff84166000908152603560205260409020600101545b9050806000036137eb576137e88161545e565b90505b8060006137f784614a96565b73ffffffffffffffffffffffffffffffffffffffff87166000908152602e602052604090205461382791906159fe565b6138319083615496565b90506000805b82841161392757613846612fa5565b80156138535750602b5484105b801561385e57508484115b801561386957508284105b61392757602b5483111561388657602b54841161392757602b5492505b506000838152602d602052604090205473ffffffffffffffffffffffffffffffffffffffff166138b78882886149a7565b6139175773ffffffffffffffffffffffffffffffffffffffff81166000908152602c602052604090205415613912576138ef8261545e565b91506138fa8461545e565b9350602b548310156139125761390f8361545e565b92505b613837565b6139208461545e565b9350613837565b60006139338684615496565b85111561395c5785613945848761544b565b61394f919061544b565b6139599088615511565b90505b61396a898960008885614888565b50876139da5780156139b15773ffffffffffffffffffffffffffffffffffffffff8916600090815260316020526040812080548392906139ab908490615496565b90915550505b73ffffffffffffffffffffffffffffffffffffffff891660009081526030602052604090208590555b602b548510156139ef57505050505050505050565b8715613a5c5773ffffffffffffffffffffffffffffffffffffffff891660008181526035602052604090207f62427b06ab2f53f0724decf97d0b787b5884c87d7d7ab86d5e2927b0044e7d7a906002015460405190815260200160405180910390a2505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff89166000818152603160209081526040918290205491519182527f62427b06ab2f53f0724decf97d0b787b5884c87d7d7ab86d5e2927b0044e7d7a910160405180910390a250505073ffffffffffffffffffffffffffffffffffffffff90951660009081526030602090815260408083206001905560319091528120555050505050565b6000613b1c82602a5473ffffffffffffffffffffffffffffffffffffffff91821691161490565b806109d757506109d782612abf565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602c602052604090205480151580613b635750613b6382614409565b15613b6d57919050565b602b60008154613b7c9061545e565b91829055506000818152602d60209081526040808320805473ffffffffffffffffffffffffffffffffffffffff9097167fffffffffffffffffffffffff000000000000000000000000000000000000000090971687179055948252602c9052929092208290555090565b613bf08284615511565b73ffffffffffffffffffffffffffffffffffffffff85166000908152602e60205260409020541015613c21856143c3565b613c33613c2e8587615511565b612c29565b604051602001613c44929190615ad7565b60405160208183030381529060405290613c8b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb09190614dc3565b50601f82613cc6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb0919061534e565b50801561154c5761154c82612eda565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611096575050151592915050565b613d1a600154614a96565b600254613d27904561544b565b613d3191906159fe565b602755600154613d4090614549565b613d4b600254614549565b613d56602754614549565b604051602001613d6893929190615b2f565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601d90611ff59082615c19565b606082613db1836001615496565b613dbb919061544b565b67ffffffffffffffff811115613dd357613dd3615557565b604051908082528060200260200182016040528015613e0c57816020015b613df9614ad4565b815260200190600190039081613df15790505b5090506000835b838111613e81576000818152602d6020526040902054613e489073ffffffffffffffffffffffffffffffffffffffff166128cf565b8383613e538161545e565b945081518110613e6557613e6561531f565b602002602001018190525080613e7a9061545e565b9050613e13565b505092915050565b60006038544614613e9c57613e9c610a7f565b5060375490565b613eab614b62565b60005b600360ff82161015613f2c5773ffffffffffffffffffffffffffffffffffffffff808616600090815260346020908152604080832093881683529290522060ff821660038110613f0057613f0061531f565b0154828260ff1660048110613f1757613f1761531f565b6020020152613f2581615d33565b9050613eae565b506020810151600090613f40846001615d52565b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16613f6b9190615496565b905042811115613f8557613f7f428261544b565b60608301525b6000837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16118015613fb857506040820151155b8015613fc657506060820151155b15613fd057600082525b509392505050565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260336020908152604080832080548251818502810185019093528083526060949383018282801561405b57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311614030575b50508351939450839250505067ffffffffffffffff81111561407f5761407f615557565b6040519080825280602002602001820160405280156140f857816020015b6140e56040518060a00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081525090565b81526020019060019003908161409d5790505b50925060005b818110156141af57600083828151811061411a5761411a61531f565b602002602001015190506000614131888389613ea3565b6040805160a08101825273ffffffffffffffffffffffffffffffffffffffff85168152825160208083019190915283015181830152606080840151908201529082015160808201528751919250908790859081106141915761419161531f565b60200260200101819052505050806141a89061545e565b90506140fe565b50505092915050565b6141e560405180608001604052806000151581526020016000815260200160008152602001600081525090565b60405180608001604052806141f984613cd6565b1515815273ffffffffffffffffffffffffffffffffffffffff93909316600081815260306020908152604080832054828801528383526031825280832054818801529282526035905220546060909301929092525090565b60608160000361429457505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b620f4240820660006142a582614549565b9050811561434d575b6142bc600a620f42406159fe565b82101561434d576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152508160405160200161430b929190615d8a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190529050614346600a83615511565b91506142ae565b61436261435d620f4240866159fe565b614549565b6040518060400160405280600181526020017f2e00000000000000000000000000000000000000000000000000000000000000815250826040516020016143ab93929190615db0565b60405160208183030381529060405292505050919050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602e60205260409020546060906009906143f890612c29565b604051602001612c479291906153f7565b600073ffffffffffffffffffffffffffffffffffffffff82161580614445575073ffffffffffffffffffffffffffffffffffffffff821661dead145b806109d7575073ffffffffffffffffffffffffffffffffffffffff8216301492915050565b6000614474612fa5565b610a785750600182156145065733600090815260346020908152604080832073ffffffffffffffffffffffffffffffffffffffff8816845290915281206002015411806144cc575060006144c9338685613ea3565b51115b610a785733600090815260346020908152604080832073ffffffffffffffffffffffffffffffffffffffff88168452909152812055610a78565b33600090815260346020908152604080832073ffffffffffffffffffffffffffffffffffffffff8816845290915281208181556001810182905560020155610a78565b60608160000361458c57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156145b35761459f8161545e565b90506145ac600a836159fe565b9150614590565b60008167ffffffffffffffff8111156145ce576145ce615557565b6040519080825280601f01601f1916602001820160405280156145f8576020820181803683370190505b5090505b84156110965761460d600a86615a8e565b614618906030615496565b60f81b8161462584615aa2565b935083815181106146385761463861531f565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350614672600a866159fe565b94506145fc565b6000818152602d602090815260408083205473ffffffffffffffffffffffffffffffffffffffff168352602f90915290205460ff16156146b7575050565b806000036147fb5773ffffffffffffffffffffffffffffffffffffffff82166000908152602f602052604090205460ff16156146f1575050565b602b805473ffffffffffffffffffffffffffffffffffffffff8481166000908152602c602081815260408084208054808652602d808552838720805499885284882080548a16808a52979096529387208054929055915581547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169094179091558154959094169490911693909317909255825490928261479383615aa2565b9091555081526020808201929092526040908101600090812080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905573ffffffffffffffffffffffffffffffffffffffff949094168452602c90915282209190915550565b73ffffffffffffffffffffffffffffffffffffffff9182166000908152602c602081815260408084208054808652602d8452828620805497875283872080548a16808952969095529290952080549590559390935582547fffffffffffffffffffffffff000000000000000000000000000000000000000090811690921790925581541691909216179055565b6000841561494d5781156148d55773ffffffffffffffffffffffffffffffffffffffff86166000908152603560205260409020829060020160008282546148cf9190615496565b90915550505b831561491a5773ffffffffffffffffffffffffffffffffffffffff86166000908152603560205260409020849060030160008282546149149190615496565b90915550505b73ffffffffffffffffffffffffffffffffffffffff86166000908152603560205260409020600181018490556003015493505b8573ffffffffffffffffffffffffffffffffffffffff167fb45345ab7bd05accbf85ceae28de4abb6b29a27e3e56ba477bd8946e5da6ee1a8360405161499591815260200190565b60405180910390a25091949350505050565b60008273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480614a08575073ffffffffffffffffffffffffffffffffffffffff83166000908152602f602052604090205460ff165b80614a175750614a1783614409565b610a785773ffffffffffffffffffffffffffffffffffffffff83166000908152602e602052604090205480158015614a50575060008054115b15614a6657614a60846000614679565b50610a78565b614a6f84613cd6565b15614a7a5750610a78565b6000548110613fd057614a8e858585612c5d565b915050610a78565b600081600003614aa857506001919050565b5090565b6040518061044001604052806022905b6060815260200190600190039081614abc5790505090565b6040805160c08101825260008082526020808301829052828401829052606080840183905284518086019095529184528301529060808201908152602001614b3f60405180608001604052806000151581526020016000815260200160008152602001600081525090565b905290565b5080546000825590600052602060002090810190611ff59190614b80565b60405180608001604052806004906020820280368337509192915050565b5b80821115614aa85760008155600101614b81565b60005b83811015614bb0578181015183820152602001614b98565b50506000910152565b60008151808452614bd1816020860160208601614b95565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020808252600090610460830183820185845b6022811015614c63577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0878503018352614c51848351614bb9565b93509184019190840190600101614c16565b50919695505050505050565b600060208284031215614c8157600080fd5b5035919050565b8051825260208082015173ffffffffffffffffffffffffffffffffffffffff908116828501526040808401518186015260608085015115158187015260808086015161012082890181905281517effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690890152850151610140880184905280516101608901819052600096918201959194939192906101808a019088905b80821015614d6a578851805187168452888101518985015287810151888501528581015186850152840151848401529787019760a09092019160019190910190614d25565b505060a08901519650614da360a08b01888051151582526020810151602083015260408101516040830152606081015160608301525050565b9998505050505050505050565b602081526000610a786020830184614c88565b602081526000610a786020830184614bb9565b803573ffffffffffffffffffffffffffffffffffffffff81168114610fe357600080fd5b60008060408385031215614e0d57600080fd5b614e1683614dd6565b946020939093013593505050565b8015158114611ff557600080fd5b60008060408385031215614e4557600080fd5b614e4e83614dd6565b91506020830135614e5e81614e24565b809150509250929050565b600080600060608486031215614e7e57600080fd5b614e8784614dd6565b9250614e9560208501614dd6565b9150604084013590509250925092565b600060208284031215614eb757600080fd5b8135610a7881614e24565b600060808284031215614ed457600080fd5b50919050565b60008060408385031215614eed57600080fd5b614ef683614dd6565b9150602083013567ffffffffffffffff811115614f1257600080fd5b614f1e85828601614ec2565b9150509250929050565b600080600060408486031215614f3d57600080fd5b833567ffffffffffffffff80821115614f5557600080fd5b818601915086601f830112614f6957600080fd5b813581811115614f7857600080fd5b876020828501011115614f8a57600080fd5b6020928301989097509590910135949350505050565b600060208284031215614fb257600080fd5b610a7882614dd6565b60008083601f840112614fcd57600080fd5b50813567ffffffffffffffff811115614fe557600080fd5b6020830191508360208260051b85010111156118b657600080fd5b6000806000806040858703121561501657600080fd5b843567ffffffffffffffff8082111561502e57600080fd5b61503a88838901614fbb565b9096509450602087013591508082111561505357600080fd5b5061506087828801614fbb565b95989497509550505050565b60006020828403121561507e57600080fd5b813567ffffffffffffffff81111561509557600080fd5b61109684828501614ec2565b600080604083850312156150b457600080fd5b50508035926020909101359150565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015615136577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452615124858351614c88565b945092850192908501906001016150ea565b5092979650505050505050565b600080600080600080600060e0888a03121561515e57600080fd5b61516788614dd6565b965061517560208901614dd6565b95506040880135945060608801359350608088013560ff8116811461519957600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156151c957600080fd5b6151d283614dd6565b91506151e060208401614dd6565b90509250929050565b6000806000604084860312156151fe57600080fd5b83359250602084013567ffffffffffffffff81111561521c57600080fd5b61522886828701614fbb565b9497909650939450505050565b600181811c9082168061524957607f821691505b602082108103614ed4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000815461528f81615235565b600182811680156152a757600181146152da57615309565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450615309565b8560005260208060002060005b858110156153005781548a8201529084019082016152e7565b50505082870194505b5050505092915050565b6000610a788284615282565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208083526000845461536281615235565b8084870152604060018084166000811461538357600181146153bb576153e9565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838a01528284151560051b8a010195506153e9565b896000528660002060005b858110156153e15781548b82018601529083019088016153c6565b8a0184019650505b509398975050505050505050565b60006154038285615282565b8351615413818360208801614b95565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156109d7576109d761541c565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361548f5761548f61541c565b5060010190565b808201808211156109d7576109d761541c565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126154de57600080fd5b83018035915067ffffffffffffffff8211156154f957600080fd5b6020019150600581901b36038213156118b657600080fd5b80820281158282048414176109d7576109d761541c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b601f821115611c0657600081815260208120601f850160051c810160208610156155ad5750805b601f850160051c820191505b81811015611ade578281556001016155b9565b67ffffffffffffffff8311156155e4576155e4615557565b6155f8836155f28354615235565b83615586565b6000601f84116001811461564a57600085156156145750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556156e0565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156156995786850135825560209485019460019092019101615679565b50868210156156d4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261576557600080fd5b830160208101925035905067ffffffffffffffff81111561578557600080fd5b8060051b36038213156118b657600080fd5b8183526000602080850194508260005b858110156157e05773ffffffffffffffffffffffffffffffffffffffff6157cd83614dd6565b16875295820195908201906001016157a7565b509495945050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561581d57600080fd5b8260051b80836020870137939093016020019392505050565b600073ffffffffffffffffffffffffffffffffffffffff8085168352604060208401528061586385614dd6565b1660408401525060208301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261589f57600080fd5b830160208101903567ffffffffffffffff8111156158bc57600080fd5b8036038213156158cb57600080fd5b608060608501526158e060c0850182846156e7565b9150506158f06040850185615730565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080868503016080870152615926848385615797565b93506159356060880188615730565b93509150808685030160a08701525061594f8383836157eb565b979650505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261598f57600080fd5b83018035915067ffffffffffffffff8211156159aa57600080fd5b6020019150368190038213156118b657600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615a0d57615a0d6159cf565b500490565b600060208284031215615a2457600080fd5b5051919050565b600060208284031215615a3d57600080fd5b8151610a7881614e24565b60008351615a5a818460208801614b95565b610f0681840185615282565b6000615a728286615282565b8451615a82818360208901614b95565b61594f81830186615282565b600082615a9d57615a9d6159cf565b500690565b600081615ab157615ab161541c565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60008351615ae9818460208801614b95565b7f2052657175697265643a200000000000000000000000000000000000000000009083019081528351615b2381600b840160208801614b95565b01600b01949350505050565b7f206761732e2052657175697265643a2000000000000000000000000000000000815260008451615b67816010850160208901614b95565b7f206761732f726563697069656e74202b200000000000000000000000000000006010918401918201528451615ba4816021840160208901614b95565b7f206761732f54782e200000000000000000000000000000000000000000000000602192909101918201528351615be281602a840160208801614b95565b7f206d617820726563697069656e74732e00000000000000000000000000000000602a9290910191820152603a0195945050505050565b815167ffffffffffffffff811115615c3357615c33615557565b615c4781615c418454615235565b84615586565b602080601f831160018114615c9a5760008415615c645750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611ade565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015615ce757888601518255948401946001909101908401615cc8565b5085821015615d2357878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600060ff821660ff8103615d4957615d4961541c565b60010192915050565b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff818116838216019080821115612ed357612ed361541c565b60008351615d9c818460208801614b95565b835190830190615413818360208801614b95565b60008451615dc2818460208901614b95565b845190830190615dd6818360208901614b95565b8451910190615de9818360208801614b95565b019594505050505056fea264697066735822122034c053c104a000e78fffe39a44e638b4da9cff0496d8b480ad4ab93278cfdc2d64736f6c6343000813003300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000054a48888000000000000000000000000eb19ffee8e29420d405a2bdb65137c53cbbd096b000000000000000000000000e524ae868b899a9d3cf7259b2579affd66c46823000000000000000000000000000000000000000000000000000000000000001d547269706c6520436f6e6669726d6174696f6e20436f6d6d756e69747900000000000000000000000000000000000000000000000000000000000000000000035443430000000000000000000000000000000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000054a48888000000000000000000000000eb19ffee8e29420d405a2bdb65137c53cbbd096b000000000000000000000000e524ae868b899a9d3cf7259b2579affd66c46823000000000000000000000000000000000000000000000000000000000000001d547269706c6520436f6e6669726d6174696f6e20436f6d6d756e69747900000000000000000000000000000000000000000000000000000000000000000000035443430000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _name (string): Triple Confirmation Community
Arg [1] : _symbol (string): TCC
Arg [2] : _supply (uint256): 1420069000
Arg [3] : _deployer (address): 0xeb19ffee8e29420d405a2bdb65137c53cbbd096b
Arg [4] : _guardian (address): 0xe524ae868b899a9d3cf7259b2579affd66c46823
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [2] : 0000000000000000000000000000000000000000000000000000000054a48888
Arg [3] : 000000000000000000000000eb19ffee8e29420d405a2bdb65137c53cbbd096b
Arg [4] : 000000000000000000000000e524ae868b899a9d3cf7259b2579affd66c46823
Arg [5] : 000000000000000000000000000000000000000000000000000000000000001d
Arg [6] : 547269706c6520436f6e6669726d6174696f6e20436f6d6d756e697479000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [8] : 5443430000000000000000000000000000000000000000000000000000000000
Deployed ByteCode Sourcemap
23379:119301:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28114:102;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;25994:28;;;;;;;;1506:25:1;;;1494:2;1479:18;25994:28:0;1360:177:1;41983:155:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;26919:34::-;;;:::i;:::-;;;;;;;:::i;95050:134::-;;;;;;:::i;:::-;;:::i;:::-;;;4749:14:1;;4742:22;4724:41;;4712:2;4697:18;95050:134:0;4584:187:1;111260:962:0;;;:::i;:::-;;25665:39;;;;;;26047:33;;;;;27997;;;;;;85873:833;;;;;;:::i;:::-;;:::i;95812:3691::-;;;;;;:::i;:::-;;:::i;110676:70::-;;;:::i;29794:663::-;;;:::i;32222:39::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;5728:42:1;5716:55;;;5698:74;;5686:2;5671:18;32222:39:0;5552:226:1;24575:34:0;;24608:1;24575:34;;;;;5955:4:1;5943:17;;;5925:36;;5913:2;5898:18;24575:34:0;5783:184:1;90158:366:0;;;;;;:::i;:::-;;:::i;111057:31::-;;;;;;29501:26;;;;;;;;;104222:267;;;;;;:::i;:::-;;:::i;100322:191::-;;;;;;:::i;:::-;;:::i;135194:6213::-;;;;;;:::i;:::-;;:::i;29534:29::-;;;;;;;;;103145:1009;;;;;;:::i;:::-;;:::i;45141:194::-;;;;;;:::i;:::-;;:::i;27003:36::-;;;;;;;;;;;;;;;;;;;;;93049:103;;;;;;:::i;:::-;93130:14;;93106:4;93130:14;;;:7;:14;;;;;;;93049:103;84307:718;;;;;;:::i;:::-;;:::i;25031:48::-;;;;;;110386:39;;;;;;:::i;:::-;;;;;;;;;;;;;;129398:526;;;;;;:::i;:::-;;:::i;:::-;;;;8040:25:1;;;8096:2;8081:18;;8074:34;;;;8013:18;129398:526:0;7866:248:1;32181:34:0;;;;;;:::i;:::-;;;;;;;;;;;;;;46852:181;;;;;;:::i;:::-;;:::i;45797:549::-;;;;;;:::i;:::-;;:::i;32151:23::-;;;;;;130757:4160;;;;;;:::i;:::-;;:::i;29570:29::-;;;;;;;;;26960:36;;;:::i;24880:48::-;;6741:7;24880:48;;111170:19;;;;;;87091:153;;;;;;:::i;:::-;;:::i;105416:313::-;;;;;;:::i;:::-;;:::i;104557:485::-;;;;;;:::i;:::-;;:::i;92331:594::-;;;;;;:::i;:::-;;:::i;127536:93::-;;;;;;:::i;:::-;;:::i;48024:229::-;;;;;;:::i;:::-;;:::i;25318:30::-;;;;;;48898:173;;;:::i;40627:624::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;88284:1570::-;;;;;;:::i;:::-;;:::i;142258:411::-;;;;;;:::i;:::-;;:::i;107978:1740::-;;;;;;:::i;:::-;;:::i;93297:937::-;;;;;;:::i;:::-;;:::i;100792:2163::-;;;;;;:::i;:::-;;:::i;27082:58::-;;;;;;;;;;;;;;;;;;;;;39891:123;;;:::i;120793:138::-;;;;;;:::i;:::-;;:::i;41349:531::-;;;;;;:::i;:::-;;:::i;119330:116::-;;;;;;:::i;:::-;;:::i;28114:102::-;28158:24;;:::i;:::-;28195:13;;;;;;;;;28202:6;28195:13;-1:-1:-1;28195:13:0;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28114:102;:::o;41983:155::-;42066:14;;:::i;:::-;42117:12;;;;:7;:12;;;;;;42106:24;;42117:12;;42106:10;:24::i;:::-;42099:31;41983:155;-1:-1:-1;;41983:155:0:o;26919:34::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;95050:134::-;95115:4;95139:37;95148:10;95160:7;95169:6;95139:8;:37::i;:::-;95132:44;95050:134;-1:-1:-1;;;95050:134:0:o;111260:962::-;111329:13;111319:7;:23;111908:22;;110867:119;;111908:22;;111924:4;;111908:22;:::i;:::-;;;;;;;;;;111999:7;;;;;;;;;;;;;;111806:397;;;;;14864:25:1;;;;14905:18;;14898:34;;;;111983:25:0;14948:18:1;;;14941:34;112056:13:0;14991:18:1;;;14984:34;112139:4:0;15034:19:1;;;15027:84;14836:19;;111806:397:0;;;;;;;;;;;;;111782:432;;111806:397;111782:432;;;;111763:16;:451;111260:962::o;85873:833::-;56836:36;56861:10;56836:24;:36::i;:::-;56887:28;;56814:112;;;;;;;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;86089:14:0::1;::::0;86012:229:::1;::::0;86057:17;;86089:14:::1;;86118::::0;:47;::::1;;;-1:-1:-1::0;86151:14:0::1;::::0;86136:11:::1;::::0;86151:14:::1;86136:11:::0;;::::1;86151:14:::0;::::1;86136:29;;86118:47;86012:229;::::0;;;;::::1;::::0;;;;86181:6:::1;5752:2;86181:23;86012:229;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;86012:229:0;;;-1:-1:-1;;86012:229:0::1;;86206:6;5790:2;86206:23;;86012:229;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;:30:::1;:229::i;:::-;86619:14;::::0;86604:49:::1;::::0;::::1;::::0;;::::1;::::0;86619:14:::1;::::0;86604:49:::1;::::0;86619:14:::1;::::0;86604:49:::1;-1:-1:-1::0;86664:14:0::1;:34:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;85873:833::o;95812:3691::-;95931:4;95948:15;95966:28;95976:5;95983:10;95966:9;:28::i;:::-;95948:46;-1:-1:-1;96294:10:0;:19;;;;:43;;;;;96331:6;96317:10;:20;;96294:43;96290:3089;;;96642:14;;96638:108;;96695:10;96684:22;;;;:10;:22;;;;;;;;:34;;;;;96677:53;96638:108;96290:3089;;;97869:20;;;;97944:32;97999:31;97869:20;97999:19;:31::i;:::-;97908:141;;;;;;;;;:::i;:::-;;;;;;;;;;;;;97843:221;;;;;;;;;;;;;;:::i;:::-;;98628:14;98614:10;:28;98610:120;;98663:17;;;;;;;:10;:17;;;;;;;;98681:10;98663:29;;;;;;;:51;;98708:6;;98663:17;:51;;98708:6;;98663:51;:::i;:::-;;;;-1:-1:-1;;98610:120:0;99460:35;99470:5;99477:9;99488:6;99460:9;:35::i;:::-;99453:42;95812:3691;-1:-1:-1;;;;;95812:3691:0:o;110676:70::-;110727:10;110720:18;;;;:6;:18;;;;;110718:20;;110720:18;;;110718:20;;;:::i;:::-;;;;-1:-1:-1;110676:70:0:o;29794:663::-;29913:11;;;;29849:4;29905:20;;;:7;:20;;;;;;29849:4;;29891:34;;:11;:34;:::i;:::-;30326:14;;30311:11;;29866:59;;-1:-1:-1;30326:14:0;30311:11;;;30326:14;;30311:29;30307:106;;30386:14;;;;30378:23;;;;:7;:23;;;;;;30357:44;;;;:::i;:::-;;;30307:106;30432:17;29794:663;-1:-1:-1;29794:663:0:o;90158:366::-;56836:36;56861:10;56836:24;:36::i;:::-;56887:28;;56814:112;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;90422:28:0;6841:10:::1;90364:43:::0;::::1;;90342:119;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;90474:18:0::1;:42:::0;90158:366::o;104222:267::-;104337:4;104360:15;104378:30;104388:10;104400:7;104378:9;:30::i;:::-;104360:48;-1:-1:-1;104426:55:0;104435:10;104447:7;104456:24;104469:11;104360:48;104456:24;:::i;:::-;104426:8;:55::i;:::-;104419:62;104222:267;-1:-1:-1;;;;104222:267:0:o;100322:191::-;100493:10;100411:4;100473:31;;;:19;:31;;;;;;100441:64;;100460:11;;100473:31;;100441:18;:64::i;135194:6213::-;135367:26;135328:10;135306:98;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;135593:14:0;;;;:5;:14;:::i;:::-;135579:28;;:10;:28;;;:64;;;-1:-1:-1;135624:10:0;:19;;;;135579:64;135658:27;;135557:139;;;;;;;;;;;;;:::i;:::-;;135724:23;135762:28;135804:30;135821:5;135828;135804:16;:30::i;:::-;136007:20;;;;;;;:13;:20;;;;;:39;135709:125;;-1:-1:-1;135709:125:0;-1:-1:-1;136061:32:0;;135985:61;;135963:141;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;136218:17:0;:29;136168:79;;136150:5038;;137357:14;137374:16;;;;:5;:16;:::i;:::-;:23;-1:-1:-1;137696:29:0;;-1:-1:-1;137711:13:0;137374:23;137723:1;137711:13;:::i;:::-;137696:14;:29::i;:::-;137997:20;;;137988:6;137997:20;;;:13;:20;;;;;4635:1;137997:32;;;138074:708;138085:9;138081:1;:13;138074:708;;;138339:30;:28;:30::i;:::-;:65;;;;;138398:6;138394:1;:10;138339:65;:107;;;;-1:-1:-1;138437:9:0;138429:5;:1;138433;138429:5;:::i;:::-;:17;138339:107;138313:261;;;138489:20;;;;;;;:13;:20;;;;;138524:1;;4635;138489:32;:36;-1:-1:-1;;;;;;;135194:6213:0:o;138313:261::-;138721:45;138728:16;;;;:5;:16;:::i;:::-;138745:1;138728:19;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;138749:13;;;;:5;:13;:::i;:::-;138763:1;138749:16;;;;;;;:::i;:::-;;;;;;;138721:6;:45::i;:::-;138096:3;;;:::i;:::-;;;138074:708;;;136259:2534;;;136150:5038;;;138922:40;;138872:90;;138854:2334;;139144:63;139162:5;139169:4;139175:16;;;;:5;:16;:::i;:::-;139193:13;;;;:5;:13;:::i;:::-;139144:17;:63::i;:::-;139263:16;;;;:5;:16;:::i;:::-;139228:20;;;;;;;:13;:20;;;;;139263:23;;-1:-1:-1;4635:1:0;139228:32;;;:58;139224:105;;;139307:7;;135194:6213;;:::o;139224:105::-;138854:2334;;;139461:32;;139411:82;;139393:1795;;139667:147;139695:5;139719:4;139742:13;;;;:5;:13;:::i;:::-;4406:1;139742:22;;;;;:::i;:::-;;;;;;;139783:5;:16;;;;;;;;:::i;:::-;139667:9;:147::i;139393:1795::-;140064:28;;140014:78;;139996:1192;;140363:134;140387:5;140411:13;;;;:5;:13;:::i;:::-;4406:1;140411:22;;;;;:::i;:::-;;;;;;;140452:5;:13;;;;;;;;:::i;:::-;4443:1;140452:30;;;;;;;:::i;:::-;;;;;;;140363:5;:134::i;139996:1192::-;140629:31;;140579:81;;140561:627;;140833:111;140860:5;140884:4;140907:13;;;;:5;:13;:::i;:::-;4406:1;140907:22;;;;;:::i;:::-;;;;;;;140833:8;:111::i;:::-;141000:11;;140965:20;;;;;;;:13;:20;;;;;4635:1;140965:32;;140561:627;141140:36;;;;;;;141147:28;;141140:36;;;:::i;140561:627::-;141379:20;;;;;;;:13;:20;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;141372:27:0;135295:6112;;135194:6213;;:::o;103145:1009::-;103507:30;103517:10;103529:7;103507:9;:30::i;:::-;103541:1;103507:35;103503:450;;103909:10;103898:22;;;;:10;:22;;;;;;;;;:31;;;;;;;;;103891:50;103503:450;104118:6;:28;;104145:1;104118:28;;;104127:15;104118:28;104070:10;104059:22;;;;:10;:22;;;;;;;;;:31;;;;;;;;;4116:1;104059:43;:87;-1:-1:-1;;103145:1009:0:o;45141:194::-;57342:44;57375:10;57342:32;:44::i;:::-;57401:36;;57320:128;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;5177:2:0::1;45276:17:::0;::::1;45269:25;;;;:::i;:::-;45321:6;;45305;45312:5;45305:13;;;;;;;:::i;:::-;;::::0;:22:::1;::::0;;:13;:22:::1;:::i;84307:718::-:0;56284:11;;;;56381:10;56273:22;56407:20;;56344:94;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;84506:11:0::1;::::0;84432:184:::1;::::0;;;;::::1;::::0;;;::::1;::::0;84477:14;;84506:11:::1;::::0;;::::1;::::0;84532:14;;84432:184;84562:6:::1;5679:2;84562:20;84432:184;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;84432:184:0;;;-1:-1:-1;;84432:184:0::1;;84584:6;5714:2;84584:20;::::0;84432:184:::1;84821:14;::::0;84806:11:::1;::::0;84821:14:::1;::::0;;::::1;84806:11:::0;::::1;:29:::0;84802:111:::1;;84852:49;84870:14;84886;84852:17;:49::i;:::-;84950:11;::::0;84938:40:::1;::::0;::::1;::::0;;::::1;::::0;84950:11:::1;::::0;84938:40:::1;::::0;84950:11:::1;::::0;84938:40:::1;-1:-1:-1::0;84989:11:0::1;:28:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;84307:718::o;129398:526::-;129522:4;129537:7;129677:5;129709;129640:97;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;129608:148;;129640:97;129608:148;;;;;129853:18;;;;:5;:18;:::i;:::-;129814:76;;;;;;;;;:::i;:::-;;;;;;;;;;;;;129786:119;;;;;;129563:353;;;;129398:526;;;;;;:::o;46852:181::-;57342:44;57375:10;57342:32;:44::i;:::-;57401:36;;57320:128;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;46988:17:0::1;::::0;;;::::1;;::::0;;;:9:::1;:17;::::0;;;;:37;;;::::1;::::0;::::1;;::::0;;;::::1;::::0;;46852:181::o;45797:549::-;57342:44;57375:10;57342:32;:44::i;:::-;57401:36;;57320:128;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;45970:8:0;46003:32;;::::1;45996:40;;;;:::i;:::-;46047:24;46062:8;46069:1;46062:4:::0;:8:::1;:::i;46047:24::-;46089:6;46084:255;46101:4;46097:1;:8;46084:255;;;46131:30;:28;:30::i;:::-;:39;;;;;46169:1;46165;:5;46131:39;:55;;;;-1:-1:-1::0;46182:4:0;46174:5:::1;:1:::0;46178::::1;46174:5;:::i;:::-;:12;46131:55;46127:102;;;46207:7;;;;46127:102;46243:24;46255:8;;46264:1;46255:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;46243;:24::i;:::-;;46307:17;;46325:1;46307:20;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;46282:9;:22;46292:8;;46301:1;46292:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;46282:22;;::::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;46282:22:0;:45;;;::::1;::::0;::::1;;::::0;;;::::1;::::0;;46107:3:::1;::::0;::::1;:::i;:::-;;;46084:255;;;;45945:401;45797:549:::0;;;;:::o;130757:4160::-;130876:10;130862:25;;;;:13;:25;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;131033:1:0;131007:14;;;;:5;:14;:::i;:::-;:28;;;131003:67;;130757:4160;:::o;131003:67::-;131562:28;131709:35;131726:10;131738:5;131709:16;:35::i;:::-;131630:10;131616:25;;;;:13;:25;;;;;131601:143;;;;132447:17;:29;131601:143;;-1:-1:-1;132397:79:0;;132379:2531;;132529:44;132562:10;132529:32;:44::i;:::-;132592:36;;132503:140;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;132747:13:0;;;;:5;:13;:::i;:::-;:20;-1:-1:-1;132686:16:0;;;;:5;:16;:::i;:::-;:81;;;;;-1:-1:-1;132786:6:0;5574:1;132786:24;;132660:165;;;;;;;;;;;;;;:::i;:::-;;130834:4083;130757:4160;:::o;132379:2531::-;132976:40;;132926:90;;132908:2002;;133130:13;;;;:5;:13;:::i;:::-;:20;-1:-1:-1;133069:16:0;;;;:5;:16;:::i;:::-;:81;;;;;-1:-1:-1;133169:6:0;5507:1;133169:27;;132908:2002;133354:32;;133304:82;;133286:1624;;133439:13;;;;:5;:13;:::i;:::-;133483:22;;-1:-1:-1;133463:1:0;133439:25;133413:107;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;133537:169:0;133574:10;133603:13;;;;:5;:13;:::i;:::-;4406:1;133603:22;;;;;:::i;:::-;;;;;;;133644:5;:16;;;;;;;;:::i;:::-;:23;;133686:5;133537:18;:169::i;:::-;130834:4083;130757:4160;:::o;133286:1624::-;133845:28;;133795:78;;133777:1133;;133928:13;;;;:5;:13;:::i;:::-;133972:22;;-1:-1:-1;133952:1:0;133928:25;133902:107;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;134248:176:0;134285:10;134314:13;;;;:5;:13;:::i;:::-;4406:1;134314:22;;;;;:::i;:::-;;;;;;;134355:5;:13;;;;;;;;:::i;:::-;4443:1;134355:30;;;;;;;:::i;:::-;;;;;;;134404:5;134248:18;:176::i;133777:1133::-;134632:31;;134682:28;;134574:89;;134548:177;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;134817:13:0;;;;:5;:13;:::i;:::-;134861:22;;-1:-1:-1;134841:1:0;134817:25;134791:107;;;;;;;;;;;;;:::i;26960:36::-;;;;;;;:::i;87091:153::-;56836:36;56861:10;56836:24;:36::i;:::-;56887:28;;56814:112;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;87202:14:0::1;:34:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;87091:153::o;105416:313::-;105615:27;105565:35;;;105543:110;;;;;;;;;;;;;:::i;:::-;;105664:57;105682:10;105694:5;105701:10;;105713:7;;105664:17;:57::i;104557:485::-;104675:4;104698:15;104716:30;104726:10;104738:7;104716:9;:30::i;:::-;104698:48;-1:-1:-1;104779:28:0;;;;104854;104901:31;104698:48;104901:19;:31::i;:::-;104822:125;;;;;;;;;:::i;:::-;;;;;;;;;;;;;104757:201;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;104976:58:0;104985:10;104997:7;105006:27;105019:14;105006:10;:27;:::i;92331:594::-;92392:4;92702:23;92714:10;92702:11;:23::i;:::-;:56;;;;92743:15;92755:2;92743:11;:15::i;:::-;92742:16;92702:56;:109;;;;92775:36;92808:2;92775:32;:36::i;:::-;92826:27;;92680:184;;;;;;;;;;;;;:::i;:::-;;92884:33;92894:10;92906:2;92910:6;92884:9;:33::i;127536:93::-;127586:35;127595:10;127607:5;127614:6;127586:8;:35::i;:::-;127536:93;:::o;48024:229::-;57342:44;57375:10;57342:32;:44::i;:::-;57401:36;;57320:128;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;48139:23:0::1;48149:12:::0;;;:7:::1;:12;::::0;;;;;;;;::::1;;48139:23:::0;;:9:::1;:23:::0;;;;;;48177:25;;48139:23:::1;;48138:24;48116:97;;;;;;;;;;;;;:::i;:::-;;48224:21;48231:8;48241:3;48224:6;:21::i;48898:173::-:0;49035:28;:26;:28::i;:::-;48898:173::o;40627:624::-;40738:16;40823:15;40795:13;;;;40773:76;;;;;;;;;;;;;:::i;:::-;;41049:11;;41042:4;:18;41038:162;;;41084:11;;;-1:-1:-1;41114:19:0;;;41110:79;;;41162:11;;41154:19;;41110:79;41217:26;41231:5;41238:4;41217:13;:26::i;88284:1570::-;57342:44;57375:10;57342:32;:44::i;:::-;57401:36;;57320:128;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;88653:19:0::1;88670:2;88653:14;:19;:::i;:::-;88687:24:::0;;88636:36;::::1;;88614:108;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;89240:23:0;89187:38;;::::1;89165:109;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;89517:18:0::1;89534:1;89517:14;:18;:::i;:::-;89550:29:::0;;89491:44;::::1;;89469:121;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;89726:10:0::1;:26:::0;;;89763:19:::1;:44:::0;;;89818:28:::1;:26;:28::i;142258:411::-:0;142373:31;;;;;142398:4;142373:31;;;5698:74:1;142336:5:0;;142313:13;;142373:16;;;;;;5671:18:1;;142373:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;142353:51;;142467:10;142438:40;;142446:5;142438:40;;;142453:12;142438:40;;;;1506:25:1;;1494:2;1479:18;;1360:177;142438:40:0;;;;;;;;142495:16;;142491:171;;142554:41;;;;;142570:10;142554:41;;;26229:74:1;26319:18;;;26312:34;;;142554:15:0;;;;;;26202:18:1;;142554:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;142614:21;;142528:122;;;;;;;;;;;;;:::i;107978:1740::-;108238:25;108208:15;108196:27;;;108174:100;;;;;;;;;;;;;:::i;:::-;;108287:15;108409:28;:26;:28::i;:::-;108665:13;;;;;;;:6;:13;;;;;:15;;106360:111;;108567:5;;108599:7;;108633:5;;108665:15;;:13;:15;;;:::i;:::-;;;;-1:-1:-1;108488:250:0;;;;;;26894:25:1;;;;26938:42;27016:15;;;26996:18;;;26989:43;27068:15;;;;27048:18;;;27041:43;27100:18;;;27093:34;27143:19;;;27136:35;27187:19;;;27180:35;;;26866:19;;108488:250:0;;;;;;;;;;;;108456:301;;;;;;108329:443;;;;;;;;27496:66:1;27484:79;;27588:1;27579:11;;27572:27;;;;27624:2;27615:12;;27608:28;27661:2;27652:12;;27226:444;108329:443:0;;;;;;;;;;;;;;108305:478;;108329:443;108305:478;;;;109245:27;;;;;;;;;27902:25:1;;;27975:4;27963:17;;27943:18;;;27936:45;;;;27997:18;;;27990:34;;;28040:18;;;28033:34;;;108305:478:0;-1:-1:-1;109245:27:0;;27874:19:1;;109245:27:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;109245:27:0;;;;;109287:23;;-1:-1:-1;109236:36:0;;;;;;;109214:107;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;109572:18:0;109538:19;;;109516:85;;;;;;;;;;;;;:::i;:::-;;109679:31;109688:5;109695:7;109704:5;109679:8;:31::i;:::-;;108163:1555;107978:1740;;;;;;;:::o;93297:937::-;94187:26;;;93404:4;94187:26;;;:19;:26;;;;;;94156:58;;94171:5;;94178:7;;94187:26;;94156:14;:58::i;:::-;:70;;;-1:-1:-1;;;93297:937:0:o;100792:2163::-;6899:2;100914:22;:54;;:132;;;;-1:-1:-1;101029:17:0;101003:43;;;100914:132;100895:210;;;-1:-1:-1;101078:27:0;;100895:210;101162:33;;100873:333;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;102205:10:0;102154:28;102185:31;;;:19;:31;;;;;;;;102245:46;;;;;;:281;;-1:-1:-1;102327:27:0;;;:184;;;102421:1;102398:20;:24;;;:94;;;;;102472:20;102447:45;;:22;:45;102398:94;102227:643;;;102770:46;102789:4;102795:20;102770:18;:46::i;:::-;102765:94;;102837:7;100792:2163;:::o;102765:94::-;-1:-1:-1;102902:10:0;102882:31;;;;:19;:31;;;;;:65;;;;;;;;;;;;;;;100792:2163::o;39891:123::-;39941:16;39977:29;39991:1;39994:11;;39977:13;:29::i;:::-;39970:36;;39891:123;:::o;120793:138::-;120875:48;120885:10;120897:5;120904:6;120912:10;;120875:9;:48::i;41349:531::-;41434:14;;:::i;:::-;41498:29;;;41467:28;41498:29;;;:19;:29;;;;;;;;;41545:327;;;;;;;41567:2;:12;;;;;;41545:327;;;;;;;;41617:17;;;:7;:17;;;;;;41545:327;;;;41649:19;;;:9;:19;;;;;;;;;41545:327;;;;;;41683:137;;;;;;;;41498:29;;;;41683:137;;;41498:29;41545:327;;;;;41683:137;;41749:56;41518:8;41498:29;41749:24;:56::i;:::-;41683:137;;41545:327;;;;41835:26;41852:8;41835:16;:26::i;:::-;41545:327;;41538:334;41349:531;-1:-1:-1;;;41349:531:0:o;119330:116::-;119397:41;119403:10;119415:6;119423:14;119397:5;:41::i;72406:2123::-;72720:18;;;;72533:4;72720:18;;;:10;:18;;;;;;;;:28;;;;;;;;;;;:50;;;4084:1;74001:40;;:45;;73997:117;;74063:24;;;;;;;;:16;:24;;;;;;;:39;;;;;;;;;;;;;;;;;;;;;;;;;;73997:117;74199:18;;;;;;;;:10;:18;;;;;;;;:28;;;;;;;;;;;;;74242:15;4084:1;74199:40;;;:58;74464:35;;1506:25:1;;;74464:35:0;;1479:18:1;74464:35:0;;;;;;;;-1:-1:-1;74517:4:0;72406:2123;;;;;:::o;56601:158::-;56674:4;56698:26;56716:7;56567:14;;;56556:25;;;56567:14;;56556:25;;56466:123;56698:26;:53;;;-1:-1:-1;56284:11:0;;;56273:22;;;56284:11;;56273:22;56728:23;56186:117;83331:867;83574:1;83548:23;83560:10;83548:11;:23::i;:::-;83590:10;;;-1:-1:-1;83526:111:0;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;83716:10:0;;;;83672:29;;;;;;;;83650:112;;;;;;;;;;;;;:::i;:::-;;83779:15;83775:256;;;83980:24;;;;;;;:7;:24;;;;;;83886:133;;83917:15;;83951:10;;83886:12;:133::i;:::-;;83775:256;84117:30;;;;;;;:13;:30;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;84110:37:0;-1:-1:-1;64388:229:0;64478:13;64545:21;64559:6;64545:13;:21::i;:::-;64517:92;;;;;64581:6;;64517:92;;;:::i;:::-;;;;;;;;;;;;;64510:99;;64388:229;;;:::o;69875:743::-;70042:14;;;69997:4;70042:14;;;:7;:14;;;;;;:25;-1:-1:-1;70042:25:0;70082:32;70050:5;70082:25;:32::i;:::-;70020:105;;;;;;;;;;;;;;:::i;:::-;;70300:16;70312:3;70300:11;:16::i;:::-;:21;;:46;;;70325:21;70340:5;70325:14;:21::i;:::-;70296:99;;;70369:14;;;;;-1:-1:-1;70296:99:0;70482:14;;;;;;;:7;:14;;;;;:25;;70500:7;;70482:14;:25;;70500:7;;70482:25;:::i;:::-;;;;-1:-1:-1;;70518:12:0;;;;;;;:7;:12;;;;;:23;;70534:7;;70518:12;:23;;70534:7;;70518:23;:::i;:::-;;;;;;;;70575:3;70559:29;;70568:5;70559:29;;;70580:7;70559:29;;;;1506:25:1;;1494:2;1479:18;;1360:177;79238:863:0;79447:10;79367:15;79430:28;;;:16;:28;;;;;;;;79401:57;;;;;;;;;;;;;;;;;79367:15;;79401:57;;79430:28;79401:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79469:40;79507:1;79488:9;:16;79484:1;:20;;;;:::i;:::-;:24;;;;:::i;79469:40::-;79674:6;79669:199;79686:9;:16;79682:1;:20;79669:199;;;79729:65;79745:9;79755:1;79745:12;;;;;;;;:::i;:::-;;;;;;;79759;79773:20;79729:15;:65::i;:::-;79724:133;;79815:17;;;;79724:133;79704:3;;;:::i;:::-;;;79669:199;;;;79893:4;79880:17;;79988:12;79983:81;;80041:10;80024:28;;;;:16;:28;;;;;80017:35;;;:::i;:::-;80076:17;79238:863;;;;:::o;67183:1443::-;68008:17;68064:8;;;:::i;:::-;;;;68051:10;;:21;;;;:::i;:::-;68028:19;;:45;;;;:::i;:::-;68008:65;-1:-1:-1;68125:3:0;68103:19;68108:14;68103:2;:19;:::i;:::-;:25;;;;:::i;:::-;68088:12;:40;68084:113;;;68182:3;68160:19;68165:14;68160:2;:19;:::i;:::-;:25;;;;:::i;:::-;68145:40;;68084:113;68419:12;68407:9;:24;68478:27;68524:28;68539:12;68524:14;:28::i;:::-;68446:161;;;;;;68571:21;;68446:161;;;:::i;:::-;;;;;;;;;;;;;68385:233;;;;;;;;;;;;;;:::i;57640:125::-;57702:4;57748:9;57726:19;;:31;57719:38;;57640:125;:::o;49457:2301::-;50589:1;50565:21;50577:8;50565:11;:21::i;:::-;:25;:1072;;;;-1:-1:-1;50929:17:0;;;;;;;:7;:17;;;;;;:22;:55;;;;-1:-1:-1;50976:8:0;;50929:55;50639:983;;;;51559:1;51553:3;:7;:50;;;;;51592:11;;51585:3;:18;;51553:50;51652:16;;50188:1491;;;;;;;;;;;;;:::i;:::-;;51727:23;51736:8;51746:3;51727:8;:23::i;74839:1666::-;75031:11;75060:20;75031:11;75060:14;:20::i;:::-;75127:6;75148:10;75144:58;;;-1:-1:-1;75166:21:0;;;;;;;:13;:21;;;;;4635:1;75166:33;;75144:58;75226:1;75212:11;75332:781;75343:4;75339:1;:8;75332:781;;;75391:10;:61;;;;;75422:30;:28;:30::i;:::-;75391:92;;;;;75477:6;75473:1;:10;75391:92;:125;;;;-1:-1:-1;75512:4:0;75504:5;:1;75508;75504:5;:::i;:::-;:12;75391:125;75551:5;75369:203;75775:46;75785:6;75793:11;;75805:1;75793:14;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;75809:8;;75818:1;75809:11;;;;;;;:::i;:::-;;;;;;;75775:9;:46::i;:::-;;76090:8;;76099:1;76090:11;;;;;;;:::i;:::-;;;;;;;76080:21;;;;;:::i;:::-;;-1:-1:-1;75349:3:0;;;:::i;:::-;;;75332:781;;;76129:10;76125:133;;;76156:21;;;;;;;:13;:21;;;;;76188:6;;4662:1;76156:28;;:38;;;;;;;:::i;:::-;;;;-1:-1:-1;;76209:21:0;;;;;;;:13;:21;;;;;76245:1;;4635;76209:33;:37;76125:133;76274:23;;;76270:228;;76354:6;76319:167;;;76379:10;:92;;76465:6;76379:92;;;76413:21;;;;;;;:13;:21;;;;;4662:1;76413:28;;76379:92;76319:167;;1506:25:1;;;1494:2;1479:18;76319:167:0;;;;;;;76270:228;75008:1497;;;;74839:1666;;;;;;:::o;119537:1162::-;119709:11;119738:47;119757:6;119765:7;119709:11;119780:4;119738:18;:47::i;:::-;119798:13;119822:6;119845:10;119841:107;;;-1:-1:-1;;119876:21:0;;;;;;;:13;:21;;;;;4635:1;119876:33;;;119841:107;119971:4;119967:1;:8;119960:540;;;120019:10;:61;;;;;120050:30;:28;:30::i;:::-;120019:94;;;;;120105:8;120101:1;:12;120019:94;:127;;;;-1:-1:-1;120142:4:0;120134:5;:1;120138;120134:5;:::i;:::-;:12;120019:127;120181:5;119997:205;120446:42;120456:6;120464:11;;120476:1;120464:14;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;120480:7;120446:9;:42::i;:::-;-1:-1:-1;119977:3:0;;;:::i;:::-;;;119960:540;;;120512:60;120521:6;120529:10;120541:1;120544;120558:12;120562:8;120544:1;120558:12;:::i;:::-;120547:24;;:7;:24;:::i;:::-;120512:8;:60::i;:::-;-1:-1:-1;120589:23:0;;;120585:107;;120634:46;;;;120651:28;120661:11;120651:7;:28;:::i;:::-;120634:46;;1506:25:1;;;1494:2;1479:18;120634:46:0;;;;;;;120585:107;119686:1013;;;119537:1162;;;;;:::o;113239:5992::-;113359:58;113378:6;113386:7;113395:15;113412:4;113359:18;:58::i;:::-;113464:13;113820:11;;113834:1;113820:15;;;;:::i;:::-;113548:234;;;113591:11;113548:234;;;29176:19:1;113629:15:0;29211:12:1;;;29204:28;;;;113671:12:0;29248::1;;;29241:28;29285:12;;;29278:28;;;29322:13;;;29315:29;;;29360:13;;113548:234:0;;;;;;;;;;;;113516:285;;;;;;113493:323;;:343;;;;:::i;:::-;113464:372;-1:-1:-1;113881:15:0;114235:19;:15;114253:1;114235:19;:::i;:::-;114020:16;114035:1;114020:12;:16;:::i;:::-;114010:27;114083:12;:8;114094:1;114083:12;:::i;:::-;114064:32;;:15;:32;:::i;:::-;114123:9;113967:230;;;;;;29714:19:1;;;;29749:12;;29742:28;;;;29786:12;;;29779:28;29823:12;;;29816:28;;;29860:13;;113967:230:0;;;;;;;;;;;;113935:281;;;;;;113912:319;;:343;;;;:::i;:::-;113881:374;-1:-1:-1;114300:18:0;114442:16;114457:1;114442:12;:16;:::i;:::-;114527:11;;114519:20;;;;:7;:20;;;;;;114432:27;;;114486:6;;114519:20;;114578:1;114566:9;:13;;;;:::i;:::-;114389:285;;;;;;30153:19:1;;;;30191:66;30295:2;30291:15;;;30287:24;;30273:12;;;30266:46;;;;30346:15;;;;30342:24;30328:12;;;30321:46;30383:12;;;30376:28;30420:13;;;30413:29;;;30458:13;;;30451:29;;;30496:13;;114389:285:0;;;;;;;;;;;;;114357:336;;114389:285;114357:336;;;;;-1:-1:-1;114758:17:0;114774:1;114357:336;114758:17;:::i;:::-;114779:1;114758:22;114754:65;;114797:10;;;:::i;:::-;;;114754:65;114833:17;114849:1;114833:13;:17;:::i;:::-;114854:1;114833:22;114829:67;;114872:12;;;:::i;:::-;;;114829:67;114910:17;114926:1;114910:13;:17;:::i;:::-;114931:1;114910:22;114906:65;;114949:10;;;:::i;:::-;;;114906:65;114985:18;115001:2;114985:13;:18;:::i;:::-;115007:1;114985:23;114981:68;;115025:12;;;:::i;:::-;;;114981:68;115074:11;;115063:8;:22;115059:78;;;115114:11;;115102:23;;;;:::i;:::-;;;115059:78;115164:11;;115151:10;:24;115147:82;;;115206:11;;115192:25;;;;:::i;:::-;;;115147:82;115290:8;115302:1;115290:13;115286:56;;115320:10;;;:::i;:::-;;;115286:56;115356:10;115370:1;115356:15;115352:60;;115388:12;;;:::i;:::-;;;115352:60;115440:8;;115424:13;;115539:3390;115550:15;115546:1;:19;115539:3390;;;115667:30;:28;:30::i;:::-;:56;;;;;115722:1;115718;:5;115667:56;:100;;;;-1:-1:-1;115752:15:0;115744:5;:1;115748;115744:5;:::i;:::-;:23;115667:100;115802:5;115645:178;116021:11;;116009:9;:23;116005:88;;;116066:11;;116053:24;;;;:::i;:::-;;;116005:88;116818:8;116805:9;:21;:30;;;;;116834:1;116830;:5;116805:30;116801:912;;;116872:8;116860;:20;116856:155;;116905:10;;;:::i;:::-;;;116856:155;;;116981:10;;;:::i;:::-;;;116856:155;117035:8;117047:1;117035:13;117031:81;;117084:8;117073:19;;117031:81;117147:11;;117136:8;:22;117132:357;;;117194:12;117205:1;117194:8;:12;:::i;:::-;117183:23;;117132:357;117521:8;117509:20;;116801:912;118318:18;;;;:7;:18;;;;;;118257:128;;118289:6;;118318:18;;118359:7;118257:9;:128::i;:::-;118234:644;;118815:11;;;:::i;:::-;;-1:-1:-1;118845:17:0;;;:::i;:::-;;;118234:644;118894:23;118907:10;118894:23;;:::i;:::-;;-1:-1:-1;115567:3:0;;;:::i;:::-;;;115539:3390;;;119167:56;119176:6;119184:5;;;119208:13;119212:9;119208:1;:13;:::i;:::-;119197:25;;:7;:25;:::i;119167:56::-;;113348:5883;;;;;;;113239:5992;;;:::o;121173:6229::-;121291:37;121306:21;;121291:14;:37::i;:::-;121375:13;121404:10;:96;;121479:21;;;;;;;:13;:21;;;;;;121404:96;;;121430:21;;;;;;;:13;:21;;;;;4635:1;121430:33;;121404:96;121375:125;;121754:8;121766:1;121754:13;121750:56;;121784:10;;;:::i;:::-;;;121750:56;121909:8;121900:6;121972:22;121986:7;121972:13;:22::i;:::-;121954:15;;;;;;;:7;:15;;;;;;:40;;;;:::i;:::-;121949:46;;:1;:46;:::i;:::-;121928:67;;122006:14;122031:18;122137:2879;122149:13;122144:1;:18;122137:2879;;122408:30;:28;:30::i;:::-;:66;;;;;122463:11;;122459:1;:15;122408:66;:99;;;;;122499:8;122495:1;:12;122408:99;:137;;;;;122532:13;122528:1;:17;122408:137;122580:5;122386:215;122988:11;;122972:13;:27;122968:442;;;123286:11;;123282:1;:15;123322:5;123278:69;123383:11;;123367:27;;122968:442;-1:-1:-1;123898:10:0;;;;:7;:10;;;;;;;;123948:120;123980:6;123898:10;124042:7;123948:9;:120::i;:::-;123925:1062;;124329:14;;;124346:1;124329:14;;;:2;:14;;;;;;:18;124325:618;;124372:11;;;:::i;:::-;;-1:-1:-1;124406:3:0;;;:::i;:::-;;;124845:11;;124829:13;:27;124825:99;;;124885:15;;;:::i;:::-;;;124825:99;122137:2879;;123925:1062;125001:3;;;:::i;:::-;;;122137:2879;;;125217:18;125254:20;125266:8;125254:9;:20;:::i;:::-;125250:1;:24;125246:108;;;125333:8;125317:13;125321:9;125317:1;:13;:::i;:::-;:24;;;;:::i;:::-;125306:36;;:7;:36;:::i;:::-;125290:52;;125246:108;125366:125;125389:6;125410:10;125435:1;125451;125467:13;125366:8;:125::i;:::-;;125725:10;125720:266;;125837:17;;125833:102;;125875:27;;;;;;;:19;:27;;;;;:44;;125906:13;;125875:27;:44;;125906:13;;125875:44;:::i;:::-;;;;-1:-1:-1;;125833:102:0;125949:21;;;;;;;:13;:21;;;;;:25;;;125720:266;126316:11;;126312:1;:15;126308:54;;;126344:7;;;;;;121173:6229;;;:::o;126308:54::-;126828:10;126824:114;;;126860:45;;;126876:21;;;;:13;:21;;;;;126860:45;;4662:1;126876:28;;126860:45;;1506:25:1;;;1494:2;1479:18;126860:45:0;;;;;;;126920:7;;;;;;121173:6229;;;:::o;126824:114::-;127125:44;;;127141:27;;;;:19;:27;;;;;;;;;;127125:44;;1506:25:1;;;127125:44:0;;1479:18:1;127125:44:0;;;;;;;-1:-1:-1;;;127244:21:0;;;;;;;;:13;:21;;;;;;;;127268:1;127244:25;;127367:19;:27;;;;;127360:34;-1:-1:-1;;;;;121173:6229:0:o;57085:176::-;57166:4;57190:26;57208:7;57055:14;;;57044:25;;;57055:14;;57044:25;;56954:123;57190:26;:63;;;;57220:33;57245:7;57220:24;:33::i;63062:871::-;63148:15;;;63121:8;63148:15;;;:2;:15;;;;;;63178:7;;;;:38;;;63189:27;63204:11;63189:14;:27::i;:::-;63174:81;;;63062:871;;;:::o;63174:81::-;63824:11;;63822:13;;;;;:::i;:::-;;;;;-1:-1:-1;63846:12:0;;;;:7;:12;;;;;;;;:26;;;;;;;;;;;;;;63883:15;;;:2;:15;;;;;;:21;;;-1:-1:-1;63822:13:0;63062:871::o;65138:1653::-;65701:25;65711:15;65701:7;:25;:::i;:::-;65682:15;;;;;;;:7;:15;;;;;;:44;;66053:33;65690:6;66053:25;:33::i;:::-;66137:46;66157:25;66167:15;66157:7;:25;:::i;:::-;66137:19;:46::i;:::-;66021:177;;;;;;;;;:::i;:::-;;;;;;;;;;;;;65660:549;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;66555:26:0;66521:19;66499:93;;;;;;;;;;;;;:::i;:::-;;66705:19;66701:83;;;66741:31;66756:15;66741:14;:31::i;7454:838::-;7516:4;8011:21;;7900:66;8239:25;;;;;;:45;;-1:-1:-1;;8268:16:0;;;8232:52;-1:-1:-1;;7454:838:0:o;55033:565::-;55182:25;55196:10;;55182:13;:25::i;:::-;55146:19;;55129:36;;:14;:36;:::i;:::-;55128:79;;;;:::i;:::-;55090:21;:117;55349:10;;55334:26;;:14;:26::i;:::-;55417:35;55432:19;;55417:14;:35::i;:::-;55501:37;55516:21;;55501:14;:37::i;:::-;55265:325;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;55228:21;;:362;;:21;:362;:::i;37991:1526::-;38096:26;38179:6;38167:9;38171:5;38167:1;:9;:::i;:::-;:18;;;;:::i;:::-;38153:33;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;38141:45:0;-1:-1:-1;38197:7:0;38267:6;38253:1228;38280:5;38275:1;:10;38253:1228;;39458:10;;;;:7;:10;;;;;;39447:22;;39458:10;;39447;:22::i;:::-;39429:9;39439:4;;;;:::i;:::-;;;39429:15;;;;;;;;:::i;:::-;;;;;;:40;;;;38287:3;;;;:::i;:::-;;;38253:1228;;;;39493:16;37991:1526;;;;:::o;112499:182::-;112554:7;112595;;112578:13;:24;112574:66;;112606:31;:29;:31::i;:::-;-1:-1:-1;112657:16:0;;;112499:182::o;76706:2438::-;76860:32;;:::i;:::-;77529:7;77524:108;4020:1;77538:12;;;;77524:108;;;77589:18;;;;;;;;:10;:18;;;;;;;;:28;;;;;;;;;:31;;;;;;;;;;:::i;:::-;;;77572:11;77584:1;77572:14;;;;;;;;;:::i;:::-;;;;:48;77552:3;;;:::i;:::-;;;77524:108;;;-1:-1:-1;78266:23:0;;;;78222:14;;78239:24;78243:20;4084:1;78239:24;:::i;:::-;:50;;;;;;:::i;:::-;78222:67;;78316:15;78304:9;:27;78300:117;;;78378:27;78390:15;78378:9;:27;:::i;:::-;78348;;;:57;78300:117;78916:1;78893:20;:24;;;:82;;;;-1:-1:-1;78947:23:0;;;;:28;78893:82;:144;;;;-1:-1:-1;79005:27:0;;;;:32;78893:144;78875:231;;;4052:1;79064:30;;78875:231;79118:18;76706:2438;;;;;:::o;34672:2494::-;34964:26;;;34935;34964;;;:16;:26;;;;;;;;34935:55;;;;;;;;;;;;;;;;;34811:31;;34935:26;:55;;34964:26;34935:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;35320:16:0;;34935:55;;-1:-1:-1;35320:16:0;;-1:-1:-1;;;35448:28:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35448:28:0;;;;;;;;;;;;;;;;;35432:44;;35632:6;35627:1499;35644:12;35640:1;:16;35627:1499;;;35817:16;35836:9;35846:1;35836:12;;;;;;;;:::i;:::-;;;;;;;35817:31;;36130;36181:138;36218:8;36249;36280:20;36181:14;:138::i;:::-;36896:218;;;;;;;;;;;;;36950:22;;36896:218;;;;;;;;36991:22;;;36896:218;;;;;37032:26;;;;36896:218;;;;37077:22;;;;36896:218;;;;36877:16;;36130:189;;-1:-1:-1;36896:218:0;36877:13;;36891:1;;36877:16;;;;;;:::i;:::-;;;;;;:237;;;;35663:1463;;35658:3;;;;:::i;:::-;;;35627:1499;;;;37138:20;;34672:2494;;;;:::o;37412:323::-;37494:17;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37494:17:0;37531:196;;;;;;;;37556:21;37568:8;37556:11;:21::i;:::-;37531:196;;;;37592:23;;;;;;;;;:13;37531:196;37592:23;;;;;;;;37531:196;;;;37630:29;;;:19;:29;;;;;;37531:196;;;;37674:23;;;:13;:23;;;:42;37531:196;;;;;;;;-1:-1:-1;37524:203:0;37412:323::o;10021:1430::-;10106:13;10221:6;10231:1;10221:11;10217:60;;-1:-1:-1;;10256:9:0;;;;;;;;;;;;;;;;;;10021:1430::o;10217:60::-;10494:13;10482:26;;10423:19;10693:30;10482:26;10693:14;:30::i;:::-;10664:59;-1:-1:-1;11044:18:0;;11040:203;;11079:153;6785:18;6801:2;6741:7;6785:18;:::i;:::-;11086:14;:34;11079:153;;;11192:9;;;;;;;;;;;;;;;;;11203:12;11178:38;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1;11122:20:0;11140:2;11122:20;;:::i;:::-;;;11079:153;;;11341:38;11356:22;6741:7;11356:6;:22;:::i;:::-;11341:14;:38::i;:::-;11394:11;;;;;;;;;;;;;;;;;11420:12;11313:130;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;11306:137;;;;10021:1430;;;:::o;64018:266::-;64249:15;;;;;;;:7;:15;;;;;;64117:13;;64184:30;;64229:36;;:19;:36::i;:::-;64156:120;;;;;;;;;:::i;69044:274::-;69108:4;69202:22;;;;;:66;;-1:-1:-1;69241:27:0;;;69261:6;69241:27;69202:66;:108;;;-1:-1:-1;69285:25:0;;;69305:4;69285:25;69182:128;69044:274;-1:-1:-1;;69044:274:0:o;80205:2758::-;80358:15;80463:30;:28;:30::i;:::-;80510:17;80459:89;-1:-1:-1;80573:4:0;81341:1364;;;;81962:10;81998:1;81951:22;;;:10;:22;;;;;;;;;:32;;;;;;;;;4116:1;81951:44;;:48;:308;;;;82258:1;82103:140;82140:10;82173:8;82204:20;82103:14;:140::i;:::-;:152;:156;81951:308;82294:17;81929:406;82620:10;82609:22;;;;:10;:22;;;;;;;;;:32;;;;;;;;;82602:51;82668:17;;81341:1364;82898:10;82887:22;;;;:10;:22;;;;;;;;;:32;;;;;;;;;-1:-1:-1;;;;;;;;;;;;82880:39:0;-1:-1:-1;8389:653:0;8476:13;8591:7;8602:1;8591:12;8587:61;;-1:-1:-1;;8627:9:0;;;;;;;;;;;;;;;;;;8389:653::o;8587:61::-;8672:7;8658:11;8714:84;8721:11;;8714:84;;8749:10;;;:::i;:::-;;-1:-1:-1;8774:12:0;8784:2;8774:12;;:::i;:::-;;;8714:84;;;8808:21;8842:8;8832:19;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;8832:19:0;;8808:43;;8862:137;8869:12;;8862:137;;8944:12;8954:2;8944:7;:12;:::i;:::-;8934:23;;:2;:23;:::i;:::-;8921:38;;8898:8;8907:10;;;:::i;:::-;;;;8898:20;;;;;;;;:::i;:::-;;;;:61;;;;;;;;;;-1:-1:-1;8974:13:0;8985:2;8974:13;;:::i;:::-;;;8862:137;;52373:2560;52857:23;52867:12;;;:7;:12;;;;;;;;;;;52857:23;;:9;:23;;;;;;;;52853:40;;;52373:2560;;:::o;52853:40::-;52941:3;52948:1;52941:8;52937:630;;53071:19;;;;;;;:9;:19;;;;;;;;53067:36;;;52373:2560;;:::o;53067:36::-;53442:11;;;52174:12;;;;52166:21;52174:12;;;:2;:12;;;;;;;;;;52166:21;;;:7;:21;;;;;;;;52202:12;;;;;;;;;;52229:16;;;;;;;;;;;;51998:285;;;;;;;;;;;;;;;;;;;52166:21;;;;51998:285;;;;;;;;;;;53484:13;;52166:7;;:21;53484:13;;;:::i;:::-;;;;-1:-1:-1;53476:22:0;;;;;;;;;;;;;;-1:-1:-1;53476:22:0;;;53469:29;;;;;;;53520:12;;;;;;:2;:12;;;;;53513:19;;;;-1:-1:-1;52373:2560:0:o;52937:630::-;52174:12;;;;52166:21;52174:12;;;:2;:12;;;;;;;;;;52166:21;;;:7;:21;;;;;;;52202:12;;;;;;;;;;52229:16;;;;;;;;;;;;;51998:285;;;;;;;;;;;;;;;;;;;;;;52166:21;;;;51998:285;;;130757:4160::o;127721:659::-;127896:4;127923:10;127919:384;;;127954:17;;127950:103;;127992:21;;;;;;;:13;:21;;;;;128024:13;;4662:1;127992:28;;:45;;;;;;;:::i;:::-;;;;-1:-1:-1;;127950:103:0;128071:13;;128067:98;;128105:21;;;;;;;:13;:21;;;;;128140:9;;4692:1;128105:31;;:44;;;;;;;:::i;:::-;;;;-1:-1:-1;;128067:98:0;128193:21;;;;;;;:13;:21;;;;;4635:1;128193:33;;:38;;;4692:1;128260:31;;;-1:-1:-1;127919:384:0;128323:6;128318:27;;;128331:13;128318:27;;;;1506:25:1;;1494:2;1479:18;;1360:177;128318:27:0;;;;;;;;-1:-1:-1;128363:9:0;;127721:659;-1:-1:-1;;;;127721:659:0:o;60630:1983::-;60760:10;61089;61079:20;;:6;:20;;;:58;;;-1:-1:-1;61116:21:0;;;;;;;:9;:21;;;;;;;;61079:58;:101;;;;61154:26;61169:10;61154:14;:26::i;:::-;61246:12;60791:479;61695:19;;;61674:18;61695:19;;;:7;:19;;;;;;61729:18;;:44;;;;;61772:1;61751:18;;:22;61729:44;61725:150;;;61790:23;61799:10;61811:1;61790:8;:23::i;:::-;61851:12;;;61725:150;62105:23;62117:10;62105:11;:23::i;:::-;62101:68;;;62145:12;;;62101:68;62394:18;;62377:13;:35;62373:113;;62436:38;62446:6;62454:10;62466:7;62436:9;:38::i;:::-;62429:45;;;;;9597:165;9658:4;9679:8;9691:1;9679:13;9675:54;;-1:-1:-1;9716:1:0;;9597:165;-1:-1:-1;9597:165:0:o;9675:54::-;-1:-1:-1;9746:8:0;9597:165::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;14:250:1;99:1;109:113;123:6;120:1;117:13;109:113;;;199:11;;;193:18;180:11;;;173:39;145:2;138:10;109:113;;;-1:-1:-1;;256:1:1;238:16;;231:27;14:250::o;269:330::-;311:3;349:5;343:12;376:6;371:3;364:19;392:76;461:6;454:4;449:3;445:14;438:4;431:5;427:16;392:76;:::i;:::-;513:2;501:15;518:66;497:88;488:98;;;;588:4;484:109;;269:330;-1:-1:-1;;269:330:1:o;604:751::-;793:2;845:21;;;764:4;;952;937:20;;818:18;;;980:6;764:4;1014:312;1028:4;1025:1;1022:11;1014:312;;;1115:66;1103:9;1095:6;1091:22;1087:95;1082:3;1075:108;1206:40;1239:6;1230;1224:13;1206:40;:::i;:::-;1196:50;-1:-1:-1;1304:12:1;;;;1269:15;;;;1048:1;1041:9;1014:312;;;-1:-1:-1;1343:6:1;;604:751;-1:-1:-1;;;;;;604:751:1:o;1542:180::-;1601:6;1654:2;1642:9;1633:7;1629:23;1625:32;1622:52;;;1670:1;1667;1660:12;1622:52;-1:-1:-1;1693:23:1;;1542:180;-1:-1:-1;1542:180:1:o;2011:1622::-;2116:12;;2104:25;;2148:4;2187:14;;;2181:21;2221:42;2293:21;;;2279:12;;;2272:43;2334:4;2374:14;;;2368:21;2354:12;;;2347:43;2409:4;2463:14;;;2457:21;2450:29;2443:37;2429:12;;;2422:59;2500:4;2541:14;;;2535:21;2089:6;2572:12;;;2565:24;;;2657:21;;2680:64;2653:92;2639:12;;;2632:114;2783:23;;2777:30;2832:3;2823:13;;2816:25;;;2890:21;;2619:3;2610:13;;2920:20;;;2061:3;;2994:23;;;;2148:4;;2334;2221:42;;2500:4;2967:3;2958:13;;;2061:3;;3045:438;3059:6;3056:1;3053:13;3045:438;;;3118:13;;3162:9;;3158:18;;3144:33;;3219:11;;;3213:18;3197:14;;;3190:42;3274:11;;;3268:18;3252:14;;;3245:42;3329:11;;;3323:18;3307:14;;;3300:42;3384:11;;3378:18;3362:14;;;3355:42;3458:15;;;;3430:4;3419:16;;;;3081:1;3074:9;;;;;3045:438;;;3049:3;;3531:4;3524:5;3520:16;3514:23;3492:45;;3546:60;3600:4;3595:3;3591:14;3575;1823:5;1817:12;1810:20;1803:28;1798:3;1791:41;1881:4;1874:5;1870:16;1864:23;1857:4;1852:3;1848:14;1841:47;1937:4;1930:5;1926:16;1920:23;1913:4;1908:3;1904:14;1897:47;1993:4;1986:5;1982:16;1976:23;1969:4;1964:3;1960:14;1953:47;;;1727:279;3546:60;3622:5;2011:1622;-1:-1:-1;;;;;;;;;2011:1622:1:o;3638:256::-;3815:2;3804:9;3797:21;3778:4;3835:53;3884:2;3873:9;3869:18;3861:6;3835:53;:::i;3899:220::-;4048:2;4037:9;4030:21;4011:4;4068:45;4109:2;4098:9;4094:18;4086:6;4068:45;:::i;4124:196::-;4192:20;;4252:42;4241:54;;4231:65;;4221:93;;4310:1;4307;4300:12;4325:254;4393:6;4401;4454:2;4442:9;4433:7;4429:23;4425:32;4422:52;;;4470:1;4467;4460:12;4422:52;4493:29;4512:9;4493:29;:::i;:::-;4483:39;4569:2;4554:18;;;;4541:32;;-1:-1:-1;;;4325:254:1:o;4776:118::-;4862:5;4855:13;4848:21;4841:5;4838:32;4828:60;;4884:1;4881;4874:12;4899:315;4964:6;4972;5025:2;5013:9;5004:7;5000:23;4996:32;4993:52;;;5041:1;5038;5031:12;4993:52;5064:29;5083:9;5064:29;:::i;:::-;5054:39;;5143:2;5132:9;5128:18;5115:32;5156:28;5178:5;5156:28;:::i;:::-;5203:5;5193:15;;;4899:315;;;;;:::o;5219:328::-;5296:6;5304;5312;5365:2;5353:9;5344:7;5340:23;5336:32;5333:52;;;5381:1;5378;5371:12;5333:52;5404:29;5423:9;5404:29;:::i;:::-;5394:39;;5452:38;5486:2;5475:9;5471:18;5452:38;:::i;:::-;5442:48;;5537:2;5526:9;5522:18;5509:32;5499:42;;5219:328;;;;;:::o;6154:241::-;6210:6;6263:2;6251:9;6242:7;6238:23;6234:32;6231:52;;;6279:1;6276;6269:12;6231:52;6318:9;6305:23;6337:28;6359:5;6337:28;:::i;6400:159::-;6463:5;6508:3;6499:6;6494:3;6490:16;6486:26;6483:46;;;6525:1;6522;6515:12;6483:46;-1:-1:-1;6547:6:1;6400:159;-1:-1:-1;6400:159:1:o;6564:435::-;6661:6;6669;6722:2;6710:9;6701:7;6697:23;6693:32;6690:52;;;6738:1;6735;6728:12;6690:52;6761:29;6780:9;6761:29;:::i;:::-;6751:39;;6841:2;6830:9;6826:18;6813:32;6868:18;6860:6;6857:30;6854:50;;;6900:1;6897;6890:12;6854:50;6923:70;6985:7;6976:6;6965:9;6961:22;6923:70;:::i;:::-;6913:80;;;6564:435;;;;;:::o;7004:666::-;7084:6;7092;7100;7153:2;7141:9;7132:7;7128:23;7124:32;7121:52;;;7169:1;7166;7159:12;7121:52;7209:9;7196:23;7238:18;7279:2;7271:6;7268:14;7265:34;;;7295:1;7292;7285:12;7265:34;7333:6;7322:9;7318:22;7308:32;;7378:7;7371:4;7367:2;7363:13;7359:27;7349:55;;7400:1;7397;7390:12;7349:55;7440:2;7427:16;7466:2;7458:6;7455:14;7452:34;;;7482:1;7479;7472:12;7452:34;7529:7;7522:4;7513:6;7509:2;7505:15;7501:26;7498:39;7495:59;;;7550:1;7547;7540:12;7495:59;7581:4;7573:13;;;;7605:6;;-1:-1:-1;7643:20:1;;;;7630:34;;7004:666;-1:-1:-1;;;;7004:666:1:o;7675:186::-;7734:6;7787:2;7775:9;7766:7;7762:23;7758:32;7755:52;;;7803:1;7800;7793:12;7755:52;7826:29;7845:9;7826:29;:::i;8119:367::-;8182:8;8192:6;8246:3;8239:4;8231:6;8227:17;8223:27;8213:55;;8264:1;8261;8254:12;8213:55;-1:-1:-1;8287:20:1;;8330:18;8319:30;;8316:50;;;8362:1;8359;8352:12;8316:50;8399:4;8391:6;8387:17;8375:29;;8459:3;8452:4;8442:6;8439:1;8435:14;8427:6;8423:27;8419:38;8416:47;8413:67;;;8476:1;8473;8466:12;8491:770;8610:6;8618;8626;8634;8687:2;8675:9;8666:7;8662:23;8658:32;8655:52;;;8703:1;8700;8693:12;8655:52;8743:9;8730:23;8772:18;8813:2;8805:6;8802:14;8799:34;;;8829:1;8826;8819:12;8799:34;8868:70;8930:7;8921:6;8910:9;8906:22;8868:70;:::i;:::-;8957:8;;-1:-1:-1;8842:96:1;-1:-1:-1;9045:2:1;9030:18;;9017:32;;-1:-1:-1;9061:16:1;;;9058:36;;;9090:1;9087;9080:12;9058:36;;9129:72;9193:7;9182:8;9171:9;9167:24;9129:72;:::i;:::-;8491:770;;;;-1:-1:-1;9220:8:1;-1:-1:-1;;;;8491:770:1:o;9266:361::-;9354:6;9407:2;9395:9;9386:7;9382:23;9378:32;9375:52;;;9423:1;9420;9413:12;9375:52;9463:9;9450:23;9496:18;9488:6;9485:30;9482:50;;;9528:1;9525;9518:12;9482:50;9551:70;9613:7;9604:6;9593:9;9589:22;9551:70;:::i;10410:248::-;10478:6;10486;10539:2;10527:9;10518:7;10514:23;10510:32;10507:52;;;10555:1;10552;10545:12;10507:52;-1:-1:-1;;10578:23:1;;;10648:2;10633:18;;;10620:32;;-1:-1:-1;10410:248:1:o;10663:898::-;10853:4;10882:2;10922;10911:9;10907:18;10952:2;10941:9;10934:21;10975:6;11010;11004:13;11041:6;11033;11026:22;11079:2;11068:9;11064:18;11057:25;;11141:2;11131:6;11128:1;11124:14;11113:9;11109:30;11105:39;11091:53;;11179:2;11171:6;11167:15;11200:1;11210:322;11224:6;11221:1;11218:13;11210:322;;;11313:66;11301:9;11293:6;11289:22;11285:95;11280:3;11273:108;11404:48;11445:6;11436;11430:13;11404:48;:::i;:::-;11394:58;-1:-1:-1;11510:12:1;;;;11475:15;;;;11246:1;11239:9;11210:322;;;-1:-1:-1;11549:6:1;;10663:898;-1:-1:-1;;;;;;;10663:898:1:o;11566:693::-;11677:6;11685;11693;11701;11709;11717;11725;11778:3;11766:9;11757:7;11753:23;11749:33;11746:53;;;11795:1;11792;11785:12;11746:53;11818:29;11837:9;11818:29;:::i;:::-;11808:39;;11866:38;11900:2;11889:9;11885:18;11866:38;:::i;:::-;11856:48;;11951:2;11940:9;11936:18;11923:32;11913:42;;12002:2;11991:9;11987:18;11974:32;11964:42;;12056:3;12045:9;12041:19;12028:33;12101:4;12094:5;12090:16;12083:5;12080:27;12070:55;;12121:1;12118;12111:12;12070:55;11566:693;;;;-1:-1:-1;11566:693:1;;;;12144:5;12196:3;12181:19;;12168:33;;-1:-1:-1;12248:3:1;12233:19;;;12220:33;;11566:693;-1:-1:-1;;11566:693:1:o;12264:260::-;12332:6;12340;12393:2;12381:9;12372:7;12368:23;12364:32;12361:52;;;12409:1;12406;12399:12;12361:52;12432:29;12451:9;12432:29;:::i;:::-;12422:39;;12480:38;12514:2;12503:9;12499:18;12480:38;:::i;:::-;12470:48;;12264:260;;;;;:::o;12529:505::-;12624:6;12632;12640;12693:2;12681:9;12672:7;12668:23;12664:32;12661:52;;;12709:1;12706;12699:12;12661:52;12745:9;12732:23;12722:33;;12806:2;12795:9;12791:18;12778:32;12833:18;12825:6;12822:30;12819:50;;;12865:1;12862;12855:12;12819:50;12904:70;12966:7;12957:6;12946:9;12942:22;12904:70;:::i;:::-;12529:505;;12993:8;;-1:-1:-1;12878:96:1;;-1:-1:-1;;;;12529:505:1:o;13039:437::-;13118:1;13114:12;;;;13161;;;13182:61;;13236:4;13228:6;13224:17;13214:27;;13182:61;13289:2;13281:6;13278:14;13258:18;13255:38;13252:218;;13326:77;13323:1;13316:88;13427:4;13424:1;13417:15;13455:4;13452:1;13445:15;13610:783;13663:3;13704:5;13698:12;13733:36;13759:9;13733:36;:::i;:::-;13788:1;13805:18;;;13832:191;;;;14037:1;14032:355;;;;13798:589;;13832:191;13880:66;13869:9;13865:82;13860:3;13853:95;14003:6;13996:14;13989:22;13981:6;13977:35;13972:3;13968:45;13961:52;;13832:191;;14032:355;14063:5;14060:1;14053:16;14092:4;14137:2;14134:1;14124:16;14162:1;14176:165;14190:6;14187:1;14184:13;14176:165;;;14268:14;;14255:11;;;14248:35;14311:16;;;;14205:10;;14176:165;;;14180:3;;;14370:6;14365:3;14361:16;14354:23;;13798:589;;;;;13610:783;;;;:::o;14398:202::-;14528:3;14553:41;14590:3;14582:6;14553:41;:::i;15122:184::-;15174:77;15171:1;15164:88;15271:4;15268:1;15261:15;15295:4;15292:1;15285:15;15311:1021;15420:4;15449:2;15478;15467:9;15460:21;15501:1;15534:6;15528:13;15564:36;15590:9;15564:36;:::i;:::-;15636:6;15631:2;15620:9;15616:18;15609:34;15662:2;15683:1;15715:2;15704:9;15700:18;15732:1;15727:216;;;;15957:1;15952:354;;;;15693:613;;15727:216;15790:66;15779:9;15775:82;15770:2;15759:9;15755:18;15748:110;15930:2;15918:6;15911:14;15904:22;15901:1;15897:30;15886:9;15882:46;15878:55;15871:62;;15727:216;;15952:354;15983:6;15980:1;15973:17;16031:2;16028:1;16018:16;16056:1;16070:180;16084:6;16081:1;16078:13;16070:180;;;16177:14;;16153:17;;;16149:26;;16142:50;16220:16;;;;16099:10;;16070:180;;;16274:17;;16270:26;;;-1:-1:-1;;15693:613:1;-1:-1:-1;16323:3:1;;15311:1021;-1:-1:-1;;;;;;;;15311:1021:1:o;16337:392::-;16513:3;16541:41;16578:3;16570:6;16541:41;:::i;:::-;16611:6;16605:13;16627:65;16685:6;16681:2;16674:4;16666:6;16662:17;16627:65;:::i;:::-;16708:15;;16337:392;-1:-1:-1;;;;16337:392:1:o;16734:184::-;16786:77;16783:1;16776:88;16883:4;16880:1;16873:15;16907:4;16904:1;16897:15;16923:128;16990:9;;;17011:11;;;17008:37;;;17025:18;;:::i;17056:195::-;17095:3;17126:66;17119:5;17116:77;17113:103;;17196:18;;:::i;:::-;-1:-1:-1;17243:1:1;17232:13;;17056:195::o;17256:125::-;17321:9;;;17342:10;;;17339:36;;;17355:18;;:::i;17386:604::-;17479:4;17485:6;17545:11;17532:25;17635:66;17624:8;17608:14;17604:29;17600:102;17580:18;17576:127;17566:155;;17717:1;17714;17707:12;17566:155;17744:33;;17796:20;;;-1:-1:-1;17839:18:1;17828:30;;17825:50;;;17871:1;17868;17861:12;17825:50;17904:4;17892:17;;-1:-1:-1;17955:1:1;17951:14;;;17935;17931:35;17921:46;;17918:66;;;17980:1;17977;17970:12;17995:168;18068:9;;;18099;;18116:15;;;18110:22;;18096:37;18086:71;;18137:18;;:::i;18777:184::-;18829:77;18826:1;18819:88;18926:4;18923:1;18916:15;18950:4;18947:1;18940:15;18966:184;19018:77;19015:1;19008:88;19115:4;19112:1;19105:15;19139:4;19136:1;19129:15;19155:545;19257:2;19252:3;19249:11;19246:448;;;19293:1;19318:5;19314:2;19307:17;19363:4;19359:2;19349:19;19433:2;19421:10;19417:19;19414:1;19410:27;19404:4;19400:38;19469:4;19457:10;19454:20;19451:47;;;-1:-1:-1;19492:4:1;19451:47;19547:2;19542:3;19538:12;19535:1;19531:20;19525:4;19521:31;19511:41;;19602:82;19620:2;19613:5;19610:13;19602:82;;;19665:17;;;19646:1;19635:13;19602:82;;19936:1328;20060:18;20055:3;20052:27;20049:53;;;20082:18;;:::i;:::-;20111:94;20201:3;20161:38;20193:4;20187:11;20161:38;:::i;:::-;20155:4;20111:94;:::i;:::-;20231:1;20256:2;20251:3;20248:11;20273:1;20268:738;;;;21050:1;21067:3;21064:93;;;-1:-1:-1;21123:19:1;;;21110:33;21064:93;19842:66;19833:1;19829:11;;;19825:84;19821:89;19811:100;19917:1;19913:11;;;19808:117;21170:78;;20241:1017;;20268:738;13557:1;13550:14;;;13594:4;13581:18;;20313:66;20304:76;;;20467:9;20489:229;20503:7;20500:1;20497:14;20489:229;;;20592:19;;;20579:33;20564:49;;20699:4;20684:20;;;;20652:1;20640:14;;;;20519:12;20489:229;;;20493:3;20746;20737:7;20734:16;20731:219;;;20866:66;20860:3;20854;20851:1;20847:11;20843:21;20839:94;20835:99;20822:9;20817:3;20813:19;20800:33;20796:139;20788:6;20781:155;20731:219;;;20993:1;20987:3;20984:1;20980:11;20976:19;20970:4;20963:33;20241:1017;;;19936:1328;;;:::o;21269:326::-;21358:6;21353:3;21346:19;21410:6;21403:5;21396:4;21391:3;21387:14;21374:43;;21462:1;21455:4;21446:6;21441:3;21437:16;21433:27;21426:38;21328:3;21584:4;21514:66;21509:2;21501:6;21497:15;21493:88;21488:3;21484:98;21480:109;21473:116;;21269:326;;;;:::o;21600:579::-;21670:5;21677:6;21737:3;21724:17;21819:66;21808:8;21792:14;21788:29;21784:102;21764:18;21760:127;21750:155;;21901:1;21898;21891:12;21750:155;21929:33;;22033:4;22020:18;;;-1:-1:-1;21981:21:1;;-1:-1:-1;22061:18:1;22050:30;;22047:50;;;22093:1;22090;22083:12;22047:50;22147:6;22144:1;22140:14;22124;22120:35;22113:5;22109:47;22106:67;;;22169:1;22166;22159:12;22184:470;22284:6;22279:3;22272:19;22254:3;22310:4;22339:2;22334:3;22330:12;22323:19;;22365:5;22388:1;22398:231;22412:6;22409:1;22406:13;22398:231;;;22505:42;22477:26;22496:6;22477:26;:::i;:::-;22473:75;22461:88;;22569:12;;;;22604:15;;;;22434:1;22427:9;22398:231;;;-1:-1:-1;22645:3:1;;22184:470;-1:-1:-1;;;;;22184:470:1:o;22659:358::-;22759:6;22754:3;22747:19;22729:3;22789:66;22781:6;22778:78;22775:98;;;22869:1;22866;22859:12;22775:98;22905:6;22902:1;22898:14;22957:8;22950:5;22943:4;22938:3;22934:14;22921:45;22986:18;;;;23006:4;22982:29;;22659:358;-1:-1:-1;;;22659:358:1:o;23022:1661::-;23198:4;23227:42;23308:2;23300:6;23296:15;23285:9;23278:34;23348:2;23343;23332:9;23328:18;23321:30;23419:2;23391:26;23410:6;23391:26;:::i;:::-;23387:35;23382:2;23371:9;23367:18;23360:63;;23483:2;23475:6;23471:15;23458:29;23563:66;23554:6;23538:14;23534:27;23530:100;23510:18;23506:125;23496:153;;23645:1;23642;23635:12;23496:153;23671:31;;23779:2;23768:14;;;23725:19;23805:18;23794:30;;23791:50;;;23837:1;23834;23827:12;23791:50;23886:6;23870:14;23866:27;23857:7;23853:41;23850:61;;;23907:1;23904;23897:12;23850:61;23947:4;23942:2;23931:9;23927:18;23920:32;23975:64;24034:3;24023:9;24019:19;24011:6;24002:7;23975:64;:::i;:::-;23961:78;;;24082:67;24145:2;24137:6;24133:15;24125:6;24082:67;:::i;:::-;24168:66;24300:2;24288:9;24280:6;24276:22;24272:31;24265:4;24254:9;24250:20;24243:61;24327:73;24393:6;24379:12;24365;24327:73;:::i;:::-;24313:87;;24447:67;24510:2;24502:6;24498:15;24490:6;24447:67;:::i;:::-;24409:105;;;;24579:2;24567:9;24559:6;24555:22;24551:31;24545:3;24534:9;24530:19;24523:60;;24600:77;24670:6;24654:14;24638;24600:77;:::i;:::-;24592:85;23022:1661;-1:-1:-1;;;;;;;23022:1661:1:o;24688:581::-;24766:4;24772:6;24832:11;24819:25;24922:66;24911:8;24895:14;24891:29;24887:102;24867:18;24863:127;24853:155;;25004:1;25001;24994:12;24853:155;25031:33;;25083:20;;;-1:-1:-1;25126:18:1;25115:30;;25112:50;;;25158:1;25155;25148:12;25112:50;25191:4;25179:17;;-1:-1:-1;25222:14:1;25218:27;;;25208:38;;25205:58;;;25259:1;25256;25249:12;25274:273;25459:6;25451;25446:3;25433:33;25415:3;25485:16;;25510:13;;;25485:16;25274:273;-1:-1:-1;25274:273:1:o;25552:184::-;25604:77;25601:1;25594:88;25701:4;25698:1;25691:15;25725:4;25722:1;25715:15;25741:120;25781:1;25807;25797:35;;25812:18;;:::i;:::-;-1:-1:-1;25846:9:1;;25741:120::o;25866:184::-;25936:6;25989:2;25977:9;25968:7;25964:23;25960:32;25957:52;;;26005:1;26002;25995:12;25957:52;-1:-1:-1;26028:16:1;;25866:184;-1:-1:-1;25866:184:1:o;26357:245::-;26424:6;26477:2;26465:9;26456:7;26452:23;26448:32;26445:52;;;26493:1;26490;26483:12;26445:52;26525:9;26519:16;26544:28;26566:5;26544:28;:::i;28078:372::-;28254:3;28292:6;28286:13;28308:66;28367:6;28362:3;28355:4;28347:6;28343:17;28308:66;:::i;:::-;28390:54;28436:6;28431:3;28427:16;28419:6;28390:54;:::i;28455:475::-;28676:3;28704:41;28741:3;28733:6;28704:41;:::i;:::-;28774:6;28768:13;28790:65;28848:6;28844:2;28837:4;28829:6;28825:17;28790:65;:::i;:::-;28871:53;28916:6;28912:2;28908:15;28900:6;28871:53;:::i;29384:112::-;29416:1;29442;29432:35;;29447:18;;:::i;:::-;-1:-1:-1;29481:9:1;;29384:112::o;30520:196::-;30559:3;30587:5;30577:39;;30596:18;;:::i;:::-;-1:-1:-1;30643:66:1;30632:78;;30520:196::o;30721:642::-;30991:3;31029:6;31023:13;31045:66;31104:6;31099:3;31092:4;31084:6;31080:17;31045:66;:::i;:::-;31172:13;31133:16;;;31158:28;;;31211:13;;31233:79;31211:13;31298:2;31287:14;;31280:4;31268:17;;31233:79;:::i;:::-;31332:20;31354:2;31328:29;;30721:642;-1:-1:-1;;;;30721:642:1:o;31368:1283::-;31988:18;31983:3;31976:31;31958:3;32036:6;32030:13;32052:75;32120:6;32115:2;32110:3;32106:12;32099:4;32091:6;32087:17;32052:75;:::i;:::-;32191:19;32186:2;32146:16;;;32178:11;;;32171:40;32236:13;;32258:76;32236:13;32320:2;32312:11;;32305:4;32293:17;;32258:76;:::i;:::-;32399:11;32394:2;32353:17;;;;32386:11;;;32379:32;32436:13;;32458:76;32436:13;32520:2;32512:11;;32505:4;32493:17;;32458:76;:::i;:::-;32599:18;32594:2;32553:17;;;;32586:11;;;32579:39;32642:2;32634:11;;31368:1283;-1:-1:-1;;;;;31368:1283:1:o;32656:1474::-;32782:3;32776:10;32809:18;32801:6;32798:30;32795:56;;;32831:18;;:::i;:::-;32860:97;32950:6;32910:38;32942:4;32936:11;32910:38;:::i;:::-;32904:4;32860:97;:::i;:::-;33012:4;;33076:2;33065:14;;33093:1;33088:785;;;;33917:1;33934:6;33931:89;;;-1:-1:-1;33986:19:1;;;33980:26;33931:89;19842:66;19833:1;19829:11;;;19825:84;19821:89;19811:100;19917:1;19913:11;;;19808:117;34033:81;;33058:1066;;33088:785;13557:1;13550:14;;;13594:4;13581:18;;33136:66;33124:79;;;33304:236;33318:7;33315:1;33312:14;33304:236;;;33407:19;;;33401:26;33386:42;;33499:27;;;;33467:1;33455:14;;;;33334:19;;33304:236;;;33308:3;33568:6;33559:7;33556:19;33553:261;;;33629:19;;;33623:26;33730:66;33712:1;33708:14;;;33724:3;33704:24;33700:97;33696:102;33681:118;33666:134;;33553:261;-1:-1:-1;;;;;33860:1:1;33844:14;;;33840:22;33827:36;;-1:-1:-1;32656:1474:1:o;34135:175::-;34172:3;34216:4;34209:5;34205:16;34245:4;34236:7;34233:17;34230:43;;34253:18;;:::i;:::-;34302:1;34289:15;;34135:175;-1:-1:-1;;34135:175:1:o;34315:227::-;34383:64;34467:10;;;34479;;;34463:27;;34502:11;;;34499:37;;;34516:18;;:::i;34547:496::-;34726:3;34764:6;34758:13;34780:66;34839:6;34834:3;34827:4;34819:6;34815:17;34780:66;:::i;:::-;34909:13;;34868:16;;;;34931:70;34909:13;34868:16;34978:4;34966:17;;34931:70;:::i;35048:703::-;35275:3;35313:6;35307:13;35329:66;35388:6;35383:3;35376:4;35368:6;35364:17;35329:66;:::i;:::-;35458:13;;35417:16;;;;35480:70;35458:13;35417:16;35527:4;35515:17;;35480:70;:::i;:::-;35617:13;;35572:20;;;35639:70;35617:13;35572:20;35686:4;35674:17;;35639:70;:::i;:::-;35725:20;;35048:703;-1:-1:-1;;;;;35048:703:1:o
Swarm Source
ipfs://34c053c104a000e78fffe39a44e638b4da9cff0496d8b480ad4ab93278cfdc2d