-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Foundry tests for HeartbeatRequester.sol (#9617)
* HeartbeatRequester.t.sol, errors with getAggregatorRequestHeartbeat tests * HeartbeatRequester.t.sol fixed * HearbeatRequester.t.sol updated * Revert pnpm-lock.yaml to match develop branch * HeartbeatRequester refactored * HeartBeatRequester.t.sol refactor * AutomationForwarder comment added * fix the solc compile path * update foundry toml --------- Co-authored-by: FelixFan1992 <fankejin@gmail.com>
- Loading branch information
1 parent
948c780
commit 665c631
Showing
11 changed files
with
188 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.6; | ||
|
||
import {IOffchainAggregator} from "../HeartbeatRequester.sol"; | ||
|
||
contract MockAggregator is IOffchainAggregator { | ||
int256 public s_answer; | ||
bool public newRoundCalled; | ||
|
||
function setLatestAnswer(int256 answer) public { | ||
s_answer = answer; | ||
} | ||
|
||
function latestAnswer() public view returns (int256) { | ||
return s_answer; | ||
} | ||
|
||
function requestNewRound() external override returns (uint80) { | ||
newRoundCalled = true; | ||
return 1; | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
contracts/src/v0.8/automation/mocks/MockAggregatorProxy.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.6; | ||
|
||
import {IAggregatorProxy} from "../HeartbeatRequester.sol"; | ||
|
||
contract MockAggregatorProxy is IAggregatorProxy { | ||
address internal s_aggregator; | ||
|
||
constructor(address _aggregator) { | ||
s_aggregator = _aggregator; | ||
} | ||
|
||
function updateAggregator(address _aggregator) external { | ||
s_aggregator = _aggregator; | ||
} | ||
|
||
function aggregator() external view override returns (address) { | ||
return s_aggregator; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.6; | ||
|
||
import "forge-std/Test.sol"; | ||
|
||
contract BaseTest is Test { | ||
address internal OWNER = 0x00007e64E1fB0C487F25dd6D3601ff6aF8d32e4e; | ||
address internal constant STRANGER = address(999); | ||
|
||
function setUp() public virtual { | ||
vm.startPrank(OWNER); | ||
deal(OWNER, 1e20); | ||
} | ||
} |
112 changes: 112 additions & 0 deletions
112
contracts/src/v0.8/automation/test/HeartbeatRequester.t.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.6; | ||
|
||
import {HeartbeatRequester, IAggregatorProxy} from "../HeartbeatRequester.sol"; | ||
import {MockAggregator} from "../mocks/MockAggregator.sol"; | ||
import {MockAggregatorProxy} from "../mocks/MockAggregatorProxy.sol"; | ||
import {BaseTest} from "./BaseTest.t.sol"; | ||
|
||
// from contracts directory, | ||
// forge test --match-path src/v0.8/automation/test/HeartbeatRequester.t.sol | ||
|
||
contract HeartbeatRequesterSetUp is BaseTest { | ||
HeartbeatRequester internal heartbeatRequester; | ||
MockAggregator internal aggregator; | ||
IAggregatorProxy internal aggregatorProxy; | ||
MockAggregator internal aggregator2; | ||
IAggregatorProxy internal aggregatorProxy2; | ||
|
||
event HeartbeatPermitted(address indexed permittedCaller, address newProxy, address oldProxy); | ||
event HeartbeatRemoved(address indexed permittedCaller, address removedProxy); | ||
error HeartbeatNotPermitted(); | ||
|
||
function setUp() public override { | ||
BaseTest.setUp(); | ||
heartbeatRequester = new HeartbeatRequester(); | ||
aggregator = new MockAggregator(); | ||
aggregatorProxy = IAggregatorProxy(new MockAggregatorProxy(address(aggregator))); | ||
aggregator2 = new MockAggregator(); | ||
aggregatorProxy2 = IAggregatorProxy(new MockAggregatorProxy(address(aggregator2))); | ||
} | ||
} | ||
|
||
contract HeartbeatRequester_permitHeartbeat is HeartbeatRequesterSetUp { | ||
function testBasicSuccess() public { | ||
vm.expectEmit(); | ||
emit HeartbeatPermitted(STRANGER, address(aggregatorProxy), address(0)); | ||
heartbeatRequester.permitHeartbeat(STRANGER, aggregatorProxy); | ||
|
||
vm.expectEmit(); | ||
emit HeartbeatPermitted(STRANGER, address(aggregatorProxy2), address(aggregatorProxy)); | ||
heartbeatRequester.permitHeartbeat(STRANGER, aggregatorProxy2); | ||
} | ||
|
||
function testBasicDeployerSuccess() public { | ||
vm.expectEmit(); | ||
emit HeartbeatPermitted(OWNER, address(aggregatorProxy), address(0)); | ||
heartbeatRequester.permitHeartbeat(OWNER, aggregatorProxy); | ||
|
||
vm.expectEmit(); | ||
emit HeartbeatPermitted(OWNER, address(aggregatorProxy2), address(aggregatorProxy)); | ||
heartbeatRequester.permitHeartbeat(OWNER, aggregatorProxy2); | ||
} | ||
|
||
function testOnlyCallableByOwnerReverts() public { | ||
vm.expectRevert(bytes("Only callable by owner")); | ||
changePrank(STRANGER); | ||
heartbeatRequester.permitHeartbeat(STRANGER, aggregatorProxy); | ||
} | ||
} | ||
|
||
contract HeartbeatRequester_removeHeartbeat is HeartbeatRequesterSetUp { | ||
function testBasicSuccess() public { | ||
vm.expectEmit(); | ||
emit HeartbeatPermitted(STRANGER, address(aggregatorProxy), address(0)); | ||
heartbeatRequester.permitHeartbeat(STRANGER, aggregatorProxy); | ||
|
||
vm.expectEmit(); | ||
emit HeartbeatRemoved(STRANGER, address(aggregatorProxy)); | ||
heartbeatRequester.removeHeartbeat(STRANGER); | ||
} | ||
|
||
function testRemoveNoPermitsSuccess() public { | ||
vm.expectEmit(); | ||
emit HeartbeatRemoved(STRANGER, address(0)); | ||
heartbeatRequester.removeHeartbeat(STRANGER); | ||
} | ||
|
||
function testOnlyCallableByOwnerReverts() public { | ||
vm.expectRevert(bytes("Only callable by owner")); | ||
changePrank(STRANGER); | ||
heartbeatRequester.removeHeartbeat(address(this)); | ||
} | ||
} | ||
|
||
contract HeartbeatRequester_getAggregatorRequestHeartbeat is HeartbeatRequesterSetUp { | ||
function testBasicSuccess() public { | ||
vm.expectEmit(); | ||
emit HeartbeatPermitted(OWNER, address(aggregatorProxy), address(0)); | ||
heartbeatRequester.permitHeartbeat(OWNER, aggregatorProxy); | ||
heartbeatRequester.getAggregatorAndRequestHeartbeat(address(aggregatorProxy)); | ||
// getter for newRoundCalled value | ||
bool val = aggregator.newRoundCalled(); | ||
assertEq(val, true); | ||
} | ||
|
||
function testHeartbeatNotPermittedReverts() public { | ||
bytes32 hashedReason = keccak256(abi.encodePacked("HeartbeatNotPermitted()")); | ||
bytes memory revertMessage = bytes32ToBytes(hashedReason); | ||
vm.expectRevert(revertMessage); | ||
heartbeatRequester.getAggregatorAndRequestHeartbeat(address(aggregatorProxy)); | ||
bool val = aggregator.newRoundCalled(); | ||
assertFalse(val); | ||
} | ||
|
||
function bytes32ToBytes(bytes32 _bytes32) public pure returns (bytes memory) { | ||
bytes memory bytesArray = new bytes(4); | ||
for (uint256 i; i < 4; ++i) { | ||
bytesArray[i] = _bytes32[i]; | ||
} | ||
return bytesArray; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
20 changes: 10 additions & 10 deletions
20
core/gethwrappers/generated/mock_aggregator_proxy/mock_aggregator_proxy.go
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters