// pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
// SPDX-License-Identifier: MIT
interface IFreeFromUpTo {
function freeFromUpTo(address from, uint256 value) external returns(uint256 freed);
function freeUpTo(uint256 value) external returns(uint256 freed);
}
interface IBuyMaxAndFree {
function buyMaxAndFree(uint256 deadline) external payable returns(uint256);
function buyAndFree(uint256 amount, uint256 deadline, address payable refundTo) external payable returns(uint256);
function buyAndFree22457070633(uint256 amount) external payable;
}
interface IUniswapV2Pair {
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}
interface IGST2 {
function balanceOf(address who) external view returns (uint256);
function free(uint256 value) external returns (bool success);
function freeUpTo(uint256 value) external returns (uint256 freed);
function freeFrom(address from, uint256 value) external returns (bool success);
function freeFromUpTo(address from, uint256 value) external returns (uint256 freed);
}
interface Uniswap {
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
}
contract Arb {
address payable owner = payable(msg.sender);
modifier onlyOwner() {
require(payable(msg.sender) == owner);
_;
}
// https://github.com/emilianobonassi/gas-saver/blob/master/ChiGasSaver.sol
modifier saveGas() {
// address(this)
address payable sponsor = payable(msg.sender);
uint256 gasStart = gasleft();
_;
uint256 gasSpent = 21000 + gasStart - gasleft() + 16 * msg.data.length;
IFreeFromUpTo chi = IFreeFromUpTo(0x0000000000004946c0e9F43F4Dee607b0eF1fA1c);
chi.freeFromUpTo(sponsor, (gasSpent + 14154) / 41947);
}
constructor() public {
owner = payable(msg.sender);
}
function deposit(uint256 amount) payable public {
require(msg.value == amount);
// nothing else to do!
}
function withdraw() onlyOwner public {
owner.transfer(address(this).balance);
}
struct ExpectedAmounts {
address exchange;
uint reserve0;
// uint reserve1;
uint amount0;
uint amount1;
}
function fastSwapOne(uint blockNumber, uint amountIn, address fromErc20Address, ExpectedAmounts calldata expectedAmounts, uint coinbaseTransfer) external {
require(payable(msg.sender) == owner);
// note, ganache by default uses a block number ~10 higher?
// which is different than mainnet where this will be the actual block being mined
require(block.number >= blockNumber, "e1");
(bool success, bytes memory data) = expectedAmounts.exchange.staticcall(abi.encodeWithSelector(0x0902f1ac));
require(success, 'could not get reserves');
(uint reserve0 ) = abi.decode(data, (uint));
require(reserve0 == expectedAmounts.reserve0, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
bytes memory emptyBytes;
(success,) = fromErc20Address.call(abi.encodeWithSelector(0xa9059cbb, expectedAmounts.exchange, amountIn));
require(
success,
'TransferHelper::safeTransfer: transfer failed'
);
if (coinbaseTransfer > 0) {
block.coinbase.transfer(coinbaseTransfer);
}
IUniswapV2Pair(expectedAmounts.exchange).swap(
expectedAmounts.amount0,
expectedAmounts.amount1,
address(this),
emptyBytes
);
}
function fastSwapOneChi(uint blockNumber, uint amountIn, address fromErc20Address, ExpectedAmounts calldata expectedAmounts, uint coinbaseTransfer) external {
require(payable(msg.sender) == owner);
// note, ganache by default uses a block number ~10 higher?
// which is different than mainnet where this will be the actual block being mined
require(block.number >= blockNumber, "e1");
uint256 gasStart = gasleft();
(bool success, bytes memory data) = expectedAmounts.exchange.staticcall(abi.encodeWithSelector(0x0902f1ac));
require(success, 'could not get reserves');
(uint reserve0 ) = abi.decode(data, (uint));
require(reserve0 == expectedAmounts.reserve0, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
bytes memory emptyBytes;
(success,) = fromErc20Address.call(abi.encodeWithSelector(0xa9059cbb, expectedAmounts.exchange, amountIn));
require(
success,
'TransferHelper::safeTransfer: transfer failed'
);
IUniswapV2Pair(expectedAmounts.exchange).swap(
expectedAmounts.amount0,
expectedAmounts.amount1,
address(this),
emptyBytes
);
if (coinbaseTransfer > 0) {
block.coinbase.transfer(coinbaseTransfer);
}
uint gasTokens = (21000 + gasStart - gasleft() + 16 * msg.data.length + 14154) / 41947;
0x0000000000004946c0e9F43F4Dee607b0eF1fA1c.call(abi.encodeWithSelector(0x6366b936, gasTokens));
}
function fastSwapOneGst2(uint blockNumber, uint amountIn, address fromErc20Address, ExpectedAmounts calldata expectedAmounts, uint coinbaseTransfer) external {
require(payable(msg.sender) == owner);
// note, ganache by default uses a block number ~10 higher?
// which is different than mainnet where this will be the actual block being mined
require(block.number >= blockNumber, "e1");
uint256 gasStart = gasleft();
(bool success, bytes memory data) = expectedAmounts.exchange.staticcall(abi.encodeWithSelector(0x0902f1ac));
require(success, 'could not get reserves');
(uint reserve0 ) = abi.decode(data, (uint));
require(reserve0 == expectedAmounts.reserve0, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
bytes memory emptyBytes;
(success,) = fromErc20Address.call(abi.encodeWithSelector(0xa9059cbb, expectedAmounts.exchange, amountIn));
require(
success,
'TransferHelper::safeTransfer: transfer failed'
);
IUniswapV2Pair(expectedAmounts.exchange).swap(
expectedAmounts.amount0,
expectedAmounts.amount1,
address(this),
emptyBytes
);
if (coinbaseTransfer > 0) {
block.coinbase.transfer(coinbaseTransfer);
}
uint256 tokens = ((gasStart - gasleft()) + 14154)/((24000*2)-6870);
// require(false, uint2str(tokens));
IGST2(0x0000000000b3F879cb30FE243b4Dfee438691c04).freeUpTo(tokens);
}
function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len;
while (_i != 0) {
k = k-1;
uint8 temp = (48 + uint8(_i - _i / 10 * 10));
bytes1 b1 = bytes1(temp);
bstr[k] = b1;
_i /= 10;
}
return string(bstr);
}
function fastSwap(uint blockNumber, uint amountIn, ExpectedAmounts[] calldata expectedAmounts, uint coinbaseTransfer) external {
require(payable(msg.sender) == owner);
// note, ganache by default uses a block number ~10 higher?
// which is different than mainnet where this will be the actual block being mined
require(block.number >= blockNumber, "e1");
// verify reserves
for (uint i = 0; i < expectedAmounts.length; i++) {
// (uint reserve0, uint reserve1,) = IUniswapV2Pair(expectedAmounts[i].exchange).getReserves();
// require(reserve0 == expectedAmounts[i].reserve0, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
// require(reserve1 == expectedAmounts[i].reserve1, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
(bool success, bytes memory data) = expectedAmounts[i].exchange.staticcall(abi.encodeWithSelector(0x0902f1ac));
require(success, 'could not get reserves');
(uint reserve0 ) = abi.decode(data, (uint));
require(reserve0 == expectedAmounts[i].reserve0, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
}
// transfer money from this contract
// https://github.com/Uniswap/uniswap-lib/blob/master/contracts/libraries/TransferHelper.sol
// (bool success, bytes memory data) = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2.call(abi.encodeWithSelector(0xa9059cbb, expectedAmounts[0].exchange, amountIn));
// require(
// success && (data.length == 0 || abi.decode(data, (bool))),
// 'TransferHelper::safeTransfer: transfer failed'
// );
(bool success,) = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2.call(abi.encodeWithSelector(0xa9059cbb, expectedAmounts[0].exchange, amountIn));
require(
success,
'TransferHelper::safeTransfer: transfer failed'
);
// saves 232802-232362, 440 gas
bytes memory emptyBytes;
// not calling expectedAmounts.length twice saves ~100 gas
uint lastIdx = expectedAmounts.length - 1;
for (uint i=0; i < lastIdx; i++) {
IUniswapV2Pair(expectedAmounts[i].exchange).swap(
expectedAmounts[i].amount0,
expectedAmounts[i].amount1,
expectedAmounts[i+1].exchange,
emptyBytes
);
// calling the ABI directly like this saves ~250 gas
// expectedAmounts[i].exchange.call(abi.encodeWithSelector(
// 0x022c0d9f,
// expectedAmounts[i].amount0,
// expectedAmounts[i].amount1,
// expectedAmounts[i+1].exchange,
// emptyBytes
// ));
}
// saves gas to call the last one outside of the loop
IUniswapV2Pair(expectedAmounts[lastIdx].exchange).swap(
expectedAmounts[lastIdx].amount0,
expectedAmounts[lastIdx].amount1,
address(this),
emptyBytes
);
// expectedAmounts[lastIdx].exchange.call(abi.encodeWithSelector(
// 0x022c0d9f,
// expectedAmounts[lastIdx].amount0,
// expectedAmounts[lastIdx].amount1,
// address(this),
// emptyBytes
// ));
if (coinbaseTransfer > 0) {
block.coinbase.transfer(coinbaseTransfer);
}
}
// transfer money from owner (this uses a lot more gas, e.g. 245k instead of 232k, and 199k instead of 189k when using gas token)
// (bool success, bytes memory data) = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2.call(abi.encodeWithSelector(0x23b872dd, owner, expectedAmounts[0].exchange, amountIn));
// require(
// success && (data.length == 0 || abi.decode(data, (bool))),
// 'TransferHelper::transferFrom: transferFrom failed'
// );
// thsi is a copy and paste of the code from fastSwap with gas token code around it
function fastSwapChi(uint blockNumber, uint amountIn, ExpectedAmounts[] calldata expectedAmounts, uint coinbaseTransfer) payable external {
require(payable(msg.sender) == owner);
// note, ganache by default uses a block number ~10 higher?
// which is different than mainnet where this will be the actual block being mined
require(block.number >= blockNumber, "e1");
uint256 gasStart = gasleft();
// verify reserves
for (uint i = 0; i < expectedAmounts.length; i++) {
(bool success, bytes memory data) = expectedAmounts[i].exchange.staticcall(abi.encodeWithSelector(0x0902f1ac));
require(success, 'could not get reserves');
(uint reserve0 ) = abi.decode(data, (uint));
require(reserve0 == expectedAmounts[i].reserve0, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
}
(bool success,) = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2.call(abi.encodeWithSelector(0xa9059cbb, expectedAmounts[0].exchange, amountIn));
require(
success,
'TransferHelper::safeTransfer: transfer failed'
);
bytes memory emptyBytes;
uint lastIdx = expectedAmounts.length - 1;
for (uint i=0; i < lastIdx; i++) {
// calling the ABI directly like this saves ~250 gas
expectedAmounts[i].exchange.call(abi.encodeWithSelector(
0x022c0d9f,
expectedAmounts[i].amount0,
expectedAmounts[i].amount1,
expectedAmounts[i+1].exchange,
emptyBytes
));
}
// saves gas to call the last one outside of the loop
IUniswapV2Pair(expectedAmounts[lastIdx].exchange).swap(
expectedAmounts[lastIdx].amount0,
expectedAmounts[lastIdx].amount1,
address(this),
emptyBytes
);
if (coinbaseTransfer > 0) {
block.coinbase.transfer(coinbaseTransfer);
}
// chi token
// uint256 gasSpent = 21000 + gasStart - gasleft() + 16 * msg.data.length;
// IFreeFromUpTo chi = IFreeFromUpTo(0x0000000000004946c0e9F43F4Dee607b0eF1fA1c);
// gasTokensUsed = (gasSpent + 14154) / 41947;
// chi.freeUpTo(gasTokensUsed);
uint gasTokens = (21000 + gasStart - gasleft() + 16 * msg.data.length + 14154) / 41947;
0x0000000000004946c0e9F43F4Dee607b0eF1fA1c.call(abi.encodeWithSelector(0x6366b936, gasTokens));
}
// this is a copy and paste of the code from fastSwap with gas token code around it
function fastSwapGst2(uint blockNumber, uint amountIn, ExpectedAmounts[] calldata expectedAmounts, uint coinbaseTransfer) payable external {
require(payable(msg.sender) == owner);
// note, ganache by default uses a block number ~10 higher?
// which is different than mainnet where this will be the actual block being mined
require(block.number >= blockNumber, "e1");
uint256 gasStart = gasleft();
// verify reserves
for (uint i = 0; i < expectedAmounts.length; i++) {
(bool success, bytes memory data) = expectedAmounts[i].exchange.staticcall(abi.encodeWithSelector(0x0902f1ac));
require(success, 'could not get reserves');
(uint reserve0 ) = abi.decode(data, (uint));
require(reserve0 == expectedAmounts[i].reserve0, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
}
(bool success,) = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2.call(abi.encodeWithSelector(0xa9059cbb, expectedAmounts[0].exchange, amountIn));
require(
success,
'TransferHelper::safeTransfer: transfer failed'
);
bytes memory emptyBytes;
uint lastIdx = expectedAmounts.length - 1;
for (uint i=0; i < lastIdx; i++) {
// calling the ABI directly like this saves ~250 gas
expectedAmounts[i].exchange.call(abi.encodeWithSelector(
0x022c0d9f,
expectedAmounts[i].amount0,
expectedAmounts[i].amount1,
expectedAmounts[i+1].exchange,
emptyBytes
));
}
// saves gas to call the last one outside of the loop
IUniswapV2Pair(expectedAmounts[lastIdx].exchange).swap(
expectedAmounts[lastIdx].amount0,
expectedAmounts[lastIdx].amount1,
address(this),
emptyBytes
);
if (coinbaseTransfer > 0) {
block.coinbase.transfer(coinbaseTransfer);
}
// gst token
// uint256 tokens = gasStart.sub(
// gasleft()
// ).add(14154).div(
// uint256(24000).mul(2).sub(6870)
// );
uint256 tokens = ((gasStart - gasleft()) + 14154)/((24000*2)-6870);
// require(false, uint2str(tokens));
IGST2(0x0000000000b3F879cb30FE243b4Dfee438691c04).freeUpTo(tokens);
}
// this is a copy and paste of the code from fastSwap with gas token code around it
function fastSwapLgt(uint blockNumber, uint amountIn, ExpectedAmounts[] calldata expectedAmounts, uint amountEthForLgt, uint coinbaseTransfer) payable external {
require(payable(msg.sender) == owner);
require(block.number >= blockNumber, "e1");
uint256 gasStart = gasleft();
// verify reserves
for (uint i = 0; i < expectedAmounts.length; i++) {
(bool success, bytes memory data) = expectedAmounts[i].exchange.staticcall(abi.encodeWithSelector(0x0902f1ac));
require(success, 'could not get reserves');
(uint reserve0 ) = abi.decode(data, (uint));
require(reserve0 == expectedAmounts[i].reserve0, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
}
(bool success,) = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2.call(abi.encodeWithSelector(0xa9059cbb, expectedAmounts[0].exchange, amountIn));
require(
success,
'TransferHelper::safeTransfer: transfer failed'
);
bytes memory emptyBytes;
uint lastIdx = expectedAmounts.length - 1;
for (uint i=0; i < lastIdx; i++) {
// calling the ABI directly like this saves ~250 gas
expectedAmounts[i].exchange.call(abi.encodeWithSelector(
0x022c0d9f,
expectedAmounts[i].amount0,
expectedAmounts[i].amount1,
expectedAmounts[i+1].exchange,
emptyBytes
));
}
// saves gas to call the last one outside of the loop
IUniswapV2Pair(expectedAmounts[lastIdx].exchange).swap(
expectedAmounts[lastIdx].amount0,
expectedAmounts[lastIdx].amount1,
address(this),
emptyBytes
);
if (coinbaseTransfer > 0) {
block.coinbase.transfer(coinbaseTransfer);
}
// lgt token
// 0x000000000000C1CB11D5c062901F32D06248CE48.call{value: 300000000000000000}(abi.encodeWithSignature('buyMaxAndFree(uint256)', now+10));
// IBuyMaxAndFree(0x000000000000C1CB11D5c062901F32D06248CE48).buyMaxAndFree{value: 200000000000000000}(now);
// 0x000000000000C1CB11D5c062901F32D06248CE48.call{value: 4000000000000000}(abi.encodeWithSignature('buyAndFree(uint256,uint256,address)', 6, now, address(this)));
// require(false,uint2str((gasStart - gasleft() + 55000) / 41300));
// this uses 3% more gas, but in theory should be way easier to use since it does not require
// the amount owed to be computed... but it doesn't refund money (or at least i dont think it does).
// 0x000000000000C1CB11D5c062901F32D06248CE48.call{value: amountEthForLgt}(abi.encodeWithSignature('buyAndFree(uint256,uint256,address)', (gasStart - gasleft() + 55000) / 41300, now, this));
// this is 3% gas savings, but more complicated because it requires us to pass the price we want to pay in
uint gasTokens = (gasStart - gasleft() + 55000) / 41300;
0x000000000000C1CB11D5c062901F32D06248CE48.call{value: amountEthForLgt}(abi.encodeWithSignature('buyAndFree22457070633(uint256)', gasTokens));
}
// function reset() external payable {
// 0x000000000000C1CB11D5c062901F32D06248CE48.call{value: msg.value}(abi.encodeWithSignature('buyAndFree22457070633(uint256)', 1));
// }
struct Call {
address to;
uint256 value;
bytes data;
}
function batch(Call[] memory calls) onlyOwner saveGas public returns (bytes[] memory returnData) {
returnData = new bytes[](calls.length);
for(uint8 i = 0; i < calls.length; i++) {
(bool success, bytes memory data) = calls[i].to.call{value:calls[i].value}(calls[i].data);
// (bool success, bytes memory data) = calls[i].to.call.value(calls[i].value)(calls[i].data);
require(success, string(data));
returnData[i] = data;
}
}
}
{
"compilationTarget": {
"Arb.sol": "Arb"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000000
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Arb.Call[]","name":"calls","type":"tuple[]"}],"name":"batch","outputs":[{"internalType":"bytes[]","name":"returnData","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"address","name":"exchange","type":"address"},{"internalType":"uint256","name":"reserve0","type":"uint256"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"internalType":"struct Arb.ExpectedAmounts[]","name":"expectedAmounts","type":"tuple[]"},{"internalType":"uint256","name":"coinbaseTransfer","type":"uint256"}],"name":"fastSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"address","name":"exchange","type":"address"},{"internalType":"uint256","name":"reserve0","type":"uint256"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"internalType":"struct Arb.ExpectedAmounts[]","name":"expectedAmounts","type":"tuple[]"},{"internalType":"uint256","name":"coinbaseTransfer","type":"uint256"}],"name":"fastSwapChi","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"address","name":"exchange","type":"address"},{"internalType":"uint256","name":"reserve0","type":"uint256"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"internalType":"struct Arb.ExpectedAmounts[]","name":"expectedAmounts","type":"tuple[]"},{"internalType":"uint256","name":"coinbaseTransfer","type":"uint256"}],"name":"fastSwapGst2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"address","name":"exchange","type":"address"},{"internalType":"uint256","name":"reserve0","type":"uint256"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"internalType":"struct Arb.ExpectedAmounts[]","name":"expectedAmounts","type":"tuple[]"},{"internalType":"uint256","name":"amountEthForLgt","type":"uint256"},{"internalType":"uint256","name":"coinbaseTransfer","type":"uint256"}],"name":"fastSwapLgt","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"fromErc20Address","type":"address"},{"components":[{"internalType":"address","name":"exchange","type":"address"},{"internalType":"uint256","name":"reserve0","type":"uint256"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"internalType":"struct Arb.ExpectedAmounts","name":"expectedAmounts","type":"tuple"},{"internalType":"uint256","name":"coinbaseTransfer","type":"uint256"}],"name":"fastSwapOne","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"fromErc20Address","type":"address"},{"components":[{"internalType":"address","name":"exchange","type":"address"},{"internalType":"uint256","name":"reserve0","type":"uint256"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"internalType":"struct Arb.ExpectedAmounts","name":"expectedAmounts","type":"tuple"},{"internalType":"uint256","name":"coinbaseTransfer","type":"uint256"}],"name":"fastSwapOneChi","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"fromErc20Address","type":"address"},{"components":[{"internalType":"address","name":"exchange","type":"address"},{"internalType":"uint256","name":"reserve0","type":"uint256"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"internalType":"struct Arb.ExpectedAmounts","name":"expectedAmounts","type":"tuple"},{"internalType":"uint256","name":"coinbaseTransfer","type":"uint256"}],"name":"fastSwapOneGst2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]