Commit 5029935a authored by aniket-engg's avatar aniket-engg Committed by Aniket

some modules in ts

parent 6a55230c
import { MISC } from './categories' import { default as category } from './categories'
const common = require('./staticAnalysisCommon') import { isSubScopeWithTopLevelUnAssignedBinOp, getUnAssignedTopLevelBinOps } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories' import { default as algorithm } from './algorithmCategories'
export class assignAndCompare { export class assignAndCompare {
warningNodes: any = [] warningNodes: any[] = []
name = 'Result not used: ' name = 'Result not used: '
description = 'The result of an operation was not used.' description = 'The result of an operation was not used.'
category = MISC category = category.MISC
algorithm = algorithm.EXACT algorithm = algorithm.EXACT
Module = this Module = this
visit (node) { visit (node) {
if (common.isSubScopeWithTopLevelUnAssignedBinOp(node)) common.getUnAssignedTopLevelBinOps(node).forEach((n) => this.warningNodes.push(n)) if (isSubScopeWithTopLevelUnAssignedBinOp(node)) getUnAssignedTopLevelBinOps(node).forEach((n) => this.warningNodes.push(n))
} }
report (compilationResults) { report (compilationResults) {
......
const name = 'Block.blockhash usage: ' import { default as category } from './categories'
const desc = 'Semantics maybe unclear' import { isBlockBlockHashAccess } from './staticAnalysisCommon'
const categories = require('./categories') import { default as algorithm } from './algorithmCategories'
const common = require('./staticAnalysisCommon')
const algo = require('./algorithmCategories')
function blockBlockhash () { export class blockBlockhash {
this.warningNodes = [] warningNodes: any[] = []
} name = 'Block.blockhash usage: '
desc = 'Semantics maybe unclear'
blockBlockhash.prototype.visit = function (node) { categories = category.SECURITY
if (common.isBlockBlockHashAccess(node)) this.warningNodes.push(node) algorithm = algorithm.EXACT
} Module = this
blockBlockhash.prototype.report = function (compilationResults) { visit (node) {
return this.warningNodes.map((item, i) => { if (isBlockBlockHashAccess(node)) this.warningNodes.push(node)
return { }
warning: `use of "block.blockhash": "block.blockhash" is used to access the last 256 block hashes.
A miner computes the block hash by "summing up" the information in the current block mined.
By "summing up" the information in a clever way a miner can try to influence the outcome of a transaction in the current block.
This is especially easy if there are only a small number of equally likely outcomes.`,
location: item.src
}
})
}
module.exports = { report (compilationResults) {
name: name, return this.warningNodes.map((item, i) => {
description: desc, return {
category: categories.SECURITY, warning: `use of "block.blockhash": "block.blockhash" is used to access the last 256 block hashes.
algorithm: algo.EXACT, A miner computes the block hash by "summing up" the information in the current block mined.
Module: blockBlockhash By "summing up" the information in a clever way a miner can try to influence the outcome of a transaction in the current block.
This is especially easy if there are only a small number of equally likely outcomes.`,
location: item.src
}
})
}
} }
const name = 'Block timestamp: ' import { default as category } from './categories'
const desc = 'Semantics maybe unclear' import { isNowAccess, isBlockTimestampAccess } from './staticAnalysisCommon'
const categories = require('./categories') import { default as algorithm } from './algorithmCategories'
const common = require('./staticAnalysisCommon')
const algo = require('./algorithmCategories')
function blockTimestamp () { export class blockTimestamp {
this.warningNowNodes = [] warningNowNodes: any[] = []
this.warningblockTimestampNodes = [] warningblockTimestampNodes: any[] = []
} name = 'Block timestamp: '
desc = 'Semantics maybe unclear'
categories = category.SECURITY
algorithm = algorithm.EXACT
Module = this
blockTimestamp.prototype.visit = function (node) { visit (node) {
if (common.isNowAccess(node)) this.warningNowNodes.push(node) if (isNowAccess(node)) this.warningNowNodes.push(node)
else if (common.isBlockTimestampAccess(node)) this.warningblockTimestampNodes.push(node) else if (isBlockTimestampAccess(node)) this.warningblockTimestampNodes.push(node)
} }
blockTimestamp.prototype.report = function (compilationResults) { report (compilationResults) {
return this.warningNowNodes.map((item, i) => { return this.warningNowNodes.map((item, i) => {
return { return {
warning: `use of "now": "now" does not mean current time. Now is an alias for block.timestamp. warning: `use of "now": "now" does not mean current time. Now is an alias for block.timestamp.
Block.timestamp can be influenced by miners to a certain degree, be careful.`, Block.timestamp can be influenced by miners to a certain degree, be careful.`,
location: item.src, location: item.src,
more: 'http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html#are-timestamps-now-block-timestamp-reliable' more: 'http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html#are-timestamps-now-block-timestamp-reliable'
} }
}).concat(this.warningblockTimestampNodes.map((item, i) => { }).concat(this.warningblockTimestampNodes.map((item, i) => {
return { return {
warning: `use of "block.timestamp": "block.timestamp" can be influenced by miners to a certain degree. warning: `use of "block.timestamp": "block.timestamp" can be influenced by miners to a certain degree.
That means that a miner can "choose" the block.timestamp, to a certain degree, to change the outcome of a transaction in the mined block.`, That means that a miner can "choose" the block.timestamp, to a certain degree, to change the outcome of a transaction in the mined block.`,
location: item.src, location: item.src,
more: 'http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html#are-timestamps-now-block-timestamp-reliable' more: 'http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html#are-timestamps-now-block-timestamp-reliable'
} }
})) }))
}
} }
module.exports = {
name: name,
description: desc,
category: categories.SECURITY,
algorithm: algo.EXACT,
Module: blockTimestamp
}
module.exports = { export default {
SECURITY: {displayName: 'Security', id: 'SEC'}, SECURITY: {displayName: 'Security', id: 'SEC'},
GAS: {displayName: 'Gas & Economy', id: 'GAS'}, GAS: {displayName: 'Gas & Economy', id: 'GAS'},
MISC: {displayName: 'Miscellaneous', id: 'MISC'}, MISC: {displayName: 'Miscellaneous', id: 'MISC'},
......
const name = 'Delete on dynamic Array: '
const desc = 'Use require and appropriately'
const categories = require('./categories')
const common = require('./staticAnalysisCommon')
const algo = require('./algorithmCategories')
function deleteDynamicArrays () {
this.rel = []
}
deleteDynamicArrays.prototype.visit = function (node) {
if (common.isDeleteOfDynamicArray(node)) this.rel.push(node)
}
deleteDynamicArrays.prototype.report = function (compilationResults) {
return this.rel.map((node) => {
return {
warning: 'The “delete” operation when applied to a dynamically sized array in Solidity generates code to delete each of the elements contained. If the array is large, this operation can surpass the block gas limit and raise an OOG exception. Also nested dynamically sized objects can produce the same results.',
location: node.src,
more: 'http://solidity.readthedocs.io/en/latest/types.html?highlight=array#delete'
}
})
}
module.exports = {
name: name,
description: desc,
category: categories.GAS,
algorithm: algo.EXACT,
Module: deleteDynamicArrays
}
import { default as category } from './categories'
import { isDeleteOfDynamicArray } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
export class deleteDynamicArrays {
rel: any = []
name = 'Delete on dynamic Array: '
desc = 'Use require and appropriately'
categories = category.GAS
algorithm = algorithm.EXACT
Module = this
visit (node) {
if (isDeleteOfDynamicArray(node)) this.rel.push(node)
}
report (compilationResults) {
return this.rel.map((node) => {
return {
warning: 'The “delete” operation when applied to a dynamically sized array in Solidity generates code to delete each of the elements contained. If the array is large, this operation can surpass the block gas limit and raise an OOG exception. Also nested dynamically sized objects can produce the same results.',
location: node.src,
more: 'http://solidity.readthedocs.io/en/latest/types.html?highlight=array#delete'
}
})
}
}
const name = 'Delete from dynamic Array: '
const desc = 'Using delete on an array leaves a gap'
const categories = require('./categories')
const common = require('./staticAnalysisCommon')
function deleteFromDynamicArray () {
this.relevantNodes = []
}
deleteFromDynamicArray.prototype.visit = function (node) {
if (common.isDeleteFromDynamicArray(node) && !common.isMappingIndexAccess(node.children[0])) this.relevantNodes.push(node)
}
deleteFromDynamicArray.prototype.report = function (compilationResults) {
return this.relevantNodes.map((node) => {
return {
warning: 'Using delete on an array leaves a gap. The length of the array remains the same. If you want to remove the empty position you need to shift items manually and update the length property.\n',
location: node.src,
more: 'https://github.com/miguelmota/solidity-idiosyncrasies'
}
})
}
module.exports = {
name: name,
description: desc,
category: categories.MISC,
Module: deleteFromDynamicArray
}
import { default as category } from './categories'
import { isDeleteFromDynamicArray, isMappingIndexAccess } from './staticAnalysisCommon'
export class deleteFromDynamicArray {
relevantNodes: any[] = []
name = 'Delete from dynamic Array: '
desc = 'Using delete on an array leaves a gap'
categories = category.MISC
Module = this
visit (node) {
if (isDeleteFromDynamicArray(node) && !isMappingIndexAccess(node.children[0])) this.relevantNodes.push(node)
}
report (compilationResults) {
return this.relevantNodes.map((node) => {
return {
warning: 'Using delete on an array leaves a gap. The length of the array remains the same. If you want to remove the empty position you need to shift items manually and update the length property.\n',
location: node.src,
more: 'https://github.com/miguelmota/solidity-idiosyncrasies'
}
})
}
}
const name = 'Ether transfer in a loop: ' import { default as category } from './categories'
const desc = 'Avoid transferring Ether to multiple addresses in a loop' import { isLoop, isBlock, getLoopBlockStartIndex, isExpressionStatement, isTransfer } from './staticAnalysisCommon'
const categories = require('./categories')
const common = require('./staticAnalysisCommon')
function etherTransferInLoop () { export class etherTransferInLoop {
this.relevantNodes = [] relevantNodes: any[] = []
} name = 'Ether transfer in a loop: '
desc = 'Avoid transferring Ether to multiple addresses in a loop'
etherTransferInLoop.prototype.visit = function (node) { category = category.GAS
if (common.isLoop(node)) { Module = this
let transferNodes = []
const loopBlockStartIndex = common.getLoopBlockStartIndex(node) visit (node) {
if (common.isBlock(node.children[loopBlockStartIndex])) { if (isLoop(node)) {
transferNodes = node.children[loopBlockStartIndex].children let transferNodes = []
.filter(child => (common.isExpressionStatement(child) && const loopBlockStartIndex = getLoopBlockStartIndex(node)
child.children[0].name === 'FunctionCall' && if (isBlock(node.children[loopBlockStartIndex])) {
common.isTransfer(child.children[0].children[0]))) transferNodes = node.children[loopBlockStartIndex].children
if (transferNodes.length > 0) { .filter(child => (isExpressionStatement(child) &&
this.relevantNodes.push(...transferNodes) child.children[0].name === 'FunctionCall' &&
isTransfer(child.children[0].children[0])))
if (transferNodes.length > 0) {
this.relevantNodes.push(...transferNodes)
}
} }
} }
} }
}
etherTransferInLoop.prototype.report = function (compilationResults) {
return this.relevantNodes.map((node) => {
return {
warning: 'Ether payout should not be done in a loop: Due to the block gas limit, transactions can only consume a certain amount of gas. The number of iterations in a loop can grow beyond the block gas limit which can cause the complete contract to be stalled at a certain point. If required then make sure that number of iterations are low and you trust each address involved.',
location: node.src,
more: 'https://solidity.readthedocs.io/en/latest/security-considerations.html#gas-limit-and-loops'
}
})
}
module.exports = { report (compilationResults) {
name: name, return this.relevantNodes.map((node) => {
description: desc, return {
category: categories.GAS, warning: 'Ether payout should not be done in a loop: Due to the block gas limit, transactions can only consume a certain amount of gas. The number of iterations in a loop can grow beyond the block gas limit which can cause the complete contract to be stalled at a certain point. If required then make sure that number of iterations are low and you trust each address involved.',
Module: etherTransferInLoop location: node.src,
more: 'https://solidity.readthedocs.io/en/latest/security-considerations.html#gas-limit-and-loops'
}
})
}
} }
const name = 'For loop iterates over dynamic array: ' import { default as category } from './categories'
const desc = 'The number of \'for\' loop iterations depends on dynamic array\'s size'
const categories = require('./categories')
const { isForLoop, isDynamicArrayLengthAccess, isBinaryOperation } = require('./staticAnalysisCommon') const { isForLoop, isDynamicArrayLengthAccess, isBinaryOperation } = require('./staticAnalysisCommon')
function forLoopIteratesOverDynamicArray () { export class forLoopIteratesOverDynamicArray {
this.relevantNodes = [] relevantNodes: any[] = []
} name = 'For loop iterates over dynamic array: '
desc = 'The number of \'for\' loop iterations depends on dynamic array\'s size'
categories = category.GAS
Module = this
forLoopIteratesOverDynamicArray.prototype.visit = function (node) { visit (node) {
if (isForLoop(node)) { if (isForLoop(node)) {
// Access 'condition' node of 'for' loop statement // Access 'condition' node of 'for' loop statement
const forLoopConditionNode = node.children[1] const forLoopConditionNode = node.children[1]
// Access right side of condition as its children // Access right side of condition as its children
const conditionChildrenNode = forLoopConditionNode.children[1] const conditionChildrenNode = forLoopConditionNode.children[1]
// Check if it is a binary operation. if yes, check if its children node access length of dynamic array // Check if it is a binary operation. if yes, check if its children node access length of dynamic array
if (isBinaryOperation(conditionChildrenNode) && isDynamicArrayLengthAccess(conditionChildrenNode.children[0])) { if (isBinaryOperation(conditionChildrenNode) && isDynamicArrayLengthAccess(conditionChildrenNode.children[0])) {
this.relevantNodes.push(node) this.relevantNodes.push(node)
} else if (isDynamicArrayLengthAccess(conditionChildrenNode)) { // else check if condition node itself access length of dynamic array } else if (isDynamicArrayLengthAccess(conditionChildrenNode)) { // else check if condition node itself access length of dynamic array
this.relevantNodes.push(node) this.relevantNodes.push(node)
}
} }
} }
}
forLoopIteratesOverDynamicArray.prototype.report = function (compilationResults) {
return this.relevantNodes.map((node) => {
return {
warning: 'Loops that do not have a fixed number of iterations, for example, loops that depend on storage values, have to be used carefully: Due to the block gas limit, transactions can only consume a certain amount of gas. The number of iterations in a loop can grow beyond the block gas limit which can cause the complete contract to be stalled at a certain point. Additionally, using unbounded loops incurs in a lot of avoidable gas costs. Carefully test how many items at maximum you can pass to such functions to make it successful.',
location: node.src,
more: 'http://solidity.readthedocs.io/en/v0.4.24/security-considerations.html#gas-limit-and-loops'
}
})
}
module.exports = { report (compilationResults) {
name: name, return this.relevantNodes.map((node) => {
description: desc, return {
category: categories.GAS, warning: 'Loops that do not have a fixed number of iterations, for example, loops that depend on storage values, have to be used carefully: Due to the block gas limit, transactions can only consume a certain amount of gas. The number of iterations in a loop can grow beyond the block gas limit which can cause the complete contract to be stalled at a certain point. Additionally, using unbounded loops incurs in a lot of avoidable gas costs. Carefully test how many items at maximum you can pass to such functions to make it successful.',
Module: forLoopIteratesOverDynamicArray location: node.src,
more: 'http://solidity.readthedocs.io/en/v0.4.24/security-considerations.html#gas-limit-and-loops'
}
})
}
} }
const name = 'Guard Conditions: '
const desc = 'Use require and appropriately'
const categories = require('./categories')
const common = require('./staticAnalysisCommon')
const algo = require('./algorithmCategories')
function guardConditions () {
this.guards = []
}
guardConditions.prototype.visit = function (node) {
if (common.isRequireCall(node) || common.isAssertCall(node)) this.guards.push(node)
}
guardConditions.prototype.report = function (compilationResults) {
if (this.guards.length > 0) {
return [{
warning: 'Use assert(x) if you never ever want x to be false, not in any circumstance (apart from a bug in your code). Use require(x) if x can be false, due to e.g. invalid input or a failing external component.',
more: 'http://solidity.readthedocs.io/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions'
}]
}
return []
}
module.exports = {
name: name,
description: desc,
category: categories.MISC,
algorithm: algo.EXACT,
Module: guardConditions
}
import { default as category } from './categories'
import { isRequireCall, isAssertCall } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
export class guardConditions {
guards: any[] = []
name = 'Guard Conditions: '
desc = 'Use require and appropriately'
categories = category.MISC
algorithm = algorithm.EXACT
Module = this
visit (node) {
if (isRequireCall(node) || isAssertCall(node)) this.guards.push(node)
}
report (compilationResults) {
if (this.guards.length > 0) {
return [{
warning: 'Use assert(x) if you never ever want x to be false, not in any circumstance (apart from a bug in your code). Use require(x) if x can be false, due to e.g. invalid input or a failing external component.',
more: 'http://solidity.readthedocs.io/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions'
}]
}
return []
}
}
const name = 'Inline assembly: '
const desc = 'Use of Inline Assembly'
const categories = require('./categories')
const common = require('./staticAnalysisCommon')
const algo = require('./algorithmCategories')
function inlineAssembly () {
this.inlineAssNodes = []
}
inlineAssembly.prototype.visit = function (node) {
if (common.isInlineAssembly(node)) this.inlineAssNodes.push(node)
}
inlineAssembly.prototype.report = function (compilationResults) {
return this.inlineAssNodes.map((node) => {
return {
warning: `CAUTION: The Contract uses inline assembly, this is only advised in rare cases.
Additionally static analysis modules do not parse inline Assembly, this can lead to wrong analysis results.`,
location: node.src,
more: 'http://solidity.readthedocs.io/en/develop/assembly.html#solidity-assembly'
}
})
}
module.exports = {
name: name,
description: desc,
category: categories.SECURITY,
algorithm: algo.EXACT,
Module: inlineAssembly
}
import { default as category } from './categories'
import { isInlineAssembly } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
export class inlineAssembly {
inlineAssNodes: any[] = []
name = 'Inline assembly: '
desc = 'Use of Inline Assembly'
categories = category.SECURITY
algorithm = algorithm.EXACT
Module = this
visit (node) {
if (isInlineAssembly(node)) this.inlineAssNodes.push(node)
}
report (compilationResults) {
return this.inlineAssNodes.map((node) => {
return {
warning: `CAUTION: The Contract uses inline assembly, this is only advised in rare cases.
Additionally static analysis modules do not parse inline Assembly, this can lead to wrong analysis results.`,
location: node.src,
more: 'http://solidity.readthedocs.io/en/develop/assembly.html#solidity-assembly'
}
})
}
}
const name = 'Data Trucated: '
const desc = 'Division on int/uint values truncates the result.'
const categories = require('./categories')
const common = require('./staticAnalysisCommon')
const algo = require('./algorithmCategories')
function intDivitionTruncate () {
this.warningNodes = []
}
intDivitionTruncate.prototype.visit = function (node) {
if (common.isIntDivision(node)) this.warningNodes.push(node)
}
intDivitionTruncate.prototype.report = function (compilationResults) {
return this.warningNodes.map((item, i) => {
return {
warning: 'Division of integer values yields an integer value again. That means e.g. 10 / 100 = 0 instead of 0.1 since the result is an integer again. This does not hold for division of (only) literal values since those yield rational constants.',
location: item.src
}
})
}
module.exports = {
name: name,
description: desc,
category: categories.MISC,
algorithm: algo.EXACT,
Module: intDivitionTruncate
}
import { default as category } from './categories'
import { isIntDivision } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
export class intDivitionTruncate {
warningNodes: any[] = []
name = 'Data Trucated: '
desc = 'Division on int/uint values truncates the result.'
categories = category.MISC
algorithm = algorithm.EXACT
Module = this
visit (node) {
if (isIntDivision(node)) this.warningNodes.push(node)
}
report (compilationResults) {
return this.warningNodes.map((item, i) => {
return {
warning: 'Division of integer values yields an integer value again. That means e.g. 10 / 100 = 0 instead of 0.1 since the result is an integer again. This does not hold for division of (only) literal values since those yield rational constants.',
location: item.src
}
})
}
}
const name = 'Low level calls: ' import { default as category } from './categories'
const desc = 'Semantics maybe unclear' import { isLowLevelCallInst, isLowLevelCallInst050, isLowLevelCallcodeInst, isLowLevelDelegatecallInst,
const categories = require('./categories') isLowLevelSendInst, isLowLevelSendInst050, isLLDelegatecallInst050, lowLevelCallTypes } from './staticAnalysisCommon'
const common = require('./staticAnalysisCommon') import { default as algorithm } from './algorithmCategories'
const algo = require('./algorithmCategories')
function lowLevelCalls () { export class lowLevelCalls {
this.llcNodes = [] llcNodes: any[] = []
} name = 'Low level calls: '
desc = 'Semantics maybe unclear'
lowLevelCalls.prototype.visit = function (node) { categories = category.SECURITY
if (common.isLowLevelCallInst(node)) { algorithm = algorithm.EXACT
this.llcNodes.push({node: node, type: common.lowLevelCallTypes.CALL}) Module = this
} else if (common.isLowLevelCallInst050(node)) {
this.llcNodes.push({node: node, type: common.lowLevelCallTypes.CALL})
} else if (common.isLowLevelCallcodeInst(node)) {
this.llcNodes.push({node: node, type: common.lowLevelCallTypes.CALLCODE})
} else if (common.isLowLevelDelegatecallInst(node)) {
this.llcNodes.push({node: node, type: common.lowLevelCallTypes.DELEGATECALL})
} else if (common.isLowLevelSendInst(node)) {
this.llcNodes.push({node: node, type: common.lowLevelCallTypes.SEND})
} else if (common.isLowLevelSendInst050(node)) {
this.llcNodes.push({node: node, type: common.lowLevelCallTypes.SEND})
} else if (common.isLLDelegatecallInst050(node)) {
this.llcNodes.push({node: node, type: common.lowLevelCallTypes.DELEGATECALL})
}
}
lowLevelCalls.prototype.report = function (compilationResults) { visit (node) {
return this.llcNodes.map((item, i) => { if (isLowLevelCallInst(node)) {
let text = '' this.llcNodes.push({node: node, type: lowLevelCallTypes.CALL})
let morehref = null } else if (isLowLevelCallInst050(node)) {
switch (item.type) { this.llcNodes.push({node: node, type: lowLevelCallTypes.CALL})
case common.lowLevelCallTypes.CALL: } else if (isLowLevelCallcodeInst(node)) {
text = `use of "call": the use of low level "call" should be avoided whenever possible. this.llcNodes.push({node: node, type: lowLevelCallTypes.CALLCODE})
It can lead to unexpected behavior if return value is not handled properly. } else if (isLowLevelDelegatecallInst(node)) {
Please use Direct Calls via specifying the called contract's interface.` this.llcNodes.push({node: node, type: lowLevelCallTypes.DELEGATECALL})
morehref = 'http://solidity.readthedocs.io/en/develop/control-structures.html?#external-function-calls' } else if (isLowLevelSendInst(node)) {
// http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html?#why-is-the-low-level-function-call-less-favorable-than-instantiating-a-contract-with-a-variable-contractb-b-and-executing-its-functions-b-dosomething this.llcNodes.push({node: node, type: lowLevelCallTypes.SEND})
break } else if (isLowLevelSendInst050(node)) {
case common.lowLevelCallTypes.CALLCODE: this.llcNodes.push({node: node, type: lowLevelCallTypes.SEND})
text = `use of "callcode": the use of low level "callcode" should be avoided whenever possible. } else if (isLLDelegatecallInst050(node)) {
External code that is called can change the state of the calling contract and send ether from the caller's balance. this.llcNodes.push({node: node, type: lowLevelCallTypes.DELEGATECALL})
If this is wanted behaviour use the Solidity library feature if possible.`
morehref = 'http://solidity.readthedocs.io/en/develop/contracts.html#libraries'
break
case common.lowLevelCallTypes.DELEGATECALL:
text = `use of "delegatecall": the use of low level "delegatecall" should be avoided whenever possible.
External code that is called can change the state of the calling contract and send ether from the caller's balance.
If this is wanted behaviour use the Solidity library feature if possible.`
morehref = 'http://solidity.readthedocs.io/en/develop/contracts.html#libraries'
break
case common.lowLevelCallTypes.SEND:
text = `use of "send": "send" does not throw an exception when not successful, make sure you deal with the failure case accordingly.
Use "transfer" whenever failure of the ether transfer should rollback the whole transaction.
Note: if you "send/transfer" ether to a contract the fallback function is called, the callees fallback function is very limited due to the limited amount of gas provided by "send/transfer".
No state changes are possible but the callee can log the event or revert the transfer. "send/transfer" is syntactic sugar for a "call" to the fallback function with 2300 gas and a specified ether value.`
morehref = 'http://solidity.readthedocs.io/en/develop/security-considerations.html#sending-and-receiving-ether'
break
} }
return { warning: text, more: morehref, location: item.node.src } }
})
}
module.exports = { report (compilationResults) {
name: name, return this.llcNodes.map((item, i) => {
description: desc, let text = ''
category: categories.SECURITY, let morehref: any = null
algorithm: algo.EXACT, switch (item.type) {
Module: lowLevelCalls case lowLevelCallTypes.CALL:
text = `use of "call": the use of low level "call" should be avoided whenever possible.
It can lead to unexpected behavior if return value is not handled properly.
Please use Direct Calls via specifying the called contract's interface.`
morehref = 'http://solidity.readthedocs.io/en/develop/control-structures.html?#external-function-calls'
// http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html?#why-is-the-low-level-function-call-less-favorable-than-instantiating-a-contract-with-a-variable-contractb-b-and-executing-its-functions-b-dosomething
break
case lowLevelCallTypes.CALLCODE:
text = `use of "callcode": the use of low level "callcode" should be avoided whenever possible.
External code that is called can change the state of the calling contract and send ether from the caller's balance.
If this is wanted behaviour use the Solidity library feature if possible.`
morehref = 'http://solidity.readthedocs.io/en/develop/contracts.html#libraries'
break
case lowLevelCallTypes.DELEGATECALL:
text = `use of "delegatecall": the use of low level "delegatecall" should be avoided whenever possible.
External code that is called can change the state of the calling contract and send ether from the caller's balance.
If this is wanted behaviour use the Solidity library feature if possible.`
morehref = 'http://solidity.readthedocs.io/en/develop/contracts.html#libraries'
break
case lowLevelCallTypes.SEND:
text = `use of "send": "send" does not throw an exception when not successful, make sure you deal with the failure case accordingly.
Use "transfer" whenever failure of the ether transfer should rollback the whole transaction.
Note: if you "send/transfer" ether to a contract the fallback function is called, the callees fallback function is very limited due to the limited amount of gas provided by "send/transfer".
No state changes are possible but the callee can log the event or revert the transfer. "send/transfer" is syntactic sugar for a "call" to the fallback function with 2300 gas and a specified ether value.`
morehref = 'http://solidity.readthedocs.io/en/develop/security-considerations.html#sending-and-receiving-ether'
break
}
return { warning: text, more: morehref, location: item.node.src }
})
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment