Compare commits

...

1 Commits

Author SHA1 Message Date
abls
139330f58e add mtx fees as two sets of fee fields but with only one fee token 2022-11-28 09:52:00 -08:00
3 changed files with 139 additions and 5 deletions

View File

@@ -92,7 +92,10 @@ contract MetaTransactionsFeature is
"bytes callData,"
"uint256 value,"
"address feeToken,"
"uint256 feeAmount"
"uint256 feeAmountOne,"
"address feeRecipientOne,"
"uint256 feeAmountTwo,"
"address feeRecipientTwo"
")"
);
@@ -219,7 +222,10 @@ contract MetaTransactionsFeature is
keccak256(mtx.callData),
mtx.value,
mtx.feeToken,
mtx.feeAmount
mtx.feeAmountOne,
mtx.feeRecipientOne,
mtx.feeAmountTwo,
mtx.feeRecipientTwo
)
)
);
@@ -238,8 +244,11 @@ contract MetaTransactionsFeature is
LibMetaTransactionsStorage.getStorage().mtxHashToExecutedBlockNumber[state.hash] = block.number;
// Pay the fee to the sender.
if (state.mtx.feeAmount > 0) {
_transferERC20TokensFrom(state.mtx.feeToken, state.mtx.signer, state.sender, state.mtx.feeAmount);
if (state.mtx.feeAmountOne > 0) {
_transferERC20TokensFrom(state.mtx.feeToken, state.mtx.signer, state.mtx.feeRecipientOne, state.mtx.feeAmountOne);
}
if (state.mtx.feeAmountTwo > 0) {
_transferERC20TokensFrom(state.mtx.feeToken, state.mtx.signer, state.mtx.feeRecipientTwo, state.mtx.feeAmountTwo);
}
// Execute the call based on the selector.

View File

@@ -46,7 +46,13 @@ interface IMetaTransactionsFeature {
// ERC20 fee `signer` pays `sender`.
IERC20TokenV06 feeToken;
// ERC20 fee amount.
uint256 feeAmount;
uint256 feeAmountOne;
// ERC20 fee recipient.
address feeRecipientOne;
// ERC20 fee amount.
uint256 feeAmountTwo;
// ERC20 fee recipient.
address feeRecipientTwo;
}
/// @dev Emitted whenever a meta-transaction is executed via

View File

@@ -0,0 +1,119 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "forge-std/Script.sol";
import "src/IZeroEx.sol";
import "src/features/MetaTransactionsFeature.sol";
import "src/features/interfaces/IMetaTransactionsFeature.sol";
import "src/features/libs/LibSignature.sol";
import "src/transformers/FillQuoteTransformer.sol";
import "src/transformers/PayTakerTransformer.sol";
contract MetaTxScript is Script {
IZeroEx private constant exchangeProxy = IZeroEx(0xDef1C0ded9bec7F1a1670819833240f027b25EfF);
IERC20TokenV06 private constant wethToken = IERC20TokenV06(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IERC20TokenV06 private constant usdcToken = IERC20TokenV06(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
uint256 private constant oneEth = 1e18;
address private constant ZERO_ADDRESS = 0x0000000000000000000000000000000000000000;
address private constant USER_ADDRESS = 0x6dc3a54FeAE57B65d185A7B159c5d3FA7fD7FD0F;
uint256 private constant USER_KEY = 0x1fc1630343b31e60b7a197a53149ca571ed9d9791e2833337bbd8110c30710ec;
uint32 private constant PAYTAKER_TFM_NONCE = 7;
uint32 private constant FILLQUOTE_TFM_NONCE = 25;
function mtxCall(bytes memory callData) private returns (bytes memory) {
IMetaTransactionsFeature.MetaTransactionData memory mtx = IMetaTransactionsFeature.MetaTransactionData({
signer: payable(USER_ADDRESS),
sender: ZERO_ADDRESS,
minGasPrice: 0,
maxGasPrice: 100000000000,
expirationTimeSeconds: block.timestamp + 600,
salt: 123,
callData: callData,
value: 0,
feeToken: wethToken,
feeAmountOne: oneEth,
feeRecipientOne: address(123),
feeAmountTwo: 0,
feeRecipientTwo: address(0)
});
bytes32 mtxHash = exchangeProxy.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(
exchangeProxy.executeMetaTransaction.selector,
mtx,
sig
);
}
function transformERC20Call() private pure returns (bytes memory) {
FillQuoteTransformer.OrderType[] memory fillSequence = new FillQuoteTransformer.OrderType[](1);
fillSequence[0] = FillQuoteTransformer.OrderType.Bridge;
FillQuoteTransformer.TransformData memory fillQuoteTransformData = FillQuoteTransformer.TransformData({
side: FillQuoteTransformer.Side.Sell,
sellToken: wethToken,
buyToken: usdcToken,
bridgeOrders: new IBridgeAdapter.BridgeOrder[](0),
limitOrders: new FillQuoteTransformer.LimitOrderInfo[](0),
rfqOrders: new FillQuoteTransformer.RfqOrderInfo[](0),
fillSequence: new FillQuoteTransformer.OrderType[](0),
fillAmount: 0,
refundReceiver: address(0),
otcOrders: new FillQuoteTransformer.OtcOrderInfo[](0)
});
IERC20TokenV06[] memory payTakerTokens = new IERC20TokenV06[](1);
payTakerTokens[0] = wethToken;
PayTakerTransformer.TransformData memory payTakerTransformData = PayTakerTransformer.TransformData(
payTakerTokens,
new uint256[](0)
);
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](2);
transformations[0] = ITransformERC20Feature.Transformation(
FILLQUOTE_TFM_NONCE,
abi.encode(fillQuoteTransformData)
);
transformations[1] = ITransformERC20Feature.Transformation(
PAYTAKER_TFM_NONCE,
abi.encode(payTakerTransformData)
);
return abi.encodeWithSelector(
exchangeProxy.transformERC20.selector,
wethToken,
usdcToken,
0,
0,
transformations
);
}
function deploy() private {
address mtxFeature = address(new MetaTransactionsFeature(address(exchangeProxy)));
address owner = exchangeProxy.owner();
vm.prank(owner);
exchangeProxy.migrate(mtxFeature, abi.encodeWithSignature("migrate()"), owner);
}
function run() public {
deploy();
bytes memory transformCalldata = transformERC20Call();
bytes memory mtxCalldata = mtxCall(transformCalldata);
vm.prank(ZERO_ADDRESS);
wethToken.transfer(USER_ADDRESS, oneEth);
vm.prank(USER_ADDRESS);
wethToken.approve(address(exchangeProxy), oneEth);
vm.prank(USER_ADDRESS);
(address(exchangeProxy).call(mtxCalldata));
}
}