給公眾號做頭像的網(wǎng)站北京百度關鍵詞優(yōu)化
Uniswap是一個開源的去中心化的交易所,在github上面有以下重要倉庫:
- uniswap-v2-core: 幣對池pair的核心智能合約。這個repository包含了Uniswap的幣對池pair的所有核心邏輯,增加流動性、減少流動性等。
- uniswap-v2-periphery:這個repository包含了Uniswap V3的所有周邊智能合約。這些合約提供了與核心合約交互的附加功能,例如多次跨路徑交易和非fungible流動性。
- uniswap-interface:這是Uniswap的主要前端接口。它是一個開源的Web應用程序,允許用戶直接與Uniswap協(xié)議進行交互,可以直接用于做客戶端
- uniswap-v3-sdk:這些開發(fā)工具包用于幫助開發(fā)者構建自己的客戶端應用程序,從而與 Uniswap 智能合約進行交互。
- uniswap-v3-subgraph:這是Uniswap V3的子圖項目,用于從以太坊區(qū)塊鏈上獲取和索引 Uniswap V3 的數(shù)據(jù)。開發(fā)者可以通過 GraphQL API 從子圖中查詢 Uniswap 的數(shù)據(jù),以便在自己的應用程序中使用。
??
一、AMM交易機制
不同于傳統(tǒng)訂單薄的交易模式, uniswap交易使用的是恒定乘積公式的自動做市商模式。即交易前后,池子內一對代幣的乘積保持不變。
? ?
?在uniswap v2中,每次會收取0.3%的手續(xù)費,即p = 0.003
,這筆手續(xù)費從交易者的x'
中扣除分發(fā)給流動性提供者。因此,只有x' *(1-p)
的A數(shù)量來兌換y'
數(shù)量的B。剩下p * x'
會作為手續(xù)費被添加到池子中,此時,上面的等式會變?yōu)?#xff1a;
二、 合約設計
- RouterContract:路由合約,對外提供api的合約。主要包括注入流動性、移除流動性、兌換等
- addLiqudity(token0, token1, amount0, amount1):幣對(token0和token1)的金額,進過計算后,會轉入到pair的地址里; pair合約同時會計算出持有代幣,轉入到msg.sender地址里。
- removeLiqudity(token0, token1, liqudity):先把msg.sender地址里的pair持有代幣,轉回給pair地址; 調用pair地址的burn方法,按token0、token1總量比例,得到各自的amount;把token0和token1的轉amount0和amount1到msg.sender地址
- swapToken: ?
- UniswapV2Library:工具庫合約,主要提供根據(jù)factory地址計算池地址、幣對token總量等
- UniswapV2Factory:幣對工廠合約,主要在合約內運行時,部署若干新的UniswapPair合約實例,并得到地址
- UniswapPair:幣對的ERC20代幣合約。每個部署實例,都對應1個幣對;幣對供應量增加,它會mint增加總量;反之,會burn減少總量
? ?
三、SDK設計
Uniswap SDK 是一個同構 (Isomorphic) 的庫,既可以在客戶端使用也可以在服務端使用。SDK不能代表用戶執(zhí)行或發(fā)送交易,它提供了實用的類和函數(shù),幫助計算出安全地與 Uniswap 交互所需要的數(shù)據(jù)。
- Token:用于構建token實例
- Pair:獲取Pair相關信息
- Route:創(chuàng)建交易路徑。 前端計算得出,比如[token0, token1],是可以直接作為交易路徑;還是要因為沒有這個幣對池,要用[token0, token2], [token2, token0]作交易路徑
- Trade:構建交易,且用于計算出交易的數(shù)據(jù),比如期望交易輸出
- Percent/Fraction: 百分比、有理數(shù)等, 都是數(shù)字類抽象,幫助計算的
// swapExactETHForTokens
import { ChainId, Token, Fetcher, Pair, TokenAmount, Route, Trade, TradeType, Percent } from '@uniswap/sdk'
import { ethers } from 'ethers'
import 'dotenv/config'// 構建client,包括provider、account
const rpcurl = `https://rinkeby.infura.io/v3/${process.env.INFURA_PROJECT_ID}`;
const provider = new ethers.providers.JsonRpcProvider(rpcurl);
const signer = new ethers.Wallet(process.env.PRIVATE_KEY);
const account = signer.connect(provider);// 構建token0、token1
const WETH = new Token(ChainId.RINKEBY, '0xc778417E063141139Fce010982780140Aa0cD5Ab', 18);
const LINK = new Token(ChainId.RINKEBY, '0x01BE23585060835E02B77ef475b0Cc51aA1e0709', 18);const uniV2ABI = ['function swapExactETHForTokens(uint amountOutMin, address[] calldata path, \address to, uint deadline) external payable returns (uint[] memory amounts)'];
const uniswapContract = new ethers.Contract('0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', uniV2ABI, account);
const run = async () => {// 獲取幣對池信息const pair = await Fetcher.fetchPairData(LINK, WETH, provider);// 構建交易路徑const route = new Route([pair], WETH);console.log(route.midPrice.numerator.toString());console.log(route.midPrice.denominator.toString());console.log('WETH-LINK', route.midPrice.toSignificant(6));// 1 LINK = ??? WETHconsole.log(route.midPrice.invert().numerator.toString());console.log(route.midPrice.invert().denominator.toString());console.log('LINK-WETH', route.midPrice.invert().toSignificant(6));// 構建交易const trade = new Trade(route, new TokenAmount(WETH, ethers.utils.parseEther('0.003')), TradeType.EXACT_INPUT);console.log(trade.executionPrice.toSignificant(6));const slippageTolerance = new Percent('50', '10000');const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw;const path = [WETH.address, LINK.address];const to = '0x...' // PRIVATE_KEY's Address, 或者隨便一個地址用來接收const deadline = Math.floor(Date.now() / 1000) + 60 * 20 // 20 minutes from the current Unix timeconst value = trade.inputAmount.raw;console.log(value.toString())// 調用合約方法,進行兌換交易const tx = await uniswapContract.swapExactETHForTokens(amountOutMin.toString(), path, to, deadline, {value: value.toString(),// maxFeePerGas: ethers.utils.parseUnits('2','gwei'),// maxPriorityFeePerGas: ethers.utils.parseUnits('2','gwei'),});console.log(`Transaction hash: ${tx.hash}`);const receipt = await tx.wait();console.log(receipt);}