본문 바로가기
카테고리 없음

[Blockchain/블록체인] CRA typescript로 Front에서 Metamask 이용하여 Transaction 발생

by dev_kong 2022. 6. 30.
728x90
728x90

0. 목차

1. 개요

2. DApp

3. window.ethereum

4. 기능구현

 

1. 개요

저번 포스팅에서는 직접 트랜잭션의 내용을 객체로 만들고,

만들어진 트랜잭션 객체의 내용을 이더리움 네트워크로 전송하는 것을

테스트 코드를 통해 작성해 보았는데,

 

이번 포스팅에서는 React로 프론트를 만든 뒤애,

프론트에서 Metamask를 통해 트랜잭션을 발생 시켜 보려고한다.

 

트랜잭션의 내용을 프론트에서 직접 만드는 것이 아니라,

프론트에서는 수신자와 금액만 입력하면,

 

Metamask에 현제 연결 되어있는 계정의 내용으로 트랜잭션을 만들고,

현재 연결되어있는 네트워크에 전달하여,

트랜잭션이 발생된다.

 

이러한 App을 DApp이라고 한다.

2. DApp

말이 나온김에 DApp을 조금 알아보자.

 

DApp 이란, decentralized application의 약자로써

탈중앙화 애플리케이션이란 뜻이다.

 

이게 말로만 들으면 뭔소린가 싶다.

그림을 보는게 조금 이해가 빠를듯 하다.

 

단순하게 이더리움으로 물건을 구매할 수 있는 애플리케션이라고 생각하고 그림을 보면 조금더 이해가 쉽다.

 

이런식으로 구성돼있는건 저번포스팅에서 테스트 코드로 작성했던 내용을 이용하면 구현이 가능하다.

그런데 이런식으로 트랜잭션을 만드는 것은 DApp과는 거리가 멀다.

 

트랜잭션의 필수적이고, 정말 중요한 내용인 signature를 만들기 위해선

개인키 즉, Private Key가 필요한데, 이 방식대로 application을 구현하게 된다면,

private key가 백엔드에 저장이 되어있어야 가능하다.

 

그리고 실제로 이런식으로 구현되어 있는 application들이 있는데,

우리가 흔히 4대 거래소라 부르는

업비트, 빗썸, 코인원, 코빗들이 이러한 방식을 사용하고 있다.

 

이러한 거래소들을 CEX(Centralized EXchange)라고 부른다.

 

반면 DApp은 어떤식으로 프로세스가 이뤄지는지 그림을 통해 살펴보자.

 

 

개인키(private key)를 백엔드나, 프론트엔드에서 관리하는 것이아닌,

 

사용자가 설치한 별도의 서비스인 Wallet을 이용해서 관리하고,

wallet에서 private key를 이용해 transaction의 내용을 만들어서

네트워크와 통신하는 방법의 application을 DApp이라고 한다.

 

DApp을 구현 하려면 결국 별도의 지갑 application이 필수인데,

현재 Ethereum 계열에서 가장 많이 사용되는 wallet 프로그램인

Metamask를 이용하려 한다.

3. window.ethereum

바로 위에서 지갑 application이 필수이기 때문에, metamask를 사용 한다고 했다.

 

그렇다면, 브라우저에서 우리가 사용할 메타마스크가 깔려있는지 안깔려 있는지를 어떻게 구분할까?

 

간략하게 얘기하면 이것도 메타마스크가 해준다.

 

이걸 간단하게 확인을 해볼수가 있는데,

메타마스크가 깔려있는 브라우저(크롬) 에서 DevTool을 켜고 콘솔에 window.ethereum을 입력해보면,

아래 사진과 같이 나온다.

 

그런데 메타마스크가 깔려있지 않은 브라우저(사파리)에서 같은 작업을 수행하면

undefined가 나온다.

 

 

이 객체의 유무를 통해 metamask 설치 여부를 확인 할 수 있고,

만약 undefined라면 metamask를 설치할 수 있는 페이지로 이동하는 버튼을 만들어주면 되지 않을까 싶다.

 

이론적인건 이만하면 된듯하다.

이제 코드를 짜보자.

 

4. 기능구현

수업에서는 js를 이용하였지만,

개인적으로 typescript가 더 맘에 들기도 하고, 연습도할겸 typescript로 작성을 해보려 한다.

 

npm i ganache-cli
npx create-react-app client --template typescript

 

테스트를 위한 ganache(가나슈)와 CRA를 typescript로 실행을 해주자.

vscode 에서 터미널을 2개를 켜서

하나는 가나슈를 실행시켜주는데,

chainId 옵션을 이용해서 chainId를 설정해주자.

 

npx gangache-cli --chainId 7722

 

다른 하나에선 react를 실행시켜주자

 

npm run start

 

그리고 App.tsx에서 최상단 div를 하나 제외하고 안의 내용을 모두 지운뒤

Hello CRA-TS! 라고 입력을 해준 뒤,

 

브라우저가 잘 동작하는 지 확인을 해보자!

 

import React from 'react';
import './App.css';

function App() {
  return <div className="App">Hello CRA-TS!</div>;
}

export default App;

 

통신에는 당연히 web3를 이용할 건데,

App.tsx에서 다 작성하기엔, 좀 지저분 하니까,

custom hook을 이용하려고 한다.

 

src 디렉토리 내에 hooks 디렉토리를 만들고,

useWeb3.ts 파일을 생성해주자.

 

 

코드를 작성하기 전에 어떤 작업을 할 것인지 먼저 설명을 하는게 좋을것 같다.

 

0. 화면 구성

-> 계정이름 표시, 해당 계정 balance, transaction 발생시킬 form

 

1. Metamask 설치여부

-> Metamask 설치 안되어있으면 Metamask 설치페이지로 이동하는 버튼

 

2. 현재 네트워크 확인 후 DApp에서 사용할 네트워크 추가 및 연결

 

3. 연결된 account 가져오기

 

4. web3 연결 (추후 전역상태로 두고 사용할 예정)

 

5. 연결된 계정의 계정명과 밸런스 보여주기

 

6. 트랜잭션 form태그 submit 함수 작성

 

위의 순서대로 만들 예정이다.

0번 부터 하나씩 해보자.

 

4-0. 화면구성

 

import React from 'react';
import './App.css';

function App() {
  return (
    <div className="App">
      <h1>Hello CRA-TS!</h1>
      <div>
        <h3>Accounts Info</h3>
        <ul>
          <li>Account : kong</li>
          <li>Balance : 0 ETH</li>
        </ul>
      </div>
      <div>
        <h3>Transaction</h3>
        <form action="">
          <ul>
            <li>
              <input type="text" id="received" placeholder="받을 사람" />
            </li>
            <li>
              <input type="text" id="amount" placeholder="보낼 금액" />
            </li>
            <li>
              <button type="submit">전송!!</button>
            </li>
          </ul>
        </form>
      </div>
    </div>
  );
}

export default App;

 

그냥 마크업이니까 딱히 설명안할 거임

 

 

그냥 이모양으로 만든거다.

 

4-1. metamask 설치여부

 

useWeb3.ts 문서에서 작성을 할거다.

 

import { useEffect, useState } from 'react';

export const useWeb3 = () => {};

 

기본 틀 잡아놓고,

metamask 설치여부를 확인하기 위해선 window.ethereum 객체의 존재 여부를 확인하면 된다고 위에서 기술 했었다.

 

리액트 생명주기 중 didMount 시점에 해주면 될듯 하다.

 

import { useEffect, useState } from 'react';

export const useWeb3 = () => {
  const [account, setAccount] = useState(false);

  useEffect(() => {
    if (window.ethereum) {
      console.log('meta mask 있음!');
    } else {
      console.log('meta mask 없음!');
    }
  });
};

 

여기 까지만 작성했을 때 에러가 터진다.

 

타입스크립트 에러인데, window 내에 ethereum이란 프로퍼티는 존재하지 않는다고 한다.

당연하다.

 

브라우저에 metamask가 설치가 되어있으면 브라우저의 전역객체에(window)에

ethereum을 추가해주는 거니까,

 

현재의 개발 환경에서의 전역객체 interface에는 ethereum이 없는게 당연한 얘기다.

그럼 뭐 어캄 타압 추가하면됨

 

stack-overflow 뒤지다가 발견한건데

src 디렉토리 안엔 react-app-env.d.ts 라는 파일이 있을거다.

 

없으면 만들어주고

/// <reference types="react-scripts" />

import { MetaMaskInpageProvider } from '@metamask/providers';

declare global {
  interface Window {
    ethereum?: MetaMaskInpageProvider;
  }
}

 

이거 입력해주면 된다.

당연히

 

npm i @metamask/providers

 

도 해줘야 함.

이러면 말끔히 에러는 해결 됐다.

 

 

meta mask 체크는 끝

 

4-3. 현재 네트워크 확인 후 DApp에서 사용할 네트워크 추가 및 연결

metamask 사용자가 정말 많은 wallet 이긴 하지만,

사용법이 쉽지 만은 않다.

 

새로운 이더리움 계열 네트워크와 통신을 하고 싶다면,

메타마스크 설정에서 네트워크를 추가해주는 작업을 해야하는데 제법 귀찮다.

 

그런데 만약 내가만든 웹페이지에 들어가면, 자동으로 내가 통신할 네트워크를 추가하고

추가된 네트워크로 연결까지 해준다면 사용성이 높아질 것이다.

 

그럼 현재 metamask가 어떤 네트워크와 연결 되어있는지 확인해보자.

 

 

현재는 메인넷으로 연결되어있다.

window.ethereum의 역할을 메타마스크의 존재여부만 확인하는데서 그치지 않는다.

 

request 메서드를 통해 메타마스크로 요청을 보낼수 있는 역할도 존재한다.

이번에 사용할건 eth_chainId,

이걸 사용하면 현재 연결된 chainId를 16 진수로 변환해서 보여준다.

 

import { useEffect, useState } from 'react';

export const useWeb3 = () => {
  const [account, setAccount] = useState(false);

  useEffect(() => {
    (async function () {
      if (window.ethereum !== undefined) {
        const chainId = await window.ethereum.request({
          method: 'eth_chainId',
        });
        console.log(chainId);
      }
    })();
  });
};

 

useEffect 콜백에 async/await 을 못써서 즉시 실행함수를 콜백안에 집어넣었음.

 

무튼 콜솔로 찍힌 내용을 확인해보면

 

 

 

이런게 찍혔다.

 

그리고 아까 우리가 ganache-cli 실행하면서 chainId를 설정해줬다.

그건 7722 였음

 

7722를 16진수로 변환하면 0x1e2a가 된다.

 

현재 chainId랑 7722를 16진수로 변환한 값이랑 일치하는지 확인해보고 일치하지 않으면,

연결을하면 될것 같다.

 

근데 useEffect가 너무 길어질거 같아서 함수좀 빼면서 작성해보려한다.

 

import { MetaMaskInpageProvider } from '@metamask/providers';

import { useEffect, useState } from 'react';

export const useWeb3 = () => {
  const [account, setAccount] = useState(false);

  const getCurChainId = async () => {
    const eth = window.ethereum as MetaMaskInpageProvider;
    const curChainId = await eth.request({
      method: 'eth_chainId',
    });

    return curChainId;
  };

  const addAndConnNetwork = async (chainId: string) => {
    const eth = window.ethereum as MetaMaskInpageProvider;

    const network = {
      chainId,
      chainName: 'kongTest',
      rpcUrls: ['http://127.0.0.1:8545'],
      nativeCurrency: {
        name: 'Ethereum',
        symbol: 'ETH',
        decimals: 18,
      },
    };

    await eth.request({
      method: 'wallet_addEthereumChain',
      params: [network],
    });
  };

  useEffect(() => {
    (async function () {
      if (window.ethereum !== undefined) {
        const curChainId = await getCurChainId();
        const targetChainId = '0x1e2a';

        if (curChainId !== targetChainId) {
          await addAndConnNetwork(targetChainId);
        }
      }
    })();
  });
};

 

현재 연결된 chainId, targetChainId 비교해서 서로 다를경우

addAndConnNetwork 함수를 호출한다.

 

해당 함수는 wallet_addEthereumChain 이라는 메서드를 metamask로 요청을 보낸다.

인자값은 params에 배열로 들어가는데,

해당 메서드같은 경우는 네트워크 객체를 인수로 받는다.

 

network의 내용은

chainId는 연결한 chainId 이고,

chainName은 메타마스크에 보여줄 네트워크의 이름

rpcurls 는 통신할 url 주소이다.

 

nativeCurrency 같은 경우는 화폐의 단위에 대한 내용인데

나머지는 그닥 중요하지 않고,

마지막의 decimals는 10의 18 승이 1ETH 다 라는 내용이다.

 

오타없이 제대로 작성했다면,

새로고침을 했을 때, 아래의 사진과 같은 화면이 뜨는게 정상이다.

 

 

스크롤을 내려서 승인 이어서 전환 까지 눌러준 뒤,

다시 메타마스크 네트워크 상태를 확인해보면

 

 

요렇게,

아주 기가 맥힌다.

 

4-3. 연결된 계정 가져오기

우선 ganache 로 생성된 privateKey를 통해 metamask에 계정을 추가해주자.

 

 

음 부자가 된 기분이다.

그리고 코드 작성

 

import { MetaMaskInpageProvider } from '@metamask/providers';

import { useEffect, useState } from 'react';

export const useWeb3 = () => {
  // 변경
  const [account, setAccount] = useState<string>('');


  const getCurChainId = async () => {
    const eth = window.ethereum as MetaMaskInpageProvider;
    const curChainId = await eth.request({
      method: 'eth_chainId',
    });

    return curChainId;
  };

  const addAndConnNetwork = async (chainId: string) => {
    const eth = window.ethereum as MetaMaskInpageProvider;

    const network = {
      chainId,
      chainName: 'kongTest',
      rpcUrls: ['http://127.0.0.1:8545'],
      nativeCurrency: {
        name: 'Ethereum',
        symbol: 'ETH',
        decimals: 18,
      },
    };

    await eth.request({
      method: 'wallet_addEthereumChain',
      params: [network],
    });
  };

  // 추가된 함수
  const getAccount = async () => {
    const eth = window.ethereum as MetaMaskInpageProvider;

    const account = await eth.request({
      method: 'eth_requestAccounts',
    });

    return account;
  };

  useEffect(() => {
    (async function () {
      if (window.ethereum !== undefined) {
        const curChainId = await getCurChainId();
        const targetChainId = '0x1e2a';

        if (curChainId !== targetChainId) {
          await addAndConnNetwork(targetChainId);
        }
                // 추가된 부분
        const [account] = (await getAccount()) as string[];
        console.log(account); //연결된 계정이 출력된다
        setAccount(account);
      }
    })();
  });
};

 

 

4-5. web3 연결

지금은 이걸 왜하나 싶지만

추후 작업을 여기서 계속 이어붙여 나갈건데,

그때 빛을 발할 아이다.

 

일단 그냥 해주자.

 

그런데 여기서 문제가 터진다.

에러가 빵빵 터지는데,

 

음 당황하지 말자.

 

stack overflow에서 해결법을 찾았다.

 

여기 답변중에 1월 4일에 달린 mseemann의 답변을 참조해서 그대로 하면된다.

 

근데 나같은 경우에는 이대로 했는데도 에러가 하나 남더라

url 어쩌구 였는데

 

npm i url

 

하니까 해결 됐다.

 

import { MetaMaskInpageProvider } from '@metamask/providers';
import Web3 from 'web3';

import { useEffect, useState } from 'react';

export const useWeb3 = () => {
  const [account, setAccount] = useState<string>('');
  //추가된 코드
  const [web3, setWeb3] = useState<Web3 | undefined>(undefined);

  const getCurChainId = async () => {
    const eth = window.ethereum as MetaMaskInpageProvider;
    const curChainId = await eth.request({
      method: 'eth_chainId',
    });

    return curChainId;
  };

  const addAndConnNetwork = async (chainId: string) => {
    const eth = window.ethereum as MetaMaskInpageProvider;

    const network = {
      chainId,
      chainName: 'kongTest',
      rpcUrls: ['http://127.0.0.1:8545'],
      nativeCurrency: {
        name: 'Ethereum',
        symbol: 'ETH',
        decimals: 18,
      },
    };

    await eth.request({
      method: 'wallet_addEthereumChain',
      params: [network],
    });
  };

  const getAccount = async () => {
    const eth = window.ethereum as MetaMaskInpageProvider;

    const account = await eth.request({
      method: 'eth_requestAccounts',
    });

    return account;
  };

  useEffect(() => {
    (async function () {
      if (window.ethereum !== undefined) {
        const curChainId = await getCurChainId();
        const targetChainId = '0x1e2a';

        if (curChainId !== targetChainId) {
          await addAndConnNetwork(targetChainId);
        }

        const [account] = (await getAccount()) as string[];
        setAccount(account);
                // 추가된 코드
        const web3 = new Web3((window as any).ethereum);
        setWeb3(web3);
      }
    })();
  });
};

 

4-5. 연결된 계정의 밸런스 보여주기

이제 커스텀 훅 작성은 거의 완료 되었다.

마지막에 return 을 account와 web3를 배열에 담아 해주면 된다.

 

import { MetaMaskInpageProvider } from '@metamask/providers';
import Web3 from 'web3';

import { useEffect, useState } from 'react';
// 리턴 타입 지정
export const useWeb3 = (): [string, Web3 | undefined] => {
  const [account, setAccount] = useState<string>('');
  const [web3, setWeb3] = useState<Web3 | undefined>(undefined);

  const getCurChainId = async () => {
    const eth = window.ethereum as MetaMaskInpageProvider;
    const curChainId = await eth.request({
      method: 'eth_chainId',
    });

    return curChainId;
  };

  const addAndConnNetwork = async (chainId: string) => {
    const eth = window.ethereum as MetaMaskInpageProvider;

    const network = {
      chainId,
      chainName: 'kongTest',
      rpcUrls: ['http://127.0.0.1:8545'],
      nativeCurrency: {
        name: 'Ethereum',
        symbol: 'ETH',
        decimals: 18,
      },
    };

    await eth.request({
      method: 'wallet_addEthereumChain',
      params: [network],
    });
  };

  const getAccount = async () => {
    const eth = window.ethereum as MetaMaskInpageProvider;

    const account = await eth.request({
      method: 'eth_requestAccounts',
    });

    return account;
  };

  useEffect(() => {
    (async function () {
      if (window.ethereum !== undefined) {
        const curChainId = await getCurChainId();
        const targetChainId = '0x1e2a';

        if (curChainId !== targetChainId) {
          await addAndConnNetwork(targetChainId);
        }

        const [account] = (await getAccount()) as string[];
        setAccount(account);

        const web3 = new Web3((window as any).ethereum);
        setWeb3(web3);
      }
    })();
  });
    // 리턴 추가
  return [account, web3];
};

 

열심히 만든 커스텀 훅 이제 App.tsx에서 불러와서 사용해보자.

 

import React, { useEffect, useState } from 'react';
import { useWeb3 } from './hooks/useWeb3';
import './App.css';

function App() {
  const [account, web3] = useWeb3();
  const [isLogin, setIsLogin] = useState<Boolean>();
  const [balance, setBalance] = useState<number>();

  useEffect(() => {
    (async function () {
      const balance = await web3?.eth.getBalance(account);
      if (balance !== undefined) {
        setBalance(Number(balance) / 10 ** 18);
      }
    })();

    if (account === '') {
      setIsLogin(false);
    } else {
      setIsLogin(true);
    }
  }, [account]);

  return (
    <div className="App">
      <h1>Hello CRA-TS!</h1>
      {isLogin ? (
        <>
          <div>
            <h3>Accounts Info</h3>
            <ul>
              <li>Account : {account}</li>
              <li>Balance : {balance} ETH</li>
            </ul>
          </div>
          <div>
            <h3>Transaction</h3>
            <form action="">
              <ul>
                <li>
                  <input type="text" id="received" placeholder="받을 사람" />
                </li>
                <li>
                  <input type="text" id="amount" placeholder="보낼 금액" />
                </li>
                <li>
                  <button type="submit">전송!!</button>
                </li>
              </ul>
            </form>
          </div>
        </>
      ) : (
        <div>메타마스크 설치해주세여</div>
      )}
    </div>
  );
}

export default App;

 

음.. 이건 설명할게 전혀 없음.

중요한 작업은 커스텀훅에서 다 했음.

 

web3통해서 잔액조회 하는거는 저번 포스팅에서 했기 때문에 설명 생략함

 

4-6 Transaction

다왔다 트랜잭션만 만들면 된다.

이거 쉬움

 

폼태그에 onSubmit attribute 추가해주고,

실행할 함수 작성해주면 되는데,

그 작업 web3가 아주 손쉽게 해준다.

 

import React, { useEffect, useState } from 'react';
import { useWeb3 } from './hooks/useWeb3';
import './App.css';

function App() {
  const [account, web3] = useWeb3();
  const [isLogin, setIsLogin] = useState<Boolean>();
  const [balance, setBalance] = useState<number>();
  // 상태추가
  const [amount, setAmount] = useState<number | undefined>(undefined);
  const [received, setReceived] = useState<string | undefined>(undefined);
// input onChange 함수
  const changeReceived = (e: React.ChangeEvent<HTMLInputElement>) => {
    setReceived(e.target.value);
  };

  const changeAmount = (e: React.ChangeEvent<HTMLInputElement>) => {
    setAmount(Number(e.target.value));
  };
//Tx 발생 함수
  const fireTx = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    await web3?.eth.sendTransaction({
      from: account,
      to: received,
      value: amount,
    });
  };

  useEffect(() => {
    (async function () {
      const balance = await web3?.eth.getBalance(account);
      if (balance !== undefined) {
        setBalance(Number(balance) / 10 ** 18);
      }
    })();

    if (account === '') {
      setIsLogin(false);
    } else {
      setIsLogin(true);
    }
  }, [account]);

  return (
    <div className="App">
      <h1>Hello CRA-TS!</h1>
      {isLogin ? (
        <>
          <div>
            <h3>Accounts Info</h3>
            <ul>
              <li>Account : {account}</li>
              <li>Balance : {balance} ETH</li>
            </ul>
          </div>
          <div>
            <h3>Transaction</h3>
          // onSubmit 추가
            <form action="" onSubmit={fireTx}>
              <ul>
                <li>
                  // onchange 추가
                  <input
                    type="text"
                    id="received"
                    placeholder="받을 사람"
                    onChange={changeReceived}
                  />
                </li>
                <li>
                  // onchange 추가
                  <input
                    type="text"
                    id="amount"
                    placeholder="보낼 금액"
                    onChange={changeAmount}
                  />
                </li>
                <li>
                  <button type="submit">전송!!</button>
                </li>
              </ul>
            </form>
          </div>
        </>
      ) : (
        <div>메타마스크 설치해주세여</div>
      )}
    </div>
  );
}

export default App;

 

위의 코드로 테스트를 해보다가 type때문에 발생한 작은 이슈로 인해

아래의 코드로 수정하였다.

 

크게 달라진건 없으니 따로 설명은 하지 않겠음

 

import React, { useEffect, useState } from 'react';
import { useWeb3 } from './hooks/useWeb3';
import './App.css';

function App() {
  const [account, web3] = useWeb3();
  const [isLogin, setIsLogin] = useState<Boolean>();
  const [balance, setBalance] = useState<number>();
  const [amount, setAmount] = useState<string>('');
  const [received, setReceived] = useState<string>('');

  const changeReceived = (e: React.ChangeEvent<HTMLInputElement>) => {
    setReceived(e.target.value);
  };

  const changeAmount = (e: React.ChangeEvent<HTMLInputElement>) => {
    setAmount(e.target.value);
  };

  const fireTx = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    await web3?.eth.sendTransaction({
      from: account,
      to: received,
      value: web3.utils.toWei(amount, 'ether'),
    });
  };

  useEffect(() => {
    (async function () {
      const balance = await web3?.eth.getBalance(account);
      if (balance !== undefined) {
        setBalance(Number(balance) / 10 ** 18);
      }
    })();

    if (account === '') {
      setIsLogin(false);
    } else {
      setIsLogin(true);
    }
  }, [account]);

  return (
    <div className="App">
      <h1>Hello CRA-TS!</h1>
      {isLogin ? (
        <>
          <div>
            <h3>Accounts Info</h3>
            <ul>
              <li>Account : {account}</li>
              <li>Balance : {balance} ETH</li>
            </ul>
          </div>
          <div>
            <h3>Transaction</h3>
            <form action="" onSubmit={fireTx}>
              <ul>
                <li>
                  <input
                    type="text"
                    id="received"
                    placeholder="받을 사람"
                    onChange={changeReceived}
                  />
                </li>
                <li>
                  <input
                    type="text"
                    id="amount"
                    placeholder="보낼 금액"
                    onChange={changeAmount}
                  />
                </li>
                <li>
                  <button type="submit">전송!!</button>
                </li>
              </ul>
            </form>
          </div>
        </>
      ) : (
        <div>메타마스크 설치해주세여</div>
      )}
    </div>
  );
}

export default App;

이제 실행을 해보자

 

 

현재 metamask에 두개의 계정을 연결했고

account2 에서 3으로 10 eth를 보내려고 한다.

 

 

전송버튼을 누르면

 

 

크으.. 확인을 눌러서 트랜잭션을 발생시키고,

새로고침을 한번 해보면!

 

 

10ETH가 이동한 것을 확인할수 있다..!

728x90
728x90

댓글