-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement evaluation from external registry
- Loading branch information
Showing
4 changed files
with
201 additions
and
2 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
#!/usr/bin/env node | ||
|
||
const yargs = require('yargs') | ||
const fs = require('fs') | ||
const path = require('path') | ||
const Eth = require('web3-eth') | ||
|
||
const { evaluateWithRegistry } = require('../dist') | ||
|
||
const NETWORKS = { | ||
rinkeby: 'https://rinkeby.eth.aragon.network', | ||
mainnet: 'https://mainnet.eth.aragon.network', | ||
} | ||
|
||
const exec = async (argv) => { | ||
const { network } = argv | ||
const [ txHash ] = argv._ | ||
|
||
const rpc = NETWORKS[network] | ||
|
||
if (!rpc) { | ||
throw new Error(`Unsupported network '${network}'`) | ||
} | ||
|
||
const eth = new Eth(rpc) | ||
|
||
console.log(`Fetching ${network} for ${txHash}`) | ||
const { | ||
to, | ||
from, | ||
blockNumber, | ||
input: data | ||
} = await eth.getTransaction(txHash) | ||
|
||
const description = await evaluateWithRegistry({ transaction: { to, data }}) | ||
|
||
console.log(`Transaction from ${from} to ${to} in block ${blockNumber}:\n`) | ||
console.log(description ? `🔥 ${description} 🔥` : 'Unknown 😢') | ||
} | ||
|
||
exec( | ||
yargs | ||
.usage('Usage: $0 [txid]') | ||
.option('network', { | ||
alias: 'n', | ||
default: 'mainnet', | ||
describe: 'Output path to radspec db file', | ||
type: 'string', | ||
}) | ||
.argv | ||
) | ||
.catch(err => { | ||
console.error(err) | ||
process.exit(1) | ||
}) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
const fs = require('fs') | ||
const { promisify } = require('util') | ||
const readFile = promisify(fs.readFile) | ||
|
||
const modifiesStateAndIsPublic = declaration => | ||
!declaration.match(/\b(internal|private|view|pure|constant)\b/) | ||
|
||
const typeOrAddress = type => { | ||
const types = ['address', 'byte', 'uint', 'int', 'bool', 'string'] | ||
|
||
// check if the type starts with any of the above types, otherwise it is probably | ||
// a typed contract, so we need to return address for the signature | ||
return types.filter(t => type.indexOf(t) === 0).length > 0 ? type : 'address' | ||
} | ||
|
||
// extracts function signature from function declaration | ||
const getSignature = declaration => { | ||
let [name, params] = declaration.match(/function ([^]*?)\)/)[1].split('(') | ||
|
||
if (!name) { | ||
return 'fallback' | ||
} | ||
|
||
let argumentNames = [] | ||
|
||
if (params) { | ||
// Has parameters | ||
const inputs = params | ||
.replace(/\n/gm, '') | ||
.replace(/\t/gm, '') | ||
.split(',') | ||
|
||
params = inputs | ||
.map(param => param.split(' ').filter(s => s.length > 0)[0]) | ||
.map(type => typeOrAddress(type)) | ||
.join(',') | ||
|
||
argumentNames = inputs.map(param => param.split(' ').filter(s => s.length > 0)[1] || '') | ||
} | ||
|
||
return { sig: `${name}(${params})`, argumentNames } | ||
} | ||
|
||
const getNotice = declaration => { | ||
// capture from @notice to either next '* @' or end of comment '*/' | ||
const notices = declaration.match(/(@notice)([^]*?)(\* @|\*\/)/m) | ||
if (!notices || notices.length === 0) return null | ||
|
||
return notices[0] | ||
.replace('*/', '') | ||
.replace('* @', '') | ||
.replace('@notice ', '') | ||
.replace(/\n/gm, '') | ||
.replace(/\t/gm, '') | ||
.split(' ') | ||
.filter(x => x.length > 0) | ||
.join(' ') | ||
} | ||
|
||
// extracts required role from function declaration | ||
const getRoles = declaration => { | ||
const auths = declaration.match(/auth.?\(([^]*?)\)/gm) | ||
if (!auths) return [] | ||
|
||
return auths.map( | ||
authStatement => | ||
authStatement | ||
.split('(')[1] | ||
.split(',')[0] | ||
.split(')')[0] | ||
) | ||
} | ||
|
||
// Takes the path to a solidity file and extracts public function signatures, | ||
// its auth role if any and its notice statement | ||
module.exports = async sourceCodePath => { | ||
const sourceCode = await readFile(sourceCodePath, 'utf8') | ||
|
||
// everything between every 'function' and '{' and its @notice | ||
const funcDecs = sourceCode.match(/(@notice|^\s*function)(?:[^]*?){/gm) | ||
|
||
if (!funcDecs) return [] | ||
|
||
return funcDecs | ||
.filter(dec => modifiesStateAndIsPublic(dec)) | ||
.map(dec => ({ | ||
roles: getRoles(dec), | ||
notice: getNotice(dec), | ||
...getSignature(dec), | ||
})) | ||
} |
This file contains 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