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

🗞️ TestHelper for OpenZeppelin v5 #442

Merged
merged 8 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion examples/oapp/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,24 @@ src = 'contracts'
out = 'out'
test = 'test/foundry'
cache_path = 'cache'
libs = ['node_modules', 'node_modules/@layerzerolabs/toolbox-foundry/lib']
libs = [
# We provide a set of useful contract utilities
# in the lib directory of @layerzerolabs/toolbox-foundry:
#
# - forge-std
# - ds-test
# - solidity-bytes-utils
'node_modules/@layerzerolabs/toolbox-foundry/lib',
'node_modules',
]

remappings = [
# Due to a misconfiguration of solidity-bytes-utils, an outdated version
# of forge-std is being dragged in
#
# To remedy this, we'll remap the ds-test and forge-std imports to ou own versions
'ds-test/=node_modules/@layerzerolabs/toolbox-foundry/lib/ds-test',
'forge-std/=node_modules/@layerzerolabs/toolbox-foundry/lib/forge-std',
'@layerzerolabs/=node_modules/@layerzerolabs/',
'@openzeppelin/=node_modules/@openzeppelin/',
]
1 change: 1 addition & 0 deletions examples/oapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@nomicfoundation/hardhat-ethers": "^3.0.5",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@openzeppelin/contracts": "^5.0.1",
"@openzeppelin/contracts-upgradeable": "^5.0.1",
"@rushstack/eslint-patch": "^1.7.0",
"@types/chai": "^4.3.11",
"@types/mocha": "^10.0.6",
Expand Down
19 changes: 17 additions & 2 deletions examples/oft/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,24 @@ src = 'contracts'
out = 'out'
test = 'test/foundry'
cache_path = 'cache'
libs = ['node_modules', 'node_modules/@layerzerolabs/toolbox-foundry/lib']
libs = [
# We provide a set of useful contract utilities
# in the lib directory of @layerzerolabs/toolbox-foundry:
#
# - forge-std
# - ds-test
# - solidity-bytes-utils
'node_modules/@layerzerolabs/toolbox-foundry/lib',
'node_modules',
]

remappings = [
'@layerzerolabs/=node_modules/@layerzerolabs',
# Due to a misconfiguration of solidity-bytes-utils, an outdated version
# of forge-std is being dragged in
#
# To remedy this, we'll remap the ds-test and forge-std imports to ou own versions
'ds-test/=node_modules/@layerzerolabs/toolbox-foundry/lib/ds-test',
'forge-std/=node_modules/@layerzerolabs/toolbox-foundry/lib/forge-std',
'@layerzerolabs/=node_modules/@layerzerolabs/',
'@openzeppelin/=node_modules/@openzeppelin/',
]
1 change: 1 addition & 0 deletions examples/oft/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@nomicfoundation/hardhat-ethers": "^3.0.5",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@openzeppelin/contracts": "^5.0.1",
"@openzeppelin/contracts-upgradeable": "^5.0.1",
"@rushstack/eslint-patch": "^1.7.0",
"@types/chai": "^4.3.11",
"@types/mocha": "^10.0.6",
Expand Down
160 changes: 160 additions & 0 deletions examples/oft/test/foundry/MyOFT.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

// Mock imports
import { OFTMock } from "../mocks/OFTMock.sol";
import { ERC20Mock } from "../mocks/ERC20Mock.sol";
import { OFTComposerMock } from "../mocks/OFTComposerMock.sol";

// OApp imports
import { IOAppOptionsType3, EnforcedOptionParam } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/libs/OAppOptionsType3.sol";
import { OptionsBuilder } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/libs/OptionsBuilder.sol";

// OFT imports
import { IOFT, SendParam, OFTReceipt } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/interfaces/IOFT.sol";
import { MessagingFee, MessagingReceipt } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFTCore.sol";
import { OFTMsgCodec } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/libs/OFTMsgCodec.sol";
import { OFTComposeMsgCodec } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/libs/OFTComposeMsgCodec.sol";

// OZ imports
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

// Forge imports
import "forge-std/console.sol";

// DevTools imports
import { TestHelperOz5 } from "@layerzerolabs/test-devtools-evm-foundry/contracts/TestHelperOz5.sol";

contract MyOFTTest is TestHelperOz5 {
using OptionsBuilder for bytes;

uint32 aEid = 1;
uint32 bEid = 2;

OFTMock aOFT;
OFTMock bOFT;

address public userA = address(0x1);
address public userB = address(0x2);
uint256 public initialBalance = 100 ether;

function setUp() public virtual override {
vm.deal(userA, 1000 ether);
vm.deal(userB, 1000 ether);

super.setUp();
setUpEndpoints(2, LibraryType.UltraLightNode);

aOFT = OFTMock(
_deployOApp(type(OFTMock).creationCode, abi.encode("aOFT", "aOFT", address(endpoints[aEid]), address(this)))
);

bOFT = OFTMock(
_deployOApp(type(OFTMock).creationCode, abi.encode("bOFT", "bOFT", address(endpoints[bEid]), address(this)))
);

// config and wire the ofts
address[] memory ofts = new address[](2);
ofts[0] = address(aOFT);
ofts[1] = address(bOFT);
this.wireOApps(ofts);

// mint tokens
aOFT.mint(userA, initialBalance);
bOFT.mint(userB, initialBalance);
}

function test_constructor() public {
assertEq(aOFT.owner(), address(this));
assertEq(bOFT.owner(), address(this));

assertEq(aOFT.balanceOf(userA), initialBalance);
assertEq(bOFT.balanceOf(userB), initialBalance);

assertEq(aOFT.token(), address(aOFT));
assertEq(bOFT.token(), address(bOFT));
}

function test_send_oft() public {
uint256 tokensToSend = 1 ether;
bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200000, 0);
SendParam memory sendParam = SendParam(
bEid,
addressToBytes32(userB),
tokensToSend,
tokensToSend,
options,
"",
""
);
MessagingFee memory fee = aOFT.quoteSend(sendParam, false);

assertEq(aOFT.balanceOf(userA), initialBalance);
assertEq(bOFT.balanceOf(userB), initialBalance);

vm.prank(userA);
aOFT.send{ value: fee.nativeFee }(sendParam, fee, payable(address(this)));
verifyPackets(bEid, addressToBytes32(address(bOFT)));

assertEq(aOFT.balanceOf(userA), initialBalance - tokensToSend);
assertEq(bOFT.balanceOf(userB), initialBalance + tokensToSend);
}

function test_send_oft_compose_msg() public {
uint256 tokensToSend = 1 ether;

OFTComposerMock composer = new OFTComposerMock();

bytes memory options = OptionsBuilder
.newOptions()
.addExecutorLzReceiveOption(200000, 0)
.addExecutorLzComposeOption(0, 500000, 0);
bytes memory composeMsg = hex"1234";
SendParam memory sendParam = SendParam(
bEid,
addressToBytes32(address(composer)),
tokensToSend,
tokensToSend,
options,
composeMsg,
""
);
MessagingFee memory fee = aOFT.quoteSend(sendParam, false);

assertEq(aOFT.balanceOf(userA), initialBalance);
assertEq(bOFT.balanceOf(address(composer)), 0);

vm.prank(userA);
(MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) = aOFT.send{ value: fee.nativeFee }(
sendParam,
fee,
payable(address(this))
);
verifyPackets(bEid, addressToBytes32(address(bOFT)));

// lzCompose params
uint32 dstEid_ = bEid;
address from_ = address(bOFT);
bytes memory options_ = options;
bytes32 guid_ = msgReceipt.guid;
address to_ = address(composer);
bytes memory composerMsg_ = OFTComposeMsgCodec.encode(
msgReceipt.nonce,
aEid,
oftReceipt.amountReceivedLD,
abi.encodePacked(addressToBytes32(userA), composeMsg)
);
this.lzCompose(dstEid_, from_, options_, guid_, to_, composerMsg_);

assertEq(aOFT.balanceOf(userA), initialBalance - tokensToSend);
assertEq(bOFT.balanceOf(address(composer)), tokensToSend);

assertEq(composer.from(), from_);
assertEq(composer.guid(), guid_);
assertEq(composer.message(), composerMsg_);
assertEq(composer.executor(), address(this));
assertEq(composer.extraData(), composerMsg_); // default to setting the extraData to the message as well to test
}

// TODO import the rest of oft tests?
}
12 changes: 12 additions & 0 deletions examples/oft/test/mocks/ERC20Mock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract ERC20Mock is ERC20 {
constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {}

function mint(address _to, uint256 _amount) public {
_mint(_to, _amount);
}
}
27 changes: 27 additions & 0 deletions examples/oft/test/mocks/OFTComposerMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import { IOAppComposer } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/interfaces/IOAppComposer.sol";

contract OFTComposerMock is IOAppComposer {
// default empty values for testing a lzCompose received message
address public from;
bytes32 public guid;
bytes public message;
address public executor;
bytes public extraData;

function lzCompose(
address _from,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata /*_extraData*/
) external payable {
from = _from;
guid = _guid;
message = _message;
executor = _executor;
extraData = _message;
}
}
59 changes: 59 additions & 0 deletions examples/oft/test/mocks/OFTMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { OFT } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFT.sol";
import { SendParam } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFTCore.sol";

contract OFTMock is OFT {
constructor(
string memory _name,
string memory _symbol,
address _lzEndpoint,
address _delegate
) Ownable(_delegate) OFT(_name, _symbol, _lzEndpoint, _delegate) {}

function mint(address _to, uint256 _amount) public {
_mint(_to, _amount);
}

// @dev expose internal functions for testing purposes
function debit(
uint256 _amountToSendLD,
uint256 _minAmountToCreditLD,
uint32 _dstEid
) public returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
return _debit(_amountToSendLD, _minAmountToCreditLD, _dstEid);
}

function debitView(
uint256 _amountToSendLD,
uint256 _minAmountToCreditLD,
uint32 _dstEid
) public view returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
return _debitView(_amountToSendLD, _minAmountToCreditLD, _dstEid);
}

function removeDust(uint256 _amountLD) public view returns (uint256 amountLD) {
return _removeDust(_amountLD);
}

function toLD(uint64 _amountSD) public view returns (uint256 amountLD) {
return _toLD(_amountSD);
}

function toSD(uint256 _amountLD) public view returns (uint64 amountSD) {
return _toSD(_amountLD);
}

function credit(address _to, uint256 _amountToCreditLD, uint32 _srcEid) public returns (uint256 amountReceivedLD) {
return _credit(_to, _amountToCreditLD, _srcEid);
}

function buildMsgAndOptions(
SendParam calldata _sendParam,
uint256 _amountToCreditLD
) public view returns (bytes memory message, bytes memory options) {
return _buildMsgAndOptions(_sendParam, _amountToCreditLD);
}
}
Loading
Loading