false
false
0

Contract Address Details

0x9BfA10ec7cBDfa029692c95E493f2fc1BdCb25af

Contract Name
RandomNumberGenerator
Creator
0xc7d98cā€“7f3521 at 0x1391d5ā€“33d13c
Balance
0 CLO
Tokens
Fetching tokens...
Transactions
237 Transactions
Transfers
0 Transfers
Gas Used
11,104,611
Last Balance Update
16292547
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
RandomNumberGenerator




Optimization enabled
true
Compiler version
v0.8.17+commit.8df45f5f




Optimization runs
200
EVM Version
default




Verified at
2024-09-26T15:33:51.886303Z

Contract source code

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// helper methods for interacting with ERC223 tokens and sending CLO that do not consistently return true/false
library TransferHelper {
    function safeApprove(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
    }

    function safeTransfer(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
    }

    function safeTransferFrom(address token, address from, address to, uint value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
    }

    function safeTransferCLO(address to, uint value) internal {
        (bool success,) = to.call{value:value}(new bytes(0));
        require(success, 'TransferHelper: CLO_TRANSFER_FAILED');
    }
}

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _owner = msg.sender;
        emit OwnershipTransferred(address(0), msg.sender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == msg.sender, "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }
}

interface ISoyLottery {
    /**
     * @notice Buy tickets for the current lottery
     * @param _lotteryId: lotteryId
     * @param _ticketNumbers: array of ticket numbers between 1,000,000 and 1,999,999
     * @dev Callable by users
     */
    function buyTickets(uint256 _lotteryId, uint32[] calldata _ticketNumbers) external;

    /**
     * @notice Claim a set of winning tickets for a lottery
     * @param _lotteryId: lottery id
     * @param _ticketIds: array of ticket ids
     * @param _brackets: array of brackets for the ticket ids
     * @dev Callable by users only, not contract!
     */
    function claimTickets(
        uint256 _lotteryId,
        uint256[] calldata _ticketIds,
        uint32[] calldata _brackets
    ) external;

    /**
     * @notice Close lottery
     * @param _lotteryId: lottery id
     * @dev Callable by operator
     */
    function closeLottery(uint256 _lotteryId) external;

    /**
     * @notice Draw the final number, calculate reward in Soy per group, and make lottery claimable
     * @param _lotteryId: lottery id
     * @param _autoInjection: reinjects funds into next lottery (vs. withdrawing all)
     * @dev Callable by operator
     */
    function drawFinalNumberAndMakeLotteryClaimable(uint256 _lotteryId, bool _autoInjection) external;

    /**
     * @notice Inject funds
     * @param _lotteryId: lottery id
     * @param _amount: amount to inject in Soy token
     * @dev Callable by operator
     */
    function injectFunds(uint256 _lotteryId, uint256 _amount) external;

    /**
     * @notice Start the lottery
     * @dev Callable by operator
     * @param _endTime: endTime of the lottery
     * @param _priceTicketInSoy: price of a ticket in Soy
     * @param _discountDivisor: the divisor to calculate the discount magnitude for bulks
     * @param _rewardsBreakdown: breakdown of rewards per bracket (must sum to 10,000)
     * @param _treasuryFee: treasury fee (10,000 = 100%, 100 = 1%)
     */
    function startLottery(
        uint256 _endTime,
        uint256 _priceTicketInSoy,
        uint256 _discountDivisor,
        uint256[6] calldata _rewardsBreakdown,
        uint256 _treasuryFee
    ) external;

    /**
     * @notice View current lottery id
     */
    function viewCurrentLotteryId() external returns (uint256);
}

interface IRandomNumberGenerator {
    /**
     * Requests randomness from a user-provided seed
     */
    function getRandomNumber(uint256 _seed) external;

    /**
     * View latest lotteryId numbers
     */
    function viewLatestLotteryId() external view returns (uint256);

    /**
     * Views random result
     */
    function viewRandomResult() external view returns (uint32);
}


contract RandomNumberGenerator is IRandomNumberGenerator, Ownable {
    using TransferHelper for address;
    address public SoyLottery;
    address public operator;
    uint32 public randomResult;
    uint256 public latestLotteryId;

    struct Entropy {
        uint256 requestId;  // equal to lottery ID that made request
        uint256 seed;   // seed from request
        bytes32 blockHash1; // the prior request block hash 
        uint256 commitBlock;    // block number of commit
        bytes32 secretHash; // hash of secret random number
    }

    Entropy public entropy;

    modifier onlyOperator() {
        require(operator == msg.sender, "Only operator");
        _;
    }

    event GetRandomNumber(uint256 requestId, address requestor);
    event RandomNumber(uint256 rnd);

    

    /**
     * @notice Request randomness from a user-provided seed
     * @param _seed: seed provided by the Soy lottery
     */
    function getRandomNumber(uint256 _seed) external override {
        require(msg.sender == SoyLottery, "Only SoyLottery");
        uint256 requestId = ISoyLottery(SoyLottery).viewCurrentLotteryId();
        entropy.requestId = requestId;
        entropy.seed = _seed;
        entropy.blockHash1 = blockhash(block.number-1);
        entropy.commitBlock = 0;    // clear last record of block number
        emit GetRandomNumber(requestId, msg.sender);
    }

    // Step 1: commit hash (keccak256) of big random number
    function commitSecret(bytes32 secretHash) external onlyOperator {
        require(entropy.commitBlock == 0, "Already committed");
        entropy.commitBlock = block.number;
        entropy.secretHash = secretHash;
    }

    // Step 2: reveal secret at least in 2 block after commitment and not longer than 255 blocks after.
    // generate random number
    function revealSecret(uint256 requestId, uint256 secret) external onlyOperator {
        require(entropy.requestId == requestId, "Wrong requestId");
        require(keccak256(abi.encodePacked(secret)) == entropy.secretHash, "Wrong secret");
        uint256 commitBlock = entropy.commitBlock;
        require(commitBlock != 0 && commitBlock + 1 < block.number, "Reveal not allowed");  // allow reveal at least in 2 blocks after commitment
        if (block.number - commitBlock > 256) {
            entropy.commitBlock = 0;    // allow to repeat commitment
            emit RandomNumber(0);   // random number generating is failed
            return;
        }
        bytes32 blockHash2 = blockhash(commitBlock + 1); // hash of next block after commitment
        uint256 randomness = uint256(keccak256(abi.encodePacked(entropy.seed, entropy.blockHash1, blockHash2, secret)));
        //randomResult = uint32(1000000 + (randomness % 1000000));
        randomResult = uint32(1000 + (randomness % 1000));
        latestLotteryId = ISoyLottery(SoyLottery).viewCurrentLotteryId();
        emit RandomNumber(randomResult);
    }

    /**
     * @notice Set the address for the SoyLottery
     * @param _SoyLottery: address of the Soy lottery
     */
    function setLotteryAddress(address _SoyLottery) external onlyOwner {
        SoyLottery = _SoyLottery;
    }

    /**
     * @notice Set the address of operator
     * @param _operator: address of operator
     */
    function setOperatorAddress(address _operator) external onlyOwner {
        operator = _operator;
    }

    /**
     * @notice It allows the admin to withdraw tokens sent to the contract
     * @param _tokenAddress: the address of the token to withdraw
     * @param _tokenAmount: the number of token amount to withdraw
     * @dev Only callable by owner.
     */
    function withdrawTokens(address _tokenAddress, uint256 _tokenAmount) external onlyOwner {
        _tokenAddress.safeTransfer(address(msg.sender), _tokenAmount);
    }

    /**
     * @notice View latestLotteryId
     */
    function viewLatestLotteryId() external view override returns (uint256) {
        return latestLotteryId;
    }

    /**
     * @notice View random result
     */
    function viewRandomResult() external view override returns (uint32) {
        return randomResult;
    }

}
        

Contract ABI

[{"type":"event","name":"GetRandomNumber","inputs":[{"type":"uint256","name":"requestId","internalType":"uint256","indexed":false},{"type":"address","name":"requestor","internalType":"address","indexed":false}],"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":"RandomNumber","inputs":[{"type":"uint256","name":"rnd","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"SoyLottery","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"commitSecret","inputs":[{"type":"bytes32","name":"secretHash","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"requestId","internalType":"uint256"},{"type":"uint256","name":"seed","internalType":"uint256"},{"type":"bytes32","name":"blockHash1","internalType":"bytes32"},{"type":"uint256","name":"commitBlock","internalType":"uint256"},{"type":"bytes32","name":"secretHash","internalType":"bytes32"}],"name":"entropy","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"getRandomNumber","inputs":[{"type":"uint256","name":"_seed","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"latestLotteryId","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"operator","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"randomResult","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revealSecret","inputs":[{"type":"uint256","name":"requestId","internalType":"uint256"},{"type":"uint256","name":"secret","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setLotteryAddress","inputs":[{"type":"address","name":"_SoyLottery","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOperatorAddress","inputs":[{"type":"address","name":"_operator","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"viewLatestLotteryId","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"viewRandomResult","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawTokens","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_tokenAmount","internalType":"uint256"}]}]
              

Contract Creation Code

Verify & Publish
0x608060405234801561001057600080fd5b50600080546001600160a01b0319163390811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3610b928061005f6000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c8063715018a611610097578063b37217a411610066578063b37217a414610227578063eed8e1ee1461023a578063fa75251614610251578063fbe5d9171461026457600080fd5b8063715018a6146101e6578063883b0bce146101ee5780638da5cb5b14610201578063a1c4f55a1461021257600080fd5b80632f1d5a60116100d35780632f1d5a601461015257806342619f661461016557806347ce07cc14610191578063570ca735146101d357600080fd5b806306b091f9146100fa5780632a332b2a1461010f5780632a57c92e14610122575b600080fd5b61010d6101083660046109d2565b61026c565b005b61010d61011d3660046109fc565b6102c6565b600154610135906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61010d6101603660046109fc565b610321565b60025461017c90600160a01b900463ffffffff1681565b60405163ffffffff9091168152602001610149565b6004546005546006546007546008546101ab949392919085565b604080519586526020860194909452928401919091526060830152608082015260a001610149565b600254610135906001600160a01b031681565b61010d61037c565b61010d6101fc366004610a1e565b6103ff565b6000546001600160a01b0316610135565b600254600160a01b900463ffffffff1661017c565b61010d610235366004610a40565b6106ed565b61024360035481565b604051908152602001610149565b61010d61025f366004610a40565b610804565b600354610243565b3361027f6000546001600160a01b031690565b6001600160a01b0316146102ae5760405162461bcd60e51b81526004016102a590610a59565b60405180910390fd5b6102c26001600160a01b038316338361089b565b5050565b336102d96000546001600160a01b031690565b6001600160a01b0316146102ff5760405162461bcd60e51b81526004016102a590610a59565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b336103346000546001600160a01b031690565b6001600160a01b03161461035a5760405162461bcd60e51b81526004016102a590610a59565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b3361038f6000546001600160a01b031690565b6001600160a01b0316146103b55760405162461bcd60e51b81526004016102a590610a59565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6002546001600160a01b031633146104495760405162461bcd60e51b815260206004820152600d60248201526c27b7363c9037b832b930ba37b960991b60448201526064016102a5565b600454821461048c5760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81c995c5d595cdd1259608a1b60448201526064016102a5565b60085460408051602081018490520160405160208183030381529060405280519060200120146104ed5760405162461bcd60e51b815260206004820152600c60248201526b15dc9bdb99c81cd958dc995d60a21b60448201526064016102a5565b6007548015801590610508575043610506826001610aa4565b105b6105495760405162461bcd60e51b815260206004820152601260248201527114995d99585b081b9bdd08185b1b1bddd95960721b60448201526064016102a5565b6101006105568243610abd565b111561059b57600060078190556040519081527fec6cdc8e735e4069f6e89062582f3e5532a8e71373e7ef2962fa916cf2af21f29060200160405180910390a1505050565b60006105a8826001610aa4565b60055460065460408051602081019390935282015290406060820181905260808201859052915060009060a00160408051601f19818403018152919052805160209091012090506105fb6103e882610ad0565b610607906103e8610aa4565b600260146101000a81548163ffffffff021916908363ffffffff160217905550600160009054906101000a90046001600160a01b03166001600160a01b03166380a061606040518163ffffffff1660e01b81526004016020604051808303816000875af115801561067c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a09190610af2565b600355600254604051600160a01b90910463ffffffff1681527fec6cdc8e735e4069f6e89062582f3e5532a8e71373e7ef2962fa916cf2af21f29060200160405180910390a15050505050565b6001546001600160a01b031633146107395760405162461bcd60e51b815260206004820152600f60248201526e4f6e6c7920536f794c6f747465727960881b60448201526064016102a5565b60015460408051630405030b60e51b815290516000926001600160a01b0316916380a06160916004808301926020929190829003018187875af1158015610784573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a89190610af2565b6004819055600583905590506107bf600143610abd565b406006556000600755604080518281523360208201527ff46c6105c0f3cb1a924510084fd3100a12d09ad7f4c945729975018dd5e838ad910160405180910390a15050565b6002546001600160a01b0316331461084e5760405162461bcd60e51b815260206004820152600d60248201526c27b7363c9037b832b930ba37b960991b60448201526064016102a5565b600754156108925760405162461bcd60e51b8152602060048201526011602482015270105b1c9958591e4818dbdb5b5a5d1d1959607a1b60448201526064016102a5565b43600755600855565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916108f79190610b0b565b6000604051808303816000865af19150503d8060008114610934576040519150601f19603f3d011682016040523d82523d6000602084013e610939565b606091505b50915091508180156109635750805115806109635750808060200190518101906109639190610b3a565b6109af5760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c45440060448201526064016102a5565b5050505050565b80356001600160a01b03811681146109cd57600080fd5b919050565b600080604083850312156109e557600080fd5b6109ee836109b6565b946020939093013593505050565b600060208284031215610a0e57600080fd5b610a17826109b6565b9392505050565b60008060408385031215610a3157600080fd5b50508035926020909101359150565b600060208284031215610a5257600080fd5b5035919050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610ab757610ab7610a8e565b92915050565b81810381811115610ab757610ab7610a8e565b600082610aed57634e487b7160e01b600052601260045260246000fd5b500690565b600060208284031215610b0457600080fd5b5051919050565b6000825160005b81811015610b2c5760208186018101518583015201610b12565b506000920191825250919050565b600060208284031215610b4c57600080fd5b81518015158114610a1757600080fdfea2646970667358221220e8f3e7b478f0fe6182f4ef77be37c8739a87fe3cf5d34408745af0f7528d72f964736f6c63430008110033

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106100f55760003560e01c8063715018a611610097578063b37217a411610066578063b37217a414610227578063eed8e1ee1461023a578063fa75251614610251578063fbe5d9171461026457600080fd5b8063715018a6146101e6578063883b0bce146101ee5780638da5cb5b14610201578063a1c4f55a1461021257600080fd5b80632f1d5a60116100d35780632f1d5a601461015257806342619f661461016557806347ce07cc14610191578063570ca735146101d357600080fd5b806306b091f9146100fa5780632a332b2a1461010f5780632a57c92e14610122575b600080fd5b61010d6101083660046109d2565b61026c565b005b61010d61011d3660046109fc565b6102c6565b600154610135906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61010d6101603660046109fc565b610321565b60025461017c90600160a01b900463ffffffff1681565b60405163ffffffff9091168152602001610149565b6004546005546006546007546008546101ab949392919085565b604080519586526020860194909452928401919091526060830152608082015260a001610149565b600254610135906001600160a01b031681565b61010d61037c565b61010d6101fc366004610a1e565b6103ff565b6000546001600160a01b0316610135565b600254600160a01b900463ffffffff1661017c565b61010d610235366004610a40565b6106ed565b61024360035481565b604051908152602001610149565b61010d61025f366004610a40565b610804565b600354610243565b3361027f6000546001600160a01b031690565b6001600160a01b0316146102ae5760405162461bcd60e51b81526004016102a590610a59565b60405180910390fd5b6102c26001600160a01b038316338361089b565b5050565b336102d96000546001600160a01b031690565b6001600160a01b0316146102ff5760405162461bcd60e51b81526004016102a590610a59565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b336103346000546001600160a01b031690565b6001600160a01b03161461035a5760405162461bcd60e51b81526004016102a590610a59565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b3361038f6000546001600160a01b031690565b6001600160a01b0316146103b55760405162461bcd60e51b81526004016102a590610a59565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6002546001600160a01b031633146104495760405162461bcd60e51b815260206004820152600d60248201526c27b7363c9037b832b930ba37b960991b60448201526064016102a5565b600454821461048c5760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81c995c5d595cdd1259608a1b60448201526064016102a5565b60085460408051602081018490520160405160208183030381529060405280519060200120146104ed5760405162461bcd60e51b815260206004820152600c60248201526b15dc9bdb99c81cd958dc995d60a21b60448201526064016102a5565b6007548015801590610508575043610506826001610aa4565b105b6105495760405162461bcd60e51b815260206004820152601260248201527114995d99585b081b9bdd08185b1b1bddd95960721b60448201526064016102a5565b6101006105568243610abd565b111561059b57600060078190556040519081527fec6cdc8e735e4069f6e89062582f3e5532a8e71373e7ef2962fa916cf2af21f29060200160405180910390a1505050565b60006105a8826001610aa4565b60055460065460408051602081019390935282015290406060820181905260808201859052915060009060a00160408051601f19818403018152919052805160209091012090506105fb6103e882610ad0565b610607906103e8610aa4565b600260146101000a81548163ffffffff021916908363ffffffff160217905550600160009054906101000a90046001600160a01b03166001600160a01b03166380a061606040518163ffffffff1660e01b81526004016020604051808303816000875af115801561067c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a09190610af2565b600355600254604051600160a01b90910463ffffffff1681527fec6cdc8e735e4069f6e89062582f3e5532a8e71373e7ef2962fa916cf2af21f29060200160405180910390a15050505050565b6001546001600160a01b031633146107395760405162461bcd60e51b815260206004820152600f60248201526e4f6e6c7920536f794c6f747465727960881b60448201526064016102a5565b60015460408051630405030b60e51b815290516000926001600160a01b0316916380a06160916004808301926020929190829003018187875af1158015610784573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a89190610af2565b6004819055600583905590506107bf600143610abd565b406006556000600755604080518281523360208201527ff46c6105c0f3cb1a924510084fd3100a12d09ad7f4c945729975018dd5e838ad910160405180910390a15050565b6002546001600160a01b0316331461084e5760405162461bcd60e51b815260206004820152600d60248201526c27b7363c9037b832b930ba37b960991b60448201526064016102a5565b600754156108925760405162461bcd60e51b8152602060048201526011602482015270105b1c9958591e4818dbdb5b5a5d1d1959607a1b60448201526064016102a5565b43600755600855565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916108f79190610b0b565b6000604051808303816000865af19150503d8060008114610934576040519150601f19603f3d011682016040523d82523d6000602084013e610939565b606091505b50915091508180156109635750805115806109635750808060200190518101906109639190610b3a565b6109af5760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c45440060448201526064016102a5565b5050505050565b80356001600160a01b03811681146109cd57600080fd5b919050565b600080604083850312156109e557600080fd5b6109ee836109b6565b946020939093013593505050565b600060208284031215610a0e57600080fd5b610a17826109b6565b9392505050565b60008060408385031215610a3157600080fd5b50508035926020909101359150565b600060208284031215610a5257600080fd5b5035919050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610ab757610ab7610a8e565b92915050565b81810381811115610ab757610ab7610a8e565b600082610aed57634e487b7160e01b600052601260045260246000fd5b500690565b600060208284031215610b0457600080fd5b5051919050565b6000825160005b81811015610b2c5760208186018101518583015201610b12565b506000920191825250919050565b600060208284031215610b4c57600080fd5b81518015158114610a1757600080fdfea2646970667358221220e8f3e7b478f0fe6182f4ef77be37c8739a87fe3cf5d34408745af0f7528d72f964736f6c63430008110033