Contract Overview
[ Download CSV Export ]
Latest 2 internal transactions
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0xbf6930da5e32752fa20c0bd5d18360bc0e8535d8fc1e11623cc967011d90f154 | 6571356 | 866 days 18 hrs ago | 0xb5da84cdc928765c15a8192bf3c6649e7802772b | 0x62799b3b97baac306498f721079f3a9405a91e41 | 1.21 Ether | ||
0xfd17a1289d06c635dc75f42e7a1f19557f7f8aa9233f435b01fcfe5645f1932e | 5428768 | 1060 days 23 hrs ago | 0xb5da84cdc928765c15a8192bf3c6649e7802772b | 0x62799b3b97baac306498f721079f3a9405a91e41 | 0.065 Ether |
[ Download CSV Export ]
Contract Name:
LicenseCore
Compiler Version
v0.4.19+commit.c4cbbb05
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2018-04-02 */ pragma solidity ^0.4.13; interface ERC721Enumerable /* is ERC721 */ { /// @notice Count NFTs tracked by this contract /// @return A count of valid NFTs tracked by this contract, where each one of /// them has an assigned and queryable owner not equal to the zero address function totalSupply() public view returns (uint256); /// @notice Enumerate valid NFTs /// @dev Throws if `_index` >= `totalSupply()`. /// @param _index A counter less than `totalSupply()` /// @return The token identifier for the `_index`th NFT, /// (sort order not specified) function tokenByIndex(uint256 _index) external view returns (uint256); /// @notice Enumerate NFTs assigned to an owner /// @dev Throws if `_index` >= `balanceOf(_owner)` or if /// `_owner` is the zero address, representing invalid NFTs. /// @param _owner An address where we are interested in NFTs owned by them /// @param _index A counter less than `balanceOf(_owner)` /// @return The token identifier for the `_index`th NFT assigned to `_owner`, /// (sort order not specified) function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256 _tokenId); } interface ERC721Metadata /* is ERC721 */ { /// @notice A descriptive name for a collection of NFTs in this contract function name() external pure returns (string _name); /// @notice An abbreviated name for NFTs in this contract function symbol() external pure returns (string _symbol); /// @notice A distinct Uniform Resource Identifier (URI) for a given asset. /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC /// 3986. The URI may point to a JSON file that conforms to the "ERC721 /// Metadata JSON Schema". function tokenURI(uint256 _tokenId) external view returns (string); } contract Ownable { address public owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function Ownable() public { owner = msg.sender; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner); _; } /** * @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 { require(_newOwner != address(0)); OwnershipTransferred(owner, _newOwner); owner = _newOwner; } } interface ERC721TokenReceiver { /// @notice Handle the receipt of an NFT /// @dev The ERC721 smart contract calls this function on the recipient /// after a `transfer`. This function MAY throw to revert and reject the /// transfer. This function MUST use 50,000 gas or less. Return of other /// than the magic value MUST result in the transaction being reverted. /// Note: the contract address is always the message sender. /// @param _from The sending address /// @param _tokenId The NFT identifier which is being transfered /// @param _data Additional data with no specified format /// @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))` /// unless throwing function onERC721Received(address _from, uint256 _tokenId, bytes _data) external returns(bytes4); } library Math { function max64(uint64 a, uint64 b) internal pure returns (uint64) { return a >= b ? a : b; } function min64(uint64 a, uint64 b) internal pure returns (uint64) { return a < b ? a : b; } function max256(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } function min256(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } } contract LicenseAccessControl { /** * @notice ContractUpgrade is the event that will be emitted if we set a new contract address */ event ContractUpgrade(address newContract); event Paused(); event Unpaused(); /** * @notice CEO's address FOOBAR */ address public ceoAddress; /** * @notice CFO's address */ address public cfoAddress; /** * @notice COO's address */ address public cooAddress; /** * @notice withdrawal address */ address public withdrawalAddress; bool public paused = false; /** * @dev Modifier to make a function only callable by the CEO */ modifier onlyCEO() { require(msg.sender == ceoAddress); _; } /** * @dev Modifier to make a function only callable by the CFO */ modifier onlyCFO() { require(msg.sender == cfoAddress); _; } /** * @dev Modifier to make a function only callable by the COO */ modifier onlyCOO() { require(msg.sender == cooAddress); _; } /** * @dev Modifier to make a function only callable by C-level execs */ modifier onlyCLevel() { require( msg.sender == cooAddress || msg.sender == ceoAddress || msg.sender == cfoAddress ); _; } /** * @dev Modifier to make a function only callable by CEO or CFO */ modifier onlyCEOOrCFO() { require( msg.sender == cfoAddress || msg.sender == ceoAddress ); _; } /** * @dev Modifier to make a function only callable by CEO or COO */ modifier onlyCEOOrCOO() { require( msg.sender == cooAddress || msg.sender == ceoAddress ); _; } /** * @notice Sets a new CEO * @param _newCEO - the address of the new CEO */ function setCEO(address _newCEO) external onlyCEO { require(_newCEO != address(0)); ceoAddress = _newCEO; } /** * @notice Sets a new CFO * @param _newCFO - the address of the new CFO */ function setCFO(address _newCFO) external onlyCEO { require(_newCFO != address(0)); cfoAddress = _newCFO; } /** * @notice Sets a new COO * @param _newCOO - the address of the new COO */ function setCOO(address _newCOO) external onlyCEO { require(_newCOO != address(0)); cooAddress = _newCOO; } /** * @notice Sets a new withdrawalAddress * @param _newWithdrawalAddress - the address where we'll send the funds */ function setWithdrawalAddress(address _newWithdrawalAddress) external onlyCEO { require(_newWithdrawalAddress != address(0)); withdrawalAddress = _newWithdrawalAddress; } /** * @notice Withdraw the balance to the withdrawalAddress * @dev We set a withdrawal address seperate from the CFO because this allows us to withdraw to a cold wallet. */ function withdrawBalance() external onlyCEOOrCFO { require(withdrawalAddress != address(0)); withdrawalAddress.transfer(this.balance); } /** Pausable functionality adapted from OpenZeppelin **/ /** * @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); _; } /** * @notice called by any C-level to pause, triggers stopped state */ function pause() public onlyCLevel whenNotPaused { paused = true; Paused(); } /** * @notice called by the CEO to unpause, returns to normal state */ function unpause() public onlyCEO whenPaused { paused = false; Unpaused(); } } contract LicenseBase is LicenseAccessControl { /** * @notice Issued is emitted when a new license is issued */ event LicenseIssued( address indexed owner, address indexed purchaser, uint256 licenseId, uint256 productId, uint256 attributes, uint256 issuedTime, uint256 expirationTime, address affiliate ); event LicenseRenewal( address indexed owner, address indexed purchaser, uint256 licenseId, uint256 productId, uint256 expirationTime ); struct License { uint256 productId; uint256 attributes; uint256 issuedTime; uint256 expirationTime; address affiliate; } /** * @notice All licenses in existence. * @dev The ID of each license is an index in this array. */ License[] licenses; /** internal **/ function _isValidLicense(uint256 _licenseId) internal view returns (bool) { return licenseProductId(_licenseId) != 0; } /** anyone **/ /** * @notice Get a license's productId * @param _licenseId the license id */ function licenseProductId(uint256 _licenseId) public view returns (uint256) { return licenses[_licenseId].productId; } /** * @notice Get a license's attributes * @param _licenseId the license id */ function licenseAttributes(uint256 _licenseId) public view returns (uint256) { return licenses[_licenseId].attributes; } /** * @notice Get a license's issueTime * @param _licenseId the license id */ function licenseIssuedTime(uint256 _licenseId) public view returns (uint256) { return licenses[_licenseId].issuedTime; } /** * @notice Get a license's issueTime * @param _licenseId the license id */ function licenseExpirationTime(uint256 _licenseId) public view returns (uint256) { return licenses[_licenseId].expirationTime; } /** * @notice Get a the affiliate credited for the sale of this license * @param _licenseId the license id */ function licenseAffiliate(uint256 _licenseId) public view returns (address) { return licenses[_licenseId].affiliate; } /** * @notice Get a license's info * @param _licenseId the license id */ function licenseInfo(uint256 _licenseId) public view returns (uint256, uint256, uint256, uint256, address) { return ( licenseProductId(_licenseId), licenseAttributes(_licenseId), licenseIssuedTime(_licenseId), licenseExpirationTime(_licenseId), licenseAffiliate(_licenseId) ); } } contract Pausable is Ownable { event Pause(); event Unpause(); bool public paused = false; /** * @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() onlyOwner whenNotPaused public { paused = true; Pause(); } /** * @dev called by the owner to unpause, returns to normal state */ function unpause() onlyOwner whenPaused public { paused = false; Unpause(); } } contract AffiliateProgram is Pausable { using SafeMath for uint256; event AffiliateCredit( // The address of the affiliate address affiliate, // The store's ID of what was sold (e.g. a tokenId) uint256 productId, // The amount owed this affiliate in this sale uint256 amount ); event Withdraw(address affiliate, address to, uint256 amount); event Whitelisted(address affiliate, uint256 amount); event RateChanged(uint256 rate, uint256 amount); // @notice A mapping from affiliate address to their balance mapping (address => uint256) public balances; // @notice A mapping from affiliate address to the time of last deposit mapping (address => uint256) public lastDepositTimes; // @notice The last deposit globally uint256 public lastDepositTime; // @notice The maximum rate for any affiliate // @dev The hard-coded maximum affiliate rate (in basis points) // All rates are measured in basis points (1/100 of a percent) // Values 0-10,000 map to 0%-100% uint256 private constant hardCodedMaximumRate = 5000; // @notice The commission exiration time // @dev Affiliate commissions expire if they are unclaimed after this amount of time uint256 private constant commissionExpiryTime = 30 days; // @notice The baseline affiliate rate (in basis points) for non-whitelisted referrals uint256 public baselineRate = 0; // @notice A mapping from whitelisted referrals to their individual rates mapping (address => uint256) public whitelistRates; // @notice The maximum rate for any affiliate // @dev overrides individual rates. This can be used to clip the rate used in bulk, if necessary uint256 public maximumRate = 5000; // @notice The address of the store selling products address public storeAddress; // @notice The contract is retired // @dev If we decide to retire this program, this value will be set to true // and then the contract cannot be unpaused bool public retired = false; /** * @dev Modifier to make a function only callable by the store or the owner */ modifier onlyStoreOrOwner() { require( msg.sender == storeAddress || msg.sender == owner); _; } /** * @dev AffiliateProgram constructor - keeps the address of it's parent store * and pauses the contract */ function AffiliateProgram(address _storeAddress) public { require(_storeAddress != address(0)); storeAddress = _storeAddress; paused = true; } /** * @notice Exposes that this contract thinks it is an AffiliateProgram */ function isAffiliateProgram() public pure returns (bool) { return true; } /** * @notice returns the commission rate for a sale * * @dev rateFor returns the rate which should be used to calculate the comission * for this affiliate/sale combination, in basis points (1/100th of a percent). * * We may want to completely blacklist a particular address (e.g. a known bad actor affilite). * To that end, if the whitelistRate is exactly 1bp, we use that as a signal for blacklisting * and return a rate of zero. The upside is that we can completely turn off * sending transactions to a particular address when this is needed. The * downside is that you can't issued 1/100th of a percent commission. * However, since this is such a small amount its an acceptable tradeoff. * * This implementation does not use the _productId, _pruchaseId, * _purchaseAmount, but we include them here as part of the protocol, because * they could be useful in more advanced affiliate programs. * * @param _affiliate - the address of the affiliate to check for */ function rateFor( address _affiliate, uint256 /*_productId*/, uint256 /*_purchaseId*/, uint256 /*_purchaseAmount*/) public view returns (uint256) { uint256 whitelistedRate = whitelistRates[_affiliate]; if(whitelistedRate > 0) { // use 1 bp as a blacklist signal if(whitelistedRate == 1) { return 0; } else { return Math.min256(whitelistedRate, maximumRate); } } else { return Math.min256(baselineRate, maximumRate); } } /** * @notice cutFor returns the affiliate cut for a sale * @dev cutFor returns the cut (amount in wei) to give in comission to the affiliate * * @param _affiliate - the address of the affiliate to check for * @param _productId - the productId in the sale * @param _purchaseId - the purchaseId in the sale * @param _purchaseAmount - the purchaseAmount */ function cutFor( address _affiliate, uint256 _productId, uint256 _purchaseId, uint256 _purchaseAmount) public view returns (uint256) { uint256 rate = rateFor( _affiliate, _productId, _purchaseId, _purchaseAmount); require(rate <= hardCodedMaximumRate); return (_purchaseAmount.mul(rate)).div(10000); } /** * @notice credit an affiliate for a purchase * @dev credit accepts eth and credits the affiliate's balance for the amount * * @param _affiliate - the address of the affiliate to credit * @param _purchaseId - the purchaseId of the sale */ function credit( address _affiliate, uint256 _purchaseId) public onlyStoreOrOwner whenNotPaused payable { require(msg.value > 0); require(_affiliate != address(0)); balances[_affiliate] += msg.value; lastDepositTimes[_affiliate] = now; // solium-disable-line security/no-block-members lastDepositTime = now; // solium-disable-line security/no-block-members AffiliateCredit(_affiliate, _purchaseId, msg.value); } /** * @dev _performWithdraw performs a withdrawal from address _from and * transfers it to _to. This can be different because we allow the owner * to withdraw unclaimed funds after a period of time. * * @param _from - the address to subtract balance from * @param _to - the address to transfer ETH to */ function _performWithdraw(address _from, address _to) private { require(balances[_from] > 0); uint256 balanceValue = balances[_from]; balances[_from] = 0; _to.transfer(balanceValue); Withdraw(_from, _to, balanceValue); } /** * @notice withdraw * @dev withdraw the msg.sender's balance */ function withdraw() public whenNotPaused { _performWithdraw(msg.sender, msg.sender); } /** * @notice withdraw from a specific account * @dev withdrawFrom allows the owner to withdraw an affiliate's unclaimed * ETH, after the alotted time. * * This function can be called even if the contract is paused * * @param _affiliate - the address of the affiliate * @param _to - the address to send ETH to */ function withdrawFrom(address _affiliate, address _to) onlyOwner public { // solium-disable-next-line security/no-block-members require(now > lastDepositTimes[_affiliate].add(commissionExpiryTime)); _performWithdraw(_affiliate, _to); } /** * @notice retire the contract (dangerous) * @dev retire - withdraws the entire balance and marks the contract as retired, which * prevents unpausing. * * If no new comissions have been deposited for the alotted time, * then the owner may pause the program and retire this contract. * This may only be performed once as the contract cannot be unpaused. * * We do this as an alternative to selfdestruct, because certain operations * can still be performed after the contract has been selfdestructed, such as * the owner withdrawing ETH accidentally sent here. */ function retire(address _to) onlyOwner whenPaused public { // solium-disable-next-line security/no-block-members require(now > lastDepositTime.add(commissionExpiryTime)); _to.transfer(this.balance); retired = true; } /** * @notice whitelist an affiliate address * @dev whitelist - white listed affiliates can receive a different * rate than the general public (whitelisted accounts would generally get a * better rate). * @param _affiliate - the affiliate address to whitelist * @param _rate - the rate, in basis-points (1/100th of a percent) to give this affiliate in each sale. NOTE: a rate of exactly 1 is the signal to blacklist this affiliate. That is, a rate of 1 will set the commission to 0. */ function whitelist(address _affiliate, uint256 _rate) onlyOwner public { require(_rate <= hardCodedMaximumRate); whitelistRates[_affiliate] = _rate; Whitelisted(_affiliate, _rate); } /** * @notice set the rate for non-whitelisted affiliates * @dev setBaselineRate - sets the baseline rate for any affiliate that is not whitelisted * @param _newRate - the rate, in bp (1/100th of a percent) to give any non-whitelisted affiliate. Set to zero to "turn off" */ function setBaselineRate(uint256 _newRate) onlyOwner public { require(_newRate <= hardCodedMaximumRate); baselineRate = _newRate; RateChanged(0, _newRate); } /** * @notice set the maximum rate for any affiliate * @dev setMaximumRate - Set the maximum rate for any affiliate, including whitelists. That is, this overrides individual rates. * @param _newRate - the rate, in bp (1/100th of a percent) */ function setMaximumRate(uint256 _newRate) onlyOwner public { require(_newRate <= hardCodedMaximumRate); maximumRate = _newRate; RateChanged(1, _newRate); } /** * @notice unpause the contract * @dev called by the owner to unpause, returns to normal state. Will not * unpause if the contract is retired. */ function unpause() onlyOwner whenPaused public { require(!retired); paused = false; Unpause(); } } contract ERC721 { event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); function balanceOf(address _owner) public view returns (uint256 _balance); function ownerOf(uint256 _tokenId) public view returns (address _owner); function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) public; function safeTransferFrom(address _from, address _to, uint256 _tokenId) external; function transfer(address _to, uint256 _tokenId) external; function transferFrom(address _from, address _to, uint256 _tokenId) public; function approve(address _to, uint256 _tokenId) external; function setApprovalForAll(address _to, bool _approved) external; function getApproved(uint256 _tokenId) public view returns (address); function isApprovedForAll(address _owner, address _operator) public view returns (bool); } contract LicenseInventory is LicenseBase { using SafeMath for uint256; event ProductCreated( uint256 id, uint256 price, uint256 available, uint256 supply, uint256 interval, bool renewable ); event ProductInventoryAdjusted(uint256 productId, uint256 available); event ProductPriceChanged(uint256 productId, uint256 price); event ProductRenewableChanged(uint256 productId, bool renewable); /** * @notice Product defines a product * * renewable: There may come a time when we which to disable the ability to renew a subscription. For example, a plan we no longer wish to support. Obviously care needs to be taken with how we communicate this to customers, but contract-wise, we want to support the ability to discontinue renewal of certain plans. */ struct Product { uint256 id; uint256 price; uint256 available; uint256 supply; uint256 sold; uint256 interval; bool renewable; } // @notice All products in existence uint256[] public allProductIds; // @notice A mapping from product ids to Products mapping (uint256 => Product) public products; /*** internal ***/ /** * @notice _productExists checks to see if a product exists */ function _productExists(uint256 _productId) internal view returns (bool) { return products[_productId].id != 0; } function _productDoesNotExist(uint256 _productId) internal view returns (bool) { return products[_productId].id == 0; } function _createProduct( uint256 _productId, uint256 _initialPrice, uint256 _initialInventoryQuantity, uint256 _supply, uint256 _interval) internal { require(_productDoesNotExist(_productId)); require(_initialInventoryQuantity <= _supply); Product memory _product = Product({ id: _productId, price: _initialPrice, available: _initialInventoryQuantity, supply: _supply, sold: 0, interval: _interval, renewable: _interval == 0 ? false : true }); products[_productId] = _product; allProductIds.push(_productId); ProductCreated( _product.id, _product.price, _product.available, _product.supply, _product.interval, _product.renewable ); } function _incrementInventory( uint256 _productId, uint256 _inventoryAdjustment) internal { require(_productExists(_productId)); uint256 newInventoryLevel = products[_productId].available.add(_inventoryAdjustment); // A supply of "0" means "unlimited". Otherwise we need to ensure that we're not over-creating this product if(products[_productId].supply > 0) { // you have to take already sold into account require(products[_productId].sold.add(newInventoryLevel) <= products[_productId].supply); } products[_productId].available = newInventoryLevel; } function _decrementInventory( uint256 _productId, uint256 _inventoryAdjustment) internal { require(_productExists(_productId)); uint256 newInventoryLevel = products[_productId].available.sub(_inventoryAdjustment); // unnecessary because we're using SafeMath and an unsigned int // require(newInventoryLevel >= 0); products[_productId].available = newInventoryLevel; } function _clearInventory(uint256 _productId) internal { require(_productExists(_productId)); products[_productId].available = 0; } function _setPrice(uint256 _productId, uint256 _price) internal { require(_productExists(_productId)); products[_productId].price = _price; } function _setRenewable(uint256 _productId, bool _isRenewable) internal { require(_productExists(_productId)); products[_productId].renewable = _isRenewable; } function _purchaseOneUnitInStock(uint256 _productId) internal { require(_productExists(_productId)); require(availableInventoryOf(_productId) > 0); // lower inventory _decrementInventory(_productId, 1); // record that one was sold products[_productId].sold = products[_productId].sold.add(1); } function _requireRenewableProduct(uint256 _productId) internal view { // productId must exist require(_productId != 0); // You can only renew a subscription product require(isSubscriptionProduct(_productId)); // The product must currently be renewable require(renewableOf(_productId)); } /*** public ***/ /** executives-only **/ /** * @notice createProduct creates a new product in the system * @param _productId - the id of the product to use (cannot be changed) * @param _initialPrice - the starting price (price can be changed) * @param _initialInventoryQuantity - the initial inventory (inventory can be changed) * @param _supply - the total supply - use `0` for "unlimited" (cannot be changed) */ function createProduct( uint256 _productId, uint256 _initialPrice, uint256 _initialInventoryQuantity, uint256 _supply, uint256 _interval) external onlyCEOOrCOO { _createProduct( _productId, _initialPrice, _initialInventoryQuantity, _supply, _interval); } /** * @notice incrementInventory - increments the inventory of a product * @param _productId - the product id * @param _inventoryAdjustment - the amount to increment */ function incrementInventory( uint256 _productId, uint256 _inventoryAdjustment) external onlyCLevel { _incrementInventory(_productId, _inventoryAdjustment); ProductInventoryAdjusted(_productId, availableInventoryOf(_productId)); } /** * @notice decrementInventory removes inventory levels for a product * @param _productId - the product id * @param _inventoryAdjustment - the amount to decrement */ function decrementInventory( uint256 _productId, uint256 _inventoryAdjustment) external onlyCLevel { _decrementInventory(_productId, _inventoryAdjustment); ProductInventoryAdjusted(_productId, availableInventoryOf(_productId)); } /** * @notice clearInventory clears the inventory of a product. * @dev decrementInventory verifies inventory levels, whereas this method * simply sets the inventory to zero. This is useful, for example, if an * executive wants to take a product off the market quickly. There could be a * race condition with decrementInventory where a product is sold, which could * cause the admins decrement to fail (because it may try to decrement more * than available). * * @param _productId - the product id */ function clearInventory(uint256 _productId) external onlyCLevel { _clearInventory(_productId); ProductInventoryAdjusted(_productId, availableInventoryOf(_productId)); } /** * @notice setPrice - sets the price of a product * @param _productId - the product id * @param _price - the product price */ function setPrice(uint256 _productId, uint256 _price) external onlyCLevel { _setPrice(_productId, _price); ProductPriceChanged(_productId, _price); } /** * @notice setRenewable - sets if a product is renewable * @param _productId - the product id * @param _newRenewable - the new renewable setting */ function setRenewable(uint256 _productId, bool _newRenewable) external onlyCLevel { _setRenewable(_productId, _newRenewable); ProductRenewableChanged(_productId, _newRenewable); } /** anyone **/ /** * @notice The price of a product * @param _productId - the product id */ function priceOf(uint256 _productId) public view returns (uint256) { return products[_productId].price; } /** * @notice The available inventory of a product * @param _productId - the product id */ function availableInventoryOf(uint256 _productId) public view returns (uint256) { return products[_productId].available; } /** * @notice The total supply of a product * @param _productId - the product id */ function totalSupplyOf(uint256 _productId) public view returns (uint256) { return products[_productId].supply; } /** * @notice The total sold of a product * @param _productId - the product id */ function totalSold(uint256 _productId) public view returns (uint256) { return products[_productId].sold; } /** * @notice The renewal interval of a product in seconds * @param _productId - the product id */ function intervalOf(uint256 _productId) public view returns (uint256) { return products[_productId].interval; } /** * @notice Is this product renewable? * @param _productId - the product id */ function renewableOf(uint256 _productId) public view returns (bool) { return products[_productId].renewable; } /** * @notice The product info for a product * @param _productId - the product id */ function productInfo(uint256 _productId) public view returns (uint256, uint256, uint256, uint256, bool) { return ( priceOf(_productId), availableInventoryOf(_productId), totalSupplyOf(_productId), intervalOf(_productId), renewableOf(_productId)); } /** * @notice Get all product ids */ function getAllProductIds() public view returns (uint256[]) { return allProductIds; } /** * @notice returns the total cost to renew a product for a number of cycles * @dev If a product is a subscription, the interval defines the period of * time, in seconds, users can subscribe for. E.g. 1 month or 1 year. * _numCycles is the number of these intervals we want to use in the * calculation of the price. * * We require that the end user send precisely the amount required (instead * of dealing with excess refunds). This method is public so that clients can * read the exact amount our contract expects to receive. * * @param _productId - the product we're calculating for * @param _numCycles - the number of cycles to calculate for */ function costForProductCycles(uint256 _productId, uint256 _numCycles) public view returns (uint256) { return priceOf(_productId).mul(_numCycles); } /** * @notice returns if this product is a subscription or not * @dev Some products are subscriptions and others are not. An interval of 0 * means the product is not a subscription * @param _productId - the product we're checking */ function isSubscriptionProduct(uint256 _productId) public view returns (bool) { return intervalOf(_productId) > 0; } } library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; assert(c / a == b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws 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 Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a - b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } } interface ERC165 { /// @notice Query if a contract implements an interface /// @param interfaceID The interface identifier, as specified in ERC-165 /// @dev Interface identification is specified in ERC-165. This function /// uses less than 30,000 gas. /// @return `true` if the contract implements `interfaceID` and /// `interfaceID` is not 0xffffffff, `false` otherwise function supportsInterface(bytes4 interfaceID) external view returns (bool); } contract LicenseOwnership is LicenseInventory, ERC721, ERC165, ERC721Metadata, ERC721Enumerable { using SafeMath for uint256; // Total amount of tokens uint256 private totalTokens; // Mapping from token ID to owner mapping (uint256 => address) private tokenOwner; // Mapping from token ID to approved address mapping (uint256 => address) private tokenApprovals; // Mapping from owner address to operator address to approval mapping (address => mapping (address => bool)) private operatorApprovals; // Mapping from owner to list of owned token IDs mapping (address => uint256[]) private ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private ownedTokensIndex; /*** Constants ***/ // Configure these for your own deployment string public constant NAME = "Dottabot"; string public constant SYMBOL = "DOTTA"; string public tokenMetadataBaseURI = "https://api.dottabot.com/"; /** * @notice token's name */ function name() external pure returns (string) { return NAME; } /** * @notice symbols's name */ function symbol() external pure returns (string) { return SYMBOL; } function implementsERC721() external pure returns (bool) { return true; } function tokenURI(uint256 _tokenId) external view returns (string infoUrl) { return Strings.strConcat( tokenMetadataBaseURI, Strings.uint2str(_tokenId)); } function supportsInterface( bytes4 interfaceID) // solium-disable-line dotta/underscore-function-arguments external view returns (bool) { return interfaceID == this.supportsInterface.selector || // ERC165 interfaceID == 0x5b5e139f || // ERC721Metadata interfaceID == 0x6466353c || // ERC-721 on 3/7/2018 interfaceID == 0x780e9d63; // ERC721Enumerable } function setTokenMetadataBaseURI(string _newBaseURI) external onlyCEOOrCOO { tokenMetadataBaseURI = _newBaseURI; } /** * @notice Guarantees msg.sender is owner of the given token * @param _tokenId uint256 ID of the token to validate its ownership belongs to msg.sender */ modifier onlyOwnerOf(uint256 _tokenId) { require(ownerOf(_tokenId) == msg.sender); _; } /** * @notice Gets the total amount of tokens stored by the contract * @return uint256 representing the total amount of tokens */ function totalSupply() public view returns (uint256) { return totalTokens; } /** * @notice Enumerate valid NFTs * @dev Our Licenses are kept in an array and each new License-token is just * the next element in the array. This method is required for ERC721Enumerable * which may support more complicated storage schemes. However, in our case the * _index is the tokenId * @param _index A counter less than `totalSupply()` * @return The token identifier for the `_index`th NFT */ function tokenByIndex(uint256 _index) external view returns (uint256) { require(_index < totalSupply()); return _index; } /** * @notice Gets the balance of the specified address * @param _owner address to query the balance of * @return uint256 representing the amount owned by the passed address */ function balanceOf(address _owner) public view returns (uint256) { require(_owner != address(0)); return ownedTokens[_owner].length; } /** * @notice Gets the list of tokens owned by a given address * @param _owner address to query the tokens of * @return uint256[] representing the list of tokens owned by the passed address */ function tokensOf(address _owner) public view returns (uint256[]) { return ownedTokens[_owner]; } /** * @notice Enumerate NFTs assigned to an owner * @dev Throws if `_index` >= `balanceOf(_owner)` or if * `_owner` is the zero address, representing invalid NFTs. * @param _owner An address where we are interested in NFTs owned by them * @param _index A counter less than `balanceOf(_owner)` * @return The token identifier for the `_index`th NFT assigned to `_owner`, */ function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256 _tokenId) { require(_index < balanceOf(_owner)); return ownedTokens[_owner][_index]; } /** * @notice Gets the owner of the specified token ID * @param _tokenId uint256 ID of the token to query the owner of * @return owner address currently marked as the owner of the given token ID */ function ownerOf(uint256 _tokenId) public view returns (address) { address owner = tokenOwner[_tokenId]; require(owner != address(0)); return owner; } /** * @notice Gets the approved address to take ownership of a given token ID * @param _tokenId uint256 ID of the token to query the approval of * @return address currently approved to take ownership of the given token ID */ function getApproved(uint256 _tokenId) public view returns (address) { return tokenApprovals[_tokenId]; } /** * @notice Tells whether the msg.sender is approved to transfer the given token ID or not * Checks both for specific approval and operator approval * @param _tokenId uint256 ID of the token to query the approval of * @return bool whether transfer by msg.sender is approved for the given token ID or not */ function isSenderApprovedFor(uint256 _tokenId) internal view returns (bool) { return ownerOf(_tokenId) == msg.sender || isSpecificallyApprovedFor(msg.sender, _tokenId) || isApprovedForAll(ownerOf(_tokenId), msg.sender); } /** * @notice Tells whether the msg.sender is approved for the given token ID or not * @param _asker address of asking for approval * @param _tokenId uint256 ID of the token to query the approval of * @return bool whether the msg.sender is approved for the given token ID or not */ function isSpecificallyApprovedFor(address _asker, uint256 _tokenId) internal view returns (bool) { return getApproved(_tokenId) == _asker; } /** * @notice Tells whether an operator is approved by a given owner * @param _owner owner address which you want to query the approval of * @param _operator operator address which you want to query the approval of * @return bool whether the given operator is approved by the given owner */ function isApprovedForAll(address _owner, address _operator) public view returns (bool) { return operatorApprovals[_owner][_operator]; } /** * @notice Transfers the ownership of a given token ID to another address * @param _to address to receive the ownership of the given token ID * @param _tokenId uint256 ID of the token to be transferred */ function transfer(address _to, uint256 _tokenId) external whenNotPaused onlyOwnerOf(_tokenId) { _clearApprovalAndTransfer(msg.sender, _to, _tokenId); } /** * @notice Approves another address to claim for the ownership of the given token ID * @param _to address to be approved for the given token ID * @param _tokenId uint256 ID of the token to be approved */ function approve(address _to, uint256 _tokenId) external whenNotPaused onlyOwnerOf(_tokenId) { address owner = ownerOf(_tokenId); require(_to != owner); if (getApproved(_tokenId) != 0 || _to != 0) { tokenApprovals[_tokenId] = _to; Approval(owner, _to, _tokenId); } } /** * @notice Enable or disable approval for a third party ("operator") to manage all your assets * @dev Emits the ApprovalForAll event * @param _to Address to add to the set of authorized operators. * @param _approved True if the operators is approved, false to revoke approval */ function setApprovalForAll(address _to, bool _approved) external whenNotPaused { if(_approved) { approveAll(_to); } else { disapproveAll(_to); } } /** * @notice Approves another address to claim for the ownership of any tokens owned by this account * @param _to address to be approved for the given token ID */ function approveAll(address _to) public whenNotPaused { require(_to != msg.sender); require(_to != address(0)); operatorApprovals[msg.sender][_to] = true; ApprovalForAll(msg.sender, _to, true); } /** * @notice Removes approval for another address to claim for the ownership of any * tokens owned by this account. * @dev Note that this only removes the operator approval and * does not clear any independent, specific approvals of token transfers to this address * @param _to address to be disapproved for the given token ID */ function disapproveAll(address _to) public whenNotPaused { require(_to != msg.sender); delete operatorApprovals[msg.sender][_to]; ApprovalForAll(msg.sender, _to, false); } /** * @notice Claims the ownership of a given token ID * @param _tokenId uint256 ID of the token being claimed by the msg.sender */ function takeOwnership(uint256 _tokenId) external whenNotPaused { require(isSenderApprovedFor(_tokenId)); _clearApprovalAndTransfer(ownerOf(_tokenId), msg.sender, _tokenId); } /** * @notice Transfer a token owned by another address, for which the calling address has * previously been granted transfer approval by the owner. * @param _from The address that owns the token * @param _to The address that will take ownership of the token. Can be any address, including the caller * @param _tokenId The ID of the token to be transferred */ function transferFrom( address _from, address _to, uint256 _tokenId ) public whenNotPaused { require(isSenderApprovedFor(_tokenId)); require(ownerOf(_tokenId) == _from); _clearApprovalAndTransfer(ownerOf(_tokenId), _to, _tokenId); } /** * @notice Transfers the ownership of an NFT from one address to another address * @dev Throws unless `msg.sender` is the current owner, an authorized * operator, or the approved address for this NFT. Throws if `_from` is * not the current owner. Throws if `_to` is the zero address. Throws if * `_tokenId` is not a valid NFT. When transfer is complete, this function * checks if `_to` is a smart contract (code size > 0). If so, it calls * `onERC721Received` on `_to` and throws if the return value is not * `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`. * @param _from The current owner of the NFT * @param _to The new owner * @param _tokenId The NFT to transfer * @param _data Additional data with no specified format, sent in call to `_to` */ function safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes _data ) public whenNotPaused { require(_to != address(0)); require(_isValidLicense(_tokenId)); transferFrom(_from, _to, _tokenId); if (_isContract(_to)) { bytes4 tokenReceiverResponse = ERC721TokenReceiver(_to).onERC721Received.gas(50000)( _from, _tokenId, _data ); require(tokenReceiverResponse == bytes4(keccak256("onERC721Received(address,uint256,bytes)"))); } } /* * @notice Transfers the ownership of an NFT from one address to another address * @dev This works identically to the other function with an extra data parameter, * except this function just sets data to "" * @param _from The current owner of the NFT * @param _to The new owner * @param _tokenId The NFT to transfer */ function safeTransferFrom( address _from, address _to, uint256 _tokenId ) external whenNotPaused { safeTransferFrom(_from, _to, _tokenId, ""); } /** * @notice Mint token function * @param _to The address that will own the minted token * @param _tokenId uint256 ID of the token to be minted by the msg.sender */ function _mint(address _to, uint256 _tokenId) internal { require(_to != address(0)); _addToken(_to, _tokenId); Transfer(0x0, _to, _tokenId); } /** * @notice Internal function to clear current approval and transfer the ownership of a given token ID * @param _from address which you want to send tokens from * @param _to address which you want to transfer the token to * @param _tokenId uint256 ID of the token to be transferred */ function _clearApprovalAndTransfer(address _from, address _to, uint256 _tokenId) internal { require(_to != address(0)); require(_to != ownerOf(_tokenId)); require(ownerOf(_tokenId) == _from); require(_isValidLicense(_tokenId)); _clearApproval(_from, _tokenId); _removeToken(_from, _tokenId); _addToken(_to, _tokenId); Transfer(_from, _to, _tokenId); } /** * @notice Internal function to clear current approval of a given token ID * @param _tokenId uint256 ID of the token to be transferred */ function _clearApproval(address _owner, uint256 _tokenId) private { require(ownerOf(_tokenId) == _owner); tokenApprovals[_tokenId] = 0; Approval(_owner, 0, _tokenId); } /** * @notice Internal function to add a token ID to the list of a given address * @param _to address representing the new owner of the given token ID * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address */ function _addToken(address _to, uint256 _tokenId) private { require(tokenOwner[_tokenId] == address(0)); tokenOwner[_tokenId] = _to; uint256 length = balanceOf(_to); ownedTokens[_to].push(_tokenId); ownedTokensIndex[_tokenId] = length; totalTokens = totalTokens.add(1); } /** * @notice Internal function to remove a token ID from the list of a given address * @param _from address representing the previous owner of the given token ID * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address */ function _removeToken(address _from, uint256 _tokenId) private { require(ownerOf(_tokenId) == _from); uint256 tokenIndex = ownedTokensIndex[_tokenId]; uint256 lastTokenIndex = balanceOf(_from).sub(1); uint256 lastToken = ownedTokens[_from][lastTokenIndex]; tokenOwner[_tokenId] = 0; ownedTokens[_from][tokenIndex] = lastToken; ownedTokens[_from][lastTokenIndex] = 0; // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to // be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping // the lastToken to the first position, and then dropping the element placed in the last position of the list ownedTokens[_from].length--; ownedTokensIndex[_tokenId] = 0; ownedTokensIndex[lastToken] = tokenIndex; totalTokens = totalTokens.sub(1); } function _isContract(address addr) internal view returns (bool) { uint size; assembly { size := extcodesize(addr) } return size > 0; } } contract LicenseSale is LicenseOwnership { AffiliateProgram public affiliateProgram; /** * @notice We credit affiliates for renewals that occur within this time of * original purchase. E.g. If this is set to 1 year, and someone subscribes to * a monthly plan, the affiliate will receive credits for that whole year, as * the user renews their plan */ uint256 public renewalsCreditAffiliatesFor = 1 years; /** internal **/ function _performPurchase( uint256 _productId, uint256 _numCycles, address _assignee, uint256 _attributes, address _affiliate) internal returns (uint) { _purchaseOneUnitInStock(_productId); return _createLicense( _productId, _numCycles, _assignee, _attributes, _affiliate ); } function _createLicense( uint256 _productId, uint256 _numCycles, address _assignee, uint256 _attributes, address _affiliate) internal returns (uint) { // You cannot create a subscription license with zero cycles if(isSubscriptionProduct(_productId)) { require(_numCycles != 0); } // Non-subscription products have an expiration time of 0, meaning "no-expiration" uint256 expirationTime = isSubscriptionProduct(_productId) ? now.add(intervalOf(_productId).mul(_numCycles)) : // solium-disable-line security/no-block-members 0; License memory _license = License({ productId: _productId, attributes: _attributes, issuedTime: now, // solium-disable-line security/no-block-members expirationTime: expirationTime, affiliate: _affiliate }); uint256 newLicenseId = licenses.push(_license) - 1; // solium-disable-line zeppelin/no-arithmetic-operations LicenseIssued( _assignee, msg.sender, newLicenseId, _license.productId, _license.attributes, _license.issuedTime, _license.expirationTime, _license.affiliate); _mint(_assignee, newLicenseId); return newLicenseId; } function _handleAffiliate( address _affiliate, uint256 _productId, uint256 _licenseId, uint256 _purchaseAmount) internal { uint256 affiliateCut = affiliateProgram.cutFor( _affiliate, _productId, _licenseId, _purchaseAmount); if(affiliateCut > 0) { require(affiliateCut < _purchaseAmount); affiliateProgram.credit.value(affiliateCut)(_affiliate, _licenseId); } } function _performRenewal(uint256 _tokenId, uint256 _numCycles) internal { // You cannot renew a non-expiring license // ... but in what scenario can this happen? // require(licenses[_tokenId].expirationTime != 0); uint256 productId = licenseProductId(_tokenId); // If our expiration is in the future, renewing adds time to that future expiration // If our expiration has passed already, then we use `now` as the base. uint256 renewalBaseTime = Math.max256(now, licenses[_tokenId].expirationTime); // We assume that the payment has been validated outside of this function uint256 newExpirationTime = renewalBaseTime.add(intervalOf(productId).mul(_numCycles)); licenses[_tokenId].expirationTime = newExpirationTime; LicenseRenewal( ownerOf(_tokenId), msg.sender, _tokenId, productId, newExpirationTime ); } function _affiliateProgramIsActive() internal view returns (bool) { return affiliateProgram != address(0) && affiliateProgram.storeAddress() == address(this) && !affiliateProgram.paused(); } /** executives **/ function setAffiliateProgramAddress(address _address) external onlyCEO { AffiliateProgram candidateContract = AffiliateProgram(_address); require(candidateContract.isAffiliateProgram()); affiliateProgram = candidateContract; } function setRenewalsCreditAffiliatesFor(uint256 _newTime) external onlyCEO { renewalsCreditAffiliatesFor = _newTime; } function createPromotionalPurchase( uint256 _productId, uint256 _numCycles, address _assignee, uint256 _attributes ) external onlyCEOOrCOO whenNotPaused returns (uint256) { return _performPurchase( _productId, _numCycles, _assignee, _attributes, address(0)); } function createPromotionalRenewal( uint256 _tokenId, uint256 _numCycles ) external onlyCEOOrCOO whenNotPaused { uint256 productId = licenseProductId(_tokenId); _requireRenewableProduct(productId); return _performRenewal(_tokenId, _numCycles); } /** anyone **/ /** * @notice Makes a purchase of a product. * @dev Requires that the value sent is exactly the price of the product * @param _productId - the product to purchase * @param _numCycles - the number of cycles being purchased. This number should be `1` for non-subscription products and the number of cycles for subscriptions. * @param _assignee - the address to assign the purchase to (doesn't have to be msg.sender) * @param _affiliate - the address to of the affiliate - use address(0) if none */ function purchase( uint256 _productId, uint256 _numCycles, address _assignee, address _affiliate ) external payable whenNotPaused returns (uint256) { require(_productId != 0); require(_numCycles != 0); require(_assignee != address(0)); // msg.value can be zero: free products are supported // Don't bother dealing with excess payments. Ensure the price paid is // accurate. No more, no less. require(msg.value == costForProductCycles(_productId, _numCycles)); // Non-subscription products should send a _numCycle of 1 -- you can't buy a // multiple quantity of a non-subscription product with this function if(!isSubscriptionProduct(_productId)) { require(_numCycles == 1); } // this can, of course, be gamed by malicious miners. But it's adequate for our application // Feel free to add your own strategies for product attributes // solium-disable-next-line security/no-block-members, zeppelin/no-arithmetic-operations uint256 attributes = uint256(keccak256(block.blockhash(block.number-1)))^_productId^(uint256(_assignee)); uint256 licenseId = _performPurchase( _productId, _numCycles, _assignee, attributes, _affiliate); if( priceOf(_productId) > 0 && _affiliate != address(0) && _affiliateProgramIsActive() ) { _handleAffiliate( _affiliate, _productId, licenseId, msg.value); } return licenseId; } /** * @notice Renews a subscription */ function renew( uint256 _tokenId, uint256 _numCycles ) external payable whenNotPaused { require(_numCycles != 0); require(ownerOf(_tokenId) != address(0)); uint256 productId = licenseProductId(_tokenId); _requireRenewableProduct(productId); // No excess payments. Ensure the price paid is exactly accurate. No more, // no less. uint256 renewalCost = costForProductCycles(productId, _numCycles); require(msg.value == renewalCost); _performRenewal(_tokenId, _numCycles); if( renewalCost > 0 && licenseAffiliate(_tokenId) != address(0) && _affiliateProgramIsActive() && licenseIssuedTime(_tokenId).add(renewalsCreditAffiliatesFor) > now ) { _handleAffiliate( licenseAffiliate(_tokenId), productId, _tokenId, msg.value); } } } contract LicenseCore is LicenseSale { address public newContractAddress; function LicenseCore() public { paused = true; ceoAddress = msg.sender; cooAddress = msg.sender; cfoAddress = msg.sender; withdrawalAddress = msg.sender; } function setNewAddress(address _v2Address) external onlyCEO whenPaused { newContractAddress = _v2Address; ContractUpgrade(_v2Address); } function() external { assert(false); } function unpause() public onlyCEO whenPaused { require(newContractAddress == address(0)); super.unpause(); } } library Strings { // via https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol function strConcat(string _a, string _b, string _c, string _d, string _e) internal pure returns (string) { bytes memory _ba = bytes(_a); bytes memory _bb = bytes(_b); bytes memory _bc = bytes(_c); bytes memory _bd = bytes(_d); bytes memory _be = bytes(_e); string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length); bytes memory babcde = bytes(abcde); uint k = 0; for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i]; for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i]; for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i]; for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i]; for (i = 0; i < _be.length; i++) babcde[k++] = _be[i]; return string(babcde); } function strConcat(string _a, string _b, string _c, string _d) internal pure returns (string) { return strConcat(_a, _b, _c, _d, ""); } function strConcat(string _a, string _b, string _c) internal pure returns (string) { return strConcat(_a, _b, _c, "", ""); } function strConcat(string _a, string _b) internal pure returns (string) { return strConcat(_a, _b, "", "", ""); } function uint2str(uint i) internal pure returns (string) { if (i == 0) return "0"; uint j = i; uint len; while (j != 0){ len++; j /= 10; } bytes memory bstr = new bytes(len); uint k = len - 1; while (i != 0){ bstr[k--] = byte(48 + i % 10); i /= 10; } return string(bstr); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[{"name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cfoAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"isSubscriptionProduct","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"}],"name":"approveAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ceoAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseAffiliate","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementsERC721","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseIssuedTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseInfo","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newBaseURI","type":"string"}],"name":"setTokenMetadataBaseURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newWithdrawalAddress","type":"address"}],"name":"setWithdrawalAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_numCycles","type":"uint256"}],"name":"costForProductCycles","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newCEO","type":"address"}],"name":"setCEO","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newCOO","type":"address"}],"name":"setCOO","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"name":"_tokenId","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_numCycles","type":"uint256"},{"name":"_assignee","type":"address"},{"name":"_attributes","type":"uint256"}],"name":"createPromotionalPurchase","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_newRenewable","type":"bool"}],"name":"setRenewable","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"renewableOf","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newCFO","type":"address"}],"name":"setCFO","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"}],"name":"disapproveAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"}],"name":"clearInventory","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"tokensOf","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"withdrawBalance","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAllProductIds","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"newContractAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_v2Address","type":"address"}],"name":"setNewAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"totalSupplyOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"products","outputs":[{"name":"id","type":"uint256"},{"name":"price","type":"uint256"},{"name":"available","type":"uint256"},{"name":"supply","type":"uint256"},{"name":"sold","type":"uint256"},{"name":"interval","type":"uint256"},{"name":"renewable","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"},{"name":"_numCycles","type":"uint256"}],"name":"createPromotionalRenewal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"availableInventoryOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_initialPrice","type":"uint256"},{"name":"_initialInventoryQuantity","type":"uint256"},{"name":"_supply","type":"uint256"},{"name":"_interval","type":"uint256"}],"name":"createProduct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"totalSold","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseProductId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"NAME","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_numCycles","type":"uint256"},{"name":"_assignee","type":"address"},{"name":"_affiliate","type":"address"}],"name":"purchase","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"cooAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"takeOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"intervalOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"affiliateProgram","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenMetadataBaseURI","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"priceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"productInfo","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"setAffiliateProgramAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"},{"name":"_numCycles","type":"uint256"}],"name":"renew","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"name":"infoUrl","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newTime","type":"uint256"}],"name":"setRenewalsCreditAffiliatesFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"allProductIds","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseExpirationTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_inventoryAdjustment","type":"uint256"}],"name":"incrementInventory","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"renewalsCreditAffiliatesFor","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"withdrawalAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseAttributes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SYMBOL","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_price","type":"uint256"}],"name":"setPrice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_inventoryAdjustment","type":"uint256"}],"name":"decrementInventory","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":false,"stateMutability":"nonpayable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_approved","type":"address"},{"indexed":false,"name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_operator","type":"address"},{"indexed":false,"name":"_approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"price","type":"uint256"},{"indexed":false,"name":"available","type":"uint256"},{"indexed":false,"name":"supply","type":"uint256"},{"indexed":false,"name":"interval","type":"uint256"},{"indexed":false,"name":"renewable","type":"bool"}],"name":"ProductCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"productId","type":"uint256"},{"indexed":false,"name":"available","type":"uint256"}],"name":"ProductInventoryAdjusted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"productId","type":"uint256"},{"indexed":false,"name":"price","type":"uint256"}],"name":"ProductPriceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"productId","type":"uint256"},{"indexed":false,"name":"renewable","type":"bool"}],"name":"ProductRenewableChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"purchaser","type":"address"},{"indexed":false,"name":"licenseId","type":"uint256"},{"indexed":false,"name":"productId","type":"uint256"},{"indexed":false,"name":"attributes","type":"uint256"},{"indexed":false,"name":"issuedTime","type":"uint256"},{"indexed":false,"name":"expirationTime","type":"uint256"},{"indexed":false,"name":"affiliate","type":"address"}],"name":"LicenseIssued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"purchaser","type":"address"},{"indexed":false,"name":"licenseId","type":"uint256"},{"indexed":false,"name":"productId","type":"uint256"},{"indexed":false,"name":"expirationTime","type":"uint256"}],"name":"LicenseRenewal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newContract","type":"address"}],"name":"ContractUpgrade","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"}]
Contract Creation Code
606060409081526003805460a060020a60ff02191690558051908101604052601981527f68747470733a2f2f6170692e646f747461626f742e636f6d2f000000000000006020820152600d9080516200005d929160200190620000d9565b506301e13380600f5534156200007257600080fd5b6003805460008054600160a060020a033316600160a060020a03199182168117909255600280548216831790556001805482168317905560a060020a60ff02199092167401000000000000000000000000000000000000000017919091161790556200017e565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200011c57805160ff19168380011785556200014c565b828001600101855582156200014c579182015b828111156200014c5782518255916020019190600101906200012f565b506200015a9291506200015e565b5090565b6200017b91905b808211156200015a576000815560010162000165565b90565b613711806200018e6000396000f3006060604052600436106103345763ffffffff60e060020a60003504166301ffc9a781146103435780630519ce79146103775780630528bb57146103a65780630621472c146103bc57806306fdde03146103db578063081812fc14610465578063095ea7b31461047b5780630a0f81681461049d5780630e9fd199146104b05780631051db34146104c65780631411d713146104d957806318160ddd146105015780631e084558146105145780631e20363a1461056357806321b8092e1461058157806323b872dd146105a057806327597f0a146105c857806327d7874c146105e15780632ba73c15146106005780632f745c591461061f5780633ac6dd9d146106415780633f4ba83a146106695780633f4f30751461067c57806342842e0e146106975780634dac7d6f146106bf5780634e0a3379146106d55780634f6ccce7146106f457806351dabd451461070a578063533f6730146107295780635a3f26721461073f5780635c975abb146107b15780635fd8c710146107c45780636352211e146107d7578063663c01af146107ed5780636af04a571461080057806370a0823114610813578063715879881461083257806375b0d9cd146108515780637acc0b20146108675780637d0385c2146108bb5780638456cb59146108d4578063892412f0146108e757806392363a42146108fd57806393b2467e1461091f5780639425753c1461093557806395d89b411461094b578063a22cb4651461095e578063a3f4df7e14610982578063a7bf1b6c14610995578063a9059cbb146109b5578063b047fb50146109d7578063b2e6ceeb146109ea578063b369af7114610a00578063b3b4fd0f14610a16578063b5cab1ce14610a29578063b88d4fde14610a3c578063b9186d7d14610aa8578063bb119f6e14610abe578063c2b7ba3214610b05578063c475abff14610b24578063c87b56dd14610b32578063cc293aea14610b48578063dde1bbcf14610b5e578063dfbebd0714610b74578063e89b5d4b14610b8a578063e9748e5814610ba3578063e985e9c514610bb6578063f2bcd02214610bdb578063f4b272db14610bee578063f76f8d7814610c04578063f7d9757714610c17578063fe3d07e414610c30575b341561033f57600080fd5bfe5b005b341561034e57600080fd5b610363600160e060020a031960043516610c49565b604051901515815260200160405180910390f35b341561038257600080fd5b61038a610d1a565b604051600160a060020a03909116815260200160405180910390f35b34156103b157600080fd5b610363600435610d29565b34156103c757600080fd5b610341600160a060020a0360043516610d3c565b34156103e657600080fd5b6103ee610df7565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561042a578082015183820152602001610412565b50505050905090810190601f1680156104575780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561047057600080fd5b61038a600435610e39565b341561048657600080fd5b610341600160a060020a0360043516602435610e54565b34156104a857600080fd5b61038a610f51565b34156104bb57600080fd5b61038a600435610f60565b34156104d157600080fd5b610363610f94565b34156104e457600080fd5b6104ef600435610f99565b60405190815260200160405180910390f35b341561050c57600080fd5b6104ef610fc3565b341561051f57600080fd5b61052a600435610fc9565b60405194855260208501939093526040808501929092526060840152600160a060020a03909116608083015260a0909101905180910390f35b341561056e57600080fd5b6103416004803560248101910135611010565b341561058c57600080fd5b610341600160a060020a0360043516611057565b34156105ab57600080fd5b610341600160a060020a03600435811690602435166044356110a9565b34156105d357600080fd5b6104ef60043560243561110d565b34156105ec57600080fd5b610341600160a060020a036004351661112f565b341561060b57600080fd5b610341600160a060020a0360043516611181565b341561062a57600080fd5b6104ef600160a060020a03600435166024356111d3565b341561064c57600080fd5b6104ef600435602435600160a060020a0360443516606435611221565b341561067457600080fd5b610341611288565b341561068757600080fd5b61034160043560243515156112db565b34156106a257600080fd5b610341600160a060020a0360043581169060243516604435611374565b34156106ca57600080fd5b6103636004356113a5565b34156106e057600080fd5b610341600160a060020a03600435166113be565b34156106ff57600080fd5b6104ef600435611410565b341561071557600080fd5b610341600160a060020a0360043516611429565b341561073457600080fd5b6103416004356114c9565b341561074a57600080fd5b61075e600160a060020a0360043516611566565b60405160208082528190810183818151815260200191508051906020019060200280838360005b8381101561079d578082015183820152602001610785565b505050509050019250505060405180910390f35b34156107bc57600080fd5b6103636115e9565b34156107cf57600080fd5b6103416115f9565b34156107e257600080fd5b61038a60043561167f565b34156107f857600080fd5b61075e6116a3565b341561080b57600080fd5b61038a611701565b341561081e57600080fd5b6104ef600160a060020a0360043516611710565b341561083d57600080fd5b610341600160a060020a0360043516611743565b341561085c57600080fd5b6104ef6004356117d1565b341561087257600080fd5b61087d6004356117e6565b60405196875260208701959095526040808701949094526060860192909252608085015260a084015290151560c083015260e0909101905180910390f35b34156108c657600080fd5b610341600435602435611827565b34156108df57600080fd5b610341611895565b34156108f257600080fd5b6104ef60043561194d565b341561090857600080fd5b610341600435602435604435606435608435611962565b341561092a57600080fd5b6104ef6004356119ac565b341561094057600080fd5b6104ef6004356119c1565b341561095657600080fd5b6103ee6119eb565b341561096957600080fd5b610341600160a060020a03600435166024351515611a2c565b341561098d57600080fd5b6103ee611a64565b6104ef600435602435600160a060020a0360443581169060643516611a9b565b34156109c057600080fd5b610341600160a060020a0360043516602435611b96565b34156109e257600080fd5b61038a611bdf565b34156109f557600080fd5b610341600435611bee565b3415610a0b57600080fd5b6104ef600435611c2f565b3415610a2157600080fd5b61038a611c44565b3415610a3457600080fd5b6103ee611c53565b3415610a4757600080fd5b610341600160a060020a036004803582169160248035909116916044359160849060643590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650611cf195505050505050565b3415610ab357600080fd5b6104ef600435611ea6565b3415610ac957600080fd5b610ad4600435611ebb565b60405194855260208501939093526040808501929092526060840152901515608083015260a0909101905180910390f35b3415610b1057600080fd5b610341600160a060020a0360043516611ef0565b610341600435602435611f9d565b3415610b3d57600080fd5b6103ee600435612089565b3415610b5357600080fd5b61034160043561213d565b3415610b6957600080fd5b6104ef60043561215d565b3415610b7f57600080fd5b6104ef60043561217c565b3415610b9557600080fd5b6103416004356024356121a6565b3415610bae57600080fd5b6104ef612245565b3415610bc157600080fd5b610363600160a060020a036004358116906024351661224b565b3415610be657600080fd5b61038a612279565b3415610bf957600080fd5b6104ef600435612288565b3415610c0f57600080fd5b6103ee6122b2565b3415610c2257600080fd5b6103416004356024356122e9565b3415610c3b57600080fd5b610341600435602435612380565b6000600160e060020a031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001480610cac57507f5b5e139f00000000000000000000000000000000000000000000000000000000600160e060020a03198316145b80610ce057507f6466353c00000000000000000000000000000000000000000000000000000000600160e060020a03198316145b80610d1457507f780e9d6300000000000000000000000000000000000000000000000000000000600160e060020a03198316145b92915050565b600154600160a060020a031681565b600080610d3583611c2f565b1192915050565b60035460a060020a900460ff1615610d5357600080fd5b33600160a060020a031681600160a060020a031614151515610d7457600080fd5b600160a060020a0381161515610d8957600080fd5b600160a060020a033381166000818152600a602090815260408083209486168084529490915290819020805460ff191660019081179091557f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319151901515815260200160405180910390a350565b610dff613536565b60408051908101604052600881527f446f747461626f74000000000000000000000000000000000000000000000000602082015290505b90565b600090815260096020526040902054600160a060020a031690565b60035460009060a060020a900460ff1615610e6e57600080fd5b8133600160a060020a0316610e828261167f565b600160a060020a031614610e9557600080fd5b610e9e8361167f565b9150600160a060020a038481169083161415610eb957600080fd5b610ec283610e39565b600160a060020a0316151580610ee05750600160a060020a03841615155b15610f4b57600083815260096020526040908190208054600160a060020a031916600160a060020a0387811691821790925591908416907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259086905190815260200160405180910390a35b50505050565b600054600160a060020a031681565b6000600482815481101515610f7157fe5b6000918252602090912060059091020160040154600160a060020a031692915050565b600190565b6000600482815481101515610faa57fe5b9060005260206000209060050201600201549050919050565b60075490565b6000806000806000610fda866119c1565b610fe387612288565b610fec88610f99565b610ff58961217c565b610ffe8a610f60565b939a9299509097509550909350915050565b60025433600160a060020a039081169116148061103b575060005433600160a060020a039081169116145b151561104657600080fd5b611052600d8383613548565b505050565b60005433600160a060020a0390811691161461107257600080fd5b600160a060020a038116151561108757600080fd5b60038054600160a060020a031916600160a060020a0392909216919091179055565b60035460a060020a900460ff16156110c057600080fd5b6110c9816123d9565b15156110d457600080fd5b82600160a060020a03166110e78261167f565b600160a060020a0316146110fa57600080fd5b6110526111068261167f565b8383612420565b60006111288261111c85611ea6565b9063ffffffff6124fa16565b9392505050565b60005433600160a060020a0390811691161461114a57600080fd5b600160a060020a038116151561115f57600080fd5b60008054600160a060020a031916600160a060020a0392909216919091179055565b60005433600160a060020a0390811691161461119c57600080fd5b600160a060020a03811615156111b157600080fd5b60028054600160a060020a031916600160a060020a0392909216919091179055565b60006111de83611710565b82106111e957600080fd5b600160a060020a0383166000908152600b6020526040902080548390811061120d57fe5b906000526020600020900154905092915050565b60025460009033600160a060020a039081169116148061124f575060005433600160a060020a039081169116145b151561125a57600080fd5b60035460a060020a900460ff161561127157600080fd5b61127f858585856000612530565b95945050505050565b60005433600160a060020a039081169116146112a357600080fd5b60035460a060020a900460ff1615156112bb57600080fd5b601054600160a060020a0316156112d157600080fd5b6112d9612548565b565b60025433600160a060020a0390811691161480611306575060005433600160a060020a039081169116145b8061131f575060015433600160a060020a039081169116145b151561132a57600080fd5b61133482826125c7565b7f8993c82fcc9b66ce01f4e84cdf9e0c368fc46c1c20e87e9c8324eb0ab6780cf58282604051918252151560208201526040908101905180910390a15050565b60035460a060020a900460ff161561138b57600080fd5b611052838383602060405190810160405260008152611cf1565b6000908152600660208190526040909120015460ff1690565b60005433600160a060020a039081169116146113d957600080fd5b600160a060020a03811615156113ee57600080fd5b60018054600160a060020a031916600160a060020a0392909216919091179055565b600061141a610fc3565b821061142557600080fd5b5090565b60035460a060020a900460ff161561144057600080fd5b33600160a060020a031681600160a060020a03161415151561146157600080fd5b600160a060020a033381166000818152600a6020908152604080832094861680845294909152808220805460ff191690557f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31919051901515815260200160405180910390a350565b60025433600160a060020a03908116911614806114f4575060005433600160a060020a039081169116145b8061150d575060015433600160a060020a039081169116145b151561151857600080fd5b61152181612600565b7f52de58a758e06868840036921f6c180f216295e8eb79f91399b9f8edb1f64daa8161154c8361194d565b60405191825260208201526040908101905180910390a150565b61156e613536565b600b600083600160a060020a0316600160a060020a031681526020019081526020016000208054806020026020016040519081016040528092919081815260200182805480156115dd57602002820191906000526020600020905b8154815260200190600101908083116115c9575b50505050509050919050565b60035460a060020a900460ff1681565b60015433600160a060020a0390811691161480611624575060005433600160a060020a039081169116145b151561162f57600080fd5b600354600160a060020a0316151561164657600080fd5b600354600160a060020a039081169030163180156108fc0290604051600060405180830381858888f1935050505015156112d957600080fd5b600081815260086020526040812054600160a060020a0316801515610d1457600080fd5b6116ab613536565b60058054806020026020016040519081016040528092919081815260200182805480156116f757602002820191906000526020600020905b8154815260200190600101908083116116e3575b5050505050905090565b601054600160a060020a031681565b6000600160a060020a038216151561172757600080fd5b50600160a060020a03166000908152600b602052604090205490565b60005433600160a060020a0390811691161461175e57600080fd5b60035460a060020a900460ff16151561177657600080fd5b60108054600160a060020a031916600160a060020a0383161790557f450db8da6efbe9c22f2347f7c2021231df1fc58d3ae9a2fa75d39fa44619930581604051600160a060020a03909116815260200160405180910390a150565b60009081526006602052604090206003015490565b600660208190526000918252604090912080546001820154600283015460038401546004850154600586015495909601549395929491939092919060ff1687565b60025460009033600160a060020a0390811691161480611855575060005433600160a060020a039081169116145b151561186057600080fd5b60035460a060020a900460ff161561187757600080fd5b611880836119c1565b905061188b81612628565b611052838361265c565b60025433600160a060020a03908116911614806118c0575060005433600160a060020a039081169116145b806118d9575060015433600160a060020a039081169116145b15156118e457600080fd5b60035460a060020a900460ff16156118fb57600080fd5b6003805474ff0000000000000000000000000000000000000000191660a060020a1790557f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e75260405160405180910390a1565b60009081526006602052604090206002015490565b60025433600160a060020a039081169116148061198d575060005433600160a060020a039081169116145b151561199857600080fd5b6119a58585858585612746565b5050505050565b60009081526006602052604090206004015490565b60006004828154811015156119d257fe5b9060005260206000209060050201600001549050919050565b6119f3613536565b60408051908101604052600581527f444f5454410000000000000000000000000000000000000000000000000000006020820152905090565b60035460a060020a900460ff1615611a4357600080fd5b8015611a5757611a5282610d3c565b611a60565b611a6082611429565b5050565b60408051908101604052600881527f446f747461626f74000000000000000000000000000000000000000000000000602082015281565b6003546000908190819060a060020a900460ff1615611ab957600080fd5b861515611ac557600080fd5b851515611ad157600080fd5b600160a060020a0385161515611ae657600080fd5b611af0878761110d565b3414611afb57600080fd5b611b0487610d29565b1515611b175760018614611b1757600080fd5b84600160a060020a031687600143034060405190815260200160405190819003902018189150611b4a8787878588612530565b90506000611b5788611ea6565b118015611b6c5750600160a060020a03841615155b8015611b7b5750611b7b6128b7565b15611b8c57611b8c848883346129b2565b9695505050505050565b60035460a060020a900460ff1615611bad57600080fd5b8033600160a060020a0316611bc18261167f565b600160a060020a031614611bd457600080fd5b611052338484612420565b600254600160a060020a031681565b60035460a060020a900460ff1615611c0557600080fd5b611c0e816123d9565b1515611c1957600080fd5b611c2c611c258261167f565b3383612420565b50565b60009081526006602052604090206005015490565b600e54600160a060020a031681565b600d8054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015611ce95780601f10611cbe57610100808354040283529160200191611ce9565b820191906000526020600020905b815481529060010190602001808311611ccc57829003601f168201915b505050505081565b60035460009060a060020a900460ff1615611d0b57600080fd5b600160a060020a0384161515611d2057600080fd5b611d2983612ac5565b1515611d3457600080fd5b611d3f8585856110a9565b611d4884612ad8565b156119a55783600160a060020a031663f0b9e5ba61c3508786866040518563ffffffff1660e060020a0281526004018084600160a060020a0316600160a060020a0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611dcf578082015183820152602001611db7565b50505050905090810190601f168015611dfc5780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600088803b1515611e1c57600080fd5b87f11515611e2957600080fd5b505050506040518051905090506040517f6f6e455243373231526563656976656428616464726573732c75696e7432353681527f2c627974657329000000000000000000000000000000000000000000000000006020820152602701604051908190039020600160e060020a03198281169116146119a557600080fd5b60009081526006602052604090206001015490565b6000806000806000611ecc86611ea6565b611ed58761194d565b611ede886117d1565b611ee789611c2f565b610ffe8a6113a5565b6000805433600160a060020a03908116911614611f0c57600080fd5b5080600160a060020a03811663cd43ee996000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515611f5457600080fd5b6102c65a03f11515611f6557600080fd5b505050604051805190501515611f7a57600080fd5b600e8054600160a060020a031916600160a060020a039290921691909117905550565b600354600090819060a060020a900460ff1615611fb957600080fd5b821515611fc557600080fd5b6000611fd08561167f565b600160a060020a03161415611fe457600080fd5b611fed846119c1565b9150611ff882612628565b612002828461110d565b905034811461201057600080fd5b61201a848461265c565b60008111801561203c5750600061203085610f60565b600160a060020a031614155b801561204b575061204b6128b7565b801561207057504261206e600f5461206287610f99565b9063ffffffff612ae016565b115b15610f4b57610f4b61208185610f60565b8386346129b2565b612091613536565b610d14600d8054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561212a5780601f106120ff5761010080835404028352916020019161212a565b820191906000526020600020905b81548152906001019060200180831161210d57829003601f168201915b505050505061213884612aef565b612be3565b60005433600160a060020a0390811691161461215857600080fd5b600f55565b600580548290811061216b57fe5b600091825260209091200154905081565b600060048281548110151561218d57fe5b9060005260206000209060050201600301549050919050565b60025433600160a060020a03908116911614806121d1575060005433600160a060020a039081169116145b806121ea575060015433600160a060020a039081169116145b15156121f557600080fd5b6121ff8282612c26565b7f52de58a758e06868840036921f6c180f216295e8eb79f91399b9f8edb1f64daa8261222a8461194d565b60405191825260208201526040908101905180910390a15050565b600f5481565b600160a060020a039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b600354600160a060020a031681565b600060048281548110151561229957fe5b9060005260206000209060050201600101549050919050565b60408051908101604052600581527f444f545441000000000000000000000000000000000000000000000000000000602082015281565b60025433600160a060020a0390811691161480612314575060005433600160a060020a039081169116145b8061232d575060015433600160a060020a039081169116145b151561233857600080fd5b6123428282612cc7565b7fd63cc1ed2f6abbff2bdc8aeb9f139df953e98c6aa57ca5bfe8e1876be9e890ec828260405191825260208201526040908101905180910390a15050565b60025433600160a060020a03908116911614806123ab575060005433600160a060020a039081169116145b806123c4575060015433600160a060020a039081169116145b15156123cf57600080fd5b6121ff8282612cf0565b600033600160a060020a03166123ee8361167f565b600160a060020a0316148061240857506124083383612d42565b80610d145750610d1461241a8361167f565b3361224b565b600160a060020a038216151561243557600080fd5b61243e8161167f565b600160a060020a038381169116141561245657600080fd5b82600160a060020a03166124698261167f565b600160a060020a03161461247c57600080fd5b61248581612ac5565b151561249057600080fd5b61249a8382612d68565b6124a48382612ded565b6124ae8282612f59565b81600160a060020a031683600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a3505050565b60008083151561250d5760009150612529565b5082820282848281151561251d57fe5b041461252557fe5b8091505b5092915050565b600061253b86613013565b611b8c868686868661307f565b60005433600160a060020a0390811691161461256357600080fd5b60035460a060020a900460ff16151561257b57600080fd5b6003805474ff0000000000000000000000000000000000000000191690557fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d1693360405160405180910390a1565b6125d082613214565b15156125db57600080fd5b6000918252600660208190526040909220909101805460ff1916911515919091179055565b61260981613214565b151561261457600080fd5b600090815260066020526040812060020155565b80151561263457600080fd5b61263d81610d29565b151561264857600080fd5b612651816113a5565b1515611c2c57600080fd5b600080600061266a856119c1565b92506126964260048781548110151561267f57fe5b906000526020600020906005020160030154613228565b91506126b56126a88561111c86611c2f565b839063ffffffff612ae016565b9050806004868154811015156126c757fe5b90600052602060002090600502016003018190555033600160a060020a03166126ef8661167f565b600160a060020a03167feaf24094683b38939d81835f96309c60277bbc3366d51527540fe4a67b42da5a87868560405180848152602001838152602001828152602001935050505060405180910390a35050505050565b61274e6135c2565b6127578661323f565b151561276257600080fd5b8284111561276f57600080fd5b60e06040519081016040528087815260200186815260200185815260200184815260200160008152602001838152602001836000146127af5760016127b2565b60005b1515905260008781526006602052604090209091508190815181556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c0820151600691909101805460ff191691151591909117905550600580546001810161282c8382613602565b5060009182526020909120018690557f712119543ff2c643b26af29b73e263a1ae26070bc4c92e6ca2b659885654a70181518260200151836040015184606001518560a001518660c0015160405195865260208601949094526040808601939093526060850191909152608084015290151560a083015260c0909101905180910390a1505050505050565b600e54600090600160a060020a0316158015906129415750600e54600160a060020a03308116911663f2c4da936000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561291b57600080fd5b6102c65a03f1151561292c57600080fd5b50505060405180519050600160a060020a0316145b80156129ad5750600e54600160a060020a0316635c975abb6000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561299057600080fd5b6102c65a03f115156129a157600080fd5b50505060405180519050155b905090565b600e54600090600160a060020a031663e230e24686868686866040516020015260405160e060020a63ffffffff8716028152600160a060020a039094166004850152602484019290925260448301526064820152608401602060405180830381600087803b1515612a2257600080fd5b6102c65a03f11515612a3357600080fd5b505050604051805191505060008111156119a557818110612a5357600080fd5b600e54600160a060020a031663ef6506db82878660405160e060020a63ffffffff8616028152600160a060020a03909216600483015260248201526044016000604051808303818588803b1515612aa957600080fd5b6125ee5a03f11515612aba57600080fd5b505050505050505050565b6000612ad0826119c1565b151592915050565b6000903b1190565b60008282018381101561252557fe5b612af7613536565b600080612b02613536565b6000851515612b465760408051908101604052600181527f300000000000000000000000000000000000000000000000000000000000000060208201529450612bda565b8593505b8315612b6157600190920191600a84049350612b4a565b82604051805910612b6f5750595b818152601f19601f8301168101602001604052905091505060001982015b8515612bd65760001981019060f860020a6030600a8906010290839081518110612bb357fe5b906020010190600160f860020a031916908160001a905350600a86049550612b8d565b8194505b50505050919050565b612beb613536565b611128838360206040519081016040528060008152506020604051908101604052806000815250602060405190810160405260008152613252565b6000612c3183613214565b1515612c3c57600080fd5b600083815260066020526040902060020154612c5e908363ffffffff612ae016565b600084815260066020526040812060030154919250901115612cae5760008381526006602052604090206003810154600490910154612ca3908363ffffffff612ae016565b1115612cae57600080fd5b6000928352600660205260409092206002019190915550565b612cd082613214565b1515612cdb57600080fd5b60009182526006602052604090912060010155565b6000612cfb83613214565b1515612d0657600080fd5b600083815260066020526040902060020154612d28908363ffffffff6134c216565b600093845260066020526040909320600201929092555050565b600082600160a060020a0316612d5783610e39565b600160a060020a0316149392505050565b81600160a060020a0316612d7b8261167f565b600160a060020a031614612d8e57600080fd5b6000818152600960205260408082208054600160a060020a0319169055600160a060020a038416907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259084905190815260200160405180910390a35050565b600080600084600160a060020a0316612e058561167f565b600160a060020a031614612e1857600080fd5b6000848152600c60205260409020549250612e436001612e3787611710565b9063ffffffff6134c216565b600160a060020a0386166000908152600b6020526040902080549193509083908110612e6b57fe5b60009182526020808320909101548683526008825260408084208054600160a060020a0319169055600160a060020a0389168452600b90925291208054919250829185908110612eb757fe5b6000918252602080832090910192909255600160a060020a0387168152600b90915260408120805484908110612ee957fe5b6000918252602080832090910192909255600160a060020a0387168152600b90915260409020805490612f20906000198301613602565b506000848152600c60205260408082208290558282529020839055600754612f4f90600163ffffffff6134c216565b6007555050505050565b600081815260086020526040812054600160a060020a031615612f7b57600080fd5b60008281526008602052604090208054600160a060020a031916600160a060020a038516179055612fab83611710565b600160a060020a0384166000908152600b6020526040902080549192509060018101612fd78382613602565b506000918252602080832091909101849055838252600c90526040902081905560075461300b90600163ffffffff612ae016565b600755505050565b61301c81613214565b151561302757600080fd5b60006130328261194d565b1161303c57600080fd5b613047816001612cf0565b60008181526006602052604090206004015461306a90600163ffffffff612ae016565b60009182526006602052604090912060040155565b60008061308a613626565b600061309589610d29565b156130a6578715156130a657600080fd5b6130af89610d29565b6130ba5760006130d7565b6130d76130ca8961111c8c611c2f565b429063ffffffff612ae016565b925060a0604051908101604052808a815260200187815260200142815260200184815260200186600160a060020a03168152509150600160048054806001018281613122919061365f565b600092835260209092208591600502018151815560208201518160010155604082015181600201556060820151816003015560808201516004919091018054600160a060020a031916600160a060020a03928316179055929091039250503381169088167f295203a2e224d53a9e7107bf20ca4642308c1afa628268bbfe5f796412f832428385518660200151876040015188606001518960800151604051958652602086019490945260408086019390935260608501919091526080840152600160a060020a0390911660a083015260c0909101905180910390a361320887826134d4565b98975050505050505050565b600090815260066020526040902054151590565b6000818310156132385781611128565b5090919050565b6000908152600660205260409020541590565b61325a613536565b613262613536565b61326a613536565b613272613536565b61327a613536565b613282613536565b61328a613536565b613292613536565b6000808e98508d97508c96508b95508a94508451865188518a518c51010101016040518059106132bf5750595b818152601f19601f83011681016020016040529050935083925060009150600090505b885181101561333b578881815181106132f757fe5b016020015160f860020a900460f860020a0283838060010194508151811061331b57fe5b906020010190600160f860020a031916908160001a9053506001016132e2565b5060005b87518110156133985787818151811061335457fe5b016020015160f860020a900460f860020a0283838060010194508151811061337857fe5b906020010190600160f860020a031916908160001a90535060010161333f565b5060005b86518110156133f5578681815181106133b157fe5b016020015160f860020a900460f860020a028383806001019450815181106133d557fe5b906020010190600160f860020a031916908160001a90535060010161339c565b5060005b85518110156134525785818151811061340e57fe5b016020015160f860020a900460f860020a0283838060010194508151811061343257fe5b906020010190600160f860020a031916908160001a9053506001016133f9565b5060005b84518110156134af5784818151811061346b57fe5b016020015160f860020a900460f860020a0283838060010194508151811061348f57fe5b906020010190600160f860020a031916908160001a905350600101613456565b50909d9c50505050505050505050505050565b6000828211156134ce57fe5b50900390565b600160a060020a03821615156134e957600080fd5b6134f38282612f59565b81600160a060020a031660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050565b60206040519081016040526000815290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106135895782800160ff198235161785556135b6565b828001600101855582156135b6579182015b828111156135b657823582559160200191906001019061359b565b5061142592915061368b565b60e0604051908101604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b8154818355818115116110525760008381526020902061105291810190830161368b565b60a060405190810160405280600081526020016000815260200160008152602001600081526020016000600160a060020a031681525090565b8154818355818115116110525760050281600502836000526020600020918201910161105291906136a5565b610e3691905b808211156114255760008155600101613691565b610e3691905b8082111561142557600080825560018201819055600282018190556003820155600481018054600160a060020a03191690556005016136ab5600a165627a7a723058200be6b83cce0244fc84b08c9dfa44e10341734a9c740f5d8b0e30f7d7e1a390fe0029
Swarm Source
bzzr://0be6b83cce0244fc84b08c9dfa44e10341734a9c740f5d8b0e30f7d7e1a390fe
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.