[0x01] Web3 App w/ Solidity, Ether Smart Contract
[0x00] 스마트 컨트랙트 작성과 로컬 이더리움 네트워크에 배포하기
0x00: 환경 셋업
<로컬 이더리움 네트워크>
- 일단 시작하기에 앞서
로컬 이더리움 네트워크를 세팅한다.
- 이를 통해, 앞으로 만들
스마트 컨트랙트 코드에 대해 컴파일, 테스트 등을 해볼 수 있다.
스마트 컨트랙트란 블록체인 상에 있는 코드 조각으로 기억하면 된다.
블록체인이란 누구나 안전하게 정보를 읽고 쓸 수 있는 공간이다.
- AWS 같은 네트워크지만, 누구의 소유도 아닌 네트워크라 생각하면 된다.
- 본 튜토리얼의 전체적인 로드맵은 아래와 같다.
스마트 컨트랙트를 작성한다.
- 서버의 코드와 같이 생각하면 된다.
- 작성한
스마트 컨트랙트를 블록체인 상에 배포(deploy)한다.
- 전 세계 누구든 우리로부터 허용되었다면
스마트 컨트랙트에 접근하고 실행시킬 수 있다.
클라이언트 웹사이트를 만든다.
- 일반 유저들이 우리의
스마트 컨트랙트와 쉽게 상호작용 할 수 있도록 한다.
- 이 튜토리얼에서 궁극적으로 만들고자 하는 것은 본인에게 누군가
안녕이라고 인사해주는 웹사이트를 만드는 것이다!
0x01: Hardhat
hardhat이라는 툴을 통해, 로컬 이더리움 네트워크환경을 만들 수 있으며 fake 이더리움, fake 계정등을 이용해 테스트도 진행할 수 있다.
- 튜토리얼 내내 이용하는
서버가 블록체인임을 기억하도록 하자.
- 또한,
hardhat을 통해 스마트 컨트랙트를 컴파일하는 것이 가능하다. 로컬 이더리움 네트워크에서 이를 테스트할 수도 있다.
hardhat을 이용하기 위해서는 node/npm이 필요하다.
- 설치에 관한 내용은 따로 다루도록 한다.
- 메모를 해두자면, Node.js 를 그냥 받으면 LTS가 아니라서 경고 메세지가 뜨기도 한다... 이를 해결하는 방법을 찾느라 나름 시간을 날렸으므로, 꼭 정리해둘 예정이다.
- 본 튜토리얼에서는
my-wave-portal 이라는 작업 디렉토리를 따로 만들어 진행하도록 한다.
npm의 설치가 완료되었으면 아래 코드를 입력해 튜토리얼을 진행한다.
mkdir my-wave-portal
cd my-wave-portal
npm init -y
npm install --save-dev hardhat
0x02: 샘플 프로젝트
hardhat을 설치 완료한 후 샘플 프로젝트를 받는 작업을 진행한다.
- 아래와 같이 입력한다.
npx hardhat

- 첫 번째 선택지인
Create a basic sample project를 선택하면 몇 가지를 더 묻는데 모두 Enter키로 넘기면 아래와 같이 설치되는 과정이 나온다.


- 잠시 후
Project created라는 문구와 함께 샘플 프로젝트가 완성된 것을 확인할 수 있다.

- 이후
hardhat-waffle과 hardhat-ethers를 추가로 설치해야 한다. 아래의 명령을 입력하면 된다.
npm install --save-dev @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers
- 설치가 완료되었으면, 아래의 명령어를 실행한 뒤 결과를 확인할 수 있다.
npx hardhat accounts

- 위 사진의 결과는
hardhat이 생성한 이더리움 주소 이다.
- 블록체인 상에서의 유저들로 생각하고
테스트에 활용할 수 있다.
- 예시)
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (첫 번째 주소)가 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 (두 번째 주소)에게 0.1 ETH를 보낸다.
0x03: 실행하기
- 실행하기 위해서는 아래 명령들을 실행하면 된다.
npx hardhat compile
npx hardhat run

- 이후 튜토리얼 단계에서는 코드를 완전히 새로 작성할 예정이다.
- 따라서,
scripts, contract, test 디렉토리에 있는 모든 파일들을 지우도록 한다.
0x04: 스마트 컨트랙트 작성
- 사이트 상에 나한테 인사해주는 기능과 인사를 받은 횟수를 저장해두는 것을 구현할 예정이다.
contract 디렉토리에 WavePortal.sol이라는 이름으로 솔리디티 파일을 하나 만든다.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;
import "hardhat/console.sol";
contract WavePortal {
constructor() {
console.log("Yo yo, I am a contract and I am smart");
}
}
- 코드를 하나 하나 살펴보면 다음과 같다.
// SPDX-License-Identifier: UNLICENSED
- 라이센스 (저작권) 에 관한 내용이다.
- Ref. https://devocean.sk.com/opensource/techBoardDetail.do?ID=159339
pragma solidity ^0.8.4;
- 우리의
스마트 컨트랙트가 이용할 컴파일러의 버전을 명시한다.
- 중요 :
hardhat.config.js에 명시된 것과 동일한 버전을 사용해야 한다.
import "hardhat/console.sol";
console log에 관한 코드를 import한다.
hardhat에서는 스마트 컨트랙트를 쉽게 디버깅할 수 있도록 console log를 사용할 수 있는 코드를 제공한다.
contract WavePortal {
constructor() {
console.log("Yo yo, I am a contract and I am smart");
}
}
스마트 컨트랙트의 구현에 대한 내용이다.
스마트 컨트랙트(=컨트랙트)는 다른 언어에서의 클래스와 상당히 비슷하게 보인다.
- 이
컨트랙트를 초기화 하면, constructor(생성자)가 호출되며 console을 통해 문장을 출력할 것이다.
0x05: 로컬 테스트 블록체인 환경 만들기
스마트 컨트랙트를 작성하였으므로, 아래 세 단계를 거쳐 이를 실행해 볼 수 있다.
컨트랙트를 컴파일한다.
로컬 블록체인 네트워크에 컴파일 된 컨트랙트를 배포(deploy) 한다.
블록체인 네트워크 상의 컨트랙트를 호출하면 console.log()가 실행된다.
- 실제
블록체인에서도 컨트랙트는 네트워크상에 존재하며, 이를 누군가 호출하는 방식으로 동작한다.
- 기술적으로, 단순히
컨트랙트를 컴파일하고 실행하는 것은 가능하다.
- 하지만,
Solidity가 블록체인 네트워크, 그리고 이더리움 지갑(wallet)과 어떻게 상호작용 할 수 있는지를 이해하는 것이 중요하다.
- 따라서,최대한 실제 환경을 모방(imitate)하여 상기한 세 단계를 실습해보도록 한다.
0x06: 컨트랙트 실행 스크립트(run.js) 작성
scripts 디렉토리에 run.js라는 자바스크립트 파일을 만든다.
컨트랙트를 실행하기 위해서는 컴파일, 배포, 실행 세 가지를 해야 한다.
- 스크립트 작성을 통해 상기한 세 가지를 손쉽게 수행할 수 있다.
const main = async () => {
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
const waveContract = await waveContractFactory.deploy();
await waveContract.deployed();
console.log("Contract deployed to:", waveContract.address);
};
const runMain = async () => {
try {
await main();
process.exit(0); // exit Node process without error
} catch (error) {
console.log(error);
process.exit(1); // exit Node process while indicating 'Uncaught Fatal Exception' error
}
// Read more about Node exit ('process.exit(num)') status codes here: https://stackoverflow.com/a/47163396/7974948
};
runMain();
0x07: 스크립트 코드(run.js) 분석
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
컨트랙트를 컴파일하고 artifacts/ 디렉토리에 컨트랙트를 다루기 위해 필요한 파일들을 생성한다.
const waveContract = await waveContractFactory.deploy();
deploy()메서드를 통해, hardhat은 로컬 이더리움 네트워크를 만든다.
- 그러나, 이 때 만들어진
로컬 이더리움 네트워크는 스크립트의 실행이 끝나면 삭제된다.
- 따라서,
컨트랙트를 실행할 때 마다 네트워크를 초기 상태로 다룰 수 있고, 이는 디버깅 등에 유용하다.
await waveContract.deployed();
컨트랙트가 블록체인 네트워크상에 잘 배포될 때까지 기다린다.
배포가 완료되면, constructor()가 실행된다.
console.log("Contract deployed to:", waveContract.address);
배포가 되면 블록체인 네트워크상의 컨트랙트의 주소를 받을 수 있다.
- 실제
블록체인 네트워크상에는 무수히 많은 컨트랙트들이 배포되어 있고, 주소를 통해 우리가 배포한 컨트랙트를 찾아서 사용할 수 있다.
- 이제
스크립트를 실제로 실행해보자.
npx hardhat run scripts/run.js

0x08: Hardhat & HRE
- 스크립트 코드에서, 반복적으로
hre.ethers를 사용하고 있다.
- 공식 문서에 나온
HRE에 관한 설명은 아래와 같다.
hre는 Hardhat Runtime Environment를 의미하며 일종의 객체(object)이다.
hardhat이 작업, 테스트 또는 스크립트를 실행할 때 표시하는 모든 기능을 포함한다.
- 따라서,
Hardhat은 HRE이다.
- 즉,
npx hardhat으로 시작되는 명령을 터미널에서 입력할 때마다, 코드에 지정된 hardhat.config.js를 사용해서 이 hre라는 객체를 즉시 만들 수 있다.
- 쉽게 말해, 코드를 작성할 때 아래와 같이 할 필요가 없다.
const hre = require("hardhat");
0x09: 데이터 저장하기
컨트랙트에 데이터를 저장할 수 있다.
- 본 튜토리얼에서 구현하고자 하는 컨트랙트는 누군가로부터 인사를 받는 것이고, 이를
함수로 구현할 수 있다.
- 이 떄,
함수 내에 인사에 대한 정보를 저장하도록 한다.
블록체인 네트워크를 클라우드 서버처럼 생각하면 편하다.
- 이
서버를 유지하는 전 세계의 수 많은 사람들을 보통 채굴자(miner)라고 부른다.
- 우리는
블록체인 네트워크의 코드를 실행하기 위해서 이런 채굴자들에게 값을 지불하는 것이다.
- 같은 맥락으로,
스마트 컨트랙트는 서버 상의 프로그램 코드라 생각하면 편하다.
- 즉, 누구나
서버 상에 존재하는 프로그램을 실행할 수 있는 것이다.
- 앞서 작성한 컨트랙트를 수정하면 아래와 같다.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;
import "hardhat/console.sol";
contract WavePortal {
uint256 totalWaves;
constructor() {
console.log("Yo yo, I am a contract and I am smart");
}
function wave() public {
totalWaves += 1;
console.log("%s has waved!", msg.sender);
}
function getTotalWaves() public view returns (uint256) {
console.log("We have %d total waves!", totalWaves);
return totalWaves;
}
}
- 코드를 하나씩 살펴보도록 한다.
uint256 totalWaves;
컨트랙트 상에 저장되는 상태 변수(state variable)로, 블록체인상에 기록된다.
- 즉,
컨트랙트와 마찬가지로 한 번 블록체인에 기록되면 영원히 존재한다.
function wave() public {
totalWave += 1;
console.log("%s has waved!", msg.sender);
}
함수를 선언했다.
public 키워드는 이 함수가 누구나 호출할 수 있음을 의미한다.
totalWaves += 1; 는 산술 연산이 다른 언어들과 크게 다르지 않음을 보여준다.
- 주목해야 할 점은
msg.sender에 관한 것이다.
- 여기서
msg.sender는 이 컨트랙트를 호출한 사람의 지갑 주소(wallet address)이며, 빌트인 인증(built-in authentication)과도 같다.
스마트 컨트랙트를 호출할 때에도 유효한 지갑이 필요함 반드시 필요하기 때문에,
우리는 이를 통해 누가 이 컨트랙트를 호출했는지 알 수 있다.
- 이를 응용하면, 특정인만
컨트랙트를 호출하도록 할 수 있다.
function getTotalWaves() public view returns (uint256) {
console.log("We have %d total waves!", totalWaves);
return totalWaves;
}
view는 이 함수에서 state variable을 읽기만 하고 쓰기는 하지 않음을 명시한다.
return 값을 지정하는 방식이 조금 특이하다.
함수의 바디가 시작되기 직전에 returns라는 키워드와 그 뒤에 (_type_)형태로 자료형을 명시한다.
0x0A: 함수 호출을 위해 run.js 업데이트
- 우리가 만든
함수들을 호출하기 위해 run.js를 다시 수정할 필요가 있다.
- 기본적으로,
public 키워드를 사용한 함수들은 블록체인에 배포된 뒤 사용할 수 있게 된다.
public API endpoint를 생각하면 편하다.
- 새로 추가된 코드들에 대해서 주석을 달아 두도록 하겠다.
const main = async () => {
// getSigners()
const [owner, randomPerson] = await hre.ethers.getSigners();
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
const waveContract = await waveContractFactory.deploy();
await waveContract.deployed();
// logs
console.log("Contract deployed to:", waveContract.address);
console.log("Contract deployed by:", owner.address);
// counts the wave using getTotalWaves() from our contract
let waveCount = await waveContract.getTotalWaves();
// call wave()
let waveTxn = await waveContract.wave();
await waveTxn.wait();
// grab the waveCount one more to see if it changed
waveCount = await waveContract.getTotalWaves();
};
const runMain = async () => {
try {
await main();
process.exit(0);
} catch (error) {
console.log(error);
process.exit(1);
}
};
runMain();
0x0B: 스크립트 코드(updated run.js) 분석
const [owner, randomPerson] = await hre.ethers.getSigners();
블록체인에 어떤 것이든 배포하기 위해서는 유효한 지갑 주소가 필요하다.
hardhat은 백그라운드에서 이것을 알아서 처리해주지만, 이 코드에서는 명시적으로 지갑 주소를 가져오고 있다.
getSigners() 함수는 npx hardhat accounts로 확인했던 지갑들을 반환한다.
console.log("Contract deployed by:", owner.address);
컨트랙트를 배포한 사람이 누구인지 확인할 수 있다.
let waveCount = await waveContract.getTotalWaves();
let waveTxn = await waveContract.wave();
await waveTxn.wait();
waveCount = await waveContract.getTotalWaves();
- 보통
API들을 사용하는 것과 같이, 여기서도 함수들을 하나 하나 호출해야 한다.
컨트랙트 상의 totalWave가 바뀌는지 확인하는 코드이다.
- 아래 명령을 통해
컨트랙트를 실행하면 다음과 같은 결과가 나온다.
npx hardhat run scripts/run.js

wave() 함수에서 인사 받는 사람으로 msg.sender를 했기 때문에, 나 자신에게 인사를 한 꼴이 된다.
-
현재 컨트랙트에서 수행하는 동작은 아래와 같다.
wave() 함수를 호출한다. ( function call )
상태 변수(state variable)를 수정한다. ( write )
상태 변수의 새로운 값을 읽는다. ( read )
-
튜토리얼을 진행함에 따라, React앱을 만들어서 동작하게 할 것이다.
0x0C: 다른 유저에게서 인사 받기
wave() 함수로 인사를 하는 사람도 나이고 인사를 받는 사람도 나인 점이 좀 어색하다.
- 따라서,
다른 유저가 나에게 인사하도록 코드를 조금 수정한다.
- 앞선 코드에서의
randomPerson을 활용하면 아래와 같이 코드를 수정할 수 있다.
// counts the wave using getTotalWaves() from our contract
let waveCount = await waveContract.getTotalWaves();
// call wave(), but the msg.sender is __randomPerson__ now
let waveTxn = await waveContract.connect(randomPerson).wave();
await waveTxn.wait();
// grab the waveCount one more to see if it changed
waveCount = await waveContract.getTotalWaves();
wave()함수를 호출하는 msg.sender가 randomPerson이 되었으므로, 실행하면 아래와 같은 결과가 나온다.

- 이전과는
다른 주소가 나에게 인사하고 있음을 확인할 수 있다.
0x0D: 배포 스크립트(deploy.js) 작성하기
0x04 ~ 0x0C 까지의 내용은 아래와 같다.
스마트 컨트랙트 작성
- 실행을 위한
스크립트 작성
컨트랙트는 블록체인 네트워크로부터 호출된다고 했으므로, 이미 로컬 블록체인 네트워크를 구축한 것이라 생각할 수 있다.
- 하지만,
0x07에서 짧게 언급한 것처럼 스크립트를 실행할 때 사용한 네트워크는 스크립트 실행이 끝남과 동시에 삭제된다.
- 따라서, 일회성이 아닌
로컬 블록체인 네트워크를 구축할 필요가 있다.
- 다행히
hardhat에서는 이를 간단히 구현할 수 있도록 해준다.
- 아래의 명령을 새로운
터미널 윈도우에서 실행한다.
npx hardhat node

- 실행 결과,
hardhat이 로컬 블록체인 네트워크를 돌리고 있는 것을 확인할 수 있다.
- 또한, 각 계정에 10000ETH (≒ 343억원, 2022년 2월 기준)의
이더리움을 설정해 두었다.
- 현재
블록체인 네트워크는 블록이 하나도 없는 상태이다.
- 이제
새로운 블록을 생성하고 우리의 컨트랙트를 그 블록 위에 기록할 것이다.
script/ 디렉토리에 deploy.js라는 파일을 만들고 아래와 같이 코딩한다.
const main = async () => {
// get deployer
const [deployer] = await hre.ethers.getSigners();
// get balance of deployer
const accountBalance = await deployer.getBalance();
console.log("Deploying contracts with account: ", deployer.address);
console.log("Account balance: ", accountBalance.toString());
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
const waveContract = await waveContractFactory.deploy();
await waveContract.deployed();
console.log("WavePortal address: ", waveContract.address);
};
const runMain = async () => {
try {
await main();
process.exit(0);
} catch (error) {
console.log(error);
process.exit(1);
}
};
runMain();
0x0E: 배포하기
- 이제 아래의 명령어를 통해
로컬 블록체인 네트워크에 컨트랙트를 배포할 수 있다.
npx hardhat run scripts/deploy.js --network localhost
- 당연한 말이지만,
npx hardhat node로 서버를 돌리고 있는 터미널이 아닌 다른 터미널 창에서 명령어를 입력해야 한다.

배포 하는 스크립트를 4 번 실행한 결과, 블록이 4개까지 만들어진 것을 확인할 수 있다.
- 앞서 이용한
run.js도 생각해보면.. 코드 내에 deploy()를 쓰고 있기 때문에 아래와 같이 로컬 블록체인 네트워크에서 실행하는 것이 가능하다.
npx hardhat run ./scripts/run.js --network localhost
[0x01] 자신의 지갑, 그리고 스마트 컨트랙트와 연결되는 Web3 앱 만들기
0x0F: 클라이언트 세팅
- 이제
터미널이 아니라 웹 상에서 Web3를 이용하여, 우리가 만든 컨트랙트를 활용해보도록 한다.
0x10: Replit
Replit은 브라우저 기반 IDE로, 웹 앱을 쉽게 빌드하고 배포할 수 있도록 해준다.
Replit을 이용하기 위해서는 계정을 만들고, 로그인 하면 된다.
- 튜토리얼에서 제공하는 틀을
fork해서 개발을 이어나가면 된다. (링크)
Replit에서는 .js대신 .jsx확장자를 사용한다.
0x11: Metamask
이더리움 지갑으로 Metamask를 활용한다.
- 이
지갑을 통해서 컨트랙트 상의 함수 호출 등을 할 수 있다.
- 마치 사이트에
로그인하는 것처럼 활용할 수 있다.
0x12: 블록체인 상에 배포하기 위한 세팅
0x12부터는 npx hardhat node로 구축했던 로컬 블록체인 네트워크를 사용하지 않는다.
0x12부터는 실제 블록체인을 이용해서 튜토리얼을 진행한다.
- 실제
블록체인 네트워크에 컨트랙트를 편리하게 배포하기 위해 Alchemy 를 이용하면 좋다.
0x13: 트랜잭션
이더리움 블록체인 상에서 행하는 모든 행위들은 모두 트랜잭션이라 불린다.
- 예)
이더리움을 전송, 컨트랙트 내의 변수 업데이트
- 따라서,
wave()함수를 호출하고 내부에서 totalWaves += 1;을 수행하면, 이것이 트랜잭션인 것이다.
스마트 컨트랙트를 배포하는 것 자체도 트랜잭션이다.
블록체인은 소유자가 없고, 네트워크에 참여하는 모든 채굴자가 블록체인 원장을 갖고 있어야 함을 명심하자.
- 즉, 우리가
컨트랙트를 블록체인 네트워크상에 올리기 위해서는 다음의 과정을 거쳐야 한다.
컨트랙트 코드에 대한 트랜잭션을 채굴자들이 블록으로 만들 수 있도록 브로드캐스팅한다.
- 생성된
블록을 브로드캐스팅하여 네트워크참여자 모두에게 전송한다.
- 위 두 과정을 Alchemy 를 이용하면 쉽게 할 수 있다.
0x14: 테스트 넷(Rinkeby)
이더리움 메인넷은 실제 돈을 사용해야 하고, 실습을 하는 데 그만한 돈을 지불하는 것은 크게 가치가 없다.
- 따라서,
가짜 이더리움을 사용하는 테스트넷에서 실습하는 것이 효과적이다.
- 하지만,
테스트넷도 블록체인 네트워크이기 때문에 블록의 생성 과정 등 이더리움 메인넷이 갖는 특성과 동일하므로 유의해야 한다.
테스트넷에서 다음을 실습할 수 있다.
- 우리의
트랜잭션을 브로드캐스트한다.
채굴자들에 의해 트랜잭션이 선택될 떄까지 기다린다.
채굴 과정을 거친다.
- 생성된
블록이 블록체인 네트워크 상의 모든 채굴자들에게 브로드캐스트되기를 기다린다.
0x15: Fake ETH 얻기
- 본 튜토리얼에서는
테스트넷으로 Rinkeby를 이용한다.
- 개인적으로 여기가 제일 확실한 것 같다. ( 링크 )
0x16: Rinkeby 테스트넷으로 배포하기
- 우선
hardhat.config.js파일을 수정해야 한다.
require("@nomiclabs/hardhat-waffle");
module.exports = {
solidity: "0.8.4",
networks: {
rinkeby: {
url: "YOUR_ALCHEMY_API_URL",
accounts: ["YOUR_PRIVATE_RINKEBY_ACCOUNT_KEY"]
},
},
};
- 코드에 명시된 대로
Alchemy API URL과 본인 지갑 계정의 비밀키를 넣으면 된다.
비밀키는 마치 블록체인에 로그인할 때 사용되는 비밀번호 처럼 사용된다.
- 좀 더 자세히 말하자면,
트랜잭션을 채굴자에게 보낼 때, 전송자가 본인임을 인증하는 전자 서명을 위해 비밀키를 필요로 한다.
비밀키를 사용하지 않으면 트랜잭션의 유효성을 검사할 수 없기 때문에, 필요하다.
Rinkeby 네트워크로 배포하는 것은 아래의 명령어로 할 수 있다.
npx hardhat run scripts/deploy.js ---network rinkeby
0x17: 테스트넷(Rinkeby)으로 배포 완료!
- 아래는 명령어의 실행 결과다.

- 여기서
WavePortal address: 뒤에 있는 내용이 블록 내의 컨트랙트주소 이다.
- 즉, 실제
블록체인 네트워크 상에 우리가 만든 스마트 컨트랙트를 올린 것이다.
0x18: window.ethereum() 사용하기
- 우리가 만들
웹 사이트가 블록체인과 상호작용하기 위해서는, 어쨋든 우리의 지갑을 연결해야 한다.
지갑을 연결하고 나면 스마트 컨트랙트 호출 권한을 받을 수 있다.
Replit으로 가서 src/디렉토리 밑에 있는 App.jsx를 찾는다.
Metamask에 로그인 되어 있다면, 윈도우에 ethereum이라는 특별한 객체가 자동으로 삽입된다.
- 우선, 이
ethereum 이라는 객체가 존재하는지 부터 확인해보자.
- 아래 코드로
App.jsx를 수정한다.
import React, { useEffect } from "react";
import "./App.css";
const App = () => {
const checkIfWalletIsConnected = () => {
/*
* First make sure we have access to window.ethereum
*/
const { ethereum } = window;
if (!ethereum) {
console.log("Make sure you have metamask!");
} else {
console.log("We have the ethereum object", ethereum);
}
}
/*
* This runs our function when the page loads.
*/
useEffect(() => {
checkIfWalletIsConnected();
}, [])
return (
<div className="mainContainer">
<div className="dataContainer">
<div className="header">
👋 Hey there!
</div>
<div className="bio">
I am farza and I worked on self-driving cars so that's pretty cool right? Connect your Ethereum wallet and wave at me!
</div>
<button className="waveButton" onClick={null}>
Wave at Me
</button>
</div>
</div>
);
}
export default App
-
Metamask가 있는 경우 아래와 같이 콘솔창에서 확인할 수 있다.
-

-
Metamask가 없는 경우 아래와 같이 콘솔창에서 확인할 수 있다.(시크릿탭 켜고 들어감)
-

0x19: 유저 계정에 접근할 수 있는지 확인
- 이제
지갑이 연결되었는지 여부는 확인했으니 유저의 지갑 계정에 접근할 수 있는지를 확인해야 한다.
Metamask는 반드시 우리가 승인한 웹 사이트에서만 우리의 지갑 계정 정보를 제공한다.
App.jsx를 아래의 코드로 업데이트한다.
import React, { useEffect, useState } from "react";
import "./App.css";
const App = () => {
/*
* Just a state variable we use to store our user's public wallet.
*/
const [currentAccount, setCurrentAccount] = useState("");
const checkIfWalletIsConnected = async () => {
try {
const { ethereum } = window;
if (!ethereum) {
console.log("Make sure you have metamask!");
return;
} else {
console.log("We have the ethereum object", ethereum);
}
/*
* Check if we're authorized to access the user's wallet
*/
const accounts = await ethereum.request({ method: "eth_accounts" });
if (accounts.length !== 0) {
const account = accounts[0];
console.log("Found an authorized account:", account);
setCurrentAccount(account)
} else {
console.log("No authorized account found")
}
} catch (error) {
console.log(error);
}
}
useEffect(() => {
checkIfWalletIsConnected();
}, [])
return (
<div className="mainContainer">
<div className="dataContainer">
<div className="header">
👋 Hey there!
</div>
<div className="bio">
I am farza and I worked on self-driving cars so that's pretty cool right? Connect your Ethereum wallet and wave at me!
</div>
<button className="waveButton" onClick={null}>
Wave at Me
</button>
</div>
</div>
);
}
export default App
- 여기서
eth_accounts라는 특별한 메서드를 사용하여, 지갑에 있는 계정들 중 하나라도 접근할 수 있는지 확인할 수 있다.
- 유저는 하나의
지갑에 여러 개의 계정을 가질 수 있으므로, 여기서는 첫 번째 것을 사용하기로 한다.
0x1A: 지갑 연결 버튼 만들기
로컬 이더리움 네트워크를 세팅한다.스마트 컨트랙트 코드에 대해 컴파일, 테스트 등을 해볼 수 있다.스마트 컨트랙트란 블록체인 상에 있는 코드 조각으로 기억하면 된다.블록체인이란 누구나 안전하게 정보를 읽고 쓸 수 있는 공간이다.- AWS 같은 네트워크지만, 누구의 소유도 아닌 네트워크라 생각하면 된다.
스마트 컨트랙트를 작성한다.- 서버의 코드와 같이 생각하면 된다.
- 작성한
스마트 컨트랙트를 블록체인 상에배포(deploy)한다.- 전 세계 누구든 우리로부터 허용되었다면
스마트 컨트랙트에접근하고실행시킬 수 있다.
- 전 세계 누구든 우리로부터 허용되었다면
클라이언트 웹사이트를 만든다.- 일반 유저들이 우리의
스마트 컨트랙트와 쉽게 상호작용 할 수 있도록 한다.
- 일반 유저들이 우리의
안녕이라고 인사해주는 웹사이트를 만드는 것이다!hardhat이라는 툴을 통해, 로컬 이더리움 네트워크환경을 만들 수 있으며 fake 이더리움, fake 계정등을 이용해 테스트도 진행할 수 있다.서버가 블록체인임을 기억하도록 하자.hardhat을 통해 스마트 컨트랙트를 컴파일하는 것이 가능하다. 로컬 이더리움 네트워크에서 이를 테스트할 수도 있다.hardhat을 이용하기 위해서는 node/npm이 필요하다.- 설치에 관한 내용은 따로 다루도록 한다.
- 메모를 해두자면, Node.js 를 그냥 받으면 LTS가 아니라서 경고 메세지가 뜨기도 한다... 이를 해결하는 방법을 찾느라 나름 시간을 날렸으므로, 꼭 정리해둘 예정이다.
my-wave-portal 이라는 작업 디렉토리를 따로 만들어 진행하도록 한다.npm의 설치가 완료되었으면 아래 코드를 입력해 튜토리얼을 진행한다.mkdir my-wave-portal
cd my-wave-portal
npm init -y
npm install --save-dev hardhat
hardhat을 설치 완료한 후 샘플 프로젝트를 받는 작업을 진행한다.npx hardhat
Create a basic sample project를 선택하면 몇 가지를 더 묻는데 모두 Enter키로 넘기면 아래와 같이 설치되는 과정이 나온다.

Project created라는 문구와 함께 샘플 프로젝트가 완성된 것을 확인할 수 있다.
hardhat-waffle과 hardhat-ethers를 추가로 설치해야 한다. 아래의 명령을 입력하면 된다.npm install --save-dev @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethersnpx hardhat accounts
hardhat이 생성한 이더리움 주소 이다.테스트에 활용할 수 있다.0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (첫 번째 주소)가 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 (두 번째 주소)에게 0.1 ETH를 보낸다.npx hardhat compile
npx hardhat run
scripts, contract, test 디렉토리에 있는 모든 파일들을 지우도록 한다.contract 디렉토리에 WavePortal.sol이라는 이름으로 솔리디티 파일을 하나 만든다.// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;
import "hardhat/console.sol";
contract WavePortal {
constructor() {
console.log("Yo yo, I am a contract and I am smart");
}
}// SPDX-License-Identifier: UNLICENSED
- 라이센스 (저작권) 에 관한 내용이다.
- Ref. https://devocean.sk.com/opensource/techBoardDetail.do?ID=159339
pragma solidity ^0.8.4;
- 우리의
스마트 컨트랙트가 이용할컴파일러의버전을 명시한다. - 중요 :
hardhat.config.js에 명시된 것과 동일한버전을 사용해야 한다.
import "hardhat/console.sol";
console log에 관한 코드를import한다.hardhat에서는스마트 컨트랙트를 쉽게디버깅할 수 있도록console log를 사용할 수 있는 코드를 제공한다.
contract WavePortal {
constructor() {
console.log("Yo yo, I am a contract and I am smart");
}
}
스마트 컨트랙트의 구현에 대한 내용이다.스마트 컨트랙트(=컨트랙트)는 다른 언어에서의클래스와 상당히 비슷하게 보인다.- 이
컨트랙트를 초기화 하면,constructor(생성자)가 호출되며console을 통해 문장을 출력할 것이다.
스마트 컨트랙트를 작성하였으므로, 아래 세 단계를 거쳐 이를 실행해 볼 수 있다.컨트랙트를컴파일한다.로컬 블록체인 네트워크에컴파일 된 컨트랙트를배포(deploy)한다.블록체인 네트워크상의컨트랙트를 호출하면console.log()가 실행된다.
블록체인에서도 컨트랙트는 네트워크상에 존재하며, 이를 누군가 호출하는 방식으로 동작한다.컨트랙트를 컴파일하고 실행하는 것은 가능하다.Solidity가 블록체인 네트워크, 그리고 이더리움 지갑(wallet)과 어떻게 상호작용 할 수 있는지를 이해하는 것이 중요하다.scripts 디렉토리에 run.js라는 자바스크립트 파일을 만든다.컨트랙트를 실행하기 위해서는 컴파일, 배포, 실행 세 가지를 해야 한다.const main = async () => {
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
const waveContract = await waveContractFactory.deploy();
await waveContract.deployed();
console.log("Contract deployed to:", waveContract.address);
};
const runMain = async () => {
try {
await main();
process.exit(0); // exit Node process without error
} catch (error) {
console.log(error);
process.exit(1); // exit Node process while indicating 'Uncaught Fatal Exception' error
}
// Read more about Node exit ('process.exit(num)') status codes here: https://stackoverflow.com/a/47163396/7974948
};
runMain();const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
컨트랙트를컴파일하고artifacts/디렉토리에컨트랙트를 다루기 위해 필요한 파일들을 생성한다.
const waveContract = await waveContractFactory.deploy();
deploy()메서드를 통해,hardhat은로컬 이더리움 네트워크를 만든다.- 그러나, 이 때 만들어진
로컬 이더리움 네트워크는스크립트의 실행이 끝나면 삭제된다. - 따라서,
컨트랙트를 실행할 때 마다네트워크를 초기 상태로 다룰 수 있고, 이는디버깅등에 유용하다.
await waveContract.deployed();
컨트랙트가블록체인 네트워크상에 잘배포될 때까지 기다린다.배포가 완료되면,constructor()가 실행된다.
console.log("Contract deployed to:", waveContract.address);
배포가 되면블록체인 네트워크상의컨트랙트의 주소를 받을 수 있다.- 실제
블록체인 네트워크상에는 무수히 많은컨트랙트들이 배포되어 있고,주소를 통해 우리가배포한컨트랙트를 찾아서 사용할 수 있다.
스크립트를 실제로 실행해보자.npx hardhat run scripts/run.js
hre.ethers를 사용하고 있다.HRE에 관한 설명은 아래와 같다.hre는Hardhat Runtime Environment를 의미하며 일종의객체(object)이다.hardhat이 작업, 테스트 또는 스크립트를 실행할 때 표시하는 모든 기능을 포함한다.- 따라서,
Hardhat은HRE이다.
npx hardhat으로 시작되는 명령을 터미널에서 입력할 때마다, 코드에 지정된 hardhat.config.js를 사용해서 이 hre라는 객체를 즉시 만들 수 있다.const hre = require("hardhat");컨트랙트에 데이터를 저장할 수 있다.함수로 구현할 수 있다.함수 내에 인사에 대한 정보를 저장하도록 한다.블록체인 네트워크를클라우드 서버처럼 생각하면 편하다.- 이
서버를 유지하는 전 세계의 수 많은 사람들을 보통채굴자(miner)라고 부른다. - 우리는
블록체인 네트워크의 코드를 실행하기 위해서 이런채굴자들에게 값을 지불하는 것이다.
- 같은 맥락으로,
스마트 컨트랙트는서버상의프로그램 코드라 생각하면 편하다. - 즉, 누구나
서버상에 존재하는프로그램을 실행할 수 있는 것이다.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;
import "hardhat/console.sol";
contract WavePortal {
uint256 totalWaves;
constructor() {
console.log("Yo yo, I am a contract and I am smart");
}
function wave() public {
totalWaves += 1;
console.log("%s has waved!", msg.sender);
}
function getTotalWaves() public view returns (uint256) {
console.log("We have %d total waves!", totalWaves);
return totalWaves;
}
}uint256 totalWaves;
컨트랙트상에 저장되는상태 변수(state variable)로,블록체인상에 기록된다.- 즉,
컨트랙트와 마찬가지로 한 번 블록체인에 기록되면 영원히 존재한다.
function wave() public {
totalWave += 1;
console.log("%s has waved!", msg.sender);
}
함수를 선언했다.public키워드는 이함수가 누구나 호출할 수 있음을 의미한다.totalWaves += 1;는 산술 연산이 다른 언어들과 크게 다르지 않음을 보여준다.- 주목해야 할 점은
msg.sender에 관한 것이다.- 여기서
msg.sender는 이컨트랙트를 호출한 사람의지갑 주소(wallet address)이며,빌트인 인증(built-in authentication)과도 같다.
스마트 컨트랙트를 호출할 때에도유효한 지갑이 필요함 반드시 필요하기 때문에,
우리는 이를 통해 누가 이컨트랙트를 호출했는지 알 수 있다.- 이를 응용하면, 특정인만
컨트랙트를 호출하도록 할 수 있다.
- 여기서
function getTotalWaves() public view returns (uint256) {
console.log("We have %d total waves!", totalWaves);
return totalWaves;
}
view는 이함수에서state variable을읽기만 하고쓰기는 하지 않음을 명시한다.return값을 지정하는 방식이 조금 특이하다.함수의바디가 시작되기 직전에returns라는 키워드와 그 뒤에(_type_)형태로 자료형을 명시한다.
함수들을 호출하기 위해 run.js를 다시 수정할 필요가 있다.public 키워드를 사용한 함수들은 블록체인에 배포된 뒤 사용할 수 있게 된다.public API endpoint를 생각하면 편하다.const main = async () => {
// getSigners()
const [owner, randomPerson] = await hre.ethers.getSigners();
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
const waveContract = await waveContractFactory.deploy();
await waveContract.deployed();
// logs
console.log("Contract deployed to:", waveContract.address);
console.log("Contract deployed by:", owner.address);
// counts the wave using getTotalWaves() from our contract
let waveCount = await waveContract.getTotalWaves();
// call wave()
let waveTxn = await waveContract.wave();
await waveTxn.wait();
// grab the waveCount one more to see if it changed
waveCount = await waveContract.getTotalWaves();
};
const runMain = async () => {
try {
await main();
process.exit(0);
} catch (error) {
console.log(error);
process.exit(1);
}
};
runMain();const [owner, randomPerson] = await hre.ethers.getSigners();
블록체인에 어떤 것이든배포하기 위해서는 유효한지갑 주소가 필요하다.hardhat은 백그라운드에서 이것을 알아서 처리해주지만, 이 코드에서는 명시적으로지갑 주소를 가져오고 있다.getSigners()함수는npx hardhat accounts로 확인했던지갑들을 반환한다.
console.log("Contract deployed by:", owner.address);
컨트랙트를배포한 사람이 누구인지 확인할 수 있다.
let waveCount = await waveContract.getTotalWaves();
let waveTxn = await waveContract.wave();
await waveTxn.wait();
waveCount = await waveContract.getTotalWaves();
- 보통
API들을 사용하는 것과 같이, 여기서도함수들을 하나 하나 호출해야 한다. 컨트랙트상의totalWave가 바뀌는지 확인하는 코드이다.
컨트랙트를 실행하면 다음과 같은 결과가 나온다.npx hardhat run scripts/run.js
wave() 함수에서 인사 받는 사람으로 msg.sender를 했기 때문에, 나 자신에게 인사를 한 꼴이 된다.현재 컨트랙트에서 수행하는 동작은 아래와 같다.
wave()함수를 호출한다. ( function call )상태 변수(state variable)를 수정한다. ( write )상태 변수의 새로운 값을 읽는다. ( read )
튜토리얼을 진행함에 따라, React앱을 만들어서 동작하게 할 것이다.
wave() 함수로 인사를 하는 사람도 나이고 인사를 받는 사람도 나인 점이 좀 어색하다.다른 유저가 나에게 인사하도록 코드를 조금 수정한다.randomPerson을 활용하면 아래와 같이 코드를 수정할 수 있다. // counts the wave using getTotalWaves() from our contract
let waveCount = await waveContract.getTotalWaves();
// call wave(), but the msg.sender is __randomPerson__ now
let waveTxn = await waveContract.connect(randomPerson).wave();
await waveTxn.wait();
// grab the waveCount one more to see if it changed
waveCount = await waveContract.getTotalWaves();wave()함수를 호출하는 msg.sender가 randomPerson이 되었으므로, 실행하면 아래와 같은 결과가 나온다.
다른 주소가 나에게 인사하고 있음을 확인할 수 있다.0x04 ~ 0x0C 까지의 내용은 아래와 같다.스마트 컨트랙트작성- 실행을 위한
스크립트작성
컨트랙트는 블록체인 네트워크로부터 호출된다고 했으므로, 이미 로컬 블록체인 네트워크를 구축한 것이라 생각할 수 있다.0x07에서 짧게 언급한 것처럼 스크립트를 실행할 때 사용한 네트워크는 스크립트 실행이 끝남과 동시에 삭제된다.로컬 블록체인 네트워크를 구축할 필요가 있다.hardhat에서는 이를 간단히 구현할 수 있도록 해준다.터미널 윈도우에서 실행한다.npx hardhat node
hardhat이 로컬 블록체인 네트워크를 돌리고 있는 것을 확인할 수 있다.이더리움을 설정해 두었다.블록체인 네트워크는 블록이 하나도 없는 상태이다.새로운 블록을 생성하고 우리의 컨트랙트를 그 블록 위에 기록할 것이다.script/ 디렉토리에 deploy.js라는 파일을 만들고 아래와 같이 코딩한다.const main = async () => {
// get deployer
const [deployer] = await hre.ethers.getSigners();
// get balance of deployer
const accountBalance = await deployer.getBalance();
console.log("Deploying contracts with account: ", deployer.address);
console.log("Account balance: ", accountBalance.toString());
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
const waveContract = await waveContractFactory.deploy();
await waveContract.deployed();
console.log("WavePortal address: ", waveContract.address);
};
const runMain = async () => {
try {
await main();
process.exit(0);
} catch (error) {
console.log(error);
process.exit(1);
}
};
runMain();로컬 블록체인 네트워크에 컨트랙트를 배포할 수 있다.npx hardhat run scripts/deploy.js --network localhostnpx hardhat node로 서버를 돌리고 있는 터미널이 아닌 다른 터미널 창에서 명령어를 입력해야 한다.
배포 하는 스크립트를 4 번 실행한 결과, 블록이 4개까지 만들어진 것을 확인할 수 있다.- 앞서 이용한
run.js도 생각해보면..코드내에deploy()를 쓰고 있기 때문에 아래와 같이로컬 블록체인 네트워크에서 실행하는 것이 가능하다.npx hardhat run ./scripts/run.js --network localhost
0x0F: 클라이언트 세팅
- 이제
터미널이 아니라웹상에서Web3를 이용하여, 우리가 만든컨트랙트를 활용해보도록 한다.
0x10: Replit
Replit은 브라우저 기반IDE로, 웹 앱을 쉽게 빌드하고 배포할 수 있도록 해준다.Replit을 이용하기 위해서는 계정을 만들고, 로그인 하면 된다.- 튜토리얼에서 제공하는 틀을
fork해서 개발을 이어나가면 된다. (링크)
Replit에서는.js대신.jsx확장자를 사용한다.
0x11: Metamask
이더리움 지갑으로Metamask를 활용한다.- 이
지갑을 통해서컨트랙트상의 함수 호출 등을 할 수 있다. - 마치 사이트에
로그인하는 것처럼 활용할 수 있다.
0x12: 블록체인 상에 배포하기 위한 세팅
0x12부터는npx hardhat node로 구축했던로컬 블록체인 네트워크를 사용하지 않는다.0x12부터는 실제블록체인을 이용해서 튜토리얼을 진행한다.- 실제
블록체인 네트워크에컨트랙트를 편리하게 배포하기 위해 Alchemy 를 이용하면 좋다.
0x13: 트랜잭션
이더리움블록체인상에서 행하는 모든 행위들은 모두트랜잭션이라 불린다.- 예)
이더리움을 전송,컨트랙트내의변수업데이트
- 따라서,
wave()함수를 호출하고 내부에서totalWaves += 1;을 수행하면, 이것이트랜잭션인 것이다. 스마트 컨트랙트를배포하는 것 자체도 트랜잭션이다.
블록체인은 소유자가 없고,네트워크에 참여하는 모든채굴자가블록체인 원장을 갖고 있어야 함을 명심하자.- 즉, 우리가
컨트랙트를블록체인 네트워크상에 올리기 위해서는 다음의 과정을 거쳐야 한다.컨트랙트 코드에 대한트랜잭션을채굴자들이블록으로 만들 수 있도록 브로드캐스팅한다.- 생성된
블록을 브로드캐스팅하여네트워크참여자 모두에게 전송한다.
- 위 두 과정을 Alchemy 를 이용하면 쉽게 할 수 있다.
0x14: 테스트 넷(Rinkeby)
이더리움 메인넷은 실제 돈을 사용해야 하고, 실습을 하는 데 그만한 돈을 지불하는 것은 크게 가치가 없다.- 따라서,
가짜 이더리움을 사용하는테스트넷에서 실습하는 것이 효과적이다. - 하지만,
테스트넷도블록체인 네트워크이기 때문에블록의 생성 과정 등이더리움 메인넷이 갖는 특성과 동일하므로 유의해야 한다.
테스트넷에서 다음을 실습할 수 있다.- 우리의
트랜잭션을브로드캐스트한다. 채굴자들에 의해트랜잭션이 선택될 떄까지 기다린다.채굴과정을 거친다.- 생성된
블록이블록체인 네트워크상의 모든채굴자들에게브로드캐스트되기를 기다린다.
- 우리의
0x15: Fake ETH 얻기
- 본 튜토리얼에서는
테스트넷으로Rinkeby를 이용한다. - 개인적으로 여기가 제일 확실한 것 같다. ( 링크 )
0x16: Rinkeby 테스트넷으로 배포하기
- 우선
hardhat.config.js파일을 수정해야 한다.
require("@nomiclabs/hardhat-waffle");
module.exports = {
solidity: "0.8.4",
networks: {
rinkeby: {
url: "YOUR_ALCHEMY_API_URL",
accounts: ["YOUR_PRIVATE_RINKEBY_ACCOUNT_KEY"]
},
},
};
- 코드에 명시된 대로
Alchemy API URL과 본인지갑 계정의비밀키를 넣으면 된다. 비밀키는 마치블록체인에로그인할 때 사용되는 비밀번호 처럼 사용된다.
- 좀 더 자세히 말하자면,
트랜잭션을채굴자에게 보낼 때,전송자가본인임을 인증하는전자 서명을 위해비밀키를 필요로 한다. 비밀키를 사용하지 않으면트랜잭션의 유효성을 검사할 수 없기 때문에, 필요하다.
Rinkeby네트워크로배포하는 것은 아래의 명령어로 할 수 있다.
npx hardhat run scripts/deploy.js ---network rinkeby
0x17: 테스트넷(Rinkeby)으로 배포 완료!
- 아래는 명령어의 실행 결과다.

- 여기서
WavePortal address:뒤에 있는 내용이블록내의컨트랙트주소 이다. - 즉, 실제
블록체인 네트워크상에 우리가 만든스마트 컨트랙트를 올린 것이다.
0x18: window.ethereum() 사용하기
- 우리가 만들
웹 사이트가블록체인과 상호작용하기 위해서는, 어쨋든 우리의지갑을 연결해야 한다. 지갑을 연결하고 나면스마트 컨트랙트호출 권한을 받을 수 있다.
Replit으로 가서src/디렉토리 밑에 있는App.jsx를 찾는다.Metamask에 로그인 되어 있다면, 윈도우에ethereum이라는 특별한 객체가 자동으로 삽입된다.- 우선, 이
ethereum이라는 객체가 존재하는지 부터 확인해보자. - 아래 코드로
App.jsx를 수정한다.
import React, { useEffect } from "react";
import "./App.css";
const App = () => {
const checkIfWalletIsConnected = () => {
/*
* First make sure we have access to window.ethereum
*/
const { ethereum } = window;
if (!ethereum) {
console.log("Make sure you have metamask!");
} else {
console.log("We have the ethereum object", ethereum);
}
}
/*
* This runs our function when the page loads.
*/
useEffect(() => {
checkIfWalletIsConnected();
}, [])
return (
<div className="mainContainer">
<div className="dataContainer">
<div className="header">
👋 Hey there!
</div>
<div className="bio">
I am farza and I worked on self-driving cars so that's pretty cool right? Connect your Ethereum wallet and wave at me!
</div>
<button className="waveButton" onClick={null}>
Wave at Me
</button>
</div>
</div>
);
}
export default App
-
Metamask가 있는 경우 아래와 같이 콘솔창에서 확인할 수 있다.
-

-
Metamask가 없는 경우 아래와 같이 콘솔창에서 확인할 수 있다.(시크릿탭 켜고 들어감)
-

0x19: 유저 계정에 접근할 수 있는지 확인
- 이제
지갑이 연결되었는지 여부는 확인했으니 유저의지갑 계정에 접근할 수 있는지를 확인해야 한다. Metamask는 반드시 우리가승인한웹 사이트에서만 우리의지갑 계정 정보를 제공한다.App.jsx를 아래의 코드로 업데이트한다.
import React, { useEffect, useState } from "react";
import "./App.css";
const App = () => {
/*
* Just a state variable we use to store our user's public wallet.
*/
const [currentAccount, setCurrentAccount] = useState("");
const checkIfWalletIsConnected = async () => {
try {
const { ethereum } = window;
if (!ethereum) {
console.log("Make sure you have metamask!");
return;
} else {
console.log("We have the ethereum object", ethereum);
}
/*
* Check if we're authorized to access the user's wallet
*/
const accounts = await ethereum.request({ method: "eth_accounts" });
if (accounts.length !== 0) {
const account = accounts[0];
console.log("Found an authorized account:", account);
setCurrentAccount(account)
} else {
console.log("No authorized account found")
}
} catch (error) {
console.log(error);
}
}
useEffect(() => {
checkIfWalletIsConnected();
}, [])
return (
<div className="mainContainer">
<div className="dataContainer">
<div className="header">
👋 Hey there!
</div>
<div className="bio">
I am farza and I worked on self-driving cars so that's pretty cool right? Connect your Ethereum wallet and wave at me!
</div>
<button className="waveButton" onClick={null}>
Wave at Me
</button>
</div>
</div>
);
}
export default App
- 여기서
eth_accounts라는 특별한 메서드를 사용하여,지갑에 있는계정들 중 하나라도 접근할 수 있는지 확인할 수 있다. - 유저는 하나의
지갑에 여러 개의계정을 가질 수 있으므로, 여기서는 첫 번째 것을 사용하기로 한다.
0x1A: 지갑 연결 버튼 만들기
( 링크 )
Author And Source
이 문제에 관하여([0x01] Web3 App w/ Solidity, Ether Smart Contract), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@c0np4nn4/0x01-Web3-App-w-Solidity-Ether-Smart-Contract저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)