version specific doc link

pull/10/head
aniket-engg 5 years ago committed by Aniket
parent 5df0146901
commit af3280d765
  1. 7
      remix-analyzer/src/solidity-analyzer/modules/abstractAstView.ts
  2. 7
      remix-analyzer/src/solidity-analyzer/modules/blockTimestamp.ts
  3. 6
      remix-analyzer/src/solidity-analyzer/modules/checksEffectsInteraction.ts
  4. 6
      remix-analyzer/src/solidity-analyzer/modules/constantFunctions.ts
  5. 5
      remix-analyzer/src/solidity-analyzer/modules/deleteDynamicArrays.ts
  6. 5
      remix-analyzer/src/solidity-analyzer/modules/etherTransferInLoop.ts
  7. 5
      remix-analyzer/src/solidity-analyzer/modules/forLoopIteratesOverDynamicArray.ts
  8. 5
      remix-analyzer/src/solidity-analyzer/modules/guardConditions.ts
  9. 4
      remix-analyzer/src/solidity-analyzer/modules/inlineAssembly.ts
  10. 11
      remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts
  11. 2
      remix-analyzer/src/solidity-analyzer/modules/noReturn.ts
  12. 4
      remix-analyzer/src/solidity-analyzer/modules/selfdestruct.ts
  13. 4
      remix-analyzer/src/solidity-analyzer/modules/similarVariableNames.ts
  14. 5
      remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts
  15. 5
      remix-analyzer/src/solidity-analyzer/modules/stringBytesLength.ts
  16. 5
      remix-analyzer/src/solidity-analyzer/modules/thisLocal.ts
  17. 5
      remix-analyzer/src/solidity-analyzer/modules/txOrigin.ts

@ -1,10 +1,10 @@
import { getStateVariableDeclarationsFromContractNode, getInheritsFromName, getContractName,
getFunctionOrModifierDefinitionParameterPart, getType, getDeclaredVariableName, getFunctionDefinitionReturnParameterPart } from './staticAnalysisCommon'
getFunctionOrModifierDefinitionParameterPart, getType, getDeclaredVariableName, getFunctionDefinitionReturnParameterPart, getCompilerVersion } from './staticAnalysisCommon'
import { AstWalker } from 'remix-astwalker'
import { FunctionDefinitionAstNode, ParameterListAstNode, ModifierDefinitionAstNode, ContractHLAst, VariableDeclarationAstNode,
FunctionHLAst, ReportObj, ReportFunction, VisitFunction, ModifierHLAst, CompilationResult } from 'types'
type WrapFunction = ((contracts: ContractHLAst[], isSameName: boolean) => ReportObj[])
type WrapFunction = ((contracts: ContractHLAst[], isSameName: boolean, version: string) => ReportObj[])
export default class abstractAstView {
contracts: ContractHLAst[] = []
@ -103,8 +103,9 @@ export default class abstractAstView {
build_report (wrap: WrapFunction): ReportFunction {
return (compilationResult: CompilationResult) => {
const solVersion = getCompilerVersion(compilationResult.contracts)
this.resolveStateVariablesInHierarchy(this.contracts)
return wrap(this.contracts, this.multipleContractsWithSameName)
return wrap(this.contracts, this.multipleContractsWithSameName, solVersion)
}
}

@ -1,5 +1,5 @@
import { default as category } from './categories'
import { isNowAccess, isBlockTimestampAccess } from './staticAnalysisCommon'
import { isNowAccess, isBlockTimestampAccess, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, IdentifierAstNode,
MemberAccessAstNode, SupportedVersion} from './../../types'
@ -21,19 +21,20 @@ export default class blockTimestamp implements AnalyzerModule {
}
report (compilationResults: CompilationResult): ReportObj[] {
const version = getCompilerVersion(compilationResults.contracts)
return this.warningNowNodes.map((item, i) => {
return {
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.`,
location: item.src,
more: 'https://solidity.readthedocs.io/en/develop/units-and-global-variables.html?highlight=block.timestamp#block-and-transaction-properties'
more: `https://solidity.readthedocs.io/en/${version}/units-and-global-variables.html?highlight=block.timestamp#block-and-transaction-properties`
}
}).concat(this.warningblockTimestampNodes.map((item, i) => {
return {
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.`,
location: item.src,
more: 'https://solidity.readthedocs.io/en/develop/units-and-global-variables.html?highlight=block.timestamp#block-and-transaction-properties'
more: `https://solidity.readthedocs.io/en/${version}/units-and-global-variables.html?highlight=block.timestamp#block-and-transaction-properties`
}
}))
}

@ -1,6 +1,6 @@
import { default as category } from './categories'
import { isInteraction, isEffect, isLocalCallGraphRelevantNode, getFullQuallyfiedFuncDefinitionIdent,
isWriteOnStateVariable, isStorageVariableDeclaration, getFullQualifiedFunctionCallIdent } from './staticAnalysisCommon'
isWriteOnStateVariable, isStorageVariableDeclaration, getFullQualifiedFunctionCallIdent, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import { buildGlobalFuncCallGraph, resolveCallGraphSymbol, analyseCallGraph } from './functionCallGraph'
import AbstractAst from './abstractAstView'
@ -25,7 +25,7 @@ export default class checksEffectsInteraction implements AnalyzerModule {
report: ReportFunction = this.abstractAst.build_report(this._report.bind(this))
private _report (contracts: ContractHLAst[], multipleContractsWithSameName: boolean): ReportObj[] {
private _report (contracts: ContractHLAst[], multipleContractsWithSameName: boolean, version: string): ReportObj[] {
const warnings: ReportObj[] = []
const hasModifiers: boolean = contracts.some((item) => item.modifiers.length > 0)
const callGraph: Record<string, ContractCallGraph> = buildGlobalFuncCallGraph(contracts)
@ -51,7 +51,7 @@ export default class checksEffectsInteraction implements AnalyzerModule {
warnings.push({
warning: `Potential violation of Checks-Effects-Interaction pattern in ${funcName}: Could potentially lead to re-entrancy vulnerability. ${comments}`,
location: func.node['src'],
more: 'http://solidity.readthedocs.io/en/develop/security-considerations.html#re-entrancy'
more: `https://solidity.readthedocs.io/en/${version}/security-considerations.html#re-entrancy`
})
}
})

@ -34,7 +34,7 @@ export default class constantFunctions implements AnalyzerModule {
report: ReportFunction = this.abstractAst.build_report(this._report.bind(this))
private _report (contracts: ContractHLAst[], multipleContractsWithSameName: boolean): ReportObj[] {
private _report (contracts: ContractHLAst[], multipleContractsWithSameName: boolean, version: string): ReportObj[] {
const warnings: ReportObj[] = []
const hasModifiers: boolean = contracts.some((item) => item.modifiers.length > 0)
@ -68,13 +68,13 @@ export default class constantFunctions implements AnalyzerModule {
warnings.push({
warning: `${funcName} : Potentially should be constant/view/pure but is not. ${comments}`,
location: func.node['src'],
more: 'https://solidity.readthedocs.io/en/develop/contracts.html#view-functions'
more: `https://solidity.readthedocs.io/en/${version}/contracts.html#view-functions`
})
} else {
warnings.push({
warning: `${funcName} : Is constant but potentially should not be. ${comments}`,
location: func.node['src'],
more: 'https://solidity.readthedocs.io/en/develop/contracts.html#view-functions'
more: `https://solidity.readthedocs.io/en/${version}/contracts.html#view-functions`
})
}
}

@ -1,5 +1,5 @@
import { default as category } from './categories'
import { isDeleteOfDynamicArray } from './staticAnalysisCommon'
import { isDeleteOfDynamicArray, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, UnaryOperationAstNode, SupportedVersion} from './../../types'
@ -18,11 +18,12 @@ export default class deleteDynamicArrays implements AnalyzerModule {
}
report (compilationResults: CompilationResult): ReportObj[] {
const version = getCompilerVersion(compilationResults.contracts)
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: 'https://solidity.readthedocs.io/en/latest/types.html#delete'
more: `https://solidity.readthedocs.io/en/${version}/types.html#delete`
}
})
}

@ -1,6 +1,6 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import { isLoop, isTransfer } from './staticAnalysisCommon'
import { isLoop, isTransfer, getCompilerVersion } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, ForStatementAstNode,
WhileStatementAstNode, ExpressionStatementAstNode, SupportedVersion} from './../../types'
@ -30,11 +30,12 @@ export default class etherTransferInLoop implements AnalyzerModule {
}
report (compilationResults: CompilationResult): ReportObj[] {
const version = getCompilerVersion(compilationResults.contracts)
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'
more: `https://solidity.readthedocs.io/en/${version}/security-considerations.html#gas-limit-and-loops`
}
})
}

@ -1,6 +1,6 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import { isDynamicArrayLengthAccess } from './staticAnalysisCommon'
import { isDynamicArrayLengthAccess, getCompilerVersion } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, ForStatementAstNode, SupportedVersion} from './../../types'
export default class forLoopIteratesOverDynamicArray implements AnalyzerModule {
@ -24,11 +24,12 @@ export default class forLoopIteratesOverDynamicArray implements AnalyzerModule {
}
report (compilationResults: CompilationResult): ReportObj[] {
const version = getCompilerVersion(compilationResults.contracts)
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. \n 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/latest/security-considerations.html#gas-limit-and-loops'
more: `https://solidity.readthedocs.io/en/${version}/security-considerations.html#gas-limit-and-loops`
}
})
}

@ -1,5 +1,5 @@
import { default as category } from './categories'
import { isRequireCall, isAssertCall } from './staticAnalysisCommon'
import { isRequireCall, isAssertCall, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, FunctionCallAstNode, SupportedVersion} from './../../types'
@ -18,11 +18,12 @@ export default class guardConditions implements AnalyzerModule {
}
report (compilationResults: CompilationResult): ReportObj[] {
const version = getCompilerVersion(compilationResults.contracts)
return this.guards.map((node) => {
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.`,
location: node.src,
more: 'http://solidity.readthedocs.io/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions'
more: `https://solidity.readthedocs.io/en/${version}/control-structures.html#error-handling-assert-require-revert-and-exceptions`
}
})
}

@ -1,6 +1,7 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, InlineAssemblyAstNode, SupportedVersion} from './../../types'
import { getCompilerVersion } from './staticAnalysisCommon'
export default class inlineAssembly implements AnalyzerModule {
inlineAssNodes: InlineAssemblyAstNode[] = []
@ -17,12 +18,13 @@ export default class inlineAssembly implements AnalyzerModule {
}
report (compilationResults: CompilationResult): ReportObj[] {
const version = getCompilerVersion(compilationResults.contracts)
return this.inlineAssNodes.map((node) => {
return {
warning: `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'
more: `https://solidity.readthedocs.io/en/${version}/assembly.html`
}
})
}

@ -1,5 +1,5 @@
import { default as category } from './categories'
import { isLLCall, isLLDelegatecall, isLLCallcode, isLLCall04, isLLDelegatecall04, isLLSend04, isLLSend, lowLevelCallTypes } from './staticAnalysisCommon'
import { isLLCall, isLLDelegatecall, isLLCallcode, isLLCall04, isLLDelegatecall04, isLLSend04, isLLSend, lowLevelCallTypes, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, MemberAccessAstNode, SupportedVersion} from './../../types'
@ -37,6 +37,7 @@ export default class lowLevelCalls implements AnalyzerModule {
}
report (compilationResults: CompilationResult): ReportObj[] {
const version = getCompilerVersion(compilationResults.contracts)
return this.llcNodes.map((item, i) => {
let text: string = ''
let morehref: string = ''
@ -45,26 +46,26 @@ export default class lowLevelCalls implements AnalyzerModule {
text = `Use of "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'
morehref = `https://solidity.readthedocs.io/en/${version}/control-structures.html?#external-function-calls`
break
case lowLevelCallTypes.CALLCODE:
text = `Use of "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'
morehref = `https://solidity.readthedocs.io/en/${version}/contracts.html#libraries`
break
case lowLevelCallTypes.DELEGATECALL:
text = `Use of "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'
morehref = `https://solidity.readthedocs.io/en/${version}/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'
morehref = `https://solidity.readthedocs.io/en/${version}/security-considerations.html#sending-and-receiving-ether`
break
}
return { warning: text, more: morehref, location: item.node.src }

@ -21,7 +21,7 @@ export default class noReturn implements AnalyzerModule {
)
report: ReportFunction = this.abstractAst.build_report(this._report.bind(this))
private _report (contracts: ContractHLAst[], multipleContractsWithSameName: boolean): ReportObj[] {
private _report (contracts: ContractHLAst[], multipleContractsWithSameName: boolean, version: string): ReportObj[] {
const warnings: ReportObj[] = []
contracts.forEach((contract: ContractHLAst) => {

@ -20,7 +20,7 @@ export default class selfdestruct implements AnalyzerModule {
)
report: ReportFunction = this.abstractAst.build_report(this._report.bind(this))
private _report (contracts: ContractHLAst[], multipleContractsWithSameName: boolean): ReportObj[] {
private _report (contracts: ContractHLAst[], multipleContractsWithSameName: boolean, version: string): ReportObj[] {
const warnings: ReportObj[] = []
contracts.forEach((contract) => {
@ -39,7 +39,7 @@ export default class selfdestruct implements AnalyzerModule {
warnings.push({
warning: `Use of selfdestruct: No code after selfdestruct is executed. Selfdestruct is a terminal.`,
location: node.src,
more: 'https://solidity.readthedocs.io/en/develop/introduction-to-smart-contracts.html#deactivate-and-self-destruct'
more: `https://solidity.readthedocs.io/en/${version}/introduction-to-smart-contracts.html#deactivate-and-self-destruct`
})
hasSelf = false
}

@ -27,7 +27,7 @@ export default class similarVariableNames implements AnalyzerModule {
report: ReportFunction = this.abstractAst.build_report(this._report.bind(this))
private _report (contracts: ContractHLAst[], multipleContractsWithSameName: boolean): ReportObj[] {
private _report (contracts: ContractHLAst[], multipleContractsWithSameName: boolean, version: string): ReportObj[] {
const warnings: ReportObj[] = []
const hasModifiers: boolean = contracts.some((item) => item.modifiers.length > 0)
@ -46,7 +46,7 @@ export default class similarVariableNames implements AnalyzerModule {
const vars: string[] = this.getFunctionVariables(contract, func).map(getDeclaredVariableName)
this.findSimilarVarNames(vars).map((sim) => {
warnings.push({
warning: `${funcName} : Variables have very similar names ${sim.var1} and ${sim.var2}. ${hasModifiersComments} ${multipleContractsWithSameNameComments}`,
warning: `${funcName} : Variables have very similar names "${sim.var1}" and "${sim.var2}". ${hasModifiersComments} ${multipleContractsWithSameNameComments}`,
location: func.node['src']
})
})

@ -1123,14 +1123,15 @@ function getTypeStringFromComponents(components: ABIParameter[]) {
}
function getCompilerVersion(contractFiles: CompiledContractObj): string {
let version = 'develop'
const fileNames: string[] = Object.keys(contractFiles)
const contracts = contractFiles[fileNames[0]]
const contractNames: string[] = Object.keys(contracts)
const contract: CompiledContract = contracts[contractNames[0]]
const metadata = JSON.parse(contract.metadata)
const compilerVersion: string = metadata.compiler.version
if(!compilerVersion.includes('nightly')) return 'v' + compilerVersion.split('+commit')[0]
else return 'develop'
if(!compilerVersion.includes('nightly')) version = 'v' + compilerVersion.split('+commit')[0]
return version
}
const helpers = {

@ -1,6 +1,6 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import { isStringToBytesConversion, isBytesLengthCheck } from './staticAnalysisCommon'
import { isStringToBytesConversion, isBytesLengthCheck, getCompilerVersion } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, MemberAccessAstNode, FunctionCallAstNode, SupportedVersion} from './../../types'
export default class stringBytesLength implements AnalyzerModule {
@ -21,11 +21,12 @@ export default class stringBytesLength implements AnalyzerModule {
}
report (compilationResults: CompilationResult): ReportObj[] {
const version = getCompilerVersion(compilationResults.contracts)
if (this.stringToBytesConversions.length > 0 && this.bytesLengthChecks.length > 0) {
return [{
warning: `"bytes" and "string" lengths are not the same since strings are assumed to be UTF-8 encoded (according to the ABI defintion) therefore one character is not nessesarily encoded in one byte of data.`,
location: this.bytesLengthChecks[0].src,
more: 'https://solidity.readthedocs.io/en/develop/abi-spec.html#argument-encoding'
more: `https://solidity.readthedocs.io/en/${version}/abi-spec.html#argument-encoding`
}]
} else {
return []

@ -1,5 +1,5 @@
import { default as category } from './categories'
import { isThisLocalCall } from './staticAnalysisCommon'
import { isThisLocalCall, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, MemberAccessAstNode, SupportedVersion} from './../../types'
@ -18,11 +18,12 @@ export default class thisLocal implements AnalyzerModule {
}
report (compilationResults: CompilationResult): ReportObj[] {
const version = getCompilerVersion(compilationResults.contracts)
return this.warningNodes.map(function (item, i) {
return {
warning: `Use of "this" for local functions: Never use "this" to call functions in the same contract, it only consumes more gas than normal local calls.`,
location: item.src,
more: 'http://solidity.readthedocs.io/en/develop/control-structures.html#external-function-calls'
more: `https://solidity.readthedocs.io/en/${version}/control-structures.html#external-function-calls`
}
})
}

@ -1,6 +1,6 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import { isTxOriginAccess } from './staticAnalysisCommon'
import { isTxOriginAccess, getCompilerVersion } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, MemberAccessAstNode, SupportedVersion} from './../../types'
export default class txOrigin implements AnalyzerModule {
@ -19,12 +19,13 @@ export default class txOrigin implements AnalyzerModule {
}
report (compilationResults: CompilationResult): ReportObj[] {
const version = getCompilerVersion(compilationResults.contracts)
return this.txOriginNodes.map((item, i) => {
return {
warning: `Use of tx.origin: "tx.origin" is useful only in very exceptional cases.
If you use it for authentication, you usually want to replace it by "msg.sender", because otherwise any contract you call can act on your behalf.`,
location: item.src,
more: 'https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin'
more: `https://solidity.readthedocs.io/en/${version}/security-considerations.html#tx-origin`
}
})
}

Loading…
Cancel
Save