Updated dist files.

This commit is contained in:
Richard Moore 2020-02-06 18:21:34 -05:00
parent a6b696d8bd
commit f9ab665b52
No known key found for this signature in database
GPG Key ID: 665176BE8E9DC651
105 changed files with 1533 additions and 876 deletions

@ -1 +1 @@
export declare const version = "abi/5.0.0-beta.144"; export declare const version = "abi/5.0.0-beta.145";

@ -1 +1 @@
export const version = "abi/5.0.0-beta.144"; export const version = "abi/5.0.0-beta.145";

@ -41,7 +41,7 @@ export declare class Interface {
}; };
readonly deploy: ConstructorFragment; readonly deploy: ConstructorFragment;
readonly _abiCoder: AbiCoder; readonly _abiCoder: AbiCoder;
static _isInterface: boolean; readonly _isInterface: boolean;
constructor(fragments: string | Array<Fragment | JsonFragment | string>); constructor(fragments: string | Array<Fragment | JsonFragment | string>);
format(format?: string): string | Array<string>; format(format?: string): string | Array<string>;
static getAbiCoder(): AbiCoder; static getAbiCoder(): AbiCoder;

@ -1 +1 @@
export declare const version = "abi/5.0.0-beta.144"; export declare const version = "abi/5.0.0-beta.145";

@ -1,3 +1,3 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "abi/5.0.0-beta.144"; exports.version = "abi/5.0.0-beta.145";

@ -41,7 +41,7 @@ export declare class Interface {
}; };
readonly deploy: ConstructorFragment; readonly deploy: ConstructorFragment;
readonly _abiCoder: AbiCoder; readonly _abiCoder: AbiCoder;
static _isInterface: boolean; readonly _isInterface: boolean;
constructor(fragments: string | Array<Fragment | JsonFragment | string>); constructor(fragments: string | Array<Fragment | JsonFragment | string>);
format(format?: string): string | Array<string>; format(format?: string): string | Array<string>;
static getAbiCoder(): AbiCoder; static getAbiCoder(): AbiCoder;

@ -31,7 +31,7 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"tarballHash": "0x6f0200ce3170d8149ac6b5a736d2bd519bfa6648d0a60ff773aafa47a17b1e85", "tarballHash": "0xea1c770d87b34f15239a3ddbc5813d90e7627b57b9afa633997dfb903ca51efd",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"version": "5.0.0-beta.144" "version": "5.0.0-beta.145"
} }

@ -1 +1 @@
export const version = "abi/5.0.0-beta.144"; export const version = "abi/5.0.0-beta.145";

@ -1 +1 @@
export declare const version = "abstract-signer/5.0.0-beta.139"; export declare const version = "abstract-signer/5.0.0-beta.140";

@ -1 +1 @@
export const version = "abstract-signer/5.0.0-beta.139"; export const version = "abstract-signer/5.0.0-beta.140";

@ -122,25 +122,9 @@ export class Signer {
if (tx.nonce == null) { if (tx.nonce == null) {
tx.nonce = this.getTransactionCount("pending"); tx.nonce = this.getTransactionCount("pending");
} }
/*
// checkTransaction does this...
if (tx.from == null) {
tx.from = this.getAddress();
} else {
tx.from = Promise.all([
this.getAddress(),
this.provider.resolveName(tx.from)
]).then((results) => {
if (results[0] !== results[1]) {
logger.throwArgumentError("from address mismatch", "transaction", transaction);
}
return results[0];
});
}
*/
if (tx.gasLimit == null) { if (tx.gasLimit == null) {
tx.gasLimit = this.estimateGas(tx).catch((error) => { tx.gasLimit = this.estimateGas(tx).catch((error) => {
logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, { return logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, {
tx: tx tx: tx
}); });
}); });

@ -1 +1 @@
export declare const version = "abstract-signer/5.0.0-beta.139"; export declare const version = "abstract-signer/5.0.0-beta.140";

@ -1,3 +1,3 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "abstract-signer/5.0.0-beta.139"; exports.version = "abstract-signer/5.0.0-beta.140";

@ -173,25 +173,9 @@ var Signer = /** @class */ (function () {
if (tx.nonce == null) { if (tx.nonce == null) {
tx.nonce = this.getTransactionCount("pending"); tx.nonce = this.getTransactionCount("pending");
} }
/*
// checkTransaction does this...
if (tx.from == null) {
tx.from = this.getAddress();
} else {
tx.from = Promise.all([
this.getAddress(),
this.provider.resolveName(tx.from)
]).then((results) => {
if (results[0] !== results[1]) {
logger.throwArgumentError("from address mismatch", "transaction", transaction);
}
return results[0];
});
}
*/
if (tx.gasLimit == null) { if (tx.gasLimit == null) {
tx.gasLimit = this.estimateGas(tx).catch(function (error) { tx.gasLimit = this.estimateGas(tx).catch(function (error) {
logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", logger_1.Logger.errors.UNPREDICTABLE_GAS_LIMIT, { return logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", logger_1.Logger.errors.UNPREDICTABLE_GAS_LIMIT, {
tx: tx tx: tx
}); });
}); });

@ -27,7 +27,7 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"tarballHash": "0xe2e6e52bcdae724519b652bf02b2c3779db22c7da7ce7af404c5a6b152a56fb0", "tarballHash": "0x45c10e64c71e99997884ff59d59e6e3829043a155d8109bc2ee644efc40c3c43",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"version": "5.0.0-beta.139" "version": "5.0.0-beta.140"
} }

@ -1 +1 @@
export const version = "abstract-signer/5.0.0-beta.139"; export const version = "abstract-signer/5.0.0-beta.140";

@ -161,32 +161,15 @@ export abstract class Signer {
// By default called from: (overriding these prevents it) // By default called from: (overriding these prevents it)
// - sendTransaction // - sendTransaction
async populateTransaction(transaction: TransactionRequest): Promise<TransactionRequest> { async populateTransaction(transaction: TransactionRequest): Promise<TransactionRequest> {
const tx = await resolveProperties(this.checkTransaction(transaction)) const tx: TransactionRequest = await resolveProperties(this.checkTransaction(transaction))
if (tx.to != null) { tx.to = Promise.resolve(tx.to).then((to) => this.resolveName(to)); } if (tx.to != null) { tx.to = Promise.resolve(tx.to).then((to) => this.resolveName(to)); }
if (tx.gasPrice == null) { tx.gasPrice = this.getGasPrice(); } if (tx.gasPrice == null) { tx.gasPrice = this.getGasPrice(); }
if (tx.nonce == null) { tx.nonce = this.getTransactionCount("pending"); } if (tx.nonce == null) { tx.nonce = this.getTransactionCount("pending"); }
/*
// checkTransaction does this...
if (tx.from == null) {
tx.from = this.getAddress();
} else {
tx.from = Promise.all([
this.getAddress(),
this.provider.resolveName(tx.from)
]).then((results) => {
if (results[0] !== results[1]) {
logger.throwArgumentError("from address mismatch", "transaction", transaction);
}
return results[0];
});
}
*/
if (tx.gasLimit == null) { if (tx.gasLimit == null) {
tx.gasLimit = this.estimateGas(tx).catch((error) => { tx.gasLimit = this.estimateGas(tx).catch((error) => {
logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, { return logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, {
tx: tx tx: tx
}); });
}); });

@ -1 +1 @@
export declare const version = "asm/5.0.0-beta.148"; export declare const version = "asm/5.0.0-beta.149";

@ -1 +1 @@
export const version = "asm/5.0.0-beta.148"; export const version = "asm/5.0.0-beta.149";

@ -1,15 +1,16 @@
import { Opcode } from "./opcodes"; import { Opcode } from "./opcodes";
export declare type Location = { export declare type Location = {
offset: number; offset: number;
line: number;
length: number; length: number;
source: string; source: string;
statement: boolean;
}; };
export declare type AssembleVisitFunc = (node: Node, bytecode: string) => void; export declare type AssembleVisitFunc = (node: Node, bytecode: string) => void;
export declare type VisitFunc = (node: Node) => void; export declare type VisitFunc = (node: Node) => void;
export declare abstract class Node { export declare abstract class Node {
readonly tag: string; readonly tag: string;
readonly location: Location; readonly location: Location;
readonly warnings: Array<string>;
constructor(guard: any, location: Location, options: { constructor(guard: any, location: Location, options: {
[key: string]: any; [key: string]: any;
}); });
@ -30,6 +31,12 @@ export declare class LiteralNode extends ValueNode {
assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>; assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>;
static from(options: any): LiteralNode; static from(options: any): LiteralNode;
} }
export declare class PopNode extends ValueNode {
readonly index: number;
constructor(guard: any, location: Location, index: number);
readonly placeholder: string;
static from(options: any): PopNode;
}
export declare class LinkNode extends ValueNode { export declare class LinkNode extends ValueNode {
readonly type: string; readonly type: string;
readonly label: string; readonly label: string;
@ -40,7 +47,8 @@ export declare class LinkNode extends ValueNode {
export declare class OpcodeNode extends ValueNode { export declare class OpcodeNode extends ValueNode {
readonly opcode: Opcode; readonly opcode: Opcode;
readonly operands: Array<ValueNode>; readonly operands: Array<ValueNode>;
constructor(guard: any, location: Location, opcode: Opcode, operands: Array<ValueNode>); readonly instructional: boolean;
constructor(guard: any, location: Location, opcode: Opcode, operands: Array<ValueNode>, instructional: boolean);
assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>; assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>;
children(): Array<Node>; children(): Array<Node>;
visit(visit: VisitFunc): void; visit(visit: VisitFunc): void;
@ -61,7 +69,6 @@ export declare class DataNode extends LabelledNode {
constructor(guard: any, location: Location, name: string, data: string); constructor(guard: any, location: Location, name: string, data: string);
assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>; assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>;
children(): Array<Node>; children(): Array<Node>;
visit(visit: VisitFunc): void;
static from(options: any): DataNode; static from(options: any): DataNode;
} }
export declare class EvaluationNode extends ValueNode { export declare class EvaluationNode extends ValueNode {
@ -82,10 +89,8 @@ export declare class ScopeNode extends LabelledNode {
constructor(guard: any, location: Location, name: string, statements: Array<Node>); constructor(guard: any, location: Location, name: string, statements: Array<Node>);
assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>; assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>;
children(): Array<Node>; children(): Array<Node>;
visit(visit: VisitFunc): void;
static from(options: any): ScopeNode; static from(options: any): ScopeNode;
} }
export declare function parse(code: string): Node;
export declare type Operation = { export declare type Operation = {
opcode: Opcode; opcode: Opcode;
offset: number; offset: number;
@ -96,15 +101,15 @@ export interface Bytecode extends Array<Operation> {
} }
export declare function disassemble(bytecode: string): Bytecode; export declare function disassemble(bytecode: string): Bytecode;
export declare function formatBytecode(bytecode: Array<Operation>): string; export declare function formatBytecode(bytecode: Array<Operation>): string;
interface DataSource extends Array<number> { export interface DataSource extends Array<number> {
readonly offset: number; offset: number;
ast: Node;
source: string;
} }
declare type NodeState = { export declare type NodeState = {
node: Node; node: Node;
offset: number; offset: number;
bytecode: string; bytecode: string;
pending: string;
object?: number | DataSource;
}; };
export declare type AssemblerOptions = { export declare type AssemblerOptions = {
filename?: string; filename?: string;
@ -113,42 +118,46 @@ export declare type AssemblerOptions = {
defines?: { defines?: {
[name: string]: any; [name: string]: any;
}; };
target?: string;
};
export declare type ParserOptions = {
ignoreWarnings?: boolean;
}; };
declare class Assembler { declare class Assembler {
readonly root: Node; readonly root: Node;
readonly positionIndependentCode: boolean;
readonly nodes: { readonly nodes: {
[tag: string]: NodeState; [tag: string]: NodeState;
}; };
readonly labels: { readonly labels: {
[name: string]: LabelledNode; [name: string]: LabelledNode;
}; };
readonly filename: string; _parents: {
readonly positionIndependentCode: boolean; [tag: string]: Node;
readonly retry: number;
readonly defines: {
[name: string]: any;
}; };
private _stack; constructor(root: Node, positionIndependentCode?: boolean);
private _parents; getTarget(label: string): LabelledNode;
private _script;
private _changed;
constructor(root: Node, options: AssemblerOptions);
readonly changed: boolean;
getTarget(name: string): LabelledNode;
reset(): void;
evaluate(script: string, source: Node): Promise<any>; evaluate(script: string, source: Node): Promise<any>;
start(node: Node): void;
end(node: Node): void;
getPendingBytecode(node: Node): string;
_appendBytecode(bytecode: string): void;
getAncestor<T = Node>(node: Node, cls: { getAncestor<T = Node>(node: Node, cls: {
new (...args: any[]): T; new (...args: any[]): T;
}): T; }): T;
getOffset(node: Node, source?: Node): number;
setOffset(node: Node, offset: number): void;
getBytecode(node: Node): string;
setBytecode(node: Node, bytecode: string): void;
getLinkValue(target: LabelledNode, source: Node): number | DataSource; getLinkValue(target: LabelledNode, source: Node): number | DataSource;
get(name: string, source: Node): any; start(node: Node): void;
_didChange(): void; end(node: Node): void;
_assemble(): Promise<string>;
assemble(): Promise<string>;
} }
export declare enum SemanticErrorSeverity {
error = "error",
warning = "warning"
}
export declare type SemanticError = {
readonly message: string;
readonly severity: SemanticErrorSeverity;
readonly node: Node;
};
export declare function parse(code: string, options?: ParserOptions): Node;
export declare function assemble(ast: Node, options?: AssemblerOptions): Promise<string>; export declare function assemble(ast: Node, options?: AssemblerOptions): Promise<string>;
export {}; export {};

@ -9,10 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}); });
}; };
// @TODO: // @TODO:
// - PIC
// - warn on opcode non-function iff parameters
// - warn return/revert non-empty, comment ; !assert(+1 @extra) // - warn return/revert non-empty, comment ; !assert(+1 @extra)
// - $$
// - In JS add config (positionIndependent) // - In JS add config (positionIndependent)
// - When checking name collisions, verify no collision in javascript // - When checking name collisions, verify no collision in javascript
import { dirname, resolve } from "path"; import { dirname, resolve } from "path";
@ -118,9 +115,8 @@ export class Node {
throw new Error("cannot instantiate class"); throw new Error("cannot instantiate class");
} }
logger.checkAbstract(new.target, Node); logger.checkAbstract(new.target, Node);
ethers.utils.defineReadOnly(this, "location", location); ethers.utils.defineReadOnly(this, "location", Object.freeze(location));
ethers.utils.defineReadOnly(this, "tag", `node-${nextTag++}-${this.constructor.name}`); ethers.utils.defineReadOnly(this, "tag", `node-${nextTag++}-${this.constructor.name}`);
ethers.utils.defineReadOnly(this, "warnings", []);
for (const key in options) { for (const key in options) {
ethers.utils.defineReadOnly(this, key, options[key]); ethers.utils.defineReadOnly(this, key, options[key]);
} }
@ -139,6 +135,9 @@ export class Node {
} }
visit(visit) { visit(visit) {
visit(this); visit(this);
this.children().forEach((child) => {
child.visit(visit);
});
} }
static from(options) { static from(options) {
const Factories = { const Factories = {
@ -151,6 +150,7 @@ export class Node {
length: LinkNode, length: LinkNode,
offset: LinkNode, offset: LinkNode,
opcode: OpcodeNode, opcode: OpcodeNode,
pop: PopNode,
scope: ScopeNode, scope: ScopeNode,
}; };
const factory = Factories[options.type]; const factory = Factories[options.type];
@ -160,14 +160,6 @@ export class Node {
return factory.from(options); return factory.from(options);
} }
} }
/*
export abstract class CodeNode extends Node {
constructor(guard: any, location: Location, options: { [ key: string ]: any }) {
logger.checkAbstract(new.target, CodeNode);
super(guard, location, options);
}
}
*/
export class ValueNode extends Node { export class ValueNode extends Node {
constructor(guard, location, options) { constructor(guard, location, options) {
logger.checkAbstract(new.target, ValueNode); logger.checkAbstract(new.target, ValueNode);
@ -215,6 +207,20 @@ export class LiteralNode extends ValueNode {
return new LiteralNode(Guard, options.loc, options.value, !!options.verbatim); return new LiteralNode(Guard, options.loc, options.value, !!options.verbatim);
} }
} }
export class PopNode extends ValueNode {
constructor(guard, location, index) {
super(guard, location, { index });
}
get placeholder() {
if (this.index === 0) {
return "$$";
}
return "$" + String(this.index);
}
static from(options) {
return new PopNode(Guard, options.loc, options.index);
}
}
export class LinkNode extends ValueNode { export class LinkNode extends ValueNode {
constructor(guard, location, type, label) { constructor(guard, location, type, label) {
super(guard, location, { type, label }); super(guard, location, { type, label });
@ -223,28 +229,65 @@ export class LinkNode extends ValueNode {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
assembler.start(this); assembler.start(this);
let value = null; let value = null;
let isOffset = false;
const target = assembler.getTarget(this.label); const target = assembler.getTarget(this.label);
if (target instanceof LabelNode) { if (target instanceof LabelNode) {
if (this.type === "offset") { if (this.type === "offset") {
//value = assembler.getOffset(this.label);
value = (assembler.getLinkValue(target, this)); value = (assembler.getLinkValue(target, this));
isOffset = true;
} }
} }
else { else {
const result = (assembler.getLinkValue(target, this)); const result = (assembler.getLinkValue(target, this));
if (this.type === "offset") { if (this.type === "offset") {
//value = assembler.getOffset(this.label);
value = result.offset; value = result.offset;
isOffset = true;
} }
else if (this.type === "length") { else if (this.type === "length") {
//value = assembler.getLength(this.label);
value = result.length; value = result.length;
} }
} }
if (value == null) { if (value == null) {
throw new Error("labels can only be targetted as offsets"); throw new Error("labels can only be targetted as offsets");
} }
if (isOffset && assembler.positionIndependentCode) {
const here = assembler.getOffset(this, this);
const opcodes = [];
if (here > value) {
// Jump backwards
// Find a literal with length the encodes its own length in the delta
let literal = "0x";
for (let w = 1; w <= 5; w++) {
if (w > 4) {
throw new Error("jump too large!");
}
literal = pushLiteral(here - value + w);
if (ethers.utils.hexDataLength(literal) <= w) {
literal = ethers.utils.hexZeroPad(literal, w);
break;
}
}
opcodes.push(literal);
opcodes.push(Opcode.from("PC"));
opcodes.push(Opcode.from("SUB"));
// This also works, in case the above literal thing doesn't work out...
//opcodes.push(Opcode.from("PC"));
//opcodes.push(pushLiteral(-delta));
//opcodes.push(Opcode.from("SWAP1"));
//opcodes.push(Opcode.from("SUB"));
}
else {
// Jump forwards; this is easy to calculate since we can
// do PC firat.
opcodes.push(Opcode.from("PC"));
opcodes.push(pushLiteral(value - here));
opcodes.push(Opcode.from("ADD"));
}
visit(this, hexConcat(opcodes));
}
else {
visit(this, pushLiteral(value)); visit(this, pushLiteral(value));
}
assembler.end(this); assembler.end(this);
}); });
} }
@ -254,11 +297,8 @@ export class LinkNode extends ValueNode {
} }
} }
export class OpcodeNode extends ValueNode { export class OpcodeNode extends ValueNode {
constructor(guard, location, opcode, operands) { constructor(guard, location, opcode, operands, instructional) {
super(guard, location, { opcode, operands }); super(guard, location, { instructional, opcode, operands });
if (opcode.isPush()) {
this.warnings.push("the PUSH opcode modifies program flow - use literals instead");
}
} }
assemble(assembler, visit) { assemble(assembler, visit) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
@ -289,23 +329,14 @@ export class OpcodeNode extends ValueNode {
if (!opcode) { if (!opcode) {
throw new Error("unknown opcode: " + options.mnemonic); throw new Error("unknown opcode: " + options.mnemonic);
} }
// Using the function syntax will check the operand count
if (!options.bare) {
if (opcode.mnemonic === "POP" && options.operands.length === 0) {
// This is ok... Pop has a delta of 0, but without operands
}
else if (options.operands.length !== opcode.delta) {
throw new Error(`opcode ${opcode.mnemonic} expects ${opcode.delta} operands`);
}
}
const operands = Object.freeze(options.operands.map((o) => { const operands = Object.freeze(options.operands.map((o) => {
const operand = Node.from(o); const operand = Node.from(o);
if (!(operand instanceof ValueNode)) { if (!(operand instanceof ValueNode)) {
throw new Error("invalid operand"); throw new Error("bad grammar?!");
} }
return operand; return operand;
})); }));
return new OpcodeNode(Guard, options.loc, opcode, operands); return new OpcodeNode(Guard, options.loc, opcode, operands, !!options.bare);
} }
} }
export class LabelledNode extends Node { export class LabelledNode extends Node {
@ -344,7 +375,7 @@ export class DataNode extends LabelledNode {
// We pad data if is contains PUSH opcodes that would overrun // We pad data if is contains PUSH opcodes that would overrun
// the data, which could eclipse valid operations (since the // the data, which could eclipse valid operations (since the
// VM won't execute or jump within PUSH operations) // VM won't execute or jump within PUSH operations)
const bytecode = ethers.utils.arrayify(assembler.getPendingBytecode(this)); const bytecode = ethers.utils.arrayify(assembler.getBytecode(this));
// Replay the data as bytecode, skipping PUSH data // Replay the data as bytecode, skipping PUSH data
let i = 0; let i = 0;
while (i < bytecode.length) { while (i < bytecode.length) {
@ -365,12 +396,6 @@ export class DataNode extends LabelledNode {
children() { children() {
return this.data; return this.data;
} }
visit(visit) {
visit(this);
for (let i = 0; i < this.data.length; i++) {
this.data[i].visit(visit);
}
}
static from(options) { static from(options) {
if (options.type !== "data") { if (options.type !== "data") {
throw new Error("expected data type"); throw new Error("expected data type");
@ -442,12 +467,6 @@ export class ScopeNode extends LabelledNode {
children() { children() {
return this.statements; return this.statements;
} }
visit(visit) {
visit(this);
for (let i = 0; i < this.statements.length; i++) {
this.statements[i].visit(visit);
}
}
static from(options) { static from(options) {
if (options.type !== "scope") { if (options.type !== "scope") {
throw new Error("expected scope type"); throw new Error("expected scope type");
@ -455,56 +474,6 @@ export class ScopeNode extends LabelledNode {
return new ScopeNode(Guard, options.loc, options.name, Object.freeze(options.statements.map((s) => Node.from(s)))); return new ScopeNode(Guard, options.loc, options.name, Object.freeze(options.statements.map((s) => Node.from(s))));
} }
} }
export function parse(code) {
// Since jison allows \n, \r or \r\n line endings, we need some
// twekaing to get the correct position
const lines = [];
let offset = 0;
code.split(/(\r\n?|\n)/g).forEach((clump, index) => {
if (index % 2) {
lines[lines.length - 1].line += clump;
}
else {
lines.push({ line: clump, offset: offset });
}
offset += clump.length;
});
// Add a mock-EOF to the end of the file so we don't out-of-bounds
// on the last character
if (lines.length) {
lines[lines.length - 1].line += "\n";
}
// Givens a line (1 offset) and column (0 offset) return the byte offset
const getOffset = function (line, column) {
const info = lines[line - 1];
if (!info || column >= info.line.length) {
throw new Error("out of range");
}
return info.offset + column;
};
// We use this in the _parser to convert locations to source
_parser.yy._ethersLocation = function (loc) {
// The _ scope should call with null to get the full source
if (loc == null) {
return Object.freeze({
offset: 0,
length: code.length,
source: code
});
}
const offset = getOffset(loc.first_line, loc.first_column);
const end = getOffset(loc.last_line, loc.last_column);
return Object.freeze({
offset: offset,
length: (end - offset),
source: code.substring(offset, end)
});
};
const result = Node.from(_parse(code));
// Nuke the source code lookup callback
_parser.yy._ethersLocation = null;
return result;
}
export function disassemble(bytecode) { export function disassemble(bytecode) {
const ops = []; const ops = [];
const offsets = {}; const offsets = {};
@ -568,14 +537,10 @@ export function formatBytecode(bytecode) {
}); });
return lines.join("\n"); return lines.join("\n");
} }
// @TODO: Rename to Assembler?
class Assembler { class Assembler {
constructor(root, options) { constructor(root, positionIndependentCode) {
ethers.utils.defineReadOnly(this, "positionIndependentCode", !!options.positionIndependentCode);
ethers.utils.defineReadOnly(this, "retry", ((options.retry != null) ? options.retry : 512));
ethers.utils.defineReadOnly(this, "filename", resolve(options.filename || "./contract.asm"));
ethers.utils.defineReadOnly(this, "defines", Object.freeze(options.defines || {}));
ethers.utils.defineReadOnly(this, "root", root); ethers.utils.defineReadOnly(this, "root", root);
ethers.utils.defineReadOnly(this, "positionIndependentCode", !!positionIndependentCode);
const nodes = {}; const nodes = {};
const labels = {}; const labels = {};
const parents = {}; const parents = {};
@ -584,8 +549,7 @@ class Assembler {
nodes[node.tag] = { nodes[node.tag] = {
node: node, node: node,
offset: 0x0, offset: 0x0,
bytecode: "0x", bytecode: "0x"
pending: "0x"
}; };
if (node instanceof LabelledNode) { if (node instanceof LabelledNode) {
// Check for duplicate labels // Check for duplicate labels
@ -611,52 +575,14 @@ class Assembler {
ethers.utils.defineReadOnly(this, "labels", Object.freeze(labels)); ethers.utils.defineReadOnly(this, "labels", Object.freeze(labels));
ethers.utils.defineReadOnly(this, "nodes", Object.freeze(nodes)); ethers.utils.defineReadOnly(this, "nodes", Object.freeze(nodes));
ethers.utils.defineReadOnly(this, "_parents", Object.freeze(parents)); ethers.utils.defineReadOnly(this, "_parents", Object.freeze(parents));
ethers.utils.defineReadOnly(this, "_stack", []);
this.reset();
}
get changed() {
return this._changed;
} }
// Link operations // Link operations
getTarget(name) { getTarget(label) {
return this.labels[name]; return this.labels[label];
}
// Reset the assmebler for another run with updated values
reset() {
this._changed = false;
for (const tag in this.nodes) {
delete this.nodes[tag].object;
}
this._script = new Script(this.filename, (name, context) => {
return this.get(name, context);
});
} }
// Evaluate script in the context of a {{! }} or {{= }}
evaluate(script, source) { evaluate(script, source) {
return this._script.evaluate(script, source); return Promise.resolve(new Uint8Array(0));
}
start(node) {
this._stack.push(node);
const info = this.nodes[node.tag];
info.pending = "0x";
}
end(node) {
if (this._stack.pop() !== node) {
throw new Error("missing push/pop pair");
}
const info = this.nodes[node.tag];
if (info.pending !== info.bytecode) {
this._didChange();
}
info.bytecode = info.pending;
}
getPendingBytecode(node) {
return this.nodes[node.tag].pending;
}
_appendBytecode(bytecode) {
this._stack.forEach((node) => {
const info = this.nodes[node.tag];
info.pending = hexConcat([info.pending, bytecode]);
});
} }
getAncestor(node, cls) { getAncestor(node, cls) {
node = this._parents[node.tag]; node = this._parents[node.tag];
@ -668,6 +594,23 @@ class Assembler {
} }
return null; return null;
} }
getOffset(node, source) {
const offset = this.nodes[node.tag].offset;
if (source == null) {
return offset;
}
const sourceScope = ((source instanceof ScopeNode) ? source : this.getAncestor(source, ScopeNode));
return offset - this.nodes[sourceScope.tag].offset;
}
setOffset(node, offset) {
this.nodes[node.tag].offset = offset;
}
getBytecode(node) {
return this.nodes[node.tag].bytecode;
}
setBytecode(node, bytecode) {
this.nodes[node.tag].bytecode = bytecode;
}
getLinkValue(target, source) { getLinkValue(target, source) {
const sourceScope = ((source instanceof ScopeNode) ? source : this.getAncestor(source, ScopeNode)); const sourceScope = ((source instanceof ScopeNode) ? source : this.getAncestor(source, ScopeNode));
const targetScope = ((target instanceof ScopeNode) ? target : this.getAncestor(target, ScopeNode)); const targetScope = ((target instanceof ScopeNode) ? target : this.getAncestor(target, ScopeNode));
@ -678,13 +621,7 @@ class Assembler {
throw new Error(`cannot access ${target.name} from ${source.tag}`); throw new Error(`cannot access ${target.name} from ${source.tag}`);
} }
// Return the offset relative to its scope // Return the offset relative to its scope
let offset = this.nodes[target.tag].offset - this.nodes[targetScope.tag].offset; return this.nodes[target.tag].offset - this.nodes[targetScope.tag].offset;
// Offsets are wrong; but we should finish this run and then try again
if (offset < 0) {
offset = 0;
this._didChange();
}
return offset;
} }
const info = this.nodes[target.tag]; const info = this.nodes[target.tag];
// Return the offset is relative to its scope // Return the offset is relative to its scope
@ -713,14 +650,209 @@ class Assembler {
// been marked as invalid, in which case accessing it will fail // been marked as invalid, in which case accessing it will fail
if (safeOffset) { if (safeOffset) {
bytes.offset = info.offset - this.nodes[sourceScope.tag].offset; bytes.offset = info.offset - this.nodes[sourceScope.tag].offset;
// Offsets are wqrong; but we should finish this run and then try again }
if (bytes.offset < 0) { return bytes;
bytes.offset = 0; }
start(node) { }
end(node) { }
}
export var SemanticErrorSeverity;
(function (SemanticErrorSeverity) {
SemanticErrorSeverity["error"] = "error";
SemanticErrorSeverity["warning"] = "warning";
})(SemanticErrorSeverity || (SemanticErrorSeverity = {}));
;
// This Assembler is designed to only check for errors and warnings
// Warnings
// - Bare PUSH opcodes
// - Instructional opcode that has parameters
// Errors
// - Using a $$ outside of RPN
// - Using a $$ when it is not adjacent to the stack
// - The operand count does not match the opcode
// - An opcode is used as an operand but does not return a value
class SemanticChecker extends Assembler {
check() {
const errors = [];
this.root.visit((node) => {
if (node instanceof OpcodeNode) {
const opcode = node.opcode;
if (node.instructional) {
if (opcode.delta) {
errors.push({
message: `${opcode.mnemonic} used as instructional`,
severity: SemanticErrorSeverity.warning,
node: node
});
}
}
else {
if (opcode.mnemonic === "POP") {
if (node.operands.length !== 0) {
errors.push({
message: "POP expects 0 operands",
severity: SemanticErrorSeverity.error,
node: node
});
}
}
else if (node.operands.length !== opcode.delta) {
errors.push({
message: `${opcode.mnemonic} expects ${opcode.delta} operands`,
severity: SemanticErrorSeverity.error,
node: node
});
}
}
if (opcode.isPush()) {
// A stray PUSH operation will gobble up the following code
// bytes which is bad. But this may be a disassembled program
// and that PUSH may actually be just some data (which is safe)
errors.push({
message: "PUSH opcode modifies program flow - use literals instead",
severity: SemanticErrorSeverity.warning,
node: node
});
}
else if (!node.location.statement && opcode.alpha !== 1) {
// If an opcode does not push anything on the stack, it
// cannot be used as an operand
errors.push({
message: `${node.opcode.mnemonic} cannot be an operand`,
severity: SemanticErrorSeverity.error,
node: node
});
}
}
if (node.location.statement) {
if (node instanceof PopNode) {
// $$ by istelf is useless and is intended to be an operand
errors.push({
message: `$$ must be an operand`,
severity: SemanticErrorSeverity.error,
node: node
});
}
else {
const scope = this.getAncestor(node, ScopeNode);
// Make sure any $$ is stack adjacent (within this scope)
const ordered = [];
node.visit((node) => {
if (scope !== this.getAncestor(node, ScopeNode)) {
return;
}
ordered.push(node);
});
// Allow any number of stack adjacent $$
let foundZero = null;
let lastIndex = 0;
while (ordered.length && ordered[0] instanceof PopNode) {
const popNode = (ordered.shift());
const index = popNode.index;
if (index === 0) {
foundZero = popNode;
}
else if (index !== lastIndex + 1) {
errors.push({
message: `out-of-order stack placeholder ${popNode.placeholder}; expected $$${lastIndex + 1}`,
severity: SemanticErrorSeverity.error,
node: popNode
});
while (ordered.length && ordered[0] instanceof PopNode) {
ordered.shift();
}
break;
}
else {
lastIndex = index;
}
}
if (foundZero && lastIndex > 0) {
errors.push({
message: "cannot mix $$ and $1 stack placeholder",
severity: SemanticErrorSeverity.error,
node: foundZero
});
}
// If there are still any buried, we have a problem
const pops = ordered.filter((n) => (n instanceof PopNode));
if (pops.length) {
errors.push({
message: `stack placeholder ${(pops[0]).placeholder} must be stack adjacent`,
severity: SemanticErrorSeverity.error,
node: pops[0]
});
}
}
}
});
return errors;
}
}
class CodeGenerationAssembler extends Assembler {
constructor(root, options) {
super(root, !!options.positionIndependentCode);
ethers.utils.defineReadOnly(this, "retry", ((options.retry != null) ? options.retry : 512));
ethers.utils.defineReadOnly(this, "filename", resolve(options.filename || "./contract.asm"));
ethers.utils.defineReadOnly(this, "defines", Object.freeze(options.defines || {}));
ethers.utils.defineReadOnly(this, "_stack", []);
this.reset();
}
_didChange() {
this._changed = true;
}
get changed() {
return this._changed;
}
// Reset the assmebler for another run with updated values
reset() {
this._changed = false;
this._oldBytecode = {};
this._objectCache = {};
this._script = new Script(this.filename, (name, context) => {
return this.get(name, context);
});
}
evaluate(script, source) {
return this._script.evaluate(script, source);
}
getLinkValue(target, source) {
// Since we are iteratively generating code, offsets and lengths
// may not be stable at any given point in time, so if an offset
// is negative the code is obviously wrong, however we set it to
// 0 so we can proceed with generation to fill in as many blanks
// as possible; then we will try assembling again
const result = super.getLinkValue(target, source);
if (typeof (result) === "number") {
if (result < 0) {
this._didChange();
return 0;
}
return result;
}
if (result.offset < 0) {
result.offset = 0;
this._didChange();
}
return result;
}
start(node) {
this._stack.push(node);
this._oldBytecode[node.tag] = this.getBytecode(node);
this.setBytecode(node, "0x");
}
end(node) {
if (this._stack.pop() !== node) {
throw new Error("missing push/pop pair");
}
if (this._oldBytecode[node.tag] !== this.getBytecode(node)) {
this._didChange(); this._didChange();
} }
} }
return Object.freeze(bytes); // This is used by evaluate to access properties in JavaScript
} // - "defines" allow meta-programming values to be used
// - jump destinations are available as numbers
// - bytecode and data are available as an immuatble DataSource
get(name, source) { get(name, source) {
if (name === "defines") { if (name === "defines") {
return this.defines; return this.defines;
@ -729,67 +861,137 @@ class Assembler {
if (!node) { if (!node) {
return undefined; return undefined;
} }
const info = this.nodes[node.tag]; // We cache objects when they are generated so all nodes
if (info.object == null) { // receive consistent data; if there is a change we will
info.object = this.getLinkValue(node, source); // run the entire assembly process again with the updated
// values
if (this._objectCache[node.tag] == null) {
this._objectCache[node.tag] = Object.freeze(this.getLinkValue(node, source));
} }
return info.object; return this._objectCache[node.tag];
}
_didChange() {
this._changed = true;
} }
_assemble() { _assemble() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
let offset = 0; let offset = 0;
const bytecodes = [];
yield this.root.assemble(this, (node, bytecode) => { yield this.root.assemble(this, (node, bytecode) => {
const state = this.nodes[node.tag];
// Things have moved; we will need to try again // Things have moved; we will need to try again
if (state.offset !== offset) { if (this.getOffset(node) !== offset) {
state.offset = offset; this.setOffset(node, offset);
this._didChange(); this._didChange();
} }
this._appendBytecode(bytecode); this._stack.forEach((node) => {
bytecodes.push(bytecode); this.setBytecode(node, hexConcat([
// The bytecode has changed; we will need to try again this.getBytecode(node),
//if (state.bytecode !== bytecode) { bytecode
// state.bytecode = bytecode; ]));
// this._didChange(); });
//}
offset += ethers.utils.hexDataLength(bytecode); offset += ethers.utils.hexDataLength(bytecode);
}); });
return hexConcat(bytecodes);
}); });
} }
assemble() { assemble(label) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (label == null) {
label = "_";
}
const target = this.getTarget(label);
if (!target) {
logger.throwArgumentError(`unknown labelled target: ${label}`, "label", label);
}
else if (!(target instanceof ScopeNode || target instanceof DataNode)) {
logger.throwArgumentError(`cannot assemble a bodyless label: ${label}`, "label", label);
}
// Continue re-evaluating the bytecode until a stable set of // Continue re-evaluating the bytecode until a stable set of
// offsets, length and values are reached. // offsets, length and values are reached.
let bytecode = yield this._assemble(); yield this._assemble();
for (let i = 0; i < this.retry; i++) { for (let i = 0; i < this.retry; i++) {
// Regenerate the code with the updated assembler values // Regenerate the code with the updated assembler values
this.reset(); this.reset();
const adjusted = yield this._assemble(); yield this._assemble();
// Generated bytecode is stable!! :) // Generated bytecode is stable!! :)
if (!this.changed) { if (!this.changed) {
console.log(`Assembled in ${i} attempts`);
return bytecode;
}
// Try again...
bytecode = adjusted;
}
// This should not happen; something is wrong with the grammar // This should not happen; something is wrong with the grammar
// or missing enter/exit call in assemble // or missing enter/exit call in assemble
if (this._stack.length !== 0) { if (this._stack.length !== 0) {
throw new Error("bad AST"); throw new Error("Bad AST! Bad grammar?!");
}
//console.log(`Assembled in ${ i } attempts`);
return this.getBytecode(target);
;
}
} }
return logger.throwError(`unable to assemble; ${this.retry} attempts failed to generate stable bytecode`, ethers.utils.Logger.errors.UNKNOWN_ERROR, {}); return logger.throwError(`unable to assemble; ${this.retry} attempts failed to generate stable bytecode`, ethers.utils.Logger.errors.UNKNOWN_ERROR, {});
}); });
} }
} }
export function parse(code, options) {
if (options == null) {
options = {};
}
// Since jison allows \n, \r or \r\n line endings, we need some
// twekaing to get the correct position
const lines = [];
let offset = 0;
code.split(/(\r\n?|\n)/g).forEach((clump, index) => {
if (index % 2) {
lines[lines.length - 1].line += clump;
}
else {
lines.push({ line: clump, offset: offset });
}
offset += clump.length;
});
// Add a mock-EOF to the end of the file so we don't out-of-bounds
// on the last character
if (lines.length) {
lines[lines.length - 1].line += "\n";
}
// Givens a line (1 offset) and column (0 offset) return the byte offset
const getOffset = function (line, column) {
const info = lines[line - 1];
if (!info || column >= info.line.length) {
throw new Error("out of range");
}
return info.offset + column;
};
// We use this in the _parser to convert locations to source
_parser.yy._ethersLocation = function (loc) {
// The _ scope should call with null to get the full source
if (loc == null) {
return {
offset: 0,
line: 0,
length: code.length,
source: code,
statement: true
};
}
const offset = getOffset(loc.first_line, loc.first_column);
const end = getOffset(loc.last_line, loc.last_column);
return {
offset: offset,
line: loc.first_line - 1,
length: (end - offset),
source: code.substring(offset, end),
statement: (!!loc.statement)
};
};
const result = Node.from(_parse(code));
// Nuke the source code lookup callback
_parser.yy._ethersLocation = null;
// Semantic Checks
const checker = new SemanticChecker(result);
const errors = checker.check();
if (errors.filter((e) => (e.severity === SemanticErrorSeverity.error)).length || (errors.length && !options.ignoreWarnings)) {
const error = new Error("semantic errors during parsing");
error.errors = errors;
throw error;
}
return result;
}
export function assemble(ast, options) { export function assemble(ast, options) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const assembler = new Assembler(ast, options || {}); const assembler = new CodeGenerationAssembler(ast, options || {});
return assembler.assemble(); return assembler.assemble(options.target || "_");
}); });
} }

@ -1,4 +1,4 @@
import { assemble, DataNode, disassemble, EvaluationNode, ExecutionNode, formatBytecode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, parse, ScopeNode, ValueNode } from "./assembler"; import { assemble, DataNode, disassemble, EvaluationNode, ExecutionNode, formatBytecode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, parse, PopNode, ScopeNode, ValueNode } from "./assembler";
import { Opcode } from "./opcodes"; import { Opcode } from "./opcodes";
import { AssemblerOptions, AssembleVisitFunc, Bytecode, Location, Operation, VisitFunc } from "./assembler"; import { AssemblerOptions, AssembleVisitFunc, Bytecode, Location, Operation, ParserOptions, SemanticError, SemanticErrorSeverity, VisitFunc } from "./assembler";
export { Opcode, assemble, disassemble, formatBytecode, parse, DataNode, EvaluationNode, ExecutionNode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, ScopeNode, ValueNode, AssemblerOptions, AssembleVisitFunc, Bytecode, Location, Operation, VisitFunc, }; export { Opcode, assemble, disassemble, formatBytecode, parse, DataNode, EvaluationNode, ExecutionNode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, PopNode, ScopeNode, ValueNode, AssemblerOptions, AssembleVisitFunc, Bytecode, Location, Operation, SemanticError, SemanticErrorSeverity, ParserOptions, VisitFunc, };

@ -1,10 +1,11 @@
"use strict"; "use strict";
import { assemble, DataNode, disassemble, EvaluationNode, ExecutionNode, formatBytecode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, parse, ScopeNode, ValueNode } from "./assembler"; import { assemble, DataNode, disassemble, EvaluationNode, ExecutionNode, formatBytecode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, parse, PopNode, ScopeNode, ValueNode } from "./assembler";
import { Opcode } from "./opcodes"; import { Opcode } from "./opcodes";
import { SemanticErrorSeverity } from "./assembler";
export { export {
// Opcodes // Opcodes
Opcode, Opcode,
// Assembler functions // Assembler functions
assemble, disassemble, formatBytecode, parse, assemble, disassemble, formatBytecode, parse,
// Assembly AST Nodes // Assembly AST Nodes
DataNode, EvaluationNode, ExecutionNode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, ScopeNode, ValueNode, }; DataNode, EvaluationNode, ExecutionNode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, PopNode, ScopeNode, ValueNode, SemanticErrorSeverity, };

@ -1,3 +1,8 @@
export declare enum OpcodeMemoryAccess {
write = "write",
read = "read",
full = "full"
}
export declare class Opcode { export declare class Opcode {
readonly value: number; readonly value: number;
readonly mnemonic: string; readonly mnemonic: string;
@ -8,7 +13,7 @@ export declare class Opcode {
isJump(): boolean; isJump(): boolean;
isValidJumpDest(): boolean; isValidJumpDest(): boolean;
isPush(): number; isPush(): number;
isMemory(readOrWrite?: boolean): boolean; isMemoryAccess(readOrWrite?: boolean): OpcodeMemoryAccess;
isStatic(): boolean; isStatic(): boolean;
static from(valueOrMnemonic: number | string): Opcode; static from(valueOrMnemonic: number | string): Opcode;
} }

@ -8,6 +8,13 @@
// EXTCODEHASH // EXTCODEHASH
// See: https://eips.ethereum.org/EIPS/eip-1052 // See: https://eips.ethereum.org/EIPS/eip-1052
import { ethers } from "ethers"; import { ethers } from "ethers";
export var OpcodeMemoryAccess;
(function (OpcodeMemoryAccess) {
OpcodeMemoryAccess["write"] = "write";
OpcodeMemoryAccess["read"] = "read";
OpcodeMemoryAccess["full"] = "full";
})(OpcodeMemoryAccess || (OpcodeMemoryAccess = {}));
;
export class Opcode { export class Opcode {
constructor(mnemonic, value, delta, alpha, doc) { constructor(mnemonic, value, delta, alpha, doc) {
ethers.utils.defineReadOnly(this, "mnemonic", mnemonic); ethers.utils.defineReadOnly(this, "mnemonic", mnemonic);
@ -31,12 +38,19 @@ export class Opcode {
return 0; return 0;
} }
// Returns true if this operation writes to memory contents (or if readOrWrite, reads memory) // Returns true if this operation writes to memory contents (or if readOrWrite, reads memory)
isMemory(readOrWrite) { // Unknown opcodes return null
throw new Error("@TODO: return true if modifies memory"); isMemoryAccess(readOrWrite) {
switch ((_Opcodes[this.mnemonic.toLowerCase()] || { memory: null }).memory) {
case "read": return OpcodeMemoryAccess.read;
case "write": return OpcodeMemoryAccess.write;
case "full": return OpcodeMemoryAccess.full;
}
return null;
} }
// Returns true if this opcode does not affect state // Returns true if this opcode does not affect state
// Unknown opcodes return false
isStatic() { isStatic() {
throw new Error("@TODO: return true if certain non-state-changing"); return !(_Opcodes[this.mnemonic.toLowerCase()] || { nonStatic: true }).nonStatic;
} }
static from(valueOrMnemonic) { static from(valueOrMnemonic) {
if (typeof (valueOrMnemonic) === "string") { if (typeof (valueOrMnemonic) === "string") {
@ -75,7 +89,7 @@ const _Opcodes = {
shr: { value: 0x1c, delta: 2, alpha: 1, doc: "v = shr(shiftBits, value)" }, shr: { value: 0x1c, delta: 2, alpha: 1, doc: "v = shr(shiftBits, value)" },
sar: { value: 0x1d, delta: 2, alpha: 1, doc: "v = sar(shiftBits, value)" }, sar: { value: 0x1d, delta: 2, alpha: 1, doc: "v = sar(shiftBits, value)" },
// SHA3 // SHA3
sha3: { value: 0x20, delta: 2, alpha: 1, doc: "v = sha3(offset, length)" }, sha3: { value: 0x20, delta: 2, alpha: 1, doc: "v = sha3(offset, length)", memory: "read" },
// Environmental Information // Environmental Information
address: { value: 0x30, delta: 0, alpha: 1, doc: "myAddr = address" }, address: { value: 0x30, delta: 0, alpha: 1, doc: "myAddr = address" },
balance: { value: 0x31, delta: 1, alpha: 1, doc: "wei = balance(address)" }, balance: { value: 0x31, delta: 1, alpha: 1, doc: "wei = balance(address)" },
@ -84,14 +98,14 @@ const _Opcodes = {
callvalue: { value: 0x34, delta: 0, alpha: 1, doc: "msgValue = callvalue" }, callvalue: { value: 0x34, delta: 0, alpha: 1, doc: "msgValue = callvalue" },
calldataload: { value: 0x35, delta: 1, alpha: 1, doc: "calldataWordValue = calldataload(byteOffet)" }, calldataload: { value: 0x35, delta: 1, alpha: 1, doc: "calldataWordValue = calldataload(byteOffet)" },
calldatasize: { value: 0x36, delta: 0, alpha: 1, doc: "calldataLength = calldatasize" }, calldatasize: { value: 0x36, delta: 0, alpha: 1, doc: "calldataLength = calldatasize" },
calldatacopy: { value: 0x37, delta: 3, alpha: 0, doc: "calldatacopy(dstMemoryIndex, dataIndex, length)" }, calldatacopy: { value: 0x37, delta: 3, alpha: 0, doc: "calldatacopy(dstMemoryIndex, dataIndex, length)", memory: "write" },
codesize: { value: 0x38, delta: 0, alpha: 1, doc: "myCodeLength = codesize" }, codesize: { value: 0x38, delta: 0, alpha: 1, doc: "myCodeLength = codesize" },
codecopy: { value: 0x39, delta: 3, alpha: 0, doc: "codecopy(dstMemoryIndex, codeIndex, length)" }, codecopy: { value: 0x39, delta: 3, alpha: 0, doc: "codecopy(dstMemoryIndex, codeIndex, length)", memory: "write" },
gasprice: { value: 0x3a, delta: 0, alpha: 1, doc: "txGasPrice = gasprice" }, gasprice: { value: 0x3a, delta: 0, alpha: 1, doc: "txGasPrice = gasprice" },
extcodesize: { value: 0x3b, delta: 1, alpha: 1, doc: "otherCodeLength = extcodesize(address)" }, extcodesize: { value: 0x3b, delta: 1, alpha: 1, doc: "otherCodeLength = extcodesize(address)" },
extcodecopy: { value: 0x3c, delta: 4, alpha: 0, doc: "extcodecopy(address, dstMemoryIndex, extcodeIndex, length)" }, extcodecopy: { value: 0x3c, delta: 4, alpha: 0, doc: "extcodecopy(address, dstMemoryIndex, extcodeIndex, length)", memory: "write" },
returndatasize: { value: 0x3d, delta: 0, alpha: 1, doc: "v = returndatasize" }, returndatasize: { value: 0x3d, delta: 0, alpha: 1, doc: "v = returndatasize" },
returndatacopy: { value: 0x3e, delta: 3, alpha: 0, doc: "returndatacopy(dstMemoryOffset, returndataIndex, length)" }, returndatacopy: { value: 0x3e, delta: 3, alpha: 0, doc: "returndatacopy(dstMemoryOffset, returndataIndex, length)", memory: "write" },
extcodehash: { value: 0x3f, delta: 1, alpha: 1, doc: "hash = extcodehash(address)" }, extcodehash: { value: 0x3f, delta: 1, alpha: 1, doc: "hash = extcodehash(address)" },
// Block Information // Block Information
blockhash: { value: 0x40, delta: 1, alpha: 1, doc: "hash = blockhash(blockNumber)" }, blockhash: { value: 0x40, delta: 1, alpha: 1, doc: "hash = blockhash(blockNumber)" },
@ -102,11 +116,11 @@ const _Opcodes = {
gaslimit: { value: 0x45, delta: 0, alpha: 1, doc: "gas = gaslimit" }, gaslimit: { value: 0x45, delta: 0, alpha: 1, doc: "gas = gaslimit" },
// Stack, Memory, Storage and Flow Operations // Stack, Memory, Storage and Flow Operations
pop: { value: 0x50, delta: 1, alpha: 0, doc: "stackTopValue = pop" }, pop: { value: 0x50, delta: 1, alpha: 0, doc: "stackTopValue = pop" },
mload: { value: 0x51, delta: 1, alpha: 1, doc: "memoryWordValue = mload(memoryByteIndex)" }, mload: { value: 0x51, delta: 1, alpha: 1, doc: "memoryWordValue = mload(memoryByteIndex)", memory: "read" },
mstore: { value: 0x52, delta: 2, alpha: 0, doc: "mstore(memoryByteIndex, valueOut)" }, mstore: { value: 0x52, delta: 2, alpha: 0, doc: "mstore(memoryByteIndex, valueOut)", memory: "write" },
mstore8: { value: 0x53, delta: 2, alpha: 0, doc: "mstore8(memoryByteIndex, valueOut [ & 0xff ])" }, mstore8: { value: 0x53, delta: 2, alpha: 0, doc: "mstore8(memoryByteIndex, valueOut [ & 0xff ])", memory: "write" },
sload: { value: 0x54, delta: 1, alpha: 1, doc: "storageWordValue = sload(storageWordIndex)" }, sload: { value: 0x54, delta: 1, alpha: 1, doc: "storageWordValue = sload(storageWordIndex)" },
sstore: { value: 0x55, delta: 2, alpha: 0, doc: "sstore(storageWordIndex, valueOut)" }, sstore: { value: 0x55, delta: 2, alpha: 0, doc: "sstore(storageWordIndex, valueOut)", nonStatic: true },
jump: { value: 0x56, delta: 1, alpha: 0, doc: "jump(target)" }, jump: { value: 0x56, delta: 1, alpha: 0, doc: "jump(target)" },
jumpi: { value: 0x57, delta: 2, alpha: 0, doc: "jumpi(target, notZero)" }, jumpi: { value: 0x57, delta: 2, alpha: 0, doc: "jumpi(target, notZero)" },
pc: { value: 0x58, delta: 0, alpha: 1, doc: "programCounter = pc" }, pc: { value: 0x58, delta: 0, alpha: 1, doc: "programCounter = pc" },
@ -181,22 +195,22 @@ const _Opcodes = {
swap15: { value: 0x9e, delta: 0, alpha: 0 }, swap15: { value: 0x9e, delta: 0, alpha: 0 },
swap16: { value: 0x9f, delta: 0, alpha: 0 }, swap16: { value: 0x9f, delta: 0, alpha: 0 },
// Loggin Operations // Loggin Operations
log0: { value: 0xa0, delta: 2, alpha: 0 }, log0: { value: 0xa0, delta: 2, alpha: 0, nonStatic: true, memory: "read" },
log1: { value: 0xa1, delta: 3, alpha: 0 }, log1: { value: 0xa1, delta: 3, alpha: 0, nonStatic: true, memory: "read" },
log2: { value: 0xa2, delta: 4, alpha: 0 }, log2: { value: 0xa2, delta: 4, alpha: 0, nonStatic: true, memory: "read" },
log3: { value: 0xa3, delta: 5, alpha: 0 }, log3: { value: 0xa3, delta: 5, alpha: 0, nonStatic: true, memory: "read" },
log4: { value: 0xa4, delta: 6, alpha: 0 }, log4: { value: 0xa4, delta: 6, alpha: 0, nonStatic: true, memory: "read" },
// System Operations // System Operations
create: { value: 0xf0, delta: 3, alpha: 1, doc: "address = create(value, index, length)" }, create: { value: 0xf0, delta: 3, alpha: 1, doc: "address = create(value, index, length)", nonStatic: true, memory: "read" },
call: { value: 0xf1, delta: 7, alpha: 1, doc: "v = call(gasLimit, address, value, inputIndex, inputLength, outputIndex, outputLength)" }, call: { value: 0xf1, delta: 7, alpha: 1, doc: "v = call(gasLimit, address, value, inputIndex, inputLength, outputIndex, outputLength)", nonStatic: true, memory: "full" },
callcode: { value: 0xf2, delta: 7, alpha: 1, doc: "v = callcode(@TODO)" }, callcode: { value: 0xf2, delta: 7, alpha: 1, doc: "v = callcode(@TODO)", nonStatic: true, memory: "full" },
"return": { value: 0xf3, delta: 2, alpha: 0, doc: "return(index, length)" }, "return": { value: 0xf3, delta: 2, alpha: 0, doc: "return(index, length)", memory: "read" },
delegatecall: { value: 0xf4, delta: 6, alpha: 1, doc: "v = delegatecall(gasLimit, address, inputIndex, inputLength, outputIndex, outputLength)" }, delegatecall: { value: 0xf4, delta: 6, alpha: 1, doc: "v = delegatecall(gasLimit, address, inputIndex, inputLength, outputIndex, outputLength)", nonStatic: true, memory: "full" },
create2: { value: 0xf5, delta: 4, alpha: 1, doc: "address = create2(value, index, length, salt)" }, create2: { value: 0xf5, delta: 4, alpha: 1, doc: "address = create2(value, index, length, salt)", nonStatic: true, memory: "read" },
staticcall: { value: 0xfa, delta: 6, alpha: 1, doc: "v = staticcall(gasLimit, address, inputIndex, inputLength, outputIndex, outputLength)" }, staticcall: { value: 0xfa, delta: 6, alpha: 1, doc: "v = staticcall(gasLimit, address, inputIndex, inputLength, outputIndex, outputLength)", memory: "full" },
revert: { value: 0xfd, delta: 2, alpha: 0, doc: "revert(returnDataOffset, returnDataLength)" }, revert: { value: 0xfd, delta: 2, alpha: 0, doc: "revert(returnDataOffset, returnDataLength)", memory: "read" },
invalid: { value: 0xfe, delta: 0, alpha: 0, doc: "invalid" }, invalid: { value: 0xfe, delta: 0, alpha: 0, doc: "invalid" },
suicide: { value: 0xff, delta: 1, alpha: 0, doc: "suicide(targetAddress)" }, suicide: { value: 0xff, delta: 1, alpha: 0, doc: "suicide(targetAddress)", nonStatic: true },
}; };
const OpcodeMap = {}; const OpcodeMap = {};
const Opcodes = []; const Opcodes = [];

@ -72,12 +72,12 @@
} }
*/ */
var parser = (function(){ var parser = (function(){
var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[2,19],$V1=[1,7],$V2=[1,8],$V3=[1,9],$V4=[1,10],$V5=[1,11],$V6=[1,12],$V7=[1,5],$V8=[1,6],$V9=[5,25],$Va=[5,11,14,15,16,17,18,22,25,28],$Vb=[2,2],$Vc=[1,19],$Vd=[5,10,11,13,14,15,16,17,18,22,25,28],$Ve=[1,25],$Vf=[1,26],$Vg=[1,27],$Vh=[2,14],$Vi=[5,10,11,13,14,15,16,17,18,22,25,27,28],$Vj=[16,17,18,27]; var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[2,21],$V1=[1,7],$V2=[1,8],$V3=[1,9],$V4=[1,10],$V5=[1,11],$V6=[1,12],$V7=[1,13],$V8=[1,14],$V9=[1,5],$Va=[1,6],$Vb=[5,27],$Vc=[5,11,14,15,16,17,18,19,20,24,27,30],$Vd=[2,2],$Ve=[1,21],$Vf=[5,10,11,13,14,15,16,17,18,19,20,24,27,30],$Vg=[1,27],$Vh=[1,28],$Vi=[1,29],$Vj=[2,16],$Vk=[5,10,11,13,14,15,16,17,18,19,20,24,27,29,30],$Vl=[16,17,20,29];
var parser = {trace: function trace () { }, var parser = {trace: function trace () { },
yy: {}, yy: {},
symbols_: {"error":2,"program":3,"statement_list":4,"EOF":5,"javascript":6,"SCRIPT_TOKEN":7,"opcode_list":8,"opcode":9,"COMMA":10,"ID":11,"OPEN_PAREN":12,"CLOSE_PAREN":13,"HASH_ID":14,"DOLLAR_ID":15,"HEX":16,"DECIMAL":17,"SCRIPT_EVAL":18,"hex_list":19,"hex":20,"statement":21,"AT_ID":22,"COLON":23,"OPEN_BRACE":24,"CLOSE_BRACE":25,"OPEN_BRACKET":26,"CLOSE_BRACKET":27,"SCRIPT_EXEC":28,"$accept":0,"$end":1}, symbols_: {"error":2,"program":3,"statement_list":4,"EOF":5,"javascript":6,"SCRIPT_TOKEN":7,"opcode_list":8,"opcode":9,"COMMA":10,"ID":11,"OPEN_PAREN":12,"CLOSE_PAREN":13,"HASH_ID":14,"DOLLAR_ID":15,"HEX":16,"DECIMAL":17,"DOLLAR_DOLLAR":18,"DOLLAR_INDEX":19,"SCRIPT_EVAL":20,"hex_list":21,"hex":22,"statement":23,"AT_ID":24,"COLON":25,"OPEN_BRACE":26,"CLOSE_BRACE":27,"OPEN_BRACKET":28,"CLOSE_BRACKET":29,"SCRIPT_EXEC":30,"$accept":0,"$end":1},
terminals_: {2:"error",5:"EOF",7:"SCRIPT_TOKEN",10:"COMMA",11:"ID",12:"OPEN_PAREN",13:"CLOSE_PAREN",14:"HASH_ID",15:"DOLLAR_ID",16:"HEX",17:"DECIMAL",18:"SCRIPT_EVAL",22:"AT_ID",23:"COLON",24:"OPEN_BRACE",25:"CLOSE_BRACE",26:"OPEN_BRACKET",27:"CLOSE_BRACKET",28:"SCRIPT_EXEC"}, terminals_: {2:"error",5:"EOF",7:"SCRIPT_TOKEN",10:"COMMA",11:"ID",12:"OPEN_PAREN",13:"CLOSE_PAREN",14:"HASH_ID",15:"DOLLAR_ID",16:"HEX",17:"DECIMAL",18:"DOLLAR_DOLLAR",19:"DOLLAR_INDEX",20:"SCRIPT_EVAL",24:"AT_ID",25:"COLON",26:"OPEN_BRACE",27:"CLOSE_BRACE",28:"OPEN_BRACKET",29:"CLOSE_BRACKET",30:"SCRIPT_EXEC"},
productions_: [0,[3,2],[6,0],[6,2],[8,1],[8,3],[9,1],[9,3],[9,4],[9,1],[9,1],[9,1],[9,1],[9,2],[19,0],[19,2],[20,1],[20,1],[20,2],[4,0],[4,2],[21,1],[21,2],[21,4],[21,4],[21,2]], productions_: [0,[3,2],[6,0],[6,2],[8,1],[8,3],[9,1],[9,3],[9,4],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,2],[21,0],[21,2],[22,1],[22,1],[22,2],[4,0],[4,2],[23,1],[23,2],[23,4],[23,4],[23,2]],
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
/* this == yyval */ /* this == yyval */
@ -124,54 +124,69 @@ case 12:
this.$ = { type: "decimal", value: $$[$0], loc: getLoc(yy, _$[$0]) }; this.$ = { type: "decimal", value: $$[$0], loc: getLoc(yy, _$[$0]) };
break; break;
case 13: case 13:
this.$ = { type: "eval", script: $$[$0], loc: getLoc(yy, _$[$0-1], _$[$0]) }; this.$ = { type: "pop", index: 0, loc: getLoc(yy, _$[$0]) };
break; break;
case 14: case 19: case 14:
this.$ = [ ]; this.$ = { type: "pop", index: parseInt(($$[$0]).substring(1)), loc: getLoc(yy, _$[$0]) };
break; break;
case 15: case 15:
this.$ = { type: "eval", script: $$[$0], loc: getLoc(yy, _$[$0-1], _$[$0]) };
break;
case 16: case 21:
this.$ = [ ];
break;
case 17:
{ {
const hexes = $$[$0].slice();; const hexes = $$[$0].slice();;
hexes.unshift($$[$0-1]); hexes.unshift($$[$0-1]);
this.$ = hexes; this.$ = hexes;
} }
break; break;
case 16: case 18:
this.$ = { type: "hex", verbatim: true, value: $$[$0], loc: getLoc(yy, _$[$0]) }; this.$ = { type: "hex", verbatim: true, value: $$[$0], loc: getLoc(yy, _$[$0]) };
break; break;
case 17: case 19:
{ {
const value = parseInt($$[$0]); const value = parseInt($$[$0]);
if (value >= 256) { throw new Error("decimal data values must be single bytes"); } if (value >= 256) { throw new Error("decimal data values must be single bytes"); }
this.$ = { type: "hex", verbatim: true, value: ("0x" + (value).toString(16)), loc: getLoc(yy, _$[$0]) }; let hex = (value).toString(16);
while (hex.length < 2) { hex = "0" + hex; }
this.$ = { type: "hex", verbatim: true, value: ("0x" + hex), loc: getLoc(yy, _$[$0]) };
} }
break; break;
case 18: case 20:
this.$ = { type: "eval", verbatim: true, script: $$[$0], loc: getLoc(yy, _$[$0-1], _$[$0]) }; this.$ = { type: "eval", verbatim: true, script: $$[$0], loc: getLoc(yy, _$[$0-1], _$[$0]) };
break; break;
case 20: case 22:
{ {
const statements = $$[$0].slice(); const statements = $$[$0].slice();
statements.unshift($$[$0-1]); statements.unshift($$[$0-1]);
this.$ = statements; this.$ = statements;
} }
break; break;
case 22:
this.$ = { type: "label", name: $$[$0-1].substring(1), loc: getLoc(yy, _$[$0-1], _$[$0]) };
break;
case 23: case 23:
this.$ = { type: "scope", name: $$[$0-3].substring(1), statements: $$[$0-1], loc: getLoc(yy, _$[$0-3], _$[$0]) }; {
const statement = $$[$0];
statement.loc.statement = true;
this.$ = statement;
}
break; break;
case 24: case 24:
this.$ = { type: "data", name: $$[$0-3].substring(1), data: $$[$0-1], loc: getLoc(yy, _$[$0-3], _$[$0]) }; this.$ = { type: "label", name: $$[$0-1].substring(1), loc: getLoc(yy, _$[$0-1], _$[$0], true) };
break; break;
case 25: case 25:
this.$ = { type: "exec", script: $$[$0], loc: getLoc(yy, _$[$0-1], _$[$0]) }; this.$ = { type: "scope", name: $$[$0-3].substring(1), statements: $$[$0-1], loc: getLoc(yy, _$[$0-3], _$[$0], true) };
break;
case 26:
this.$ = { type: "data", name: $$[$0-3].substring(1), data: $$[$0-1], loc: getLoc(yy, _$[$0-3], _$[$0], true) };
break;
case 27:
this.$ = { type: "exec", script: $$[$0], loc: getLoc(yy, _$[$0-1], _$[$0], true) };
break; break;
} }
}, },
table: [{3:1,4:2,5:$V0,9:4,11:$V1,14:$V2,15:$V3,16:$V4,17:$V5,18:$V6,21:3,22:$V7,28:$V8},{1:[3]},{5:[1,13]},o($V9,$V0,{21:3,9:4,4:14,11:$V1,14:$V2,15:$V3,16:$V4,17:$V5,18:$V6,22:$V7,28:$V8}),o($Va,[2,21]),{23:[1,15],24:[1,16],26:[1,17]},o($Va,$Vb,{6:18,7:$Vc}),o($Vd,[2,6],{12:[1,20]}),o($Vd,[2,9]),o($Vd,[2,10]),o($Vd,[2,11]),o($Vd,[2,12]),o($Vd,$Vb,{6:21,7:$Vc}),{1:[2,1]},o($V9,[2,20]),o($Va,[2,22]),{4:22,9:4,11:$V1,14:$V2,15:$V3,16:$V4,17:$V5,18:$V6,21:3,22:$V7,25:$V0,28:$V8},{16:$Ve,17:$Vf,18:$Vg,19:23,20:24,27:$Vh},o($Va,[2,25]),o($Vi,$Vb,{6:28,7:$Vc}),{8:30,9:31,11:$V1,13:[1,29],14:$V2,15:$V3,16:$V4,17:$V5,18:$V6},o($Vd,[2,13]),{25:[1,32]},{27:[1,33]},{16:$Ve,17:$Vf,18:$Vg,19:34,20:24,27:$Vh},o($Vj,[2,16]),o($Vj,[2,17]),o($Vj,$Vb,{6:35,7:$Vc}),o($Vi,[2,3]),o($Vd,[2,7]),{13:[1,36]},{10:[1,37],13:[2,4]},o($Va,[2,23]),o($Va,[2,24]),{27:[2,15]},o($Vj,[2,18]),o($Vd,[2,8]),{8:38,9:31,11:$V1,14:$V2,15:$V3,16:$V4,17:$V5,18:$V6},{13:[2,5]}], table: [{3:1,4:2,5:$V0,9:4,11:$V1,14:$V2,15:$V3,16:$V4,17:$V5,18:$V6,19:$V7,20:$V8,23:3,24:$V9,30:$Va},{1:[3]},{5:[1,15]},o($Vb,$V0,{23:3,9:4,4:16,11:$V1,14:$V2,15:$V3,16:$V4,17:$V5,18:$V6,19:$V7,20:$V8,24:$V9,30:$Va}),o($Vc,[2,23]),{25:[1,17],26:[1,18],28:[1,19]},o($Vc,$Vd,{6:20,7:$Ve}),o($Vf,[2,6],{12:[1,22]}),o($Vf,[2,9]),o($Vf,[2,10]),o($Vf,[2,11]),o($Vf,[2,12]),o($Vf,[2,13]),o($Vf,[2,14]),o($Vf,$Vd,{6:23,7:$Ve}),{1:[2,1]},o($Vb,[2,22]),o($Vc,[2,24]),{4:24,9:4,11:$V1,14:$V2,15:$V3,16:$V4,17:$V5,18:$V6,19:$V7,20:$V8,23:3,24:$V9,27:$V0,30:$Va},{16:$Vg,17:$Vh,20:$Vi,21:25,22:26,29:$Vj},o($Vc,[2,27]),o($Vk,$Vd,{6:30,7:$Ve}),{8:32,9:33,11:$V1,13:[1,31],14:$V2,15:$V3,16:$V4,17:$V5,18:$V6,19:$V7,20:$V8},o($Vf,[2,15]),{27:[1,34]},{29:[1,35]},{16:$Vg,17:$Vh,20:$Vi,21:36,22:26,29:$Vj},o($Vl,[2,18]),o($Vl,[2,19]),o($Vl,$Vd,{6:37,7:$Ve}),o($Vk,[2,3]),o($Vf,[2,7]),{13:[1,38]},{10:[1,39],13:[2,4]},o($Vc,[2,25]),o($Vc,[2,26]),{29:[2,17]},o($Vl,[2,20]),o($Vf,[2,8]),{8:40,9:33,11:$V1,14:$V2,15:$V3,16:$V4,17:$V5,18:$V6,19:$V7,20:$V8},{13:[2,5]}],
defaultActions: {13:[2,1],34:[2,15],38:[2,5]}, defaultActions: {15:[2,1],36:[2,17],40:[2,5]},
parseError: function parseError (str, hash) { parseError: function parseError (str, hash) {
if (hash.recoverable) { if (hash.recoverable) {
this.trace(str); this.trace(str);
@ -320,7 +335,7 @@ parse: function parse(input) {
}}; }};
function getLoc(yy, start, end) { function getLoc(yy, start, end, statement) {
if (end == null) { end = start; } if (end == null) { end = start; }
let result = null; let result = null;
@ -329,7 +344,8 @@ function getLoc(yy, start, end) {
first_line: start.first_line, first_line: start.first_line,
first_column: start.first_column, first_column: start.first_column,
last_line: end.last_line, last_line: end.last_line,
last_column: end.last_column last_column: end.last_column,
statement: !!statement
}; };
} }
@ -337,7 +353,7 @@ function getLoc(yy, start, end) {
return yy._ethersLocation(result); return yy._ethersLocation(result);
} }
return Object.freeze(result); return result;
} }
/* generated by jison-lex 0.3.4 */ /* generated by jison-lex 0.3.4 */
@ -690,9 +706,9 @@ case 9:return "COMMA"
break; break;
case 10:return "AT_ID" case 10:return "AT_ID"
break; break;
case 11:return "HASH_ID" case 11:return "DOLLAR_ID"
break; break;
case 12:return "DOLLAR_ID" case 12:return "HASH_ID"
break; break;
case 13:return "OPEN_BRACE" case 13:return "OPEN_BRACE"
break; break;
@ -708,14 +724,18 @@ case 18:return "HEX"
break; break;
case 19:return "DECIMAL" case 19:return "DECIMAL"
break; break;
case 20:return "EOF" case 20:return "DOLLAR_DOLLAR"
break; break;
case 21:return "INVALID" case 21:return "DOLLAR_INDEX"
break;
case 22:return "EOF"
break;
case 23:return "INVALID"
break; break;
} }
}, },
rules: [/^(?:\{\{=)/,/^(?:\{\{!)/,/^(?:([^\}]|\n|\}[^}]))/,/^(?:\}\})/,/^(?:([;][^\n]*\n))/,/^(?:(\s+))/,/^(?:([A-Za-z][A-Za-z0-9]*))/,/^(?:\()/,/^(?:\))/,/^(?:,)/,/^(?:([@][A-Za-z][A-Za-z0-9]*))/,/^(?:([#][A-Za-z][A-Za-z0-9]*))/,/^(?:([$][A-Za-z][A-Za-z0-9]*))/,/^(?:\{)/,/^(?:\})/,/^(?::)/,/^(?:\[)/,/^(?:\])/,/^(?:(0x([0-9a-fA-F][0-9a-fA-F])*))/,/^(?:([1-9][0-9]*|0))/,/^(?:$)/,/^(?:)/], rules: [/^(?:\{\{=)/,/^(?:\{\{!)/,/^(?:([^\}]|\n|\}[^}]))/,/^(?:\}\})/,/^(?:([;][^\n]*\n))/,/^(?:(\s+))/,/^(?:([A-Za-z][A-Za-z0-9]*))/,/^(?:\()/,/^(?:\))/,/^(?:,)/,/^(?:([@][A-Za-z][A-Za-z0-9]*))/,/^(?:([$](_|[A-Za-z][A-Za-z0-9]*)))/,/^(?:([#](_|[A-Za-z][A-Za-z0-9]*)))/,/^(?:\{)/,/^(?:\})/,/^(?::)/,/^(?:\[)/,/^(?:\])/,/^(?:(0x([0-9a-fA-F][0-9a-fA-F])*))/,/^(?:([1-9][0-9]*|0))/,/^(?:\$\$)/,/^(?:([$][1-9][0-9]*))/,/^(?:$)/,/^(?:)/],
conditions: {"script":{"rules":[2,3],"inclusive":false},"INITIAL":{"rules":[0,1,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21],"inclusive":true}} conditions: {"script":{"rules":[2,3],"inclusive":false},"INITIAL":{"rules":[0,1,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],"inclusive":true}}
}); });
return lexer; return lexer;
})(); })();

@ -1 +1 @@
export declare const version = "asm/5.0.0-beta.148"; export declare const version = "asm/5.0.0-beta.149";

@ -1,3 +1,3 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "asm/5.0.0-beta.148"; exports.version = "asm/5.0.0-beta.149";

@ -1,15 +1,16 @@
import { Opcode } from "./opcodes"; import { Opcode } from "./opcodes";
export declare type Location = { export declare type Location = {
offset: number; offset: number;
line: number;
length: number; length: number;
source: string; source: string;
statement: boolean;
}; };
export declare type AssembleVisitFunc = (node: Node, bytecode: string) => void; export declare type AssembleVisitFunc = (node: Node, bytecode: string) => void;
export declare type VisitFunc = (node: Node) => void; export declare type VisitFunc = (node: Node) => void;
export declare abstract class Node { export declare abstract class Node {
readonly tag: string; readonly tag: string;
readonly location: Location; readonly location: Location;
readonly warnings: Array<string>;
constructor(guard: any, location: Location, options: { constructor(guard: any, location: Location, options: {
[key: string]: any; [key: string]: any;
}); });
@ -30,6 +31,12 @@ export declare class LiteralNode extends ValueNode {
assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>; assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>;
static from(options: any): LiteralNode; static from(options: any): LiteralNode;
} }
export declare class PopNode extends ValueNode {
readonly index: number;
constructor(guard: any, location: Location, index: number);
readonly placeholder: string;
static from(options: any): PopNode;
}
export declare class LinkNode extends ValueNode { export declare class LinkNode extends ValueNode {
readonly type: string; readonly type: string;
readonly label: string; readonly label: string;
@ -40,7 +47,8 @@ export declare class LinkNode extends ValueNode {
export declare class OpcodeNode extends ValueNode { export declare class OpcodeNode extends ValueNode {
readonly opcode: Opcode; readonly opcode: Opcode;
readonly operands: Array<ValueNode>; readonly operands: Array<ValueNode>;
constructor(guard: any, location: Location, opcode: Opcode, operands: Array<ValueNode>); readonly instructional: boolean;
constructor(guard: any, location: Location, opcode: Opcode, operands: Array<ValueNode>, instructional: boolean);
assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>; assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>;
children(): Array<Node>; children(): Array<Node>;
visit(visit: VisitFunc): void; visit(visit: VisitFunc): void;
@ -61,7 +69,6 @@ export declare class DataNode extends LabelledNode {
constructor(guard: any, location: Location, name: string, data: string); constructor(guard: any, location: Location, name: string, data: string);
assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>; assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>;
children(): Array<Node>; children(): Array<Node>;
visit(visit: VisitFunc): void;
static from(options: any): DataNode; static from(options: any): DataNode;
} }
export declare class EvaluationNode extends ValueNode { export declare class EvaluationNode extends ValueNode {
@ -82,10 +89,8 @@ export declare class ScopeNode extends LabelledNode {
constructor(guard: any, location: Location, name: string, statements: Array<Node>); constructor(guard: any, location: Location, name: string, statements: Array<Node>);
assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>; assemble(assembler: Assembler, visit: AssembleVisitFunc): Promise<void>;
children(): Array<Node>; children(): Array<Node>;
visit(visit: VisitFunc): void;
static from(options: any): ScopeNode; static from(options: any): ScopeNode;
} }
export declare function parse(code: string): Node;
export declare type Operation = { export declare type Operation = {
opcode: Opcode; opcode: Opcode;
offset: number; offset: number;
@ -96,15 +101,15 @@ export interface Bytecode extends Array<Operation> {
} }
export declare function disassemble(bytecode: string): Bytecode; export declare function disassemble(bytecode: string): Bytecode;
export declare function formatBytecode(bytecode: Array<Operation>): string; export declare function formatBytecode(bytecode: Array<Operation>): string;
interface DataSource extends Array<number> { export interface DataSource extends Array<number> {
readonly offset: number; offset: number;
ast: Node;
source: string;
} }
declare type NodeState = { export declare type NodeState = {
node: Node; node: Node;
offset: number; offset: number;
bytecode: string; bytecode: string;
pending: string;
object?: number | DataSource;
}; };
export declare type AssemblerOptions = { export declare type AssemblerOptions = {
filename?: string; filename?: string;
@ -113,42 +118,46 @@ export declare type AssemblerOptions = {
defines?: { defines?: {
[name: string]: any; [name: string]: any;
}; };
target?: string;
};
export declare type ParserOptions = {
ignoreWarnings?: boolean;
}; };
declare class Assembler { declare class Assembler {
readonly root: Node; readonly root: Node;
readonly positionIndependentCode: boolean;
readonly nodes: { readonly nodes: {
[tag: string]: NodeState; [tag: string]: NodeState;
}; };
readonly labels: { readonly labels: {
[name: string]: LabelledNode; [name: string]: LabelledNode;
}; };
readonly filename: string; _parents: {
readonly positionIndependentCode: boolean; [tag: string]: Node;
readonly retry: number;
readonly defines: {
[name: string]: any;
}; };
private _stack; constructor(root: Node, positionIndependentCode?: boolean);
private _parents; getTarget(label: string): LabelledNode;
private _script;
private _changed;
constructor(root: Node, options: AssemblerOptions);
readonly changed: boolean;
getTarget(name: string): LabelledNode;
reset(): void;
evaluate(script: string, source: Node): Promise<any>; evaluate(script: string, source: Node): Promise<any>;
start(node: Node): void;
end(node: Node): void;
getPendingBytecode(node: Node): string;
_appendBytecode(bytecode: string): void;
getAncestor<T = Node>(node: Node, cls: { getAncestor<T = Node>(node: Node, cls: {
new (...args: any[]): T; new (...args: any[]): T;
}): T; }): T;
getOffset(node: Node, source?: Node): number;
setOffset(node: Node, offset: number): void;
getBytecode(node: Node): string;
setBytecode(node: Node, bytecode: string): void;
getLinkValue(target: LabelledNode, source: Node): number | DataSource; getLinkValue(target: LabelledNode, source: Node): number | DataSource;
get(name: string, source: Node): any; start(node: Node): void;
_didChange(): void; end(node: Node): void;
_assemble(): Promise<string>;
assemble(): Promise<string>;
} }
export declare enum SemanticErrorSeverity {
error = "error",
warning = "warning"
}
export declare type SemanticError = {
readonly message: string;
readonly severity: SemanticErrorSeverity;
readonly node: Node;
};
export declare function parse(code: string, options?: ParserOptions): Node;
export declare function assemble(ast: Node, options?: AssemblerOptions): Promise<string>; export declare function assemble(ast: Node, options?: AssemblerOptions): Promise<string>;
export {}; export {};

@ -53,10 +53,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
// @TODO: // @TODO:
// - PIC
// - warn on opcode non-function iff parameters
// - warn return/revert non-empty, comment ; !assert(+1 @extra) // - warn return/revert non-empty, comment ; !assert(+1 @extra)
// - $$
// - In JS add config (positionIndependent) // - In JS add config (positionIndependent)
// - When checking name collisions, verify no collision in javascript // - When checking name collisions, verify no collision in javascript
var path_1 = require("path"); var path_1 = require("path");
@ -174,9 +171,8 @@ var Node = /** @class */ (function () {
throw new Error("cannot instantiate class"); throw new Error("cannot instantiate class");
} }
logger.checkAbstract(_newTarget, Node); logger.checkAbstract(_newTarget, Node);
ethers_1.ethers.utils.defineReadOnly(this, "location", location); ethers_1.ethers.utils.defineReadOnly(this, "location", Object.freeze(location));
ethers_1.ethers.utils.defineReadOnly(this, "tag", "node-" + nextTag++ + "-" + this.constructor.name); ethers_1.ethers.utils.defineReadOnly(this, "tag", "node-" + nextTag++ + "-" + this.constructor.name);
ethers_1.ethers.utils.defineReadOnly(this, "warnings", []);
for (var key in options) { for (var key in options) {
ethers_1.ethers.utils.defineReadOnly(this, key, options[key]); ethers_1.ethers.utils.defineReadOnly(this, key, options[key]);
} }
@ -198,6 +194,9 @@ var Node = /** @class */ (function () {
}; };
Node.prototype.visit = function (visit) { Node.prototype.visit = function (visit) {
visit(this); visit(this);
this.children().forEach(function (child) {
child.visit(visit);
});
}; };
Node.from = function (options) { Node.from = function (options) {
var Factories = { var Factories = {
@ -210,6 +209,7 @@ var Node = /** @class */ (function () {
length: LinkNode, length: LinkNode,
offset: LinkNode, offset: LinkNode,
opcode: OpcodeNode, opcode: OpcodeNode,
pop: PopNode,
scope: ScopeNode, scope: ScopeNode,
}; };
var factory = Factories[options.type]; var factory = Factories[options.type];
@ -221,14 +221,6 @@ var Node = /** @class */ (function () {
return Node; return Node;
}()); }());
exports.Node = Node; exports.Node = Node;
/*
export abstract class CodeNode extends Node {
constructor(guard: any, location: Location, options: { [ key: string ]: any }) {
logger.checkAbstract(new.target, CodeNode);
super(guard, location, options);
}
}
*/
var ValueNode = /** @class */ (function (_super) { var ValueNode = /** @class */ (function (_super) {
__extends(ValueNode, _super); __extends(ValueNode, _super);
function ValueNode(guard, location, options) { function ValueNode(guard, location, options) {
@ -288,6 +280,27 @@ var LiteralNode = /** @class */ (function (_super) {
return LiteralNode; return LiteralNode;
}(ValueNode)); }(ValueNode));
exports.LiteralNode = LiteralNode; exports.LiteralNode = LiteralNode;
var PopNode = /** @class */ (function (_super) {
__extends(PopNode, _super);
function PopNode(guard, location, index) {
return _super.call(this, guard, location, { index: index }) || this;
}
Object.defineProperty(PopNode.prototype, "placeholder", {
get: function () {
if (this.index === 0) {
return "$$";
}
return "$" + String(this.index);
},
enumerable: true,
configurable: true
});
PopNode.from = function (options) {
return new PopNode(Guard, options.loc, options.index);
};
return PopNode;
}(ValueNode));
exports.PopNode = PopNode;
var LinkNode = /** @class */ (function (_super) { var LinkNode = /** @class */ (function (_super) {
__extends(LinkNode, _super); __extends(LinkNode, _super);
function LinkNode(guard, location, type, label) { function LinkNode(guard, location, type, label) {
@ -295,32 +308,67 @@ var LinkNode = /** @class */ (function (_super) {
} }
LinkNode.prototype.assemble = function (assembler, visit) { LinkNode.prototype.assemble = function (assembler, visit) {
return __awaiter(this, void 0, void 0, function () { return __awaiter(this, void 0, void 0, function () {
var value, target, result; var value, isOffset, target, result, here, opcodes, literal, w;
return __generator(this, function (_a) { return __generator(this, function (_a) {
assembler.start(this); assembler.start(this);
value = null; value = null;
isOffset = false;
target = assembler.getTarget(this.label); target = assembler.getTarget(this.label);
if (target instanceof LabelNode) { if (target instanceof LabelNode) {
if (this.type === "offset") { if (this.type === "offset") {
//value = assembler.getOffset(this.label);
value = (assembler.getLinkValue(target, this)); value = (assembler.getLinkValue(target, this));
isOffset = true;
} }
} }
else { else {
result = (assembler.getLinkValue(target, this)); result = (assembler.getLinkValue(target, this));
if (this.type === "offset") { if (this.type === "offset") {
//value = assembler.getOffset(this.label);
value = result.offset; value = result.offset;
isOffset = true;
} }
else if (this.type === "length") { else if (this.type === "length") {
//value = assembler.getLength(this.label);
value = result.length; value = result.length;
} }
} }
if (value == null) { if (value == null) {
throw new Error("labels can only be targetted as offsets"); throw new Error("labels can only be targetted as offsets");
} }
if (isOffset && assembler.positionIndependentCode) {
here = assembler.getOffset(this, this);
opcodes = [];
if (here > value) {
literal = "0x";
for (w = 1; w <= 5; w++) {
if (w > 4) {
throw new Error("jump too large!");
}
literal = pushLiteral(here - value + w);
if (ethers_1.ethers.utils.hexDataLength(literal) <= w) {
literal = ethers_1.ethers.utils.hexZeroPad(literal, w);
break;
}
}
opcodes.push(literal);
opcodes.push(opcodes_1.Opcode.from("PC"));
opcodes.push(opcodes_1.Opcode.from("SUB"));
// This also works, in case the above literal thing doesn't work out...
//opcodes.push(Opcode.from("PC"));
//opcodes.push(pushLiteral(-delta));
//opcodes.push(Opcode.from("SWAP1"));
//opcodes.push(Opcode.from("SUB"));
}
else {
// Jump forwards; this is easy to calculate since we can
// do PC firat.
opcodes.push(opcodes_1.Opcode.from("PC"));
opcodes.push(pushLiteral(value - here));
opcodes.push(opcodes_1.Opcode.from("ADD"));
}
visit(this, hexConcat(opcodes));
}
else {
visit(this, pushLiteral(value)); visit(this, pushLiteral(value));
}
assembler.end(this); assembler.end(this);
return [2 /*return*/]; return [2 /*return*/];
}); });
@ -335,12 +383,8 @@ var LinkNode = /** @class */ (function (_super) {
exports.LinkNode = LinkNode; exports.LinkNode = LinkNode;
var OpcodeNode = /** @class */ (function (_super) { var OpcodeNode = /** @class */ (function (_super) {
__extends(OpcodeNode, _super); __extends(OpcodeNode, _super);
function OpcodeNode(guard, location, opcode, operands) { function OpcodeNode(guard, location, opcode, operands, instructional) {
var _this = _super.call(this, guard, location, { opcode: opcode, operands: operands }) || this; return _super.call(this, guard, location, { instructional: instructional, opcode: opcode, operands: operands }) || this;
if (opcode.isPush()) {
_this.warnings.push("the PUSH opcode modifies program flow - use literals instead");
}
return _this;
} }
OpcodeNode.prototype.assemble = function (assembler, visit) { OpcodeNode.prototype.assemble = function (assembler, visit) {
return __awaiter(this, void 0, void 0, function () { return __awaiter(this, void 0, void 0, function () {
@ -386,23 +430,14 @@ var OpcodeNode = /** @class */ (function (_super) {
if (!opcode) { if (!opcode) {
throw new Error("unknown opcode: " + options.mnemonic); throw new Error("unknown opcode: " + options.mnemonic);
} }
// Using the function syntax will check the operand count
if (!options.bare) {
if (opcode.mnemonic === "POP" && options.operands.length === 0) {
// This is ok... Pop has a delta of 0, but without operands
}
else if (options.operands.length !== opcode.delta) {
throw new Error("opcode " + opcode.mnemonic + " expects " + opcode.delta + " operands");
}
}
var operands = Object.freeze(options.operands.map(function (o) { var operands = Object.freeze(options.operands.map(function (o) {
var operand = Node.from(o); var operand = Node.from(o);
if (!(operand instanceof ValueNode)) { if (!(operand instanceof ValueNode)) {
throw new Error("invalid operand"); throw new Error("bad grammar?!");
} }
return operand; return operand;
})); }));
return new OpcodeNode(Guard, options.loc, opcode, operands); return new OpcodeNode(Guard, options.loc, opcode, operands, !!options.bare);
}; };
return OpcodeNode; return OpcodeNode;
}(ValueNode)); }(ValueNode));
@ -469,7 +504,7 @@ var DataNode = /** @class */ (function (_super) {
i_1++; i_1++;
return [3 /*break*/, 1]; return [3 /*break*/, 1];
case 4: case 4:
bytecode = ethers_1.ethers.utils.arrayify(assembler.getPendingBytecode(this)); bytecode = ethers_1.ethers.utils.arrayify(assembler.getBytecode(this));
i = 0; i = 0;
while (i < bytecode.length) { while (i < bytecode.length) {
opcode = opcodes_1.Opcode.from(bytecode[i++]); opcode = opcodes_1.Opcode.from(bytecode[i++]);
@ -491,12 +526,6 @@ var DataNode = /** @class */ (function (_super) {
DataNode.prototype.children = function () { DataNode.prototype.children = function () {
return this.data; return this.data;
}; };
DataNode.prototype.visit = function (visit) {
visit(this);
for (var i = 0; i < this.data.length; i++) {
this.data[i].visit(visit);
}
};
DataNode.from = function (options) { DataNode.from = function (options) {
if (options.type !== "data") { if (options.type !== "data") {
throw new Error("expected data type"); throw new Error("expected data type");
@ -610,12 +639,6 @@ var ScopeNode = /** @class */ (function (_super) {
ScopeNode.prototype.children = function () { ScopeNode.prototype.children = function () {
return this.statements; return this.statements;
}; };
ScopeNode.prototype.visit = function (visit) {
visit(this);
for (var i = 0; i < this.statements.length; i++) {
this.statements[i].visit(visit);
}
};
ScopeNode.from = function (options) { ScopeNode.from = function (options) {
if (options.type !== "scope") { if (options.type !== "scope") {
throw new Error("expected scope type"); throw new Error("expected scope type");
@ -625,57 +648,6 @@ var ScopeNode = /** @class */ (function (_super) {
return ScopeNode; return ScopeNode;
}(LabelledNode)); }(LabelledNode));
exports.ScopeNode = ScopeNode; exports.ScopeNode = ScopeNode;
function parse(code) {
// Since jison allows \n, \r or \r\n line endings, we need some
// twekaing to get the correct position
var lines = [];
var offset = 0;
code.split(/(\r\n?|\n)/g).forEach(function (clump, index) {
if (index % 2) {
lines[lines.length - 1].line += clump;
}
else {
lines.push({ line: clump, offset: offset });
}
offset += clump.length;
});
// Add a mock-EOF to the end of the file so we don't out-of-bounds
// on the last character
if (lines.length) {
lines[lines.length - 1].line += "\n";
}
// Givens a line (1 offset) and column (0 offset) return the byte offset
var getOffset = function (line, column) {
var info = lines[line - 1];
if (!info || column >= info.line.length) {
throw new Error("out of range");
}
return info.offset + column;
};
// We use this in the _parser to convert locations to source
_parser_1.parser.yy._ethersLocation = function (loc) {
// The _ scope should call with null to get the full source
if (loc == null) {
return Object.freeze({
offset: 0,
length: code.length,
source: code
});
}
var offset = getOffset(loc.first_line, loc.first_column);
var end = getOffset(loc.last_line, loc.last_column);
return Object.freeze({
offset: offset,
length: (end - offset),
source: code.substring(offset, end)
});
};
var result = Node.from(_parser_1.parse(code));
// Nuke the source code lookup callback
_parser_1.parser.yy._ethersLocation = null;
return result;
}
exports.parse = parse;
function disassemble(bytecode) { function disassemble(bytecode) {
var ops = []; var ops = [];
var offsets = {}; var offsets = {};
@ -741,14 +713,10 @@ function formatBytecode(bytecode) {
return lines.join("\n"); return lines.join("\n");
} }
exports.formatBytecode = formatBytecode; exports.formatBytecode = formatBytecode;
// @TODO: Rename to Assembler?
var Assembler = /** @class */ (function () { var Assembler = /** @class */ (function () {
function Assembler(root, options) { function Assembler(root, positionIndependentCode) {
ethers_1.ethers.utils.defineReadOnly(this, "positionIndependentCode", !!options.positionIndependentCode);
ethers_1.ethers.utils.defineReadOnly(this, "retry", ((options.retry != null) ? options.retry : 512));
ethers_1.ethers.utils.defineReadOnly(this, "filename", path_1.resolve(options.filename || "./contract.asm"));
ethers_1.ethers.utils.defineReadOnly(this, "defines", Object.freeze(options.defines || {}));
ethers_1.ethers.utils.defineReadOnly(this, "root", root); ethers_1.ethers.utils.defineReadOnly(this, "root", root);
ethers_1.ethers.utils.defineReadOnly(this, "positionIndependentCode", !!positionIndependentCode);
var nodes = {}; var nodes = {};
var labels = {}; var labels = {};
var parents = {}; var parents = {};
@ -757,8 +725,7 @@ var Assembler = /** @class */ (function () {
nodes[node.tag] = { nodes[node.tag] = {
node: node, node: node,
offset: 0x0, offset: 0x0,
bytecode: "0x", bytecode: "0x"
pending: "0x"
}; };
if (node instanceof LabelledNode) { if (node instanceof LabelledNode) {
// Check for duplicate labels // Check for duplicate labels
@ -784,58 +751,14 @@ var Assembler = /** @class */ (function () {
ethers_1.ethers.utils.defineReadOnly(this, "labels", Object.freeze(labels)); ethers_1.ethers.utils.defineReadOnly(this, "labels", Object.freeze(labels));
ethers_1.ethers.utils.defineReadOnly(this, "nodes", Object.freeze(nodes)); ethers_1.ethers.utils.defineReadOnly(this, "nodes", Object.freeze(nodes));
ethers_1.ethers.utils.defineReadOnly(this, "_parents", Object.freeze(parents)); ethers_1.ethers.utils.defineReadOnly(this, "_parents", Object.freeze(parents));
ethers_1.ethers.utils.defineReadOnly(this, "_stack", []);
this.reset();
} }
Object.defineProperty(Assembler.prototype, "changed", {
get: function () {
return this._changed;
},
enumerable: true,
configurable: true
});
// Link operations // Link operations
Assembler.prototype.getTarget = function (name) { Assembler.prototype.getTarget = function (label) {
return this.labels[name]; return this.labels[label];
};
// Reset the assmebler for another run with updated values
Assembler.prototype.reset = function () {
var _this = this;
this._changed = false;
for (var tag in this.nodes) {
delete this.nodes[tag].object;
}
this._script = new Script(this.filename, function (name, context) {
return _this.get(name, context);
});
}; };
// Evaluate script in the context of a {{! }} or {{= }}
Assembler.prototype.evaluate = function (script, source) { Assembler.prototype.evaluate = function (script, source) {
return this._script.evaluate(script, source); return Promise.resolve(new Uint8Array(0));
};
Assembler.prototype.start = function (node) {
this._stack.push(node);
var info = this.nodes[node.tag];
info.pending = "0x";
};
Assembler.prototype.end = function (node) {
if (this._stack.pop() !== node) {
throw new Error("missing push/pop pair");
}
var info = this.nodes[node.tag];
if (info.pending !== info.bytecode) {
this._didChange();
}
info.bytecode = info.pending;
};
Assembler.prototype.getPendingBytecode = function (node) {
return this.nodes[node.tag].pending;
};
Assembler.prototype._appendBytecode = function (bytecode) {
var _this = this;
this._stack.forEach(function (node) {
var info = _this.nodes[node.tag];
info.pending = hexConcat([info.pending, bytecode]);
});
}; };
Assembler.prototype.getAncestor = function (node, cls) { Assembler.prototype.getAncestor = function (node, cls) {
node = this._parents[node.tag]; node = this._parents[node.tag];
@ -847,6 +770,23 @@ var Assembler = /** @class */ (function () {
} }
return null; return null;
}; };
Assembler.prototype.getOffset = function (node, source) {
var offset = this.nodes[node.tag].offset;
if (source == null) {
return offset;
}
var sourceScope = ((source instanceof ScopeNode) ? source : this.getAncestor(source, ScopeNode));
return offset - this.nodes[sourceScope.tag].offset;
};
Assembler.prototype.setOffset = function (node, offset) {
this.nodes[node.tag].offset = offset;
};
Assembler.prototype.getBytecode = function (node) {
return this.nodes[node.tag].bytecode;
};
Assembler.prototype.setBytecode = function (node, bytecode) {
this.nodes[node.tag].bytecode = bytecode;
};
Assembler.prototype.getLinkValue = function (target, source) { Assembler.prototype.getLinkValue = function (target, source) {
var sourceScope = ((source instanceof ScopeNode) ? source : this.getAncestor(source, ScopeNode)); var sourceScope = ((source instanceof ScopeNode) ? source : this.getAncestor(source, ScopeNode));
var targetScope = ((target instanceof ScopeNode) ? target : this.getAncestor(target, ScopeNode)); var targetScope = ((target instanceof ScopeNode) ? target : this.getAncestor(target, ScopeNode));
@ -857,13 +797,7 @@ var Assembler = /** @class */ (function () {
throw new Error("cannot access " + target.name + " from " + source.tag); throw new Error("cannot access " + target.name + " from " + source.tag);
} }
// Return the offset relative to its scope // Return the offset relative to its scope
var offset = this.nodes[target.tag].offset - this.nodes[targetScope.tag].offset; return this.nodes[target.tag].offset - this.nodes[targetScope.tag].offset;
// Offsets are wrong; but we should finish this run and then try again
if (offset < 0) {
offset = 0;
this._didChange();
}
return offset;
} }
var info = this.nodes[target.tag]; var info = this.nodes[target.tag];
// Return the offset is relative to its scope // Return the offset is relative to its scope
@ -892,15 +826,224 @@ var Assembler = /** @class */ (function () {
// been marked as invalid, in which case accessing it will fail // been marked as invalid, in which case accessing it will fail
if (safeOffset) { if (safeOffset) {
bytes.offset = info.offset - this.nodes[sourceScope.tag].offset; bytes.offset = info.offset - this.nodes[sourceScope.tag].offset;
// Offsets are wqrong; but we should finish this run and then try again }
if (bytes.offset < 0) { return bytes;
bytes.offset = 0; };
Assembler.prototype.start = function (node) { };
Assembler.prototype.end = function (node) { };
return Assembler;
}());
var SemanticErrorSeverity;
(function (SemanticErrorSeverity) {
SemanticErrorSeverity["error"] = "error";
SemanticErrorSeverity["warning"] = "warning";
})(SemanticErrorSeverity = exports.SemanticErrorSeverity || (exports.SemanticErrorSeverity = {}));
;
// This Assembler is designed to only check for errors and warnings
// Warnings
// - Bare PUSH opcodes
// - Instructional opcode that has parameters
// Errors
// - Using a $$ outside of RPN
// - Using a $$ when it is not adjacent to the stack
// - The operand count does not match the opcode
// - An opcode is used as an operand but does not return a value
var SemanticChecker = /** @class */ (function (_super) {
__extends(SemanticChecker, _super);
function SemanticChecker() {
return _super !== null && _super.apply(this, arguments) || this;
}
SemanticChecker.prototype.check = function () {
var _this = this;
var errors = [];
this.root.visit(function (node) {
if (node instanceof OpcodeNode) {
var opcode = node.opcode;
if (node.instructional) {
if (opcode.delta) {
errors.push({
message: opcode.mnemonic + " used as instructional",
severity: SemanticErrorSeverity.warning,
node: node
});
}
}
else {
if (opcode.mnemonic === "POP") {
if (node.operands.length !== 0) {
errors.push({
message: "POP expects 0 operands",
severity: SemanticErrorSeverity.error,
node: node
});
}
}
else if (node.operands.length !== opcode.delta) {
errors.push({
message: opcode.mnemonic + " expects " + opcode.delta + " operands",
severity: SemanticErrorSeverity.error,
node: node
});
}
}
if (opcode.isPush()) {
// A stray PUSH operation will gobble up the following code
// bytes which is bad. But this may be a disassembled program
// and that PUSH may actually be just some data (which is safe)
errors.push({
message: "PUSH opcode modifies program flow - use literals instead",
severity: SemanticErrorSeverity.warning,
node: node
});
}
else if (!node.location.statement && opcode.alpha !== 1) {
// If an opcode does not push anything on the stack, it
// cannot be used as an operand
errors.push({
message: node.opcode.mnemonic + " cannot be an operand",
severity: SemanticErrorSeverity.error,
node: node
});
}
}
if (node.location.statement) {
if (node instanceof PopNode) {
// $$ by istelf is useless and is intended to be an operand
errors.push({
message: "$$ must be an operand",
severity: SemanticErrorSeverity.error,
node: node
});
}
else {
var scope_1 = _this.getAncestor(node, ScopeNode);
// Make sure any $$ is stack adjacent (within this scope)
var ordered_1 = [];
node.visit(function (node) {
if (scope_1 !== _this.getAncestor(node, ScopeNode)) {
return;
}
ordered_1.push(node);
});
// Allow any number of stack adjacent $$
var foundZero = null;
var lastIndex = 0;
while (ordered_1.length && ordered_1[0] instanceof PopNode) {
var popNode = (ordered_1.shift());
var index = popNode.index;
if (index === 0) {
foundZero = popNode;
}
else if (index !== lastIndex + 1) {
errors.push({
message: "out-of-order stack placeholder " + popNode.placeholder + "; expected $$" + (lastIndex + 1),
severity: SemanticErrorSeverity.error,
node: popNode
});
while (ordered_1.length && ordered_1[0] instanceof PopNode) {
ordered_1.shift();
}
break;
}
else {
lastIndex = index;
}
}
if (foundZero && lastIndex > 0) {
errors.push({
message: "cannot mix $$ and $1 stack placeholder",
severity: SemanticErrorSeverity.error,
node: foundZero
});
}
// If there are still any buried, we have a problem
var pops = ordered_1.filter(function (n) { return (n instanceof PopNode); });
if (pops.length) {
errors.push({
message: "stack placeholder " + (pops[0]).placeholder + " must be stack adjacent",
severity: SemanticErrorSeverity.error,
node: pops[0]
});
}
}
}
});
return errors;
};
return SemanticChecker;
}(Assembler));
var CodeGenerationAssembler = /** @class */ (function (_super) {
__extends(CodeGenerationAssembler, _super);
function CodeGenerationAssembler(root, options) {
var _this = _super.call(this, root, !!options.positionIndependentCode) || this;
ethers_1.ethers.utils.defineReadOnly(_this, "retry", ((options.retry != null) ? options.retry : 512));
ethers_1.ethers.utils.defineReadOnly(_this, "filename", path_1.resolve(options.filename || "./contract.asm"));
ethers_1.ethers.utils.defineReadOnly(_this, "defines", Object.freeze(options.defines || {}));
ethers_1.ethers.utils.defineReadOnly(_this, "_stack", []);
_this.reset();
return _this;
}
CodeGenerationAssembler.prototype._didChange = function () {
this._changed = true;
};
Object.defineProperty(CodeGenerationAssembler.prototype, "changed", {
get: function () {
return this._changed;
},
enumerable: true,
configurable: true
});
// Reset the assmebler for another run with updated values
CodeGenerationAssembler.prototype.reset = function () {
var _this = this;
this._changed = false;
this._oldBytecode = {};
this._objectCache = {};
this._script = new Script(this.filename, function (name, context) {
return _this.get(name, context);
});
};
CodeGenerationAssembler.prototype.evaluate = function (script, source) {
return this._script.evaluate(script, source);
};
CodeGenerationAssembler.prototype.getLinkValue = function (target, source) {
// Since we are iteratively generating code, offsets and lengths
// may not be stable at any given point in time, so if an offset
// is negative the code is obviously wrong, however we set it to
// 0 so we can proceed with generation to fill in as many blanks
// as possible; then we will try assembling again
var result = _super.prototype.getLinkValue.call(this, target, source);
if (typeof (result) === "number") {
if (result < 0) {
this._didChange();
return 0;
}
return result;
}
if (result.offset < 0) {
result.offset = 0;
this._didChange(); this._didChange();
} }
} return result;
return Object.freeze(bytes);
}; };
Assembler.prototype.get = function (name, source) { CodeGenerationAssembler.prototype.start = function (node) {
this._stack.push(node);
this._oldBytecode[node.tag] = this.getBytecode(node);
this.setBytecode(node, "0x");
};
CodeGenerationAssembler.prototype.end = function (node) {
if (this._stack.pop() !== node) {
throw new Error("missing push/pop pair");
}
if (this._oldBytecode[node.tag] !== this.getBytecode(node)) {
this._didChange();
}
};
// This is used by evaluate to access properties in JavaScript
// - "defines" allow meta-programming values to be used
// - jump destinations are available as numbers
// - bytecode and data are available as an immuatble DataSource
CodeGenerationAssembler.prototype.get = function (name, source) {
if (name === "defines") { if (name === "defines") {
return this.defines; return this.defines;
} }
@ -908,55 +1051,67 @@ var Assembler = /** @class */ (function () {
if (!node) { if (!node) {
return undefined; return undefined;
} }
var info = this.nodes[node.tag]; // We cache objects when they are generated so all nodes
if (info.object == null) { // receive consistent data; if there is a change we will
info.object = this.getLinkValue(node, source); // run the entire assembly process again with the updated
// values
if (this._objectCache[node.tag] == null) {
this._objectCache[node.tag] = Object.freeze(this.getLinkValue(node, source));
} }
return info.object; return this._objectCache[node.tag];
}; };
Assembler.prototype._didChange = function () { CodeGenerationAssembler.prototype._assemble = function () {
this._changed = true;
};
Assembler.prototype._assemble = function () {
return __awaiter(this, void 0, void 0, function () { return __awaiter(this, void 0, void 0, function () {
var offset, bytecodes; var offset;
var _this = this; var _this = this;
return __generator(this, function (_a) { return __generator(this, function (_a) {
switch (_a.label) { switch (_a.label) {
case 0: case 0:
offset = 0; offset = 0;
bytecodes = [];
return [4 /*yield*/, this.root.assemble(this, function (node, bytecode) { return [4 /*yield*/, this.root.assemble(this, function (node, bytecode) {
var state = _this.nodes[node.tag];
// Things have moved; we will need to try again // Things have moved; we will need to try again
if (state.offset !== offset) { if (_this.getOffset(node) !== offset) {
state.offset = offset; _this.setOffset(node, offset);
_this._didChange(); _this._didChange();
} }
_this._appendBytecode(bytecode); _this._stack.forEach(function (node) {
bytecodes.push(bytecode); _this.setBytecode(node, hexConcat([
// The bytecode has changed; we will need to try again _this.getBytecode(node),
//if (state.bytecode !== bytecode) { bytecode
// state.bytecode = bytecode; ]));
// this._didChange(); });
//}
offset += ethers_1.ethers.utils.hexDataLength(bytecode); offset += ethers_1.ethers.utils.hexDataLength(bytecode);
})]; })];
case 1: case 1:
_a.sent(); _a.sent();
return [2 /*return*/, hexConcat(bytecodes)]; return [2 /*return*/];
} }
}); });
}); });
}; };
Assembler.prototype.assemble = function () { CodeGenerationAssembler.prototype.assemble = function (label) {
return __awaiter(this, void 0, void 0, function () { return __awaiter(this, void 0, void 0, function () {
var bytecode, i, adjusted; var target, i;
return __generator(this, function (_a) { return __generator(this, function (_a) {
switch (_a.label) { switch (_a.label) {
case 0: return [4 /*yield*/, this._assemble()]; case 0:
if (label == null) {
label = "_";
}
target = this.getTarget(label);
if (!target) {
logger.throwArgumentError("unknown labelled target: " + label, "label", label);
}
else if (!(target instanceof ScopeNode || target instanceof DataNode)) {
logger.throwArgumentError("cannot assemble a bodyless label: " + label, "label", label);
}
// Continue re-evaluating the bytecode until a stable set of
// offsets, length and values are reached.
return [4 /*yield*/, this._assemble()];
case 1: case 1:
bytecode = _a.sent(); // Continue re-evaluating the bytecode until a stable set of
// offsets, length and values are reached.
_a.sent();
i = 0; i = 0;
_a.label = 2; _a.label = 2;
case 2: case 2:
@ -965,37 +1120,101 @@ var Assembler = /** @class */ (function () {
this.reset(); this.reset();
return [4 /*yield*/, this._assemble()]; return [4 /*yield*/, this._assemble()];
case 3: case 3:
adjusted = _a.sent(); _a.sent();
// Generated bytecode is stable!! :) // Generated bytecode is stable!! :)
if (!this.changed) { if (!this.changed) {
console.log("Assembled in " + i + " attempts"); // This should not happen; something is wrong with the grammar
return [2 /*return*/, bytecode]; // or missing enter/exit call in assemble
if (this._stack.length !== 0) {
throw new Error("Bad AST! Bad grammar?!");
}
//console.log(`Assembled in ${ i } attempts`);
return [2 /*return*/, this.getBytecode(target)];
;
} }
// Try again...
bytecode = adjusted;
_a.label = 4; _a.label = 4;
case 4: case 4:
i++; i++;
return [3 /*break*/, 2]; return [3 /*break*/, 2];
case 5: case 5: return [2 /*return*/, logger.throwError("unable to assemble; " + this.retry + " attempts failed to generate stable bytecode", ethers_1.ethers.utils.Logger.errors.UNKNOWN_ERROR, {})];
// This should not happen; something is wrong with the grammar
// or missing enter/exit call in assemble
if (this._stack.length !== 0) {
throw new Error("bad AST");
}
return [2 /*return*/, logger.throwError("unable to assemble; " + this.retry + " attempts failed to generate stable bytecode", ethers_1.ethers.utils.Logger.errors.UNKNOWN_ERROR, {})];
} }
}); });
}); });
}; };
return Assembler; return CodeGenerationAssembler;
}()); }(Assembler));
function parse(code, options) {
if (options == null) {
options = {};
}
// Since jison allows \n, \r or \r\n line endings, we need some
// twekaing to get the correct position
var lines = [];
var offset = 0;
code.split(/(\r\n?|\n)/g).forEach(function (clump, index) {
if (index % 2) {
lines[lines.length - 1].line += clump;
}
else {
lines.push({ line: clump, offset: offset });
}
offset += clump.length;
});
// Add a mock-EOF to the end of the file so we don't out-of-bounds
// on the last character
if (lines.length) {
lines[lines.length - 1].line += "\n";
}
// Givens a line (1 offset) and column (0 offset) return the byte offset
var getOffset = function (line, column) {
var info = lines[line - 1];
if (!info || column >= info.line.length) {
throw new Error("out of range");
}
return info.offset + column;
};
// We use this in the _parser to convert locations to source
_parser_1.parser.yy._ethersLocation = function (loc) {
// The _ scope should call with null to get the full source
if (loc == null) {
return {
offset: 0,
line: 0,
length: code.length,
source: code,
statement: true
};
}
var offset = getOffset(loc.first_line, loc.first_column);
var end = getOffset(loc.last_line, loc.last_column);
return {
offset: offset,
line: loc.first_line - 1,
length: (end - offset),
source: code.substring(offset, end),
statement: (!!loc.statement)
};
};
var result = Node.from(_parser_1.parse(code));
// Nuke the source code lookup callback
_parser_1.parser.yy._ethersLocation = null;
// Semantic Checks
var checker = new SemanticChecker(result);
var errors = checker.check();
if (errors.filter(function (e) { return (e.severity === SemanticErrorSeverity.error); }).length || (errors.length && !options.ignoreWarnings)) {
var error = new Error("semantic errors during parsing");
error.errors = errors;
throw error;
}
return result;
}
exports.parse = parse;
function assemble(ast, options) { function assemble(ast, options) {
return __awaiter(this, void 0, void 0, function () { return __awaiter(this, void 0, void 0, function () {
var assembler; var assembler;
return __generator(this, function (_a) { return __generator(this, function (_a) {
assembler = new Assembler(ast, options || {}); assembler = new CodeGenerationAssembler(ast, options || {});
return [2 /*return*/, assembler.assemble()]; return [2 /*return*/, assembler.assemble(options.target || "_")];
}); });
}); });
} }

@ -1,4 +1,4 @@
import { assemble, DataNode, disassemble, EvaluationNode, ExecutionNode, formatBytecode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, parse, ScopeNode, ValueNode } from "./assembler"; import { assemble, DataNode, disassemble, EvaluationNode, ExecutionNode, formatBytecode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, parse, PopNode, ScopeNode, ValueNode } from "./assembler";
import { Opcode } from "./opcodes"; import { Opcode } from "./opcodes";
import { AssemblerOptions, AssembleVisitFunc, Bytecode, Location, Operation, VisitFunc } from "./assembler"; import { AssemblerOptions, AssembleVisitFunc, Bytecode, Location, Operation, ParserOptions, SemanticError, SemanticErrorSeverity, VisitFunc } from "./assembler";
export { Opcode, assemble, disassemble, formatBytecode, parse, DataNode, EvaluationNode, ExecutionNode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, ScopeNode, ValueNode, AssemblerOptions, AssembleVisitFunc, Bytecode, Location, Operation, VisitFunc, }; export { Opcode, assemble, disassemble, formatBytecode, parse, DataNode, EvaluationNode, ExecutionNode, LabelNode, LabelledNode, LinkNode, LiteralNode, Node, OpcodeNode, PopNode, ScopeNode, ValueNode, AssemblerOptions, AssembleVisitFunc, Bytecode, Location, Operation, SemanticError, SemanticErrorSeverity, ParserOptions, VisitFunc, };

@ -14,7 +14,10 @@ exports.LiteralNode = assembler_1.LiteralNode;
exports.Node = assembler_1.Node; exports.Node = assembler_1.Node;
exports.OpcodeNode = assembler_1.OpcodeNode; exports.OpcodeNode = assembler_1.OpcodeNode;
exports.parse = assembler_1.parse; exports.parse = assembler_1.parse;
exports.PopNode = assembler_1.PopNode;
exports.ScopeNode = assembler_1.ScopeNode; exports.ScopeNode = assembler_1.ScopeNode;
exports.ValueNode = assembler_1.ValueNode; exports.ValueNode = assembler_1.ValueNode;
var opcodes_1 = require("./opcodes"); var opcodes_1 = require("./opcodes");
exports.Opcode = opcodes_1.Opcode; exports.Opcode = opcodes_1.Opcode;
var assembler_2 = require("./assembler");
exports.SemanticErrorSeverity = assembler_2.SemanticErrorSeverity;

@ -1,3 +1,8 @@
export declare enum OpcodeMemoryAccess {
write = "write",
read = "read",
full = "full"
}
export declare class Opcode { export declare class Opcode {
readonly value: number; readonly value: number;
readonly mnemonic: string; readonly mnemonic: string;
@ -8,7 +13,7 @@ export declare class Opcode {
isJump(): boolean; isJump(): boolean;
isValidJumpDest(): boolean; isValidJumpDest(): boolean;
isPush(): number; isPush(): number;
isMemory(readOrWrite?: boolean): boolean; isMemoryAccess(readOrWrite?: boolean): OpcodeMemoryAccess;
isStatic(): boolean; isStatic(): boolean;
static from(valueOrMnemonic: number | string): Opcode; static from(valueOrMnemonic: number | string): Opcode;
} }

@ -9,6 +9,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
// EXTCODEHASH // EXTCODEHASH
// See: https://eips.ethereum.org/EIPS/eip-1052 // See: https://eips.ethereum.org/EIPS/eip-1052
var ethers_1 = require("ethers"); var ethers_1 = require("ethers");
var OpcodeMemoryAccess;
(function (OpcodeMemoryAccess) {
OpcodeMemoryAccess["write"] = "write";
OpcodeMemoryAccess["read"] = "read";
OpcodeMemoryAccess["full"] = "full";
})(OpcodeMemoryAccess = exports.OpcodeMemoryAccess || (exports.OpcodeMemoryAccess = {}));
;
var Opcode = /** @class */ (function () { var Opcode = /** @class */ (function () {
function Opcode(mnemonic, value, delta, alpha, doc) { function Opcode(mnemonic, value, delta, alpha, doc) {
ethers_1.ethers.utils.defineReadOnly(this, "mnemonic", mnemonic); ethers_1.ethers.utils.defineReadOnly(this, "mnemonic", mnemonic);
@ -32,12 +39,19 @@ var Opcode = /** @class */ (function () {
return 0; return 0;
}; };
// Returns true if this operation writes to memory contents (or if readOrWrite, reads memory) // Returns true if this operation writes to memory contents (or if readOrWrite, reads memory)
Opcode.prototype.isMemory = function (readOrWrite) { // Unknown opcodes return null
throw new Error("@TODO: return true if modifies memory"); Opcode.prototype.isMemoryAccess = function (readOrWrite) {
switch ((_Opcodes[this.mnemonic.toLowerCase()] || { memory: null }).memory) {
case "read": return OpcodeMemoryAccess.read;
case "write": return OpcodeMemoryAccess.write;
case "full": return OpcodeMemoryAccess.full;
}
return null;
}; };
// Returns true if this opcode does not affect state // Returns true if this opcode does not affect state
// Unknown opcodes return false
Opcode.prototype.isStatic = function () { Opcode.prototype.isStatic = function () {
throw new Error("@TODO: return true if certain non-state-changing"); return !(_Opcodes[this.mnemonic.toLowerCase()] || { nonStatic: true }).nonStatic;
}; };
Opcode.from = function (valueOrMnemonic) { Opcode.from = function (valueOrMnemonic) {
if (typeof (valueOrMnemonic) === "string") { if (typeof (valueOrMnemonic) === "string") {
@ -78,7 +92,7 @@ var _Opcodes = {
shr: { value: 0x1c, delta: 2, alpha: 1, doc: "v = shr(shiftBits, value)" }, shr: { value: 0x1c, delta: 2, alpha: 1, doc: "v = shr(shiftBits, value)" },
sar: { value: 0x1d, delta: 2, alpha: 1, doc: "v = sar(shiftBits, value)" }, sar: { value: 0x1d, delta: 2, alpha: 1, doc: "v = sar(shiftBits, value)" },
// SHA3 // SHA3
sha3: { value: 0x20, delta: 2, alpha: 1, doc: "v = sha3(offset, length)" }, sha3: { value: 0x20, delta: 2, alpha: 1, doc: "v = sha3(offset, length)", memory: "read" },
// Environmental Information // Environmental Information
address: { value: 0x30, delta: 0, alpha: 1, doc: "myAddr = address" }, address: { value: 0x30, delta: 0, alpha: 1, doc: "myAddr = address" },
balance: { value: 0x31, delta: 1, alpha: 1, doc: "wei = balance(address)" }, balance: { value: 0x31, delta: 1, alpha: 1, doc: "wei = balance(address)" },
@ -87,14 +101,14 @@ var _Opcodes = {
callvalue: { value: 0x34, delta: 0, alpha: 1, doc: "msgValue = callvalue" }, callvalue: { value: 0x34, delta: 0, alpha: 1, doc: "msgValue = callvalue" },
calldataload: { value: 0x35, delta: 1, alpha: 1, doc: "calldataWordValue = calldataload(byteOffet)" }, calldataload: { value: 0x35, delta: 1, alpha: 1, doc: "calldataWordValue = calldataload(byteOffet)" },
calldatasize: { value: 0x36, delta: 0, alpha: 1, doc: "calldataLength = calldatasize" }, calldatasize: { value: 0x36, delta: 0, alpha: 1, doc: "calldataLength = calldatasize" },
calldatacopy: { value: 0x37, delta: 3, alpha: 0, doc: "calldatacopy(dstMemoryIndex, dataIndex, length)" }, calldatacopy: { value: 0x37, delta: 3, alpha: 0, doc: "calldatacopy(dstMemoryIndex, dataIndex, length)", memory: "write" },
codesize: { value: 0x38, delta: 0, alpha: 1, doc: "myCodeLength = codesize" }, codesize: { value: 0x38, delta: 0, alpha: 1, doc: "myCodeLength = codesize" },
codecopy: { value: 0x39, delta: 3, alpha: 0, doc: "codecopy(dstMemoryIndex, codeIndex, length)" }, codecopy: { value: 0x39, delta: 3, alpha: 0, doc: "codecopy(dstMemoryIndex, codeIndex, length)", memory: "write" },
gasprice: { value: 0x3a, delta: 0, alpha: 1, doc: "txGasPrice = gasprice" }, gasprice: { value: 0x3a, delta: 0, alpha: 1, doc: "txGasPrice = gasprice" },
extcodesize: { value: 0x3b, delta: 1, alpha: 1, doc: "otherCodeLength = extcodesize(address)" }, extcodesize: { value: 0x3b, delta: 1, alpha: 1, doc: "otherCodeLength = extcodesize(address)" },
extcodecopy: { value: 0x3c, delta: 4, alpha: 0, doc: "extcodecopy(address, dstMemoryIndex, extcodeIndex, length)" }, extcodecopy: { value: 0x3c, delta: 4, alpha: 0, doc: "extcodecopy(address, dstMemoryIndex, extcodeIndex, length)", memory: "write" },
returndatasize: { value: 0x3d, delta: 0, alpha: 1, doc: "v = returndatasize" }, returndatasize: { value: 0x3d, delta: 0, alpha: 1, doc: "v = returndatasize" },
returndatacopy: { value: 0x3e, delta: 3, alpha: 0, doc: "returndatacopy(dstMemoryOffset, returndataIndex, length)" }, returndatacopy: { value: 0x3e, delta: 3, alpha: 0, doc: "returndatacopy(dstMemoryOffset, returndataIndex, length)", memory: "write" },
extcodehash: { value: 0x3f, delta: 1, alpha: 1, doc: "hash = extcodehash(address)" }, extcodehash: { value: 0x3f, delta: 1, alpha: 1, doc: "hash = extcodehash(address)" },
// Block Information // Block Information
blockhash: { value: 0x40, delta: 1, alpha: 1, doc: "hash = blockhash(blockNumber)" }, blockhash: { value: 0x40, delta: 1, alpha: 1, doc: "hash = blockhash(blockNumber)" },
@ -105,11 +119,11 @@ var _Opcodes = {
gaslimit: { value: 0x45, delta: 0, alpha: 1, doc: "gas = gaslimit" }, gaslimit: { value: 0x45, delta: 0, alpha: 1, doc: "gas = gaslimit" },
// Stack, Memory, Storage and Flow Operations // Stack, Memory, Storage and Flow Operations
pop: { value: 0x50, delta: 1, alpha: 0, doc: "stackTopValue = pop" }, pop: { value: 0x50, delta: 1, alpha: 0, doc: "stackTopValue = pop" },
mload: { value: 0x51, delta: 1, alpha: 1, doc: "memoryWordValue = mload(memoryByteIndex)" }, mload: { value: 0x51, delta: 1, alpha: 1, doc: "memoryWordValue = mload(memoryByteIndex)", memory: "read" },
mstore: { value: 0x52, delta: 2, alpha: 0, doc: "mstore(memoryByteIndex, valueOut)" }, mstore: { value: 0x52, delta: 2, alpha: 0, doc: "mstore(memoryByteIndex, valueOut)", memory: "write" },
mstore8: { value: 0x53, delta: 2, alpha: 0, doc: "mstore8(memoryByteIndex, valueOut [ & 0xff ])" }, mstore8: { value: 0x53, delta: 2, alpha: 0, doc: "mstore8(memoryByteIndex, valueOut [ & 0xff ])", memory: "write" },
sload: { value: 0x54, delta: 1, alpha: 1, doc: "storageWordValue = sload(storageWordIndex)" }, sload: { value: 0x54, delta: 1, alpha: 1, doc: "storageWordValue = sload(storageWordIndex)" },
sstore: { value: 0x55, delta: 2, alpha: 0, doc: "sstore(storageWordIndex, valueOut)" }, sstore: { value: 0x55, delta: 2, alpha: 0, doc: "sstore(storageWordIndex, valueOut)", nonStatic: true },
jump: { value: 0x56, delta: 1, alpha: 0, doc: "jump(target)" }, jump: { value: 0x56, delta: 1, alpha: 0, doc: "jump(target)" },
jumpi: { value: 0x57, delta: 2, alpha: 0, doc: "jumpi(target, notZero)" }, jumpi: { value: 0x57, delta: 2, alpha: 0, doc: "jumpi(target, notZero)" },
pc: { value: 0x58, delta: 0, alpha: 1, doc: "programCounter = pc" }, pc: { value: 0x58, delta: 0, alpha: 1, doc: "programCounter = pc" },
@ -184,22 +198,22 @@ var _Opcodes = {
swap15: { value: 0x9e, delta: 0, alpha: 0 }, swap15: { value: 0x9e, delta: 0, alpha: 0 },
swap16: { value: 0x9f, delta: 0, alpha: 0 }, swap16: { value: 0x9f, delta: 0, alpha: 0 },
// Loggin Operations // Loggin Operations
log0: { value: 0xa0, delta: 2, alpha: 0 }, log0: { value: 0xa0, delta: 2, alpha: 0, nonStatic: true, memory: "read" },
log1: { value: 0xa1, delta: 3, alpha: 0 }, log1: { value: 0xa1, delta: 3, alpha: 0, nonStatic: true, memory: "read" },
log2: { value: 0xa2, delta: 4, alpha: 0 }, log2: { value: 0xa2, delta: 4, alpha: 0, nonStatic: true, memory: "read" },
log3: { value: 0xa3, delta: 5, alpha: 0 }, log3: { value: 0xa3, delta: 5, alpha: 0, nonStatic: true, memory: "read" },
log4: { value: 0xa4, delta: 6, alpha: 0 }, log4: { value: 0xa4, delta: 6, alpha: 0, nonStatic: true, memory: "read" },
// System Operations // System Operations
create: { value: 0xf0, delta: 3, alpha: 1, doc: "address = create(value, index, length)" }, create: { value: 0xf0, delta: 3, alpha: 1, doc: "address = create(value, index, length)", nonStatic: true, memory: "read" },
call: { value: 0xf1, delta: 7, alpha: 1, doc: "v = call(gasLimit, address, value, inputIndex, inputLength, outputIndex, outputLength)" }, call: { value: 0xf1, delta: 7, alpha: 1, doc: "v = call(gasLimit, address, value, inputIndex, inputLength, outputIndex, outputLength)", nonStatic: true, memory: "full" },
callcode: { value: 0xf2, delta: 7, alpha: 1, doc: "v = callcode(@TODO)" }, callcode: { value: 0xf2, delta: 7, alpha: 1, doc: "v = callcode(@TODO)", nonStatic: true, memory: "full" },
"return": { value: 0xf3, delta: 2, alpha: 0, doc: "return(index, length)" }, "return": { value: 0xf3, delta: 2, alpha: 0, doc: "return(index, length)", memory: "read" },
delegatecall: { value: 0xf4, delta: 6, alpha: 1, doc: "v = delegatecall(gasLimit, address, inputIndex, inputLength, outputIndex, outputLength)" }, delegatecall: { value: 0xf4, delta: 6, alpha: 1, doc: "v = delegatecall(gasLimit, address, inputIndex, inputLength, outputIndex, outputLength)", nonStatic: true, memory: "full" },
create2: { value: 0xf5, delta: 4, alpha: 1, doc: "address = create2(value, index, length, salt)" }, create2: { value: 0xf5, delta: 4, alpha: 1, doc: "address = create2(value, index, length, salt)", nonStatic: true, memory: "read" },
staticcall: { value: 0xfa, delta: 6, alpha: 1, doc: "v = staticcall(gasLimit, address, inputIndex, inputLength, outputIndex, outputLength)" }, staticcall: { value: 0xfa, delta: 6, alpha: 1, doc: "v = staticcall(gasLimit, address, inputIndex, inputLength, outputIndex, outputLength)", memory: "full" },
revert: { value: 0xfd, delta: 2, alpha: 0, doc: "revert(returnDataOffset, returnDataLength)" }, revert: { value: 0xfd, delta: 2, alpha: 0, doc: "revert(returnDataOffset, returnDataLength)", memory: "read" },
invalid: { value: 0xfe, delta: 0, alpha: 0, doc: "invalid" }, invalid: { value: 0xfe, delta: 0, alpha: 0, doc: "invalid" },
suicide: { value: 0xff, delta: 1, alpha: 0, doc: "suicide(targetAddress)" }, suicide: { value: 0xff, delta: 1, alpha: 0, doc: "suicide(targetAddress)", nonStatic: true },
}; };
var OpcodeMap = {}; var OpcodeMap = {};
var Opcodes = []; var Opcodes = [];

@ -29,7 +29,7 @@
"generate": "node ./generate.js", "generate": "node ./generate.js",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"tarballHash": "0xff54a87fe1756a7bc92d6d3b007dd65d85713495eabf6186a44f687098b67aa1", "tarballHash": "0x6a57190906839e057c493a8ffaf2c5e57b4ac513d882bddc115884bc5092649b",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"version": "5.0.0-beta.148" "version": "5.0.0-beta.149"
} }

@ -1 +1 @@
export const version = "asm/5.0.0-beta.148"; export const version = "asm/5.0.0-beta.149";

@ -1 +1 @@
export declare const version = "basex/5.0.0-beta.131"; export declare const version = "basex/5.0.0-beta.132";

@ -1 +1 @@
export const version = "basex/5.0.0-beta.131"; export const version = "basex/5.0.0-beta.132";

@ -41,8 +41,10 @@ import { BytesLike } from "@ethersproject/bytes";
export declare class BaseX { export declare class BaseX {
readonly alphabet: string; readonly alphabet: string;
readonly base: number; readonly base: number;
private _alphabetMap; _alphabetMap: {
private _leader; [character: string]: number;
};
_leader: string;
constructor(alphabet: string); constructor(alphabet: string);
encode(value: BytesLike): string; encode(value: BytesLike): string;
decode(value: string): Uint8Array; decode(value: string): Uint8Array;

@ -1 +1 @@
export declare const version = "basex/5.0.0-beta.131"; export declare const version = "basex/5.0.0-beta.132";

@ -1,3 +1,3 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "basex/5.0.0-beta.131"; exports.version = "basex/5.0.0-beta.132";

@ -41,8 +41,10 @@ import { BytesLike } from "@ethersproject/bytes";
export declare class BaseX { export declare class BaseX {
readonly alphabet: string; readonly alphabet: string;
readonly base: number; readonly base: number;
private _alphabetMap; _alphabetMap: {
private _leader; [character: string]: number;
};
_leader: string;
constructor(alphabet: string); constructor(alphabet: string);
encode(value: BytesLike): string; encode(value: BytesLike): string;
decode(value: string): Uint8Array; decode(value: string): Uint8Array;

@ -24,7 +24,7 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"tarballHash": "0xb05390e395a38be994749f03651ccc3c7d744517c9437e0fe1d1a7679266a33f", "tarballHash": "0x4f195cbe70a4657e86326d67c58dc6e244b4c816eafc232c5a8f82bb43d3dba3",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"version": "5.0.0-beta.131" "version": "5.0.0-beta.132"
} }

@ -1 +1 @@
export const version = "basex/5.0.0-beta.131"; export const version = "basex/5.0.0-beta.132";

@ -1 +1 @@
export declare const version = "cli/5.0.0-beta.150"; export declare const version = "cli/5.0.0-beta.151";

@ -1 +1 @@
export const version = "cli/5.0.0-beta.150"; export const version = "cli/5.0.0-beta.151";

@ -11,7 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}; };
import fs from "fs"; import fs from "fs";
import { resolve } from "path"; import { resolve } from "path";
import { assemble, disassemble, formatBytecode, parse } from "@ethersproject/asm"; import { assemble, disassemble, formatBytecode, parse, SemanticErrorSeverity } from "@ethersproject/asm";
import { CLI, Plugin } from "../cli"; import { CLI, Plugin } from "../cli";
function repeat(text, length) { function repeat(text, length) {
if (text.length === 0) { if (text.length === 0) {
@ -37,14 +37,26 @@ class AssemblePlugin extends Plugin {
} }
static getOptionHelp() { static getOptionHelp() {
return [ return [
{
name: "--define KEY=VALUE",
help: "provide assembler defines"
},
{ {
name: "--disassemble", name: "--disassemble",
help: "Disassemble input bytecode" help: "Disassemble input bytecode"
}, },
{ {
name: "--define KEY=VALUE", name: "--ignore-warnings",
help: "provide assembler defines" help: "Ignore warnings"
} },
{
name: "--pic",
help: "generate position independent code"
},
{
name: "--target LABEL",
help: "output LABEL bytecode (default: _)"
},
]; ];
} }
prepareOptions(argParser) { prepareOptions(argParser) {
@ -64,6 +76,9 @@ class AssemblePlugin extends Plugin {
}); });
// We are disassembling... // We are disassembling...
this.disassemble = argParser.consumeFlag("disassemble"); this.disassemble = argParser.consumeFlag("disassemble");
this.ignoreWarnings = argParser.consumeFlag("ignore-warnings");
this.pic = argParser.consumeFlag("pic");
this.target = argParser.consumeOption("target");
}); });
} }
prepareArgs(args) { prepareArgs(args) {
@ -126,11 +141,37 @@ class AssemblePlugin extends Plugin {
console.log(formatBytecode(disassemble(this.content))); console.log(formatBytecode(disassemble(this.content)));
} }
else { else {
console.log(yield assemble(parse(this.content), { try {
const ast = parse(this.content, {
ignoreWarnings: !!this.ignoreWarnings
});
console.log(yield assemble(ast, {
defines: this.defines, defines: this.defines,
filename: this.filename, filename: this.filename,
positionIndependentCode: this.pic,
target: (this.target || "_")
})); }));
} }
catch (error) {
if (error.errors) {
(error.errors).forEach((error) => {
if (error.severity === SemanticErrorSeverity.error) {
console.log(`Error: ${error.message} (line: ${error.node.location.line + 1})`);
}
else if (error.severity === SemanticErrorSeverity.warning) {
console.log(`Warning: ${error.message} (line: ${error.node.location.line + 1})`);
}
else {
console.log(error);
return;
}
});
}
else {
throw error;
}
}
}
}); });
} }
} }

@ -238,15 +238,6 @@ class AccountPlugin extends EnsPlugin {
} }
}); });
} }
prepareOptions(argParser) {
const _super = Object.create(null, {
prepareOptions: { get: () => super.prepareOptions }
});
return __awaiter(this, void 0, void 0, function* () {
yield _super.prepareOptions.call(this, argParser);
ethers.utils.defineReadOnly(this, "_wait", argParser.consumeFlag("wait"));
});
}
prepareArgs(args) { prepareArgs(args) {
const _super = Object.create(null, { const _super = Object.create(null, {
prepareArgs: { get: () => super.prepareArgs } prepareArgs: { get: () => super.prepareArgs }

@ -12,12 +12,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
import fs from "fs"; import fs from "fs";
import { dirname, resolve } from "path"; import { dirname, resolve } from "path";
import REPL from "repl"; import REPL from "repl";
import util from "util";
import vm from "vm"; import vm from "vm";
import { ethers } from "ethers"; import { ethers } from "ethers";
import { parseExpression as babelParseExpression } from "@babel/parser";
import { CLI, dump, Plugin } from "../cli"; import { CLI, dump, Plugin } from "../cli";
import { getPassword, getProgressBar } from "../prompt"; import { getPassword, getProgressBar } from "../prompt";
import { compile, customRequire } from "../solc"; import { compile, customRequire } from "../solc";
function repeat(c, length) {
if (c.length === 0) {
throw new Error("too short");
}
let result = c;
while (result.length < length) {
result += result;
}
return result.substring(0, length);
}
function setupContext(path, context, plugin) { function setupContext(path, context, plugin) {
context.provider = plugin.provider; context.provider = plugin.provider;
context.accounts = plugin.accounts; context.accounts = plugin.accounts;
@ -31,7 +41,6 @@ function setupContext(path, context, plugin) {
context.console = console; context.console = console;
} }
if (!context.require) { if (!context.require) {
//context.require = _module.createRequireFromPath(path);
context.require = customRequire(path); context.require = customRequire(path);
} }
if (!context.process) { if (!context.process) {
@ -52,7 +61,9 @@ function setupContext(path, context, plugin) {
context.getContractAddress = ethers.utils.getContractAddress; context.getContractAddress = ethers.utils.getContractAddress;
context.getIcapAddress = ethers.utils.getIcapAddress; context.getIcapAddress = ethers.utils.getIcapAddress;
context.arrayify = ethers.utils.arrayify; context.arrayify = ethers.utils.arrayify;
context.concat = ethers.utils.concat;
context.hexlify = ethers.utils.hexlify; context.hexlify = ethers.utils.hexlify;
context.zeroPad = ethers.utils.zeroPad;
context.joinSignature = ethers.utils.joinSignature; context.joinSignature = ethers.utils.joinSignature;
context.splitSignature = ethers.utils.splitSignature; context.splitSignature = ethers.utils.splitSignature;
context.id = ethers.utils.id; context.id = ethers.utils.id;
@ -71,6 +82,37 @@ function setupContext(path, context, plugin) {
context.toUtf8String = ethers.utils.toUtf8String; context.toUtf8String = ethers.utils.toUtf8String;
} }
const cli = new CLI("sandbox"); const cli = new CLI("sandbox");
function prepareCode(code) {
let ast = babelParseExpression(code, {
createParenthesizedExpressions: true
});
// Crawl the AST, to compute needed source code manipulations
const insert = [];
const descend = function (node) {
if (node == null || typeof (node) !== "object") {
return;
}
if (Array.isArray(node)) {
return node.forEach(descend);
}
// We will add parenthesis around ObjectExpressions, which
// otherwise look like blocks
if (node.type === "ObjectExpression") {
insert.push({ char: "(", offset: node.start });
insert.push({ char: ")", offset: node.end });
}
Object.keys(node).forEach((key) => descend(key));
};
descend(ast);
// We make modifications from back to front, so we don't need
// to adjust offsets
insert.sort((a, b) => (b.offset - a.offset));
// Modify the code for REPL
insert.forEach((mod) => {
code = code.substring(0, mod.offset) + mod.char + code.substring(mod.offset);
});
return code;
}
class SandboxPlugin extends Plugin { class SandboxPlugin extends Plugin {
static getHelp() { static getHelp() {
return { return {
@ -101,33 +143,59 @@ class SandboxPlugin extends Plugin {
}); });
} }
run() { run() {
console.log("network: " + this.network.name + " (chainId: " + this.network.chainId + ")"); console.log(`version: ${ethers.version}`);
let nextPromiseId = 0; console.log(`network: ${this.network.name} (chainId: ${this.network.chainId})`);
function promiseWriter(output) { const filename = resolve(process.cwd(), "./sandbox.js");
if (output instanceof Promise) { const prompt = (this.provider ? this.network.name : "no-network") + "> ";
repl.context._p = output; const evaluate = function (code, context, file, _callback) {
let promiseId = nextPromiseId++; // Pausing the stdin (which prompt does when it leaves), causes
output.then((result) => { // readline to end us. So, we always re-enable stdin on a result
console.log(`\n<Promise id=${promiseId} resolved>`); const callback = (error, result) => {
console.log(util.inspect(result)); _callback(error, result);
repl.context._r = result; process.stdin.resume();
repl.displayPrompt(true); };
try {
code = prepareCode(code);
}
catch (error) {
if (error instanceof SyntaxError) {
const leftover = code.substring(error.pos);
const loc = error.loc;
if (leftover.trim()) {
// After the first line, the prompt is "... "
console.log(repeat("-", ((loc.line === 1) ? prompt.length : 4) + loc.column - 1) + "^");
console.log(`Syntax Error! ${error.message}`);
}
else {
error = new REPL.Recoverable(error);
}
}
return callback(error);
}
try {
const result = vm.runInContext(code, context, {
filename: filename
});
if (result instanceof Promise) {
result.then((result) => {
callback(null, result);
}, (error) => { }, (error) => {
console.log(`\n<Promise id=${promiseId} rejected>`); callback(error);
console.log(util.inspect(error));
repl.displayPrompt(true);
}); });
return `<Promise id=${promiseId} pending>`;
} }
return util.inspect(output); else {
callback(null, result);
} }
let repl = REPL.start({ }
input: process.stdin, catch (error) {
output: process.stdout, callback(error);
prompt: (this.provider ? this.network.name : "no-network") + "> ", }
writer: promiseWriter };
const repl = REPL.start({
prompt: prompt,
eval: evaluate
}); });
setupContext(resolve(process.cwd(), "./sandbox.js"), repl.context, this); setupContext(filename, repl.context, this);
return new Promise((resolve) => { return new Promise((resolve) => {
repl.on("exit", function () { repl.on("exit", function () {
console.log(""); console.log("");

@ -39,7 +39,7 @@ export interface PluginType {
export declare abstract class Plugin { export declare abstract class Plugin {
network: ethers.providers.Network; network: ethers.providers.Network;
provider: ethers.providers.Provider; provider: ethers.providers.Provider;
accounts: Array<WrappedSigner>; accounts: ReadonlyArray<WrappedSigner>;
mnemonicPassword: boolean; mnemonicPassword: boolean;
_xxxMnemonicPasswordHard: boolean; _xxxMnemonicPasswordHard: boolean;
gasLimit: ethers.BigNumber; gasLimit: ethers.BigNumber;

@ -1 +1 @@
export declare const version = "cli/5.0.0-beta.150"; export declare const version = "cli/5.0.0-beta.151";

@ -1,3 +1,3 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "cli/5.0.0-beta.150"; exports.version = "cli/5.0.0-beta.151";

57
packages/cli/lib/bin/ethers-asm.js Normal file → Executable file

@ -85,14 +85,26 @@ var AssemblePlugin = /** @class */ (function (_super) {
}; };
AssemblePlugin.getOptionHelp = function () { AssemblePlugin.getOptionHelp = function () {
return [ return [
{
name: "--define KEY=VALUE",
help: "provide assembler defines"
},
{ {
name: "--disassemble", name: "--disassemble",
help: "Disassemble input bytecode" help: "Disassemble input bytecode"
}, },
{ {
name: "--define KEY=VALUE", name: "--ignore-warnings",
help: "provide assembler defines" help: "Ignore warnings"
} },
{
name: "--pic",
help: "generate position independent code"
},
{
name: "--target LABEL",
help: "output LABEL bytecode (default: _)"
},
]; ];
}; };
AssemblePlugin.prototype.prepareOptions = function (argParser) { AssemblePlugin.prototype.prepareOptions = function (argParser) {
@ -114,6 +126,9 @@ var AssemblePlugin = /** @class */ (function (_super) {
}); });
// We are disassembling... // We are disassembling...
this.disassemble = argParser.consumeFlag("disassemble"); this.disassemble = argParser.consumeFlag("disassemble");
this.ignoreWarnings = argParser.consumeFlag("ignore-warnings");
this.pic = argParser.consumeFlag("pic");
this.target = argParser.consumeOption("target");
return [2 /*return*/]; return [2 /*return*/];
} }
}); });
@ -181,23 +196,49 @@ var AssemblePlugin = /** @class */ (function (_super) {
}; };
AssemblePlugin.prototype.run = function () { AssemblePlugin.prototype.run = function () {
return __awaiter(this, void 0, void 0, function () { return __awaiter(this, void 0, void 0, function () {
var _a, _b; var ast, _a, _b, error_1;
return __generator(this, function (_c) { return __generator(this, function (_c) {
switch (_c.label) { switch (_c.label) {
case 0: case 0:
if (!this.disassemble) return [3 /*break*/, 1]; if (!this.disassemble) return [3 /*break*/, 1];
console.log(asm_1.formatBytecode(asm_1.disassemble(this.content))); console.log(asm_1.formatBytecode(asm_1.disassemble(this.content)));
return [3 /*break*/, 3]; return [3 /*break*/, 4];
case 1: case 1:
_c.trys.push([1, 3, , 4]);
ast = asm_1.parse(this.content, {
ignoreWarnings: !!this.ignoreWarnings
});
_b = (_a = console).log; _b = (_a = console).log;
return [4 /*yield*/, asm_1.assemble(asm_1.parse(this.content), { return [4 /*yield*/, asm_1.assemble(ast, {
defines: this.defines, defines: this.defines,
filename: this.filename, filename: this.filename,
positionIndependentCode: this.pic,
target: (this.target || "_")
})]; })];
case 2: case 2:
_b.apply(_a, [_c.sent()]); _b.apply(_a, [_c.sent()]);
_c.label = 3; return [3 /*break*/, 4];
case 3: return [2 /*return*/]; case 3:
error_1 = _c.sent();
if (error_1.errors) {
(error_1.errors).forEach(function (error) {
if (error.severity === asm_1.SemanticErrorSeverity.error) {
console.log("Error: " + error.message + " (line: " + (error.node.location.line + 1) + ")");
}
else if (error.severity === asm_1.SemanticErrorSeverity.warning) {
console.log("Warning: " + error.message + " (line: " + (error.node.location.line + 1) + ")");
}
else {
console.log(error);
return;
}
});
}
else {
throw error_1;
}
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
} }
}); });
}); });

@ -404,19 +404,6 @@ var AccountPlugin = /** @class */ (function (_super) {
}); });
}); });
}; };
AccountPlugin.prototype.prepareOptions = function (argParser) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, _super.prototype.prepareOptions.call(this, argParser)];
case 1:
_a.sent();
ethers_1.ethers.utils.defineReadOnly(this, "_wait", argParser.consumeFlag("wait"));
return [2 /*return*/];
}
});
});
};
AccountPlugin.prototype.prepareArgs = function (args) { AccountPlugin.prototype.prepareArgs = function (args) {
return __awaiter(this, void 0, void 0, function () { return __awaiter(this, void 0, void 0, function () {
var helpLine, params, command, i; var helpLine, params, command, i;

@ -56,12 +56,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
var fs_1 = __importDefault(require("fs")); var fs_1 = __importDefault(require("fs"));
var path_1 = require("path"); var path_1 = require("path");
var repl_1 = __importDefault(require("repl")); var repl_1 = __importDefault(require("repl"));
var util_1 = __importDefault(require("util"));
var vm_1 = __importDefault(require("vm")); var vm_1 = __importDefault(require("vm"));
var ethers_1 = require("ethers"); var ethers_1 = require("ethers");
var parser_1 = require("@babel/parser");
var cli_1 = require("../cli"); var cli_1 = require("../cli");
var prompt_1 = require("../prompt"); var prompt_1 = require("../prompt");
var solc_1 = require("../solc"); var solc_1 = require("../solc");
function repeat(c, length) {
if (c.length === 0) {
throw new Error("too short");
}
var result = c;
while (result.length < length) {
result += result;
}
return result.substring(0, length);
}
function setupContext(path, context, plugin) { function setupContext(path, context, plugin) {
context.provider = plugin.provider; context.provider = plugin.provider;
context.accounts = plugin.accounts; context.accounts = plugin.accounts;
@ -75,7 +85,6 @@ function setupContext(path, context, plugin) {
context.console = console; context.console = console;
} }
if (!context.require) { if (!context.require) {
//context.require = _module.createRequireFromPath(path);
context.require = solc_1.customRequire(path); context.require = solc_1.customRequire(path);
} }
if (!context.process) { if (!context.process) {
@ -96,7 +105,9 @@ function setupContext(path, context, plugin) {
context.getContractAddress = ethers_1.ethers.utils.getContractAddress; context.getContractAddress = ethers_1.ethers.utils.getContractAddress;
context.getIcapAddress = ethers_1.ethers.utils.getIcapAddress; context.getIcapAddress = ethers_1.ethers.utils.getIcapAddress;
context.arrayify = ethers_1.ethers.utils.arrayify; context.arrayify = ethers_1.ethers.utils.arrayify;
context.concat = ethers_1.ethers.utils.concat;
context.hexlify = ethers_1.ethers.utils.hexlify; context.hexlify = ethers_1.ethers.utils.hexlify;
context.zeroPad = ethers_1.ethers.utils.zeroPad;
context.joinSignature = ethers_1.ethers.utils.joinSignature; context.joinSignature = ethers_1.ethers.utils.joinSignature;
context.splitSignature = ethers_1.ethers.utils.splitSignature; context.splitSignature = ethers_1.ethers.utils.splitSignature;
context.id = ethers_1.ethers.utils.id; context.id = ethers_1.ethers.utils.id;
@ -115,6 +126,37 @@ function setupContext(path, context, plugin) {
context.toUtf8String = ethers_1.ethers.utils.toUtf8String; context.toUtf8String = ethers_1.ethers.utils.toUtf8String;
} }
var cli = new cli_1.CLI("sandbox"); var cli = new cli_1.CLI("sandbox");
function prepareCode(code) {
var ast = parser_1.parseExpression(code, {
createParenthesizedExpressions: true
});
// Crawl the AST, to compute needed source code manipulations
var insert = [];
var descend = function (node) {
if (node == null || typeof (node) !== "object") {
return;
}
if (Array.isArray(node)) {
return node.forEach(descend);
}
// We will add parenthesis around ObjectExpressions, which
// otherwise look like blocks
if (node.type === "ObjectExpression") {
insert.push({ char: "(", offset: node.start });
insert.push({ char: ")", offset: node.end });
}
Object.keys(node).forEach(function (key) { return descend(key); });
};
descend(ast);
// We make modifications from back to front, so we don't need
// to adjust offsets
insert.sort(function (a, b) { return (b.offset - a.offset); });
// Modify the code for REPL
insert.forEach(function (mod) {
code = code.substring(0, mod.offset) + mod.char + code.substring(mod.offset);
});
return code;
}
var SandboxPlugin = /** @class */ (function (_super) { var SandboxPlugin = /** @class */ (function (_super) {
__extends(SandboxPlugin, _super); __extends(SandboxPlugin, _super);
function SandboxPlugin() { function SandboxPlugin() {
@ -166,33 +208,59 @@ var SandboxPlugin = /** @class */ (function (_super) {
}); });
}; };
SandboxPlugin.prototype.run = function () { SandboxPlugin.prototype.run = function () {
console.log("version: " + ethers_1.ethers.version);
console.log("network: " + this.network.name + " (chainId: " + this.network.chainId + ")"); console.log("network: " + this.network.name + " (chainId: " + this.network.chainId + ")");
var nextPromiseId = 0; var filename = path_1.resolve(process.cwd(), "./sandbox.js");
function promiseWriter(output) { var prompt = (this.provider ? this.network.name : "no-network") + "> ";
if (output instanceof Promise) { var evaluate = function (code, context, file, _callback) {
repl.context._p = output; // Pausing the stdin (which prompt does when it leaves), causes
var promiseId_1 = nextPromiseId++; // readline to end us. So, we always re-enable stdin on a result
output.then(function (result) { var callback = function (error, result) {
console.log("\n<Promise id=" + promiseId_1 + " resolved>"); _callback(error, result);
console.log(util_1.default.inspect(result)); process.stdin.resume();
repl.context._r = result; };
repl.displayPrompt(true); try {
code = prepareCode(code);
}
catch (error) {
if (error instanceof SyntaxError) {
var leftover = code.substring(error.pos);
var loc = error.loc;
if (leftover.trim()) {
// After the first line, the prompt is "... "
console.log(repeat("-", ((loc.line === 1) ? prompt.length : 4) + loc.column - 1) + "^");
console.log("Syntax Error! " + error.message);
}
else {
error = new repl_1.default.Recoverable(error);
}
}
return callback(error);
}
try {
var result = vm_1.default.runInContext(code, context, {
filename: filename
});
if (result instanceof Promise) {
result.then(function (result) {
callback(null, result);
}, function (error) { }, function (error) {
console.log("\n<Promise id=" + promiseId_1 + " rejected>"); callback(error);
console.log(util_1.default.inspect(error));
repl.displayPrompt(true);
}); });
return "<Promise id=" + promiseId_1 + " pending>";
} }
return util_1.default.inspect(output); else {
callback(null, result);
} }
}
catch (error) {
callback(error);
}
};
var repl = repl_1.default.start({ var repl = repl_1.default.start({
input: process.stdin, prompt: prompt,
output: process.stdout, eval: evaluate
prompt: (this.provider ? this.network.name : "no-network") + "> ",
writer: promiseWriter
}); });
setupContext(path_1.resolve(process.cwd(), "./sandbox.js"), repl.context, this); setupContext(filename, repl.context, this);
return new Promise(function (resolve) { return new Promise(function (resolve) {
repl.on("exit", function () { repl.on("exit", function () {
console.log(""); console.log("");

@ -39,7 +39,7 @@ export interface PluginType {
export declare abstract class Plugin { export declare abstract class Plugin {
network: ethers.providers.Network; network: ethers.providers.Network;
provider: ethers.providers.Provider; provider: ethers.providers.Provider;
accounts: Array<WrappedSigner>; accounts: ReadonlyArray<WrappedSigner>;
mnemonicPassword: boolean; mnemonicPassword: boolean;
_xxxMnemonicPasswordHard: boolean; _xxxMnemonicPasswordHard: boolean;
gasLimit: ethers.BigNumber; gasLimit: ethers.BigNumber;

@ -8,6 +8,7 @@
}, },
"dependencies": { "dependencies": {
"@babel/parser": "7.8.4", "@babel/parser": "7.8.4",
"@babel/types": "7.8.3",
"@ethersproject/asm": ">=5.0.0-beta.148", "@ethersproject/asm": ">=5.0.0-beta.148",
"@ethersproject/basex": ">=5.0.0-beta.127", "@ethersproject/basex": ">=5.0.0-beta.127",
"ethers": ">=5.0.0-beta.156", "ethers": ">=5.0.0-beta.156",
@ -40,7 +41,7 @@
"scripts": { "scripts": {
"test": "exit 1" "test": "exit 1"
}, },
"tarballHash": "0xf20ecfe28643c5e68c573b3204e4a03e02494722929d2fa2467d800ef0ff6edb", "tarballHash": "0xf7cdf17b34ec310a5d6e2f93116a70787764532f9c9a11d7dcb5484ed44d731d",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"version": "5.0.0-beta.150" "version": "5.0.0-beta.151"
} }

@ -1 +1 @@
export const version = "cli/5.0.0-beta.150"; export const version = "cli/5.0.0-beta.151";

@ -180,6 +180,8 @@ class AssemblePlugin extends Plugin {
return; return;
} }
}); });
} else {
throw error;
} }
} }
} }

@ -57,7 +57,9 @@ function setupContext(path: string, context: any, plugin: Plugin) {
context.getIcapAddress = ethers.utils.getIcapAddress; context.getIcapAddress = ethers.utils.getIcapAddress;
context.arrayify = ethers.utils.arrayify; context.arrayify = ethers.utils.arrayify;
context.concat = ethers.utils.concat;
context.hexlify = ethers.utils.hexlify; context.hexlify = ethers.utils.hexlify;
context.zeroPad = ethers.utils.zeroPad;
context.joinSignature = ethers.utils.joinSignature; context.joinSignature = ethers.utils.joinSignature;
context.splitSignature = ethers.utils.splitSignature; context.splitSignature = ethers.utils.splitSignature;

@ -1,7 +1,7 @@
"use strict"; "use strict";
import { EventFragment, Fragment, Indexed, Interface, JsonFragment, ParamType, Result } from "@ethersproject/abi"; import { EventFragment, Fragment, Indexed, Interface, JsonFragment, ParamType, Result } from "@ethersproject/abi";
import { Block, BlockTag, Listener, Log, Provider, TransactionReceipt, TransactionRequest, TransactionResponse } from "@ethersproject/abstract-provider"; import { Block, BlockTag, Filter, FilterByBlockHash, Listener, Log, Provider, TransactionReceipt, TransactionRequest, TransactionResponse } from "@ethersproject/abstract-provider";
import { Signer, VoidSigner } from "@ethersproject/abstract-signer"; import { Signer, VoidSigner } from "@ethersproject/abstract-signer";
import { getContractAddress } from "@ethersproject/address"; import { getContractAddress } from "@ethersproject/address";
import { BigNumber, BigNumberish } from "@ethersproject/bignumber"; import { BigNumber, BigNumberish } from "@ethersproject/bignumber";
@ -780,10 +780,10 @@ export class Contract {
if (toBlock != null) { if (toBlock != null) {
logger.throwArgumentError("cannot specify toBlock with blockhash", "toBlock", toBlock); logger.throwArgumentError("cannot specify toBlock with blockhash", "toBlock", toBlock);
} }
filter.blockhash = fromBlockOrBlockhash; (<FilterByBlockHash>filter).blockhash = fromBlockOrBlockhash;
} else { } else {
filter.fromBlock = ((fromBlockOrBlockhash != null) ? fromBlockOrBlockhash: 0); (<Filter>filter).fromBlock = ((fromBlockOrBlockhash != null) ? fromBlockOrBlockhash: 0);
filter.toBlock = ((toBlock != null) ? toBlock: "latest"); (<Filter>filter).toBlock = ((toBlock != null) ? toBlock: "latest");
} }
return this.provider.getLogs(filter).then((logs) => { return this.provider.getLogs(filter).then((logs) => {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -4629,7 +4629,7 @@ class FixedNumber {
} }
} }
const version$3 = "properties/5.0.0-beta.136"; const version$3 = "properties/5.0.0-beta.137";
"use strict"; "use strict";
const logger$3 = new Logger(version$3); const logger$3 = new Logger(version$3);
@ -4665,10 +4665,10 @@ function resolveProperties(object) {
}); });
return Promise.all(promises).then((results) => { return Promise.all(promises).then((results) => {
const result = {}; const result = {};
return results.reduce((accum, result) => { return (results.reduce((accum, result) => {
accum[result.key] = result.value; accum[result.key] = result.value;
return accum; return accum;
}, result); }, result));
}); });
} }
function checkProperties(object, properties) { function checkProperties(object, properties) {
@ -4691,7 +4691,7 @@ function shallowCopy(object) {
const opaque = { bigint: true, boolean: true, number: true, string: true }; const opaque = { bigint: true, boolean: true, number: true, string: true };
// Returns a new copy of object, such that no properties may be replaced. // Returns a new copy of object, such that no properties may be replaced.
// New properties may be added only to objects. // New properties may be added only to objects.
function deepCopy(object) { function _deepCopy(object) {
// Opaque objects are not mutable, so safe to copy by assignment // Opaque objects are not mutable, so safe to copy by assignment
if (object === undefined || object === null || opaque[typeof (object)]) { if (object === undefined || object === null || opaque[typeof (object)]) {
return object; return object;
@ -4719,7 +4719,10 @@ function deepCopy(object) {
if (typeof (object) === "function") { if (typeof (object) === "function") {
return object; return object;
} }
throw new Error("Cannot deepCopy " + typeof (object)); logger$3.throwArgumentError(`Cannot deepCopy ${typeof (object)}`, "object", object);
}
function deepCopy(object) {
return _deepCopy(object);
} }
class Description { class Description {
constructor(info) { constructor(info) {
@ -4739,7 +4742,7 @@ var lib_esm$2 = /*#__PURE__*/Object.freeze({
Description: Description Description: Description
}); });
const version$4 = "abi/5.0.0-beta.144"; const version$4 = "abi/5.0.0-beta.145";
"use strict"; "use strict";
const logger$4 = new Logger(version$4); const logger$4 = new Logger(version$4);
@ -7715,7 +7718,7 @@ class Provider {
} }
} }
const version$9 = "abstract-signer/5.0.0-beta.139"; const version$9 = "abstract-signer/5.0.0-beta.140";
"use strict"; "use strict";
var __awaiter = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) { var __awaiter = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
@ -7838,25 +7841,9 @@ class Signer {
if (tx.nonce == null) { if (tx.nonce == null) {
tx.nonce = this.getTransactionCount("pending"); tx.nonce = this.getTransactionCount("pending");
} }
/*
// checkTransaction does this...
if (tx.from == null) {
tx.from = this.getAddress();
} else {
tx.from = Promise.all([
this.getAddress(),
this.provider.resolveName(tx.from)
]).then((results) => {
if (results[0] !== results[1]) {
logger.throwArgumentError("from address mismatch", "transaction", transaction);
}
return results[0];
});
}
*/
if (tx.gasLimit == null) { if (tx.gasLimit == null) {
tx.gasLimit = this.estimateGas(tx).catch((error) => { tx.gasLimit = this.estimateGas(tx).catch((error) => {
logger$d.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, { return logger$d.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, {
tx: tx tx: tx
}); });
}); });
@ -15111,7 +15098,7 @@ function decryptJsonWallet(json, password, progressCallback) {
return Promise.reject(new Error("invalid JSON wallet")); return Promise.reject(new Error("invalid JSON wallet"));
} }
const version$g = "wallet/5.0.0-beta.136"; const version$g = "wallet/5.0.0-beta.137";
"use strict"; "use strict";
const logger$k = new Logger(version$g); const logger$k = new Logger(version$g);
@ -15148,7 +15135,6 @@ class Wallet extends Signer {
} }
else { else {
defineReadOnly(this, "_mnemonic", () => null); defineReadOnly(this, "_mnemonic", () => null);
defineReadOnly(this, "path", null);
} }
} }
else { else {
@ -15163,7 +15149,6 @@ class Wallet extends Signer {
defineReadOnly(this, "_signingKey", () => signingKey); defineReadOnly(this, "_signingKey", () => signingKey);
} }
defineReadOnly(this, "_mnemonic", () => null); defineReadOnly(this, "_mnemonic", () => null);
defineReadOnly(this, "path", null);
defineReadOnly(this, "address", computeAddress(this.publicKey)); defineReadOnly(this, "address", computeAddress(this.publicKey));
} }
if (provider && !Provider.isProvider(provider)) { if (provider && !Provider.isProvider(provider)) {
@ -16265,7 +16250,7 @@ function poll(func, options) {
}); });
} }
const version$j = "providers/5.0.0-beta.152"; const version$j = "providers/5.0.0-beta.153";
"use strict"; "use strict";
const logger$n = new Logger(version$j); const logger$n = new Logger(version$j);
@ -19362,7 +19347,7 @@ var utils$1 = /*#__PURE__*/Object.freeze({
Indexed: Indexed Indexed: Indexed
}); });
const version$l = "ethers/5.0.0-beta.172"; const version$l = "ethers/5.0.0-beta.173";
"use strict"; "use strict";
const errors = Logger.errors; const errors = Logger.errors;

File diff suppressed because one or more lines are too long

@ -4757,7 +4757,7 @@
var _version$6 = createCommonjsModule(function (module, exports) { var _version$6 = createCommonjsModule(function (module, exports) {
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "properties/5.0.0-beta.136"; exports.version = "properties/5.0.0-beta.137";
}); });
var _version$7 = unwrapExports(_version$6); var _version$7 = unwrapExports(_version$6);
@ -4803,10 +4803,10 @@
}); });
return Promise.all(promises).then(function (results) { return Promise.all(promises).then(function (results) {
var result = {}; var result = {};
return results.reduce(function (accum, result) { return (results.reduce(function (accum, result) {
accum[result.key] = result.value; accum[result.key] = result.value;
return accum; return accum;
}, result); }, result));
}); });
} }
exports.resolveProperties = resolveProperties; exports.resolveProperties = resolveProperties;
@ -4832,7 +4832,7 @@
var opaque = { bigint: true, boolean: true, number: true, string: true }; var opaque = { bigint: true, boolean: true, number: true, string: true };
// Returns a new copy of object, such that no properties may be replaced. // Returns a new copy of object, such that no properties may be replaced.
// New properties may be added only to objects. // New properties may be added only to objects.
function deepCopy(object) { function _deepCopy(object) {
// Opaque objects are not mutable, so safe to copy by assignment // Opaque objects are not mutable, so safe to copy by assignment
if (object === undefined || object === null || opaque[typeof (object)]) { if (object === undefined || object === null || opaque[typeof (object)]) {
return object; return object;
@ -4860,7 +4860,10 @@
if (typeof (object) === "function") { if (typeof (object) === "function") {
return object; return object;
} }
throw new Error("Cannot deepCopy " + typeof (object)); logger.throwArgumentError("Cannot deepCopy " + typeof (object), "object", object);
}
function deepCopy(object) {
return _deepCopy(object);
} }
exports.deepCopy = deepCopy; exports.deepCopy = deepCopy;
var Description = /** @class */ (function () { var Description = /** @class */ (function () {
@ -4886,7 +4889,7 @@
var _version$8 = createCommonjsModule(function (module, exports) { var _version$8 = createCommonjsModule(function (module, exports) {
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "abi/5.0.0-beta.144"; exports.version = "abi/5.0.0-beta.145";
}); });
var _version$9 = unwrapExports(_version$8); var _version$9 = unwrapExports(_version$8);
@ -8545,7 +8548,7 @@
var _version$i = createCommonjsModule(function (module, exports) { var _version$i = createCommonjsModule(function (module, exports) {
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "abstract-signer/5.0.0-beta.139"; exports.version = "abstract-signer/5.0.0-beta.140";
}); });
var _version$j = unwrapExports(_version$i); var _version$j = unwrapExports(_version$i);
@ -8727,25 +8730,9 @@
if (tx.nonce == null) { if (tx.nonce == null) {
tx.nonce = this.getTransactionCount("pending"); tx.nonce = this.getTransactionCount("pending");
} }
/*
// checkTransaction does this...
if (tx.from == null) {
tx.from = this.getAddress();
} else {
tx.from = Promise.all([
this.getAddress(),
this.provider.resolveName(tx.from)
]).then((results) => {
if (results[0] !== results[1]) {
logger.throwArgumentError("from address mismatch", "transaction", transaction);
}
return results[0];
});
}
*/
if (tx.gasLimit == null) { if (tx.gasLimit == null) {
tx.gasLimit = this.estimateGas(tx).catch(function (error) { tx.gasLimit = this.estimateGas(tx).catch(function (error) {
logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", lib.Logger.errors.UNPREDICTABLE_GAS_LIMIT, { return logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", lib.Logger.errors.UNPREDICTABLE_GAS_LIMIT, {
tx: tx tx: tx
}); });
}); });
@ -16414,7 +16401,7 @@
var _version$A = createCommonjsModule(function (module, exports) { var _version$A = createCommonjsModule(function (module, exports) {
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "wallet/5.0.0-beta.136"; exports.version = "wallet/5.0.0-beta.137";
}); });
var _version$B = unwrapExports(_version$A); var _version$B = unwrapExports(_version$A);
@ -16487,7 +16474,6 @@
} }
else { else {
lib$3.defineReadOnly(_this, "_mnemonic", function () { return null; }); lib$3.defineReadOnly(_this, "_mnemonic", function () { return null; });
lib$3.defineReadOnly(_this, "path", null);
} }
} }
else { else {
@ -16502,7 +16488,6 @@
lib$3.defineReadOnly(_this, "_signingKey", function () { return signingKey_2; }); lib$3.defineReadOnly(_this, "_signingKey", function () { return signingKey_2; });
} }
lib$3.defineReadOnly(_this, "_mnemonic", function () { return null; }); lib$3.defineReadOnly(_this, "_mnemonic", function () { return null; });
lib$3.defineReadOnly(_this, "path", null);
lib$3.defineReadOnly(_this, "address", lib$g.computeAddress(_this.publicKey)); lib$3.defineReadOnly(_this, "address", lib$g.computeAddress(_this.publicKey));
} }
if (provider && !lib$b.Provider.isProvider(provider)) { if (provider && !lib$b.Provider.isProvider(provider)) {
@ -17710,7 +17695,7 @@
var _version$G = createCommonjsModule(function (module, exports) { var _version$G = createCommonjsModule(function (module, exports) {
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "providers/5.0.0-beta.152"; exports.version = "providers/5.0.0-beta.153";
}); });
var _version$H = unwrapExports(_version$G); var _version$H = unwrapExports(_version$G);
@ -21875,7 +21860,7 @@
var _version$K = createCommonjsModule(function (module, exports) { var _version$K = createCommonjsModule(function (module, exports) {
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "ethers/5.0.0-beta.172"; exports.version = "ethers/5.0.0-beta.173";
}); });
var _version$L = unwrapExports(_version$K); var _version$L = unwrapExports(_version$K);

File diff suppressed because one or more lines are too long

@ -1 +1 @@
export declare const version = "ethers/5.0.0-beta.172"; export declare const version = "ethers/5.0.0-beta.173";

@ -1 +1 @@
export const version = "ethers/5.0.0-beta.172"; export const version = "ethers/5.0.0-beta.173";

@ -20,10 +20,11 @@ import { verifyMessage } from "@ethersproject/wallet";
import { fetchJson, poll } from "@ethersproject/web"; import { fetchJson, poll } from "@ethersproject/web";
import { SupportedAlgorithm } from "@ethersproject/sha2"; import { SupportedAlgorithm } from "@ethersproject/sha2";
import { UnicodeNormalizationForm, Utf8ErrorReason } from "@ethersproject/strings"; import { UnicodeNormalizationForm, Utf8ErrorReason } from "@ethersproject/strings";
import { UnsignedTransaction } from "@ethersproject/transactions";
import { CoerceFunc } from "@ethersproject/abi"; import { CoerceFunc } from "@ethersproject/abi";
import { Bytes, BytesLike, Hexable } from "@ethersproject/bytes"; import { Bytes, BytesLike, Hexable } from "@ethersproject/bytes";
import { Mnemonic } from "@ethersproject/hdnode"; import { Mnemonic } from "@ethersproject/hdnode";
import { EncryptOptions, ProgressCallback } from "@ethersproject/json-wallets"; import { EncryptOptions, ProgressCallback } from "@ethersproject/json-wallets";
import { Utf8ErrorFunc } from "@ethersproject/strings"; import { Utf8ErrorFunc } from "@ethersproject/strings";
import { ConnectionInfo, FetchJsonResponse, OnceBlockable, PollOptions } from "@ethersproject/web"; import { ConnectionInfo, FetchJsonResponse, OnceBlockable, PollOptions } from "@ethersproject/web";
export { AbiCoder, defaultAbiCoder, Fragment, EventFragment, FunctionFragment, ParamType, FormatTypes, Logger, RLP, fetchJson, poll, checkProperties, deepCopy, defineReadOnly, getStatic, resolveProperties, shallowCopy, arrayify, concat, stripZeros, zeroPad, isBytes, isBytesLike, defaultPath, HDNode, SigningKey, Interface, base64, hexlify, isHexString, hexStripZeros, hexValue, hexZeroPad, hexDataLength, hexDataSlice, nameprep, _toEscapedUtf8String, toUtf8Bytes, toUtf8CodePoints, toUtf8String, Utf8ErrorFuncs, formatBytes32String, parseBytes32String, hashMessage, namehash, isValidName, id, getAddress, getIcapAddress, getContractAddress, getCreate2Address, isAddress, formatEther, parseEther, formatUnits, parseUnits, commify, keccak256, sha256, randomBytes, solidityPack, solidityKeccak256, soliditySha256, splitSignature, joinSignature, parseTransaction, serializeTransaction, getJsonWalletAddress, computeAddress, recoverAddress, computePublicKey, recoverPublicKey, verifyMessage, mnemonicToEntropy, entropyToMnemonic, isValidMnemonic, mnemonicToSeed, SupportedAlgorithm, UnicodeNormalizationForm, Utf8ErrorReason, Bytes, BytesLike, Hexable, CoerceFunc, Indexed, Mnemonic, Utf8ErrorFunc, ConnectionInfo, OnceBlockable, PollOptions, FetchJsonResponse, EncryptOptions, ProgressCallback }; export { AbiCoder, defaultAbiCoder, Fragment, EventFragment, FunctionFragment, ParamType, FormatTypes, Logger, RLP, fetchJson, poll, checkProperties, deepCopy, defineReadOnly, getStatic, resolveProperties, shallowCopy, arrayify, concat, stripZeros, zeroPad, isBytes, isBytesLike, defaultPath, HDNode, SigningKey, Interface, base64, hexlify, isHexString, hexStripZeros, hexValue, hexZeroPad, hexDataLength, hexDataSlice, nameprep, _toEscapedUtf8String, toUtf8Bytes, toUtf8CodePoints, toUtf8String, Utf8ErrorFuncs, formatBytes32String, parseBytes32String, hashMessage, namehash, isValidName, id, getAddress, getIcapAddress, getContractAddress, getCreate2Address, isAddress, formatEther, parseEther, formatUnits, parseUnits, commify, keccak256, sha256, randomBytes, solidityPack, solidityKeccak256, soliditySha256, splitSignature, joinSignature, parseTransaction, serializeTransaction, getJsonWalletAddress, computeAddress, recoverAddress, computePublicKey, recoverPublicKey, verifyMessage, mnemonicToEntropy, entropyToMnemonic, isValidMnemonic, mnemonicToSeed, SupportedAlgorithm, UnicodeNormalizationForm, Utf8ErrorReason, Bytes, BytesLike, Hexable, UnsignedTransaction, CoerceFunc, Indexed, Mnemonic, Utf8ErrorFunc, ConnectionInfo, OnceBlockable, PollOptions, FetchJsonResponse, EncryptOptions, ProgressCallback };

@ -1 +1 @@
export declare const version = "ethers/5.0.0-beta.172"; export declare const version = "ethers/5.0.0-beta.173";

@ -1,3 +1,3 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "ethers/5.0.0-beta.172"; exports.version = "ethers/5.0.0-beta.173";

@ -20,10 +20,11 @@ import { verifyMessage } from "@ethersproject/wallet";
import { fetchJson, poll } from "@ethersproject/web"; import { fetchJson, poll } from "@ethersproject/web";
import { SupportedAlgorithm } from "@ethersproject/sha2"; import { SupportedAlgorithm } from "@ethersproject/sha2";
import { UnicodeNormalizationForm, Utf8ErrorReason } from "@ethersproject/strings"; import { UnicodeNormalizationForm, Utf8ErrorReason } from "@ethersproject/strings";
import { UnsignedTransaction } from "@ethersproject/transactions";
import { CoerceFunc } from "@ethersproject/abi"; import { CoerceFunc } from "@ethersproject/abi";
import { Bytes, BytesLike, Hexable } from "@ethersproject/bytes"; import { Bytes, BytesLike, Hexable } from "@ethersproject/bytes";
import { Mnemonic } from "@ethersproject/hdnode"; import { Mnemonic } from "@ethersproject/hdnode";
import { EncryptOptions, ProgressCallback } from "@ethersproject/json-wallets"; import { EncryptOptions, ProgressCallback } from "@ethersproject/json-wallets";
import { Utf8ErrorFunc } from "@ethersproject/strings"; import { Utf8ErrorFunc } from "@ethersproject/strings";
import { ConnectionInfo, FetchJsonResponse, OnceBlockable, PollOptions } from "@ethersproject/web"; import { ConnectionInfo, FetchJsonResponse, OnceBlockable, PollOptions } from "@ethersproject/web";
export { AbiCoder, defaultAbiCoder, Fragment, EventFragment, FunctionFragment, ParamType, FormatTypes, Logger, RLP, fetchJson, poll, checkProperties, deepCopy, defineReadOnly, getStatic, resolveProperties, shallowCopy, arrayify, concat, stripZeros, zeroPad, isBytes, isBytesLike, defaultPath, HDNode, SigningKey, Interface, base64, hexlify, isHexString, hexStripZeros, hexValue, hexZeroPad, hexDataLength, hexDataSlice, nameprep, _toEscapedUtf8String, toUtf8Bytes, toUtf8CodePoints, toUtf8String, Utf8ErrorFuncs, formatBytes32String, parseBytes32String, hashMessage, namehash, isValidName, id, getAddress, getIcapAddress, getContractAddress, getCreate2Address, isAddress, formatEther, parseEther, formatUnits, parseUnits, commify, keccak256, sha256, randomBytes, solidityPack, solidityKeccak256, soliditySha256, splitSignature, joinSignature, parseTransaction, serializeTransaction, getJsonWalletAddress, computeAddress, recoverAddress, computePublicKey, recoverPublicKey, verifyMessage, mnemonicToEntropy, entropyToMnemonic, isValidMnemonic, mnemonicToSeed, SupportedAlgorithm, UnicodeNormalizationForm, Utf8ErrorReason, Bytes, BytesLike, Hexable, CoerceFunc, Indexed, Mnemonic, Utf8ErrorFunc, ConnectionInfo, OnceBlockable, PollOptions, FetchJsonResponse, EncryptOptions, ProgressCallback }; export { AbiCoder, defaultAbiCoder, Fragment, EventFragment, FunctionFragment, ParamType, FormatTypes, Logger, RLP, fetchJson, poll, checkProperties, deepCopy, defineReadOnly, getStatic, resolveProperties, shallowCopy, arrayify, concat, stripZeros, zeroPad, isBytes, isBytesLike, defaultPath, HDNode, SigningKey, Interface, base64, hexlify, isHexString, hexStripZeros, hexValue, hexZeroPad, hexDataLength, hexDataSlice, nameprep, _toEscapedUtf8String, toUtf8Bytes, toUtf8CodePoints, toUtf8String, Utf8ErrorFuncs, formatBytes32String, parseBytes32String, hashMessage, namehash, isValidName, id, getAddress, getIcapAddress, getContractAddress, getCreate2Address, isAddress, formatEther, parseEther, formatUnits, parseUnits, commify, keccak256, sha256, randomBytes, solidityPack, solidityKeccak256, soliditySha256, splitSignature, joinSignature, parseTransaction, serializeTransaction, getJsonWalletAddress, computeAddress, recoverAddress, computePublicKey, recoverPublicKey, verifyMessage, mnemonicToEntropy, entropyToMnemonic, isValidMnemonic, mnemonicToSeed, SupportedAlgorithm, UnicodeNormalizationForm, Utf8ErrorReason, Bytes, BytesLike, Hexable, UnsignedTransaction, CoerceFunc, Indexed, Mnemonic, Utf8ErrorFunc, ConnectionInfo, OnceBlockable, PollOptions, FetchJsonResponse, EncryptOptions, ProgressCallback };

@ -52,7 +52,7 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"tarballHash": "0x8bf3df33da732d3a07a569560633f98fd9b7826cfc306fb4f3c159f98873b29c", "tarballHash": "0x6eba00cc347e154a1bacd6b073af290f2da00b3e1e0b06e4ea342d94940832be",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"version": "5.0.0-beta.172" "version": "5.0.0-beta.173"
} }

@ -1 +1 @@
export const version = "ethers/5.0.0-beta.172"; export const version = "ethers/5.0.0-beta.173";

@ -26,7 +26,7 @@ import { fetchJson, poll } from "@ethersproject/web";
import { SupportedAlgorithm } from "@ethersproject/sha2"; import { SupportedAlgorithm } from "@ethersproject/sha2";
import { UnicodeNormalizationForm, Utf8ErrorReason } from "@ethersproject/strings"; import { UnicodeNormalizationForm, Utf8ErrorReason } from "@ethersproject/strings";
import { UnsignedTransaction } from "@ethersproject/transactions";
//////////////////////// ////////////////////////
// Types and Interfaces // Types and Interfaces
@ -165,6 +165,8 @@ export {
BytesLike, BytesLike,
Hexable, Hexable,
UnsignedTransaction,
CoerceFunc, CoerceFunc,
Indexed, Indexed,

@ -95,11 +95,11 @@ export class LedgerSigner extends ethers.Signer {
async signTransaction(transaction: ethers.providers.TransactionRequest): Promise<string> { async signTransaction(transaction: ethers.providers.TransactionRequest): Promise<string> {
const tx = transaction = await ethers.utils.resolveProperties(transaction); const tx = transaction = await ethers.utils.resolveProperties(transaction);
const unsignedTx = ethers.utils.serializeTransaction(tx).substring(2); const unsignedTx = ethers.utils.serializeTransaction(<ethers.utils.UnsignedTransaction>tx).substring(2);
const sig = await this._retry((eth) => eth.signTransaction(this.path, unsignedTx)); const sig = await this._retry((eth) => eth.signTransaction(this.path, unsignedTx));
return ethers.utils.serializeTransaction(tx, { return ethers.utils.serializeTransaction(<ethers.utils.UnsignedTransaction>tx, {
v: sig.v, v: sig.v,
r: ("0x" + sig.r), r: ("0x" + sig.r),
s: ("0x" + sig.s), s: ("0x" + sig.s),

@ -1 +1 @@
export declare const version = "properties/5.0.0-beta.136"; export declare const version = "properties/5.0.0-beta.137";

@ -1 +1 @@
export const version = "properties/5.0.0-beta.136"; export const version = "properties/5.0.0-beta.137";

@ -1,11 +1,17 @@
export declare function defineReadOnly(object: any, name: string, value: any): void; export declare function defineReadOnly<T, K extends keyof T>(object: T, name: K, value: T[K]): void;
export declare function getStatic<T>(ctor: any, key: string): T; export declare function getStatic<T>(ctor: any, key: string): T;
export declare function resolveProperties(object: any): Promise<any>; export declare type Similar<T> = {
[P in keyof T]: T[P];
};
export declare type Resolvable<T> = {
[P in keyof T]: T[P] | Promise<T[P]>;
};
export declare function resolveProperties<T>(object: Resolvable<T>): Promise<Similar<T>>;
export declare function checkProperties(object: any, properties: { export declare function checkProperties(object: any, properties: {
[name: string]: boolean; [name: string]: boolean;
}): void; }): void;
export declare function shallowCopy(object: any): any; export declare function shallowCopy<T>(object: T): Similar<T>;
export declare function deepCopy(object: any): any; export declare function deepCopy<T>(object: T): Similar<T>;
export declare class Description<T = any> { export declare class Description<T = any> {
constructor(info: T); constructor(info: T);
} }

@ -34,10 +34,10 @@ export function resolveProperties(object) {
}); });
return Promise.all(promises).then((results) => { return Promise.all(promises).then((results) => {
const result = {}; const result = {};
return results.reduce((accum, result) => { return (results.reduce((accum, result) => {
accum[result.key] = result.value; accum[result.key] = result.value;
return accum; return accum;
}, result); }, result));
}); });
} }
export function checkProperties(object, properties) { export function checkProperties(object, properties) {
@ -60,7 +60,7 @@ export function shallowCopy(object) {
const opaque = { bigint: true, boolean: true, number: true, string: true }; const opaque = { bigint: true, boolean: true, number: true, string: true };
// Returns a new copy of object, such that no properties may be replaced. // Returns a new copy of object, such that no properties may be replaced.
// New properties may be added only to objects. // New properties may be added only to objects.
export function deepCopy(object) { function _deepCopy(object) {
// Opaque objects are not mutable, so safe to copy by assignment // Opaque objects are not mutable, so safe to copy by assignment
if (object === undefined || object === null || opaque[typeof (object)]) { if (object === undefined || object === null || opaque[typeof (object)]) {
return object; return object;
@ -88,7 +88,10 @@ export function deepCopy(object) {
if (typeof (object) === "function") { if (typeof (object) === "function") {
return object; return object;
} }
throw new Error("Cannot deepCopy " + typeof (object)); logger.throwArgumentError(`Cannot deepCopy ${typeof (object)}`, "object", object);
}
export function deepCopy(object) {
return _deepCopy(object);
} }
export class Description { export class Description {
constructor(info) { constructor(info) {

@ -1 +1 @@
export declare const version = "properties/5.0.0-beta.136"; export declare const version = "properties/5.0.0-beta.137";

@ -1,3 +1,3 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "properties/5.0.0-beta.136"; exports.version = "properties/5.0.0-beta.137";

@ -1,11 +1,17 @@
export declare function defineReadOnly(object: any, name: string, value: any): void; export declare function defineReadOnly<T, K extends keyof T>(object: T, name: K, value: T[K]): void;
export declare function getStatic<T>(ctor: any, key: string): T; export declare function getStatic<T>(ctor: any, key: string): T;
export declare function resolveProperties(object: any): Promise<any>; export declare type Similar<T> = {
[P in keyof T]: T[P];
};
export declare type Resolvable<T> = {
[P in keyof T]: T[P] | Promise<T[P]>;
};
export declare function resolveProperties<T>(object: Resolvable<T>): Promise<Similar<T>>;
export declare function checkProperties(object: any, properties: { export declare function checkProperties(object: any, properties: {
[name: string]: boolean; [name: string]: boolean;
}): void; }): void;
export declare function shallowCopy(object: any): any; export declare function shallowCopy<T>(object: T): Similar<T>;
export declare function deepCopy(object: any): any; export declare function deepCopy<T>(object: T): Similar<T>;
export declare class Description<T = any> { export declare class Description<T = any> {
constructor(info: T); constructor(info: T);
} }

@ -37,10 +37,10 @@ function resolveProperties(object) {
}); });
return Promise.all(promises).then(function (results) { return Promise.all(promises).then(function (results) {
var result = {}; var result = {};
return results.reduce(function (accum, result) { return (results.reduce(function (accum, result) {
accum[result.key] = result.value; accum[result.key] = result.value;
return accum; return accum;
}, result); }, result));
}); });
} }
exports.resolveProperties = resolveProperties; exports.resolveProperties = resolveProperties;
@ -66,7 +66,7 @@ exports.shallowCopy = shallowCopy;
var opaque = { bigint: true, boolean: true, number: true, string: true }; var opaque = { bigint: true, boolean: true, number: true, string: true };
// Returns a new copy of object, such that no properties may be replaced. // Returns a new copy of object, such that no properties may be replaced.
// New properties may be added only to objects. // New properties may be added only to objects.
function deepCopy(object) { function _deepCopy(object) {
// Opaque objects are not mutable, so safe to copy by assignment // Opaque objects are not mutable, so safe to copy by assignment
if (object === undefined || object === null || opaque[typeof (object)]) { if (object === undefined || object === null || opaque[typeof (object)]) {
return object; return object;
@ -94,7 +94,10 @@ function deepCopy(object) {
if (typeof (object) === "function") { if (typeof (object) === "function") {
return object; return object;
} }
throw new Error("Cannot deepCopy " + typeof (object)); logger.throwArgumentError("Cannot deepCopy " + typeof (object), "object", object);
}
function deepCopy(object) {
return _deepCopy(object);
} }
exports.deepCopy = deepCopy; exports.deepCopy = deepCopy;
var Description = /** @class */ (function () { var Description = /** @class */ (function () {

@ -25,7 +25,7 @@
"build": "tsc -p ./tsconfig.json", "build": "tsc -p ./tsconfig.json",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"tarballHash": "0x6a1817252456f7b6cbd2edd780d3b2585fcb477da55f7e7282869c0a5a7f5184", "tarballHash": "0xfbf63fe67dfb09b4e1d9cf19010f61f540f63105cc006a148d91ab9bbf016c61",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"version": "5.0.0-beta.136" "version": "5.0.0-beta.137"
} }

@ -1 +1 @@
export const version = "properties/5.0.0-beta.136"; export const version = "properties/5.0.0-beta.137";

@ -22,11 +22,19 @@ export function getStatic<T>(ctor: any, key: string): T {
return null; return null;
} }
export type Similar<T> = {
[P in keyof T]: T[P];
}
export type Resolvable<T> = {
[P in keyof T]: T[P] | Promise<T[P]>;
}
type Result = { key: string, value: any}; type Result = { key: string, value: any};
export function resolveProperties(object: any): Promise<any> { export function resolveProperties<T>(object: Resolvable<T>): Promise<Similar<T>> {
const promises: Array<Promise<Result>> = Object.keys(object).map((key) => { const promises: Array<Promise<Result>> = Object.keys(object).map((key) => {
const value = object[key]; const value = (<any>object)[key];
if (!(value instanceof Promise)) { if (!(value instanceof Promise)) {
return Promise.resolve({ key: key, value: value }); return Promise.resolve({ key: key, value: value });
@ -39,10 +47,10 @@ export function resolveProperties(object: any): Promise<any> {
return Promise.all(promises).then((results) => { return Promise.all(promises).then((results) => {
const result: any = { }; const result: any = { };
return results.reduce((accum, result) => { return (<Similar<T>>(results.reduce((accum, result) => {
accum[result.key] = result.value; accum[result.key] = result.value;
return accum; return accum;
}, result); }, result)));
}); });
} }
@ -58,7 +66,7 @@ export function checkProperties(object: any, properties: { [ name: string ]: boo
}); });
} }
export function shallowCopy(object: any): any { export function shallowCopy<T>(object: T): Similar<T> {
const result: any = {}; const result: any = {};
for (const key in object) { result[key] = object[key]; } for (const key in object) { result[key] = object[key]; }
return result; return result;
@ -68,7 +76,7 @@ const opaque: { [key: string]: boolean } = { bigint: true, boolean: true, number
// Returns a new copy of object, such that no properties may be replaced. // Returns a new copy of object, such that no properties may be replaced.
// New properties may be added only to objects. // New properties may be added only to objects.
export function deepCopy(object: any): any { function _deepCopy(object: any): any {
// Opaque objects are not mutable, so safe to copy by assignment // Opaque objects are not mutable, so safe to copy by assignment
if (object === undefined || object === null || opaque[typeof(object)]) { return object; } if (object === undefined || object === null || opaque[typeof(object)]) { return object; }
@ -98,7 +106,11 @@ export function deepCopy(object: any): any {
return object; return object;
} }
throw new Error("Cannot deepCopy " + typeof(object)); logger.throwArgumentError(`Cannot deepCopy ${ typeof(object) }`, "object", object);
}
export function deepCopy<T>(object: T): Similar<T> {
return _deepCopy(object);
} }
export class Description<T = any> { export class Description<T = any> {

@ -1 +1 @@
export declare const version = "providers/5.0.0-beta.152"; export declare const version = "providers/5.0.0-beta.153";

@ -1 +1 @@
export const version = "providers/5.0.0-beta.152"; export const version = "providers/5.0.0-beta.153";

@ -7,7 +7,7 @@ export interface FallbackProviderConfig {
weight?: number; weight?: number;
} }
export declare class FallbackProvider extends BaseProvider { export declare class FallbackProvider extends BaseProvider {
readonly providerConfigs: Array<FallbackProviderConfig>; readonly providerConfigs: ReadonlyArray<FallbackProviderConfig>;
readonly quorum: number; readonly quorum: number;
_highestBlockNumber: number; _highestBlockNumber: number;
constructor(providers: Array<Provider | FallbackProviderConfig>, quorum?: number); constructor(providers: Array<Provider | FallbackProviderConfig>, quorum?: number);

@ -1 +1 @@
export declare const version = "providers/5.0.0-beta.152"; export declare const version = "providers/5.0.0-beta.153";

@ -1,3 +1,3 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "providers/5.0.0-beta.152"; exports.version = "providers/5.0.0-beta.153";

@ -7,7 +7,7 @@ export interface FallbackProviderConfig {
weight?: number; weight?: number;
} }
export declare class FallbackProvider extends BaseProvider { export declare class FallbackProvider extends BaseProvider {
readonly providerConfigs: Array<FallbackProviderConfig>; readonly providerConfigs: ReadonlyArray<FallbackProviderConfig>;
readonly quorum: number; readonly quorum: number;
_highestBlockNumber: number; _highestBlockNumber: number;
constructor(providers: Array<Provider | FallbackProviderConfig>, quorum?: number); constructor(providers: Array<Provider | FallbackProviderConfig>, quorum?: number);

@ -44,7 +44,7 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"tarballHash": "0xce9a626d62434fe628a5ab60fd3a05198eda8d7cf7ff7d54b63096e5b95d918c", "tarballHash": "0x54990412c71ac1e81ce962062a2bbcc0127a32b1243f1db28fbb2af511b3e749",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"version": "5.0.0-beta.152" "version": "5.0.0-beta.153"
} }

@ -1 +1 @@
export const version = "providers/5.0.0-beta.152"; export const version = "providers/5.0.0-beta.153";

@ -1 +1 @@
export declare const version = "wallet/5.0.0-beta.136"; export declare const version = "wallet/5.0.0-beta.137";

@ -1 +1 @@
export const version = "wallet/5.0.0-beta.136"; export const version = "wallet/5.0.0-beta.137";

@ -47,7 +47,6 @@ export class Wallet extends Signer {
} }
else { else {
defineReadOnly(this, "_mnemonic", () => null); defineReadOnly(this, "_mnemonic", () => null);
defineReadOnly(this, "path", null);
} }
} }
else { else {
@ -62,7 +61,6 @@ export class Wallet extends Signer {
defineReadOnly(this, "_signingKey", () => signingKey); defineReadOnly(this, "_signingKey", () => signingKey);
} }
defineReadOnly(this, "_mnemonic", () => null); defineReadOnly(this, "_mnemonic", () => null);
defineReadOnly(this, "path", null);
defineReadOnly(this, "address", computeAddress(this.publicKey)); defineReadOnly(this, "address", computeAddress(this.publicKey));
} }
if (provider && !Provider.isProvider(provider)) { if (provider && !Provider.isProvider(provider)) {

@ -1 +1 @@
export declare const version = "wallet/5.0.0-beta.136"; export declare const version = "wallet/5.0.0-beta.137";

Some files were not shown because too many files have changed in this diff Show More