js を使用して Uniswap V3 と対話する (1) - 流動性を作成する

ネットワーク設定

ゲルリテストネット

Infura を使用して goerli テスト ネットワークの RPC を取得し、水を入手する方法を見つけます。

使用される契約

Uniswap V3 契約
契約名 契約住所
UniswapV3Factory 0x1F98431c8aD98523631AE4a59f267346ea31F984
スワップルーター 0xE592427A0AEce92De3Edee1F18E0157C05861564
NonfungiblePositionManager 0xC36442b4a4522E871399CD717aBDD847Ab11FE88
WETH9 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6

流動性プールを作成する

トークンソート

保証されたトークン0 < トークン1

ウェスパッキン

XXX/ETH 流動性を作成し、ETH を WETH にパッケージ化する必要がある場合は、パッケージ化に WETH9 コントラクトを使用してください。この WETH9 のコントラクト アドレスは、NonfungiblePositionManager コントラクトの WETH9 パラメーターから取得できます。

const { ethers, BigNumber : BN } = require('ethers');
const provider = new ethers.providers.JsonRpcProvider(process.env.GOERLI_TEST_RPC);
const wallet = new ethers.Wallet(process.env.DEPLOYER_PK, provider);
const WETH9 = {
    address:'0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6',
    abi:'',
    decimals:18,
}

//Create Contract for WETH9
const contract = new ethers.Contract(WETH9.address, WETH9.abi, wallet);
(async () =>{
    //eg. you want wrap 1 ether to weth
    const amount = ethers.utils.parseUnits("1", WETH9.decimals);
    await contract.deposit({value:amount});
})()

認可された契約消費制限

WETH は消費制限を承認する必要はありませんが、他のトークンは許容量を確認して、新しい制限を承認する必要があるかどうかを判断する必要があります。

const contract = new ethers.Contract(token.address, token.abi, wallet);
const tokenAllowance = await contract.allowance(owner, spender);
if(tokenAllowance < yourDesiredAmount){
    await contract.approve(spender, yourDesiredAmount);
}

プールの作成

コアメソッド

NonfungiblePositionManager.sol > createAndInitializePoolIfNecessary()

パラメータを渡す

token0 のアドレスと token1 のアドレスについては何も言うことはありませんが、ソートされたトークンであることに注意してください。

選択できる料金オプションは 500、3000、10,000 からあり、対応するtickerSpacingはそれぞれ 10、60、200 です。

最後のパラメータの価格は、Q96.64 形式の token1 に対する token0 の価格の平方根です。

1 つの token0 と交換できる token1 の数を求め、この値の平方根に 2 の 96 乗を乗算します。コードは次のように実装されます。

const bn = require('bignumber.js');
const {BigNumber, BigNumberish} = require("ethers");

bn.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 })
function encodePriceSqrt(reserve1, reserve0) {
    return BigNumber.from(
        new bn(reserve1.toString())
            .div(reserve0.toString())
            .sqrt()
            .multipliedBy(new bn(2).pow(96))
            .integerValue(3)
            .toString()
    )
}

//eg. 
const sqrtPriceX96 = encodePriceSqrt(`token1's amount`, `token0's amount`);

ミントの流動性

コアメソッド

NonfungiblePositionManager.sol > mint()

受信パラメータはオブジェクトです

const param = {
        token0:token0.address,
        token1:token1.address,
        fee:fee,
        tickLower:tickLower,
        tickUpper:tickUpper,
        amount0Desired:token0.amount,
        amount1Desired:token1.amount,
        amount0Min:token0.amount.mul(90).div(100),
        amount1Min:token1.amount.mul(90).div(100),
        recipient:wallet.address,
        deadline:deadline,
        sqrtPriceX96:sqrtPriceX96.toString(),
    };

最初の 3 つのパラメータについては説明する必要はありません。

重要なのは 4 番目と 5 番目のティックです。このティックを処理するには特別なメソッドが必要です。理論的には、このティックの計算には次の式のみが必要です。

check=\log_{1.0001}{価格}

ただし、結果のティックはtickerSpacingで均等に分割する必要があります。そうしないと、以下に示すように、有用なエラー情報なしで呼び出しが元に戻されます。

 したがって、変換するにはメソッドが必要です。

function priceToTick(price, tickSpacing) {
    let tick = Math.floor(Math.log(price) / Math.log(1.0001));
    for (let i = 1; i < tickSpacing; i++){
        if((tick - i) % tickSpacing === 0){
            tick = tick - i;
            break;
        }
        if((tick + i) % tickSpacing === 0){
            tick = tick + i;
            break;
        }
    }
    return tick;
}

次に、mint メソッドを実行します。これでフローの作成は完了です

おすすめ

転載: blog.csdn.net/bbandxq521/article/details/130847376