خوبصورت اور سادہ! کوڈ کی 200 لائنوں کے ساتھ FMZ پر Uniswap V3 سے منسلک ہے۔
حالیہ برسوں میں Defi تصور کی مقبولیت کے ساتھ، Uniswap V3 وکندریقرت مالیات (DeFi) کے میدان میں سب سے زیادہ مقبول موضوعات میں سے ایک بن گیا ہے۔ مرکزی وکندریقرت تبادلہ پروٹوکول کے طور پر، Uniswap V3 زیادہ موثر، زیادہ محفوظ اور بہتر صارف کا تجربہ فراہم کرتا ہے۔ اب، کوڈ کی صرف 200 لائنوں کے ساتھ، تاجر اور ڈویلپرز آسانی سے FMZ پلیٹ فارم پر Uniswap V3 تک رسائی حاصل کر سکتے ہیں۔
FMZ ایک مقداری تجارتی پلیٹ فارم ہے جو مقداری تجارتی حکمت عملیوں کی ترقی، بیک ٹیسٹنگ اور حقیقی وقت میں تعیناتی کی حمایت کرتا ہے۔ اس کے استعمال میں آسان انٹرفیس اور طاقتور خصوصیات کے ساتھ، یہ سمجھنا آسان ہے کہ کیوں FMZ DeFi ٹریڈرز اور ڈیولپرز کے لیے پہلی پسند بن رہا ہے۔
Uniswap V3 کو FMZ میں ضم کرنے کا عمل آسان اور سمجھنے میں آسان ہے، اور اسے مکمل کرنے کے لیے کوڈ کی صرف 200 لائنیں درکار ہیں۔ اس کا مطلب ہے کہ یہاں تک کہ اگر آپ کوڈنگ میں نئے ہیں، آپ آسانی سے FMZ پر Uniswap V3 سے جڑ سکتے ہیں اور فوراً ٹریڈنگ شروع کر سکتے ہیں۔
FMZ نے بنیادی web3 فنکشنز کی ایک سیریز کو سمیٹ لیا ہے Uniswap کے علاوہ، دیگر 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 پر تعینات اور چلتا ہے۔
- روٹ: روٹ ایک سمارٹ کنٹریکٹ بھی ہے جسے انتظام کرنے کے لیے استعمال کیا جاتا ہے۔
tokenتبادلہ - پول: پول ایک سمارٹ کنٹریکٹ بھی ہے جو دو ایتھریم ٹوکنز کو ذخیرہ کرنے اور ان کے درمیان تبادلہ کرنے کے لیے استعمال ہوتا ہے۔
- فیکٹری کا معاہدہ: فیکٹری کا معاہدہ ایک سمارٹ کنٹریکٹ ہے جو پول بنانے کے لیے استعمال ہوتا ہے۔
- ABI: (Application Binary Interface) ایک تصریح ہے جو بتاتی ہے کہ کس طرح سمارٹ معاہدے بیرونی دنیا کے ساتھ بات چیت کرتے ہیں۔ یہ سمارٹ کنٹریکٹ کے فنکشن کا نام، پیرامیٹر کی اقسام، اور ریٹرن ویلیو کی اقسام کے ساتھ ساتھ ڈیٹا کو انکوڈ اور ڈی کوڈ کرنے کا طریقہ بتاتا ہے، اور سمارٹ کنٹریکٹ کے بیرونی انٹرفیس کا تعین کرتا ہے۔ یہ سمجھا جا سکتا ہے کہ کسی خاص انٹرفیس کو کال کرنے کے لیے، اسے انٹرفیس کے متفقہ معیارات کے مطابق بلایا جانا چاہیے، اور ABI متفقہ معیارات کی ایک سیریز کو ریکارڈ کرتا ہے۔
ایک بار جب ایتھرئم پر سمارٹ کنٹریکٹ تعینات ہو جاتا ہے، تو اس کا ایک پتہ ہوتا ہے۔
Uniswap V3 ٹریڈنگ لائبریری کوڈ کو الگ کرنا
Uniswap V3 ٹریڈنگ لائبریری کوڈ کو بنیادی طور پر 4 حصوں میں تقسیم کیا گیا ہے۔
حصہ 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فیکٹری کے معاہدے کے لیے ABI۔
چونکہ یہ تار بہت طویل ہیں، اس لیے یہ صرف اقتباسات ہیں۔ یہ مواد پروگرام کو سمارٹ کنٹریکٹ کے طریقوں کو کال کرنے کے معیارات فراہم کرتے ہیں (مثال کے طور پر، اس سمارٹ کنٹریکٹ انٹرفیس کے پیرامیٹرز کیا ہیں، کتنے پیرامیٹرز ہیں، وہ کس قسم کے ہیں، واپس کیا گیا ڈیٹا کس قسم کا ہے، وغیرہ)۔
ہم نے پہلے ذکر کیا ہے کہ ایک بار Ethereum پر ایک سمارٹ کنٹریکٹ تعینات کیا جاتا ہے، اس کا ایک پتہ ہوتا ہے۔
ContractV3Factory: فیکٹری کے معاہدے کا پتہ ریکارڈ کرتا ہے۔
ContractV3SwapRouterV2: Uniswap V3 کے روٹر V2 ایڈریس میں V1 اور 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ہاںETH,token1ہاںUSDT。decimals0یہ ہےtoken0درستگی کے اعداد و شمار،decimals1یہ ہےtoken1درستگی کا ڈیٹا۔sqrtPriceX96یہ قیمت سے متعلق ڈیٹا ہے (براہ راست قیمت کی قدر نہیں)، جو پول کنٹریکٹ سے حاصل کیا جا سکتا ہے۔slot0طریقہ حصول۔
sqrtPriceX96 : The current price of the pool as a sqrt(token1/token0) Q64.96 value
Q64.96 ڈیٹا پروسیسنگ اسٹوریج کا معیار ہے۔
decimals0,decimals1, sqrtPriceX96یہ تینوں ڈیٹا پیرامیٹرز کے طور پر پاس کیے جاتے ہیں۔computePoolPriceفنکشن لین دین کے جوڑے کا حساب لگا سکتا ہے۔ETH_USDTقیمت فنکشن آخر میںreturnبیان میں الگورتھم تبدیل کرنا ہے۔sqrtPriceX96بحال کریں۔token1/token0عمل مثال کے طور پر، اس وقت، پول میں ٹوکن0 (ETH) کی تعداد 1 ہے، اور ٹوکن1 (USDT) کی تعداد 1100 ہے۔ تو1100/1=1100، موجودہ تجارتی جوڑیETH_USDTپول میں قیمت 1100 ہے۔
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 ٹریڈنگ لائبریری" کے کوڈ کا تجزیہ کریں۔
حصہ 3: Uniswap V3 آپریشن آبجیکٹ کا کنسٹرکٹر
اس ٹیمپلیٹ کلاس لائبریری کا بنیادی حصہ Uniswap V3 آپریشن آبجیکٹ ہے، جو Uniswap V3 پر بنیادی کارروائیوں کو نافذ کرتا ہے۔ مزید فنکشنز کو بعد میں اپ گریڈ کیا جا سکتا ہے۔ اس کوڈ مثال کا تجزیہ کرنے سے، یہاں تک کہ اگر آپ FMZ پلیٹ فارم استعمال نہیں کرتے ہیں، تو آپ کی سمجھ میں اضافہ ہوگاUniswapیہDEXہر لنک کے عمل اور تفصیلات کو سمجھنے کے لیے، آئیے اب سیکھتے ہیں کہ یہ بنیادی فنکشن FMZ پر کس طرح ڈیزائن اور لاگو کیے جاتے ہیں۔
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نام دینا قدرے عجیب ہے، کے ساتھ$.شروع میں فنکشن اشارہ کرتا ہے کہ یہ فنکشن ایف ایم زیڈ پر ٹیمپلیٹ لائبریری کا انٹرفیس فنکشن ہے (ٹیمپلیٹ لائبریری کیا ہےدیکھیں)، سادہ الفاظ میں$.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 پر ایکسچینج کنفیگریشن) کی نمائندگی کرتا ہے۔ کیونکہ FMZ پر حکمت عملی کو ملٹی ایکسچینج کے لیے ڈیزائن کیا جا سکتا ہے، اگر یہاں کوئی مخصوص ایکسچینج پاس کیا جاتا ہے، تو اس کا مطلب ہے کہ اسے بنایا گیا ہے۔Uniswap V3آبجیکٹ ایکسچینج آبجیکٹ کو چلانے کے لیے استعمال ہوتا ہے۔ اگر کوئی پیرامیٹرز پاس نہیں ہوتے ہیں۔e, پہلے سے طے شدہ آپریشن پہلی شامل کردہ ایکسچینج آبجیکٹ ہے۔
نوڈ سروس ایڈریس اور نجی کلید کو ترتیب دیں (نجی کلید کو مقامی طور پر تعینات کیا جا سکتا ہے، اور مقامی تعیناتی کے لیے صرف راستے کو ترتیب دینے کی ضرورت ہوتی ہے) ایک تبادلہ آبجیکٹ بنانے کے لیے۔ اسے حقیقی ٹریڈنگ کے دوران حکمت عملی میں شامل کیا جا سکتا ہے۔exchangeیعنیexchanges[0]اگر آپ دوسرا اضافہ کرتے ہیں،exchanges[1]، ایک تہائی شامل کریں۔exchanges[2],...
اس نوڈ کا پتہ جو میں نے اسکرین شاٹ میں ترتیب دیا ہے: 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
کچھ طلباء پوچھ سکتے ہیں: یہ فنکشن کیوں استعمال کریں؟
A: کچھ آپریشنز کرتے وقت، جیسے ٹوکن ایکسچینج، آپ کو نتائج کا انتظار کرنا ہوگا۔
اگلا، آئیے دیکھتے ہیں۔$.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 جیسا کہ ہم نے پہلے ذکر کیا ہے، آپ اسے چیک کر سکتے ہیں)، اگر یہ نہیں ملتا ہے، تو پول ایڈریس کا حساب لگانے کے لیے دو ٹوکن اور فیس کے پتے استعمال کیے جاتے ہیں۔ لہذا ایک تجارتی جوڑے میں متعدد پول ہوسکتے ہیں کیونکہ فیس مختلف ہوسکتی ہے۔
Uniswap 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');
اگر آپ کے پاس کافی ایکسچینج کوٹہ ہے، تو آپ ایکسچینج کر سکتے ہیں۔ لیکن یہاں تفصیلات بھی موجود ہیں اگر ایکسچینج میں شامل ٹوکن ETH ہے تو وصول کرنے والے ایڈریس میں ترمیم کرنے کی ضرورت ہے:
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 میں تبدیل کرنے کے لیے، پیکنگ کھولنے کے آپریشن کی ضرورت ہوتی ہے، اس سلسلے کو انجام دینے کے لیے راؤٹر کا ملٹی کال طریقہ (سمارٹ کنٹریکٹ) بلایا جا سکتا ہے۔ ایک اور تفصیل ہے جس پر آپ کو اضافی توجہ دینے کی ضرورت ہے۔ 0۔
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 سیٹ نہیں کیا جب tokenIn ETH ٹوکن کے برابر نہیں تھا، جس کی وجہ سے ETH کی غلطی سے منتقلی ہوئی۔ اس لیے ٹرانسفر کوڈ لکھتے وقت زیادہ محتاط رہیں۔
حصہ 4: Uniswap V3 آپریشن آبجیکٹ کو کیسے استعمال کریں۔
اس ٹیمپلیٹ میں موجود کوڈ میں اصل میں 200 سے کم سطریں ہیں مندرجہ ذیل سیکشن دراصل استعمال کا مظاہرہ ہے۔
$.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()یہ فنکشن صرف ایک مظاہرہ ہے، اگر اس کا کوئی عملی استعمال نہیں ہے تو براہ کرم اسے کال نہ کریں۔ ہم اس فنکشن کا استعمال یہ دیکھنے کے لیے کریں گے کہ اس ٹیمپلیٹ لائبریری کو یونی سویپ 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转账操作
Goerli testnet کا استعمال کرتے ہوئے ٹیسٹ کریں۔
- ٹیسٹ نیٹ ایکسچینج آبجیکٹ کو کنفیگر کریں۔
براہ کرم نوٹ کریں کہ نوڈ سیٹ کرتے وقت، آپ کو اسے ٹیسٹ نیٹ ورک Goerli کے نوڈ پر سیٹ کرنا ہوگا۔
- ایک حکمت عملی لکھیں اور ٹیسٹ نیٹ ورک 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 ٹیسٹ نیٹ ورک Goerli پر ہے، اس لیے ایک ہی نام کے ٹوکن ایڈریس مختلف ہیں جہاں تک ٹیسٹ کوائنز کے لیے آپ اس ٹیسٹ نیٹ ورک کا ٹوکن استعمال کر سکتے ہیں۔ آپ تفصیلات کے لیے گوگل کو چیک کر سکتے ہیں۔
نوٹ کریں کہ آپ کو اسے استعمال کرنے کے لیے "Uniswap V3 Trading Library" ٹیمپلیٹ کو چیک کرنے کی ضرورت ہے۔$.NewUniswapV3()فنکشن، اگر آپ کے FMZ اکاؤنٹ میں یہ ٹیمپلیٹ نہیں ہے، تو آپ کلک کر سکتے ہیں۔اسے یہاں حاصل کریں۔。
حکمت عملی آپریشن لاگ:
اثاثہ کی قدریں Unswap صفحہ پر دکھائی دیتی ہیں۔
ان کارروائیوں سے سلسلہ پر بھی استفسار کیا جا سکتا ہے:
ETH کا UNI سے تبادلہ ایک بار ہوا، UNI کی اجازت ایک بار عمل میں لائی گئی، اور UNI سے LINK کا تبادلہ ایک بار عمل میں آیا۔
END
اس لائبریری میں بہت سے فنکشنز ہیں جن کو بڑھایا جا سکتا ہے، اور یہاں تک کہ اسے ایک سے زیادہ چھٹکارے کے پیکج تک بڑھایا جا سکتا ہے۔tokenA -> tokenB -> tokenCراستے کا تبادلہ۔ اسے مخصوص ضروریات کے مطابق بہتر بنایا جا سکتا ہے اور اس قسم کا لائبریری کوڈ بنیادی طور پر تدریس کے لیے فراہم کیا جاتا ہے۔
تجدید
اپ گریڈswapTokenفنکشن، سپورٹ کرتا ہے۔tokenA -> tokenB -> tokenC ... -> tokenDمسلسل چھٹکارا فنکشن. آپ FMZ پر Strategy Square پر شائع ہونے والے اس ٹیمپلیٹ کا تازہ ترین کوڈ دیکھ سکتے ہیں۔
- 1








