UNPKG

@josojo/realitycheck-contracts

Version:

RealityCheck demo

245 lines (221 loc) 7.03 kB
/* eslint no-console:0, no-confusing-arrow:0, no-unused-expressions:0, */ // `truffle test --silent` or `truffle test -s` to suppress logs const { silent, contract: contractFlag, gas: gasLog, gasTx, noevents, } = require('minimist')(process.argv.slice(2), { alias: { silent: 's', contract: 'c', gas: 'g', gasTx: 'gtx' } }) const log = silent ? () => {} : console.log.bind(console) const logger = (desc, fn) => log(`---- \n => ${desc} ${fn ? `|| - - - - - - - - - - - > ${fn}` : ''}`) const varLogger = (varName, varValue) => log(varName, '--->', varValue) /** * gasLogWrapper * @param {*} obj */ let totalGas = 0 const gasLogWrapper = (contracts) => { const handler = { // intercept all GETS to contracts get(target, propKey) { const origMethod = target[propKey] // if prompted prop !== a FUNCTION return prop if (typeof origMethod !== 'function' || !origMethod.sendTransaction) { return origMethod } // go one level deeper into actual METHOD - here access to (.call, .apply etc) return new Proxy(origMethod, { // called if @transaction function async apply(target, thisArg, argumentsList) { const result = await Reflect.apply(target, thisArg, argumentsList) // safeguards against constant functions and BigNumber returns if (typeof result !== 'object' || !result.receipt) return result const { receipt: { gasUsed } } = result // check that BOTH gas flags are used gasLog && gasTx && console.info(` ============================== TX name ==> ${propKey} TX gasCost ==> ${gasUsed} ============================== `) totalGas += gasUsed return result }, }) }, } return contracts.map(c => new Proxy(c, handler)) } /** * gasLogger * @param {contracts from testFunctions} contracts */ const gasLogger = () => { gasLog && console.info(` ******************************* TOTAL GAS Gas ==> ${totalGas} ******************************* `) // reset totalGas state totalGas = 0 } const assertRejects = async (q, msg) => { let res, catchFlag = false try { res = await q // checks if there was a Log event and its argument l contains string "R<number>" catchFlag = res.logs && !!res.logs.find(log => log.event === 'Log' && /\bR(\d+\.?)+/.test(log.args.l)) } catch (e) { catchFlag = true } finally { if (!catchFlag) { assert.fail(res, null, msg) } } } function getParamFromTxEvent(transaction, paramName, eventName) { assert.isObject(transaction) let logs = transaction.logs if(eventName != null) { logs = logs.filter((l) => l.event === eventName) } assert.equal(logs.length, 1, 'too many logs found!') let param = logs[0].args[paramName] return param } const blockNumber = () => web3.eth.blockNumber const timestamp = (block = 'latest') => web3.eth.getBlock(block).timestamp // keeps track of watched events let stopWatching = {} /** * eventWatcher - ...watches events * @param {contract} contract - dx, usually * @param {string} event - name of event on DutchExchange.sol to track * @param {Object} args? - not required, args to look for * @returns stopWatching function */ const eventWatcher = noevents ? () => {} : (contract, eventName, argum = {}) => { const eventFunc = contract[eventName] if (!eventFunc) { log(`No event ${eventName} available in the contract`) return null } const eventObject = eventFunc(argum).watch((err, result) => { const { event, args } = result if (err) return log(err) switch (event) { // const { args: { returned, tulipsIssued } } = result case 'LogNumber': return log(` LOG FOUND: ======================== ${args.l} ==> ${Number(args.n).toEth()} ======================== `) case 'ClaimBuyerFunds': return log(` LOG FOUND: ======================== RETURNED ==> ${Number(args.returned).toEth()} TULIPS ISSUED ==> ${Number(args.tulipsIssued).toEth()} ======================== `) default: return log(` LOG FOUND: ======================== Event Name: ${event} Args: ${JSON.stringify(args, undefined, 2)} ======================== `) } }) const contractEvents = stopWatching[contract.address] || (stopWatching[contract.address] = {}) if (contractEvents[eventName]) contractEvents[eventName]() const unwatch = contractEvents[eventName] = eventObject.stopWatching.bind(eventObject) return unwatch } /** * eventWatcher.stopWatching - stops watching an event * @param {contract} contract? - dx, ususally, * if none specified stops watching all contracts * @param {string} event? - name of event to stop watching, * if none specified stops watching all events for this contract */ eventWatcher.stopWatching = noevents ? () => {} : (contract, event) => { // if given particular event name, stop watching it if (contract && typeof contract === 'object' && contract.address) { const contractEvents = stopWatching[contract.address] if (!contractEvents) { log('contract was never watched') return } // if event isn't specified // stop watching all for this contract if (!event) { for (const ev of Object.keys(contractEvents)) { contractEvents[ev]() } delete stopWatching[contract.address] return } // stop watching a single event const unwatch = contractEvents[event] if (unwatch) { unwatch() delete stopWatching[event] } else { log(`${event} event was never watched`) } return } // otherwise stop watching all events const unwatchAll = () => { for (const key of Object.keys(stopWatching)) { const contractEvents = stopWatching[key] for (const ev of Object.keys(contractEvents)) { contractEvents[ev]() } } stopWatching = {} } // allow to be used as a direct input to mocha hooks (contract === done callback) if (typeof contract === 'function') { // don't wait if no events were watched if (!Object.keys(stopWatching).length) { contract() return } // unwatch after a delay as not all events a typically has been displayed // in case of after() hook setTimeout(() => { unwatchAll() contract() }, 500) } else unwatchAll() } const enableContractFlag = (...contractTests) => { const cTest = contractTests[contractFlag - 1] if (cTest) cTest() else contractTests.forEach(c => c()) } module.exports = { assertRejects, blockNumber, enableContractFlag, eventWatcher, gasLogger, gasLogWrapper, log, logger, timestamp, varLogger, getParamFromTxEvent, }