스마트 컨트랙트 기본세팅
// 위의 작업 이후 이어짐
// 현재 경로 : 최상위폴더/contracs
// Fruitshop.sol파일 생성
// Fruitshop.sol파일 내용
pragma solidity >=0.4.22 <0.9.0;
contract Fruitshop {
mapping(address=>uint) myApple;
constructor () public {
}
function buyApple() payable external{
myApple[msg.sender]++;
}
function getMyApple() public view returns(uint){
return myApple[msg.sender];
}
function sellApple(uint _applePrice) payable external {
uint totalPrice = (myApple[msg.sender] * _applePrice);
myApple[msg.sender] = 0;
msg.sender.transfer(totalPrice);
}
}
// migration폴더 안에 Fruitshop관련 배포를 위한 파일을 생성하겠다는 의미
//기존 내용
module.exports = function(_deployer) {
// Use deployer to state migration tasks.
};
-------------------------------------------------------------------------------
// 추가된 내용
var Fruitshop = artifacts.require("./Fruitshop.sol");
// 이는 contract폴더에 생성한 파일을 가져오는 것임.
module.exports = function(_deployer) {
_deployer.deploy(Fruitshop);
};
-- 기존에 client-src-contracts해당 경로의 폴더 내에 파일이 존재시에는 파일들 삭제 후
// 현 경로 최상위폴더
-- 터미널에 입력
>> truffle compile
>> truffle migrate
import React, {useState, useEffect,useReducer } from "react";
import FruitshopContract from "./contracts/Fruitshop.json";
// SimpleStorage.json은 컴파일하면 생성되는 파일로 abi,bin파일에 대한 내용이 합쳐져서 담겨있다.
import getWeb3 from "./getWeb3";
// promise 객체로 되어있다. -> async await로 가져와야함
import "./App.css";
const App = () => {
const [myApple,setMyApple] = useState(0);
let initialState = {web3:null,instance:null,account:null}
const [state,dispatch] = useReducer(reducer,initialState)
function reducer(state,action) {
switch(action.type){
case "INIT":
let {web3,instance,account} = action
return{
...state,
web3,
instance,
account
}
}
}
const buyApple = async () => {
let {instance,account} = state;
await instance.buyApple({
from:account,
value:10000000000000000000,
gas:90000,
})
setMyApple(prev=>prev+1)
}
const sellApple = async () => {
let {instance, account,web3} = state
await instance.sellApple(web3.utils.toWei("10","ether"),{
//web3.utils.toWei --> wei 단위로 바꾸어줌
// toWei의 인자값
// 첫번째 ==> 내가 보낼 이더
// 두번째 ==> 단위
from:account,
gas:90000
})
}
const getApple = async (instance) => {
if(instance == null) return
let result = await instance.getMyApple();
setMyApple(result.toNumber())
}
const getweb = async () => {
const contract = require('@truffle/contract');
// require는 가능한 사용하지 않는 게 좋음
// 특히나 함수 밖에서 사용시 오류 발생 가능성 매우 높음
let web3 = await getWeb3();
let fruitshop = contract(FruitshopContract);
fruitshop.setProvider(web3.currentProvider);
let instance = await fruitshop.deployed();
let accounts = await web3.eth.getAccounts();
// 계정가져오기
// web3를 통해 metamask에 있는 주소 가져오기 가능
console.log(accounts)
let InitActions = {
type:"INIT",
web3,
instance,
account:accounts[0]
}
dispatch(InitActions);
// reducer를 이용해서 web과 instance, account값 상태에 저장.
getApple(instance)
// 함수의 마지막 시점에서 현재 내가고 있는 사과 리턴해줌.
// 즉 페이지가 로드(렌더링)되는 시점에서 현재 내가 가진 사과 리턴해줌.
}
/*reducer 내용
let initialState = {web3:null,instance:null,account:null}
const [state,dispatch] = useReducer(reducer,initialState);
function reducer(state,action){
switch(action.type){
case "INIT":
let {web3,instance,account} = action
return{
...state,
web3,
instance,
account
}
}
}
*/
useEffect(()=>{
getweb()
},[])
// useEffect를 사용하여 페이지 완료시 요청을 한 번 보내고 결과물을 화면에 띄어줌
return(
<div>
<h1>사과가격 : 10ETH</h1>
<button onClick={()=>buyApple()}>Buy</button>
{/*함수 호출은 함수에 담아서 바로 함수가 실행되는 것을 막음 */}
<p>내가 가진 사과 : {myApple}</p>
<button onClick={()=>sellApple()}>Sell(판매가격은:{myApple*10}ETH)</button>
</div>
)
}
export default App;
>>npm run start
//이렇게 하고 오류남
// 원인 : '@truffle/contract' 를 설치해주지 않아서 반드시 설치해주어야함