Box

Box

3BoxTech Founder / Web3Box Founder/ solidity dev./Several years of experience in Solidity and full-stack development.
twitter

Web3企業向けエンジニアリング - 初級編:4. 完全版UniswapV3のデプロイ

前言#

文接上回,我们已经部署了 Uniswap のコア契約、次に私たちは UniswapV3 の完全版をデプロイします。完全版の UniswapV3 には以下の契約が含まれています:

  • UniswapV3Factory (プール生成契約)

  • UniswapV3SwapRouter (ラッパークラス取引契約)

  • NonfungiblePositionManager (NFT 管理契約)

  • NonfungibleTokenPositionDescriptor (NFT ポジション記述契約)

  • NFTDescriptor (NFT 記述契約)

  • WETH9 (WrapperETH)

私たちの前の章では最初の 2 つの契約をデプロイしましたので、この章では残りの契約をデプロイし始める必要があります。実際、デプロイ方法は同じです。ただし、注意が必要なのは、NonfungibleTokenPositionDescriptorは Library リンクを行う必要があり、NFTDescriptorをデプロイした後に Library としてNonfungibleTokenPositionDescriptorにリンクする必要があります。次に、私たちはデプロイスクリプトをさらに改善し、これらの契約をすべてデプロイします。

完善部署脚本#

私たちはデプロイスクリプトをさらに改善し、前の章でデプロイした契約とこの章でデプロイする必要がある契約をすべてデプロイします。デプロイ方法は前の章と同じなので、00_deploy_univ3.tsにいくつかのコードを追加するだけで済みます。
しかし、私たちは WETH9 の契約も追加する必要があります。前の章では WETH9 の位置に 0 アドレスを直接使用しましたが、今はそれはできません。ですので、まずhttps://github.com/gnosis/canonical-weth/blob/master/contracts/WETH9.solの URL を開き、中のコードをコピーして、contracts フォルダの下に新しいWETH9.solファイルを作成し、コードを貼り付けます。それからyarn hardhat compileを実行して契約をコンパイルします。予想通り、エラーが発生します。

image

これは私たちのコンパイラのバージョンが正しくないためです。WETH9 の契約は>=0.4.22 <0.6のバージョンでコンパイルされているのに対し、私たちのデフォルトは^0.8.0のバージョンですので、コンパイラのバージョンを変更する必要があります。しかし、Hardhat の強力な機能のおかげで、複数のバージョンのコンパイラを設定できるため、私たちは複数のバージョンのコンパイラで契約をコンパイルできます。
私たちはhardhat.config.tsを開き、solidityの設定項目にcompilersの設定項目を追加し、それを配列として設定し、必要なコンパイラのバージョンを含めます。

const config: HardhatUserConfig = {
  solidity: {
    compilers: [
      {
        version: '0.8.0',
      },
      {
        version: '0.4.22',
      },
    ],
  },
};

変更が完了したら、再度コンパイルします。

image

修改 deploy 文件#

私たちは00_deploy_univ3.tsを開き、main関数にいくつかのコードを追加します。

import { utils } from 'ethers'
import { DeployFunction } from "hardhat-deploy/types";
import {
    abi as FACTORY_ABI,
    bytecode as FACTORY_BYTECODE,
} from '@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json'

import {
    abi as SWAP_ROUTER_ABI,
    bytecode as SWAP_ROUTER_BYTECODE,
} from '@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json'
import { HardhatRuntimeEnvironment } from "hardhat/types";

import {
    abi as NFTDescriptor_ABI, bytecode as NFTDescriptor_BYTECODE
} from '@uniswap/v3-periphery/artifacts/contracts/libraries/NFTDescriptor.sol/NFTDescriptor.json'

import {
    abi as NFTPositionManager_ABI, bytecode as NFTPositionManager_BYTECODE
} from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'

import {
    abi as NFTPositionDescriptor_ABI, bytecode as NFTPositionDescriptor_BYTECODE
} from '@uniswap/v3-periphery/artifacts/contracts/NonfungibleTokenPositionDescriptor.sol/NonfungibleTokenPositionDescriptor.json'


const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
    const { deployments, ethers } = hre
    const [deployer] = await ethers.getSigners()
    const factory = await deployments.deploy("UniV3Factory", {
        from: deployer.address,
        contract: {
            bytecode: FACTORY_BYTECODE,
            abi: FACTORY_ABI
        },
    })

    const WETH9 = await deployments.deploy("WETH9", {
        from: deployer.address
    })

    await deployments.deploy("UniV3SwapRouter", {
        from: deployer.address,
        contract: {
            abi: SWAP_ROUTER_ABI,
            bytecode: SWAP_ROUTER_BYTECODE
        },
        args: [factory.address, WETH9.address]
    })

    const NFTDescriptorlibrary = await deployments.deploy('NFTDescriptorLibrary', {
        from: deployer.address,
        contract: {
            abi: NFTDescriptor_ABI,
            bytecode: NFTDescriptor_BYTECODE
        }
    })

    const linkedBytecode = linkLibrary(NFTPositionDescriptor_BYTECODE,
        {
            ['contracts/libraries/NFTDescriptor.sol:NFTDescriptor']: NFTDescriptorlibrary.address
        }
    )

    const positionDescriptor = await deployments.deploy('NFTPositionDescriptor', {
        from: deployer.address,
        contract: {
            abi: NFTPositionDescriptor_ABI,
            bytecode: linkedBytecode
        },
        args: [
            WETH9.address,
            // 'ETH' as a bytes32 string
            '0x4554480000000000000000000000000000000000000000000000000000000000'
        ]
    })

    await deployments.deploy('NFTPositionManager', {
        from: deployer.address,
        contract: {
            abi: NFTPositionManager_ABI,
            bytecode: NFTPositionManager_BYTECODE
        },
        args: [factory.address, WETH9.address, positionDescriptor.address]
    })
}

function linkLibrary(bytecode: string, libraries: {
    [name: string]: string
} = {}): string {
    let linkedBytecode = bytecode
    for (const [name, address] of Object.entries(libraries)) {
        const placeholder = `__\$${utils.solidityKeccak256(['string'], [name]).slice(2, 36)}\$__`
        const formattedAddress = utils.getAddress(address).toLowerCase().replace('0x', '')
        if (linkedBytecode.indexOf(placeholder) === -1) {
            throw new Error(`Unable to find placeholder for library ${name}`)
        }
        while (linkedBytecode.indexOf(placeholder) !== -1) {
            linkedBytecode = linkedBytecode.replace(placeholder, formattedAddress)
        }
    }
    return linkedBytecode
}

export default func;

実際、上記の多くは繰り返しのコードですので、私たちは 2 つの内容に注目する必要があります。最初の部分はこのlinkLibrary関数です。

function linkLibrary(bytecode: string, libraries: {
    [name: string]: string
} = {}): string {
    let linkedBytecode = bytecode
    for (const [name, address] of Object.entries(libraries)) {
        const placeholder = `__\$${utils.solidityKeccak256(['string'], [name]).slice(2, 36)}\$__`
        const formattedAddress = utils.getAddress(address).toLowerCase().replace('0x', '')
        if (linkedBytecode.indexOf(placeholder) === -1) {
            throw new Error(`Unable to find placeholder for library ${name}`)
        }
        while (linkedBytecode.indexOf(placeholder) !== -1) {
            linkedBytecode = linkedBytecode.replace(placeholder, formattedAddress)
        }
    }
    return linkedBytecode
}

この関数の役割は、ファイル内のlibraryを Bytecode にリンクすることですが、一般的にはこの方法を採用することはありません。なぜなら、ソースコードをデプロイする際に、ツールを利用してこのプロセスを簡素化できるからです。また、libraryは契約のバイトコードを大幅に削減する非常に効果的な方法であり、今後の文章でこの問題について詳しく説明します。2 つ目の部分はこのNFTDescriptorlibraryのデプロイです。

const linkedBytecode = linkLibrary(NFTTokenPositionDescriptor_BYTECODE,
    {
        ['contracts/libraries/NFTDescriptor.sol:NFTDescriptor']: NFTDescriptorlibrary.address
    }
)

const positionDescriptor = await deployments.deploy('NFTPositionDescriptor', {
    from: deployer.address,
    contract: {
        abi: NFTPositionDescriptor_ABI,
        bytecode: linkedBytecode
    },
    args: [
        WETH9.address,
        // 'ETH' as a bytes32 string
        '0x4554480000000000000000000000000000000000000000000000000000000000'
    ]
})

ここでは、linkLibrary関数を利用して、NFTDescriptorのアドレスをNFTTokenPositionDescriptorの Bytecode にリンクしています。

部署合约#

ここまで来たら、私たちはデプロイスクリプトに問題がないか確認できます。yarn hardhat deployを実行し、すべてが順調であれば、以下の出力が表示されます。

Nothing to compile
No need to generate any newer typings.
  Done in 1.45s.

簡単に言うと、特に出力はありません。もしここでエラーが発生した場合、私たちのデプロイスクリプトに問題があることを示しています。誰かが疑問に思うかもしれませんが、ここで何のパラメータも入力していないのに、私の契約は一体どこにデプロイされたのでしょうか?実際、私たちがデプロイスクリプトを直接実行すると、デフォルトでローカルネットワークにデプロイされます。また、yarn hardhat nodeを使用してローカルネットワークを起動することもできます。しかし、私たちはローカルネットワークを起動していないため、デプロイ時に自動的にローカルネットワークが起動され、デプロイが完了すると自動的にこのネットワークが閉じられます。したがって、私たちはほとんどフィードバックを目にすることはありませんが、フィードバックがないということは、実際には最良のフィードバックです。

结语#

この章では、UniswapV3 を完全にデプロイしました。このデプロイがあれば、今後の章でいくつかのテストを行うことができます。もちろん、能力のある方はこの上で初歩的な契約開発作業を行うこともできます。しかし、私はこの方法をあまりお勧めしません。なぜなら、この方法では契約がエラーを起こした場合、行単位でのデバッグができないからです。しかし、この問題については今後の章で解決します。次の章では、Uniswap のフロントエンドをデプロイしてテストを行います。

文章首发于: ee.web3box.dev
作者:https://twitter.com/BoxMrChen
SafeHouseDAO出品

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。