add multiplex TokenForEth functions to metatransactions

This commit is contained in:
abls 2023-02-20 12:36:19 -08:00
parent 90b826da61
commit 2507028612
2 changed files with 99 additions and 4 deletions

View File

@ -15,6 +15,7 @@
pragma solidity ^0.6.5; pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol"; import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
@ -92,6 +93,9 @@ contract MetaTransactionsFeature is
")" ")"
); );
/// @dev The WETH token contract.
IEtherTokenV06 private immutable WETH;
/// @dev Refunds up to `msg.value` leftover ETH at the end of the call. /// @dev Refunds up to `msg.value` leftover ETH at the end of the call.
modifier refundsAttachedEth() { modifier refundsAttachedEth() {
_; _;
@ -109,7 +113,12 @@ contract MetaTransactionsFeature is
require(initialBalance <= address(this).balance, "MetaTransactionsFeature/ETH_LEAK"); require(initialBalance <= address(this).balance, "MetaTransactionsFeature/ETH_LEAK");
} }
constructor(address zeroExAddress) public FixinCommon() FixinEIP712(zeroExAddress) {} constructor(
address zeroExAddress,
IEtherTokenV06 weth
) public FixinCommon() FixinEIP712(zeroExAddress) {
WETH = weth;
}
/// @dev Initialize and register this feature. /// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`. /// Should be delegatecalled by `Migrate.migrate()`.
@ -248,8 +257,12 @@ contract MetaTransactionsFeature is
returnResult = _executeFillRfqOrderCall(state); returnResult = _executeFillRfqOrderCall(state);
} else if (state.selector == IMultiplexFeature.multiplexBatchSellTokenForToken.selector) { } else if (state.selector == IMultiplexFeature.multiplexBatchSellTokenForToken.selector) {
returnResult = _executeMultiplexBatchSellTokenForTokenCall(state); returnResult = _executeMultiplexBatchSellTokenForTokenCall(state);
} else if (state.selector == IMultiplexFeature.multiplexBatchSellTokenForEth.selector) {
returnResult = _executeMultiplexBatchSellTokenForEthCall(state);
} else if (state.selector == IMultiplexFeature.multiplexMultiHopSellTokenForToken.selector) { } else if (state.selector == IMultiplexFeature.multiplexMultiHopSellTokenForToken.selector) {
returnResult = _executeMultiplexMultiHopSellTokenForTokenCall(state); returnResult = _executeMultiplexMultiHopSellTokenForTokenCall(state);
} else if (state.selector == IMultiplexFeature.multiplexMultiHopSellTokenForEth.selector) {
returnResult = _executeMultiplexMultiHopSellTokenForEthCall(state);
} else { } else {
LibMetaTransactionsRichErrors.MetaTransactionUnsupportedFunctionError(state.hash, state.selector).rrevert(); LibMetaTransactionsRichErrors.MetaTransactionUnsupportedFunctionError(state.hash, state.selector).rrevert();
} }
@ -497,6 +510,46 @@ contract MetaTransactionsFeature is
); );
} }
/// @dev Execute a `IMultiplexFeature.multiplexBatchSellTokenForEth()` meta-transaction
/// call by decoding the call args and translating the call to the internal
/// `IMultiplexFeature._multiplexBatchSellTokenForEth()` variant, where we can override the
/// msgSender address.
function _executeMultiplexBatchSellTokenForEthCall(ExecuteState memory state) private returns (bytes memory returnResult) {
IERC20TokenV06 inputToken;
IMultiplexFeature.BatchSellSubcall[] memory calls;
uint256 sellAmount;
uint256 minBuyAmount;
bytes memory args = _extractArgumentsFromCallData(state.mtx.callData);
(inputToken, calls, sellAmount, minBuyAmount) = abi.decode(
args,
(IERC20TokenV06, IMultiplexFeature.BatchSellSubcall[], uint256, uint256)
);
returnResult = _callSelf(
state.hash,
abi.encodeWithSelector(
IMultiplexFeature._multiplexBatchSell.selector,
IMultiplexFeature.BatchSellParams({
inputToken: inputToken,
outputToken: IERC20TokenV06(WETH),
sellAmount: sellAmount,
calls: calls,
useSelfBalance: false,
recipient: address(this),
msgSender: state.mtx.signer
}),
minBuyAmount
),
state.mtx.value
);
// Unwrap and transfer WETH
uint256 boughtAmount = abi.decode(returnResult, (uint256));
WETH.withdraw(boughtAmount);
_transferEth(state.mtx.signer, boughtAmount);
}
/// @dev Execute a `IMultiplexFeature.multiplexMultiHopSellTokenForToken()` meta-transaction /// @dev Execute a `IMultiplexFeature.multiplexMultiHopSellTokenForToken()` meta-transaction
/// call by decoding the call args and translating the call to the internal /// call by decoding the call args and translating the call to the internal
/// `IMultiplexFeature._multiplexMultiHopSell()` variant, where we can override the /// `IMultiplexFeature._multiplexMultiHopSell()` variant, where we can override the
@ -532,6 +585,50 @@ contract MetaTransactionsFeature is
); );
} }
/// @dev Execute a `IMultiplexFeature.multiplexMultiHopSellTokenForEth()` meta-transaction
/// call by decoding the call args and translating the call to the internal
/// `IMultiplexFeature._multiplexMultiHopSellTokenForEth()` variant, where we can override the
/// msgSender address.
function _executeMultiplexMultiHopSellTokenForEthCall(ExecuteState memory state) private returns (bytes memory returnResult) {
address[] memory tokens;
IMultiplexFeature.MultiHopSellSubcall[] memory calls;
uint256 sellAmount;
uint256 minBuyAmount;
bytes memory args = _extractArgumentsFromCallData(state.mtx.callData);
(tokens, calls, sellAmount, minBuyAmount) = abi.decode(
args,
(address[], IMultiplexFeature.MultiHopSellSubcall[], uint256, uint256)
);
require(
tokens[tokens.length - 1] == address(WETH),
"MetaTransactionsFeature::multiplexMultiHopSellTokenForEth/NOT_WETH"
);
returnResult = _callSelf(
state.hash,
abi.encodeWithSelector(
IMultiplexFeature._multiplexMultiHopSell.selector,
IMultiplexFeature.MultiHopSellParams({
tokens: tokens,
sellAmount: sellAmount,
calls: calls,
useSelfBalance: false,
recipient: address(this),
msgSender: state.mtx.signer
}),
minBuyAmount
),
state.mtx.value
);
// Unwrap and transfer WETH
uint256 boughtAmount = abi.decode(returnResult, (uint256));
WETH.withdraw(boughtAmount);
_transferEth(state.mtx.signer, boughtAmount);
}
/// @dev Make an arbitrary internal, meta-transaction call. /// @dev Make an arbitrary internal, meta-transaction call.
/// Warning: Do not let unadulterated `callData` into this function. /// Warning: Do not let unadulterated `callData` into this function.
function _callSelf(bytes32 hash, bytes memory callData, uint256 value) private returns (bytes memory returnResult) { function _callSelf(bytes32 hash, bytes memory callData, uint256 value) private returns (bytes memory returnResult) {

View File

@ -331,9 +331,7 @@ contract MultiplexFeature is
); );
} }
/// @dev Executes a multi-hop sell and checks that at least /// @dev Executes a multi-hop sell. Internal variant.
/// `minBuyAmount` of output tokens were bought. Internal
/// variant.
/// @param params Multi-hop sell parameters. /// @param params Multi-hop sell parameters.
/// @param minBuyAmount The minimum amount of output tokens that /// @param minBuyAmount The minimum amount of output tokens that
/// must be bought for this function to not revert. /// must be bought for this function to not revert.