Contract Address Details

0xA4434AFEae0dECb9820D906BF01b13291D00651a

Token
Agile (AGL)
Creator
0x934998–cd1b8b at 0x7379fc–856cbb
Balance
0 CRO ( )
Tokens
Fetching tokens...
Transactions
3,600 Transactions
Transfers
805 Transfers
Gas Used
153,934,672
Last Balance Update
13779425
Contract name:
AGL




Optimization enabled
true
Compiler version
v0.5.17+commit.d19bba13




Optimization runs
200
EVM Version
default




Verified at
2021-12-03T07:44:29.608574Z

Constructor Arguments

0000000000000000000000009349982fa1079dedae653af3612fdea7cccd1b8b

Arg [0] (address) : 0x9349982fa1079dedae653af3612fdea7cccd1b8b

              

Contract source code

// File: Governance/AGL.sol

pragma solidity ^0.5.16;


/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * magler, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context {
  // Empty internal constructor, to prevent people from mistakenly deploying
  // an instance of this contract, which should be used via inheritance.
  constructor () internal { }

  function _msgSender() internal view returns (address payable) {
    return msg.sender;
  }

  function _msgData() internal view returns (bytes memory) {
    this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
    return msg.data;
  }
}

// File: @openzeppelin/contracts/access/Ownable.sol
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable is Context {
    address private _owner;
    address private _authorizedNewOwner;
    event OwnershipTransferAuthorization(address indexed authorizedAddress);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }
    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }
    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }
    /**
     * @dev Returns the address of the current authorized new owner.
     */
    function authorizedNewOwner() public view returns (address) {
        return _authorizedNewOwner;
    }
    /**
     * @notice Authorizes the transfer of ownership from _owner to the provided address.
     * NOTE: No transfer will occur unless authorizedAddress calls assumeOwnership( ).
     * This authorization may be removed by another call to this function authorizing
     * the null address.
     *
     * @param authorizedAddress The address authorized to become the new owner.
     */
    function authorizeOwnershipTransfer(address authorizedAddress) external onlyOwner {
        _authorizedNewOwner = authorizedAddress;
        emit OwnershipTransferAuthorization(_authorizedNewOwner);
    }
    /**
     * @notice Transfers ownership of this contract to the _authorizedNewOwner.
     */
    function assumeOwnership() external {
        require(_msgSender() == _authorizedNewOwner, "Ownable: only the authorized new owner can accept ownership");
        emit OwnershipTransferred(_owner, _authorizedNewOwner);
        _owner = _authorizedNewOwner;
        _authorizedNewOwner = address(0);
    }
    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     *
     * @param confirmAddress The address wants to give up ownership.
     */
    function renounceOwnership(address confirmAddress) public onlyOwner {
        require(confirmAddress == _owner, "Ownable: confirm address is wrong");
        emit OwnershipTransferred(_owner, address(0));
        _authorizedNewOwner = address(0);
        _owner = address(0);
    }
}

contract AGL is Ownable {
    /// @notice BEP-20 token name for this token
    string public constant name = "Agile";

    /// @notice BEP-20 token symbol for this token
    string public constant symbol = "AGL";

    /// @notice BEP-20 token decimals for this token
    uint8 public constant decimals = 18;

    /// @notice Total number of tokens in circulation
    uint public constant totalSupply = 1000000000e18; // 1 billion AGL

    /// @notice Reward eligible epochs
    uint32 public constant eligibleEpochs = 60; // 60 epochs

    /// @notice Allowance amounts on behalf of others
    mapping (address => mapping (address => uint96)) internal allowances;

    /// @notice Official record of token balances for each account
    mapping (address => uint96) internal balances;

    /// @notice A record of each accounts delegate
    mapping (address => address) public delegates;

    /// @notice A checkpoint for marking number of votes from a given block
    struct Checkpoint {
        uint32 fromBlock;
        uint96 votes;
    }

    /// @notice A transferPoint for marking balance from given epoch
    struct TransferPoint {
        uint32 epoch;
        uint96 balance;
    }

    /// @notice A epoch config for blocks or ROI per epoch
    struct EpochConfig {
        uint32 epoch;
        uint32 blocks;
        uint32 roi;
    }

    /// @notice A record of votes checkpoints for each account, by index
    mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;

    /// @notice A record of transfer checkpoints for each account
    mapping (address => mapping (uint32 => TransferPoint)) public transferPoints;

    /// @notice The number of checkpoints for each account
    mapping (address => uint32) public numCheckpoints;

    /// @notice The number of transferPoints for each account
    mapping (address => uint32) public numTransferPoints;

    /// @notice The claimed amount for each account
    mapping (address => uint96) public claimedAmounts;

    /// @notice Configs for epoch
    EpochConfig[] public epochConfigs;

    /// @notice The EIP-712 typehash for the contract's domain
    bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");

    /// @notice The EIP-712 typehash for the delegation struct used by the contract
    bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");

    /// @notice A record of states for signing / validating signatures
    mapping (address => uint) public nonces;

    /// @notice An event thats emitted when an account changes its delegate
    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);

    /// @notice An event thats emitted when a delegate account's vote balance changes
    event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);

    /// @notice An event thats emitted when a transfer point balance changes
    // event TransferPointChanged(address indexed src, uint srcBalance, address indexed dst, uint dstBalance);

    /// @notice An event thats emitted when epoch block count changes
    event EpochConfigChanged(uint32 indexed previousEpoch, uint32 previousBlocks, uint32 previousROI, uint32 indexed newEpoch, uint32 newBlocks, uint32 newROI);

    /// @notice The standard BEP-20 transfer event
    event Transfer(address indexed from, address indexed to, uint256 amount);

    /// @notice The standard BEP-20 approval event
    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /**
     * @notice Construct a new AGL token
     * @param account The initial account to grant all the tokens
     */
    constructor(address account) public {
        EpochConfig memory newEpochConfig = EpochConfig(
            0,
            24 * 60 * 60 / 6, // 1 day blocks in BSC
            20 // 0.2% ROI increase per epoch
        );
        epochConfigs.push(newEpochConfig);
        emit EpochConfigChanged(0, 0, 0, newEpochConfig.epoch, newEpochConfig.blocks, newEpochConfig.roi);
        balances[account] = uint96(totalSupply);
        _writeTransferPoint(address(0), account, 0, 0, uint96(totalSupply));
        emit Transfer(address(0), account, totalSupply);
    }

    /**
     * @notice Get the number of tokens `spender` is approved to spend on behalf of `account`
     * @param account The address of the account holding the funds
     * @param spender The address of the account spending the funds
     * @return The number of tokens approved
     */
    function allowance(address account, address spender) external view returns (uint) {
        return allowances[account][spender];
    }

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     * @param spender The address of the account which may transfer tokens
     * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)
     * @return Whether or not the approval succeeded
     */
    function approve(address spender, uint rawAmount) external returns (bool) {
        uint96 amount;
        if (rawAmount == uint(-1)) {
            amount = uint96(-1);
        } else {
            amount = safe96(rawAmount, "AGL::approve: amount exceeds 96 bits");
        }

        allowances[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);
        return true;
    }

    /**
     * @notice Get the number of tokens held by the `account`
     * @param account The address of the account to get the balance of
     * @return The number of tokens held
     */
    function balanceOf(address account) external view returns (uint) {
        return balances[account];
    }

    /**
     * @notice Transfer `amount` tokens from `msg.sender` to `dst`
     * @param dst The address of the destination account
     * @param rawAmount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transfer(address dst, uint rawAmount) external  returns (bool) {
        uint96 amount = safe96(rawAmount, "AGL::transfer: amount exceeds 96 bits");
        _transferTokens(msg.sender, dst, amount);
        return true;
    }

    /**
     * @notice Transfer `amount` tokens from `src` to `dst`
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param rawAmount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferFrom(address src, address dst, uint rawAmount) external  returns (bool) {
        address spender = msg.sender;
        uint96 spenderAllowance = allowances[src][spender];
        uint96 amount = safe96(rawAmount, "AGL::approve: amount exceeds 96 bits");

        if (spender != src && spenderAllowance != uint96(-1)) {
            uint96 newAllowance = sub96(spenderAllowance, amount, "AGL::transferFrom: transfer amount exceeds spender allowance");
            allowances[src][spender] = newAllowance;

            emit Approval(src, spender, newAllowance);
        }

        _transferTokens(src, dst, amount);
        return true;
    }

    /**
     * @notice Delegate votes from `msg.sender` to `delegatee`
     * @param delegatee The address to delegate votes to
     */
    function delegate(address delegatee) public  {
        return _delegate(msg.sender, delegatee);
    }

    /**
     * @notice Delegates votes from signatory to `delegatee`
     * @param delegatee The address to delegate votes to
     * @param nonce The contract state required to match the signature
     * @param expiry The time at which to expire the signature
     * @param v The recovery byte of the signature
     * @param r Half of the ECDSA signature pair
     * @param s Half of the ECDSA signature pair
     */
    function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public  {
        bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this)));
        bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));
        bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
        address signatory = ecrecover(digest, v, r, s);
        require(signatory != address(0), "AGL::delegateBySig: invalid signature");
        require(nonce == nonces[signatory]++, "AGL::delegateBySig: invalid nonce");
        require(now <= expiry, "AGL::delegateBySig: signature expired");
        return _delegate(signatory, delegatee);
    }

    /**
     * @notice Gets the current votes balance for `account`
     * @param account The address to get votes balance
     * @return The number of current votes for `account`
     */
    function getCurrentVotes(address account) external view returns (uint96) {
        uint32 nCheckpoints = numCheckpoints[account];
        return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
    }

    /**
     * @notice Determine the prior number of votes for an account as of a block number
     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
     * @param account The address of the account to check
     * @param blockNumber The block number to get the vote balance at
     * @return The number of votes the account had as of the given block
     */
    function getPriorVotes(address account, uint blockNumber) public view returns (uint96) {
        require(blockNumber < block.number, "AGL::getPriorVotes: not yet determined");

        uint32 nCheckpoints = numCheckpoints[account];
        if (nCheckpoints == 0) {
            return 0;
        }

        // First check most recent balance
        if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
            return checkpoints[account][nCheckpoints - 1].votes;
        }

        // Next check implicit zero balance
        if (checkpoints[account][0].fromBlock > blockNumber) {
            return 0;
        }

        uint32 lower = 0;
        uint32 upper = nCheckpoints - 1;
        while (upper > lower) {
            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            Checkpoint memory cp = checkpoints[account][center];
            if (cp.fromBlock == blockNumber) {
                return cp.votes;
            } else if (cp.fromBlock < blockNumber) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return checkpoints[account][lower].votes;
    }

    /**
     * @notice Sets block counter per epoch
     * @param blocks The count of blocks per epoch
     * @param roi The interet of rate increased per epoch
     */
    function setEpochConfig(uint32 blocks, uint32 roi) public onlyOwner {
        require(blocks > 0, "AGL::setEpochConfig: zero blocks");
        require(roi < 10000, "AGL::setEpochConfig: roi exceeds max fraction");
        EpochConfig memory prevEC = epochConfigs[epochConfigs.length - 1];
        EpochConfig memory newEC = EpochConfig(getEpochs(block.number), blocks, roi);
        require(prevEC.blocks != newEC.blocks || prevEC.roi != newEC.roi, "AGL::setEpochConfig: blocks and roi same as before");
        //if (prevEC.epoch == newEC.epoch && epochConfigs.length > 1) {
        if (prevEC.epoch == newEC.epoch) {
            epochConfigs[epochConfigs.length - 1] = newEC;
        } else {
            epochConfigs.push(newEC);
        }
        emit EpochConfigChanged(prevEC.epoch, prevEC.blocks, prevEC.roi, newEC.epoch, newEC.blocks, newEC.roi);
    }

    /**
     * @notice Gets block counter per epoch
     * @return The count of blocks for current epoch
     */
    function getCurrentEpochBlocks() public view returns (uint32 blocks) {
        blocks = epochConfigs[epochConfigs.length - 1].blocks;
    }

    /**
     * @notice Gets rate of interest for current epoch
     * @return The rate of interest for current epoch
     */
    function getCurrentEpochROI() public view returns (uint32 roi) {
        roi = epochConfigs[epochConfigs.length - 1].roi;
    }

    /**
     * @notice Gets current epoch config
     * @return The EpochConfig for current epoch
     */
    function getCurrentEpochConfig() public view returns (uint32 epoch, uint32 blocks, uint32 roi) {
        EpochConfig memory ec = epochConfigs[epochConfigs.length - 1];
        epoch = ec.epoch;
        blocks = ec.blocks;
        roi = ec.roi;
    }

    /**
     * @notice Gets epoch config at given epoch index
     * @param forEpoch epoch
     * @return (index of config,
                config at epoch)
     */
    function getEpochConfig(uint32 forEpoch) public view returns (uint32 index, uint32 epoch, uint32 blocks, uint32 roi) {
        index = uint32(epochConfigs.length - 1);
        // solhint-disable-next-line no-inline-assembly
        for (; index > 0; index--) {
            if (forEpoch >= epochConfigs[index].epoch) {
                break;
            }
        }
        EpochConfig memory ec = epochConfigs[index];
        epoch = ec.epoch;
        blocks = ec.blocks;
        roi = ec.roi;
    }

    /**
     * @notice Gets epoch index at given block number
     * @param blockNumber The number of blocks
     * @return epoch index
     */
    function getEpochs(uint blockNumber) public view returns (uint32) {
        uint96 blocks = 0;
        uint96 epoch = 0;
        uint blockNum = blockNumber;
        for (uint32 i = 0; i < epochConfigs.length; i++) {
            uint96 deltaBlocks = (uint96(epochConfigs[i].epoch) - epoch) * blocks;
            if (blockNum < deltaBlocks) {
                break;
            }
            blockNum = blockNum - deltaBlocks;
            epoch = epochConfigs[i].epoch;
            blocks = epochConfigs[i].blocks;
        }

        if (blocks == 0) {
            blocks = getCurrentEpochBlocks();
        }
        epoch = epoch + uint96(blockNum / blocks);
        if (epoch >= 2**32) {
            epoch = 2**32 - 1;
        }
        return uint32(epoch);
    }

    /**
     * @notice Gets the current holding rewart amount for `account`
     * @param account The address to get holding reward amount
     * @return The number of current holding reward for `account`
     */
    function getHoldingReward(address account) public view returns (uint96) {
        // Check if account is holding more than eligible delay
        uint32 nTransferPoint = numTransferPoints[account];

        if (nTransferPoint == 0) {
            return 0;
        }

        uint32 lastEpoch = getEpochs(block.number);
        if (lastEpoch == 0) {
            return 0;
        }

        lastEpoch = lastEpoch - 1;
        if (lastEpoch < eligibleEpochs) {
            return 0;
        } else {
            uint32 lastEligibleEpoch = lastEpoch - eligibleEpochs;

            // Next check implicit zero balance
            if (transferPoints[account][0].epoch > lastEligibleEpoch) {
                return 0;
            }

            // First check most recent balance
            if (transferPoints[account][nTransferPoint - 1].epoch <= lastEligibleEpoch) {
                nTransferPoint = nTransferPoint - 1;
            } else {
                uint32 upper = nTransferPoint - 1;
                nTransferPoint = 0;
                while (upper > nTransferPoint) {
                    uint32 center = upper - (upper - nTransferPoint) / 2; // ceil, avoiding overflow
                    TransferPoint memory tp = transferPoints[account][center];
                    if (tp.epoch == lastEligibleEpoch) {
                        nTransferPoint = center;
                        break;
                    } if (tp.epoch < lastEligibleEpoch) {
                        nTransferPoint = center;
                    } else {
                        upper = center - 1;
                    }
                }
            }
        }

        // Calculate total rewards amount
        uint256 reward = 0;
        for (uint32 iTP = 0; iTP <= nTransferPoint; iTP++) {
            TransferPoint memory tp = transferPoints[account][iTP];
            (uint32 iEC,,,uint32 roi) = getEpochConfig(tp.epoch);
            uint32 startEpoch = tp.epoch;
            for (; iEC < epochConfigs.length; iEC++) {
                uint32 epoch = lastEpoch;
                bool tookNextTP = false;
                if (iEC < (epochConfigs.length - 1) && epoch > epochConfigs[iEC + 1].epoch) {
                    epoch = epochConfigs[iEC + 1].epoch;
                }
                if (iTP < nTransferPoint && epoch > transferPoints[account][iTP + 1].epoch) {
                    epoch = transferPoints[account][iTP + 1].epoch;
                    tookNextTP = true;
                }
                reward = reward + (uint256(tp.balance) * roi * sub32(epoch, startEpoch, "AGL::getHoldingReward: invalid epochs"));
                if (tookNextTP) {
                    break;
                }
                startEpoch = epoch;
                if (iEC < (epochConfigs.length - 1)) {
                    roi = epochConfigs[iEC + 1].roi;
                }
            }
        }
        uint96 amount = safe96(reward / 10000, "AGL::getHoldingReward: reward exceeds 96 bits");

        // Exclude already claimed amount
        if (claimedAmounts[account] > 0) {
            amount = sub96(amount, claimedAmounts[account], "AGL::getHoldingReward: invalid claimed amount");
        }

        return amount;
    }

    /**
     * @notice Receive the current holding rewart amount to msg.sender
     */
    function claimReward() public  {
        uint96 holdingReward = getHoldingReward(msg.sender);
        if (balances[address(this)] < holdingReward) {
            holdingReward = balances[address(this)];
        }
        claimedAmounts[msg.sender] = add96(claimedAmounts[msg.sender], holdingReward, "AGL::claimReward: invalid claimed amount");
        _transferTokens(address(this), msg.sender, holdingReward);
    }

    function _delegate(address delegator, address delegatee) internal {
        address currentDelegate = delegates[delegator];
        uint96 delegatorBalance = balances[delegator];
        delegates[delegator] = delegatee;

        emit DelegateChanged(delegator, currentDelegate, delegatee);

        _moveDelegates(currentDelegate, delegatee, delegatorBalance);
    }

    function _transferTokens(address src, address dst, uint96 amount) internal {
        require(src != address(0), "AGL::_transferTokens: caglot transfer from the zero address");
        require(dst != address(0), "AGL::_transferTokens: caglot transfer to the zero address");

        balances[src] = sub96(balances[src], amount, "AGL::_transferTokens: transfer amount exceeds balance");
        balances[dst] = add96(balances[dst], amount, "AGL::_transferTokens: transfer amount overflows");
        emit Transfer(src, dst, amount);

        _moveDelegates(delegates[src], delegates[dst], amount);
        if (amount > 0) {
            _writeTransferPoint(src, dst, numTransferPoints[dst], balances[src], balances[dst]);
        }
    }

    function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal {
        if (srcRep != dstRep && amount > 0) {
            if (srcRep != address(0)) {
                uint32 srcRepNum = numCheckpoints[srcRep];
                uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                uint96 srcRepNew = sub96(srcRepOld, amount, "AGL::_moveVotes: vote amount underflows");
                _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
            }

            if (dstRep != address(0)) {
                uint32 dstRepNum = numCheckpoints[dstRep];
                uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                uint96 dstRepNew = add96(dstRepOld, amount, "AGL::_moveVotes: vote amount overflows");
                _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
            }
        }
    }

    function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal {
      uint32 blockNumber = safe32(block.number, "AGL::_writeCheckpoint: block number exceeds 32 bits");

      if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
          checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
      } else {
          checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
          numCheckpoints[delegatee] = nCheckpoints + 1;
      }

      emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
    }

    function _writeTransferPoint(address src, address dst, uint32 nDstPoint, uint96 srcBalance, uint96 dstBalance) internal {
        uint32 epoch = getEpochs(block.number);

        if (src != address(this)) {
            // Revoke sender in reward eligible list
            for (uint32 i = 0; i < numTransferPoints[src]; i++) {
                delete transferPoints[src][i];
            }

            // Remove claim amount
            claimedAmounts[src] = 0;

            // delete transferPoints[src];
            if (srcBalance > 0) {
                transferPoints[src][0] = TransferPoint(epoch, srcBalance);
                numTransferPoints[src] = 1;
            } else {
                numTransferPoints[src] = 0;
            }
        }

        if (dst != address(this)) {
            // Add recipient in reward eligible list
            if (nDstPoint > 0 && transferPoints[dst][nDstPoint - 1].epoch >= epoch) {
                transferPoints[dst][nDstPoint - 1].balance = dstBalance;
            } else {
                transferPoints[dst][nDstPoint] = TransferPoint(epoch, dstBalance);
                numTransferPoints[dst] = nDstPoint + 1;
            }
        }

        // emit TransferPointChanged(src, balances[src], dst, balances[dst]);
    }

    function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
        require(n < 2**32, errorMessage);
        return uint32(n);
    }

    function add32(uint32 a, uint32 b, string memory errorMessage) internal pure returns (uint32) {
        uint32 c = a + b;
        require(c >= a, errorMessage);
        return c;
    }

    function sub32(uint32 a, uint32 b, string memory errorMessage) internal pure returns (uint32) {
        require(b <= a, errorMessage);
        return a - b;
    }

    function safe96(uint n, string memory errorMessage) internal pure returns (uint96) {
        require(n < 2**96, errorMessage);
        return uint96(n);
    }

    function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
        uint96 c = a + b;
        require(c >= a, errorMessage);
        return c;
    }

    function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
        require(b <= a, errorMessage);
        return a - b;
    }

    function getChainId() internal pure returns (uint) {
        uint256 chainId;
        assembly { chainId := chainid() }
        return chainId;
    }
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DelegateChanged","inputs":[{"type":"address","name":"delegator","internalType":"address","indexed":true},{"type":"address","name":"fromDelegate","internalType":"address","indexed":true},{"type":"address","name":"toDelegate","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"DelegateVotesChanged","inputs":[{"type":"address","name":"delegate","internalType":"address","indexed":true},{"type":"uint256","name":"previousBalance","internalType":"uint256","indexed":false},{"type":"uint256","name":"newBalance","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EpochConfigChanged","inputs":[{"type":"uint32","name":"previousEpoch","internalType":"uint32","indexed":true},{"type":"uint32","name":"previousBlocks","internalType":"uint32","indexed":false},{"type":"uint32","name":"previousROI","internalType":"uint32","indexed":false},{"type":"uint32","name":"newEpoch","internalType":"uint32","indexed":true},{"type":"uint32","name":"newBlocks","internalType":"uint32","indexed":false},{"type":"uint32","name":"newROI","internalType":"uint32","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferAuthorization","inputs":[{"type":"address","name":"authorizedAddress","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DELEGATION_TYPEHASH","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DOMAIN_TYPEHASH","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"rawAmount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"assumeOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"authorizeOwnershipTransfer","inputs":[{"type":"address","name":"authorizedAddress","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"authorizedNewOwner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"fromBlock","internalType":"uint32"},{"type":"uint96","name":"votes","internalType":"uint96"}],"name":"checkpoints","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint32","name":"","internalType":"uint32"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"claimReward","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint96","name":"","internalType":"uint96"}],"name":"claimedAmounts","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"delegate","inputs":[{"type":"address","name":"delegatee","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"delegateBySig","inputs":[{"type":"address","name":"delegatee","internalType":"address"},{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"uint256","name":"expiry","internalType":"uint256"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"delegates","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"eligibleEpochs","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"epoch","internalType":"uint32"},{"type":"uint32","name":"blocks","internalType":"uint32"},{"type":"uint32","name":"roi","internalType":"uint32"}],"name":"epochConfigs","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"blocks","internalType":"uint32"}],"name":"getCurrentEpochBlocks","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"epoch","internalType":"uint32"},{"type":"uint32","name":"blocks","internalType":"uint32"},{"type":"uint32","name":"roi","internalType":"uint32"}],"name":"getCurrentEpochConfig","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"roi","internalType":"uint32"}],"name":"getCurrentEpochROI","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint96","name":"","internalType":"uint96"}],"name":"getCurrentVotes","inputs":[{"type":"address","name":"account","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"index","internalType":"uint32"},{"type":"uint32","name":"epoch","internalType":"uint32"},{"type":"uint32","name":"blocks","internalType":"uint32"},{"type":"uint32","name":"roi","internalType":"uint32"}],"name":"getEpochConfig","inputs":[{"type":"uint32","name":"forEpoch","internalType":"uint32"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"getEpochs","inputs":[{"type":"uint256","name":"blockNumber","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint96","name":"","internalType":"uint96"}],"name":"getHoldingReward","inputs":[{"type":"address","name":"account","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint96","name":"","internalType":"uint96"}],"name":"getPriorVotes","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"blockNumber","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nonces","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"numCheckpoints","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"numTransferPoints","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[{"type":"address","name":"confirmAddress","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setEpochConfig","inputs":[{"type":"uint32","name":"blocks","internalType":"uint32"},{"type":"uint32","name":"roi","internalType":"uint32"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"dst","internalType":"address"},{"type":"uint256","name":"rawAmount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"src","internalType":"address"},{"type":"address","name":"dst","internalType":"address"},{"type":"uint256","name":"rawAmount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"epoch","internalType":"uint32"},{"type":"uint96","name":"balance","internalType":"uint96"}],"name":"transferPoints","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint32","name":"","internalType":"uint32"}],"constant":true}]
            

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106102275760003560e01c806387f4427e11610130578063b88a802f116100b8578063dd62ed3e1161007c578063dd62ed3e14610751578063e7a324dc1461077f578063f1127ed814610787578063f2a60b61146107b9578063f665a206146107c157610227565b8063b88a802f1461067b578063c3cda52014610683578063c717d7be146106ca578063cc2740b71461071e578063cddfea471461072657610227565b806391f4cfba116100ff57806391f4cfba1461061157806395d89b4114610619578063a2c1cae214610621578063a9059cbb14610629578063b4b5ea571461065557610227565b806387f4427e146105785780638b028b7e1461059e5780638c4b553c146105c45780638da5cb5b1461060957610227565b806338bf3cfa116101b35780636fcfff45116101825780636fcfff451461049857806370a08231146104be57806371417b32146104e4578063782d6fe1146105265780637ecebe001461055257610227565b806338bf3cfa146104005780635481eed314610428578063587cde1e1461044c5780635c19a95c1461047257610227565b806320606b70116101fa57806320606b701461034257806323b872dd1461034a57806326e6760b14610380578063313ce5671461038857806332e2a55d146103a657610227565b806306fdde031461022c578063095ea7b3146102a95780630b7cbac7146102e957806318160ddd14610328575b600080fd5b6102346107de565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561026e578181015183820152602001610256565b50505050905090810190601f16801561029b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102d5600480360360408110156102bf57600080fd5b506001600160a01b0381351690602001356107ff565b604080519115158252519081900360200190f35b61030f600480360360208110156102ff57600080fd5b50356001600160a01b03166108bd565b6040805163ffffffff9092168252519081900360200190f35b6103306108d5565b60408051918252519081900360200190f35b6103306108e5565b6102d56004803603606081101561036057600080fd5b506001600160a01b03813581169160208101359091169060400135610900565b61030f610a45565b610390610a79565b6040805160ff9092168252519081900360200190f35b6103d8600480360360408110156103bc57600080fd5b5080356001600160a01b0316906020013563ffffffff16610a7e565b6040805163ffffffff90931683526001600160601b0390911660208301528051918290030190f35b6104266004803603602081101561041657600080fd5b50356001600160a01b0316610ab3565b005b610430610bca565b604080516001600160a01b039092168252519081900360200190f35b6104306004803603602081101561046257600080fd5b50356001600160a01b0316610bd9565b6104266004803603602081101561048857600080fd5b50356001600160a01b0316610bf4565b61030f600480360360208110156104ae57600080fd5b50356001600160a01b0316610c01565b610330600480360360208110156104d457600080fd5b50356001600160a01b0316610c19565b61050a600480360360208110156104fa57600080fd5b50356001600160a01b0316610c41565b604080516001600160601b039092168252519081900360200190f35b61050a6004803603604081101561053c57600080fd5b506001600160a01b038135169060200135610c5c565b6103306004803603602081101561056857600080fd5b50356001600160a01b0316610e89565b6104266004803603602081101561058e57600080fd5b50356001600160a01b0316610e9b565b61050a600480360360208110156105b457600080fd5b50356001600160a01b0316610f5f565b6105e1600480360360208110156105da57600080fd5b5035611425565b6040805163ffffffff9485168152928416602084015292168183015290519081900360600190f35b61043061145d565b61030f61146c565b610234611471565b610426611490565b6102d56004803603604081101561063f57600080fd5b506001600160a01b03813516906020013561154d565b61050a6004803603602081101561066b57600080fd5b50356001600160a01b0316611589565b6104266115fa565b610426600480360360c081101561069957600080fd5b506001600160a01b038135169060208101359060408101359060ff6060820135169060808101359060a001356116c2565b6106ed600480360360208110156106e057600080fd5b503563ffffffff16611968565b6040805163ffffffff9586168152938516602085015291841683830152909216606082015290519081900360800190f35b6105e1611a2e565b6104266004803603604081101561073c57600080fd5b5063ffffffff81358116916020013516611a9c565b6103306004803603604081101561076757600080fd5b506001600160a01b0381358116916020013516611e4b565b610330611e7f565b6103d86004803603604081101561079d57600080fd5b5080356001600160a01b0316906020013563ffffffff16611e9a565b61030f611ecf565b61030f600480360360208110156107d757600080fd5b5035611f03565b604051806040016040528060058152602001644167696c6560d81b81525081565b600080600019831415610815575060001961083a565b61083783604051806060016040528060248152602001612c5d60249139612025565b90505b3360008181526002602090815260408083206001600160a01b0389168085529083529281902080546001600160601b0319166001600160601b038716908117909155815190815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a360019150505b92915050565b60086020526000908152604090205463ffffffff1681565b6b033b2e3c9fd0803ce800000081565b604051806043612e8f82396043019050604051809103902081565b6001600160a01b03831660009081526002602090815260408083203380855290835281842054825160608101909352602480845291936001600160601b039091169285926109589288929190612c5d90830139612025565b9050866001600160a01b0316836001600160a01b03161415801561098557506001600160601b0382811614155b15610a2d5760006109af83836040518060600160405280603c8152602001612c81603c91396120bf565b6001600160a01b038981166000818152600260209081526040808320948a168084529482529182902080546001600160601b0319166001600160601b03871690811790915582519081529151949550929391927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92592918290030190a3505b610a3887878361212c565b5060019695505050505050565b600a8054600091906000198101908110610a5b57fe5b600091825260209091200154600160201b900463ffffffff16919050565b601281565b600660209081526000928352604080842090915290825290205463ffffffff811690600160201b90046001600160601b031682565b610abb612374565b6001600160a01b0316610acc61145d565b6001600160a01b031614610b27576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6000546001600160a01b03828116911614610b735760405162461bcd60e51b8152600401808060200182810382526021815260200180612d6e6021913960400191505060405180910390fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a350600180546001600160a01b0319908116909155600080549091169055565b6001546001600160a01b031690565b6004602052600090815260409020546001600160a01b031681565b610bfe3382612378565b50565b60076020526000908152604090205463ffffffff1681565b6001600160a01b0381166000908152600360205260409020546001600160601b03165b919050565b6009602052600090815260409020546001600160601b031681565b6000438210610c9c5760405162461bcd60e51b8152600401808060200182810382526026815260200180612ce26026913960400191505060405180910390fd5b6001600160a01b03831660009081526007602052604090205463ffffffff1680610cca5760009150506108b7565b6001600160a01b038416600090815260056020908152604080832063ffffffff600019860181168552925290912054168310610d46576001600160a01b03841660009081526005602090815260408083206000199490940163ffffffff1683529290522054600160201b90046001600160601b031690506108b7565b6001600160a01b038416600090815260056020908152604080832083805290915290205463ffffffff16831015610d815760009150506108b7565b600060001982015b8163ffffffff168163ffffffff161115610e4457600282820363ffffffff16048103610db3612b3a565b506001600160a01b038716600090815260056020908152604080832063ffffffff858116855290835292819020815180830190925254928316808252600160201b9093046001600160601b03169181019190915290871415610e1f576020015194506108b79350505050565b805163ffffffff16871115610e3657819350610e3d565b6001820392505b5050610d89565b506001600160a01b038516600090815260056020908152604080832063ffffffff909416835292905220546001600160601b03600160201b9091041691505092915050565b600b6020526000908152604090205481565b610ea3612374565b6001600160a01b0316610eb461145d565b6001600160a01b031614610f0f576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383811691909117918290556040519116907fb58bcc286020502f4931905baafed22acc969c092ed724234c73361efc68839090600090a250565b6001600160a01b03811660009081526008602052604081205463ffffffff1680610f8d576000915050610c3c565b6000610f9843611f03565b905063ffffffff8116610fb057600092505050610c3c565b60001901603c63ffffffff82161015610fce57600092505050610c3c565b6001600160a01b0384166000908152600660209081526040808320838052909152902054603b1982019063ffffffff808316911611156110145760009350505050610c3c565b6001600160a01b038516600090815260066020908152604080832063ffffffff60001988018116855292529091205482821691161161105857600183039250611119565b600092600019015b8363ffffffff168163ffffffff16111561111757600284820363ffffffff1604810361108a612b3a565b506001600160a01b038716600090815260066020908152604080832063ffffffff858116855290835292819020815180830190925254808416808352600160201b9091046001600160601b03169282019290925291851614156110ef57509350611117565b805163ffffffff8086169116101561110957819550611110565b6001820392505b5050611060565b505b506000805b8363ffffffff168163ffffffff161161136b57611139612b3a565b506001600160a01b038616600090815260066020908152604080832063ffffffff8581168552908352818420825180840190935254908116808352600160201b9091046001600160601b0316928201929092529190819061119990611968565b8651939550935050505b600a5463ffffffff8416101561135b57600a5487906000906000190163ffffffff86161080156111fd5750600a8560010163ffffffff16815481106111e457fe5b60009182526020909120015463ffffffff908116908316115b1561122d57600a8560010163ffffffff168154811061121857fe5b60009182526020909120015463ffffffff1691505b8963ffffffff168763ffffffff1610801561127857506001600160a01b038c16600090815260066020908152604080832063ffffffff60018c01811685529252909120548116908316115b156112b25750506001600160a01b038a16600090815260066020908152604080832063ffffffff6001808b01821686529190935292205416905b6112d58284604051806060016040528060258152602001612e6a60259139612402565b63ffffffff168463ffffffff1687602001516001600160601b0316020288019750801561130357505061135b565b600a5491925082916000190163ffffffff8616101561134e57600a8560010163ffffffff168154811061133257fe5b600091825260209091200154600160401b900463ffffffff1693505b50506001909201916111a3565b50506001909201915061111e9050565b50600061139461271083046040518060600160405280602d8152602001612d08602d9139612025565b6001600160a01b0387166000908152600960205260409020549091506001600160601b03161561141c576114198160096000896001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a90046001600160601b03166040518060600160405280602d8152602001612ef8602d91396120bf565b90505b95945050505050565b600a818154811061143257fe5b60009182526020909120015463ffffffff8082169250600160201b8204811691600160401b90041683565b6000546001600160a01b031690565b603c81565b604051806040016040528060038152602001621051d360ea1b81525081565b6001546001600160a01b03166114a4612374565b6001600160a01b0316146114e95760405162461bcd60e51b815260040180806020018281038252603b815260200180612f25603b913960400191505060405180910390fd5b600154600080546040516001600160a01b0393841693909116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b60008061157283604051806060016040528060258152602001612e1260259139612025565b905061157f33858361212c565b5060019392505050565b6001600160a01b03811660009081526007602052604081205463ffffffff16806115b45760006115f3565b6001600160a01b0383166000908152600560209081526040808320600019850163ffffffff168452909152902054600160201b90046001600160601b03165b9392505050565b600061160533610f5f565b306000908152600360205260409020549091506001600160601b03808316911610156116465750306000908152600360205260409020546001600160601b03165b33600090815260096020908152604091829020548251606081019093526028808452611688936001600160601b039092169285929190612b7290830139612461565b33600081815260096020526040902080546001600160601b0319166001600160601b039390931692909217909155610bfe9030908361212c565b60006040518080612e8f604391396040805191829003604301822082820190915260058252644167696c6560d81b60209092019190915290507fdf62de8d512333d8e1288bad15f1c1efd2dbe23b4319759607c883965b8f37dc6117246124cb565b3060405160200180858152602001848152602001838152602001826001600160a01b03166001600160a01b0316815260200194505050505060405160208183030381529060405280519060200120905060006040518080612f85603a91396040805191829003603a0182206020808401919091526001600160a01b038c1683830152606083018b905260808084018b90528251808503909101815260a08401835280519082012061190160f01b60c085015260c2840187905260e2808501829052835180860390910181526101028501808552815191840191909120600091829052610122860180865281905260ff8c1661014287015261016286018b905261018286018a9052935191965092945091926001926101a28083019392601f198301929081900390910190855afa158015611862573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166118b45760405162461bcd60e51b8152600401808060200182810382526025815260200180612f606025913960400191505060405180910390fd5b6001600160a01b0381166000908152600b6020526040902080546001810190915589146119125760405162461bcd60e51b8152600401808060200182810382526021815260200180612df16021913960400191505060405180910390fd5b874211156119515760405162461bcd60e51b8152600401808060200182810382526025815260200180612cbd6025913960400191505060405180910390fd5b61195b818b612378565b505050505b505050505050565b600a5460001901600080805b63ffffffff8416156119c057600a8463ffffffff168154811061199357fe5b60009182526020909120015463ffffffff908116908616106119b4576119c0565b60001990930192611974565b6119c8612b51565b600a8563ffffffff16815481106119db57fe5b600091825260209182902060408051606081018252919092015463ffffffff808216808452600160201b83048216958401869052600160401b909204169190920181905296989097509095945092505050565b6000806000611a3b612b51565b600a80546000198101908110611a4d57fe5b600091825260209182902060408051606081018252929091015463ffffffff808216808552600160201b83048216958501869052600160401b9092041692909101829052969195509350915050565b611aa4612374565b6001600160a01b0316611ab561145d565b6001600160a01b031614611b10576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b60008263ffffffff1611611b6b576040805162461bcd60e51b815260206004820181905260248201527f41474c3a3a73657445706f6368436f6e6669673a207a65726f20626c6f636b73604482015290519081900360640190fd5b6127108163ffffffff1610611bb15760405162461bcd60e51b815260040180806020018281038252602d815260200180612d8f602d913960400191505060405180910390fd5b611bb9612b51565b600a80546000198101908110611bcb57fe5b600091825260209182902060408051606081018252919092015463ffffffff8082168352600160201b8204811694830194909452600160401b9004909216908201529050611c17612b51565b6040518060600160405280611c2b43611f03565b63ffffffff1681526020018563ffffffff1681526020018463ffffffff168152509050806020015163ffffffff16826020015163ffffffff16141580611c855750806040015163ffffffff16826040015163ffffffff1614155b611cc05760405162461bcd60e51b8152600401808060200182810382526032815260200180612b9a6032913960400191505060405180910390fd5b8051825163ffffffff90811691161415611d4d57600a80548291906000198101908110611ce957fe5b60009182526020918290208351910180549284015160409094015163ffffffff1990931663ffffffff9283161767ffffffff000000001916600160201b948316949094029390931763ffffffff60401b1916600160401b9190921602179055611dd7565b600a805460018101825560009190915281517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890910180546020840151604085015163ffffffff1990921663ffffffff9485161767ffffffff000000001916600160201b918516919091021763ffffffff60401b1916600160401b93909116929092029190911790555b805182516020808501516040808701518387015182880151835163ffffffff958616815292851695830195909552831681830152928216606084015251938116939216917fc01a508838d7b848b9827d7aefede67746ea1738597aa80f453c99f537ab6c499181900360800190a350505050565b6001600160a01b0391821660009081526002602090815260408083209390941682529190915220546001600160601b031690565b60405180603a612f858239603a019050604051809103902081565b600560209081526000928352604080842090915290825290205463ffffffff811690600160201b90046001600160601b031682565b600a8054600091906000198101908110611ee557fe5b600091825260209091200154600160401b900463ffffffff16919050565b6000808083815b600a5463ffffffff82161015611fca5760008484600a8463ffffffff1681548110611f3157fe5b60009182526020909120015463ffffffff16030290506001600160601b038116831015611f5e5750611fca565b806001600160601b031683039250600a8263ffffffff1681548110611f7f57fe5b600091825260209091200154600a805463ffffffff928316965090918416908110611fa657fe5b600091825260209091200154600160201b900463ffffffff16945050600101611f0a565b506001600160601b038316611fea57611fe1610a45565b63ffffffff1692505b826001600160601b03168181611ffc57fe5b0482019150600160201b826001600160601b03161061201d5763ffffffff91505b509392505050565b600081600160601b84106120b75760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561207c578181015183820152602001612064565b50505050905090810190601f1680156120a95780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509192915050565b6000836001600160601b0316836001600160601b0316111582906121245760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561207c578181015183820152602001612064565b505050900390565b6001600160a01b0383166121715760405162461bcd60e51b815260040180806020018281038252603b815260200180612bcc603b913960400191505060405180910390fd5b6001600160a01b0382166121b65760405162461bcd60e51b8152600401808060200182810382526039815260200180612d356039913960400191505060405180910390fd5b6001600160a01b038316600090815260036020908152604091829020548251606081019093526035808452612201936001600160601b039092169285929190612dbc908301396120bf565b6001600160a01b03848116600090815260036020908152604080832080546001600160601b0319166001600160601b0396871617905592861682529082902054825160608101909352602f8084526122699491909116928592909190612c2e90830139612461565b6001600160a01b0383811660008181526003602090815260409182902080546001600160601b0319166001600160601b039687161790558151948616855290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a36001600160a01b0380841660009081526004602052604080822054858416835291205461230c929182169116836124cf565b6001600160601b0381161561236f576001600160a01b03808316600081815260086020908152604080832054948816835260039091528082205492825290205461236f928692869263ffffffff909216916001600160601b039182169116612661565b505050565b3390565b6001600160a01b03808316600081815260046020818152604080842080546003845282862054949093528787166001600160a01b031984168117909155905191909516946001600160601b039092169391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a46123fc8284836124cf565b50505050565b60008363ffffffff168363ffffffff16111582906121245760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561207c578181015183820152602001612064565b6000838301826001600160601b0380871690831610156124c25760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561207c578181015183820152602001612064565b50949350505050565b4690565b816001600160a01b0316836001600160a01b0316141580156124fa57506000816001600160601b0316115b1561236f576001600160a01b038316156125b2576001600160a01b03831660009081526007602052604081205463ffffffff16908161253a576000612579565b6001600160a01b0385166000908152600560209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b905060006125a08285604051806060016040528060278152602001612c07602791396120bf565b90506125ae86848484612930565b5050505b6001600160a01b0382161561236f576001600160a01b03821660009081526007602052604081205463ffffffff1690816125ed57600061262c565b6001600160a01b0384166000908152600560209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b905060006126538285604051806060016040528060268152602001612ed260269139612461565b905061196085848484612930565b600061266c43611f03565b90506001600160a01b03861630146127e05760005b6001600160a01b03871660009081526008602052604090205463ffffffff90811690821610156126f3576001600160a01b038716600090815260066020908152604080832063ffffffff85168452909152902080546fffffffffffffffffffffffffffffffff19169055600101612681565b506001600160a01b038616600090815260096020526040902080546001600160601b03191690556001600160601b038316156127bc5760408051808201825263ffffffff80841682526001600160601b0380871660208085019182526001600160a01b038c166000818152600683528781208180528352878120965187549451909516600160201b02640100000000600160801b03199590961663ffffffff199485161794909416949094179094559181526008909252919020805490911660011790556127e0565b6001600160a01b0386166000908152600860205260409020805463ffffffff191690555b6001600160a01b03851630146119605760008463ffffffff1611801561283857506001600160a01b038516600090815260066020908152604080832063ffffffff600019890181168552925290912054828216911610155b15612892576001600160a01b0385166000908152600660209081526040808320600019880163ffffffff16845290915290208054640100000000600160801b031916600160201b6001600160601b03851602179055611960565b60408051808201825263ffffffff92831681526001600160601b0393841660208083019182526001600160a01b0398909816600081815260068a5284812089871682528a5284812093518454935163ffffffff1994851691881691909117640100000000600160801b031916600160201b91909816029690961790925590845260089096529091208054909416600190930116919091179091555050565b600061295443604051806060016040528060338152602001612e3760339139612ae5565b905060008463ffffffff1611801561299d57506001600160a01b038516600090815260056020908152604080832063ffffffff6000198901811685529252909120548282169116145b156129f7576001600160a01b0385166000908152600560209081526040808320600019880163ffffffff16845290915290208054640100000000600160801b031916600160201b6001600160601b03851602179055612a91565b60408051808201825263ffffffff80841682526001600160601b0380861660208085019182526001600160a01b038b166000818152600583528781208c871682528352878120965187549451909516600160201b02640100000000600160801b031995871663ffffffff19958616179590951694909417909555938252600790935292909220805460018801909316929091169190911790555b604080516001600160601b0380861682528416602082015281516001600160a01b038816927fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724928290030190a25050505050565b600081600160201b84106120b75760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561207c578181015183820152602001612064565b604080518082019091526000808252602082015290565b60408051606081018252600080825260208201819052918101919091529056fe41474c3a3a636c61696d5265776172643a20696e76616c696420636c61696d656420616d6f756e7441474c3a3a73657445706f6368436f6e6669673a20626c6f636b7320616e6420726f692073616d65206173206265666f726541474c3a3a5f7472616e73666572546f6b656e733a206361676c6f74207472616e736665722066726f6d20746865207a65726f206164647265737341474c3a3a5f6d6f7665566f7465733a20766f746520616d6f756e7420756e646572666c6f777341474c3a3a5f7472616e73666572546f6b656e733a207472616e7366657220616d6f756e74206f766572666c6f777341474c3a3a617070726f76653a20616d6f756e742065786365656473203936206269747341474c3a3a7472616e7366657246726f6d3a207472616e7366657220616d6f756e742065786365656473207370656e64657220616c6c6f77616e636541474c3a3a64656c656761746542795369673a207369676e6174757265206578706972656441474c3a3a6765745072696f72566f7465733a206e6f74207965742064657465726d696e656441474c3a3a676574486f6c64696e675265776172643a207265776172642065786365656473203936206269747341474c3a3a5f7472616e73666572546f6b656e733a206361676c6f74207472616e7366657220746f20746865207a65726f20616464726573734f776e61626c653a20636f6e6669726d20616464726573732069732077726f6e6741474c3a3a73657445706f6368436f6e6669673a20726f692065786365656473206d6178206672616374696f6e41474c3a3a5f7472616e73666572546f6b656e733a207472616e7366657220616d6f756e7420657863656564732062616c616e636541474c3a3a64656c656761746542795369673a20696e76616c6964206e6f6e636541474c3a3a7472616e736665723a20616d6f756e742065786365656473203936206269747341474c3a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d6265722065786365656473203332206269747341474c3a3a676574486f6c64696e675265776172643a20696e76616c69642065706f636873454950373132446f6d61696e28737472696e67206e616d652c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e74726163742941474c3a3a5f6d6f7665566f7465733a20766f746520616d6f756e74206f766572666c6f777341474c3a3a676574486f6c64696e675265776172643a20696e76616c696420636c61696d656420616d6f756e744f776e61626c653a206f6e6c792074686520617574686f72697a6564206e6577206f776e65722063616e20616363657074206f776e65727368697041474c3a3a64656c656761746542795369673a20696e76616c6964207369676e617475726544656c65676174696f6e28616464726573732064656c6567617465652c75696e74323536206e6f6e63652c75696e743235362065787069727929a265627a7a72315820ed2643d3527ae90bbee9850c89894dad0a6f33882887e1c2d8e42ce9dcabd56264736f6c63430005110032