Getting this error when attempting to deploy a contract that reads in three addresses and two tuples
creation of PairFlash errored: Error encoding arguments: Error: types/values length mismatch (count={"types":5,"values":11}, value={"types":["address","address","address","tuple(address,address,uint24,uint256,uint256)","tuple(address,address,uint24,uint256,uint256)"],"values":["0xE592427A0AEce92De3Edee1F18E0157C05861564","0x1F98431c8aD98523631AE4a59f267346ea31F984","0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270","",",0x9c2C5fd7b07E95EE044DDeba0E97a665F142394f,",",10,","","",",0x85955046DF4668e1DD369D2DE9f3AEB98DD2A369,",",22875,",""]}, code=INVALID_ARGUMENT, version=abi/5.7.0)
The tuple reads as: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2,0x9c2C5fd7b07E95EE044DDeba0E97a665F142394f,3000,10,22875
Are the commas not supposed to be added?
Code below:
pragma solidity >=0.7.6 <=0.8.18;
pragma abicoder v2;
pragma experimental ABIEncoderV2;
import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3FlashCallback.sol';
import '@uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol';
import '@uniswap/v3-periphery/contracts/base/PeripheryPayments.sol';
import '@uniswap/v3-periphery/contracts/base/PeripheryImmutableState.sol';
import '@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol';
import '@uniswap/v3-periphery/contracts/libraries/CallbackValidation.sol';
import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';
import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol';
/// @title Flash contract implementation
/// @notice An example contract using the Uniswap V3 flash function
contract PairFlash is IUniswapV3FlashCallback, PeripheryImmutableState, PeripheryPayments {
using LowGasSafeMath for uint256;
using LowGasSafeMath for int256;
ISwapRouter public immutable swapRouter;
constructor(
ISwapRouter _swapRouter,
address _factory,
address _WETH9,
FlashParams memory flashParams,
FlashParams2 memory flashParams2
) PeripheryImmutableState(_factory, _WETH9) {
swapRouter = _swapRouter;
flashParams.token0;
flashParams2.token1;
flashParams2.token2;
}
/// @param fee0 The fee from calling flash for token0
/// @param fee1 The fee from calling flash for token1
/// @param data The data needed in the callback passed as FlashCallbackData from `initFlash`
/// @notice implements the callback called from flash
/// @dev fails if the flash is not profitable, meaning the amountOut from the flash is less than the amount borrowed
function uniswapV3FlashCallback(
uint256 fee0,
uint256 fee1,
bytes calldata data
) external override {
FlashCallbackData memory decoded = abi.decode(data, (FlashCallbackData));
CallbackValidation.verifyCallback(factory, decoded.poolKey);
FlashCallbackData2 memory decoded2 = abi.decode(data, (FlashCallbackData2));
CallbackValidation.verifyCallback(factory, decoded2.poolKey2);
FlashCallbackData3 memory decoded3 = abi.decode(data, (FlashCallbackData3));
CallbackValidation.verifyCallback(factory, decoded3.poolKey3);
//address token0 = decoded.poolKey.token0;
//address token1 = decoded.poolKey.token1;
//address token2 = decoded2.poolKey2.token1;
//address token3 = decoded3.poolKey3.token0;
//uint24 poolfee0 = decoded.poolKey.fee;
//uint24 poolfee1 = decoded2.poolKey2.fee;
//uint24 poolfee2 = decoded3.poolKey3.fee;
//uint256 amount0 = decoded.amount0;
//uint256 amount1 = decoded.amount1;
//uint256 amount1a = decoded2.amount1;
//uint256 amount2 = decoded2.amount2;
//uint256 amount2a = decoded3.amount2;
//uint256 amount0a = decoded3.amount0;
TransferHelper.safeApprove(decoded.poolKey.token0, address(swapRouter), decoded.amount0);
TransferHelper.safeApprove(decoded.poolKey.token1, address(swapRouter), decoded.amount1);
TransferHelper.safeApprove(decoded2.poolKey2.token1, address(swapRouter), decoded2.amount2);
// profitable check
// exactInputSingle will fail if this amount not met
//uint256 amount1Min = LowGasSafeMath.add(amount1, poolfee1);
uint256 amount0Min = LowGasSafeMath.add(decoded.amount0, decoded.poolKey.fee);
uint256 amount0aMin = LowGasSafeMath.add(decoded3.amount0, decoded3.poolKey3.fee);
//multihop swap from WETH to token1 to token2
swapRouter.exactInput(
ISwapRouter.ExactInputParams({
path: abi.encodePacked(decoded.poolKey.token0, decoded.poolKey.fee, decoded.poolKey.token1, decoded2.poolKey2.fee, decoded2.poolKey2.token1),
recipient: address(this),
deadline: block.timestamp,
amountIn: decoded.amount1,
amountOutMinimum: amount0Min
})
);
//single swap from token2 back to WETH
uint256 amountOut0 =
swapRouter.exactInputSingle(
ISwapRouter.ExactInputSingleParams({
tokenIn: decoded3.poolKey3.token0,
tokenOut: decoded3.poolKey3.token1,
fee: decoded3.poolKey3.fee,
recipient: address(this),
deadline: block.timestamp,
amountIn: decoded3.amount2,
amountOutMinimum: amount0aMin,
sqrtPriceLimitX96: 0
})
);
/*
// call exactInputSingle for swapping token1 for token0 in pool w/fee2
uint256 amountOut0 =
swapRouter.exactInputSingle(
ISwapRouter.ExactInputSingleParams({
tokenIn: decoded.poolKey.token1,
tokenOut: decoded.poolKey.token0,
fee: poolfee0,
recipient: address(this),
deadline: block.timestamp,
amountIn: amount1,
amountOutMinimum: amount0,
sqrtPriceLimitX96: 0
})
);
// call exactInputSingle for swapping token2 for token 1 in pool
//last call to return to WETH
uint256 amountOut2 =
swapRouter.exactInputSingle(
ISwapRouter.ExactInputSingleParams({
tokenIn: token3,
tokenOut: token2,
fee: poolfee2,
recipient: address(this),
deadline: block.timestamp,
amountIn: amount2a,
amountOutMinimum: amount0a,
sqrtPriceLimitX96: 0
})
);
*/
// end up with amountOut0 of token0 from first swap and amountOut1 of token1 from second swap
uint256 amount0Owed = LowGasSafeMath.add(amountOut0, decoded3.poolKey3.fee);
// uint256 amount1Owed = LowGasSafeMath.add(decoded.amount1, poolfee1);
TransferHelper.safeApprove(decoded3.poolKey3.token1, address(this), amount0Owed);
//TransferHelper.safeApprove(token1, address(this), amount1Owed);
if (amount0Owed > 0) pay(decoded3.poolKey3.token1, address(this), msg.sender, amount0Owed);
//if (amount1Owed > 0) pay(token1, address(this), msg.sender, amount1Owed);
// if profitable pay profits to payer
if (amountOut0 > amount0Owed) {
uint256 profit0 = LowGasSafeMath.sub(amountOut0, amount0Owed);
TransferHelper.safeApprove(decoded3.poolKey3.token1, address(this), profit0);
pay(decoded3.poolKey3.token1, address(this), decoded.payer, profit0);
}
/*
if (amount1a > amount1Owed) {
uint256 profit1 = LowGasSafeMath.sub(amount1a, amount1Owed);
TransferHelper.safeApprove(token0, address(this), profit1);
pay(token1, address(this), decoded.payer, profit1);
}
*/
}
//fee1 is the fee of the pool from the initial borrow
//fee2 is the fee of the first pool to arb from
//fee3 is the fee of the second pool to arb from
struct FlashParams {
address token0;
address token1;
uint24 fee1;
uint256 amount0;
uint256 amount1;
}
struct FlashParams2 {
address token1;
address token2;
uint24 fee4;
uint256 amount1;
uint256 amount2;
}
struct FlashParams3 {
address token2;
address token0;
uint24 fee7;
uint256 amount2;
uint256 amount0;
}
// fee2 and fee3 are the two other fees associated with the two other pools of token0 and token1
struct FlashCallbackData {
uint256 amount0;
uint256 amount1;
address payer;
PoolAddress.PoolKey poolKey;
}
struct FlashCallbackData2 {
uint256 amount1;
uint256 amount2;
address payer;
PoolAddress.PoolKey poolKey2;
}
struct FlashCallbackData3 {
uint256 amount2;
uint256 amount0;
address payer;
PoolAddress.PoolKey poolKey3;
}
/// @param params The parameters necessary for flash and the callback, passed in as FlashParams
/// @notice Calls the pools flash function with data needed in `uniswapV3FlashCallback`
function initFlash(FlashParams memory params, FlashParams2 memory params2, FlashParams3 memory params3) external {
PoolAddress.PoolKey memory poolKey =
PoolAddress.PoolKey({token0: params.token0, token1: params.token1, fee: params.fee1});
PoolAddress.PoolKey memory poolKey2 =
PoolAddress.PoolKey({token0: params2.token1, token1: params2.token2, fee: params2.fee4});
PoolAddress.PoolKey memory poolKey3 =
PoolAddress.PoolKey({token0: params3.token2, token1: params3.token0, fee: params3.fee7});
IUniswapV3Pool pool = IUniswapV3Pool(PoolAddress.computeAddress(factory, poolKey));
IUniswapV3Pool pool2 = IUniswapV3Pool(PoolAddress.computeAddress(factory, poolKey2));
IUniswapV3Pool pool3 = IUniswapV3Pool(PoolAddress.computeAddress(factory, poolKey3));
// recipient of borrowed amounts
// amount of token0 requested to borrow
// amount of token1 requested to borrow
// need amount 0 and amount1 in callback to pay back pool
// recipient of flash should be THIS contract
pool.flash(
address(this),
params.amount0,
params.amount1,
abi.encode(
FlashCallbackData({
amount0: params.amount0,
amount1: params.amount1,
payer: msg.sender,
poolKey: poolKey
})
)
);
pool2.flash(
address(this),
params2.amount1,
params2.amount2,
abi.encode(
FlashCallbackData2({
amount1: params2.amount1,
amount2: params2.amount2,
payer: msg.sender,
poolKey2: poolKey2
})
)
);
pool3.flash(
address(this),
params3.amount2,
params3.amount0,
abi.encode(
FlashCallbackData3({
amount2: params3.amount2,
amount0: params3.amount0,
payer: msg.sender,
poolKey3: poolKey3
})
)
);
}
}```