// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity >=0.8.0;/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values./// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)/// @author Modified from Gnosis (https://github.com/gnosis/gp-v2-contracts/blob/main/src/contracts/libraries/GPv2SafeERC20.sol)/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.librarySafeTransferLib{
/*///////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/functionsafeTransferETH(address to, uint256 amount) internal{
bool callStatus;
assembly {
// Transfer the ETH and store if it succeeded or not.
callStatus :=call(gas(), to, amount, 0, 0, 0, 0)
}
require(callStatus, "ETH_TRANSFER_FAILED");
}
/*///////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/functionsafeTransferFrom(address token,
addressfrom,
address to,
uint256 amount
) internal{
bool callStatus;
assembly {
// Get a pointer to some free memory.let freeMemoryPointer :=mload(0x40)
// Write the abi-encoded calldata to memory piece by piece:mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) // Begin with the function selector.mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "from" argument.mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.mstore(add(freeMemoryPointer, 68), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.// Call the token and store if it succeeded or not.// We use 100 because the calldata length is 4 + 32 * 3.
callStatus :=call(gas(), token, 0, freeMemoryPointer, 100, 0, 0)
}
require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FROM_FAILED");
}
functionsafeTransfer(address token,
address to,
uint256 amount
) internal{
bool callStatus;
assembly {
// Get a pointer to some free memory.let freeMemoryPointer :=mload(0x40)
// Write the abi-encoded calldata to memory piece by piece:mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // Begin with the function selector.mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.// Call the token and store if it succeeded or not.// We use 68 because the calldata length is 4 + 32 * 2.
callStatus :=call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)
}
require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FAILED");
}
functionsafeApprove(address token,
address to,
uint256 amount
) internal{
bool callStatus;
assembly {
// Get a pointer to some free memory.let freeMemoryPointer :=mload(0x40)
// Write the abi-encoded calldata to memory piece by piece:mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) // Begin with the function selector.mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.// Call the token and store if it succeeded or not.// We use 68 because the calldata length is 4 + 32 * 2.
callStatus :=call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)
}
require(didLastOptionalReturnCallSucceed(callStatus), "APPROVE_FAILED");
}
/*///////////////////////////////////////////////////////////////
INTERNAL HELPER LOGIC
//////////////////////////////////////////////////////////////*/functiondidLastOptionalReturnCallSucceed(bool callStatus) privatepurereturns (bool success) {
assembly {
// Get how many bytes the call returned.let returnDataSize :=returndatasize()
// If the call reverted:ifiszero(callStatus) {
// Copy the revert message into memory.returndatacopy(0, 0, returnDataSize)
// Revert with the same message.revert(0, returnDataSize)
}
switch returnDataSize
case32 {
// Copy the return data into memory.returndatacopy(0, 0, returnDataSize)
// Set success to whether it returned true.
success :=iszero(iszero(mload(0)))
}
case0 {
// There was no return data.
success :=1
}
default {
// It returned some malformed input.
success :=0
}
}
}
}
Contract Source Code
File 7 of 9: TSAggregator.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.10;import { SafeTransferLib } from"../lib/SafeTransferLib.sol";
import { ReentrancyGuard } from"../lib/ReentrancyGuard.sol";
import { Owners } from"./Owners.sol";
import { TSAggregatorTokenTransferProxy } from'./TSAggregatorTokenTransferProxy.sol';
abstractcontractTSAggregatorisOwners, ReentrancyGuard{
usingSafeTransferLibforaddress;
eventFeeSet(uint256 fee, address feeRecipient);
uint256public fee;
addresspublic feeRecipient;
TSAggregatorTokenTransferProxy public tokenTransferProxy;
constructor(address _tokenTransferProxy) {
_setOwner(msg.sender, true);
tokenTransferProxy = TSAggregatorTokenTransferProxy(_tokenTransferProxy);
}
// Needed for the swap router to be able to send back ETHreceive() externalpayable{}
functionsetFee(uint256 _fee, address _feeRecipient) externalisOwner{
require(_fee <=1000, "fee can not be more than 10%");
fee = _fee;
feeRecipient = _feeRecipient;
emit FeeSet(_fee, _feeRecipient);
}
functionskimFee(uint256 amount) internalreturns (uint256) {
if (fee !=0&& feeRecipient !=address(0)) {
uint256 feeAmount = (amount * fee) /10000;
feeRecipient.safeTransferETH(feeAmount);
amount -= feeAmount;
}
return amount;
}
// Parse amountOutMin treating the last 2 digits as an exponent// So 15e4 = 150000. This allows for compressed memos on chains// with limited space like Bitcoinfunction_parseAmountOutMin(uint256 amount) internalpurereturns (uint256) {
return amount /100* (10** (amount %100));
}
}
Contract Source Code
File 8 of 9: TSAggregatorTokenTransferProxy.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.10;import { SafeTransferLib } from"../lib/SafeTransferLib.sol";
import { Owners } from"./Owners.sol";
contractTSAggregatorTokenTransferProxyisOwners{
usingSafeTransferLibforaddress;
constructor() {
_setOwner(msg.sender, true);
}
functiontransferTokens(address token, addressfrom, address to, uint256 amount) externalisOwner{
require(from==tx.origin|| _isContract(from), "Invalid from address");
token.safeTransferFrom(from, to, amount);
}
function_isContract(address account) internalviewreturns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in// construction, since the code is only stored at the end of the// constructor execution.uint256 size;
// solhint-disable-next-line no-inline-assemblyassembly { size :=extcodesize(account) }
return size >0;
}
}