0

Context

As part of a test I would like to assert the funds from wallet investorWallet are reduced with the investmentAmount after an investment is made (by calling the receiveInvestment function in the dim contract. Furthermore, I would like to assert some attribute values within that dim contract, are as expected.

Issue

When I call the function from the investorWallet, the debugging console2.log logs from the within the dim contract are not shown in the terminal when I run forge test -vvvvv, and the changes to the attributes of the dim contract are not preserved/made. However the balance of the investor is reduced succesfully.

When I call the function directly, the logs are shown, and the contract attributes are preserved, but the investment amount is not subtracted from the investorWallet (because that was not the one calling the dim contract function).

Approach I

Calling the dim contract from the investor wallet:

function testSingleInvestment() public {
    uint256 startBalance = _investorWallet.balance;
    uint256 investmentAmount = 20 ether;
    
    
    // Send investment directly from the investor wallet.
    (bool success, bytes memory result) = _investorWallet.call{ value: investmentAmount }(
      abi.encodeWithSelector(_dim.receiveInvestment.selector)
    );


    // Directly call the function on the deployed contract.
    // _dim.receiveInvestment{value: investmentAmount}();
  
    
    uint256 endBalance = _investorWallet.balance;

    // Assert that user balance decreased by the investment amount
    assertEq(endBalance - startBalance, investmentAmount);

    // Assert the tier investments are processed as expected.
    console2.log("BEFORE ASSERTION", _dim.getTierInvestmentLength());
    assertEq(_dim.getTierInvestmentLength(), 3);
  }

Output approach 1

[⠊] Compiling...
[⠰] Compiling 31 files with 0.8.23
[⠔] Solc 0.8.23 finished in 1.30s
Compiler run successful with warnings:
Warning (2519): This declaration shadows an existing declaration.
   --> src/CustomPaymentSplitter.sol:150:52:
    |
150 |   function publicAddSharesToPayee(address account, uint256 dai) public onlyOwner {
    |                                                    ^^^^^^^^^^^
Note: The shadowed declaration is here:
  --> src/CustomPaymentSplitter.sol:67:3:
   |
67 |   function dai(address account) public view returns (uint256) {
   |   ^ (Relevant source part starts here and spans across multiple lines).

Warning (2072): Unused local variable.
  --> test/SingleInvestment.t.sol:43:6:
   |
43 |     (bool success, bytes memory result) = _investorWallet.call{ value: investmentAmount }(
   |      ^^^^^^^^^^^^

Warning (2072): Unused local variable.
  --> test/SingleInvestment.t.sol:43:20:
   |
43 |     (bool success, bytes memory result) = _investorWallet.call{ value: investmentAmount }(
   |                    ^^^^^^^^^^^^^^^^^^^


Ran 1 test for test/SingleInvestment.t.sol:SingleInvestmentTest
[FAIL. Reason: assertion failed] testSingleInvestment() (gas: 55245)
Logs:
  Before length assertion 0

Traces:
  [55245] SingleInvestmentTest::testSingleInvestment()
    ├─ [0] 0x82Df0950F5A951637E0307CdCB4c672F298B8Bc6::receiveInvestment{value: 20000000000000000000}()
    │   └─ ← [Stop] 
    ├─ [2290] DecentralisedInvestmentManager::getTierInvestmentLength() [staticcall]
    │   └─ ← [Return] 0
    ├─ [0] console::log("Before length assertion", 0) [staticcall]
    │   └─ ← [Stop] 
    ├─ [290] DecentralisedInvestmentManager::getTierInvestmentLength() [staticcall]
    │   └─ ← [Return] 0
    ├─ emit Log(err: "Error: a == b not satisfied [uint256]")
    ├─ emit LogNamedUint256(key: "   Left", value: 0)
    ├─ emit LogNamedUint256(key: "  Right", value: 3)
    ├─ [0] VM::store(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 0x6661696c65640000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000001)
    │   └─ ← [Return] 
    └─ ← [Stop] 

Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 513.52µs (68.46µs CPU time)

Ran 1 test for test/InvestmentTier.t.sol:TierTest
[PASS] testAttributes() (gas: 10390)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 288.90µs (64.64µs CPU time)

Ran 1 test for test/Deploy.t.sol:TestDeploy
[PASS] testRunTier() (gas: 113931)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.71ms (56.79µs CPU time)

Ran 4 tests for test/Tier.t.sol:TierTest
[PASS] testAttributes() (gas: 13233)
[PASS] testThrowsOnMaxValLargerThanMinVal() (gas: 34693)
[PASS] testThrowsOnOneMultiple() (gas: 34745)
[PASS] testThrowsOnZeroMultiple() (gas: 34700)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 357.20µs (268.72µs CPU time)

Ran 4 test suites in 525.88ms (2.87ms CPU time): 6 tests passed, 1 failed, 0 skipped (7 total tests)

Failing tests:
Encountered 1 failing test in test/SingleInvestment.t.sol:SingleInvestmentTest
[FAIL. Reason: assertion failed] testSingleInvestment() (gas: 55245)

Encountered a total of 1 failing tests, 6 tests succeeded

Note the logs from the test file are shown, just the logs of the dim contract are not shown, regardless of how many -vvvv'v's I add.

Approach 2

Calling the dim contract not from the investorWallet:

  function testSingleInvestment() public {
    uint256 startBalance = _investorWallet.balance;
    uint256 investmentAmount = 20 ether;
    
    
    // Send investment directly from the investor wallet.
    // (bool success, bytes memory result) = _investorWallet.call{ value: investmentAmount }(
      // abi.encodeWithSelector(_dim.receiveInvestment.selector)
    // );


    // Directly call the function on the deployed contract.
    _dim.receiveInvestment{value: investmentAmount}();
  
    
    uint256 endBalance = _investorWallet.balance;

    // Assert that user balance decreased by the investment amount
    assertEq(endBalance - startBalance, investmentAmount);

    // Assert the tier investments are processed as expected.
    console2.log("BEFORE ASSERTION", _dim.getTierInvestmentLength());
    assertEq(_dim.getTierInvestmentLength(), 3);
  }

Output approach 2

[⠊] Compiling...
[⠰] Compiling 31 files with 0.8.23
[⠔] Solc 0.8.23 finished in 1.30s
Compiler run successful with warnings:
Warning (2519): This declaration shadows an existing declaration.
   --> src/CustomPaymentSplitter.sol:150:52:
    |
150 |   function publicAddSharesToPayee(address account, uint256 dai) public onlyOwner {
    |                                                    ^^^^^^^^^^^
Note: The shadowed declaration is here:
  --> src/CustomPaymentSplitter.sol:67:3:
   |
67 |   function dai(address account) public view returns (uint256) {
   |   ^ (Relevant source part starts here and spans across multiple lines).


Ran 1 test for test/InvestmentTier.t.sol:TierTest
[PASS] testAttributes() (gas: 10390)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 422.89µs (64.83µs CPU time)

Ran 4 tests for test/Tier.t.sol:TierTest
[PASS] testAttributes() (gas: 13233)
[PASS] testThrowsOnMaxValLargerThanMinVal() (gas: 34693)
[PASS] testThrowsOnOneMultiple() (gas: 34745)
[PASS] testThrowsOnZeroMultiple() (gas: 34700)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 721.81µs (449.41µs CPU time)

Ran 1 test for test/SingleInvestment.t.sol:SingleInvestmentTest
[FAIL. Reason: assertion failed] testSingleInvestment() (gas: 858502)
Logs:
  Hello world.
  Did not reach investment ceiling
  Did not reach investment ceiling
  Did not reach investment ceiling
  REACHED investment ceiling
  Before length assertion 3

Traces:
  [858502] SingleInvestmentTest::testSingleInvestment()
    ├─ [807811] DecentralisedInvestmentManager::receiveInvestment{value: 20000000000000000000}()
    │   ├─ [0] console::log("Hello world.") [staticcall]
    │   │   └─ ← [Stop] 
    │   ├─ [6492] DecentralisedInvestmentHelper::hasReachedInvestmentCeiling(0, [0xDDc10602782af652bB913f7bdE1fD82981Db7dd9, 0x7FdB3132Ff7D02d8B9e221c61cC895ce9a4bb773, 0xfD07C974e33dd1626640bA3a5acF0418FaacCA7a]) [staticcall]
    │   │   ├─ [2283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 100000 [1e5]
    │   │   └─ ← [Return] false
    │   ├─ [1992] DecentralisedInvestmentHelper::hasReachedInvestmentCeiling(0, [0xDDc10602782af652bB913f7bdE1fD82981Db7dd9, 0x7FdB3132Ff7D02d8B9e221c61cC895ce9a4bb773, 0xfD07C974e33dd1626640bA3a5acF0418FaacCA7a]) [staticcall]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 100000 [1e5]
    │   │   └─ ← [Return] false
    │   ├─ [0] console::log("Did not reach investment ceiling") [staticcall]
    │   │   └─ ← [Stop] 
    │   ├─ [10045] DecentralisedInvestmentHelper::computeCurrentInvestmentTier(0, [0xDDc10602782af652bB913f7bdE1fD82981Db7dd9, 0x7FdB3132Ff7D02d8B9e221c61cC895ce9a4bb773, 0xfD07C974e33dd1626640bA3a5acF0418FaacCA7a]) [staticcall]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 100000 [1e5]
    │   │   ├─ [2305] Tier::minVal() [staticcall]
    │   │   │   └─ ← [Return] 0
    │   │   ├─ [2283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 10000 [1e4]
    │   │   └─ ← [Return] Tier: [0xDDc10602782af652bB913f7bdE1fD82981Db7dd9]
    │   ├─ [2422] DecentralisedInvestmentHelper::getRemainingAmountInCurrentTier(0, Tier: [0xDDc10602782af652bB913f7bdE1fD82981Db7dd9]) [staticcall]
    │   │   ├─ [305] Tier::minVal() [staticcall]
    │   │   │   └─ ← [Return] 0
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 10000 [1e4]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 10000 [1e4]
    │   │   └─ ← [Return] 10000 [1e4]
    │   ├─ [171231] → new TierInvestment@0xD76ffbd1eFF76C510C3a509fE22864688aC3A588
    │   │   └─ ← [Return] 400 bytes of code
    │   ├─ [1992] DecentralisedInvestmentHelper::hasReachedInvestmentCeiling(10000 [1e4], [0xDDc10602782af652bB913f7bdE1fD82981Db7dd9, 0x7FdB3132Ff7D02d8B9e221c61cC895ce9a4bb773, 0xfD07C974e33dd1626640bA3a5acF0418FaacCA7a]) [staticcall]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 100000 [1e5]
    │   │   └─ ← [Return] false
    │   ├─ [0] console::log("Did not reach investment ceiling") [staticcall]
    │   │   └─ ← [Stop] 
    │   ├─ [11501] DecentralisedInvestmentHelper::computeCurrentInvestmentTier(10000 [1e4], [0xDDc10602782af652bB913f7bdE1fD82981Db7dd9, 0x7FdB3132Ff7D02d8B9e221c61cC895ce9a4bb773, 0xfD07C974e33dd1626640bA3a5acF0418FaacCA7a]) [staticcall]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 100000 [1e5]
    │   │   ├─ [305] Tier::minVal() [staticcall]
    │   │   │   └─ ← [Return] 0
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 10000 [1e4]
    │   │   ├─ [2305] Tier::minVal() [staticcall]
    │   │   │   └─ ← [Return] 10000 [1e4]
    │   │   ├─ [2283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 50000 [5e4]
    │   │   └─ ← [Return] Tier: [0x7FdB3132Ff7D02d8B9e221c61cC895ce9a4bb773]
    │   ├─ [2422] DecentralisedInvestmentHelper::getRemainingAmountInCurrentTier(10000 [1e4], Tier: [0x7FdB3132Ff7D02d8B9e221c61cC895ce9a4bb773]) [staticcall]
    │   │   ├─ [305] Tier::minVal() [staticcall]
    │   │   │   └─ ← [Return] 10000 [1e4]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 50000 [5e4]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 50000 [5e4]
    │   │   └─ ← [Return] 40000 [4e4]
    │   ├─ [171231] → new TierInvestment@0x4ff05a443250A64a18C68CEdd2122cFDf3872140
    │   │   └─ ← [Return] 400 bytes of code
    │   ├─ [1992] DecentralisedInvestmentHelper::hasReachedInvestmentCeiling(50000 [5e4], [0xDDc10602782af652bB913f7bdE1fD82981Db7dd9, 0x7FdB3132Ff7D02d8B9e221c61cC895ce9a4bb773, 0xfD07C974e33dd1626640bA3a5acF0418FaacCA7a]) [staticcall]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 100000 [1e5]
    │   │   └─ ← [Return] false
    │   ├─ [0] console::log("Did not reach investment ceiling") [staticcall]
    │   │   └─ ← [Stop] 
    │   ├─ [8457] DecentralisedInvestmentHelper::computeCurrentInvestmentTier(50000 [5e4], [0xDDc10602782af652bB913f7bdE1fD82981Db7dd9, 0x7FdB3132Ff7D02d8B9e221c61cC895ce9a4bb773, 0xfD07C974e33dd1626640bA3a5acF0418FaacCA7a]) [staticcall]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 100000 [1e5]
    │   │   ├─ [305] Tier::minVal() [staticcall]
    │   │   │   └─ ← [Return] 0
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 10000 [1e4]
    │   │   ├─ [305] Tier::minVal() [staticcall]
    │   │   │   └─ ← [Return] 10000 [1e4]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 50000 [5e4]
    │   │   ├─ [2305] Tier::minVal() [staticcall]
    │   │   │   └─ ← [Return] 50000 [5e4]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 100000 [1e5]
    │   │   └─ ← [Return] Tier: [0xfD07C974e33dd1626640bA3a5acF0418FaacCA7a]
    │   ├─ [2422] DecentralisedInvestmentHelper::getRemainingAmountInCurrentTier(50000 [5e4], Tier: [0xfD07C974e33dd1626640bA3a5acF0418FaacCA7a]) [staticcall]
    │   │   ├─ [305] Tier::minVal() [staticcall]
    │   │   │   └─ ← [Return] 50000 [5e4]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 100000 [1e5]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 100000 [1e5]
    │   │   └─ ← [Return] 50000 [5e4]
    │   ├─ [171231] → new TierInvestment@0xc98D9175A32ca68C4B83dB84B4707AF82ae37cC4
    │   │   └─ ← [Return] 400 bytes of code
    │   ├─ [1992] DecentralisedInvestmentHelper::hasReachedInvestmentCeiling(100000 [1e5], [0xDDc10602782af652bB913f7bdE1fD82981Db7dd9, 0x7FdB3132Ff7D02d8B9e221c61cC895ce9a4bb773, 0xfD07C974e33dd1626640bA3a5acF0418FaacCA7a]) [staticcall]
    │   │   ├─ [283] Tier::maxVal() [staticcall]
    │   │   │   └─ ← [Return] 100000 [1e5]
    │   │   └─ ← [Return] true
    │   ├─ [0] console::log("REACHED investment ceiling") [staticcall]
    │   │   └─ ← [Stop] 
    │   ├─ emit InvestmentReceived(from: SingleInvestmentTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], amount: 20000000000000000000 [2e19])
    │   └─ ← [Stop] 
    ├─ emit Log(err: "Error: a == b not satisfied [uint256]")
    ├─ emit LogNamedUint256(key: "   Left", value: 0)
    ├─ emit LogNamedUint256(key: "  Right", value: 20000000000000000000 [2e19])
    ├─ [0] VM::store(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 0x6661696c65640000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000001)
    │   └─ ← [Return] 
    ├─ [290] DecentralisedInvestmentManager::getTierInvestmentLength() [staticcall]
    │   └─ ← [Return] 3
    ├─ [0] console::log("Before length assertion", 3) [staticcall]
    │   └─ ← [Stop] 
    ├─ [290] DecentralisedInvestmentManager::getTierInvestmentLength() [staticcall]
    │   └─ ← [Return] 3
    └─ ← [Stop] 

Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 1.15ms (576.20µs CPU time)

Ran 1 test for test/Deploy.t.sol:TestDeploy
[PASS] testRunTier() (gas: 113931)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.29ms (93.76µs CPU time)

Ran 4 test suites in 672.77ms (5.58ms CPU time): 6 tests passed, 1 failed, 0 skipped (7 total tests)

Failing tests:
Encountered 1 failing test in test/SingleInvestment.t.sol:SingleInvestmentTest
[FAIL. Reason: assertion failed] testSingleInvestment() (gas: 858502)

Encountered a total of 1 failing tests, 6 tests succeeded

For completeness, here is the function within the dim contract:

function receiveInvestment() external payable {
    console2.log("Hello world.");
    require(msg.value > 0, "The amount invested was not larger than 0.");

    require(msg.sender == 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496);

    require(!_helper.hasReachedInvestmentCeiling(_cumReceivedInvestments, _tiers));

    allocateInvestment(msg.value, msg.sender);

    emit InvestmentReceived(msg.sender, msg.value);
  }

And in case you would like to run it yourself you could clone this commit

Question

How could one call the receiveInvestment function of the dim contract from the investorWallet, and display the console2.log logs from the dim contract, and assert properties of the dim contract afterwards from the forge test?

1 Answer 1

0

The syntax of the call towards the receiveInvestment function was not suited for the objective of performing a transaction towards a function that changes an attribute, whilst displaying console2.log statements that occur in the receiveInvestment function. A valid solution is found with test file:

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.23 <0.9.0;
import { console2 } from "forge-std/src/console2.sol";

// Used to run the tests
import { PRBTest } from "@prb/test/src/PRBTest.sol";
import { StdCheats } from "forge-std/src/StdCheats.sol";

// Import the main contract that is being tested.
import { DecentralisedInvestmentManager } from "../src/DecentralisedInvestmentManager.sol";

/// @dev If this is your first time with Forge, read this tutorial in the Foundry Book:
/// https://book.getfoundry.sh/forge/writing-tests
contract SimplifiedTest is PRBTest, StdCheats {
  address internal projectLeadAddress;
  address private _investorWallet;
  address private _userWallet;
  DecentralisedInvestmentManager private _dim;

  /// @dev A function invoked before each test case is run.
  function setUp() public virtual {
    // Initialise the main contract that is being tested.
    projectLeadAddress = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
    uint256 projectLeadFracNumerator = 4;
    uint256 projectLeadFracDenominator = 10;
    _dim = new DecentralisedInvestmentManager(projectLeadFracNumerator, projectLeadFracDenominator, projectLeadAddress);

    // Initialsie the investor and user wallets used to interact with the main contract.
    _investorWallet = address(uint160(uint256(keccak256(bytes("1")))));
    deal(_investorWallet, 80000000 wei);
    _userWallet = address(uint160(uint256(keccak256(bytes("2")))));
    deal(_userWallet, 100002 wei);

    // Print the addresses to console.
    console2.log("projectLeadAddress=    ", projectLeadAddress);
    console2.log("_investorWallet=       ", _investorWallet);
    console2.log("_userWallet=           ", _userWallet, "\n");
  }

  /**
  Test whether the _someStoredValue attribute in the _dim contract is saved
  after its value is set in the receiveInvestment function.*/
  function testPaymentTriggersAttributeChange() public {
    uint256 startBalance = _investorWallet.balance;
    uint256 investmentAmount = 200_000 wei;

    console2.log("_dim balance before=", address(_dim).balance);
    vm.deal(address(_investorWallet), startBalance);
    vm.prank(address(_investorWallet));
    _dim.receiveInvestment{ value: investmentAmount }();

    // require(success, "Send ether failed");

    // Call receiveInvestment directly on _dim
    // _dim.receiveInvestment{value: investmentAmount}();
    // bytes memory callData = abi.encodeWithSelector(_dim.receiveInvestment.selector, investmentAmount);

    // Assert that investor balance decreased by the investment amount
    uint256 endBalance = _investorWallet.balance;

    console2.log("startBalance=", startBalance);
    console2.log("endBalance=", endBalance);
    console2.log("investmentAmount=", investmentAmount);
    console2.log("_dim balance after=", address(_dim).balance);

    assertEq(startBalance - endBalance, investmentAmount);

    // Assert balance in dim contract equals the investmentAmount.
    assertEq(investmentAmount, address(_dim).balance);

    // Assert investment data is stored in contract object _dim.
    assertEq(_dim.getSomeStoredValue(), 15);
  }
}

and as contract that receives the investment:

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.23; // Specifies the Solidity compiler version.

import { console2 } from "forge-std/src/console2.sol";

contract DecentralisedInvestmentManager {
  event PaymentReceived(address from, uint256 amount);
  event InvestmentReceived(address from, uint256 amount);

  uint256 private _projectLeadFracNumerator;
  uint256 private _projectLeadFracDenominator;
  address private _projectLead;

  uint256 public _someStoredValue;

  /**
   * Constructor for creating a Tier instance. The values cannot be changed
   * after creation.
   *
   */
  constructor(uint256 projectLeadFracNumerator, uint256 projectLeadFracDenominator, address projectLead) {
    // Store incoming arguments in contract.
    _projectLeadFracNumerator = projectLeadFracNumerator;
    _projectLeadFracDenominator = projectLeadFracDenominator;
    _projectLead = projectLead;
  }

  function receiveInvestment() external payable {

    require(msg.value > 0, "The amount invested was not larger than 0.");

    require(msg.sender == 0x82Df0950F5A951637E0307CdCB4c672F298B8Bc6, "The sender was unexpected.");

    _someStoredValue = 15;
    console2.log("Set _someStoredValue to:", _someStoredValue);

    emit InvestmentReceived(msg.sender, msg.value);
  }

  function getSomeStoredValue() public view returns (uint256) {
    return _someStoredValue;
  }
}

In summary, one can set the msg.sender implicitly before calling a function using vm.prank(address(_investorWallet)); followed by a call to the function in the other contract with: _dim.receiveInvestment{ value: investmentAmount }();. That will simulate the transaction from _investorWallet into that _dim.receiveInvestment function, assert the _someStoredValue attribute is changed in the _dim contract, whilst displaying the logs from the receiveInvestment function, granted you call forge with sufficient verbosity, e.g.:

clear && forge test -vvv --match-test testPaymentTriggersAttributeChange

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.