Merge pull request #12 from PombeirP/bug/prevent-funding-won-bounties
Prevent bot from funding issues that contain 'Winner:' in comment.
This commit is contained in:
commit
d49e372fbd
|
@ -23,6 +23,21 @@
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Launch Program",
|
"name": "Launch Program",
|
||||||
"program": "${workspaceFolder}/index.js"
|
"program": "${workspaceFolder}/index.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Mocha Tests",
|
||||||
|
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
|
||||||
|
"args": [
|
||||||
|
"-u",
|
||||||
|
"tdd",
|
||||||
|
"--timeout",
|
||||||
|
"999999",
|
||||||
|
"--colors",
|
||||||
|
"${workspaceFolder}/test"
|
||||||
|
],
|
||||||
|
"internalConsoleOptions": "openOnSessionStart"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
16
bot/index.js
16
bot/index.js
|
@ -7,7 +7,8 @@ const config = require('../config')
|
||||||
const prices = require('./prices')
|
const prices = require('./prices')
|
||||||
const github = require('./github')
|
const github = require('./github')
|
||||||
|
|
||||||
const contractAddressString = 'Contract address:'
|
const winnerString = 'Winner:'
|
||||||
|
const contractAddressString = 'Contract address: '
|
||||||
|
|
||||||
const logger = winston.createLogger({
|
const logger = winston.createLogger({
|
||||||
level: 'info',
|
level: 'info',
|
||||||
|
@ -26,23 +27,31 @@ const logger = winston.createLogger({
|
||||||
})
|
})
|
||||||
|
|
||||||
function needsFunding (req) {
|
function needsFunding (req) {
|
||||||
|
if (req.headers['x-github-event'] !== 'issue_comment') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if (req.body.action !== 'edited' || !req.body.hasOwnProperty('comment')) {
|
if (req.body.action !== 'edited' || !req.body.hasOwnProperty('comment')) {
|
||||||
return false
|
return false
|
||||||
} else if (req.body.comment.user.login !== config.githubUsername) {
|
} else if (req.body.comment.user.login !== config.githubUsername) {
|
||||||
return false
|
return false
|
||||||
} else if (!hasAddress(req)) {
|
} else if (!hasAddress(req)) {
|
||||||
return false
|
return false
|
||||||
|
} else if (hasWinner(req)) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasWinner (req) {
|
||||||
|
return req.body.comment.body.search(winnerString) !== -1
|
||||||
|
}
|
||||||
function hasAddress (req) {
|
function hasAddress (req) {
|
||||||
return req.body.comment.body.search(contractAddressString) !== -1
|
return req.body.comment.body.search(contractAddressString) !== -1
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAddress (req) {
|
function getAddress (req) {
|
||||||
const commentBody = req.body.comment.body
|
const commentBody = req.body.comment.body
|
||||||
const index = commentBody.search(contractAddressString) + 19
|
const index = commentBody.search(contractAddressString) + contractAddressString.length
|
||||||
return commentBody.substring(index, index + 42)
|
return commentBody.substring(index, index + 42)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +94,7 @@ function info (msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function error (errorMessage) {
|
function error (errorMessage) {
|
||||||
logger.error(`[ERROR] Request processing failed: ${errorMessage}`)
|
logger.error(`Request processing failed: ${errorMessage}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendTransaction (to, amount, gasPrice) {
|
async function sendTransaction (to, amount, gasPrice) {
|
||||||
|
@ -169,6 +178,7 @@ module.exports = {
|
||||||
getAddress: getAddress,
|
getAddress: getAddress,
|
||||||
getAmount: getAmount,
|
getAmount: getAmount,
|
||||||
getGasPrice: prices.getGasPrice,
|
getGasPrice: prices.getGasPrice,
|
||||||
|
getTokenPrice: prices.getTokenPrice,
|
||||||
sendTransaction: sendTransaction,
|
sendTransaction: sendTransaction,
|
||||||
info: info,
|
info: info,
|
||||||
logTransaction: logTransaction,
|
logTransaction: logTransaction,
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
const chai = require('chai')
|
const chai = require('chai')
|
||||||
const expect = require('chai').expect
|
const { expect, assert, should } = chai
|
||||||
const assert = require('chai').assert
|
|
||||||
const should = require('chai').should
|
|
||||||
const config = require('../config')
|
const config = require('../config')
|
||||||
const bot = require('../bot')
|
const bot = require('../bot')
|
||||||
|
|
||||||
// status-open-bounty comment from https://github.com/status-im/autobounty/issues/1
|
// status-open-bounty comment from https://github.com/status-im/autobounty/issues/1
|
||||||
const sobComment = 'Current balance: 0.000000 ETH\nTokens: SNT: 2500.00 ANT: 25.00\nContract address: 0x3645fe42b1a744ad98cc032c22472388806f86f9\nNetwork: Mainnet\n To claim this bounty sign up at https://openbounty.status.im and make sure to update your Ethereum address in My Payment Details so that the bounty is correctly allocated.\nTo fund it, send ETH or ERC20/ERC223 tokens to the contract address.'
|
const sobComment = 'Current balance: 0.000000 ETH\nTokens: SNT: 2500.00 ANT: 25.00\nContract address: 0x3645fe42b1a744ad98cc032c22472388806f86f9\nNetwork: Mainnet\n To claim this bounty sign up at https://openbounty.status.im and make sure to update your Ethereum address in My Payment Details so that the bounty is correctly allocated.\nTo fund it, send ETH or ERC20/ERC223 tokens to the contract address.'
|
||||||
|
const sobCommentWithWinner = 'Balance: 0.000000 ETH\nContract address: [0xe02fbffb3422ddb8e2227c3495f710ba4f8e0c10](https://etherscan.io/address/0xe02fbffb3422ddb8e2227c3495f710ba4f8e0c10)\nNetwork: Mainnet\nStatus: Pending maintainer confirmation\nWinner: foopang\nVisit [https://openbounty.status.im](https://openbounty.status.im) to learn more.'
|
||||||
|
|
||||||
// Fake requests
|
// Fake requests
|
||||||
const requests = [
|
const requests = [
|
||||||
{ body: { action: 'created', comment: { body: 'Creating my first comment', user: { login: 'randomUser' } } } },
|
{ headers: {'x-github-event': 'issue_comment'}, body: { action: 'created', comment: { body: 'Creating my first comment', user: { login: 'randomUser' } } } },
|
||||||
{ body: { action: 'edited', comment: { body: 'Editing my comment', user: { login: 'RandomUser' } } } },
|
{ headers: {'x-github-event': 'issue_comment'}, body: { action: 'edited', comment: { body: 'Editing my comment', user: { login: 'RandomUser' } } } },
|
||||||
{ body: { action: 'edited', comment: { body: sobComment, user: { login: 'status-open-bounty' } } } },
|
{ headers: {'x-github-event': 'issue_comment'}, body: { action: 'created', comment: { body: sobComment, user: { login: 'status-open-bounty' } } } },
|
||||||
{ body: { action: 'created', issue: { labels: ['bounty', 'bounty-s'] }, comment: { body: sobComment, user: { login: 'status-open-bounty' } } } }
|
{ headers: {'x-github-event': 'issue_comment'}, body: { action: 'edited', repository: { owner: { login: 'status-im' }, name: 'autobounty' }, issue: { labels: ['bounty', 'bounty-xl'], number: 1 }, comment: { body: sobComment, user: { login: 'status-open-bounty' } } } },
|
||||||
|
{ headers: {'x-github-event': 'issue_comment'}, body: { action: 'edited', repository: { owner: { login: 'status-im' }, name: 'autobounty' }, issue: { labels: ['bounty', 'bounty-xl'], number: 1 }, comment: { body: sobCommentWithWinner, user: { login: 'status-open-bounty' } } } },
|
||||||
|
{ headers: {'x-github-event': 'labels'}, body: { action: 'created' } }
|
||||||
]
|
]
|
||||||
|
|
||||||
describe('Bot behavior', function () {
|
describe('Bot behavior', function () {
|
||||||
|
@ -30,6 +31,12 @@ describe('Bot behavior', function () {
|
||||||
it('should return true, it is all right and we should fund', function () {
|
it('should return true, it is all right and we should fund', function () {
|
||||||
assert.isTrue(bot.needsFunding(requests[3]))
|
assert.isTrue(bot.needsFunding(requests[3]))
|
||||||
})
|
})
|
||||||
|
it('should return false because issue already has a winner', function () {
|
||||||
|
assert.isFalse(bot.needsFunding(requests[4]))
|
||||||
|
})
|
||||||
|
it('should return false because the action is not related to issue comments', function () {
|
||||||
|
assert.isFalse(bot.needsFunding(requests[5]))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#getAddress', function () {
|
describe('#getAddress', function () {
|
||||||
|
@ -39,17 +46,29 @@ describe('Bot behavior', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#getAmount', function () {
|
describe('#getAmount', function () {
|
||||||
it('should return the amount for the issue given the price per hour and the bounty label for this issue', (done) => {
|
it('should return the amount for the issue given the price per hour and the bounty label for this issue', async () => {
|
||||||
bot.getAmount(requests[3])
|
try {
|
||||||
.then(function (amount) {
|
const amount = await bot.getAmount(requests[3])
|
||||||
const label = 'bounty-s'
|
const label = 'bounty-xl'
|
||||||
const tokenPrice = 0.35
|
const tokenPrice = await bot.getTokenPrice(config.token)
|
||||||
const priceInDollars = config.priceHour * config.bountyLabels[label]
|
const priceInDollars = config.priceHour * config.bountyLabels[label]
|
||||||
expected_amount = priceInDollars / tokenPrice
|
const expectedAmount = priceInDollars / tokenPrice
|
||||||
assert.equal(amount, expected_amount)
|
assert.equal(amount, expectedAmount)
|
||||||
done()
|
} catch (err) {
|
||||||
})
|
console.log(err)
|
||||||
.catch(() => { console.log('error'), done() })
|
}
|
||||||
|
})
|
||||||
|
it('should return the amount for the issue given the price per hour and the bounty label for this issue, even when label issue has different case', async () => {
|
||||||
|
try {
|
||||||
|
const amount = await bot.getAmount(requests[3])
|
||||||
|
const label = 'bounty-XL'
|
||||||
|
const tokenPrice = await bot.getTokenPrice(config.token)
|
||||||
|
const priceInDollars = config.priceHour * config.bountyLabels[label.toLowerCase()]
|
||||||
|
const expectedAmount = priceInDollars / tokenPrice
|
||||||
|
assert.equal(amount, expectedAmount)
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue