Skip to content

Commit

Permalink
Merge pull request #24 from 0xJurassicPunk/tests-low-level
Browse files Browse the repository at this point in the history
test: Low level calls
  • Loading branch information
0xJurassicPunk authored Sep 28, 2022
2 parents 1cc9ac5 + 1ad485f commit 0a43c17
Show file tree
Hide file tree
Showing 12 changed files with 366 additions and 23 deletions.
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ It also contains generic contract interfaces (for EIP/ERC) that can be used.

## Current contracts

| Name | Description | Type | Latest version |
| ---------------- | ----------------------------------------------------------------------------------------------------------- | -------- | -------------- |
| OwnableTwoSteps | Contract for managing ownership of a smart contract. The transfer of ownership is done in a 2-step process. | Contract | 1.0.0 |
| SignatureChecker | Contract for verifying the validity of a signature for EOA (64-byte, 65-byte signatures) and EIP-1271. | Contract | 1.0.0 |
| ReentrancyGuard | Contract with a modifier to prevent reentrancy calls. | Contract | 1.0.0 |
| Name | Description | Type | Latest version |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------- | -------------- |
| OwnableTwoSteps | Contract for managing ownership of a smart contract. The transfer of ownership is done in a 2-step process. | Contract | 2.0.0 |
| SignatureChecker | Contract for verifying the validity of a signature for EOA (64-byte, 65-byte signatures) and EIP-1271. | Contract | 2.0.0 |
| ReentrancyGuard | Contract with a modifier to prevent reentrancy calls. | Contract | 2.0.0 |
| LowLevelETH | Low-level call functions to transfer ETH or return ETH back to sender in a payable function | Contract | 2.0.0 |
| LowLevelWETH | Low-level call functions to transfer ETH with an option to wrap to WETH if the original ETH transfer fails within a gas limit | Contract | 2.0.0 |
| LowLevelERC20 | Low-level call functions for ERC20 functions | Contract | 2.0.0 |
| LowLevelERC721 | Low-level call functions for ERC721 functions | Contract | 2.0.0 |
| LowLevelERC1155 | Low-level call functions for ERC1155 functions | Contract | 2.0.0 |

## About this repo

Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"files": [
"/abis/*.json",
"/contracts/*.sol",
"/contracts/interfaces/*.sol"
"/contracts/interfaces/*.sol",
"/contracts/interfaces/generic/*.sol",
"/contracts/lowLevelCallers/*.sol"
],
"keywords": [
"looksrare",
Expand Down Expand Up @@ -75,6 +77,7 @@
"release-it": "^15.0.0",
"solhint": "^3.3.7",
"solidity-coverage": "^0.7.21",
"solmate": "^6.6.1",
"ts-node": "^10.1.0",
"typechain": "^5.1.2",
"typescript": "^4.5.2"
Expand Down
74 changes: 74 additions & 0 deletions test/foundry/LowLevelERC1155.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {LowLevelERC1155} from "../../contracts/lowLevelCallers/LowLevelERC1155.sol";
import {MockERC1155} from "../mock/MockERC1155.sol";
import {TestHelpers} from "./utils/TestHelpers.sol";

contract ImplementedLowLevelERC1155 is LowLevelERC1155 {
function safeTransferFromERC1155(
address collection,
address from,
address to,
uint256 tokenId,
uint256 amount
) external {
_executeERC1155SafeTransferFrom(collection, from, to, tokenId, amount);
}

function safeBatchTransferFromERC1155(
address collection,
address from,
address to,
uint256[] calldata tokenIds,
uint256[] calldata amounts
) external {
_executeERC1155SafeBatchTransferFrom(collection, from, to, tokenIds, amounts);
}
}

abstract contract TestParameters {
address internal _sender = address(100);
address internal _recipient = address(101);
}

contract LowLevelERC1155Test is TestParameters, TestHelpers {
ImplementedLowLevelERC1155 public lowLevelERC1155;
MockERC1155 public mockERC1155;

function setUp() external {
lowLevelERC1155 = new ImplementedLowLevelERC1155();
mockERC1155 = new MockERC1155();
}

function testSafeTransferFromERC1155(uint256 tokenId, uint256 amount) external asPrankedUser(_sender) {
mockERC1155.mint(_sender, tokenId, amount);
mockERC1155.setApprovalForAll(address(lowLevelERC1155), true);
lowLevelERC1155.safeTransferFromERC1155(address(mockERC1155), _sender, _recipient, tokenId, amount);
assertEq(mockERC1155.balanceOf(_recipient, tokenId), amount);
}

function testSafeBatchTransferFromERC1155(
uint256 tokenId0,
uint256 amount0,
uint256 amount1
) external asPrankedUser(_sender) {
vm.assume(tokenId0 < type(uint256).max);
uint256 tokenId1 = tokenId0 + 1;
mockERC1155.mint(_sender, tokenId0, amount0);
mockERC1155.mint(_sender, tokenId1, amount1);
mockERC1155.setApprovalForAll(address(lowLevelERC1155), true);

uint256[] memory amounts = new uint256[](2);
amounts[0] = amount0;
amounts[1] = amount1;

uint256[] memory tokenIds = new uint256[](2);
tokenIds[0] = tokenId0;
tokenIds[1] = tokenId1;

lowLevelERC1155.safeBatchTransferFromERC1155(address(mockERC1155), _sender, _recipient, tokenIds, amounts);
assertEq(mockERC1155.balanceOf(_recipient, tokenId0), amount0);
assertEq(mockERC1155.balanceOf(_recipient, tokenId1), amount1);
}
}
53 changes: 53 additions & 0 deletions test/foundry/LowLevelERC20.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {LowLevelERC20} from "../../contracts/lowLevelCallers/LowLevelERC20.sol";
import {MockERC20} from "../mock/MockERC20.sol";
import {TestHelpers} from "./utils/TestHelpers.sol";

contract ImplementedLowLevelERC20 is LowLevelERC20 {
function transferERC20(
address currency,
address to,
uint256 amount
) external {
_executeERC20DirectTransfer(currency, to, amount);
}

function transferFromERC20(
address currency,
address from,
address to,
uint256 amount
) external {
_executeERC20TransferFrom(currency, from, to, amount);
}
}

abstract contract TestParameters {
address internal _sender = address(100);
address internal _recipient = address(101);
}

contract LowLevelERC20Test is TestHelpers, TestParameters {
ImplementedLowLevelERC20 public lowLevelERC20;
MockERC20 public mockERC20;

function setUp() external {
lowLevelERC20 = new ImplementedLowLevelERC20();
mockERC20 = new MockERC20();
}

function testTransferFromERC20(uint256 amount) external asPrankedUser(_sender) {
mockERC20.mint(_sender, amount);
mockERC20.approve(address(lowLevelERC20), amount);
lowLevelERC20.transferFromERC20(address(mockERC20), _sender, _recipient, amount);
assertEq(mockERC20.balanceOf(_recipient), amount);
}

function testTransferERC20(uint256 amount) external asPrankedUser(_sender) {
mockERC20.mint(address(lowLevelERC20), amount);
lowLevelERC20.transferERC20(address(mockERC20), _recipient, amount);
assertEq(mockERC20.balanceOf(_recipient), amount);
}
}
39 changes: 39 additions & 0 deletions test/foundry/LowLevelERC721.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {LowLevelERC721} from "../../contracts/lowLevelCallers/LowLevelERC721.sol";
import {MockERC721} from "../mock/MockERC721.sol";
import {TestHelpers} from "./utils/TestHelpers.sol";

contract ImplementedLowLevelERC721 is LowLevelERC721 {
function transferERC721(
address collection,
address from,
address to,
uint256 tokenId
) external {
_executeERC721TransferFrom(collection, from, to, tokenId);
}
}

abstract contract TestParameters {
address internal _sender = address(100);
address internal _recipient = address(101);
}

contract LowLevelERC721Test is TestParameters, TestHelpers {
ImplementedLowLevelERC721 public lowLevelERC721;
MockERC721 public mockERC721;

function setUp() external {
lowLevelERC721 = new ImplementedLowLevelERC721();
mockERC721 = new MockERC721();
}

function testTransferFromERC721(uint256 tokenId) external asPrankedUser(_sender) {
mockERC721.mint(_sender, tokenId);
mockERC721.setApprovalForAll(address(lowLevelERC721), true);
lowLevelERC721.transferERC721(address(mockERC721), _sender, _recipient, tokenId);
assertEq(mockERC721.ownerOf(tokenId), _recipient);
}
}
59 changes: 59 additions & 0 deletions test/foundry/LowLevelETH.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {LowLevelETH} from "../../contracts/lowLevelCallers/LowLevelETH.sol";
import {TestHelpers} from "./utils/TestHelpers.sol";

contract ImplementedLowLevelETH is LowLevelETH {
function transferETH(address _to) external payable {
_transferETH(_to, msg.value);
}

function transferETHAndReturnFunds() external payable {
_returnETHIfAny();
}

function transferETHAndReturnFundsExceptOneWei() external payable {
_returnETHIfAnyWithOneWeiLeft();
}
}

abstract contract TestParameters {
address internal _sender = address(100);
address internal _recipient = address(101);
uint256 internal _GAS_LIMIT = 10000;
}

contract LowLevelETHTest is TestParameters, TestHelpers {
ImplementedLowLevelETH public lowLevelETH;

function setUp() external {
lowLevelETH = new ImplementedLowLevelETH();
}

function testTransferETH(address randomSender, uint112 amount) external payable {
vm.deal(randomSender, amount);
vm.prank(randomSender);
lowLevelETH.transferETH{value: amount}(_recipient);
assertEq(_recipient.balance, amount);
}

function testTransferETHAndReturnFunds(uint112 amount) external payable asPrankedUser(_sender) {
vm.deal(_sender, amount);
lowLevelETH.transferETHAndReturnFunds{value: amount}();
assertEq(_sender.balance, amount);
}

function testTransferETHAndReturnFundsExceptOneWei(uint112 amount) external payable asPrankedUser(_sender) {
vm.deal(_sender, amount);
lowLevelETH.transferETHAndReturnFundsExceptOneWei{value: amount}();

if (amount > 1) {
assertEq(_sender.balance, amount - 1);
assertEq(address(lowLevelETH).balance, 1);
} else {
assertEq(_sender.balance, 0);
assertEq(address(lowLevelETH).balance, amount);
}
}
}
52 changes: 52 additions & 0 deletions test/foundry/LowLevelWETH.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {WETH} from "solmate/src/tokens/WETH.sol";
import {LowLevelWETH} from "../../contracts/lowLevelCallers/LowLevelWETH.sol";
import {TestHelpers} from "./utils/TestHelpers.sol";

contract ImplementedLowLevelWETH is LowLevelWETH {
function transferETH(
address _WETH,
address _to,
uint256 _amount,
uint256 _gasLimit
) external payable {
_transferETHAndWrapIfFailWithGasLimit(_WETH, _to, _amount, _gasLimit);
}
}

abstract contract TestParameters {
address internal _sender = address(100);
uint256 internal _GAS_LIMIT = 10000;
}

contract RecipientFallback {
ImplementedLowLevelWETH public lowLevelWETH;

receive() external payable {
// Infinite loop
for (uint256 i; i < type(uint256).max; i++) {
keccak256(abi.encode(i));
}
}
}

contract LowLevelWETHTest is TestParameters, TestHelpers {
ImplementedLowLevelWETH public lowLevelWETH;
RecipientFallback public recipientFallback;
WETH public weth;

function setUp() external {
lowLevelWETH = new ImplementedLowLevelWETH();
recipientFallback = new RecipientFallback();
weth = new WETH();
}

function testTransferETH(uint256 amount) external payable asPrankedUser(_sender) {
vm.deal(_sender, amount);
lowLevelWETH.transferETH{value: amount}(address(weth), address(recipientFallback), amount, _GAS_LIMIT);
assertEq(address(recipientFallback).balance, 0);
assertEq(weth.balanceOf(address(recipientFallback)), amount);
}
}
Loading

0 comments on commit 0a43c17

Please sign in to comment.