UNPKG

@tempus-labs/utils

Version:

Tempus utility helpers

165 lines 6.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.expectRevert = exports.getRevertMessage = exports.impersonateAccount = exports.setBalanceOf = exports.setStorageField = exports.setStorageAtAddr = exports.setNextBlockTimestamp = exports.setEvmTime = exports.increaseTime = exports.evmMineInSingleBlock = exports.evmSetAutomine = exports.evmMine = exports.blockTimestamp = void 0; const hardhat_1 = require("hardhat"); const chai_1 = require("chai"); const ContractBase_1 = require("./ContractBase"); /** * @returns Latest timestamp of the blockchain */ async function blockTimestamp() { return (await hardhat_1.ethers.provider.getBlock('latest')).timestamp; } exports.blockTimestamp = blockTimestamp; /** * Mines a block */ async function evmMine() { await hardhat_1.ethers.provider.send("evm_mine", []); } exports.evmMine = evmMine; /** * sets the current EVM automining behavior. * if true - a block is mined for every sent transaction (default is true) */ async function evmSetAutomine(automine) { await hardhat_1.ethers.provider.send("evm_setAutomine", [automine]); } exports.evmSetAutomine = evmSetAutomine; /** * Disables Automine until the block `fn` is finished executing. * Then manually processes all pending transactions. */ async function evmMineInSingleBlock(fn) { await evmSetAutomine(false); await fn(); await evmMine(); await evmSetAutomine(true); } exports.evmMineInSingleBlock = evmMineInSingleBlock; /** * Increase current EVM time by seconds */ async function increaseTime(addSeconds) { await hardhat_1.ethers.provider.send("evm_increaseTime", [addSeconds]); await evmMine(); } exports.increaseTime = increaseTime; /** * Set current EVM time */ async function setEvmTime(timestamp) { await setNextBlockTimestamp(timestamp); await evmMine(); } exports.setEvmTime = setEvmTime; /** * Set The timestamp of the next block (without mining it) */ async function setNextBlockTimestamp(timestamp) { await hardhat_1.ethers.provider.send("evm_setNextBlockTimestamp", [timestamp]); } exports.setNextBlockTimestamp = setNextBlockTimestamp; /** * Overwrites storage at address with a new value */ async function setStorageAtAddr(contract, addr, value) { const val = value.toHexString(); return hardhat_1.ethers.provider.send('hardhat_setStorageAt', [contract.address, addr, val]); } exports.setStorageAtAddr = setStorageAtAddr; /** * Overwrites storage by full field name, eg "lido.Lido.beaconBalance" with a new value */ async function setStorageField(contract, fieldName, value) { const addr = hardhat_1.ethers.utils.keccak256(hardhat_1.ethers.utils.toUtf8Bytes(fieldName)).replace("0x0", "0x"); return setStorageAtAddr(contract, addr, value); } exports.setStorageField = setStorageField; /** * Modifies the ETH Balance of an account */ async function setBalanceOf(address, ethAmount) { await hardhat_1.network.provider.send("hardhat_setBalance", [(0, ContractBase_1.addressOf)(address), ethAmount.toHexString()]); } exports.setBalanceOf = setBalanceOf; /** * Impersonates an account and creates a Signer from it * @returns A new Signer that impersonates account from `address` */ async function impersonateAccount(address) { await hardhat_1.network.provider.request({ method: "hardhat_impersonateAccount", params: [(0, ContractBase_1.addressOf)(address)] }); return hardhat_1.ethers.getSigner((0, ContractBase_1.addressOf)(address)); } exports.impersonateAccount = impersonateAccount; function parseRevertMessage(msg) { if (msg.indexOf("VM Exception while processing transaction:") !== -1) { const error1 = "VM Exception while processing transaction: reverted with reason string '"; let idx = msg.indexOf(error1); if (idx !== -1) { // ex: "VM Exception while processing transaction: reverted with reason string 'Receiver cannot be 0.'" // returns: "Receiver cannot be 0." return msg.slice(idx + error1.length, msg.length - 1); } const error2 = "VM Exception while processing transaction: reverted with custom error '"; idx = msg.indexOf(error2); if (idx !== -1) { // ex: "VM Exception while processing transaction: reverted with custom error 'OnlyControllerAuthorized("0x81aBfd14a19131A347a557A6c5757e7f71910E73")'" // returns: ":SenderIsNotStaker" const customError = msg.slice(idx + error2.length, msg.length - 1); // discard the "(arg0, arg1, ...)" part if it's present const parentheses = customError.indexOf('('); return ":" + (parentheses !== -1 ? customError.substring(0, parentheses) : customError); } // old style where ": revert " was directly followed by error string const error3 = "VM Exception while processing transaction: revert "; idx = msg.indexOf(error3); if (idx !== -1) { return msg.slice(idx + error3.length); } const error4 = "VM Exception while processing transaction: reverted"; idx = msg.indexOf(error4); if (idx !== -1) { return msg.slice(idx + error4.length - 8); } throw new Error(`Unrecognized VM Exception format: "${msg}"`); } // most likely a raw error or revert string return msg; } /** * Tries to get the Revert Message from an Error */ function getRevertMessage(e) { // always prefer e.reason if it's present, because some if (e.reason) { // ex: "VM Exception while processing transaction: reverted with reason string 'reverted'" // or: "No vesting data for receiver." return parseRevertMessage(e.reason); } if (e.errorName) { // errorName: "InvalidTokenIn" return ":" + e.errorName; // for custom errors we use ":" prefix } // this is usually an Error object with revert message in Error.message property return parseRevertMessage(e.message); } exports.getRevertMessage = getRevertMessage; /** * Expect called promise to revert with message * (await expectRevert(lido.withdraw(..))).to.equal("expected revert msg"); * * We use this helper instead of `.to.be.revertedWith`, because that doesn't allow showing a stack trace, * and this one does. */ async function expectRevert(promise) { try { await promise; return (0, chai_1.expect)('success'); } catch (e) { return (0, chai_1.expect)(getRevertMessage(e)); } } exports.expectRevert = expectRevert; //# sourceMappingURL=Utils.js.map