좋아좋아!!!!!!
맑은 정신으로 수업을 듣는거야!!!!!!
솔리디티 코드를 배포하면 하나의 주소를 반환해준다.
'서명'이라는 단계가 존재함
서명: 블록체인 네트워크의 컨트랙트를 사용하기 직전에 나오는 확인받는 절차임
- 메타마스크를 통해 사용자가 '확인'버튼을 눌러서 직접 서명하는 방식
(지갑을 통해 서명하는 방식)(저번 시간에 했던 방식)- 사용자가 직접 서명하지만 Server를 거쳤다가 서명하는 방식
서명하기 전에 백엔드 서버에서 DB를 거쳐서 정보를 저장하고 프론트에 '확인'버튼을 누르도록 한다.- 서버에서 서명까지 완료하는 작업
사용자는 메타마스크가 필요가 없다. 서명할 필요가 없어서.
서버가 바로 블록체인 네트워크에 뿌리고 그리고 사용자에게 서버가 정보르 전달해준다.
흔히 거래소임.
비밀키가 필요함.
트랜잭션을 일으킬 때 필요함.
라이트코인에서 getnewaddress는 비밀키와 암호키를 함축하고 있는 API였다. 그래서 그 주소로 sendtoaddress로 보내면 로컬과 서버의 작업이 이루어진 것이었다.
const path = require("path");
module.exports = {
// See <http://truffleframework.com/docs/advanced/configuration>
// to customize your Truffle configuration!
contracts_build_directory: path.join(__dirname, "client/src/contracts"),
networks: {
develop: {
host:"127.0.0.1",
port: 7545,
network_id:"*"
}
}
};
event Change(string message, uint newVal);
를 추가해줌으로써 이벤트를 선언한다.
그리고
function set(uint x) public {
storedData = x;
emit Change("set",x);
}
를 추가해줌으로써 이벤트를 정의한다.
전체코드
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
contract SimpleStorage {
uint storedData;
//이벤트를 만든다. 웹소켓 코드를 써준다고 생각하면 편하다.
event Change(string message, uint newVal); //이벤트의 선언
function set(uint x) public {
storedData = x;
emit Change("set",x);
}
function get() public view returns (uint) {
return storedData;
}
}
npx truffle compile
npx truffle migrate
작업을 하면 된다.
import React, { useState,useEffect } from "react";
import SimpleStorageContract from "./contracts/SimpleStorage.json";
import getWeb3 from "./getWeb3";
import "./App.css";
const App=()=>{
const [value,setValue]=useState(0);
const [storage,setStorage] = useState(0);
const [loadding,setLoadding] = useState(false);
const handleResult =()=>{
setStorage(value);
setLoadding(prev=>!prev)
}
const handleChange = (e) =>{
let val = e.target.value;
setValue(val);
}
//button 함수
const send =()=>{
if(value > 0){
setLoadding(prev=>!prev);
//비동기적 처리
handleResult()
}
}
const sendAPI = ()=> {
if(value > 0){
setLoadding(prev=>!prev);
//비동기적 처리
handleResult()
}
}
const sendTx = () => {
if(value > 0){
setLoadding(prev=>!prev);
handleResult()
}
}
const init = async() => {
const contract=require('@truffle/contract');
const web3 = await getWeb3();
const [account] = await web3.eth.getAccounts();//하나인거 알고 있을 때는 이렇ㄹ게 쓰자
// const networkId= await web3.eth.net.getId();//네트워크 아이들 가져올 수 있다.
let simpleStorage = contract(SimpleStorageContract);
simpleStorage.setProvider(web3.currentProvider);
const Instance = await simpleStorage.deployed();
console.log(Instance);
}
useEffect(()=>{
init();
},[])
return (
<div>
<input type = "text" value={value} onChange={handleChange}/>
<div>
<button onClick={send}>일반 서명</button>
<button onClick={sendAPI}>DB거치고 서명</button>
<button onClick={sendTx}>DB 서명</button>
</div>
<div>
{loadding? `loading`:storage}
</div>
</div>
)
}
export default App;
하면 콘솔창에 이렇게 address에 대해서도 뜬다.
계좌가 하나일때는 이렇게 써주도록 하자.
const [account] = await web3.eth.getAccounts();
import React, { useState,useEffect,useReducer } from "react";
import SimpleStorageContract from "./contracts/SimpleStorage.json";
import getWeb3 from "./getWeb3";
import "./App.css";
const reducer = (state,action)=>{
switch(action.type){
case "INIT":{
let {web3,Instance,account} = action;
return {
...state,web3,Instance,account
}
}
}
}
const INIT_ACTIONS=(web3,Instance,account)=>{
return{ type:'INIT',web3,Instance,account}
}
const App=()=>{
const initialState={
web3:null,
Instance:null,
account:null,
}
const [state,dispatch]=useReducer(reducer,initialState);
const [value,setValue]=useState(0);
const [storage,setStorage] = useState(0);
const [loadding,setLoadding] = useState(false);
const handleResult =()=>{
setStorage(value);
setLoadding(prev=>!prev)
}
const handleChange = (e) =>{
let val = e.target.value;
setValue(val);
}
//button 함수
const send =()=>{
if(value > 0){
setLoadding(prev=>!prev);
//비동기적 처리
handleResult()
}
}
const sendAPI = ()=> {
if(value > 0){
setLoadding(prev=>!prev);
//비동기적 처리
handleResult()
}
}
const sendTx = () => {
if(value > 0){
setLoadding(prev=>!prev);
handleResult()
}
}
const init = async() => {
const contract=require('@truffle/contract');
const web3 = await getWeb3();
const [account] = await web3.eth.getAccounts();//하나인거 알고 있을 때는 이렇ㄹ게 쓰자
// const networkId= await web3.eth.net.getId();//네트워크 아이들 가져올 수 있다.
let simpleStorage = contract(SimpleStorageContract);
simpleStorage.setProvider(web3.currentProvider);
const Instance = await simpleStorage.deployed();
console.log(Instance);
}
useEffect(()=>{
init();
},[])
return (
<div>
<input type = "text" value={value} onChange={handleChange}/>
<div>
<button onClick={send}>일반 서명</button>
<button onClick={sendAPI}>DB거치고 서명</button>
<button onClick={sendTx}>DB 서명</button>
</div>
<div>
{loadding? `loading`:storage}
</div>
</div>
)
}
export default App;
React dev-tool로 확인할 수 있다.
import React, { useState,useEffect,useReducer } from "react";
import SimpleStorageContract from "./contracts/SimpleStorage.json";
import getWeb3 from "./getWeb3";
import "./App.css";
const reducer = (state,action)=>{
switch(action.type){
case "INIT":{
let {web3,Instance,account} = action;
return {
...state,web3,Instance,account
}
}
}
}
const INIT_ACTIONS=(web3,Instance,account)=>{
return{ type:'INIT',web3,Instance,account}
}
const App=()=>{
const initialState={
web3:null,
Instance:null,
account:null,
}
const [state,dispatch]=useReducer(reducer,initialState);
const [value,setValue]=useState(0);
const [storage,setStorage] = useState(0);
const [loadding,setLoadding] = useState(false);
const handleResult =()=>{
setStorage(value);
setLoadding(prev=>!prev)
}
const handleChange = (e) =>{
let val = e.target.value;
setValue(val);
}
//button 함수
const send =()=>{
if(value > 0){
setLoadding(prev=>!prev);
//비동기적 처리
handleResult()
}
}
const sendAPI = ()=> {
if(value > 0){
setLoadding(prev=>!prev);
//비동기적 처리
handleResult()
}
}
const sendTx = () => {
if(value > 0){
setLoadding(prev=>!prev);
handleResult()
}
}
const init = async() => {
const contract=require('@truffle/contract');
const web3 = await getWeb3();
const [account] = await web3.eth.getAccounts();//하나인거 알고 있을 때는 이렇ㄹ게 쓰자
// const networkId= await web3.eth.net.getId();//네트워크 아이들 가져올 수 있다.
let simpleStorage = contract(SimpleStorageContract);
simpleStorage.setProvider(web3.currentProvider);
const Instance = await simpleStorage.deployed();
console.log(Instance);
dispatch(INIT_ACTIONS(web3,Instance,account))
}
useEffect(()=>{
init();
},[])
return (
<div>
<input type = "text" value={value} onChange={handleChange}/>
<div>
<button onClick={send}>일반 서명</button>
<button onClick={sendAPI}>DB거치고 서명</button>
<button onClick={sendTx}>DB 서명</button>
</div>
<div>
{loadding? `loading`:storage}
</div>
</div>
)
}
export default App;
init 부분 하기
const init = async() => {
const contract=require('@truffle/contract');
const web3 = await getWeb3();
const [account] = await web3.eth.getAccounts();//하나인거 알고 있을 때는 이렇ㄹ게 쓰자
// const networkId= await web3.eth.net.getId();//네트워크 아이들 가져올 수 있다.
let simpleStorage = contract(SimpleStorageContract);
simpleStorage.setProvider(web3.currentProvider);
const Instance = await simpleStorage.deployed();
console.log(Instance);
dispatch(INIT_ACTIONS(web3,Instance,account))
}
(event받아서 처리)
init함수에 더 추가한다.
const init = async() => {
const contract=require('@truffle/contract');
const web3 = await getWeb3();
const [account] = await web3.eth.getAccounts();//하나인거 알고 있을 때는 이렇ㄹ게 쓰자
// const networkId= await web3.eth.net.getId();//네트워크 아이들 가져올 수 있다.
let simpleStorage = contract(SimpleStorageContract);
simpleStorage.setProvider(web3.currentProvider);
const Instance = await simpleStorage.deployed();
console.log(Instance);
dispatch(INIT_ACTIONS(web3,Instance,account))
web3.eth.subscribe("logs",{address:Instance.address})//사용자의 어드레스가 아니라 contract계정의 address임
.on('data',log=>{
console.log(log)
})
.on('error',err=>console.log(err))
}
데이터를 이상하게 보내준다. 컴퓨터가 사용하기 편한 값으로 보내준다. 그래서 우리는 변경해서 보내주어야 한다.
그리고 이제 send, sendAPI, sendTx의 handleresult()를 삭제해준다.
hadleResult 메소드를 다음과 같이 수정한다.
const handleResult =(log,web3)=>{
const params=[
{type:'string',name:'message'},
{type:'uint256',name:'newVal'}
//uint만 적는 것이 아니라 uint256으로 적어준다.
]
const returnValues = web3.eth.abi.decodeLog(params,log.data)//dat:0x00000.....을 우리가 원하는 형식으로 변경해준다.
//decode는 첫번째는 데이터 형식, 두번째는 log.data
console.log(`returnValues:`,returnValues);//서명까지 해야 보인다.
setStorage(value);
setLoadding(prev=>!prev)
}
init 함수를 이렇게 바꾸어준다.
const init = async() => {
const contract=require('@truffle/contract');
const web3 = await getWeb3();
const [account] = await web3.eth.getAccounts();//하나인거 알고 있을 때는 이렇ㄹ게 쓰자
// const networkId= await web3.eth.net.getId();//네트워크 아이들 가져올 수 있다.
let simpleStorage = contract(SimpleStorageContract);
simpleStorage.setProvider(web3.currentProvider);
const Instance = await simpleStorage.deployed();
console.log(Instance);
dispatch(INIT_ACTIONS(web3,Instance,account))
web3.eth.subscribe("logs",{address:Instance.address})//사용자의 어드레스가 아니라 contract계정의 address임
.on('data',log=>{
// console.log(log)
handleResult(log,web3)
})
.on('error',err=>console.log(err))
}
서명을 해주면 다음곽 같은 것이 뜬다.
아까와는 다르게 우리가 해석할 수 있는 언어로 던져주는 것을 알 수 있다. 그리고 이것은 Simplestorage.js의 event 의 설정값이라는 것을 알 수 있다.
다음 사이트에 가면 web.js의 메소드에 관해 자세히 알 수 있다.
https://web3js.readthedocs.io/en/v1.5.2/
import React, { useState,useEffect,useReducer } from "react";
import SimpleStorageContract from "./contracts/SimpleStorage.json";
import getWeb3 from "./getWeb3";
// import axios from 'axios'
import "./App.css";
const reducer = (state,action)=>{
switch(action.type){
case "INIT":{
let {web3,Instance,account} = action;
return {
...state,web3,Instance,account
}
}
}
}
const INIT_ACTIONS=(web3,Instance,account)=>{
return{ type:'INIT',web3,Instance,account}
}
const App=()=>{
const initialState={
web3:null,
Instance:null,
account:null,
}
const [state,dispatch]=useReducer(reducer,initialState);
const [value,setValue]=useState(0);
const [storage,setStorage] = useState(0);
const [loadding,setLoadding] = useState(false);
const handleResult =(log,web3)=>{
const params=[
{type:'string',name:'message'},
{type:'uint256',name:'newVal'}
//uint만 적는 것이 아니라 uint256으로 적어준다.
]
const returnValues = web3.eth.abi.decodeLog(params,log.data)//dat:0x00000.....을 우리가 원하는 형식으로 변경해준다.
//decode는 첫번째는 데이터 형식, 두번째는 log.data
console.log(`returnValues:`,returnValues);//서명까지 해야 보인다.
//returnValues.message=="set" 이렇게 다양한 이벤트 ㅊㅓ리가 가능하다.스위치문으로 가능
setStorage(returnValues.newVal);
setLoadding(prev=>!prev);
}
const handleChange = (e) =>{
let val = e.target.value;
setValue(val);
}
//button 함수
const send = async() => {
const {account,Instance} = state;
if(value > 0){
setLoadding(prev=>!prev);
//비동기적 처리
await Instance.set(value,{from:account})
}
}
const sendAPI = ()=> {
//역할
/*1. 백엔드에 요청한다.(비동기axios)
백엔드에서 reqTx객체를 반환해준다.
반환받은 값을 sendTransaction()을 실행한다.(실질적으로 서명하는 과정) */
if(value > 0){
setLoadding(prev=>!prev);
//비동기적 처리
//web3.eth.sendTransaction() 서명만 처리하는 방법이 있다.
//인자값으로 객체가 들어간다.
/*rawTx={
"from":"adress,,,",
"to":"",
"data":"실질적인 데이터부분 이제는 우리가 컴퓨터가 이해 편하도록인코딩을 해야한다. 이걸 백엔드에서 처리해야함 여기서 set함수로 넣는다."
"gasLimit":"...",
"gasPrice":",,,"
}*/
}
}
const sendTx = () => {
if(value > 0){
setLoadding(prev=>!prev);
}
}
const init = async() => {
const contract=require('@truffle/contract');
const web3 = await getWeb3();
const [account] = await web3.eth.getAccounts();//하나인거 알고 있을 때는 이렇ㄹ게 쓰자
// const networkId= await web3.eth.net.getId();//네트워크 아이들 가져올 수 있다.
let simpleStorage = contract(SimpleStorageContract);
simpleStorage.setProvider(web3.currentProvider);
const Instance = await simpleStorage.deployed();
console.log(Instance);
dispatch(INIT_ACTIONS(web3,Instance,account))
web3.eth.subscribe("logs",{address:Instance.address})//사용자의 어드레스가 아니라 contract계정의 address임
.on('data',log=>{
// console.log(log)
handleResult(log,web3)
})
.on('error',err=>console.log(err))
}
useEffect(()=>{
init();
},[])
return (
<div>
<input type = "text" value={value} onChange={handleChange}/>
<div>
<button onClick={send}>일반 서명</button>
<button onClick={sendAPI}>DB거치고 서명</button>
<button onClick={sendTx}>DB 서명</button>
</div>
<div>
{loadding? `loading`:storage}
</div>
</div>
)
}
export default App;
여기서 setStoarage(value)
가 아니라 setStorage(returnValues.newVal)
으로 처리함으로 블록체인에서 변경된 값을 넣어주었다.
숫자가 잘 바뀌는 것을 확인할 수 있다. 여기서의 값은 화면에서만 처리되는 것이 아니라 블록체인의 값이 바뀐 것임을 명심하자!
npm i web3 express body-parser ethereumjs-tx cors