feat: Add transferFromNeeded to non permit2 methods

This will block an attempt to transfer from the user when we expect the funds to already be in the router.

chores:
- add docs
- in EncodingContext, rename transfer to transfer_type

Took 58 minutes
This commit is contained in:
Diana Carvalho
2025-05-19 12:02:57 +01:00
parent e0c195f63d
commit cc9e88cfed
13 changed files with 179 additions and 76 deletions

View File

@@ -52,21 +52,37 @@ contract RestrictTransferFrom {
None
}
/**
* @dev This function is used to store the transfer information in the
* contract's storage. This is done as the first step in the swap process in TychoRouter.
*/
// slither-disable-next-line assembly
function _tstoreTransferFromInfo(
address tokenIn,
uint256 amountIn,
bool isPermit2
bool isPermit2,
bool transferFromNeeded
) internal {
uint256 amountAllowed = amountIn;
if (!transferFromNeeded) {
amountAllowed = 0;
}
assembly {
tstore(_TOKEN_IN_SLOT, tokenIn)
tstore(_AMOUNT_ALLOWED_SLOT, amountIn)
tstore(_AMOUNT_ALLOWED_SLOT, amountAllowed)
tstore(_IS_PERMIT2_SLOT, isPermit2)
tstore(_SENDER_SLOT, caller())
tstore(_AMOUNT_SPENT_SLOT, 0)
}
}
/**
* @dev This function is used to transfer the tokens from the sender to the receiver.
* This function is called within the Executor contracts.
* If the TransferType is TransferFrom, it will check if the amount is within the allowed amount and transfer those funds from the user.
* If the TransferType is Transfer, it will transfer the funds from the TychoRouter to the receiver.
* If the TransferType is None, it will do nothing.
*/
// slither-disable-next-line assembly
function _transfer(
address receiver,

View File

@@ -123,6 +123,7 @@ contract TychoRouter is
* @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver.
* @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations).
* @param receiver The address to receive the output tokens.
* @param transferFromNeeded If false, the contract will assume that the input token is already transferred to the contract and don't allow any transferFroms
* @param swaps Encoded swap graph data containing details of each swap.
*
* @return amountOut The total amount of the output token received by the receiver.
@@ -136,10 +137,11 @@ contract TychoRouter is
bool unwrapEth,
uint256 nTokens,
address receiver,
bool transferFromNeeded,
bytes calldata swaps
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
_tstoreTransferFromInfo(tokenIn, amountIn, false);
_tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded);
return _splitSwapChecked(
amountIn,
@@ -199,7 +201,7 @@ contract TychoRouter is
if (tokenIn != address(0)) {
permit2.permit(msg.sender, permitSingle, signature);
}
_tstoreTransferFromInfo(tokenIn, amountIn, true);
_tstoreTransferFromInfo(tokenIn, amountIn, true, true);
return _splitSwapChecked(
amountIn,
@@ -233,6 +235,7 @@ contract TychoRouter is
* @param wrapEth If true, wraps the input token (native ETH) into WETH.
* @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver.
* @param receiver The address to receive the output tokens.
* @param transferFromNeeded If false, the contract will assume that the input token is already transferred to the contract and don't allow any transferFroms
* @param swaps Encoded swap graph data containing details of each swap.
*
* @return amountOut The total amount of the output token received by the receiver.
@@ -245,10 +248,11 @@ contract TychoRouter is
bool wrapEth,
bool unwrapEth,
address receiver,
bool transferFromNeeded,
bytes calldata swaps
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
_tstoreTransferFromInfo(tokenIn, amountIn, false);
_tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded);
return _sequentialSwapChecked(
amountIn,
@@ -305,7 +309,7 @@ contract TychoRouter is
permit2.permit(msg.sender, permitSingle, signature);
}
_tstoreTransferFromInfo(tokenIn, amountIn, true);
_tstoreTransferFromInfo(tokenIn, amountIn, true, true);
return _sequentialSwapChecked(
amountIn,
@@ -336,6 +340,7 @@ contract TychoRouter is
* @param wrapEth If true, wraps the input token (native ETH) into WETH.
* @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver.
* @param receiver The address to receive the output tokens.
* @param transferFromNeeded If false, the contract will assume that the input token is already transferred to the contract and don't allow any transferFroms
* @param swapData Encoded swap details.
*
* @return amountOut The total amount of the output token received by the receiver.
@@ -348,10 +353,11 @@ contract TychoRouter is
bool wrapEth,
bool unwrapEth,
address receiver,
bool transferFromNeeded,
bytes calldata swapData
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
_tstoreTransferFromInfo(tokenIn, amountIn, false);
_tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded);
return _singleSwap(
amountIn,
@@ -407,7 +413,7 @@ contract TychoRouter is
if (tokenIn != address(0)) {
permit2.permit(msg.sender, permitSingle, signature);
}
_tstoreTransferFromInfo(tokenIn, amountIn, true);
_tstoreTransferFromInfo(tokenIn, amountIn, true, true);
return _singleSwap(
amountIn,