Type/to search
8
Follow
1364
Followers
মার্জিত এবং সহজ! 200 লাইন কোড সহ FMZ-এ Uniswap V3 এর সাথে সংযুক্ত
Discussions
Created 2023-01-30 15:38:02  Updated 2023-09-18 19:39:40
 5
 3104

img

মার্জিত এবং সহজ! 200 লাইন কোড সহ FMZ-এ Uniswap V3 এর সাথে সংযুক্ত

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

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

FMZ-এ Uniswap V3 সংহত করার প্রক্রিয়াটি সহজ এবং বোঝা সহজ, সম্পূর্ণ করার জন্য মাত্র 200 লাইনের কোড প্রয়োজন। এর মানে হল যে আপনি কোডে নতুন হলেও, আপনি সহজেই FMZ-এ Uniswap V3 সংযোগ করতে পারেন এবং অবিলম্বে ট্রেডিং শুরু করতে পারেন।

এফএমজেড মৌলিক ওয়েব3 ফাংশনগুলির একটি সিরিজকে এনক্যাপসুলেট করেছে, ইউনিসঅ্যাপ ছাড়াও, এটি খুব কম কোড সহ অন্যান্য DEX এক্সচেঞ্জগুলিকে এনক্যাপসুলেট করতে পারে৷ এর পরে, আমি আপনাকে স্ক্র্যাচ থেকে ডিফি অ্যাপ্লিকেশনের ধারণা এবং প্রযুক্তি শেখা শুরু করি, স্থানের কারণে নিম্নলিখিত বর্ণনাটি যতটা সহজ এবং বোঝা সম্ভব ততটা কঠিন নাও হতে পারে .

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)) }

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

ইথেরিয়াম নেটওয়ার্ককে একটি সফ্টওয়্যার অবকাঠামো হিসাবে বোঝা যেতে পারে, যার উপর বিভিন্ন স্মার্ট চুক্তি স্থাপন করা যেতে পারে এবং চালানো যেতে পারে স্মার্ট চুক্তির বিভিন্ন ফাংশন এবং অ্যাপ্লিকেশন পরিস্থিতি। Ethereum ক্লায়েন্ট চালিত ডিভাইসগুলি Ethereum নেটওয়ার্কে নোড গঠন করে।

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

সাথে পরিচিত নয়Uniswap V3যারা চুক্তির সাথে পরিচিত তাদের জন্য আপনাকে এখানে কয়েকটি ধারণা সংক্ষেপে বুঝতে হবে।Uniswap V3এটি একটি স্মার্ট চুক্তিও স্থাপন করা হয়েছে এবং Ethereum এ চালিত হয়।

  1. রুট: রুট হল ব্যবস্থাপনার জন্য একটি স্মার্ট চুক্তিtokenবিনিময়
  2. পুল: পুলটি একটি স্মার্ট চুক্তি যা দুটি ইথেরিয়াম টোকেন সংরক্ষণ করতে এবং দুটি টোকেনের মধ্যে বিনিময় করতে ব্যবহৃত হয়।
    ৩. কারখানার চুক্তি: কারখানার চুক্তি হল একটি স্মার্ট চুক্তি যা একটি পুল তৈরি করতে ব্যবহৃত হয়।
  3. ABI: (অ্যাপ্লিকেশন বাইনারি ইন্টারফেস) একটি স্পেসিফিকেশন যা বর্ণনা করে যে কীভাবে স্মার্ট চুক্তিগুলি বাইরের বিশ্বের সাথে যোগাযোগ করে। এটি স্মার্ট কন্ট্রাক্টের ফাংশনের নাম, প্যারামিটারের ধরন এবং রিটার্ন ভ্যালু টাইপ, সেইসাথে কীভাবে ডেটা এনকোড এবং ডিকোড করতে হয় তা নির্দিষ্ট করে এবং স্মার্ট চুক্তির বাহ্যিক ইন্টারফেস নির্ধারণ করে। এটি বোঝা যায় যে একটি ইন্টারফেস কল করার জন্য, এটিকে অবশ্যই ইন্টারফেসে সম্মত মান অনুযায়ী কল করতে হবে এবং ABI তে যা রেকর্ড করা হয়েছে তা হল সম্মত মানগুলির একটি সিরিজ।

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

Uniswap V3 লেনদেন লাইব্রেরির কোড বিশ্লেষণ করা হচ্ছে

Uniswap V3 ট্রেডিং লাইব্রেরি কোডটি মূলত ৪টি ভাগে বিভক্ত। আসুন একে একে সেগুলো ব্যাখ্যা করি।

অংশ 1: ​​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.
ABI_Factoryকারখানার চুক্তির এবিআই.

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

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

ContractV3Factory: কারখানার চুক্তির ঠিকানা রেকর্ড করুন।
ContractV3SwapRouterV2: Uniswap V3 এর রাউটার V2 ঠিকানাটি মনে রাখবেন যে Uniswap V3 এর রাউটারে V1 এবং V2 রয়েছে।

পার্ট 2: টুল ফাংশন

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
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()) }

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

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

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

এর পরে, আসুন "Uniswap V3 ট্রানজ্যাকশন লাইব্রেরি" এর কোড বিশ্লেষণ করি।

Part3: Uniswap V3 অপারেশন অবজেক্টের কনস্ট্রাক্টর

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

Uniswap V3 অপারেশন অবজেক্টের কনস্ট্রাক্টর কোড:

javascript
$.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 } return toAmount(e.IO("api", tokenInfo.address, "balanceOf", address || self.walletAddress), tokenInfo.decimals) } self.sendETH = function(to, amount, options) { // 向某个地址发送ETH代币,即转账 return e.IO("api", "eth", "send", to, toInnerAmount(amount, 18), options || {}) } self.getPrice = function(pair, fee) { // 获取交易对价格 let arr = pair.split('_') let token0 = self.tokenInfo[arr[0]] if (!token0) { throw "token " + arr[0] + "not found" } let token1 = self.tokenInfo[arr[1]] // 首先拿到构成交易对的两个token信息 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, typeof(fee) === 'number' ? fee : 3000) // 调用工厂合约的getPool方法,获取兑换池的地址 if (pool) { self.pool[key] = pool // 注册池地址,并注册池合约的ABI // 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") // 调用池合约的slot0方法,拿到价格相关信息 if (!slot0) { return null } let price = computePoolPrice(token0.decimals, token1.decimals, slot0.sqrtPriceX96) // 计算出可读的价格 if (reverse) { price = 1 / price } return price } return self }

FMZ এর সাথে পরিচিত নাও হতে পারে এমন ছাত্ররা এই ফাংশনটি দেখতে পারে$.NewUniswapV3নামকরণ একটু অদ্ভুত, সঙ্গে$.শুরুতে ফাংশনটি নির্দেশ করে যে এই ফাংশনটি FMZ-এ টেমপ্লেট ক্লাস লাইব্রেরির একটি ইন্টারফেস ফাংশন (টেমপ্লেট ক্লাস লাইব্রেরি কী?চেক করুন), সহজভাবে বললে$.NewUniswapV3ফাংশন অন্যান্য দ্বারা উল্লেখ করা যেতে পারেটেমপ্লেট ক্লাস লাইব্রেরিকৌশলটি সরাসরি বলা হয়। কৌশলটি সরাসরি মালিকানাধীনUniswap V3ফাংশন

এই$.NewUniswapV3ফাংশনটি সরাসরি একটি বস্তু তৈরি করে এবং তৈরি করে এবং আপনি এই বস্তুটি ব্যবহার করে কিছু অপারেশন করতে পারেন:

  • টোকেন রিডেম্পশন: বস্তুর দ্বারাswapTokenপদ্ধতি বাস্তবায়ন।
  • ETH ব্যালেন্স কোয়েরি: অবজেক্ট দ্বারাgetETHBalanceপদ্ধতি বাস্তবায়ন।
  • টোকেন ব্যালেন্স কোয়েরি: অবজেক্ট দ্বারাbalanceOfপদ্ধতি বাস্তবায়ন।
  • ট্রেডিং জোড়া মূল্য প্রশ্ন: বস্তুর দ্বারাgetPriceপদ্ধতি বাস্তবায়ন।
  • স্থানান্তরের জন্য ETH পাঠান: বস্তুর দ্বারাsendETHপদ্ধতি বাস্তবায়ন।

এই ক্লাস লাইব্রেরি ভবিষ্যতে এই ফাংশনগুলির মধ্যে সীমাবদ্ধ নাও থাকতে পারে, এবং এমনকি "তরলতা যোগ করার" মত ফাংশন যোগ করতে আপগ্রেড করা হতে পারে। কোড ব্যবচ্ছেদ চালিয়ে যাওয়া যাক:

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)

নির্মাতা$.NewUniswapV3শুধুমাত্র একটি প্যারামিটারe, এটি ই বিনিময় বস্তুর প্রতিনিধিত্ব করে (এফএমজেডে এক্সচেঞ্জ কনফিগারেশন)। কারণ FMZ-এর নীতি একাধিক এক্সচেঞ্জের সাথে ডিজাইন করা যেতে পারে, যদি এখানে একটি নির্দিষ্ট এক্সচেঞ্জ পাস করা হয়, এর মানে হল এটি তৈরি করা হয়েছে।Uniswap V3এক্সচেঞ্জ অবজেক্ট পরিচালনা করতে অবজেক্টটি ব্যবহৃত হয়। যদি কোন প্যারামিটার পাস না করা হয়e, ডিফল্ট অপারেশন প্রথম যোগ করা বিনিময় বস্তু।

নোড পরিষেবা ঠিকানা এবং ব্যক্তিগত কী কনফিগার করুন (ব্যক্তিগত কী স্থানীয়ভাবে স্থাপন করা যেতে পারে, এবং শুধুমাত্র কনফিগারেশন পথ স্থানীয় স্থাপনার জন্য ব্যবহার করা হয়), এবং একটি বিনিময় বস্তু তৈরি করা হয়। এটি বাস্তব ট্রেডিং এর সময় কৌশলে যোগ করা যেতে পারে এই বস্তুটি কৌশল কোডে প্রতিফলিত হয়।exchangeবলতে হয়exchanges[0], আপনি যদি দ্বিতীয়টি যোগ করেন তবে এটি হবেexchanges[1], তৃতীয়টি হিসাবে যোগ করুনexchanges[2],...

img

স্ক্রিনশটে আমি যে নোড ঠিকানাটি কনফিগার করেছি: https://mainnet.infura.io/v3/xxx এটি প্রতিটি অ্যাকাউন্টের নিজস্ব নির্দিষ্ট ঠিকানা রয়েছে প্রতিটি অ্যাকাউন্টের xxx বিভাগ আলাদা।

কোডটি অনুসরণ করে, কনস্ট্রাক্টর এক্সচেঞ্জ অবজেক্টটি Web3 কিনা তা নির্ধারণ করতে শুরু করে এবং যদি এটি Web3 না হয় তবে একটি ত্রুটি রিপোর্ট করে। তারপর একটি ভেরিয়েবল তৈরি করলেনself, এই স্ব হল অবজেক্ট যা কনস্ট্রাক্টর দ্বারা প্রত্যাবর্তিত হয় পরবর্তী কনস্ট্রাক্টররা এই অবজেক্টে বিভিন্ন ফাংশন যোগ করে এবং নির্দিষ্ট ফাংশন প্রয়োগ করে। সেলফ ভ্যারিয়েবলের 3টি বৈশিষ্ট্য রয়েছে:

  • tokenInfo: এই বস্তুতে নিবন্ধিত টোকেন তথ্য রেকর্ড করে টোকেন ঠিকানা, টোকেন সঠিকতা এবং টোকেন নাম।
  • walletAddress: বর্তমান বিনিময় বস্তুর ওয়ালেট ঠিকানা।
  • পুল: এই বস্তুতে নিবন্ধিত এক্সচেঞ্জ পুলের তথ্য, প্রধানত এক্সচেঞ্জ পুলের নাম এবং বিনিময় পুলের ঠিকানা।

তারপরে আমরা পূর্ববর্তী নিবন্ধে যে ধারণাগুলি শিখেছি তা ব্যবহার করেছি:

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

কেন আমাদের এই ইন্টারফেস তথ্য নিবন্ধন করতে হবে?

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

স্ব অবজেক্টের ইউটিলিটি ফাংশন

1、self.addToken = function(name, address)

এই ফাংশনের নির্দিষ্ট কোডটি পর্যবেক্ষণ করলে আমরা দেখতে পাব যে এই ফাংশনটি বর্তমান অবজেক্টকে দেওয়াselfমাঝারি রেকর্ডtokenতথ্য সদস্যtokenInfoএকটি টোকেন (টোকেন) তথ্য যোগ করুন (অন্য কথায়: নিবন্ধন করুন)। কারণtoken(টোকেন) এর নির্ভুলতা ডেটা প্রায়ই পরবর্তী গণনায় ব্যবহৃত হয়, তাই যখন এই ফাংশনটি টোকেন তথ্য যোগ করে (নিবন্ধন করে) তখন একে বলা হয়let ret = e.IO("api", address, "decimals")FMZ দ্বারা encapsulated exchange.IO ফাংশনের মাধ্যমে ফাংশন (আমরা আগে উল্লেখ করেছি যে e হল ইনকামিং এক্সচেঞ্জ অবজেক্ট), টোকেন চুক্তিকে কল করে"decimals"টোকেনের নির্ভুলতা পাওয়ার পদ্ধতি।

তাইself.tokenInfoএটি একটি অভিধান গঠন, প্রতিটি মূল নাম হল টোকেন নাম, এবং মূল মান হল এই টোকেনের তথ্য, যার মধ্যে রয়েছে: ঠিকানা, নাম এবং নির্ভুলতা। এটি সম্ভবত এই মত দেখায়:

{ "ETH": {name: "ETH", decimals: 18, address: "0x..."}, "USDT": {name: "USDT", decimals: 6, address: "0x..."}, ... }

2、self.waitMined = function(tx)

এই ফাংশনটি Ethereum-এ স্মার্ট কন্ট্রাক্টের কার্যকরী ফলাফলের জন্য অপেক্ষা করতে ব্যবহৃত হয়let info = e.IO("api", "eth", "eth_getTransactionReceipt", tx), Ethereum এর RPC পদ্ধতিতে কল করেeth_getTransactionReceipt, জিজ্ঞাসা করতেলেনদেন হ্যাশ লেনদেনের রসিদ ফেরত দেয়,পরামিটারtxঅর্থাৎলেনদেন হ্যাশ

eth_getTransactionReceiptঅন্যান্য সম্পর্কিত তথ্য দেখা যেতে পারে: https://ethereum.org/zh/developers/docs/apis/json-rpc/#eth_gettransactionreceipt

কিছু ছাত্র জিজ্ঞাসা করতে পারে: কেন এই ফাংশন ব্যবহার?

উত্তর: কিছু ক্রিয়াকলাপ সম্পাদন করার সময়, যেমন টোকেন বিনিময়, আপনাকে ফলাফলের জন্য অপেক্ষা করতে হবে।

এর পরের দিকে তাকান$.NewUniswapV3ফাংশন দ্বারা স্বয়ং তৈরি বস্তুর অন্যান্য প্রধান ফাংশনগুলির সহজতম বাস্তবায়নের সাথে শুরু করা যাক।

প্রধান ফাংশন

1、self.getETHBalance = function(address)

টোকেন ব্যালেন্স জিজ্ঞাসা করার মধ্যে একটি পার্থক্য রয়েছে, যা ETH (Ethereum) এর ভারসাম্য অনুসন্ধান এবং অন্যান্য ERC20 টোকেনের ভারসাম্য অনুসন্ধানের মধ্যে বিভক্ত। স্ব-অবজেক্টের getETHBalance ফাংশনটি ETH ব্যালেন্স জিজ্ঞাসা করতে ব্যবহৃত হয় যখন নির্দিষ্ট ওয়ালেট ঠিকানা প্যারামিটার ঠিকানাটি পাস করা হয়, তখন এই ঠিকানার ETH ব্যালেন্স জিজ্ঞাসা করা হয়। ঠিকানা প্যারামিটার পাস না হলে, প্রশ্নself.walletAddressঠিকানার ETH ব্যালেন্স (অর্থাৎ বর্তমান এক্সচেঞ্জে কনফিগার করা ওয়ালেট)।

এগুলি Ethereum এর RPC পদ্ধতিতে কল করে করা হয়eth_getBalanceসম্পন্ন করা

2、self.balanceOf = function(token, address)

ETH ব্যতীত অন্য টোকেনের ব্যালেন্স জানতে, আপনাকে প্যারামিটার টোকেন পাস করতে হবে, যা টোকেনের নাম, যেমন USDT। জিজ্ঞাসা করার জন্য ওয়ালেট ঠিকানাটি পাস করুন, যদি কোনো ঠিকানা পাস না হয়, প্রশ্ন করুনself.walletAddressঠিকানার ব্যালেন্স। এই ফাংশন দ্বারা বাস্তবায়িত কোড পর্যবেক্ষণ করে, আমরা দেখতে পাচ্ছি যে এটি আগে থেকেই পাস করা দরকারself.addTokenশুধুমাত্র ফাংশন দ্বারা নিবন্ধিত টোকেন জিজ্ঞাসা করা যেতে পারে, কারণ চুক্তি যে টোকেন কল করেbalanceOfএই পদ্ধতি ব্যবহার করার সময়, টোকেনের (টোকেন) সঠিক তথ্য এবং ঠিকানা ব্যবহার করতে হবে।

3、self.sendETH = function(to, amount, options)

এই ফাংশনের কাজ হল একটি নির্দিষ্ট ওয়ালেট ঠিকানায় ETH স্থানান্তর করা (ব্যবহার করেtoপ্যারামিটার সেটিংস) একটি নির্দিষ্ট পরিমাণ ETH স্থানান্তর করতে (ব্যবহার করেamountপ্যারামিটার সেটিং), আপনি অন্য সেট করতে পারেনoptionsপরামিতি (ডেটা গঠন:{gasPrice: 111, gasLimit: 111, nonce: 111}) নির্দিষ্ট করতে ব্যবহৃত হয়gasLimit/gasPrice/nonce, বিকল্প প্যারামিটার পাস না হলে সিস্টেম ডিফল্ট সেটিংস ব্যবহার করা হবে।

gasLimit/gasPriceEthereum-এ ক্রিয়াকলাপ সম্পাদন করার সময় ETH-কে প্রভাবিত করে (Ethereum-এর কিছু অপারেশন গ্যাস গ্রহণ করে, অর্থাৎ, নির্দিষ্ট পরিমাণ ETH টোকেন খাওয়া হয়)।

4、self.getPrice = function(pair, fee)

এই ফাংশনটি Uniswap-এ একটি নির্দিষ্ট ট্রেডিং পেয়ারের মূল্য প্রাপ্ত করার জন্য ব্যবহার করা হয় যেমন আপনি ফাংশন বাস্তবায়ন কোড থেকে দেখতে পাচ্ছেন, যখন ফাংশনটি কার্যকর করা শুরু হবে, ট্রেডিং পেয়ারটিকে প্রথমে পার্স করা হবে বেস কারেন্সি এবং কোট কারেন্সি। উদাহরণস্বরূপ, যদি ট্রেডিং পেয়ারটি ETH_USDT হয়, তাহলে এটি ETH এবং USDT-এ বিভক্ত হবে। তারপর জিজ্ঞাসাself.tokenInfoএই দুটি টোকেন (টোকেন) সম্পর্কে তথ্য আছে কিনা, যদি না থাকে তবে একটি ত্রুটি রিপোর্ট করা হবে।

Uniswap-এ এক্সচেঞ্জ পুল ঠিকানা দুটি অংশগ্রহণকারী টোকেন (টোকেন) ঠিকানা এবং ফি (রেট স্ট্যান্ডার্ড) গণনার সমন্বয়ে গঠিত, তাই জিজ্ঞাসা করার সময়self.pool(আমরা এটি আগে self.pool এ উল্লেখ করেছি, আপনি এটি নীচে দেখতে পারেন) যদি পুলের ঠিকানাটি অনুসন্ধানে না পাওয়া যায়, তাহলে পুলের ঠিকানা গণনা করতে দুটি টোকেনের ঠিকানা এবং ফি ব্যবহার করুন। তাই একটি ট্রেডিং পেয়ারের জন্য একাধিক পুল থাকতে পারে কারণ ফি ভিন্ন হতে পারে।

ইউনিসওয়াপ V3 এর ফ্যাক্টরি চুক্তিতে কল করে এক্সচেঞ্জ পুলের ঠিকানা জিজ্ঞাসা করুন এবং গণনা করুনgetPoolপ্রাপ্তির পদ্ধতি (সুতরাং শুরুতে কারখানার চুক্তির ABI নিবন্ধন করুন)।
এই ট্রেডিং পেয়ারের পুলের ঠিকানা পাওয়ার পর, আপনি পুল চুক্তির ABI নিবন্ধন করতে পারেন। শুধুমাত্র এই ভাবে এই পুল (স্মার্ট চুক্তি) বলা যেতে পারেslot0মূল্য তথ্য পাওয়ার পদ্ধতি। অবশ্যই, এই পদ্ধতির দ্বারা প্রত্যাবর্তিত ডেটা মানব-পঠনযোগ্য মূল্য নয়, কিন্তু একটি মূল্য-সম্পর্কিত ডেটা কাঠামো, যা এই সময়ে, আমরা পূর্ববর্তী নিবন্ধে উল্লেখিত পদ্ধতিটি ব্যবহার করা হয়েছে৷computePoolPriceফাংশন

5、self.swapToken = function(tokenIn, amountInDecimal, tokenOut, options)

এই ফাংশনটি হল টোকেন রিডিম করার সময় প্যারামিটার টোকেনের নাম যা রিডিম করার সময় প্রাপ্ত টোকেনের নাম ইনডেসিমাল। পরামিতি বিকল্পগুলি যেমন আমরা আগে উল্লেখ করেছি একই রকম, আপনি বিনিময়ের সময় গ্যাসের ব্যবহার, ননস ইত্যাদি সেট করতে পারেন৷

যখন ফাংশনটি কার্যকর করা হয়, এটি প্রথমে পাস করা হয়self.tokenInfoভেরিয়েবলে টোকেন (টোকেন) তথ্য পান, এবং এক্সচেঞ্জেরও অনেকগুলি বিবরণ রয়েছে প্রথমত, বিনিময়ে অংশগ্রহণকারী টোকেনগুলির মধ্যে যদি অর্থপ্রদানের টোকেনটি ETH না হয় তবে আপনাকে প্রথমে এটি দিতে হবে।রাউটিং(মোচনের জন্য দায়ী স্মার্ট চুক্তি) অনুমোদন। অনুমোদন করার আগে, পর্যাপ্ত অনুমোদন কোটা আছে কিনা তা পরীক্ষা করুন।

let allowanceAmount = e.IO("api", tokenInInfo.address, "allowance", self.walletAddress, ContractV3SwapRouterV2);

অনুমোদিত পরিমাণ জিজ্ঞাসা করতে টোকেন চুক্তি ভাতা পদ্ধতি ব্যবহার করুন। বর্তমান রিডেম্পশনের পরিমাণের সাথে অনুমোদিত পরিমাণের তুলনা করে, যদি অনুমোদিত পরিমাণ রিডেম্পশনের জন্য যথেষ্ট হয়, তাহলে আর কোন অনুমোদনের প্রয়োজন নেই। যদি পরিমাণ অপর্যাপ্ত হয়, অনুমোদন প্রক্রিয়াকরণ সঞ্চালিত হবে.

এখানে অনুমোদনের একটি বিশদও রয়েছে যদি অনুমোদিত টোকেনটি USDT হয়, তাহলে অনুমোদনের আগে আপনাকে অনুমোদনের পরিমাণ 0 এ রিসেট করতে হবে। টোকেন চুক্তির অনুমোদন পদ্ধতির ব্যবহার অনুমোদন করুন। নোট করুন যে অনুমোদনের অনুমোদন পদ্ধতিটি একটি গ্যাস-ব্যবহারকারী পদ্ধতি এবং এটি একটি নির্দিষ্ট পরিমাণ ETH ব্যবহার করবে। সুতরাং প্রক্রিয়াকরণের ফলাফলের জন্য অপেক্ষা করার জন্য আপনাকে self.waitMined ফাংশনটি ব্যবহার করতে হবে।

ঘন ঘন অনুমোদন এবং ETH-এর অপ্রয়োজনীয় অর্থপ্রদান এড়াতে, এই অনুমোদন অপারেশনের সর্বোচ্চ এককালীন অনুমোদনের মান রয়েছে।

let txApprove = e.IO("api", tokenInInfo.address, "approve", ContractV3SwapRouterV2, '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');

আপনার যদি পর্যাপ্ত পরিমাণ রিডেম্পশন থাকে, তাহলে আপনি তা রিডিম করতে পারেন। তবে এখানেও বিশদ আছে যদি বিনিময়ে অংশগ্রহণকারী টোকেনগুলির মধ্যে, বিনিময়ের পরে প্রাপ্ত টোকেনটি ইটিএইচ হয়, তবে প্রাপ্তির ঠিকানাটি পরিবর্তন করতে হবে:

recipientAddress = '0x0000000000000000000000000000000000000002'

নির্দিষ্ট কারণগুলি তুলনামূলকভাবে জটিল এবং আপনি এখানে উল্লেখ করতে পারেন:

ADDRESS_THIS https://degencode.substack.com/p/uniswapv3-multicall
https://etherscan.io/address/0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45#code

তারপর FMZ প্ল্যাটফর্ম দ্বারা এনক্যাপসুলেটেড প্যাকেজিং ফাংশন ব্যবহার করুনe.IO("encode", ..., রাউটারের জন্য swapExactTokensForTokens পদ্ধতি কল প্যাকেজ করুন (স্মার্ট চুক্তি)। যদি বিনিময়ের পরে প্রাপ্ত টোকেনটি ETH হয়, তাহলে আপনাকে WETH9 আনপ্যাকিং অপারেশনের একটি ধাপ যোগ করতে হবে:

data.push(e.IO("encode", ContractV3SwapRouterV2, "unwrapWETH9(uint256,address)", 1, self.walletAddress))

যেহেতু WETH বিনিময়ে অংশগ্রহণ করছে, এটি ETH-এর একটি প্যাকেজ টোকেন। আসল ইটিএইচ-এ পরিবর্তন করার জন্য একটি আনপ্যাকিং অপারেশন প্রয়োজন হয় প্যাকেজ করার পরে, আপনি এই সিরিজের অপারেশনগুলি সম্পাদন করার জন্য রাউটিং (স্মার্ট চুক্তি) এর মাল্টিকল পদ্ধতিতে কল করতে পারেন৷ এখানে আরও একটি বিশদ রয়েছে যা এক্সচেঞ্জে অংশগ্রহণকারী ট্রেডিং পেয়ার এবং পেমেন্ট টোকেনটি যদি ইটিএইচ হয়, তাহলে আপনাকে নিচের ধাপে ট্রান্সফার করা ETH-এর পরিমাণ সেট করতে হবে।

let tx = e.IO("api", ContractV3SwapRouterV2, "multicall(uint256,bytes[])", (tokenInInfo.name == 'ETH' ? amountIn : 0), (new Date().getTime() / 1000) + 3600, data, options || {})

এই সেটিংটি এখানে প্রতিফলিত হয়েছে:(tokenInInfo.name == 'ETH' ? amountIn : 0). সম্পাদক আগে এটি বের করেননি এবং 0 সেট করেননি যখন টোকেনইন ETH টোকেনের সমান ছিল না, যার ফলে ETH-এর ভুল স্থানান্তর হয়েছে। তাই ট্রান্সফার কোড লেখার সময় অতিরিক্ত সতর্ক থাকুন।

Part4: কিভাবে Uniswap V3 অপারেশন অবজেক্ট ব্যবহার করবেন

এই টেমপ্লেটের কোডটিতে আসলে ২০০ লাইনেরও কম কার্যকারিতা রয়েছে। পরবর্তী অংশটি আসলে একটি ব্যবহার প্রদর্শন।

$.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)) }

$.testUniswap = function()এই ফাংশন শুধুমাত্র একটি প্রদর্শন, ব্যবহারিক ব্যবহার ছাড়া এটি কল করবেন না দয়া করে. Uniswap V3 এর ফাংশনগুলি পরিচালনা করতে এই টেমপ্লেট ক্লাস লাইব্রেরিটি কীভাবে ব্যবহার করা যায় তা দেখতে আমরা এই ফাংশনটি ব্যবহার করি।

কোডটি প্রথমে কার্যকর করা হয়let ex = $.NewUniswapV3()একটি Uniswap V3 অপারেশন অবজেক্ট তৈরি করা হয়েছে যদি আপনি বর্তমান এক্সচেঞ্জে আবদ্ধ ওয়ালেট ঠিকানা পেতে চান, আপনি ব্যবহার করতে পারেনex.walletAddressপান। তারপর কোডে ব্যবহার করুনex.addTokenতিন ধরনের টোকেন নিবন্ধিত হয়েছে, যথা ETH, USDT, এবং 1INCH৷

একটি নির্দিষ্ট ট্রেডিং পেয়ারের মূল্য প্রিন্ট করুন (টোকেন প্রথমে নিবন্ধিত করা প্রয়োজন):

Log(ex.getPrice('ETH_USDT')) Log(ex.getPrice('1INCH_USDT'))

যদি getPrice ফাংশন ফি সেট না করে, তবে এটি 3000 এর ডিফল্ট হার ব্যবহার করে, যা 0.3% এর একটি পাঠযোগ্য মানের মধ্যে রূপান্তরিত হয়।

আপনি যদি 0.01 ETH-কে USDT-তে বিনিময় করতে চান, তাহলে ব্যালেন্স চেক করুন এবং তারপরে আবার বিনিময় করুন, কোড ব্যবহার করুন:

Log(ex.swapToken('ETH', 0.01, 'USDT')) let usdtBalance = ex.balanceOf('USDT') // 查询兑换后的USDT余额 Log("balance of USDT", usdtBalance) Log(ex.swapToken('USDT', usdtBalance, 'ETH')) // 把USDT兑换为ETH Log("balance of ETH", ex.getETHBalance()) // 查询ETH余额 // Log(ex.sendETH('0x11111', 0.02)) // ETH转账操作

Testnet Goerli ব্যবহার করে পরীক্ষা করুন

  1. টেস্টনেট এক্সচেঞ্জ অবজেক্ট কনফিগার করুন

নোট করুন যে নোড সেট করার সময়, আপনাকে এটি পরীক্ষা নেটওয়ার্ক গোয়েরলির নোডে সেট করতে হবে।

img

  1. একটি কৌশল লিখুন এবং এটি পরীক্ষা নেটওয়ার্ক Goerli এ পরীক্ষা করুন।
function main() { let ex = $.NewUniswapV3() Log("walletAddress: ", ex.walletAddress) let tokenAddressMap = { "ETH" : "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", // WETH "LINK" : "0x326C977E6efc84E512bB9C30f76E30c160eD06FB", "UNI" : "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", } for (let name in tokenAddressMap) { ex.addToken(name, tokenAddressMap[name]) } // ETH_UNI 、 UNI_ETH Log("ETH_UNI:", ex.getPrice('ETH_UNI')) Log("UNI_ETH:", ex.getPrice('UNI_ETH')) // ETH Log("balance of ETH", ex.getETHBalance()) // UNI let uniBalance = ex.balanceOf('UNI') Log("balance of UNI", uniBalance) // LINK let linkBalance = ex.balanceOf('LINK') Log("balance of LINK", linkBalance) // swap 0.001 ETH to UNI Log(ex.swapToken('ETH', 0.001, 'UNI')) // swap UNI to LINK Log(ex.swapToken('UNI', ex.balanceOf('UNI') - uniBalance, 'LINK')) }

পরীক্ষার কোডে, আমরা ওয়ালেট ঠিকানা মুদ্রণ, টোকেন তথ্য নিবন্ধন, সম্পদের ব্যালেন্স মুদ্রণ এবং একটি অবিচ্ছিন্ন বিনিময় সম্পাদন পরীক্ষা করেছি।ETH -> UNI -> LINK. এটি উল্লেখ করা উচিত যে এখানে নিবন্ধিত টোকেন ঠিকানাটি Ethereum পরীক্ষা নেটওয়ার্কে রয়েছে, তাই একই নামের টোকেন ঠিকানাগুলি পরীক্ষার কয়েনের জন্য, আপনি পরীক্ষার টোকেনের জন্য আবেদন করতে পারেন৷ বিস্তারিত জানার জন্য Google চেক করতে পারেন।

img

মনে রাখবেন যে এটি ব্যবহার করতে আপনাকে অবশ্যই "Uniswap V3 ট্রানজ্যাকশন লাইব্রেরি" টেমপ্লেটটি পরীক্ষা করতে হবে৷$.NewUniswapV3()ফাংশন, যদি আপনার FMZ অ্যাকাউন্টে এখনও এই টেমপ্লেটটি না থাকে, আপনি ক্লিক করতে পারেনএটা এখানে পান

পলিসি অপারেশন লগ:

img

img

Uniswap পৃষ্ঠায় প্রদর্শিত সম্পদের মান

https://app.uniswap.org/

img

এই ক্রিয়াকলাপগুলিও চেইনে অনুরূপভাবে জিজ্ঞাসা করা যেতে পারে:

https://goerli.etherscan.io/

img

ETH-কে UNI-তে রূপান্তর একবার সম্পাদিত হয়েছিল, UNI-এর অনুমোদন একবার সম্পাদিত হয়েছিল, এবং UNI-কে LINK-তে রূপান্তর একবার সম্পাদিত হয়েছিল।

END

এই ক্লাস লাইব্রেরিতে অনেকগুলি ফাংশন রয়েছে যা প্রসারিত করা যেতে পারে এবং এমনকি প্যাকেজ পর্যন্ত বাড়ানো যেতে পারে এবং একাধিক রিডেমশন বাস্তবায়ন করতে পারে।tokenA -> tokenB -> tokenCপথ বিনিময়। নির্দিষ্ট চাহিদা অনুসারে এটিকে অপ্টিমাইজ এবং সম্প্রসারিত করা যেতে পারে। এই ধরণের লাইব্রেরি কোড মূলত শিক্ষাদানের জন্য প্রদান করা হয়।

পুনর্নবীকরণ

আপগ্রেডswapTokenফাংশন, সমর্থিতtokenA -> tokenB -> tokenC ... -> tokenDক্রমাগত রিডেম্পশন ফাংশন। আপনি FMZ-এ স্ট্র্যাটেজি স্কোয়ার দ্বারা প্রকাশিত এই টেমপ্লেটের সর্বশেষ কোডটি দেখতে পারেন।

Comment
All comments (3)

    梦总,有python版本的吗

    3 years ago

    可以回头移植一个,调用都一样。

    3 years ago

    学习中,mark

    3 years ago
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)