사과가게 만들기
함수의 payable 개념
- payable 키워드가 있어야만 tx 객체의 to 속성값인 CA 계정으로, value 속성값인 ETH를 줄 수 있다.
- 즉, tx 객체를 보낼 때, value 속성에 이더를 넣기 위해서 payable를 작성해주어야 한다,
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
contract AppleShop{
mapping(address => uint) myApple;
// 구매: myApple 변수의 address에 사과 갯수++,
// tx 객체 보낼 때 단위당 사과 갯수 만큼 value값을 주기 위해 payable 작성
function buyApple() public payable {
myApple[msg.sender]++;
}
// 환불: 스마트 컨트랙트에 보관해놓은 모든 돈을 돌려 받는 것과 같은 느낌
// 해당 계정의 사과 갯수를 0으로 만들고
function sellApple(uint _applePrice) public payable{
uint256 refund = myApple[msg.sender] * _applePrice;
myApple[msg.sender] = 0;
payable(msg.sender).transfer(refund);
// 어드레스 타입의 계정에 돈을 보내는 행위를 할 수 있게 하기 위해
// payable(bytes20)의 명시적인 타입 변환 방식을 통해 transfer() 메서드 사용
}
function getApple() view public returns(uint){
return myApple[msg.sender];
}
}
프론트 코드 작성
프론트 코드?
counter 만들었던 코드랑 비슷하다.
appleShop의 구매, 환불 버튼 클릭 시 실행되는 온클릭 함수 부분만 눈여겨 보면 된다.
// front/src/hooks/useWeb3.jsx
import { useState, useEffect } from "react";
import Web3 from "web3/dist/web3.min.js";
const useWeb3 = () => {
const [account, setAccount] = useState();
const [web3, setWeb3] = useState();
const getAccount = async () => {
const [account] = await window.ethereum.request({
method: "eth_requestAccounts",
});
return account;
};
useEffect(() => {
(async () => {
if (!window.ethereum) return;
const account = await getAccount();
const web3 = new Web3(window.ethereum);
setAccount(account);
setWeb3(web3);
})();
}, []);
return [web3, account];
};
export default useWeb3;
// front/app.jsx
import logo from "./logo.svg";
import useWeb3 from "./hooks/useWeb3";
import "./App.css";
import AppleShop from "./components/AppleShop";
function App() {
const [web3, account] = useWeb3();
if (!account) return <div> 돌아가 </div>;
return (
<div className="App">
<h2> AppleShop </h2>
<h3> Account: {account} </h3>
<AppleShop _web3={web3} _account={account}></AppleShop>
</div>
);
}
export default App;
// front/src/components/AppleShop.jsx
import { useState, useEffect } from "react";
import AppleShopContract from "../contracts/AppleShop.json";
const AppleShop = ({ _account, _web3 }) => {
const [apple, setApple] = useState(0);
const [deployed, setDeplyed] = useState();
//바로 이부분. contract 작성 시 함수에 payable를 달아주었기 때문에 tx 객체에 value 값(단위: wei)을 줄 수 있게 되었다.
const getBuy = async () => {
await deployed.methods.buyApple().send({
from: _account,
to: "0x2B77E2d6B41f693732F507d65791983060dCbfC3", //CA 계정
value: _web3.utils.toWei("1", "Ether"),
});
const current = await deployed.methods.getApple().call();
setApple(current);
};
//마찬가지. contract 작성 시 함수에 payable를 달아주었기 컨트랙트의 함수 내부에서 transfer()메서드 호출이 가능했다.
const getRefund = async () => {
const ether = _web3.utils.toWei("1", "ether");
await deployed.methods.sellApple(ether).send({
from: _account,
to: "0x2B77E2d6B41f693732F507d65791983060dCbfC3", //CA 계정
});
const current = await deployed.methods.getApple().call();
setApple(current);
};
useEffect(() => {
(async () => {
const { abi } = AppleShopContract;
const CA = "0x2B77E2d6B41f693732F507d65791983060dCbfC3";
const instance = await new _web3.eth.Contract(abi, CA);
const current = await instance.methods.getApple().call();
setDeplyed(instance);
setApple(current);
})();
}, []);
return (
<>
<h3> 개당 사과 가격: 1ETH </h3>
<div> 나의 사과 갯수: {apple}</div>
<button onClick={getBuy}> 구매하기 </button>
<button onClick={getRefund}> 환불하기 </button>
</>
);
};
export default AppleShop;
'블록체인 > 솔리디티' 카테고리의 다른 글
ERC20토큰 (0) | 2022.07.21 |
---|---|
address 타입의 분류: address / address payable (0) | 2022.07.20 |
솔리디티 문법 실행 (0) | 2022.07.11 |
댓글