编译器
0.8.17+commit.8df45f5f
文件 1 的 35:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 35:Allowance.sol
pragma solidity ^0.8.17;
import {IAllowanceTransfer} from "../interfaces/IAllowanceTransfer.sol";
library Allowance {
uint256 private constant BLOCK_TIMESTAMP_EXPIRATION = 0;
function updateAll(
IAllowanceTransfer.PackedAllowance storage allowed,
uint160 amount,
uint48 expiration,
uint48 nonce
) internal {
uint48 storedNonce;
unchecked {
storedNonce = nonce + 1;
}
uint48 storedExpiration = expiration == BLOCK_TIMESTAMP_EXPIRATION ? uint48(block.timestamp) : expiration;
uint256 word = pack(amount, storedExpiration, storedNonce);
assembly {
sstore(allowed.slot, word)
}
}
function updateAmountAndExpiration(
IAllowanceTransfer.PackedAllowance storage allowed,
uint160 amount,
uint48 expiration
) internal {
allowed.expiration = expiration == 0 ? uint48(block.timestamp) : expiration;
allowed.amount = amount;
}
function pack(uint160 amount, uint48 expiration, uint48 nonce) internal pure returns (uint256 word) {
word = (uint256(nonce) << 208) | uint256(expiration) << 160 | amount;
}
}
文件 3 的 35:AllowanceTransfer.sol
pragma solidity 0.8.17;
import {ERC20} from "../solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "../solmate/utils/SafeTransferLib.sol";
import {PermitHash} from "./libraries/PermitHash.sol";
import {SignatureVerification} from "./libraries/SignatureVerification.sol";
import {EIP712} from "./EIP712.sol";
import {IAllowanceTransfer} from "../src/interfaces/IAllowanceTransfer.sol";
import {SignatureExpired, InvalidNonce} from "./PermitErrors.sol";
import {Allowance} from "./libraries/Allowance.sol";
contract AllowanceTransfer is IAllowanceTransfer, EIP712 {
using SignatureVerification for bytes;
using SafeTransferLib for ERC20;
using PermitHash for PermitSingle;
using PermitHash for PermitBatch;
using Allowance for PackedAllowance;
mapping(address => mapping(address => mapping(address => PackedAllowance))) public allowance;
function approve(address token, address spender, uint160 amount, uint48 expiration) external {
PackedAllowance storage allowed = allowance[msg.sender][token][spender];
allowed.updateAmountAndExpiration(amount, expiration);
emit Approval(msg.sender, token, spender, amount, expiration);
}
function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external {
if (block.timestamp > permitSingle.sigDeadline) revert SignatureExpired(permitSingle.sigDeadline);
signature.verify(_hashTypedData(permitSingle.hash()), owner);
_updateApproval(permitSingle.details, owner, permitSingle.spender);
}
function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external {
if (block.timestamp > permitBatch.sigDeadline) revert SignatureExpired(permitBatch.sigDeadline);
signature.verify(_hashTypedData(permitBatch.hash()), owner);
address spender = permitBatch.spender;
unchecked {
uint256 length = permitBatch.details.length;
for (uint256 i = 0; i < length; ++i) {
_updateApproval(permitBatch.details[i], owner, spender);
}
}
}
function transferFrom(address from, address to, uint160 amount, address token) external {
_transfer(from, to, amount, token);
}
function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external {
unchecked {
uint256 length = transferDetails.length;
for (uint256 i = 0; i < length; ++i) {
AllowanceTransferDetails memory transferDetail = transferDetails[i];
_transfer(transferDetail.from, transferDetail.to, transferDetail.amount, transferDetail.token);
}
}
}
function _transfer(address from, address to, uint160 amount, address token) private {
PackedAllowance storage allowed = allowance[from][token][msg.sender];
if (block.timestamp > allowed.expiration) revert AllowanceExpired(allowed.expiration);
uint256 maxAmount = allowed.amount;
if (maxAmount != type(uint160).max) {
if (amount > maxAmount) {
revert InsufficientAllowance(maxAmount);
} else {
unchecked {
allowed.amount = uint160(maxAmount) - amount;
}
}
}
ERC20(token).safeTransferFrom(from, to, amount);
}
function lockdown(TokenSpenderPair[] calldata approvals) external {
address owner = msg.sender;
unchecked {
uint256 length = approvals.length;
for (uint256 i = 0; i < length; ++i) {
address token = approvals[i].token;
address spender = approvals[i].spender;
allowance[owner][token][spender].amount = 0;
emit Lockdown(owner, token, spender);
}
}
}
function invalidateNonces(address token, address spender, uint48 newNonce) external {
uint48 oldNonce = allowance[msg.sender][token][spender].nonce;
if (newNonce <= oldNonce) revert InvalidNonce();
unchecked {
uint48 delta = newNonce - oldNonce;
if (delta > type(uint16).max) revert ExcessiveInvalidation();
}
allowance[msg.sender][token][spender].nonce = newNonce;
emit NonceInvalidation(msg.sender, token, spender, newNonce, oldNonce);
}
function _updateApproval(PermitDetails memory details, address owner, address spender) private {
uint48 nonce = details.nonce;
address token = details.token;
uint160 amount = details.amount;
uint48 expiration = details.expiration;
PackedAllowance storage allowed = allowance[owner][token][spender];
if (allowed.nonce != nonce) revert InvalidNonce();
allowed.updateAll(amount, expiration, nonce);
emit Permit(owner, token, spender, amount, expiration, nonce);
}
}
文件 4 的 35:Commands.sol
pragma solidity ^0.8.17;
library Commands {
bytes1 internal constant FLAG_ALLOW_REVERT = 0x80;
bytes1 internal constant COMMAND_TYPE_MASK = 0x3f;
uint256 constant V3_SWAP_EXACT_IN = 0x00;
uint256 constant V3_SWAP_EXACT_OUT = 0x01;
uint256 constant PERMIT2_TRANSFER_FROM = 0x02;
uint256 constant PERMIT2_PERMIT_BATCH = 0x03;
uint256 constant SWEEP = 0x04;
uint256 constant TRANSFER = 0x05;
uint256 constant PAY_PORTION = 0x06;
uint256 constant FIRST_IF_BOUNDARY = 0x08;
uint256 constant V2_SWAP_EXACT_IN = 0x08;
uint256 constant V2_SWAP_EXACT_OUT = 0x09;
uint256 constant PERMIT2_PERMIT = 0x0a;
uint256 constant WRAP_ETH = 0x0b;
uint256 constant UNWRAP_WETH = 0x0c;
uint256 constant PERMIT2_TRANSFER_FROM_BATCH = 0x0d;
uint256 constant BALANCE_CHECK_ERC20 = 0x0e;
uint256 constant SECOND_IF_BOUNDARY = 0x10;
uint256 constant SEAPORT_V1_5 = 0x10;
uint256 constant LOOKS_RARE_V2 = 0x11;
uint256 constant NFTX = 0x12;
uint256 constant CRYPTOPUNKS = 0x13;
uint256 constant OWNER_CHECK_721 = 0x15;
uint256 constant OWNER_CHECK_1155 = 0x16;
uint256 constant SWEEP_ERC721 = 0x17;
uint256 constant THIRD_IF_BOUNDARY = 0x18;
uint256 constant X2Y2_721 = 0x18;
uint256 constant SUDOSWAP = 0x19;
uint256 constant NFT20 = 0x1a;
uint256 constant X2Y2_1155 = 0x1b;
uint256 constant FOUNDATION = 0x1c;
uint256 constant SWEEP_ERC1155 = 0x1d;
uint256 constant ELEMENT_MARKET = 0x1e;
uint256 constant FOURTH_IF_BOUNDARY = 0x20;
uint256 constant SEAPORT_V1_4 = 0x20;
uint256 constant EXECUTE_SUB_PLAN = 0x21;
uint256 constant APPROVE_ERC20 = 0x22;
uint256 constant WRAP_STETH = 0x23;
uint256 constant UNWRAP_STETH = 0x24;
}
文件 5 的 35:Constants.sol
pragma solidity ^0.8.17;
import {IWETH9} from '../interfaces/external/IWETH9.sol';
library Constants {
uint256 internal constant CONTRACT_BALANCE = 0x8000000000000000000000000000000000000000000000000000000000000000;
uint256 internal constant ALREADY_PAID = 0;
address internal constant ETH = address(0);
address internal constant MSG_SENDER = address(1);
address internal constant ADDRESS_THIS = address(2);
uint256 internal constant ADDR_SIZE = 20;
uint256 internal constant V3_FEE_SIZE = 3;
uint256 internal constant NEXT_V3_POOL_OFFSET = ADDR_SIZE + V3_FEE_SIZE;
uint256 internal constant V3_POP_OFFSET = NEXT_V3_POOL_OFFSET + ADDR_SIZE;
uint256 internal constant MULTIPLE_V3_POOLS_MIN_LENGTH = V3_POP_OFFSET + NEXT_V3_POOL_OFFSET;
}
文件 6 的 35:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 7 的 35:ECDSA.sol
pragma solidity ^0.8.0;
import "../Strings.sol";
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return;
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
文件 8 的 35:EIP712.sol
pragma solidity 0.8.17;
contract EIP712 {
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID;
bytes32 private constant _HASHED_NAME = keccak256("Permit2");
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
constructor() {
_CACHED_CHAIN_ID = block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME);
}
function DOMAIN_SEPARATOR() public view returns (bytes32) {
return block.chainid == _CACHED_CHAIN_ID
? _CACHED_DOMAIN_SEPARATOR
: _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME);
}
function _buildDomainSeparator(bytes32 typeHash, bytes32 nameHash) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, block.chainid, address(this)));
}
function _hashTypedData(bytes32 dataHash) internal view returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), dataHash));
}
}
文件 9 的 35:ERC20.sol
pragma solidity >=0.8.0;
abstract contract ERC20 {
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
string public name;
string public symbol;
uint8 public immutable decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender];
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
文件 10 的 35:IAllowanceTransfer.sol
pragma solidity ^0.8.17;
interface IAllowanceTransfer {
error AllowanceExpired(uint256 deadline);
error InsufficientAllowance(uint256 amount);
error ExcessiveInvalidation();
event NonceInvalidation(
address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce
);
event Approval(
address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration
);
event Permit(
address indexed owner,
address indexed token,
address indexed spender,
uint160 amount,
uint48 expiration,
uint48 nonce
);
event Lockdown(address indexed owner, address token, address spender);
struct PermitDetails {
address token;
uint160 amount;
uint48 expiration;
uint48 nonce;
}
struct PermitSingle {
PermitDetails details;
address spender;
uint256 sigDeadline;
}
struct PermitBatch {
PermitDetails[] details;
address spender;
uint256 sigDeadline;
}
struct PackedAllowance {
uint160 amount;
uint48 expiration;
uint48 nonce;
}
struct TokenSpenderPair {
address token;
address spender;
}
struct AllowanceTransferDetails {
address from;
address to;
uint160 amount;
address token;
}
function allowance(address, address, address) external view returns (uint160, uint48, uint48);
function approve(address token, address spender, uint160 amount, uint48 expiration) external;
function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;
function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;
function transferFrom(address from, address to, uint160 amount, address token) external;
function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;
function lockdown(TokenSpenderPair[] calldata approvals) external;
function invalidateNonces(address token, address spender, uint48 newNonce) external;
}
文件 11 的 35:IERC1155Receiver.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC1155Receiver is IERC165 {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
文件 12 的 35:IERC1271.sol
pragma solidity ^0.8.17;
interface IERC1271 {
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}
文件 13 的 35:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 14 的 35:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 15 的 35:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 16 的 35:IRewardsCollector.sol
pragma solidity ^0.8.15;
import {ERC20} from 'solmate/src/tokens/ERC20.sol';
interface IRewardsCollector {
function collectRewards(bytes calldata looksRareClaim) external;
}
文件 17 的 35:ISignatureTransfer.sol
pragma solidity ^0.8.17;
interface ISignatureTransfer {
error InvalidAmount(uint256 maxAmount);
error LengthMismatch();
event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);
struct TokenPermissions {
address token;
uint256 amount;
}
struct PermitTransferFrom {
TokenPermissions permitted;
uint256 nonce;
uint256 deadline;
}
struct SignatureTransferDetails {
address to;
uint256 requestedAmount;
}
struct PermitBatchTransferFrom {
TokenPermissions[] permitted;
uint256 nonce;
uint256 deadline;
}
function nonceBitmap(address, uint256) external view returns (uint256);
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
function permitWitnessTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
function permitTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes calldata signature
) external;
function permitWitnessTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;
}
文件 18 的 35:ITransfers.sol
pragma solidity ^0.8.17;
import "../permit2/src/interfaces/ISignatureTransfer.sol";
struct TransferIntent {
uint256 recipientAmount;
uint256 deadline;
address payable recipient;
address recipientCurrency;
address refundDestination;
uint256 feeAmount;
bytes16 id;
address operator;
bytes signature;
bytes prefix;
}
struct Permit2SignatureTransferData {
ISignatureTransfer.PermitTransferFrom permit;
ISignatureTransfer.SignatureTransferDetails transferDetails;
bytes signature;
}
interface ITransfers {
event Transferred(
address indexed operator,
bytes16 id,
address recipient,
address sender,
uint256 spentAmount,
address spentCurrency
);
error NativeTransferFailed(address recipient, uint256 amount, bool isRefund, bytes data);
event OperatorRegistered(address operator, address feeDestination);
event OperatorUnregistered(address operator);
error OperatorNotRegistered();
error InvalidSignature();
error InvalidNativeAmount(int256 difference);
error InsufficientBalance(uint256 difference);
error InsufficientAllowance(uint256 difference);
error IncorrectCurrency(address attemptedCurrency);
error InvalidTransferDetails();
error ExpiredIntent();
error NullRecipient();
error AlreadyProcessed();
error InexactTransfer();
error SwapFailedString(string reason);
error SwapFailedBytes(bytes reason);
function transferNative(TransferIntent calldata _intent) external payable;
function transferToken(
TransferIntent calldata _intent,
Permit2SignatureTransferData calldata _signatureTransferData
) external;
function transferTokenPreApproved(TransferIntent calldata _intent) external;
function wrapAndTransfer(TransferIntent calldata _intent) external payable;
function unwrapAndTransfer(
TransferIntent calldata _intent,
Permit2SignatureTransferData calldata _signatureTransferData
) external;
function unwrapAndTransferPreApproved(TransferIntent calldata _intent) external;
function swapAndTransferUniswapV3Native(TransferIntent calldata _intent, uint24 poolFeesTier) external payable;
function swapAndTransferUniswapV3Token(
TransferIntent calldata _intent,
Permit2SignatureTransferData calldata _signatureTransferData,
uint24 poolFeesTier
) external;
function swapAndTransferUniswapV3TokenPreApproved(
TransferIntent calldata _intent,
address _tokenIn,
uint256 maxWillingToPay,
uint24 poolFeesTier
) external;
}
文件 19 的 35:IUniversalRouter.sol
pragma solidity ^0.8.17;
import {IERC721Receiver} from '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol';
import {IERC1155Receiver} from '@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol';
import {IRewardsCollector} from './IRewardsCollector.sol';
interface IUniversalRouter is IRewardsCollector, IERC721Receiver, IERC1155Receiver {
error ExecutionFailed(uint256 commandIndex, bytes message);
error ETHNotAccepted();
error TransactionDeadlinePassed();
error LengthMismatch();
function execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline) external payable;
}
文件 20 的 35:IWETH9.sol
pragma solidity ^0.8.4;
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
interface IWETH9 is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}
文件 21 的 35:IWrappedNativeCurrency.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWrappedNativeCurrency is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}
文件 22 的 35:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 23 的 35:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 24 的 35:Permit2.sol
pragma solidity 0.8.17;
import {SignatureTransfer} from "./SignatureTransfer.sol";
import {AllowanceTransfer} from "./AllowanceTransfer.sol";
contract Permit2 is SignatureTransfer, AllowanceTransfer {
}
文件 25 的 35:PermitErrors.sol
pragma solidity 0.8.17;
error SignatureExpired(uint256 signatureDeadline);
error InvalidNonce();
文件 26 的 35:PermitHash.sol
pragma solidity ^0.8.17;
import {IAllowanceTransfer} from "../interfaces/IAllowanceTransfer.sol";
import {ISignatureTransfer} from "../interfaces/ISignatureTransfer.sol";
library PermitHash {
bytes32 public constant _PERMIT_DETAILS_TYPEHASH =
keccak256("PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)");
bytes32 public constant _PERMIT_SINGLE_TYPEHASH = keccak256(
"PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"
);
bytes32 public constant _PERMIT_BATCH_TYPEHASH = keccak256(
"PermitBatch(PermitDetails[] details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"
);
bytes32 public constant _TOKEN_PERMISSIONS_TYPEHASH = keccak256("TokenPermissions(address token,uint256 amount)");
bytes32 public constant _PERMIT_TRANSFER_FROM_TYPEHASH = keccak256(
"PermitTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline)TokenPermissions(address token,uint256 amount)"
);
bytes32 public constant _PERMIT_BATCH_TRANSFER_FROM_TYPEHASH = keccak256(
"PermitBatchTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline)TokenPermissions(address token,uint256 amount)"
);
string public constant _TOKEN_PERMISSIONS_TYPESTRING = "TokenPermissions(address token,uint256 amount)";
string public constant _PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB =
"PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline,";
string public constant _PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB =
"PermitBatchWitnessTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline,";
function hash(IAllowanceTransfer.PermitSingle memory permitSingle) internal pure returns (bytes32) {
bytes32 permitHash = _hashPermitDetails(permitSingle.details);
return
keccak256(abi.encode(_PERMIT_SINGLE_TYPEHASH, permitHash, permitSingle.spender, permitSingle.sigDeadline));
}
function hash(IAllowanceTransfer.PermitBatch memory permitBatch) internal pure returns (bytes32) {
uint256 numPermits = permitBatch.details.length;
bytes32[] memory permitHashes = new bytes32[](numPermits);
for (uint256 i = 0; i < numPermits; ++i) {
permitHashes[i] = _hashPermitDetails(permitBatch.details[i]);
}
return keccak256(
abi.encode(
_PERMIT_BATCH_TYPEHASH,
keccak256(abi.encodePacked(permitHashes)),
permitBatch.spender,
permitBatch.sigDeadline
)
);
}
function hash(ISignatureTransfer.PermitTransferFrom memory permit) internal view returns (bytes32) {
bytes32 tokenPermissionsHash = _hashTokenPermissions(permit.permitted);
return keccak256(
abi.encode(_PERMIT_TRANSFER_FROM_TYPEHASH, tokenPermissionsHash, msg.sender, permit.nonce, permit.deadline)
);
}
function hash(ISignatureTransfer.PermitBatchTransferFrom memory permit) internal view returns (bytes32) {
uint256 numPermitted = permit.permitted.length;
bytes32[] memory tokenPermissionHashes = new bytes32[](numPermitted);
for (uint256 i = 0; i < numPermitted; ++i) {
tokenPermissionHashes[i] = _hashTokenPermissions(permit.permitted[i]);
}
return keccak256(
abi.encode(
_PERMIT_BATCH_TRANSFER_FROM_TYPEHASH,
keccak256(abi.encodePacked(tokenPermissionHashes)),
msg.sender,
permit.nonce,
permit.deadline
)
);
}
function hashWithWitness(
ISignatureTransfer.PermitTransferFrom memory permit,
bytes32 witness,
string calldata witnessTypeString
) internal view returns (bytes32) {
bytes32 typeHash = keccak256(abi.encodePacked(_PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB, witnessTypeString));
bytes32 tokenPermissionsHash = _hashTokenPermissions(permit.permitted);
return keccak256(abi.encode(typeHash, tokenPermissionsHash, msg.sender, permit.nonce, permit.deadline, witness));
}
function hashWithWitness(
ISignatureTransfer.PermitBatchTransferFrom memory permit,
bytes32 witness,
string calldata witnessTypeString
) internal view returns (bytes32) {
bytes32 typeHash =
keccak256(abi.encodePacked(_PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB, witnessTypeString));
uint256 numPermitted = permit.permitted.length;
bytes32[] memory tokenPermissionHashes = new bytes32[](numPermitted);
for (uint256 i = 0; i < numPermitted; ++i) {
tokenPermissionHashes[i] = _hashTokenPermissions(permit.permitted[i]);
}
return keccak256(
abi.encode(
typeHash,
keccak256(abi.encodePacked(tokenPermissionHashes)),
msg.sender,
permit.nonce,
permit.deadline,
witness
)
);
}
function _hashPermitDetails(IAllowanceTransfer.PermitDetails memory details) private pure returns (bytes32) {
return keccak256(abi.encode(_PERMIT_DETAILS_TYPEHASH, details));
}
function _hashTokenPermissions(ISignatureTransfer.TokenPermissions memory permitted)
private
pure
returns (bytes32)
{
return keccak256(abi.encode(_TOKEN_PERMISSIONS_TYPEHASH, permitted));
}
}
文件 27 的 35:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 28 的 35:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 29 的 35:SafeTransferLib.sol
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
library SafeTransferLib {
function safeTransferETH(address to, uint256 amount) internal {
bool success;
assembly {
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), from)
mstore(add(freeMemoryPointer, 36), to)
mstore(add(freeMemoryPointer, 68), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to)
mstore(add(freeMemoryPointer, 36), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to)
mstore(add(freeMemoryPointer, 36), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}
文件 30 的 35:SignatureTransfer.sol
pragma solidity 0.8.17;
import {ISignatureTransfer} from "./interfaces/ISignatureTransfer.sol";
import {SignatureExpired, InvalidNonce} from "./PermitErrors.sol";
import {ERC20} from "../solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "../solmate/utils/SafeTransferLib.sol";
import {SignatureVerification} from "./libraries/SignatureVerification.sol";
import {PermitHash} from "./libraries/PermitHash.sol";
import {EIP712} from "./EIP712.sol";
contract SignatureTransfer is ISignatureTransfer, EIP712 {
using SignatureVerification for bytes;
using SafeTransferLib for ERC20;
using PermitHash for PermitTransferFrom;
using PermitHash for PermitBatchTransferFrom;
mapping(address => mapping(uint256 => uint256)) public nonceBitmap;
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external {
_permitTransferFrom(permit, transferDetails, owner, permit.hash(), signature);
}
function permitWitnessTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external {
_permitTransferFrom(
permit, transferDetails, owner, permit.hashWithWitness(witness, witnessTypeString), signature
);
}
function _permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes32 dataHash,
bytes calldata signature
) private {
uint256 requestedAmount = transferDetails.requestedAmount;
if (block.timestamp > permit.deadline) revert SignatureExpired(permit.deadline);
if (requestedAmount > permit.permitted.amount) revert InvalidAmount(permit.permitted.amount);
_useUnorderedNonce(owner, permit.nonce);
signature.verify(_hashTypedData(dataHash), owner);
ERC20(permit.permitted.token).safeTransferFrom(owner, transferDetails.to, requestedAmount);
}
function permitTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes calldata signature
) external {
_permitTransferFrom(permit, transferDetails, owner, permit.hash(), signature);
}
function permitWitnessTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external {
_permitTransferFrom(
permit, transferDetails, owner, permit.hashWithWitness(witness, witnessTypeString), signature
);
}
function _permitTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes32 dataHash,
bytes calldata signature
) private {
uint256 numPermitted = permit.permitted.length;
if (block.timestamp > permit.deadline) revert SignatureExpired(permit.deadline);
if (numPermitted != transferDetails.length) revert LengthMismatch();
_useUnorderedNonce(owner, permit.nonce);
signature.verify(_hashTypedData(dataHash), owner);
unchecked {
for (uint256 i = 0; i < numPermitted; ++i) {
TokenPermissions memory permitted = permit.permitted[i];
uint256 requestedAmount = transferDetails[i].requestedAmount;
if (requestedAmount > permitted.amount) revert InvalidAmount(permitted.amount);
if (requestedAmount != 0) {
ERC20(permitted.token).safeTransferFrom(owner, transferDetails[i].to, requestedAmount);
}
}
}
}
function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external {
nonceBitmap[msg.sender][wordPos] |= mask;
emit UnorderedNonceInvalidation(msg.sender, wordPos, mask);
}
function bitmapPositions(uint256 nonce) private pure returns (uint256 wordPos, uint256 bitPos) {
wordPos = uint248(nonce >> 8);
bitPos = uint8(nonce);
}
function _useUnorderedNonce(address from, uint256 nonce) internal {
(uint256 wordPos, uint256 bitPos) = bitmapPositions(nonce);
uint256 bit = 1 << bitPos;
uint256 flipped = nonceBitmap[from][wordPos] ^= bit;
if (flipped & bit == 0) revert InvalidNonce();
}
}
文件 31 的 35:SignatureVerification.sol
pragma solidity ^0.8.17;
import {IERC1271} from "../interfaces/IERC1271.sol";
library SignatureVerification {
error InvalidSignatureLength();
error InvalidSignature();
error InvalidSigner();
error InvalidContractSignature();
bytes32 constant UPPER_BIT_MASK = (0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
function verify(bytes calldata signature, bytes32 hash, address claimedSigner) internal view {
bytes32 r;
bytes32 s;
uint8 v;
if (claimedSigner.code.length == 0) {
if (signature.length == 65) {
(r, s) = abi.decode(signature, (bytes32, bytes32));
v = uint8(signature[64]);
} else if (signature.length == 64) {
bytes32 vs;
(r, vs) = abi.decode(signature, (bytes32, bytes32));
s = vs & UPPER_BIT_MASK;
v = uint8(uint256(vs >> 255)) + 27;
} else {
revert InvalidSignatureLength();
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) revert InvalidSignature();
if (signer != claimedSigner) revert InvalidSigner();
} else {
bytes4 magicValue = IERC1271(claimedSigner).isValidSignature(hash, signature);
if (magicValue != IERC1271.isValidSignature.selector) revert InvalidContractSignature();
}
}
}
文件 32 的 35:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
文件 33 的 35:Sweepable.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
abstract contract Sweepable is Context, Ownable {
using SafeERC20 for IERC20;
address private _sweeper;
modifier onlySweeper() {
require(sweeper() == _msgSender(), "Sweepable: not the sweeper");
_;
}
modifier notZero(address a) {
require(a != address(0), "Sweepable: cannot be zero address");
_;
}
function sweeper() public view virtual returns (address) {
return _sweeper;
}
function setSweeper(address newSweeper) public virtual onlyOwner notZero(newSweeper) {
_sweeper = newSweeper;
}
function sweepETH(address payable destination) public virtual onlySweeper notZero(destination) {
uint256 balance = address(this).balance;
require(balance > 0, "Sweepable: zero balance");
(bool success, ) = destination.call{value: balance}("");
require(success, "Sweepable: transfer error");
}
function sweepETHAmount(address payable destination, uint256 amount)
public
virtual
onlySweeper
notZero(destination)
{
uint256 balance = address(this).balance;
require(balance >= amount, "Sweepable: insufficient balance");
(bool success, ) = destination.call{value: amount}("");
require(success, "Sweepable: transfer error");
}
function sweepToken(address _token, address destination) public virtual onlySweeper notZero(destination) {
IERC20 token = IERC20(_token);
uint256 balance = token.balanceOf(address(this));
require(balance > 0, "Sweepable: zero balance");
token.safeTransfer(destination, balance);
}
function sweepTokenAmount(
address _token,
address destination,
uint256 amount
) public virtual onlySweeper notZero(destination) {
IERC20 token = IERC20(_token);
uint256 balance = token.balanceOf(address(this));
require(balance >= amount, "Sweepable: insufficient balance");
token.safeTransfer(destination, amount);
}
}
文件 34 的 35:Transfers.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@uniswap/universal-router/contracts/interfaces/IUniversalRouter.sol";
import {Commands as UniswapCommands} from "@uniswap/universal-router/contracts/libraries/Commands.sol";
import {Constants as UniswapConstants} from "@uniswap/universal-router/contracts/libraries/Constants.sol";
import "../interfaces/IWrappedNativeCurrency.sol";
import "../interfaces/ITransfers.sol";
import "../utils/Sweepable.sol";
import "../permit2/src/Permit2.sol";
bytes32 constant V3_INVALID_SWAP = keccak256(hex"316cf0eb");
bytes32 constant V3_TOO_LITTLE_RECEIVED = keccak256(hex"39d35496");
bytes32 constant V3_TOO_MUCH_REQUESTED = keccak256(hex"739dbe52");
bytes32 constant V3_INVALID_AMOUNT_OUT = keccak256(hex"d4e0248e");
bytes32 constant V3_INVALID_CALLER = keccak256(hex"32b13d91");
contract Transfers is Context, Ownable, Pausable, ReentrancyGuard, Sweepable, ITransfers {
using SafeERC20 for IERC20;
using SafeERC20 for IWrappedNativeCurrency;
mapping(address => address) private feeDestinations;
mapping(address => mapping(bytes16 => bool)) private processedTransferIntents;
address private immutable NATIVE_CURRENCY = address(0);
IUniversalRouter private immutable uniswap;
Permit2 public immutable permit2;
IWrappedNativeCurrency private immutable wrappedNativeCurrency;
constructor(
IUniversalRouter _uniswap,
Permit2 _permit2,
address _initialOperator,
address _initialFeeDestination,
IWrappedNativeCurrency _wrappedNativeCurrency
) {
require(
address(_uniswap) != address(0) &&
address(_permit2) != address(0) &&
address(_wrappedNativeCurrency) != address(0) &&
_initialOperator != address(0) &&
_initialFeeDestination != address(0),
"invalid constructor parameters"
);
uniswap = _uniswap;
permit2 = _permit2;
wrappedNativeCurrency = _wrappedNativeCurrency;
feeDestinations[_initialOperator] = _initialFeeDestination;
}
modifier validIntent(TransferIntent calldata _intent) {
bytes32 hash = keccak256(
abi.encodePacked(
_intent.recipientAmount,
_intent.deadline,
_intent.recipient,
_intent.recipientCurrency,
_intent.refundDestination,
_intent.feeAmount,
_intent.id,
_intent.operator,
block.chainid,
_msgSender(),
address(this)
)
);
bytes32 signedMessageHash;
if (_intent.prefix.length == 0) {
signedMessageHash = ECDSA.toEthSignedMessageHash(hash);
} else {
signedMessageHash = keccak256(abi.encodePacked(_intent.prefix, hash));
}
address signer = ECDSA.recover(signedMessageHash, _intent.signature);
if (signer != _intent.operator) {
revert InvalidSignature();
}
if (_intent.deadline < block.timestamp) {
revert ExpiredIntent();
}
if (_intent.recipient == address(0)) {
revert NullRecipient();
}
if (processedTransferIntents[_intent.operator][_intent.id]) {
revert AlreadyProcessed();
}
_;
}
modifier operatorIsRegistered(TransferIntent calldata _intent) {
if (feeDestinations[_intent.operator] == address(0)) revert OperatorNotRegistered();
_;
}
modifier exactValueSent(TransferIntent calldata _intent) {
uint256 neededAmount = _intent.recipientAmount + _intent.feeAmount;
if (msg.value > neededAmount) {
revert InvalidNativeAmount(int256(msg.value - neededAmount));
} else if (msg.value < neededAmount) {
revert InvalidNativeAmount(-int256(neededAmount - msg.value));
}
_;
}
function transferNative(TransferIntent calldata _intent)
external
payable
override
nonReentrant
whenNotPaused
validIntent(_intent)
operatorIsRegistered(_intent)
exactValueSent(_intent)
{
if (_intent.recipientCurrency != NATIVE_CURRENCY) revert IncorrectCurrency(NATIVE_CURRENCY);
if (msg.value > 0) {
transferFundsToDestinations(_intent);
}
succeedPayment(_intent, msg.value, NATIVE_CURRENCY);
}
function transferToken(
TransferIntent calldata _intent,
Permit2SignatureTransferData calldata _signatureTransferData
) external override nonReentrant whenNotPaused validIntent(_intent) operatorIsRegistered(_intent) {
if (
_intent.recipientCurrency == NATIVE_CURRENCY ||
_signatureTransferData.permit.permitted.token != _intent.recipientCurrency
) {
revert IncorrectCurrency(_signatureTransferData.permit.permitted.token);
}
IERC20 erc20 = IERC20(_intent.recipientCurrency);
uint256 neededAmount = _intent.recipientAmount + _intent.feeAmount;
uint256 payerBalance = erc20.balanceOf(_msgSender());
if (payerBalance < neededAmount) {
revert InsufficientBalance(neededAmount - payerBalance);
}
if (neededAmount > 0) {
if (
_signatureTransferData.transferDetails.to != address(this) ||
_signatureTransferData.transferDetails.requestedAmount != neededAmount
) {
revert InvalidTransferDetails();
}
uint256 balanceBefore = erc20.balanceOf(address(this));
permit2.permitTransferFrom(
_signatureTransferData.permit,
_signatureTransferData.transferDetails,
_msgSender(),
_signatureTransferData.signature
);
revertIfInexactTransfer(neededAmount, balanceBefore, erc20, address(this));
transferFundsToDestinations(_intent);
}
succeedPayment(_intent, neededAmount, _intent.recipientCurrency);
}
function transferTokenPreApproved(TransferIntent calldata _intent)
external
override
nonReentrant
whenNotPaused
validIntent(_intent)
operatorIsRegistered(_intent)
{
if (_intent.recipientCurrency == NATIVE_CURRENCY) {
revert IncorrectCurrency(_intent.recipientCurrency);
}
IERC20 erc20 = IERC20(_intent.recipientCurrency);
uint256 neededAmount = _intent.recipientAmount + _intent.feeAmount;
uint256 payerBalance = erc20.balanceOf(_msgSender());
if (payerBalance < neededAmount) {
revert InsufficientBalance(neededAmount - payerBalance);
}
uint256 allowance = erc20.allowance(_msgSender(), address(this));
if (allowance < neededAmount) {
revert InsufficientAllowance(neededAmount - allowance);
}
if (neededAmount > 0) {
uint256 balanceBefore = erc20.balanceOf(address(this));
erc20.safeTransferFrom(_msgSender(), address(this), neededAmount);
revertIfInexactTransfer(neededAmount, balanceBefore, erc20, address(this));
transferFundsToDestinations(_intent);
}
succeedPayment(_intent, neededAmount, _intent.recipientCurrency);
}
function wrapAndTransfer(TransferIntent calldata _intent)
external
payable
override
nonReentrant
whenNotPaused
validIntent(_intent)
operatorIsRegistered(_intent)
exactValueSent(_intent)
{
if (_intent.recipientCurrency != address(wrappedNativeCurrency)) {
revert IncorrectCurrency(NATIVE_CURRENCY);
}
if (msg.value > 0) {
wrappedNativeCurrency.deposit{value: msg.value}();
transferFundsToDestinations(_intent);
}
succeedPayment(_intent, msg.value, NATIVE_CURRENCY);
}
function unwrapAndTransfer(
TransferIntent calldata _intent,
Permit2SignatureTransferData calldata _signatureTransferData
) external override nonReentrant whenNotPaused validIntent(_intent) operatorIsRegistered(_intent) {
if (
_intent.recipientCurrency != NATIVE_CURRENCY ||
_signatureTransferData.permit.permitted.token != address(wrappedNativeCurrency)
) {
revert IncorrectCurrency(_signatureTransferData.permit.permitted.token);
}
uint256 neededAmount = _intent.recipientAmount + _intent.feeAmount;
uint256 payerBalance = wrappedNativeCurrency.balanceOf(_msgSender());
if (payerBalance < neededAmount) {
revert InsufficientBalance(neededAmount - payerBalance);
}
if (neededAmount > 0) {
if (
_signatureTransferData.transferDetails.to != address(this) ||
_signatureTransferData.transferDetails.requestedAmount != neededAmount
) {
revert InvalidTransferDetails();
}
permit2.permitTransferFrom(
_signatureTransferData.permit,
_signatureTransferData.transferDetails,
_msgSender(),
_signatureTransferData.signature
);
unwrapAndTransferFundsToDestinations(_intent);
}
succeedPayment(_intent, neededAmount, address(wrappedNativeCurrency));
}
function unwrapAndTransferPreApproved(TransferIntent calldata _intent)
external
override
nonReentrant
whenNotPaused
validIntent(_intent)
operatorIsRegistered(_intent)
{
if (_intent.recipientCurrency != NATIVE_CURRENCY) {
revert IncorrectCurrency(address(wrappedNativeCurrency));
}
uint256 neededAmount = _intent.recipientAmount + _intent.feeAmount;
uint256 payerBalance = wrappedNativeCurrency.balanceOf(_msgSender());
if (payerBalance < neededAmount) {
revert InsufficientBalance(neededAmount - payerBalance);
}
uint256 allowance = wrappedNativeCurrency.allowance(_msgSender(), address(this));
if (allowance < neededAmount) {
revert InsufficientAllowance(neededAmount - allowance);
}
if (neededAmount > 0) {
wrappedNativeCurrency.safeTransferFrom(_msgSender(), address(this), neededAmount);
unwrapAndTransferFundsToDestinations(_intent);
}
succeedPayment(_intent, neededAmount, address(wrappedNativeCurrency));
}
function swapAndTransferUniswapV3Native(TransferIntent calldata _intent, uint24 poolFeesTier)
external
payable
override
nonReentrant
whenNotPaused
validIntent(_intent)
operatorIsRegistered(_intent)
{
if (
_intent.recipientCurrency == NATIVE_CURRENCY || _intent.recipientCurrency == address(wrappedNativeCurrency)
) {
revert IncorrectCurrency(NATIVE_CURRENCY);
}
uint256 amountSwapped = 0;
if (msg.value > 0) {
amountSwapped = swapTokens(_intent, address(wrappedNativeCurrency), msg.value, poolFeesTier);
}
succeedPayment(_intent, amountSwapped, NATIVE_CURRENCY);
}
function swapAndTransferUniswapV3Token(
TransferIntent calldata _intent,
Permit2SignatureTransferData calldata _signatureTransferData,
uint24 poolFeesTier
) external override nonReentrant whenNotPaused validIntent(_intent) operatorIsRegistered(_intent) {
IERC20 tokenIn = IERC20(_signatureTransferData.permit.permitted.token);
if (address(tokenIn) == _intent.recipientCurrency) {
revert IncorrectCurrency(address(tokenIn));
}
if (_signatureTransferData.transferDetails.to != address(this)) {
revert InvalidTransferDetails();
}
uint256 maxWillingToPay = _signatureTransferData.transferDetails.requestedAmount;
uint256 amountSwapped = 0;
if (maxWillingToPay > 0) {
uint256 balanceBefore = tokenIn.balanceOf(address(this));
permit2.permitTransferFrom(
_signatureTransferData.permit,
_signatureTransferData.transferDetails,
_msgSender(),
_signatureTransferData.signature
);
revertIfInexactTransfer(maxWillingToPay, balanceBefore, tokenIn, address(this));
amountSwapped = swapTokens(_intent, address(tokenIn), maxWillingToPay, poolFeesTier);
}
succeedPayment(_intent, amountSwapped, address(tokenIn));
}
function swapAndTransferUniswapV3TokenPreApproved(
TransferIntent calldata _intent,
address _tokenIn,
uint256 maxWillingToPay,
uint24 poolFeesTier
) external override nonReentrant whenNotPaused validIntent(_intent) operatorIsRegistered(_intent) {
IERC20 tokenIn = IERC20(_tokenIn);
if (address(tokenIn) == _intent.recipientCurrency) {
revert IncorrectCurrency(address(tokenIn));
}
uint256 payerBalance = tokenIn.balanceOf(_msgSender());
if (payerBalance < maxWillingToPay) {
revert InsufficientBalance(maxWillingToPay - payerBalance);
}
uint256 allowance = tokenIn.allowance(_msgSender(), address(this));
if (allowance < maxWillingToPay) {
revert InsufficientAllowance(maxWillingToPay - allowance);
}
uint256 amountSwapped = 0;
if (maxWillingToPay > 0) {
uint256 balanceBefore = tokenIn.balanceOf(address(this));
tokenIn.safeTransferFrom(_msgSender(), address(this), maxWillingToPay);
revertIfInexactTransfer(maxWillingToPay, balanceBefore, tokenIn, address(this));
amountSwapped = swapTokens(_intent, address(tokenIn), maxWillingToPay, poolFeesTier);
}
succeedPayment(_intent, amountSwapped, address(tokenIn));
}
function swapTokens(
TransferIntent calldata _intent,
address tokenIn,
uint256 maxAmountWillingToPay,
uint24 poolFeesTier
) internal returns (uint256) {
address tokenOut = _intent.recipientCurrency == NATIVE_CURRENCY
? address(wrappedNativeCurrency)
: _intent.recipientCurrency;
uint256 neededAmount = _intent.recipientAmount + _intent.feeAmount;
bytes memory uniswap_commands;
bytes[] memory uniswap_inputs;
bytes memory swapPath = abi.encodePacked(tokenOut, poolFeesTier, tokenIn);
bytes memory swapParams = abi.encode(address(uniswap), neededAmount, maxAmountWillingToPay, swapPath, false);
bytes memory transferToRecipient = abi.encode(
_intent.recipientCurrency,
_intent.recipient,
_intent.recipientAmount
);
bytes memory collectFees = abi.encode(
_intent.recipientCurrency,
feeDestinations[_intent.operator],
_intent.feeAmount
);
uint256 payerBalanceBefore;
uint256 routerBalanceBefore;
uint256 feeBalanceBefore;
uint256 recipientBalanceBefore;
if (msg.value > 0) {
payerBalanceBefore = _msgSender().balance + msg.value;
routerBalanceBefore = address(uniswap).balance + IERC20(wrappedNativeCurrency).balanceOf(address(uniswap));
feeBalanceBefore = IERC20(tokenOut).balanceOf(feeDestinations[_intent.operator]);
recipientBalanceBefore = IERC20(tokenOut).balanceOf(_intent.recipient);
uniswap_commands = abi.encodePacked(
bytes1(uint8(UniswapCommands.WRAP_ETH)),
bytes1(uint8(UniswapCommands.V3_SWAP_EXACT_OUT)),
bytes1(uint8(UniswapCommands.TRANSFER)),
bytes1(uint8(UniswapCommands.TRANSFER)),
bytes1(uint8(UniswapCommands.UNWRAP_WETH)),
bytes1(uint8(UniswapCommands.SWEEP))
);
uniswap_inputs = new bytes[](6);
uniswap_inputs[0] = abi.encode(address(uniswap), msg.value);
uniswap_inputs[1] = swapParams;
uniswap_inputs[2] = collectFees;
uniswap_inputs[3] = transferToRecipient;
uniswap_inputs[4] = abi.encode(address(uniswap), 0);
uniswap_inputs[5] = abi.encode(UniswapConstants.ETH, _msgSender(), 0);
} else {
payerBalanceBefore = IERC20(tokenIn).balanceOf(_msgSender()) + maxAmountWillingToPay;
routerBalanceBefore = IERC20(tokenIn).balanceOf(address(uniswap));
if (_intent.recipientCurrency == NATIVE_CURRENCY) {
uniswap_commands = abi.encodePacked(
bytes1(uint8(UniswapCommands.V3_SWAP_EXACT_OUT)),
bytes1(uint8(UniswapCommands.UNWRAP_WETH)),
bytes1(uint8(UniswapCommands.TRANSFER)),
bytes1(uint8(UniswapCommands.TRANSFER)),
bytes1(uint8(UniswapCommands.SWEEP))
);
uniswap_inputs = new bytes[](5);
uniswap_inputs[0] = swapParams;
uniswap_inputs[1] = abi.encode(address(uniswap), neededAmount);
uniswap_inputs[2] = collectFees;
uniswap_inputs[3] = transferToRecipient;
uniswap_inputs[4] = abi.encode(tokenIn, _msgSender(), 0);
} else {
feeBalanceBefore = IERC20(tokenOut).balanceOf(feeDestinations[_intent.operator]);
recipientBalanceBefore = IERC20(tokenOut).balanceOf(_intent.recipient);
uniswap_commands = abi.encodePacked(
bytes1(uint8(UniswapCommands.V3_SWAP_EXACT_OUT)),
bytes1(uint8(UniswapCommands.TRANSFER)),
bytes1(uint8(UniswapCommands.TRANSFER)),
bytes1(uint8(UniswapCommands.SWEEP))
);
uniswap_inputs = new bytes[](4);
uniswap_inputs[0] = swapParams;
uniswap_inputs[1] = collectFees;
uniswap_inputs[2] = transferToRecipient;
uniswap_inputs[3] = abi.encode(tokenIn, _msgSender(), 0);
}
IERC20(tokenIn).safeTransfer(address(uniswap), maxAmountWillingToPay);
}
try uniswap.execute{value: msg.value}(uniswap_commands, uniswap_inputs, _intent.deadline) {
if (_intent.recipientCurrency != NATIVE_CURRENCY) {
revertIfInexactTransfer(
_intent.feeAmount,
feeBalanceBefore,
IERC20(tokenOut),
feeDestinations[_intent.operator]
);
revertIfInexactTransfer(
_intent.recipientAmount,
recipientBalanceBefore,
IERC20(tokenOut),
_intent.recipient
);
}
uint256 payerBalanceAfter;
uint256 routerBalanceAfter;
if (msg.value > 0) {
payerBalanceAfter = _msgSender().balance;
routerBalanceAfter =
address(uniswap).balance +
IERC20(wrappedNativeCurrency).balanceOf(address(uniswap));
} else {
payerBalanceAfter = IERC20(tokenIn).balanceOf(_msgSender());
routerBalanceAfter = IERC20(tokenIn).balanceOf(address(uniswap));
}
return (payerBalanceBefore + routerBalanceBefore) - (payerBalanceAfter + routerBalanceAfter);
} catch Error(string memory reason) {
revert SwapFailedString(reason);
} catch (bytes memory reason) {
bytes32 reasonHash = keccak256(reason);
if (reasonHash == V3_INVALID_SWAP) {
revert SwapFailedString("V3InvalidSwap");
} else if (reasonHash == V3_TOO_LITTLE_RECEIVED) {
revert SwapFailedString("V3TooLittleReceived");
} else if (reasonHash == V3_TOO_MUCH_REQUESTED) {
revert SwapFailedString("V3TooMuchRequested");
} else if (reasonHash == V3_INVALID_AMOUNT_OUT) {
revert SwapFailedString("V3InvalidAmountOut");
} else if (reasonHash == V3_INVALID_CALLER) {
revert SwapFailedString("V3InvalidCaller");
} else {
revert SwapFailedBytes(reason);
}
}
}
function transferFundsToDestinations(TransferIntent calldata _intent) internal {
if (_intent.recipientCurrency == NATIVE_CURRENCY) {
if (_intent.recipientAmount > 0) {
sendNative(_intent.recipient, _intent.recipientAmount, false);
}
if (_intent.feeAmount > 0) {
sendNative(feeDestinations[_intent.operator], _intent.feeAmount, false);
}
} else {
IERC20 requestedCurrency = IERC20(_intent.recipientCurrency);
if (_intent.recipientAmount > 0) {
requestedCurrency.safeTransfer(_intent.recipient, _intent.recipientAmount);
}
if (_intent.feeAmount > 0) {
requestedCurrency.safeTransfer(feeDestinations[_intent.operator], _intent.feeAmount);
}
}
}
function unwrapAndTransferFundsToDestinations(TransferIntent calldata _intent) internal {
uint256 amountToWithdraw = _intent.recipientAmount + _intent.feeAmount;
if (_intent.recipientCurrency == NATIVE_CURRENCY && amountToWithdraw > 0) {
wrappedNativeCurrency.withdraw(amountToWithdraw);
}
transferFundsToDestinations(_intent);
}
function succeedPayment(
TransferIntent calldata _intent,
uint256 spentAmount,
address spentCurrency
) internal {
processedTransferIntents[_intent.operator][_intent.id] = true;
emit Transferred(_intent.operator, _intent.id, _intent.recipient, _msgSender(), spentAmount, spentCurrency);
}
function sendNative(
address destination,
uint256 amount,
bool isRefund
) internal {
(bool success, bytes memory data) = payable(destination).call{value: amount}("");
if (!success) {
revert NativeTransferFailed(destination, amount, isRefund, data);
}
}
function revertIfInexactTransfer(
uint256 expectedDiff,
uint256 balanceBefore,
IERC20 token,
address target
) internal view {
uint256 balanceAfter = token.balanceOf(target);
if (balanceAfter - balanceBefore != expectedDiff) {
revert InexactTransfer();
}
}
function registerOperatorWithFeeDestination(address _feeDestination) external {
feeDestinations[_msgSender()] = _feeDestination;
emit OperatorRegistered(_msgSender(), _feeDestination);
}
function registerOperator() external {
feeDestinations[_msgSender()] = _msgSender();
emit OperatorRegistered(_msgSender(), _msgSender());
}
function unregisterOperator() external {
delete feeDestinations[_msgSender()];
emit OperatorUnregistered(_msgSender());
}
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
receive() external payable {
require(msg.sender == address(wrappedNativeCurrency), "only payable for unwrapping");
}
}
文件 35 的 35:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"contracts/transfers/Transfers.sol": "Transfers"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 100000
},
"remappings": [],
"viaIR": true
}
[{"inputs":[{"internalType":"contract IUniversalRouter","name":"_uniswap","type":"address"},{"internalType":"contract Permit2","name":"_permit2","type":"address"},{"internalType":"address","name":"_initialOperator","type":"address"},{"internalType":"address","name":"_initialFeeDestination","type":"address"},{"internalType":"contract IWrappedNativeCurrency","name":"_wrappedNativeCurrency","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyProcessed","type":"error"},{"inputs":[],"name":"ExpiredIntent","type":"error"},{"inputs":[{"internalType":"address","name":"attemptedCurrency","type":"address"}],"name":"IncorrectCurrency","type":"error"},{"inputs":[],"name":"InexactTransfer","type":"error"},{"inputs":[{"internalType":"uint256","name":"difference","type":"uint256"}],"name":"InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"uint256","name":"difference","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"int256","name":"difference","type":"int256"}],"name":"InvalidNativeAmount","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidTransferDetails","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isRefund","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"NativeTransferFailed","type":"error"},{"inputs":[],"name":"NullRecipient","type":"error"},{"inputs":[],"name":"OperatorNotRegistered","type":"error"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"SwapFailedBytes","type":"error"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"name":"SwapFailedString","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"address","name":"feeDestination","type":"address"}],"name":"OperatorRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorUnregistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bytes16","name":"id","type":"bytes16"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"spentAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"spentCurrency","type":"address"}],"name":"Transferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permit2","outputs":[{"internalType":"contract Permit2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registerOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeDestination","type":"address"}],"name":"registerOperatorWithFeeDestination","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSweeper","type":"address"}],"name":"setSweeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"recipientAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address","name":"recipientCurrency","type":"address"},{"internalType":"address","name":"refundDestination","type":"address"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes16","name":"id","type":"bytes16"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"prefix","type":"bytes"}],"internalType":"struct TransferIntent","name":"_intent","type":"tuple"},{"internalType":"uint24","name":"poolFeesTier","type":"uint24"}],"name":"swapAndTransferUniswapV3Native","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"recipientAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address","name":"recipientCurrency","type":"address"},{"internalType":"address","name":"refundDestination","type":"address"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes16","name":"id","type":"bytes16"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"prefix","type":"bytes"}],"internalType":"struct TransferIntent","name":"_intent","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ISignatureTransfer.TokenPermissions","name":"permitted","type":"tuple"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ISignatureTransfer.PermitTransferFrom","name":"permit","type":"tuple"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"requestedAmount","type":"uint256"}],"internalType":"struct ISignatureTransfer.SignatureTransferDetails","name":"transferDetails","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2SignatureTransferData","name":"_signatureTransferData","type":"tuple"},{"internalType":"uint24","name":"poolFeesTier","type":"uint24"}],"name":"swapAndTransferUniswapV3Token","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"recipientAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address","name":"recipientCurrency","type":"address"},{"internalType":"address","name":"refundDestination","type":"address"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes16","name":"id","type":"bytes16"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"prefix","type":"bytes"}],"internalType":"struct TransferIntent","name":"_intent","type":"tuple"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"uint256","name":"maxWillingToPay","type":"uint256"},{"internalType":"uint24","name":"poolFeesTier","type":"uint24"}],"name":"swapAndTransferUniswapV3TokenPreApproved","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"destination","type":"address"}],"name":"sweepETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"destination","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sweepETHAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"destination","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sweepTokenAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sweeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"recipientAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address","name":"recipientCurrency","type":"address"},{"internalType":"address","name":"refundDestination","type":"address"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes16","name":"id","type":"bytes16"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"prefix","type":"bytes"}],"internalType":"struct TransferIntent","name":"_intent","type":"tuple"}],"name":"transferNative","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"recipientAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address","name":"recipientCurrency","type":"address"},{"internalType":"address","name":"refundDestination","type":"address"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes16","name":"id","type":"bytes16"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"prefix","type":"bytes"}],"internalType":"struct TransferIntent","name":"_intent","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ISignatureTransfer.TokenPermissions","name":"permitted","type":"tuple"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ISignatureTransfer.PermitTransferFrom","name":"permit","type":"tuple"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"requestedAmount","type":"uint256"}],"internalType":"struct ISignatureTransfer.SignatureTransferDetails","name":"transferDetails","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2SignatureTransferData","name":"_signatureTransferData","type":"tuple"}],"name":"transferToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"recipientAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address","name":"recipientCurrency","type":"address"},{"internalType":"address","name":"refundDestination","type":"address"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes16","name":"id","type":"bytes16"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"prefix","type":"bytes"}],"internalType":"struct TransferIntent","name":"_intent","type":"tuple"}],"name":"transferTokenPreApproved","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unregisterOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"recipientAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address","name":"recipientCurrency","type":"address"},{"internalType":"address","name":"refundDestination","type":"address"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes16","name":"id","type":"bytes16"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"prefix","type":"bytes"}],"internalType":"struct TransferIntent","name":"_intent","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ISignatureTransfer.TokenPermissions","name":"permitted","type":"tuple"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ISignatureTransfer.PermitTransferFrom","name":"permit","type":"tuple"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"requestedAmount","type":"uint256"}],"internalType":"struct ISignatureTransfer.SignatureTransferDetails","name":"transferDetails","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2SignatureTransferData","name":"_signatureTransferData","type":"tuple"}],"name":"unwrapAndTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"recipientAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address","name":"recipientCurrency","type":"address"},{"internalType":"address","name":"refundDestination","type":"address"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes16","name":"id","type":"bytes16"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"prefix","type":"bytes"}],"internalType":"struct TransferIntent","name":"_intent","type":"tuple"}],"name":"unwrapAndTransferPreApproved","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"recipientAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address","name":"recipientCurrency","type":"address"},{"internalType":"address","name":"refundDestination","type":"address"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes16","name":"id","type":"bytes16"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"prefix","type":"bytes"}],"internalType":"struct TransferIntent","name":"_intent","type":"tuple"}],"name":"wrapAndTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]