[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-wafflehardhat-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
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: 로컬 테스트 블록체인 환경 만들기

  • 스마트 컨트랙트를 작성하였으므로, 아래 세 단계를 거쳐 이를 실행해 볼 수 있다.
    1. 컨트랙트컴파일한다.
    2. 로컬 블록체인 네트워크컴파일 된 컨트랙트배포(deploy) 한다.
    3. 블록체인 네트워크 상의 컨트랙트를 호출하면 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에 관한 설명은 아래와 같다.
  • hreHardhat Runtime Environment를 의미하며 일종의 객체(object)이다.
  • hardhat이 작업, 테스트 또는 스크립트를 실행할 때 표시하는 모든 기능을 포함한다.
  • 따라서, HardhatHRE이다.
  • 즉, 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를 했기 때문에, 나 자신에게 인사를 한 꼴이 된다.
  • 현재 컨트랙트에서 수행하는 동작은 아래와 같다.

    1. wave() 함수를 호출한다. ( function call )
    2. 상태 변수(state variable)를 수정한다. ( write )
    3. 상태 변수의 새로운 값을 읽는다. ( 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.senderrandomPerson이 되었으므로, 실행하면 아래와 같은 결과가 나온다.
  • 이전과는 다른 주소에게 인사하고 있음을 확인할 수 있다.

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;을 수행하면, 이것이 트랜잭션인 것이다.
  • 스마트 컨트랙트배포하는 것 자체도 트랜잭션이다.
  • 블록체인은 소유자가 없고, 네트워크에 참여하는 모든 채굴자블록체인 원장을 갖고 있어야 함을 명심하자.
  • 즉, 우리가 컨트랙트블록체인 네트워크상에 올리기 위해서는 다음의 과정을 거쳐야 한다.
    1. 컨트랙트 코드에 대한 트랜잭션채굴자들이 블록으로 만들 수 있도록 브로드캐스팅한다.
    2. 생성된 블록을 브로드캐스팅하여 네트워크참여자 모두에게 전송한다.
  • 위 두 과정을 Alchemy 를 이용하면 쉽게 할 수 있다.

0x14: 테스트 넷(Rinkeby)

  • 이더리움 메인넷은 실제 돈을 사용해야 하고, 실습을 하는 데 그만한 돈을 지불하는 것은 크게 가치가 없다.
  • 따라서, 가짜 이더리움을 사용하는 테스트넷에서 실습하는 것이 효과적이다.
  • 하지만, 테스트넷블록체인 네트워크이기 때문에 블록의 생성 과정 등 이더리움 메인넷이 갖는 특성과 동일하므로 유의해야 한다.
  • 테스트넷에서 다음을 실습할 수 있다.
    1. 우리의 트랜잭션브로드캐스트한다.
    2. 채굴자들에 의해 트랜잭션이 선택될 떄까지 기다린다.
    3. 채굴 과정을 거친다.
    4. 생성된 블록블록체인 네트워크 상의 모든 채굴자들에게 브로드캐스트되기를 기다린다.

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: 지갑 연결 버튼 만들기

( 링크 )

좋은 웹페이지 즐겨찾기