当前位置: 首页 > news >正文

做网站域名有什么用自媒体是干什么的

做网站域名有什么用,自媒体是干什么的,成都网站制作培训,在汕头的网络公司有哪些本文首发于公众号#xff1a;Keegan小钢 SwapRouter 合约封装了面向用户的交易接口#xff0c;但不再像 UniswapV2Router 一样根据不同交易场景拆分为了那么多函数#xff0c;UniswapV3 的 SwapRouter 核心就只有 4 个交易函数#xff1a; exactInputSingle#xff1a;指…本文首发于公众号Keegan小钢 SwapRouter 合约封装了面向用户的交易接口但不再像 UniswapV2Router 一样根据不同交易场景拆分为了那么多函数UniswapV3 的 SwapRouter 核心就只有 4 个交易函数 exactInputSingle指定输入数量的单池内交易exactOutputSingle指定输出数量的单池内交易exactInput指定输入数量和交易路径的交易exactOutput指定输出数量和交易路径的交易 带 Single 的只支持单池内的交易而不带 Single 的则支持跨不同池子的互换交易。 exactInputSingle 先来看简单的单池交易以 exactInputSingle 为始其代码实现如下 struct ExactInputSingleParams {address tokenIn; //输入tokenaddress tokenOut; //输出tokenuint24 fee; //手续费率address recipient; //收款地址uint256 deadline; //过期时间uint256 amountIn; //指定的输入token数量uint256 amountOutMinimum; //输出token的最小数量uint160 sqrtPriceLimitX96; //限定的价格 }function exactInputSingle(ExactInputSingleParams calldata params)externalpayableoverridecheckDeadline(params.deadline)returns (uint256 amountOut) {amountOut exactInputInternal(params.amountIn,params.recipient,params.sqrtPriceLimitX96,SwapCallbackData({path: abi.encodePacked(params.tokenIn, params.fee, params.tokenOut), payer: msg.sender}));require(amountOut params.amountOutMinimum, Too little received); }其入参有 9 个参数返回值就一个 amountOut即输出的 token 数量。 从代码上可看出实际的逻辑实现是在内部函数 exactInputInternal。查看该内部函数之前我们先来了解下 SwapCallbackData。我们从上面代码可以看到调用 exactInputInternal 时最后一个传入的参数就是 SwapCallbackData这其实是一个结构体定义了两个属性 struct SwapCallbackData {bytes path;address payer; }path 表示交易路径在以上代码中就是由 tokenIn、fee、tokenOut 这三个变量拼接而成。payer 表示支付输入 token 的地址上面的就是 msg.sender。 接着来看看内部函数 exactInputInternal 的代码实现 function exactInputInternal(uint256 amountIn,address recipient,uint160 sqrtPriceLimitX96,SwapCallbackData memory data ) private returns (uint256 amountOut) {// allow swapping to the router address with address 0if (recipient address(0)) recipient address(this);//从路径中解码出第一个池子(address tokenIn, address tokenOut, uint24 fee) data.path.decodeFirstPool();//当tokenIntokenOUt时则说明tokenIn为token0所以是要将token0兑换成token1bool zeroForOne tokenIn tokenOut;//调用底层池子的swap函数执行交易(int256 amount0, int256 amount1) getPool(tokenIn, tokenOut, fee).swap(recipient,zeroForOne,amountIn.toInt256(),sqrtPriceLimitX96 0? (zeroForOne ? TickMath.MIN_SQRT_RATIO 1 : TickMath.MAX_SQRT_RATIO - 1): sqrtPriceLimitX96,abi.encode(data));//返回amountOutreturn uint256(-(zeroForOne ? amount1 : amount0)); }首先如果 recipient 地址为零地址的话那会把 recipient 重置为当前合约地址。 接着通过 data.path.decodeFirstPool() 从路径中解码得出 tokenIn、tokenOut 和 fee。decodeFirstPool 函数是在库合约 Path 里实现的。 布尔类型的 zeroForOne 表示底层 token0 和 token1 的兑换方向为 true 表示用 token0 兑换 token1false 则反之。因为底层的 token0 是小于 token1 的所以当 tokenIn 也小于 tokenOut 的时候说明 tokenIn token0所以 zeroForOne 为 true。 然后通过 getPool 函数可得到池子地址再调用底层池子的 swap 函数来执行实际的交易逻辑。 最后我们要得到的是 amountOut这是 amount0 和 amount1 中的其中一个。我们已经知道zeroForOne 为 true 的时候tokenIn 等于 token0所以 tokenOut 就是 token1因此 amountOut 就是 amount1。另外对底层池子来说属于输出的时候返回的数值是负数即 amount1 其实是一个负数因此需要再加个负号转为正数的 uint256 类型。 在这个函数里我们可以看出并没有支付 token 的功能但前面讲解 UniswapV3Pool 时已经了解到支付是在回调函数 uniswapV3SwapCallback 里完成的。因为这个回调函数会涉及到所有 4 种交易类型所以我们留到最后再来讲解。 exactOutputSingle 接着来看 exactOutputSingle 函数的实现其代码如下 struct ExactOutputSingleParams {address tokenIn; //输入tokenaddress tokenOut; //输出tokenuint24 fee; //手续费率address recipient; //收款地址uint256 deadline; //过期时间uint256 amountOut; //指定的输出token数量uint256 amountInMaximum; //输入token的最大数量uint160 sqrtPriceLimitX96; //限定的价格 }function exactOutputSingle(ExactOutputSingleParams calldata params)externalpayableoverridecheckDeadline(params.deadline)returns (uint256 amountIn) {// avoid an SLOAD by using the swap return dataamountIn exactOutputInternal(params.amountOut,params.recipient,params.sqrtPriceLimitX96,SwapCallbackData({path: abi.encodePacked(params.tokenOut, params.fee, params.tokenIn), payer: msg.sender}));require(amountIn params.amountInMaximum, Too much requested);// has to be reset even though we dont use it in the single hop caseamountInCached DEFAULT_AMOUNT_IN_CACHED; }可看出exactOutputSingle 函数的实现与 exactInputSingle 函数大同小异。首先参数上只有两个不同exactInputSingle 函数指定的是 amountIn 和 amountOutMinimum而 exactOutputSingle 函数改为了 amountOut 和 amountInMaximum即输出是指定的而输入则限制了最大值。其次实际逻辑封装在了 exactOutputInternal 内部函数而且传给该内部函数的最后一个参数的 path 组装顺序也不一样了排在第一位的是 tokenOut。 核心实现还是在 exactOutputInternal 内部函数其代码实现如下 function exactOutputInternal(uint256 amountOut,address recipient,uint160 sqrtPriceLimitX96,SwapCallbackData memory data ) private returns (uint256 amountIn) {// allow swapping to the router address with address 0if (recipient address(0)) recipient address(this);//从路径中解码出第一个池子(address tokenOut, address tokenIn, uint24 fee) data.path.decodeFirstPool();//是否token0兑换token1bool zeroForOne tokenIn tokenOut;//调用底层池子的swap函数执行交易(int256 amount0Delta, int256 amount1Delta) getPool(tokenIn, tokenOut, fee).swap(recipient,zeroForOne,-amountOut.toInt256(), //指定输出需转为负数sqrtPriceLimitX96 0? (zeroForOne ? TickMath.MIN_SQRT_RATIO 1 : TickMath.MAX_SQRT_RATIO - 1): sqrtPriceLimitX96,abi.encode(data));//确定amountIn和amountOutuint256 amountOutReceived;(amountIn, amountOutReceived) zeroForOne? (uint256(amount0Delta), uint256(-amount1Delta)): (uint256(amount1Delta), uint256(-amount0Delta));// its technically possible to not receive the full output amount,// so if no price limit has been specified, require this possibility awayif (sqrtPriceLimitX96 0) require(amountOutReceived amountOut); }可见和 exactInputInternal 的实现也是大同小异。不过有一个细节需要补充一下。因为是指定的输出数额所以调用底层的 swap 函数时第三个传参转为了负数这也是前面讲解 UniswapV3Pool 的 swap 函数时讲过的当指定的交易数额是输出的数额时则需传负数。 和 exactInputInternal 一样在当前函数里没有支付 token 的逻辑也是统一在 uniswapV3SwapCallback 回调函数里去完成支付。 exactInput exactInput 函数则用于处理跨多个池子的指定输入数量的交易相比单池交易会复杂一些而且这里面的逻辑还有点绕我们来进行一一剖析。其实现代码如下 struct ExactInputParams {bytes path; //交易路径address recipient; //收款地址uint256 deadline; //过期时间uint256 amountIn; //指定输入token数量uint256 amountOutMinimum; //输出token的最小数量 }function exactInput(ExactInputParams memory params)externalpayableoverridecheckDeadline(params.deadline)returns (uint256 amountOut) {//调用者需支付路径中的第一个代币address payer msg.sender;//遍历路径while (true) {//路径中是否还存在多个池子bool hasMultiplePools params.path.hasMultiplePools();//先前交换的输出成为后续交换的输入params.amountIn exactInputInternal(params.amountIn,hasMultiplePools ? address(this) : params.recipient,0,SwapCallbackData({path: params.path.getFirstPool(), // 只需要路径里的第一个池子payer: payer}));//当路径依然由多个池子组成时则继续循环否则退出循环if (hasMultiplePools) {payer address(this);//跳过第一个token作为下一轮的路径params.path params.path.skipToken();} else {//最后一次兑换把前面设为了amountIn的重新赋值给amountOutamountOut params.amountIn;break;}}require(amountOut params.amountOutMinimum, Too little received); }其中需要跨多个池子的路径编码方式如下图 和 UniswapV2 一样这个路径是由前端计算出来再传给合约的。寻找最优路径的算法也是和 UniswapV2 一样的思路。 exactInput 函数的核心实现逻辑是循环处理路径中的每一个配对池每处理完一个池子的交易就从路径中移除第一个 token 和 fee直到路径只剩下最后一个池子就结束循环。期间每一次执行 exactInputInternal 后将返回的 amounOut 作为下一轮的 amountIn。第一轮兑换时payer 是合约的调用者即 msg.sender而输出代币的 recipient 则是当前合约地址。中间的每一次兑换payer 和 recipient 都是当前合约地址。到最后一次兑换时recipient 才转为用户传入的地址。 exactOutput 剩下最后一个函数 exactOutput 了也是用于处理跨多个池子的的交易而指定的是输出的数量。以下是其代码实现 struct ExactOutputParams {bytes path; //交易路径address recipient; //收款地址uint256 deadline; //过期时间uint256 amountOut; //指定输出token数量uint256 amountInMaximum; //输入token的最大数量 }function exactOutput(ExactOutputParams calldata params)externalpayableoverridecheckDeadline(params.deadline)returns (uint256 amountIn) {// its okay that the payer is fixed to msg.sender here, as theyre only paying for the final exact output// swap, which happens first, and subsequent swaps are paid for within nested callback framesexactOutputInternal(params.amountOut,params.recipient,0,SwapCallbackData({path: params.path, payer: msg.sender}));amountIn amountInCached;require(amountIn params.amountInMaximum, Too much requested);amountInCached DEFAULT_AMOUNT_IN_CACHED; }可看到其逻辑就直接调用内部函数 exactOutputInternal 完成交易并没有像 exactInput 一样的循环处理。但在整个流程中其实还是进行了遍历路径的多次交易的只是这个流程完成得比较隐晦。其关键其实是在 uniswapV3SwapCallback 回调函数里后面我们会说到。 uniswapV3SwapCallback 以下就是回调函数的实现 function uniswapV3SwapCallback(int256 amount0Delta,int256 amount1Delta,bytes calldata _data ) external override {require(amount0Delta 0 || amount1Delta 0);//解码出_data数据SwapCallbackData memory data abi.decode(_data, (SwapCallbackData));//解码出路径的第一个池子(address tokenIn, address tokenOut, uint24 fee) data.path.decodeFirstPool();//校验callback的调用者CallbackValidation.verifyCallback(factory, tokenIn, tokenOut, fee);//用于判断当前需要支付的代币(bool isExactInput, uint256 amountToPay) amount0Delta 0? (tokenIn tokenOut, uint256(amount0Delta)): (tokenOut tokenIn, uint256(amount1Delta));if (isExactInput) { //指定金额的是输入直接执行支付pay(tokenIn, data.payer, msg.sender, amountToPay);} else { //指定金额的是输出// either initiate the next swap or payif (data.path.hasMultiplePools()) {// 路径里有多个池子时则跳过路径的第一个token使用下一个配对的池子进行交易data.path data.path.skipToken();exactOutputInternal(amountToPay, msg.sender, 0, data);} else { //只剩下一个池子执行支付amountInCached amountToPay;tokenIn tokenOut; // swap in/out because exact output swaps are reversedpay(tokenIn, data.payer, msg.sender, amountToPay);}} }另外这个是 swap 时的回调函数。而之前的文章我们还讲了另一个回调函数 uniswapV3MintCallback 是添加流动性时的回调函数两者是不同的不要搞混了。 其逻辑实现并不复杂。首先先把 _data 解码成 SwapCallbackData 结构体类型数据。接着解码出路径的第一个池子。然后通过 verifyCallback 校验调用当前回调函数的是否为底层 pool 合约非底层 pool 合约是不允许调起回调函数的。 isExactInput 和 amountToPay 的赋值需要拆解一下才好理解。首先需知道amount0Delta 和 amount1Delta 其实是一正一负的正数是输入的负数是输出的。因此amount0Delta 大于 0 的话则 amountToPay 就是 amount0Delta否则就是 amount1Delta 了。 amount0Delta 大于 0 也说明了输入的是 token0因此当 tokenIn tokenOut 的时候说明 tokenIn 就是 token0也即是说用户指定的是输入数量所以这时候的 isExactInput 即为 true。 当指定金额为输出的时候也就是处理 exactOutput 和 exactOutputSingle 函数的时候。我们前面看到 exactOutput 的代码逻辑里并没有对路径进行遍历处理这个遍历其实就是在这个回调函数里完成的。仔细看这段代码 if (data.path.hasMultiplePools()) {// 路径里有多个池子时则跳过路径的第一个token使用下一个配对的池子进行交易data.path data.path.skipToken();exactOutputInternal(amountToPay, msg.sender, 0, data); }这不就是遍历路径多次执行 exactOutputInternal 了吗。 至此SwapRouter 合约也讲解完了。
http://www.dnsts.com.cn/news/183024.html

相关文章:

  • 无棣县建设局网站文老师网络规划设计师
  • 徐州网站建设方案开发网页设计与制作教程的页数是
  • 在哪个网站上做实验仪器比较好莱芜融媒体中心网站
  • 泰州网站建设公司百度网址大全网站大全
  • 网站漂浮广告南昌建站软件
  • 辽宁省住房和城乡建设网站如何在国外网站做免费推广
  • 桂建云平台注册宁波seo品牌推广排名
  • 宁海有做网站的吗网站seo课程
  • 企业网站管理的含义网上商城代码
  • wordpress自己发文章标题优化怎么做
  • 网站被301跳转阿里指数官网
  • 百度网站地址提交北滘企业网站开发
  • 网站建设好后能直接打开吗苏州网站建设推广案例
  • 品牌网站建设小蝌蚪c太原谁想做网站
  • 网站开发需求收集济南专业网站制作公司
  • jsp网站建设项目实战课本内容临沂有哪几家做网站的
  • 网页特效代码下载邢台移动网络优化是哪家公司
  • 网站建设与管理大作业wordpress关联adsense
  • 自己做网站的二维码烟台建设集团网站
  • 搞一个网站需要多少钱长安外贸网站建设公司
  • 招聘网站推广怎么做怎么做微信推送 网站
  • 浙江省住房和城乡建设部网站湖南做网站磐石网络
  • 网站建设公司岗位做网站需要的公司
  • 软件开发做网站网站优化18600119496
  • 江苏企业网站建设公司北京果木烤鸭制作方法
  • 苏州前程无忧官上做网站百度指数的使用方法
  • 环保网站 源码ui设计官网
  • wordpress网站前台打开慢又一个wordpress博客
  • 网站开发的专业能力网站开发用户分析
  • 网站制作推广招聘互联网行业五行属什么