Ethereum - 사과가게 만들기

728x90

목차

1. 목표

2. 관련 패키지

3. truffle 설치 및 세팅

4. 코드 작성하기

5. 확인하기

 

 

 

 

사과 가게

1. 목표

  • 1 ETH를 이용해서 사과 1개를 산다.
  • 내 계정이 가지고 있는 사과의 개수를 보여준다.
  • 내가 가진 모든 사과를 한 번에 환불할 수 있다. (CA의 값이 줄고 EOA의 값이 늘어난다.)

2. 관련 패키지

  • react
  • ganache-cli
  • truffle
  • web3

 

3. truffle 설치 및 세팅

$ npx truffle init

 

truffle-config.js

ganache-cli를 이용해서 로컬환경에서 테스트를 진행하기 위해서 development 주석을 해제한다.




4. 코드 작성하기

$ npx create-react-app front

4-1.App.jsx

import useWeb3 from "./hooks/useWeb3"
import AppleShop from "./pages/appleShop"

const App = () => {
    const [account, web3] = useWeb3()
    if (!account || !web3) return <> 메타마스크와 연결 후 사용해주세요!</>
    return (
        <>
            <h1> 사과가게 </h1>
            <AppleShop web3={web3} account={account} />
        </>
    )
}
export default App



4-2.hooks/useWeb3.js

import { useEffect, useState } from "react"
import Web3 from "web3"

const useWeb3 = () => {
    const [account, setAccount] = useState(null)
    const [web3, setWeb3] = useState(null)
    const init = async () => {
        try {
            const [account] = await window.ethereum.request({ method: "eth_requestAccounts" })
            const web3 = new Web3(window.ethereum)
            setAccount(account)
            setWeb3(web3)
        } catch (e) {
            setAccount(null)
            setWeb3(null)
        }
    }
    useEffect(() => {
        if (!window.ethereum) return
        init()
    }, [])
    return [account, web3]
}

export default useWeb3

사용자에게 직접 서명을 얻는 것이 아닌 메타마스크에 저장되어 있는 개인키로 서명을 하는 과정을 위해서 브라우저에서 메타마스크에 연동하여 web3를 이용해서 네트워크에 요청한다.



4-3.contract/appleShop.sol

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract AppleShop {
    mapping (address=>uint256) public myApple;

    function buy() public payable {
        myApple[msg.sender] += 1;
    }

    function get() public view returns(uint256){
        return myApple[msg.sender];
    }

    //전체 환불
    function sell() public payable {
        uint256 refund = myApple[msg.sender] * 10 ** 18; //1
        myApple[msg.sender] = 0;
        payable(msg.sender).transfer(refund);
    }
}

상태변수 myApple은 어떤 계정이 얼마의 사과를 가지고 있는지 확실하게 알기 위해서 키-값형태로 관리하는 것이 좋다.

 

payable

스마트 컨트랙트를 작성할 때 함수 부분에 payable 키워드를 작성하게 되면 해당 함수가 'ETH'를 받을 수 있다는 것을 의미한다.

function A () public payable {
    // 함수에서 이더를 받을 수 있다.
}

CA계정에서 EOA로 이더를 보낼 때 payable을 작성하여 해당 주소로 이더를 보내줄 수 있다.

payable(msg.sender).transfer(/* 주소가 받을 이더의 양*/)

transfer() 함수는 호출을 하는 CA의 ETH를 msg.sender에게 보내준다.



4-4.migrations/1_deploy_appleShop.js

배포를 위해서 마이그레이션 파일을 작성한다.

const AppleShop = artifacts.require("appleShop")

module.exports = (deployer) => {
    deployer.deploy(AppleShop)
}
$ npx truffle migrate

생성된 json파일을 src/contract/AppleShop.json 디렉터리 생성 후 추가 해준다.



4-5.pages/appleShop.jsx

import { useEffect, useState } from "react"
import AppleShopContract from "../contract/AppleShop.json"

const AppleShop = ({ web3, account }) => {
    const [deployed, setDeployed] = useState(null)
    const [apple, setApple] = useState(0)

    const buy = async () => {
        await deployed.methods.buy().send({
            from: account,
            value: web3.utils.toWei("1", "ether"),
        })
        get()
    }

    const sell = async () => {
        await deployed.methods.sell().send({
            from: account,
        })
        get()
    }

    const get = async () => {
        if (!deployed) return
        try {
            const apple = await deployed.methods.get().call()
            setApple(apple)
        } catch (e) {
            console.log(e.message)
        }
    }

    useEffect(() => {
        get()
    }, [deployed])

    useEffect(() => {
        //CALL
        if (!web3) return
        const instance = new web3.eth.Contract(AppleShopContract.abi, "0x597d8e20f66c89c1d2b38817f1af3588c7156d8c")
        setDeployed(instance)
    }, [])

    return (
        <>
            <h2>사과 가격 : 1ETH</h2>
            <div>
                내가 가진 사과 개수 : {apple}
                <button onClick={buy}>사과 구매</button>
            </div>
            <div>
                총 사과 판매 가격 : 1ETH <button onClick={sell}>사과 판매</button>
            </div>
        </>
    )
}

export default AppleShop



 

5. 확인하기

메타마스크에 가나쉬 네트워크가 연결되어 있지 않다면 화면이 제대로 렌더링 되지 않을 것이다. 

 

메타마스크 설치 및 계정에 연결을 하면 맨 위의 목표에 있었던 화면이 보인다.

 

사과구매 버튼을 누르면 메타마스크와 연동되어 서명을 포함한 트랜잭션 생성 후 가나쉬 네트워크로 요청 후 블록이 담기면 화면에서 볼 수 있다. 

사과판매 버튼을 누르면 내가 보유한 개수를 * 1 ETH만큼을 반환되는 로직이 구현되어 있다.

 

당연히 스마트 컨트랙트를 배포하거나 send() 함수를 사용하게 되면서 가스 소비가 생기니 맨 처음 잔액보다는 적다!!

 

 


 

반응형