* smart contract 기반의 token 기능을 하는 contract를 만들어볼 예정
1. Token contract 작성
2. Token contract 배포
3. Token contract 테스트
Token (smart contract based)
--> native token과는 다르지만 비슷하게 기능하는 것을 구현하기..?
native token 이란?
ex) BTC, ETH.. 등등
해당 네트워크에서 발생한 수수료는 native token으로만 받는다.
contract 폴더 > MyToken.sol 파일 생성
// SPDX-License-Identifer: MIT
// 라이센스 정책 기입 (위에는 주석상태 그대로 기입함!)
// pragma = 컴파일러에게 알려주는 내용
pragma solidity ^0.8.28;
//class
contract MyToken {
string public name;
string public symbol;
uint8 public decimals; // 1wei --> 1 * 10^-18 ETH 소수점 자리 지원하는 범위 알려줌
//uint = 음수x 8= 8bit ==> unsigned 8bit int. uint16, uint256....
//생성자
// uint8 의 경우 길이 알고있음 (지정되어있음)
// string은 길이 제한x ==> memory를 사용해서 string을 복사해라 지정? (+@)
constructor(string memory _name, string memory _symbol, uint8 _decimals) {
name = _name;
symbol = _symbol;
decimals = _decimals;
// 변수 이름이 같으면 contract의 필드를 우선 인식한다고 함
// 혼동 방지를 위해 언더바 사용
}
}
memory가 뭐하는 걸까
Solidity의 메모리 구조 (추후첨부)
name, symbol, decimals
name : 토큰 이름 (ex. Ether)
symbol : 화폐 기호 (ex. ETH --> 6ETH, 16ETH...)
decimal : 값으로 유효한 소수점 n째 자리 (ex. ETH는 18)
(ex. decimal이 1인 경우 --> 0.1까지만 유효, 0.01은 무의미)
변수 이름 인식 우선순위는 다른 프로그래밍 언어랑 좀 다른 것 같다...
보통은 매개변수 우선이라 this 같은 걸로 멤버변수(필드에 위치함)는 따로 지정해줘야 하지 않나..?
하여튼 작성 후
npx hardhat compile
터미널에 실행
Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: \" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.
--> contracts/MyToken.sol
Generating typings for: 1 artifacts in dir: typechain-types for target: ethers-v6 Successfully generated 6 typings! Compiled 1 Solidity file successfully (evm target: paris).
경고가 뜨지만 괜찮다고 하고..

이렇게 뭔가 더 생긴 것을 볼 수 있다.
(typechain-types, bulid-info, contracts/MyToken.sol폴더 등등...)
contracts/MyToken.sol/MyToken.json
여기에 가면 컴파일 결과가 bytecode로 나온다
(자바도 컴파일하면 bytecode로 나옴)
typechain-types/factories
배포, 테스트에 관련된 코드들이 자동으로 생성된다 (이거 사용해서 배포,테스트 할 예정)
ignition/modules 폴더 > MyToken.ts 파일 생성.
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
// 빌드 모듈 가져오기 --> nomic...에서
// buildModule (모듈id, 모듈 정의 함수 입력받음)
export default buildModule("MyTokenDeploy", (m) => {
const MyTokenC = m.contract("MyToken", ["MyToken", "MT" , 18])
return { MyTokenC };
// 오브젝트로 감싸서 리턴해줘야 한다?
})
+@.. 오브젝트로 감싼다는게...? 뭔지 모르겠다..
npx hardhat ignition deploy ignition/modules/MyToken.ts
You are running Hardhat Ignition against an in-process instance of Hardhat Network.
This will execute the deployment, but the results will be lost.
You can use --network \ to deploy to a different network.Hardhat Ignition 🚀
Deploying [ MyTokenDeploy ]
Batch #1
Executed MyTokenDeploy#MyToken[ MyTokenDeploy ] successfully deployed 🚀
Deployed Addresses
MyTokenDeploy#MyToken - 0x5FbDB2315678afecb367f032d93F642f64180aa3
마지막이 smartcontract가 배포된 주소 (찾아가는데 필요)
npx hardhat node
nvm use v20.11.0 하고
npx hardhat ignition deploy ignition/modules/MyToken.ts --networkd localhost
로 로컬호스트로 해도 동일하게 배포되고
어떤 상호작용으로 배포했는지 node에 뜨는 걸로.. 볼 수 있다고..
test 폴더 > MyToken.ts 파일 생성.
보통 contract와 test 파일 이름은 같게 한다 (배포는 케바케)
import hre from "hardhat";
//hardhat runtime environment ..!
describe("mytoken deploy", () => {
it("should deploy", async () => {
const myTokenC = (await) hre.ethers.deployContract("MyToken", [
"MyToken",
"MT",
18,
]);
// 일반 hardhat에 없고 hardhat-ethers에 있는 기능임
// 알아서 컴파일 결과에서 배포할 contract를 받아온다 (hardhat ethers가)
console.log(await myTokenC.name());
});
});
해당 코드에는 await 부분에 괄호가 쳐져있다 (안넣고 실행시켰음)
npx hardhat test
그래서 위의 코드로 실행을 해도
mytoken deploy
Promise { <pending> } <-- promise만 나옴
✔ should deploy (2471ms)1 passing (2s)
이렇게 promise가 나온다
저 deployContract가 비동기함수(시간걸리니까 일단 promise 주고 다음거 먼저 넘어가는 함수)라서, 기다리지 않고 (await없이) 그냥 받으면 promise가 나온다
비동기함수에 대해 좀 더 알아보고
블록체인 기본 개념 정리... 는 따로 해둬야겠다 (추후첨부)
import hre from "hardhat";
//hardhat runtime environment ..!
describe("mytoken deploy", () => {
it("should deploy", async () => {
const myTokenC = await hre.ethers.deployContract("MyToken", [
"MyToken",
"MT",
18,
]);
// 일반 hardhat에 없고 hardhat-ethers에 있는 기능임
// 알아서 컴파일 결과에서 배포할 contract를 받아온다 (hardhat ethers가)
console.log(await myTokenC.name());
});
});
await 잘 써주면~
mytoken deploy
MyToken
✔ should deploy (6524ms)1 passing (7s)
잘 나와준다
각각 목표한 게 잘 나오는지 테스트..? 하는 코드
import hre from "hardhat";
import { expect } from "chai";
import { MyToken } from "../typechain-types";
// hardhat에서 컴파일 할 때 필요한 타입 정의 파일을 여기에 보관함
// 타입 작성하면 요 코드는 알아서 채워줌
describe("mytoken deploy", () => {
let myTokenC: MyToken; //변수로 선언
// 타입 지정이 되어있지 않을 시 --> 타입스크립트에서 에러로 표시함
// 이 그룹(describe)을 실행하기 전에 실행시킨다
// 미리 실행 --> let myTokenC에 의해 변수로 저장
// 그러면 아래 테스트 코드에서도 myTokenC를 사용 가능함
before("should deploy", async () => {
myTokenC = await hre.ethers.deployContract("MyToken", [
"MyToken",
"MT",
18,
]);
});
it("should return name", async () => {
expect(await myTokenC.name()).equal("MyToken");
});
it("should return symbol", async () => {
expect(await myTokenC.symbol()).equal("MT");
});
it("should return decimals", async () => {
expect(await myTokenC.decimals()).equal(18);
});
});
아까와 똑같이 npx~~ 치면
mytoken deploy
✔ should return name (50ms)
✔ should return symbol (45ms)
✔ should return decimals3 passing (3s)
역시 잘 나온다~!