ネットワーク設定
ゲルリテストネット
Infura を使用して goerli テスト ネットワークの RPC を取得し、水を入手する方法を見つけます。
使用される契約
契約名 | 契約住所 |
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 番目のティックです。このティックを処理するには特別なメソッドが必要です。理論的には、このティックの計算には次の式のみが必要です。
ただし、結果のティックは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 メソッドを実行します。これでフローの作成は完了です