Skip to content

Commit

Permalink
Merge pull request #122 from nomoixyz/develop
Browse files Browse the repository at this point in the history
v0.2.0
  • Loading branch information
gnkz authored Aug 22, 2023
2 parents c9305ad + 1d5cf93 commit 6de3f10
Show file tree
Hide file tree
Showing 13 changed files with 353 additions and 9 deletions.
15 changes: 14 additions & 1 deletion docs/src/reference/modules/accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,26 @@ Creates an address using the hash of the specified `name` as the private key and

Creates an address using the hash of the specified `name` as the private key and adds a label to the address.

#### **`getDeploymentAddress(address who, uint64 nonce) → (address)`**

Calculates the deployment address of `who` with nonce `nonce`.

#### **`getDeploymentAddress(address who) → (address)`**

Calculates the deployment address of `who` with the current nonce.

#### **`setStorage(address self, bytes32 slot, bytes32 value) → (address)`**

Sets the specified `slot` in the storage of the given `self` address to the provided `value`.

#### **`setNonce(address self, uint64 n) → (address)`**

Sets the nonce of the given `self` address to the provided value `n`.
Sets the nonce of the given `self` address to the provided value `n`. It will revert if the new
nonce is lower than the current address nonce.

#### **`setNonceUnsafe(address self, uint64 n) → (address)`**

Sets the nonce of the given `self` address to the provided arbitrary value `n`.

#### **`impersonateOnce(address self) → (address)`**

Expand Down
48 changes: 48 additions & 0 deletions docs/src/reference/modules/context.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ sets the `block.basefee` to `baseFee`

sets the `block.basefee` to `baseFee`

#### **`setBlockPrevrandao(Context self, bytes32 newPrevrandao) → (Context)`**

sets the `block.prevrandao` to `newPrevrandao`

#### **`setBlockPrevrandao(bytes32 newPrevrandao) → (Context)`**

sets the `block.prevrandao` to `newPrevrandao`

#### **`setChainId(Context self, uint64 chainId) → (Context)`**

sets the `block.chainid` to `chainId`
Expand All @@ -73,6 +81,14 @@ Sets the block coinbase to `who`.

Sets the block coinbase to `who`.

#### **`setGasPrice(Context self, address newGasPrice) → (Context)`**

Sets the gas price to `newGasPrice`.

#### **`setGasPrice(address newGasPrice) → (Context)`**

Sets the gas price to `newGasPrice`.

#### **`expectRevert(bytes revertData)`**

Function used to check whether the next call reverts or not.
Expand Down Expand Up @@ -113,6 +129,22 @@ Used to check if a call to `callee` with `data` was made.

Used to check if a call to `callee` with `data` and `msgValue` was made.

#### **`expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data)`**

Expect a call from `callee` with the specified `msgValue` and `data`, and a minimum amount of gas `minGas`.

#### **`expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data, uint64 count)`**

Expect a number of calls `count` from `callee` with the specified `msgValue` and `data`, and a minimum amount of gas `minGas`.

#### **`expectSafeMemory(uint64 min, uint64 max)`**

Allows to write on memory only between [0x00, 0x60) and [`min`, `max`) in the current subcontext

#### **`expectsafememorycall(uint64 min, uint64 max)`**

Allows to write on memory only between [0x00, 0x60) and [`min`, `max`) in the next subcontext

#### **`snapshot(Context) → (uint256)`**

Takes a snapshot of the current state of the vm and returns an identifier.
Expand All @@ -129,3 +161,19 @@ Reverts the state of the vm to the snapshot with id `snapshotId`.

Reverts the state of the vm to the snapshot with id `snapshotId`.

#### **`addBreakpoint(Context self, string memory name)`**

Creates a breakpoint to jump to in the debugger with `name`.

#### **`addBreakpoint(string memory name)`**

Creates a breakpoint to jump to in the debugger with `name`.

#### **`addConditionalBreakpoint(Context self, string memory name, bool condition)`**

Creates a conditional breakpoint to jump to in the debugger with name `name` and condition `condition`.

#### **`addConditionalBreakpoint(string memory name, bool condition)`**

Creates a conditional breakpoint to jump to in the debugger with name `name` and condition `condition`.

62 changes: 61 additions & 1 deletion src/_modules/Accounts.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,43 @@ library accountsSafe {

return label(addr, lbl);
}

/// @dev Calculates the deployment address of `who` with nonce `nonce`.
/// @param who The deployer address.
/// @param nonce The deployer nonce.
function getDeploymentAddress(address who, uint64 nonce) internal pure returns (address) {
bytes memory data;

if (nonce == 0x00) {
data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), who, bytes1(0x80));
} else if (nonce <= 0x7f) {
data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), who, uint8(nonce));
} else if (nonce <= 0xff) {
data = abi.encodePacked(bytes1(0xd7), bytes1(0x94), who, bytes1(0x81), uint8(nonce));
} else if (nonce <= 0xffff) {
data = abi.encodePacked(bytes1(0xd8), bytes1(0x94), who, bytes1(0x82), uint16(nonce));
} else if (nonce <= 0xffffff) {
data = abi.encodePacked(bytes1(0xd9), bytes1(0x94), who, bytes1(0x83), uint24(nonce));
} else if (nonce <= 0xffffffff) {
data = abi.encodePacked(bytes1(0xda), bytes1(0x94), who, bytes1(0x84), uint32(nonce));
} else if (nonce <= 0xffffffffff) {
data = abi.encodePacked(bytes1(0xdb), bytes1(0x94), who, bytes1(0x85), uint40(nonce));
} else if (nonce <= 0xffffffffffff) {
data = abi.encodePacked(bytes1(0xdc), bytes1(0x94), who, bytes1(0x86), uint48(nonce));
} else if (nonce <= 0xffffffffffffff) {
data = abi.encodePacked(bytes1(0xdd), bytes1(0x94), who, bytes1(0x87), uint56(nonce));
} else if (nonce <= 0xffffffffffffffff) {
data = abi.encodePacked(bytes1(0xde), bytes1(0x94), who, bytes1(0x88), uint64(nonce));
}

return address(uint160(uint256(keccak256(data))));
}

/// @dev Calculates the deployment address of `who` with the current nonce.
/// @param who The deployer address.
function getDeploymentAddress(address who) internal view returns (address) {
return getDeploymentAddress(who, getNonce(who));
}
}

library accounts {
Expand Down Expand Up @@ -167,6 +204,19 @@ library accounts {
return accountsSafe.create(name, lbl);
}

/// @dev Calculates the deployment address of `who` with nonce `nonce`.
/// @param who The deployer address.
/// @param nonce The deployer nonce.
function getDeploymentAddress(address who, uint64 nonce) internal pure returns (address) {
return accountsSafe.getDeploymentAddress(who, nonce);
}

/// @dev Calculates the deployment address of `who` with the current nonce.
/// @param who The deployer address.
function getDeploymentAddress(address who) internal view returns (address) {
return accountsSafe.getDeploymentAddress(who);
}

/// @dev Sets the specified `slot` in the storage of the given `self` address to the provided `value`.
/// @param self The address to modify the storage of.
/// @param slot The storage slot to set.
Expand All @@ -177,7 +227,8 @@ library accounts {
return self;
}

/// @dev Sets the nonce of the given `self` address to the provided value `n`.
/// @dev Sets the nonce of the given `self` address to the provided value `n`. It will revert if
// the new nonce is lower than the current address nonce.
/// @param self The address to set the nonce for.
/// @param n The value to set the nonce to.
/// @return The updated address with the modified nonce.
Expand All @@ -186,6 +237,15 @@ library accounts {
return self;
}

/// @dev Sets the nonce of the given `self` address to the arbitrary provided value `n`.
/// @param self The address to set the nonce for.
/// @param n The value to set the nonce to.
/// @return The updated address with the modified nonce.
function setNonceUnsafe(address self, uint64 n) internal returns (address) {
vulcan.hevm.setNonceUnsafe(self, n);
return self;
}

/// @dev Sets the `msg.sender` of the next call to `self`.
/// @param self The address to impersonate.
/// @return The address that was impersonated.
Expand Down
125 changes: 125 additions & 0 deletions src/_modules/Context.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ pragma solidity >=0.8.13 <0.9.0;

import "./Vulcan.sol";
import "./Accounts.sol";
import "./Strings.sol";
import "../_utils/println.sol";

type Context is bytes32;

Expand Down Expand Up @@ -69,6 +71,30 @@ library ctxSafe {
function resumeGasMetering() internal {
vulcan.hevm.resumeGasMetering();
}

function startGasReport(string memory name) internal {
if (bytes(name).length > 32) {
revert("ctx.startGasReport: Gas report name can't have more than 32 characters");
}

bytes32 b32Name = bytes32(bytes(name));
bytes32 slot = keccak256(bytes("vulcan.ctx.gasReport.name"));
accounts.setStorage(address(vulcan.hevm), slot, b32Name);
bytes32 valueSlot = keccak256(abi.encodePacked("vulcan.ctx.gasReport", b32Name));
accounts.setStorage(address(vulcan.hevm), valueSlot, bytes32(gasleft()));
}

function endGasReport() internal view {
uint256 gas = gasleft();
bytes32 slot = keccak256(bytes("vulcan.ctx.gasReport.name"));
bytes32 b32Name = accounts.readStorage(address(vulcan.hevm), slot);
bytes32 valueSlot = keccak256(abi.encodePacked("vulcan.ctx.gasReport", b32Name));
uint256 prevGas = uint256(accounts.readStorage(address(vulcan.hevm), valueSlot));
if (gas > prevGas) {
revert("ctx.endGasReport: Gas used can't have a negative value");
}
println(string.concat("gas(", string(abi.encodePacked(b32Name)), "):", strings.toString(prevGas - gas)));
}
}

library ctx {
Expand Down Expand Up @@ -120,6 +146,14 @@ library ctx {
ctxSafe.resumeGasMetering();
}

function startGasReport(string memory name) internal {
ctxSafe.startGasReport(name);
}

function endGasReport() internal view {
ctxSafe.endGasReport();
}

/// @dev Checks whether the current call is a static call or not.
/// @return True if the current call is a static call, false otherwise.
function isStaticcall() internal view returns (bool) {
Expand Down Expand Up @@ -165,6 +199,19 @@ library ctx {
return setBlockBaseFee(Context.wrap(0), baseFee);
}

/// @dev Sets block.prevrandao.
/// @param newPrevrandao The new `block.prevrandao`.
function setBlockPrevrandao(Context self, bytes32 newPrevrandao) internal returns (Context) {
vulcan.hevm.prevrandao(newPrevrandao);
return self;
}

/// @dev Sets block.prevrandao.
/// @param newPrevrandao The new `block.prevrandao`.
function setBlockPrevrandao(bytes32 newPrevrandao) internal returns (Context) {
return setBlockPrevrandao(Context.wrap(0), newPrevrandao);
}

/// @dev sets the `block.chainid` to `chainId`
/// @param chainId the new block chain id
function setChainId(Context self, uint64 chainId) internal returns (Context) {
Expand Down Expand Up @@ -194,6 +241,19 @@ library ctx {
return setBlockCoinbase(Context.wrap(0), who);
}

/// @dev Sets the transaction gas price.
/// @param newGasPrice The new transaction gas price.
function setGasPrice(Context self, uint256 newGasPrice) internal returns (Context) {
vulcan.hevm.txGasPrice(newGasPrice);
return self;
}

/// @dev Sets the transaction gas price.
/// @param newGasPrice The new transaction gas price.
function setGasPrice(uint256 newGasPrice) internal returns (Context) {
return setGasPrice(Context.wrap(0), newGasPrice);
}

/// @dev Function used to check whether the next call reverts or not.
/// @param revertData The function call data that that is expected to fail.
function expectRevert(bytes memory revertData) internal {
Expand Down Expand Up @@ -269,6 +329,43 @@ library ctx {
vulcan.hevm.expectCall(callee, msgValue, data);
}

/// @dev Expect a call to an address with the specified msg.value and calldata, and a minimum amount of gas.
/// @param callee The address that is expected to be called.
/// @param msgValue The `msg.value` that is expected to be sent.
/// @param minGas The expected minimum amount of gas for the call.
/// @param data The call data that is expected to be used.
function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data) internal {
vulcan.hevm.expectCallMinGas(callee, msgValue, minGas, data);
}

/// @dev Expect a number call to an address with the specified msg.value and calldata, and a minimum amount of gas.
/// @param callee The address that is expected to be called.
/// @param msgValue The `msg.value` that is expected to be sent.
/// @param minGas The expected minimum amount of gas for the call.
/// @param data The call data that is expected to be used.
/// @param count The number of calls that are expected.
function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data, uint64 count)
external
{
vulcan.hevm.expectCallMinGas(callee, msgValue, minGas, data, count);
}

/// @dev Allows to write on memory only between [0x00, 0x60) and [min, max) in the current.
/// subcontext.
/// @param min The lower limit of the allowed memory slot.
/// @param max The upper limit of the allowed memory slot.
function expectSafeMemory(uint64 min, uint64 max) external {
vulcan.hevm.expectSafeMemory(min, max);
}

/// @dev Allows to write on memory only between [0x00, 0x60) and [min, max) in the next
// subcontext.
/// @param min The lower limit of the allowed memory slot.
/// @param max The upper limit of the allowed memory slot.
function expectsafememorycall(uint64 min, uint64 max) external {
vulcan.hevm.expectSafeMemoryCall(min, max);
}

/// @dev Takes a snapshot of the current state of the vm and returns an identifier.
/// @return The snapshot identifier.
function snapshot(Context) internal returns (uint256) {
Expand All @@ -294,6 +391,34 @@ library ctx {
function revertToSnapshot(uint256 snapshotId) internal returns (bool) {
return revertToSnapshot(Context.wrap(0), snapshotId);
}

/// @dev Creates a breakpoint to jump to in the debugger.
/// @param name The name of the breakpoint.
function addBreakpoint(Context self, string memory name) internal returns (Context) {
vulcan.hevm.breakpoint(name);
return self;
}

/// @dev Creates a breakpoint to jump to in the debugger.
/// @param name The name of the breakpoint.
function addBreakpoint(string memory name) internal returns (Context) {
return addBreakpoint(Context.wrap(0), name);
}

/// @dev Creates a breakpoint to jump to in the debugger.
/// @param name The name of the breakpoint.
/// @param condition The condition that needs to be fulfilled in order to add the breakpoint.
function addConditionalBreakpoint(Context self, string memory name, bool condition) internal returns (Context) {
vulcan.hevm.breakpoint(name, condition);
return self;
}

/// @dev Creates a breakpoint to jump to in the debugger.
/// @param name The name of the breakpoint.
/// @param condition The condition that needs to be fulfilled in order to add the breakpoint.
function addConditionalBreakpoint(string memory name, bool condition) internal returns (Context) {
return addConditionalBreakpoint(Context.wrap(0), name, condition);
}
}

using ctx for Context global;
4 changes: 2 additions & 2 deletions src/_modules/Fs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ library fs {
/// @dev Obtains the metadata of the specified file or directory.
/// @param fileOrDir The path to the file or directory.
/// @return data The metadata of the file or directory.
function metadata(string memory fileOrDir) internal returns (FsMetadata memory data) {
function metadata(string memory fileOrDir) internal view returns (FsMetadata memory data) {
Hevm.FsMetadata memory md = vulcan.hevm.fsMetadata(fileOrDir);
assembly {
data := md
Expand Down Expand Up @@ -103,7 +103,7 @@ library fs {
/// @dev Checks if a file or directory exists.
/// @param path The file or directory to check.
/// @return Whether the file on `path` exists or not.
function fileExists(string memory path) internal returns (bool) {
function fileExists(string memory path) internal view returns (bool) {
try vulcan.hevm.fsMetadata(path) {
return true;
} catch Error(string memory) {
Expand Down
Loading

0 comments on commit 6de3f10

Please sign in to comment.