diff --git a/src/abi/zuludmm.abi.json b/src/abi/zuludmm.abi.json new file mode 100644 index 000000000..cd6ff1093 --- /dev/null +++ b/src/abi/zuludmm.abi.json @@ -0,0 +1,1148 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_factory", + "type": "address" + }, + { + "internalType": "contract IWETH", + "name": "_weth", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "uint256[2]", + "name": "vReserveRatioBounds", + "type": "uint256[2]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "uint256[2]", + "name": "vReserveRatioBounds", + "type": "uint256[2]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint32", + "name": "ampBps", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityNewPool", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "uint32", + "name": "ampBps", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityNewPoolETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETHSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapETHForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "weth", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/src/abi/zuludmm/zulu-dmm-exchange-router.abi.json b/src/abi/zuludmm/zulu-dmm-exchange-router.abi.json new file mode 100644 index 000000000..cd6ff1093 --- /dev/null +++ b/src/abi/zuludmm/zulu-dmm-exchange-router.abi.json @@ -0,0 +1,1148 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_factory", + "type": "address" + }, + { + "internalType": "contract IWETH", + "name": "_weth", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "uint256[2]", + "name": "vReserveRatioBounds", + "type": "uint256[2]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "uint256[2]", + "name": "vReserveRatioBounds", + "type": "uint256[2]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint32", + "name": "ampBps", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityNewPool", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "uint32", + "name": "ampBps", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityNewPoolETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETHSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapETHForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "poolsPath", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "weth", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/src/abi/zuludmm/zulu-dmm-factory.abi.json b/src/abi/zuludmm/zulu-dmm-factory.abi.json new file mode 100644 index 000000000..963ca86de --- /dev/null +++ b/src/abi/zuludmm/zulu-dmm-factory.abi.json @@ -0,0 +1,335 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_feeToSetter", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IERC20", + "name": "token0", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "token1", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "ampBps", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalPool", + "type": "uint256" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "feeTo", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "governmentFeeBps", + "type": "uint16" + } + ], + "name": "SetFeeConfiguration", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "feeToSetter", + "type": "address" + } + ], + "name": "SetFeeToSetter", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "allPools", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "allPoolsLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint32", + "name": "ampBps", + "type": "uint32" + } + ], + "name": "createPool", + "outputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "feeToSetter", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getFeeConfiguration", + "outputs": [ + { + "internalType": "address", + "name": "_feeTo", + "type": "address" + }, + { + "internalType": "uint16", + "name": "_governmentFeeBps", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token0", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "token1", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "getPoolAtIndex", + "outputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token0", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "token1", + "type": "address" + } + ], + "name": "getPools", + "outputs": [ + { + "internalType": "address[]", + "name": "_tokenPools", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token0", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "token1", + "type": "address" + } + ], + "name": "getPoolsLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "name": "getUnamplifiedPool", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token0", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "token1", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPool", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeTo", + "type": "address" + }, + { + "internalType": "uint16", + "name": "_governmentFeeBps", + "type": "uint16" + } + ], + "name": "setFeeConfiguration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeToSetter", + "type": "address" + } + ], + "name": "setFeeToSetter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/abi/zuludmm/zulu-dmm-pool.abi.json b/src/abi/zuludmm/zulu-dmm-pool.abi.json new file mode 100644 index 000000000..ec77d7db3 --- /dev/null +++ b/src/abi/zuludmm/zulu-dmm-pool.abi.json @@ -0,0 +1,803 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "Burn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0In", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1In", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0Out", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1Out", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeInPrecision", + "type": "uint256" + } + ], + "name": "Swap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "vReserve0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "vReserve1", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reserve0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reserve1", + "type": "uint256" + } + ], + "name": "Sync", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "shortEMA", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "longEMA", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "lastBlockVolume", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "skipBlock", + "type": "uint256" + } + ], + "name": "UpdateEMA", + "type": "event" + }, + { + "inputs": [], + "name": "MINIMUM_LIQUIDITY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PERMIT_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ampBps", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "burn", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "domainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "contract IDMMFactory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getReserves", + "outputs": [ + { + "internalType": "uint112", + "name": "_reserve0", + "type": "uint112" + }, + { + "internalType": "uint112", + "name": "_reserve1", + "type": "uint112" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTradeInfo", + "outputs": [ + { + "internalType": "uint112", + "name": "_reserve0", + "type": "uint112" + }, + { + "internalType": "uint112", + "name": "_reserve1", + "type": "uint112" + }, + { + "internalType": "uint112", + "name": "_vReserve0", + "type": "uint112" + }, + { + "internalType": "uint112", + "name": "_vReserve1", + "type": "uint112" + }, + { + "internalType": "uint256", + "name": "feeInPrecision", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVolumeTrendData", + "outputs": [ + { + "internalType": "uint128", + "name": "_shortEMA", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "_longEMA", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "_currentBlockVolume", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "_lastTradeBlock", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "_token0", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "_token1", + "type": "address" + }, + { + "internalType": "uint32", + "name": "_ampBps", + "type": "uint32" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "kLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "skim", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount0Out", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Out", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callbackData", + "type": "bytes" + } + ], + "name": "swap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "sync", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "token0", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token1", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/abi/zuludmm/zulu-storage.abi.json b/src/abi/zuludmm/zulu-storage.abi.json new file mode 100644 index 000000000..3d42f8254 --- /dev/null +++ b/src/abi/zuludmm/zulu-storage.abi.json @@ -0,0 +1,824 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "_admin", "type": "address" }, + { + "internalType": "contract IZuluHistory", + "name": "_zuluNetworkHistory", + "type": "address" + }, + { + "internalType": "contract IZuluHistory", + "name": "_zuluFeeHandlerHistory", + "type": "address" + }, + { + "internalType": "contract IZuluHistory", + "name": "_zuluDaoHistory", + "type": "address" + }, + { + "internalType": "contract IZuluHistory", + "name": "_zuluMatchingEngineHistory", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "reserve", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "reserveId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "enum IZuluStorage.ReserveType", + "name": "reserveType", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "address", + "name": "rebateWallet", + "type": "address" + } + ], + "name": "AddReserveToStorage", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + } + ], + "name": "AdminClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newAlerter", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isAdd", + "type": "bool" + } + ], + "name": "AlerterAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract IZuluNetwork", + "name": "newZuluNetwork", + "type": "address" + } + ], + "name": "ZuluNetworkUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "reserveId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "reserve", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "dest", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "add", + "type": "bool" + } + ], + "name": "ListReservePairs", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newOperator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isAdd", + "type": "bool" + } + ], + "name": "OperatorAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "reserve", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "reserveId", + "type": "bytes32" + } + ], + "name": "RemoveReserveFromStorage", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "reserveId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "rebateWallet", + "type": "address" + } + ], + "name": "ReserveRebateWalletSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "pendingAdmin", + "type": "address" + } + ], + "name": "TransferAdminPending", + "type": "event" + }, + { + "inputs": [ + { "internalType": "address", "name": "newAlerter", "type": "address" } + ], + "name": "addAlerter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "zuluProxy", "type": "address" }, + { + "internalType": "uint256", + "name": "maxApprovedProxies", + "type": "uint256" + } + ], + "name": "addZuluProxy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "newOperator", "type": "address" } + ], + "name": "addOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "reserve", "type": "address" }, + { "internalType": "bytes32", "name": "reserveId", "type": "bytes32" }, + { + "internalType": "enum IZuluStorage.ReserveType", + "name": "resType", + "type": "uint8" + }, + { + "internalType": "address payable", + "name": "rebateWallet", + "type": "address" + } + ], + "name": "addReserve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "admin", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getAlerters", + "outputs": [ + { "internalType": "address[]", "name": "", "type": "address[]" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getContracts", + "outputs": [ + { + "internalType": "address[]", + "name": "zuluDaoAddresses", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "zuluFeeHandlerAddresses", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "zuluMatchingEngineAddresses", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "zuluNetworkAddresses", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32[]", "name": "reserveIds", "type": "bytes32[]" } + ], + "name": "getEntitledRebateData", + "outputs": [ + { + "internalType": "bool[]", + "name": "entitledRebateArr", + "type": "bool[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32[]", "name": "reserveIds", "type": "bytes32[]" } + ], + "name": "getFeeAccountedData", + "outputs": [ + { "internalType": "bool[]", "name": "feeAccountedArr", "type": "bool[]" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getZuluProxies", + "outputs": [ + { + "internalType": "contract IZuluNetworkProxy[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "reserveId", "type": "bytes32" } + ], + "name": "getListedTokensByReserveId", + "outputs": [ + { + "internalType": "contract IERC20[]", + "name": "srcTokens", + "type": "address[]" + }, + { + "internalType": "contract IERC20[]", + "name": "destTokens", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOperators", + "outputs": [ + { "internalType": "address[]", "name": "", "type": "address[]" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32[]", "name": "reserveIds", "type": "bytes32[]" } + ], + "name": "getRebateWalletsFromIds", + "outputs": [ + { + "internalType": "address[]", + "name": "rebateWallets", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "reserveId", "type": "bytes32" } + ], + "name": "getReserveAddressesByReserveId", + "outputs": [ + { + "internalType": "address[]", + "name": "reserveAddresses", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32[]", "name": "reserveIds", "type": "bytes32[]" } + ], + "name": "getReserveAddressesFromIds", + "outputs": [ + { + "internalType": "address[]", + "name": "reserveAddresses", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "contract IERC20", "name": "token", "type": "address" }, + { "internalType": "uint256", "name": "startIndex", "type": "uint256" }, + { "internalType": "uint256", "name": "endIndex", "type": "uint256" } + ], + "name": "getReserveAddressesPerTokenSrc", + "outputs": [ + { + "internalType": "address[]", + "name": "reserveAddresses", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "reserve", "type": "address" } + ], + "name": "getReserveDetailsByAddress", + "outputs": [ + { "internalType": "bytes32", "name": "reserveId", "type": "bytes32" }, + { "internalType": "address", "name": "rebateWallet", "type": "address" }, + { + "internalType": "enum IZuluStorage.ReserveType", + "name": "resType", + "type": "uint8" + }, + { "internalType": "bool", "name": "isFeeAccountedFlag", "type": "bool" }, + { "internalType": "bool", "name": "isEntitledRebateFlag", "type": "bool" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "reserveId", "type": "bytes32" } + ], + "name": "getReserveDetailsById", + "outputs": [ + { + "internalType": "address", + "name": "reserveAddress", + "type": "address" + }, + { "internalType": "address", "name": "rebateWallet", "type": "address" }, + { + "internalType": "enum IZuluStorage.ReserveType", + "name": "resType", + "type": "uint8" + }, + { "internalType": "bool", "name": "isFeeAccountedFlag", "type": "bool" }, + { "internalType": "bool", "name": "isEntitledRebateFlag", "type": "bool" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "reserve", "type": "address" } + ], + "name": "getReserveId", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "reserveAddresses", + "type": "address[]" + } + ], + "name": "getReserveIdsFromAddresses", + "outputs": [ + { "internalType": "bytes32[]", "name": "reserveIds", "type": "bytes32[]" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "contract IERC20", "name": "token", "type": "address" } + ], + "name": "getReserveIdsPerTokenDest", + "outputs": [ + { "internalType": "bytes32[]", "name": "reserveIds", "type": "bytes32[]" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "contract IERC20", "name": "token", "type": "address" } + ], + "name": "getReserveIdsPerTokenSrc", + "outputs": [ + { "internalType": "bytes32[]", "name": "reserveIds", "type": "bytes32[]" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getReserves", + "outputs": [ + { + "internalType": "contract IZuluReserve[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[]", + "name": "reserveIds", + "type": "bytes32[]" + }, + { "internalType": "contract IERC20", "name": "src", "type": "address" }, + { "internalType": "contract IERC20", "name": "dest", "type": "address" } + ], + "name": "getReservesData", + "outputs": [ + { + "internalType": "bool", + "name": "areAllReservesListed", + "type": "bool" + }, + { "internalType": "bool[]", "name": "feeAccountedArr", "type": "bool[]" }, + { + "internalType": "bool[]", + "name": "entitledRebateArr", + "type": "bool[]" + }, + { + "internalType": "contract IZuluReserve[]", + "name": "reserveAddresses", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum IZuluStorage.ReserveType", + "name": "resType", + "type": "uint8" + } + ], + "name": "getReservesPerType", + "outputs": [ + { "internalType": "bytes32[]", "name": "", "type": "bytes32[]" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isZuluProxyAdded", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zuluDaoHistory", + "outputs": [ + { + "internalType": "contract IZuluHistory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zuluFeeHandlerHistory", + "outputs": [ + { + "internalType": "contract IZuluHistory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zuluMatchingEngineHistory", + "outputs": [ + { + "internalType": "contract IZuluHistory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zuluNetwork", + "outputs": [ + { + "internalType": "contract IZuluNetwork", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zuluNetworkHistory", + "outputs": [ + { + "internalType": "contract IZuluHistory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "reserveId", "type": "bytes32" }, + { "internalType": "contract IERC20", "name": "token", "type": "address" }, + { "internalType": "bool", "name": "ethToToken", "type": "bool" }, + { "internalType": "bool", "name": "tokenToEth", "type": "bool" }, + { "internalType": "bool", "name": "add", "type": "bool" } + ], + "name": "listPairForReserve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pendingAdmin", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "alerter", "type": "address" } + ], + "name": "removeAlerter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "zuluProxy", "type": "address" } + ], + "name": "removeZuluProxy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "operator", "type": "address" } + ], + "name": "removeOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "reserveId", "type": "bytes32" }, + { "internalType": "uint256", "name": "startIndex", "type": "uint256" } + ], + "name": "removeReserve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_zuluFeeHandler", + "type": "address" + }, + { + "internalType": "address", + "name": "_zuluMatchingEngine", + "type": "address" + } + ], + "name": "setContracts", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bool", "name": "fpr", "type": "bool" }, + { "internalType": "bool", "name": "apr", "type": "bool" }, + { "internalType": "bool", "name": "bridge", "type": "bool" }, + { "internalType": "bool", "name": "utility", "type": "bool" }, + { "internalType": "bool", "name": "custom", "type": "bool" }, + { "internalType": "bool", "name": "orderbook", "type": "bool" } + ], + "name": "setEntitledRebatePerReserveType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bool", "name": "fpr", "type": "bool" }, + { "internalType": "bool", "name": "apr", "type": "bool" }, + { "internalType": "bool", "name": "bridge", "type": "bool" }, + { "internalType": "bool", "name": "utility", "type": "bool" }, + { "internalType": "bool", "name": "custom", "type": "bool" }, + { "internalType": "bool", "name": "orderbook", "type": "bool" } + ], + "name": "setFeeAccountedPerReserveType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_zuluDao", "type": "address" } + ], + "name": "setZuluDaoContract", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IZuluNetwork", + "name": "_zuluNetwork", + "type": "address" + } + ], + "name": "setNetworkContract", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "reserveId", "type": "bytes32" }, + { "internalType": "address", "name": "rebateWallet", "type": "address" } + ], + "name": "setRebateWallet", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "newAdmin", "type": "address" } + ], + "name": "transferAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "newAdmin", "type": "address" } + ], + "name": "transferAdminQuickly", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/dex/index.ts b/src/dex/index.ts index 071902885..2f4d557cc 100644 --- a/src/dex/index.ts +++ b/src/dex/index.ts @@ -36,6 +36,7 @@ import { Lido } from './lido'; import { Excalibur } from './uniswap-v2/excalibur'; import { MakerPsm } from './maker-psm/maker-psm'; import { KyberDmm } from './kyberdmm/kyberdmm'; +import { ZuluDmm } from './zuludmm/zuludmm'; import { Platypus } from './platypus/platypus'; import { GMX } from './gmx/gmx'; // import { WooFi } from './woo-fi/woo-fi'; diff --git a/src/dex/zuludmm/config.ts b/src/dex/zuludmm/config.ts new file mode 100644 index 000000000..4e8470848 --- /dev/null +++ b/src/dex/zuludmm/config.ts @@ -0,0 +1,65 @@ +import { Network } from '../../constants'; +import { Address, DexConfigMap } from '../../types'; +import { DexParams } from './types'; + +export const ZuluDmmConfig: DexConfigMap = { + ZuluDmm: { + [Network.MAINNET]: { + subgraphURL: + 'https://api.thegraph.com/subgraphs/name/dynamic-amm/dynamic-amm', + routerAddress: '0x1c87257F5e8609940Bc751a07BB085Bb7f8cDBE6', + factoryAddress: '0x833e4083B7ae46CeA85695c4f7ed25CDAd8886dE', + poolGasCost: 150 * 1000, + }, + [Network.POLYGON]: { + subgraphURL: + 'https://api.thegraph.com/subgraphs/name/dynamic-amm/dmm-exchange-matic', + routerAddress: '0x546C79662E028B661dFB4767664d0273184E4dD1', + factoryAddress: '0x5f1fe642060b5b9658c15721ea22e982643c095c', + poolGasCost: 150 * 1000, + }, + [Network.BSC]: { + subgraphURL: + 'https://api.thegraph.com/subgraphs/name/dynamic-amm/dmm-exchange-bsc', + routerAddress: '0x78df70615ffc8066cc0887917f2Cd72092C86409', + factoryAddress: '0x878dfe971d44e9122048308301f540910bbd934c', + poolGasCost: 150 * 1000, + }, + [Network.AVALANCHE]: { + subgraphURL: + 'https://api.thegraph.com/subgraphs/name/dynamic-amm/dmm-exchange-avax', + routerAddress: '0x8Efa5A9AD6D594Cf76830267077B78cE0Bc5A5F8', + factoryAddress: '0x10908c875d865c66f271f5d3949848971c9595c9', + poolGasCost: 150 * 1000, + }, + }, +}; + +export const Adapters: { + [chainId: number]: { name: string; index: number }[]; +} = { + [Network.MAINNET]: [ + { + name: 'Adapter03', + index: 6, + }, + ], + [Network.POLYGON]: [ + { + name: 'PolygonAdapter01', + index: 10, + }, + ], + [Network.BSC]: [ + { + name: 'BscAdapter01', + index: 12, + }, + ], + [Network.AVALANCHE]: [ + { + name: 'AvalancheAdapter01', + index: 4, + }, + ], +}; diff --git a/src/dex/zuludmm/fee-formula.ts b/src/dex/zuludmm/fee-formula.ts new file mode 100644 index 000000000..4a76232cd --- /dev/null +++ b/src/dex/zuludmm/fee-formula.ts @@ -0,0 +1,113 @@ +import { BI_POWS } from '../../bigint-constants'; +import { mulInPrecision, unsafePowInPrecision } from './math-ext'; + +export const PRECISION = BI_POWS[18]; +const R0 = 1477405064814996100n; // 1.4774050648149961 + +const C0 = (60n * PRECISION) / 10000n; + +const A = (PRECISION * 20000n) / 27n; +const B = (PRECISION * 250n) / 9n; +const C1 = (PRECISION * 985n) / 27n; +const U = (120n * PRECISION) / 100n; + +const G = (836n * PRECISION) / 1000n; +const F = 5n * PRECISION; +const L = (2n * PRECISION) / 10000n; +// C2 = 25 * PRECISION - (F * (PRECISION - G)**2) / ((PRECISION - G)**2 + L * PRECISION) +const C2 = 20036905816356657810n; + +/// @dev calculate fee from rFactorInPrecision, see section 3.2 in dmmSwap white paper +/// @dev fee in [15, 60] bps +/// @return fee percentage in Precision +export const getFee = (rFactorInPrecision: bigint): bigint => { + if (rFactorInPrecision >= R0) { + return C0; + } else if (rFactorInPrecision >= PRECISION) { + // C1 + A * (r-U)^3 + b * (r -U) + if (rFactorInPrecision > U) { + const tmp = rFactorInPrecision - U; + const tmp3 = unsafePowInPrecision(tmp, 3n); + return (C1 + mulInPrecision(A, tmp3) + mulInPrecision(B, tmp)) / 10000n; + } else { + const tmp = U - rFactorInPrecision; + const tmp3 = unsafePowInPrecision(tmp, 3n); + return (C1 - mulInPrecision(A, tmp3) - mulInPrecision(B, tmp)) / 10000n; + } + } else { + // [ C2 + sign(r - G) * F * (r-G) ^2 / (L + (r-G) ^2) ] / 10000 + let tmp = + rFactorInPrecision > G ? rFactorInPrecision - G : G - rFactorInPrecision; + tmp = unsafePowInPrecision(tmp, 2n); + const tmp2 = (F * tmp) / (tmp + L); + if (rFactorInPrecision > G) { + return (C2 + tmp2) / 10000n; + } else { + return (C2 - tmp2) / 10000n; + } + } +}; + +/** + * TrendVolume calculation + */ + +type TrendData = { + shortEMA: bigint; + longEMA: bigint; + lastBlockVolume: bigint; + lastTradeBlock: bigint; +}; + +const SHORT_ALPHA = (2n * PRECISION) / 5401n; +const LONG_ALPHA = (2n * PRECISION) / 10801n; + +/// @return rFactor in Precision for this trade +export const getRFactor = ( + blockNumber: bigint, + trendData: TrendData, +): bigint => { + const { + shortEMA, + longEMA, + lastBlockVolume: currentBlockVolume, + lastTradeBlock, + } = trendData; + // this can not be underflow because block.number always increases + const skipBlock = blockNumber - lastTradeBlock; + if (skipBlock == 0n) { + return calculateRFactor(shortEMA, longEMA); + } + let _shortEMA = newEMA(shortEMA, SHORT_ALPHA, currentBlockVolume); + let _longEMA = newEMA(longEMA, LONG_ALPHA, currentBlockVolume); + _shortEMA = mulInPrecision( + _shortEMA, + unsafePowInPrecision(PRECISION - SHORT_ALPHA, skipBlock - 1n), + ); + _longEMA = mulInPrecision( + _longEMA, + unsafePowInPrecision(PRECISION - LONG_ALPHA, skipBlock - 1n), + ); + return calculateRFactor(_shortEMA, _longEMA); +}; + +export const calculateRFactor = ( + _shortEMA: bigint, + _longEMA: bigint, +): bigint => { + if (_longEMA == 0n) { + return 0n; + } + return (_shortEMA * PRECISION) / _longEMA; +}; + +/// @dev return newEMA value +/// @param ema previous ema value in wei +/// @param alpha in Precision (required < Precision) +/// @param value current value to update ema +/// @dev ema and value is uint128 and alpha < Precision +/// @dev so this function can not overflow and returned ema is not overflow uint128 +export const newEMA = (ema: bigint, alpha: bigint, value: bigint): bigint => { + if (alpha > PRECISION) throw new Error('NewEma: alpha > PRECISION'); + return ((PRECISION - alpha) * ema + alpha * value) / PRECISION; +}; diff --git a/src/dex/zuludmm/math-ext.ts b/src/dex/zuludmm/math-ext.ts new file mode 100644 index 000000000..ab2a932fe --- /dev/null +++ b/src/dex/zuludmm/math-ext.ts @@ -0,0 +1,29 @@ +import { BI_POWS } from '../../bigint-constants'; + +const PRECISION = BI_POWS[18]; + +/// @dev Returns x*y in precision +export const mulInPrecision = (x: bigint, y: bigint): bigint => { + return (x * y) / PRECISION; +}; + +/// @dev source: dsMath +/// @param xInPrecision should be < PRECISION, so this can not overflow +/// @return zInPrecision = (x/PRECISION) ^k * PRECISION +export const unsafePowInPrecision = ( + xInPrecision: bigint, + k: bigint, +): bigint => { + if (xInPrecision > PRECISION) throw new Error(`MathExt: x > PRECISION`); + + let zInPrecision = k % 2n == 0n ? PRECISION : xInPrecision; + + for (let c = k / 2n; c != 0n; c = c / 2n) { + xInPrecision = mulInPrecision(xInPrecision, xInPrecision); + + if (c % 2n != 0n) { + zInPrecision = mulInPrecision(zInPrecision, xInPrecision); + } + } + return zInPrecision; +}; diff --git a/src/dex/zuludmm/pool.ts b/src/dex/zuludmm/pool.ts new file mode 100644 index 000000000..b7451c3c8 --- /dev/null +++ b/src/dex/zuludmm/pool.ts @@ -0,0 +1,226 @@ +import { AbiCoder, Interface } from '@ethersproject/abi'; +import { DeepReadonly } from 'ts-essentials'; +import zuluDmmPoolABI from '../../abi/zuludmm/zulu-dmm-pool.abi.json'; +import { getFee, getRFactor } from './fee-formula'; +import { ZuluDmmAbiEvents, TradeInfo } from './types'; +import { StatefulEventSubscriber } from '../../stateful-event-subscriber'; +import { Address, BlockHeader, Log, Logger, Token } from '../../types'; +import { IDexHelper } from '../../dex-helper/idex-helper'; +import { BI_POWS } from '../../bigint-constants'; + +export type ZuluDmmPools = { [poolAddress: string]: ZuluDmmPool }; + +export type ZuluDmmPair = { + token0: Token; + token1: Token; + exchanges: Address[]; + pools: ZuluDmmPools; +}; + +export interface ZuluDmmPoolState { + reserves: { + reserves0: bigint; + reserves1: bigint; + vReserves0: bigint; + vReserves1: bigint; + }; + trendData: { + shortEMA: bigint; + longEMA: bigint; + lastBlockVolume: bigint; + lastTradeBlock: bigint; + }; + ampBps: bigint; +} + +export interface ZuluDmmPoolOrderedParams { + tokenIn: string; + tokenOut: string; + poolData: Array<{ + poolAddress: string; + state: ZuluDmmPoolState; + }>; + direction: boolean; + exchanges: string[]; +} + +const iface = new Interface(zuluDmmPoolABI); +const coder = new AbiCoder(); + +export class ZuluDmmPool extends StatefulEventSubscriber { + decoder: (log: Log) => ZuluDmmAbiEvents = (log: Log) => + iface.parseLog(log) as any as ZuluDmmAbiEvents; + + constructor( + parentName: string, + protected dexHelper: IDexHelper, + private poolAddress: Address, + + token0: Token, + token1: Token, + public ampBps: bigint, + + logger: Logger, + ) { + super( + parentName, + (token0.symbol || token0.address) + + '-' + + (token1.symbol || token1.address) + + ' pool', + dexHelper, + logger, + ); + } + + protected async processLog( + state: DeepReadonly, + log: Readonly, + blockHeader: BlockHeader, + ): Promise | null> { + const event = this.decoder(log); + switch (event.name) { + case 'Sync': { + if (this.isAmpPool()) + return { + ...state, + reserves: { + reserves0: BigInt(event.args.reserve0.toString()), + reserves1: BigInt(event.args.reserve1.toString()), + vReserves0: BigInt(event.args.vReserve0.toString()), + vReserves1: BigInt(event.args.vReserve1.toString()), + }, + }; + else + return { + ...state, + reserves: { + reserves0: BigInt(event.args.reserve0.toString()), + reserves1: BigInt(event.args.reserve1.toString()), + vReserves0: BigInt(event.args.reserve0.toString()), + vReserves1: BigInt(event.args.reserve1.toString()), + }, + }; + } + case 'UpdateEMA': + return { + ...state, + trendData: { + shortEMA: BigInt(event.args.shortEMA.toString()), + longEMA: BigInt(event.args.longEMA.toString()), + lastBlockVolume: BigInt(event.args.lastBlockVolume.toString()), + lastTradeBlock: BigInt(blockHeader.number.toString()), + }, + }; + } + return null; + } + + isAmpPool(): boolean { + return this.ampBps != BPS; + } + + async generateState( + blockNumber: number | 'latest' = 'latest', + ): Promise> { + const data: { returnData: any[] } = + await this.dexHelper.multiContract.methods + .aggregate([ + { + target: this.poolAddress, + callData: iface.encodeFunctionData('getTradeInfo', []), + }, + { + target: this.poolAddress, + callData: iface.encodeFunctionData('getVolumeTrendData', []), + }, + ]) + .call({}, blockNumber); + + const [reserves0, reserves1, vReserves0, vReserves1] = coder + .decode(['uint256', 'uint256', 'uint256', 'uint256'], data.returnData[0]) + .map(a => BigInt(a.toString())); + + const [shortEMA, longEMA, , lastTradeBlock] = coder + .decode(['uint256', 'uint256', 'uint128', 'uint256'], data.returnData[1]) + .map(a => BigInt(a.toString())); + + if (blockNumber == 'latest') + blockNumber = await this.dexHelper.web3Provider.eth.getBlockNumber(); + + const prevBlockData: { returnData: any[] } = + await this.dexHelper.multiContract.methods + .aggregate([ + { + target: this.poolAddress, + callData: iface.encodeFunctionData('getVolumeTrendData', []), + }, + ]) + .call({}, blockNumber - 1); + + const [, , lastBlockVolume] = coder + .decode( + ['uint256', 'uint256', 'uint128', 'uint256'], + prevBlockData.returnData[0], + ) + .map(a => BigInt(a.toString())); + + return { + trendData: { + shortEMA, + longEMA, + lastBlockVolume, + lastTradeBlock, + }, + reserves: { + reserves0, + reserves1, + vReserves0, + vReserves1, + }, + ampBps: this.ampBps, + }; + } +} + +const BPS = 10000n; + +const getFinalFee = (feeInPrecision: bigint, _ampBps: bigint): bigint => { + if (_ampBps <= 20000) { + return feeInPrecision; + } else if (_ampBps <= 50000) { + return (feeInPrecision * 20n) / 30n; + } else if (_ampBps <= 200000) { + return (feeInPrecision * 10n) / 30n; + } else { + return (feeInPrecision * 4n) / 30n; + } +}; + +/// @dev returns data to calculate amountIn, amountOut +export const getTradeInfo = ( + state: ZuluDmmPoolState, + blockNumber: number, + isTokenOrdered: boolean, +): TradeInfo => { + const _ampBps = state.ampBps; + let vReserves0 = state.reserves.vReserves0; + let vReserves1 = state.reserves.vReserves1; + if (_ampBps == BPS) { + vReserves0 = state.reserves.reserves0; + vReserves1 = state.reserves.reserves1; + } + const rFactorInPrecision = getRFactor(BigInt(blockNumber), state.trendData); + const feeInPrecision = getFinalFee(getFee(rFactorInPrecision), _ampBps); + return { + reserves0: isTokenOrdered + ? state.reserves.reserves0 + : state.reserves.reserves1, + reserves1: isTokenOrdered + ? state.reserves.reserves1 + : state.reserves.reserves0, + vReserves0: isTokenOrdered ? vReserves0 : vReserves1, + vReserves1: isTokenOrdered ? vReserves1 : vReserves0, + feeInPrecision, + }; +}; diff --git a/src/dex/zuludmm/types.ts b/src/dex/zuludmm/types.ts new file mode 100644 index 000000000..3c3cc95b8 --- /dev/null +++ b/src/dex/zuludmm/types.ts @@ -0,0 +1,85 @@ +import { EventFragment } from '@ethersproject/abi'; +import { BigNumberish } from '@ethersproject/bignumber'; +import { ValueOf } from 'ts-essentials'; +import { Address, Token } from '../../types'; + +export type ZuluDmmSellParam = [ + srcAmount: string, + destAmount: string, + pools: string[], + path: string[], + to: string, + deadline: string, +]; + +export type ZuluDmmBuyParam = [ + destAmount: string, + srcAmount: string, + pools: string[], + path: string[], + to: string, + deadline: string, +]; + +export type ZuluDmmParam = ZuluDmmBuyParam | ZuluDmmSellParam; + +export enum ZuluDMMFunctions { + swapExactTokensForTokens = 'swapExactTokensForTokens', + swapTokensForExactTokens = 'swapTokensForExactTokens', +} + +export type ZuluDmmData = { + router: Address; + path: Address[]; + pools: { + address: Address; + direction: boolean; + fee: number; + }[]; + factory: Address; +}; + +export type TradeInfo = { + reserves0: bigint; + reserves1: bigint; + vReserves0: bigint; + vReserves1: bigint; + feeInPrecision: bigint; +}; + +export type ZuluDmmAbiEventMap = { + Sync: { + readonly eventFragment: EventFragment; + readonly name: 'Sync'; + readonly signature: 'Sync(uint256,uint256,uint256,uint256)'; + readonly topic: '0x2f9d55abfefdfd4c3a83e00a1b419b3c2fe4b83100c559f0e2213e57f6e0bba9'; + readonly args: { + reserve0: BigNumberish; + reserve1: BigNumberish; + vReserve0: BigNumberish; + vReserve1: BigNumberish; + }; + }; + UpdateEMA: { + readonly eventFragment: EventFragment; + readonly name: 'UpdateEMA'; + readonly signature: 'UpdateEMA(uint256,uint256,uint128,uint256)'; + readonly topic: '0x96e2c334d3c0fa98c8b728ee84471864ffe5b28e05f46e52f8a469d0ab3a8b8b'; + readonly args: { + shortEMA: BigNumberish; + longEMA: BigNumberish; + lastBlockVolume: BigNumberish; + skipBlock: BigNumberish; + }; + }; +}; + +export type ZuluDmmAbiEvents = ValueOf; + +export type DexParams = { + subgraphURL: string; + routerAddress: Address; + factoryAddress: Address; + adapters?: { [side: string]: { name: string; index: number }[] | null }; + poolGasCost?: number; +}; diff --git a/src/dex/zuludmm/zuludmm-e2e.test.ts b/src/dex/zuludmm/zuludmm-e2e.test.ts new file mode 100644 index 000000000..5c78ca14f --- /dev/null +++ b/src/dex/zuludmm/zuludmm-e2e.test.ts @@ -0,0 +1,322 @@ +import dotenv from 'dotenv'; +dotenv.config(); + +import { testE2E } from '../../../tests/utils-e2e'; +import { + Tokens, + Holders, + NativeTokenSymbols, +} from '../../../tests/constants-e2e'; +import { Network, ContractMethod, SwapSide } from '../../constants'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { generateConfig } from '../../config'; + +jest.setTimeout(50 * 1000); + +describe('ZuluDmm E2E', () => { + const dexKey = 'ZuluDmm'; + + describe('ZuluDmm MAINNET', () => { + const network = Network.MAINNET; + const tokens = Tokens[network]; + const holders = Holders[network]; + const provider = new StaticJsonRpcProvider( + generateConfig(network).privateHttpProvider, + network, + ); + + const tokenASymbol: string = 'USDT'; + const tokenBSymbol: string = 'WBTC'; + const nativeTokenSymbol = NativeTokenSymbols[network]; + + const tokenAAmount: string = '2000000'; + const tokenBAmount: string = '2000000'; + const nativeTokenAmount = '1000000000000000000'; + + const sideToContractMethods = new Map([ + [ + SwapSide.SELL, + [ + ContractMethod.simpleSwap, + ContractMethod.multiSwap, + ContractMethod.megaSwap, + ], + ], + [SwapSide.BUY, [ContractMethod.simpleBuy]], + ]); + + sideToContractMethods.forEach((contractMethods, side) => + contractMethods.forEach((contractMethod: ContractMethod) => { + describe(`${contractMethod}`, () => { + it(nativeTokenSymbol + ' -> TOKEN', async () => { + await testE2E( + tokens[nativeTokenSymbol], + tokens[tokenASymbol], + holders[nativeTokenSymbol], + side === SwapSide.SELL ? nativeTokenAmount : tokenAAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it('TOKEN -> ' + nativeTokenSymbol, async () => { + await testE2E( + tokens[tokenASymbol], + tokens[nativeTokenSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : nativeTokenAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it('TOKEN -> TOKEN', async () => { + await testE2E( + tokens[tokenASymbol], + tokens[tokenBSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : tokenBAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + }); + }), + ); + }); + + describe('ZuluDmm POLYGON', () => { + const network = Network.POLYGON; + const tokens = Tokens[network]; + const holders = Holders[network]; + const provider = new StaticJsonRpcProvider( + generateConfig(network).privateHttpProvider, + network, + ); + + const tokenASymbol: string = 'DAI'; + const tokenBSymbol: string = 'USDC'; + const nativeTokenSymbol = NativeTokenSymbols[network]; + + const tokenAAmount: string = '700000000000000000000'; + const tokenBAmount: string = '7000000'; + const nativeTokenAmount = '7000000000000000000'; + + const sideToContractMethods = new Map([ + [ + SwapSide.SELL, + [ + ContractMethod.simpleSwap, + ContractMethod.multiSwap, + ContractMethod.megaSwap, + ], + ], + [SwapSide.BUY, [ContractMethod.simpleBuy]], + ]); + + sideToContractMethods.forEach((contractMethods, side) => + contractMethods.forEach((contractMethod: ContractMethod) => { + describe(`${contractMethod}`, () => { + it(nativeTokenSymbol + ' -> TOKEN', async () => { + await testE2E( + tokens[nativeTokenSymbol], + tokens[tokenASymbol], + holders[nativeTokenSymbol], + side === SwapSide.SELL ? nativeTokenAmount : tokenAAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it('TOKEN -> ' + nativeTokenSymbol, async () => { + await testE2E( + tokens[tokenASymbol], + tokens[nativeTokenSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : nativeTokenAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it('TOKEN -> TOKEN', async () => { + await testE2E( + tokens[tokenASymbol], + tokens[tokenBSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : tokenBAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + }); + }), + ); + }); + + describe('ZuluDmm BSC', () => { + const network = Network.BSC; + const tokens = Tokens[network]; + const holders = Holders[network]; + const provider = new StaticJsonRpcProvider( + generateConfig(network).privateHttpProvider, + network, + ); + + const tokenASymbol: string = 'USDT'; + const tokenBSymbol: string = 'BUSD'; + const nativeTokenSymbol = NativeTokenSymbols[network]; + + const tokenAAmount: string = '700000000000000000000'; + const tokenBAmount: string = '700000000000000000000'; + const nativeTokenAmount = '7000000000000000000'; + + const sideToContractMethods = new Map([ + [ + SwapSide.SELL, + [ + ContractMethod.simpleSwap, + ContractMethod.multiSwap, + ContractMethod.megaSwap, + ], + ], + [SwapSide.BUY, [ContractMethod.simpleBuy]], + ]); + + sideToContractMethods.forEach((contractMethods, side) => + contractMethods.forEach((contractMethod: ContractMethod) => { + describe(`${contractMethod}`, () => { + it(nativeTokenSymbol + ' -> TOKEN', async () => { + await testE2E( + tokens[nativeTokenSymbol], + tokens[tokenASymbol], + holders[nativeTokenSymbol], + side === SwapSide.SELL ? nativeTokenAmount : tokenAAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it('TOKEN -> ' + nativeTokenSymbol, async () => { + await testE2E( + tokens[tokenASymbol], + tokens[nativeTokenSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : nativeTokenAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it('TOKEN -> TOKEN', async () => { + await testE2E( + tokens[tokenASymbol], + tokens[tokenBSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : tokenBAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + }); + }), + ); + }); + + describe('ZuluDmm AVALANCHE', () => { + const network = Network.AVALANCHE; + const tokens = Tokens[network]; + const holders = Holders[network]; + const provider = new StaticJsonRpcProvider( + generateConfig(network).privateHttpProvider, + network, + ); + + const tokenASymbol: string = 'USDCe'; + const tokenBSymbol: string = 'USDTe'; + const nativeTokenSymbol = NativeTokenSymbols[network]; + + const tokenAAmount: string = '7000000'; + const tokenBAmount: string = '7000000'; + const nativeTokenAmount = '70000000000000000'; + + const sideToContractMethods = new Map([ + [ + SwapSide.SELL, + [ + ContractMethod.simpleSwap, + ContractMethod.multiSwap, + ContractMethod.megaSwap, + ], + ], + [SwapSide.BUY, [ContractMethod.simpleBuy]], + ]); + + sideToContractMethods.forEach((contractMethods, side) => + contractMethods.forEach((contractMethod: ContractMethod) => { + describe(`${contractMethod}`, () => { + it(nativeTokenSymbol + ' -> TOKEN', async () => { + await testE2E( + tokens[nativeTokenSymbol], + tokens[tokenASymbol], + holders[nativeTokenSymbol], + side === SwapSide.SELL ? nativeTokenAmount : tokenAAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it('TOKEN -> ' + nativeTokenSymbol, async () => { + await testE2E( + tokens[tokenASymbol], + tokens[nativeTokenSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : nativeTokenAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it('TOKEN -> TOKEN', async () => { + await testE2E( + tokens[tokenASymbol], + tokens[tokenBSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : tokenBAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + }); + }), + ); + }); +}); diff --git a/src/dex/zuludmm/zuludmm-events.test.ts b/src/dex/zuludmm/zuludmm-events.test.ts new file mode 100644 index 000000000..0a4a5e36b --- /dev/null +++ b/src/dex/zuludmm/zuludmm-events.test.ts @@ -0,0 +1,122 @@ +import dotenv from 'dotenv'; +dotenv.config(); + +import { ZuluDmmPool, ZuluDmmPoolState } from './pool'; +import { ZuluDmmConfig } from './config'; +import { Network } from '../../constants'; +import { DummyDexHelper } from '../../dex-helper/index'; +import { testEventSubscriber } from '../../../tests/utils-events'; +import { Tokens } from './../../../tests/constants-e2e'; +import { DeepReadonly } from 'ts-essentials'; +import { BI_POWS } from '../../bigint-constants'; + +jest.setTimeout(50 * 1000); + +const dexKey = 'ZuluDmm'; +const network = Network.MAINNET; +const config = ZuluDmmConfig[dexKey][network]; +const tokens = Tokens[network]; + +type PoolParam = { + address: string; + token0Symbol: string; + token1Symbol: string; + ampBps: bigint; +}; + +const poolsParams: PoolParam[] = [ + { + address: '0xD343d5dba2FBa55EEF58189619c05e33CAB95cA1', + ampBps: 15000n, + token0Symbol: 'WBTC', + token1Symbol: 'USDT', + }, + { + address: '0x1cf68Bbc2b6D3C6CfE1BD3590CF0E10b06a05F17', + ampBps: 20000n, + token0Symbol: 'WBTC', + token1Symbol: 'WETH', + }, + { + address: '0xA97642500517C728cE1339A466DE0F10C19034CD', + ampBps: 10000n, + token0Symbol: 'REQ', + token1Symbol: 'WETH', + }, +]; + +async function fetchPoolState( + zuluDmmPool: ZuluDmmPool, + blockNumber: number, +): Promise> { + return zuluDmmPool.generateState(blockNumber); +} + +describe('ZuluDmm Event', function () { + const blockNumbers: { [eventName: string]: [number, PoolParam][] } = { + Sync: [ + [14336994, poolsParams[0]], + [14341503, poolsParams[0]], + [14340012, poolsParams[0]], + [14336359, poolsParams[0]], + [14341726, poolsParams[0]], + [14337005, poolsParams[1]], + [14339216, poolsParams[1]], + [14336398, poolsParams[1]], + [14336231, poolsParams[1]], + [14340006, poolsParams[1]], + [14336723, poolsParams[2]], + [14336819, poolsParams[2]], + [14337049, poolsParams[2]], + [14337053, poolsParams[2]], + [14338292, poolsParams[2]], + ], + UpdateEMA: [ + [14336994, poolsParams[0]], + [14340012, poolsParams[0]], + [14341503, poolsParams[0]], + [14336359, poolsParams[0]], + [14341726, poolsParams[0]], + [14337005, poolsParams[1]], + [14339216, poolsParams[1]], + [14336398, poolsParams[1]], + [14336231, poolsParams[1]], + [14340006, poolsParams[1]], + [14336723, poolsParams[2]], + [14336819, poolsParams[2]], + [14337049, poolsParams[2]], + [14337053, poolsParams[2]], + [14338292, poolsParams[2]], + ], + }; + + describe('ZuluDmmPool', function () { + Object.keys(blockNumbers).forEach((event: string) => { + blockNumbers[event].forEach(([blockNumber, poolParam]) => { + it(`Should return the correct state after the ${blockNumber}:${event}`, async function () { + const dexHelper = new DummyDexHelper(network); + const logger = dexHelper.getLogger(dexKey); + + const zuluDmmPool = new ZuluDmmPool( + dexKey, + dexHelper, + poolParam.address, + tokens[poolParam.token0Symbol], + tokens[poolParam.token1Symbol], + poolParam.ampBps, + logger, + ); + + await testEventSubscriber( + zuluDmmPool, + [poolParam.address], + (_blockNumber: number) => fetchPoolState(zuluDmmPool, _blockNumber), + blockNumber, + `${dexKey}_${poolParam.address}`, + dexHelper.provider, + ); + }); + }); + }); + }); +}); diff --git a/src/dex/zuludmm/zuludmm-integration.test.ts b/src/dex/zuludmm/zuludmm-integration.test.ts new file mode 100644 index 000000000..0405e3ee7 --- /dev/null +++ b/src/dex/zuludmm/zuludmm-integration.test.ts @@ -0,0 +1,90 @@ +import dotenv from 'dotenv'; +dotenv.config(); + +import { DummyDexHelper } from '../../dex-helper/index'; +import { Network, SwapSide } from '../../constants'; +import { ZuluDmm } from './zuludmm'; +import { checkPoolPrices, checkPoolsLiquidity } from '../../../tests/utils'; +import { Tokens } from '../../../tests/constants-e2e'; +import { BI_POWS } from '../../bigint-constants'; + +const network = Network.MAINNET; +const TokenASymbol = 'USDT'; +const TokenA = Tokens[network][TokenASymbol]; + +const TokenBSymbol = 'WBTC'; +const TokenB = Tokens[network][TokenBSymbol]; + +const amounts = [0n, BI_POWS[6], 2000000n]; + +const dexKey = 'ZuluDmm'; + +describe('ZuluDmm', function () { + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + const dexHelper = new DummyDexHelper(network); + const blocknumber = await dexHelper.web3Provider.eth.getBlockNumber(); + const zuluDmm = new ZuluDmm(network, dexKey, dexHelper); + + const pools = await zuluDmm.getPoolIdentifiers( + TokenA, + TokenB, + SwapSide.SELL, + blocknumber, + ); + console.log(`${TokenASymbol} <> ${TokenBSymbol} Pool Identifiers: `, pools); + + expect(pools.length).toBeGreaterThan(0); + + const poolPrices = await zuluDmm.getPricesVolume( + TokenA, + TokenB, + amounts, + SwapSide.SELL, + blocknumber, + pools, + ); + console.log('${TokenASymbol} <> ${TokenBSymbol} Pool Prices: ', poolPrices); + + expect(poolPrices).not.toBeNull(); + checkPoolPrices(poolPrices!, amounts, SwapSide.SELL, dexKey); + }); + + it('getPoolIdentifiers and getPricesVolume BUY', async function () { + const dexHelper = new DummyDexHelper(network); + const blocknumber = await dexHelper.web3Provider.eth.getBlockNumber(); + const zuluDmm = new ZuluDmm(network, dexKey, dexHelper); + + const pools = await zuluDmm.getPoolIdentifiers( + TokenA, + TokenB, + SwapSide.BUY, + blocknumber, + ); + console.log(`${TokenASymbol} <> ${TokenBSymbol} Pool Identifiers: `, pools); + + expect(pools.length).toBeGreaterThan(0); + + const poolPrices = await zuluDmm.getPricesVolume( + TokenA, + TokenB, + amounts, + SwapSide.BUY, + blocknumber, + pools, + ); + console.log('${TokenASymbol} <> ${TokenBSymbol} Pool Prices: ', poolPrices); + + expect(poolPrices).not.toBeNull(); + checkPoolPrices(poolPrices!, amounts, SwapSide.BUY, dexKey); + }); + + it('getTopPoolsForToken', async function () { + const dexHelper = new DummyDexHelper(network); + const zuluDmm = new ZuluDmm(network, dexKey, dexHelper); + + const poolLiquidity = await zuluDmm.getTopPoolsForToken(TokenA.address, 10); + console.log(`${TokenASymbol} Top Pools:`, poolLiquidity); + + checkPoolsLiquidity(poolLiquidity, TokenA.address, dexKey); + }); +}); diff --git a/src/dex/zuludmm/zuludmm.ts b/src/dex/zuludmm/zuludmm.ts new file mode 100644 index 000000000..6db6bb728 --- /dev/null +++ b/src/dex/zuludmm/zuludmm.ts @@ -0,0 +1,603 @@ +import { Interface, AbiCoder } from '@ethersproject/abi'; +import { SimpleExchange } from '../simple-exchange'; +import { IDex } from '../idex'; +import _ from 'lodash'; +import { Network, SUBGRAPH_TIMEOUT, SwapSide } from '../../constants'; +import * as CALLDATA_GAS_COST from '../../calldata-gas-cost'; +import { PRECISION } from './fee-formula'; +import { + getTradeInfo, + ZuluDmmPair, + ZuluDmmPool, + ZuluDmmPoolOrderedParams, + ZuluDmmPoolState, +} from './pool'; +import { + AdapterExchangeParam, + ExchangePrices, + PoolPrices, + PoolLiquidity, + SimpleExchangeParam, + Token, +} from '../../types'; +import { + ZuluDmmData, + ZuluDMMFunctions, + ZuluDmmParam, + TradeInfo, +} from './types'; +import { IDexHelper } from '../../dex-helper'; +import { Adapters, ZuluDmmConfig } from './config'; +import { Logger } from 'log4js'; +import { Contract } from 'web3-eth-contract'; + +import zuluDmmFactoryABI from '../../abi/zuludmm/zulu-dmm-factory.abi.json'; +import zuluDmmPoolABI from '../../abi/zuludmm/zulu-dmm-pool.abi.json'; +import ZuluDmmExchangeRouterABI from '../../abi/zuludmm/zulu-dmm-exchange-router.abi.json'; +import { getBigIntPow, getDexKeysWithNetwork } from '../../utils'; + +const MAX_TRACKED_PAIR_POOLS = 3; + +const iface = new Interface(zuluDmmPoolABI); +const coder = new AbiCoder(); + +export class ZuluDmm + extends SimpleExchange + implements IDex +{ + pairs: { [key: string]: ZuluDmmPair } = {}; + needWrapNative = true; + factory: Contract; + logger: Logger; + + exchangeRouterInterface: Interface; + + readonly hasConstantPriceLargeAmounts = false; + readonly isFeeOnTransferSupported = false; + + public static dexKeysWithNetwork: { key: string; networks: Network[] }[] = + getDexKeysWithNetwork(ZuluDmmConfig); + + constructor( + protected network: Network, + dexKey: string, + protected dexHelper: IDexHelper, + protected config = ZuluDmmConfig[dexKey][network], + protected adapters = Adapters[network], + ) { + super(dexHelper, dexKey); + + this.logger = dexHelper.getLogger(dexKey); + + this.factory = new this.dexHelper.web3Provider.eth.Contract( + zuluDmmFactoryABI as any, + config.factoryAddress, + ); + + this.exchangeRouterInterface = new Interface(ZuluDmmExchangeRouterABI); + } + + async getPoolIdentifiers( + from: Token, + to: Token, + side: SwapSide, + blockNumber: number, + ): Promise { + from = this.dexHelper.config.wrapETH(from); + to = this.dexHelper.config.wrapETH(to); + + const pair = await this.findPair(from, to); + + if (pair && pair.exchanges.length > 0) { + const z = pair.exchanges.map(poolAddress => { + return `${this.dexKey}_${poolAddress.toLowerCase()}`; + }); + + return z; + } else return []; + } + + getAdapters(side: SwapSide): { name: string; index: number }[] | null { + if (side === SwapSide.BUY) return null; + return this.adapters; + } + + async getTopPoolsForToken( + tokenAddress: string, + count: number, + ): Promise { + if (!this.config.subgraphURL) return []; + + const query = ` + query ($token: Bytes!, $count: Int) { + pools0: pairs(first: $count, orderBy: reserveUSD, orderDirection: desc, where: {token0: $token}) { + id + reserveUSD + token0{ + id + decimals + } + token1{ + id + decimals + } + } + pools1: pairs(first: $count, orderBy: reserveUSD, orderDirection: desc, where: {token1: $token}) { + id + reserveUSD + token1{ + id + decimals + } + token0{ + id + decimals + } + } + } + `; + + const { data } = await this.dexHelper.httpRequest.post( + this.config.subgraphURL, + { + query, + variables: { token: tokenAddress.toLowerCase(), count }, + }, + SUBGRAPH_TIMEOUT, + ); + + if (!(data && data.pools0 && data.pools1)) + throw new Error( + `Error_${this.dexKey}_Subgraph: couldn't fetch the pools from the subgraph`, + ); + + const pools = _.map(_.concat(data.pools0, data.pools1), pool => ({ + exchange: this.dexKey, + address: pool.id.toLowerCase(), + connectorTokens: [pool.token0, pool.token1].reduce( + (acc, { decimals, id }) => { + if (id.toLowerCase() != tokenAddress.toLowerCase()) + acc.push({ + decimals: parseInt(decimals), + address: id.toLowerCase(), + }); + return acc; + }, + [], + ), + liquidityUSD: parseFloat(pool.reserveUSD), + })); + + return _.slice(_.sortBy(pools, [pool => -1 * pool.liquidityUSD]), 0, count); + } + + getAdapterParam( + srcToken: string, + destToken: string, + srcAmount: string, + destAmount: string, + data: ZuluDmmData, + side: SwapSide, + ): AdapterExchangeParam { + const payload = this.abiCoder.encodeParameter( + { + ParentStruct: { + poolPath: 'address[]', + path: 'address[]', + }, + }, + { poolPath: data.pools.map(p => p.address), path: data.path }, + ); + return { + targetExchange: data.router, + payload, + networkFee: '0', + }; + } + + async getSimpleParam( + srcToken: string, + destToken: string, + srcAmount: string, + destAmount: string, + data: ZuluDmmData, + side: SwapSide, + ): Promise { + const isSell = side === SwapSide.SELL; + const swapFunctionParams: ZuluDmmParam = [ + isSell ? srcAmount : destAmount, + isSell ? destAmount : srcAmount, + data.pools.map(p => p.address), + data.path, + this.augustusAddress, + Number.MAX_SAFE_INTEGER.toString(), + ]; + const swapData = this.exchangeRouterInterface.encodeFunctionData( + isSell + ? ZuluDMMFunctions.swapExactTokensForTokens + : ZuluDMMFunctions.swapTokensForExactTokens, + swapFunctionParams, + ); + + return this.buildSimpleParamWithoutWETHConversion( + srcToken, + srcAmount, + destToken, + destAmount, + swapData, + data.router, + ); + } + + private async addPool( + pair: ZuluDmmPair, + poolAddress: string, + poolData: ZuluDmmPoolState, + blockNumber: number, + ) { + if ( + pair.exchanges.find(p => p === poolAddress) && + !(poolAddress in pair.pools) + ) { + const pool = new ZuluDmmPool( + this.dexKey, + this.dexHelper, + poolAddress, + pair.token0, + pair.token1, + poolData.ampBps, + this.logger, + ); + pair.pools[poolAddress] = pool; + pool.addressesSubscribed.push(poolAddress); + await pool.initialize(blockNumber, { + state: poolData, + }); + } + } + + async getPricesVolume( + from: Token, + to: Token, + amounts: bigint[], + side: SwapSide, + blockNumber: number, + limitPools?: string[], + ): Promise | null> { + try { + if (!this.factory) { + return null; + } + + from = this.dexHelper.config.wrapETH(from); + to = this.dexHelper.config.wrapETH(to); + + if (from.address.toLowerCase() === to.address.toLowerCase()) { + return null; + } + + await this.catchUpPair(from, to, blockNumber); + const pairParam = await this.getPairOrderedParams(from, to, blockNumber); + + if (!pairParam) return null; + + pairParam.poolData = pairParam.poolData.filter(pool => { + const poolIdentifier = `${ + this.dexKey + }_${pool.poolAddress.toLowerCase()}`; + return !limitPools || limitPools.includes(poolIdentifier); + }); + + if (!pairParam.poolData.length) return null; + + return Promise.all( + pairParam.poolData.map(pool => { + return this.getPoolPrice( + from, + to, + side, + amounts, + pool, + pairParam.direction, + `${this.dexKey}_${pool.poolAddress.toLowerCase()}`, + blockNumber, + ); + }), + ); + } catch (e) { + if (blockNumber === 0) + this.logger.error( + `${this.dexKey}_getPricesVolume: Aurelius block manager not yet instantiated`, + ); + this.logger.error(`${this.dexKey}_getPrices`, e); + return null; + } + } + + // Returns estimated gas cost of calldata for this DEX in multiSwap + getCalldataGasCost(poolPrices: PoolPrices): number | number[] { + return ( + CALLDATA_GAS_COST.DEX_OVERHEAD + + CALLDATA_GAS_COST.LENGTH_LARGE + + CALLDATA_GAS_COST.OFFSET_SMALL + + CALLDATA_GAS_COST.OFFSET_SMALL + + CALLDATA_GAS_COST.OFFSET_SMALL + + CALLDATA_GAS_COST.LENGTH_SMALL + + CALLDATA_GAS_COST.ADDRESS + + CALLDATA_GAS_COST.LENGTH_SMALL + + CALLDATA_GAS_COST.ADDRESS * 2 + ); + } + + private async getPoolPrice( + from: Token, + to: Token, + side: SwapSide, + amounts: bigint[], + pool: { poolAddress: string; state: ZuluDmmPoolState }, + direction: boolean, + poolIdentifier: string, + blockNumber: number, + ): Promise { + // const [tokenA] = [ + // from.address.toLowerCase(), + // to.address.toLowerCase(), + // ].sort((a, b) => (a > b ? 1 : -1)); + + const unitAmount = getBigIntPow( + side == SwapSide.BUY ? to.decimals : from.decimals, + ).toString(); + + const tradeInfo = getTradeInfo(pool.state, blockNumber, direction); + + const unit = + side == SwapSide.BUY + ? await this.getBuyPrice(tradeInfo, BigInt(unitAmount)) + : await this.getSellPrice(tradeInfo, BigInt(unitAmount)); + + const prices = + side == SwapSide.BUY + ? await Promise.all( + amounts.map(amount => + this.getBuyPrice(tradeInfo, BigInt(amount.toString())), + ), + ) + : await Promise.all( + amounts.map(amount => + this.getSellPrice(tradeInfo, BigInt(amount.toString())), + ), + ); + + return { + prices: prices.map(p => BigInt(p.toString())), + unit: BigInt(unit.toString()), + data: { + router: this.config.routerAddress, + path: [from.address.toLowerCase(), to.address.toLowerCase()], + factory: this.config.factoryAddress, + pools: [ + { + address: pool.poolAddress, + fee: tradeInfo.feeInPrecision.toString(), + direction, + }, + ], + }, + exchange: this.dexKey, + poolIdentifier, + gasCost: this.config.poolGasCost, + poolAddresses: [pool.poolAddress], + }; + } + + private async getManyPoolReserves( + pair: ZuluDmmPair, + blockNumber: number, + ): Promise<{ [poolAddress: string]: ZuluDmmPoolState }> { + try { + const calldata = pair.exchanges + .map(poolAddress => [ + { + target: poolAddress, + callData: iface.encodeFunctionData('getTradeInfo', []), + }, + { + target: poolAddress, + callData: iface.encodeFunctionData('getVolumeTrendData', []), + }, + { + target: poolAddress, + callData: iface.encodeFunctionData('ampBps', []), + }, + ]) + .flat(); + + const data: { returnData: any[] } = + await this.dexHelper.multiContract.methods + .aggregate(calldata) + .call({}, blockNumber); + + return pair.exchanges.reduce( + (acc: { [key: string]: ZuluDmmPoolState }, poolAddress, poolIndex) => { + const poolData = data.returnData.slice( + poolIndex * 3, + (poolIndex + 1) * 3, + ); + const [reserves0, reserves1, vReserves0, vReserves1] = coder + .decode(['uint256', 'uint256', 'uint256', 'uint256'], poolData[0]) + .map(n => BigInt(n.toString())); + const [shortEMA, longEMA, lastBlockVolume, lastTradeBlock] = coder + .decode(['uint256', 'uint256', 'uint128', 'uint256'], poolData[1]) + .map(n => BigInt(n.toString())); + const ampBps = BigInt( + coder.decode(['uint256'], poolData[2]).toString(), + ); + acc[poolAddress] = { + reserves: { + reserves0, + reserves1, + vReserves0, + vReserves1, + }, + trendData: { + shortEMA, + longEMA, + lastBlockVolume, + lastTradeBlock, + }, + ampBps, + }; + return acc; + }, + {}, + ); + } catch (e) { + this.logger.error( + `${this.dexKey}_getManyPoolReserves could not get reserves`, + e, + ); + return {}; + } + } + + private async catchUpPair(from: Token, to: Token, blockNumber: number) { + if (!blockNumber) return; + + const pair = await this.findPair(from, to); + + if (!pair || !pair.exchanges.length) return; + if ( + Object.keys(pair.pools).length && + !Object.values(pair.pools).find(pool => !pool.getState(blockNumber)) + ) + return; + + let poolsState = await this.getManyPoolReserves(pair, blockNumber); + + if (!Object.keys(poolsState).length) { + this.logger.error( + `${this.dexKey}_getManyPoolReserves didn't get any pool reserves`, + ); + return; + } + + // Filter out pools + if (pair.exchanges.length > MAX_TRACKED_PAIR_POOLS) { + poolsState = Object.fromEntries( + Object.entries(poolsState) + .sort(([, stateA], [, stateB]) => + stateA.reserves.reserves0 < stateB.reserves.reserves0 ? 1 : -1, + ) + .slice(0, MAX_TRACKED_PAIR_POOLS), + ); + pair.exchanges = pair.exchanges.filter(pool => poolsState[pool]); + } + + await Promise.all( + Object.entries(poolsState).map(async ([poolAddress, state]) => { + if (!pair.pools[poolAddress]) { + await this.addPool(pair, poolAddress, state, blockNumber); + } else pair.pools[poolAddress].setState(state, blockNumber); + }), + ); + } + + private async getPairOrderedParams( + from: Token, + to: Token, + blockNumber: number, + ): Promise { + const pair = await this.findPair(from, to); + if (!(pair && Object.keys(pair.pools).length && pair.exchanges.length)) + return null; + + const pairState = Object.entries(pair.pools) + .map(([poolAddress, pool]) => ({ + poolAddress, + state: pool.getState(blockNumber) as ZuluDmmPoolState, + ampBps: pool.ampBps, + })) + .filter(s => s.state); + + if (!pairState.length) { + this.logger.error( + `${this.dexKey}_orderPairParams expected reserves, got none (maybe the pool doesn't exist)`, + from.symbol || from.address, + to.symbol || to.address, + ); + return null; + } + const pairReversed = + pair.token1.address.toLowerCase() === from.address.toLowerCase(); + + return { + tokenIn: from.address, + tokenOut: to.address, + poolData: pairState, + exchanges: pair.exchanges, + direction: !pairReversed, + }; + } + + private async findPair(from: Token, to: Token) { + if (from.address.toLowerCase() === to.address.toLowerCase()) return null; + const [token0, token1] = + from.address.toLowerCase() < to.address.toLowerCase() + ? [from, to] + : [to, from]; + + const key = `${token0.address.toLowerCase()}-${token1.address.toLowerCase()}`; + let pair = this.pairs[key]; + if (pair) return pair; + const exchanges = await this.factory.methods + .getPools(token0.address, token1.address) + .call(); + if (!exchanges || !exchanges.length) { + pair = { token0, token1, exchanges: [], pools: {} }; + } else { + pair = { token0, token1, exchanges, pools: {} }; + } + this.pairs[key] = pair; + return pair; + } + + private async getBuyPrice(priceParams: TradeInfo, amountOut: bigint) { + const { + reserves0: reserveIn, + reserves1: reserveOut, + vReserves0: vReserveIn, + vReserves1: vReserveOut, + feeInPrecision, + } = priceParams; + if (amountOut <= 0) return 0; + if (reserveIn <= 0n || reserveOut <= amountOut) return 0; + + let numerator = vReserveIn * amountOut; + let denominator = vReserveOut - amountOut; + const amountIn = numerator / denominator + 1n; + // amountIn = floor(amountIN *PRECISION / (PRECISION - feeInPrecision)); + numerator = amountIn * PRECISION; + denominator = PRECISION - feeInPrecision; + return (numerator + denominator - 1n) / denominator; + } + + private async getSellPrice(priceParams: TradeInfo, amountIn: bigint) { + const { + reserves0: reserveIn, + reserves1: reserveOut, + vReserves0: vReserveIn, + vReserves1: vReserveOut, + feeInPrecision, + } = priceParams; + if (amountIn <= 0) return 0; + if (reserveIn <= 0 || reserveOut <= 0) return 0; + + const amountInWithFee = + (amountIn * (PRECISION - feeInPrecision)) / PRECISION; + const numerator = amountInWithFee * vReserveOut; + const denominator = vReserveIn + amountInWithFee; + const amountOut = numerator / denominator; + if (reserveOut <= amountOut) return 0; + return amountOut; + } +}