UNPKG

@nomiclabs/buidler

Version:

Buidler is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.

129 lines (104 loc) 3.68 kB
import { BN } from "ethereumjs-util"; import * as t from "io-ts"; import { InvalidInputError, MethodNotFoundError, MethodNotSupportedError, } from "../errors"; import { rpcQuantity, validateParams } from "../input"; import { BuidlerNode } from "../node"; import { numberToRpcQuantity } from "../output"; // tslint:disable only-buidler-error export class EvmModule { constructor(private readonly _node: BuidlerNode) {} public async processRequest( method: string, params: any[] = [] ): Promise<any> { switch (method) { case "evm_increaseTime": return this._increaseTimeAction(...this._increaseTimeParams(params)); case "evm_setNextBlockTimestamp": return this._setNextBlockTimestampAction( ...this._setNextBlockTimestampParams(params) ); case "evm_mine": return this._mineAction(...this._mineParams(params)); case "evm_revert": return this._revertAction(...this._revertParams(params)); case "evm_snapshot": return this._snapshotAction(...this._snapshotParams(params)); } throw new MethodNotFoundError(`Method ${method} not found`); } // evm_setNextBlockTimestamp private _setNextBlockTimestampParams(params: any[]): [number] { return validateParams(params, t.number); } private async _setNextBlockTimestampAction( timestamp: number ): Promise<string> { const latestBlock = await this._node.getLatestBlock(); const increment = new BN(timestamp).sub( new BN(latestBlock.header.timestamp) ); if (increment.lte(new BN(0))) { throw new InvalidInputError( `Timestamp ${timestamp} is lower than previous block's timestamp` + `${new BN(latestBlock.header.timestamp).toNumber()}` ); } await this._node.setNextBlockTimestamp(new BN(timestamp)); return timestamp.toString(); } // evm_increaseTime private _increaseTimeParams(params: any[]): [number] { return validateParams(params, t.number); } private async _increaseTimeAction(increment: number): Promise<string> { await this._node.increaseTime(new BN(increment)); const totalIncrement = await this._node.getTimeIncrement(); // This RPC call is an exception: it returns a number in decimal return totalIncrement.toString(); } // evm_mine private _mineParams(params: any[]): [number] { if (params.length === 0) { params.push(0); } return validateParams(params, t.number); } private async _mineAction(timestamp: number): Promise<string> { // if timestamp is specified, make sure it is bigger than previous // block's timestamp if (timestamp !== 0) { const latestBlock = await this._node.getLatestBlock(); const increment = new BN(timestamp).sub( new BN(latestBlock.header.timestamp) ); if (increment.lte(new BN(0))) { throw new InvalidInputError( `Timestamp ${timestamp} is lower than previous block's timestamp` + `${new BN(latestBlock.header.timestamp).toNumber()}` ); } } await this._node.mineEmptyBlock(new BN(timestamp)); return numberToRpcQuantity(0); } // evm_revert private _revertParams(params: any[]): [BN] { return validateParams(params, rpcQuantity); } private async _revertAction(snapshotId: BN): Promise<boolean> { return this._node.revertToSnapshot(snapshotId.toNumber()); } // evm_snapshot private _snapshotParams(params: any[]): [] { return []; } private async _snapshotAction(): Promise<string> { const snapshotId = await this._node.takeSnapshot(); return numberToRpcQuantity(snapshotId); } }