Skip to content

Commit

Permalink
WIP: Working TestHelper.sol in OZ5 migration
Browse files Browse the repository at this point in the history
  • Loading branch information
TRileySchwarz committed Feb 17, 2024
1 parent 9c3f395 commit 5e8dc60
Show file tree
Hide file tree
Showing 18 changed files with 2,195 additions and 59 deletions.
7 changes: 2 additions & 5 deletions examples/oft/contracts/MyOFT.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;

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

contract MyOFT is OFT {
Expand All @@ -10,8 +10,5 @@ contract MyOFT is OFT {
string memory _symbol,
address _lzEndpoint,
address _delegate
)
// ) OFT(_name, _symbol, _lzEndpoint, _delegate) Ownable(_delegate) {}
OFT(_name, _symbol, _lzEndpoint, _delegate)
{}
) OFT(_name, _symbol, _lzEndpoint, _delegate) Ownable(_delegate) {}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;

import { MyOFT } from "../contracts/MyOFT.sol";
import { MyOFT } from "../MyOFT.sol";

// @dev WARNING: This is for testing purposes only
contract MyOFTMock is MyOFT {
Expand Down
4 changes: 2 additions & 2 deletions examples/oft/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
"@layerzerolabs/toolbox-hardhat": "~0.1.6",
"@nomicfoundation/hardhat-ethers": "^3.0.5",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@openzeppelin/contracts": "^4.8.1",
"@openzeppelin/contracts-upgradeable": "^4.8.1",
"@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
3 changes: 2 additions & 1 deletion examples/oft/test/mocks/OFTMock.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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";

Expand All @@ -10,7 +11,7 @@ contract OFTMock is OFT {
string memory _symbol,
address _lzEndpoint,
address _delegate
) OFT(_name, _symbol, _lzEndpoint, _delegate) {}
) Ownable(_delegate) OFT(_name, _symbol, _lzEndpoint, _delegate) {}

function mint(address _to, uint256 _amount) public {
_mint(_to, _amount);
Expand Down
43 changes: 24 additions & 19 deletions packages/test-devtools-evm-foundry/contracts/TestHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,40 @@

pragma solidity ^0.8.18;

// Forge
import { Test } from "forge-std/Test.sol";
import "forge-std/console.sol";

// Oz
import { DoubleEndedQueue } from "@openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol";

// Msg Lib
import { UlnConfig, SetDefaultUlnConfigParam } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/UlnBase.sol";
import { SetDefaultExecutorConfigParam, ExecutorConfig } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/SendLibBase.sol";
import { ReceiveUln302 } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/uln302/ReceiveUln302.sol";
import { IDVN } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/interfaces/IDVN.sol";
import { DVN, ExecuteParam } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/dvn/DVN.sol";
import { DVNFeeLib } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/dvn/DVNFeeLib.sol";
import { IExecutor } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/interfaces/IExecutor.sol";
import { Executor } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/Executor.sol";
import { PriceFeed } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/PriceFeed.sol";
import { ILayerZeroPriceFeed } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/interfaces/ILayerZeroPriceFeed.sol";
import { IReceiveUlnE2 } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/interfaces/IReceiveUlnE2.sol";
import { ReceiveUln302 } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/uln302/ReceiveUln302.sol";

// Protocol
import { IMessageLib } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLib.sol";
import { EndpointV2 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/EndpointV2.sol";
import { ExecutorOptions } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/ExecutorOptions.sol";
import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
import { Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";

// @dev oz4/5 breaking change...
import { ReceiveUln302Mock as ReceiveUln302, IReceiveUlnE2 } from "./mocks/ReceiveUln302Mock.sol";
import { DVNMock as DVN, ExecuteParam, IDVN } from "./mocks/DVNMock.sol";
import { DVNFeeLibMock as DVNFeeLib } from "./mocks/DVNFeeLibMock.sol";
import { ExecutorMock as Executor, IExecutor } from "./mocks/ExecutorMock.sol";
import { PriceFeedMock as PriceFeed, ILayerZeroPriceFeed } from "./mocks/PriceFeedMock.sol";
import { EndpointV2Mock as EndpointV2 } from "./mocks//EndpointV2Mock.sol";

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

// Misc. Mocks
import { OptionsHelper } from "./OptionsHelper.sol";
import { SendUln302Mock as SendUln302 } from "./mocks/SendUln302Mock.sol";
import { SimpleMessageLibMock } from "./mocks/SimpleMessageLibMock.sol";
import "./mocks/ExecutorFeeLibMock.sol";
import "forge-std/console.sol";
import { ExecutorFeeLibMock as ExecutorFeeLib } from "./mocks/ExecutorFeeLibMock.sol";

/**
* @title TestHelper
Expand Down Expand Up @@ -94,8 +99,8 @@ contract TestHelper is Test, OptionsHelper {
address[] memory signers = new address[](1);
signers[0] = vm.addr(1);

PriceFeed priceFeed = new PriceFeed();
priceFeed.initialize(address(this));
// @dev oz4/5 breaking change... constructor init
PriceFeed priceFeed = new PriceFeed(address(this));

for (uint8 i = 0; i < _endpointNum; i++) {
if (_libraryType == LibraryType.UltraLightNode) {
Expand All @@ -112,7 +117,7 @@ contract TestHelper is Test, OptionsHelper {
receiveLibs[i] = address(receiveUln);
}

Executor executor = new Executor();
Executor executor;
DVN dvn;
{
address[] memory admins = new address[](1);
Expand All @@ -121,16 +126,16 @@ contract TestHelper is Test, OptionsHelper {
address[] memory messageLibs = new address[](2);
messageLibs[0] = address(sendUln);
messageLibs[1] = address(receiveUln);

executor.initialize(
executor = new Executor(
endpointAddr,
address(0x0),
messageLibs,
address(priceFeed),
address(this),
admins
);
ExecutorFeeLib executorLib = new ExecutorFeeLibMock();

ExecutorFeeLib executorLib = new ExecutorFeeLib();
executor.setWorkerFeeLib(address(executorLib));

dvn = new DVN(i + 1, messageLibs, address(priceFeed), signers, 1, admins);
Expand Down
147 changes: 147 additions & 0 deletions packages/test-devtools-evm-foundry/contracts/mocks/DVNFeeLibMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// SPDX-License-Identifier: LZBL-1.2

pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Transfer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";

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

import { IDVN } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/interfaces/IDVN.sol";
import { IDVNFeeLib } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/interfaces/IDVNFeeLib.sol";
import { DVNOptions } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/libs/DVNOptions.sol";

contract DVNFeeLibMock is Ownable, IDVNFeeLib {
using DVNOptions for bytes;

uint16 internal constant EXECUTE_FIXED_BYTES = 68; // encoded: funcSigHash + params -> 4 + (32 * 2)
uint16 internal constant SIGNATURE_RAW_BYTES = 65; // not encoded
// callData(updateHash) = 132 (4 + 32 * 4), padded to 32 = 160 and encoded as bytes with an 64 byte overhead = 224
uint16 internal constant UPDATE_HASH_BYTES = 224;

uint256 private immutable nativeDecimalsRate;

// @dev oz4/5 breaking change... Ownable constructor
constructor(uint256 _nativeDecimalsRate) Ownable(msg.sender) {
nativeDecimalsRate = _nativeDecimalsRate;
}

// ================================ OnlyOwner ================================
function withdrawToken(address _token, address _to, uint256 _amount) external onlyOwner {
// transfers native if _token is address(0x0)
Transfer.nativeOrToken(_token, _to, _amount);
}

// ========================= External =========================
/// @dev get fee function that can change state. e.g. paying priceFeed
/// @param _params fee params
/// @param _dstConfig dst config
/// @param //_options options
function getFeeOnSend(
FeeParams calldata _params,
IDVN.DstConfig calldata _dstConfig,
bytes calldata _options
) external payable returns (uint256) {
if (_dstConfig.gas == 0) revert DVN_EidNotSupported(_params.dstEid);

_decodeDVNOptions(_options); // todo: validate options

uint256 callDataSize = _getCallDataSize(_params.quorum);

// for future versions where priceFeed charges a fee
// uint256 priceFeedFee = ILayerZeroPriceFeed(_params.priceFeed).getFee(_params.dstEid, callDataSize, _dstConfig.gas);
// (uint256 fee, , , uint128 nativePriceUSD) = ILayerZeroPriceFeed(_params.priceFeed).estimateFeeOnSend{
// value: priceFeedFee
// }(_params.dstEid, callDataSize, _dstConfig.gas);

(uint256 fee, , , uint128 nativePriceUSD) = ILayerZeroPriceFeed(_params.priceFeed).estimateFeeOnSend(
_params.dstEid,
callDataSize,
_dstConfig.gas
);

return
_applyPremium(
fee,
_dstConfig.multiplierBps,
_params.defaultMultiplierBps,
_dstConfig.floorMarginUSD,
nativePriceUSD
);
}

// ========================= View =========================
/// @dev get fee view function
/// @param _params fee params
/// @param _dstConfig dst config
/// @param //_options options
function getFee(
FeeParams calldata _params,
IDVN.DstConfig calldata _dstConfig,
bytes calldata _options
) external view returns (uint256) {
if (_dstConfig.gas == 0) revert DVN_EidNotSupported(_params.dstEid);

_decodeDVNOptions(_options); // validate options

uint256 callDataSize = _getCallDataSize(_params.quorum);
(uint256 fee, , , uint128 nativePriceUSD) = ILayerZeroPriceFeed(_params.priceFeed).estimateFeeByEid(
_params.dstEid,
callDataSize,
_dstConfig.gas
);
return
_applyPremium(
fee,
_dstConfig.multiplierBps,
_params.defaultMultiplierBps,
_dstConfig.floorMarginUSD,
nativePriceUSD
);
}

// ========================= Internal =========================
function _getCallDataSize(uint256 _quorum) internal pure returns (uint256) {
uint256 totalSignatureBytes = _quorum * SIGNATURE_RAW_BYTES;
if (totalSignatureBytes % 32 != 0) {
totalSignatureBytes = totalSignatureBytes - (totalSignatureBytes % 32) + 32;
}
// getFee should charge on execute(updateHash)
// totalSignatureBytesPadded also has 64 overhead for bytes
return uint256(EXECUTE_FIXED_BYTES) + UPDATE_HASH_BYTES + totalSignatureBytes + 64;
}

function _applyPremium(
uint256 _fee,
uint16 _bps,
uint16 _defaultBps,
uint128 _marginUSD,
uint128 _nativePriceUSD
) internal view returns (uint256) {
uint16 multiplierBps = _bps == 0 ? _defaultBps : _bps;

uint256 feeWithMultiplier = (_fee * multiplierBps) / 10000;
if (_nativePriceUSD == 0 || _marginUSD == 0) {
return feeWithMultiplier;
}

uint256 feeWithFloorMargin = _fee + (_marginUSD * nativeDecimalsRate) / _nativePriceUSD;

return feeWithFloorMargin > feeWithMultiplier ? feeWithFloorMargin : feeWithMultiplier;
}

function _decodeDVNOptions(bytes calldata _options) internal pure returns (uint256) {
uint256 cursor;
while (cursor < _options.length) {
(uint8 optionType, , uint256 newCursor) = _options.nextDVNOption(cursor);
cursor = newCursor;
revert DVN_UnsupportedOptionType(optionType);
}
if (cursor != _options.length) revert DVNOptions.DVN_InvalidDVNOptions(cursor);

return 0; // todo: precrime fee model
}

// send funds here to pay for price feed directly
receive() external payable {}
}
Loading

0 comments on commit 5e8dc60

Please sign in to comment.