- Don't use payable(receiver).transfer(amount) and use OpenZeppelin's Address.sendValue instead
- In Univ4Executor send funds to the poolManager and not msg.sender
- In OneTransferFromOnly:
- rename method name
- don't pass the sender but hardcode it to caller() (msg.sender)
- Move marking the transfer as done up (before we actually transfer) to prevent reentrancy attacks
Took 18 minutes
This needs to be calculated before we perform a transferFrom in the router! This worked before since we were doing the transferFroms always from inside the executors.
we will never perform a manual transfer into these protocols, as they require the tokens to be in the router contract in order to perform a transferFrom.
Delete TokenTransfer.sol
Make slither happy
Bugfixes:
- Executors
- Ekubo:
- Fix the POOL_DATA_OFFSET value and remove sender from callback data
- Use SafeERC20
- Maverick and Univ2: Use safeTransfer and not safeTransferFrom
- Univ3: update expected data length
- Univ4: update the selectors (the signature changed)
- Router:
- For split swap we don't need to pass the tokenInReceiver, it should always be the router address
- For single and sequential: change order of the parameters (to be before the permit2 specific objects)
- Encoders:
- Update selector signatures
- For split swap pass the transfer_from (we might not need to if the token in is ETH)
Took 2 hours 51 minutes
The transfer from the user into the router is supposed to happen in the router (we only support this in the executors for callback constrained protocols). This is necessary because of some security concerns that were found in the audit. This way we reduce the space of attack.
- Refactored TransferOptimization not to handle TransferTypes anymore but just return bools.
- Split get_transfer_type into get_transfers and get_in_between_transfer. Updates tests
- Updated the strategies to use this
- Updated function signatures to pass transfer_from and funds_receiver
- Updated SwapEncoders to handle this
- SplitSwapStrategy just assumes all tokens are sent to and from the router at all times
Took 2 hours 46 minutes
The problem was that the pool manager was expecting an ABI encoded result to be returned and we were not returning that (we were returning just a result)
Special thanks to Max for figuring this out
Took 31 minutes
- Also added integration test to test the optimizations, where we can see the in and out transfers being optimized if we enable verbose foundry testing
- Fixed typo in swap encoder builder initialization
This way we can automatically replace the calldata when something changes. We don't need to manually replace the string ourselves.
--- don't change below this line ---
ENG-4453 Took 3 hours 26 minutes
- This was originally remaining if no callback was performed, possible resulting in unexpected behaviour and an increased attack surface.
- Also specify nonzero slot for transient storage in order to reduce the risk of dangerous slot collision.
- Store the executor address when deploying instead.
- We would like to keep all instances of tload and tstore within the callback mechanism of our main TychoRouter contract for security reasons and to prevent any unexpected behaviour
- This way it's easy to reason that UniswapV4Executor will only ever execute a delegatecall to itself. Before it could in theory execute a delegatecall to any address. One had to look at all occurences of tstore(0, x) to ensure the address was constrained.
- Needed to add ekubo and uniswap v4 to callback-limited protocols.
- I had to bump the fork block in all of our integration tests: The way it was before meant that certain integration tests were using certain executor addresses, and others were using different ones, because of the redeployment. This was a pain to account for on the rust side. Instead, all tests now use an Ekubo-compatible fork block. Values needed to be updated because of price changes between blocks.