এলিগ্যান্ট এবং সংক্ষিপ্ত! এফএমজেডে 200 লাইনের কোড দিয়ে ইউনিস্যাপ ভি 3 অ্যাক্সেস করুন

লেখক:ছোট্ট স্বপ্ন, সৃষ্টিঃ ২০২৩-০১-৩০ 15:38:02, আপডেটঃ ২০২৩-০৯-১৮ 19:39:40

img

এলিগ্যান্ট এবং সংক্ষিপ্ত! এফএমজেডে 200 লাইনের কোড দিয়ে ইউনিস্যাপ ভি 3 অ্যাক্সেস করুন

সাম্প্রতিক বছরগুলোতে Defi ধারণার জনপ্রিয়তার সাথে সাথে বিকেন্দ্রীভূত অর্থনীতির (DeFi) ক্ষেত্রে Uniswap V3 অন্যতম আলোচিত বিষয়। একটি শীর্ষস্থানীয় বিকেন্দ্রীভূত বিনিময় প্রোটোকল হিসাবে, Uniswap V3 আরও দক্ষ, সুরক্ষিত এবং আরও ভাল ব্যবহারকারীর অভিজ্ঞতা প্রদান করে। এখন, মাত্র 200 টি কোডের সাথে, ব্যবসায়ী এবং বিকাশকারীরা FMZ প্ল্যাটফর্মে সহজেই Uniswap V3 অ্যাক্সেস করতে পারেন।

এফএমজেড একটি পরিমাণগত ট্রেডিং প্ল্যাটফর্ম যা পরিমাণগত ট্রেডিং কৌশলগুলির বিকাশ, পুনর্বিবেচনা এবং বাস্তব স্থাপনার জন্য সমর্থন করে। এর সহজেই ব্যবহারযোগ্য ইন্টারফেস এবং শক্তিশালী বৈশিষ্ট্যগুলি দেখে বোঝা যায় যে কেন এফএমজেড ডিএফআই ব্যবসায়ী এবং বিকাশকারীদের কাছে প্রথম পছন্দ হয়ে উঠছে।

FMZ-তে Uniswap V3 একীভূত করার প্রক্রিয়াটি সহজ এবং সহজেই 200 টি কোড লাইন দিয়ে সম্পন্ন করা যায়। এর অর্থ আপনি এমনকি যদি কোডিংয়ের নতুন হন তবে আপনি সহজেই FMZ-তে Uniswap V3 সংযুক্ত করতে পারেন এবং তাত্ক্ষণিকভাবে লেনদেন শুরু করতে পারেন।

এফএমজেড ওয়েব৩ এর মৌলিক বৈশিষ্ট্যগুলির একটি সিরিজকে প্যাকেজ করেছে, যা ইউনিস্যাপের পাশাপাশি অন্যান্য ডিএক্স এক্সচেঞ্জগুলিকে খুব কম কোডের সাথে প্যাকেজ করতে পারে। এরপরে আসুন আমি আপনাকে শূন্য ভিত্তিতে ডিএফআই অ্যাপ্লিকেশনগুলির ধারণাগুলি এবং প্রযুক্তিগুলি শিখতে শুরু করি।

এফএমজেড প্ল্যাটফর্মটি উন্মুক্ত"ইউনিস্যাপ ভি৩" ট্রেডিং লাইব্রেরি

কোডটি নিম্নরূপঃ

/* jshint esversion: 7 */

const ABI_Route = '[{"inputs":[{"internalType":"address","name":"_factoryV2","type":"address"},{"internalType":"address","name":"factoryV3","type":"address"},{"internalType":"address","name":"_positionManager","type":"address"},{"internalType":"address","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"callPositionManager","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"paths","type":"bytes[]"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactInputParams","name":"params","type":"tuple"}],"name":"exactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactInputSingleParams","name":"params","type":"tuple"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactOutputSingleParams","name":"params","type":"tuple"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factoryV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getApprovalType","outputs":[{"internalType":"enum IApproveAndCall.ApprovalType","name":"","type":"uint8"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"}],"internalType":"struct IApproveAndCall.IncreaseLiquidityParams","name":"params","type":"tuple"}],"name":"increaseLiquidity","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IApproveAndCall.MintParams","name":"params","type":"tuple"}],"name":"mint","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"previousBlockhash","type":"bytes32"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"positionManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"pull","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","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":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowedIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","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":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"wrapETH","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]';
const ABI_Pool = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Burn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"Collect\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"CollectProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid1\",\"type\":\"uint256\"}],\"name\":\"Flash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextOld\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextNew\",\"type\":\"uint16\"}],\"name\":\"IncreaseObservationCardinalityNext\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Initialize\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0New\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1New\",\"type\":\"uint8\"}],\"name\":\"SetFeeProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Swap\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"burn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collect\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collectProtocol\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"factory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fee\",\"outputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal0X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal1X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"flash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"}],\"name\":\"increaseObservationCardinalityNext\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquidity\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxLiquidityPerTick\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"observations\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"blockTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"int56\",\"name\":\"tickCumulative\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityCumulativeX128\",\"type\":\"uint160\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"secondsAgos\",\"type\":\"uint32[]\"}],\"name\":\"observe\",\"outputs\":[{\"internalType\":\"int56[]\",\"name\":\"tickCumulatives\",\"type\":\"int56[]\"},{\"internalType\":\"uint160[]\",\"name\":\"secondsPerLiquidityCumulativeX128s\",\"type\":\"uint160[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"positions\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside0LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside1LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"token0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"token1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"feeProtocol0\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol1\",\"type\":\"uint8\"}],\"name\":\"setFeeProtocol\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slot0\",\"outputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"},{\"internalType\":\"uint16\",\"name\":\"observationIndex\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinality\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"unlocked\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"}],\"name\":\"snapshotCumulativesInside\",\"outputs\":[{\"internalType\":\"int56\",\"name\":\"tickCumulativeInside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityInsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsInside\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"zeroForOne\",\"type\":\"bool\"},{\"internalType\":\"int256\",\"name\":\"amountSpecified\",\"type\":\"int256\"},{\"internalType\":\"uint160\",\"name\":\"sqrtPriceLimitX96\",\"type\":\"uint160\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"swap\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int16\",\"name\":\"\",\"type\":\"int16\"}],\"name\":\"tickBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"name\":\"ticks\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidityGross\",\"type\":\"uint128\"},{\"internalType\":\"int128\",\"name\":\"liquidityNet\",\"type\":\"int128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside0X128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside1X128\",\"type\":\"uint256\"},{\"internalType\":\"int56\",\"name\":\"tickCumulativeOutside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityOutsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsOutside\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token0\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token1\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]'
const ABI_Factory = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"FeeAmountEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenA\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenB\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"}],\"name\":\"createPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"enableFeeAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"feeAmountTickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"getPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"parameters\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]'

let ContractV3Factory = "0x1F98431c8aD98523631AE4a59f267346ea31F984"
let ContractV3SwapRouterV2 = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"


function computePoolPrice(decimals0, decimals1, sqrtPriceX96) {
    [decimals0, decimals1, sqrtPriceX96] = [decimals0, decimals1, sqrtPriceX96].map(BigInt);
    const TWO = BigInt(2);
    const TEN = BigInt(10);
    const SIX_TENTH = BigInt(1000000);
    const Q192 = (TWO ** BigInt(96)) ** TWO;
    return (
        Number((sqrtPriceX96 ** TWO * TEN ** decimals0 * SIX_TENTH) / (Q192 * TEN ** decimals1)) /
        Number(SIX_TENTH)
    );
}

function toAmount(s, decimals) {
    return Number((BigDecimal(BigInt(s))/BigDecimal(Math.pow(10, decimals))).toString())
}

function toInnerAmount(n, decimals) {
    return (BigDecimal(n)*BigDecimal(Math.pow(10,decimals))).toFixed(0)
}

$.NewUniswapV3 = function(e) {
    e = e || exchange
    if (e.GetName() !== 'Web3') {
        panic("only support Web3 exchange")
    }


    let self = {
        tokenInfo: {},
        walletAddress: e.IO("address"),
        pool: {}
    }

    // register
    e.IO("abi", ContractV3Factory, ABI_Factory)
    e.IO("abi", ContractV3SwapRouterV2, ABI_Route)

    self.addToken = function(name, address) {
        let ret = e.IO("api", address, "decimals")
        if (!ret) {
            throw "get token decimals failed"
        }
        let decimals = Number(ret)
        self.tokenInfo[name] = {
            name: name,
            decimals: decimals,
            address: address
        }
    }
    self.waitMined = function(tx) {
        while (true) {
            Sleep(1000)
            let info = e.IO("api", "eth", "eth_getTransactionReceipt", tx)
            if (info && info.gasUsed) {
                return true
            }
            Log('Transaction not yet mined', tx)
        }
    }

    self.swapToken = function(tokenIn, amountInDecimal, tokenOut, options) {
        // options like {gasPrice: 11, gasLimit: 111, nonce: 111}
        let tokenInInfo = self.tokenInfo[tokenIn]
        let tokenOutInfo = self.tokenInfo[tokenOut]
        if (!tokenInInfo) {
            throw "not found token info " + tokenIn
        }

        if (!tokenOutInfo) {
            throw "not found token info " + tokenOut
        }
        
        let amountIn = toInnerAmount(amountInDecimal, tokenInInfo.decimals)
        let recipientAddress = self.walletAddress
        if (tokenInInfo.name != 'ETH') {
            let allowanceAmount = e.IO("api", tokenInInfo.address, "allowance", self.walletAddress, ContractV3SwapRouterV2);
            let realAmount = toAmount(allowanceAmount, tokenInInfo.decimals)
            if (realAmount < toAmount(amountIn, tokenInInfo.decimals)) {
                Log("realAmount is", realAmount, "too small, try to approve large amount")
                if (tokenInInfo.name == 'USDT') {
                    // As described in Tether code: To change the approve amount you first have to reduce the addresses allowance to 0 calling approve(spender, 0)
                    let txApprove = e.IO("api", tokenInInfo.address, "approve", ContractV3SwapRouterV2, 0)
                    if (!txApprove) {
                        throw "approve error"
                    }
                    Log("wait reduce approve", txApprove)
                    self.waitMined(txApprove)
                }

                let txApprove = e.IO("api", tokenInInfo.address, "approve", ContractV3SwapRouterV2, '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
                if (!txApprove) {
                    throw "approve error"
                }
                Log("wait approve", txApprove)
                self.waitMined(txApprove)
                Log("approve success amountIn", amountIn)
            } else {
                Log("allowance", realAmount, "no need to approve")
            }
        }

        if (tokenOutInfo.name == 'ETH' || tokenOutInfo.address.toLowerCase() == '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2') {
            /*
            ADDRESS_THIS https://degencode.substack.com/p/uniswapv3-multicall
            https://etherscan.io/address/0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45#code
            */
            recipientAddress = '0x0000000000000000000000000000000000000002'
        }

        let swapToken = e.IO("encode", ContractV3SwapRouterV2, "swapExactTokensForTokens", amountIn, 1, [tokenInInfo.address, tokenOutInfo.address], recipientAddress)
        let data = [swapToken]
        if (tokenOutInfo.name == 'ETH') {
            data.push(e.IO("encode", ContractV3SwapRouterV2, "unwrapWETH9(uint256,address)", 1, self.walletAddress))
        }
        let tx = e.IO("api", ContractV3SwapRouterV2, "multicall(uint256,bytes[])", (tokenInInfo.name == 'ETH' ? amountIn : 0), (new Date().getTime() / 1000) + 3600, data, options || {})
        if (tx) {
            Log("tx: ", tx)
            self.waitMined(tx)
            Log("swap", tokenInInfo.name, "to", tokenOutInfo.name, "success")
            return true
        } else {
            Log("trans error")
            return false
        }
    }

    self.getETHBalance = function(address) {
        return toAmount(e.IO("api", "eth", "eth_getBalance", address || self.walletAddress, "latest"), 18)
    }

    self.balanceOf = function(token, address) {
        let tokenInfo = self.tokenInfo[token]
        if (!tokenInfo) {
            throw "not found token info " + token
        }

        return toAmount(e.IO("api", tokenInfo.address, "balanceOf", address || self.walletAddress), tokenInfo.decimals)
    }

    self.sendETH = function(to, amount, options) {
        return e.IO("api", "eth", "send", to, toInnerAmount(amount, 18), options || {})
    }

    self.getPrice = function(pair) {
        let arr = pair.split('_')
        let token0 = self.tokenInfo[arr[0]]
        if (!token0) {
            throw "token " + arr[0] + "not found"
        }
        let token1 = self.tokenInfo[arr[1]]
        if (!token1) {
            throw "token " + arr[1] + "not found"
        }
        let reverse = false
        if (BigInt(token0.address) > BigInt(token1.address)) {
            let tmp = token0
            token0 = token1
            token1 = tmp
            reverse = true
        }
        let key = token0.address + '/' + token1.address
        if (typeof(self.pool[key]) == 'undefined') {
            let pool = e.IO("api", ContractV3Factory, "getPool", token0.address, token1.address, 3000)
            if (pool) {
                self.pool[key] = pool
                // register pool address
                e.IO("abi", pool, ABI_Pool)
            }
        }
        if (typeof(self.pool[key]) == 'undefined') {
            throw "pool " + pair + " not found"
        }

        let slot0 = e.IO("api", self.pool[key], "slot0")

        if (!slot0) {
            return null
        }

        let price = computePoolPrice(token0.decimals, token1.decimals, slot0.sqrtPriceX96)
        if (reverse) {
            price = 1 / price
        }
        return price
    }

    return self
}

$.testUniswap = function() {
    let ex = $.NewUniswapV3()
    Log("walletAddress: ", ex.walletAddress)
    let tokenAddressMap = {
        "ETH": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH
        "USDT": "0xdac17f958d2ee523a2206206994597c13d831ec7",
        "1INCH": "0x111111111117dC0aa78b770fA6A738034120C302",
    }
    for (let name in tokenAddressMap) {
        ex.addToken(name, tokenAddressMap[name])
    }

    Log(ex.getPrice('ETH_USDT'))
    Log(ex.getPrice('1INCH_USDT'))
    // swap 0.01 ETH to USDT
    Log(ex.swapToken('ETH', 0.01, 'USDT'))
    let usdtBalance = ex.balanceOf('USDT')
    Log("balance of USDT", usdtBalance)
    // swap reverse
    Log(ex.swapToken('USDT', usdtBalance, 'ETH'))
    
    Log("balance of ETH", ex.getETHBalance())
    
    // Log(ex.sendETH('0x11111', 0.02))
}

ইথেরিয়াম নেটওয়ার্ক

ইথেরিয়াম নেটওয়ার্ককে একটি সফটওয়্যার অবকাঠামো হিসাবে বোঝা যায়, যেখানে বিভিন্ন স্মার্ট কন্ট্রাক্ট চালানোর জন্য বিভিন্ন ধরণের স্মার্ট কন্ট্রাক্ট স্থাপন করা যেতে পারে।

Uniswap V3 এর কিছু ধারণা

অজানাUniswap V3এই চুক্তির শিক্ষার্থীদের প্রথমে কয়েকটি ধারণার একটি সাধারণ ধারণা জানা দরকার।Uniswap V3ইথেরিয়ামে স্থাপন করা স্মার্ট কন্ট্রাক্টগুলিও।

১, রাউটিং (Route): রাউটিং হল একটি স্মার্ট কন্ট্রাক্ট যা ম্যানেজমেন্টের জন্য ব্যবহৃত হয়।tokenএই ছবির ছবির ছবির নামঃ ২, পুল (Pool): পুলটি একটি স্মার্ট কন্ট্রাক্ট যা দুটি ইথেরিয়ামের টোকেন সংরক্ষণ করে এবং এই দুটি টোকেনের মধ্যে বিনিময় করে। ৩, কারখানা চুক্তি (Factory): কারখানা চুক্তি হল একটি স্মার্ট চুক্তি যা পুল তৈরির জন্য ব্যবহৃত হয়। এবিআই (অ্যাপ্লিকেশন বাইনারি ইন্টারফেস) হল একটি স্পেসিফিকেশন যা স্মার্ট কন্ট্রাক্টগুলিকে বহির্বিশ্বের সাথে কীভাবে যোগাযোগ করতে হয় তা বর্ণনা করে। এটি স্মার্ট কন্ট্রাক্টগুলির ফাংশন নাম, প্যারামিটার টাইপ এবং রিটার্ন ভ্যালু টাইপ, এবং কীভাবে ডেটা কোডিং এবং ডিকোডিং করা যায় তা নির্দিষ্ট করে এবং স্মার্ট কন্ট্রাক্টগুলির বহিরাগত ইন্টারফেসগুলি নির্ধারণ করে। বোঝা যায় যে একটি ইন্টারফেস কল করার জন্য, ইন্টারফেসটি সম্মত মানদণ্ড অনুসারে কল করা আবশ্যক, যা একটি ABI-তে রেকর্ড করা হয় যা সম্মত মানদণ্ডের একটি সেট।

একবার স্মার্ট কন্ট্রাক্ট ইথেরিয়ামে স্থাপন করা হলে একটি ঠিকানা থাকবে।

Uniswap V3 ট্রেডিং ক্লাসের কোড বিশ্লেষণ

Uniswap V3 ট্রেডিং লাইব্রেরির কোড প্রধানত চারটি অংশে বিভক্ত।

পার্ট ১ঃ Uniswap V3 এর সাথে ইন্টারঅ্যাক্ট করার জন্য ব্যবহৃত ধ্রুবক

const ABI_Route = '[{"inputs":[{"internalType":"address...
const ABI_Pool = '[{\"inputs\":[],\"stateMutability\":\"nonpayable...
const ABI_Factory = '[{\"inputs\":[],\"stateMutability\":\"...

let ContractV3Factory = "0x1F98431c8aD98523631AE4a59f267346ea31F984"
let ContractV3SwapRouterV2 = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"

এখানে খুব সহজেই বোঝা যায়, উপরের মৌলিক ধারণাটি দিয়ে।

ABI_Routeএই ধ্রুবক সংরক্ষিত স্ট্রিংটি হল ABI, যা একটি স্মার্ট কন্ট্রাক্টের রাউটার।ABI_Poolএপিআই-র স্টোরেজ পুল চুক্তি।ABI_Factoryএ বি আই কারখানার চুক্তির কথাও উল্লেখ করেন।

যেহেতু এই স্ট্রিংগুলি দীর্ঘ, তাই কেবল সেটআপ করা হয়। এই বিষয়বস্তুগুলি প্রোগ্রামকে স্মার্ট কন্ট্রাক্ট পদ্ধতি কল করার জন্য একটি মানদণ্ড সরবরাহ করে ((যেমন এই স্মার্ট কন্ট্রাক্ট ইন্টারফেসের পরামিতিগুলি কী, কয়েকটি পরামিতি, কী ধরণের, কী ধরণের ডেটা ফিরে আসে ইত্যাদি)) ।

আমরা আগেই বলেছি যে, একবার স্মার্ট কন্ট্রাক্ট ইথেরিয়ামে স্থাপিত হলে একটি ঠিকানা থাকে।

ContractV3Factory: কারখানার চুক্তির ঠিকানা নথিভুক্ত করা হয়েছে ।ContractV3SwapRouterV2:Uniswap V3 এর রাউটার V2 ঠিকানা, মনে রাখবেন যে Uniswap এর V1, V2 আছে, Uniswap V3 এর রাউটার V1, V2 ভাগ আছে, বিভিন্ন চুক্তি ঠিকানা ভিন্ন হয়।

পার্ট ২ঃ টুল ফাংশন

1、computePoolPriceফাংশনটি পুলের টোকেনের দাম গণনা করতে ব্যবহৃত হয়।

function computePoolPrice(decimals0, decimals1, sqrtPriceX96) {
    [decimals0, decimals1, sqrtPriceX96] = [decimals0, decimals1, sqrtPriceX96].map(BigInt);   // 使用BigInt函数处理,因为JavaScript语言数值精度的原因,需要使用FMZ的一个底层处理函数BigInt来处理
    const TWO = BigInt(2);     // 定义常量2用于计算
    const TEN = BigInt(10);    // 定义常量10用于计算
    const SIX_TENTH = BigInt(1000000);    // 定义常量10的6次方,即1e6
    const Q192 = (TWO ** BigInt(96)) ** TWO;  // 2^192
    return (
        Number((sqrtPriceX96 ** TWO * TEN ** decimals0 * SIX_TENTH) / (Q192 * TEN ** decimals1)) /
        Number(SIX_TENTH)
    );
}

যদি এই লেনদেন সঠিক হয়ETH_USDTতাহলে,token0হ্যাঁETHtoken1হ্যাঁUSDTdecimals0এটি হলtoken0এই তথ্যের সঠিকতা,decimals1এটি হলtoken1এই তথ্যের সঠিকতা।sqrtPriceX96এটি মূল্য সম্পর্কিত ডেটা (এটি সরাসরি দামের সংখ্যা নয়) যা পুল চুক্তি থেকে সংগ্রহ করা যেতে পারে।slot0কিভাবে তা পাওয়া যায়।

sqrtPriceX96 : The current price of the pool as a sqrt ((token1/token0) Q64.96 value sqrt (টোকন/টোকন) এর বর্তমান মূল্য Q64.96 একটি ডেটা প্রসেসিং স্টোরেজ স্ট্যান্ডার্ড।

decimals0decimals1sqrtPriceX96এই তিনটি তথ্য প্যারামিটার হিসেবে প্রেরণ করা হয়computePoolPriceফাংশনটি একটি লেনদেনের জোড়া গণনা করে।ETH_USDTফাংশনটির শেষের অংশেreturnএই বাক্যের অ্যালগরিদম হলsqrtPriceX96রেডিয়েশনtoken1/token0উদাহরণস্বরূপ, যদি পুলের টোকন 0 (ETH) সংখ্যা 1 হয়, তবে টোকন 1 (USDT) সংখ্যা 1100 হবে।1100/1=1100বর্তমান লেনদেনETH_USDTপুকুরের দাম ১১০০।

2、toAmountফাংশনটি শৃঙ্খলে সংখ্যাগত তথ্যকে পাঠযোগ্য তথ্যে রূপান্তর করতে ব্যবহৃত হয়।

function toAmount(s, decimals) {
    return Number((BigDecimal(BigInt(s))/BigDecimal(Math.pow(10, decimals))).toString())
}

সহজভাবে বলতে গেলে, উদাহরণস্বরূপ, একটি ইটিএইচ টোকেন যখন চেইনে সংখ্যাটি প্রকাশ করে তখন এটি 1e18 হয়, অর্থাৎ 10 এর 18 তম, কারণ ইটিএইচ এর নির্ভুলতা 18 হয়; সমস্ত টোকেনের নির্ভুলতা 18 নয়, ইউএসডিটি এর নির্ভুলতা ইটিএইচ এর মতো নয়।toAmountফাংশন হল 1e18 কে 1তে রূপান্তর করা।

3、toInnerAmountফাংশনটি হলtoAmountপরিবর্তে, এটি পাঠযোগ্য ডেটাকে চেইনে ব্যবহৃত মানগুলিতে রূপান্তরিত করে।

function toInnerAmount(n, decimals) {
    return (BigDecimal(n)*BigDecimal(Math.pow(10,decimals))).toFixed(0)
}

এখন আসুন আমরা একসাথে "Uniswap V3 Transaction Library" এর কোড বিশ্লেষণ করি।

Part3: Uniswap V3 অপারেটরগুলির জন্য নির্মাণ ফাংশন

এই টেমপ্লেট শ্রেণিবিলার কেন্দ্রবিন্দু হচ্ছে Uniswap V3 অপারেটিং অবজেক্ট, যা Uniswap V3 এর উপর মৌলিক অপারেশন বাস্তবায়ন করে। পরবর্তী সংস্করণে আরও অনেকগুলি বৈশিষ্ট্য আপগ্রেড করা হতে পারে। এই কোড উদাহরণটি বিশ্লেষণ করে, এমনকি FMZ প্ল্যাটফর্ম ব্যবহার না করেও, এটির মান বাড়ানো সম্ভব।UniswapএইটাDEXএফএমজেড-এর বিভিন্ন লিংক প্রক্রিয়া, বিবরণ এবং বোঝার জন্য, আমরা এখন শিখব কিভাবে এই মৌলিক বৈশিষ্ট্যগুলি এফএমজেডে ডিজাইন করা হয়েছে।

Uniswap V3 অপারেটরগুলির জন্য কনস্ট্রাক্টর ফাংশন কোডঃ

$.NewUniswapV3 = function(e) {
    e = e || exchange                          // 如果没有传参数e,就使用交易所对象exchange,即策略上第一个添加的交易所
    if (e.GetName() !== 'Web3') {              // 判断交易所对象是否是Web3,因为这个模板只支持Web3交易所对象
        panic("only support Web3 exchange")
    }


    let self = {                               // 当前函数是一个构造函数,构造的对象就是self这个对象
        tokenInfo: {},                         // self对象的成员变量,用于记录token的注册信息
        walletAddress: e.IO("address"),        // 记录当前交易所对象绑定的钱包地址
        pool: {}                               // 用于记录注册的池信息
    }

    // register
    e.IO("abi", ContractV3Factory, ABI_Factory)       // 注册工厂合约的ABI
    e.IO("abi", ContractV3SwapRouterV2, ABI_Route)    // 注册路由合约的ABI

    self.addToken = function(name, address) {         // 用于注册token
        let ret = e.IO("api", address, "decimals")    // 调用decimals方法,获取token精度信息
        if (!ret) {
            throw "get token decimals failed"
        }
        let decimals = Number(ret)
        self.tokenInfo[name] = {
            name: name,
            decimals: decimals,
            address: address
        }
    }
    self.waitMined = function(tx) {             // 用于等待以太坊上某个操作的结果,哈希为tx参数
        while (true) {
            Sleep(1000)
            let info = e.IO("api", "eth", "eth_getTransactionReceipt", tx)  // 查询结果使用eth_getTransactionReceipt方法,没有查询到,循环继续查询
            if (info && info.gasUsed) {
                return true
            }
            Log('Transaction not yet mined', tx)
        }
    }

    self.swapToken = function(tokenIn, amountInDecimal, tokenOut, options) {   // 用于token兑换
        // options like {gasPrice: 11, gasLimit: 111, nonce: 111}
        let tokenInInfo = self.tokenInfo[tokenIn]      // 拿到兑换出去的token的信息
        let tokenOutInfo = self.tokenInfo[tokenOut]    // 拿到兑换回来的token的信息
        if (!tokenInInfo) {
            throw "not found token info " + tokenIn
        }

        if (!tokenOutInfo) {
            throw "not found token info " + tokenOut
        }
        
        let amountIn = toInnerAmount(amountInDecimal, tokenInInfo.decimals)  // 转换为智能合约上使用的数据
        let recipientAddress = self.walletAddress
        if (tokenInInfo.name != 'ETH') {
            let allowanceAmount = e.IO("api", tokenInInfo.address, "allowance", self.walletAddress, ContractV3SwapRouterV2);   // 查询授权的数量
            let realAmount = toAmount(allowanceAmount, tokenInInfo.decimals)
            if (realAmount < toAmount(amountIn, tokenInInfo.decimals)) {    // 如果授权数量不足
                Log("realAmount is", realAmount, "too small, try to approve large amount")
                if (tokenInInfo.name == 'USDT') {
                    // As described in Tether code: To change the approve amount you first have to reduce the addresses allowance to 0 calling approve(spender, 0)
                    let txApprove = e.IO("api", tokenInInfo.address, "approve", ContractV3SwapRouterV2, 0)  // 如果授权的token是USDT,需要先授权为0
                    if (!txApprove) {
                        throw "approve error"
                    }
                    Log("wait reduce approve", txApprove)
                    self.waitMined(txApprove)
                }

                let txApprove = e.IO("api", tokenInInfo.address, "approve", ContractV3SwapRouterV2, '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');  // 授权Router合约操作钱包的代币
                if (!txApprove) {
                    throw "approve error"
                }
                Log("wait approve", txApprove)
                self.waitMined(txApprove)
                Log("approve success amountIn", amountIn)
            } else {
                Log("allowance", realAmount, "no need to approve")
            }
        }

        if (tokenOutInfo.name == 'ETH' || tokenOutInfo.address.toLowerCase() == '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2') {
            /*
            ADDRESS_THIS https://degencode.substack.com/p/uniswapv3-multicall
            https://etherscan.io/address/0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45#code
            */
            recipientAddress = '0x0000000000000000000000000000000000000002'
            // 其它币换成 WETH的时候,要让合约HOLD住WETH才可以赎回
        }

        let swapToken = e.IO("encode", ContractV3SwapRouterV2, "swapExactTokensForTokens", amountIn, 1, [tokenInInfo.address, tokenOutInfo.address], recipientAddress)   // 打包swapExactTokensForTokens调用
        let data = [swapToken]
        if (tokenOutInfo.name == 'ETH') {    // 如果兑换时,兑换回来的token是ETH,这里实际是WETH,则需要解包
            data.push(e.IO("encode", ContractV3SwapRouterV2, "unwrapWETH9(uint256,address)", 1, self.walletAddress))   // 所以这里再打包一个unwrapWETH9解包调用
        }
        let tx = e.IO("api", ContractV3SwapRouterV2, "multicall(uint256,bytes[])", (tokenInInfo.name == 'ETH' ? amountIn : 0), (new Date().getTime() / 1000) + 3600, data, options || {})   // 使用multicall执行这些打包的操作(swapExactTokensForTokens、unwrapWETH9)
        if (tx) {
            Log("tx: ", tx)
            self.waitMined(tx)
            Log("swap", tokenInInfo.name, "to", tokenOutInfo.name, "success")
            return true
        } else {
            Log("trans error")
            return false
        }
    }

    self.getETHBalance = function(address) {   // 查询钱包的ETH余额
        return toAmount(e.IO("api", "eth", "eth_getBalance", address || self.walletAddress, "latest"), 18)
    }

    self.balanceOf = function(token, address) {  // 查询钱包的某个token余额(根据参数确定)
        let tokenInfo = self.tokenInfo[token]
        if (!tokenInfo) {
            throw "not found token info " + token

সম্পর্কিত

আরো

15559953001স্বপ্ন, পাইথন সংস্করণ আছে?

উজ্জ্বল রোফারশেখার ক্ষেত্রে, মার্ক

ছোট্ট স্বপ্নআপনি যদি আপনার ফোনটি ব্যবহার করেন তবে আপনি এটিকে আবার ব্যবহার করতে পারবেন।