├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── paySnapshot.js ├── returnSnapshot.js ├── takeIncome.js ├── takeNames.js └── takeSnapshot.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.csv 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Nathan Rempel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # airdrop-tools 2 | A set of nodejs tools to take a current snapshot and deploy tokens on the EOS network 3 | 4 | # Installation 5 | * Install Nodejs 6 | * Clone this repository 7 | * Run `npm install` 8 | 9 | # The steps: 10 | * Update `takeNames.js`, `takeSnapshot.js`, and `paySnapshot.js` with your preferred eos node connection 11 | * Update `takeSnapshot.js` by setting `airgrab = 'yourairgrabtoken'` or `airgrab=false` 12 | * Update `paySnapshot.js` by setting `airdropConfig` as appropriate 13 | * 1. Get the most recent complete snapshot from https://www.eossnapshots.io/ by EOS New York 14 | 15 | Change the csv to a single column of names and rename it `names.csv` 16 | 17 | (These snapshots grab every account on EOS) 18 | 19 | 1. or Run `node takesNames.js`. 20 | 21 | This tool only gets names from the "voters table" of EOS... meaning they are either a genesis account or have voted for a block producer or proxy. 22 | 23 | If you don't pause blocks you may get duplicate names. Remove duplicates in excel or file editor. Rename the `names-timestamp.csv` to `names.csv` 24 | * Run `node takeSnapshot.js`. This will take a while. 25 | * Review `snapshot-timestamp.csv` and create a new file `snapshot.csv` in the following format: 26 | 27 | `account name,quantity` quantity should be just a number, no precision or symbol neccessary 28 | * Finally, run `node paysnapShot.js`. 29 | 30 | If you want to run a test be sure to set broadcast: false and uncomment mockTransactions => 'pass' 31 | * Review `payment-timestamp.csv` to confirm the deployment went out to everyone desired. 32 | 33 | # Recommendations: 34 | ***This code is experimental*** 35 | 36 | Run this code against testnets and test thoroughly before doing a mainnet deploy 37 | 38 | As per the license, GenerEOS does not accept any responsibility or liability for loss of tokens, invalid deployments, deployment failures, or damages of any kind related to using these snapshot and deployment tools. 39 | 40 | # We hope this helps everyone with your future tokens! 41 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "airdrop-tools", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "async": { 8 | "version": "2.6.1", 9 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", 10 | "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", 11 | "requires": { 12 | "lodash": "^4.17.10" 13 | } 14 | }, 15 | "babel-runtime": { 16 | "version": "6.26.0", 17 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 18 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 19 | "requires": { 20 | "core-js": "^2.4.0", 21 | "regenerator-runtime": "^0.11.0" 22 | } 23 | }, 24 | "base-x": { 25 | "version": "3.0.4", 26 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.4.tgz", 27 | "integrity": "sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA==", 28 | "requires": { 29 | "safe-buffer": "^5.0.1" 30 | } 31 | }, 32 | "bigi": { 33 | "version": "1.4.2", 34 | "resolved": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz", 35 | "integrity": "sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU=" 36 | }, 37 | "binaryen": { 38 | "version": "37.0.0", 39 | "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-37.0.0.tgz", 40 | "integrity": "sha512-ACBhSXtQvZvJZ8LNM5R/8HTk57Nr4J+HIrGfIfbIM9OpyaMePsXMgzVt+cMcCgX+sm4bmq5ed0kGgxd9RZ3Kkw==" 41 | }, 42 | "bn.js": { 43 | "version": "4.11.8", 44 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", 45 | "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" 46 | }, 47 | "browserify-aes": { 48 | "version": "1.2.0", 49 | "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", 50 | "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", 51 | "requires": { 52 | "buffer-xor": "^1.0.3", 53 | "cipher-base": "^1.0.0", 54 | "create-hash": "^1.1.0", 55 | "evp_bytestokey": "^1.0.3", 56 | "inherits": "^2.0.1", 57 | "safe-buffer": "^5.0.1" 58 | } 59 | }, 60 | "bs58": { 61 | "version": "4.0.1", 62 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 63 | "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", 64 | "requires": { 65 | "base-x": "^3.0.2" 66 | } 67 | }, 68 | "buffer-xor": { 69 | "version": "1.0.3", 70 | "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", 71 | "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" 72 | }, 73 | "bytebuffer": { 74 | "version": "5.0.1", 75 | "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", 76 | "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", 77 | "requires": { 78 | "long": "~3" 79 | } 80 | }, 81 | "camel-case": { 82 | "version": "3.0.0", 83 | "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", 84 | "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", 85 | "requires": { 86 | "no-case": "^2.2.0", 87 | "upper-case": "^1.1.1" 88 | } 89 | }, 90 | "cipher-base": { 91 | "version": "1.0.4", 92 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", 93 | "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", 94 | "requires": { 95 | "inherits": "^2.0.1", 96 | "safe-buffer": "^5.0.1" 97 | } 98 | }, 99 | "core-js": { 100 | "version": "2.5.7", 101 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", 102 | "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" 103 | }, 104 | "create-hash": { 105 | "version": "1.2.0", 106 | "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", 107 | "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", 108 | "requires": { 109 | "cipher-base": "^1.0.1", 110 | "inherits": "^2.0.1", 111 | "md5.js": "^1.3.4", 112 | "ripemd160": "^2.0.1", 113 | "sha.js": "^2.4.0" 114 | } 115 | }, 116 | "create-hmac": { 117 | "version": "1.1.7", 118 | "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", 119 | "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", 120 | "requires": { 121 | "cipher-base": "^1.0.3", 122 | "create-hash": "^1.1.0", 123 | "inherits": "^2.0.1", 124 | "ripemd160": "^2.0.0", 125 | "safe-buffer": "^5.0.1", 126 | "sha.js": "^2.4.8" 127 | } 128 | }, 129 | "ecurve": { 130 | "version": "1.0.6", 131 | "resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz", 132 | "integrity": "sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w==", 133 | "requires": { 134 | "bigi": "^1.1.0", 135 | "safe-buffer": "^5.0.1" 136 | } 137 | }, 138 | "encoding": { 139 | "version": "0.1.12", 140 | "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", 141 | "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", 142 | "requires": { 143 | "iconv-lite": "~0.4.13" 144 | } 145 | }, 146 | "eosjs": { 147 | "version": "15.0.3", 148 | "resolved": "https://registry.npmjs.org/eosjs/-/eosjs-15.0.3.tgz", 149 | "integrity": "sha512-SkQ1YgmVOzyn/iS/k51AE4vz+nydhuk9kKVXCzLGAvVi6trDWO3uP7TLPKQ4ItbUBbATHdWJpNojgq68yI8PSg==", 150 | "requires": { 151 | "babel-runtime": "^6.26.0", 152 | "binaryen": "^37.0.0", 153 | "create-hash": "^1.1.3", 154 | "eosjs-api": "6.3.0", 155 | "eosjs-ecc": "4.0.1", 156 | "fcbuffer": "2.2.0" 157 | } 158 | }, 159 | "eosjs-api": { 160 | "version": "6.3.0", 161 | "resolved": "https://registry.npmjs.org/eosjs-api/-/eosjs-api-6.3.0.tgz", 162 | "integrity": "sha512-HTd1zWCohrDC+jekeecL6Y3Lik4zGpeDFl9b2gl5VZtptQUkyrTi/8bkKY/e9siu8jYgulxUFaRZhvzdA7Hy/A==", 163 | "requires": { 164 | "camel-case": "^3.0.0", 165 | "isomorphic-fetch": "^2.2.1" 166 | } 167 | }, 168 | "eosjs-ecc": { 169 | "version": "4.0.1", 170 | "resolved": "https://registry.npmjs.org/eosjs-ecc/-/eosjs-ecc-4.0.1.tgz", 171 | "integrity": "sha512-j6241infAq5pCBl9vzZ6mKQ/yRdNz60Zwv4FWh4H/34q2HR9sTFLlyT+UHfe6eD2HLEqDvJ6rntFeHArG+wDKA==", 172 | "requires": { 173 | "bigi": "^1.4.2", 174 | "browserify-aes": "^1.0.6", 175 | "bs58": "^4.0.1", 176 | "bytebuffer": "^5.0.1", 177 | "create-hash": "^1.1.3", 178 | "create-hmac": "^1.1.6", 179 | "ecurve": "^1.0.5", 180 | "randombytes": "^2.0.5" 181 | } 182 | }, 183 | "evp_bytestokey": { 184 | "version": "1.0.3", 185 | "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", 186 | "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", 187 | "requires": { 188 | "md5.js": "^1.3.4", 189 | "safe-buffer": "^5.1.1" 190 | } 191 | }, 192 | "fcbuffer": { 193 | "version": "2.2.0", 194 | "resolved": "https://registry.npmjs.org/fcbuffer/-/fcbuffer-2.2.0.tgz", 195 | "integrity": "sha512-ytgOVjGINWJbiWzaD/7nYQgUY+wIW1N4F4mUiC0irWXgg5mSr+wCo1vri8jOpI+cqERhjQlvTB0CX0WTF1g5dA==", 196 | "requires": { 197 | "bn.js": "^4.11.8", 198 | "bytebuffer": "^5.0.1", 199 | "ieee-float": "^0.6.0" 200 | } 201 | }, 202 | "hash-base": { 203 | "version": "3.0.4", 204 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", 205 | "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", 206 | "requires": { 207 | "inherits": "^2.0.1", 208 | "safe-buffer": "^5.0.1" 209 | } 210 | }, 211 | "iconv-lite": { 212 | "version": "0.4.23", 213 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 214 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 215 | "requires": { 216 | "safer-buffer": ">= 2.1.2 < 3" 217 | } 218 | }, 219 | "ieee-float": { 220 | "version": "0.6.0", 221 | "resolved": "https://registry.npmjs.org/ieee-float/-/ieee-float-0.6.0.tgz", 222 | "integrity": "sha1-poqFa6HvUR5/oOfn4VXDpjZCpV0=" 223 | }, 224 | "inherits": { 225 | "version": "2.0.3", 226 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 227 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 228 | }, 229 | "is-stream": { 230 | "version": "1.1.0", 231 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 232 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" 233 | }, 234 | "isomorphic-fetch": { 235 | "version": "2.2.1", 236 | "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", 237 | "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", 238 | "requires": { 239 | "node-fetch": "^1.0.1", 240 | "whatwg-fetch": ">=0.10.0" 241 | } 242 | }, 243 | "lodash": { 244 | "version": "4.17.10", 245 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", 246 | "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" 247 | }, 248 | "long": { 249 | "version": "3.2.0", 250 | "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", 251 | "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" 252 | }, 253 | "lower-case": { 254 | "version": "1.1.4", 255 | "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", 256 | "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" 257 | }, 258 | "md5.js": { 259 | "version": "1.3.4", 260 | "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", 261 | "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", 262 | "requires": { 263 | "hash-base": "^3.0.0", 264 | "inherits": "^2.0.1" 265 | } 266 | }, 267 | "no-case": { 268 | "version": "2.3.2", 269 | "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", 270 | "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", 271 | "requires": { 272 | "lower-case": "^1.1.1" 273 | } 274 | }, 275 | "node-fetch": { 276 | "version": "1.7.3", 277 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", 278 | "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", 279 | "requires": { 280 | "encoding": "^0.1.11", 281 | "is-stream": "^1.0.1" 282 | } 283 | }, 284 | "papaparse": { 285 | "version": "4.5.0", 286 | "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-4.5.0.tgz", 287 | "integrity": "sha1-+2JdOQtuXVRNsgZYzjZlACw9joA=" 288 | }, 289 | "randombytes": { 290 | "version": "2.0.6", 291 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", 292 | "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", 293 | "requires": { 294 | "safe-buffer": "^5.1.0" 295 | } 296 | }, 297 | "regenerator-runtime": { 298 | "version": "0.11.1", 299 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", 300 | "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" 301 | }, 302 | "ripemd160": { 303 | "version": "2.0.2", 304 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", 305 | "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", 306 | "requires": { 307 | "hash-base": "^3.0.0", 308 | "inherits": "^2.0.1" 309 | } 310 | }, 311 | "safe-buffer": { 312 | "version": "5.1.2", 313 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 314 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 315 | }, 316 | "safer-buffer": { 317 | "version": "2.1.2", 318 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 319 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 320 | }, 321 | "sha.js": { 322 | "version": "2.4.11", 323 | "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", 324 | "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", 325 | "requires": { 326 | "inherits": "^2.0.1", 327 | "safe-buffer": "^5.0.1" 328 | } 329 | }, 330 | "upper-case": { 331 | "version": "1.1.3", 332 | "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", 333 | "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" 334 | }, 335 | "whatwg-fetch": { 336 | "version": "2.0.4", 337 | "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", 338 | "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" 339 | } 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "airdrop-tools", 3 | "version": "1.0.0", 4 | "description": "Take snapshots of EOS network and deploy tokens", 5 | "main": "takeSnapshot.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/genereos//airdrop-tools.git" 12 | }, 13 | "author": "Nathan Rempel", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/genereos//airdrop-tools/issues" 17 | }, 18 | "homepage": "https://github.com/genereos/airdrop-tools#readme", 19 | "dependencies": { 20 | "async": "^2.6.1", 21 | "eosjs": "^15.0.0", 22 | "papaparse": "^4.5.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /paySnapshot.js: -------------------------------------------------------------------------------- 1 | Eos = require('eosjs'); 2 | fs = require("fs"); 3 | Papa = require("papaparse"); 4 | filename = "payment-" + Date.now() + ".csv"; 5 | 6 | 7 | process.on('unhandledRejection', error => { 8 | // Nodejs generic handler 9 | }); 10 | 11 | 12 | airdropConfig = { 13 | contract: 'democoindrop', 14 | privKey: '', 15 | symbol: 'DEMO', 16 | precision: 4, 17 | minimum: '1.0000 DEMO', //minimum award 18 | threshold: 1, //minimum awarded to anyone below this threshold 19 | memo: "Have a DEMO coin", 20 | } 21 | 22 | eosConfig = { 23 | chainId: '038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca', // 32 byte (64 char) hex string 24 | keyProvider: [airdropConfig.privKey], // WIF string or array of keys.. 25 | httpEndpoint: 'http://jungle.cryptolions.io:38888', //probably localhost 26 | expireInSeconds: 60, 27 | broadcast: true, //set to false for testing 28 | verbose: false, // API and transactions 29 | debug: false, 30 | sign: true, 31 | //mockTransactions: () => 'fail', //use this to test success and fail 32 | } 33 | 34 | eosClient = Eos(eosConfig); 35 | 36 | async function Payment(tr,name,quantity) { 37 | //Calculate the actual payment amount based on the provided CSV 38 | let actual = `${Number(quantity).toFixed(airdropConfig.precision).toString()} ${airdropConfig.symbol}`; 39 | //Determine if we award the minimum 40 | let payment = Number(quantity) < airdropConfig.threshold ? airdropConfig.minimum : actual; 41 | return tr.issue( 42 | name.toString().trim(), //the person receiving the airdrop 43 | payment, //the payment quantity 44 | airdropConfig.memo, //the airdrop memo 45 | {authorization: airdropConfig.contract} 46 | ); 47 | } 48 | 49 | async function IssuePayment(names) { 50 | //we create a transaction with multiple issue actions 51 | return eosClient.transaction(airdropConfig.contract,tr => { 52 | for(let i = 0; i < names.length; i++) { 53 | if(names[i][0] !== "") { 54 | Payment(tr,names[i][0],names[i][1]); 55 | } 56 | } 57 | },{broadcast: eosConfig.broadcast}); 58 | } 59 | 60 | async function PayAllAccounts() { 61 | //read the snapshot.csv file 62 | fs.readFile(__dirname + '/' + 'snapshot.csv', 'utf8', async function (err,csv) { 63 | if (err) { 64 | return console.log(err); 65 | } 66 | 67 | var data = Papa.parse(csv).data; 68 | let total = data.length; 69 | let start = Date.now(); 70 | console.log(start); 71 | 72 | console.log("Found " + total + " accounts."); 73 | let proc = 0; 74 | 75 | fs.appendFile(__dirname + '/' + filename, 'name,payment,processed', (err) => { 76 | if (err) throw err; 77 | }); 78 | 79 | //we get a chunk of 30 payments at a time 80 | while(data.length > 0) { 81 | let names = data.splice(0,30); 82 | let success = false; 83 | let done = false; 84 | let attempts = 0; 85 | proc += names.length; 86 | 87 | while(!done) { 88 | if(attempts < 3) { 89 | try { 90 | await IssuePayment(names); 91 | success = true; 92 | done = true; 93 | } catch(e) { 94 | console.log("Failed, retrying segement " + proc + "..."); 95 | attempts++; 96 | } 97 | } else { 98 | done = true; 99 | } 100 | } 101 | 102 | names.map(name => { 103 | let formatted = { 104 | name: name[0], 105 | payment: name[1], 106 | processed: success 107 | }; 108 | var write = Papa.unparse([formatted],{header:false}); 109 | fs.appendFile(__dirname + '/' + filename, '\n'+write, (err) => { 110 | if (err) throw err; 111 | }); 112 | }) 113 | 114 | process.stdout.write("Have processed " + proc + " of " + total + "\r"); 115 | } 116 | let end = Date.now(); 117 | console.log(end); 118 | console.log("Have processed " + proc + " of " + total); 119 | console.log("Done"); 120 | }); 121 | } 122 | 123 | async function run() { 124 | await PayAllAccounts(); 125 | } 126 | 127 | // Let's do it!!! 128 | run(); 129 | -------------------------------------------------------------------------------- /returnSnapshot.js: -------------------------------------------------------------------------------- 1 | Eos = require('eosjs'); 2 | fs = require("fs"); 3 | Papa = require("papaparse"); 4 | filename = "payment-" + Date.now() + ".csv"; 5 | 6 | 7 | process.on('unhandledRejection', error => { 8 | // Nodejs generic handler 9 | }); 10 | 11 | 12 | airdropConfig = { 13 | contract: 'democoindrop', 14 | privKey: '', 15 | symbol: 'DEMO', 16 | precision: 4, 17 | minimum: '1.0000 DEMO', //minimum award 18 | threshold: 1, //minimum awarded to anyone below this threshold 19 | memo: "Have a DEMO coin", 20 | } 21 | 22 | eosConfig = { 23 | chainId: '038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca', // 32 byte (64 char) hex string 24 | keyProvider: [airdropConfig.privKey], // WIF string or array of keys.. 25 | httpEndpoint: 'http://jungle.cryptolions.io:38888', //probably localhost 26 | expireInSeconds: 60, 27 | broadcast: true, //set to false for testing 28 | verbose: false, // API and transactions 29 | debug: false, 30 | sign: true, 31 | //mockTransactions: () => 'fail', //use this to test success and fail 32 | } 33 | 34 | eosClient = Eos(eosConfig); 35 | 36 | async function Payment(tr,name,quantity) { 37 | return tr.recover( 38 | name.toString().trim(), //the person losing the airdrop 39 | `${airdropConfig.precision},${airdropConfig.symbol}`, //the symbol 40 | {authorization: airdropConfig.contract} 41 | ); 42 | } 43 | 44 | async function IssuePayment(names) { 45 | //we create a transaction with multiple issue actions 46 | return eosClient.transaction(airdropConfig.contract,tr => { 47 | for(let i = 0; i < names.length; i++) { 48 | if(names[i][0] !== "") { 49 | Payment(tr,names[i][0],names[i][1]); 50 | } 51 | } 52 | },{broadcast: eosConfig.broadcast}); 53 | } 54 | 55 | async function PayAllAccounts() { 56 | //read the snapshot.csv file 57 | fs.readFile(__dirname + '/' + 'snapshot.csv', 'utf8', async function (err,csv) { 58 | if (err) { 59 | return console.log(err); 60 | } 61 | 62 | var data = Papa.parse(csv).data; 63 | let total = data.length; 64 | let start = Date.now(); 65 | console.log(start); 66 | 67 | console.log("Found " + total + " accounts."); 68 | let proc = 0; 69 | 70 | fs.appendFile(__dirname + '/' + filename, 'name,payment,processed', (err) => { 71 | if (err) throw err; 72 | }); 73 | 74 | //we get a chunk of 30 payments at a time 75 | while(data.length > 0) { 76 | let names = data.splice(0,30); 77 | let success = false; 78 | let done = false; 79 | let attempts = 0; 80 | proc += names.length; 81 | 82 | while(!done) { 83 | if(attempts < 3) { 84 | try { 85 | await IssuePayment(names); 86 | success = true; 87 | done = true; 88 | } catch(e) { 89 | console.log("Failed, retrying segement " + proc + "..."); 90 | attempts++; 91 | } 92 | } else { 93 | done = true; 94 | } 95 | } 96 | 97 | names.map(name => { 98 | let formatted = { 99 | name: name[0], 100 | payment: name[1], 101 | processed: success 102 | }; 103 | var write = Papa.unparse([formatted],{header:false}); 104 | fs.appendFile(__dirname + '/' + filename, '\n'+write, (err) => { 105 | if (err) throw err; 106 | }); 107 | }) 108 | 109 | process.stdout.write("Have processed " + proc + " of " + total + "\r"); 110 | } 111 | let end = Date.now(); 112 | console.log(end); 113 | console.log("Have processed " + proc + " of " + total); 114 | console.log("Done"); 115 | }); 116 | } 117 | 118 | async function run() { 119 | await PayAllAccounts(); 120 | } 121 | 122 | // Let's do it!!! 123 | run(); 124 | -------------------------------------------------------------------------------- /takeIncome.js: -------------------------------------------------------------------------------- 1 | Eos = require('eosjs'); // Eos = require('./src') 2 | fs = require("fs"); 3 | Papa = require("papaparse"); 4 | filename = "incomeReport-" + Date.now() + ".csv"; 5 | 6 | 7 | process.on('unhandledRejection', error => { 8 | // Nodejs generic handler 9 | }); 10 | 11 | // if you are running an airgrab, specify your contract 12 | airgrab = false; //set to false if no airgrab 13 | 14 | config = { 15 | chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', // 32 byte (64 char) hex string 16 | httpEndpoint: 'https://mainnet.genereos.io', //probably localhost 17 | expireInSeconds: 60, 18 | broadcast: true, 19 | debug: false, // API and transactions 20 | sign: true 21 | } 22 | 23 | eosClient = Eos(config); 24 | 25 | async function IsRegistered(token,name) { 26 | try { 27 | return await eosClient.getCurrencyBalance(token, name); 28 | } catch(e) { 29 | return []; 30 | } 31 | } 32 | 33 | async function GetDetails(name,tries=0) { 34 | try { 35 | const account = await eosClient.getAccount(name); 36 | if(airgrab) { 37 | const registered = await IsRegistered(airgrab,name); 38 | account.registered = registered; 39 | } else { 40 | account.registered = []; 41 | } 42 | return account; 43 | } catch(e) { 44 | console.log(name + ": " + tries); 45 | if(tries < 3) { 46 | return await GetDetails(name,++tries); 47 | } else { 48 | return false; 49 | } 50 | } 51 | } 52 | 53 | async function GetProxyVotes(proxy) { 54 | const account = await eosClient.getAccount(proxy); 55 | if(account.voter_info.proxy) { 56 | return await GetProxyVotes(account.voter_info.proxy); 57 | } else { 58 | return account.voter_info.producers.length 59 | } 60 | } 61 | 62 | async function CreateRow(row) { 63 | let name = row[0].trim() 64 | if(name === '') return; 65 | let details = await GetDetails(name); 66 | 67 | if(details) { 68 | try { 69 | let eos = Number(details.core_liquid_balance ? details.core_liquid_balance.split(' ')[0] : 0); 70 | let net = Number(details.self_delegated_bandwidth ? details.self_delegated_bandwidth.net_weight.split(' ')[0] : 0); 71 | let cpu = Number(details.self_delegated_bandwidth ? details.self_delegated_bandwidth.cpu_weight.split(' ')[0] : 0); 72 | let refundNet = Number(details.refund_request ? details.refund_request.net_amount.split(' ')[0] : 0); 73 | let refundCpu = Number(details.refund_request ? details.refund_request.cpu_amount.split(' ')[0] : 0); 74 | let proxyVotes = 0; 75 | if(details.voter_info && details.voter_info.proxy) { 76 | proxyVotes = await GetProxyVotes(details.voter_info.proxy); 77 | } 78 | let formatted = { 79 | "name": details.account_name, 80 | "eos": Number(eos.toFixed(4)), 81 | "stake": Number((net+cpu).toFixed(4)), 82 | "refund": Number((refundNet+refundCpu).toFixed(4)), 83 | "totalEos": Number((net+cpu+eos+refundNet+refundCpu).toFixed(4)), 84 | "totalRam": Number(details.ram_quota), 85 | }; 86 | var write = Papa.unparse([formatted],{header:false}); 87 | fs.appendFile(__dirname + '/' + filename, '\n'+write, (err) => { 88 | if (err) throw err; 89 | }); 90 | } catch(e) { 91 | console.log(JSON.stringify(details)); 92 | console.log(JSON.stringify(e)); 93 | } 94 | 95 | } else { 96 | //console.log("Skipping: " + name); 97 | } 98 | } 99 | 100 | async function GetAllAccounts() { 101 | fs.readFile(__dirname + '/' + 'income.csv', 'utf8', async function (err,csv) { 102 | if (err) { 103 | return console.log(err); 104 | } 105 | 106 | var data = Papa.parse(csv).data; 107 | let total = data.length; 108 | 109 | console.log("Found " + total + " accounts."); 110 | let proc = 0; 111 | 112 | fs.appendFile(__dirname + '/' + filename, 'name,eos,stake,totalEos,proxy,proxyVotes,votes,registered', (err) => { 113 | if (err) throw err; 114 | }); 115 | 116 | while(data.length > 0) { 117 | let names = data.splice(0,100); 118 | await Promise.all( 119 | names.map(CreateRow) 120 | ); 121 | 122 | proc += names.length; 123 | process.stdout.write("Have processed " + proc + " of " + total + "\r"); 124 | } 125 | 126 | console.log("Have processed " + proc + " of " + total); 127 | console.log("Done"); 128 | }); 129 | } 130 | 131 | async function run() { 132 | await GetAllAccounts(); 133 | } 134 | 135 | run(); 136 | -------------------------------------------------------------------------------- /takeNames.js: -------------------------------------------------------------------------------- 1 | Eos = require('eosjs'); 2 | fs = require("fs"); 3 | Papa = require("papaparse"); 4 | filename = "snapshot-" + Date.now() + ".csv"; 5 | names = "names-" + Date.now() + ".csv"; 6 | 7 | 8 | process.on('unhandledRejection', error => { 9 | // Nodejs generic handler 10 | }); 11 | 12 | 13 | config = { 14 | chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', // 32 byte (64 char) hex string 15 | httpEndpoint: //'localhost:8080', //probably localhost 16 | expireInSeconds: 60, 17 | broadcast: true, 18 | debug: false, // API and transactions 19 | sign: true 20 | } 21 | 22 | eosClient = Eos(config); 23 | 24 | 25 | async function GetAccountsSegment(key) { 26 | var voters = { 27 | json: true, 28 | scope: "eosio", 29 | code: "eosio", 30 | table: "voters", 31 | limit: 1001, 32 | table_key: "owner", 33 | lower_bound: key, 34 | } 35 | 36 | return await eosClient.getTableRows(voters); 37 | } 38 | 39 | async function GetAllAccountNames() { 40 | let accounts = []; 41 | let key = ""; 42 | let data = {"more":true}; 43 | 44 | while(data.more) { 45 | process.stdout.write("Have downloaded " + accounts.length + " accounts\r"); 46 | data = await GetAccountsSegment(key); 47 | key = data.rows.pop().owner; 48 | data.rows.map(async function(v) { 49 | let formatted = { 50 | "name": v.owner, 51 | }; 52 | accounts.push(formatted); 53 | }); 54 | } 55 | 56 | console.log("Have downloaded " + accounts.length + " accounts\r"); 57 | console.log("Making unique"); 58 | 59 | try { 60 | let unique = [...new Set(accounts)]; 61 | console.log("Saving names"); 62 | var csv = Papa.unparse(unique,{header:false}); 63 | fs.appendFile(__dirname + '/' + names, '\n'+csv, (err) => { 64 | if (err) throw err; 65 | }); 66 | console.log("Have saved " + unique.length + " accounts\r"); 67 | } catch(e) { 68 | console.log(e); 69 | } 70 | } 71 | 72 | async function run() { 73 | await GetAllAccountNames() 74 | } 75 | 76 | run(); 77 | -------------------------------------------------------------------------------- /takeSnapshot.js: -------------------------------------------------------------------------------- 1 | Eos = require('eosjs'); // Eos = require('./src') 2 | fs = require("fs"); 3 | Papa = require("papaparse"); 4 | filename = "snapshot-" + Date.now() + ".csv"; 5 | names = "names-" + Date.now() + ".csv"; 6 | 7 | 8 | process.on('unhandledRejection', error => { 9 | // Nodejs generic handler 10 | }); 11 | 12 | // if you are running an airgrab, specify your contract 13 | airgrab = 'zkstokensr4u'; //set to false if no airgrab 14 | 15 | config = { 16 | chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', // 32 byte (64 char) hex string 17 | httpEndpoint: 'https://mainnet.genereos.io:443', //probably localhost 18 | expireInSeconds: 60, 19 | broadcast: true, 20 | debug: false, // API and transactions 21 | sign: true 22 | } 23 | 24 | eosClient = Eos(config); 25 | 26 | async function IsRegistered(token,name) { 27 | try { 28 | return await eosClient.getCurrencyBalance(token, name); 29 | } catch(e) { 30 | return []; 31 | } 32 | } 33 | 34 | async function GetDelegated(name) { 35 | try { 36 | const table = { 37 | json: true, 38 | scope: name, 39 | code: 'eosio', 40 | table: 'delband', 41 | limit: 500 42 | } 43 | let total = 0; 44 | const delegated = await eosClient.getTableRows(table); 45 | delegated.rows.map((row)=> { 46 | const net = Number(row.net_weight.split(' ')[0]); 47 | const cpu = Number(row.cpu_weight.split(' ')[0]); 48 | total += (net+cpu); 49 | }); 50 | return total; 51 | } catch(e) { 52 | return 0; 53 | } 54 | } 55 | 56 | async function GetClaimed(name) { 57 | try { 58 | const table = { 59 | json: true, 60 | scope: name, 61 | code: airgrab, 62 | table: "accounts", 63 | limit: 5 64 | } 65 | let claimed = false; 66 | const data = await eosClient.getTableRows(table); 67 | console.log(data); 68 | data.rows.map((row)=> { 69 | claimed = row.claimed == 1; 70 | }); 71 | return claimed; 72 | } catch(e) { 73 | console.log(e); 74 | return false; 75 | } 76 | } 77 | 78 | async function GetDetails(name,tries=0) { 79 | try { 80 | const account = await eosClient.getAccount(name); 81 | account.delegated = await GetDelegated(name); 82 | account.claimed = await GetClaimed(name); 83 | if(airgrab) { 84 | const registered = await IsRegistered(airgrab,name); 85 | account.registered = registered; 86 | } else { 87 | account.registered = []; 88 | } 89 | 90 | const liquid = await IsRegistered('eosio.token',name); 91 | account.core_liquid_balance = liquid[0]; 92 | return account; 93 | } catch(e) { 94 | console.log(name + ": " + tries); 95 | if(tries < 3) { 96 | return await GetDetails(name,++tries); 97 | } else { 98 | return false; 99 | } 100 | } 101 | } 102 | 103 | async function GetProxyVotes(proxy) { 104 | const account = await eosClient.getAccount(proxy); 105 | if(account.voter_info.proxy) { 106 | return await GetProxyVotes(account.voter_info.proxy); 107 | } else { 108 | return account.voter_info.producers.length 109 | } 110 | } 111 | 112 | async function CreateRow(row) { 113 | let name = row[0].trim() 114 | if(name === '') return; 115 | let details = await GetDetails(name); 116 | 117 | if(details) { 118 | try { 119 | let eos = Number(details.core_liquid_balance ? details.core_liquid_balance.split(' ')[0] : 0); 120 | let stake = details.delegated; 121 | let proxyVotes = 0; 122 | if(details.voter_info && details.voter_info.proxy) { 123 | proxyVotes = await GetProxyVotes(details.voter_info.proxy); 124 | } 125 | let formatted = { 126 | "name": details.account_name, 127 | "eos": Number(eos.toFixed(4)), 128 | "stake": Number(stake.toFixed(4)), 129 | "totalEos": Number((stake+eos).toFixed(4)), 130 | "proxy": details.voter_info ? details.voter_info.proxy : '', 131 | "proxyVotes": proxyVotes, 132 | "votes": details.voter_info ? details.voter_info.producers.length : 0, 133 | "registered": details.registered, 134 | "claimed": details.claimed, 135 | }; 136 | var write = Papa.unparse([formatted],{header:false}); 137 | fs.appendFile(__dirname + '/' + filename, '\n'+write, (err) => { 138 | if (err) throw err; 139 | }); 140 | } catch(e) { 141 | console.log(JSON.stringify(details)); 142 | console.log(JSON.stringify(e)); 143 | } 144 | 145 | } else { 146 | //console.log("Skipping: " + name); 147 | } 148 | } 149 | 150 | async function GetAllAccounts() { 151 | fs.readFile(__dirname + '/' + 'names.csv', 'utf8', async function (err,csv) { 152 | if (err) { 153 | return console.log(err); 154 | } 155 | 156 | var data = Papa.parse(csv).data; 157 | let total = data.length; 158 | 159 | console.log("Found " + total + " accounts."); 160 | let proc = 0; 161 | 162 | fs.appendFile(__dirname + '/' + filename, 'name,eos,stake,totalEos,proxy,proxyVotes,votes,registered', (err) => { 163 | if (err) throw err; 164 | }); 165 | 166 | while(data.length > 0) { 167 | let names = data.splice(0,100); 168 | await Promise.all( 169 | names.map(CreateRow) 170 | ); 171 | 172 | proc += names.length; 173 | process.stdout.write("Have processed " + proc + " of " + total + "\r"); 174 | } 175 | 176 | console.log("Have processed " + proc + " of " + total); 177 | console.log("Done"); 178 | }); 179 | } 180 | 181 | async function run() { 182 | await GetAllAccounts(); 183 | } 184 | 185 | run(); 186 | --------------------------------------------------------------------------------