Transaction Hash:
Block:
6399926 at Sep-26-2018 12:33:34 AM +UTC
Transaction Fee:
0.00685758128 ETH
$14.60
Gas Used:
758,582 Gas / 9.04 Gwei
Emitted Events:
| 103 |
LivepeerToken.Transfer( from=MerkleMine, to=[Receiver] MultiMerkleMine, value=357295353344847003 )
|
| 104 |
LivepeerToken.Transfer( from=MerkleMine, to=0x3B6374efF72490d99C7c54f060B084C781a0ffb0, value=2084400812772245255 )
|
| 105 |
MerkleMine.Generate( _recipient=0x3B6374efF72490d99C7c54f060B084C781a0ffb0, _caller=[Receiver] MultiMerkleMine, _recipientTokenAmount=2084400812772245255, _callerTokenAmount=357295353344847003, _block=6399926 )
|
| 106 |
LivepeerToken.Transfer( from=MerkleMine, to=[Receiver] MultiMerkleMine, value=357295353344847003 )
|
| 107 |
LivepeerToken.Transfer( from=MerkleMine, to=0x3b638C34332A8aB737990cDc9d896806042FD032, value=2084400812772245255 )
|
| 108 |
MerkleMine.Generate( _recipient=0x3b638C34332A8aB737990cDc9d896806042FD032, _caller=[Receiver] MultiMerkleMine, _recipientTokenAmount=2084400812772245255, _callerTokenAmount=357295353344847003, _block=6399926 )
|
| 109 |
LivepeerToken.Transfer( from=MerkleMine, to=[Receiver] MultiMerkleMine, value=357295353344847003 )
|
| 110 |
LivepeerToken.Transfer( from=MerkleMine, to=0x3B63B3bf0f90FD298e5e556C2097a33b5De8a067, value=2084400812772245255 )
|
| 111 |
MerkleMine.Generate( _recipient=0x3B63B3bf0f90FD298e5e556C2097a33b5De8a067, _caller=[Receiver] MultiMerkleMine, _recipientTokenAmount=2084400812772245255, _callerTokenAmount=357295353344847003, _block=6399926 )
|
| 112 |
LivepeerToken.Transfer( from=MerkleMine, to=[Receiver] MultiMerkleMine, value=357295353344847003 )
|
| 113 |
LivepeerToken.Transfer( from=MerkleMine, to=0x3B63cF7b0C05D4D626702015102a2489A19d9Ca3, value=2084400812772245255 )
|
| 114 |
MerkleMine.Generate( _recipient=0x3B63cF7b0C05D4D626702015102a2489A19d9Ca3, _caller=[Receiver] MultiMerkleMine, _recipientTokenAmount=2084400812772245255, _callerTokenAmount=357295353344847003, _block=6399926 )
|
| 115 |
LivepeerToken.Transfer( from=MerkleMine, to=[Receiver] MultiMerkleMine, value=357295353344847003 )
|
| 116 |
LivepeerToken.Transfer( from=MerkleMine, to=0x3b63DD076184Ae837bFC8b80C244C7f964e1a9b9, value=2084400812772245255 )
|
| 117 |
MerkleMine.Generate( _recipient=0x3b63DD076184Ae837bFC8b80C244C7f964e1a9b9, _caller=[Receiver] MultiMerkleMine, _recipientTokenAmount=2084400812772245255, _callerTokenAmount=357295353344847003, _block=6399926 )
|
| 118 |
LivepeerToken.Transfer( from=[Receiver] MultiMerkleMine, to=[Sender] 0x4830116608c1f6aa444149d9cb32a5abf5f1c72a, value=1786476766724235015 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x48301166...bF5f1c72a |
0.267915116523210608 Eth
Nonce: 5688
|
0.261057535243210608 Eth
Nonce: 5689
| 0.00685758128 | ||
|
0x52bc44d5...b7d7bE3b5
Miner
| (Nanopool) | 8,124.296833443439183749 Eth | 8,124.303691024719183749 Eth | 0.00685758128 | |
| 0x58b6A8A3...e733aB239 | |||||
| 0x8e306b00...766cC15c8 | (Livepeer: Merkle Mine) |
Execution Trace
MultiMerkleMine.multiGenerate( _merkleMineContract=0x8e306b005773bee6bA6A6e8972Bc79D766cC15c8, _recipients=[0x3B6374efF72490d99C7c54f060B084C781a0ffb0, 0x3b638C34332A8aB737990cDc9d896806042FD032, 0x3B63B3bf0f90FD298e5e556C2097a33b5De8a067, 0x3B63cF7b0C05D4D626702015102a2489A19d9Ca3, 0x3b63DD076184Ae837bFC8b80C244C7f964e1a9b9], _merkleProofs=0x00000000000000000000000000000000000000000000000000000000000002C0B47028439DF94124A09D1009732155CB94E306A53305065A7F0B8F4642AA5335505B9E983126BB790964FC354860E44FCD05D207A0D064BA9FA3C2B0B7F7052BC11F7E1C66811C36E7BE377388562A6AD375B1BE930983219B108900E9190555DDA9FB579A4E5E1C502B2046818445EB993D27BFC114F340F75C5C36D7AA8BBD6352D91C2C96C1E4F5881FDA00BAF5AF0C22DDCB00350F8F6E266CA4759DE584878CB387F5978342498DE3F9AE703E7C4387DE0A821E94574D465B1BF758B999C9951FD49E38779F604CD1AAF392E328357A08CA5C6085337EB5B7ADF44AF58371B854D2BF9E31B1EF88F5A47C8D741DF1D27912389B767FAD6CADF65067BAE6B6C1D5BD583B0080978BD84013EF29D489E6CB40C14ECEBC8ECCB306895C390F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC300000000000000000000000000000000000000000000000000000000000002C07D73EB1F588755E3191A30722435C2F4C66EA556363CBF4BB8405D29C322229E787FA3C41189CDFCB36F542DF5328418F5A374784262192A913DBD0B07BD779E6BABF95E1684FD6922DE097EDD8C808BB1B21B31C816DCC31DC312779F564EB8D0C26163E90A3FBC0F2F90FEF7F3B85A981FC4C29E7F5065A0B3380DAC2BF04F6352D91C2C96C1E4F5881FDA00BAF5AF0C22DDCB00350F8F6E266CA4759DE584878CB387F5978342498DE3F9AE703E7C4387DE0A821E94574D465B1BF758B999C9951FD49E38779F604CD1AAF392E328357A08CA5C6085337EB5B7ADF44AF58371B854D2BF9E31B1EF88F5A47C8D741DF1D27912389B767FAD6CADF65067BAE6B6C1D5BD583B0080978BD84013EF29D489E6CB40C14ECEBC8ECCB306895C390F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC300000000000000000000000000000000000000000000000000000000000002C08FA733725CE993BFBAFE64CF0B7DEEF59197CE51E223555D41B458B312ACCBEC5103D18B24DEC0DC3D90E0929A1DBA85AE41F8CE3D7C84135D6F37ECC81BA74415B3DE5D7B14B0989A4112911F1ACD8F19A1970B726126016B5676C99BE5DC39DD078715E7746C0BF870D5B4487E5CB05C3B623B174F2FA8C36864EAF917247801AC31BAFD600B0C10E92B625927890AE22A120542A0C1D0DD21EA02A7250C558D3FC421AEDA2A64929D6D4367D9386FD80129FE913E64E3886055CEA199BDA425890299CADB39AA20CC808CDD473201B4006238381B4EBDA918E04AE5ABD15C96D9CF9D36A39DFF971C88888B38D5BFC44D85980B1E4555C13F2A82DFF56FCA47BF237E597FC3E07A0E15EF791DE946090DB75E20A2FE514C32D6A177B18E9F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC300000000000000000000000000000000000000000000000000000000000002C08B4AC23C9151E615E6981C4EC5663CA4C3D5232A13BE3EA7497A1BB504D6823B2C3524C7D6FC8B9D955BA4F3A766F5AF59BF94A7DE3DE7BEB73247BD850F040611EF2C6206DFB3FEBE6F2D715BC985676661992A2353D24ACA09D561EF1DE8A8DD078715E7746C0BF870D5B4487E5CB05C3B623B174F2FA8C36864EAF917247801AC31BAFD600B0C10E92B625927890AE22A120542A0C1D0DD21EA02A7250C558D3FC421AEDA2A64929D6D4367D9386FD80129FE913E64E3886055CEA199BDA425890299CADB39AA20CC808CDD473201B4006238381B4EBDA918E04AE5ABD15C96D9CF9D36A39DFF971C88888B38D5BFC44D85980B1E4555C13F2A82DFF56FCA47BF237E597FC3E07A0E15EF791DE946090DB75E20A2FE514C32D6A177B18E9F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC300000000000000000000000000000000000000000000000000000000000002C065545DDA88FA0B5423E92201DB2FA20445BD148566430637DCBD5542384D214B7C7A1ABA0ACC0545567219224E379194A791BA76AE3075B660513FACF22393FC47A63717EF236A73B750BFC0AE71A25618DFF436C99765E298A9C10846F9C79E9305E440C1C5726BE6AFF5437428D88D91225C01DFE5CDC8A134BD44BCEF37B101AC31BAFD600B0C10E92B625927890AE22A120542A0C1D0DD21EA02A7250C558D3FC421AEDA2A64929D6D4367D9386FD80129FE913E64E3886055CEA199BDA425890299CADB39AA20CC808CDD473201B4006238381B4EBDA918E04AE5ABD15C96D9CF9D36A39DFF971C88888B38D5BFC44D85980B1E4555C13F2A82DFF56FCA47BF237E597FC3E07A0E15EF791DE946090DB75E20A2FE514C32D6A177B18E9F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3 )
-
MerkleMine.CALL( ) -
MerkleMine.CALL( ) -
LivepeerToken.balanceOf( _owner=0xBfd0fb15e6C04b396EA12f5BB9Ba803E29B282Be ) => ( balance=0 )
-
MerkleMine.generated( 0x3B6374efF72490d99C7c54f060B084C781a0ffb0 ) => ( False ) MerkleMine.generate( _recipient=0x3B6374efF72490d99C7c54f060B084C781a0ffb0, _merkleProof=0xB47028439DF94124A09D1009732155CB94E306A53305065A7F0B8F4642AA5335505B9E983126BB790964FC354860E44FCD05D207A0D064BA9FA3C2B0B7F7052BC11F7E1C66811C36E7BE377388562A6AD375B1BE930983219B108900E9190555DDA9FB579A4E5E1C502B2046818445EB993D27BFC114F340F75C5C36D7AA8BBD6352D91C2C96C1E4F5881FDA00BAF5AF0C22DDCB00350F8F6E266CA4759DE584878CB387F5978342498DE3F9AE703E7C4387DE0A821E94574D465B1BF758B999C9951FD49E38779F604CD1AAF392E328357A08CA5C6085337EB5B7ADF44AF58371B854D2BF9E31B1EF88F5A47C8D741DF1D27912389B767FAD6CADF65067BAE6B6C1D5BD583B0080978BD84013EF29D489E6CB40C14ECEBC8ECCB306895C390F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3 )-
MerkleProof.verifyProof( _proof=0xB47028439DF94124A09D1009732155CB94E306A53305065A7F0B8F4642AA5335505B9E983126BB790964FC354860E44FCD05D207A0D064BA9FA3C2B0B7F7052BC11F7E1C66811C36E7BE377388562A6AD375B1BE930983219B108900E9190555DDA9FB579A4E5E1C502B2046818445EB993D27BFC114F340F75C5C36D7AA8BBD6352D91C2C96C1E4F5881FDA00BAF5AF0C22DDCB00350F8F6E266CA4759DE584878CB387F5978342498DE3F9AE703E7C4387DE0A821E94574D465B1BF758B999C9951FD49E38779F604CD1AAF392E328357A08CA5C6085337EB5B7ADF44AF58371B854D2BF9E31B1EF88F5A47C8D741DF1D27912389B767FAD6CADF65067BAE6B6C1D5BD583B0080978BD84013EF29D489E6CB40C14ECEBC8ECCB306895C390F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3, _root=53F35A304A1E1E20D6648E09BB3073CCD44A5BF1638A01355897A71E801879F8, _leaf=E2B390B1FE727478F19983FDA1FB8F597CC703410024AD03C243B10805D335D3 ) => ( True ) -
LivepeerToken.transfer( _to=0xBfd0fb15e6C04b396EA12f5BB9Ba803E29B282Be, _value=357295353344847003 ) => ( True )
-
LivepeerToken.transfer( _to=0x3B6374efF72490d99C7c54f060B084C781a0ffb0, _value=2084400812772245255 ) => ( True )
-
-
MerkleMine.generated( 0x3b638C34332A8aB737990cDc9d896806042FD032 ) => ( False ) MerkleMine.generate( _recipient=0x3b638C34332A8aB737990cDc9d896806042FD032, _merkleProof=0x7D73EB1F588755E3191A30722435C2F4C66EA556363CBF4BB8405D29C322229E787FA3C41189CDFCB36F542DF5328418F5A374784262192A913DBD0B07BD779E6BABF95E1684FD6922DE097EDD8C808BB1B21B31C816DCC31DC312779F564EB8D0C26163E90A3FBC0F2F90FEF7F3B85A981FC4C29E7F5065A0B3380DAC2BF04F6352D91C2C96C1E4F5881FDA00BAF5AF0C22DDCB00350F8F6E266CA4759DE584878CB387F5978342498DE3F9AE703E7C4387DE0A821E94574D465B1BF758B999C9951FD49E38779F604CD1AAF392E328357A08CA5C6085337EB5B7ADF44AF58371B854D2BF9E31B1EF88F5A47C8D741DF1D27912389B767FAD6CADF65067BAE6B6C1D5BD583B0080978BD84013EF29D489E6CB40C14ECEBC8ECCB306895C390F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3 )-
MerkleProof.verifyProof( _proof=0x7D73EB1F588755E3191A30722435C2F4C66EA556363CBF4BB8405D29C322229E787FA3C41189CDFCB36F542DF5328418F5A374784262192A913DBD0B07BD779E6BABF95E1684FD6922DE097EDD8C808BB1B21B31C816DCC31DC312779F564EB8D0C26163E90A3FBC0F2F90FEF7F3B85A981FC4C29E7F5065A0B3380DAC2BF04F6352D91C2C96C1E4F5881FDA00BAF5AF0C22DDCB00350F8F6E266CA4759DE584878CB387F5978342498DE3F9AE703E7C4387DE0A821E94574D465B1BF758B999C9951FD49E38779F604CD1AAF392E328357A08CA5C6085337EB5B7ADF44AF58371B854D2BF9E31B1EF88F5A47C8D741DF1D27912389B767FAD6CADF65067BAE6B6C1D5BD583B0080978BD84013EF29D489E6CB40C14ECEBC8ECCB306895C390F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3, _root=53F35A304A1E1E20D6648E09BB3073CCD44A5BF1638A01355897A71E801879F8, _leaf=A5FA0131EB655CA2293A06D34D6A00B41015AD007EA27A06B920A2D74D1102AA ) => ( True ) -
LivepeerToken.transfer( _to=0xBfd0fb15e6C04b396EA12f5BB9Ba803E29B282Be, _value=357295353344847003 ) => ( True )
-
LivepeerToken.transfer( _to=0x3b638C34332A8aB737990cDc9d896806042FD032, _value=2084400812772245255 ) => ( True )
-
-
MerkleMine.generated( 0x3B63B3bf0f90FD298e5e556C2097a33b5De8a067 ) => ( False ) MerkleMine.generate( _recipient=0x3B63B3bf0f90FD298e5e556C2097a33b5De8a067, _merkleProof=0x8FA733725CE993BFBAFE64CF0B7DEEF59197CE51E223555D41B458B312ACCBEC5103D18B24DEC0DC3D90E0929A1DBA85AE41F8CE3D7C84135D6F37ECC81BA74415B3DE5D7B14B0989A4112911F1ACD8F19A1970B726126016B5676C99BE5DC39DD078715E7746C0BF870D5B4487E5CB05C3B623B174F2FA8C36864EAF917247801AC31BAFD600B0C10E92B625927890AE22A120542A0C1D0DD21EA02A7250C558D3FC421AEDA2A64929D6D4367D9386FD80129FE913E64E3886055CEA199BDA425890299CADB39AA20CC808CDD473201B4006238381B4EBDA918E04AE5ABD15C96D9CF9D36A39DFF971C88888B38D5BFC44D85980B1E4555C13F2A82DFF56FCA47BF237E597FC3E07A0E15EF791DE946090DB75E20A2FE514C32D6A177B18E9F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3 )-
MerkleProof.verifyProof( _proof=0x8FA733725CE993BFBAFE64CF0B7DEEF59197CE51E223555D41B458B312ACCBEC5103D18B24DEC0DC3D90E0929A1DBA85AE41F8CE3D7C84135D6F37ECC81BA74415B3DE5D7B14B0989A4112911F1ACD8F19A1970B726126016B5676C99BE5DC39DD078715E7746C0BF870D5B4487E5CB05C3B623B174F2FA8C36864EAF917247801AC31BAFD600B0C10E92B625927890AE22A120542A0C1D0DD21EA02A7250C558D3FC421AEDA2A64929D6D4367D9386FD80129FE913E64E3886055CEA199BDA425890299CADB39AA20CC808CDD473201B4006238381B4EBDA918E04AE5ABD15C96D9CF9D36A39DFF971C88888B38D5BFC44D85980B1E4555C13F2A82DFF56FCA47BF237E597FC3E07A0E15EF791DE946090DB75E20A2FE514C32D6A177B18E9F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3, _root=53F35A304A1E1E20D6648E09BB3073CCD44A5BF1638A01355897A71E801879F8, _leaf=7B401AFEF6A9C6A81F68455C121070A66D31610DD6E8E9531081C643340B4AF8 ) => ( True ) -
LivepeerToken.transfer( _to=0xBfd0fb15e6C04b396EA12f5BB9Ba803E29B282Be, _value=357295353344847003 ) => ( True )
-
LivepeerToken.transfer( _to=0x3B63B3bf0f90FD298e5e556C2097a33b5De8a067, _value=2084400812772245255 ) => ( True )
-
-
MerkleMine.generated( 0x3B63cF7b0C05D4D626702015102a2489A19d9Ca3 ) => ( False ) MerkleMine.generate( _recipient=0x3B63cF7b0C05D4D626702015102a2489A19d9Ca3, _merkleProof=0x8B4AC23C9151E615E6981C4EC5663CA4C3D5232A13BE3EA7497A1BB504D6823B2C3524C7D6FC8B9D955BA4F3A766F5AF59BF94A7DE3DE7BEB73247BD850F040611EF2C6206DFB3FEBE6F2D715BC985676661992A2353D24ACA09D561EF1DE8A8DD078715E7746C0BF870D5B4487E5CB05C3B623B174F2FA8C36864EAF917247801AC31BAFD600B0C10E92B625927890AE22A120542A0C1D0DD21EA02A7250C558D3FC421AEDA2A64929D6D4367D9386FD80129FE913E64E3886055CEA199BDA425890299CADB39AA20CC808CDD473201B4006238381B4EBDA918E04AE5ABD15C96D9CF9D36A39DFF971C88888B38D5BFC44D85980B1E4555C13F2A82DFF56FCA47BF237E597FC3E07A0E15EF791DE946090DB75E20A2FE514C32D6A177B18E9F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3 )-
MerkleProof.verifyProof( _proof=0x8B4AC23C9151E615E6981C4EC5663CA4C3D5232A13BE3EA7497A1BB504D6823B2C3524C7D6FC8B9D955BA4F3A766F5AF59BF94A7DE3DE7BEB73247BD850F040611EF2C6206DFB3FEBE6F2D715BC985676661992A2353D24ACA09D561EF1DE8A8DD078715E7746C0BF870D5B4487E5CB05C3B623B174F2FA8C36864EAF917247801AC31BAFD600B0C10E92B625927890AE22A120542A0C1D0DD21EA02A7250C558D3FC421AEDA2A64929D6D4367D9386FD80129FE913E64E3886055CEA199BDA425890299CADB39AA20CC808CDD473201B4006238381B4EBDA918E04AE5ABD15C96D9CF9D36A39DFF971C88888B38D5BFC44D85980B1E4555C13F2A82DFF56FCA47BF237E597FC3E07A0E15EF791DE946090DB75E20A2FE514C32D6A177B18E9F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3, _root=53F35A304A1E1E20D6648E09BB3073CCD44A5BF1638A01355897A71E801879F8, _leaf=FA902EBD5E7FF762A69C606EB8D3345A0A5B8318893752F7B326A9B91F0B8998 ) => ( True ) -
LivepeerToken.transfer( _to=0xBfd0fb15e6C04b396EA12f5BB9Ba803E29B282Be, _value=357295353344847003 ) => ( True )
-
LivepeerToken.transfer( _to=0x3B63cF7b0C05D4D626702015102a2489A19d9Ca3, _value=2084400812772245255 ) => ( True )
-
-
MerkleMine.generated( 0x3b63DD076184Ae837bFC8b80C244C7f964e1a9b9 ) => ( False ) MerkleMine.generate( _recipient=0x3b63DD076184Ae837bFC8b80C244C7f964e1a9b9, _merkleProof=0x65545DDA88FA0B5423E92201DB2FA20445BD148566430637DCBD5542384D214B7C7A1ABA0ACC0545567219224E379194A791BA76AE3075B660513FACF22393FC47A63717EF236A73B750BFC0AE71A25618DFF436C99765E298A9C10846F9C79E9305E440C1C5726BE6AFF5437428D88D91225C01DFE5CDC8A134BD44BCEF37B101AC31BAFD600B0C10E92B625927890AE22A120542A0C1D0DD21EA02A7250C558D3FC421AEDA2A64929D6D4367D9386FD80129FE913E64E3886055CEA199BDA425890299CADB39AA20CC808CDD473201B4006238381B4EBDA918E04AE5ABD15C96D9CF9D36A39DFF971C88888B38D5BFC44D85980B1E4555C13F2A82DFF56FCA47BF237E597FC3E07A0E15EF791DE946090DB75E20A2FE514C32D6A177B18E9F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3 )-
MerkleProof.verifyProof( _proof=0x65545DDA88FA0B5423E92201DB2FA20445BD148566430637DCBD5542384D214B7C7A1ABA0ACC0545567219224E379194A791BA76AE3075B660513FACF22393FC47A63717EF236A73B750BFC0AE71A25618DFF436C99765E298A9C10846F9C79E9305E440C1C5726BE6AFF5437428D88D91225C01DFE5CDC8A134BD44BCEF37B101AC31BAFD600B0C10E92B625927890AE22A120542A0C1D0DD21EA02A7250C558D3FC421AEDA2A64929D6D4367D9386FD80129FE913E64E3886055CEA199BDA425890299CADB39AA20CC808CDD473201B4006238381B4EBDA918E04AE5ABD15C96D9CF9D36A39DFF971C88888B38D5BFC44D85980B1E4555C13F2A82DFF56FCA47BF237E597FC3E07A0E15EF791DE946090DB75E20A2FE514C32D6A177B18E9F385EBFE9D279E1AB055441BFBA2D5638E23DEAE3CB2481A6EB083FC422F2AD150A5804D25B83A60CA73B19399226C6C22CDF6A8C0F14DFA59E5C0A17A6E4FBBBEB8C56CE45C4B49F1DDEDCBD9CC222BC5B396353413D2495407EE7C14CDCCC9C36CF26A6E552373A0951DFEA8CB5F78496B8C05BC2BA893CD49A585D54168D583CCF190318996DFCDAD086A523EB84973EE880BF270F05787A2C10A3CF609D5077C8C8988A91E4EF5AF85ED3F54126D4BC8299541C698F63C56C7AFE900AEE88925761081D23A5BF567596EA50EEE4822D8F9F6234F2D92F50A548FBF24CBB3A5733B7690227C94E3780B05AB4CC16027E5F5C15B2F304C86FE7668C2CC88C4946325B2D95526F40211F79B088369F2C22B44975413790EC990DE87D939A97C709A8F3F5B413E2D7187DEDEF2CE22DC5DDF0C86E42913DF72261BF1246958497B44EF0309B36AB364CCF72EAE1F219DB188ACBC7821CDD57D053CA5E37DFA1FC7460F55592404A5BD804DD4060FBBAF11A6BDC0557C70C812EC5CD9AA8007ED51E74A86B2F0ACEAA39987CE1EE5E1150DC99DB6336CCA1BF9A005C776D0E3FC3, _root=53F35A304A1E1E20D6648E09BB3073CCD44A5BF1638A01355897A71E801879F8, _leaf=856056F29941CB6E188F76C61A166C708BBFD2CF64FC91C70261072E76E4B2D5 ) => ( True ) -
LivepeerToken.transfer( _to=0xBfd0fb15e6C04b396EA12f5BB9Ba803E29B282Be, _value=357295353344847003 ) => ( True )
-
LivepeerToken.transfer( _to=0x3b63DD076184Ae837bFC8b80C244C7f964e1a9b9, _value=2084400812772245255 ) => ( True )
-
-
LivepeerToken.balanceOf( _owner=0xBfd0fb15e6C04b396EA12f5BB9Ba803E29B282Be ) => ( balance=1786476766724235015 )
-
LivepeerToken.transfer( _to=0x4830116608C1F6aA444149D9cB32A5AbF5f1c72a, _value=1786476766724235015 ) => ( True )
multiGenerate[MultiMerkleMine (ln:388)]
token[MultiMerkleMine (ln:390)]callerAllocationStartBlock[MultiMerkleMine (ln:393)]balanceOf[MultiMerkleMine (ln:397)]readBytes32[MultiMerkleMine (ln:407)]dataPtr[BytesUtil (ln:364)]
substr[MultiMerkleMine (ln:414)]dataPtr[BytesUtil (ln:352)]toBytes[BytesUtil (ln:353)]dataPtr[BytesUtil (ln:333)]copy[BytesUtil (ln:334)]
generated[MultiMerkleMine (ln:428)]generate[MultiMerkleMine (ln:429)]balanceOf[MultiMerkleMine (ln:433)]sub[MultiMerkleMine (ln:434)]transfer[MultiMerkleMine (ln:438)]
File 1 of 4: MultiMerkleMine
File 2 of 4: MerkleMine
File 3 of 4: LivepeerToken
File 4 of 4: MerkleProof
pragma solidity 0.4.24;
/**
* @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);
}
}
}
/**
* @title BytesUtil
* @dev Utilities for extracting bytes from byte arrays
* Functions taken from:
* - https://github.com/ethereum/solidity-examples/blob/master/src/unsafe/Memory.sol
* - https://github.com/ethereum/solidity-examples/blob/master/src/bytes/Bytes.sol
*/
library BytesUtil{
uint256 internal constant BYTES_HEADER_SIZE = 32;
uint256 internal constant WORD_SIZE = 32;
/**
* @dev Returns a memory pointer to the data portion of the provided bytes array.
* @param bts Memory byte array
*/
function dataPtr(bytes memory bts) internal pure returns (uint256 addr) {
assembly {
addr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
}
/**
* @dev Copy 'len' bytes from memory address 'src', to address 'dest'.
* This function does not check the or destination, it only copies
* the bytes.
* @param src Memory address of source byte array
* @param dest Memory address of destination byte array
* @param len Number of bytes to copy from `src` to `dest`
*/
function copy(uint256 src, uint256 dest, uint256 len) internal pure {
// Copy word-length chunks while possible
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
dest += WORD_SIZE;
src += WORD_SIZE;
}
// Copy remaining bytes
uint256 mask = 256 ** (WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
/**
* @dev Creates a 'bytes memory' variable from the memory address 'addr', with the
* length 'len'. The function will allocate new memory for the bytes array, and
* the 'len bytes starting at 'addr' will be copied into that new memory.
* @param addr Memory address of input byte array
* @param len Number of bytes to copy from input byte array
*/
function toBytes(uint256 addr, uint256 len) internal pure returns (bytes memory bts) {
bts = new bytes(len);
uint256 btsptr = dataPtr(bts);
copy(addr, btsptr, len);
}
/**
* @dev Copies 'len' bytes from 'bts' into a new array, starting at the provided 'startIndex'.
* Returns the new copy.
* Requires that:
* - 'startIndex + len <= self.length'
* The length of the substring is: 'len'
* @param bts Memory byte array to copy from
* @param startIndex Index of `bts` to start copying bytes from
* @param len Number of bytes to copy from `bts`
*/
function substr(bytes memory bts, uint256 startIndex, uint256 len) internal pure returns (bytes memory) {
require(startIndex + len <= bts.length);
if (len == 0) {
return;
}
uint256 addr = dataPtr(bts);
return toBytes(addr + startIndex, len);
}
/**
* @dev Reads a bytes32 value from a byte array by copying 32 bytes from `bts` starting at the provided `startIndex`.
* @param bts Memory byte array to copy from
* @param startIndex Index of `bts` to start copying bytes from
*/
function readBytes32(bytes memory bts, uint256 startIndex) internal pure returns (bytes32 result) {
require(startIndex + 32 <= bts.length);
uint256 addr = dataPtr(bts);
assembly {
result := mload(add(addr, startIndex))
}
return result;
}
}
/**
* @title MultiMerkleMine
* @dev The MultiMerkleMine contract is purely a convenience wrapper around an existing MerkleMine contract deployed on the blockchain.
*/
contract MultiMerkleMine {
using SafeMath for uint256;
/**
* @dev Generates token allocations for multiple recipients. Generation period must be started.
* @param _merkleMineContract Address of the deployed MerkleMine contract
* @param _recipients Array of recipients
* @param _merkleProofs Proofs for respective recipients constructed in the format:
* [proof_1_size, proof_1, proof_2_size, proof_2, ... , proof_n_size, proof_n]
*/
function multiGenerate(address _merkleMineContract, address[] _recipients, bytes _merkleProofs) public {
MerkleMine mine = MerkleMine(_merkleMineContract);
ERC20 token = ERC20(mine.token());
require(
block.number >= mine.callerAllocationStartBlock(),
"caller allocation period has not started"
);
uint256 initialBalance = token.balanceOf(this);
bytes[] memory proofs = new bytes[](_recipients.length);
// Counter to keep track of position in `_merkleProofs` byte array
uint256 i = 0;
// Counter to keep track of index of each extracted Merkle proof
uint256 j = 0;
// Extract proofs
while(i < _merkleProofs.length){
uint256 proofSize = uint256(BytesUtil.readBytes32(_merkleProofs, i));
require(
proofSize % 32 == 0,
"proof size must be a multiple of 32"
);
proofs[j] = BytesUtil.substr(_merkleProofs, i + 32, proofSize);
i = i + 32 + proofSize;
j++;
}
require(
_recipients.length == j,
"number of recipients != number of proofs"
);
for (uint256 k = 0; k < _recipients.length; k++) {
// If recipient's token allocation has not been generated, generate the token allocation
// Else, continue to the next recipient
if (!mine.generated(_recipients[k])) {
mine.generate(_recipients[k], proofs[k]);
}
}
uint256 newBalanceSinceAllocation = token.balanceOf(this);
uint256 callerTokensGenerated = newBalanceSinceAllocation.sub(initialBalance);
// Transfer caller's portion of tokens generated by this function call
if (callerTokensGenerated > 0) {
require(token.transfer(msg.sender, callerTokensGenerated));
}
}
}File 2 of 4: MerkleMine
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 3 of 4: 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 4 of 4: 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;
}
}