From da591f56d8884c5824c0c1b3103fbcfd81123c4c Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Mon, 4 Nov 2024 20:00:21 +0530 Subject: [PATCH] feat(`vm`): get broadcasts (#627) Add cheatcodes introduced in https://github.com/foundry-rs/foundry/pull/9107. ```solidity // Returns the most recent broadcast for the given contract on `chainId` matching `txType`. function getBroadcast(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary memory); // Returns all broadcasts for the given contract on `chainId` with the specified `txType`. // Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. function getBroadcasts(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary[] memory); // Returns all broadcasts for the given contract on `chainId`. // Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. function getBroadcasts(string memory contractName, uint64 chainId) external returns (BroadcastTxSummary[] memory); // Returns the most recent deployment for the current `chainId`. function getDeployment(string memory contractName) external returns (address deployedAddress); // Returns the most recent deployment for the given contract on `chainId` function getDeployment(string memory contractName, uint64 chainId) external returns (address deployedAddress); // Returns all deployments for the given contract on `chainId` // Sorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber. // The most recent deployment is the first element, and the oldest is the last. function getDeployments(string memory contractName, uint64 chainId) external returns (address[] memory deployedAddresses); ``` These cheatcodes enable the following behaviour: - Deploy a contract `forge script CounterDeployScript --broadcast` - Access the broadcast artifacts `forge script BroadcastCollector` ```solidity contract BroadcastCollector is Script { function run() public { // Get the most recent counter deployment Vm.BroadcastTxSummary memory broadcast = Vm(address(vm)).getBroadcast( "Counter", 31337, Vm.BroadcastTxType.Create ); console.logBytes32(broadcast.txHash); console.logAddress(broadcast.contractAddress); // New contract address } } ``` --- src/Vm.sol | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ test/Vm.t.sol | 2 +- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/Vm.sol b/src/Vm.sol index 0f2dc50f..73fc47e5 100644 --- a/src/Vm.sol +++ b/src/Vm.sol @@ -264,6 +264,31 @@ interface VmSafe { address contractAddr; } + /// The transaction type (`txType`) of the broadcast. + enum BroadcastTxType { + // Represents a CALL broadcast tx. + Call, + // Represents a CREATE broadcast tx. + Create, + // Represents a CREATE2 broadcast tx. + Create2 + } + + /// Represents a transaction's broadcast details. + struct BroadcastTxSummary { + // The hash of the transaction that was broadcasted + bytes32 txHash; + // Represent the type of transaction among CALL, CREATE, CREATE2 + BroadcastTxType txType; + // The address of the contract that was called or created. + // This is address of the contract that is created if the txType is CREATE or CREATE2. + address contractAddress; + // The block number the transaction landed in. + uint64 blockNumber; + // Status of the transaction, retrieved from the transaction receipt. + bool success; + } + // ======== Crypto ======== /// Derives a private key from the name, labels the account with that name, and returns the wallet. @@ -771,6 +796,46 @@ interface VmSafe { /// `path` is relative to the project root. function writeLine(string calldata path, string calldata data) external; + /// Returns the most recent broadcast for the given contract on `chainId` matching `txType`. + /// + /// For example: + /// + /// The most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`. + /// + /// The most recent call can be fetched by passing `txType` as `CALL`. + function getBroadcast(string calldata contractName, uint64 chainId, BroadcastTxType txType) + external + returns (BroadcastTxSummary memory); + + /// Returns all broadcasts for the given contract on `chainId` with the specified `txType`. + /// + /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. + function getBroadcasts(string calldata contractName, uint64 chainId, BroadcastTxType txType) + external + returns (BroadcastTxSummary[] memory); + + /// Returns all broadcasts for the given contract on `chainId`. + /// + /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. + function getBroadcasts(string calldata contractName, uint64 chainId) + external + returns (BroadcastTxSummary[] memory); + + /// Returns the most recent deployment for the current `chainId`. + function getDeployment(string calldata contractName) external returns (address deployedAddress); + + /// Returns the most recent deployment for the given contract on `chainId` + function getDeployment(string calldata contractName, uint64 chainId) external returns (address deployedAddress); + + /// Returns all deployments for the given contract on `chainId` + /// + /// Sorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber. + /// + /// The most recent deployment is the first element, and the oldest is the last. + function getDeployments(string calldata contractName, uint64 chainId) + external + returns (address[] memory deployedAddresses); + // ======== JSON ======== /// Checks if `key` exists in a JSON object. diff --git a/test/Vm.t.sol b/test/Vm.t.sol index 8642067f..8b6113cf 100644 --- a/test/Vm.t.sol +++ b/test/Vm.t.sol @@ -13,6 +13,6 @@ contract VmTest is Test { } function test_VmSafeInterfaceId() public pure { - assertEq(type(VmSafe).interfaceId, bytes4(0xb09496a4), "VmSafe"); + assertEq(type(VmSafe).interfaceId, bytes4(0x590bc2b4), "VmSafe"); } }