Add bot script to tip kudos recipients. Closes #21

This commit is contained in:
Pedro Pombeiro 2018-03-27 20:40:14 +02:00
parent 8c701a61fa
commit 3f3282e19c
No known key found for this signature in database
GPG Key ID: A65DEB11E4BBC647
7 changed files with 959 additions and 56 deletions

2
.vscode/launch.json vendored
View File

@ -25,7 +25,7 @@
],
"env": {
"DEBUG": "true",
"KUDOS_BOT_CONFIG": "{'options':{'process_whole_history':true},'slack':{'channel_id':'C8P4F6WTB'},'rules':{'tip_per_kudo_in_usd':0.02,'tip_per_reaction_in_usd':0.001,'reaction_threshold':3},'payments':{'STT':{'network_id':'ropsten','private_key':'0xaaaa','contract_address':'0xc55cF4B03948D7EBc8b9E8BAD92643703811d162'},'SNT':{'network_id':'homestead','private_key':'0xaaaa','contract_address':'0x744d70FDBE2Ba4CF95131626614a1763DF805B9E'}}}",
"KUDOS_BOT_CONFIG": "{'options':{'inter_transaction_delay':20},'slack':{'channel_id':'C8P4F6WTB'},'rules':{'tip_per_kudo_in_usd':2,'tip_per_reaction_in_usd':0.2,'reaction_threshold':3},'payments':{'STT':{'network_id':'ropsten','private_key':'0xef04012ca9314315db69e27c8cfc8b99f529775a1503605223449f5b7f0e334b','contract_address':'0xc55cF4B03948D7EBc8b9E8BAD92643703811d162'},'SNT':{'network_id':'homestead','private_key':'0xecf69ec4a078f7010667c72ad40d0aad35bbdf9289dd484961281b5f89e2f866','contract_address':'0x744d70FDBE2Ba4CF95131626614a1763DF805B9E'}}}",
"MEMCACHE_URL": "",
"MEMCACHE_USERNAME": "",
"MEMCACHE_PASSWORD": ""

View File

@ -0,0 +1,302 @@
// Description:
// Script that monitors #kudos Slack channel and sends
// a tip for each star attributes to target users
//
// Dependencies:
// axios: "^0.18.0"
// memjs: "^1.2.0"
//
// Author:
// PombeirP
const axios = require('axios')
const tokenPayments = require('../lib/token-payments')
const options = getOptions(process.env.KUDOS_BOT_CONFIG)
const botName = 'tip-kudos-recipients'
const kudosChannelId = options.slack.channel_id
const tipPerKudoInUsd = parseFloat(options.rules.tip_per_kudo_in_usd)
const tipPerReactionInUsd = parseFloat(options.rules.tip_per_reaction_in_usd)
const reactionThreshold = parseInt(options.rules.reaction_threshold)
const interTransactionDelay = parseInt(options.options.inter_transaction_delay)
const tokenID = process.env.DEBUG ? 'STT' : 'SNT'
const token = options.payments[tokenID]
const privateKey = token.private_key
const contractAddress = token.contract_address
const kudosBotDataMemcachedKey = 'tip-kudos-recipients-data'
const userIdRegex = /@[A-Z0-9]+/gi
var isCheckingUpdates = false
module.exports = robot => {
if (!privateKey.startsWith('0x')) {
robot.log.error(`${botName} - Private key must start with 0x. Disabling script`)
return
}
setTimeout(() => processKudosChannelUpdates(robot), process.env.DISABLE_DELAY ? 1 * 1000 : 30 * 1000)
setInterval(() => processKudosChannelUpdates(robot), 24 * 60 * 60 * 1000)
}
function getOptions (optionsString) {
return JSON.parse(optionsString.split(`'`).join(`"`))
}
async function processKudosChannelUpdates (robot) {
if (isCheckingUpdates) {
return
}
isCheckingUpdates = true
try {
const mc = robot['memcache']
const data = await getSavedData(mc)
await fetchPendingKudos(robot, data)
try {
await processPendingPayments(robot, data, d => setSavedData(mc, d))
} catch (error) {
robot.log.warn(`${botName} - Failed to make payment: ${error.responseText}`)
}
} catch (error) {
robot.log.error(`${botName} - Error while processing kudos: ${error}`)
} finally {
isCheckingUpdates = false
}
}
async function getSavedData (mc) {
const json = await mc.get(kudosBotDataMemcachedKey)
if (json.value) {
const data = JSON.parse(json.value)
if (!data.hasOwnProperty('lastMessageTimestamp') || !data.hasOwnProperty('userPendingPayouts')) {
throw new Error(`${botName} - Invalid cached data`)
}
return data
}
return {
lastMessageTimestamp: (new Date(2017, 1, 1)).getTime() / 1000,
userPendingPayouts: {
}
}
}
async function setSavedData (mc, data) {
if (!data.hasOwnProperty('lastMessageTimestamp') || !data.hasOwnProperty('userPendingPayouts')) {
throw new Error(`${botName} - Invalid data, saving aborted`)
}
return mc.set(kudosBotDataMemcachedKey, JSON.stringify(data, {}, 2), {})
}
async function fetchPendingKudos (robot, data) {
const slackWeb = robot.slackWeb
const startTime = (new Date()).getTime()
const thresholdTs = startTime / 1000 - 24 * 60 * 60
let newMessagesProcessed = 0
while (true) {
const historyPayload = await slackWeb.channels.history(kudosChannelId, { oldest: data.lastMessageTimestamp })
if (historyPayload.ok) {
if (!historyPayload.has_more && newMessagesProcessed === 0) {
robot.log.debug(`${botName} - No new entries in ${kudosChannelId} channel history`)
break
}
for (const message of historyPayload.messages.reverse()) {
const messageTs = parseFloat(message.ts)
if (messageTs >= thresholdTs) {
// If the kudos was given less than 24 hours ago, let's ignore it
// and leave it for a later time, so that people have time to vote
continue
}
if (message.type !== 'message' || message.subtype || !message.bot_id) {
continue
}
++newMessagesProcessed
const kudosReceivers = parseKudosReceivers(message.attachments[0].text)
const kudosTimestamp = new Date(message.ts * 1000).toISOString()
if (kudosReceivers.length > 0) {
const reactionCount = countStarReactions(message, kudosReceivers)
if (reactionCount >= reactionThreshold) {
const additionalReactionCount = reactionCount - 1
const totalTip = tipPerKudoInUsd + additionalReactionCount * tipPerReactionInUsd
const tipPerUser = totalTip / kudosReceivers.length
const kudosReceiversData = await fetchKudosReceiversData(robot, kudosReceivers, slackWeb)
robot.log.trace(`${botName} - ${kudosTimestamp}: ${JSON.stringify(kudosReceiversData)} received ${reactionCount} reactions (~${tipPerUser}$ each)`)
for (const userInfo of kudosReceiversData) {
let userPendingPayout = data.userPendingPayouts[userInfo.user]
if (!userPendingPayout) {
userPendingPayout = { kudosCount: 0, reactionCount: 0, balanceInUsd: 0 }
data.userPendingPayouts[userInfo.user] = userPendingPayout
}
userPendingPayout.kudosCount++
userPendingPayout.reactionCount += additionalReactionCount
userPendingPayout.balanceInUsd += tipPerUser
}
} else {
robot.log.trace(`${botName} - ${kudosTimestamp}: ${JSON.stringify(kudosReceivers)} only received ${reactionCount} reactions`)
}
} else {
robot.log.trace(`${botName} - ${kudosTimestamp}: No receivers`)
}
if (!data.lastMessageTimestamp || messageTs > data.lastMessageTimestamp) {
data.lastMessageTimestamp = messageTs
}
}
if (!historyPayload.has_more) {
robot.log.debug(`${botName} - Reached end of ${kudosChannelId} channel history`)
break
}
} else {
robot.log.debug(`${botName} - Failed to fetch ${kudosChannelId} channel history`)
break
}
}
return data
}
async function processPendingPayments (robot, data, saveStateAsyncFunc) {
if (!process.env.DEBUG && !contractAddress) {
return
}
const tokenPrice = await getTokenPrice(tokenID)
const slackProfileCache = robot['slackProfileCache']
const { contract, wallet } = tokenPayments.getContract(contractAddress, privateKey, token.network_id)
// Sort users from lowest to highest balance
const sortedUsers = Object.keys(data.userPendingPayouts).sort((a, b) => compareBalances(data.userPendingPayouts, a, b))
// Print stats
robot.log.debug(`User name\tAmount (${tokenID})\t# Kudos\t# Reactions\tPub key`)
for (const slackUserId of sortedUsers) {
const userPendingPayout = data.userPendingPayouts[slackUserId]
const slackUsername = await slackProfileCache.getSlackUsernameFromSlackId(slackUserId)
const pubkey = await slackProfileCache.getMainnetPubKeyFromSlackId(slackUserId)
const tokenBalance = getTokenBalance(userPendingPayout.balanceInUsd, tokenPrice)
robot.log.debug(`@${slackUsername}\t${tokenBalance}\t${userPendingPayout.kudosCount}\t${userPendingPayout.reactionCount}\t${pubkey}`)
}
// Make payments
let totalPayments = 0
for (const slackUserId of sortedUsers) {
const userPendingPayout = data.userPendingPayouts[slackUserId]
const slackUsername = await slackProfileCache.getSlackUsernameFromSlackId(slackUserId)
const pubkey = await slackProfileCache.getMainnetPubKeyFromSlackId(slackUserId)
if (pubkey && userPendingPayout.balanceInUsd > 0) {
const tokenBalance = getTokenBalance(userPendingPayout.balanceInUsd, tokenPrice)
totalPayments += tokenBalance
try {
const transaction = await tokenPayments.transfer(contract, wallet, pubkey, (process.env.DEBUG ? '0.0001' : tokenBalance.toString()))
// Reset the outstanding payout values
delete data.userPendingPayouts[slackUserId]
robot.log.info(`${botName} - Made payment to @${slackUsername} (https://etherscan.io/tx/${transaction.hash}): ${JSON.stringify(transaction)}`)
await saveStateAsyncFunc(data)
} catch (error) {
robot.log.warn(`${botName} - Failed to make payment to @${slackUsername}: ${error}`)
}
// Need to wait for a bit between transactions, otherwise we start receiving errors
if (interTransactionDelay > 0) {
await new Promise(resolve => setTimeout(resolve, interTransactionDelay * 1000))
}
}
}
robot.log.debug(`Total payments: ${totalPayments}`)
}
function compareBalances (userToPendingPayouts, a, b) {
const x = userToPendingPayouts[a]
const y = userToPendingPayouts[b]
if (x.balanceInUsd > y.balanceInUsd) {
return 1
}
if (x.balanceInUsd < y.balanceInUsd) {
return -1
}
return 0
}
function getTokenBalance (balanceInUsd, tokenPrice) {
return Math.round(balanceInUsd / tokenPrice * 100) / 100
}
async function fetchKudosReceiversData (robot, kudosReceivers, slackWeb) {
const slackProfileCache = robot['slackProfileCache']
const result = []
for (const user of kudosReceivers) {
const pubkey = await slackProfileCache.getMainnetPubKeyFromSlackId(user)
result.push({ user: user, pubkey: pubkey })
}
return result
}
function parseKudosReceivers (message) {
const match = message.match(userIdRegex)
const result = []
if (match) {
for (const k of match) {
result.push(k.substring(1))
}
}
return result
}
function countStarReactions (message, kudosReceivers) {
let reactionCount = 0
if (message.reactions) {
const starsRegex = /&gt; \*(\d+) :star:s\s+\*/g
reactionCount = getReactionCount(starsRegex, message.text)
if (reactionCount === 0) {
const reactionsRegex = /&gt; \*`(\d+)` Reactions?\s+\*/g
reactionCount = getReactionCount(reactionsRegex, message.text)
}
}
return reactionCount
}
function getReactionCount (regex, text) {
let reactionCount = 0
let m
if ((m = regex.exec(text)) !== null) {
reactionCount = parseInt(m[1])
}
return reactionCount
}
async function getTokenPrice (tokenID) {
if (tokenID === 'STT') {
tokenID = 'SNT'
}
const currency = 'USD'
const response = await axios.get(`https://min-api.cryptocompare.com/data/price?fsym=${tokenID}&tsyms=${currency}`)
const tokenPrice = parseFloat(response.data[currency])
return tokenPrice
}

View File

@ -1,4 +1,16 @@
// Description:
// Startup script
//
// Dependencies:
// mem-cache: "0.0.5"
// memjs: "^1.2.0"
// @slack/client: "^3.16.0"
//
// Author:
// PombeirP
const Slack = require('./lib/slack')
const memjs = require('memjs')
module.exports = async (robot) => {
console.log('Yay, the app was loaded!')
@ -11,6 +23,7 @@ module.exports = async (robot) => {
robot.log.trace = console.log
}
setupMemcache(robot)
await setupSlack(robot)
robot['slackProfileCache'] = require('./lib/slack-profile-cache')(robot)
@ -23,6 +36,7 @@ module.exports = async (robot) => {
require('./bot_scripts/trigger-automation-test-build')(robot)
require('./bot_scripts/bounty-awaiting-approval-slack-ping')(robot)
require('./bot_scripts/notify-reviewers-via-slack')(robot)
require('./bot_scripts/tip-kudos-recipients')(robot)
// For more information on building apps:
// https://probot.github.io/docs/
@ -46,3 +60,18 @@ async function setupSlack (robot) {
})
})
}
function setupMemcache (robot) {
// Environment variables are defined in .env
let MEMCACHE_URL = process.env.MEMCACHE_URL || '127.0.0.1:11211'
if (process.env.USE_GAE_MEMCACHE) {
MEMCACHE_URL = `${process.env.GAE_MEMCACHE_HOST}:${process.env.GAE_MEMCACHE_PORT}`
}
const mc = memjs.Client.create(MEMCACHE_URL, {
username: process.env.MEMCACHE_USERNAME,
password: process.env.MEMCACHE_PASSWORD
})
// Copy memcache client to the robot object
robot['memcache'] = mc
}

View File

@ -3,29 +3,19 @@
//
// Dependencies:
// mem-cache: "0.0.5"
// memjs: "^1.2.0"
// @slack/client: "^3.16.0"
//
// Author:
// PombeirP
const MemCache = require('mem-cache')
const memjs = require('memjs')
const { WebClient } = require('@slack/client')
const token = process.env.SLACK_USER_TOKEN || ''
const cacheMemcachedKey = 'slack-profile-cache-json'
var allowLoadFromCache = true
// Environment variables are defined in app.yaml.
let MEMCACHE_URL = process.env.MEMCACHE_URL || '127.0.0.1:11211'
if (process.env.USE_GAE_MEMCACHE) {
MEMCACHE_URL = `${process.env.GAE_MEMCACHE_HOST}:${process.env.GAE_MEMCACHE_PORT}`
}
const mc = memjs.Client.create(MEMCACHE_URL, {
username: process.env.MEMCACHE_USERNAME,
password: process.env.MEMCACHE_PASSWORD
})
module.exports = (robot) => new GitHubSlackIdMapper(robot)
class GitHubSlackIdMapper {
@ -68,20 +58,37 @@ class GitHubSlackIdMapper {
}
return `<@${id}>`
}
async getMainnetPubKeyFromSlackId (slackUserId) {
await this.buildPromise
const profile = this.cache.get(getSlackId2ProfileCacheKeyName(slackUserId))
if (profile) {
return profile.pubkey
}
return null
}
}
async function internalBuild (robot, cache) {
if (allowLoadFromCache) {
const mc = robot['memcache']
if (allowLoadFromCache && mc) {
try {
const json = await mc.get(cacheMemcachedKey)
if (json.value) {
const cacheFromFile = JSON.parse(json.value)
for (const kvp of cacheFromFile) {
if (kvp.k.startsWith('Slack-') && !kvp.v.hasOwnProperty('pubkey')) {
cache.clean()
break
}
cache.set(kvp.k, kvp.v)
}
robot.log.info(`Read Slack user cache from ${MEMCACHE_URL} (${cache.length} entries)`)
allowLoadFromCache = false
return
if (cache.length > 0) {
robot.log.info(`Read Slack user cache from Memcached (${cache.length} entries)`)
return
}
}
} catch (error) {
// Ignore
@ -97,8 +104,11 @@ async function internalBuild (robot, cache) {
const activeUsersList = usersList.members.filter(u => !u.deleted && !u.is_bot && u.id !== 'USLACKBOT')
let gitHubFieldId = null
let pubKeyFieldId = null
let usersMissingGitHubInfo = []
let usersMissingMainnetAddress = []
let usersContainingGitHubInfo = []
let usersWithMainnetPubkey = 0
let rateLimitWait = 10000
let profileFetchPreviousBatchCount = 3
let profileFetchBatchCount = 0
@ -107,17 +117,24 @@ async function internalBuild (robot, cache) {
try {
++profileFetchBatchCount
const { profile } = await slackWeb.users.profile.get({ user: user.id, include_labels: !gitHubFieldId })
const { profile } = await slackWeb.users.profile.get({ user: user.id, include_labels: !gitHubFieldId || !pubKeyFieldId })
const username = profile.display_name_normalized || profile.real_name_normalized
if (!gitHubFieldId) {
// Find the field ID for the field with the 'Github ID' label
gitHubFieldId = findProfileLabelId(profile, 'Github ID')
}
if (!pubKeyFieldId) {
// Find the field ID for the field with the 'Mainnet Address' label
pubKeyFieldId = findProfileLabelId(profile, 'Mainnet Address')
}
if (!gitHubFieldId) {
robot.log.warn(`No GitHub ID field found in @${username} (${user.id}) profile!`)
}
if (!pubKeyFieldId) {
robot.log.warn(`No Mainnet Address field found in @${username} (${user.id}) profile!`)
}
const gitHubUsername = gitHubFieldId && profile.fields && profile.fields[gitHubFieldId] ? profile.fields[gitHubFieldId].value.replace('https://github.com/', '') : null
if (gitHubUsername) {
@ -126,7 +143,14 @@ async function internalBuild (robot, cache) {
usersMissingGitHubInfo = usersMissingGitHubInfo.concat(username)
}
const data = { name: username, github_handle: gitHubUsername }
const pubkey = profile.fields && profile.fields[pubKeyFieldId] ? profile.fields[pubKeyFieldId].value : null
if (pubkey) {
++usersWithMainnetPubkey
} else {
usersMissingMainnetAddress = usersMissingMainnetAddress.concat(username)
}
const data = { name: username, github_handle: gitHubUsername, pubkey: pubkey }
robot.log.debug(`@${username} (${user.id}) -> ${JSON.stringify(data)}`)
@ -157,6 +181,10 @@ async function internalBuild (robot, cache) {
if (usersMissingGitHubInfo) {
robot.log.warn(`The following ${usersMissingGitHubInfo.length} Slack users have no GitHub info in their profiles: ${usersMissingGitHubInfo.map(s => '@' + s).join(', ')}`)
}
if (usersMissingMainnetAddress) {
robot.log.warn(`The following ${usersMissingMainnetAddress.length} Slack users have no Mainnet address in their profiles: ${usersMissingMainnetAddress.map(s => '@' + s).join(', ')}`)
}
robot.log.info(`${usersWithMainnetPubkey} users in ${activeUsersList.length} have a mainnet public key address configured`)
// Write cache out to JSON file for faster startup next time
const c = []
@ -166,7 +194,7 @@ async function internalBuild (robot, cache) {
if (mc) {
try {
await mc.set(cacheMemcachedKey, c, {})
await mc.set(cacheMemcachedKey, JSON.stringify(c, {}, 2), {})
robot.log.info(`Saved cache to Memcached`)
} catch (error) {
robot.log.warn(`Error while saving cache to Memcached: ${error}`)

100
lib/token-payments.js Normal file
View File

@ -0,0 +1,100 @@
// Description:
// Ethereum token payment logic
//
// Dependencies:
// ethers: "^3.0.8",
//
// Author:
// PombeirP
const ethers = require('ethers')
const { Wallet, Contract, providers } = ethers
const ERC20_ABI = [
{
'constant': false,
'inputs': [
{
'name': '_to',
'type': 'address'
},
{
'name': '_amount',
'type': 'uint256'
}
],
'name': 'transfer',
'outputs': [
{
'name': 'success',
'type': 'bool'
}
],
'payable': false,
'type': 'function'
}
]
module.exports = {
getContract: _getContract,
transfer: _transfer
}
let transaction = null
let hash = null
function _getContract (contractAddress, privateKey, networkId) {
const network = providers.Provider.getNetwork(networkId)
const wallet = new Wallet(privateKey, ethers.providers.getDefaultProvider(network))
async function customSendTransaction (tx) {
hash = await wallet.provider.sendTransaction(tx)
return hash
}
async function customSignTransaction (tx) {
transaction = tx
return wallet.sign(tx)
}
const customSigner = _getCustomSigner(wallet, customSignTransaction, customSendTransaction)
const contract = new Contract(contractAddress, ERC20_ABI, customSigner)
return { contract: contract, wallet: wallet }
}
async function _transfer (contract, wallet, pubkey, tokenAmount) {
const bigNumberAmount = ethers.utils.parseUnits(tokenAmount.toString(), 'ether')
await contract.transfer(pubkey, bigNumberAmount)
transaction.hash = hash
transaction.from = wallet.address
transaction.value = bigNumberAmount
return transaction
}
function _getCustomSigner (wallet, signTransaction, sendTransaction) {
const provider = wallet.provider
async function getAddress () { return wallet.address }
async function resolveName (addressOrName) { return provider.resolveName(addressOrName) }
async function estimateGas (transaction) { return provider.estimateGas(transaction) }
async function getGasPrice () { return process.env.DEBUG ? 5000000 : provider.getGasPrice() }
async function getTransactionCount (blockTag) { return provider.getTransactionCount(blockTag) }
const customSigner = {
getAddress: getAddress,
provider: {
resolveName: resolveName,
estimateGas: estimateGas,
getGasPrice: getGasPrice,
getTransactionCount: getTransactionCount,
sendTransaction: sendTransaction
},
sign: signTransaction
}
return customSigner
}

516
package-lock.json generated
View File

@ -15,6 +15,59 @@
"js-tokens": "3.0.2"
}
},
"@octokit/rest": {
"version": "15.2.0",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-15.2.0.tgz",
"integrity": "sha512-Dn56HRk3445JiZOHIKNWyLjfm3DEWEOfomcfON8Fm6mV+aFtzntuEmcnUIHHdIL7RPuMAFF3aE74CXMW+JpA2w==",
"requires": {
"before-after-hook": "1.1.0",
"btoa-lite": "1.0.0",
"debug": "3.1.0",
"http-proxy-agent": "2.1.0",
"https-proxy-agent": "2.2.1",
"lodash": "4.17.4",
"node-fetch": "2.1.2",
"url-template": "2.0.8"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"https-proxy-agent": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
"integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
"requires": {
"agent-base": "4.2.0",
"debug": "3.1.0"
}
}
}
},
"@octokit/webhooks": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-3.1.1.tgz",
"integrity": "sha512-VqpGDClqhLw5sKV+or5AnkPmUyur/Oktr9paqiR+yH69Tew9QA/vXHjKP4zctxj5PVAsOdTQFhSzP53qbNLVOg==",
"requires": {
"buffer-equal-constant-time": "1.0.1",
"debug": "3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"@slack/client": {
"version": "3.16.0",
"resolved": "https://registry.npmjs.org/@slack/client/-/client-3.16.0.tgz",
@ -241,7 +294,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.1.0.tgz",
"integrity": "sha512-KjZwU26uG3u6eZcfGbTULzFcsoz6pegNKtHPksZPOUsiKo5bUmiBPa38FuHZ/Eun+XYh/JCCkS9AS3Lu4McQOQ==",
"dev": true,
"requires": {
"acorn": "5.3.0"
}
@ -261,6 +313,11 @@
}
}
},
"aes-js": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz",
"integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0="
},
"agent-base": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz",
@ -432,8 +489,7 @@
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
"dev": true
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
},
"asynckit": {
"version": "0.4.0",
@ -450,6 +506,33 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
},
"axios": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
"requires": {
"follow-redirects": "1.4.1",
"is-buffer": "1.1.6"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"follow-redirects": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz",
"integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==",
"requires": {
"debug": "3.1.0"
}
}
}
},
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@ -715,6 +798,11 @@
"tweetnacl": "0.14.5"
}
},
"before-after-hook": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.1.0.tgz",
"integrity": "sha512-VOMDtYPwLbIncTxNoSzRyvaMxtXmLWLUqr8k5AfC1BzLk34HvBXaQX8snOwQZ4c0aX8aSERqtJSiI9/m2u5kuA=="
},
"bl": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz",
@ -728,6 +816,11 @@
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
},
"bn.js": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
"integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
},
"body-parser": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
@ -777,11 +870,15 @@
"repeat-element": "1.1.2"
}
},
"brorand": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
},
"browser-process-hrtime": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz",
"integrity": "sha1-Ql1opY00R/AqBKqJQYf86K+Le44=",
"dev": true
"integrity": "sha1-Ql1opY00R/AqBKqJQYf86K+Le44="
},
"browser-resolve": {
"version": "1.11.2",
@ -806,6 +903,11 @@
"node-int64": "0.4.0"
}
},
"btoa-lite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
"integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc="
},
"buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
@ -915,6 +1017,11 @@
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
},
"charenc": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
"integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
},
"ci-info": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.2.tgz",
@ -1116,6 +1223,11 @@
}
}
},
"crypt": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
"integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
},
"cryptiles": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
@ -1322,15 +1434,52 @@
"esutils": "2.0.2"
}
},
"dom-serializer": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
"integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
"requires": {
"domelementtype": "1.1.3",
"entities": "1.1.1"
},
"dependencies": {
"domelementtype": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
"integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs="
}
}
},
"domelementtype": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
"integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI="
},
"domexception": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
"integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
"dev": true,
"requires": {
"webidl-conversions": "4.0.2"
}
},
"domhandler": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz",
"integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=",
"requires": {
"domelementtype": "1.3.0"
}
},
"domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
"requires": {
"dom-serializer": "0.1.0",
"domelementtype": "1.3.0"
}
},
"dotenv": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz",
@ -1373,11 +1522,27 @@
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz",
"integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo="
},
"elliptic": {
"version": "6.3.3",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz",
"integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=",
"requires": {
"bn.js": "4.11.8",
"brorand": "1.1.0",
"hash.js": "1.1.3",
"inherits": "2.0.3"
}
},
"encodeurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
"integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="
},
"entities": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
"integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
},
"errno": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.6.tgz",
@ -1549,9 +1714,9 @@
}
},
"eslint": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.17.0.tgz",
"integrity": "sha512-AyxBUCANU/o/xC0ijGMKavo5Ls3oK6xykiOITlMdjFjrKOsqLrA7Nf5cnrDgcKrHzBirclAZt63XO7YZlVUPwA==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz",
"integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==",
"requires": {
"ajv": "5.5.2",
"babel-code-frame": "6.26.0",
@ -1562,13 +1727,13 @@
"doctrine": "2.1.0",
"eslint-scope": "3.7.1",
"eslint-visitor-keys": "1.0.0",
"espree": "3.5.2",
"espree": "3.5.4",
"esquery": "1.0.0",
"esutils": "2.0.2",
"file-entry-cache": "2.0.0",
"functional-red-black-tree": "1.0.1",
"glob": "7.1.2",
"globals": "11.3.0",
"globals": "11.4.0",
"ignore": "3.3.7",
"imurmurhash": "0.1.4",
"inquirer": "3.3.0",
@ -1584,6 +1749,7 @@
"path-is-inside": "1.0.2",
"pluralize": "7.0.0",
"progress": "2.0.0",
"regexpp": "1.0.1",
"require-uncached": "1.0.3",
"semver": "5.5.0",
"strip-ansi": "4.0.0",
@ -1592,6 +1758,11 @@
"text-table": "0.2.0"
},
"dependencies": {
"acorn": {
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz",
"integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ=="
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
@ -1600,6 +1771,15 @@
"ms": "2.0.0"
}
},
"espree": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
"integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
"requires": {
"acorn": "5.5.3",
"acorn-jsx": "3.0.1"
}
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
@ -1614,9 +1794,9 @@
}
},
"globals": {
"version": "11.3.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.3.0.tgz",
"integrity": "sha512-kkpcKNlmQan9Z5ZmgqKH/SMbSmjxQ7QjyNqfXVc8VJcoBV2UEg+sxQD15GQofGRh2hfpwUb70VC31DR7Rq5Hdw=="
"version": "11.4.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.4.0.tgz",
"integrity": "sha512-Dyzmifil8n/TmSqYDEXbm+C8yitzJQqQIlJQLNRMwa+BOUJpRC19pyVeN12JAjt61xonvXjtff+hJruTRXn5HA=="
}
}
},
@ -1814,6 +1994,7 @@
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz",
"integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==",
"dev": true,
"requires": {
"acorn": "5.3.0",
"acorn-jsx": "3.0.1"
@ -1856,6 +2037,35 @@
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"ethers": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/ethers/-/ethers-3.0.8.tgz",
"integrity": "sha512-SdPjKGd95/+oo/G+72dBUVO9A/z1LipcCr5keb8RFh8o7xUBsx+pwskUJKzup1E5oCqnrrYOt6g4ypx14/wUzA==",
"requires": {
"aes-js": "3.0.0",
"bn.js": "4.11.8",
"elliptic": "6.3.3",
"hash.js": "1.1.3",
"inherits": "2.0.1",
"js-sha3": "0.5.7",
"scrypt-js": "2.0.3",
"setimmediate": "1.0.4",
"uuid": "2.0.1",
"xmlhttprequest": "1.8.0"
},
"dependencies": {
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
},
"uuid": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz",
"integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w="
}
}
},
"event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
@ -3216,6 +3426,15 @@
"integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
"dev": true
},
"hash.js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
"integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
"requires": {
"inherits": "2.0.3",
"minimalistic-assert": "1.0.0"
}
},
"hashmap": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/hashmap/-/hashmap-2.3.0.tgz",
@ -3276,6 +3495,19 @@
"whatwg-encoding": "1.0.3"
}
},
"htmlparser2": {
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
"integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=",
"requires": {
"domelementtype": "1.3.0",
"domhandler": "2.4.1",
"domutils": "1.7.0",
"entities": "1.1.1",
"inherits": "2.0.3",
"readable-stream": "2.0.6"
}
},
"http-errors": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
@ -3299,6 +3531,25 @@
}
}
},
"http-proxy-agent": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
"integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
"requires": {
"agent-base": "4.2.0",
"debug": "3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@ -4209,6 +4460,11 @@
"merge-stream": "1.0.1"
}
},
"js-sha3": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz",
"integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc="
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
@ -4233,7 +4489,6 @@
"version": "11.6.2",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.6.2.tgz",
"integrity": "sha512-pAeZhpbSlUp5yQcS6cBQJwkbzmv4tWFaYxHbFVSxzXefqjvtRA851Z5N2P+TguVG9YeUDcgb8pdeVQRJh0XR3Q==",
"dev": true,
"requires": {
"abab": "1.0.4",
"acorn": "5.3.0",
@ -4266,14 +4521,12 @@
"ultron": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
"dev": true
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og=="
},
"ws": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-4.0.0.tgz",
"integrity": "sha512-QYslsH44bH8O7/W2815u5DpnCpXWpEK44FmaHffNwgJI4JMaSZONgPBTOfrxJ29mXKbXak+LsJ2uAkDTYq2ptQ==",
"dev": true,
"requires": {
"async-limiter": "1.0.0",
"safe-buffer": "5.1.1",
@ -4422,8 +4675,7 @@
"left-pad": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.2.0.tgz",
"integrity": "sha1-0wpzxrggHY99jnlWupYWCHpo4O4=",
"dev": true
"integrity": "sha1-0wpzxrggHY99jnlWupYWCHpo4O4="
},
"leven": {
"version": "2.1.0",
@ -4513,8 +4765,7 @@
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
"dev": true
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg="
},
"longest": {
"version": "1.0.1",
@ -4551,6 +4802,16 @@
"tmpl": "1.0.4"
}
},
"md5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
"integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=",
"requires": {
"charenc": "0.0.2",
"crypt": "0.0.2",
"is-buffer": "1.1.6"
}
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -4641,6 +4902,11 @@
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz",
"integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg="
},
"minimalistic-assert": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
"integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@ -4729,6 +4995,11 @@
"resolved": "https://registry.npmjs.org/netrc/-/netrc-0.1.4.tgz",
"integrity": "sha1-a+lPysqNd63gqWcNxGCRTJRHJEQ="
},
"node-fetch": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz",
"integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U="
},
"node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@ -4988,8 +5259,7 @@
"parse5": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
"integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==",
"dev": true
"integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
},
"parseurl": {
"version": "1.3.2",
@ -5167,8 +5437,7 @@
"pn": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
"dev": true
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA=="
},
"prelude-ls": {
"version": "1.1.2",
@ -6114,6 +6383,11 @@
"is-equal-shallow": "0.1.3"
}
},
"regexpp": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.0.1.tgz",
"integrity": "sha512-8Ph721maXiOYSLtaDGKVmDn5wdsNaF6Px85qFNeMPQq0r8K5Y10tgP6YuR65Ws35n4DvzFcCxEnRNBIXQunzLw=="
},
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@ -6177,7 +6451,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
"integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
"dev": true,
"requires": {
"lodash": "4.17.4"
}
@ -6186,7 +6459,6 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz",
"integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=",
"dev": true,
"requires": {
"request-promise-core": "1.1.1",
"stealthy-require": "1.1.1",
@ -6344,6 +6616,11 @@
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"scrypt-js": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz",
"integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q="
},
"semver": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
@ -6385,6 +6662,11 @@
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
},
"setimmediate": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz",
"integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48="
},
"setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
@ -6942,8 +7224,7 @@
"stealthy-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
"dev": true
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
},
"stream-consume": {
"version": "0.1.0",
@ -7137,7 +7418,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
"integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
"dev": true,
"requires": {
"punycode": "2.1.0"
},
@ -7145,8 +7425,7 @@
"punycode": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz",
"integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=",
"dev": true
"integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0="
}
}
},
@ -7221,6 +7500,97 @@
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
"integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po="
},
"unfurl": {
"version": "github:probot/unfurl#2931ec3b8c16717fba76555b2ffdd30e3d3126e0",
"requires": {
"ejs": "2.5.7",
"jsdom": "11.6.2",
"probot": "6.1.0",
"probot-attachments": "github:probot/attachments#c17f86a1bc9e3fc7c7dac1038d77f9ff0c7a5617",
"unfurl.js": "1.1.6"
},
"dependencies": {
"bottleneck": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.2.2.tgz",
"integrity": "sha512-2b24YzUWbbyTdUmCOvIZ8f7CTcVtRpYaFChq63RIZegxIrISTTHGtnK5GqxKS6h1lxUydUF/taMjQvn81gwKTQ=="
},
"dotenv": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz",
"integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow=="
},
"express-async-errors": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/express-async-errors/-/express-async-errors-2.1.1.tgz",
"integrity": "sha512-iI7wKVK1SvmmEe368hWPkX25nOh3gTcgIlTqlre/m7iduLiSa4vCsYhlVlTtBFYl+nkLHRm8jOI+2/8jUceJJQ==",
"requires": {
"express": "4.16.2"
}
},
"probot": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/probot/-/probot-6.1.0.tgz",
"integrity": "sha512-yQwAB+KdTJLyO8jyke0s7CdR/PHqj9ySWn+6f4hCGcr0fLeVOBiTjnXVCrnf6+QdYJfKtoqlTovxgfBLMF9Xew==",
"requires": {
"@octokit/rest": "15.2.0",
"@octokit/webhooks": "3.1.1",
"bottleneck": "2.2.2",
"bunyan": "1.8.12",
"bunyan-format": "0.2.1",
"bunyan-sentry-stream": "1.2.1",
"cache-manager": "2.6.0",
"commander": "2.13.0",
"dotenv": "5.0.1",
"express": "4.16.2",
"express-async-errors": "2.1.1",
"github-webhook-handler": "0.7.1",
"hbs": "4.0.1",
"js-yaml": "3.10.0",
"jsonwebtoken": "8.1.0",
"pkg-conf": "2.1.0",
"promise-events": "0.1.4",
"raven": "2.4.2",
"resolve": "1.5.0",
"semver": "5.5.0"
}
},
"probot-attachments": {
"version": "github:probot/attachments#c17f86a1bc9e3fc7c7dac1038d77f9ff0c7a5617"
},
"raven": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/raven/-/raven-2.4.2.tgz",
"integrity": "sha1-ASnircMHiGRv1TC2fQioziXU9tw=",
"requires": {
"cookie": "0.3.1",
"md5": "2.2.1",
"stack-trace": "0.0.9",
"timed-out": "4.0.1",
"uuid": "3.0.0"
}
}
}
},
"unfurl.js": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/unfurl.js/-/unfurl.js-1.1.6.tgz",
"integrity": "sha1-L2Ycvov50xtvbsIv4eGnFKJFxN8=",
"requires": {
"debug": "2.6.9",
"htmlparser2": "3.9.2",
"lodash": "4.17.4",
"pify": "2.3.0",
"request": "2.83.0"
},
"dependencies": {
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
}
}
},
"uniq": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
@ -7247,6 +7617,11 @@
"requires-port": "1.0.0"
}
},
"url-template": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
"integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE="
},
"user-home": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
@ -7309,7 +7684,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz",
"integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=",
"dev": true,
"requires": {
"browser-process-hrtime": "0.1.2"
}
@ -7363,7 +7737,6 @@
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.4.0.tgz",
"integrity": "sha512-Z0CVh/YE217Foyb488eo+iBv+r7eAQ0wSTyApi9n06jhcA3z6Nidg/EGvl0UFkg7kMdKxfBzzr+o9JF+cevgMg==",
"dev": true,
"requires": {
"lodash.sortby": "4.7.0",
"tr46": "1.0.1",
@ -7409,6 +7782,71 @@
}
}
},
"wip-bot": {
"version": "github:gr2m/wip-bot#0a9786db57d01f3c7c789fdf0d6f93ce11accbb1",
"requires": {
"probot": "6.1.0"
},
"dependencies": {
"bottleneck": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.2.2.tgz",
"integrity": "sha512-2b24YzUWbbyTdUmCOvIZ8f7CTcVtRpYaFChq63RIZegxIrISTTHGtnK5GqxKS6h1lxUydUF/taMjQvn81gwKTQ=="
},
"dotenv": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz",
"integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow=="
},
"express-async-errors": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/express-async-errors/-/express-async-errors-2.1.1.tgz",
"integrity": "sha512-iI7wKVK1SvmmEe368hWPkX25nOh3gTcgIlTqlre/m7iduLiSa4vCsYhlVlTtBFYl+nkLHRm8jOI+2/8jUceJJQ==",
"requires": {
"express": "4.16.2"
}
},
"probot": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/probot/-/probot-6.1.0.tgz",
"integrity": "sha512-yQwAB+KdTJLyO8jyke0s7CdR/PHqj9ySWn+6f4hCGcr0fLeVOBiTjnXVCrnf6+QdYJfKtoqlTovxgfBLMF9Xew==",
"requires": {
"@octokit/rest": "15.2.0",
"@octokit/webhooks": "3.1.1",
"bottleneck": "2.2.2",
"bunyan": "1.8.12",
"bunyan-format": "0.2.1",
"bunyan-sentry-stream": "1.2.1",
"cache-manager": "2.6.0",
"commander": "2.13.0",
"dotenv": "5.0.1",
"express": "4.16.2",
"express-async-errors": "2.1.1",
"github-webhook-handler": "0.7.1",
"hbs": "4.0.1",
"js-yaml": "3.10.0",
"jsonwebtoken": "8.1.0",
"pkg-conf": "2.1.0",
"promise-events": "0.1.4",
"raven": "2.4.2",
"resolve": "1.5.0",
"semver": "5.5.0"
}
},
"raven": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/raven/-/raven-2.4.2.tgz",
"integrity": "sha1-ASnircMHiGRv1TC2fQioziXU9tw=",
"requires": {
"cookie": "0.3.1",
"md5": "2.2.1",
"stack-trace": "0.0.9",
"timed-out": "4.0.1",
"uuid": "3.0.0"
}
}
}
},
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
@ -7494,8 +7932,12 @@
"xml-name-validator": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
"dev": true
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
},
"xmlhttprequest": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
"integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw="
},
"xtend": {
"version": "2.1.2",

View File

@ -11,7 +11,9 @@
},
"dependencies": {
"@slack/client": "^3.16.0",
"eslint": "^4.17.0",
"axios": "^0.18.0",
"eslint": "^4.19.1",
"ethers": "^3.0.8",
"hashmap": "^2.3.0",
"hashset": "0.0.6",
"jenkins": "^0.20.1",