├── .gitattributes ├── .github └── FUNDING.yml ├── LICENSE ├── README.md ├── bin └── solidity │ ├── AirDropChannels-solc-output.json │ ├── AirdropChannels.abi │ ├── AirdropChannels.bin │ ├── AirdropChannels.json │ ├── ChannelsV4-solc-output.json │ ├── ChannelsV5-solc-output.json │ ├── PaymentChannels.abi │ ├── PaymentChannels.bin │ └── PaymentChannels.json ├── compilers └── soljson_v070.js ├── notes └── how_to.txt ├── python ├── .t.swo ├── .t.swp └── signer.py ├── solidity ├── AirDropChannels.sol ├── ChannelsV3.sol ├── ChannelsV4.sol ├── ChannelsV5.sol ├── Interfaces │ └── ERC20Interface.sol ├── Libs │ └── EcRecovery.sol ├── Math │ └── SafeMath.sol ├── Modules │ └── Administration.sol └── old │ ├── ChannelsV1.sol │ ├── ChannelsV2.sol │ ├── DateTime.sol │ ├── TestToken.sol │ ├── TimeApi.sol │ ├── micro.sol │ └── re_report.report └── src └── airdrop ├── airdrop ├── bindings └── airdrop_channels.go └── main.go /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [bonedaddy] 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Postables-Payment-Channel 2 | 3 | > **warning: none of this code is audited use at your own risk** 4 | 5 | Postables-Payment-Channel is a collection of easy to use smart contracts that can be used to facilitate arbitrary ERC20 and ETH payment channels between two parties, as well as an extremely cheap method of distributing airdrops using signed messages instead of mass transaction broadcasting called "AirDropChannels". 6 | 7 | The payment channels are robust allowing for any ERC20 to be used, along with ETH itself. The channels support micro payments allowing a party to withdraw micro amounts from the channels available balance. This is useful in situations where the two parties may want the trust that comes with payment channels, but don't want to end the channel by withdrawing funds from it as is typical with the standard payment channel examples. This can be very useful if you are paying a contractor, and the contractor wants the assurance that all the funds they are being promised actually exist, but you don't want to pay them for work they haven't done yet. 8 | 9 | AirDropChannels are a slightly modified payment channel concept, but instead of one-to-one unidirectional channels, it is a one-to-many unidirectional channel, allowing any number of parties to withdraw tokens from the channel! This can be used to facilitate stupidly cheap airdrops! Gone are the days of airdrops costing the token develop tens of thousands of dollars. One of the benefits to using this method of airdrops, is that unclaimed tokens are refunded back to the token developers wallet as soon as they close the channel! No more wasted money from tokens floating around in unused addresses for ethernity! 10 | 11 | In addition golang, as well as **very** out of date python bindings exist to interact with the contracts using go-ethereum (go) and web3py (python). 12 | 13 | # Files 14 | 15 | - solidity/AirDropChannels.sol (modified payment channel allowing for cheap airdrops) 16 | - solidity/ChannelsV3.sol (base channel setup, no micropayment) 17 | - solidity/ChannelsV4.sol (base channel setup, micropayments) 18 | - solidity/ChannelsV5.sol (WIP) 19 | 20 | # Bugs and Fixes 21 | 22 | ## Improper address returned from signature verification using python bindings 23 | 24 | > **note: this uses a very out of date version of web3py ** 25 | 26 | ``` 27 | >>> private 28 | b'\xd8Y\xe3T\xb8\x15\xaaJ\xe6i\xaf\xf9\x02\x8a\xbf\x89#\xf9D\x03\xdd\tc\xf2\xed\xc3\x9eQ\r\x98\xb7|' 29 | >>> signature = w3.eth.account.sign(message_text="hello", private_key=private) 30 | 31 | AttributeDict({'message': HexBytes('0x68656c6c6f'), 'messageHash': HexBytes('0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750'), 'r': 53665784189267139251820747046956462498355115993943239404465477346598658281299, 's': 6629064374810355767282561830725699037469490635953226814818888019755260187756, 'v': 27, 'signature': HexBytes('0x76a5c1e7f682df3375a2bdd6f72ad2171b0cf826fc8a8a3209c33a4e57e88f530ea7eadf8603ba2c4a5c5006571be7665020812aa7e403a614587cfe7a18146c1b')}) 32 | >>> h = Web3.toHex(signature.messageHash) 33 | >>> v = signature.v 34 | >>> r = Web3.toHex(signature.r) 35 | >>> s = Web3.toHex(signature.s) 36 | >>> h 37 | '0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750' 38 | >>> v 39 | 27 40 | >>> r 41 | '0x76a5c1e7f682df3375a2bdd6f72ad2171b0cf826fc8a8a3209c33a4e57e88f53' 42 | >>> s 43 | '0xea7eadf8603ba2c4a5c5006571be7665020812aa7e403a614587cfe7a18146c' 44 | >>> Web3.toHex(Web3.toBytes(signature.s)) 45 | '0x0ea7eadf8603ba2c4a5c5006571be7665020812aa7e403a614587cfe7a18146c' (returns the correct address) 46 | ``` 47 | -------------------------------------------------------------------------------- /bin/solidity/AirdropChannels.abi: -------------------------------------------------------------------------------- 1 | [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_admin","type":"address"},{"indexed":true,"internalType":"bool","name":"_adminSet","type":"bool"}],"name":"AdminSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"AirDropDispersed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"AirDropsEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"ChannelClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"ChannelOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"},{"indexed":true,"internalType":"bool","name":"_ownershipTransferred","type":"bool"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_h","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"_proof","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"prefixedProof","type":"bytes32"},{"indexed":false,"internalType":"address","name":"signer","type":"address"}],"name":"SigDebug","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signer","type":"address"}],"name":"SignatureRecovered","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"channels","outputs":[{"internalType":"address","name":"source","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"closingDate","type":"uint256"},{"internalType":"uint256","name":"openDate","type":"uint256"},{"internalType":"uint256","name":"dropAmount","type":"uint256"},{"internalType":"uint256","name":"totalDrops","type":"uint256"},{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"contract ERC20Interface","name":"intf","type":"address"},{"internalType":"enum AirdropChannels.ChannelStates","name":"state","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_h","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"closeChannel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dev","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_h","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"internalType":"bytes32","name":"_channelId","type":"bytes32"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"enableAirdrops","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"frozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"moderators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_channelValue","type":"uint256"},{"internalType":"uint256","name":"_durationInDays","type":"uint256"},{"internalType":"uint256","name":"_dropAmount","type":"uint256"}],"name":"openChannel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_h","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"internalType":"bytes32","name":"_channelId","type":"bytes32"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"retrieveAirdrop","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newAdmin","type":"address"}],"name":"setAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_h","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"verifyProof","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"withdrawEth","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] -------------------------------------------------------------------------------- /bin/solidity/AirdropChannels.bin: -------------------------------------------------------------------------------- 1 | 60c0604052601c60808190527f19457468657265756d205369676e6564204d6573736167653a0a33320000000060a090815261003e9160039190610080565b506004805460ff1916600117905534801561005857600080fd5b5060008054336001600160a01b03199182168117909255600180549091169091179055610113565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100c157805160ff19168380011785556100ee565b828001600101855582156100ee579182015b828111156100ee5782518255916020019190600101906100d3565b506100fa9291506100fe565b5090565b5b808211156100fa57600081556001016100ff565b6111f580620001236000396000f3fe6080604052600436106100ec5760003560e01c80638da5cb5b1161008a578063f2fde38b11610059578063f2fde38b1461039e578063f36bdb49146103d1578063f851a44014610409578063ffa1ad741461041e576100f3565b80638da5cb5b1461030457806391456d3d1461033557806391cca3db14610374578063a0ef91df14610389576100f3565b806356715148116100c6578063567151481461019c5780635c9bd273146101e7578063704b6c021461022c5780637a7ebd7b1461025f576100f3565b8063054f7d9c146100f557806314d0f1ba1461011e578063515982f614610151576100f3565b366100f357005b005b34801561010157600080fd5b5061010a6104a8565b604080519115158252519081900360200190f35b34801561012a57600080fd5b5061010a6004803603602081101561014157600080fd5b50356001600160a01b03166104b8565b34801561015d57600080fd5b5061010a600480360360c081101561017457600080fd5b5080359060ff6020820135169060408101359060608101359060808101359060a001356104cd565b3480156101a857600080fd5b5061010a600480360360c08110156101bf57600080fd5b5080359060ff6020820135169060408101359060608101359060808101359060a00135610822565b3480156101f357600080fd5b5061010a600480360360a081101561020a57600080fd5b5080359060ff6020820135169060408101359060608101359060800135610ad0565b34801561023857600080fd5b5061010a6004803603602081101561024f57600080fd5b50356001600160a01b0316610d37565b34801561026b57600080fd5b506102896004803603602081101561028257600080fd5b5035610db5565b604051808b6001600160a01b031681526020018a6001600160a01b03168152602001898152602001888152602001878152602001868152602001858152602001848152602001836001600160a01b031681526020018260028111156102ea57fe5b81526020019a505050505050505050505060405180910390f35b34801561031057600080fd5b50610319610e1b565b604080516001600160a01b039092168252519081900360200190f35b34801561034157600080fd5b506103196004803603608081101561035857600080fd5b5080359060ff6020820135169060408101359060600135610e2a565b34801561038057600080fd5b5061010a610e9a565b34801561039557600080fd5b5061010a610ea3565b3480156103aa57600080fd5b5061010a600480360360208110156103c157600080fd5b50356001600160a01b0316610f13565b61010a600480360360808110156103e757600080fd5b506001600160a01b038135169060208101359060408101359060600135610f94565b34801561041557600080fd5b5061031961115c565b34801561042a57600080fd5b5061043361116b565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561046d578181015183820152602001610455565b50505050905090810190601f16801561049a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600154600160a01b900460ff1681565b60026020526000908152604090205460ff1681565b60008281526005602052604081205460ff166104e857600080fd5b6001600084815260066020526040902060080154600160a01b900460ff16600281111561051157fe5b1461051b57600080fd5b60008381526006602052604090206005810154600290910154101561053f57600080fd5b600083815260076020908152604080832033845290915290205460ff161561056657600080fd5b600083833360405160200180848152602001838152602001826001600160a01b031660601b81526014019350505050604051602081830303815290604052805190602001209050600060038260405160200180838054600181600116156101000203166002900480156106105780601f106105ee576101008083540402835291820191610610565b820191906000526020600020905b8154815290600101906020018083116105fc575b505082815260200192505050604051602081830303815290604052805190602001209050600060018a8a8a8a60405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610690573d6000803e3d6000fd5b505060408051601f1901516000898152600660205291909120549092506001600160a01b0380841691161490506106c357fe5b8982146106cc57fe5b60008681526007602090815260408083203384528252808320805460ff1916600117905588835260069091529020600581015460029091015461070e91611191565b6000878152600660208190526040909120600281019290925501546107349060016111a6565b600087815260066020819052604080832090910192909255905187917fa467a409776bfc50e32dd8496edd970b5e7a84a38acda61529d8022bf757c2fd91a260008681526006602090815260408083206008810154600590910154825163a9059cbb60e01b8152336004820152602481019190915291516001600160a01b039091169363a9059cbb93604480850194919392918390030190829087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050506040513d602081101561080757600080fd5b505161081257600080fd5b5060019998505050505050505050565b60008281526005602052604081205460ff1661083d57600080fd5b60008084815260066020526040902060080154600160a01b900460ff16600281111561086557fe5b1461086f57600080fd5b6000838152600660205260409020546001600160a01b0316331461089257600080fd5b600083836040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209050600060038260405160200180838054600181600116156101000203166002900480156109285780601f10610906576101008083540402835291820191610928565b820191906000526020600020905b815481529060010190602001808311610914575b505082815260200192505050604051602081830303815290604052805190602001209050600060018a8a8a8a60405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156109a8573d6000803e3d6000fd5b505060408051601f1901516000898152600660205291909120549092506001600160a01b0380841691161490506109db57fe5b8982146109e457fe5b6000868152600660205260409020600801805460ff60a01b1916600160a01b17905560045460ff1615610a6157604080518b8152602081018590528082018490526001600160a01b038316606082015290517f6b7f08f909e42085ce2477fcf9f51be4ff86e5bcc7936c2dbe39e6757d33f9149181900360800190a15b60405186907ff857a98ed55303cc061ea3bc4c498fe49361c82cb72894280249b89848f9ce4690600090a26040516001600160a01b038216907f5c001d7523e0202fd001401f8393d128fbb1fafa8f637949f7d231d814f93b1390600090a25060019998505050505050505050565b60008181526005602052604081205460ff16610aeb57600080fd5b60008083815260066020526040902060080154600160a01b900460ff166002811115610b1357fe5b1480610b4557506001600083815260066020526040902060080154600160a01b900460ff166002811115610b4357fe5b145b610b4e57600080fd5b60045460ff16610b75576000828152600660205260409020600301544211610b7557600080fd5b6000828152600660205260409020546001600160a01b03163314610b9857600080fd5b600060018787878760405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610bf4573d6000803e3d6000fd5b505060408051601f1901516000868152600660205291909120549092506001600160a01b038084169116149050610c2757fe5b600083815260066020526040902060088101805460ff60a01b1916600160a11b1790554260038201556002015415610cff57600083815260066020908152604080832060028101805490859055600890910154825163a9059cbb60e01b815233600482015260248101839052925191946001600160a01b039091169363a9059cbb936044808201949293918390030190829087803b158015610cc857600080fd5b505af1158015610cdc573d6000803e3d6000fd5b505050506040513d6020811015610cf257600080fd5b5051610cfd57600080fd5b505b60405183907fceeab2eef998c17fe96f30f83fbf3c55fc5047f6e40c55a0cf72d236e9d2ba7290600090a25060019695505050505050565b600080546001600160a01b03163314610d4f57600080fd5b6001546001600160a01b0383811691161415610d6a57600080fd5b600180546001600160a01b0319166001600160a01b03841690811782556040517fe68d2c359a771606c400cf8b87000cf5864010363d6a736e98f5047b7bbe18e990600090a3919050565b60066020819052600091825260409091208054600182015460028301546003840154600485015460058601549686015460078701546008909701546001600160a01b0396871698958716979496939592949293919291811690600160a01b900460ff168a565b6000546001600160a01b031681565b600060018585858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610e86573d6000803e3d6000fd5b5050604051601f1901519695505050505050565b60045460ff1681565b600080546001600160a01b0316331480610ec757506001546001600160a01b031633145b610ed057600080fd5b60045460ff16610edf57600080fd5b60405133904780156108fc02916000818181858888f19350505050158015610f0b573d6000803e3d6000fd5b506001905090565b600080546001600160a01b03163314610f2b57600080fd5b6000546001600160a01b0383811691161415610f4657600080fd5b600080546001600160a01b0319166001600160a01b038416908117825560405160019233917f7fdc2a4b6eb39ec3363d710d188620bd1e97b3c434161f187b4d0dc0544faa589190a4919050565b6040805133606090811b6020808401919091529087901b6bffffffffffffffffffffffff191660348301524260488084018290528451808503909101815260689093018452825192820192909220600081815260059092529281205490929060ff161561100057600080fd5b600081815260066020908152604080832080546001600160a01b031990811633178255600180830180546001600160a01b038f16931683179055600283018c905542620151808c020160038401556004830188905560058084018b905560078401889055600890930180546001600160a81b0319169092179091559252808320805460ff19169092179091555182917f7ffc675d721b8768e035a323722842743bb523487b535906abc97e6b3e2095d091a260008181526006602090815260408083206008015481516323b872dd60e01b8152336004820152306024820152604481018b905291516001600160a01b03909116936323b872dd93606480850194919392918390030190829087803b15801561111a57600080fd5b505af115801561112e573d6000803e3d6000fd5b505050506040513d602081101561114457600080fd5b505161114f57600080fd5b5060019695505050505050565b6001546001600160a01b031681565b6040518060400160405280600a815260200169302e302e35616c70686160b01b81525081565b6000828211156111a057600080fd5b50900390565b6000828201838110156111b857600080fd5b939250505056fea2646970667358221220270639091140375d4a12c44e609a244a78f56046eaecbfb9b6ebfafd909425c764736f6c63430007000033 -------------------------------------------------------------------------------- /bin/solidity/PaymentChannels.abi: -------------------------------------------------------------------------------- 1 | [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_admin","type":"address"},{"indexed":true,"internalType":"bool","name":"_adminSet","type":"bool"}],"name":"AdminSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"ChannelClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"ChannelExpired","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_channelId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"_recoveredAddress","type":"address"}],"name":"DestinationProofSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"ErcChannelOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"EthChannelOpened","type":"event"},{"anonymous":false,"inputs":[],"name":"EthWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_channelId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_remainingChannelValue","type":"uint256"}],"name":"MicroPaymentWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"},{"indexed":true,"internalType":"bool","name":"_ownershipTransferred","type":"bool"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_channelId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"_recoveredAddress","type":"address"}],"name":"SourceProofSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"TokensWithdrawn","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_channelId","type":"bytes32"},{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"closeErcChannel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultState","outputs":[{"internalType":"enum PaymentChannels.ChannelStates","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dev","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"ercChannels","outputs":[{"internalType":"address","name":"source","type":"address"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"closingDate","type":"uint256"},{"internalType":"uint256","name":"openDate","type":"uint256"},{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"bool","name":"sourceProofSubmitted","type":"bool"},{"internalType":"bool","name":"destinationProofSubmitted","type":"bool"},{"internalType":"enum PaymentChannels.ChannelStates","name":"state","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"ethChannels","outputs":[{"internalType":"address","name":"source","type":"address"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"closingDate","type":"uint256"},{"internalType":"uint256","name":"openDate","type":"uint256"},{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"bool","name":"sourceProofSubmitted","type":"bool"},{"internalType":"bool","name":"destinationProofSubmitted","type":"bool"},{"internalType":"enum PaymentChannels.ChannelStates","name":"state","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_channelId","type":"bytes32"},{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"expireErcChannel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"frozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"moderators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"address","name":"_destination","type":"address"},{"internalType":"uint256","name":"_channelValueInWei","type":"uint256"},{"internalType":"uint256","name":"_durationInDays","type":"uint256"}],"name":"openErcChannel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_destination","type":"address"},{"internalType":"uint256","name":"_channelValueInWei","type":"uint256"},{"internalType":"uint256","name":"_durationInDays","type":"uint256"}],"name":"openEthChannel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newAdmin","type":"address"}],"name":"setAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_h","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"submitErcDestinationProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_h","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"internalType":"bytes32","name":"_channelId","type":"bytes32"},{"internalType":"uint256","name":"_paymentId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"submitErcMicroPaymentProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_h","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"submitErcSourceProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_h","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"submitEthDestinationProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_h","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"internalType":"bytes32","name":"_channelId","type":"bytes32"},{"internalType":"uint256","name":"_paymentId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"submitEthMicroPaymentProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_h","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"internalType":"bytes32","name":"_channelId","type":"bytes32"}],"name":"submitEthSourceProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawEth","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"withdrawTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] -------------------------------------------------------------------------------- /bin/solidity/PaymentChannels.bin: -------------------------------------------------------------------------------- 1 | 60c0604052601c60808190527f19457468657265756d205369676e6564204d6573736167653a0a33320000000060a090815262000040916003919062000089565b506004805460ff191660011761ff00191690553480156200006057600080fd5b5060008054336001600160a01b0319918216811790925560018054909116909117905562000125565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620000cc57805160ff1916838001178555620000fc565b82800160010185558215620000fc579182015b82811115620000fc578251825591602001919060010190620000df565b506200010a9291506200010e565b5090565b5b808211156200010a57600081556001016200010f565b611f1f80620001356000396000f3fe6080604052600436106101445760003560e01c8063914c62da116100b6578063c21d92d81161006f578063c21d92d8146105c5578063f2fde38b1461060a578063f851a4401461063d578063f8be342e14610652578063fcf0301d14610688578063ffa1ad74146106cd5761014b565b8063914c62da1461043a57806391cca3db1461048b5780639ef3ae9d146104a0578063a0ef91df146104e5578063aa13a612146104fa578063b1653e671461052c5761014b565b806349df728c1161010857806349df728c146102d4578063704b6c021461030757806378bdd8391461033a5780637baccc6d1461037f5780638da5cb5b146103d05780638db53802146104015761014b565b8063054f7d9c1461014d57806314d0f1ba146101765780632b2b4a75146101a95780633f73cfd7146101f25780633f93cc451461022b5761014b565b3661014b57005b005b34801561015957600080fd5b50610162610757565b604080519115158252519081900360200190f35b34801561018257600080fd5b506101626004803603602081101561019957600080fd5b50356001600160a01b0316610767565b3480156101b557600080fd5b50610162600480360360808110156101cc57600080fd5b506001600160a01b0381358116916020810135909116906040810135906060013561077c565b3480156101fe57600080fd5b506101626004803603604081101561021557600080fd5b50803590602001356001600160a01b031661093a565b34801561023757600080fd5b506102556004803603602081101561024e57600080fd5b5035610ae2565b604051808b6001600160a01b031681526020018a6001600160a01b03168152602001896001600160a01b03168152602001888152602001878152602001868152602001858152602001841515815260200183151581526020018260038111156102ba57fe5b81526020019a505050505050505050505060405180910390f35b3480156102e057600080fd5b50610162600480360360208110156102f757600080fd5b50356001600160a01b0316610b4c565b34801561031357600080fd5b506101626004803603602081101561032a57600080fd5b50356001600160a01b0316610cb2565b34801561034657600080fd5b50610162600480360360a081101561035d57600080fd5b5080359060ff6020820135169060408101359060608101359060800135610d30565b34801561038b57600080fd5b50610162600480360360e08110156103a257600080fd5b5080359060ff6020820135169060408101359060608101359060808101359060a08101359060c00135610ee5565b3480156103dc57600080fd5b506103e56111b6565b604080516001600160a01b039092168252519081900360200190f35b34801561040d57600080fd5b506101626004803603604081101561042457600080fd5b50803590602001356001600160a01b03166111c5565b34801561044657600080fd5b50610162600480360360e081101561045d57600080fd5b5080359060ff6020820135169060408101359060608101359060808101359060a08101359060c0013561132e565b34801561049757600080fd5b50610162611595565b3480156104ac57600080fd5b50610162600480360360a08110156104c357600080fd5b5080359060ff602082013516906040810135906060810135906080013561159e565b3480156104f157600080fd5b50610162611764565b6101626004803603606081101561051057600080fd5b506001600160a01b0381351690602081013590604001356117fd565b34801561053857600080fd5b506105566004803603602081101561054f57600080fd5b503561195e565b604051808a6001600160a01b03168152602001896001600160a01b03168152602001888152602001878152602001868152602001858152602001841515815260200183151581526020018260038111156105ac57fe5b8152602001995050505050505050505060405180910390f35b3480156105d157600080fd5b50610162600480360360a08110156105e857600080fd5b5080359060ff60208201351690604081013590606081013590608001356119bf565b34801561061657600080fd5b506101626004803603602081101561062d57600080fd5b50356001600160a01b0316611b42565b34801561064957600080fd5b506103e5611bc3565b34801561065e57600080fd5b50610667611bd2565b6040518082600381111561067757fe5b815260200191505060405180910390f35b34801561069457600080fd5b50610162600480360360a08110156106ab57600080fd5b5080359060ff6020820135169060408101359060608101359060800135611be0565b3480156106d957600080fd5b506106e2611d84565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561071c578181015183820152602001610704565b50505050905090810190601f1680156107495780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600154600160a01b900460ff1681565b60026020526000908152604090205460ff1681565b6040805133606090811b6020808401919091526bffffffffffffffffffffffff1987831b811660348501529188901b909116604883015242605c8084019190915283518084039091018152607c9092018352815191810191909120600081815260089092529181205490919060ff16156107f557600080fd5b6000818152600860209081526040808320805460ff1916600190811790915560069283905281842080546001600160a01b03199081163317825591810180546001600160a01b038c811691851691909117909155600282018054918d169190931617909155600381018890554262015180880281016004830155600582015590910183905551879183917f41063c1edfbec39fdaea4c9b553c1fb2832454799895fcd189a36facbb7327629190a2604080516323b872dd60e01b81523360048201523060248201526044810187905290516001600160a01b038316916323b872dd9160648083019260209291908290030181600087803b1580156108f857600080fd5b505af115801561090c573d6000803e3d6000fd5b505050506040513d602081101561092257600080fd5b505161092d57600080fd5b5060019695505050505050565b60008281526008602052604081205460ff1661095557600080fd5b6000808481526006602052604090206007015462010000900460ff16600381111561097c57fe5b1461098657600080fd5b6000838152600660205260409020546001600160a01b031633146109a957600080fd5b6000838152600660205260409020600201546001600160a01b038381169116146109d257600080fd5b600083815260066020526040812060038101805492905560070180546001919062ff0000191662010000830217905550604051839085907fb0b1a2376e938b887ac88a6049e44d46d0042dd3d17f70089e61339792cb2fbe90600090a26040516001600160a01b03851690600080516020611eca83398151915290600090a26040805163a9059cbb60e01b81523360048201526024810184905290516001600160a01b0383169163a9059cbb9160448083019260209291908290030181600087803b158015610aa057600080fd5b505af1158015610ab4573d6000803e3d6000fd5b505050506040513d6020811015610aca57600080fd5b5051610ad557600080fd5b6001925050505b92915050565b6006602081905260009182526040909120805460018201546002830154600384015460048501546005860154968601546007909601546001600160a01b039586169794861696939095169491939092909160ff80821691610100810482169162010000909104168a565b600080546001600160a01b0316331480610b7057506001546001600160a01b031633145b610b7957600080fd5b60045460ff16610b8857600080fd5b604080516370a0823160e01b8152306004820152905183916000916001600160a01b038416916370a08231916024808301926020929190829003018186803b158015610bd357600080fd5b505afa158015610be7573d6000803e3d6000fd5b505050506040513d6020811015610bfd57600080fd5b50516040519091506001600160a01b03851690600080516020611eca83398151915290600090a26040805163a9059cbb60e01b81523360048201526024810183905290516001600160a01b0384169163a9059cbb9160448083019260209291908290030181600087803b158015610c7357600080fd5b505af1158015610c87573d6000803e3d6000fd5b505050506040513d6020811015610c9d57600080fd5b5051610ca857600080fd5b5060019392505050565b600080546001600160a01b03163314610cca57600080fd5b6001546001600160a01b0383811691161415610ce557600080fd5b600180546001600160a01b0319166001600160a01b03841690811782556040517fe68d2c359a771606c400cf8b87000cf5864010363d6a736e98f5047b7bbe18e990600090a3919050565b60008181526008602052604081205460ff16610d4b57600080fd5b6000808381526006602052604090206007015462010000900460ff166003811115610d7257fe5b14610d7c57600080fd5b60008281526006602052604090206007015460ff1615610d9b57600080fd5b600060018787878760405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610df7573d6000803e3d6000fd5b505060408051601f1901516000868152600660205291909120549092506001600160a01b038084169116149050610e2a57fe5b60008381526006602090815260408083206007018054600160ff199182168117909255600984528285208c86528452828520338652909352818420805490931617909155516001600160a01b0383169185917fef7fbbdebba5df7bf59c00d02ad872d452a67a5a4a4170adc3c95f794b478a679190a3610eab836001611daa565b1561092d57600083815260066020526040902060070180546002919062ff0000191662010000835b02179055505060019695505050505050565b60008381526008602052604081205460ff16610f0057600080fd5b6000808581526006602052604090206007015462010000900460ff166003811115610f2757fe5b14610f3157600080fd5b600084815260066020526040902060030154610f4c57600080fd5b6000848152600660205260409020600101546001600160a01b03163314610f7257600080fd5b6000848484604051602001808481526020018381526020018281526020019350505050604051602081830303815290604052805190602001209050600060038260405160200180838054600181600116156101000203166002900480156110105780601f10610fee576101008083540402835291820191611010565b820191906000526020600020905b815481529060010190602001808311610ffc575b5050918252506040805180830381526020928301909152805191012091505089811461103857fe5b600060018b8b8b8b60405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015611094573d6000803e3d6000fd5b505060408051601f19015160008a8152600660205291909120549092506001600160a01b0380841691161490506110c757fe5b6000878152600660205260408120600301546110e39087611eb4565b600089815260066020526040808220600381018490556002015490519293506001600160a01b0316918291600080516020611eca83398151915291a26040805163a9059cbb60e01b81523360048201526024810189905290516001600160a01b0383169163a9059cbb9160448083019260209291908290030181600087803b15801561116e57600080fd5b505af1158015611182573d6000803e3d6000fd5b505050506040513d602081101561119857600080fd5b50516111a357600080fd5b5060019c9b505050505050505050505050565b6000546001600160a01b031681565b60008281526008602052604081205460ff166111e057600080fd5b600260008481526006602052604090206007015462010000900460ff16600381111561120857fe5b1461121257600080fd5b6000838152600660205260409020600101546001600160a01b0316331461123857600080fd5b6000838152600660205260409020600201546001600160a01b0383811691161461126157600080fd5b6000838152600660205260408120600380820180549390556007909101805462ff0000191662010000830217905550604051839085907fceeab2eef998c17fe96f30f83fbf3c55fc5047f6e40c55a0cf72d236e9d2ba7290600090a26040516001600160a01b03851690600080516020611eca83398151915290600090a26040805163a9059cbb60e01b81523360048201526024810184905290516001600160a01b0383169163a9059cbb9160448083019260209291908290030181600087803b158015610aa057600080fd5b60008381526008602052604081205460ff1661134957600080fd5b6000808581526005602052604090206006015462010000900460ff16600381111561137057fe5b1461137a57600080fd5b60008481526005602052604090206002015461139557600080fd5b6000848152600560205260409020600101546001600160a01b031633146113bb57600080fd5b6000848484604051602001808481526020018381526020018281526020019350505050604051602081830303815290604052805190602001209050600060038260405160200180838054600181600116156101000203166002900480156114595780601f10611437576101008083540402835291820191611459565b820191906000526020600020905b815481529060010190602001808311611445575b5050918252506040805180830381526020928301909152805191012091505089811461148157fe5b600060018b8b8b8b60405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156114dd573d6000803e3d6000fd5b505060408051601f19015160008a8152600560205291909120549092506001600160a01b03808416911614905061151057fe5b60008781526005602052604081206002015461152c9087611eb4565b600089815260056020526040808220600201839055519192507fe85db8c769971e615d7122e20c48e239d21cfd4b1a3561caf49010903e1ff5ac91a1604051339087156108fc029088906000818181858888f193505050501580156111a3573d6000803e3d6000fd5b60045460ff1681565b60008181526008602052604081205460ff166115b957600080fd5b6000808381526005602052604090206006015462010000900460ff1660038111156115e057fe5b146115ea57600080fd5b60008281526005602052604090206006015460ff161561160957600080fd5b6000828152600960209081526040808320898452825280832033845290915290205460ff161561163857600080fd5b600060018787878760405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015611694573d6000803e3d6000fd5b505060408051601f1901516000868152600560205291909120549092506001600160a01b0380841691161490506116c757fe5b6000838152600560209081526040808320600601805460ff19166001179055600982528083208a84528252808320338452909152516001600160a01b0383169185917fef7fbbdebba5df7bf59c00d02ad872d452a67a5a4a4170adc3c95f794b478a679190a3611738836000611daa565b1561092d57600083815260056020526040902060060180546002919062ff000019166201000083610ed3565b600080546001600160a01b031633148061178857506001546001600160a01b031633145b61179157600080fd5b60045460ff166117a057600080fd5b6040517fe85db8c769971e615d7122e20c48e239d21cfd4b1a3561caf49010903e1ff5ac90600090a160405133904780156108fc02916000818181858888f193505050501580156117f5573d6000803e3d6000fd5b506001905090565b600082341461180b57600080fd5b6040805133606090811b6020808401919091529087901b6bffffffffffffffffffffffff19166034830152604882018690524260688084018290528451808503909101815260889093018452825192820192909220600081815260089092529290205490919060ff161561187e57600080fd5b6000818152600860209081526040808320805460ff19166001908117909155600592839052922080546001600160a01b03199081163317825592810180546001600160a01b038b16941693909317909255600282018790554262015180870201600380840191909155600480840186905591830184905590546006909201805461010090930460ff1692909162ff000019909116906201000090849081111561192357fe5b021790555060405181907ec725122f067c5ca4dfb33fb90955e8c8ace1fbba4578cd42779dd95ed21faa90600090a250600195945050505050565b600560208190526000918252604090912080546001820154600283015460038401546004850154958501546006909501546001600160a01b0394851696939094169491939092919060ff808216916101008104821691620100009091041689565b60008181526008602052604081205460ff166119da57600080fd5b6000808381526006602052604090206007015462010000900460ff166003811115611a0157fe5b14611a0b57600080fd5b600082815260066020526040902060070154610100900460ff1615611a2f57600080fd5b600060018787878760405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015611a8b573d6000803e3d6000fd5b505060408051601f1901516000868152600660205291909120600101549092506001600160a01b038084169116149050611ac157fe5b6000838152600660209081526040808320600701805461ff001916610100179055600982528083208a84528252808320338452909152808220805460ff19166001179055516001600160a01b0383169185917f4bfcb0e4fde38226ea7f6e76bc336e1aa934fec6abce5c6a98826c226c27bcac9190a3610eab836001611daa565b600080546001600160a01b03163314611b5a57600080fd5b6000546001600160a01b0383811691161415611b7557600080fd5b600080546001600160a01b0319166001600160a01b038416908117825560405160019233917f7fdc2a4b6eb39ec3363d710d188620bd1e97b3c434161f187b4d0dc0544faa589190a4919050565b6001546001600160a01b031681565b600454610100900460ff1681565b60008181526008602052604081205460ff16611bfb57600080fd5b6000808381526005602052604090206006015462010000900460ff166003811115611c2257fe5b14611c2c57600080fd5b600082815260056020526040902060060154610100900460ff1615611c5057600080fd5b6000828152600960209081526040808320898452825280832033845290915290205460ff1615611c7f57600080fd5b600060018787878760405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015611cdb573d6000803e3d6000fd5b505060408051601f1901516000868152600560205291909120600101549092506001600160a01b038084169116149050611d1157fe5b6000838152600560209081526040808320600601805461ff001916610100179055600982528083208a84528252808320338452909152516001600160a01b0383169185917f4bfcb0e4fde38226ea7f6e76bc336e1aa934fec6abce5c6a98826c226c27bcac9190a3611738836000611daa565b6040518060400160405280600a815260200169302e352e30616c70686160b01b81525081565b60008115611e31576000808481526006602052604090206007015462010000900460ff166003811115611dd957fe5b14611de357600080fd5b60008381526006602052604090206007015460ff1615156001148015611e1f5750600083815260066020526040902060070154610100900460ff165b15611e2c57506001610adc565b611eab565b6000808481526005602052604090206006015462010000900460ff166003811115611e5857fe5b14611e6257600080fd5b60008381526005602052604090206006015460ff1615156001148015611e9e5750600083815260056020526040902060060154610100900460ff165b15611eab57506001610adc565b50600092915050565b600082821115611ec357600080fd5b5090039056feb47e37d80bb9227b793caed3e80256b8eac5e891b85d33f583d43ce03cf34273a26469706673582212204779c725330effb33a79741adb81c459284d0f386dcfb01b97d28e8795f57cae64736f6c63430007000033 -------------------------------------------------------------------------------- /notes/how_to.txt: -------------------------------------------------------------------------------- 1 | >>> w3 = Web3(IPCProvider('/home/solidity/.ethereum/geth.ipc')) 2 | >>> import json 3 | >>> with open('UTC--2018-', 'r') as fh: 4 | ... private = w3.eth.account.decrypt(json.load(fh), 'password123') 5 | ... 6 | >>> w3.eth.accounts[1] 7 | '0x069bA77207aD40B7d386F8E2979a9337A36f991c' 8 | >>> signature = w3.eth.account.sign(message_text="hello", private_key=private) 9 | >>> signature 10 | AttributeDict({'message': HexBytes('0x68656c6c6f'), 'messageHash': HexBytes('0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750'), 'r': 53665784189267139251820747046956462498355115993943239404465477346598658281299, 's': 6629064374810355767282561830725699037469490635953226814818888019755260187756, 'v': 27, 'signature': HexBytes('0x76a5c1e7f682df3375a2bdd6f72ad2171b0cf826fc8a8a3209c33a4e57e88f530ea7eadf8603ba2c4a5c5006571be7665020812aa7e403a614587cfe7a18146c1b')}) 11 | >>> h = Web3.toHex(Web3.toBytes(signature.messageHash) 12 | ... 13 | KeyboardInterrupt 14 | >>> h = Web3.toHex(Web3.toBytes(signature.messageHash)) 15 | >>> v = signature.v 16 | >>> r = Web3.toHex(Web3.toBytes(signature.r)) 17 | >>> s = Web3.toHex(Web3.toBytes(signature.s)) 18 | >>> h 19 | '0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750' 20 | >>> v 21 | 27 22 | >>> r 23 | '0x76a5c1e7f682df3375a2bdd6f72ad2171b0cf826fc8a8a3209c33a4e57e88f53' 24 | >>> s 25 | '0x0ea7eadf8603ba2c4a5c5006571be7665020812aa7e403a614587cfe7a18146c' 26 | 27 | 28 | 29 | 30 | Setting up a value to be recovered through solidity: 31 | function b() public returns (bytes32) { 32 | return keccak256("\x19Ethereum Signed Message:\n32", keccak256("hello")); 33 | } 34 | 35 | >>> Web3.soliditySha3(['string'], ['hello']) 36 | HexBytes('0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8') 37 | >>> a = Web3.toHex(Web3.soliditySha3(['string'], ['hello'])) 38 | >>> a 39 | '0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8' 40 | >>> signature = w3.eth.account.sign(message_hexstr=a, private_key=private_key)>>> signature 41 | AttributeDict({'message': HexBytes('0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8'), 'messageHash': HexBytes('0x456e9aea5e197a1f1af7a3e85a3212fa4049a3ba34c2289b4c860fc0b0c64ef3'), 'r': 54150066364395414263804789069996729215089810591645507777527533480373294301640, 's': 11186801252309812249513270222306045538593842938682421499922595213176213608438, 'v': 27, 'signature': HexBytes('0x77b7d9f83081733e09ffc432157ed5b1d0940d2172e391d8b5e1ce891e5581c818bb81501da88b6deaa810fc6fd54201952f07519791367dd7c5bc4312e017f61b')}) 42 | -------------------------------------------------------------------------------- /python/.t.swo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bonedaddy/Postables-Payment-Channel/b70fa471f81a32c4b278721856bb118fcc848a4d/python/.t.swo -------------------------------------------------------------------------------- /python/.t.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bonedaddy/Postables-Payment-Channel/b70fa471f81a32c4b278721856bb118fcc848a4d/python/.t.swp -------------------------------------------------------------------------------- /python/signer.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3 2 | import json 3 | import getpass 4 | 5 | # micropayment 6 | # keccak256(channelId, paymentString, withdrawalAmount) 7 | 8 | 9 | def sigParts(h,v,r,s): 10 | print("h\t\t",h,"\nv\t\t",v,"\nr\t\t",r,"\ns\t\t",s,"\n") 11 | 12 | def genSigParts(signature): 13 | h = Web3.toHex(signature.messageHash) 14 | v = signature.v 15 | # zero-pad with 32 bytes, issue #617 in web3py 16 | r = Web3.toHex(Web3.toBytes(signature.r).rjust(32, b'\0')) 17 | s = Web3.toHex(Web3.toBytes(signature.s).rjust(32, b'\0')) 18 | return (h, v, r, s) 19 | w3 = Web3() 20 | 21 | keyFilePath = input('Enter the absolute path to your key file:\t') 22 | keyFilePassword = getpass.getpass('Enter the password to decrypt your key file:\t') 23 | with open(keyFilePath, 'r') as fh: 24 | private_key = w3.eth.account.decrypt(json.load(fh), keyFilePassword) 25 | 26 | 27 | print("Options") 28 | choice = int(input("0\tSign message\n1\tsign micro pay\t\t")) 29 | 30 | if choice == 0: 31 | messageTextToSign = input('What is the message you wish to sign:\t') 32 | hashStr = Web3.toHex(Web3.soliditySha3(['string'], [messageTextToSign])) 33 | signature = w3.eth.account.sign(message_hexstr=hashStr, private_key=private_key) 34 | h, v, r, s = genSigParts(signature) 35 | sigParts(h,v,r,s) 36 | elif choice == 1: 37 | channelId = Web3.toHex(0x021e26844f552d2d1c76aac6d9324ae42f498b73a5c09b9871c9fea9e3ef9559) 38 | paymentId = int(input('Enter payment id\t')) 39 | withdrawalAmount = int(input('Enter withdrawal amount\t')) 40 | rawMessageHash = Web3.toHex(Web3.soliditySha3(['bytes32', 'uint256', 'uint256'], [channelId, paymentId, withdrawalAmount])) 41 | print(rawMessageHash) 42 | signature = w3.eth.account.sign(message_hexstr=rawMessageHash, private_key=private_key) 43 | h, v, r, s = genSigParts(signature) 44 | sigParts(h,v,r,s) 45 | else: 46 | print('try again') 47 | exit(1) 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /solidity/AirDropChannels.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.7.0; 2 | import "./Modules/Administration.sol"; 3 | import "./Math/SafeMath.sol"; 4 | import "./Interfaces/ERC20Interface.sol"; 5 | 6 | contract AirdropChannels is Administration { 7 | 8 | using SafeMath for uint256; 9 | 10 | string constant public VERSION = "0.0.5alpha"; 11 | bytes private prefix = "\x19Ethereum Signed Message:\n32"; 12 | // prevent any possible accidental triggering of developer only conditions 13 | bool public dev = true; 14 | 15 | enum ChannelStates { opened, releasing, closed } 16 | 17 | struct ChannelStruct { 18 | address source; 19 | address tokenAddress; 20 | uint256 value; 21 | uint256 closingDate; 22 | uint256 openDate; 23 | uint256 dropAmount; 24 | uint256 totalDrops; 25 | bytes32 channelId; 26 | ERC20Interface intf; 27 | ChannelStates state; 28 | } 29 | 30 | mapping (bytes32 => bool) private channelIds; 31 | mapping (bytes32 => ChannelStruct) public channels; 32 | // k1 = channel id 33 | // k2 = address 34 | mapping (bytes32 => mapping (address => bool)) private receivedBonus; 35 | 36 | event ChannelOpened(bytes32 indexed _channelId); 37 | event ChannelClosed(bytes32 indexed _channelId); 38 | event AirDropsEnabled(bytes32 indexed _channelId); 39 | event AirDropDispersed(bytes32 indexed _channelId); 40 | event SignatureRecovered(address indexed signer); 41 | event SigDebug(bytes32 _h, bytes32 _proof, bytes32 prefixedProof, address signer); 42 | 43 | 44 | receive() external payable {} 45 | fallback() external payable {} 46 | 47 | function openChannel( 48 | address _tokenAddress, 49 | uint256 _channelValue, 50 | uint256 _durationInDays, 51 | uint256 _dropAmount) 52 | public 53 | payable 54 | returns (bool) 55 | { 56 | uint256 currentDate = block.timestamp; 57 | // channel hash = keccak256(purchaser, vendor, channel value, date of open) 58 | bytes32 channelId = keccak256(abi.encodePacked(msg.sender, _tokenAddress, currentDate)); 59 | // make sure the channel id doens't already exist 60 | require(!channelIds[channelId]); 61 | channels[channelId].source = msg.sender; 62 | channels[channelId].tokenAddress = _tokenAddress; 63 | channels[channelId].value = _channelValue; 64 | channels[channelId].closingDate = (block.timestamp + (_durationInDays * 1 days)); 65 | channels[channelId].openDate = currentDate; 66 | channels[channelId].dropAmount = _dropAmount; 67 | channels[channelId].channelId = channelId; 68 | channels[channelId].state = ChannelStates.opened; 69 | channels[channelId].intf = ERC20Interface(_tokenAddress); 70 | channelIds[channelId] = true; 71 | emit ChannelOpened(channelId); 72 | require(channels[channelId].intf.transferFrom(msg.sender, address(this), _channelValue)); 73 | return true; 74 | } 75 | 76 | // airdrop enable proof = keccak256(prefix, keccak256(channelId, airdropID)) 77 | // used to enable the air drop channel 78 | function enableAirdrops( 79 | bytes32 _h, 80 | uint8 _v, 81 | bytes32 _r, 82 | bytes32 _s, 83 | bytes32 _channelId, 84 | uint256 _id) 85 | public 86 | returns (bool) 87 | { 88 | require(channelIds[_channelId]); 89 | require(channels[_channelId].state == ChannelStates.opened); 90 | require(msg.sender == channels[_channelId].source); 91 | // we need to recreate the signed message hash, so first lets compute the raw hash using the preimages 92 | bytes32 _proof = keccak256(abi.encodePacked(_channelId, _id)); 93 | // block.timestamp lets add the prefix, to get the signed message hash, or pefixed message hash 94 | bytes32 proof = keccak256(abi.encodePacked(prefix, _proof)); 95 | // retrieve the signer of the message 96 | address signer = ecrecover(_h, _v, _r, _s); 97 | // if someone fails this chances are it was malicious, so lets waste their gas 98 | assert(signer == channels[_channelId].source); 99 | // however we need to make sure they also submitted the right message 100 | // so we compare our dynamically generated proof, with the passed in signed message hash 101 | assert(proof == _h); 102 | // mark channel as releasing 103 | channels[_channelId].state = ChannelStates.releasing; 104 | if (dev) { emit SigDebug(_h, _proof, proof, signer); } 105 | emit AirDropsEnabled(_channelId); 106 | emit SignatureRecovered(signer); 107 | return true; 108 | } 109 | 110 | // air drop proof: keccak256(prefix, keccak256(_channelId, _id, msg.sender)) 111 | function retrieveAirdrop( 112 | bytes32 _h, 113 | uint8 _v, 114 | bytes32 _r, 115 | bytes32 _s, 116 | bytes32 _channelId, 117 | uint256 _id) 118 | public 119 | returns (bool) 120 | { 121 | // verify channel id 122 | require(channelIds[_channelId]); 123 | // verify we are in the correct state 124 | require(channels[_channelId].state == ChannelStates.releasing); 125 | // verify channel balance 126 | require(channels[_channelId].value >= channels[_channelId].dropAmount); 127 | require(!receivedBonus[_channelId][msg.sender]); 128 | // this ensure only the intended recipient of a signed message can redeem 129 | bytes32 _proof = keccak256(abi.encodePacked(_channelId, _id, msg.sender)); 130 | bytes32 proof = keccak256(abi.encodePacked(prefix, _proof)); 131 | address signer = ecrecover(_h, _v, _r, _s); 132 | // validate the signer 133 | assert(signer == channels[_channelId].source); 134 | // signer checks out, but does the data? 135 | /** 136 | 68 74 74 70 73 3a 2f 2f 70 69 63 73 2e 6d 137 | 65 2e 6d 65 2f 69 74 73 2d 61 6e 2d 6f 6c 138 | 64 65 72 2d 6d 65 6d 65 2d 73 69 72 2d 62 139 | 75 74 2d 69 74 2d 63 68 65 63 6b 73 2d 6f 140 | 75 74 2d 31 39 38 39 39 39 37 34 2e 70 6e 141 | 67 142 | */ 143 | assert(proof == _h); 144 | // mark them as having received a bonus so they can't double dip. 145 | receivedBonus[_channelId][msg.sender] = true; 146 | // reduce the channel value 147 | channels[_channelId].value = channels[_channelId].value.sub(channels[_channelId].dropAmount); 148 | // increase number of air drops 149 | channels[_channelId].totalDrops = channels[_channelId].totalDrops.add(1); 150 | // notify blockchain 151 | emit AirDropDispersed(_channelId); 152 | // transfer tokens 153 | require(channels[_channelId].intf.transfer(msg.sender, channels[_channelId].dropAmount)); 154 | return true; 155 | } 156 | 157 | function closeChannel( 158 | bytes32 _h, 159 | uint8 _v, 160 | bytes32 _r, 161 | bytes32 _s, 162 | bytes32 _channelId) 163 | public 164 | returns (bool) 165 | { 166 | require(channelIds[_channelId]); 167 | require(channels[_channelId].state == ChannelStates.opened || 168 | channels[_channelId].state == ChannelStates.releasing); 169 | // if we aren't in dev mode, make sure the closing date has passed 170 | if (!dev) { 171 | require(block.timestamp > channels[_channelId].closingDate); 172 | } 173 | // make sure msg.sender is channel owner 174 | require(msg.sender == channels[_channelId].source); 175 | address signer = ecrecover(_h, _v, _r, _s); 176 | assert(signer == channels[_channelId].source); 177 | channels[_channelId].state = ChannelStates.closed; 178 | channels[_channelId].closingDate = block.timestamp; 179 | // check to see if channe lvalue is greater than 0, if so withdraw remaining funds 180 | if (channels[_channelId].value > 0 ) { 181 | uint256 deposit = channels[_channelId].value; 182 | channels[_channelId].value = 0; 183 | require(channels[_channelId].intf.transfer(msg.sender, deposit)); 184 | } 185 | emit ChannelClosed(_channelId); 186 | return true; 187 | } 188 | 189 | function verifyProof( 190 | bytes32 _h, 191 | uint8 _v, 192 | bytes32 _r, 193 | bytes32 _s) 194 | public 195 | pure 196 | returns (address) 197 | { 198 | return ecrecover(_h, _v, _r, _s); 199 | } 200 | 201 | /**tested 202 | withdraw any ether in the contract, only when in developer mode 203 | */ 204 | function withdrawEth() 205 | public 206 | onlyAdmin 207 | returns (bool) 208 | { 209 | require(dev); 210 | msg.sender.transfer(address(this).balance); 211 | return true; 212 | } 213 | 214 | } -------------------------------------------------------------------------------- /solidity/ChannelsV3.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.7.0; 2 | import "./Modules/Administration.sol"; 3 | import "./Math/SafeMath.sol"; 4 | 5 | /* 6 | Will be used as the basis for V4 which will enable two parties to pay each other who payment have a channel with each other 7 | A --> B --> C 8 | A can pay C without having a direct path to C through its connection with B 9 | */ 10 | contract PaymentChannels is Administration { 11 | 12 | using SafeMath for uint256; 13 | 14 | string constant public VERSION = "0.3.1alpha"; 15 | 16 | uint256 private channelCount; 17 | bytes private prefix = "\x19Ethereum Signed Message:\n32"; 18 | // prevent any possible accidental triggering of developer only conditions 19 | bool public dev = true; 20 | 21 | enum ChannelStates { opened, expired, closed } 22 | 23 | ChannelStates public defaultState = ChannelStates.opened; 24 | 25 | struct ChannelStruct { 26 | address source; 27 | address destination; 28 | uint256 value; 29 | uint256 closingDate; 30 | uint256 openDate; 31 | bytes32 channelId; 32 | bool sourceProofSubmitted; 33 | bool destinationProofSubmitted; 34 | ChannelStates state; 35 | } 36 | 37 | mapping (bytes32 => ChannelStruct) public channels; 38 | mapping (uint256 => bytes32) private channelNumber; 39 | mapping (bytes32 => bool) private channelIds; 40 | // prevent resubmission of the same signed messages by a particular address within a channel 41 | mapping (bytes32 => mapping (bytes32 => mapping(address => bool))) private signedMessages; 42 | /** 43 | keeps track of micro payment proofs and prevent them from being reused. 44 | key 1 (bytes32) = channel ID 45 | key 2 (bytes32) = message hash 46 | val 1 (bool) = boolean, true (message hash used), false (message hash not used) 47 | 48 | */ 49 | mapping (bytes32 => mapping (bytes32 => bool)) private microPaymentHashes; 50 | 51 | /** Micropayment proof 52 | bytes32, uint256, uint256 53 | hash: keccak256(channelId, paymentId, withdrawalAmount) 54 | */ 55 | 56 | event ChannelOpened(bytes32 indexed _channelId); 57 | event ChannelClosed(bytes32 indexed _channelId); 58 | event ChannelExpired(bytes32 indexed _channelId); 59 | event DestinationProofSubmitted(bytes32 indexed _channelId, address indexed _recoveredAddress); 60 | event SourceProofSubmitted(bytes32 indexed _channelId, address indexed _recoveredAddress); 61 | event MicroPaymentWithdrawn(bytes32 indexed _channelId, uint256 _amount, uint256 _remainingChannelValue); 62 | 63 | modifier bothProofsSubmitted(bytes32 _channelId) { 64 | require(channels[_channelId].sourceProofSubmitted); 65 | require(channels[_channelId].destinationProofSubmitted); 66 | _; 67 | } 68 | 69 | fallback() external payable {} 70 | receive() external payable {} 71 | 72 | function openChannel( 73 | address _destination, 74 | uint256 _channelValueInWei, 75 | uint256 _durationInDays) 76 | public 77 | payable 78 | returns (bool) 79 | { 80 | require(msg.value == _channelValueInWei); 81 | uint256 currentDate = block.timestamp; 82 | // channel hash = keccak256(purchaser, vendor, channel value, date of open) 83 | bytes32 channelId = keccak256(abi.encodePacked(msg.sender, _destination, _channelValueInWei, currentDate)); 84 | // make sure the channel id doens't already exist 85 | require(!channelIds[channelId]); 86 | channelIds[channelId] = true; 87 | channels[channelId].source = msg.sender; 88 | channels[channelId].destination = _destination; 89 | channels[channelId].value = _channelValueInWei; 90 | channels[channelId].closingDate = (block.timestamp + (_durationInDays * 1 days)); 91 | channels[channelId].openDate = currentDate; 92 | channels[channelId].channelId = channelId; 93 | channels[channelId].state = defaultState; 94 | ChannelOpened(channelId); 95 | return true; 96 | } 97 | 98 | function submitSourceProof( 99 | bytes32 _h, 100 | uint8 _v, 101 | bytes32 _r, 102 | bytes32 _s, 103 | bytes32 _channelId) 104 | public 105 | returns (bool) 106 | { 107 | require(channelIds[_channelId]); 108 | require(channels[_channelId].state == ChannelStates.opened); 109 | require(!signedMessages[_channelId][_h][msg.sender]); 110 | signedMessages[_channelId][_h][msg.sender] = true; 111 | address signer = ecrecover(_h, _v, _r, _s); 112 | require(signer == channels[_channelId].source); 113 | channels[_channelId].sourceProofSubmitted = true; 114 | SourceProofSubmitted(_channelId, signer); 115 | return true; 116 | } 117 | 118 | function submitDestinationProof( 119 | bytes32 _h, 120 | uint8 _v, 121 | bytes32 _r, 122 | bytes32 _s, 123 | bytes32 _channelId) 124 | public 125 | returns (bool) 126 | { 127 | require(channelIds[_channelId]); 128 | require(channels[_channelId].state == ChannelStates.opened); 129 | require(!signedMessages[_channelId][_h][msg.sender]); 130 | signedMessages[_channelId][_h][msg.sender] = true; 131 | address signer = ecrecover(_h, _v, _r, _s); 132 | require(signer == channels[_channelId].destination); 133 | channels[_channelId].destinationProofSubmitted = true; 134 | DestinationProofSubmitted(_channelId, signer); 135 | return true; 136 | } 137 | 138 | function closeChannel( 139 | bytes32 _channelId) 140 | public 141 | bothProofsSubmitted(_channelId) 142 | returns (bool) 143 | { 144 | require(channelIds[_channelId]); 145 | require(channels[_channelId].state == ChannelStates.opened); 146 | require(channels[_channelId].value > 0); 147 | require(msg.sender == channels[_channelId].destination); 148 | uint256 deposit = channels[_channelId].value; 149 | channels[_channelId].value = 0; 150 | channels[_channelId].state = ChannelStates.closed; 151 | ChannelClosed(_channelId); 152 | msg.sender.transfer(deposit); 153 | return true; 154 | } 155 | 156 | function submitMicroPaymentProof( 157 | bytes32 _channelId, 158 | bytes32 _h, 159 | uint8 _v, 160 | bytes32 _r, 161 | bytes32 _s, 162 | uint256 _paymentId, 163 | uint256 _withdrawalAmount) 164 | public 165 | returns (bool) 166 | { 167 | // validate channel id 168 | require(channelIds[_channelId]); 169 | // validate channel state 170 | require(channels[_channelId].state == ChannelStates.opened); 171 | // make sure nobody else is trying to withdraw the funds 172 | require(msg.sender == channels[_channelId].destination); 173 | // prevent a micropayment from reducing the entire balance 174 | require(channels[_channelId].value > _withdrawalAmount && _withdrawalAmount > 0); 175 | // following two lines construct the proof, with prefix to validate _h 176 | bytes32 _proof = keccak256(abi.encodePacked(_channelId, _paymentId, _withdrawalAmount)); 177 | bytes32 proof = keccak256(abi.encodePacked(prefix, _proof)); 178 | // validate the proof, if it fails most likely malicious submitter, so lets waste their gas ;) 179 | assert(proof == _h); 180 | // make sure the proof hasn't already bee submitted 181 | require(!microPaymentHashes[_channelId][_h]); 182 | // mark proof as submitted 183 | microPaymentHashes[_channelId][_h] = true; 184 | // time to recover the signature 185 | address signer = ecrecover(_h, _v, _r, _s); 186 | // make sure its from the source, otherwise someones up to no good so lets waste their gas ;) 187 | assert(signer == channels[_channelId].source); 188 | // calculate remaining channel value 189 | uint256 remainingChannelValue = channels[_channelId].value.sub(_withdrawalAmount); 190 | // adjust channel value 191 | channels[_channelId].value = remainingChannelValue; 192 | // notify blockchain 193 | MicroPaymentWithdrawn(_channelId, _withdrawalAmount, remainingChannelValue); 194 | // withdraw funds 195 | msg.sender.transfer(_withdrawalAmount); 196 | return true; 197 | } 198 | 199 | /** 200 | So long as both proofs have *NOT* been submitted, and it is past closing, terminate channel 201 | */ 202 | function expireChannel( 203 | bytes32 _channelId) 204 | public 205 | returns (bool) 206 | { 207 | require(channelIds[_channelId]); 208 | require(msg.sender == channels[_channelId].source); 209 | // require that the channel is open 210 | require(channels[_channelId].state == ChannelStates.opened); 211 | // if both proofs have been submitted, throw 212 | if (channels[_channelId].sourceProofSubmitted && channels[_channelId].destinationProofSubmitted) { 213 | revert(); 214 | } 215 | if (!dev) { 216 | require(block.timestamp >= channels[_channelId].closingDate); 217 | } 218 | channels[_channelId].state = ChannelStates.expired; 219 | uint256 deposit = channels[_channelId].value; 220 | channels[_channelId].value = 0; 221 | ChannelExpired(_channelId); 222 | msg.sender.transfer(deposit); 223 | return true; 224 | } 225 | 226 | /**tested 227 | withdraw any ether in the contract, only when in developer mode 228 | */ 229 | function withdrawEth() 230 | public 231 | onlyAdmin 232 | returns (bool) 233 | { 234 | require(dev); 235 | msg.sender.transfer(address(this).balance); 236 | return true; 237 | } 238 | 239 | } -------------------------------------------------------------------------------- /solidity/ChannelsV4.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.7.0; 2 | import "./Modules/Administration.sol"; 3 | import "./Math/SafeMath.sol"; 4 | import "./Interfaces/ERC20Interface.sol"; 5 | 6 | contract PaymentChannels is Administration { 7 | 8 | using SafeMath for uint256; 9 | 10 | string constant public VERSION = "0.4.3alpha"; 11 | 12 | bytes private prefix = "\x19Ethereum Signed Message:\n32"; 13 | // prevent any possible accidental triggering of developer only conditions 14 | bool public dev = true; 15 | 16 | enum ChannelStates { opened, expired, finalized, closed } 17 | 18 | ChannelStates public defaultState = ChannelStates.opened; 19 | 20 | struct EthChannelStruct { 21 | address source; 22 | address destination; 23 | uint256 value; 24 | uint256 closingDate; 25 | uint256 openDate; 26 | bytes32 channelId; 27 | bool sourceProofSubmitted; 28 | bool destinationProofSubmitted; 29 | ChannelStates state; 30 | } 31 | 32 | struct ErcChannelStruct { 33 | address source; 34 | address destination; 35 | address tokenAddress; 36 | uint256 value; 37 | uint256 closingDate; 38 | uint256 openDate; 39 | bytes32 channelId; 40 | bool sourceProofSubmitted; 41 | bool destinationProofSubmitted; 42 | ChannelStates state; 43 | } 44 | 45 | mapping (bytes32 => EthChannelStruct) public ethChannels; 46 | mapping (bytes32 => ErcChannelStruct) public ercChannels; 47 | mapping (uint256 => bytes32) private channelNumber; 48 | mapping (bytes32 => bool) private channelIds; 49 | /* prevent resubmission of the same signed messages by a particular address within a channel 50 | key 1 (bytes32) = channel id 51 | key 2 (bytes32) = messageHash 52 | key 3 (address) = address of the submitter 53 | val (bool) = whether or not the message has already been submitted 54 | */ 55 | mapping (bytes32 => mapping (bytes32 => mapping(address => bool))) private signedMessages; 56 | /* 57 | keeps track of micro payment proofs and prevent them from being reused. 58 | key 1 (bytes32) = channel ID 59 | key 2 (bytes32) = message hash 60 | val 1 (bool) = boolean, true (message hash used), false (message hash not used) 61 | 62 | */ 63 | mapping (bytes32 => mapping (bytes32 => bool)) private microPaymentHashes; 64 | 65 | /* Micropayment proof 66 | bytes32, uint256, uint256 67 | hash: keccak256(channelId, paymentId, withdrawalAmount) 68 | */ 69 | 70 | event EthChannelOpened(bytes32 indexed _channelId); 71 | event ErcChannelOpened(bytes32 indexed _channelId); 72 | event ChannelClosed(bytes32 indexed _channelId); 73 | event ChannelExpired(bytes32 indexed _channelId); 74 | event DestinationProofSubmitted(bytes32 indexed _channelId, address indexed _recoveredAddress); 75 | event SourceProofSubmitted(bytes32 indexed _channelId, address indexed _recoveredAddress); 76 | event MicroPaymentWithdrawn(bytes32 indexed _channelId, uint256 _amount, uint256 _remainingChannelValue); 77 | event EthWithdrawn(); 78 | event TokensWithdrawn(address indexed _tokenAddress); 79 | 80 | 81 | fallback() external payable {} 82 | receive() external payable {} 83 | 84 | /** start of eth channel functions */ 85 | 86 | function openEthChannel( 87 | address _destination, 88 | uint256 _channelValueInWei, 89 | uint256 _durationInDays) 90 | public 91 | payable 92 | returns (bool) 93 | { 94 | require(msg.value == _channelValueInWei); 95 | uint256 currentDate = block.timestamp; 96 | // channel hash = keccak256(purchaser, vendor, channel value, date of open) 97 | bytes32 channelId = keccak256(abi.encodePacked(msg.sender, _destination, _channelValueInWei, currentDate)); 98 | // make sure the channel id doens't already exist 99 | require(!channelIds[channelId]); 100 | channelIds[channelId] = true; 101 | ethChannels[channelId].source = msg.sender; 102 | ethChannels[channelId].destination = _destination; 103 | ethChannels[channelId].value = _channelValueInWei; 104 | ethChannels[channelId].closingDate = (block.timestamp + (_durationInDays * 1 days)); 105 | ethChannels[channelId].openDate = currentDate; 106 | ethChannels[channelId].channelId = channelId; 107 | ethChannels[channelId].state = defaultState; 108 | emit EthChannelOpened(channelId); 109 | return true; 110 | } 111 | 112 | function submitEthSourceProof( 113 | bytes32 _h, 114 | uint8 _v, 115 | bytes32 _r, 116 | bytes32 _s, 117 | bytes32 _channelId) 118 | public 119 | returns (bool) 120 | { 121 | require(channelIds[_channelId]); 122 | require(ethChannels[_channelId].state == ChannelStates.opened); 123 | require(!ethChannels[_channelId].sourceProofSubmitted); 124 | require(!signedMessages[_channelId][_h][msg.sender]); 125 | address signer = ecrecover(_h, _v, _r, _s); 126 | assert(signer == ethChannels[_channelId].source); 127 | ethChannels[_channelId].sourceProofSubmitted = true; 128 | signedMessages[_channelId][_h][msg.sender]; 129 | emit SourceProofSubmitted(_channelId, signer); 130 | if (verifyDoubleProof(_channelId, false)) { 131 | ethChannels[_channelId].state = ChannelStates.finalized; 132 | } 133 | return true; 134 | } 135 | 136 | function submitEthDestinationProof( 137 | bytes32 _h, 138 | uint8 _v, 139 | bytes32 _r, 140 | bytes32 _s, 141 | bytes32 _channelId) 142 | public 143 | returns (bool) 144 | { 145 | require(channelIds[_channelId]); 146 | require(ethChannels[_channelId].state == ChannelStates.opened); 147 | require(!ethChannels[_channelId].destinationProofSubmitted); 148 | require(!signedMessages[_channelId][_h][msg.sender]); 149 | address signer = ecrecover(_h, _v, _r, _s); 150 | assert(signer == ethChannels[_channelId].destination); 151 | ethChannels[_channelId].destinationProofSubmitted = true; 152 | signedMessages[_channelId][_h][msg.sender]; 153 | emit DestinationProofSubmitted(_channelId, signer); 154 | if (verifyDoubleProof(_channelId, false)) { 155 | ethChannels[_channelId].state = ChannelStates.finalized; 156 | } 157 | return true; 158 | } 159 | 160 | 161 | /** end of eth channel functions */ 162 | 163 | 164 | /** start of ERC20 channel functions */ 165 | 166 | function openErcChannel( 167 | address _tokenAddress, 168 | address _destination, 169 | uint256 _channelValueInWei, 170 | uint256 _durationInDays) 171 | public 172 | returns (bool) 173 | { 174 | bytes32 channelId = keccak256(abi.encodePacked(msg.sender, _destination, _tokenAddress, block.timestamp)); 175 | // make sure the chanel ID doesn't already exist 176 | require(!channelIds[channelId]); 177 | channelIds[channelId] = true; 178 | ercChannels[channelId].source = msg.sender; 179 | ercChannels[channelId].destination = _destination; 180 | ercChannels[channelId].tokenAddress = _tokenAddress; 181 | ercChannels[channelId].value = _channelValueInWei; 182 | ercChannels[channelId].closingDate = (block.timestamp + (_durationInDays * 1 days)); 183 | ercChannels[channelId].openDate = block.timestamp; 184 | ercChannels[channelId].channelId = channelId; 185 | ERC20Interface e = ERC20Interface(_tokenAddress); 186 | emit ErcChannelOpened(channelId); 187 | require(e.transferFrom(msg.sender, address(this), _channelValueInWei)); 188 | return true; 189 | } 190 | 191 | /** 192 | Need to add a require function to ensure the signed message hash hasn't already been submitted 193 | */ 194 | function submitErcSourceProof( 195 | bytes32 _h, 196 | uint8 _v, 197 | bytes32 _r, 198 | bytes32 _s, 199 | bytes32 _channelId) 200 | public 201 | returns (bool) 202 | { 203 | // verify correct channel id 204 | require(channelIds[_channelId]); 205 | // ensure channel state is opened 206 | require(ercChannels[_channelId].state == ChannelStates.opened); 207 | // make sure source proof hasn't already been submitted 208 | require(!ercChannels[_channelId].sourceProofSubmitted); 209 | // recover address of signer 210 | address signer = ecrecover(_h, _v, _r, _s); 211 | // ensure that the signer is the source of the channel 212 | assert (signer == ercChannels[_channelId].source); 213 | // mark source proof as submitted 214 | ercChannels[_channelId].sourceProofSubmitted = true; 215 | // ensure this proof can't be reused by the same sender 216 | signedMessages[_channelId][_h][msg.sender] = true; 217 | // notify blockchain 218 | emit SourceProofSubmitted(_channelId, signer); 219 | if (verifyDoubleProof(_channelId, true)) { 220 | ercChannels[_channelId].state = ChannelStates.finalized; 221 | } 222 | return true; 223 | } 224 | 225 | /** 226 | Need to add a require function to check for sign messaged hash use 227 | */ 228 | function submitErcDestinationProof( 229 | bytes32 _h, 230 | uint8 _v, 231 | bytes32 _r, 232 | bytes32 _s, 233 | bytes32 _channelId) 234 | public 235 | returns (bool) 236 | { 237 | // verify correct channel id 238 | require(channelIds[_channelId]); 239 | // ensure channel state is opened 240 | require(ercChannels[_channelId].state == ChannelStates.opened); 241 | // make sure destination proof hasn't already been submitted 242 | require(!ercChannels[_channelId].destinationProofSubmitted); 243 | // recover address of signer 244 | address signer = ecrecover(_h, _v, _r, _s); 245 | // ensure that the signer is the destionation of the channel 246 | assert (signer == ercChannels[_channelId].destination); 247 | // mark destination proof as submitted 248 | ercChannels[_channelId].destinationProofSubmitted = true; 249 | // ensure this proof can't be reused by the same sender 250 | signedMessages[_channelId][_h][msg.sender] = true; 251 | // notify blockchain 252 | emit DestinationProofSubmitted(_channelId, signer); 253 | if (verifyDoubleProof(_channelId, true)) { 254 | ercChannels[_channelId].state = ChannelStates.finalized; 255 | } 256 | return true; 257 | } 258 | 259 | function submitErcMicroPaymentProof( 260 | bytes32 _h, 261 | uint8 _v, 262 | bytes32 _r, 263 | bytes32 _s, 264 | bytes32 _channelId, 265 | uint256 _paymentId, 266 | uint256 _amount) 267 | public 268 | returns (bool) 269 | { 270 | require(channelIds[_channelId]); 271 | require(ercChannels[_channelId].state == ChannelStates.opened); 272 | require(ercChannels[_channelId].value > 0); 273 | require(msg.sender == ercChannels[_channelId].destination); 274 | bytes32 proof = keccak256(abi.encodePacked(_channelId, _paymentId, _amount)); 275 | bytes32 prefixedProof = keccak256(abi.encodePacked(prefix, proof)); 276 | assert(prefixedProof == _h); 277 | address signer = ecrecover(_h, _v, _r, _s); 278 | assert(signer == ercChannels[_channelId].source); 279 | uint256 remainingChannelValue = ercChannels[_channelId].value.sub(_amount); 280 | ercChannels[_channelId].value = remainingChannelValue; 281 | ERC20Interface e = ERC20Interface(ercChannels[_channelId].tokenAddress); 282 | emit TokensWithdrawn(ercChannels[_channelId].tokenAddress); 283 | require(e.transfer(msg.sender, _amount)); 284 | return true; 285 | } 286 | 287 | function closeErcChannel( 288 | bytes32 _channelId, 289 | address _tokenAddress) 290 | public 291 | returns (bool) 292 | { 293 | require(channelIds[_channelId]); 294 | require(ercChannels[_channelId].state == ChannelStates.finalized); 295 | // make sure that once the channel is finalized *ONLY* the destination can withdraw funds 296 | require(msg.sender == ercChannels[_channelId].destination); 297 | require(_tokenAddress == ercChannels[_channelId].tokenAddress); 298 | uint256 deposit = ercChannels[_channelId].value; 299 | ercChannels[_channelId].value = 0; 300 | // lets close the channel 301 | ercChannels[_channelId].state = ChannelStates.closed; 302 | ERC20Interface e = ERC20Interface(_tokenAddress); 303 | emit ChannelClosed(_channelId); 304 | emit TokensWithdrawn(_tokenAddress); 305 | require(e.transfer(msg.sender, deposit)); 306 | return true; 307 | } 308 | 309 | 310 | /** 311 | Used to withdraw whatever funds are remaining in the channel, so long as the channel is opened 312 | */ 313 | function expireErcChannel( 314 | bytes32 _channelId, 315 | address _tokenAddress) 316 | public 317 | returns (bool) 318 | { 319 | require(channelIds[_channelId]); 320 | require(ercChannels[_channelId].state == ChannelStates.opened); 321 | // make sure that only the source is allowed to invoke this function 322 | require(msg.sender == ercChannels[_channelId].source); 323 | require(_tokenAddress == ercChannels[_channelId].tokenAddress); 324 | uint256 deposit = ercChannels[_channelId].value; 325 | ercChannels[_channelId].value = 0; 326 | ercChannels[_channelId].state = ChannelStates.expired; 327 | ERC20Interface e = ERC20Interface(_tokenAddress); 328 | emit ChannelExpired(_channelId); 329 | emit TokensWithdrawn(_tokenAddress); 330 | require(e.transfer(msg.sender, deposit)); 331 | return true; 332 | } 333 | 334 | /** end of erc20 channel functions */ 335 | 336 | /** start of internal functions */ 337 | 338 | /** 339 | Set _ercChannel to true if you are attempting to verify the submission status of both proofs for an ERC channel 340 | Set _ercChannel to false if you are attempting to verify the submission status of both proofs for an ETH channel 341 | */ 342 | function verifyDoubleProof( 343 | bytes32 _channelId, 344 | bool _ercChannel) 345 | internal 346 | view 347 | returns (bool) 348 | { 349 | if (_ercChannel) { 350 | require(ercChannels[_channelId].state == ChannelStates.opened); 351 | if (ercChannels[_channelId].sourceProofSubmitted == true && ercChannels[_channelId].destinationProofSubmitted) { 352 | return true; 353 | } 354 | } else { 355 | require(ethChannels[_channelId].state == ChannelStates.opened); 356 | if (ethChannels[_channelId].sourceProofSubmitted == true && ethChannels[_channelId].destinationProofSubmitted) { 357 | return true; 358 | } 359 | } 360 | return false; 361 | } 362 | 363 | /** 364 | withdraw any ether in the contract, only when in developer mode 365 | */ 366 | function withdrawEth() 367 | public 368 | onlyAdmin 369 | returns (bool) 370 | { 371 | require(dev); 372 | emit EthWithdrawn(); 373 | msg.sender.transfer(address(this).balance); 374 | return true; 375 | } 376 | 377 | function withdrawTokens( 378 | address _tokenAddress) 379 | public 380 | onlyAdmin 381 | returns (bool) 382 | { 383 | require(dev); 384 | ERC20Interface e = ERC20Interface(_tokenAddress); 385 | uint256 balance = e.balanceOf(address(this)); 386 | emit TokensWithdrawn(_tokenAddress); 387 | require(e.transfer(msg.sender, balance)); 388 | return true; 389 | } 390 | 391 | } -------------------------------------------------------------------------------- /solidity/ChannelsV5.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.7.0; 2 | import "./Modules/Administration.sol"; 3 | import "./Math/SafeMath.sol"; 4 | import "./Interfaces/ERC20Interface.sol"; 5 | 6 | contract PaymentChannels is Administration { 7 | 8 | using SafeMath for uint256; 9 | 10 | string constant public VERSION = "0.5.0alpha"; 11 | 12 | bytes private prefix = "\x19Ethereum Signed Message:\n32"; 13 | // prevent any possible accidental triggering of developer only conditions 14 | bool public dev = true; 15 | 16 | enum ChannelStates { opened, expired, finalized, closed } 17 | 18 | ChannelStates public defaultState = ChannelStates.opened; 19 | 20 | struct EthChannelStruct { 21 | address source; 22 | address destination; 23 | uint256 value; 24 | uint256 closingDate; 25 | uint256 openDate; 26 | bytes32 channelId; 27 | bool sourceProofSubmitted; 28 | bool destinationProofSubmitted; 29 | ChannelStates state; 30 | } 31 | 32 | struct ErcChannelStruct { 33 | address source; 34 | address destination; 35 | address tokenAddress; 36 | uint256 value; 37 | uint256 closingDate; 38 | uint256 openDate; 39 | bytes32 channelId; 40 | bool sourceProofSubmitted; 41 | bool destinationProofSubmitted; 42 | ChannelStates state; 43 | } 44 | 45 | mapping (bytes32 => EthChannelStruct) public ethChannels; 46 | mapping (bytes32 => ErcChannelStruct) public ercChannels; 47 | mapping (uint256 => bytes32) private channelNumber; 48 | mapping (bytes32 => bool) private channelIds; 49 | /* prevent resubmission of the same signed messages by a particular address within a channel 50 | key 1 (bytes32) = channel id 51 | key 2 (bytes32) = messageHash 52 | key 3 (address) = address of the submitter 53 | val (bool) = whether or not the message has already been submitted 54 | */ 55 | mapping (bytes32 => mapping (bytes32 => mapping(address => bool))) private signedMessages; 56 | /* 57 | keeps track of micro payment proofs and prevent them from being reused. 58 | key 1 (bytes32) = channel ID 59 | key 2 (bytes32) = message hash 60 | val 1 (bool) = boolean, true (message hash used), false (message hash not used) 61 | 62 | */ 63 | mapping (bytes32 => mapping (bytes32 => bool)) private microPaymentHashes; 64 | 65 | /* Micropayment proof 66 | bytes32, uint256, uint256 67 | hash: keccak256(channelId, paymentId, withdrawalAmount) 68 | */ 69 | 70 | event EthChannelOpened(bytes32 indexed _channelId); 71 | event ErcChannelOpened(bytes32 indexed _channelId); 72 | event ChannelClosed(bytes32 indexed _channelId); 73 | event ChannelExpired(bytes32 indexed _channelId); 74 | event DestinationProofSubmitted(bytes32 indexed _channelId, address indexed _recoveredAddress); 75 | event SourceProofSubmitted(bytes32 indexed _channelId, address indexed _recoveredAddress); 76 | event MicroPaymentWithdrawn(bytes32 indexed _channelId, uint256 _amount, uint256 _remainingChannelValue); 77 | event EthWithdrawn(); 78 | event TokensWithdrawn(address indexed _tokenAddress); 79 | 80 | fallback() external payable {} 81 | receive() external payable {} 82 | 83 | /** start of eth channel functions */ 84 | 85 | function openEthChannel( 86 | address _destination, 87 | uint256 _channelValueInWei, 88 | uint256 _durationInDays) 89 | public 90 | payable 91 | returns (bool) 92 | { 93 | require(msg.value == _channelValueInWei); 94 | uint256 currentDate = block.timestamp; 95 | // channel hash = keccak256(purchaser, vendor, channel value, date of open) 96 | bytes32 channelId = keccak256(abi.encodePacked(msg.sender, _destination, _channelValueInWei, currentDate)); 97 | // make sure the channel id doens't already exist 98 | require(!channelIds[channelId]); 99 | channelIds[channelId] = true; 100 | ethChannels[channelId].source = msg.sender; 101 | ethChannels[channelId].destination = _destination; 102 | ethChannels[channelId].value = _channelValueInWei; 103 | ethChannels[channelId].closingDate = (block.timestamp + (_durationInDays * 1 days)); 104 | ethChannels[channelId].openDate = currentDate; 105 | ethChannels[channelId].channelId = channelId; 106 | ethChannels[channelId].state = defaultState; 107 | EthChannelOpened(channelId); 108 | return true; 109 | } 110 | 111 | function submitEthSourceProof( 112 | bytes32 _h, 113 | uint8 _v, 114 | bytes32 _r, 115 | bytes32 _s, 116 | bytes32 _channelId) 117 | public 118 | returns (bool) 119 | { 120 | require(channelIds[_channelId]); 121 | require(ethChannels[_channelId].state == ChannelStates.opened); 122 | require(!ethChannels[_channelId].sourceProofSubmitted); 123 | require(!signedMessages[_channelId][_h][msg.sender]); 124 | address signer = ecrecover(_h, _v, _r, _s); 125 | assert(signer == ethChannels[_channelId].source); 126 | ethChannels[_channelId].sourceProofSubmitted = true; 127 | signedMessages[_channelId][_h][msg.sender]; 128 | SourceProofSubmitted(_channelId, signer); 129 | if (verifyDoubleProof(_channelId, false)) { 130 | ethChannels[_channelId].state = ChannelStates.finalized; 131 | } 132 | return true; 133 | } 134 | 135 | function submitEthDestinationProof( 136 | bytes32 _h, 137 | uint8 _v, 138 | bytes32 _r, 139 | bytes32 _s, 140 | bytes32 _channelId) 141 | public 142 | returns (bool) 143 | { 144 | require(channelIds[_channelId]); 145 | require(ethChannels[_channelId].state == ChannelStates.opened); 146 | require(!ethChannels[_channelId].destinationProofSubmitted); 147 | require(!signedMessages[_channelId][_h][msg.sender]); 148 | address signer = ecrecover(_h, _v, _r, _s); 149 | assert(signer == ethChannels[_channelId].destination); 150 | ethChannels[_channelId].destinationProofSubmitted = true; 151 | signedMessages[_channelId][_h][msg.sender]; 152 | DestinationProofSubmitted(_channelId, signer); 153 | if (verifyDoubleProof(_channelId, false)) { 154 | ethChannels[_channelId].state = ChannelStates.finalized; 155 | } 156 | return true; 157 | } 158 | 159 | function submitEthMicroPaymentProof( 160 | bytes32 _h, 161 | uint8 _v, 162 | bytes32 _r, 163 | bytes32 _s, 164 | bytes32 _channelId, 165 | uint256 _paymentId, 166 | uint256 _amount) 167 | public 168 | returns (bool) 169 | { 170 | require(channelIds[_channelId]); 171 | require(ethChannels[_channelId].state == ChannelStates.opened); 172 | require(ethChannels[_channelId].value > 0); 173 | require(msg.sender == ethChannels[_channelId].destination); 174 | bytes32 proof = keccak256(abi.encodePacked(_channelId, _paymentId, _amount)); 175 | bytes32 prefixedProof = keccak256(abi.encodePacked(prefix, proof)); 176 | assert(prefixedProof == _h); 177 | address signer = ecrecover(_h, _v, _r, _s); 178 | assert(signer == ethChannels[_channelId].source); 179 | uint256 remainingChannelValue = ethChannels[_channelId].value.sub(_amount); 180 | ethChannels[_channelId].value = remainingChannelValue; 181 | EthWithdrawn(); 182 | msg.sender.transfer(_amount); 183 | return true; 184 | } 185 | 186 | /** end of eth channel functions */ 187 | 188 | 189 | /** start of ERC20 channel functions */ 190 | 191 | function openErcChannel( 192 | address _tokenAddress, 193 | address _destination, 194 | uint256 _channelValueInWei, 195 | uint256 _durationInDays) 196 | public 197 | returns (bool) 198 | { 199 | bytes32 channelId = keccak256(abi.encodePacked(msg.sender, _destination, _tokenAddress, block.timestamp)); 200 | // make sure the chanel ID doesn't already exist 201 | require(!channelIds[channelId]); 202 | channelIds[channelId] = true; 203 | ercChannels[channelId].source = msg.sender; 204 | ercChannels[channelId].destination = _destination; 205 | ercChannels[channelId].tokenAddress = _tokenAddress; 206 | ercChannels[channelId].value = _channelValueInWei; 207 | ercChannels[channelId].closingDate = (block.timestamp + (_durationInDays * 1 days)); 208 | ercChannels[channelId].openDate = block.timestamp; 209 | ercChannels[channelId].channelId = channelId; 210 | ERC20Interface e = ERC20Interface(_tokenAddress); 211 | ErcChannelOpened(channelId); 212 | require(e.transferFrom(msg.sender, address(this), _channelValueInWei)); 213 | return true; 214 | } 215 | 216 | /** 217 | Need to add a require function to ensure the signed message hash hasn't already been submitted 218 | */ 219 | function submitErcSourceProof( 220 | bytes32 _h, 221 | uint8 _v, 222 | bytes32 _r, 223 | bytes32 _s, 224 | bytes32 _channelId) 225 | public 226 | returns (bool) 227 | { 228 | // verify correct channel id 229 | require(channelIds[_channelId]); 230 | // ensure channel state is opened 231 | require(ercChannels[_channelId].state == ChannelStates.opened); 232 | // make sure source proof hasn't already been submitted 233 | require(!ercChannels[_channelId].sourceProofSubmitted); 234 | // recover address of signer 235 | address signer = ecrecover(_h, _v, _r, _s); 236 | // ensure that the signer is the source of the channel 237 | assert (signer == ercChannels[_channelId].source); 238 | // mark source proof as submitted 239 | ercChannels[_channelId].sourceProofSubmitted = true; 240 | // ensure this proof can't be reused by the same sender 241 | signedMessages[_channelId][_h][msg.sender] = true; 242 | // notify blockchain 243 | SourceProofSubmitted(_channelId, signer); 244 | if (verifyDoubleProof(_channelId, true)) { 245 | ercChannels[_channelId].state = ChannelStates.finalized; 246 | } 247 | return true; 248 | } 249 | 250 | /** 251 | Need to add a require function to check for sign messaged hash use 252 | */ 253 | function submitErcDestinationProof( 254 | bytes32 _h, 255 | uint8 _v, 256 | bytes32 _r, 257 | bytes32 _s, 258 | bytes32 _channelId) 259 | public 260 | returns (bool) 261 | { 262 | // verify correct channel id 263 | require(channelIds[_channelId]); 264 | // ensure channel state is opened 265 | require(ercChannels[_channelId].state == ChannelStates.opened); 266 | // make sure destination proof hasn't already been submitted 267 | require(!ercChannels[_channelId].destinationProofSubmitted); 268 | // recover address of signer 269 | address signer = ecrecover(_h, _v, _r, _s); 270 | // ensure that the signer is the destionation of the channel 271 | assert (signer == ercChannels[_channelId].destination); 272 | // mark destination proof as submitted 273 | ercChannels[_channelId].destinationProofSubmitted = true; 274 | // ensure this proof can't be reused by the same sender 275 | signedMessages[_channelId][_h][msg.sender] = true; 276 | // notify blockchain 277 | DestinationProofSubmitted(_channelId, signer); 278 | if (verifyDoubleProof(_channelId, true)) { 279 | ercChannels[_channelId].state = ChannelStates.finalized; 280 | } 281 | return true; 282 | } 283 | 284 | function submitErcMicroPaymentProof( 285 | bytes32 _h, 286 | uint8 _v, 287 | bytes32 _r, 288 | bytes32 _s, 289 | bytes32 _channelId, 290 | uint256 _paymentId, 291 | uint256 _amount) 292 | public 293 | returns (bool) 294 | { 295 | require(channelIds[_channelId]); 296 | require(ercChannels[_channelId].state == ChannelStates.opened); 297 | require(ercChannels[_channelId].value > 0); 298 | require(msg.sender == ercChannels[_channelId].destination); 299 | bytes32 proof = keccak256(abi.encodePacked(_channelId, _paymentId, _amount)); 300 | bytes32 prefixedProof = keccak256(abi.encodePacked(prefix, proof)); 301 | assert(prefixedProof == _h); 302 | address signer = ecrecover(_h, _v, _r, _s); 303 | assert(signer == ercChannels[_channelId].source); 304 | uint256 remainingChannelValue = ercChannels[_channelId].value.sub(_amount); 305 | ercChannels[_channelId].value = remainingChannelValue; 306 | ERC20Interface e = ERC20Interface(ercChannels[_channelId].tokenAddress); 307 | TokensWithdrawn(ercChannels[_channelId].tokenAddress); 308 | require(e.transfer(msg.sender, _amount)); 309 | return true; 310 | } 311 | 312 | function closeErcChannel( 313 | bytes32 _channelId, 314 | address _tokenAddress) 315 | public 316 | returns (bool) 317 | { 318 | require(channelIds[_channelId]); 319 | require(ercChannels[_channelId].state == ChannelStates.finalized); 320 | // make sure that once the channel is finalized *ONLY* the destination can withdraw funds 321 | require(msg.sender == ercChannels[_channelId].destination); 322 | require(_tokenAddress == ercChannels[_channelId].tokenAddress); 323 | uint256 deposit = ercChannels[_channelId].value; 324 | ercChannels[_channelId].value = 0; 325 | // lets close the channel 326 | ercChannels[_channelId].state = ChannelStates.closed; 327 | ERC20Interface e = ERC20Interface(_tokenAddress); 328 | ChannelClosed(_channelId); 329 | TokensWithdrawn(_tokenAddress); 330 | require(e.transfer(msg.sender, deposit)); 331 | return true; 332 | } 333 | 334 | 335 | /** 336 | Used to withdraw whatever funds are remaining in the channel, so long as the channel is opened 337 | */ 338 | function expireErcChannel( 339 | bytes32 _channelId, 340 | address _tokenAddress) 341 | public 342 | returns (bool) 343 | { 344 | require(channelIds[_channelId]); 345 | require(ercChannels[_channelId].state == ChannelStates.opened); 346 | // make sure that only the source is allowed to invoke this function 347 | require(msg.sender == ercChannels[_channelId].source); 348 | require(_tokenAddress == ercChannels[_channelId].tokenAddress); 349 | uint256 deposit = ercChannels[_channelId].value; 350 | ercChannels[_channelId].value = 0; 351 | ercChannels[_channelId].state = ChannelStates.expired; 352 | ERC20Interface e = ERC20Interface(_tokenAddress); 353 | ChannelExpired(_channelId); 354 | TokensWithdrawn(_tokenAddress); 355 | require(e.transfer(msg.sender, deposit)); 356 | return true; 357 | } 358 | 359 | /** end of erc20 channel functions */ 360 | 361 | /** start of internal functions */ 362 | 363 | /** 364 | Set _ercChannel to true if you are attempting to verify the submission status of both proofs for an ERC channel 365 | Set _ercChannel to false if you are attempting to verify the submission status of both proofs for an ETH channel 366 | */ 367 | function verifyDoubleProof( 368 | bytes32 _channelId, 369 | bool _ercChannel) 370 | internal 371 | view 372 | returns (bool) 373 | { 374 | if (_ercChannel) { 375 | require(ercChannels[_channelId].state == ChannelStates.opened); 376 | if (ercChannels[_channelId].sourceProofSubmitted == true && ercChannels[_channelId].destinationProofSubmitted) { 377 | return true; 378 | } 379 | } else { 380 | require(ethChannels[_channelId].state == ChannelStates.opened); 381 | if (ethChannels[_channelId].sourceProofSubmitted == true && ethChannels[_channelId].destinationProofSubmitted) { 382 | return true; 383 | } 384 | } 385 | return false; 386 | } 387 | 388 | /** 389 | withdraw any ether in the contract, only when in developer mode 390 | */ 391 | function withdrawEth() 392 | public 393 | onlyAdmin 394 | returns (bool) 395 | { 396 | require(dev); 397 | EthWithdrawn(); 398 | msg.sender.transfer(address(this).balance); 399 | return true; 400 | } 401 | 402 | function withdrawTokens( 403 | address _tokenAddress) 404 | public 405 | onlyAdmin 406 | returns (bool) 407 | { 408 | require(dev); 409 | ERC20Interface e = ERC20Interface(_tokenAddress); 410 | uint256 balance = e.balanceOf(address(this)); 411 | TokensWithdrawn(_tokenAddress); 412 | require(e.transfer(msg.sender, balance)); 413 | return true; 414 | } 415 | 416 | } -------------------------------------------------------------------------------- /solidity/Interfaces/ERC20Interface.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.7.0; 2 | 3 | /* 4 | ERC20 Standard Token interface 5 | */ 6 | interface ERC20Interface { 7 | function owner() external view returns (address); 8 | function decimals() external view returns (uint8); 9 | function transfer(address _to, uint256 _value) external returns (bool); 10 | function transferFrom(address _from, address _to, uint256 _value) external returns (bool); 11 | function approve(address _spender, uint256 _amount) external returns (bool); 12 | function totalSupply() external view returns (uint256); 13 | function balanceOf(address _owner) external view returns (uint256); 14 | function allowance(address _owner, address _spender) external view returns (uint256); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /solidity/Libs/EcRecovery.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | 4 | /** 5 | * @title Eliptic curve signature operations 6 | * 7 | * @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d 8 | */ 9 | 10 | library ECRecovery { 11 | 12 | /** 13 | * @dev Recover signer address from a message by using his signature 14 | * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address. 15 | * @param sig bytes signature, the signature is generated using web3.eth.sign() 16 | */ 17 | function recover(bytes32 hash, bytes sig) public pure returns (address) { 18 | bytes32 r; 19 | bytes32 s; 20 | uint8 v; 21 | 22 | //Check the signature length 23 | if (sig.length != 65) { 24 | return (address(0)); 25 | } 26 | 27 | // Divide the signature in r, s and v variables 28 | assembly { 29 | r := mload(add(sig, 32)) 30 | s := mload(add(sig, 64)) 31 | v := byte(0, mload(add(sig, 96))) 32 | } 33 | 34 | // Version of signature should be 27 or 28, but 0 and 1 are also possible versions 35 | if (v < 27) { 36 | v += 27; 37 | } 38 | 39 | // If the version is correct return the signer address 40 | if (v != 27 && v != 28) { 41 | return (address(0)); 42 | } else { 43 | return ecrecover(hash, v, r, s); 44 | } 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /solidity/Math/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.7.0; 2 | 3 | // implement safemath as a library 4 | library SafeMath { 5 | 6 | // We use `pure` bbecause it promises that the value for the function depends ONLY 7 | // on the function arguments 8 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 9 | uint256 c = a * b; 10 | require(a == 0 || c / a == b); 11 | return c; 12 | } 13 | 14 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 15 | uint256 c = a / b; 16 | return c; 17 | } 18 | 19 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 20 | require(b <= a); 21 | return a - b; 22 | } 23 | 24 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 25 | uint256 c = a + b; 26 | require(c >= a); 27 | return c; 28 | } 29 | } -------------------------------------------------------------------------------- /solidity/Modules/Administration.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.7.0; 2 | 3 | contract Administration { 4 | 5 | address public owner; 6 | address public admin; 7 | bool public frozen; 8 | 9 | mapping (address => bool) public moderators; 10 | 11 | event AdminSet(address indexed _admin, bool indexed _adminSet); 12 | event OwnershipTransferred(address indexed _previousOwner, address indexed _newOwner, bool indexed _ownershipTransferred); 13 | 14 | modifier onlyOwner() { 15 | require(msg.sender == owner); 16 | _; 17 | } 18 | 19 | modifier onlyAdmin() { 20 | require(msg.sender == owner || msg.sender == admin); 21 | _; 22 | } 23 | 24 | modifier onlyPrivileged() { 25 | require(msg.sender == owner || msg.sender == admin || moderators[msg.sender] == true); 26 | _; 27 | } 28 | 29 | constructor() { 30 | owner = msg.sender; 31 | admin = msg.sender; 32 | } 33 | 34 | function setAdmin( 35 | address _newAdmin 36 | ) 37 | public 38 | onlyOwner 39 | returns (bool) 40 | { 41 | require(_newAdmin != admin); 42 | admin = _newAdmin; 43 | emit AdminSet(_newAdmin, true); 44 | } 45 | 46 | function transferOwnership( 47 | address _newOwner 48 | ) 49 | public 50 | onlyOwner 51 | returns (bool) 52 | { 53 | require(_newOwner != owner); 54 | owner = _newOwner; 55 | emit OwnershipTransferred(msg.sender, _newOwner, true); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /solidity/old/ChannelsV1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.4.20; 2 | import "./Modules/Administration.sol"; 3 | import "./Math/SafeMath.sol"; 4 | import "./Libs/EcRecovery.sol"; 5 | /** 6 | Add message hash verificaton when submitting a second signature. 7 | first signature to submit commits the message hash, subsequent signatures mush also submit a signature 8 | which verifies off that message hash. This should help reduce exploitation attempts 9 | */ 10 | contract PaymentChannels is Administration { 11 | 12 | using SafeMath for uint256; 13 | 14 | 15 | uint256 private channelCount; 16 | bool public dev = true; 17 | 18 | struct ChannelStruct { 19 | address purchaser; 20 | address vendor; 21 | uint256 value; 22 | uint256 autoClosureDate; 23 | bytes32 channelId; 24 | bool opened; 25 | bool closed; 26 | bool timedOut; 27 | mapping (address => bool) proofSubmitted; 28 | } 29 | 30 | mapping (uint256 => bytes32) private channelNumber; 31 | mapping (bytes32 => ChannelStruct) public channels; 32 | mapping (bytes32 => bool) private channelIds; 33 | 34 | event ChannelOpened(address indexed _purchaser, address indexed _vendor, bytes32 indexed _channelId); 35 | event ChannelClosed(bytes32 indexed _channelId); 36 | event VendorProofSubmitted(bytes32 indexed _channelId, address indexed _recoveredAddress); 37 | event PurchaserProofSubmitted(bytes32 indexed _channelId, address indexed _recoveredAddress); 38 | 39 | function () public payable {} 40 | 41 | function openChannel( 42 | address _vendor, 43 | uint256 _value) 44 | public 45 | payable 46 | returns (bool) 47 | { 48 | bytes32 channelId = keccak256(msg.sender, _vendor, _value); 49 | require(!channelIds[channelId]); 50 | require(!channels[channelId].opened); 51 | channelIds[channelId] = true; 52 | channels[channelId].purchaser = msg.sender; 53 | channels[channelId].vendor = _vendor; 54 | channels[channelId].value = _value; 55 | channels[channelId].channelId = channelId; 56 | channels[channelId].opened = true; 57 | channels[channelId].autoClosureDate = block.timestamp + 10 days; 58 | ChannelOpened(msg.sender, _vendor, channelId); 59 | return true; 60 | } 61 | 62 | 63 | /** 64 | Working 65 | */ 66 | function submitPurchaserProof( 67 | bytes32 _h, // message hash signed by purchaser 68 | uint8 _v, 69 | bytes32 _r, 70 | bytes32 _s, 71 | address _purchaser, // address of the purchaser 72 | uint256 _channelValue) // value of the channel, used to generate channel ID 73 | public 74 | returns (bool) 75 | { 76 | bytes32 channelId = keccak256(_purchaser, msg.sender, _channelValue); 77 | require(channels[channelId].vendor == msg.sender); 78 | require(channels[channelId].closed == false && channels[channelId].timedOut == false); 79 | require(_purchaser == channels[channelId].purchaser); 80 | address signer = ecrecover(_h, _v, _r, _s); 81 | require(signer == _purchaser); 82 | channels[channelId].proofSubmitted[signer] = true; 83 | PurchaserProofSubmitted(channelId, signer); 84 | return true; 85 | } 86 | 87 | /** 88 | For some reason, not with the purchaser proof but ONLY with the vendor proof (in testing at least) 89 | is not returning the correct value for `s`. In order to do so, we must convert `s` to bytes, then to hex. 90 | See readme for an explanation 91 | */ 92 | function submitVendorProof( 93 | bytes32 _h, 94 | uint8 _v, 95 | bytes32 _r, 96 | bytes32 _s, 97 | address _vendor, 98 | uint256 _channelValue) 99 | public 100 | returns (bool) 101 | { 102 | bytes32 channelId = keccak256(msg.sender, _vendor, _channelValue); 103 | require(channels[channelId].purchaser == msg.sender); 104 | require(channels[channelId].closed == false && channels[channelId].timedOut == false); 105 | require(_vendor == channels[channelId].vendor); 106 | address signer = ecrecover(_h, _v, _r, _s); 107 | require(signer == _vendor); 108 | channels[channelId].proofSubmitted[signer] = true; 109 | VendorProofSubmitted(channelId, signer); 110 | return true; 111 | } 112 | 113 | function vendorWithdraw( 114 | bytes32 _channelId) 115 | public 116 | returns (bool) 117 | { 118 | require(channelIds[_channelId]); 119 | require(channels[_channelId].vendor == msg.sender); 120 | require(channels[_channelId].closed == false); 121 | require(channels[_channelId].timedOut == false); 122 | require(channels[_channelId].proofSubmitted[msg.sender] == true); 123 | address purchaser = channels[_channelId].purchaser; 124 | require(channels[_channelId].proofSubmitted[purchaser] = true); 125 | channels[_channelId].closed =true; 126 | ChannelClosed(_channelId); 127 | msg.sender.transfer(channels[_channelId].value); 128 | return true; 129 | } 130 | function withdrawEth() 131 | public 132 | onlyAdmin 133 | returns (bool) 134 | { 135 | require(dev); 136 | msg.sender.transfer(this.balance); 137 | return true; 138 | } 139 | 140 | } -------------------------------------------------------------------------------- /solidity/old/ChannelsV2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.4.20; 2 | import "./Modules/Administration.sol"; 3 | import "./Math/SafeMath.sol"; 4 | 5 | /* 6 | Will be used as the basis for V3 which will enable icro payments, ontop of full channel payments 7 | */ 8 | contract PaymentChannels is Administration { 9 | 10 | using SafeMath for uint256; 11 | 12 | string constant public VERSION = "0.0.2alpha"; 13 | 14 | uint256 private channelCount; 15 | // prevent any possible accidental triggering of developer only conditions 16 | bool public dev = true; 17 | 18 | enum ChannelStates { opened, expired, closed } 19 | 20 | ChannelStates public defaultState = ChannelStates.opened; 21 | 22 | struct ChannelStruct { 23 | address purchaser; 24 | address vendor; 25 | uint256 value; 26 | uint256 closingDate; 27 | uint256 openDate; 28 | bytes32 channelId; 29 | bool purchaserProofSubmitted; 30 | bool vendorProofSubmitted; 31 | ChannelStates state; 32 | } 33 | 34 | mapping (bytes32 => ChannelStruct) public channels; 35 | mapping (uint256 => bytes32) private channelNumber; 36 | mapping (bytes32 => bool) private channelIds; 37 | // prevent resubmission of the same signed messages by a particular address within a channel 38 | mapping (bytes32 => mapping (bytes32 => mapping(address => bool))) private signedMessages; 39 | 40 | event ChannelOpened(bytes32 indexed _channelId); 41 | event ChannelClosed(bytes32 indexed _channelId); 42 | event ChannelExpired(bytes32 indexed _channelId); 43 | event VendorProofSubmitted(bytes32 indexed _channelId, address indexed _recoveredAddress); 44 | event PurchaserProofSubmitted(bytes32 indexed _channelId, address indexed _recoveredAddress); 45 | 46 | modifier bothProofsSubmitted(bytes32 _channelId) { 47 | require(channels[_channelId].vendorProofSubmitted); 48 | require(channels[_channelId].purchaserProofSubmitted); 49 | _; 50 | } 51 | 52 | function () public payable {} 53 | 54 | 55 | function openChannel( 56 | address _vendor, 57 | uint256 _channelValueInWei, 58 | uint256 _durationInDays) 59 | public 60 | payable 61 | returns (bool) 62 | { 63 | require(msg.value == _channelValueInWei); 64 | uint256 currentDate = block.timestamp; 65 | // channel hash = keccak256(purchaser, vendor, channel value, date of open) 66 | bytes32 channelId = keccak256(msg.sender, _vendor, _channelValueInWei, currentDate); 67 | // make sure the channel id doens't already exist 68 | require(!channelIds[channelId]); 69 | channelIds[channelId] = true; 70 | channels[channelId].purchaser = msg.sender; 71 | channels[channelId].vendor = _vendor; 72 | channels[channelId].value = _channelValueInWei; 73 | channels[channelId].closingDate = (block.timestamp + (_durationInDays * 1 days)); 74 | channels[channelId].openDate = currentDate; 75 | channels[channelId].channelId = channelId; 76 | channels[channelId].state = defaultState; 77 | ChannelOpened(channelId); 78 | return true; 79 | } 80 | 81 | function submitPurchaserProof( 82 | bytes32 _h, 83 | uint8 _v, 84 | bytes32 _r, 85 | bytes32 _s, 86 | bytes32 _channelId) 87 | public 88 | returns (bool) 89 | { 90 | require(channelIds[_channelId]); 91 | require(channels[_channelId].state == ChannelStates.opened); 92 | require(!signedMessages[_channelId][_h][msg.sender]); 93 | signedMessages[_channelId][_h][msg.sender] = true; 94 | address signer = ecrecover(_h, _v, _r, _s); 95 | require(signer == channels[_channelId].purchaser); 96 | channels[_channelId].purchaserProofSubmitted = true; 97 | PurchaserProofSubmitted(_channelId, signer); 98 | return true; 99 | } 100 | 101 | function submitVendorProof( 102 | bytes32 _h, 103 | uint8 _v, 104 | bytes32 _r, 105 | bytes32 _s, 106 | bytes32 _channelId) 107 | public 108 | returns (bool) 109 | { 110 | require(channelIds[_channelId]); 111 | require(channels[_channelId].state == ChannelStates.opened); 112 | require(!signedMessages[_channelId][_h][msg.sender]); 113 | signedMessages[_channelId][_h][msg.sender] = true; 114 | address signer = ecrecover(_h, _v, _r, _s); 115 | require(signer == channels[_channelId].vendor); 116 | channels[_channelId].vendorProofSubmitted = true; 117 | VendorProofSubmitted(_channelId, signer); 118 | return true; 119 | } 120 | 121 | function closeChannel( 122 | bytes32 _channelId) 123 | public 124 | bothProofsSubmitted(_channelId) 125 | returns (bool) 126 | { 127 | require(channelIds[_channelId]); 128 | require(channels[_channelId].state == ChannelStates.opened); 129 | require(channels[_channelId].value > 0); 130 | require(msg.sender == channels[_channelId].vendor); 131 | uint256 deposit = channels[_channelId].value; 132 | channels[_channelId].value = 0; 133 | channels[_channelId].state = ChannelStates.closed; 134 | ChannelClosed(_channelId); 135 | msg.sender.transfer(deposit); 136 | return true; 137 | } 138 | 139 | /** 140 | So long as both proofs have *NOT* been submitted, and it is past closing, terminate channel 141 | */ 142 | function expireChannel( 143 | bytes32 _channelId) 144 | public 145 | returns (bool) 146 | { 147 | require(channelIds[_channelId]); 148 | require(msg.sender == channels[_channelId].purchaser); 149 | // require that the channel is open 150 | require(channels[_channelId].state == ChannelStates.opened); 151 | // if both proofs have been submitted, throw 152 | if (channels[_channelId].purchaserProofSubmitted && channels[_channelId].vendorProofSubmitted) { 153 | revert(); 154 | } 155 | if (!dev) { 156 | require(block.timestamp >= channels[_channelId].closingDate); 157 | } 158 | channels[_channelId].state = ChannelStates.expired; 159 | uint256 deposit = channels[_channelId].value; 160 | channels[_channelId].value = 0; 161 | ChannelExpired(_channelId); 162 | msg.sender.transfer(deposit); 163 | return true; 164 | } 165 | 166 | /**tested 167 | withdraw any ether in the contract, only when in developer mode 168 | */ 169 | function withdrawEth() 170 | public 171 | onlyAdmin 172 | returns (bool) 173 | { 174 | require(dev); 175 | msg.sender.transfer(this.balance); 176 | return true; 177 | } 178 | 179 | } -------------------------------------------------------------------------------- /solidity/old/DateTime.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.4.20; 2 | 3 | import "./Math/SafeMath.sol"; 4 | 5 | contract DateTime { 6 | 7 | using SafeMath for uint256; 8 | 9 | /* 10 | * Date and Time utilities for ethereum contracts 11 | * 12 | */ 13 | struct _DateTime { 14 | uint16 year; 15 | uint8 month; 16 | uint8 day; 17 | uint8 hour; 18 | uint8 minute; 19 | uint8 second; 20 | uint8 weekday; 21 | } 22 | 23 | uint constant DAY_IN_SECONDS = 86400; 24 | uint constant YEAR_IN_SECONDS = 31536000; 25 | uint constant LEAP_YEAR_IN_SECONDS = 31622400; 26 | 27 | uint constant HOUR_IN_SECONDS = 3600; 28 | uint constant MINUTE_IN_SECONDS = 60; 29 | 30 | uint16 constant ORIGIN_YEAR = 1970; 31 | 32 | function retrieveTimeDifferenceInDays( 33 | uint256 _timeA, 34 | uint256 _timeB) 35 | public 36 | pure 37 | returns (uint256) 38 | { 39 | uint256 diff = _timeB - _timeA; 40 | return (((diff / 60)/60)/24); 41 | } 42 | 43 | function retrieveTimeDifferenceInHours( 44 | uint256 _timeA, 45 | uint256 _timeB) 46 | public 47 | pure 48 | returns (uint256) 49 | { 50 | uint256 diff = _timeB - _timeA; 51 | return ((diff / 60)/60); 52 | } 53 | 54 | function retrieveTimeDifferenceInSeconds( 55 | uint256 _timeA, 56 | uint256 _timeB) 57 | public 58 | pure 59 | returns (uint256) 60 | { 61 | uint256 diff = _timeB - _timeA; 62 | return (diff / 60); 63 | } 64 | 65 | function isLeapYear(uint16 year) public pure returns (bool) { 66 | if (year % 4 != 0) { 67 | return false; 68 | } 69 | if (year % 100 != 0) { 70 | return true; 71 | } 72 | if (year % 400 != 0) { 73 | return false; 74 | } 75 | return true; 76 | } 77 | 78 | function leapYearsBefore(uint year) public pure returns (uint) { 79 | year -= 1; 80 | return year / 4 - year / 100 + year / 400; 81 | } 82 | 83 | function getDaysInMonth(uint8 month, uint16 year) public pure returns (uint8) { 84 | if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { 85 | return 31; 86 | } 87 | else if (month == 4 || month == 6 || month == 9 || month == 11) { 88 | return 30; 89 | } 90 | else if (isLeapYear(year)) { 91 | return 29; 92 | } 93 | else { 94 | return 28; 95 | } 96 | } 97 | 98 | function parseTimestamp(uint timestamp) internal pure returns (_DateTime dt) { 99 | uint secondsAccountedFor = 0; 100 | uint buf; 101 | uint8 i; 102 | 103 | // Year 104 | dt.year = getYear(timestamp); 105 | buf = leapYearsBefore(dt.year) - leapYearsBefore(ORIGIN_YEAR); 106 | 107 | secondsAccountedFor += LEAP_YEAR_IN_SECONDS * buf; 108 | secondsAccountedFor += YEAR_IN_SECONDS * (dt.year - ORIGIN_YEAR - buf); 109 | 110 | // Month 111 | uint secondsInMonth; 112 | for (i = 1; i <= 12; i++) { 113 | secondsInMonth = DAY_IN_SECONDS * getDaysInMonth(i, dt.year); 114 | if (secondsInMonth + secondsAccountedFor > timestamp) { 115 | dt.month = i; 116 | break; 117 | } 118 | secondsAccountedFor += secondsInMonth; 119 | } 120 | 121 | // Day 122 | for (i = 1; i <= getDaysInMonth(dt.month, dt.year); i++) { 123 | if (DAY_IN_SECONDS + secondsAccountedFor > timestamp) { 124 | dt.day = i; 125 | break; 126 | } 127 | secondsAccountedFor += DAY_IN_SECONDS; 128 | } 129 | 130 | // Hour 131 | dt.hour = getHour(timestamp); 132 | 133 | // Minute 134 | dt.minute = getMinute(timestamp); 135 | 136 | // Second 137 | dt.second = getSecond(timestamp); 138 | 139 | // Day of week. 140 | dt.weekday = getWeekday(timestamp); 141 | } 142 | 143 | function getYear(uint timestamp) public pure returns (uint16) { 144 | uint secondsAccountedFor = 0; 145 | uint16 year; 146 | uint numLeapYears; 147 | 148 | // Year 149 | year = uint16(ORIGIN_YEAR + timestamp / YEAR_IN_SECONDS); 150 | numLeapYears = leapYearsBefore(year) - leapYearsBefore(ORIGIN_YEAR); 151 | 152 | secondsAccountedFor += LEAP_YEAR_IN_SECONDS * numLeapYears; 153 | secondsAccountedFor += YEAR_IN_SECONDS * (year - ORIGIN_YEAR - numLeapYears); 154 | 155 | while (secondsAccountedFor > timestamp) { 156 | if (isLeapYear(uint16(year - 1))) { 157 | secondsAccountedFor -= LEAP_YEAR_IN_SECONDS; 158 | } 159 | else { 160 | secondsAccountedFor -= YEAR_IN_SECONDS; 161 | } 162 | year -= 1; 163 | } 164 | return year; 165 | } 166 | 167 | function getMonth(uint timestamp) public pure returns (uint8) { 168 | return parseTimestamp(timestamp).month; 169 | } 170 | 171 | function getDay(uint timestamp) public pure returns (uint8) { 172 | return parseTimestamp(timestamp).day; 173 | } 174 | 175 | function getHour(uint timestamp) public pure returns (uint8) { 176 | return uint8((timestamp / 60 / 60) % 24); 177 | } 178 | 179 | function getMinute(uint timestamp) public pure returns (uint8) { 180 | return uint8((timestamp / 60) % 60); 181 | } 182 | 183 | function getSecond(uint timestamp) public pure returns (uint8) { 184 | return uint8(timestamp % 60); 185 | } 186 | 187 | function getWeekday(uint timestamp) public pure returns (uint8) { 188 | return uint8((timestamp / DAY_IN_SECONDS + 4) % 7); 189 | } 190 | 191 | function toTimestamp(uint16 year, uint8 month, uint8 day) public pure returns (uint timestamp) { 192 | return toTimestamp(year, month, day, 0, 0, 0); 193 | } 194 | 195 | function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour) public pure returns (uint timestamp) { 196 | return toTimestamp(year, month, day, hour, 0, 0); 197 | } 198 | 199 | function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute) public pure returns (uint timestamp) { 200 | return toTimestamp(year, month, day, hour, minute, 0); 201 | } 202 | 203 | function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute, uint8 second) public pure returns (uint timestamp) { 204 | uint16 i; 205 | 206 | // Year 207 | for (i = ORIGIN_YEAR; i < year; i++) { 208 | if (isLeapYear(i)) { 209 | timestamp += LEAP_YEAR_IN_SECONDS; 210 | } 211 | else { 212 | timestamp += YEAR_IN_SECONDS; 213 | } 214 | } 215 | 216 | // Month 217 | uint8[12] memory monthDayCounts; 218 | monthDayCounts[0] = 31; 219 | if (isLeapYear(year)) { 220 | monthDayCounts[1] = 29; 221 | } 222 | else { 223 | monthDayCounts[1] = 28; 224 | } 225 | monthDayCounts[2] = 31; 226 | monthDayCounts[3] = 30; 227 | monthDayCounts[4] = 31; 228 | monthDayCounts[5] = 30; 229 | monthDayCounts[6] = 31; 230 | monthDayCounts[7] = 31; 231 | monthDayCounts[8] = 30; 232 | monthDayCounts[9] = 31; 233 | monthDayCounts[10] = 30; 234 | monthDayCounts[11] = 31; 235 | 236 | for (i = 1; i < month; i++) { 237 | timestamp += DAY_IN_SECONDS * monthDayCounts[i - 1]; 238 | } 239 | 240 | // Day 241 | timestamp += DAY_IN_SECONDS * (day - 1); 242 | 243 | // Hour 244 | timestamp += HOUR_IN_SECONDS * (hour); 245 | 246 | // Minute 247 | timestamp += MINUTE_IN_SECONDS * (minute); 248 | 249 | // Second 250 | timestamp += second; 251 | 252 | return timestamp; 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /solidity/old/TestToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.4.20; 2 | 3 | import "./Math/SafeMath.sol"; 4 | import "./Modules/Administration.sol"; 5 | 6 | contract ERC20 { 7 | 8 | using SafeMath for uint256; 9 | 10 | string public name; 11 | string public symbol; 12 | uint256 public totalSupply; 13 | uint8 public decimals; 14 | 15 | mapping (address => uint256) public balances; 16 | mapping (address => mapping (address => uint256)) public allowed; 17 | 18 | event Transfer(address indexed _sender, address indexed _recipient, uint256 _amount); 19 | event Approve(address indexed _owner, address indexed _spender, uint256 _amount); 20 | 21 | function ERC20() { 22 | name = "SafeOrDapp"; 23 | symbol = "SOD"; 24 | decimals = 18; 25 | totalSupply = 2000000000000000000000000000; 26 | balances[msg.sender] = totalSupply; 27 | } 28 | 29 | function transfer( 30 | address _recipient, 31 | uint256 _amount 32 | ) 33 | public 34 | returns (bool transferred) 35 | { 36 | require(transferCheck(msg.sender, _recipient, _amount)); 37 | balances[msg.sender] = balances[msg.sender].sub(_amount); 38 | balances[_recipient] = balances[_recipient].add(_amount); 39 | Transfer(msg.sender, _recipient, _amount); 40 | return true; 41 | } 42 | 43 | function transferFrom( 44 | address _owner, 45 | address _recipient, 46 | uint256 _amount 47 | ) 48 | public 49 | returns (bool transferredFrom) 50 | { 51 | require(transferCheck(_owner, _recipient, _amount)); 52 | require(allowed[_owner][msg.sender] >= _amount); 53 | require(allowed[_owner][msg.sender].sub(_amount) >= 0); 54 | allowed[_owner][msg.sender] = allowed[_owner][msg.sender].sub(_amount); 55 | balances[_owner] = balances[_owner].sub(_amount); 56 | balances[_recipient] = balances[_recipient].add(_amount); 57 | Transfer(_owner, _recipient, _amount); 58 | return true; 59 | } 60 | 61 | function approve( 62 | address _spender, 63 | uint256 _amount 64 | ) 65 | public 66 | returns (bool approved) 67 | { 68 | require(_spender != address(0x0)); 69 | require(_amount > 0); 70 | require(allowed[msg.sender][_spender].add(_amount) > allowed[msg.sender][_spender]); 71 | allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_amount); 72 | return true; 73 | } 74 | 75 | /**INTERNALS */ 76 | 77 | function transferCheck( 78 | address _sender, 79 | address _recipient, 80 | uint256 _amount 81 | ) 82 | internal 83 | view 84 | returns (bool valid) 85 | { 86 | require(_sender != address(0x0) && _recipient != address(0x0) && _amount > 0); 87 | require(balances[_sender].sub(_amount) >= 0); 88 | require(balances[_recipient].add(_amount) > 0); 89 | require(balances[_recipient].add(_amount) > balances[_recipient]); 90 | return true; 91 | } 92 | 93 | /**GETTERS */ 94 | 95 | function totalSupply() 96 | public 97 | view 98 | returns (uint256) 99 | { 100 | return totalSupply; 101 | } 102 | 103 | function balanceOf( 104 | address _holder 105 | ) 106 | public 107 | view 108 | returns (uint256) 109 | { 110 | return balances[_holder]; 111 | } 112 | 113 | function allowance( 114 | address _owner, 115 | address _spender 116 | ) 117 | public 118 | view 119 | returns (uint256) 120 | { 121 | return allowed[_owner][_spender]; 122 | } 123 | } -------------------------------------------------------------------------------- /solidity/old/TimeApi.sol: -------------------------------------------------------------------------------- 1 | contract DateTimeAPI { 2 | /* 3 | * Abstract contract for interfacing with the DateTime contract. 4 | * 5 | */ 6 | function retrieveTimeDifferenceInDays(uint256 _timeA, uint256 _timeB) public pure returns (uint256); 7 | function retrieveTimeDifferenceInHours(uint256 _timeA, uint256 _timeB) public pure returns (uint256); 8 | function retrieveTimeDifferenceInSeconds(uint256 _timeA, uint256 _timeB) public returns (uint256); 9 | function isLeapYear(uint16 year) constant returns (bool); 10 | function getYear(uint timestamp) constant returns (uint16); 11 | function getMonth(uint timestamp) constant returns (uint8); 12 | function getDay(uint timestamp) constant returns (uint8); 13 | function getHour(uint timestamp) constant returns (uint8); 14 | function getMinute(uint timestamp) constant returns (uint8); 15 | function getSecond(uint timestamp) constant returns (uint8); 16 | function getWeekday(uint timestamp) constant returns (uint8); 17 | function toTimestamp(uint16 year, uint8 month, uint8 day) constant returns (uint timestamp); 18 | function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour) constant returns (uint timestamp); 19 | function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute) constant returns (uint timestamp); 20 | function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute, uint8 second) constant returns (uint timestamp); 21 | } -------------------------------------------------------------------------------- /solidity/old/micro.sol: -------------------------------------------------------------------------------- 1 | function submitMicroPaymentProof( 2 | bytes32 _channelId, 3 | bytes32 _h, 4 | uint8 _v, 5 | bytes32 _r, 6 | bytes32 _s, 7 | uint256 _paymentId, 8 | uint256 _withdrawalAmount) 9 | public 10 | returns (bool) 11 | { 12 | // validate channel id 13 | require(channelIds[_channelId]); 14 | // validate channel state 15 | require(channels[_channelId].state == ChannelStates.opened); 16 | // make sure nobody else is trying to withdraw the funds 17 | require(msg.sender == channels[_channelId].destination); 18 | // prevent a micropayment from reducing the entire balance 19 | require(channels[_channelId].value > _withdrawalAmount && _withdrawalAmount > 0); 20 | // following two lines construct the proof, with prefix to validate _h 21 | bytes32 _proof = keccak256(_channelId, _paymentId, _withdrawalAmount); 22 | bytes32 proof = keccak256(prefix, _proof); 23 | // validate the proof, if it fails most likely malicious submitter, so lets waste their gas ;) 24 | assert(proof == _h); 25 | // make sure the proof hasn't already bee submitted 26 | require(!microPaymentHashes[_channelId][_h]); 27 | // mark proof as submitted 28 | microPaymentHashes[_channelId][_h] = true; 29 | // time to recover the signature 30 | address signer = ecrecover(_h, _v, _r, _s); 31 | // make sure its from the source, otherwise someones up to no good so lets waste their gas ;) 32 | assert(signer == channels[_channelId].source); 33 | // calculate remaining channel value 34 | uint256 remainingChannelValue = channels[_channelId].value.sub(_withdrawalAmount); 35 | // adjust channel value 36 | channels[_channelId].value = remainingChannelValue; 37 | // notify blockchain 38 | MicroPaymentWithdrawn(_channelId, _withdrawalAmount, remainingChannelValue); 39 | // withdraw funds 40 | msg.sender.transfer(_withdrawalAmount); 41 | return true; 42 | } -------------------------------------------------------------------------------- /solidity/old/re_report.report: -------------------------------------------------------------------------------- 1 | 2 | nelsV4.sol:PaymentChannels.evm.disasm -------------------------------------------------------------------------------- /src/airdrop/airdrop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bonedaddy/Postables-Payment-Channel/b70fa471f81a32c4b278721856bb118fcc848a4d/src/airdrop/airdrop -------------------------------------------------------------------------------- /src/airdrop/bindings/airdrop_channels.go: -------------------------------------------------------------------------------- 1 | // Code generated - DO NOT EDIT. 2 | // This file is a generated binding and any manual changes will be lost. 3 | 4 | package bindings 5 | 6 | import ( 7 | "math/big" 8 | "strings" 9 | 10 | ethereum "github.com/ethereum/go-ethereum" 11 | "github.com/ethereum/go-ethereum/accounts/abi" 12 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 13 | "github.com/ethereum/go-ethereum/common" 14 | "github.com/ethereum/go-ethereum/core/types" 15 | "github.com/ethereum/go-ethereum/event" 16 | ) 17 | 18 | // AirdropABI is the input ABI used to generate the binding from. 19 | const AirdropABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"frozen\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"}],\"name\":\"moderators\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_h\",\"type\":\"bytes32\"},{\"name\":\"_v\",\"type\":\"uint8\"},{\"name\":\"_r\",\"type\":\"bytes32\"},{\"name\":\"_s\",\"type\":\"bytes32\"},{\"name\":\"_channelId\",\"type\":\"bytes32\"},{\"name\":\"_id\",\"type\":\"uint256\"}],\"name\":\"retrieveAirdrop\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_h\",\"type\":\"bytes32\"},{\"name\":\"_v\",\"type\":\"uint8\"},{\"name\":\"_r\",\"type\":\"bytes32\"},{\"name\":\"_s\",\"type\":\"bytes32\"},{\"name\":\"_channelId\",\"type\":\"bytes32\"},{\"name\":\"_id\",\"type\":\"uint256\"}],\"name\":\"enableAirdrops\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_h\",\"type\":\"bytes32\"},{\"name\":\"_v\",\"type\":\"uint8\"},{\"name\":\"_r\",\"type\":\"bytes32\"},{\"name\":\"_s\",\"type\":\"bytes32\"},{\"name\":\"_channelId\",\"type\":\"bytes32\"}],\"name\":\"closeChannel\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_newAdmin\",\"type\":\"address\"}],\"name\":\"setAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"channels\",\"outputs\":[{\"name\":\"source\",\"type\":\"address\"},{\"name\":\"tokenAddress\",\"type\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\"},{\"name\":\"closingDate\",\"type\":\"uint256\"},{\"name\":\"openDate\",\"type\":\"uint256\"},{\"name\":\"dropAmount\",\"type\":\"uint256\"},{\"name\":\"totalDrops\",\"type\":\"uint256\"},{\"name\":\"channelId\",\"type\":\"bytes32\"},{\"name\":\"intf\",\"type\":\"address\"},{\"name\":\"state\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_h\",\"type\":\"bytes32\"},{\"name\":\"_v\",\"type\":\"uint8\"},{\"name\":\"_r\",\"type\":\"bytes32\"},{\"name\":\"_s\",\"type\":\"bytes32\"}],\"name\":\"verifyProof\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"dev\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"withdrawEth\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_tokenAddress\",\"type\":\"address\"},{\"name\":\"_channelValue\",\"type\":\"uint256\"},{\"name\":\"_durationInDays\",\"type\":\"uint256\"},{\"name\":\"_dropAmount\",\"type\":\"uint256\"}],\"name\":\"openChannel\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"VERSION\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_channelId\",\"type\":\"bytes32\"}],\"name\":\"ChannelOpened\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_channelId\",\"type\":\"bytes32\"}],\"name\":\"ChannelClosed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_channelId\",\"type\":\"bytes32\"}],\"name\":\"AirDropsEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_channelId\",\"type\":\"bytes32\"}],\"name\":\"AirDropDispersed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"signer\",\"type\":\"address\"}],\"name\":\"SignatureRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"_h\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"_proof\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"prefixedProof\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"signer\",\"type\":\"address\"}],\"name\":\"SigDebug\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_admin\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_adminSet\",\"type\":\"bool\"}],\"name\":\"AdminSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_newOwner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_ownershipTransferred\",\"type\":\"bool\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"}]" 20 | 21 | // AirdropBin is the compiled bytecode used for deploying new contracts. 22 | const AirdropBin = `60c0604052601c60808190527f19457468657265756d205369676e6564204d6573736167653a0a33320000000060a090815262000040916003919062000074565b506004805460ff1916600190811790915560008054600160a060020a03199081163390811790925582541617905562000119565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620000b757805160ff1916838001178555620000e7565b82800160010185558215620000e7579182015b82811115620000e7578251825591602001919060010190620000ca565b50620000f5929150620000f9565b5090565b6200011691905b80821115620000f5576000815560010162000100565b90565b6113b680620001296000396000f3006080604052600436106100da5763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663054f7d9c81146100dc57806314d0f1ba14610105578063515982f61461012657806356715148146101505780635c9bd2731461017a578063704b6c02146101a15780637a7ebd7b146101c25780638da5cb5b1461025357806391456d3d1461028457806391cca3db146102a8578063a0ef91df146102bd578063f2fde38b146102d2578063f36bdb49146102f3578063f851a44014610310578063ffa1ad7414610325575b005b3480156100e857600080fd5b506100f16103af565b604080519115158252519081900360200190f35b34801561011157600080fd5b506100f1600160a060020a03600435166103bf565b34801561013257600080fd5b506100f160043560ff6024351660443560643560843560a4356103d4565b34801561015c57600080fd5b506100f160043560ff6024351660443560643560843560a435610813565b34801561018657600080fd5b506100f160043560ff60243516604435606435608435610b93565b3480156101ad57600080fd5b506100f1600160a060020a0360043516610e40565b3480156101ce57600080fd5b506101da600435610ecb565b60408051600160a060020a03808d1682528b811660208301529181018a9052606081018990526080810188905260a0810187905260c0810186905260e08101859052908316610100820152610120810182600281111561023657fe5b60ff1681526020019a505050505050505050505060405180910390f35b34801561025f57600080fd5b50610268610f31565b60408051600160a060020a039092168252519081900360200190f35b34801561029057600080fd5b5061026860043560ff60243516604435606435610f40565b3480156102b457600080fd5b506100f1610fad565b3480156102c957600080fd5b506100f1610fb6565b3480156102de57600080fd5b506100f1600160a060020a036004351661102b565b6100f1600160a060020a03600435166024356044356064356110b9565b34801561031c57600080fd5b50610268611316565b34801561033157600080fd5b5061033a611325565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561037457818101518382015260200161035c565b50505050905090810190601f1680156103a15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60015460a060020a900460ff1681565b60026020526000908152604090205460ff1681565b60008281526005602052604081205481908190819060ff1615156103f757600080fd5b600160008781526006602052604090206008015460a060020a900460ff16600281111561042057fe5b1461042a57600080fd5b60008681526006602052604090206005810154600290910154101561044e57600080fd5b600086815260076020908152604080832033845290915290205460ff161561047557600080fd5b6040805160208082018990528183018890526c010000000000000000000000003302606083015282516054818403018152607490920192839052815191929182918401908083835b602083106104dc5780518252601f1990920191602091820191016104bd565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250600383604051602001808380546001816001161561010002031660029004801561056c5780601f1061054a57610100808354040283529182019161056c565b820191906000526020600020905b815481529060010190602001808311610558575b505091825250604080518083038152602092830191829052805190935090918291908401908083835b602083106105b45780518252601f199092019160209182019101610595565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020915060018a8a8a8a604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af115801561065a573d6000803e3d6000fd5b505060408051601f190151600089815260066020529190912054909250600160a060020a03808416911614905061068d57fe5b818a1461069657fe5b60008681526007602090815260408083203384528252808320805460ff191660011790558883526006909152902060058101546002909101546106de9163ffffffff61135c16565b60008781526006602081905260409091206002810192909255015461070a90600163ffffffff61137116565b600087815260066020819052604080832090910192909255905187917fa467a409776bfc50e32dd8496edd970b5e7a84a38acda61529d8022bf757c2fd91a26000868152600660209081526040808320600881015460059091015482517fa9059cbb00000000000000000000000000000000000000000000000000000000815233600482015260248101919091529151600160a060020a039091169363a9059cbb93604480850194919392918390030190829087803b1580156107cc57600080fd5b505af11580156107e0573d6000803e3d6000fd5b505050506040513d60208110156107f657600080fd5b5051151561080357600080fd5b5060019998505050505050505050565b60008281526005602052604081205481908190819060ff16151561083657600080fd5b6000808781526006602052604090206008015460a060020a900460ff16600281111561085e57fe5b1461086857600080fd5b600086815260066020526040902054600160a060020a0316331461088b57600080fd5b604080516020808201899052818301889052825180830384018152606090920192839052815191929182918401908083835b602083106108dc5780518252601f1990920191602091820191016108bd565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250600383604051602001808380546001816001161561010002031660029004801561096c5780601f1061094a57610100808354040283529182019161096c565b820191906000526020600020905b815481529060010190602001808311610958575b505091825250604080518083038152602092830191829052805190935090918291908401908083835b602083106109b45780518252601f199092019160209182019101610995565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020915060018a8a8a8a604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af1158015610a5a573d6000803e3d6000fd5b505060408051601f190151600089815260066020529190912054909250600160a060020a038084169116149050610a8d57fe5b818a14610a9657fe5b6000868152600660205260409020600801805474ff0000000000000000000000000000000000000000191660a060020a17905560045460ff1615610b2457604080518b815260208101859052808201849052600160a060020a038316606082015290517f6b7f08f909e42085ce2477fcf9f51be4ff86e5bcc7936c2dbe39e6757d33f9149181900360800190a15b60405186907ff857a98ed55303cc061ea3bc4c498fe49361c82cb72894280249b89848f9ce4690600090a2604051600160a060020a038216907f5c001d7523e0202fd001401f8393d128fbb1fafa8f637949f7d231d814f93b1390600090a25060019998505050505050505050565b6000818152600560205260408120548190819060ff161515610bb457600080fd5b6000808581526006602052604090206008015460a060020a900460ff166002811115610bdc57fe5b1480610c0e5750600160008581526006602052604090206008015460a060020a900460ff166002811115610c0c57fe5b145b1515610c1957600080fd5b60045460ff161515610c42576000848152600660205260409020600301544211610c4257600080fd5b600084815260066020526040902054600160a060020a03163314610c6557600080fd5b60408051600080825260208083018085528c905260ff8b1683850152606083018a905260808301899052925160019360a0808501949193601f19840193928390039091019190865af1158015610cbf573d6000803e3d6000fd5b505060408051601f190151600087815260066020529190912054909350600160a060020a038085169116149050610cf257fe5b600084815260066020526040812060088101805474ff0000000000000000000000000000000000000000191674020000000000000000000000000000000000000000179055426003820155600201541115610e07575060008381526006602090815260408083206002810180549085905560089091015482517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905292519194600160a060020a039091169363a9059cbb936044808201949293918390030190829087803b158015610dd057600080fd5b505af1158015610de4573d6000803e3d6000fd5b505050506040513d6020811015610dfa57600080fd5b50511515610e0757600080fd5b60405184907fceeab2eef998c17fe96f30f83fbf3c55fc5047f6e40c55a0cf72d236e9d2ba7290600090a2506001979650505050505050565b60008054600160a060020a03163314610e5857600080fd5b600154600160a060020a0383811691161415610e7357600080fd5b6001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03841690811782556040517fe68d2c359a771606c400cf8b87000cf5864010363d6a736e98f5047b7bbe18e990600090a3919050565b6006602081905260009182526040909120805460018201546002830154600384015460048501546005860154968601546007870154600890970154600160a060020a039687169895871697949693959294929391929181169060a060020a900460ff168a565b600054600160a060020a031681565b604080516000808252602080830180855288905260ff87168385015260608301869052608083018590529251909260019260a080820193601f198101928190039091019086865af1158015610f99573d6000803e3d6000fd5b5050604051601f1901519695505050505050565b60045460ff1681565b60008054600160a060020a0316331480610fda5750600154600160a060020a031633145b1515610fe557600080fd5b60045460ff161515610ff657600080fd5b6040513390303180156108fc02916000818181858888f19350505050158015611023573d6000803e3d6000fd5b506001905090565b60008054600160a060020a0316331461104357600080fd5b600054600160a060020a038381169116141561105e57600080fd5b6000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038416908117825560405160019233917f7fdc2a4b6eb39ec3363d710d188620bd1e97b3c434161f187b4d0dc0544faa589190a4919050565b604080516c01000000000000000000000000338102602080840191909152600160a060020a03881690910260348301524260488084018290528451808503909101815260689093019384905282516000949193859390929182918401908083835b602083106111395780518252601f19909201916020918201910161111a565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181526005909252929020549194505060ff16159150611184905057600080fd5b6000818152600660209081526040808320805473ffffffffffffffffffffffffffffffffffffffff199081163317825560018083018054600160a060020a038f16931683179055600283018c905542620151808c020160038401556004830188905560058084018b9055600784018890556008909301805474ffffffffffffffffffffffffffffffffffffffffff19169092179091559252808320805460ff19169092179091555182917f7ffc675d721b8768e035a323722842743bb523487b535906abc97e6b3e2095d091a260008181526006602090815260408083206008015481517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018b90529151600160a060020a03909116936323b872dd93606480850194919392918390030190829087803b1580156112d257600080fd5b505af11580156112e6573d6000803e3d6000fd5b505050506040513d60208110156112fc57600080fd5b5051151561130957600080fd5b5060019695505050505050565b600154600160a060020a031681565b60408051808201909152600a81527f302e302e35616c70686100000000000000000000000000000000000000000000602082015281565b60008282111561136b57600080fd5b50900390565b60008282018381101561138357600080fd5b93925050505600a165627a7a7230582083bad4c52e2c7b8b9861873f2f57a0dc92b16eb88997c98ceafc1cb9f42de04d0029` 23 | 24 | // DeployAirdrop deploys a new Ethereum contract, binding an instance of Airdrop to it. 25 | func DeployAirdrop(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Airdrop, error) { 26 | parsed, err := abi.JSON(strings.NewReader(AirdropABI)) 27 | if err != nil { 28 | return common.Address{}, nil, nil, err 29 | } 30 | address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(AirdropBin), backend) 31 | if err != nil { 32 | return common.Address{}, nil, nil, err 33 | } 34 | return address, tx, &Airdrop{AirdropCaller: AirdropCaller{contract: contract}, AirdropTransactor: AirdropTransactor{contract: contract}, AirdropFilterer: AirdropFilterer{contract: contract}}, nil 35 | } 36 | 37 | // Airdrop is an auto generated Go binding around an Ethereum contract. 38 | type Airdrop struct { 39 | AirdropCaller // Read-only binding to the contract 40 | AirdropTransactor // Write-only binding to the contract 41 | AirdropFilterer // Log filterer for contract events 42 | } 43 | 44 | // AirdropCaller is an auto generated read-only Go binding around an Ethereum contract. 45 | type AirdropCaller struct { 46 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 47 | } 48 | 49 | // AirdropTransactor is an auto generated write-only Go binding around an Ethereum contract. 50 | type AirdropTransactor struct { 51 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 52 | } 53 | 54 | // AirdropFilterer is an auto generated log filtering Go binding around an Ethereum contract events. 55 | type AirdropFilterer struct { 56 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 57 | } 58 | 59 | // AirdropSession is an auto generated Go binding around an Ethereum contract, 60 | // with pre-set call and transact options. 61 | type AirdropSession struct { 62 | Contract *Airdrop // Generic contract binding to set the session for 63 | CallOpts bind.CallOpts // Call options to use throughout this session 64 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 65 | } 66 | 67 | // AirdropCallerSession is an auto generated read-only Go binding around an Ethereum contract, 68 | // with pre-set call options. 69 | type AirdropCallerSession struct { 70 | Contract *AirdropCaller // Generic contract caller binding to set the session for 71 | CallOpts bind.CallOpts // Call options to use throughout this session 72 | } 73 | 74 | // AirdropTransactorSession is an auto generated write-only Go binding around an Ethereum contract, 75 | // with pre-set transact options. 76 | type AirdropTransactorSession struct { 77 | Contract *AirdropTransactor // Generic contract transactor binding to set the session for 78 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 79 | } 80 | 81 | // AirdropRaw is an auto generated low-level Go binding around an Ethereum contract. 82 | type AirdropRaw struct { 83 | Contract *Airdrop // Generic contract binding to access the raw methods on 84 | } 85 | 86 | // AirdropCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. 87 | type AirdropCallerRaw struct { 88 | Contract *AirdropCaller // Generic read-only contract binding to access the raw methods on 89 | } 90 | 91 | // AirdropTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. 92 | type AirdropTransactorRaw struct { 93 | Contract *AirdropTransactor // Generic write-only contract binding to access the raw methods on 94 | } 95 | 96 | // NewAirdrop creates a new instance of Airdrop, bound to a specific deployed contract. 97 | func NewAirdrop(address common.Address, backend bind.ContractBackend) (*Airdrop, error) { 98 | contract, err := bindAirdrop(address, backend, backend, backend) 99 | if err != nil { 100 | return nil, err 101 | } 102 | return &Airdrop{AirdropCaller: AirdropCaller{contract: contract}, AirdropTransactor: AirdropTransactor{contract: contract}, AirdropFilterer: AirdropFilterer{contract: contract}}, nil 103 | } 104 | 105 | // NewAirdropCaller creates a new read-only instance of Airdrop, bound to a specific deployed contract. 106 | func NewAirdropCaller(address common.Address, caller bind.ContractCaller) (*AirdropCaller, error) { 107 | contract, err := bindAirdrop(address, caller, nil, nil) 108 | if err != nil { 109 | return nil, err 110 | } 111 | return &AirdropCaller{contract: contract}, nil 112 | } 113 | 114 | // NewAirdropTransactor creates a new write-only instance of Airdrop, bound to a specific deployed contract. 115 | func NewAirdropTransactor(address common.Address, transactor bind.ContractTransactor) (*AirdropTransactor, error) { 116 | contract, err := bindAirdrop(address, nil, transactor, nil) 117 | if err != nil { 118 | return nil, err 119 | } 120 | return &AirdropTransactor{contract: contract}, nil 121 | } 122 | 123 | // NewAirdropFilterer creates a new log filterer instance of Airdrop, bound to a specific deployed contract. 124 | func NewAirdropFilterer(address common.Address, filterer bind.ContractFilterer) (*AirdropFilterer, error) { 125 | contract, err := bindAirdrop(address, nil, nil, filterer) 126 | if err != nil { 127 | return nil, err 128 | } 129 | return &AirdropFilterer{contract: contract}, nil 130 | } 131 | 132 | // bindAirdrop binds a generic wrapper to an already deployed contract. 133 | func bindAirdrop(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { 134 | parsed, err := abi.JSON(strings.NewReader(AirdropABI)) 135 | if err != nil { 136 | return nil, err 137 | } 138 | return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil 139 | } 140 | 141 | // Call invokes the (constant) contract method with params as input values and 142 | // sets the output to result. The result type might be a single field for simple 143 | // returns, a slice of interfaces for anonymous returns and a struct for named 144 | // returns. 145 | func (_Airdrop *AirdropRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { 146 | return _Airdrop.Contract.AirdropCaller.contract.Call(opts, result, method, params...) 147 | } 148 | 149 | // Transfer initiates a plain transaction to move funds to the contract, calling 150 | // its default method if one is available. 151 | func (_Airdrop *AirdropRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 152 | return _Airdrop.Contract.AirdropTransactor.contract.Transfer(opts) 153 | } 154 | 155 | // Transact invokes the (paid) contract method with params as input values. 156 | func (_Airdrop *AirdropRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 157 | return _Airdrop.Contract.AirdropTransactor.contract.Transact(opts, method, params...) 158 | } 159 | 160 | // Call invokes the (constant) contract method with params as input values and 161 | // sets the output to result. The result type might be a single field for simple 162 | // returns, a slice of interfaces for anonymous returns and a struct for named 163 | // returns. 164 | func (_Airdrop *AirdropCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { 165 | return _Airdrop.Contract.contract.Call(opts, result, method, params...) 166 | } 167 | 168 | // Transfer initiates a plain transaction to move funds to the contract, calling 169 | // its default method if one is available. 170 | func (_Airdrop *AirdropTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 171 | return _Airdrop.Contract.contract.Transfer(opts) 172 | } 173 | 174 | // Transact invokes the (paid) contract method with params as input values. 175 | func (_Airdrop *AirdropTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 176 | return _Airdrop.Contract.contract.Transact(opts, method, params...) 177 | } 178 | 179 | // VERSION is a free data retrieval call binding the contract method 0xffa1ad74. 180 | // 181 | // Solidity: function VERSION() constant returns(string) 182 | func (_Airdrop *AirdropCaller) VERSION(opts *bind.CallOpts) (string, error) { 183 | var ( 184 | ret0 = new(string) 185 | ) 186 | out := ret0 187 | err := _Airdrop.contract.Call(opts, out, "VERSION") 188 | return *ret0, err 189 | } 190 | 191 | // VERSION is a free data retrieval call binding the contract method 0xffa1ad74. 192 | // 193 | // Solidity: function VERSION() constant returns(string) 194 | func (_Airdrop *AirdropSession) VERSION() (string, error) { 195 | return _Airdrop.Contract.VERSION(&_Airdrop.CallOpts) 196 | } 197 | 198 | // VERSION is a free data retrieval call binding the contract method 0xffa1ad74. 199 | // 200 | // Solidity: function VERSION() constant returns(string) 201 | func (_Airdrop *AirdropCallerSession) VERSION() (string, error) { 202 | return _Airdrop.Contract.VERSION(&_Airdrop.CallOpts) 203 | } 204 | 205 | // Admin is a free data retrieval call binding the contract method 0xf851a440. 206 | // 207 | // Solidity: function admin() constant returns(address) 208 | func (_Airdrop *AirdropCaller) Admin(opts *bind.CallOpts) (common.Address, error) { 209 | var ( 210 | ret0 = new(common.Address) 211 | ) 212 | out := ret0 213 | err := _Airdrop.contract.Call(opts, out, "admin") 214 | return *ret0, err 215 | } 216 | 217 | // Admin is a free data retrieval call binding the contract method 0xf851a440. 218 | // 219 | // Solidity: function admin() constant returns(address) 220 | func (_Airdrop *AirdropSession) Admin() (common.Address, error) { 221 | return _Airdrop.Contract.Admin(&_Airdrop.CallOpts) 222 | } 223 | 224 | // Admin is a free data retrieval call binding the contract method 0xf851a440. 225 | // 226 | // Solidity: function admin() constant returns(address) 227 | func (_Airdrop *AirdropCallerSession) Admin() (common.Address, error) { 228 | return _Airdrop.Contract.Admin(&_Airdrop.CallOpts) 229 | } 230 | 231 | // Channels is a free data retrieval call binding the contract method 0x7a7ebd7b. 232 | // 233 | // Solidity: function channels( bytes32) constant returns(source address, tokenAddress address, value uint256, closingDate uint256, openDate uint256, dropAmount uint256, totalDrops uint256, channelId bytes32, intf address, state uint8) 234 | func (_Airdrop *AirdropCaller) Channels(opts *bind.CallOpts, arg0 [32]byte) (struct { 235 | Source common.Address 236 | TokenAddress common.Address 237 | Value *big.Int 238 | ClosingDate *big.Int 239 | OpenDate *big.Int 240 | DropAmount *big.Int 241 | TotalDrops *big.Int 242 | ChannelId [32]byte 243 | Intf common.Address 244 | State uint8 245 | }, error) { 246 | ret := new(struct { 247 | Source common.Address 248 | TokenAddress common.Address 249 | Value *big.Int 250 | ClosingDate *big.Int 251 | OpenDate *big.Int 252 | DropAmount *big.Int 253 | TotalDrops *big.Int 254 | ChannelId [32]byte 255 | Intf common.Address 256 | State uint8 257 | }) 258 | out := ret 259 | err := _Airdrop.contract.Call(opts, out, "channels", arg0) 260 | return *ret, err 261 | } 262 | 263 | // Channels is a free data retrieval call binding the contract method 0x7a7ebd7b. 264 | // 265 | // Solidity: function channels( bytes32) constant returns(source address, tokenAddress address, value uint256, closingDate uint256, openDate uint256, dropAmount uint256, totalDrops uint256, channelId bytes32, intf address, state uint8) 266 | func (_Airdrop *AirdropSession) Channels(arg0 [32]byte) (struct { 267 | Source common.Address 268 | TokenAddress common.Address 269 | Value *big.Int 270 | ClosingDate *big.Int 271 | OpenDate *big.Int 272 | DropAmount *big.Int 273 | TotalDrops *big.Int 274 | ChannelId [32]byte 275 | Intf common.Address 276 | State uint8 277 | }, error) { 278 | return _Airdrop.Contract.Channels(&_Airdrop.CallOpts, arg0) 279 | } 280 | 281 | // Channels is a free data retrieval call binding the contract method 0x7a7ebd7b. 282 | // 283 | // Solidity: function channels( bytes32) constant returns(source address, tokenAddress address, value uint256, closingDate uint256, openDate uint256, dropAmount uint256, totalDrops uint256, channelId bytes32, intf address, state uint8) 284 | func (_Airdrop *AirdropCallerSession) Channels(arg0 [32]byte) (struct { 285 | Source common.Address 286 | TokenAddress common.Address 287 | Value *big.Int 288 | ClosingDate *big.Int 289 | OpenDate *big.Int 290 | DropAmount *big.Int 291 | TotalDrops *big.Int 292 | ChannelId [32]byte 293 | Intf common.Address 294 | State uint8 295 | }, error) { 296 | return _Airdrop.Contract.Channels(&_Airdrop.CallOpts, arg0) 297 | } 298 | 299 | // Dev is a free data retrieval call binding the contract method 0x91cca3db. 300 | // 301 | // Solidity: function dev() constant returns(bool) 302 | func (_Airdrop *AirdropCaller) Dev(opts *bind.CallOpts) (bool, error) { 303 | var ( 304 | ret0 = new(bool) 305 | ) 306 | out := ret0 307 | err := _Airdrop.contract.Call(opts, out, "dev") 308 | return *ret0, err 309 | } 310 | 311 | // Dev is a free data retrieval call binding the contract method 0x91cca3db. 312 | // 313 | // Solidity: function dev() constant returns(bool) 314 | func (_Airdrop *AirdropSession) Dev() (bool, error) { 315 | return _Airdrop.Contract.Dev(&_Airdrop.CallOpts) 316 | } 317 | 318 | // Dev is a free data retrieval call binding the contract method 0x91cca3db. 319 | // 320 | // Solidity: function dev() constant returns(bool) 321 | func (_Airdrop *AirdropCallerSession) Dev() (bool, error) { 322 | return _Airdrop.Contract.Dev(&_Airdrop.CallOpts) 323 | } 324 | 325 | // Frozen is a free data retrieval call binding the contract method 0x054f7d9c. 326 | // 327 | // Solidity: function frozen() constant returns(bool) 328 | func (_Airdrop *AirdropCaller) Frozen(opts *bind.CallOpts) (bool, error) { 329 | var ( 330 | ret0 = new(bool) 331 | ) 332 | out := ret0 333 | err := _Airdrop.contract.Call(opts, out, "frozen") 334 | return *ret0, err 335 | } 336 | 337 | // Frozen is a free data retrieval call binding the contract method 0x054f7d9c. 338 | // 339 | // Solidity: function frozen() constant returns(bool) 340 | func (_Airdrop *AirdropSession) Frozen() (bool, error) { 341 | return _Airdrop.Contract.Frozen(&_Airdrop.CallOpts) 342 | } 343 | 344 | // Frozen is a free data retrieval call binding the contract method 0x054f7d9c. 345 | // 346 | // Solidity: function frozen() constant returns(bool) 347 | func (_Airdrop *AirdropCallerSession) Frozen() (bool, error) { 348 | return _Airdrop.Contract.Frozen(&_Airdrop.CallOpts) 349 | } 350 | 351 | // Moderators is a free data retrieval call binding the contract method 0x14d0f1ba. 352 | // 353 | // Solidity: function moderators( address) constant returns(bool) 354 | func (_Airdrop *AirdropCaller) Moderators(opts *bind.CallOpts, arg0 common.Address) (bool, error) { 355 | var ( 356 | ret0 = new(bool) 357 | ) 358 | out := ret0 359 | err := _Airdrop.contract.Call(opts, out, "moderators", arg0) 360 | return *ret0, err 361 | } 362 | 363 | // Moderators is a free data retrieval call binding the contract method 0x14d0f1ba. 364 | // 365 | // Solidity: function moderators( address) constant returns(bool) 366 | func (_Airdrop *AirdropSession) Moderators(arg0 common.Address) (bool, error) { 367 | return _Airdrop.Contract.Moderators(&_Airdrop.CallOpts, arg0) 368 | } 369 | 370 | // Moderators is a free data retrieval call binding the contract method 0x14d0f1ba. 371 | // 372 | // Solidity: function moderators( address) constant returns(bool) 373 | func (_Airdrop *AirdropCallerSession) Moderators(arg0 common.Address) (bool, error) { 374 | return _Airdrop.Contract.Moderators(&_Airdrop.CallOpts, arg0) 375 | } 376 | 377 | // Owner is a free data retrieval call binding the contract method 0x8da5cb5b. 378 | // 379 | // Solidity: function owner() constant returns(address) 380 | func (_Airdrop *AirdropCaller) Owner(opts *bind.CallOpts) (common.Address, error) { 381 | var ( 382 | ret0 = new(common.Address) 383 | ) 384 | out := ret0 385 | err := _Airdrop.contract.Call(opts, out, "owner") 386 | return *ret0, err 387 | } 388 | 389 | // Owner is a free data retrieval call binding the contract method 0x8da5cb5b. 390 | // 391 | // Solidity: function owner() constant returns(address) 392 | func (_Airdrop *AirdropSession) Owner() (common.Address, error) { 393 | return _Airdrop.Contract.Owner(&_Airdrop.CallOpts) 394 | } 395 | 396 | // Owner is a free data retrieval call binding the contract method 0x8da5cb5b. 397 | // 398 | // Solidity: function owner() constant returns(address) 399 | func (_Airdrop *AirdropCallerSession) Owner() (common.Address, error) { 400 | return _Airdrop.Contract.Owner(&_Airdrop.CallOpts) 401 | } 402 | 403 | // VerifyProof is a free data retrieval call binding the contract method 0x91456d3d. 404 | // 405 | // Solidity: function verifyProof(_h bytes32, _v uint8, _r bytes32, _s bytes32) constant returns(address) 406 | func (_Airdrop *AirdropCaller) VerifyProof(opts *bind.CallOpts, _h [32]byte, _v uint8, _r [32]byte, _s [32]byte) (common.Address, error) { 407 | var ( 408 | ret0 = new(common.Address) 409 | ) 410 | out := ret0 411 | err := _Airdrop.contract.Call(opts, out, "verifyProof", _h, _v, _r, _s) 412 | return *ret0, err 413 | } 414 | 415 | // VerifyProof is a free data retrieval call binding the contract method 0x91456d3d. 416 | // 417 | // Solidity: function verifyProof(_h bytes32, _v uint8, _r bytes32, _s bytes32) constant returns(address) 418 | func (_Airdrop *AirdropSession) VerifyProof(_h [32]byte, _v uint8, _r [32]byte, _s [32]byte) (common.Address, error) { 419 | return _Airdrop.Contract.VerifyProof(&_Airdrop.CallOpts, _h, _v, _r, _s) 420 | } 421 | 422 | // VerifyProof is a free data retrieval call binding the contract method 0x91456d3d. 423 | // 424 | // Solidity: function verifyProof(_h bytes32, _v uint8, _r bytes32, _s bytes32) constant returns(address) 425 | func (_Airdrop *AirdropCallerSession) VerifyProof(_h [32]byte, _v uint8, _r [32]byte, _s [32]byte) (common.Address, error) { 426 | return _Airdrop.Contract.VerifyProof(&_Airdrop.CallOpts, _h, _v, _r, _s) 427 | } 428 | 429 | // CloseChannel is a paid mutator transaction binding the contract method 0x5c9bd273. 430 | // 431 | // Solidity: function closeChannel(_h bytes32, _v uint8, _r bytes32, _s bytes32, _channelId bytes32) returns(bool) 432 | func (_Airdrop *AirdropTransactor) CloseChannel(opts *bind.TransactOpts, _h [32]byte, _v uint8, _r [32]byte, _s [32]byte, _channelId [32]byte) (*types.Transaction, error) { 433 | return _Airdrop.contract.Transact(opts, "closeChannel", _h, _v, _r, _s, _channelId) 434 | } 435 | 436 | // CloseChannel is a paid mutator transaction binding the contract method 0x5c9bd273. 437 | // 438 | // Solidity: function closeChannel(_h bytes32, _v uint8, _r bytes32, _s bytes32, _channelId bytes32) returns(bool) 439 | func (_Airdrop *AirdropSession) CloseChannel(_h [32]byte, _v uint8, _r [32]byte, _s [32]byte, _channelId [32]byte) (*types.Transaction, error) { 440 | return _Airdrop.Contract.CloseChannel(&_Airdrop.TransactOpts, _h, _v, _r, _s, _channelId) 441 | } 442 | 443 | // CloseChannel is a paid mutator transaction binding the contract method 0x5c9bd273. 444 | // 445 | // Solidity: function closeChannel(_h bytes32, _v uint8, _r bytes32, _s bytes32, _channelId bytes32) returns(bool) 446 | func (_Airdrop *AirdropTransactorSession) CloseChannel(_h [32]byte, _v uint8, _r [32]byte, _s [32]byte, _channelId [32]byte) (*types.Transaction, error) { 447 | return _Airdrop.Contract.CloseChannel(&_Airdrop.TransactOpts, _h, _v, _r, _s, _channelId) 448 | } 449 | 450 | // EnableAirdrops is a paid mutator transaction binding the contract method 0x56715148. 451 | // 452 | // Solidity: function enableAirdrops(_h bytes32, _v uint8, _r bytes32, _s bytes32, _channelId bytes32, _id uint256) returns(bool) 453 | func (_Airdrop *AirdropTransactor) EnableAirdrops(opts *bind.TransactOpts, _h [32]byte, _v uint8, _r [32]byte, _s [32]byte, _channelId [32]byte, _id *big.Int) (*types.Transaction, error) { 454 | return _Airdrop.contract.Transact(opts, "enableAirdrops", _h, _v, _r, _s, _channelId, _id) 455 | } 456 | 457 | // EnableAirdrops is a paid mutator transaction binding the contract method 0x56715148. 458 | // 459 | // Solidity: function enableAirdrops(_h bytes32, _v uint8, _r bytes32, _s bytes32, _channelId bytes32, _id uint256) returns(bool) 460 | func (_Airdrop *AirdropSession) EnableAirdrops(_h [32]byte, _v uint8, _r [32]byte, _s [32]byte, _channelId [32]byte, _id *big.Int) (*types.Transaction, error) { 461 | return _Airdrop.Contract.EnableAirdrops(&_Airdrop.TransactOpts, _h, _v, _r, _s, _channelId, _id) 462 | } 463 | 464 | // EnableAirdrops is a paid mutator transaction binding the contract method 0x56715148. 465 | // 466 | // Solidity: function enableAirdrops(_h bytes32, _v uint8, _r bytes32, _s bytes32, _channelId bytes32, _id uint256) returns(bool) 467 | func (_Airdrop *AirdropTransactorSession) EnableAirdrops(_h [32]byte, _v uint8, _r [32]byte, _s [32]byte, _channelId [32]byte, _id *big.Int) (*types.Transaction, error) { 468 | return _Airdrop.Contract.EnableAirdrops(&_Airdrop.TransactOpts, _h, _v, _r, _s, _channelId, _id) 469 | } 470 | 471 | // OpenChannel is a paid mutator transaction binding the contract method 0xf36bdb49. 472 | // 473 | // Solidity: function openChannel(_tokenAddress address, _channelValue uint256, _durationInDays uint256, _dropAmount uint256) returns(bool) 474 | func (_Airdrop *AirdropTransactor) OpenChannel(opts *bind.TransactOpts, _tokenAddress common.Address, _channelValue *big.Int, _durationInDays *big.Int, _dropAmount *big.Int) (*types.Transaction, error) { 475 | return _Airdrop.contract.Transact(opts, "openChannel", _tokenAddress, _channelValue, _durationInDays, _dropAmount) 476 | } 477 | 478 | // OpenChannel is a paid mutator transaction binding the contract method 0xf36bdb49. 479 | // 480 | // Solidity: function openChannel(_tokenAddress address, _channelValue uint256, _durationInDays uint256, _dropAmount uint256) returns(bool) 481 | func (_Airdrop *AirdropSession) OpenChannel(_tokenAddress common.Address, _channelValue *big.Int, _durationInDays *big.Int, _dropAmount *big.Int) (*types.Transaction, error) { 482 | return _Airdrop.Contract.OpenChannel(&_Airdrop.TransactOpts, _tokenAddress, _channelValue, _durationInDays, _dropAmount) 483 | } 484 | 485 | // OpenChannel is a paid mutator transaction binding the contract method 0xf36bdb49. 486 | // 487 | // Solidity: function openChannel(_tokenAddress address, _channelValue uint256, _durationInDays uint256, _dropAmount uint256) returns(bool) 488 | func (_Airdrop *AirdropTransactorSession) OpenChannel(_tokenAddress common.Address, _channelValue *big.Int, _durationInDays *big.Int, _dropAmount *big.Int) (*types.Transaction, error) { 489 | return _Airdrop.Contract.OpenChannel(&_Airdrop.TransactOpts, _tokenAddress, _channelValue, _durationInDays, _dropAmount) 490 | } 491 | 492 | // RetrieveAirdrop is a paid mutator transaction binding the contract method 0x515982f6. 493 | // 494 | // Solidity: function retrieveAirdrop(_h bytes32, _v uint8, _r bytes32, _s bytes32, _channelId bytes32, _id uint256) returns(bool) 495 | func (_Airdrop *AirdropTransactor) RetrieveAirdrop(opts *bind.TransactOpts, _h [32]byte, _v uint8, _r [32]byte, _s [32]byte, _channelId [32]byte, _id *big.Int) (*types.Transaction, error) { 496 | return _Airdrop.contract.Transact(opts, "retrieveAirdrop", _h, _v, _r, _s, _channelId, _id) 497 | } 498 | 499 | // RetrieveAirdrop is a paid mutator transaction binding the contract method 0x515982f6. 500 | // 501 | // Solidity: function retrieveAirdrop(_h bytes32, _v uint8, _r bytes32, _s bytes32, _channelId bytes32, _id uint256) returns(bool) 502 | func (_Airdrop *AirdropSession) RetrieveAirdrop(_h [32]byte, _v uint8, _r [32]byte, _s [32]byte, _channelId [32]byte, _id *big.Int) (*types.Transaction, error) { 503 | return _Airdrop.Contract.RetrieveAirdrop(&_Airdrop.TransactOpts, _h, _v, _r, _s, _channelId, _id) 504 | } 505 | 506 | // RetrieveAirdrop is a paid mutator transaction binding the contract method 0x515982f6. 507 | // 508 | // Solidity: function retrieveAirdrop(_h bytes32, _v uint8, _r bytes32, _s bytes32, _channelId bytes32, _id uint256) returns(bool) 509 | func (_Airdrop *AirdropTransactorSession) RetrieveAirdrop(_h [32]byte, _v uint8, _r [32]byte, _s [32]byte, _channelId [32]byte, _id *big.Int) (*types.Transaction, error) { 510 | return _Airdrop.Contract.RetrieveAirdrop(&_Airdrop.TransactOpts, _h, _v, _r, _s, _channelId, _id) 511 | } 512 | 513 | // SetAdmin is a paid mutator transaction binding the contract method 0x704b6c02. 514 | // 515 | // Solidity: function setAdmin(_newAdmin address) returns(bool) 516 | func (_Airdrop *AirdropTransactor) SetAdmin(opts *bind.TransactOpts, _newAdmin common.Address) (*types.Transaction, error) { 517 | return _Airdrop.contract.Transact(opts, "setAdmin", _newAdmin) 518 | } 519 | 520 | // SetAdmin is a paid mutator transaction binding the contract method 0x704b6c02. 521 | // 522 | // Solidity: function setAdmin(_newAdmin address) returns(bool) 523 | func (_Airdrop *AirdropSession) SetAdmin(_newAdmin common.Address) (*types.Transaction, error) { 524 | return _Airdrop.Contract.SetAdmin(&_Airdrop.TransactOpts, _newAdmin) 525 | } 526 | 527 | // SetAdmin is a paid mutator transaction binding the contract method 0x704b6c02. 528 | // 529 | // Solidity: function setAdmin(_newAdmin address) returns(bool) 530 | func (_Airdrop *AirdropTransactorSession) SetAdmin(_newAdmin common.Address) (*types.Transaction, error) { 531 | return _Airdrop.Contract.SetAdmin(&_Airdrop.TransactOpts, _newAdmin) 532 | } 533 | 534 | // TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. 535 | // 536 | // Solidity: function transferOwnership(_newOwner address) returns(bool) 537 | func (_Airdrop *AirdropTransactor) TransferOwnership(opts *bind.TransactOpts, _newOwner common.Address) (*types.Transaction, error) { 538 | return _Airdrop.contract.Transact(opts, "transferOwnership", _newOwner) 539 | } 540 | 541 | // TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. 542 | // 543 | // Solidity: function transferOwnership(_newOwner address) returns(bool) 544 | func (_Airdrop *AirdropSession) TransferOwnership(_newOwner common.Address) (*types.Transaction, error) { 545 | return _Airdrop.Contract.TransferOwnership(&_Airdrop.TransactOpts, _newOwner) 546 | } 547 | 548 | // TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. 549 | // 550 | // Solidity: function transferOwnership(_newOwner address) returns(bool) 551 | func (_Airdrop *AirdropTransactorSession) TransferOwnership(_newOwner common.Address) (*types.Transaction, error) { 552 | return _Airdrop.Contract.TransferOwnership(&_Airdrop.TransactOpts, _newOwner) 553 | } 554 | 555 | // WithdrawEth is a paid mutator transaction binding the contract method 0xa0ef91df. 556 | // 557 | // Solidity: function withdrawEth() returns(bool) 558 | func (_Airdrop *AirdropTransactor) WithdrawEth(opts *bind.TransactOpts) (*types.Transaction, error) { 559 | return _Airdrop.contract.Transact(opts, "withdrawEth") 560 | } 561 | 562 | // WithdrawEth is a paid mutator transaction binding the contract method 0xa0ef91df. 563 | // 564 | // Solidity: function withdrawEth() returns(bool) 565 | func (_Airdrop *AirdropSession) WithdrawEth() (*types.Transaction, error) { 566 | return _Airdrop.Contract.WithdrawEth(&_Airdrop.TransactOpts) 567 | } 568 | 569 | // WithdrawEth is a paid mutator transaction binding the contract method 0xa0ef91df. 570 | // 571 | // Solidity: function withdrawEth() returns(bool) 572 | func (_Airdrop *AirdropTransactorSession) WithdrawEth() (*types.Transaction, error) { 573 | return _Airdrop.Contract.WithdrawEth(&_Airdrop.TransactOpts) 574 | } 575 | 576 | // AirdropAdminSetIterator is returned from FilterAdminSet and is used to iterate over the raw logs and unpacked data for AdminSet events raised by the Airdrop contract. 577 | type AirdropAdminSetIterator struct { 578 | Event *AirdropAdminSet // Event containing the contract specifics and raw log 579 | 580 | contract *bind.BoundContract // Generic contract to use for unpacking event data 581 | event string // Event name to use for unpacking event data 582 | 583 | logs chan types.Log // Log channel receiving the found contract events 584 | sub ethereum.Subscription // Subscription for errors, completion and termination 585 | done bool // Whether the subscription completed delivering logs 586 | fail error // Occurred error to stop iteration 587 | } 588 | 589 | // Next advances the iterator to the subsequent event, returning whether there 590 | // are any more events found. In case of a retrieval or parsing error, false is 591 | // returned and Error() can be queried for the exact failure. 592 | func (it *AirdropAdminSetIterator) Next() bool { 593 | // If the iterator failed, stop iterating 594 | if it.fail != nil { 595 | return false 596 | } 597 | // If the iterator completed, deliver directly whatever's available 598 | if it.done { 599 | select { 600 | case log := <-it.logs: 601 | it.Event = new(AirdropAdminSet) 602 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 603 | it.fail = err 604 | return false 605 | } 606 | it.Event.Raw = log 607 | return true 608 | 609 | default: 610 | return false 611 | } 612 | } 613 | // Iterator still in progress, wait for either a data or an error event 614 | select { 615 | case log := <-it.logs: 616 | it.Event = new(AirdropAdminSet) 617 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 618 | it.fail = err 619 | return false 620 | } 621 | it.Event.Raw = log 622 | return true 623 | 624 | case err := <-it.sub.Err(): 625 | it.done = true 626 | it.fail = err 627 | return it.Next() 628 | } 629 | } 630 | 631 | // Error returns any retrieval or parsing error occurred during filtering. 632 | func (it *AirdropAdminSetIterator) Error() error { 633 | return it.fail 634 | } 635 | 636 | // Close terminates the iteration process, releasing any pending underlying 637 | // resources. 638 | func (it *AirdropAdminSetIterator) Close() error { 639 | it.sub.Unsubscribe() 640 | return nil 641 | } 642 | 643 | // AirdropAdminSet represents a AdminSet event raised by the Airdrop contract. 644 | type AirdropAdminSet struct { 645 | Admin common.Address 646 | AdminSet bool 647 | Raw types.Log // Blockchain specific contextual infos 648 | } 649 | 650 | // FilterAdminSet is a free log retrieval operation binding the contract event 0xe68d2c359a771606c400cf8b87000cf5864010363d6a736e98f5047b7bbe18e9. 651 | // 652 | // Solidity: e AdminSet(_admin indexed address, _adminSet indexed bool) 653 | func (_Airdrop *AirdropFilterer) FilterAdminSet(opts *bind.FilterOpts, _admin []common.Address, _adminSet []bool) (*AirdropAdminSetIterator, error) { 654 | 655 | var _adminRule []interface{} 656 | for _, _adminItem := range _admin { 657 | _adminRule = append(_adminRule, _adminItem) 658 | } 659 | var _adminSetRule []interface{} 660 | for _, _adminSetItem := range _adminSet { 661 | _adminSetRule = append(_adminSetRule, _adminSetItem) 662 | } 663 | 664 | logs, sub, err := _Airdrop.contract.FilterLogs(opts, "AdminSet", _adminRule, _adminSetRule) 665 | if err != nil { 666 | return nil, err 667 | } 668 | return &AirdropAdminSetIterator{contract: _Airdrop.contract, event: "AdminSet", logs: logs, sub: sub}, nil 669 | } 670 | 671 | // WatchAdminSet is a free log subscription operation binding the contract event 0xe68d2c359a771606c400cf8b87000cf5864010363d6a736e98f5047b7bbe18e9. 672 | // 673 | // Solidity: e AdminSet(_admin indexed address, _adminSet indexed bool) 674 | func (_Airdrop *AirdropFilterer) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *AirdropAdminSet, _admin []common.Address, _adminSet []bool) (event.Subscription, error) { 675 | 676 | var _adminRule []interface{} 677 | for _, _adminItem := range _admin { 678 | _adminRule = append(_adminRule, _adminItem) 679 | } 680 | var _adminSetRule []interface{} 681 | for _, _adminSetItem := range _adminSet { 682 | _adminSetRule = append(_adminSetRule, _adminSetItem) 683 | } 684 | 685 | logs, sub, err := _Airdrop.contract.WatchLogs(opts, "AdminSet", _adminRule, _adminSetRule) 686 | if err != nil { 687 | return nil, err 688 | } 689 | return event.NewSubscription(func(quit <-chan struct{}) error { 690 | defer sub.Unsubscribe() 691 | for { 692 | select { 693 | case log := <-logs: 694 | // New log arrived, parse the event and forward to the user 695 | event := new(AirdropAdminSet) 696 | if err := _Airdrop.contract.UnpackLog(event, "AdminSet", log); err != nil { 697 | return err 698 | } 699 | event.Raw = log 700 | 701 | select { 702 | case sink <- event: 703 | case err := <-sub.Err(): 704 | return err 705 | case <-quit: 706 | return nil 707 | } 708 | case err := <-sub.Err(): 709 | return err 710 | case <-quit: 711 | return nil 712 | } 713 | } 714 | }), nil 715 | } 716 | 717 | // AirdropAirDropDispersedIterator is returned from FilterAirDropDispersed and is used to iterate over the raw logs and unpacked data for AirDropDispersed events raised by the Airdrop contract. 718 | type AirdropAirDropDispersedIterator struct { 719 | Event *AirdropAirDropDispersed // Event containing the contract specifics and raw log 720 | 721 | contract *bind.BoundContract // Generic contract to use for unpacking event data 722 | event string // Event name to use for unpacking event data 723 | 724 | logs chan types.Log // Log channel receiving the found contract events 725 | sub ethereum.Subscription // Subscription for errors, completion and termination 726 | done bool // Whether the subscription completed delivering logs 727 | fail error // Occurred error to stop iteration 728 | } 729 | 730 | // Next advances the iterator to the subsequent event, returning whether there 731 | // are any more events found. In case of a retrieval or parsing error, false is 732 | // returned and Error() can be queried for the exact failure. 733 | func (it *AirdropAirDropDispersedIterator) Next() bool { 734 | // If the iterator failed, stop iterating 735 | if it.fail != nil { 736 | return false 737 | } 738 | // If the iterator completed, deliver directly whatever's available 739 | if it.done { 740 | select { 741 | case log := <-it.logs: 742 | it.Event = new(AirdropAirDropDispersed) 743 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 744 | it.fail = err 745 | return false 746 | } 747 | it.Event.Raw = log 748 | return true 749 | 750 | default: 751 | return false 752 | } 753 | } 754 | // Iterator still in progress, wait for either a data or an error event 755 | select { 756 | case log := <-it.logs: 757 | it.Event = new(AirdropAirDropDispersed) 758 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 759 | it.fail = err 760 | return false 761 | } 762 | it.Event.Raw = log 763 | return true 764 | 765 | case err := <-it.sub.Err(): 766 | it.done = true 767 | it.fail = err 768 | return it.Next() 769 | } 770 | } 771 | 772 | // Error returns any retrieval or parsing error occurred during filtering. 773 | func (it *AirdropAirDropDispersedIterator) Error() error { 774 | return it.fail 775 | } 776 | 777 | // Close terminates the iteration process, releasing any pending underlying 778 | // resources. 779 | func (it *AirdropAirDropDispersedIterator) Close() error { 780 | it.sub.Unsubscribe() 781 | return nil 782 | } 783 | 784 | // AirdropAirDropDispersed represents a AirDropDispersed event raised by the Airdrop contract. 785 | type AirdropAirDropDispersed struct { 786 | ChannelId [32]byte 787 | Raw types.Log // Blockchain specific contextual infos 788 | } 789 | 790 | // FilterAirDropDispersed is a free log retrieval operation binding the contract event 0xa467a409776bfc50e32dd8496edd970b5e7a84a38acda61529d8022bf757c2fd. 791 | // 792 | // Solidity: e AirDropDispersed(_channelId indexed bytes32) 793 | func (_Airdrop *AirdropFilterer) FilterAirDropDispersed(opts *bind.FilterOpts, _channelId [][32]byte) (*AirdropAirDropDispersedIterator, error) { 794 | 795 | var _channelIdRule []interface{} 796 | for _, _channelIdItem := range _channelId { 797 | _channelIdRule = append(_channelIdRule, _channelIdItem) 798 | } 799 | 800 | logs, sub, err := _Airdrop.contract.FilterLogs(opts, "AirDropDispersed", _channelIdRule) 801 | if err != nil { 802 | return nil, err 803 | } 804 | return &AirdropAirDropDispersedIterator{contract: _Airdrop.contract, event: "AirDropDispersed", logs: logs, sub: sub}, nil 805 | } 806 | 807 | // WatchAirDropDispersed is a free log subscription operation binding the contract event 0xa467a409776bfc50e32dd8496edd970b5e7a84a38acda61529d8022bf757c2fd. 808 | // 809 | // Solidity: e AirDropDispersed(_channelId indexed bytes32) 810 | func (_Airdrop *AirdropFilterer) WatchAirDropDispersed(opts *bind.WatchOpts, sink chan<- *AirdropAirDropDispersed, _channelId [][32]byte) (event.Subscription, error) { 811 | 812 | var _channelIdRule []interface{} 813 | for _, _channelIdItem := range _channelId { 814 | _channelIdRule = append(_channelIdRule, _channelIdItem) 815 | } 816 | 817 | logs, sub, err := _Airdrop.contract.WatchLogs(opts, "AirDropDispersed", _channelIdRule) 818 | if err != nil { 819 | return nil, err 820 | } 821 | return event.NewSubscription(func(quit <-chan struct{}) error { 822 | defer sub.Unsubscribe() 823 | for { 824 | select { 825 | case log := <-logs: 826 | // New log arrived, parse the event and forward to the user 827 | event := new(AirdropAirDropDispersed) 828 | if err := _Airdrop.contract.UnpackLog(event, "AirDropDispersed", log); err != nil { 829 | return err 830 | } 831 | event.Raw = log 832 | 833 | select { 834 | case sink <- event: 835 | case err := <-sub.Err(): 836 | return err 837 | case <-quit: 838 | return nil 839 | } 840 | case err := <-sub.Err(): 841 | return err 842 | case <-quit: 843 | return nil 844 | } 845 | } 846 | }), nil 847 | } 848 | 849 | // AirdropAirDropsEnabledIterator is returned from FilterAirDropsEnabled and is used to iterate over the raw logs and unpacked data for AirDropsEnabled events raised by the Airdrop contract. 850 | type AirdropAirDropsEnabledIterator struct { 851 | Event *AirdropAirDropsEnabled // Event containing the contract specifics and raw log 852 | 853 | contract *bind.BoundContract // Generic contract to use for unpacking event data 854 | event string // Event name to use for unpacking event data 855 | 856 | logs chan types.Log // Log channel receiving the found contract events 857 | sub ethereum.Subscription // Subscription for errors, completion and termination 858 | done bool // Whether the subscription completed delivering logs 859 | fail error // Occurred error to stop iteration 860 | } 861 | 862 | // Next advances the iterator to the subsequent event, returning whether there 863 | // are any more events found. In case of a retrieval or parsing error, false is 864 | // returned and Error() can be queried for the exact failure. 865 | func (it *AirdropAirDropsEnabledIterator) Next() bool { 866 | // If the iterator failed, stop iterating 867 | if it.fail != nil { 868 | return false 869 | } 870 | // If the iterator completed, deliver directly whatever's available 871 | if it.done { 872 | select { 873 | case log := <-it.logs: 874 | it.Event = new(AirdropAirDropsEnabled) 875 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 876 | it.fail = err 877 | return false 878 | } 879 | it.Event.Raw = log 880 | return true 881 | 882 | default: 883 | return false 884 | } 885 | } 886 | // Iterator still in progress, wait for either a data or an error event 887 | select { 888 | case log := <-it.logs: 889 | it.Event = new(AirdropAirDropsEnabled) 890 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 891 | it.fail = err 892 | return false 893 | } 894 | it.Event.Raw = log 895 | return true 896 | 897 | case err := <-it.sub.Err(): 898 | it.done = true 899 | it.fail = err 900 | return it.Next() 901 | } 902 | } 903 | 904 | // Error returns any retrieval or parsing error occurred during filtering. 905 | func (it *AirdropAirDropsEnabledIterator) Error() error { 906 | return it.fail 907 | } 908 | 909 | // Close terminates the iteration process, releasing any pending underlying 910 | // resources. 911 | func (it *AirdropAirDropsEnabledIterator) Close() error { 912 | it.sub.Unsubscribe() 913 | return nil 914 | } 915 | 916 | // AirdropAirDropsEnabled represents a AirDropsEnabled event raised by the Airdrop contract. 917 | type AirdropAirDropsEnabled struct { 918 | ChannelId [32]byte 919 | Raw types.Log // Blockchain specific contextual infos 920 | } 921 | 922 | // FilterAirDropsEnabled is a free log retrieval operation binding the contract event 0xf857a98ed55303cc061ea3bc4c498fe49361c82cb72894280249b89848f9ce46. 923 | // 924 | // Solidity: e AirDropsEnabled(_channelId indexed bytes32) 925 | func (_Airdrop *AirdropFilterer) FilterAirDropsEnabled(opts *bind.FilterOpts, _channelId [][32]byte) (*AirdropAirDropsEnabledIterator, error) { 926 | 927 | var _channelIdRule []interface{} 928 | for _, _channelIdItem := range _channelId { 929 | _channelIdRule = append(_channelIdRule, _channelIdItem) 930 | } 931 | 932 | logs, sub, err := _Airdrop.contract.FilterLogs(opts, "AirDropsEnabled", _channelIdRule) 933 | if err != nil { 934 | return nil, err 935 | } 936 | return &AirdropAirDropsEnabledIterator{contract: _Airdrop.contract, event: "AirDropsEnabled", logs: logs, sub: sub}, nil 937 | } 938 | 939 | // WatchAirDropsEnabled is a free log subscription operation binding the contract event 0xf857a98ed55303cc061ea3bc4c498fe49361c82cb72894280249b89848f9ce46. 940 | // 941 | // Solidity: e AirDropsEnabled(_channelId indexed bytes32) 942 | func (_Airdrop *AirdropFilterer) WatchAirDropsEnabled(opts *bind.WatchOpts, sink chan<- *AirdropAirDropsEnabled, _channelId [][32]byte) (event.Subscription, error) { 943 | 944 | var _channelIdRule []interface{} 945 | for _, _channelIdItem := range _channelId { 946 | _channelIdRule = append(_channelIdRule, _channelIdItem) 947 | } 948 | 949 | logs, sub, err := _Airdrop.contract.WatchLogs(opts, "AirDropsEnabled", _channelIdRule) 950 | if err != nil { 951 | return nil, err 952 | } 953 | return event.NewSubscription(func(quit <-chan struct{}) error { 954 | defer sub.Unsubscribe() 955 | for { 956 | select { 957 | case log := <-logs: 958 | // New log arrived, parse the event and forward to the user 959 | event := new(AirdropAirDropsEnabled) 960 | if err := _Airdrop.contract.UnpackLog(event, "AirDropsEnabled", log); err != nil { 961 | return err 962 | } 963 | event.Raw = log 964 | 965 | select { 966 | case sink <- event: 967 | case err := <-sub.Err(): 968 | return err 969 | case <-quit: 970 | return nil 971 | } 972 | case err := <-sub.Err(): 973 | return err 974 | case <-quit: 975 | return nil 976 | } 977 | } 978 | }), nil 979 | } 980 | 981 | // AirdropChannelClosedIterator is returned from FilterChannelClosed and is used to iterate over the raw logs and unpacked data for ChannelClosed events raised by the Airdrop contract. 982 | type AirdropChannelClosedIterator struct { 983 | Event *AirdropChannelClosed // Event containing the contract specifics and raw log 984 | 985 | contract *bind.BoundContract // Generic contract to use for unpacking event data 986 | event string // Event name to use for unpacking event data 987 | 988 | logs chan types.Log // Log channel receiving the found contract events 989 | sub ethereum.Subscription // Subscription for errors, completion and termination 990 | done bool // Whether the subscription completed delivering logs 991 | fail error // Occurred error to stop iteration 992 | } 993 | 994 | // Next advances the iterator to the subsequent event, returning whether there 995 | // are any more events found. In case of a retrieval or parsing error, false is 996 | // returned and Error() can be queried for the exact failure. 997 | func (it *AirdropChannelClosedIterator) Next() bool { 998 | // If the iterator failed, stop iterating 999 | if it.fail != nil { 1000 | return false 1001 | } 1002 | // If the iterator completed, deliver directly whatever's available 1003 | if it.done { 1004 | select { 1005 | case log := <-it.logs: 1006 | it.Event = new(AirdropChannelClosed) 1007 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 1008 | it.fail = err 1009 | return false 1010 | } 1011 | it.Event.Raw = log 1012 | return true 1013 | 1014 | default: 1015 | return false 1016 | } 1017 | } 1018 | // Iterator still in progress, wait for either a data or an error event 1019 | select { 1020 | case log := <-it.logs: 1021 | it.Event = new(AirdropChannelClosed) 1022 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 1023 | it.fail = err 1024 | return false 1025 | } 1026 | it.Event.Raw = log 1027 | return true 1028 | 1029 | case err := <-it.sub.Err(): 1030 | it.done = true 1031 | it.fail = err 1032 | return it.Next() 1033 | } 1034 | } 1035 | 1036 | // Error returns any retrieval or parsing error occurred during filtering. 1037 | func (it *AirdropChannelClosedIterator) Error() error { 1038 | return it.fail 1039 | } 1040 | 1041 | // Close terminates the iteration process, releasing any pending underlying 1042 | // resources. 1043 | func (it *AirdropChannelClosedIterator) Close() error { 1044 | it.sub.Unsubscribe() 1045 | return nil 1046 | } 1047 | 1048 | // AirdropChannelClosed represents a ChannelClosed event raised by the Airdrop contract. 1049 | type AirdropChannelClosed struct { 1050 | ChannelId [32]byte 1051 | Raw types.Log // Blockchain specific contextual infos 1052 | } 1053 | 1054 | // FilterChannelClosed is a free log retrieval operation binding the contract event 0xceeab2eef998c17fe96f30f83fbf3c55fc5047f6e40c55a0cf72d236e9d2ba72. 1055 | // 1056 | // Solidity: e ChannelClosed(_channelId indexed bytes32) 1057 | func (_Airdrop *AirdropFilterer) FilterChannelClosed(opts *bind.FilterOpts, _channelId [][32]byte) (*AirdropChannelClosedIterator, error) { 1058 | 1059 | var _channelIdRule []interface{} 1060 | for _, _channelIdItem := range _channelId { 1061 | _channelIdRule = append(_channelIdRule, _channelIdItem) 1062 | } 1063 | 1064 | logs, sub, err := _Airdrop.contract.FilterLogs(opts, "ChannelClosed", _channelIdRule) 1065 | if err != nil { 1066 | return nil, err 1067 | } 1068 | return &AirdropChannelClosedIterator{contract: _Airdrop.contract, event: "ChannelClosed", logs: logs, sub: sub}, nil 1069 | } 1070 | 1071 | // WatchChannelClosed is a free log subscription operation binding the contract event 0xceeab2eef998c17fe96f30f83fbf3c55fc5047f6e40c55a0cf72d236e9d2ba72. 1072 | // 1073 | // Solidity: e ChannelClosed(_channelId indexed bytes32) 1074 | func (_Airdrop *AirdropFilterer) WatchChannelClosed(opts *bind.WatchOpts, sink chan<- *AirdropChannelClosed, _channelId [][32]byte) (event.Subscription, error) { 1075 | 1076 | var _channelIdRule []interface{} 1077 | for _, _channelIdItem := range _channelId { 1078 | _channelIdRule = append(_channelIdRule, _channelIdItem) 1079 | } 1080 | 1081 | logs, sub, err := _Airdrop.contract.WatchLogs(opts, "ChannelClosed", _channelIdRule) 1082 | if err != nil { 1083 | return nil, err 1084 | } 1085 | return event.NewSubscription(func(quit <-chan struct{}) error { 1086 | defer sub.Unsubscribe() 1087 | for { 1088 | select { 1089 | case log := <-logs: 1090 | // New log arrived, parse the event and forward to the user 1091 | event := new(AirdropChannelClosed) 1092 | if err := _Airdrop.contract.UnpackLog(event, "ChannelClosed", log); err != nil { 1093 | return err 1094 | } 1095 | event.Raw = log 1096 | 1097 | select { 1098 | case sink <- event: 1099 | case err := <-sub.Err(): 1100 | return err 1101 | case <-quit: 1102 | return nil 1103 | } 1104 | case err := <-sub.Err(): 1105 | return err 1106 | case <-quit: 1107 | return nil 1108 | } 1109 | } 1110 | }), nil 1111 | } 1112 | 1113 | // AirdropChannelOpenedIterator is returned from FilterChannelOpened and is used to iterate over the raw logs and unpacked data for ChannelOpened events raised by the Airdrop contract. 1114 | type AirdropChannelOpenedIterator struct { 1115 | Event *AirdropChannelOpened // Event containing the contract specifics and raw log 1116 | 1117 | contract *bind.BoundContract // Generic contract to use for unpacking event data 1118 | event string // Event name to use for unpacking event data 1119 | 1120 | logs chan types.Log // Log channel receiving the found contract events 1121 | sub ethereum.Subscription // Subscription for errors, completion and termination 1122 | done bool // Whether the subscription completed delivering logs 1123 | fail error // Occurred error to stop iteration 1124 | } 1125 | 1126 | // Next advances the iterator to the subsequent event, returning whether there 1127 | // are any more events found. In case of a retrieval or parsing error, false is 1128 | // returned and Error() can be queried for the exact failure. 1129 | func (it *AirdropChannelOpenedIterator) Next() bool { 1130 | // If the iterator failed, stop iterating 1131 | if it.fail != nil { 1132 | return false 1133 | } 1134 | // If the iterator completed, deliver directly whatever's available 1135 | if it.done { 1136 | select { 1137 | case log := <-it.logs: 1138 | it.Event = new(AirdropChannelOpened) 1139 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 1140 | it.fail = err 1141 | return false 1142 | } 1143 | it.Event.Raw = log 1144 | return true 1145 | 1146 | default: 1147 | return false 1148 | } 1149 | } 1150 | // Iterator still in progress, wait for either a data or an error event 1151 | select { 1152 | case log := <-it.logs: 1153 | it.Event = new(AirdropChannelOpened) 1154 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 1155 | it.fail = err 1156 | return false 1157 | } 1158 | it.Event.Raw = log 1159 | return true 1160 | 1161 | case err := <-it.sub.Err(): 1162 | it.done = true 1163 | it.fail = err 1164 | return it.Next() 1165 | } 1166 | } 1167 | 1168 | // Error returns any retrieval or parsing error occurred during filtering. 1169 | func (it *AirdropChannelOpenedIterator) Error() error { 1170 | return it.fail 1171 | } 1172 | 1173 | // Close terminates the iteration process, releasing any pending underlying 1174 | // resources. 1175 | func (it *AirdropChannelOpenedIterator) Close() error { 1176 | it.sub.Unsubscribe() 1177 | return nil 1178 | } 1179 | 1180 | // AirdropChannelOpened represents a ChannelOpened event raised by the Airdrop contract. 1181 | type AirdropChannelOpened struct { 1182 | ChannelId [32]byte 1183 | Raw types.Log // Blockchain specific contextual infos 1184 | } 1185 | 1186 | // FilterChannelOpened is a free log retrieval operation binding the contract event 0x7ffc675d721b8768e035a323722842743bb523487b535906abc97e6b3e2095d0. 1187 | // 1188 | // Solidity: e ChannelOpened(_channelId indexed bytes32) 1189 | func (_Airdrop *AirdropFilterer) FilterChannelOpened(opts *bind.FilterOpts, _channelId [][32]byte) (*AirdropChannelOpenedIterator, error) { 1190 | 1191 | var _channelIdRule []interface{} 1192 | for _, _channelIdItem := range _channelId { 1193 | _channelIdRule = append(_channelIdRule, _channelIdItem) 1194 | } 1195 | 1196 | logs, sub, err := _Airdrop.contract.FilterLogs(opts, "ChannelOpened", _channelIdRule) 1197 | if err != nil { 1198 | return nil, err 1199 | } 1200 | return &AirdropChannelOpenedIterator{contract: _Airdrop.contract, event: "ChannelOpened", logs: logs, sub: sub}, nil 1201 | } 1202 | 1203 | // WatchChannelOpened is a free log subscription operation binding the contract event 0x7ffc675d721b8768e035a323722842743bb523487b535906abc97e6b3e2095d0. 1204 | // 1205 | // Solidity: e ChannelOpened(_channelId indexed bytes32) 1206 | func (_Airdrop *AirdropFilterer) WatchChannelOpened(opts *bind.WatchOpts, sink chan<- *AirdropChannelOpened, _channelId [][32]byte) (event.Subscription, error) { 1207 | 1208 | var _channelIdRule []interface{} 1209 | for _, _channelIdItem := range _channelId { 1210 | _channelIdRule = append(_channelIdRule, _channelIdItem) 1211 | } 1212 | 1213 | logs, sub, err := _Airdrop.contract.WatchLogs(opts, "ChannelOpened", _channelIdRule) 1214 | if err != nil { 1215 | return nil, err 1216 | } 1217 | return event.NewSubscription(func(quit <-chan struct{}) error { 1218 | defer sub.Unsubscribe() 1219 | for { 1220 | select { 1221 | case log := <-logs: 1222 | // New log arrived, parse the event and forward to the user 1223 | event := new(AirdropChannelOpened) 1224 | if err := _Airdrop.contract.UnpackLog(event, "ChannelOpened", log); err != nil { 1225 | return err 1226 | } 1227 | event.Raw = log 1228 | 1229 | select { 1230 | case sink <- event: 1231 | case err := <-sub.Err(): 1232 | return err 1233 | case <-quit: 1234 | return nil 1235 | } 1236 | case err := <-sub.Err(): 1237 | return err 1238 | case <-quit: 1239 | return nil 1240 | } 1241 | } 1242 | }), nil 1243 | } 1244 | 1245 | // AirdropOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Airdrop contract. 1246 | type AirdropOwnershipTransferredIterator struct { 1247 | Event *AirdropOwnershipTransferred // Event containing the contract specifics and raw log 1248 | 1249 | contract *bind.BoundContract // Generic contract to use for unpacking event data 1250 | event string // Event name to use for unpacking event data 1251 | 1252 | logs chan types.Log // Log channel receiving the found contract events 1253 | sub ethereum.Subscription // Subscription for errors, completion and termination 1254 | done bool // Whether the subscription completed delivering logs 1255 | fail error // Occurred error to stop iteration 1256 | } 1257 | 1258 | // Next advances the iterator to the subsequent event, returning whether there 1259 | // are any more events found. In case of a retrieval or parsing error, false is 1260 | // returned and Error() can be queried for the exact failure. 1261 | func (it *AirdropOwnershipTransferredIterator) Next() bool { 1262 | // If the iterator failed, stop iterating 1263 | if it.fail != nil { 1264 | return false 1265 | } 1266 | // If the iterator completed, deliver directly whatever's available 1267 | if it.done { 1268 | select { 1269 | case log := <-it.logs: 1270 | it.Event = new(AirdropOwnershipTransferred) 1271 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 1272 | it.fail = err 1273 | return false 1274 | } 1275 | it.Event.Raw = log 1276 | return true 1277 | 1278 | default: 1279 | return false 1280 | } 1281 | } 1282 | // Iterator still in progress, wait for either a data or an error event 1283 | select { 1284 | case log := <-it.logs: 1285 | it.Event = new(AirdropOwnershipTransferred) 1286 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 1287 | it.fail = err 1288 | return false 1289 | } 1290 | it.Event.Raw = log 1291 | return true 1292 | 1293 | case err := <-it.sub.Err(): 1294 | it.done = true 1295 | it.fail = err 1296 | return it.Next() 1297 | } 1298 | } 1299 | 1300 | // Error returns any retrieval or parsing error occurred during filtering. 1301 | func (it *AirdropOwnershipTransferredIterator) Error() error { 1302 | return it.fail 1303 | } 1304 | 1305 | // Close terminates the iteration process, releasing any pending underlying 1306 | // resources. 1307 | func (it *AirdropOwnershipTransferredIterator) Close() error { 1308 | it.sub.Unsubscribe() 1309 | return nil 1310 | } 1311 | 1312 | // AirdropOwnershipTransferred represents a OwnershipTransferred event raised by the Airdrop contract. 1313 | type AirdropOwnershipTransferred struct { 1314 | PreviousOwner common.Address 1315 | NewOwner common.Address 1316 | OwnershipTransferred bool 1317 | Raw types.Log // Blockchain specific contextual infos 1318 | } 1319 | 1320 | // FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x7fdc2a4b6eb39ec3363d710d188620bd1e97b3c434161f187b4d0dc0544faa58. 1321 | // 1322 | // Solidity: e OwnershipTransferred(_previousOwner indexed address, _newOwner indexed address, _ownershipTransferred indexed bool) 1323 | func (_Airdrop *AirdropFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, _previousOwner []common.Address, _newOwner []common.Address, _ownershipTransferred []bool) (*AirdropOwnershipTransferredIterator, error) { 1324 | 1325 | var _previousOwnerRule []interface{} 1326 | for _, _previousOwnerItem := range _previousOwner { 1327 | _previousOwnerRule = append(_previousOwnerRule, _previousOwnerItem) 1328 | } 1329 | var _newOwnerRule []interface{} 1330 | for _, _newOwnerItem := range _newOwner { 1331 | _newOwnerRule = append(_newOwnerRule, _newOwnerItem) 1332 | } 1333 | var _ownershipTransferredRule []interface{} 1334 | for _, _ownershipTransferredItem := range _ownershipTransferred { 1335 | _ownershipTransferredRule = append(_ownershipTransferredRule, _ownershipTransferredItem) 1336 | } 1337 | 1338 | logs, sub, err := _Airdrop.contract.FilterLogs(opts, "OwnershipTransferred", _previousOwnerRule, _newOwnerRule, _ownershipTransferredRule) 1339 | if err != nil { 1340 | return nil, err 1341 | } 1342 | return &AirdropOwnershipTransferredIterator{contract: _Airdrop.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil 1343 | } 1344 | 1345 | // WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x7fdc2a4b6eb39ec3363d710d188620bd1e97b3c434161f187b4d0dc0544faa58. 1346 | // 1347 | // Solidity: e OwnershipTransferred(_previousOwner indexed address, _newOwner indexed address, _ownershipTransferred indexed bool) 1348 | func (_Airdrop *AirdropFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AirdropOwnershipTransferred, _previousOwner []common.Address, _newOwner []common.Address, _ownershipTransferred []bool) (event.Subscription, error) { 1349 | 1350 | var _previousOwnerRule []interface{} 1351 | for _, _previousOwnerItem := range _previousOwner { 1352 | _previousOwnerRule = append(_previousOwnerRule, _previousOwnerItem) 1353 | } 1354 | var _newOwnerRule []interface{} 1355 | for _, _newOwnerItem := range _newOwner { 1356 | _newOwnerRule = append(_newOwnerRule, _newOwnerItem) 1357 | } 1358 | var _ownershipTransferredRule []interface{} 1359 | for _, _ownershipTransferredItem := range _ownershipTransferred { 1360 | _ownershipTransferredRule = append(_ownershipTransferredRule, _ownershipTransferredItem) 1361 | } 1362 | 1363 | logs, sub, err := _Airdrop.contract.WatchLogs(opts, "OwnershipTransferred", _previousOwnerRule, _newOwnerRule, _ownershipTransferredRule) 1364 | if err != nil { 1365 | return nil, err 1366 | } 1367 | return event.NewSubscription(func(quit <-chan struct{}) error { 1368 | defer sub.Unsubscribe() 1369 | for { 1370 | select { 1371 | case log := <-logs: 1372 | // New log arrived, parse the event and forward to the user 1373 | event := new(AirdropOwnershipTransferred) 1374 | if err := _Airdrop.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { 1375 | return err 1376 | } 1377 | event.Raw = log 1378 | 1379 | select { 1380 | case sink <- event: 1381 | case err := <-sub.Err(): 1382 | return err 1383 | case <-quit: 1384 | return nil 1385 | } 1386 | case err := <-sub.Err(): 1387 | return err 1388 | case <-quit: 1389 | return nil 1390 | } 1391 | } 1392 | }), nil 1393 | } 1394 | 1395 | // AirdropSigDebugIterator is returned from FilterSigDebug and is used to iterate over the raw logs and unpacked data for SigDebug events raised by the Airdrop contract. 1396 | type AirdropSigDebugIterator struct { 1397 | Event *AirdropSigDebug // Event containing the contract specifics and raw log 1398 | 1399 | contract *bind.BoundContract // Generic contract to use for unpacking event data 1400 | event string // Event name to use for unpacking event data 1401 | 1402 | logs chan types.Log // Log channel receiving the found contract events 1403 | sub ethereum.Subscription // Subscription for errors, completion and termination 1404 | done bool // Whether the subscription completed delivering logs 1405 | fail error // Occurred error to stop iteration 1406 | } 1407 | 1408 | // Next advances the iterator to the subsequent event, returning whether there 1409 | // are any more events found. In case of a retrieval or parsing error, false is 1410 | // returned and Error() can be queried for the exact failure. 1411 | func (it *AirdropSigDebugIterator) Next() bool { 1412 | // If the iterator failed, stop iterating 1413 | if it.fail != nil { 1414 | return false 1415 | } 1416 | // If the iterator completed, deliver directly whatever's available 1417 | if it.done { 1418 | select { 1419 | case log := <-it.logs: 1420 | it.Event = new(AirdropSigDebug) 1421 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 1422 | it.fail = err 1423 | return false 1424 | } 1425 | it.Event.Raw = log 1426 | return true 1427 | 1428 | default: 1429 | return false 1430 | } 1431 | } 1432 | // Iterator still in progress, wait for either a data or an error event 1433 | select { 1434 | case log := <-it.logs: 1435 | it.Event = new(AirdropSigDebug) 1436 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 1437 | it.fail = err 1438 | return false 1439 | } 1440 | it.Event.Raw = log 1441 | return true 1442 | 1443 | case err := <-it.sub.Err(): 1444 | it.done = true 1445 | it.fail = err 1446 | return it.Next() 1447 | } 1448 | } 1449 | 1450 | // Error returns any retrieval or parsing error occurred during filtering. 1451 | func (it *AirdropSigDebugIterator) Error() error { 1452 | return it.fail 1453 | } 1454 | 1455 | // Close terminates the iteration process, releasing any pending underlying 1456 | // resources. 1457 | func (it *AirdropSigDebugIterator) Close() error { 1458 | it.sub.Unsubscribe() 1459 | return nil 1460 | } 1461 | 1462 | // AirdropSigDebug represents a SigDebug event raised by the Airdrop contract. 1463 | type AirdropSigDebug struct { 1464 | H [32]byte 1465 | Proof [32]byte 1466 | PrefixedProof [32]byte 1467 | Signer common.Address 1468 | Raw types.Log // Blockchain specific contextual infos 1469 | } 1470 | 1471 | // FilterSigDebug is a free log retrieval operation binding the contract event 0x6b7f08f909e42085ce2477fcf9f51be4ff86e5bcc7936c2dbe39e6757d33f914. 1472 | // 1473 | // Solidity: e SigDebug(_h bytes32, _proof bytes32, prefixedProof bytes32, signer address) 1474 | func (_Airdrop *AirdropFilterer) FilterSigDebug(opts *bind.FilterOpts) (*AirdropSigDebugIterator, error) { 1475 | 1476 | logs, sub, err := _Airdrop.contract.FilterLogs(opts, "SigDebug") 1477 | if err != nil { 1478 | return nil, err 1479 | } 1480 | return &AirdropSigDebugIterator{contract: _Airdrop.contract, event: "SigDebug", logs: logs, sub: sub}, nil 1481 | } 1482 | 1483 | // WatchSigDebug is a free log subscription operation binding the contract event 0x6b7f08f909e42085ce2477fcf9f51be4ff86e5bcc7936c2dbe39e6757d33f914. 1484 | // 1485 | // Solidity: e SigDebug(_h bytes32, _proof bytes32, prefixedProof bytes32, signer address) 1486 | func (_Airdrop *AirdropFilterer) WatchSigDebug(opts *bind.WatchOpts, sink chan<- *AirdropSigDebug) (event.Subscription, error) { 1487 | 1488 | logs, sub, err := _Airdrop.contract.WatchLogs(opts, "SigDebug") 1489 | if err != nil { 1490 | return nil, err 1491 | } 1492 | return event.NewSubscription(func(quit <-chan struct{}) error { 1493 | defer sub.Unsubscribe() 1494 | for { 1495 | select { 1496 | case log := <-logs: 1497 | // New log arrived, parse the event and forward to the user 1498 | event := new(AirdropSigDebug) 1499 | if err := _Airdrop.contract.UnpackLog(event, "SigDebug", log); err != nil { 1500 | return err 1501 | } 1502 | event.Raw = log 1503 | 1504 | select { 1505 | case sink <- event: 1506 | case err := <-sub.Err(): 1507 | return err 1508 | case <-quit: 1509 | return nil 1510 | } 1511 | case err := <-sub.Err(): 1512 | return err 1513 | case <-quit: 1514 | return nil 1515 | } 1516 | } 1517 | }), nil 1518 | } 1519 | 1520 | // AirdropSignatureRecoveredIterator is returned from FilterSignatureRecovered and is used to iterate over the raw logs and unpacked data for SignatureRecovered events raised by the Airdrop contract. 1521 | type AirdropSignatureRecoveredIterator struct { 1522 | Event *AirdropSignatureRecovered // Event containing the contract specifics and raw log 1523 | 1524 | contract *bind.BoundContract // Generic contract to use for unpacking event data 1525 | event string // Event name to use for unpacking event data 1526 | 1527 | logs chan types.Log // Log channel receiving the found contract events 1528 | sub ethereum.Subscription // Subscription for errors, completion and termination 1529 | done bool // Whether the subscription completed delivering logs 1530 | fail error // Occurred error to stop iteration 1531 | } 1532 | 1533 | // Next advances the iterator to the subsequent event, returning whether there 1534 | // are any more events found. In case of a retrieval or parsing error, false is 1535 | // returned and Error() can be queried for the exact failure. 1536 | func (it *AirdropSignatureRecoveredIterator) Next() bool { 1537 | // If the iterator failed, stop iterating 1538 | if it.fail != nil { 1539 | return false 1540 | } 1541 | // If the iterator completed, deliver directly whatever's available 1542 | if it.done { 1543 | select { 1544 | case log := <-it.logs: 1545 | it.Event = new(AirdropSignatureRecovered) 1546 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 1547 | it.fail = err 1548 | return false 1549 | } 1550 | it.Event.Raw = log 1551 | return true 1552 | 1553 | default: 1554 | return false 1555 | } 1556 | } 1557 | // Iterator still in progress, wait for either a data or an error event 1558 | select { 1559 | case log := <-it.logs: 1560 | it.Event = new(AirdropSignatureRecovered) 1561 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 1562 | it.fail = err 1563 | return false 1564 | } 1565 | it.Event.Raw = log 1566 | return true 1567 | 1568 | case err := <-it.sub.Err(): 1569 | it.done = true 1570 | it.fail = err 1571 | return it.Next() 1572 | } 1573 | } 1574 | 1575 | // Error returns any retrieval or parsing error occurred during filtering. 1576 | func (it *AirdropSignatureRecoveredIterator) Error() error { 1577 | return it.fail 1578 | } 1579 | 1580 | // Close terminates the iteration process, releasing any pending underlying 1581 | // resources. 1582 | func (it *AirdropSignatureRecoveredIterator) Close() error { 1583 | it.sub.Unsubscribe() 1584 | return nil 1585 | } 1586 | 1587 | // AirdropSignatureRecovered represents a SignatureRecovered event raised by the Airdrop contract. 1588 | type AirdropSignatureRecovered struct { 1589 | Signer common.Address 1590 | Raw types.Log // Blockchain specific contextual infos 1591 | } 1592 | 1593 | // FilterSignatureRecovered is a free log retrieval operation binding the contract event 0x5c001d7523e0202fd001401f8393d128fbb1fafa8f637949f7d231d814f93b13. 1594 | // 1595 | // Solidity: e SignatureRecovered(signer indexed address) 1596 | func (_Airdrop *AirdropFilterer) FilterSignatureRecovered(opts *bind.FilterOpts, signer []common.Address) (*AirdropSignatureRecoveredIterator, error) { 1597 | 1598 | var signerRule []interface{} 1599 | for _, signerItem := range signer { 1600 | signerRule = append(signerRule, signerItem) 1601 | } 1602 | 1603 | logs, sub, err := _Airdrop.contract.FilterLogs(opts, "SignatureRecovered", signerRule) 1604 | if err != nil { 1605 | return nil, err 1606 | } 1607 | return &AirdropSignatureRecoveredIterator{contract: _Airdrop.contract, event: "SignatureRecovered", logs: logs, sub: sub}, nil 1608 | } 1609 | 1610 | // WatchSignatureRecovered is a free log subscription operation binding the contract event 0x5c001d7523e0202fd001401f8393d128fbb1fafa8f637949f7d231d814f93b13. 1611 | // 1612 | // Solidity: e SignatureRecovered(signer indexed address) 1613 | func (_Airdrop *AirdropFilterer) WatchSignatureRecovered(opts *bind.WatchOpts, sink chan<- *AirdropSignatureRecovered, signer []common.Address) (event.Subscription, error) { 1614 | 1615 | var signerRule []interface{} 1616 | for _, signerItem := range signer { 1617 | signerRule = append(signerRule, signerItem) 1618 | } 1619 | 1620 | logs, sub, err := _Airdrop.contract.WatchLogs(opts, "SignatureRecovered", signerRule) 1621 | if err != nil { 1622 | return nil, err 1623 | } 1624 | return event.NewSubscription(func(quit <-chan struct{}) error { 1625 | defer sub.Unsubscribe() 1626 | for { 1627 | select { 1628 | case log := <-logs: 1629 | // New log arrived, parse the event and forward to the user 1630 | event := new(AirdropSignatureRecovered) 1631 | if err := _Airdrop.contract.UnpackLog(event, "SignatureRecovered", log); err != nil { 1632 | return err 1633 | } 1634 | event.Raw = log 1635 | 1636 | select { 1637 | case sink <- event: 1638 | case err := <-sub.Err(): 1639 | return err 1640 | case <-quit: 1641 | return nil 1642 | } 1643 | case err := <-sub.Err(): 1644 | return err 1645 | case <-quit: 1646 | return nil 1647 | } 1648 | } 1649 | }), nil 1650 | } 1651 | -------------------------------------------------------------------------------- /src/airdrop/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io/ioutil" 7 | "log" 8 | "os" 9 | "strings" 10 | 11 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 12 | "github.com/ethereum/go-ethereum/ethclient" 13 | "github.com/postables/Postables-Payment-Channel/src/airdrop/bindings" 14 | ) 15 | 16 | func main() { 17 | if len(os.Args) > 2 || len(os.Args) < 2 { 18 | fmt.Println("improper invocation") 19 | fmt.Println("./airdrop ") 20 | fmt.Println("mode: .....") 21 | os.Exit(1) 22 | } 23 | keyPath := os.Getenv("KEY_PATH") 24 | keyPass := os.Getenv("KEY_PASS") 25 | ipcPath := os.Getenv("IPC_PATH") 26 | if keyPath == "" { 27 | log.Fatal("KEY_PATH env var not set") 28 | } 29 | if keyPass == "" { 30 | log.Fatal("KEY_PASS env var not set") 31 | } 32 | if ipcPath == "" { 33 | log.Fatal("IPC_PATH env var not set") 34 | } 35 | keyBytes, err := ioutil.ReadFile(keyPath) 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | client, err := ethclient.Dial(ipcPath) 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | auth, err := bind.NewTransactor(strings.NewReader(string(keyBytes)), keyPass) 44 | if err != nil { 45 | log.Fatal(err) 46 | } 47 | 48 | runMode := os.Args[1] 49 | switch runMode { 50 | case "deploy": 51 | _, tx, _, err := bindings.DeployAirdrop(auth, client) 52 | if err != nil { 53 | log.Fatal(err) 54 | } 55 | _, err = bind.WaitDeployed(context.Background(), client, tx) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | fmt.Println("airdrop contract deployment succeeded") 60 | default: 61 | log.Fatal("invalid run mode") 62 | } 63 | 64 | } 65 | --------------------------------------------------------------------------------