-
Notifications
You must be signed in to change notification settings - Fork 212
feat: Multiplex + MetaTransaction integration and MetaTransaction Multi-Fee Support [RFQ-795] [LIT-870] #665
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
// The sender of the transaction. | ||
address msgSender; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the beneficiary of the metatransaction, or the relayer? We should invent new terminology here so that it's clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This naming is used elsewhere, such as openzeppelin's _msgSender()
. msg.sender for regular transactions, and the end-user for GSN relayed calls
.
So upon as long as this holds everywhere, the naming is ok.
I believe this is needed to disambiguate in the cases of receiving WETH and the user wanting ETH. In which case we need to be the recipient (to unwrap), but things need to be verified for the real user, such as the OTC/RFQ order was for that user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a discussion we had earlier today, @duncancmt and @abls and I felt that the best naming would be payer (// the sender of the input token), which kinda mirrors what's going on with recipient - the receiver of the output token.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dekz I see what you mean. I think this gets a little confusing with OTC/RFQ when the flow of value is bidirectional (equivalently: when the operation being executed is effectively a metatransaction with 2 signers). I concede that this isn't a big deal for the present PR, though.
address private constant ZERO_ADDRESS = 0x0000000000000000000000000000000000000000; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just use address(0)
?
contracts/zero-ex/contracts/src/features/MetaTransactionsFeatureV2.sol
Outdated
Show resolved
Hide resolved
contracts/zero-ex/contracts/src/features/MetaTransactionsFeatureV2.sol
Outdated
Show resolved
Hide resolved
// TODO: Remove this field from SignatureValidationError | ||
// when rich reverts are part of the protocol repo. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Open TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is sadly copy/pasted from the original metatransaction v1. Happy to open a TODO if this is something we actually want to fix.
ExternalTransformERC20Args memory args; | ||
{ | ||
bytes memory encodedStructArgs = new bytes(state.mtx.callData.length - 4 + 32); | ||
// Copy the args data from the original, after the new struct offset prefix. | ||
bytes memory fromCallData = state.mtx.callData; | ||
assert(fromCallData.length >= 160); | ||
uint256 fromMem; | ||
uint256 toMem; | ||
assembly { | ||
// Prefix the calldata with a struct offset, | ||
// which points to just one word over. | ||
mstore(add(encodedStructArgs, 32), 32) | ||
// Copy everything after the selector. | ||
fromMem := add(fromCallData, 36) | ||
// Start copying after the struct offset. | ||
toMem := add(encodedStructArgs, 64) | ||
} | ||
LibBytesV06.memCopy(toMem, fromMem, fromCallData.length - 4); | ||
// Decode call args for `ITransformERC20Feature.transformERC20()` as a struct. | ||
args = abi.decode(encodedStructArgs, (ExternalTransformERC20Args)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think this would be cleaner with the destructive version:
{
bytes memory data = state.mtx.callData;
assert(data.length > 4);
assembly {
let newLen := sub(mload(data), 4)
data := add(data, 4)
mstore(data, newLen)
}
state.mtx.callData = data;
}
args = abi.decode(state.mtx.callData, ExternalTransformERC20Args);
@dekz do you have an opinion?
contracts/zero-ex/contracts/src/features/MetaTransactionsFeatureV2.sol
Outdated
Show resolved
Hide resolved
contracts/zero-ex/contracts/src/features/MetaTransactionsFeatureV2.sol
Outdated
Show resolved
Hide resolved
DeployZeroEx.ZeroExDeployed zeroExDeployed; | ||
address private constant ZERO_ADDRESS = 0x0000000000000000000000000000000000000000; | ||
address private constant USER_ADDRESS = 0x6dc3a54FeAE57B65d185A7B159c5d3FA7fD7FD0F; | ||
uint256 private constant USER_KEY = 0x1fc1630343b31e60b7a197a53149ca571ed9d9791e2833337bbd8110c30710ec; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While USER_KEY
and address constants were useful when thrown together for that reference script, we should probably have a better system for this in the test utils. A lot of things from that script are not good practice because that script was intended for a single use within an entirely different context.
Regarding improving our utils, a single getSigner
function that can return only one signer isn't enough. It is common in our tests that we need multiple signers. Also, maybe we should be able to sign for any of the account
s in BaseTest
. Unsure exactly the best solution, but imo all the people writing tests should have a discussion about organization of the shared test utils at some point.
4e317f2
to
16fcf1f
Compare
7d43762
to
00399e6
Compare
contracts/zero-ex/contracts/src/features/MetaTransactionsFeatureV2.sol
Outdated
Show resolved
Hide resolved
contracts/zero-ex/contracts/src/features/MetaTransactionsFeatureV2.sol
Outdated
Show resolved
Hide resolved
contracts/zero-ex/contracts/src/features/MetaTransactionsFeatureV2.sol
Outdated
Show resolved
Hide resolved
contracts/zero-ex/contracts/src/features/MetaTransactionsFeatureV2.sol
Outdated
Show resolved
Hide resolved
// The sender of the transaction. | ||
address msgSender; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This naming is used elsewhere, such as openzeppelin's _msgSender()
. msg.sender for regular transactions, and the end-user for GSN relayed calls
.
So upon as long as this holds everywhere, the naming is ok.
I believe this is needed to disambiguate in the cases of receiving WETH and the user wanting ETH. In which case we need to be the recipient (to unwrap), but things need to be verified for the real user, such as the OTC/RFQ order was for that user.
…en, multiplex TokenForEth functions to metatransactions, add msgSender field to multiplex params
…sk, and fixing lint issues
ecefe5b
to
152accf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As instructed by @patrick-dowell , I re-reviewed this by diffing MetaTransactionsFeatureV2.sol
against MetaTransactionsFeature.sol
. Seems pretty straightforward. I left a comment about reentrancy; I haven't gone deep on whether this is a real concern, but it's something to think about. Please add a comment addressing this concern before merging.
import "@0x/contracts-erc20/src/IEtherToken.sol"; | ||
|
||
contract MetaTransactionTest is LocalTest { | ||
address private constant ZERO_ADDRESS = address(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a named constant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just copy/pasted from previous test code that we wrote. I can get rid of it.
…or MultiplexSubcall.OTC [#667]
contracts/zero-ex/contracts/src/features/multiplex/MultiplexOtc.sol
Outdated
Show resolved
Hide resolved
|
||
_executeMetaTransaction( | ||
abi.encodeWithSelector( | ||
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken.selector, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@abls this should be multiplexMultiHopSellTokenForEth.selector
Description
There are four big changes included in this PR:
Allow
executeMetaTransaction
to pay out multiple fees by modifying the data structureMetaTransactionData
. This results in the creation of a v2 MetaTransactions feature contract andMetaTransactionV2Data
struct.Inclusion of four new selectors in
MetaTransactionsFeatureV2
:_executeMultiplexBatchSellTokenForTokenCall
_executeMultiplexBatchSellTokenForEthCall
_executeMultiplexMultiHopSellTokenForTokenCall
_executeMultiplexMultiHopSellTokenForEthCall
Modifications to Multiplex to account for the possibility that the
MultiplexFeature
is entered viaMetaTransactionFeatureV2
. Specifically, we refactor calls tomsg.sender
intoBatchSellParams.payer
andMultiHopSellParams.payer
Add a call to
multiHopBatchSellOtc
toMultiplexFeature
and add a conditional forMultiplexSubcall.OTC
in Multiplex's_computeHopTarget
. To accomplish this, changes were cherrypicked from Feat/multi hop sell otc [LIT-870] #667 at f32e834.Testing instructions
Run forge test from contracts/zero-ex. There are numerous new local tests and a new forked test that cover the new functionality and contract, located at
MetaTransactionV2Test.t.sol
,MultiplexMetaTransactionsV2.t.sol
, andMultiplexRfqTest.t.sol
.Types of changes
MetaTransactionsFeatureV2
was created, copying logic fromMetaTransactionsFeature
.MetaTransactionsFeatureV2
MultiplexFeature
Checklist: