하드햇(Hardhat)
트러플과 유사한 이더리움 기반 스마트 컨트랙트 개발 도구
자바스크립트 기반으로 자유도가 높고 유연한 개발 환경을 제공
스마트 컨트랙트에서 console.log를 사용하여 값을 출력할 수 있는 기능도 제공
Ganache같은 가상 이더리움 제공
web3.js대신 ethers.js 사용
오픈제펠린의 Upgrades
수정 가능한 "Upgradable" 컨트랙트를 쉽게 작성하고 배포할 수 있도록 개발도구와 함께 쓸 수 있는 플러그인
트러플과 하드햇에서 사용할 수 있는 플러그인
하드햇 설치
글로벌 패키지로 설치하지 않음 (-g)
yarn, npx 사용
cd mydapp
yarn init -y
yarn add hardhat --dev
npx hardhat help
하드햇 프로젝트 폴더
npx hardhat // "sample project" 선택
mydapp
-- artifacts // 컴파일 결과물
-- cache
-- contracts // 컨트랙트
-- scripts // 배포 등의 실행 스크립트
-- test // 단위테스트
-hardhat-config.js // 개발환경 설정
하드햇 플러그인
모든 작업들이 플러그인 기반으로 이루어짐
기본적으로 설치해야 할 플러그인 🔽
yarn add
// 단위테스트 플러그인
@nomiclabs/hardhat-waffle
ethereum-waffle
chai
// ethers.js 이더리움 웹 라이브러리
@nomiclabs/hardhat-ethers
ethers
--dev
// 오픈제펠린 Upgradable 컨트랙트 플러그인
yarn add @openzeppelin/hardhat-upgrades --dev
하드햇 명령어 확인
npx hardhat help
하드햇 주요 Task(명령어)
npx hardhat compile
npx hardhat test --netwowrk rinkeby ./test/mytest.js
npx hardhat run --network rinkeby ./scripts/mydeploy.js
npx hardhat console --network rinkeby
hardhat.config.js
accounts라는 task 정의
// require("@nomicfoundation/hardhat-toolbox");
require("@nomiclabs/hardhat-waffle");
task("accounts", "Prints the list of accounts", async () => {
const accounts = await ethers.getSigners();
for (const account of accounts) {
console.log(account.address)
}
})
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.15",
};
*업그레이더블 컨트랙트는 constructor 생성자 함수를 쓰지 않는다.
accounts task 실행
npx hardhat accounts // 계정확인
SimpleStorageUpgrade.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;
import "hardhat/console.sol";
contract SimpleStorageUpgrade {
uint storedData;
event Change(string message, uint newVal);
function set(uint x) public {
// console.log("The value is %d", x);
require(x < 5000, "Should be less than 5000");
storedData = x;
emit Change("set", x);
}
function get() public view returns (uint) {
return storedData;
}
}
단위 테스트
SimpleStorageUpgrade.test.js
const hre = require("hardhat");
const {exprect, expect} = require("chai");
describe ("SimpleStorageUpgrade", function() {
const wallets = waffle.provider.getWallets();
before(async () => {
const signer = waffle.provider.getSigner();
const SimpleStorageUpgrade = await hre.artifacts.readArtifact("SimpleStorageUpgrade");
this.instance = await waffle.deployContract(signer, SimpleStorageUpgrade);
});
it("should change the value", async () => {
const tx = await this.instance.connect(wallets[1]).set(500);
const v = await this.instance.get();
expect(v).to.be.equal(500);
});
// revert reason
it("sould revert", async() => {
await expect(this.instance.set(6000))
.to.be.revertedWith("Should be less than 5000");
});
})
npx hardhat test ./test/SimpleStorageUpgrade.test.js
오픈제펠린 업그레이드 플러그인 추가
- hardhat-config.js에 오픈제펠린 업그레이드 플러그인 추가
require("@openzeppelin/hardhat-upgrades");
- 배포 스크립트 작성 (SimpleStorageUpgrades.deploy.js)
const hre = require("hardhat");
async function main() {
//TODO
const SimpleStorageUpgrade = await hre.ethers.getContractFactory("SimpleStorageUpgrade")
const ssu = await upgrades.deployProxyy(SimpleStorageUpgrade, [500], { initializer: 'set' }); // 초기값 지정
console.log("SimpleStorageUpgrade deployed to:", ssu.address);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
- upgrades.deployProxy를 사용하여 배포
npx hardhat node // 가나슈처럼
npx hardhat run --network localhost .\\scripts\\SimpleStorageUpgrades.deploy.js
노드 콘솔에서
> const f = await ethers.getContractFactory("SimpleStorageUpgrade") // 컨트랙트 인스턴스 생성
> const ssu = await f.attach("0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0") // 배포 주소에 attach
> ssu.address
> (await ssu.get()).toString() // '500' 출력
> let tx = await ssu.set(1000) // 값 변경
> (await ssu.get()).toString() // '1000' 출력
컨트랙트 내용 바꾸기
SimpleStorageUpgradeV2.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;
import "hardhat/console.sol";
contract SimpleStorageUpgrade {
uint storedData;
uint storedKey;
event Change(string message, uint newVal);
function set(uint x) public {
// console.log("The value is %d", x);
require(x < 10000, "Should be less than 5000");
storedData = x;
emit Change("set", x);
}
function get() public view returns (uint) {
return storedData;
}
function setKey(uint key) public {
storedKey = key;
}
function getKey() public view returns (uint) {
return storedKey;
}
}
SimpleStorageUpgradesV2.deploy.js
const hre = require("hardhat");
async function main() {
const proxyAddress = "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0";
const SimpleStorageUpgradeV2 = await hre.ethers.getContractFactory("SimpleStorageUpgradeV2");
const ssu2 = await upgrades.upgradeProxy(proxyAddress, SimpleStorageUpgradeV2); // 초기값 지정
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
'블록체인' 카테고리의 다른 글
[블록체인] 이더리움 & 솔리디티 기반의 투표 dApp 구현하기 (0) | 2022.09.01 |
---|---|
[블록체인] Klaytn 클레이튼 블록체인 어플리케이션 만들기 - 이론과 실습 (2) | 2022.08.31 |
[블록체인] 솔리디티(Solidity) 문법 총정리 (0) | 2022.08.30 |
[블록체인] 이더리움 입문 바이블 (0) | 2022.08.29 |
[블록체인] 블록체인과 클레이튼 (0) | 2022.08.28 |