Created
February 14, 2018 01:07
-
-
Save raypulver/3086316ba97fd1775ba34117469fa459 to your computer and use it in GitHub Desktop.
IDXM distribution script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const { | |
readFile, | |
appendFile, | |
readdir, | |
mkdirp | |
} = require('fs-extra'); | |
const { | |
flow, | |
mergeWith, | |
mergeAllWith, | |
filter, | |
mapKeys, | |
omitBy, | |
curryN, | |
map, | |
get, | |
mapValues | |
} = require('lodash/fp'); | |
const { | |
join, | |
parse | |
} = require('path'); | |
const { | |
zipObject, | |
bindKey, | |
partial, | |
property, | |
noop, | |
method, | |
compact, | |
rearg, | |
partialRight, | |
toPairs, | |
sortBy | |
} = require('lodash'); | |
const { | |
promisify | |
} = require('bluebird'); | |
const { EOL } = require('os'); | |
const { name } = require('./package'); | |
const { unitMap } = require('web3-utils'); | |
let { | |
argv: { | |
o: outputFilename, | |
r: gasPriceGwei, | |
g: gas | |
} | |
} = require('yargs'); | |
outputFilename = outputFilename || 'bounty.log'; | |
gasPriceGwei = gasPriceGwei || '3'; | |
gas = gas || 100000; | |
const logDir = join(process.env.HOME, '.' + name); | |
const filename = join(logDir, outputFilename); | |
const appendToLog = partial(appendFile, filename); | |
const stripAnsi = require('strip-ansi'); | |
const chalk = require('chalk'); | |
const PromiseQueue = require('promiseq'); | |
const logDrain = new PromiseQueue(1); | |
const queueLogJob = (job) => logDrain.push(() => Promise.resolve().then(job)); | |
const log = bindKey(console, 'log'); | |
const moment = require('moment'); | |
const info = (v) => { | |
const toLog = chalk.cyan('[' + moment().format('MM-DD HH:mm:ss') + ']') + ' ' + v; | |
queueLogJob(() => appendToLog(stripAnsi(toLog) + EOL)).catch(noop); | |
log(v); | |
return v; | |
}; | |
const swallowError = (err) => { | |
const toLog = chalk.red('[error]') + ' ' + err.stack; | |
queueLogJob(() => appendToLog(stripToAnsi(toLog) + EOL)).catch(noop); | |
console.error(toLog); | |
return err; | |
}; | |
const Web3 = require('web3'); | |
const web3 = new Web3('https://mainnet.infura.io/aR7WPNCrZhhnYRnn8yRT'); | |
const { | |
encodeFunctionCall | |
} = ['encodeFunctionCall'].reduce((r, v) => { | |
r[v] = bindKey(web3.eth.abi, v); | |
return r; | |
}, {}); | |
const { | |
getTransactionCount, | |
sendSignedTransaction | |
} = [ | |
'getTransactionCount', | |
'sendSignedTransaction' | |
].reduce((r, v) => { | |
r[v] = promisify(bindKey(web3.eth, v)); | |
return r; | |
}, {}); | |
const Transaction = require('ethereumjs-tx'); | |
const { addHexPrefix, bufferToHex } = require('ethereumjs-util'); | |
const BN = require('bignumber.js'); | |
const senderWallet = require('ethereumjs-wallet').fromV3(require('./idxm-sender'), 'idxm-to-the-moon'); | |
const from = senderWallet.getAddressString(); | |
const key = senderWallet.getPrivateKey(); | |
const mapSeriesCurried = curryN(2, rearg(require('bluebird').mapSeries, [1, 0])); | |
const { mapSeries } = require('bluebird'); | |
const readFileAsUtf8 = partialRight(readFile, 'utf8'); | |
const readProgramDirectory = partial(readdir, __dirname); | |
const ln = (v) => ((console.log(require('util').inspect(v, { colors: true }))), v); | |
const exit = () => { | |
info('exiting ...'); | |
logDrain.push(() => Promise.resolve().then(() => process.exit(0))).catch(() => process.exit(0)); | |
}; | |
const cheaters = require('./cheaters'); | |
const hacked = require('./hacked'); | |
const remaining = {}; | |
mkdirp(logDir) | |
.then(() => info('this is ' + chalk.magenta(name))) | |
.then(noop) | |
.then(readProgramDirectory) | |
.then(filter((v) => parse(v).ext === '.csv')) | |
.then(mapSeriesCurried((v) => readFileAsUtf8(v))) | |
.then(map(flow( | |
method('trim'), | |
method('split', '\n'), | |
map(flow( | |
method('replace', /"(.*?),(.*?)"/g, '$1.$2'), | |
method('split', ','), | |
map(method('trim')) | |
)) | |
))) | |
.then(map((v) => v.slice(1).map((u) => zipObject(v[0], u)))) | |
.then(map((v) => v.reduce((r, v) => { | |
let address = v['Ethereum Address'].toLowerCase(); | |
const match = address.match(/0x[a-f0-9]{40}/); | |
if (!match) { | |
remaining[address] = v.Tokens; | |
return r; | |
} | |
address = match[0]; | |
const balance = new BN(r[address] || 0).plus(!isNaN(v.Tokens) && v.Tokens || !isNaN(v['Tokens Earned']) && v['Tokens Earned'] || 0).toPrecision(); | |
r[address] = balance; | |
return r; | |
}, {}))) | |
.then(mergeAllWith((a, b) => new BN(a || 0).plus(b || 0).toPrecision())) | |
.then(omitBy((v) => !+v)) | |
.then(mapKeys((k) => hacked[k] || k)) | |
.then(mapValues((v) => new BN(v).times(new BN(10).pow(8)).dividedToIntegerBy(1).toPrecision())) | |
.then(toPairs) | |
.then(filter((v) => !cheaters.includes(v[0]))) | |
.then((v) => { | |
const r = require('repl').start('> '); | |
Object.assign(r.context, { | |
ary: v, | |
remaining, | |
info | |
}); | |
return sortBy(v, (v) => v[0]); | |
}) | |
.then((targets) => getTransactionCount(from, 'pending').then((nonce) => { | |
let i = nonce; | |
const gasPrice = +new BN(gasPriceGwei).times(unitMap.gwei).toPrecision(); | |
return mapSeries(targets, ([ user, amount ]) => { | |
const tx = new Transaction({ | |
nonce: i, | |
to: '0xcc13fc627effd6e35d2d2706ea3c4d7396c610ea', | |
gas, | |
gasPrice, | |
from, | |
data: encodeFunctionCall({ | |
name: 'transfer', | |
inputs: [{ | |
name: 'target', | |
type: 'address' | |
}, { | |
name: 'amount', | |
type: 'uint256' | |
}] | |
}, [ user, amount ]) | |
}); | |
++i; | |
info('sending ' + chalk.yellow(new BN(amount).div(new BN(10).pow(8)).toPrecision()) + ' IDXM to ' + chalk.magenta(user) + ' with gasPrice of ' + chalk.yellow(gasPriceGwei) + ' gwei and gas of ' + gas); | |
tx.sign(key); | |
return sendSignedTransaction(bufferToHex(tx.serialize())).then((tx) => info('tx available at ' + chalk.magenta(tx))); | |
}); | |
})) | |
.catch(swallowError); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment