Compare commits

...

23 Commits

Author SHA1 Message Date
Patrick Dowell
b89dc44889 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:05:32 -08:00
Patrick Dowell
c958e34b7c Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:05:21 -08:00
Patrick Dowell
b6d61b7eb0 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:05:10 -08:00
Patrick Dowell
ece874dffe Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:04:57 -08:00
Patrick Dowell
f35bdc97b7 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:04:33 -08:00
Patrick Dowell
47e493d190 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:04:13 -08:00
Patrick Dowell
c3a0a64471 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:04:00 -08:00
Patrick Dowell
5e5ce13b97 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:03:49 -08:00
Patrick Dowell
7630bc8c54 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:03:32 -08:00
Patrick Dowell
1665028c8c Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:03:20 -08:00
Patrick Dowell
4545b6daa2 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:02:55 -08:00
Patrick Dowell
880ca94a12 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:02:40 -08:00
Patrick Dowell
8dd013299b Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:02:15 -08:00
Patrick Dowell
da3e300fed Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:02:07 -08:00
Patrick Dowell
bf7fc8c9f5 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:01:56 -08:00
Patrick Dowell
19dd1e2b88 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:01:41 -08:00
Patrick Dowell
af65ae3abd Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:01:36 -08:00
Patrick Dowell
991b966413 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:01:23 -08:00
Patrick Dowell
44ead87abc Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:01:15 -08:00
Patrick Dowell
68260c47e5 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:01:07 -08:00
Patrick Dowell
1109fe7d25 Update contracts/zero-ex/tests/MetaTransactionTest.t.sol
Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
2023-02-05 23:00:55 -08:00
Patrick Dowell
01fcbf0ac4 Adding the rest of the migrated tests 2023-02-01 01:23:25 -08:00
Patrick Dowell
911cc8609c Initial MTX Test Migration to forge 2023-01-31 17:08:29 -08:00
2 changed files with 454 additions and 0 deletions

View File

@@ -31,6 +31,8 @@ import "./interfaces/INativeOrdersFeature.sol";
import "./interfaces/ITransformERC20Feature.sol";
import "./libs/LibSignature.sol";
import "forge-std/console.sol";
/// @dev MetaTransactions feature.
contract MetaTransactionsFeature is
IFeature,
@@ -253,24 +255,28 @@ contract MetaTransactionsFeature is
/// @dev Validate that a meta-transaction is executable.
function _validateMetaTransaction(ExecuteState memory state) private view {
console.log("Must be from required sender, if set");
// Must be from the required sender, if set.
if (state.mtx.sender != address(0) && state.mtx.sender != state.sender) {
LibMetaTransactionsRichErrors
.MetaTransactionWrongSenderError(state.hash, state.sender, state.mtx.sender)
.rrevert();
}
console.log("Must not be expired");
// Must not be expired.
if (state.mtx.expirationTimeSeconds <= block.timestamp) {
LibMetaTransactionsRichErrors
.MetaTransactionExpiredError(state.hash, block.timestamp, state.mtx.expirationTimeSeconds)
.rrevert();
}
console.log("Must have a valid gas price");
// Must have a valid gas price.
if (state.mtx.minGasPrice > tx.gasprice || state.mtx.maxGasPrice < tx.gasprice) {
LibMetaTransactionsRichErrors
.MetaTransactionGasPriceError(state.hash, tx.gasprice, state.mtx.minGasPrice, state.mtx.maxGasPrice)
.rrevert();
}
console.log("Must have enough ETH");
// Must have enough ETH.
state.selfBalance = address(this).balance;
if (state.mtx.value > state.selfBalance) {
@@ -291,6 +297,7 @@ contract MetaTransactionsFeature is
)
.rrevert();
}
console.log("Must not have already been executed");
// Transaction must not have been already executed.
state.executedBlockNumber = LibMetaTransactionsStorage.getStorage().mtxHashToExecutedBlockNumber[state.hash];
if (state.executedBlockNumber != 0) {

View File

@@ -0,0 +1,447 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2023 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "./utils/BaseTest.sol";
import "forge-std/Test.sol";
import "./utils/DeployZeroEx.sol";
import "../contracts/src/features/MetaTransactionsFeature.sol";
import "../contracts/src/features/interfaces/IMetaTransactionsFeature.sol";
import "../contracts/test/TestMintTokenERC20Transformer.sol";
import "../contracts/src/features/libs/LibSignature.sol";
import "src/features/libs/LibNativeOrder.sol";
import "../contracts/test/tokens/TestMintableERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
contract MetaTransactionTest is BaseTest {
DeployZeroEx.ZeroExDeployed zeroExDeployed;
address private constant ZERO_ADDRESS = 0x0000000000000000000000000000000000000000;
address private constant USER_ADDRESS = 0x6dc3a54FeAE57B65d185A7B159c5d3FA7fD7FD0F;
uint256 private constant USER_KEY = 0x1fc1630343b31e60b7a197a53149ca571ed9d9791e2833337bbd8110c30710ec;
IEtherTokenV06 private wethToken;
IERC20TokenV06 private usdcToken;
IERC20TokenV06 private zrxToken;
uint256 private constant oneEth = 1e18;
address private signerAddress;
uint256 private signerKey;
uint256 private transformerNonce;
function setUp() public {
(signerAddress, signerKey) = getSigner();
zeroExDeployed = new DeployZeroEx().deployZeroEx();
wethToken = zeroExDeployed.weth;
usdcToken = IERC20TokenV06(address(new TestMintableERC20Token()));
zrxToken = IERC20TokenV06(address(new TestMintableERC20Token()));
transformerNonce = zeroExDeployed.transformerDeployer.nonce();
vm.prank(zeroExDeployed.transformerDeployer.authorities(0));
zeroExDeployed.transformerDeployer.deploy(type(TestMintTokenERC20Transformer).creationCode);
vm.deal(address(this), 10e18);
vm.deal(USER_ADDRESS, 10e18);
vm.deal(signerAddress, 10e18);
}
function _getSigner() private returns (address, uint) {
string memory mnemonic = "test test test test test test test test test test test junk";
uint256 privateKey = vm.deriveKey(mnemonic, 0);
vm.label(vm.addr(privateKey), "zeroEx/MarketMaker");
return (vm.addr(privateKey), privateKey);
}
function _makeTestRfqOrder() private returns (bytes memory callData) {
LibNativeOrder.RfqOrder memory order = LibNativeOrder.RfqOrder({
makerToken: wethToken,
takerToken: usdcToken,
makerAmount: 1e18,
takerAmount: 1e18,
maker: signerAddress,
taker: ZERO_ADDRESS,
txOrigin: tx.origin,
pool: 0x0000000000000000000000000000000000000000000000000000000000000000,
expiry: uint64(block.timestamp + 60),
salt: 123
});
mintTo(address(order.makerToken), order.maker, order.makerAmount);
vm.prank(order.maker);
order.makerToken.approve(address(zeroExDeployed.zeroEx), order.makerAmount);
mintTo(address(order.takerToken), USER_ADDRESS, order.takerAmount);
vm.prank(USER_ADDRESS);
order.takerToken.approve(address(zeroExDeployed.zeroEx), order.takerAmount);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(signerKey, zeroExDeployed.features.nativeOrdersFeature.getRfqOrderHash(order));
LibSignature.Signature memory sig = LibSignature.Signature(LibSignature.SignatureType.EIP712, v, r, s);
return abi.encodeWithSelector(
INativeOrdersFeature.fillRfqOrder.selector, // ??
order, // RFQOrder
sig, // Order Signature
1e18 // Fill Amount
);
}
function _makeTestLimitOrder() private returns (bytes memory callData) {
LibNativeOrder.LimitOrder memory order = LibNativeOrder.LimitOrder({
makerToken: wethToken,
takerToken: usdcToken,
makerAmount: 1e18,
takerAmount: 1e18,
maker: signerAddress,
taker: ZERO_ADDRESS,
sender: ZERO_ADDRESS,
takerTokenFeeAmount: 0,
feeRecipient: address(this),
pool: 0x0000000000000000000000000000000000000000000000000000000000000000,
expiry: uint64(block.timestamp + 60),
salt: 123
});
mintTo(address(order.makerToken), order.maker, order.makerAmount);
vm.prank(order.maker);
order.makerToken.approve(address(zeroExDeployed.zeroEx), order.makerAmount);
mintTo(address(order.takerToken), USER_ADDRESS, order.takerAmount);
vm.prank(USER_ADDRESS);
order.takerToken.approve(address(zeroExDeployed.zeroEx), order.takerAmount);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(signerKey, zeroExDeployed.features.nativeOrdersFeature.getLimitOrderHash(order));
LibSignature.Signature memory sig = LibSignature.Signature(LibSignature.SignatureType.EIP712, v, r, s);
return abi.encodeWithSelector(
INativeOrdersFeature.fillLimitOrder.selector, // ??
order, // LimitOrder
sig, // Order Signature
1e18 // Fill Amount
);
}
function _mintTo(address token, address recipient, uint256 amount) private {
if (token == address(wethToken)) {
//vm.prank(recipient);
IEtherTokenV06(token).deposit{value: amount}();
WETH9V06(payable(token)).transfer(recipient, amount);
} else {
TestMintableERC20Token(token).mint(recipient, amount);
}
}
function _getMetaTransaction(bytes memory callData) private view returns (IMetaTransactionsFeature.MetaTransactionData memory) {
IMetaTransactionsFeature.MetaTransactionData memory mtx = IMetaTransactionsFeature.MetaTransactionData({
signer: payable(USER_ADDRESS),
sender: address(this),
minGasPrice: 0,
maxGasPrice: 100000000000,
expirationTimeSeconds: block.timestamp + 60,
salt: 123,
callData: callData,
value: 0,
feeToken: wethToken,
feeAmount: 1
});
return mtx;
}
function _transformERC20Call() private returns (bytes memory) {
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](1);
transformations[0] = ITransformERC20Feature.Transformation(
uint32(transformerNonce),
abi.encode(address(usdcToken), address(zrxToken), 0, oneEth, 0)
);
mintTo(address(usdcToken), USER_ADDRESS, oneEth);
vm.prank(USER_ADDRESS);
usdcToken.approve(address(zeroExDeployed.zeroEx), oneEth);
return abi.encodeWithSelector(
zeroExDeployed.zeroEx.transformERC20.selector, // 0x415565b0
usdcToken,
zrxToken,
oneEth,
oneEth,
transformations
);
}
function _badSelectorTransformERC20Call() private returns (bytes memory) {
return abi.encodeWithSelector(
ITransformERC20Feature.createTransformWallet.selector
);
}
function _badTokenTransformERC20Call() private returns (bytes memory) {
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](1);
transformations[0] = ITransformERC20Feature.Transformation(
uint32(transformerNonce),
abi.encode(address(usdcToken), address(wethToken), 0, oneEth, 0)
);
mintTo(address(usdcToken), USER_ADDRESS, oneEth);
vm.prank(USER_ADDRESS);
usdcToken.approve(address(zeroExDeployed.zeroEx), oneEth);
return abi.encodeWithSelector(
zeroExDeployed.zeroEx.transformERC20.selector, // 0x415565b0
usdcToken,
wethToken,
oneEth,
oneEth,
transformations
);
}
function _mtxCall(IMetaTransactionsFeature.MetaTransactionData memory mtx) private returns (bytes memory) {
// Mint fee to signer and approve
if (mtx.feeAmount > 0) {
mintTo(address(mtx.feeToken), mtx.signer, mtx.feeAmount);
vm.prank(mtx.signer);
mtx.feeToken.approve(address(zeroExDeployed.zeroEx), oneEth);
}
bytes32 mtxHash = zeroExDeployed.features.metaTransactionsFeature.getMetaTransactionHash(mtx);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(USER_KEY, mtxHash);
LibSignature.Signature memory sig = LibSignature.Signature(LibSignature.SignatureType.EIP712, v, r, s);
return abi.encodeWithSelector(
zeroExDeployed.zeroEx.executeMetaTransaction.selector, // 0x3d61ed3e
mtx,
sig
);
}
function test_createHash() external {
bytes memory transformCallData = transformERC20Call();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(transformCallData);
//mtxData.signer = address(0);
bytes32 mtxHash = zeroExDeployed.features.metaTransactionsFeature.getMetaTransactionHash(mtxData);
assertTrue(mtxHash != bytes32(0));
}
function test_transformERC20() external {
bytes memory transformCallData = transformERC20Call();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(transformCallData);
bytes memory theCallData = mtxCall(mtxData);
assertEq(usdcToken.balanceOf(USER_ADDRESS), oneEth);
(bool success, ) = address(zeroExDeployed.zeroEx).call{ value: 0}(theCallData);
assertTrue(success);
assertEq(zrxToken.balanceOf(USER_ADDRESS), oneEth);
assertEq(usdcToken.balanceOf(USER_ADDRESS), 0);
assertEq(wethToken.balanceOf(address(this)), 1);
}
function test_rfqOrder() external {
bytes memory callData = makeTestRfqOrder();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(callData);
bytes memory rfqCallData = mtxCall(mtxData);
(bool success, ) = address(zeroExDeployed.zeroEx).call{ value: 0 }(rfqCallData);
assertTrue(success);
assertEq(wethToken.balanceOf(signerAddress), 0);
assertEq(wethToken.balanceOf(USER_ADDRESS), 1e18);
assertEq(usdcToken.balanceOf(USER_ADDRESS), 0);
assertEq(usdcToken.balanceOf(signerAddress), 1e18);
assertEq(wethToken.balanceOf(address(this)), 1);
// TODO: check event log for TestMetaTransactionsNativeOrdersFeatureEvents.FillLimitOrderCalled?
}
function test_fillLimitOrder() external {
bytes memory callData = makeTestLimitOrder();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(callData);
bytes memory limitCallData = mtxCall(mtxData);
(bool success, ) = address(zeroExDeployed.zeroEx).call{ value: 0 }(limitCallData);
assertTrue(success);
assertEq(wethToken.balanceOf(signerAddress), 0);
assertEq(wethToken.balanceOf(USER_ADDRESS), 1e18);
assertEq(usdcToken.balanceOf(USER_ADDRESS), 0);
assertEq(usdcToken.balanceOf(signerAddress), 1e18);
}
function test_transformERC20WithAnySender() external {
bytes memory transformCallData = transformERC20Call();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(transformCallData);
mtxData.sender = ZERO_ADDRESS;
bytes memory theCallData = mtxCall(mtxData);
assertEq(usdcToken.balanceOf(USER_ADDRESS), oneEth);
(bool success, ) = address(zeroExDeployed.zeroEx).call{ value: 0}(theCallData);
assertTrue(success);
assertEq(zrxToken.balanceOf(USER_ADDRESS), oneEth);
assertEq(usdcToken.balanceOf(USER_ADDRESS), 0);
assertEq(wethToken.balanceOf(address(this)), 1);
}
function test_transformERC20WithoutFee() external {
bytes memory transformCallData = transformERC20Call();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(transformCallData);
mtxData.feeAmount = 0;
bytes memory theCallData = mtxCall(mtxData);
assertEq(usdcToken.balanceOf(USER_ADDRESS), oneEth);
(bool success, ) = address(zeroExDeployed.zeroEx).call{ value: 0}(theCallData);
assertTrue(success);
assertEq(zrxToken.balanceOf(USER_ADDRESS), oneEth);
assertEq(usdcToken.balanceOf(USER_ADDRESS), 0);
assertEq(wethToken.balanceOf(address(this)), 0); // no fee paid out
}
function test_transformERC20TranslatedCallFail() external {
bytes memory transformCallData = badTokenTransformERC20Call();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(transformCallData);
bytes memory theCallData = mtxCall(mtxData);
(bool success, ) = address(zeroExDeployed.zeroEx).call{ value: 0}(theCallData);
assertFalse(success);
}
function test_transformERC20UnsupportedFunction() external {
bytes memory transformCallData = badSelectorTransformERC20Call();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(transformCallData);
bytes memory theCallData = mtxCall(mtxData);
(bool success, ) = address(zeroExDeployed.zeroEx).call{ value: 0}(theCallData);
assertFalse(success);
}
function test_transformERC20CantExecuteTwice() external {
bytes memory callData = makeTestRfqOrder();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(callData);
bytes memory theCallData1 = mtxCall(mtxData);
(bool success, ) = address(zeroExDeployed.zeroEx).call{ value: 0}(theCallData1);
assertTrue(success);
bytes memory theCallData2 = mtxCall(mtxData);
(success, ) = address(zeroExDeployed.zeroEx).call{ value: 0}(theCallData2);
assertFalse(success);
}
function test_metaTxnFailsNotEnoughEth() external {
bytes memory callData = makeTestRfqOrder();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(callData);
mtxData.value = 1;
bytes memory theCallData = mtxCall(mtxData);
(bool success, ) = address(zeroExDeployed.zeroEx).call{ value: 0}(theCallData);
assertFalse(success);
}
/*******
* Unclear whether we need to port these, as MetaTransactionDataV2 might deprecate these fields
*******
function test_metaTxnFailsGasPriceTooLow() public {
}
function test_metaTxnFailsGasPriceTooHigh() public {
}
*******/
function test_metaTxnFailsIfExpired() external {
bytes memory callData = makeTestRfqOrder();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(callData);
mtxData.expirationTimeSeconds = block.timestamp - 1;
bytes memory theCallData = mtxCall(mtxData);
(bool success, ) = address(zeroExDeployed.zeroEx).call{ value: 0}(theCallData);
assertFalse(success);
}
function test_metaTxnFailsIfWrongSender() external {
bytes memory transformCallData = transformERC20Call();
IMetaTransactionsFeature.MetaTransactionData memory mtxData = getRandomMetaTransaction(transformCallData);
mtxData.sender = USER_ADDRESS;
bytes memory theCallData = mtxCall(mtxData);
assertEq(usdcToken.balanceOf(USER_ADDRESS), oneEth);
(bool success, ) = address(zeroExDeployed.zeroEx).call{ value: 0}(theCallData);
assertFalse(success);
}
function test_metaTxnFailsWrongSignature() public {
}
/***********
* These functions require TestMetaTransactionsTransformERC20Feature.sol
***********
function test_metaTxnCantReenterExecuteMetaTransaction() public {
}
function test_metaTxnCantReenterBatchExecuteMetaTransaction() public {
}
function test_metaTxnCantReduceInitialEthBalance() public {
}
*********/
}