feat: Sketch for OneTransferFromOnly.sol

Took 49 seconds
This commit is contained in:
Diana Carvalho
2025-05-14 11:22:54 +01:00
parent 67eba8d7d2
commit 9401ce2620
4 changed files with 148 additions and 30 deletions

View File

@@ -0,0 +1,77 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.26;
import "@interfaces/IExecutor.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
error TokenTransfer__AddressZero();
contract OneTransferFromOnly {
using SafeERC20 for IERC20;
// this is a stupid name but the compiler was complaining that we already had a permit2 variable in TychoRouter
IAllowanceTransfer public immutable permit2lal;
uint256 private constant _TOKEN_IN_SLOT = 123;
uint256 private constant _AMOUNT_IN_SLOT = 124;
uint256 private constant _IS_PERMIT2_SLOT = 125;
uint256 private constant _SENDER_SLOT = 126;
uint256 private constant _IS_TRANSFER_EXECUTED_SLOT = 127;
constructor(address _permit2) {
if (_permit2 == address(0)) {
revert TokenTransfer__AddressZero();
}
permit2lal = IAllowanceTransfer(_permit2);
}
function tstoreTransferFromInfo(
address tokenIn,
address amountIn,
bool isPermit2,
address sender
) internal {
assembly {
tstore(_TOKEN_IN_SLOT, tokenIn)
tstore(_AMOUNT_IN_SLOT, amountIn)
tstore(_IS_PERMIT2_SLOT, isPermit2)
tstore(_SENDER_SLOT, sender)
tstore(_IS_TRANSFER_EXECUTED_SLOT, false)
}
}
function _transfer(address receiver)
// we could pass the amount and address too and compare to what is in the slots?
internal
{
address tokenIn;
uint256 amount;
bool isPermit2;
address sender;
bool isTransferExecuted;
assembly {
tokenIn := tload(_TOKEN_IN_SLOT)
amount := tload(_AMOUNT_IN_SLOT)
isPermit2 := tload(_IS_PERMIT2_SLOT)
sender := tload(_SENDER_SLOT)
isTransferExecuted := tload(_IS_TRANSFER_EXECUTED_SLOT)
}
if (isTransferExecuted) {
return; // or revert?
}
if (isPermit2) {
// Permit2.permit is already called from the TychoRouter
permit2lal.transferFrom(sender, receiver, uint160(amount), tokenIn);
assembly {
tstore(_IS_TRANSFER_EXECUTED_SLOT, true)
}
} else {
// slither-disable-next-line arbitrary-send-erc20
IERC20(tokenIn).safeTransferFrom(sender, receiver, amount);
assembly {
tstore(_IS_TRANSFER_EXECUTED_SLOT, true)
}
}
}
}