forked from ethereum-optimism/optimism
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ctp): add solidity tests with foundry (ethereum-optimism#2585)
This commits adds solidity tests for contracts-periphery package. More specific it covers AssetReceiver, TeleportrWithdrawer & Transactor
- Loading branch information
1 parent
65fa917
commit 9a69357
Showing
14 changed files
with
480 additions
and
10 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
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,26 @@ | ||
AssetReceiverTest:testFail_withdrawERC20() (gas: 199441) | ||
AssetReceiverTest:testFail_withdrawERC20withAmount() (gas: 199389) | ||
AssetReceiverTest:testFail_withdrawERC721() (gas: 55930) | ||
AssetReceiverTest:testFail_withdrawETH() (gas: 10523) | ||
AssetReceiverTest:testFail_withdrawETHwithAmount() (gas: 10639) | ||
AssetReceiverTest:test_constructor() (gas: 9845) | ||
AssetReceiverTest:test_receive() (gas: 18860) | ||
AssetReceiverTest:test_withdrawERC20() (gas: 183388) | ||
AssetReceiverTest:test_withdrawERC20withAmount() (gas: 182436) | ||
AssetReceiverTest:test_withdrawERC721() (gas: 49149) | ||
AssetReceiverTest:test_withdrawETH() (gas: 26121) | ||
AssetReceiverTest:test_withdrawETHwithAmount() (gas: 26161) | ||
TeleportrWithdrawerTest:testFail_setData() (gas: 8546) | ||
TeleportrWithdrawerTest:testFail_setRecipient() (gas: 9952) | ||
TeleportrWithdrawerTest:testFail_setTeleportr() (gas: 9918) | ||
TeleportrWithdrawerTest:test_constructor() (gas: 9790) | ||
TeleportrWithdrawerTest:test_setData() (gas: 41835) | ||
TeleportrWithdrawerTest:test_setRecipient() (gas: 36176) | ||
TeleportrWithdrawerTest:test_setTeleportr() (gas: 38023) | ||
TeleportrWithdrawerTest:test_withdrawFromTeleportrToContract() (gas: 191517) | ||
TeleportrWithdrawerTest:test_withdrawFromTeleportrToEOA() (gas: 78597) | ||
TransactorTest:testFail_CALL() (gas: 15737) | ||
TransactorTest:testFail_DELEGATECALLL() (gas: 15704) | ||
TransactorTest:test_CALL() (gas: 27132) | ||
TransactorTest:test_DELEGATECALL() (gas: 21266) | ||
TransactorTest:test_constructor() (gas: 9823) |
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 |
---|---|---|
@@ -1,6 +1,7 @@ | ||
module.exports = { | ||
skipFiles: [ | ||
'./test-libraries', | ||
'./foundry-tests' | ||
], | ||
mocha: { | ||
grep: "@skip-on-coverage", | ||
|
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 |
---|---|---|
@@ -1 +1,2 @@ | ||
node_modules | ||
contracts/foundry-tests/*.t.sol |
190 changes: 190 additions & 0 deletions
190
packages/contracts-periphery/contracts/foundry-tests/AssetReceiver.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,190 @@ | ||
//SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.10; | ||
|
||
/* Testing utilities */ | ||
import { Test } from "forge-std/Test.sol"; | ||
import { TestERC20 } from "../testing/helpers/TestERC20.sol"; | ||
import { TestERC721 } from "../testing/helpers/TestERC721.sol"; | ||
import { AssetReceiver } from "../universal/AssetReceiver.sol"; | ||
|
||
contract AssetReceiver_Initializer is Test { | ||
address alice = address(128); | ||
address bob = address(256); | ||
|
||
uint8 immutable DEFAULT_TOKEN_ID = 0; | ||
|
||
TestERC20 testERC20; | ||
TestERC721 testERC721; | ||
AssetReceiver assetReceiver; | ||
|
||
function _setUp() public { | ||
// Deploy ERC20 and ERC721 tokens | ||
testERC20 = new TestERC20(); | ||
testERC721 = new TestERC721(); | ||
|
||
// Deploy AssetReceiver contract | ||
assetReceiver = new AssetReceiver(address(alice)); | ||
vm.label(address(assetReceiver), "AssetReceiver"); | ||
|
||
// Give alice and bob some ETH | ||
vm.deal(alice, 1 ether); | ||
vm.deal(bob, 1 ether); | ||
|
||
testERC721.mint(alice, DEFAULT_TOKEN_ID); | ||
|
||
vm.label(alice, "alice"); | ||
vm.label(bob, "bob"); | ||
} | ||
} | ||
|
||
contract AssetReceiverTest is AssetReceiver_Initializer { | ||
function setUp() public { | ||
super._setUp(); | ||
} | ||
|
||
// Tests if the owner was set correctly during deploy | ||
function test_constructor() external { | ||
assertEq(address(alice), assetReceiver.owner()); | ||
} | ||
|
||
// Tests that receive works as inteded | ||
function test_receive() external { | ||
// Check that contract balance is 0 initially | ||
assertEq(address(assetReceiver).balance, 0); | ||
|
||
// Send funds | ||
vm.prank(alice); | ||
(bool success, ) = address(assetReceiver).call{ value: 100 }(hex""); | ||
|
||
// Compare balance after the tx sent | ||
assertTrue(success); | ||
assertEq(address(assetReceiver).balance, 100); | ||
} | ||
|
||
// Tests withdrawETH function with only an address as argument, called by owner | ||
function test_withdrawETH() external { | ||
// Check contract initial balance | ||
assertEq(address(assetReceiver).balance, 0); | ||
// Fund contract with 1 eth and check caller and contract balances | ||
vm.deal(address(assetReceiver), 1 ether); | ||
assertEq(address(assetReceiver).balance, 1 ether); | ||
|
||
assertEq(address(alice).balance, 1 ether); | ||
|
||
// call withdrawETH | ||
vm.prank(alice); | ||
assetReceiver.withdrawETH(payable(alice)); | ||
|
||
// check balances after the call | ||
assertEq(address(assetReceiver).balance, 0); | ||
assertEq(address(alice).balance, 2 ether); | ||
} | ||
|
||
// withdrawETH should fail if called by non-owner | ||
function testFail_withdrawETH() external { | ||
vm.deal(address(assetReceiver), 1 ether); | ||
assetReceiver.withdrawETH(payable(alice)); | ||
vm.expectRevert("UNAUTHORIZED"); | ||
} | ||
|
||
// Similar as withdrawETH but specify amount to withdraw | ||
function test_withdrawETHwithAmount() external { | ||
assertEq(address(assetReceiver).balance, 0); | ||
|
||
vm.deal(address(assetReceiver), 1 ether); | ||
assertEq(address(assetReceiver).balance, 1 ether); | ||
|
||
assertEq(address(alice).balance, 1 ether); | ||
|
||
// call withdrawETH | ||
vm.prank(alice); | ||
assetReceiver.withdrawETH(payable(alice), 0.5 ether); | ||
|
||
// check balances after the call | ||
assertEq(address(assetReceiver).balance, 0.5 ether); | ||
assertEq(address(alice).balance, 1.5 ether); | ||
} | ||
|
||
// withdrawETH with address and amount as arguments called by non-owner | ||
function testFail_withdrawETHwithAmount() external { | ||
vm.deal(address(assetReceiver), 1 ether); | ||
assetReceiver.withdrawETH(payable(alice), 0.5 ether); | ||
vm.expectRevert("UNAUTHORIZED"); | ||
} | ||
|
||
// Test withdrawERC20 with token and address arguments, from owner | ||
function test_withdrawERC20() external { | ||
// check balances before the call | ||
assertEq(testERC20.balanceOf(address(assetReceiver)), 0); | ||
|
||
deal(address(testERC20), address(assetReceiver), 100_000); | ||
assertEq(testERC20.balanceOf(address(assetReceiver)), 100_000); | ||
assertEq(testERC20.balanceOf(alice), 0); | ||
|
||
// call withdrawERC20 | ||
vm.prank(alice); | ||
assetReceiver.withdrawERC20(testERC20, alice); | ||
|
||
// check balances after the call | ||
assertEq(testERC20.balanceOf(alice), 100_000); | ||
assertEq(testERC20.balanceOf(address(assetReceiver)), 0); | ||
} | ||
|
||
// Same as withdrawERC20 but call from non-owner | ||
function testFail_withdrawERC20() external { | ||
deal(address(testERC20), address(assetReceiver), 100_000); | ||
assetReceiver.withdrawERC20(testERC20, alice); | ||
vm.expectRevert("UNAUTHORIZED"); | ||
} | ||
|
||
// Similar as withdrawERC20 but specify amount to withdraw | ||
function test_withdrawERC20withAmount() external { | ||
// check balances before the call | ||
assertEq(testERC20.balanceOf(address(assetReceiver)), 0); | ||
|
||
deal(address(testERC20), address(assetReceiver), 100_000); | ||
assertEq(testERC20.balanceOf(address(assetReceiver)), 100_000); | ||
assertEq(testERC20.balanceOf(alice), 0); | ||
|
||
// call withdrawERC20 | ||
vm.prank(alice); | ||
assetReceiver.withdrawERC20(testERC20, alice, 50_000); | ||
|
||
// check balances after the call | ||
assertEq(testERC20.balanceOf(alice), 50_000); | ||
assertEq(testERC20.balanceOf(address(assetReceiver)), 50_000); | ||
} | ||
|
||
// Similar as withdrawERC20 with amount but call from non-owner | ||
function testFail_withdrawERC20withAmount() external { | ||
deal(address(testERC20), address(assetReceiver), 100_000); | ||
assetReceiver.withdrawERC20(testERC20, alice, 50_000); | ||
vm.expectRevert("UNAUTHORIZED"); | ||
} | ||
|
||
// Test withdrawERC721 from owner | ||
function test_withdrawERC721() external { | ||
// Check owner of the token before calling withdrawERC721 | ||
assertEq(testERC721.ownerOf(DEFAULT_TOKEN_ID), alice); | ||
|
||
// Send the token from alice to the contract | ||
vm.prank(alice); | ||
testERC721.transferFrom(alice, address(assetReceiver), DEFAULT_TOKEN_ID); | ||
assertEq(testERC721.ownerOf(DEFAULT_TOKEN_ID), address(assetReceiver)); | ||
|
||
// Call withdrawERC721 | ||
vm.prank(alice); | ||
assetReceiver.withdrawERC721(testERC721, alice, DEFAULT_TOKEN_ID); | ||
|
||
// Check the owner after the call | ||
assertEq(testERC721.ownerOf(DEFAULT_TOKEN_ID), alice); | ||
} | ||
|
||
// Similar as withdrawERC721 but call from non-owner | ||
function testFail_withdrawERC721() external { | ||
vm.prank(alice); | ||
testERC721.transferFrom(alice, address(assetReceiver), DEFAULT_TOKEN_ID); | ||
assetReceiver.withdrawERC721(testERC721, alice, DEFAULT_TOKEN_ID); | ||
vm.expectRevert("UNAUTHORIZED"); | ||
} | ||
} |
125 changes: 125 additions & 0 deletions
125
packages/contracts-periphery/contracts/foundry-tests/TeleportrWithdrawer.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,125 @@ | ||
//SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.10; | ||
|
||
/* Testing utilities */ | ||
import { Test } from "forge-std/Test.sol"; | ||
import { SimpleStorage } from "../testing/helpers/SimpleStorage.sol"; | ||
import { MockTeleportr } from "../testing/helpers/MockTeleportr.sol"; | ||
import { TeleportrWithdrawer } from "../universal/TeleportrWithdrawer.sol"; | ||
|
||
contract TeleportrWithdrawer_Initializer is Test { | ||
address alice = address(128); | ||
address bob = address(256); | ||
|
||
TeleportrWithdrawer teleportrWithdrawer; | ||
MockTeleportr mockTeleportr; | ||
SimpleStorage simpleStorage; | ||
|
||
function _setUp() public { | ||
// Deploy MockTeleportr and SimpleStorage helper contracts | ||
mockTeleportr = new MockTeleportr(); | ||
simpleStorage = new SimpleStorage(); | ||
|
||
// Deploy Transactor contract | ||
teleportrWithdrawer = new TeleportrWithdrawer(address(alice)); | ||
vm.label(address(teleportrWithdrawer), "TeleportrWithdrawer"); | ||
|
||
// Give alice and bob some ETH | ||
vm.deal(alice, 1 ether); | ||
vm.deal(bob, 1 ether); | ||
|
||
vm.label(alice, "alice"); | ||
vm.label(bob, "bob"); | ||
} | ||
} | ||
|
||
contract TeleportrWithdrawerTest is TeleportrWithdrawer_Initializer { | ||
function setUp() public { | ||
super._setUp(); | ||
} | ||
|
||
// Tests if the owner was set correctly during deploy | ||
function test_constructor() external { | ||
assertEq(address(alice), teleportrWithdrawer.owner()); | ||
} | ||
|
||
// Tests setRecipient function when called by authorized address | ||
function test_setRecipient() external { | ||
// Call setRecipient from alice | ||
vm.prank(alice); | ||
teleportrWithdrawer.setRecipient(address(alice)); | ||
assertEq(teleportrWithdrawer.recipient(), address(alice)); | ||
} | ||
|
||
// setRecipient should fail if called by unauthorized address | ||
function testFail_setRecipient() external { | ||
teleportrWithdrawer.setRecipient(address(alice)); | ||
vm.expectRevert("UNAUTHORIZED"); | ||
} | ||
|
||
// Tests setTeleportr function when called by authorized address | ||
function test_setTeleportr() external { | ||
// Call setRecipient from alice | ||
vm.prank(alice); | ||
teleportrWithdrawer.setTeleportr(address(mockTeleportr)); | ||
assertEq(teleportrWithdrawer.teleportr(), address(mockTeleportr)); | ||
} | ||
|
||
// setTeleportr should fail if called by unauthorized address | ||
function testFail_setTeleportr() external { | ||
teleportrWithdrawer.setTeleportr(address(bob)); | ||
vm.expectRevert("UNAUTHORIZED"); | ||
} | ||
|
||
// Tests setData function when called by authorized address | ||
function test_setData() external { | ||
bytes memory data = "0x1234567890"; | ||
// Call setData from alice | ||
vm.prank(alice); | ||
teleportrWithdrawer.setData(data); | ||
assertEq(teleportrWithdrawer.data(), data); | ||
} | ||
|
||
// setData should fail if called by unauthorized address | ||
function testFail_setData() external { | ||
bytes memory data = "0x1234567890"; | ||
teleportrWithdrawer.setData(data); | ||
vm.expectRevert("UNAUTHORIZED"); | ||
} | ||
|
||
// Tests withdrawFromTeleportr, when called expected to withdraw the balance | ||
// to the recipient address when the target is an EOA | ||
function test_withdrawFromTeleportrToEOA() external { | ||
// Fund the Teleportr contract with 1 ETH | ||
vm.deal(address(teleportrWithdrawer), 1 ether); | ||
// Set target address and Teleportr | ||
vm.startPrank(alice); | ||
teleportrWithdrawer.setRecipient(address(bob)); | ||
teleportrWithdrawer.setTeleportr(address(mockTeleportr)); | ||
vm.stopPrank(); | ||
// Run withdrawFromTeleportr | ||
assertEq(address(bob).balance, 1 ether); | ||
teleportrWithdrawer.withdrawFromTeleportr(); | ||
assertEq(address(bob).balance, 2 ether); | ||
} | ||
|
||
// When called from a contract account it should withdraw the balance and trigger the code | ||
function test_withdrawFromTeleportrToContract() external { | ||
bytes32 key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; | ||
bytes32 value = 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; | ||
bytes memory data = abi.encodeWithSelector(simpleStorage.set.selector, key, value); | ||
// Fund the Teleportr contract with 1 ETH | ||
vm.deal(address(teleportrWithdrawer), 1 ether); | ||
// Set target address and Teleportr | ||
vm.startPrank(alice); | ||
teleportrWithdrawer.setRecipient(address(simpleStorage)); | ||
teleportrWithdrawer.setTeleportr(address(mockTeleportr)); | ||
teleportrWithdrawer.setData(data); | ||
vm.stopPrank(); | ||
// Run withdrawFromTeleportr | ||
assertEq(address(simpleStorage).balance, 0); | ||
teleportrWithdrawer.withdrawFromTeleportr(); | ||
assertEq(address(simpleStorage).balance, 1 ether); | ||
assertEq(simpleStorage.get(key), value); | ||
} | ||
} |
Oops, something went wrong.