Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invariant tests: what is the best way of managing blockchain-timestamp? #376

Open
JacoboLansac opened this issue May 10, 2023 · 2 comments

Comments

@JacoboLansac
Copy link

When doing invariant tests on a staking protocol, it is important to be able to simulate the pass of time. I tried two approaches:

  1. Adding a function to a handler contract that internally uses skip(time). However, blockchain timestamp was reverted to the original point after executing the function. Time advancement was not preserved outside that function.

  2. In the handler contract, declare a state variable called timestamp and add a modifier to all functions in the handler contract, which would add some time to that variable before using vm.warp(timestamp). This worked.

Is there a better way of doing it?

@PaulRBerg
Copy link
Contributor

Invariants are still a relatively new feature in Forge Std, so there are few best practices for them. In our code base, we went with your 2nd suggested solution, but we made sure to bound each warp so that the overall invariant campaign doesn't get chaotic (our protocol assumes that time flows linearly 😅)

/// @dev Simulate the passage of time. The time warp is upper bounded so streams don't settle too quickly.
function warp(uint256 timeWarp) external instrument("warp") {
    uint256 lowerBound = 24 hours;
    uint256 currentTime = getLatestTimestamp();
    uint256 upperBound = (MAX_UNIX_TIMESTAMP - currentTime) / MAX_STREAM_COUNT;
    timeWarp = _bound(timeWarp, lowerBound, upperBound);
    uint256 newTime = currentTime + timeWarp;
    vm.warp({ timestamp: newTime });
    setLatestTimestamp(newTime);
}

getLatestTimestamp and setLatestTimestamp do what your state variable timestamp does; block.timestamp is returned on the first run.

@PaulRBerg
Copy link
Contributor

Also, I think this issue should have opened in the Foundry Book repo:

https://github.com/foundry-rs/book/issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants