编译器
0.8.17+commit.8df45f5f
文件 1 的 14: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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 14:CommandBuilder.sol
pragma solidity 0.8.17;
library CommandBuilder {
uint256 constant IDX_VARIABLE_LENGTH = 0x80;
uint256 constant IDX_VALUE_MASK = 0x7f;
uint256 constant IDX_END_OF_ARGS = 0xff;
uint256 constant IDX_USE_STATE = 0xfe;
function buildInputs(
bytes[] memory state,
bytes4 selector,
bytes32 indices
) internal view returns (bytes memory ret) {
uint256 count;
uint256 free;
bytes memory stateData;
uint256 idx;
for (uint256 i; i < 32;) {
idx = uint8(indices[i]);
if (idx == IDX_END_OF_ARGS) break;
if (idx & IDX_VARIABLE_LENGTH != 0) {
if (idx == IDX_USE_STATE) {
if (stateData.length == 0) {
stateData = abi.encode(state);
}
count += stateData.length;
} else {
uint256 arglen = state[idx & IDX_VALUE_MASK].length;
require(
arglen % 32 == 0,
"Dynamic state variables must be a multiple of 32 bytes"
);
count += arglen + 32;
}
} else {
require(
state[idx & IDX_VALUE_MASK].length == 32,
"Static state variables must be 32 bytes"
);
count += 32;
}
unchecked{free += 32;}
unchecked{++i;}
}
ret = new bytes(count + 4);
assembly {
mstore(add(ret, 32), selector)
}
count = 0;
for (uint256 i; i < 32;) {
idx = uint8(indices[i]);
if (idx == IDX_END_OF_ARGS) break;
if (idx & IDX_VARIABLE_LENGTH != 0) {
if (idx == IDX_USE_STATE) {
assembly {
mstore(add(add(ret, 36), count), free)
}
memcpy(stateData, 32, ret, free + 4, stateData.length - 32);
free += stateData.length - 32;
} else {
uint256 arglen = state[idx & IDX_VALUE_MASK].length;
assembly {
mstore(add(add(ret, 36), count), free)
}
memcpy(
state[idx & IDX_VALUE_MASK],
0,
ret,
free + 4,
arglen
);
free += arglen;
}
} else {
bytes memory statevar = state[idx & IDX_VALUE_MASK];
assembly {
mstore(add(add(ret, 36), count), mload(add(statevar, 32)))
}
}
unchecked{count += 32;}
unchecked{++i;}
}
}
function writeOutputs(
bytes[] memory state,
bytes1 index,
bytes memory output
) internal view returns (bytes[] memory) {
uint256 idx = uint8(index);
if (idx == IDX_END_OF_ARGS) return state;
if (idx & IDX_VARIABLE_LENGTH != 0) {
if (idx == IDX_USE_STATE) {
state = abi.decode(output, (bytes[]));
} else {
uint256 argptr;
assembly {
argptr := mload(add(output, 32))
}
require(
argptr == 32,
"Only one return value permitted (variable)"
);
assembly {
mstore(add(output, 32), sub(mload(output), 32))
mstore(
add(add(state, 32), mul(and(idx, IDX_VALUE_MASK), 32)),
add(output, 32)
)
}
}
} else {
require(output.length >= 32, "Return at least 32 bytes");
if (output.length > 32) {
bytes memory newOutput = new bytes(32);
memcpy(output, 0, newOutput, 0, output.length);
output = newOutput;
}
state[idx & IDX_VALUE_MASK] = output;
}
return state;
}
function writeTuple(
bytes[] memory state,
bytes1 index,
bytes memory output
) internal view {
uint256 idx = uint256(uint8(index));
if (idx == IDX_END_OF_ARGS) return;
bytes memory entry = state[idx] = new bytes(output.length + 32);
memcpy(output, 0, entry, 32, output.length);
assembly {
let l := mload(output)
mstore(add(entry, 32), l)
}
}
function memcpy(
bytes memory src,
uint256 srcidx,
bytes memory dest,
uint256 destidx,
uint256 len
) internal view {
assembly {
pop(
staticcall(
gas(),
4,
add(add(src, 32), srcidx),
len,
add(add(dest, 32), destidx),
len
)
)
}
}
}
文件 3 的 14: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;
}
}
文件 4 的 14:ERC2771Context.sol
pragma solidity ^0.8.9;
import "../utils/Context.sol";
abstract contract ERC2771Context is Context {
address private immutable _trustedForwarder;
constructor(address trustedForwarder) {
_trustedForwarder = trustedForwarder;
}
function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
return forwarder == _trustedForwarder;
}
function _msgSender() internal view virtual override returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
assembly {
sender := shr(96, calldataload(sub(calldatasize(), 20)))
}
} else {
return super._msgSender();
}
}
function _msgData() internal view virtual override returns (bytes calldata) {
if (isTrustedForwarder(msg.sender)) {
return msg.data[:msg.data.length - 20];
} else {
return super._msgData();
}
}
}
文件 5 的 14: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);
}
文件 6 的 14:IPermit2.sol
pragma solidity ^0.8.17;
struct TokenPermissions {
address token;
uint256 amount;
}
struct PermitTransferFrom {
TokenPermissions permitted;
uint256 nonce;
uint256 deadline;
}
struct SignatureTransferDetails {
address to;
uint256 requestedAmount;
}
interface IPermit2 {
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
function allowance(
address,
address,
address
) external view returns (uint160, uint48, uint48);
}
error SignatureExpired(uint256 signatureDeadline);
error InvalidNonce();
文件 7 的 14:IRTokenZapper.sol
pragma solidity 0.8.17;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
struct Call {
address to;
bytes data;
uint256 value;
}
struct ZapERC20Params {
IERC20 tokenIn;
uint256 amountIn;
bytes32[] commands;
bytes[] state;
IERC20[] tokens;
uint256 amountOut;
IERC20 tokenOut;
}
interface FacadeRead {
function maxIssuable(RToken rToken, address account) external returns (uint256);
}
interface RToken {
function issueTo(address recipient, uint256 amount) external;
}
文件 8 的 14:IWrappedNative.sol
pragma solidity 0.8.17;
interface IWrappedNative {
function deposit() external payable;
function withdraw(uint256 amount) external;
function balanceOf(address account) external view returns (uint256);
}
文件 9 的 14:PreventTampering.sol
pragma solidity 0.8.17;
abstract contract PreventTampering {
modifier revertOnCodeHashChange() {
bytes32 hashBefore;
assembly {
hashBefore := extcodehash(address())
}
_;
bytes32 hashPostExecution;
assembly {
hashPostExecution := extcodehash(address())
}
require(hashPostExecution == hashBefore, "PreventTampering: Code has changed");
}
}
contract SelfDestruct {
function destroy() external {
selfdestruct(payable(msg.sender));
}
function doNothing() external {}
}
contract TestPreventTampering is PreventTampering {
function shouldNotRevert() external {
SelfDestruct selfDestruct = new SelfDestruct();
address(selfDestruct).delegatecall(abi.encodeWithSelector(selfDestruct.destroy.selector));
}
function shouldRevert() revertOnCodeHashChange() external {
SelfDestruct selfDestruct = new SelfDestruct();
address(selfDestruct).delegatecall(abi.encodeWithSelector(selfDestruct.destroy.selector));
}
function markedRevertOnCodeHashChangeDontRevert() revertOnCodeHashChange() external {
SelfDestruct selfDestruct = new SelfDestruct();
address(selfDestruct).delegatecall(abi.encodeWithSelector(selfDestruct.doNothing.selector));
}
}
文件 10 的 14: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() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
}
文件 11 的 14: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");
}
}
}
文件 12 的 14:VM.sol
pragma solidity 0.8.17;
import "./CommandBuilder.sol";
abstract contract VM {
using CommandBuilder for bytes[];
uint256 constant FLAG_CT_DELEGATECALL = 0x00;
uint256 constant FLAG_CT_CALL = 0x01;
uint256 constant FLAG_CT_STATICCALL = 0x02;
uint256 constant FLAG_CT_VALUECALL = 0x03;
uint256 constant FLAG_CT_MASK = 0x03;
uint256 constant FLAG_EXTENDED_COMMAND = 0x80;
uint256 constant FLAG_TUPLE_RETURN = 0x40;
uint256 constant SHORT_COMMAND_FILL = 0x000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
address immutable self;
error ExecutionFailed(
uint256 command_index,
address target,
string message
);
constructor() {
self = address(this);
}
function _execute(bytes32[] calldata commands, bytes[] memory state)
internal returns (bytes[] memory)
{
bytes32 command;
uint256 flags;
bytes32 indices;
bool success;
bytes memory outdata;
uint256 commandsLength = commands.length;
for (uint256 i; i < commandsLength;) {
command = commands[i];
flags = uint256(uint8(bytes1(command << 32)));
if (flags & FLAG_EXTENDED_COMMAND != 0) {
indices = commands[i++];
} else {
indices = bytes32(uint256(command << 40) | SHORT_COMMAND_FILL);
}
if (flags & FLAG_CT_MASK == FLAG_CT_DELEGATECALL) {
(success, outdata) = address(uint160(uint256(command))).delegatecall(
state.buildInputs(
bytes4(command),
indices
)
);
} else if (flags & FLAG_CT_MASK == FLAG_CT_CALL) {
(success, outdata) = address(uint160(uint256(command))).call(
state.buildInputs(
bytes4(command),
indices
)
);
} else if (flags & FLAG_CT_MASK == FLAG_CT_STATICCALL) {
(success, outdata) = address(uint160(uint256(command))).staticcall(
state.buildInputs(
bytes4(command),
indices
)
);
} else if (flags & FLAG_CT_MASK == FLAG_CT_VALUECALL) {
uint256 calleth;
bytes memory v = state[uint8(bytes1(indices))];
require(v.length == 32, "_execute: value call has no value indicated.");
assembly {
calleth := mload(add(v, 0x20))
}
(success, outdata) = address(uint160(uint256(command))).call{
value: calleth
}(
state.buildInputs(
bytes4(command),
bytes32(uint256(indices << 8) | CommandBuilder.IDX_END_OF_ARGS)
)
);
} else {
revert("Invalid calltype");
}
if (!success) {
if (outdata.length > 0) {
assembly {
outdata := add(outdata, 68)
}
}
revert ExecutionFailed({
command_index: i,
target: address(uint160(uint256(command))),
message: string(outdata)
});
}
if (flags & FLAG_TUPLE_RETURN != 0) {
state.writeTuple(bytes1(command << 88), outdata);
} else {
state = state.writeOutputs(bytes1(command << 88), outdata);
}
unchecked{++i;}
}
return state;
}
}
文件 13 的 14:Zapper.sol
pragma solidity 0.8.17;
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ERC2771Context } from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
import { IWrappedNative } from "./IWrappedNative.sol";
import { FacadeRead, RToken, Call, ZapERC20Params } from "./IRTokenZapper.sol";
import { IPermit2, SignatureTransferDetails, PermitTransferFrom } from "./IPermit2.sol";
import { VM } from "./weiroll/VM.sol";
import { PreventTampering } from "./PreventTampering.sol";
struct ExecuteOutput {
uint256[] dust;
}
contract ZapperExecutor is VM, PreventTampering {
receive() external payable {}
function add(
uint256 a,
uint256 b
) external pure returns (uint256) {
return a + b;
}
function sub(
uint256 a,
uint256 b
) external pure returns (uint256) {
return a - b;
}
function fpMul(
uint256 a,
uint256 b,
uint256 scale
) external pure returns (uint256) {
return (a * b) / scale;
}
function assertLarger(
uint256 a,
uint256 b
) external pure returns (bool) {
require(a > b, "!ASSERT_GT");
return true;
}
function assertEqual(
uint256 a,
uint256 b
) external pure returns (bool) {
require(a == b, "!ASSERT_EQ");
return true;
}
function execute(
bytes32[] calldata commands,
bytes[] memory state,
IERC20[] memory tokens
)
revertOnCodeHashChange
public
payable
returns (ExecuteOutput memory out)
{
_execute(commands, state);
out.dust = new uint256[](tokens.length);
for(uint256 i; i < tokens.length; i++) {
out.dust[i] = tokens[i].balanceOf(address(this));
}
}
function rawCall(
address to,
uint256 value,
bytes calldata data
) external returns (bool success, bytes memory out) {
require(msg.sender == address(this), "ZapperExecutor: Only callable by Zapper");
(success, out) = to.call{value: value}(data);
}
function mintMaxRToken(
FacadeRead facade,
RToken token,
address recipient
) external {
uint256 maxIssueableAmount = facade.maxIssuable(token, address(this));
token.issueTo(recipient, maxIssueableAmount);
}
}
struct ZapperOutput {
uint256[] dust;
uint256 amountOut;
uint256 gasUsed;
}
contract Zapper is ReentrancyGuard {
IWrappedNative internal immutable wrappedNative;
IPermit2 internal immutable permit2;
ZapperExecutor internal immutable zapperExecutor;
constructor(
IWrappedNative wrappedNative_,
IPermit2 permit2_,
ZapperExecutor executor_
) {
wrappedNative = wrappedNative_;
permit2 = permit2_;
zapperExecutor = executor_;
}
function zapInner(ZapERC20Params calldata params) internal returns (ZapperOutput memory out) {
uint256 initialBalance = params.tokenOut.balanceOf(msg.sender);
out.dust = zapperExecutor.execute(
params.commands,
params.state,
params.tokens
).dust;
uint256 newBalance = params.tokenOut.balanceOf(msg.sender);
require(newBalance > initialBalance, "INVALID_NEW_BALANCE");
uint256 difference = newBalance - initialBalance;
require(difference >= params.amountOut, "INSUFFICIENT_OUT");
out.amountOut = difference;
}
receive() external payable {}
function zapERC20(
ZapERC20Params calldata params
) external nonReentrant returns (ZapperOutput memory out) {
uint256 startGas = gasleft();
require(params.amountIn != 0, "INVALID_INPUT_AMOUNT");
require(params.amountOut != 0, "INVALID_OUTPUT_AMOUNT");
SafeERC20.safeTransferFrom(
params.tokenIn,
msg.sender,
address(zapperExecutor),
params.amountIn
);
out = zapInner(params);
out.gasUsed = startGas - gasleft();
}
function zapERC20WithPermit2(
ZapERC20Params calldata params,
PermitTransferFrom calldata permit,
bytes calldata signature
) external nonReentrant returns (ZapperOutput memory out) {
uint256 startGas = gasleft();
require(params.amountIn != 0, "INVALID_INPUT_AMOUNT");
require(params.amountOut != 0, "INVALID_OUTPUT_AMOUNT");
permit2.permitTransferFrom(
permit,
SignatureTransferDetails({
to: address(zapperExecutor),
requestedAmount: params.amountIn
}),
msg.sender,
signature
);
out = zapInner(params);
out.gasUsed = startGas - gasleft();
}
function zapETH(
ZapERC20Params calldata params
) external payable nonReentrant returns (ZapperOutput memory out) {
uint256 startGas = gasleft();
require(address(params.tokenIn) == address(wrappedNative), "INVALID_INPUT_TOKEN");
require(params.amountIn == msg.value, "INVALID_INPUT_AMOUNT");
require(msg.value != 0, "INVALID_INPUT_AMOUNT");
require(params.amountOut != 0, "INVALID_OUTPUT_AMOUNT");
wrappedNative.deposit{ value: msg.value }();
SafeERC20.safeTransfer(
IERC20(address(wrappedNative)),
address(zapperExecutor),
wrappedNative.balanceOf(address(this))
);
out = zapInner(params);
out.gasUsed = startGas - gasleft();
}
function zapToETH(
ZapERC20Params calldata params
) external payable nonReentrant returns (ZapperOutput memory out) {
uint256 startGas = gasleft();
require(params.amountIn != 0, "INVALID_INPUT_AMOUNT");
require(params.amountOut != 0, "INVALID_OUTPUT_AMOUNT");
SafeERC20.safeTransferFrom(
params.tokenIn,
msg.sender,
address(zapperExecutor),
params.amountIn
);
out = zapInner(params);
out.gasUsed = startGas - gasleft();
}
}
文件 14 的 14: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/Zapper.sol": "Zapper"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IWrappedNative","name":"wrappedNative_","type":"address"},{"internalType":"contract IPermit2","name":"permit2_","type":"address"},{"internalType":"contract ZapperExecutor","name":"executor_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bytes32[]","name":"commands","type":"bytes32[]"},{"internalType":"bytes[]","name":"state","type":"bytes[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IERC20","name":"tokenOut","type":"address"}],"internalType":"struct ZapERC20Params","name":"params","type":"tuple"}],"name":"zapERC20","outputs":[{"components":[{"internalType":"uint256[]","name":"dust","type":"uint256[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"internalType":"struct ZapperOutput","name":"out","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bytes32[]","name":"commands","type":"bytes32[]"},{"internalType":"bytes[]","name":"state","type":"bytes[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IERC20","name":"tokenOut","type":"address"}],"internalType":"struct ZapERC20Params","name":"params","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenPermissions","name":"permitted","type":"tuple"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct PermitTransferFrom","name":"permit","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"zapERC20WithPermit2","outputs":[{"components":[{"internalType":"uint256[]","name":"dust","type":"uint256[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"internalType":"struct ZapperOutput","name":"out","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bytes32[]","name":"commands","type":"bytes32[]"},{"internalType":"bytes[]","name":"state","type":"bytes[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IERC20","name":"tokenOut","type":"address"}],"internalType":"struct ZapERC20Params","name":"params","type":"tuple"}],"name":"zapETH","outputs":[{"components":[{"internalType":"uint256[]","name":"dust","type":"uint256[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"internalType":"struct ZapperOutput","name":"out","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bytes32[]","name":"commands","type":"bytes32[]"},{"internalType":"bytes[]","name":"state","type":"bytes[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IERC20","name":"tokenOut","type":"address"}],"internalType":"struct ZapERC20Params","name":"params","type":"tuple"}],"name":"zapToETH","outputs":[{"components":[{"internalType":"uint256[]","name":"dust","type":"uint256[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"internalType":"struct ZapperOutput","name":"out","type":"tuple"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]