Skip to content

Commit

Permalink
🗞️ TestHelper for OpenZeppelin v5 (#442)
Browse files Browse the repository at this point in the history
Co-authored-by: lz.wΔrlock() <[email protected]>
  • Loading branch information
janjakubnanista and TRileySchwarz authored Mar 1, 2024
1 parent fe35b1f commit 93f4ec5
Show file tree
Hide file tree
Showing 24 changed files with 2,481 additions and 96 deletions.
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

0 comments on commit 93f4ec5

Please sign in to comment.