ETH Price: $3,432.93 (-0.16%)

Contract

0x3C24e076Ea0d370c004e2771aD545e211860f5CE
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Refund Remaining...73589462019-03-13 5:54:422436 days ago1552456482IN
0x3C24e076...11860f5CE
0 ETH0.000151045
Approve Remainin...73589412019-03-13 5:53:092436 days ago1552456389IN
0x3C24e076...11860f5CE
0 ETH0.000151545
Bulk Approve KYC...72626662019-02-24 18:09:412453 days ago1551031781IN
0x3C24e076...11860f5CE
0 ETH0.000240545
Bulk Approve KYC...71825992019-02-06 9:43:572471 days ago1549446237IN
0x3C24e076...11860f5CE
0 ETH0.000144323
Bulk Approve KYC...71645672019-02-02 17:38:222475 days ago1549129102IN
0x3C24e076...11860f5CE
0 ETH0.000144323
Claim Tokens71337812019-01-27 11:06:492481 days ago1548587209IN
0x3C24e076...11860f5CE
0 ETH0.000046452
Claim Tokens71337732019-01-27 11:06:172481 days ago1548587177IN
0x3C24e076...11860f5CE
0 ETH0.000046452
Claim Tokens71337632019-01-27 11:03:482481 days ago1548587028IN
0x3C24e076...11860f5CE
0 ETH0.000046452
Claim Tokens71337632019-01-27 11:03:482481 days ago1548587028IN
0x3C24e076...11860f5CE
0 ETH0.000046452
Claim Tokens71337612019-01-27 11:02:572481 days ago1548586977IN
0x3C24e076...11860f5CE
0 ETH0.000046452
Claim Tokens71337592019-01-27 11:02:342481 days ago1548586954IN
0x3C24e076...11860f5CE
0 ETH0.000061732
Transfer71337262019-01-27 10:53:302481 days ago1548586410IN
0x3C24e076...11860f5CE
1.32 ETH0.0020562225
Transfer71337202019-01-27 10:51:152481 days ago1548586275IN
0x3C24e076...11860f5CE
1.32 ETH0.0007510
Transfer71337072019-01-27 10:48:212481 days ago1548586101IN
0x3C24e076...11860f5CE
1.32 ETH0.0002510
Claim Tokens71281062019-01-26 7:58:472482 days ago1548489527IN
0x3C24e076...11860f5CE
0 ETH0.000160286.90000025
Claim Tokens71281042019-01-26 7:57:192482 days ago1548489439IN
0x3C24e076...11860f5CE
0 ETH0.000212976.90000025
Transfer71280412019-01-26 7:37:452482 days ago1548488265IN
0x3C24e076...11860f5CE
1 ETH0.000747239.0850007
Claim Tokens71250952019-01-25 17:49:512483 days ago1548438591IN
0x3C24e076...11860f5CE
0 ETH0.000186998.04999987
Claim Tokens71250802019-01-25 17:46:172483 days ago1548438377IN
0x3C24e076...11860f5CE
0 ETH0.000248478.04999987
Transfer71250742019-01-25 17:43:392483 days ago1548438219IN
0x3C24e076...11860f5CE
2 ETH0.00066218.04999987
Claim Tokens71110702019-01-22 23:09:542486 days ago1548198594IN
0x3C24e076...11860f5CE
0 ETH0.000266218.62500044
Transfer71110512019-01-22 23:05:142486 days ago1548198314IN
0x3C24e076...11860f5CE
1 ETH0.000691998.4133975
Claim Tokens71103392019-01-22 19:42:382486 days ago1548186158IN
0x3C24e076...11860f5CE
0 ETH0.000046452
Claim Tokens71103372019-01-22 19:42:072486 days ago1548186127IN
0x3C24e076...11860f5CE
0 ETH0.000046452
Claim Tokens71103312019-01-22 19:41:132486 days ago1548186073IN
0x3C24e076...11860f5CE
0 ETH0.000091732
View all transactions

Latest 9 internal transactions

Advanced mode:
Parent Transaction Hash Method Block
From
To
-71337262019-01-27 10:53:302481 days ago1548586410
0x3C24e076...11860f5CE
1.32 ETH
-71280412019-01-26 7:37:452482 days ago1548488265
0x3C24e076...11860f5CE
1 ETH
-71250742019-01-25 17:43:392483 days ago1548438219
0x3C24e076...11860f5CE
2 ETH
-71110512019-01-22 23:05:142486 days ago1548198314
0x3C24e076...11860f5CE
1 ETH
-71097102019-01-22 16:44:362486 days ago1548175476
0x3C24e076...11860f5CE
1 ETH
-71039532019-01-21 13:34:572487 days ago1548077697
0x3C24e076...11860f5CE
2 ETH
-71039212019-01-21 13:28:202487 days ago1548077300
0x3C24e076...11860f5CE
2 ETH
-70987182019-01-20 13:56:322488 days ago1547992592
0x3C24e076...11860f5CE
1.02 ETH
-70750932019-01-16 8:47:072492 days ago1547628427
0x3C24e076...11860f5CE
1.005 ETH
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SparkleCrowdsale

Compiler Version
v0.4.25+commit.59dbf8f1

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
/**
 *Submitted for verification at Etherscan.io on 2018-12-10
*/

pragma solidity 0.4.25;

// File: openzeppelin-solidity/contracts/ownership/Ownable.sol

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
  address private _owner;

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

  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  constructor() internal {
    _owner = msg.sender;
    emit OwnershipTransferred(address(0), _owner);
  }

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

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(isOwner());
    _;
  }

  /**
   * @return true if `msg.sender` is the owner of the contract.
   */
  function isOwner() public view returns(bool) {
    return msg.sender == _owner;
  }

  /**
   * @dev Allows the current owner to relinquish control of the contract.
   * @notice Renouncing to ownership will leave the contract without an owner.
   * It will not be possible to call the functions with the `onlyOwner`
   * modifier anymore.
   */
  function renounceOwnership() public onlyOwner {
    emit OwnershipTransferred(_owner, address(0));
    _owner = address(0);
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    _transferOwnership(newOwner);
  }

  /**
   * @dev Transfers control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function _transferOwnership(address newOwner) internal {
    require(newOwner != address(0));
    emit OwnershipTransferred(_owner, newOwner);
    _owner = newOwner;
  }
}

// File: contracts/MultiOwnable.sol

/**
 * @title MultiOwnable.sol
 * @dev Provide multi-ownable functionality to a smart contract.
 * @dev Note this contract preserves the idea of a master owner where this owner
 * cannot be removed or deleted. Master owner's are the only owner's who can add
 * and remove other owner's. Transfer of master ownership is supported and can 
 * also only be transferred by the current master owner
 * @dev When master ownership is transferred the original master owner is not
 * removed from the additional owners list
 */
pragma solidity 0.4.25;

/**
 * @dev OpenZeppelin Solidity v2.0.0 imports (Using: npm [email protected])
 */


contract MultiOwnable is Ownable {
	/**
	 * @dev Mapping of additional addresses that are considered owners
	 */
	mapping (address => bool) additionalOwners;

	/**
	 * @dev Modifier that overrides 'Ownable' to support multiple owners
	 */
	modifier onlyOwner() {
		// Ensure that msg.sender is an owner or revert
		require(isOwner(msg.sender), "Permission denied [owner].");
		_;
	}

	/**
	 * @dev Modifier that provides additional testing to ensure msg.sender
	 * is master owner, or first address to deploy contract
	 */
	modifier onlyMaster() {
		// Ensure that msg.sender is the master user
		require(super.isOwner(), "Permission denied [master].");
		_;
	}

	/**
	 * @dev Ownership added event for Dapps interested in this event
	 */
	event OwnershipAdded (
		address indexed addedOwner
	);
	
	/**
	 * @dev Ownership removed event for Dapps interested in this event
	 */
	event OwnershipRemoved (
		address indexed removedOwner
	);

  	/**
	 * @dev MultiOwnable .cTor responsible for initialising the masterOwner
	 * or contract super-user
	 * @dev The super user cannot be deleted from the ownership mapping and
	 * can only be transferred
	 */
	constructor() 
	Ownable()
	public
	{
		// Obtain owner of the contract (msg.sender)
		address masterOwner = owner();
		// Add the master owner to the additional owners list
		additionalOwners[masterOwner] = true;
	}

	/**
	 * @dev Returns the owner status of the specified address
	 */
	function isOwner(address _ownerAddressToLookup)
	public
	view
	returns (bool)
	{
		// Return the ownership state of the specified owner address
		return additionalOwners[_ownerAddressToLookup];
	}

	/**
	 * @dev Returns the master status of the specfied address
	 */
	function isMaster(address _masterAddressToLookup)
	public
	view
	returns (bool)
	{
		return (super.owner() == _masterAddressToLookup);
	}

	/**
	 * @dev Add a new owner address to additional owners mapping
	 * @dev Only the master owner can add additional owner addresses
	 */
	function addOwner(address _ownerToAdd)
	onlyMaster
	public
	returns (bool)
	{
		// Ensure the new owner address is not address(0)
		require(_ownerToAdd != address(0), "Invalid address specified (0x0)");
		// Ensure that new owner address is not already in the owners list
		require(!isOwner(_ownerToAdd), "Address specified already in owners list.");
		// Add new owner to additional owners mapping
		additionalOwners[_ownerToAdd] = true;
		emit OwnershipAdded(_ownerToAdd);
		return true;
	}

	/**
	 * @dev Add a new owner address to additional owners mapping
	 * @dev Only the master owner can add additional owner addresses
	 */
	function removeOwner(address _ownerToRemove)
	onlyMaster
	public
	returns (bool)
	{
		// Ensure that the address to remove is not the master owner
		require(_ownerToRemove != super.owner(), "Permission denied [master].");
		// Ensure that owner address to remove is actually an owner
		require(isOwner(_ownerToRemove), "Address specified not found in owners list.");
		// Add remove ownership from address in the additional owners mapping
		additionalOwners[_ownerToRemove] = false;
		emit OwnershipRemoved(_ownerToRemove);
		return true;
	}

	/**
	 * @dev Transfer ownership of this contract to another address
	 * @dev Only the master owner can transfer ownership to another address
	 * @dev Only existing owners can have ownership transferred to them
	 */
	function transferOwnership(address _newOwnership) 
	onlyMaster 
	public 
	{
		// Ensure the new ownership is not address(0)
		require(_newOwnership != address(0), "Invalid address specified (0x0)");
		// Ensure the new ownership address is not the current ownership addressess
		require(_newOwnership != owner(), "Address specified must not match current owner address.");		
		// Ensure that the new ownership is promoted from existing owners
		require(isOwner(_newOwnership), "Master ownership can only be transferred to an existing owner address.");
		// Call into the parent class and transfer ownership
		super.transferOwnership(_newOwnership);
		// If we get here, then add the new ownership address to the additional owners mapping
		// Note that the original master owner address was not removed and is still an owner until removed
		additionalOwners[_newOwnership] = true;
	}

}

// File: openzeppelin-solidity/contracts/access/Roles.sol

/**
 * @title Roles
 * @dev Library for managing addresses assigned to a Role.
 */
library Roles {
  struct Role {
    mapping (address => bool) bearer;
  }

  /**
   * @dev give an account access to this role
   */
  function add(Role storage role, address account) internal {
    require(account != address(0));
    require(!has(role, account));

    role.bearer[account] = true;
  }

  /**
   * @dev remove an account's access to this role
   */
  function remove(Role storage role, address account) internal {
    require(account != address(0));
    require(has(role, account));

    role.bearer[account] = false;
  }

  /**
   * @dev check if an account has this role
   * @return bool
   */
  function has(Role storage role, address account)
    internal
    view
    returns (bool)
  {
    require(account != address(0));
    return role.bearer[account];
  }
}

// File: openzeppelin-solidity/contracts/access/roles/PauserRole.sol

contract PauserRole {
  using Roles for Roles.Role;

  event PauserAdded(address indexed account);
  event PauserRemoved(address indexed account);

  Roles.Role private pausers;

  constructor() internal {
    _addPauser(msg.sender);
  }

  modifier onlyPauser() {
    require(isPauser(msg.sender));
    _;
  }

  function isPauser(address account) public view returns (bool) {
    return pausers.has(account);
  }

  function addPauser(address account) public onlyPauser {
    _addPauser(account);
  }

  function renouncePauser() public {
    _removePauser(msg.sender);
  }

  function _addPauser(address account) internal {
    pausers.add(account);
    emit PauserAdded(account);
  }

  function _removePauser(address account) internal {
    pausers.remove(account);
    emit PauserRemoved(account);
  }
}

// File: openzeppelin-solidity/contracts/lifecycle/Pausable.sol

/**
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism.
 */
contract Pausable is PauserRole {
  event Paused(address account);
  event Unpaused(address account);

  bool private _paused;

  constructor() internal {
    _paused = false;
  }

  /**
   * @return true if the contract is paused, false otherwise.
   */
  function paused() public view returns(bool) {
    return _paused;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is not paused.
   */
  modifier whenNotPaused() {
    require(!_paused);
    _;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is paused.
   */
  modifier whenPaused() {
    require(_paused);
    _;
  }

  /**
   * @dev called by the owner to pause, triggers stopped state
   */
  function pause() public onlyPauser whenNotPaused {
    _paused = true;
    emit Paused(msg.sender);
  }

  /**
   * @dev called by the owner to unpause, returns to normal state
   */
  function unpause() public onlyPauser whenPaused {
    _paused = false;
    emit Unpaused(msg.sender);
  }
}

// File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol

/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
interface IERC20 {
  function totalSupply() external view returns (uint256);

  function balanceOf(address who) external view returns (uint256);

  function allowance(address owner, address spender)
    external view returns (uint256);

  function transfer(address to, uint256 value) external returns (bool);

  function approve(address spender, uint256 value)
    external returns (bool);

  function transferFrom(address from, address to, uint256 value)
    external returns (bool);

  event Transfer(
    address indexed from,
    address indexed to,
    uint256 value
  );

  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 value
  );
}

// File: openzeppelin-solidity/contracts/math/SafeMath.sol

/**
 * @title SafeMath
 * @dev Math operations with safety checks that revert on error
 */
library SafeMath {

  /**
  * @dev Multiplies two numbers, reverts on overflow.
  */
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
    // benefit is lost if 'b' is also tested.
    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
    if (a == 0) {
      return 0;
    }

    uint256 c = a * b;
    require(c / a == b);

    return c;
  }

  /**
  * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
  */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b > 0); // Solidity only automatically asserts when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold

    return c;
  }

  /**
  * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b <= a);
    uint256 c = a - b;

    return c;
  }

  /**
  * @dev Adds two numbers, reverts on overflow.
  */
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    require(c >= a);

    return c;
  }

  /**
  * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
  * reverts when dividing by zero.
  */
  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b != 0);
    return a % b;
  }
}

// File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol

/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
 * Originally based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
 */
contract ERC20 is IERC20 {
  using SafeMath for uint256;

  mapping (address => uint256) private _balances;

  mapping (address => mapping (address => uint256)) private _allowed;

  uint256 private _totalSupply;

  /**
  * @dev Total number of tokens in existence
  */
  function totalSupply() public view returns (uint256) {
    return _totalSupply;
  }

  /**
  * @dev Gets the balance of the specified address.
  * @param owner The address to query the balance of.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address owner) public view returns (uint256) {
    return _balances[owner];
  }

  /**
   * @dev Function to check the amount of tokens that an owner allowed to a spender.
   * @param owner address The address which owns the funds.
   * @param spender address The address which will spend the funds.
   * @return A uint256 specifying the amount of tokens still available for the spender.
   */
  function allowance(
    address owner,
    address spender
   )
    public
    view
    returns (uint256)
  {
    return _allowed[owner][spender];
  }

  /**
  * @dev Transfer token for a specified address
  * @param to The address to transfer to.
  * @param value The amount to be transferred.
  */
  function transfer(address to, uint256 value) public returns (bool) {
    _transfer(msg.sender, to, value);
    return true;
  }

  /**
   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
   * 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
   * @param spender The address which will spend the funds.
   * @param value The amount of tokens to be spent.
   */
  function approve(address spender, uint256 value) public returns (bool) {
    require(spender != address(0));

    _allowed[msg.sender][spender] = value;
    emit Approval(msg.sender, spender, value);
    return true;
  }

  /**
   * @dev Transfer tokens from one address to another
   * @param from address The address which you want to send tokens from
   * @param to address The address which you want to transfer to
   * @param value uint256 the amount of tokens to be transferred
   */
  function transferFrom(
    address from,
    address to,
    uint256 value
  )
    public
    returns (bool)
  {
    require(value <= _allowed[from][msg.sender]);

    _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
    _transfer(from, to, value);
    return true;
  }

  /**
   * @dev Increase the amount of tokens that an owner allowed to a spender.
   * approve should be called when allowed_[_spender] == 0. To increment
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param spender The address which will spend the funds.
   * @param addedValue The amount of tokens to increase the allowance by.
   */
  function increaseAllowance(
    address spender,
    uint256 addedValue
  )
    public
    returns (bool)
  {
    require(spender != address(0));

    _allowed[msg.sender][spender] = (
      _allowed[msg.sender][spender].add(addedValue));
    emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
    return true;
  }

  /**
   * @dev Decrease the amount of tokens that an owner allowed to a spender.
   * approve should be called when allowed_[_spender] == 0. To decrement
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param spender The address which will spend the funds.
   * @param subtractedValue The amount of tokens to decrease the allowance by.
   */
  function decreaseAllowance(
    address spender,
    uint256 subtractedValue
  )
    public
    returns (bool)
  {
    require(spender != address(0));

    _allowed[msg.sender][spender] = (
      _allowed[msg.sender][spender].sub(subtractedValue));
    emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
    return true;
  }

  /**
  * @dev Transfer token for a specified addresses
  * @param from The address to transfer from.
  * @param to The address to transfer to.
  * @param value The amount to be transferred.
  */
  function _transfer(address from, address to, uint256 value) internal {
    require(value <= _balances[from]);
    require(to != address(0));

    _balances[from] = _balances[from].sub(value);
    _balances[to] = _balances[to].add(value);
    emit Transfer(from, to, value);
  }

  /**
   * @dev Internal function that mints an amount of the token and assigns it to
   * an account. This encapsulates the modification of balances such that the
   * proper events are emitted.
   * @param account The account that will receive the created tokens.
   * @param value The amount that will be created.
   */
  function _mint(address account, uint256 value) internal {
    require(account != 0);
    _totalSupply = _totalSupply.add(value);
    _balances[account] = _balances[account].add(value);
    emit Transfer(address(0), account, value);
  }

  /**
   * @dev Internal function that burns an amount of the token of a given
   * account.
   * @param account The account whose tokens will be burnt.
   * @param value The amount that will be burnt.
   */
  function _burn(address account, uint256 value) internal {
    require(account != 0);
    require(value <= _balances[account]);

    _totalSupply = _totalSupply.sub(value);
    _balances[account] = _balances[account].sub(value);
    emit Transfer(account, address(0), value);
  }

  /**
   * @dev Internal function that burns an amount of the token of a given
   * account, deducting from the sender's allowance for said account. Uses the
   * internal burn function.
   * @param account The account whose tokens will be burnt.
   * @param value The amount that will be burnt.
   */
  function _burnFrom(address account, uint256 value) internal {
    require(value <= _allowed[account][msg.sender]);

    // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
    // this function needs to emit an event with the updated approval.
    _allowed[account][msg.sender] = _allowed[account][msg.sender].sub(
      value);
    _burn(account, value);
  }
}

// File: openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure.
 * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {

  using SafeMath for uint256;

  function safeTransfer(
    IERC20 token,
    address to,
    uint256 value
  )
    internal
  {
    require(token.transfer(to, value));
  }

  function safeTransferFrom(
    IERC20 token,
    address from,
    address to,
    uint256 value
  )
    internal
  {
    require(token.transferFrom(from, to, value));
  }

  function safeApprove(
    IERC20 token,
    address spender,
    uint256 value
  )
    internal
  {
    // safeApprove should only be called when setting an initial allowance, 
    // or when resetting it to zero. To increase and decrease it, use 
    // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
    require((value == 0) || (token.allowance(msg.sender, spender) == 0));
    require(token.approve(spender, value));
  }

  function safeIncreaseAllowance(
    IERC20 token,
    address spender,
    uint256 value
  )
    internal
  {
    uint256 newAllowance = token.allowance(address(this), spender).add(value);
    require(token.approve(spender, newAllowance));
  }

  function safeDecreaseAllowance(
    IERC20 token,
    address spender,
    uint256 value
  )
    internal
  {
    uint256 newAllowance = token.allowance(address(this), spender).sub(value);
    require(token.approve(spender, newAllowance));
  }
}

// File: openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol

/**
 * @title Helps contracts guard against reentrancy attacks.
 * @author Remco Bloemen <remco@2π.com>, Eenae <[email protected]>
 * @dev If you mark a function `nonReentrant`, you should also
 * mark it `external`.
 */
contract ReentrancyGuard {

  /// @dev counter to allow mutex lock with only one SSTORE operation
  uint256 private _guardCounter;

  constructor() internal {
    // The counter starts at one to prevent changing it from zero to a non-zero
    // value, which is a more expensive operation.
    _guardCounter = 1;
  }

  /**
   * @dev Prevents a contract from calling itself, directly or indirectly.
   * Calling a `nonReentrant` function from another `nonReentrant`
   * function is not supported. It is possible to prevent this from happening
   * by making the `nonReentrant` function external, and make it call a
   * `private` function that does the actual work.
   */
  modifier nonReentrant() {
    _guardCounter += 1;
    uint256 localCounter = _guardCounter;
    _;
    require(localCounter == _guardCounter);
  }

}

// File: openzeppelin-solidity/contracts/crowdsale/Crowdsale.sol

/**
 * @title Crowdsale
 * @dev Crowdsale is a base contract for managing a token crowdsale,
 * allowing investors to purchase tokens with ether. This contract implements
 * such functionality in its most fundamental form and can be extended to provide additional
 * functionality and/or custom behavior.
 * The external interface represents the basic interface for purchasing tokens, and conform
 * the base architecture for crowdsales. They are *not* intended to be modified / overridden.
 * The internal interface conforms the extensible and modifiable surface of crowdsales. Override
 * the methods to add functionality. Consider using 'super' where appropriate to concatenate
 * behavior.
 */
contract Crowdsale is ReentrancyGuard {
  using SafeMath for uint256;
  using SafeERC20 for IERC20;

  // The token being sold
  IERC20 private _token;

  // Address where funds are collected
  address private _wallet;

  // How many token units a buyer gets per wei.
  // The rate is the conversion between wei and the smallest and indivisible token unit.
  // So, if you are using a rate of 1 with a ERC20Detailed token with 3 decimals called TOK
  // 1 wei will give you 1 unit, or 0.001 TOK.
  uint256 private _rate;

  // Amount of wei raised
  uint256 private _weiRaised;

  /**
   * Event for token purchase logging
   * @param purchaser who paid for the tokens
   * @param beneficiary who got the tokens
   * @param value weis paid for purchase
   * @param amount amount of tokens purchased
   */
  event TokensPurchased(
    address indexed purchaser,
    address indexed beneficiary,
    uint256 value,
    uint256 amount
  );

  /**
   * @param rate Number of token units a buyer gets per wei
   * @dev The rate is the conversion between wei and the smallest and indivisible
   * token unit. So, if you are using a rate of 1 with a ERC20Detailed token
   * with 3 decimals called TOK, 1 wei will give you 1 unit, or 0.001 TOK.
   * @param wallet Address where collected funds will be forwarded to
   * @param token Address of the token being sold
   */
  constructor(uint256 rate, address wallet, IERC20 token) internal {
    require(rate > 0);
    require(wallet != address(0));
    require(token != address(0));

    _rate = rate;
    _wallet = wallet;
    _token = token;
  }

  // -----------------------------------------
  // Crowdsale external interface
  // -----------------------------------------

  /**
   * @dev fallback function ***DO NOT OVERRIDE***
   * Note that other contracts will transfer fund with a base gas stipend
   * of 2300, which is not enough to call buyTokens. Consider calling
   * buyTokens directly when purchasing tokens from a contract.
   */
  function () external payable {
    buyTokens(msg.sender);
  }

  /**
   * @return the token being sold.
   */
  function token() public view returns(IERC20) {
    return _token;
  }

  /**
   * @return the address where funds are collected.
   */
  function wallet() public view returns(address) {
    return _wallet;
  }

  /**
   * @return the number of token units a buyer gets per wei.
   */
  function rate() public view returns(uint256) {
    return _rate;
  }

  /**
   * @return the amount of wei raised.
   */
  function weiRaised() public view returns (uint256) {
    return _weiRaised;
  }

  /**
   * @dev low level token purchase ***DO NOT OVERRIDE***
   * This function has a non-reentrancy guard, so it shouldn't be called by
   * another `nonReentrant` function.
   * @param beneficiary Recipient of the token purchase
   */
  function buyTokens(address beneficiary) public nonReentrant payable {

    uint256 weiAmount = msg.value;
    _preValidatePurchase(beneficiary, weiAmount);

    // calculate token amount to be created
    uint256 tokens = _getTokenAmount(weiAmount);

    // update state
    _weiRaised = _weiRaised.add(weiAmount);

    _processPurchase(beneficiary, tokens);
    emit TokensPurchased(
      msg.sender,
      beneficiary,
      weiAmount,
      tokens
    );

    _updatePurchasingState(beneficiary, weiAmount);

    _forwardFunds();
    _postValidatePurchase(beneficiary, weiAmount);
  }

  // -----------------------------------------
  // Internal interface (extensible)
  // -----------------------------------------

  /**
   * @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. Use `super` in contracts that inherit from Crowdsale to extend their validations.
   * Example from CappedCrowdsale.sol's _preValidatePurchase method:
   *   super._preValidatePurchase(beneficiary, weiAmount);
   *   require(weiRaised().add(weiAmount) <= cap);
   * @param beneficiary Address performing the token purchase
   * @param weiAmount Value in wei involved in the purchase
   */
  function _preValidatePurchase(
    address beneficiary,
    uint256 weiAmount
  )
    internal
    view
  {
    require(beneficiary != address(0));
    require(weiAmount != 0);
  }

  /**
   * @dev Validation of an executed purchase. Observe state and use revert statements to undo rollback when valid conditions are not met.
   * @param beneficiary Address performing the token purchase
   * @param weiAmount Value in wei involved in the purchase
   */
  function _postValidatePurchase(
    address beneficiary,
    uint256 weiAmount
  )
    internal
    view
  {
    // optional override
  }

  /**
   * @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends its tokens.
   * @param beneficiary Address performing the token purchase
   * @param tokenAmount Number of tokens to be emitted
   */
  function _deliverTokens(
    address beneficiary,
    uint256 tokenAmount
  )
    internal
  {
    _token.safeTransfer(beneficiary, tokenAmount);
  }

  /**
   * @dev Executed when a purchase has been validated and is ready to be executed. Doesn't necessarily emit/send tokens.
   * @param beneficiary Address receiving the tokens
   * @param tokenAmount Number of tokens to be purchased
   */
  function _processPurchase(
    address beneficiary,
    uint256 tokenAmount
  )
    internal
  {
    _deliverTokens(beneficiary, tokenAmount);
  }

  /**
   * @dev Override for extensions that require an internal state to check for validity (current user contributions, etc.)
   * @param beneficiary Address receiving the tokens
   * @param weiAmount Value in wei involved in the purchase
   */
  function _updatePurchasingState(
    address beneficiary,
    uint256 weiAmount
  )
    internal
  {
    // optional override
  }

  /**
   * @dev Override to extend the way in which ether is converted to tokens.
   * @param weiAmount Value in wei to be converted into tokens
   * @return Number of tokens that can be purchased with the specified _weiAmount
   */
  function _getTokenAmount(uint256 weiAmount)
    internal view returns (uint256)
  {
    return weiAmount.mul(_rate);
  }

  /**
   * @dev Determines how ETH is stored/forwarded on purchases.
   */
  function _forwardFunds() internal {
    _wallet.transfer(msg.value);
  }
}

// File: openzeppelin-solidity/contracts/crowdsale/validation/TimedCrowdsale.sol

/**
 * @title TimedCrowdsale
 * @dev Crowdsale accepting contributions only within a time frame.
 */
contract TimedCrowdsale is Crowdsale {
  using SafeMath for uint256;

  uint256 private _openingTime;
  uint256 private _closingTime;

  /**
   * @dev Reverts if not in crowdsale time range.
   */
  modifier onlyWhileOpen {
    require(isOpen());
    _;
  }

  /**
   * @dev Constructor, takes crowdsale opening and closing times.
   * @param openingTime Crowdsale opening time
   * @param closingTime Crowdsale closing time
   */
  constructor(uint256 openingTime, uint256 closingTime) internal {
    // solium-disable-next-line security/no-block-members
    require(openingTime >= block.timestamp);
    require(closingTime > openingTime);

    _openingTime = openingTime;
    _closingTime = closingTime;
  }

  /**
   * @return the crowdsale opening time.
   */
  function openingTime() public view returns(uint256) {
    return _openingTime;
  }

  /**
   * @return the crowdsale closing time.
   */
  function closingTime() public view returns(uint256) {
    return _closingTime;
  }

  /**
   * @return true if the crowdsale is open, false otherwise.
   */
  function isOpen() public view returns (bool) {
    // solium-disable-next-line security/no-block-members
    return block.timestamp >= _openingTime && block.timestamp <= _closingTime;
  }

  /**
   * @dev Checks whether the period in which the crowdsale is open has already elapsed.
   * @return Whether crowdsale period has elapsed
   */
  function hasClosed() public view returns (bool) {
    // solium-disable-next-line security/no-block-members
    return block.timestamp > _closingTime;
  }

  /**
   * @dev Extend parent behavior requiring to be within contributing period
   * @param beneficiary Token purchaser
   * @param weiAmount Amount of wei contributed
   */
  function _preValidatePurchase(
    address beneficiary,
    uint256 weiAmount
  )
    internal
    onlyWhileOpen
    view
  {
    super._preValidatePurchase(beneficiary, weiAmount);
  }

}

// File: contracts/SparkleBaseCrowdsale.sol

/**
 * @dev SparkelBaseCrowdsale: Core crowdsale functionality
 */
contract SparkleBaseCrowdsale is MultiOwnable, Pausable, TimedCrowdsale {
	using SafeMath for uint256;

	/**
	 * @dev CrowdsaleStage enumeration indicating which operational stage this contract is running
	 */
	enum CrowdsaleStage { 
		preICO, 
		bonusICO, 
		mainICO
	}

 	/**
 	 * @dev Internal contract variable stored
 	 */
	ERC20   public tokenAddress;
	uint256 public tokenRate;
	uint256 public tokenCap;
	uint256 public startTime;
	uint256 public endTime;
	address public depositWallet;
	bool    public kycRequired;	
	bool	public refundRemainingOk;

	uint256 public tokensSold;

	/**
	 * @dev Contribution structure representing a token purchase 
	 */
	struct OrderBook {
		uint256 weiAmount;   // Amount of Wei that has been contributed towards tokens by this address
		uint256 pendingTokens; // Total pending tokens held by this address waiting for KYC verification, and user to claim their tokens(pending restrictions)
		bool    kycVerified;   // Has this address been kyc validated
	}

	// Contributions mapping to user addresses
	mapping(address => OrderBook) private orders;

	// Initialize the crowdsale stage to preICO (this stage will change)
	CrowdsaleStage public crowdsaleStage = CrowdsaleStage.preICO;

	/**
	 * @dev Event signaling that a number of addresses have been approved for KYC
	 */
	event ApprovedKYCAddresses (address indexed _appovedByAddress, uint256 _numberOfApprovals);

	/**
	 * @dev Event signaling that a number of addresses have been revoked from KYC
	 */
	event RevokedKYCAddresses (address indexed _revokedByAddress, uint256 _numberOfRevokals);

	/**
	 * @dev Event signalling that tokens have been claimed from the crowdsale
	 */
	event TokensClaimed (address indexed _claimingAddress, uint256 _tokensClaimed);

	/**
	 * @dev Event signaling that tokens were sold and how many were sold
	 */
	event TokensSold(address indexed _beneficiary, uint256 _tokensSold);

	/**
	 * @dev Event signaling that toke burn approval has been changed
	 */
	event TokenRefundApprovalChanged(address indexed _approvingAddress, bool tokenBurnApproved);

	/**
	 * @dev Event signaling that token burn approval has been changed
	 */
	event CrowdsaleStageChanged(address indexed _changingAddress, uint _newStageValue);

	/**
	 * @dev Event signaling that crowdsale tokens have been burned
	 */
	event CrowdsaleTokensRefunded(address indexed _refundingToAddress, uint256 _numberOfTokensBurned);

	/**
	 * @dev SparkleTokenCrowdsale Contract contructor
	 */
	constructor(ERC20 _tokenAddress, uint256 _tokenRate, uint256 _tokenCap, uint256 _startTime, uint256 _endTime, address _depositWallet, bool _kycRequired)
	public
	Crowdsale(_tokenRate, _depositWallet, _tokenAddress)
	TimedCrowdsale(_startTime, _endTime)
	MultiOwnable()
	Pausable()
	{ 
		tokenAddress      = _tokenAddress;
		tokenRate         = _tokenRate;
		tokenCap          = _tokenCap;
		startTime         = _startTime;
		endTime           = _endTime;
		depositWallet     = _depositWallet;
		kycRequired       = _kycRequired;
		refundRemainingOk = false;
	}

	/**
	 * @dev claimPendingTokens() provides users with a function to receive their purchase tokens
	 * after their KYC Verification
	 */
	function claimTokens()
	whenNotPaused
	onlyWhileOpen
	public
	{
		// Ensure calling address is not address(0)
		require(msg.sender != address(0), "Invalid address specified: address(0)");
		// Obtain a copy of the caller's order record
		OrderBook storage order = orders[msg.sender];
		// Ensure caller has been KYC Verified
		require(order.kycVerified, "Address attempting to claim tokens is not KYC Verified.");
		// Ensure caller has pending tokens to claim
		require(order.pendingTokens > 0, "Address does not have any pending tokens to claim.");
		// For security sake grab the pending token value
		uint256 localPendingTokens = order.pendingTokens;
		// zero out pendingTokens to prevent potential re-entrancy vulnverability
		order.pendingTokens = 0;
		// Deliver the callers tokens
		_deliverTokens(msg.sender, localPendingTokens);
		// Emit event
		emit TokensClaimed(msg.sender, localPendingTokens);
	}

	/**
	 * @dev getExchangeRate() provides a public facing manner in which to 
	 * determine the current rate of exchange in the crowdsale
	 * @param _weiAmount is the amount of wei to purchase tokens with
	 * @return number of tokens the specified wei amount would purchase
	 */
	function getExchangeRate(uint256 _weiAmount)
	whenNotPaused
	onlyWhileOpen
	public
	view
	returns (uint256)
	{
		if (crowdsaleStage == CrowdsaleStage.preICO) {
			// Ensure _weiAmount is > than current stage minimum
			require(_weiAmount >= 1 ether, "PreICO minimum ether required: 1 ETH.");
		}
		else if (crowdsaleStage == CrowdsaleStage.bonusICO || crowdsaleStage == CrowdsaleStage.mainICO) {
			// Ensure _weiAmount is > than current stage minimum
			require(_weiAmount >= 500 finney, "bonusICO/mainICO minimum ether required: 0.5 ETH.");
		}

		// Calculate the number of tokens this amount of wei is worth
		uint256 tokenAmount = _getTokenAmount(_weiAmount);
		// Ensure the number of tokens requests will not exceed available tokens
		require(getRemainingTokens() >= tokenAmount, "Specified wei value woudld exceed amount of tokens remaining.");
		// Calculate and return the token amount this amount of wei is worth (includes bonus factor)
		return tokenAmount;
	}

	/**
	 * @dev getRemainingTokens() provides function to return the current remaining token count
	 * @return number of tokens remaining in the crowdsale to be sold
	 */
	function getRemainingTokens()
	whenNotPaused
	public
	view
	returns (uint256)
	{
		// Return the balance of the contract (IE: tokenCap - tokensSold)
		return tokenCap.sub(tokensSold);
	}

	/**
	 * @dev refundRemainingTokens provides functionn to refund remaining tokens to the specified address
	 * @param _addressToRefund is the address in which the remaining tokens will be refunded to
	 */
	function refundRemainingTokens(address _addressToRefund)
	onlyOwner
	whenNotPaused
	public
	{
		// Ensure the specified address is not address(0)
		require(_addressToRefund != address(0), "Specified address is invalid [0x0]");
		// Ensure the crowdsale has closed before burning tokens
		require(hasClosed(), "Crowdsale must be finished to burn tokens.");
		// Ensure that step-1 of the burning process is satisfied (owner set to true)
		require(refundRemainingOk, "Crowdsale remaining token refund is disabled.");
		uint256 tempBalance = token().balanceOf(this);
		// Transfer the remaining tokens to specified address
		_deliverTokens(_addressToRefund, tempBalance);
		// Emit event
		emit CrowdsaleTokensRefunded(_addressToRefund, tempBalance);
	}

	/**
	 * @dev approveRemainingTokenRefund approves the function to withdraw any remaining tokens
	 * after the crowdsale ends
	 * @dev This was put in place as a two-step process to burn tokens so burning was secure
	 */
	function approveRemainingTokenRefund()
	onlyOwner
	whenNotPaused
	public
	{
		// Ensure calling address is not address(0)
		require(msg.sender != address(0), "Calling address invalid [0x0]");
		// Ensure the crowdsale has closed before approving token burning
		require(hasClosed(), "Token burn approval can only be set after crowdsale closes");
		refundRemainingOk = true;
		emit TokenRefundApprovalChanged(msg.sender, refundRemainingOk);
	}

	/**
	 * @dev setStage() sets the current crowdsale stage to the specified value
	 * @param _newStageValue is the new stage to be changed to
	 */
	function changeCrowdsaleStage(uint _newStageValue)
	onlyOwner
	whenNotPaused
	onlyWhileOpen
	public
	{
		// Create temporary stage variable
		CrowdsaleStage _stage;
		// Determine if caller is trying to set: preICO
		if (uint(CrowdsaleStage.preICO) == _newStageValue) {
			// Set the internal stage to the new value
			_stage = CrowdsaleStage.preICO;
		}
		// Determine if caller is trying to set: bonusICO
		else if (uint(CrowdsaleStage.bonusICO) == _newStageValue) {
			// Set the internal stage to the new value
			_stage = CrowdsaleStage.bonusICO;
		}
		// Determine if caller is trying to set: mainICO
		else if (uint(CrowdsaleStage.mainICO) == _newStageValue) {
			// Set the internal stage to the new value
			_stage = CrowdsaleStage.mainICO;
		}
		else {
			revert("Invalid stage selected");
		}

		// Update the internal crowdsale stage to the new stage
		crowdsaleStage = _stage;
		// Emit event
		emit CrowdsaleStageChanged(msg.sender, uint(_stage));
	}

	/**
	 * @dev isAddressKYCVerified() checks the KYV Verification status of the specified address
	 * @param _addressToLookuo address to check status of KYC Verification
	 * @return kyc status of the specified address 
	 */
	function isKYCVerified(address _addressToLookuo) 
	whenNotPaused
	onlyWhileOpen
	public
	view
	returns (bool)
	{
		// Ensure _addressToLookuo is not address(0)
		require(_addressToLookuo != address(0), "Invalid address specified: address(0)");
		// Obtain the addresses order record
		OrderBook storage order = orders[_addressToLookuo];
		// Return the JYC Verification status for the specified address
		return order.kycVerified;
	}

	/**
	 * @dev Approve in bulk the specified addfresses indicating they were KYC Verified
	 * @param _addressesForApproval is a list of addresses that are to be KYC Verified
	 */
	function bulkApproveKYCAddresses(address[] _addressesForApproval) 
	onlyOwner
	whenNotPaused
	onlyWhileOpen
	public
	{

		// Ensure that there are any address(es) in the provided array
		require(_addressesForApproval.length > 0, "Specified address array is empty");
		// Interate through all addresses provided
		for (uint i = 0; i <_addressesForApproval.length; i++) {
			// Approve this address using the internal function
			_approveKYCAddress(_addressesForApproval[i]);
		}

		// Emit event indicating address(es) have been approved for KYC Verification
		emit ApprovedKYCAddresses(msg.sender, _addressesForApproval.length);
	}

	/**
	 * @dev Revoke in bulk the specified addfresses indicating they were denied KYC Verified
	 * @param _addressesToRevoke is a list of addresses that are to be KYC Verified
	 */
	function bulkRevokeKYCAddresses(address[] _addressesToRevoke) 
	onlyOwner
	whenNotPaused
	onlyWhileOpen
	public
	{
		// Ensure that there are any address(es) in the provided array
		require(_addressesToRevoke.length > 0, "Specified address array is empty");
		// Interate through all addresses provided
		for (uint i = 0; i <_addressesToRevoke.length; i++) {
			// Approve this address using the internal function
			_revokeKYCAddress(_addressesToRevoke[i]);
		}

		// Emit event indicating address(es) have been revoked for KYC Verification
		emit RevokedKYCAddresses(msg.sender, _addressesToRevoke.length);
	}

	/**
	 * @dev tokensPending() provides owners the function to retrieve an addresses pending
	 * token amount
	 * @param _addressToLookup is the address to return the pending token value for
	 * @return the number of pending tokens waiting to be claimed from specified address
	 */
	function tokensPending(address _addressToLookup)
	onlyOwner
	whenNotPaused
	onlyWhileOpen
	public
	view
	returns (uint256)
	{
		// Ensure specified address is not address(0)
		require(_addressToLookup != address(0), "Specified address is invalid [0x0]");
		// Obtain the order for specified address
		OrderBook storage order = orders[_addressToLookup];
		// Return the pendingTokens amount
		return order.pendingTokens;
	}

	/**
	 * @dev contributionAmount() provides owners the function to retrieve an addresses total
	 * contribution amount in eth
	 * @param _addressToLookup is the address to return the contribution amount value for
	 * @return the number of ether contribured to the crowdsale by specified address
	 */
	function contributionAmount(address _addressToLookup)
	onlyOwner
	whenNotPaused
	onlyWhileOpen
	public
	view
	returns (uint256)
	{
		// Ensure specified address is not address(0)
		require(_addressToLookup != address(0), "Specified address is Invalid [0x0]");
		// Obtain the order for specified address
		OrderBook storage order = orders[_addressToLookup];
		// Return the contribution amount in wei
		return order.weiAmount;
	}

	/**
	 * @dev _approveKYCAddress provides the function to approve the specified address 
	 * indicating KYC Verified
	 * @param _addressToApprove of the user that is being verified
	 */
	function _approveKYCAddress(address _addressToApprove) 
	onlyOwner
	internal
	{
		// Ensure that _addressToApprove is not address(0)
		require(_addressToApprove != address(0), "Invalid address specified: address(0)");
		// Get this addesses contribution record
		OrderBook storage order = orders[_addressToApprove];
		// Set the contribution record to indicate address has been kyc verified
		order.kycVerified = true;
	}

	/**
	 * @dev _revokeKYCAddress() provides the function to revoke previously
	 * granted KYC verification in cases of fraud or false/invalid KYC data
	 * @param _addressToRevoke is the address to remove KYC verification from
	 */
	function _revokeKYCAddress(address _addressToRevoke)
	onlyOwner
	internal
	{
		// Ensure address is not address(0)
		require(_addressToRevoke != address(0), "Invalid address specified: address(0)");
		// Obtain a copy of this addresses contribution record
		OrderBook storage order = orders[_addressToRevoke];
		// Revoke this addresses KYC verification
		order.kycVerified = false;
	}

	/**
	 * @dev _rate() provides the function of calcualting the rate based on crowdsale stage
	 * @param _weiAmount indicated the amount of ether intended to use for purchase
	 * @return number of tokens worth based on specified Wei value
	 */
	function _rate(uint _weiAmount)
	internal
	view
	returns (uint256)
	{
		require(_weiAmount > 0, "Specified wei amoount must be > 0");

		// Determine if the current operation stage of the crowdsale is preICO
		if (crowdsaleStage == CrowdsaleStage.preICO)
		{
			// Determine if the purchase is >= 21 ether
			if (_weiAmount >= 21 ether) { // 20% bonus
				return 480e8;
			}
			
			// Determine if the purchase is >= 11 ether
			if (_weiAmount >= 11 ether) { // 15% bonus
				return 460e8;
			}
			
			// Determine if the purchase is >= 5 ether
			if (_weiAmount >= 5 ether) { // 10% bonus
				return 440e8;
			}

		}
		else
		// Determine if the current operation stage of the crowdsale is bonusICO
		if (crowdsaleStage == CrowdsaleStage.bonusICO)
		{
			// Determine if the purchase is >= 21 ether
			if (_weiAmount >= 21 ether) { // 10% bonus
				return 440e8;
			}
			else if (_weiAmount >= 11 ether) { // 7% bonus
				return 428e8;
			}
			else
			if (_weiAmount >= 5 ether) { // 5% bonus
				return 420e8;
			}

		}

		// Rate is either < bounus or is main sale so return base rate only
		return rate();
	}

	/**
	 * @dev Performs token to wei converstion calculations based on crowdsale specification
	 * @param _weiAmount to spend
	 * @return number of tokens purchasable for the specified _weiAmount at crowdsale stage rates
	 */
	function _getTokenAmount(uint256 _weiAmount)
	whenNotPaused
	internal
	view
	returns (uint256)
	{
		// Get the current rate set in the constructor and calculate token units per wei
		uint256 currentRate = _rate(_weiAmount);
		// Calculate the total number of tokens buyable at based rate (before adding bonus)
		uint256 sparkleToBuy = currentRate.mul(_weiAmount).div(10e17);
		// Return proposed token amount
		return sparkleToBuy;
	}

	/**
	 * @dev _preValidatePurchase provides the functionality of pre validating a potential purchase
	 * @param _beneficiary is the address that is currently purchasing tokens
	 * @param _weiAmount is the number of tokens this address is attempting to purchase
	 */
	function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) 
	whenNotPaused
	internal
	view
	{
		// Call into the parent validation to ensure _beneficiary and _weiAmount are valid
		super._preValidatePurchase(_beneficiary, _weiAmount);
		// Calculate amount of tokens for the specified _weiAmount
		uint256 requestedTokens = getExchangeRate(_weiAmount);
		// Calculate the currently sold tokens
		uint256 tempTotalTokensSold = tokensSold;
		// Incrememt total tokens		
		tempTotalTokensSold.add(requestedTokens);
		// Ensure total max token cap is > tempTotalTokensSold
		require(tempTotalTokensSold <= tokenCap, "Requested wei amount will exceed the max token cap and was not accepted.");
		// Ensure that requested tokens will not go over the remaining token balance
		require(requestedTokens <= getRemainingTokens(), "Requested tokens would exceed tokens available and was not accepted.");
		// Obtain the order record for _beneficiary if one exists
		OrderBook storage order = orders[_beneficiary];
		// Ensure this address has been kyc validated
		require(order.kycVerified, "Address attempting to purchase is not KYC Verified.");
		// Update this addresses order to reflect the purchase and ether spent
		order.weiAmount = order.weiAmount.add(_weiAmount);
		order.pendingTokens = order.pendingTokens.add(requestedTokens);
		// increment totalTokens sold
		tokensSold = tokensSold.add(requestedTokens);
		// Emit event
		emit TokensSold(_beneficiary, requestedTokens);
	}

	/**
	 * @dev _processPurchase() is overridden and will be called by OpenZep v2.0 internally
	 * @param _beneficiary is the address that is currently purchasing tokens
	 * @param _tokenAmount is the number of tokens this address is attempting to purchase
	 */
	function _processPurchase(address _beneficiary, uint256 _tokenAmount)
	whenNotPaused
	internal
	{
		// We do not call the base class _processPurchase() functions. This is needed here or the base
		// classes function will be called.
	}

}


// File: contracts/SparkleCrowdsale.sol

contract SparkleCrowdsale is SparkleBaseCrowdsale {

  // Token contract address 
  address public initTokenAddress = 0x4b7aD3a56810032782Afce12d7d27122bDb96efF;
  // Crowdsale specification
  uint256 public initTokenRate     = 400e8;
  uint256 public initTokenCap      = 19698000e8;
  uint256 public initStartTime     = now;
  uint256 public initEndTime       = now + 12 weeks; // Set this accordingly as it cannot be changed
  address public initDepositWallet = 0x0926a84C83d7B88338588Dca2729b590D787FA34;
  bool public initKYCRequired      = true;

  constructor() 
	SparkleBaseCrowdsale(ERC20(initTokenAddress), initTokenRate, initTokenCap, initStartTime, initEndTime, initDepositWallet, initKYCRequired)
	public
	{
	}

}

Contract Security Audit

Contract ABI

API
[{"constant":true,"inputs":[],"name":"crowdsaleStage","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_addressToLookup","type":"address"}],"name":"contributionAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"depositWallet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"hasClosed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_ownerToRemove","type":"address"}],"name":"removeOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"rate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ownerAddressToLookup","type":"address"}],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"endTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"weiRaised","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"isPauser","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOpen","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"claimTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"closingTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokensSold","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"wallet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_addressToLookuo","type":"address"}],"name":"isKYCVerified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_addressToLookup","type":"address"}],"name":"tokensPending","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newStageValue","type":"uint256"}],"name":"changeCrowdsaleStage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_weiAmount","type":"uint256"}],"name":"getExchangeRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renouncePauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_ownerToAdd","type":"address"}],"name":"addOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_addressesToRevoke","type":"address[]"}],"name":"bulkRevokeKYCAddresses","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"refundRemainingOk","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"startTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initKYCRequired","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initEndTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"addPauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initDepositWallet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getRemainingTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_addressToRefund","type":"address"}],"name":"refundRemainingTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"openingTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kycRequired","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"approveRemainingTokenRefund","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"tokenCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initTokenCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"}],"name":"buyTokens","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_newOwnership","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"initStartTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initTokenRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_masterAddressToLookup","type":"address"}],"name":"isMaster","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_addressesForApproval","type":"address[]"}],"name":"bulkApproveKYCAddresses","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initTokenAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_appovedByAddress","type":"address"},{"indexed":false,"name":"_numberOfApprovals","type":"uint256"}],"name":"ApprovedKYCAddresses","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_revokedByAddress","type":"address"},{"indexed":false,"name":"_numberOfRevokals","type":"uint256"}],"name":"RevokedKYCAddresses","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_claimingAddress","type":"address"},{"indexed":false,"name":"_tokensClaimed","type":"uint256"}],"name":"TokensClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_beneficiary","type":"address"},{"indexed":false,"name":"_tokensSold","type":"uint256"}],"name":"TokensSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_approvingAddress","type":"address"},{"indexed":false,"name":"tokenBurnApproved","type":"bool"}],"name":"TokenRefundApprovalChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_changingAddress","type":"address"},{"indexed":false,"name":"_newStageValue","type":"uint256"}],"name":"CrowdsaleStageChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_refundingToAddress","type":"address"},{"indexed":false,"name":"_numberOfTokensBurned","type":"uint256"}],"name":"CrowdsaleTokensRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"purchaser","type":"address"},{"indexed":true,"name":"beneficiary","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"TokensPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"PauserAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"PauserRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"addedOwner","type":"address"}],"name":"OwnershipAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"removedOwner","type":"address"}],"name":"OwnershipRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]

60806040526000601360006101000a81548160ff021916908360028111156200002457fe5b0217905550734b7ad3a56810032782afce12d7d27122bdb96eff601360016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506409502f90006014556606ff85cd47500060155542601655626ebe004201601755730926a84c83d7b88338588dca2729b590d787fa34601860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001601860146101000a81548160ff0219169083151502179055503480156200011c57600080fd5b50601360019054906101000a900473ffffffffffffffffffffffffffffffffffffffff16601454601554601654601754601860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16601860149054906101000a900460ff16838387848a6000336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36200025b62000517640100000000026401000000009004565b905060018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050620002cf3362000540640100000000026401000000009004565b6000600360006101000a81548160ff02191690831515021790555060016004819055506000831115156200030257600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141515156200033f57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515156200037c57600080fd5b8260078190555081600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050504282101515156200041857600080fd5b81811115156200042757600080fd5b8160098190555080600a81905550505086600b60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555085600c8190555084600d8190555083600e8190555082600f8190555081601060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080601060146101000a81548160ff0219169083151502179055506000601060156101000a81548160ff0219169083151502179055505050505050505062000702565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b62000564816002620005aa64010000000002620041a7179091906401000000009004565b8073ffffffffffffffffffffffffffffffffffffffff167f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f860405160405180910390a250565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515620005e757600080fd5b6200060282826200066d640100000000026401000000009004565b1515156200060f57600080fd5b60018260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515620006ab57600080fd5b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6143cd80620007126000396000f300608060405260043610610267576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063047abf1f14610272578063086b60dd146102ab57806309904c00146103025780631515bc2b14610359578063173825d9146103885780632c4e722e146103e35780632f54bf6e1461040e57806331711884146104695780633197cbb6146104945780633f4ba83a146104bf5780634042b66f146104d657806346fbf68e1461050157806347535d7b1461055c57806348c54b9d1461058b5780634b6753bc146105a2578063518ab2a8146105cd578063521eb273146105f857806354b7636e1461064f578063573cf3fa146106aa57806357857c92146107015780635c975abb1461072e57806362aaf0891461075d5780636ef8d66d1461079e5780637065cb48146107b5578063715018a61461081057806371cbf9c3146108275780637345da191461088d57806378e97925146108bc57806379d8b4b0146108e75780637d70e87c1461091657806382dc1ec4146109415780638456cb59146109845780638da5cb5b1461099b5780638f32d59b146109f25780639d76ea5814610a21578063a03224a814610a78578063af35ae2714610acf578063b651833914610afa578063b7a8807c14610b3d578063b969909114610b68578063c5ab2a0714610b97578063dd54291b14610bae578063e8f32bd614610bd9578063ec8ac4d814610c04578063f2fde38b14610c3a578063f36ce69b14610c7d578063f6c5394414610ca8578063f720f80b14610cd3578063fbd3ec2714610d2e578063fc0c546a14610d94578063fdde4b6e14610deb575b61027033610e42565b005b34801561027e57600080fd5b50610287610f39565b6040518082600281111561029757fe5b60ff16815260200191505060405180910390f35b3480156102b757600080fd5b506102ec600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610f4c565b6040518082815260200191505060405180910390f35b34801561030e57600080fd5b50610317611114565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561036557600080fd5b5061036e61113a565b604051808215151515815260200191505060405180910390f35b34801561039457600080fd5b506103c9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611146565b604051808215151515815260200191505060405180910390f35b3480156103ef57600080fd5b506103f86113b6565b6040518082815260200191505060405180910390f35b34801561041a57600080fd5b5061044f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506113c0565b604051808215151515815260200191505060405180910390f35b34801561047557600080fd5b5061047e611416565b6040518082815260200191505060405180910390f35b3480156104a057600080fd5b506104a961141c565b6040518082815260200191505060405180910390f35b3480156104cb57600080fd5b506104d4611422565b005b3480156104e257600080fd5b506104eb6114d1565b6040518082815260200191505060405180910390f35b34801561050d57600080fd5b50610542600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506114db565b604051808215151515815260200191505060405180910390f35b34801561056857600080fd5b506105716114f8565b604051808215151515815260200191505060405180910390f35b34801561059757600080fd5b506105a0611513565b005b3480156105ae57600080fd5b506105b761180c565b6040518082815260200191505060405180910390f35b3480156105d957600080fd5b506105e2611816565b6040518082815260200191505060405180910390f35b34801561060457600080fd5b5061060d61181c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561065b57600080fd5b50610690600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611846565b604051808215151515815260200191505060405180910390f35b3480156106b657600080fd5b506106eb600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061199e565b6040518082815260200191505060405180910390f35b34801561070d57600080fd5b5061072c60048036038101908080359060200190929190505050611b66565b005b34801561073a57600080fd5b50610743611d5a565b604051808215151515815260200191505060405180910390f35b34801561076957600080fd5b5061078860048036038101908080359060200190929190505050611d71565b6040518082815260200191505060405180910390f35b3480156107aa57600080fd5b506107b361203a565b005b3480156107c157600080fd5b506107f6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612045565b604051808215151515815260200191505060405180910390f35b34801561081c57600080fd5b506108256122af565b005b34801561083357600080fd5b5061088b600480360381019080803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192905050506123eb565b005b34801561089957600080fd5b506108a26125a0565b604051808215151515815260200191505060405180910390f35b3480156108c857600080fd5b506108d16125b3565b6040518082815260200191505060405180910390f35b3480156108f357600080fd5b506108fc6125b9565b604051808215151515815260200191505060405180910390f35b34801561092257600080fd5b5061092b6125cc565b6040518082815260200191505060405180910390f35b34801561094d57600080fd5b50610982600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506125d2565b005b34801561099057600080fd5b506109996125f2565b005b3480156109a757600080fd5b506109b06126a2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156109fe57600080fd5b50610a076126cb565b604051808215151515815260200191505060405180910390f35b348015610a2d57600080fd5b50610a36612722565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610a8457600080fd5b50610a8d612748565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610adb57600080fd5b50610ae461276e565b6040518082815260200191505060405180910390f35b348015610b0657600080fd5b50610b3b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506127a8565b005b348015610b4957600080fd5b50610b52612b95565b6040518082815260200191505060405180910390f35b348015610b7457600080fd5b50610b7d612b9f565b604051808215151515815260200191505060405180910390f35b348015610ba357600080fd5b50610bac612bb2565b005b348015610bba57600080fd5b50610bc3612e10565b6040518082815260200191505060405180910390f35b348015610be557600080fd5b50610bee612e16565b6040518082815260200191505060405180910390f35b610c38600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610e42565b005b348015610c4657600080fd5b50610c7b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612e1c565b005b348015610c8957600080fd5b50610c9261313a565b6040518082815260200191505060405180910390f35b348015610cb457600080fd5b50610cbd613140565b6040518082815260200191505060405180910390f35b348015610cdf57600080fd5b50610d14600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613146565b604051808215151515815260200191505060405180910390f35b348015610d3a57600080fd5b50610d9260048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290505050613185565b005b348015610da057600080fd5b50610da961333a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610df757600080fd5b50610e00613364565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600080600060016004600082825401925050819055506004549050349250610e6a848461338a565b610e7383613705565b9150610e8a8360085461376a90919063ffffffff16565b600881905550610e9a848361378b565b8373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f6faf93231a456e552dbc9961f58d9713ee4f2e69d15f1975b050ef0911053a7b8585604051808381526020018281526020019250505060405180910390a3610f1184846137ab565b610f196137af565b610f23848461381a565b60045481141515610f3357600080fd5b50505050565b601360009054906101000a900460ff1681565b600080610f58336113c0565b1515610fcc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff16151515610fe857600080fd5b610ff06114f8565b1515610ffb57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141515156110c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001807f537065636966696564206164647265737320697320496e76616c6964205b307881526020017f305d00000000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060000154915050919050565b601060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600a544211905090565b60006111506126cb565b15156111c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f5065726d697373696f6e2064656e696564205b6d61737465725d2e000000000081525060200191505060405180910390fd5b6111cc6126a2565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561126f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f5065726d697373696f6e2064656e696564205b6d61737465725d2e000000000081525060200191505060405180910390fd5b611278826113c0565b1515611312576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b8152602001807f4164647265737320737065636966696564206e6f7420666f756e6420696e206f81526020017f776e657273206c6973742e00000000000000000000000000000000000000000081525060400191505060405180910390fd5b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff167f86d076ecf250a6d90a67a7c75317f44709d5001395ecf1df6d9dad5278f1e68160405160405180910390a260019050919050565b6000600754905090565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600c5481565b600f5481565b61142b336114db565b151561143657600080fd5b600360009054906101000a900460ff16151561145157600080fd5b6000600360006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1565b6000600854905090565b60006114f182600261381e90919063ffffffff16565b9050919050565b6000600954421015801561150e5750600a544211155b905090565b600080600360009054906101000a900460ff1615151561153257600080fd5b61153a6114f8565b151561154557600080fd5b600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151515611610576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001807f496e76616c69642061646472657373207370656369666965643a20616464726581526020017f737328302900000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002091508160020160009054906101000a900460ff1615156116fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260378152602001807f4164647265737320617474656d7074696e6720746f20636c61696d20746f6b6581526020017f6e73206973206e6f74204b59432056657269666965642e00000000000000000081525060400191505060405180910390fd5b6000826001015411151561179f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001807f4164647265737320646f6573206e6f74206861766520616e792070656e64696e81526020017f6720746f6b656e7320746f20636c61696d2e000000000000000000000000000081525060400191505060405180910390fd5b81600101549050600082600101819055506117ba33826138b2565b3373ffffffffffffffffffffffffffffffffffffffff167f896e034966eaaf1adc54acc0f257056febbd300c9e47182cf761982cf1f5e430826040518082815260200191505060405180910390a25050565b6000600a54905090565b60115481565b6000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080600360009054906101000a900460ff1615151561186557600080fd5b61186d6114f8565b151561187857600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515611943576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001807f496e76616c69642061646472657373207370656369666965643a20616464726581526020017f737328302900000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060020160009054906101000a900460ff16915050919050565b6000806119aa336113c0565b1515611a1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff16151515611a3a57600080fd5b611a426114f8565b1515611a4d57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515611b18576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001807f537065636966696564206164647265737320697320696e76616c6964205b307881526020017f305d00000000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010154915050919050565b6000611b71336113c0565b1515611be5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff16151515611c0157600080fd5b611c096114f8565b1515611c1457600080fd5b8160006002811115611c2257fe5b1415611c315760009050611cda565b8160016002811115611c3f57fe5b1415611c4e5760019050611cd9565b81600280811115611c5b57fe5b1415611c6a5760029050611cd8565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f496e76616c69642073746167652073656c65637465640000000000000000000081525060200191505060405180910390fd5b5b5b80601360006101000a81548160ff02191690836002811115611cf857fe5b02179055503373ffffffffffffffffffffffffffffffffffffffff167f3c23266d1b5bf80319da6c021af8d582247ce10c9087b72628722380ad6013cf826002811115611d4157fe5b6040518082815260200191505060405180910390a25050565b6000600360009054906101000a900460ff16905090565b600080600360009054906101000a900460ff16151515611d9057600080fd5b611d986114f8565b1515611da357600080fd5b60006002811115611db057fe5b601360009054906101000a900460ff166002811115611dcb57fe5b1415611e7c57670de0b6b3a76400008310151515611e77576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001807f50726549434f206d696e696d756d2065746865722072657175697265643a203181526020017f204554482e00000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b611f81565b60016002811115611e8957fe5b601360009054906101000a900460ff166002811115611ea457fe5b1480611ed45750600280811115611eb757fe5b601360009054906101000a900460ff166002811115611ed257fe5b145b15611f80576706f05b59d3b200008310151515611f7f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260318152602001807f626f6e757349434f2f6d61696e49434f206d696e696d756d206574686572207281526020017f657175697265643a20302e35204554482e00000000000000000000000000000081525060400191505060405180910390fd5b5b5b611f8a83613705565b905080611f9561276e565b10151515612031576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603d8152602001807f537065636966696564207765692076616c756520776f75646c6420657863656581526020017f6420616d6f756e74206f6620746f6b656e732072656d61696e696e672e00000081525060400191505060405180910390fd5b80915050919050565b61204333613903565b565b600061204f6126cb565b15156120c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f5065726d697373696f6e2064656e696564205b6d61737465725d2e000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515612168576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f496e76616c69642061646472657373207370656369666965642028307830290081525060200191505060405180910390fd5b612171826113c0565b15151561220c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001807f416464726573732073706563696669656420616c726561647920696e206f776e81526020017f657273206c6973742e000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b60018060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff167fb4cd6c6140e1db788f68710738b06ef4d0df6a884a06a088433a4c2f5e036e7c60405160405180910390a260019050919050565b6122b8336113c0565b151561232c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60006123f6336113c0565b151561246a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff1615151561248657600080fd5b61248e6114f8565b151561249957600080fd5b60008251111515612512576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f537065636966696564206164647265737320617272617920697320656d70747981525060200191505060405180910390fd5b600090505b815181101561254d57612540828281518110151561253157fe5b9060200190602002015161395d565b8080600101915050612517565b3373ffffffffffffffffffffffffffffffffffffffff167f1dfb1bfb196b8891d9a5333eee4b12c6b1f1a3bb7c92476c1f790835b8c8403883516040518082815260200191505060405180910390a25050565b601060159054906101000a900460ff1681565b600e5481565b601860149054906101000a900460ff1681565b60175481565b6125db336114db565b15156125e657600080fd5b6125ef81613b09565b50565b6125fb336114db565b151561260657600080fd5b600360009054906101000a900460ff1615151561262257600080fd5b6001600360006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b601860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600360009054906101000a900460ff1615151561278c57600080fd5b6127a3601154600d54613b6390919063ffffffff16565b905090565b60006127b3336113c0565b1515612827576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff1615151561284357600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561290e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001807f537065636966696564206164647265737320697320696e76616c6964205b307881526020017f305d00000000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b61291661113a565b15156129b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a8152602001807f43726f776473616c65206d7573742062652066696e697368656420746f20627581526020017f726e20746f6b656e732e0000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601060159054906101000a900460ff161515612a5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602d8152602001807f43726f776473616c652072656d61696e696e6720746f6b656e20726566756e6481526020017f2069732064697361626c65642e0000000000000000000000000000000000000081525060400191505060405180910390fd5b612a6261333a565b73ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015612afc57600080fd5b505af1158015612b10573d6000803e3d6000fd5b505050506040513d6020811015612b2657600080fd5b81019080805190602001909291905050509050612b4382826138b2565b8173ffffffffffffffffffffffffffffffffffffffff167f060be99623451c08be99560be3e8aecc2bb84341ecc5a399619a1c3c47e03c1a826040518082815260200191505060405180910390a25050565b6000600954905090565b601060149054906101000a900460ff1681565b612bbb336113c0565b1515612c2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff16151515612c4b57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151515612cf0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f43616c6c696e67206164647265737320696e76616c6964205b3078305d00000081525060200191505060405180910390fd5b612cf861113a565b1515612d92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603a8152602001807f546f6b656e206275726e20617070726f76616c2063616e206f6e6c792062652081526020017f7365742061667465722063726f776473616c6520636c6f73657300000000000081525060400191505060405180910390fd5b6001601060156101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167f2b3cb8ff19a977ee7e3214688d5612066b83fdf40e465f4c56f013655f926744601060159054906101000a900460ff16604051808215151515815260200191505060405180910390a2565b600d5481565b60155481565b612e246126cb565b1515612e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f5065726d697373696f6e2064656e696564205b6d61737465725d2e000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515612f3d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f496e76616c69642061646472657373207370656369666965642028307830290081525060200191505060405180910390fd5b612f456126a2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561300e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260378152602001807f4164647265737320737065636966696564206d757374206e6f74206d6174636881526020017f2063757272656e74206f776e657220616464726573732e00000000000000000081525060400191505060405180910390fd5b613017816113c0565b15156130d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260468152602001807f4d6173746572206f776e6572736869702063616e206f6e6c792062652074726181526020017f6e7366657272656420746f20616e206578697374696e67206f776e657220616481526020017f64726573732e000000000000000000000000000000000000000000000000000081525060600191505060405180910390fd5b6130e081613b84565b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60165481565b60145481565b60008173ffffffffffffffffffffffffffffffffffffffff166131676126a2565b73ffffffffffffffffffffffffffffffffffffffff16149050919050565b6000613190336113c0565b1515613204576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff1615151561322057600080fd5b6132286114f8565b151561323357600080fd5b600082511115156132ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f537065636966696564206164647265737320617272617920697320656d70747981525060200191505060405180910390fd5b600090505b81518110156132e7576132da82828151811015156132cb57fe5b90602001906020020151613c0d565b80806001019150506132b1565b3373ffffffffffffffffffffffffffffffffffffffff167fd857400c5dd07f949d2beb4612ab761c028dc6bc160c428b18b76d906d361bf383516040518082815260200191505060405180910390a25050565b6000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b601360019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000600360009054906101000a900460ff161515156133ab57600080fd5b6133b58585613db9565b6133be84611d71565b925060115491506133d8838361376a90919063ffffffff16565b50600d54821115151561349f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260488152602001807f5265717565737465642077656920616d6f756e742077696c6c2065786365656481526020017f20746865206d617820746f6b656e2063617020616e6420776173206e6f74206181526020017f636365707465642e00000000000000000000000000000000000000000000000081525060600191505060405180910390fd5b6134a761276e565b831115151561356a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260448152602001807f52657175657374656420746f6b656e7320776f756c642065786365656420746f81526020017f6b656e7320617661696c61626c6520616e6420776173206e6f7420616363657081526020017f7465642e0000000000000000000000000000000000000000000000000000000081525060600191505060405180910390fd5b601260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060020160009054906101000a900460ff161515613657576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001807f4164647265737320617474656d7074696e6720746f207075726368617365206981526020017f73206e6f74204b59432056657269666965642e0000000000000000000000000081525060400191505060405180910390fd5b61366e84826000015461376a90919063ffffffff16565b816000018190555061368d83826001015461376a90919063ffffffff16565b81600101819055506136aa8360115461376a90919063ffffffff16565b6011819055508473ffffffffffffffffffffffffffffffffffffffff167f57d61f3ccd4ccd25ec5d234d6049553a586fac134c85c98d0b0d9d5724f4e43e846040518082815260200191505060405180910390a25050505050565b6000806000600360009054906101000a900460ff1615151561372657600080fd5b61372f84613dda565b915061375e670de0b6b3a76400006137508685613fa290919063ffffffff16565b613fe090919063ffffffff16565b90508092505050919050565b600080828401905083811015151561378157600080fd5b8091505092915050565b600360009054906101000a900460ff161515156137a757600080fd5b5050565b5050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015613817573d6000803e3d6000fd5b50565b5050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561385b57600080fd5b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6138ff8282600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1661400a9092919063ffffffff16565b5050565b6139178160026140f890919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e60405160405180910390a250565b6000613968336113c0565b15156139dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515613aa7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001807f496e76616c69642061646472657373207370656369666965643a20616464726581526020017f737328302900000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008160020160006101000a81548160ff0219169083151502179055505050565b613b1d8160026141a790919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f860405160405180910390a250565b600080838311151515613b7557600080fd5b82840390508091505092915050565b613b8d336113c0565b1515613c01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b613c0a81614257565b50565b6000613c18336113c0565b1515613c8c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515613d57576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001807f496e76616c69642061646472657373207370656369666965643a20616464726581526020017f737328302900000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060018160020160006101000a81548160ff0219169083151502179055505050565b613dc16114f8565b1515613dcc57600080fd5b613dd68282614351565b5050565b60008082111515613e79576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001807f5370656369666965642077656920616d6f6f756e74206d757374206265203e2081526020017f300000000000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b60006002811115613e8657fe5b601360009054906101000a900460ff166002811115613ea157fe5b1415613f07576801236efcbcbb34000082101515613ec657640b2d05e0009050613f9d565b6798a7d9b8314c000082101515613ee457640ab5d04c009050613f9d565b674563918244f4000082101515613f0257640a3e9ab8009050613f9d565b613f92565b60016002811115613f1457fe5b601360009054906101000a900460ff166002811115613f2f57fe5b1415613f91576801236efcbcbb34000082101515613f5457640a3e9ab8009050613f9d565b6798a7d9b8314c000082101515613f72576409f7142c009050613f9d565b674563918244f4000082101515613f90576409c76524009050613f9d565b5b5b613f9a6113b6565b90505b919050565b6000806000841415613fb75760009150613fd9565b8284029050828482811515613fc857fe5b04141515613fd557600080fd5b8091505b5092915050565b600080600083111515613ff257600080fd5b8284811515613ffd57fe5b0490508091505092915050565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156140ad57600080fd5b505af11580156140c1573d6000803e3d6000fd5b505050506040513d60208110156140d757600080fd5b810190808051906020019092919050505015156140f357600080fd5b505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561413457600080fd5b61413e828261381e565b151561414957600080fd5b60008260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515156141e357600080fd5b6141ed828261381e565b1515156141f957600080fd5b60018260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561429357600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561438d57600080fd5b6000811415151561439d57600080fd5b50505600a165627a7a72305820963159d4bf355a82b79143806a111b960c17df59d23a7080377003ebf4537f5b0029

Deployed Bytecode

0x608060405260043610610267576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063047abf1f14610272578063086b60dd146102ab57806309904c00146103025780631515bc2b14610359578063173825d9146103885780632c4e722e146103e35780632f54bf6e1461040e57806331711884146104695780633197cbb6146104945780633f4ba83a146104bf5780634042b66f146104d657806346fbf68e1461050157806347535d7b1461055c57806348c54b9d1461058b5780634b6753bc146105a2578063518ab2a8146105cd578063521eb273146105f857806354b7636e1461064f578063573cf3fa146106aa57806357857c92146107015780635c975abb1461072e57806362aaf0891461075d5780636ef8d66d1461079e5780637065cb48146107b5578063715018a61461081057806371cbf9c3146108275780637345da191461088d57806378e97925146108bc57806379d8b4b0146108e75780637d70e87c1461091657806382dc1ec4146109415780638456cb59146109845780638da5cb5b1461099b5780638f32d59b146109f25780639d76ea5814610a21578063a03224a814610a78578063af35ae2714610acf578063b651833914610afa578063b7a8807c14610b3d578063b969909114610b68578063c5ab2a0714610b97578063dd54291b14610bae578063e8f32bd614610bd9578063ec8ac4d814610c04578063f2fde38b14610c3a578063f36ce69b14610c7d578063f6c5394414610ca8578063f720f80b14610cd3578063fbd3ec2714610d2e578063fc0c546a14610d94578063fdde4b6e14610deb575b61027033610e42565b005b34801561027e57600080fd5b50610287610f39565b6040518082600281111561029757fe5b60ff16815260200191505060405180910390f35b3480156102b757600080fd5b506102ec600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610f4c565b6040518082815260200191505060405180910390f35b34801561030e57600080fd5b50610317611114565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561036557600080fd5b5061036e61113a565b604051808215151515815260200191505060405180910390f35b34801561039457600080fd5b506103c9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611146565b604051808215151515815260200191505060405180910390f35b3480156103ef57600080fd5b506103f86113b6565b6040518082815260200191505060405180910390f35b34801561041a57600080fd5b5061044f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506113c0565b604051808215151515815260200191505060405180910390f35b34801561047557600080fd5b5061047e611416565b6040518082815260200191505060405180910390f35b3480156104a057600080fd5b506104a961141c565b6040518082815260200191505060405180910390f35b3480156104cb57600080fd5b506104d4611422565b005b3480156104e257600080fd5b506104eb6114d1565b6040518082815260200191505060405180910390f35b34801561050d57600080fd5b50610542600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506114db565b604051808215151515815260200191505060405180910390f35b34801561056857600080fd5b506105716114f8565b604051808215151515815260200191505060405180910390f35b34801561059757600080fd5b506105a0611513565b005b3480156105ae57600080fd5b506105b761180c565b6040518082815260200191505060405180910390f35b3480156105d957600080fd5b506105e2611816565b6040518082815260200191505060405180910390f35b34801561060457600080fd5b5061060d61181c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561065b57600080fd5b50610690600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611846565b604051808215151515815260200191505060405180910390f35b3480156106b657600080fd5b506106eb600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061199e565b6040518082815260200191505060405180910390f35b34801561070d57600080fd5b5061072c60048036038101908080359060200190929190505050611b66565b005b34801561073a57600080fd5b50610743611d5a565b604051808215151515815260200191505060405180910390f35b34801561076957600080fd5b5061078860048036038101908080359060200190929190505050611d71565b6040518082815260200191505060405180910390f35b3480156107aa57600080fd5b506107b361203a565b005b3480156107c157600080fd5b506107f6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612045565b604051808215151515815260200191505060405180910390f35b34801561081c57600080fd5b506108256122af565b005b34801561083357600080fd5b5061088b600480360381019080803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192905050506123eb565b005b34801561089957600080fd5b506108a26125a0565b604051808215151515815260200191505060405180910390f35b3480156108c857600080fd5b506108d16125b3565b6040518082815260200191505060405180910390f35b3480156108f357600080fd5b506108fc6125b9565b604051808215151515815260200191505060405180910390f35b34801561092257600080fd5b5061092b6125cc565b6040518082815260200191505060405180910390f35b34801561094d57600080fd5b50610982600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506125d2565b005b34801561099057600080fd5b506109996125f2565b005b3480156109a757600080fd5b506109b06126a2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156109fe57600080fd5b50610a076126cb565b604051808215151515815260200191505060405180910390f35b348015610a2d57600080fd5b50610a36612722565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610a8457600080fd5b50610a8d612748565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610adb57600080fd5b50610ae461276e565b6040518082815260200191505060405180910390f35b348015610b0657600080fd5b50610b3b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506127a8565b005b348015610b4957600080fd5b50610b52612b95565b6040518082815260200191505060405180910390f35b348015610b7457600080fd5b50610b7d612b9f565b604051808215151515815260200191505060405180910390f35b348015610ba357600080fd5b50610bac612bb2565b005b348015610bba57600080fd5b50610bc3612e10565b6040518082815260200191505060405180910390f35b348015610be557600080fd5b50610bee612e16565b6040518082815260200191505060405180910390f35b610c38600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610e42565b005b348015610c4657600080fd5b50610c7b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612e1c565b005b348015610c8957600080fd5b50610c9261313a565b6040518082815260200191505060405180910390f35b348015610cb457600080fd5b50610cbd613140565b6040518082815260200191505060405180910390f35b348015610cdf57600080fd5b50610d14600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613146565b604051808215151515815260200191505060405180910390f35b348015610d3a57600080fd5b50610d9260048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290505050613185565b005b348015610da057600080fd5b50610da961333a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610df757600080fd5b50610e00613364565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600080600060016004600082825401925050819055506004549050349250610e6a848461338a565b610e7383613705565b9150610e8a8360085461376a90919063ffffffff16565b600881905550610e9a848361378b565b8373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f6faf93231a456e552dbc9961f58d9713ee4f2e69d15f1975b050ef0911053a7b8585604051808381526020018281526020019250505060405180910390a3610f1184846137ab565b610f196137af565b610f23848461381a565b60045481141515610f3357600080fd5b50505050565b601360009054906101000a900460ff1681565b600080610f58336113c0565b1515610fcc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff16151515610fe857600080fd5b610ff06114f8565b1515610ffb57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141515156110c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001807f537065636966696564206164647265737320697320496e76616c6964205b307881526020017f305d00000000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060000154915050919050565b601060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600a544211905090565b60006111506126cb565b15156111c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f5065726d697373696f6e2064656e696564205b6d61737465725d2e000000000081525060200191505060405180910390fd5b6111cc6126a2565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561126f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f5065726d697373696f6e2064656e696564205b6d61737465725d2e000000000081525060200191505060405180910390fd5b611278826113c0565b1515611312576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b8152602001807f4164647265737320737065636966696564206e6f7420666f756e6420696e206f81526020017f776e657273206c6973742e00000000000000000000000000000000000000000081525060400191505060405180910390fd5b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff167f86d076ecf250a6d90a67a7c75317f44709d5001395ecf1df6d9dad5278f1e68160405160405180910390a260019050919050565b6000600754905090565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600c5481565b600f5481565b61142b336114db565b151561143657600080fd5b600360009054906101000a900460ff16151561145157600080fd5b6000600360006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1565b6000600854905090565b60006114f182600261381e90919063ffffffff16565b9050919050565b6000600954421015801561150e5750600a544211155b905090565b600080600360009054906101000a900460ff1615151561153257600080fd5b61153a6114f8565b151561154557600080fd5b600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151515611610576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001807f496e76616c69642061646472657373207370656369666965643a20616464726581526020017f737328302900000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002091508160020160009054906101000a900460ff1615156116fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260378152602001807f4164647265737320617474656d7074696e6720746f20636c61696d20746f6b6581526020017f6e73206973206e6f74204b59432056657269666965642e00000000000000000081525060400191505060405180910390fd5b6000826001015411151561179f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001807f4164647265737320646f6573206e6f74206861766520616e792070656e64696e81526020017f6720746f6b656e7320746f20636c61696d2e000000000000000000000000000081525060400191505060405180910390fd5b81600101549050600082600101819055506117ba33826138b2565b3373ffffffffffffffffffffffffffffffffffffffff167f896e034966eaaf1adc54acc0f257056febbd300c9e47182cf761982cf1f5e430826040518082815260200191505060405180910390a25050565b6000600a54905090565b60115481565b6000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080600360009054906101000a900460ff1615151561186557600080fd5b61186d6114f8565b151561187857600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515611943576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001807f496e76616c69642061646472657373207370656369666965643a20616464726581526020017f737328302900000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060020160009054906101000a900460ff16915050919050565b6000806119aa336113c0565b1515611a1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff16151515611a3a57600080fd5b611a426114f8565b1515611a4d57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515611b18576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001807f537065636966696564206164647265737320697320696e76616c6964205b307881526020017f305d00000000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010154915050919050565b6000611b71336113c0565b1515611be5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff16151515611c0157600080fd5b611c096114f8565b1515611c1457600080fd5b8160006002811115611c2257fe5b1415611c315760009050611cda565b8160016002811115611c3f57fe5b1415611c4e5760019050611cd9565b81600280811115611c5b57fe5b1415611c6a5760029050611cd8565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f496e76616c69642073746167652073656c65637465640000000000000000000081525060200191505060405180910390fd5b5b5b80601360006101000a81548160ff02191690836002811115611cf857fe5b02179055503373ffffffffffffffffffffffffffffffffffffffff167f3c23266d1b5bf80319da6c021af8d582247ce10c9087b72628722380ad6013cf826002811115611d4157fe5b6040518082815260200191505060405180910390a25050565b6000600360009054906101000a900460ff16905090565b600080600360009054906101000a900460ff16151515611d9057600080fd5b611d986114f8565b1515611da357600080fd5b60006002811115611db057fe5b601360009054906101000a900460ff166002811115611dcb57fe5b1415611e7c57670de0b6b3a76400008310151515611e77576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001807f50726549434f206d696e696d756d2065746865722072657175697265643a203181526020017f204554482e00000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b611f81565b60016002811115611e8957fe5b601360009054906101000a900460ff166002811115611ea457fe5b1480611ed45750600280811115611eb757fe5b601360009054906101000a900460ff166002811115611ed257fe5b145b15611f80576706f05b59d3b200008310151515611f7f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260318152602001807f626f6e757349434f2f6d61696e49434f206d696e696d756d206574686572207281526020017f657175697265643a20302e35204554482e00000000000000000000000000000081525060400191505060405180910390fd5b5b5b611f8a83613705565b905080611f9561276e565b10151515612031576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603d8152602001807f537065636966696564207765692076616c756520776f75646c6420657863656581526020017f6420616d6f756e74206f6620746f6b656e732072656d61696e696e672e00000081525060400191505060405180910390fd5b80915050919050565b61204333613903565b565b600061204f6126cb565b15156120c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f5065726d697373696f6e2064656e696564205b6d61737465725d2e000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515612168576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f496e76616c69642061646472657373207370656369666965642028307830290081525060200191505060405180910390fd5b612171826113c0565b15151561220c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001807f416464726573732073706563696669656420616c726561647920696e206f776e81526020017f657273206c6973742e000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b60018060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff167fb4cd6c6140e1db788f68710738b06ef4d0df6a884a06a088433a4c2f5e036e7c60405160405180910390a260019050919050565b6122b8336113c0565b151561232c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60006123f6336113c0565b151561246a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff1615151561248657600080fd5b61248e6114f8565b151561249957600080fd5b60008251111515612512576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f537065636966696564206164647265737320617272617920697320656d70747981525060200191505060405180910390fd5b600090505b815181101561254d57612540828281518110151561253157fe5b9060200190602002015161395d565b8080600101915050612517565b3373ffffffffffffffffffffffffffffffffffffffff167f1dfb1bfb196b8891d9a5333eee4b12c6b1f1a3bb7c92476c1f790835b8c8403883516040518082815260200191505060405180910390a25050565b601060159054906101000a900460ff1681565b600e5481565b601860149054906101000a900460ff1681565b60175481565b6125db336114db565b15156125e657600080fd5b6125ef81613b09565b50565b6125fb336114db565b151561260657600080fd5b600360009054906101000a900460ff1615151561262257600080fd5b6001600360006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b601860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600360009054906101000a900460ff1615151561278c57600080fd5b6127a3601154600d54613b6390919063ffffffff16565b905090565b60006127b3336113c0565b1515612827576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff1615151561284357600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561290e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001807f537065636966696564206164647265737320697320696e76616c6964205b307881526020017f305d00000000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b61291661113a565b15156129b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a8152602001807f43726f776473616c65206d7573742062652066696e697368656420746f20627581526020017f726e20746f6b656e732e0000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601060159054906101000a900460ff161515612a5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602d8152602001807f43726f776473616c652072656d61696e696e6720746f6b656e20726566756e6481526020017f2069732064697361626c65642e0000000000000000000000000000000000000081525060400191505060405180910390fd5b612a6261333a565b73ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015612afc57600080fd5b505af1158015612b10573d6000803e3d6000fd5b505050506040513d6020811015612b2657600080fd5b81019080805190602001909291905050509050612b4382826138b2565b8173ffffffffffffffffffffffffffffffffffffffff167f060be99623451c08be99560be3e8aecc2bb84341ecc5a399619a1c3c47e03c1a826040518082815260200191505060405180910390a25050565b6000600954905090565b601060149054906101000a900460ff1681565b612bbb336113c0565b1515612c2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff16151515612c4b57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151515612cf0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f43616c6c696e67206164647265737320696e76616c6964205b3078305d00000081525060200191505060405180910390fd5b612cf861113a565b1515612d92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603a8152602001807f546f6b656e206275726e20617070726f76616c2063616e206f6e6c792062652081526020017f7365742061667465722063726f776473616c6520636c6f73657300000000000081525060400191505060405180910390fd5b6001601060156101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167f2b3cb8ff19a977ee7e3214688d5612066b83fdf40e465f4c56f013655f926744601060159054906101000a900460ff16604051808215151515815260200191505060405180910390a2565b600d5481565b60155481565b612e246126cb565b1515612e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f5065726d697373696f6e2064656e696564205b6d61737465725d2e000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515612f3d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f496e76616c69642061646472657373207370656369666965642028307830290081525060200191505060405180910390fd5b612f456126a2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561300e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260378152602001807f4164647265737320737065636966696564206d757374206e6f74206d6174636881526020017f2063757272656e74206f776e657220616464726573732e00000000000000000081525060400191505060405180910390fd5b613017816113c0565b15156130d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260468152602001807f4d6173746572206f776e6572736869702063616e206f6e6c792062652074726181526020017f6e7366657272656420746f20616e206578697374696e67206f776e657220616481526020017f64726573732e000000000000000000000000000000000000000000000000000081525060600191505060405180910390fd5b6130e081613b84565b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60165481565b60145481565b60008173ffffffffffffffffffffffffffffffffffffffff166131676126a2565b73ffffffffffffffffffffffffffffffffffffffff16149050919050565b6000613190336113c0565b1515613204576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600360009054906101000a900460ff1615151561322057600080fd5b6132286114f8565b151561323357600080fd5b600082511115156132ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f537065636966696564206164647265737320617272617920697320656d70747981525060200191505060405180910390fd5b600090505b81518110156132e7576132da82828151811015156132cb57fe5b90602001906020020151613c0d565b80806001019150506132b1565b3373ffffffffffffffffffffffffffffffffffffffff167fd857400c5dd07f949d2beb4612ab761c028dc6bc160c428b18b76d906d361bf383516040518082815260200191505060405180910390a25050565b6000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b601360019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000600360009054906101000a900460ff161515156133ab57600080fd5b6133b58585613db9565b6133be84611d71565b925060115491506133d8838361376a90919063ffffffff16565b50600d54821115151561349f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260488152602001807f5265717565737465642077656920616d6f756e742077696c6c2065786365656481526020017f20746865206d617820746f6b656e2063617020616e6420776173206e6f74206181526020017f636365707465642e00000000000000000000000000000000000000000000000081525060600191505060405180910390fd5b6134a761276e565b831115151561356a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260448152602001807f52657175657374656420746f6b656e7320776f756c642065786365656420746f81526020017f6b656e7320617661696c61626c6520616e6420776173206e6f7420616363657081526020017f7465642e0000000000000000000000000000000000000000000000000000000081525060600191505060405180910390fd5b601260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060020160009054906101000a900460ff161515613657576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001807f4164647265737320617474656d7074696e6720746f207075726368617365206981526020017f73206e6f74204b59432056657269666965642e0000000000000000000000000081525060400191505060405180910390fd5b61366e84826000015461376a90919063ffffffff16565b816000018190555061368d83826001015461376a90919063ffffffff16565b81600101819055506136aa8360115461376a90919063ffffffff16565b6011819055508473ffffffffffffffffffffffffffffffffffffffff167f57d61f3ccd4ccd25ec5d234d6049553a586fac134c85c98d0b0d9d5724f4e43e846040518082815260200191505060405180910390a25050505050565b6000806000600360009054906101000a900460ff1615151561372657600080fd5b61372f84613dda565b915061375e670de0b6b3a76400006137508685613fa290919063ffffffff16565b613fe090919063ffffffff16565b90508092505050919050565b600080828401905083811015151561378157600080fd5b8091505092915050565b600360009054906101000a900460ff161515156137a757600080fd5b5050565b5050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015613817573d6000803e3d6000fd5b50565b5050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561385b57600080fd5b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6138ff8282600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1661400a9092919063ffffffff16565b5050565b6139178160026140f890919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e60405160405180910390a250565b6000613968336113c0565b15156139dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515613aa7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001807f496e76616c69642061646472657373207370656369666965643a20616464726581526020017f737328302900000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008160020160006101000a81548160ff0219169083151502179055505050565b613b1d8160026141a790919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f860405160405180910390a250565b600080838311151515613b7557600080fd5b82840390508091505092915050565b613b8d336113c0565b1515613c01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b613c0a81614257565b50565b6000613c18336113c0565b1515613c8c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f5065726d697373696f6e2064656e696564205b6f776e65725d2e00000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515613d57576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001807f496e76616c69642061646472657373207370656369666965643a20616464726581526020017f737328302900000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b601260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060018160020160006101000a81548160ff0219169083151502179055505050565b613dc16114f8565b1515613dcc57600080fd5b613dd68282614351565b5050565b60008082111515613e79576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001807f5370656369666965642077656920616d6f6f756e74206d757374206265203e2081526020017f300000000000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b60006002811115613e8657fe5b601360009054906101000a900460ff166002811115613ea157fe5b1415613f07576801236efcbcbb34000082101515613ec657640b2d05e0009050613f9d565b6798a7d9b8314c000082101515613ee457640ab5d04c009050613f9d565b674563918244f4000082101515613f0257640a3e9ab8009050613f9d565b613f92565b60016002811115613f1457fe5b601360009054906101000a900460ff166002811115613f2f57fe5b1415613f91576801236efcbcbb34000082101515613f5457640a3e9ab8009050613f9d565b6798a7d9b8314c000082101515613f72576409f7142c009050613f9d565b674563918244f4000082101515613f90576409c76524009050613f9d565b5b5b613f9a6113b6565b90505b919050565b6000806000841415613fb75760009150613fd9565b8284029050828482811515613fc857fe5b04141515613fd557600080fd5b8091505b5092915050565b600080600083111515613ff257600080fd5b8284811515613ffd57fe5b0490508091505092915050565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156140ad57600080fd5b505af11580156140c1573d6000803e3d6000fd5b505050506040513d60208110156140d757600080fd5b810190808051906020019092919050505015156140f357600080fd5b505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561413457600080fd5b61413e828261381e565b151561414957600080fd5b60008260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515156141e357600080fd5b6141ed828261381e565b1515156141f957600080fd5b60018260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561429357600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561438d57600080fd5b6000811415151561439d57600080fd5b50505600a165627a7a72305820963159d4bf355a82b79143806a111b960c17df59d23a7080377003ebf4537f5b0029

Swarm Source

bzzr://963159d4bf355a82b79143806a111b960c17df59d23a7080377003ebf4537f5b

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.