Transaction Hash:
Block:
6187468 at Aug-21-2018 12:57:50 PM +UTC
Transaction Fee:
0.0003173016 ETH
$0.67
Gas Used:
151,096 Gas / 2.1 Gwei
Emitted Events:
| 59 |
LivepeerToken.Transfer( from=[Receiver] MerkleMine, to=[Sender] 0xd293c81397f762e21a10f7cb78253e44f692ea72, value=149792199720484929 )
|
| 60 |
LivepeerToken.Transfer( from=[Receiver] MerkleMine, to=0x281ceA258Bd51086332Fa6F225c80453154f9694, value=2291903966396607329 )
|
| 61 |
MerkleMine.Generate( _recipient=0x281ceA258Bd51086332Fa6F225c80453154f9694, _caller=[Sender] 0xd293c81397f762e21a10f7cb78253e44f692ea72, _recipientTokenAmount=2291903966396607329, _callerTokenAmount=149792199720484929, _block=6187468 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
|
0x52bc44d5...b7d7bE3b5
Miner
| (Nanopool) | 7,667.97791843668946959 Eth | 7,667.97823573828946959 Eth | 0.0003173016 | |
| 0x58b6A8A3...e733aB239 | |||||
| 0x8e306b00...766cC15c8 | (Livepeer: Merkle Mine) | ||||
| 0xD293C813...4f692ea72 |
0.171098487 Eth
Nonce: 88
|
0.1707811854 Eth
Nonce: 89
| 0.0003173016 |
Execution Trace
MerkleMine.generate( _recipient=0x281ceA258Bd51086332Fa6F225c80453154f9694, _merkleProof=0x56CB2FCEB66EFDF6A1F6976F5E2E80BC2D9CE8843BE8C628CC96FB9B9F6ACF712E53D1A328D7EE83F6890EE00161FE99F820F1EE570414C8698568562AA817601EF0BAAEBDA5C6310D05AEB17651FCDC119B5A6C76089BDE4A44B4B9FBD8C8A02F8B513D184EAF362DF717C39A4FA5783EC8A220C032BC379B3C02EFD3252474669496D8074E47631607F176CEC95FDB929A7A129BEB7520A471D084C155DA7F595B659717592BC6C2FC8ED28405AF5ED0503AC1D8CA5543565F8E48C630C6EAE781550EC52917713796263F2548DF29958BB747018DB0CDDC8B1492E6F0C1BCF76D69D794234A3BB72A6276F8991CE7A42EA12C9E130811EAB097289BD0A84285189FA17C2ADCF1D4EE377DDB22A66B80BAB4407C27D8A9ACFAB865052DF3FD02C37248D6A47DEE228CBBEC29C1322160C21851DAC90DE9BC2FB006247115547B5803A7CEA9732F42F163F673AEB2C0250B3FEF37C839897FB48FB43C25E0834ADC87EDAA7E5661040FD0A99631D1B287D77397A92E2129BDF0EE631FDCA67AD4C7A4AC99B3D007982355BB9DDDFFCA6AE6F025EF30320D71E01D7078C9A65A9879622E5108FFDC811AAB6B27C63B6A333932E3BAADD7F81B0BC6A5F59FF3EC44B6FAD9205BEE2805485C556AA2C8E9E6F334E7C2F992A3A4E1EBCE4F3E5B65AC41A5692CCA8B82A2C03D436C3E00B08A714F932ECE58644CFD0685B12497F0E5E590E498C7B28B5E4060E81BBFF379882CC5251004B547924D7F16A93B20EB9CAF2611660388715BC8D3554DAE199E700A8F12A6E798C3AAEF4D7C96A9D64559DE69342DF69503B70424F7D2642AFF4658E0097C4520A06FC6B25B7BBA84C1CCB9167971B92FE9762830D3F20908FB10FAFA9929ADFDE2F65A4E90327EBC1F7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3 )
-
MerkleProof.verifyProof( _proof=0x56CB2FCEB66EFDF6A1F6976F5E2E80BC2D9CE8843BE8C628CC96FB9B9F6ACF712E53D1A328D7EE83F6890EE00161FE99F820F1EE570414C8698568562AA817601EF0BAAEBDA5C6310D05AEB17651FCDC119B5A6C76089BDE4A44B4B9FBD8C8A02F8B513D184EAF362DF717C39A4FA5783EC8A220C032BC379B3C02EFD3252474669496D8074E47631607F176CEC95FDB929A7A129BEB7520A471D084C155DA7F595B659717592BC6C2FC8ED28405AF5ED0503AC1D8CA5543565F8E48C630C6EAE781550EC52917713796263F2548DF29958BB747018DB0CDDC8B1492E6F0C1BCF76D69D794234A3BB72A6276F8991CE7A42EA12C9E130811EAB097289BD0A84285189FA17C2ADCF1D4EE377DDB22A66B80BAB4407C27D8A9ACFAB865052DF3FD02C37248D6A47DEE228CBBEC29C1322160C21851DAC90DE9BC2FB006247115547B5803A7CEA9732F42F163F673AEB2C0250B3FEF37C839897FB48FB43C25E0834ADC87EDAA7E5661040FD0A99631D1B287D77397A92E2129BDF0EE631FDCA67AD4C7A4AC99B3D007982355BB9DDDFFCA6AE6F025EF30320D71E01D7078C9A65A9879622E5108FFDC811AAB6B27C63B6A333932E3BAADD7F81B0BC6A5F59FF3EC44B6FAD9205BEE2805485C556AA2C8E9E6F334E7C2F992A3A4E1EBCE4F3E5B65AC41A5692CCA8B82A2C03D436C3E00B08A714F932ECE58644CFD0685B12497F0E5E590E498C7B28B5E4060E81BBFF379882CC5251004B547924D7F16A93B20EB9CAF2611660388715BC8D3554DAE199E700A8F12A6E798C3AAEF4D7C96A9D64559DE69342DF69503B70424F7D2642AFF4658E0097C4520A06FC6B25B7BBA84C1CCB9167971B92FE9762830D3F20908FB10FAFA9929ADFDE2F65A4E90327EBC1F7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3, _root=53F35A304A1E1E20D6648E09BB3073CCD44A5BF1638A01355897A71E801879F8, _leaf=489F71BB60A21B5510BCA9C695FE86E705CDE832AF555AFC7655B6A281F791E2 ) => ( True ) -
LivepeerToken.transfer( _to=0xD293C81397F762E21A10F7cb78253E44f692ea72, _value=149792199720484929 ) => ( True )
-
LivepeerToken.transfer( _to=0x281ceA258Bd51086332Fa6F225c80453154f9694, _value=2291903966396607329 ) => ( True )
generate[MerkleMine (ln:220)]
verifyProof[MerkleMine (ln:224)]transfer[MerkleMine (ln:232)]Generate[MerkleMine (ln:234)]callerTokenAmountAtBlock[MerkleMine (ln:240)]sub[MerkleMine (ln:241)]transfer[MerkleMine (ln:244)]transfer[MerkleMine (ln:248)]Generate[MerkleMine (ln:251)]
File 1 of 3: MerkleMine
File 2 of 3: LivepeerToken
File 3 of 3: MerkleProof
pragma solidity 0.4.18;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
uint256 public totalSupply;
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
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;
}
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;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
/*
* @title MerkleProof
* @dev Merkle proof verification
* @note Based on https://github.com/ameensol/merkle-tree-solidity/blob/master/src/MerkleProof.sol
*/
library MerkleProof {
/*
* @dev Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves
* and each pair of pre-images is sorted.
* @param _proof Merkle proof containing sibling hashes on the branch from the leaf to the root of the Merkle tree
* @param _root Merkle root
* @param _leaf Leaf of Merkle tree
*/
function verifyProof(bytes _proof, bytes32 _root, bytes32 _leaf) public pure returns (bool) {
// Check if proof length is a multiple of 32
if (_proof.length % 32 != 0) return false;
bytes32 proofElement;
bytes32 computedHash = _leaf;
for (uint256 i = 32; i <= _proof.length; i += 32) {
assembly {
// Load the current element of the proof
proofElement := mload(add(_proof, i))
}
if (computedHash < proofElement) {
// Hash(current computed hash + current element of the proof)
computedHash = keccak256(computedHash, proofElement);
} else {
// Hash(current element of the proof + current computed hash)
computedHash = keccak256(proofElement, computedHash);
}
}
// Check if the computed hash (root) is equal to the provided root
return computedHash == _root;
}
}
/**
* @title MerkleMine
* @dev Token distribution based on providing Merkle proofs of inclusion in genesis state to generate allocation
*/
contract MerkleMine {
using SafeMath for uint256;
// ERC20 token being distributed
ERC20 public token;
// Merkle root representing genesis state which encodes token recipients
bytes32 public genesisRoot;
// Total amount of tokens that can be generated
uint256 public totalGenesisTokens;
// Total number of recipients included in genesis state
uint256 public totalGenesisRecipients;
// Amount of tokens per recipient allocation. Equal to `totalGenesisTokens` / `totalGenesisRecipients`
uint256 public tokensPerAllocation;
// Minimum ETH balance threshold for recipients included in genesis state
uint256 public balanceThreshold;
// Block number of genesis - used to determine which ETH accounts are included in the genesis state
uint256 public genesisBlock;
// Start block where a third party caller (not the recipient) can generate and split the allocation with the recipient
// As the current block gets closer to `callerAllocationEndBlock`, the caller receives a larger precentage of the allocation
uint256 public callerAllocationStartBlock;
// From this block onwards, a third party caller (not the recipient) can generate and claim the recipient's full allocation
uint256 public callerAllocationEndBlock;
// Number of blocks in the caller allocation period as defined by `callerAllocationEndBlock` - `callerAllocationStartBlock`
uint256 public callerAllocationPeriod;
// Track if the generation process is started
bool public started;
// Track the already generated allocations for recipients
mapping (address => bool) public generated;
// Check that a recipient's allocation has not been generated
modifier notGenerated(address _recipient) {
require(!generated[_recipient]);
_;
}
// Check that the generation period is started
modifier isStarted() {
require(started);
_;
}
// Check that the generation period is not started
modifier isNotStarted() {
require(!started);
_;
}
event Generate(address indexed _recipient, address indexed _caller, uint256 _recipientTokenAmount, uint256 _callerTokenAmount, uint256 _block);
/**
* @dev MerkleMine constructor
* @param _token ERC20 token being distributed
* @param _genesisRoot Merkle root representing genesis state which encodes token recipients
* @param _totalGenesisTokens Total amount of tokens that can be generated
* @param _totalGenesisRecipients Total number of recipients included in genesis state
* @param _balanceThreshold Minimum ETH balance threshold for recipients included in genesis state
* @param _genesisBlock Block number of genesis - used to determine which ETH accounts are included in the genesis state
* @param _callerAllocationStartBlock Start block where a third party caller (not the recipient) can generate and split the allocation with the recipient
* @param _callerAllocationEndBlock From this block onwards, a third party caller (not the recipient) can generate and claim the recipient's full allocation
*/
function MerkleMine(
address _token,
bytes32 _genesisRoot,
uint256 _totalGenesisTokens,
uint256 _totalGenesisRecipients,
uint256 _balanceThreshold,
uint256 _genesisBlock,
uint256 _callerAllocationStartBlock,
uint256 _callerAllocationEndBlock
)
public
{
// Address of token contract must not be null
require(_token != address(0));
// Number of recipients must be non-zero
require(_totalGenesisRecipients > 0);
// Genesis block must be at or before the current block
require(_genesisBlock <= block.number);
// Start block for caller allocation must be after current block
require(_callerAllocationStartBlock > block.number);
// End block for caller allocation must be after caller allocation start block
require(_callerAllocationEndBlock > _callerAllocationStartBlock);
token = ERC20(_token);
genesisRoot = _genesisRoot;
totalGenesisTokens = _totalGenesisTokens;
totalGenesisRecipients = _totalGenesisRecipients;
tokensPerAllocation = _totalGenesisTokens.div(_totalGenesisRecipients);
balanceThreshold = _balanceThreshold;
genesisBlock = _genesisBlock;
callerAllocationStartBlock = _callerAllocationStartBlock;
callerAllocationEndBlock = _callerAllocationEndBlock;
callerAllocationPeriod = _callerAllocationEndBlock.sub(_callerAllocationStartBlock);
}
/**
* @dev Start the generation period - first checks that this contract's balance is equal to `totalGenesisTokens`
* The generation period must not already be started
*/
function start() external isNotStarted {
// Check that this contract has a sufficient balance for the generation period
require(token.balanceOf(this) >= totalGenesisTokens);
started = true;
}
/**
* @dev Generate a recipient's token allocation. Generation period must be started. Starting from `callerAllocationStartBlock`
* a third party caller (not the recipient) can invoke this function to generate the recipient's token
* allocation and claim a percentage of it. The percentage of the allocation claimed by the
* third party caller is determined by how many blocks have elapsed since `callerAllocationStartBlock`.
* After `callerAllocationEndBlock`, a third party caller can claim the full allocation
* @param _recipient Recipient of token allocation
* @param _merkleProof Proof of recipient's inclusion in genesis state Merkle root
*/
function generate(address _recipient, bytes _merkleProof) external isStarted notGenerated(_recipient) {
// Check the Merkle proof
bytes32 leaf = keccak256(_recipient);
// _merkleProof must prove inclusion of _recipient in the genesis state root
require(MerkleProof.verifyProof(_merkleProof, genesisRoot, leaf));
generated[_recipient] = true;
address caller = msg.sender;
if (caller == _recipient) {
// If the caller is the recipient, transfer the full allocation to the caller/recipient
require(token.transfer(_recipient, tokensPerAllocation));
Generate(_recipient, _recipient, tokensPerAllocation, 0, block.number);
} else {
// If the caller is not the recipient, the token allocation generation
// can only take place if we are in the caller allocation period
require(block.number >= callerAllocationStartBlock);
uint256 callerTokenAmount = callerTokenAmountAtBlock(block.number);
uint256 recipientTokenAmount = tokensPerAllocation.sub(callerTokenAmount);
if (callerTokenAmount > 0) {
require(token.transfer(caller, callerTokenAmount));
}
if (recipientTokenAmount > 0) {
require(token.transfer(_recipient, recipientTokenAmount));
}
Generate(_recipient, caller, recipientTokenAmount, callerTokenAmount, block.number);
}
}
/**
* @dev Return the amount of tokens claimable by a third party caller when generating a recipient's token allocation at a given block
* @param _blockNumber Block at which to compute the amount of tokens claimable by a third party caller
*/
function callerTokenAmountAtBlock(uint256 _blockNumber) public view returns (uint256) {
if (_blockNumber < callerAllocationStartBlock) {
// If the block is before the start of the caller allocation period, the third party caller can claim nothing
return 0;
} else if (_blockNumber >= callerAllocationEndBlock) {
// If the block is at or after the end block of the caller allocation period, the third party caller can claim everything
return tokensPerAllocation;
} else {
// During the caller allocation period, the third party caller can claim an increasing percentage
// of the recipient's allocation based on a linear curve - as more blocks pass in the caller allocation
// period, the amount claimable by the third party caller increases linearly
uint256 blocksSinceCallerAllocationStartBlock = _blockNumber.sub(callerAllocationStartBlock);
return tokensPerAllocation.mul(blocksSinceCallerAllocationStartBlock).div(callerAllocationPeriod);
}
}
}File 2 of 3: LivepeerToken
/**
*Submitted for verification at Etherscan.io on 2018-04-30
*/
pragma solidity 0.4.18;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
uint256 public totalSupply;
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address 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;
}
}
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
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;
}
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;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
}
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* @dev https://github.com/ethereum/EIPs/issues/20
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) internal allowed;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
Transfer(_from, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
*
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address _owner, address _spender) public view returns (uint256) {
return allowed[_owner][_spender];
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
*
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _addedValue The amount of tokens to increase the allowance by.
*/
function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
*
* approve should be called when allowed[_spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
uint oldValue = allowed[msg.sender][_spender];
if (_subtractedValue > oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
/**
* @title Mintable token
* @dev Simple ERC20 Token example, with mintable token creation
* @dev Issue: * https://github.com/OpenZeppelin/zeppelin-solidity/issues/120
* Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
*/
contract MintableToken is StandardToken, Ownable {
event Mint(address indexed to, uint256 amount);
event MintFinished();
bool public mintingFinished = false;
modifier canMint() {
require(!mintingFinished);
_;
}
/**
* @dev Function to mint tokens
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
totalSupply = totalSupply.add(_amount);
balances[_to] = balances[_to].add(_amount);
Mint(_to, _amount);
Transfer(address(0), _to, _amount);
return true;
}
/**
* @dev Function to stop minting new tokens.
* @return True if the operation was successful.
*/
function finishMinting() onlyOwner canMint public returns (bool) {
mintingFinished = true;
MintFinished();
return true;
}
}
contract VariableSupplyToken is MintableToken {
event Burn(address indexed burner, uint256 value);
/*
* @dev Burns a specific amount of the sender's tokens
* @param _value The amount of tokens to be burned
*/
function burn(uint256 _amount) public {
// Must not burn more than the sender owns
require(_amount <= balances[msg.sender]);
address burner = msg.sender;
balances[burner] = balances[burner].sub(_amount);
totalSupply = totalSupply.sub(_amount);
Burn(burner, _amount);
}
}
contract ILivepeerToken is ERC20, Ownable {
function mint(address _to, uint256 _amount) public returns (bool);
function burn(uint256 _amount) public;
}
contract LivepeerToken is ILivepeerToken, VariableSupplyToken {
string public name = "Livepeer Token";
uint8 public decimals = 18;
string public symbol = "LPT";
string public version = "0.1";
}File 3 of 3: MerkleProof
pragma solidity 0.4.18;
/*
* @title MerkleProof
* @dev Merkle proof verification
* @note Based on https://github.com/ameensol/merkle-tree-solidity/blob/master/src/MerkleProof.sol
*/
library MerkleProof {
/*
* @dev Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves
* and each pair of pre-images is sorted.
* @param _proof Merkle proof containing sibling hashes on the branch from the leaf to the root of the Merkle tree
* @param _root Merkle root
* @param _leaf Leaf of Merkle tree
*/
function verifyProof(bytes _proof, bytes32 _root, bytes32 _leaf) public pure returns (bool) {
// Check if proof length is a multiple of 32
if (_proof.length % 32 != 0) return false;
bytes32 proofElement;
bytes32 computedHash = _leaf;
for (uint256 i = 32; i <= _proof.length; i += 32) {
assembly {
// Load the current element of the proof
proofElement := mload(add(_proof, i))
}
if (computedHash < proofElement) {
// Hash(current computed hash + current element of the proof)
computedHash = keccak256(computedHash, proofElement);
} else {
// Hash(current element of the proof + current computed hash)
computedHash = keccak256(proofElement, computedHash);
}
}
// Check if the computed hash (root) is equal to the provided root
return computedHash == _root;
}
}