Remix에서는 배포를 테스넷이나 메인넷에서 쉽게 가능하다. 하지만 항상 메인넷이나 테스넷에 배포를 하고싶지 않다. 로컬에서 테스트를 마친 후 마지막 버전을 배포를 하고 싶을 수 있다. 또한 구체적으로 코드가 동작하는지 알아보고 싶을 수 있다. 체인링크 문서 같은 예가 있다. Mock을 이용해 가능하다.
FundMe.sol
AggregatorV3Interface public priceFeed;
constructor(address priceFeedAddress){
i_owner = msg.sender;
priceFeed = AggregatorV3Interface(priceFeedAddress);
}
function fund() public payable{
require(msg.value.getConversionRate(priceFeed) >= MINIMUM_USD, "Didn't send enough!"); // 1e18 == 1 * 10 ** 18
funders.push(msg.sender);
addressToAmountFunded[msg.sender] = msg.value;
}
구조체에 priceFeedAddress
를 파라미터에 넣어주고 priceFeed
를 AggregatorV3Interface
타입으로 전역변수화 해준다. getConversionRate
함수에 통과시킨다.
priceConverter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
library PriceConverter {
function getPrice(AggregatorV3Interface priceFeed)
internal
view
returns (uint256)
{
(, int256 price, , , ) = priceFeed.latestRoundData();
return uint256(price * 1e10);
}
function getConversionRate(
uint256 ethAmount,
AggregatorV3Interface priceFeed
) internal view returns (uint256) {
uint256 ethPrice = getPrice(priceFeed);
uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1e18;
return ethAmountInUsd;
}
}
getConversionRate
두번째 파라미터에 넣어주고 getPrice
함수에 통과시킨다. 이제 컴파일이 가능하다.
실제로 나머지를 배포하자.
01-deploy-fund-me.js
module.exports = async ({ getNamedAccounts, deployment }) => {
const { deploy, log } = deployments
const { deployer } = await getNamedAccounts()
const chainId = network.config.chainId
const fundMe = await deploy("FundMe", {
from: deployer,
args: [],
log: true,
})
}
arg에 priceFeedAddress에 넣어줘야한다. 실제로 주소를 하드코딩하는대신 chianId가 이용하는 주소를 이용한다.
루트에 helper-hardhat-config.js을 추가한다.
helper-hardhat-config.js
const networkConfig = {
5: {
name: "goreli",
ethUsdPriceFeed: "0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e"
},
}
module.exports = {
networkConfig,
}
goreli
은 체인아이디로 5를 쓴다. 모듈화한다.
01-deploy-fund-me.js
const {networkConfig} = require("../helper-hardhat-config")
const {network} = require("hardhat")
module.exports = async ({ getNamedAccounts, deployment }) => {
const { deploy, log } = deployments
const { deployer } = await getNamedAccounts()
const chainId = network.config.chainId
const ethUsdPriceFeedAddress = networkConfig[chianId]["etherUsdPriceFeed"]
const fundMe = await deploy("FundMe", {
from: deployer,
args: [],
log: true,
})
}
networkConfig
를 임포트하고 ethUsdPriceFeedAddress에 주소값을 가져온다.
yarn hardhat deploy --network goreli
터미널에 입력하면 goerli pricefeedaddress를 이용한다.
pricefeedaddress가 없는 체인을 사용하기 위해 mockcontract를 이용한다.
00-deploy-fund-me.js를 deploy폴더안에 만들어 준다.
const { network } = require("hardhat")
module.exports = async ({ getNamedAccounts, deployment }) => {
const { deploy, log } = deployments
const { deployer } = await getNamedAccounts()
const chainId = network.config.chainId
}
contracts/
test/
mockV3Aggregator.sol
프로젝트에서 분리하기 위해 test폴더안에 파일을 만들어준다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "@chainlink/contracts/src/v0.6/tests/MockV3Aggregator.sol";
chianlink깃헙에 있는 MockV3Aggregator.sol
을 그대로 이용해준다.
The Solidity version pragma statement in these files doesn't match any of the configured compilers in your config. Change the pragma or configure additional compiler versions in your hardhat config.
* contracts/test/mockV3Aggregator.sol (^0.6.0)
* @chainlink/contracts/src/v0.6/tests/MockV3Aggregator.sol (^0.6.0)
* @chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol (^0.6.0)
* @chainlink/contracts/src/v0.6/interfaces/AggregatorInterface.sol (^0.6.0)
* @chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol (^0.6.0)
require("@nomicfoundation/hardhat-toolbox")
require("hardhat-deploy")
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: {
compilers: [{ version: "0.8.8" }, { version: "0.6.6" }],
},
defaultNetwork: "hardhat",
namedAccounts: {
deployer: 0,
},
user: {
default: 1,
},
}
컴파일을 하면 에러가 발생한다. 버전이 다르기 때문에 발생한다. 위와 같이 다수의 버전 추가가 가능하다. 컴파일이 가능하다. 어떻게 배포를 해야할까?
FundMe 컨트렉트 배포와 흡사하다. 테스넷이나 pricefeed를 가진 실제 넷워크에 배포를 하고 싶지는 않다.
helper-hardhat-config.js
const developmentChains = ["hardhat", "localhost"]
const DECIMALS = 8
const INITIAL_ANSWER = 20000000000
module.exports = {
networkConfig,
developmentChains,
DECIMALS,
INITIAL_ANSWER
}
목에서 사용할 체인을 구체적으로 명시하고 모듈에 추가한다.
const { network } = require("hardhat")
const {
developmentChains,
DECIMALS,
INITIAL_ANSWER
} = require("../helper-hardhat-config")
module.exports = async ({ getNameAccounts, deployments }) => {
const { deploy, log } = deployments
const { deployer } = await getNamedAccounts()
if (developmentChains.includes(network.name)) {
log("Local network detected! Deploying mocks..")
await deploy("MockV3Aggregator", {
contract: "MockV3Aggregator",
from: deployer,
log: true,
args: [DECIMALS, INITIAL_ANSWER],
})
log("Mocks deployed!")
log("--------------------------------------------------------------")
}
}
module.exports.tags = ["all", "mocks"]
network.name으로 조건을 검증한다.
yarn hardhat deploy --tags mocks
--tags를 이용하여 mocks만 deploy하게 한다.
이제 이것을 deploy FundMe script에 적용시킬 차례이다.
const {networkConfig, developmentChains} = require("../helper-hardhat-config")
const { network } = require("hardhat")
module.exports = async ({ getNamedAccounts, deployment }) => {
const { deploy, log } = deployments
const { deployer } = await getNamedAccounts()
const chainId = network.config.chainId
// const ethUsdPriceFeedAddress = networkConfig[chianId]["etherUsdPriceFeed"]
let ethUsdPriceFeedAddresss
if (developmentChains.includes(network.name)) {
const ethUsdAggregator = await deployments.get("MockV3Aggregator")
ethUsdPriceFeedAddresss = ethUsdAggregator.address
} else {
ethUsdPriceFeedAddresss = networkConfig[chainId]["ethUsdPriceFeed"]
}
const fundMe = await deploy("FundMe", {
from: deployer,
args: [ethUsdPriceFeedAddresss],
log: true,
})
}
module.exports.tags = ["all", "fundme"]
yarn hardhat deploy