fix(@embark/coverage): function types and single statement ifs

This commit is contained in:
Michael Bradley, Jr 2019-06-20 10:16:25 -05:00 committed by Michael Bradley
parent 610d8f1baa
commit 2ce9ca6bb0
28 changed files with 963 additions and 556 deletions

View File

@ -4,3 +4,5 @@
Visit [embark.status.im](https://embark.status.im/) to get started with
[Embark](https://github.com/embark-framework/embark).
Contracts in `test/fixture/contracts` are from [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-solidity) and [Gnosis Prediction Markets](https://github.com/gnosis/pm-contracts)

View File

@ -24,7 +24,7 @@
"type": "git",
"url": "https://github.com/embark-framework/embark.git"
},
"main": "./dist/index.js",
"main": "./dist/lib/index.js",
"scripts": {
"build": "cross-env BABEL_ENV=node babel src --extensions \".ts\" --out-dir dist --root-mode upward --source-maps",
"ci": "npm run qa",
@ -35,6 +35,7 @@
"qa": "npm-run-all lint typecheck build package",
"reset": "npx rimraf dist embark-*.tgz package",
"start": "npm run watch",
"test": "nyc --reporter=html --reporter=json mocha dist/test/**/*.js --exit --no-timeouts --require source-map-support/register",
"typecheck": "tsc",
"watch": "run-p watch:*",
"watch:build": "npm run build -- --verbose --watch",
@ -46,16 +47,20 @@
"embark-utils": "^4.1.0-beta.3",
"fs-extra": "7.0.1",
"globule": "1.2.1",
"prettier-plugin-solidity": "1.0.0-alpha.25",
"semver": "5.6.0",
"solidity-parser-antlr": "0.4.2",
"solidity-parser-antlr": "0.4.5",
"web3-eth-contract": "1.0.0-beta.37"
},
"devDependencies": {
"@babel/cli": "7.2.3",
"@babel/core": "7.2.2",
"@types/mocha": "5.2.0",
"@types/prettier": "1.16.4",
"@types/web3": "1.0.12",
"cross-env": "5.2.0",
"eslint": "5.7.0",
"mocha": "5.2.0",
"npm-run-all": "4.1.5",
"rimraf": "2.6.3",
"tslint": "5.16.0",

View File

@ -1,42 +0,0 @@
import * as semver from "semver";
import { ContractEnhanced } from "./contractEnhanced";
import { encrypt } from "./eventId";
import { InjectionPoint } from "./types";
const EMIT_VERSION = "0.4.21";
export class Injector {
private isEmitSupported: boolean;
constructor(private contract: ContractEnhanced) {
this.isEmitSupported = semver.gte(this.contract.solcVersion, EMIT_VERSION);
}
public process(injectionPoint: InjectionPoint) {
switch (injectionPoint.type) {
case "statement":
return this.statement(injectionPoint);
case "contractDefinition":
return this.contractDefinition(injectionPoint);
}
}
private statement(injectionPoint: InjectionPoint) {
const data = `${this.isEmitSupported ? "emit" : ""} __StatementCoverage(${encrypt(this.contract.id, injectionPoint.id)});`;
this.insertAt(injectionPoint.location.start.line - 1, data);
}
private contractDefinition(injectionPoint: InjectionPoint) {
const data = [
"event __StatementCoverage(uint32 value);",
].join("\n");
this.insertAt(injectionPoint.location.start.line, data);
}
private insertAt(line: number, data: string) {
const lines = this.contract.source.split("\n");
lines.splice(line, 0, data);
this.contract.source = lines.join("\n");
}
}

View File

@ -1,63 +0,0 @@
import parser, {
ASTNode,
BreakStatement,
ContinueStatement,
ContractDefinition,
EmitStatement,
ExpressionStatement,
FunctionDefinition,
IfStatement,
ModifierDefinition,
ReturnStatement,
ThrowStatement,
VariableDeclarationStatement,
WhileStatement,
} from "solidity-parser-antlr";
import { Instrumenter } from "./instrumenter";
export class InstrumentWalker {
constructor(private instrumenter: Instrumenter) {
}
public walk(ast: ASTNode) {
parser.visit(ast, {
BreakStatement: (node: BreakStatement) => {
this.instrumenter.instrumentStatement(node);
},
ContinueStatement: (node: ContinueStatement) => {
this.instrumenter.instrumentStatement(node);
},
ContractDefinition: (node: ContractDefinition) => {
this.instrumenter.instrumentContractDefinition(node);
},
EmitStatement: (node: EmitStatement) => {
this.instrumenter.instrumentStatement(node);
},
ExpressionStatement: (node: ExpressionStatement) => {
this.instrumenter.instrumentStatement(node);
},
FunctionDefinition: (node: FunctionDefinition) => {
this.instrumenter.instrumentFunction(node);
},
IfStatement: (node: IfStatement) => {
this.instrumenter.instrumentStatement(node);
this.instrumenter.instrumentIfStatement(node);
},
ModifierDefinition: (node: ModifierDefinition) => {
this.instrumenter.instrumentFunction(node);
},
ReturnStatement: (node: ReturnStatement) => {
this.instrumenter.instrumentStatement(node);
},
ThrowStatement: (node: ThrowStatement) => {
this.instrumenter.instrumentStatement(node);
},
VariableDeclarationStatement: (node: VariableDeclarationStatement) => {
this.instrumenter.instrumentStatement(node);
},
WhileStatement: (node: WhileStatement) => {
this.instrumenter.instrumentStatement(node);
},
});
}
}

View File

@ -1,77 +0,0 @@
import {
ContractDefinition,
FunctionDefinition,
IfStatement,
Location,
Statement,
} from "solidity-parser-antlr";
import { ContractEnhanced } from "./contractEnhanced";
import { InjectionPoint, InjectionPointType } from "./types";
export class Instrumenter {
private injectionPoints: InjectionPoint[] = [];
constructor(private contract: ContractEnhanced) {
}
public getInjectionPoints() {
return this.injectionPoints.sort((a, b) => b.location.start.line - a.location.start.line);
}
public instrumentContractDefinition(node: ContractDefinition) {
if (!node.loc) {
return;
}
if (node.loc.start.line === node.loc.end.line) {
return;
}
this.addInjectionPoints("contractDefinition", 1, node.loc);
}
public instrumentFunction(node: FunctionDefinition) {
if (!node.loc) {
return;
}
if (!node.body || !node.body.loc) {
return;
}
if (node.body.loc.start.line === node.body.loc.end.line) {
return;
}
this.contract.addFunction(node.loc, node.name, node.body.loc);
}
public instrumentStatement(node: Statement) {
if (!node.loc) {
return;
}
const id = this.contract.addStatement(node.loc);
this.addInjectionPoints("statement", id, node.loc);
}
public instrumentIfStatement(node: IfStatement) {
if (!node.loc) {
return;
}
const locations = [node.trueBody, node.falseBody].reduce((acc: Location[], body) => {
if (body && body.loc) {
acc.push(body.loc);
}
return acc;
}, []);
this.contract.addBranch(node.loc.start.line, "if", locations);
}
private addInjectionPoints(type: InjectionPointType, id: number, location: Location) {
this.injectionPoints.push({type, id, location});
}
}

View File

@ -1,7 +1,7 @@
import { File } from "embark-utils";
import * as fs from "fs-extra";
import * as path from "path";
import parser, { LineColumn, Location } from "solidity-parser-antlr";
import parser, { LineColumn, Location, SourceUnit } from "solidity-parser-antlr";
import { EventLog } from "web3/types";
import { decrypt } from "./eventId";
@ -9,6 +9,7 @@ import { Injector } from "./injector";
import { Instrumenter } from "./instrumenter";
import { InstrumentWalker } from "./instrumentWalker";
import { coverageContractsPath } from "./path";
import { Printer } from "./printer";
import { BranchType, Coverage } from "./types";
const STATEMENT_EVENT = "__StatementCoverage";
@ -26,7 +27,7 @@ export class ContractEnhanced {
public coverageFilepath: string;
public originalSource: string;
public source: string;
private ast!: parser.ASTNode;
private ast!: SourceUnit;
private functionsBodyLocation: {[id: number]: Location} = {};
constructor(public filepath: string, public solcVersion: string) {
@ -38,7 +39,7 @@ export class ContractEnhanced {
try {
this.source = fs.readFileSync(filepath, "utf-8");
this.originalSource = this.source;
this.ast = parser.parse(this.source, {loc: true, range: true});
this.ast = parser.parse(this.source, {loc: true, range: true}) as SourceUnit;
} catch (error) {
const {line, column, message} = error.errors[0];
console.warn(`Error on ${this.filepath}:${line}:${column}: "${message}". Could not setup for coverage.`);
@ -67,13 +68,26 @@ export class ContractEnhanced {
const instrumentWalker = new InstrumentWalker(instrumenter);
instrumentWalker.walk(this.ast);
const injector = new Injector(this);
const injector = new Injector(this, this.solcVersion);
instrumenter.getInjectionPoints().forEach(injector.process.bind(injector));
}
public save() {
fs.ensureFileSync(this.coverageFilepath);
fs.writeFileSync(this.coverageFilepath, this.source);
if (!this.ast) {
return fs.writeFileSync(this.coverageFilepath, this.source);
}
try {
const printer = new Printer(this.ast);
this.source = printer.print();
} catch (err) {
// Something might have happened with the printer. Write the original source.
console.warn(`Error with coverage printer for ${this.filepath}. Please submit an issue with this code.`);
} finally {
fs.writeFileSync(this.coverageFilepath, this.source);
}
}
public updateCoverage(events: EventLog[]) {

View File

@ -1,4 +1,4 @@
import { dappPath, File, removePureView } from "embark-utils";
import { dappPath, File } from "embark-utils";
import * as globule from "globule";
import * as path from "path";
import Web3Contract from "web3/eth/contract";
@ -44,7 +44,6 @@ export default class Coverage {
contract.save();
});
await Promise.all(promises);
removePureView(coverageContractsPath());
}
private swapContracts() {

View File

@ -0,0 +1,83 @@
import { ContractEnhanced } from "./contractEnhanced";
import { encrypt } from "./eventId";
import { CoverageEmitNodeType, InjectionPoint } from "./types";
import * as semver from "semver";
import parser, { ASTNode, ContractDefinition, EmitStatement, EventDefinition, ExpressionStatement } from "solidity-parser-antlr";
const EMIT_VERSION = "0.4.21";
const EVENT_NODE = {
name: "__StatementCoverage",
parameters: {
parameters: [
{
name: "value",
type: "VariableDeclaration",
typeName: { name: "uint32", type: "ElementaryTypeName" },
},
],
type: "ParameterList",
},
type: "EventDefinition",
};
export class Injector {
private isEmitSupported: boolean;
constructor(private contract: ContractEnhanced, private solcVersion: string) {
this.solcVersion = solcVersion;
this.isEmitSupported = semver.gte(this.solcVersion, EMIT_VERSION);
}
public process(injectionPoint: InjectionPoint) {
switch (injectionPoint.type) {
case "statement":
return this.statement(injectionPoint);
case "contractDefinition":
return this.contractDefinition(injectionPoint);
}
}
private emitStatementNode(id: number): CoverageEmitNodeType {
// Depending on what solidity version we're handling, "emit" statements might not
// be supported, so we check here.
const functionCall = {
arguments: [{ number: id.toString(), type: "NumberLiteral", subdenomination: null }],
expression: { name: "__StatementCoverage", type: "Identifier" },
names: [],
type: "FunctionCall",
};
if (this.isEmitSupported) {
return { eventCall: functionCall, type: "EmitStatement" } as EmitStatement;
}
return { expression: functionCall, type: "ExpressionStatement" } as ExpressionStatement;
}
private statement(injectionPoint: InjectionPoint) {
const eventId = encrypt(this.contract.id, injectionPoint.id);
// Get the proper node that we're going to inject instead of building a string.
// There _might_ be a better way to do this.
const node = this.emitStatementNode(eventId);
this.insertAt(node, injectionPoint);
}
private contractDefinition(injectionPoint: InjectionPoint) {
const contractNode = injectionPoint.node as ContractDefinition;
contractNode.subNodes.splice(0, 0, EVENT_NODE as EventDefinition);
}
private insertAt(emit: CoverageEmitNodeType, injectionPoint: InjectionPoint) {
const { parent, node } = injectionPoint;
if (!parent) {
return;
}
const idx = parent.statements.findIndex((s: ASTNode) => s.loc === node.loc);
parent.statements.splice(idx, 0, emit);
}
}

View File

@ -0,0 +1,74 @@
import parser, {
ASTNode,
Block,
BreakStatement,
ContinueStatement,
ContractDefinition,
EmitStatement,
ExpressionStatement,
FunctionDefinition,
IfStatement,
ReturnStatement,
SourceUnit,
ThrowStatement,
VariableDeclarationStatement,
WhileStatement,
} from "solidity-parser-antlr";
import { Instrumenter } from "./instrumenter";
export class InstrumentWalker {
private blockStack: Block[];
constructor(private instrumenter: Instrumenter) {
this.blockStack = [];
}
private blockTail(): Block {
return this.blockStack[this.blockStack.length - 1];
}
public walk(ast: ASTNode) {
parser.visit(ast, {
"Block": (node: Block) => {
this.blockStack.push(node);
},
"Block:exit": (node: Block) => {
this.blockStack.pop();
},
"BreakStatement": (node: BreakStatement) => {
this.instrumenter.instrumentStatement(node, this.blockTail());
},
"ContinueStatement": (node: ContinueStatement) => {
this.instrumenter.instrumentStatement(node, this.blockTail());
},
"ContractDefinition": (node: ContractDefinition) => {
this.instrumenter.instrumentContractDefinition(node);
},
"EmitStatement": (node: EmitStatement) => {
this.instrumenter.instrumentStatement(node, this.blockTail());
},
"ExpressionStatement": (node: ExpressionStatement) => {
this.instrumenter.instrumentStatement(node, this.blockTail());
},
"FunctionDefinition": (node: FunctionDefinition) => {
this.instrumenter.instrumentFunction(node);
},
"IfStatement": (node: IfStatement) => {
this.instrumenter.instrumentStatement(node, this.blockTail());
this.instrumenter.instrumentIfStatement(node);
},
"ReturnStatement": (node: ReturnStatement) => {
this.instrumenter.instrumentStatement(node, this.blockTail());
},
"ThrowStatement": (node: ThrowStatement) => {
this.instrumenter.instrumentStatement(node, this.blockTail());
},
"VariableDeclarationStatement": (node: VariableDeclarationStatement) => {
this.instrumenter.instrumentStatement(node, this.blockTail());
},
"WhileStatement": (node: WhileStatement) => {
this.instrumenter.instrumentStatement(node, this.blockTail());
},
});
}
}

View File

@ -0,0 +1,112 @@
import {
ASTNode,
Block,
ContractDefinition,
FunctionDefinition,
IfStatement,
Location,
ModifierDefinition,
Statement,
} from "solidity-parser-antlr";
import {ContractEnhanced} from "./contractEnhanced";
import {InjectionPoint, InjectionPointType} from "./types";
export class Instrumenter {
private injectionPoints: InjectionPoint[] = [];
constructor(private contract: ContractEnhanced) {
}
public getInjectionPoints() {
return this.injectionPoints.sort((a, b) => {
return (a.node.loc && b.node.loc) ? b.node.loc.start.line - a.node.loc.start.line : 0;
});
}
public instrumentContractDefinition(node: ContractDefinition) {
if (!node.loc) {
return;
}
if (node.loc.start.line === node.loc.end.line) {
return;
}
this.addInjectionPoints("contractDefinition", 1, node);
}
public instrumentFunction(node: FunctionDefinition) {
// Remove stateMutability so that the function is not exported
// as "view" or "pure", seen as it will contain some emit
// statements and those require a transaction.
if (node.stateMutability === "view" || node.stateMutability === "pure") {
node.stateMutability = undefined;
}
if (!node.loc) {
return;
}
if (!node.body || !node.body.loc) {
return;
}
if (node.body.loc.start.line === node.body.loc.end.line) {
return;
}
this.contract.addFunction(node.loc, node.name || "", node.body.loc);
}
public instrumentStatement(node: Statement, parent: Block) {
if (!node.loc) {
return;
}
const id = this.contract.addStatement(node.loc);
this.addInjectionPoints("statement", id, node, parent);
}
public instrumentIfStatement(node: IfStatement) {
if (!node.loc) {
return;
}
// Ensure that the trueBody and falseBody are Blocks. This prevents single
// statement `if` checks from breaking when we try to add an emit statement.
node.trueBody = this.wrapInBlock(node.trueBody);
if (node.falseBody) {
node.falseBody = this.wrapInBlock(node.falseBody);
}
const locations = [node.trueBody, node.falseBody].reduce((acc: Location[], body) => {
if (body && body.loc) {
acc.push(body.loc);
}
return acc;
}, []);
this.contract.addBranch(node.loc.start.line, "if", locations);
}
private wrapInBlock(node: Statement): Block {
if (node.type === "Block") {
return node;
}
const newNode: Block = {
loc: node.loc,
range: node.range,
statements: [node],
type: "Block",
};
return newNode;
}
private addInjectionPoints(type: InjectionPointType, id: number, node: ASTNode, parent?: Block | undefined) {
this.injectionPoints.push({type, id, node, parent});
}
}

View File

@ -0,0 +1,32 @@
import fs from "fs";
import prettier from "prettier";
import { printers } from "prettier-plugin-solidity";
import { SourceUnit } from "solidity-parser-antlr";
export class Printer {
constructor(private ast: SourceUnit) {}
public print() {
const { ast } = this;
// Yes, yes. This is ridiculous. But go and try and write
// an AST to code writer and then tell me it's ridiculous.
let code = prettier.format("<code>", {
parser(_, parsers, options) {
// The types on this library don't account for Options.printer,
// so we'll ask the typechecker to ignore this one, as it errors.
//
// @ts-ignore
options.printer = printers["solidity-ast"];
return ast;
},
});
// Fix some weird cases with the library.
code = code.replace(/;\)/gm, ")");
code = code.replace(/;;/gm, ";");
return code;
}
}

View File

@ -1,12 +1,14 @@
import { Location } from "solidity-parser-antlr";
import { ASTNode, Block, EmitStatement, ExpressionStatement, Location } from "solidity-parser-antlr";
export type InjectionPointType = "statement" | "contractDefinition";
export type BranchType = "if" | "switch";
export type CoverageEmitNodeType = EmitStatement | ExpressionStatement;
export interface InjectionPoint {
type: InjectionPointType;
id: number;
location: Location;
node: ASTNode;
parent: Block | undefined;
}
export interface Coverage {

View File

@ -0,0 +1,228 @@
pragma solidity ^0.5.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
/**
* @dev Implementation of the `IERC20` interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using `_mint`.
* For a generic mechanism see `ERC20Mintable`.
*
* *For a detailed writeup see our guide [How to implement supply
* mechanisms](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).*
*
* We have followed general OpenZeppelin guidelines: functions revert instead
* of returning `false` on failure. This behavior is nonetheless conventional
* and does not conflict with the expectations of ERC20 applications.
*
* Additionally, an `Approval` event is emitted on calls to `transferFrom`.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard `decreaseAllowance` and `increaseAllowance`
* functions have been added to mitigate the well-known issues around setting
* allowances. See `IERC20.approve`.
*/
contract ERC20 is IERC20 {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
/**
* @dev See `IERC20.totalSupply`.
*/
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
/**
* @dev See `IERC20.balanceOf`.
*/
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
/**
* @dev See `IERC20.transfer`.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
/**
* @dev See `IERC20.allowance`.
*/
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See `IERC20.approve`.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
/**
* @dev See `IERC20.transferFrom`.
*
* Emits an `Approval` event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of `ERC20`;
*
* Requirements:
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `value`.
* - the caller must have allowance for `sender`'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount));
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to `approve` that can be used as a mitigation for
* problems described in `IERC20.approve`.
*
* Emits an `Approval` event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue));
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to `approve` that can be used as a mitigation for
* problems described in `IERC20.approve`.
*
* Emits an `Approval` event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue));
return true;
}
/**
* @dev Moves tokens `amount` from `sender` to `recipient`.
*
* This is internal function is equivalent to `transfer`, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a `Transfer` event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(address sender, address recipient, uint256 amount) internal {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_balances[sender] = _balances[sender].sub(amount);
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a `Transfer` event with `from` set to the zero address.
*
* Requirements
*
* - `to` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal {
require(account != address(0), "ERC20: mint to the zero address");
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
/**
* @dev Destoys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a `Transfer` event with `to` set to the zero address.
*
* Requirements
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 value) internal {
require(account != address(0), "ERC20: burn from the zero address");
_totalSupply = _totalSupply.sub(value);
_balances[account] = _balances[account].sub(value);
emit Transfer(account, address(0), value);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
*
* This is internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an `Approval` event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 value) internal {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = value;
emit Approval(owner, spender, value);
}
/**
* @dev Destoys `amount` tokens from `account`.`amount` is then deducted
* from the caller's allowance.
*
* See `_burn` and `_approve`.
*/
function _burnFrom(address account, uint256 amount) internal {
_burn(account, amount);
_approve(account, msg.sender, _allowances[account][msg.sender].sub(amount));
}
}

View File

@ -0,0 +1,111 @@
pragma solidity ^0.4.21;
import "./Token.sol";
import "./Math.sol";
import "./Proxy.sol";
/**
* Deprecated: Use Open Zeppeling one instead
*/
contract StandardTokenData {
/*
* Storage
*/
mapping (address => uint) balances;
mapping (address => mapping (address => uint)) allowances;
uint totalTokens;
}
/**
* Deprecated: Use Open Zeppeling one instead
*/
/// @title Standard token contract with overflow protection
contract GnosisStandardToken is Token, StandardTokenData {
using Math for *;
/*
* Public functions
*/
/// @dev Transfers sender's tokens to a given address. Returns success
/// @param to Address of token receiver
/// @param value Number of tokens to transfer
/// @return Was transfer successful?
function transfer(address to, uint value)
public
returns (bool)
{
if ( !balances[msg.sender].safeToSub(value)
|| !balances[to].safeToAdd(value))
return false;
balances[msg.sender] -= value;
balances[to] += value;
emit Transfer(msg.sender, to, value);
return true;
}
/// @dev Allows allowed third party to transfer tokens from one address to another. Returns success
/// @param from Address from where tokens are withdrawn
/// @param to Address to where tokens are sent
/// @param value Number of tokens to transfer
/// @return Was transfer successful?
function transferFrom(address from, address to, uint value)
public
returns (bool)
{
if ( !balances[from].safeToSub(value)
|| !allowances[from][msg.sender].safeToSub(value)
|| !balances[to].safeToAdd(value))
return false;
balances[from] -= value;
allowances[from][msg.sender] -= value;
balances[to] += value;
emit Transfer(from, to, value);
return true;
}
/// @dev Sets approved amount of tokens for spender. Returns success
/// @param spender Address of allowed account
/// @param value Number of approved tokens
/// @return Was approval successful?
function approve(address spender, uint value)
public
returns (bool)
{
allowances[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
/// @dev Returns number of allowed tokens for given address
/// @param owner Address of token owner
/// @param spender Address of token spender
/// @return Remaining allowance for spender
function allowance(address owner, address spender)
public
view
returns (uint)
{
return allowances[owner][spender];
}
/// @dev Returns number of tokens owned by given address
/// @param owner Address of token owner
/// @return Balance of owner
function balanceOf(address owner)
public
view
returns (uint)
{
return balances[owner];
}
/// @dev Returns total supply of tokens
/// @return Total supply
function totalSupply()
public
view
returns (uint)
{
return totalTokens;
}
}

View File

@ -0,0 +1,122 @@
pragma solidity ^0.5.0;
import "../access/roles/SignerRole.sol";
import "../cryptography/ECDSA.sol";
/**
* @title SignatureBouncer
* @author PhABC, Shrugs and aflesher
* @dev SignatureBouncer allows users to submit a signature as a permission to
* do an action.
* If the signature is from one of the authorized signer addresses, the
* signature is valid.
* Note that SignatureBouncer offers no protection against replay attacks, users
* must add this themselves!
*
* Signer addresses can be individual servers signing grants or different
* users within a decentralized club that have permission to invite other
* members. This technique is useful for whitelists and airdrops; instead of
* putting all valid addresses on-chain, simply sign a grant of the form
* keccak256(abi.encodePacked(`:contractAddress` + `:granteeAddress`)) using a
* valid signer address.
* Then restrict access to your crowdsale/whitelist/airdrop using the
* `onlyValidSignature` modifier (or implement your own using _isValidSignature).
* In addition to `onlyValidSignature`, `onlyValidSignatureAndMethod` and
* `onlyValidSignatureAndData` can be used to restrict access to only a given
* method or a given method with given parameters respectively.
* See the tests in SignatureBouncer.test.js for specific usage examples.
*
* @notice A method that uses the `onlyValidSignatureAndData` modifier must make
* the _signature parameter the "last" parameter. You cannot sign a message that
* has its own signature in it so the last 128 bytes of msg.data (which
* represents the length of the _signature data and the _signature data itself)
* is ignored when validating. Also non fixed sized parameters make constructing
* the data in the signature much more complex.
* See https://ethereum.stackexchange.com/a/50616 for more details.
*/
contract SignatureBouncer is SignerRole {
using ECDSA for bytes32;
// Function selectors are 4 bytes long, as documented in
// https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector
uint256 private constant _METHOD_ID_SIZE = 4;
// Signature size is 65 bytes (tightly packed v + r + s), but gets padded to 96 bytes
uint256 private constant _SIGNATURE_SIZE = 96;
constructor () internal {
// solhint-disable-previous-line no-empty-blocks
}
/**
* @dev Requires that a valid signature of a signer was provided.
*/
modifier onlyValidSignature(bytes memory signature) {
require(_isValidSignature(msg.sender, signature), "SignatureBouncer: invalid signature for caller");
_;
}
/**
* @dev Requires that a valid signature with a specified method of a signer was provided.
*/
modifier onlyValidSignatureAndMethod(bytes memory signature) {
// solhint-disable-next-line max-line-length
require(_isValidSignatureAndMethod(msg.sender, signature), "SignatureBouncer: invalid signature for caller and method");
_;
}
/**
* @dev Requires that a valid signature with a specified method and params of a signer was provided.
*/
modifier onlyValidSignatureAndData(bytes memory signature) {
// solhint-disable-next-line max-line-length
require(_isValidSignatureAndData(msg.sender, signature), "SignatureBouncer: invalid signature for caller and data");
_;
}
/**
* @dev is the signature of `this + account` from a signer?
* @return bool
*/
function _isValidSignature(address account, bytes memory signature) internal view returns (bool) {
return _isValidDataHash(keccak256(abi.encodePacked(address(this), account)), signature);
}
/**
* @dev is the signature of `this + account + methodId` from a signer?
* @return bool
*/
function _isValidSignatureAndMethod(address account, bytes memory signature) internal view returns (bool) {
bytes memory data = new bytes(_METHOD_ID_SIZE);
for (uint i = 0; i < data.length; i++) {
data[i] = msg.data[i];
}
return _isValidDataHash(keccak256(abi.encodePacked(address(this), account, data)), signature);
}
/**
* @dev is the signature of `this + account + methodId + params(s)` from a signer?
* @notice the signature parameter of the method being validated must be the "last" parameter
* @return bool
*/
function _isValidSignatureAndData(address account, bytes memory signature) internal view returns (bool) {
require(msg.data.length > _SIGNATURE_SIZE, "SignatureBouncer: data is too short");
bytes memory data = new bytes(msg.data.length - _SIGNATURE_SIZE);
for (uint i = 0; i < data.length; i++) {
data[i] = msg.data[i];
}
return _isValidDataHash(keccak256(abi.encodePacked(address(this), account, data)), signature);
}
/**
* @dev Internal function to convert a hash to an eth signed message
* and then recover the signature and check it against the signer role.
* @return bool
*/
function _isValidDataHash(bytes32 hash, bytes memory signature) internal view returns (bool) {
address signer = hash.toEthSignedMessageHash().recover(signature);
return signer != address(0) && isSigner(signer);
}
}

View File

@ -0,0 +1,60 @@
pragma solidity ^0.5.0;
/**
* @title SignedSafeMath
* @dev Signed math operations with safety checks that revert on error.
*/
library SignedSafeMath {
int256 constant private INT256_MIN = -2**255;
/**
* @dev Multiplies two signed integers, reverts on overflow.
*/
function mul(int256 a, int256 b) internal pure returns (int256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
require(!(a == -1 && b == INT256_MIN), "SignedSafeMath: multiplication overflow");
int256 c = a * b;
require(c / a == b, "SignedSafeMath: multiplication overflow");
return c;
}
/**
* @dev Integer division of two signed integers truncating the quotient, reverts on division by zero.
*/
function div(int256 a, int256 b) internal pure returns (int256) {
require(b != 0, "SignedSafeMath: division by zero");
require(!(b == -1 && a == INT256_MIN), "SignedSafeMath: division overflow");
int256 c = a / b;
return c;
}
/**
* @dev Subtracts two signed integers, reverts on overflow.
*/
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");
return c;
}
/**
* @dev Adds two signed integers, reverts on overflow.
*/
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");
return c;
}
}

View File

@ -0,0 +1,45 @@
import assert from "assert";
import fs from "fs";
import { describe, it } from "mocha";
import path from "path";
import parser, { SourceUnit } from "solidity-parser-antlr";
import { Printer } from "../lib/printer";
const FIXTURE_PATH = path.join(__dirname, "../", "../", "src", "test", "fixtures", "contracts");
const FIXTURES = fs.readdirSync(FIXTURE_PATH).map((f) => {
const fp = path.join(FIXTURE_PATH, f);
return {
basename: f,
path: fp,
source: fs.readFileSync(fp, "utf8"),
};
});
describe("Printer", () => {
describe("printing an AST", () => {
describe("prints equivalent code", () => {
for (const fixture of FIXTURES) {
it(fixture.basename, () => {
const astBefore = parser.parse(fixture.source, {loc: false, range: false}) as SourceUnit;
const printer = new Printer(astBefore);
const source = printer.print();
const astAfter = parser.parse(source, {loc: false, range: false}) as SourceUnit;
// Remove .tokens from the AST as it gets walked and processed by
// prettier. This is not consequential for anything else. Also, the
// tokens property is added without types, and as we can't remove it
// without Typescript doing some type checks, we'll have to ask it to
// ignore those here.
//
// @ts-ignore
delete astBefore.tokens;
assert.deepEqual(astBefore, astAfter);
});
}
});
});
});

View File

@ -214,6 +214,7 @@ class Solidity {
fileCb();
}).catch((e) => {
self.logger.error(__('Error while loading the content of ') + filename);
self.logger.error(JSON.stringify(e));
self.logger.debug(e);
fileCb();
});

View File

@ -1,5 +1,5 @@
import "./src/prettier-plugin-solidity";
import "./src/remix-debug-debugtest";
import "./src/solidity-parser-antlr";
export * from "./src/callbacks";
export * from "./src/contract";

View File

@ -0,0 +1 @@
declare module "prettier-plugin-solidity";

View File

@ -1,332 +0,0 @@
declare module "solidity-parser-antlr" {
export interface LineColumn {
line: number;
column: number;
}
export interface Location {
start: LineColumn;
end: LineColumn;
}
export interface BaseASTNode {
type: string;
range?: [number, number];
loc?: Location;
}
export interface SourceUnit extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface PragmaDirective extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface PragmaName extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface PragmaValue extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface Version extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface VersionOperator extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface VersionConstraint extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ImportDeclaration extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ImportDirective extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ContractDefinition extends BaseASTNode {
name: string;
}
export interface InheritanceSpecifier extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ContractPart extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface StateVariableDeclaration extends BaseASTNode {
variables: VariableDeclaration[];
}
export interface UsingForDeclaration extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface StructDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ModifierDefinition extends BaseASTNode {
name: string;
}
export interface ModifierInvocation extends BaseASTNode {
name: string;
}
export interface FunctionDefinition extends BaseASTNode {
name: string;
body?: Block;
}
export interface ReturnParameters extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ModifierList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface EventDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface EnumValue extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface EnumDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ParameterList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface Parameter extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface EventParameterList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface EventParameter extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface FunctionTypeParameterList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface FunctionTypeParameter extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface VariableDeclaration extends BaseASTNode {
visibility: "public" | "private";
isStateVar: boolean;
}
export interface TypeName extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface UserDefinedTypeName extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface Mapping extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface FunctionTypeName extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface StorageLocation extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface StateMutability extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface Block extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface Statement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface EmitStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ExpressionStatement extends BaseASTNode {
expression: ASTNode;
}
export interface IfStatement extends BaseASTNode {
trueBody: ASTNode;
falseBody: ASTNode;
}
export interface WhileStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface SimpleStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ForStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface InlineAssemblyStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface DoWhileStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ContinueStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface BreakStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ReturnStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ThrowStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface VariableDeclarationStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface IdentifierList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ElementaryTypeName extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface Expression extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface PrimaryExpression extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ExpressionList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface NameValueList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface NameValue extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface FunctionCallArguments extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyBlock extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyItem extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyExpression extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyCall extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyLocalDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyAssignment extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyIdentifierOrList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyIdentifierList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyStackAssignment extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface LabelDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblySwitch extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyCase extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyFunctionDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyFunctionReturns extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyFor extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyIf extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface AssemblyLiteral extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface SubAssembly extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface TupleExpression extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface ElementaryTypeNameExpression extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface NumberLiteral extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export interface Identifier extends BaseASTNode {} // tslint:disable-line:no-empty-interface
export type BinOp =
| "+"
| "-"
| "*"
| "/"
| "**"
| "%"
| "<<"
| ">>"
| "&&"
| "||"
| "&"
| "|"
| "^"
| "<"
| ">"
| "<="
| ">="
| "=="
| "!="
| "="
| "|="
| "^="
| "&="
| "<<="
| ">>="
| "+="
| "-="
| "*="
| "/="
| "%=";
export interface BinaryOperation extends BaseASTNode {
left: ASTNode;
right: ASTNode;
operator: BinOp;
}
export interface Conditional extends BaseASTNode {
trueExpression: ASTNode;
falseExpression: ASTNode;
}
export type ASTNode =
| SourceUnit
| PragmaDirective
| PragmaName
| PragmaValue
| Version
| VersionOperator
| VersionConstraint
| ImportDeclaration
| ImportDirective
| ContractDefinition
| InheritanceSpecifier
| ContractPart
| StateVariableDeclaration
| UsingForDeclaration
| StructDefinition
| ModifierDefinition
| ModifierInvocation
| FunctionDefinition
| ReturnParameters
| ModifierList
| EventDefinition
| EnumValue
| EnumDefinition
| ParameterList
| Parameter
| EventParameterList
| EventParameter
| FunctionTypeParameterList
| FunctionTypeParameter
| VariableDeclaration
| TypeName
| UserDefinedTypeName
| Mapping
| FunctionTypeName
| StorageLocation
| StateMutability
| Block
| Statement
| EmitStatement
| ExpressionStatement
| IfStatement
| WhileStatement
| SimpleStatement
| ForStatement
| InlineAssemblyStatement
| DoWhileStatement
| ContinueStatement
| BreakStatement
| ReturnStatement
| ThrowStatement
| VariableDeclarationStatement
| IdentifierList
| ElementaryTypeName
| Expression
| PrimaryExpression
| ExpressionList
| NameValueList
| NameValue
| FunctionCallArguments
| AssemblyBlock
| AssemblyItem
| AssemblyExpression
| AssemblyCall
| AssemblyLocalDefinition
| AssemblyAssignment
| AssemblyIdentifierOrList
| AssemblyIdentifierList
| AssemblyStackAssignment
| LabelDefinition
| AssemblySwitch
| AssemblyCase
| AssemblyFunctionDefinition
| AssemblyFunctionReturns
| AssemblyFor
| AssemblyIf
| AssemblyLiteral
| SubAssembly
| TupleExpression
| ElementaryTypeNameExpression
| NumberLiteral
| Identifier
| BinaryOperation
| Conditional;
export interface Visitor {
SourceUnit?: (node: SourceUnit) => void;
PragmaDirective?: (node: PragmaDirective) => void;
PragmaName?: (node: PragmaName) => void;
PragmaValue?: (node: PragmaValue) => void;
Version?: (node: Version) => void;
VersionOperator?: (node: VersionOperator) => void;
VersionConstraint?: (node: VersionConstraint) => void;
ImportDeclaration?: (node: ImportDeclaration) => void;
ImportDirective?: (node: ImportDirective) => void;
ContractDefinition?: (node: ContractDefinition) => void;
InheritanceSpecifier?: (node: InheritanceSpecifier) => void;
ContractPart?: (node: ContractPart) => void;
StateVariableDeclaration?: (node: StateVariableDeclaration) => void;
UsingForDeclaration?: (node: UsingForDeclaration) => void;
StructDefinition?: (node: StructDefinition) => void;
ModifierDefinition?: (node: ModifierDefinition) => void;
ModifierInvocation?: (node: ModifierInvocation) => void;
FunctionDefinition?: (node: FunctionDefinition) => void;
ReturnParameters?: (node: ReturnParameters) => void;
ModifierList?: (node: ModifierList) => void;
EventDefinition?: (node: EventDefinition) => void;
EnumValue?: (node: EnumValue) => void;
EnumDefinition?: (node: EnumDefinition) => void;
ParameterList?: (node: ParameterList) => void;
Parameter?: (node: Parameter) => void;
EventParameterList?: (node: EventParameterList) => void;
EventParameter?: (node: EventParameter) => void;
FunctionTypeParameterList?: (node: FunctionTypeParameterList) => void;
FunctionTypeParameter?: (node: FunctionTypeParameter) => void;
VariableDeclaration?: (node: VariableDeclaration) => void;
TypeName?: (node: TypeName) => void;
UserDefinedTypeName?: (node: UserDefinedTypeName) => void;
Mapping?: (node: Mapping) => void;
FunctionTypeName?: (node: FunctionTypeName) => void;
StorageLocation?: (node: StorageLocation) => void;
StateMutability?: (node: StateMutability) => void;
Block?: (node: Block) => void;
Statement?: (node: Statement) => void;
EmitStatement?: (node: Statement) => void;
ExpressionStatement?: (node: ExpressionStatement) => void;
IfStatement?: (node: IfStatement) => void;
WhileStatement?: (node: WhileStatement) => void;
SimpleStatement?: (node: SimpleStatement) => void;
ForStatement?: (node: ForStatement) => void;
InlineAssemblyStatement?: (node: InlineAssemblyStatement) => void;
DoWhileStatement?: (node: DoWhileStatement) => void;
ContinueStatement?: (node: ContinueStatement) => void;
BreakStatement?: (node: BreakStatement) => void;
ReturnStatement?: (node: ReturnStatement) => void;
ThrowStatement?: (node: ThrowStatement) => void;
VariableDeclarationStatement?: (node: VariableDeclarationStatement) => void;
IdentifierList?: (node: IdentifierList) => void;
ElementaryTypeName?: (node: ElementaryTypeName) => void;
Expression?: (node: Expression) => void;
PrimaryExpression?: (node: PrimaryExpression) => void;
ExpressionList?: (node: ExpressionList) => void;
NameValueList?: (node: NameValueList) => void;
NameValue?: (node: NameValue) => void;
FunctionCallArguments?: (node: FunctionCallArguments) => void;
AssemblyBlock?: (node: AssemblyBlock) => void;
AssemblyItem?: (node: AssemblyItem) => void;
AssemblyExpression?: (node: AssemblyExpression) => void;
AssemblyCall?: (node: AssemblyCall) => void;
AssemblyLocalDefinition?: (node: AssemblyLocalDefinition) => void;
AssemblyAssignment?: (node: AssemblyAssignment) => void;
AssemblyIdentifierOrList?: (node: AssemblyIdentifierOrList) => void;
AssemblyIdentifierList?: (node: AssemblyIdentifierList) => void;
AssemblyStackAssignment?: (node: AssemblyStackAssignment) => void;
LabelDefinition?: (node: LabelDefinition) => void;
AssemblySwitch?: (node: AssemblySwitch) => void;
AssemblyCase?: (node: AssemblyCase) => void;
AssemblyFunctionDefinition?: (node: AssemblyFunctionDefinition) => void;
AssemblyFunctionReturns?: (node: AssemblyFunctionReturns) => void;
AssemblyFor?: (node: AssemblyFor) => void;
AssemblyIf?: (node: AssemblyIf) => void;
AssemblyLiteral?: (node: AssemblyLiteral) => void;
SubAssembly?: (node: SubAssembly) => void;
TupleExpression?: (node: TupleExpression) => void;
ElementaryTypeNameExpression?: (node: ElementaryTypeNameExpression) => void;
NumberLiteral?: (node: NumberLiteral) => void;
Identifier?: (node: Identifier) => void;
BinaryOperation?: (node: BinaryOperation) => void;
Conditional?: (node: Conditional) => void;
}
export interface ParserOpts {
tolerant?: boolean;
range?: boolean;
loc?: boolean;
}
export function parse(sourceCode: string, parserOpts: ParserOpts): ASTNode;
export function visit(ast: ASTNode, visitor: Visitor): void;
}

View File

@ -48,7 +48,6 @@ const { extendZeroAddressShorthand, replaceZeroAddressShorthand } = AddressUtils
import { compact, last, recursiveMerge, groupBy } from './collections';
import { prepareForCompilation } from './solidity/remapImports';
import { removePureView } from './solidity/code';
import { File, getExternalContractUrl, Types } from './file';
function timer(ms) {
@ -320,7 +319,6 @@ const Utils = {
Types,
unitRegex,
urlJoin,
removePureView,
runCmd,
escapeHtml: logUtils.escapeHtml,
normalizeInput: logUtils.normalizeInput,

View File

@ -1,15 +0,0 @@
import * as fs from "fs-extra";
import * as globule from "globule";
import * as path from "path";
export const removePureView = (dir: string) => {
globule.find(path.join(dir, "**/*.sol")).forEach((filepath) => {
let source = fs.readFileSync(filepath, "utf-8");
source = replacePureView(source);
fs.writeFileSync(filepath, source);
});
};
export const replacePureView = (source: string) => {
return source.replace(/pure/g, "").replace(/view/g, "");
};

View File

@ -3,7 +3,6 @@ import * as path from "path";
import { groupBy } from "../collections";
import { File, Types } from "../file";
import { dappPath, embarkPath, urlJoin } from "../pathUtils";
import { removePureView, replacePureView } from "./code";
const FIND_IMPORTS_REGEX = /^import[\s]*(['"])(.*)\1;/gm;
const FIND_FILE_REGEX = /import[\s]*(['"])(.*)\1;/;
@ -197,10 +196,5 @@ export const prepareForCompilation = async (file: File, isCoverage = false) => {
content = await file.content;
}
if (!isCoverage) {
return content;
}
removePureView(dappPath(".embark"));
return replacePureView(content);
return content;
};

View File

@ -177,7 +177,6 @@
"shelljs": "0.5.3",
"simples": "0.8.8",
"solc": "0.5.0",
"solidity-parser-antlr": "0.4.2",
"source-map-support": "0.5.9",
"stream-json": "1.1.3",
"string-replace-async": "1.2.1",

View File

@ -2823,6 +2823,11 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/mocha@5.2.0":
version "5.2.0"
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.0.tgz#b3c8e69f038835db1a7fdc0b3d879fc50506e29e"
integrity sha512-YeDiSEzznwZwwp766SJ6QlrTyBYUGPSIwmREHVTmktUYiT/WADdWtpt9iH0KuUSf8lZLdI4lP0X6PBzPo5//JQ==
"@types/node-fetch@^1.6.8":
version "1.6.9"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-1.6.9.tgz#a750fb0f4cf2960bf72b462e4c86908022dd69c5"
@ -2845,6 +2850,11 @@
resolved "https://registry.yarnpkg.com/@types/os-locale/-/os-locale-2.1.0.tgz#0ded736612a79e900fa76f02c6ad566d046ad17a"
integrity sha512-1FI8uCzD//cYu6eDMrik91BevmE8xQLeV5Br2+dDjiluhTM5vtxTDXSaVY20rRV8V/XT6l+A1H12g5+hBtSQZg==
"@types/prettier@1.16.4":
version "1.16.4"
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.16.4.tgz#5e5e97702cb68498aaba7349b941648daaf2385c"
integrity sha512-MG7ExKBo7AQ5UrL1awyYLNinNM/kyXgE4iP4Ul9fB+T7n768Z5Xem8IZeP6Bna0xze8gkDly49Rgge2HOEw4xA==
"@types/pretty-ms@3.2.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@types/pretty-ms/-/pretty-ms-3.2.0.tgz#cdd35f7edac2310bbe2af86f5244625db7a101b1"
@ -6789,6 +6799,11 @@ dir-glob@^2.0.0:
dependencies:
path-type "^3.0.0"
dir-to-object@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/dir-to-object/-/dir-to-object-2.0.0.tgz#29723e9bd1c3e58e4f307bd04ff634c0370c8f8a"
integrity sha512-sXs0JKIhymON7T1UZuO2Ud6VTNAx/VTBXIl4+3mjb2RgfOpt+hectX0x04YqPOPdkeOAKoJuKqwqnXXURNPNEA==
dns-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@ -7095,7 +7110,7 @@ emoji-regex@^6.5.1:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2"
integrity sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==
emoji-regex@^7.0.1:
emoji-regex@^7.0.1, emoji-regex@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
@ -7487,6 +7502,13 @@ espree@^4.0.0:
acorn-jsx "^5.0.0"
eslint-visitor-keys "^1.0.0"
esprima-extract-comments@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/esprima-extract-comments/-/esprima-extract-comments-1.1.0.tgz#0dacab567a5900240de6d344cf18c33617becbc9"
integrity sha512-sBQUnvJwpeE9QnPrxh7dpI/dp67erYG4WXEAreAMoelPRpMR7NWb4YtwRPn9b+H1uLQKl/qS8WYmyaljTpjIsw==
dependencies:
esprima "^4.0.0"
esprima@2.7.x, esprima@^2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
@ -8042,6 +8064,14 @@ extglob@^2.0.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
extract-comments@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/extract-comments/-/extract-comments-1.1.0.tgz#b90bca033a056bd69b8ba1c6b6b120fc2ee95c18"
integrity sha512-dzbZV2AdSSVW/4E7Ti5hZdHWbA+Z80RJsJhr5uiL10oyjl/gy7/o+HI1HwK4/WSZhlq4SNKU3oUzXlM13Qx02Q==
dependencies:
esprima-extract-comments "^1.1.0"
parse-code-context "^1.0.0"
extract-opts@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/extract-opts/-/extract-opts-2.2.0.tgz#1fa28eba7352c6db480f885ceb71a46810be6d7d"
@ -13562,6 +13592,11 @@ parse-asn1@^5.0.0:
evp_bytestokey "^1.0.0"
pbkdf2 "^3.0.3"
parse-code-context@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-code-context/-/parse-code-context-1.0.0.tgz#718c295c593d0d19a37f898473268cc75e98de1e"
integrity sha512-OZQaqKaQnR21iqhlnPfVisFjBWjhnMl5J9MgbP8xC+EwoVqbXrq78lp+9Zb3ahmLzrIX5Us/qbvBnaS3hkH6OA==
parse-github-repo-url@^1.3.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50"
@ -14520,11 +14555,30 @@ preserve@^0.2.0:
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
prettier-plugin-solidity@1.0.0-alpha.25:
version "1.0.0-alpha.25"
resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-alpha.25.tgz#45b5c7aa68f69f2aa160cd1d2590c459cd89e6d4"
integrity sha512-NsjhpK/td17apZz8Jnp5FDzIvXyrTGqKIg7PNrpLcKMi+XBDoMV/sFrWiN1VLI4oqjHnDJo/e4VhALiUCBHfBQ==
dependencies:
dir-to-object "^2.0.0"
emoji-regex "^7.0.3"
escape-string-regexp "^1.0.5"
extract-comments "^1.1.0"
prettier "^1.15.3"
semver "^5.6.0"
solidity-parser-antlr "^0.4.4"
string-width "^3.0.0"
prettier@^1.14.2:
version "1.16.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.1.tgz#534c2c9d7853f8845e5e078384e71973bd74089f"
integrity sha512-XXUITwIkGb3CPJ2hforHah/zTINRyie5006Jd2HKy2qz7snEJXl0KLfsJZW/wst9g6R2rFvqba3VpNYdu1hDcA==
prettier@^1.15.3:
version "1.18.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea"
integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==
pretty-bytes@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
@ -16868,10 +16922,10 @@ solc@^0.4.13, solc@^0.4.25:
semver "^5.3.0"
yargs "^4.7.1"
solidity-parser-antlr@0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/solidity-parser-antlr/-/solidity-parser-antlr-0.4.2.tgz#b862eba5936e7a90b4f5f1c8eb1d33fe86650f78"
integrity sha512-0OKT2YKZAqPe14HN7Nbo24hjmnyUYh92UjyZG0Zz2rpQhl/w8asX8qHb+ASSXfayQaiW8g9zGIupXEE355tOQQ==
solidity-parser-antlr@0.4.5, solidity-parser-antlr@^0.4.4:
version "0.4.5"
resolved "https://registry.yarnpkg.com/solidity-parser-antlr/-/solidity-parser-antlr-0.4.5.tgz#4de1867f1a12df4553886209225bc80328aeb0c1"
integrity sha512-5GzhIs4hpY3XnGwMndgrOksD567O5WdUQPbpy2n2WA1m3algzUKYMf+Ne/QHd36TTUNvVV+iTWD5tKaCZfaOjg==
sort-keys@^2.0.0:
version "2.0.0"