[1014] truffle ํธ๋ฌํ ๋ฆฌ์กํธ๋ฅผ ํ์ฉํด ๊ฐ๋จํ ์์ transaction ๋ง๋ค๊ธฐ - ์ฌ๊ณผ๋์ฅ ๋ง๋ค๊ธฐ
- 1๊ต์ -
๐ ์์ฒญ ๊ตฌ์กฐ ์ดํดํ๊ธฐ
user - client - web3 - metamask - ๊ฐ๋์ฌ
๐ ๋ฉํ๋ง์คํฌ๊ณผ ์ฐ๊ฒฐํ์ฌ truffle ์์ react ํ์ฉํ๊ธฐ (๊ธฐ๋ณธ ๊ตฌ์กฐ)
1. ํธ๋ฌํ์์ ๋ฆฌ์กํธ ์์ ํ๊ฒฝ ์ธํ ํ๊ธฐ
> truffle unbox react
ํธ๋ฌํ์ด ๊น๋ ค์์ง ์์ ๊ฒฝ์ฐ์๋
> npm install -g truffle ๋จผ์ ํด์ฃผ๊ธฐ
๐ truffle ์์ react ์ด์ฉํ๊ธฐ
https://muna76.tistory.com/113
[1013] Truffle ํธ๋ฌํ ๊ฐ๋ฐํ๊ฒฝ์์ ์์ ํ๊ธฐ - with. ganache & Meta mask & react
- 1๊ต์ - ๐ ๋ฉํ๋ง์คํฌ๋? - ๊ฐ์ธ์ ๊ณ์ ์ ์ฃผ์๊ฐ์ ์ ์ฅํด์ ์ด๋๋ฆฌ์๊ณผ ์ด๋๋ฆฌ์ ํ ํฐ์ ์ฝ๊ณ ์์ ํ๊ฒ ๋ณด๊ดํ ์ ์๊ฒ ํด์ฃผ๋ ํ๋ก๊ทธ๋จ. - ํซ์๋ ์ด๋ผ๊ณ ๋ ํจ. - ์๋ํค๋ผ๋๊ฒ์ด ์กด์ฌํจ. (
muna76.tistory.com
2. ganache ์คํ ํ metamask ์ฐ๊ฒฐํ๊ธฐ
ํด๋ผ์ด์ธํธ์ metamask ์ฐ๊ฒฐ ( web3์ด์ฉ ) -> truffle์ด ์์์ ํด์ค
- 2๊ต์ -
3. truffle-config.js ํ์ผ ์ค์ ํด์ฃผ๊ธฐ
root ๋๋ ํ ๋ฆฌ > truffle-config.js ํ์ผ ์์
network:{
development:{
host:"127.0.0.1"
port:7545,
network_id:"*"
},
develop:{
port: 8545
}
}
โโโ ๋ค๋ฅธ ๋ธ๋ผ์ฐ์ ์์ ์ด์๋ ์ฃผ์๋ฅผ ๊ทธ๋๋ก ๋ค๋ฅธ ๋ถ๋ผ์ฐ์ ์์ ์ด๊ธฐ!!->
๊ทธ๋ฅ ๋ณต๋ถํ์ง๋ง๊ณ ๋ถ์ฌ๋ฃ๊ธฐ ํ ๋ ctrl + shift + v ํด์ฃผ๋ฉด ๋จ โโโ
4. ๋ด๊ฐ ๋ฐฐํฌํ contract ์ฝ๋ ์์ฑํ๊ธฐ
- ์ฌ๊ธฐ์ ์ํ๋๋๋ก ์ฝ๋๋ฅผ ์์ฑํ๋ฉด ๋จ!
์ด ๋ถ๋ถ์ ๋ค์์
์ฌ๊ณผ๋์ฅ ๋ง๋ค๊ธฐ๋ก ์ค์ตํด๋ณผ๊ฒ์!! -
5. contract ์ฝ๋ ์ปดํ์ผํ๊ธฐ
> truffle compile
-root ๋๋ ํ ๋ฆฌ > clinet > src > contracts ํด๋๊ฐ ์์ฑ๋์์.
์ด ํ์ผ์ ๋ค์ด๊ฐ๋ณด๋ฉด json ์์ abi์ byte ๊ฐ ๋ค์ด๊ฐ ์์!
web3๋ก ์ปดํ์ผ ์งํํ์ ๋ -> abi / bin ํด๋ ๋ฐ๋ก ์๊ฒผ์์ง๋ง
truffle๋ก ํ๋ -> abi/ bin ํด๋ ๋ด์ฉ์ ํ๋ฐ ํฉ์ณ์ค๊ฒ์~
6. contract ๋ด์ฉ์ ๋ฐฐํฌํ๊ธฐ
> truffle migrate
ํฐ๋ฏธ๋ ๋ช ๋ น์ด ์คํ ํ (์ด๋ gas ์๋ชจ ๋์์ ๊ฒ์! ์ด๋๊ฐ ๊น์ฌ์์ผ๋ฉด ์คํ ์ ์์ ์ผ๋ก ๋์๋ค๋๊ฑธ ํ์ธ ๊ฐ๋ฅ!)
migrations ํด๋์ ์ฝ๋ ์์ฑ
7. react ์คํํ๊ธฐ
> cd clinet && npm run start
>> ๋ฆฌ์กํธ ์คํ ํ์ ๋ ์ด๋ฐ ํ๋ฉด์ด ๋์จ๋ค๋ฉด ์ฑ๊ณต~~
โโ ๋ง์ฝ ์คํํ๋๋ฐ ๊ณ์ ๋ก๋ฉ๋ง ๋จ๊ณ ์ด๋ฐ ํ๋ฉด์ด ์๋์จ๋ค๋ฉด?
- ๋ฉํ๋ง์คํฌ์์ ๊ฐ๋์ฌ๋ฅผ ๋ฐ๋ผ๋ณด๊ณ ์๋ ๊ณ์ ๊ณผ ํ์ฌ ํด๋ผ์ด์ธํธ ์ฃผ์์ ์ฐ๊ฒฐ๋์ด์๋์ง ํ์ธํด๋ณผ๊ฒ!
์ฌ๊ธฐ์ >> ๊ฐ๋์ฌ๋ฅผ ๋ฐ๋ผ๋ณด๊ณ ์๋ ๊ณ์ <<์ด๋, ๋ด๊ฐ ๊ฐ๋์ฌ์์ ์์ฑ๋ ๊ฐ์ธํค๋ฅผ ์ ๋ ฅํ ๊ณ์ ์ ๋งํจ.
์ด๋ ๊ฒ ๋จ๋ฉด ์๋๊ณ ,
๊ณ์ ๊ฐ์ ธ์ค๊ธฐํด์
๋ด๊ฐ ๊ฐ๋์ฌ์์ ๊ฐ์ธํค ๊ฐ์ ธ์จ๊ฑฐ ์ ๋ ฅํ ๊ทธ ๊ณ์ !!
๊ทธ๊ฑฐ๋ localhost:3000์ด๋ ์ฐ๊ฒฐ ๋์ด์๋์ง ํ์ธํด์ผํจ!!
์ฐ๊ฒฐ์ด ์๋์ด์์ผ๋ฉด, ์ด๋ ๊ฒ
์๋์ผ๋ก ์ฐ๊ฒฐํ๊ธฐ ํด์
์ฐ๊ฒฐ ์์ผ์ค์ผ ํจ~
- ๋น์ฐํ ์ฃผ์ 7545๋ ์ ๋ ฅ๋์ด์๋ ์ํ์ฌ์ผ ํจ! (๊ฐ๋์ฌ ์ฃผ์ - ์ด๊ฑฐ๋ฅผ truffle-config.js์๋ ์ธํ ํด์คฌ์์)
๐ App.js ํ์ผ ์ฝ๋ ํํค์น๊ธฐ
root ํด๋ - client - src - app.js
import SimpleStorageContract from "./contracts/SimpleStorage.json";
๐น ./contracts/SimpleStorage.json
- ์ปดํ์ผ ์งํํ ๋ ์๊ฒผ๋ ํด๋์. ์ฌ๊ธฐ์ abi / byte ๋ด์ฉ์ด ๋ด๊ฒจ์๋ค๊ณ ํ์!
ํ๋ฒ์ import๋ก ๋๊ฐ์ ๋ด์ฉ์ ๋ชจ๋ ๊ฐ์ ธ์๋ค๊ณ ํ ์์์ฐ.
๐น App component
- ์ ์ผ ๋จผ์ ์์๋๋ ๋ถ๋ถ!
why? -> index.js ํ์ผ์ ๋ณด์
ReactDOM.render(<App />, document.getElementById('root'));
App ์ปดํฌ๋ํธ๋ฅผ ๊ทธ๋ฆฌ๊ฒ ๋ค๊ณ ๋์ด์์์ ํ์ธ ๊ฐ๋ฅ
- ํด๋์คํ์ผ๋ก ์ ์ธ๋์์
componentDidMount = async () => {
try {
// Get network provider and web3 instance.
const web3 = await getWeb3();
// Use web3 to get the user's accounts.
const accounts = await web3.eth.getAccounts();
const networkId = await web3.eth.net.getId();
.
.
.
- const web3 = await getweb3() : ๋ฉํ๋ง์คํฌ ์ฐ๊ฒฐ์์ . "getweb3()" ์ ์์ด๋ getWeb3.js ํ์ผ์ ๋ปํจ.
getWeb3.js์์๋ window.ehereum ์ด ์๋์ง ์ฒดํฌํ๊ณ ์์ผ๋ฉด ๋ฉํ๋ง์คํฌ์ ์ฐ๊ฒฐํ๋๋ก ํ๋ ์ฝ๋๊ฐ ์์ฑ๋์ด ์์!
- const accounts = await web3.eth.getAccounts() : getAccounts() ๊ฐ rpc ํต์ ๋งค์๋์ ๊ณ์ ๊ฐ์ ธ์ค๋ผ๋ ๋ป.
- const networkId = await web3.eth.net.getId() : ๋ง์ฐฌ๊ฐ์ง๋ก rpc ๋งค์๋. ๋ฉํ๋ง์คํฌ์ ์ ์ํ ๋ ์ ๋ ฅํ๋ id๊ฐ ๊ฐ์ ธ์ค๋ผ๋ ๋ป
//SimpleStorageContract -> ์ ๊ธฐ ์ฌํ ์คํ ๋ฆฌ์ง json ํ์ผ๋ปํจ. ๊ทธ์์์ networks๊ฐ์ฒด ๊ฐ์ ธ์จ๊ฑฐ
const deployedNetwork = SimpleStorageContract.networks[networkId];
// networks๊ฐ์ฒด ์๊ธฐ์๋ค
// {
// "events": {},
// "links": {},
// "address": "0x4E3B49bA55a2601e87C1e39742b411BA47fa1b90",
// "transactionHash": "0x148436ea5699ce83eb2dc11aa7433906"
// }
//์ด์ ์ปจํธ๋ํธ ์์ ์๋ ๋ด์ฉ์ ์ ์ํ๋ ค๊ณ ~
const instance = new web3.eth.Contract(
SimpleStorageContract.abi, //abi๊ฐ ๊ฐ์ ธ์ค๊ณ
deployedNetwork && deployedNetwork.address,
// address ๊ฐ -> ๋ฐฐํฌํ ์ปจํธ๋ํธ์ ๋ค์ด์๋ ์ฃผ์๊ฐ ๊ฐ์ ธ์์ instance ์๋ค๊ฐ ๋ด์!
- 3๊ต์ -
๐ ์ฌ๊ณผ๋์ฅ ๋ง๋ค์ด์ด์ด์ด์ด~!
๐น contract ์ฝ๋ ์์ฑํ๊ธฐ
1. ๋ํดํธ ํด๋๋ฅผ ์ง์์ ํ์์๋ ํด๋๋ ๋ ๋ ค์ฃผ๊ธฐ
- (ํ์ฌ ์ค์ตํ๋ ํด๋ ๊ธฐ์ค์ผ๋ก) contracts ํด๋!
๊ธฐ๋ณธ ํ ๊ตฌ์กฐ๋ฅผ ์ตํ๋๋ผ ์ปดํ์ผํ์๋ ์๊ฒผ๋ ํ์ผ์ ์ง์์ค๋ค! client > src > contracts > [ ]
- client > contracts > SimpleStorage.sol ๋ํดํธ ํ์ผ์ด๋ฏ๋ก ์ง์์ฃผ๊ธฐ
- ๋ฐฐํฌํ ๋ ์๊ฒผ๋ ํ์ผ๋ ์ง์์ฃผ์ client > migrations > 2_deploy_contracts.js ์ญ์
2. contract ํ์ผ๊ณผ migration ํ์ผ ๋ง๋ค์ด๋๊ณ ์์ํ๊ธฐ
- ์ฌ๊ณผ ๋์ฅ์ ๋ง๋ค๊ฑฐ๋๊น contract ํ์ผ๋ช ์ fruitshop์ผ๋ก ๋ง๋ค์!
> truffle create contract Fruitshop
> truffle create migration fruitshop
- ์ดํ ํ์ผ๋ค์ด ์์ฑ๋์๋์ง ํ์ธํด์ค๋ค!
(contracts > Fruitshop.sol ์ด๋ migrations > 1633127453_fruitshop.js ์ด๋ฐ ์์ผ๋ก ์๊ฒจ์ผ๋)
3. migrations ํด๋ ํ์ผ ๋ฏธ๋ฆฌ ์์ฑํด์ฃผ๊ธฐ
- ๋ํดํธ๊ฐ์ผ๋ก ํ์ผ์ด ์์ฑ๋์๊ธฐ๋์ ๋ฐ๊ฟ์ค๋น
- ๊ฑ initial ํ์ผ์ ์๋ ์ ๋ณต๋ถํด์ ํ์ผ ์ด๋ฆ๋ง ๋ง์ถฐ์ ์ ๋ฐ๊ฟ์ค์ ์ฌ์ฉ
- migrations > 2_fruitshop.js ์ฝ๋ ์์
var Fruitshop = artifacts.require("./Migrations.sol");
module.exports = function(_deployer) {
// Use deployer to state migration tasks.
_deployer.deploy(Fruitshop);
};
4. solidity ์ธ์ด ์์ฑํด์ฃผ๊ธฐ
FruitShop.sol ์์ฑ
๐น a. ๋ณด๋ธ ์ฌ๋์ ๊ณ์ ์ด ์ฌ๊ณผ๋ฅผ ์ด ๋ช๊ฐ ๊ฐ์ง๊ณ ์๋๊ฐ?
๐น b. ์ฌ๊ณผ ๊ตฌ๋งค์ : ํด๋น ๊ณ์ (์ฃผ์)์ ์ฌ๊ณผ๋ฅผ ์ถ๊ฐํด์ฃผ๋ ์ฝ๋ ์์ฑ
๐น c. ์ฌ๊ณผ ํ๋งค์ : "๋ด๊ฐ ๊ฐ์ง๊ณ ์๋ ์ฌ๊ณผ x ์ฌ๊ณผ ๊ตฌ๋งค ๊ฐ๊ฒฉ" ๋งํผ ํ ํฐ์ ๋ฐํํด์ฃผ๊ณ ,
์ฌ๊ณผ๋ฅผ 0๊ฐ๋ก ๋ฐ๊ฟ์ฃผ๊ธฐ
๐น d. ๋ด ์ฌ๊ณผ๋ฅผ ๋ฐํํด์ฃผ๋ ํจ์
a. ๋ณด๋ธ ์ฌ๋์ ๊ณ์ ์ด ์ฌ๊ณผ๋ฅผ ์ด ๋ช๊ฐ ๊ฐ์ง๊ณ ์๋๊ฐ?
Contract Fruitshop {
mapping(address=>uint)myApple;
constructor() public{
}
}
- mapping ํจ์ ์ด์ฉ!
key : address , value : uint ์ธ myApple ํจ์
b. ์ฌ๊ณผ ๊ตฌ๋งค์ : ํด๋น ๊ณ์ (์ฃผ์)์ ์ฌ๊ณผ๋ฅผ ์ถ๊ฐํด์ฃผ๋ ์ฝ๋ ์์ฑ
function buyApple() payable public{
myApple[msg.sender]++;
}
//ํ ํฐ ๊ฑฐ๋๊ฐ ์ด๋ฃจ์ด์ง๋ฏ๋ก payable ์ถ๊ฐ
c-1. ์ฌ๊ณผ ํ๋งค์ : "๋ด๊ฐ ๊ฐ์ง๊ณ ์๋ ์ฌ๊ณผ x ์ฌ๊ณผ ๊ตฌ๋งค ๊ฐ๊ฒฉ" ๋งํผ ํ ํฐ์ ๋ฐํ
- ์ผ๋จ ์ฌ๊ณผ ํ๋งค์ , ๋ด๊ฐ ๊ฐ์ง๊ณ ์๋ ์ฌ๊ณผ๋ฅผ ๊ตฌํ๋ ํจ์!
function sellApple(uint _applePrice) public {
uint totalPrice = (myApple[msg.sender]* _applePrice);
//์ด ๊ฐ๊ฒฉ = ์ฌ๊ณผ ํ์ฌ๋์ ์ฌ๊ณผ๊ฐฏ์ x ์ฌ๊ณผ ๊ฐ๊ฒฉ
}
- ์ฌ๊ณผ๋ฅผ ํ์์ผ๋๊น ๋ด ์ฌ๊ณผ์ ๊ฐฏ์๋ฅผ 0๊ฐ๋ก ๋ฐ๊ฟ์ค์ผ ํจ!
function sellApple (uint _applePrice) public {
uint totalPrice = (myApple[msg.sender] * _applePrice);
myApple[msg.sender] = 0; // ํ๋งค์์ ์ฌ๊ณผ 0๊ฐ๋ก ๋ฐ๊ฟ
}
- ํ๋งค์์ ์ฃผ์์๋ค๊ฐ ์ฌ๊ณผ ๊ฐ๊ฒฉ๋งํผ ํ ํฐ ์ ๋ฌํ๊ธฐ
function sellApple (uint _applePrice) payable public {
uint totalPrice = (myApple[msg.sender] * _applePrice);
myApple[msg.sender] = 0;
msg.sender.transfer(totalPrice); // ๋ณด๋ธ์ฌ๋์ ์ฃผ์์ ์ด ๊ฐ๊ฒฉ์ ๋ฐํํ๋ค
}
* payable : ์ด ํจ์์์๋ ํ ํฐ์ ๊ฑฐ๋๊ฐ ๊ฐ๋ฅํ๋ค๋ ๋ป
transfer ๋ถ๋ถ์ด ์ ํ๋ถ์ด๋ผ๋๊ฑฐ์ง..? ํ๋งค์๊ฐ ์ฌ๊ณผ ํ ๊ธ์ก๋งํผ ๋ ๋ฐ๋๋ค๋ ๋ป ์๋๊ฐ
โโ ์ ์ฝ๋๋ฅผ ์ ๋ ฅํ์ ๋ ๋นจ๊ฐ์ค์ด ๋จ๋๋ฐ, ์ด ์ค๋ฅ๋ฅผ ํด๊ฒฐํ๋ ค๊ณ ์ฝ๋๋ฅผ ๊ณ ์น๋ฉด , ์ปดํ์ผํ๋ ๊ณผ์ ์์ ๋ ์ค๋ฅ๊ฐ ๋ ๊ฒ์. ๋นจ๊ฐ์ค์ด ๋ ๋ ๊ทธ๋ฅ ๊ทธ๋๋ก ๋ ๋ฌ์ผ ํจ.
why ? -> ์ฐ๋ฆฌ๊ฐ ํ๋ฉด์ผ๋ก ๋ณด๋, ์ฆ vs๊ฐ ์๋ฆฌ๋ํฐ ์ธ์ด๋ฅผ ํด์ํด์ฃผ๋ ๋ฒ์ ์ 8๋ฒ์ ์ธ๋ฐ, ํธ๋ฌํ์์ ์ปดํ์ผํ ๋ ์๋ฆฌ๋ํฐ ์ธ์ด๋ฅผ ํด์ํ๋ ๋ฒ์ ์ 5๋ฒ์ ์.
truffle version
solcjs 0.5.16
solcjs --version
solcjs 0.8.9
-------------------------
ํด์๋๋ ์๋ฆฌ๋ํฐ ์ธ์ด ๋ฒ์ ์ด ๋ค๋ฆ!
d. ๋ด ์ฌ๊ณผ๋ฅผ ๋ฐํํด์ฃผ๋ ํจ์
function getMyApple() public view returns(uint){
return myApple[msg.sender];
}
------- ์ฌ๊ธฐ๊น์ง solidity ์ฝ๋ ์์ฑ ๋! ์ด์ ์ด๊ฑธ ๋ฆฌ์กํธ๋ก ๊ตฌ๋ํด๋ด ๋๋ค!
( ์ปดํ์ผ๊ณผ ๋ฐฐํฌ ํ์ -
> truffle compile ์ดํ contracts ํด๋์ ํ์ผ ์๊ฒผ๋์ง ํ์ธ
> truffle migrate ๊ฐ์ค ๋น ์ง๊ฑฐ ํ์ธ )
๐ solidity๋ก ์์ฑ๋ ์ฝ๋๋ฅผ ๋ฆฌ์กํธ๋ก ๊ตฌ๋์์ผ๋ณด๊ธฐ
1. ๋ฆฌ์กํธ ์คํํ๊ธฐ ์ ์ app.js ํ์ผ ๋ค ์์ ํด์ผ ํจ!
import SimpleStorageContract from "./contracts/SimpleStorage.json" ๋ถ๋ถ ๋ฐ๊ฟ์ฃผ๊ณ
App ์ปดํฌ๋ํธ๋ฅผ ์ ๋ถ ์ง์ฐ๊ณ ์๋ก ์์ฑ.
import React, { Component } from "react";
import FruitshopContract from "./contracts/Fruitshop.json";
import getWeb3 from "./getWeb3";
import "./App.css";
export default App;
(์ง์ด ์ํ. ์ฌ๊ธฐ๋ค๊ฐ ์ฝ๋ ์ถ๊ฐ)
2. ์ผ๋จ ๊ทธ๋ ค์ง๋ ํ๋ฉด ๋ง๋ค๊ธฐ ๊ธฐ๋ณธ์ ์ธ ๋ด์ฉ๋ค
import React, { Component } from "react";
import FruitshopContract from "./contracts/Fruitshop.json";
import getWeb3 from "./getWeb3";
import "./App.css";
const App = ()=>{
return (
<div>
<h1>์ฌ๊ณผ ๊ฐ๊ฒฉ : 10 ETH </h1>
<button> Buy </button>
<p> ๋ด๊ฐ ๊ฐ์ง๊ณ ์๋ ์ฌ๊ณผ : 0 </p>
<button> Sell (ํ๋งค ๊ฐ๊ฒฉ์ {0 * 10}ETH) </button>
</div>
)
}
export default App;
(์์ฑ ํ npm run start ํด์ ํ๋ฉด ํ์ธํ๊ธฐ)
3- a. ์ํ๋ฅผ ์ ์ฅ ํ๊ธฐ
import React, { Component, useState } from "react";
import FruitshopContract from "./contracts/Fruitshop.json";
import getWeb3 from "./getWeb3";
import "./App.css";
const App = ()=>{
const [myApple, setMyApple] = useState(0);
return (
<div>
<h1>์ฌ๊ณผ ๊ฐ๊ฒฉ : 10 ETH </h1>
<button> Buy </button>
<p> ๋ด๊ฐ ๊ฐ์ง๊ณ ์๋ ์ฌ๊ณผ : {myApple} </p>
<button> Sell (ํ๋งค ๊ฐ๊ฒฉ์ {myApple * 10}ETH) </button>
</div>
)
}
export default App;
3-b. onClick ํจ์ ์ง์
import React, { Component, useState } from "react";
import FruitshopContract from "./contracts/Fruitshop.json";
import getWeb3 from "./getWeb3";
import "./App.css";
const App = ()=>{
const [myApple, setMyApple] = useState(0);
const buyApple = ()=>{
// buy๋๊น ์ฌ๊ณผ๋ฅผ ์ถ๊ฐํด์ฃผ๋ฉด ๋จ
setMyApple(prev=>prev+1); // ํน์ setMyApple(myApple+1);๋ ๊ฐ๋ฅ. ํํ ๋ฐฉ์ ์ฐจ์ด
}
const sellApple = ()=>{
// ๊ฐ์ง๊ฑฐ ์ ๋ถ 0์ผ๋ก ๋ง๋ค๊ธฐ
setMyApple(0);
}
return (
<div>
<h1>์ฌ๊ณผ ๊ฐ๊ฒฉ : 10 ETH </h1>
<button onClick={()=>buyApple()}> Buy </button>
<p> ๋ด๊ฐ ๊ฐ์ง๊ณ ์๋ ์ฌ๊ณผ : {myApple} </p>
<button onClick={()=>sellApple()}> Sell (ํ๋งค ๊ฐ๊ฒฉ์ {myApple * 10}ETH) </button>
</div>
)
}
export default App;
๊ทธ๋ฌ๋ฉด ์๋ฐ ์์ผ๋ก ํ๋ฉด์ด ๋น๋๋ ์์
4. useEffect ์ ์ธํ๊ธฐ : componentDidMount WEB3 ๊ฐ์ ธ์์ ๋ฉํ๋ง์คํฌ ์ฐ๊ฒฐํ๊ธฐ
import getWeb3 from "./getWeb3";
...
const getweb = async ()=>{ //web3 ๊ฐ์ ธ์ค๋ ํจ์ ๋ง๋ค๊ธฐ
let web3 = await getWeb3()
console.log(web3); // ์คํ์ด ์ ๋์๋ค๋ฉด ์ฝ์์ ์ฌ๋ฌ ๊ฐ์ฒด๊ฐ ์ฐํ๊ฒ์ด์ผ
}
useEffect(()=>{
getweb(); // ์ค๋ฅผ ์ฌ๊ธฐ์ ํธ์ถ! web3 ๊ฐ์ ธ์
},[])
- 4๊ต์ -
@truffle/contract
> npm install @truffle/contract
* ์ฃผ์- ๋๋ ํ ๋ฆฌ๊ฐ client ์์ ๋ค์ด๊ฐ์๋๊ฑฐ ํ์ธํ๊ณ ์ค์น ํด์ผ ํจ *
์ฝ๋๋ฅผ ์ข ๋ ๊ฐ์ํ & ๊น๋ํ๊ฒ ๋ณด์ด๊ฒ ํ๊ธฐ ์ํด์ ์ฌ์ฉํ๋ค๊ณ ํจ.
์๋ฅผ ์ ์ฐ๋๊ฑด์ง ์์ง ํ์คํ ์ดํด๋ ๋ชปํ๊ฒ ์... ์ฌ์ฉ๋ฒ์ ํํ์ด์ง์ ์ ๋์์์
https://www.npmjs.com/package/@truffle/contract
@truffle/contract
A better contract abstraction for Ethereum (formerly EtherPudding)
www.npmjs.com
5-a. @truffle/contract ๊ฐ์ ธ์ค๊ธฐ
const contract = require('@truffle/contract');
์ด๋ ๊ฒ contract๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋๋ฉด web3 ์์ ์๋ ๊ฐ์ฒด๋ฅผ ์ข ๋ ์ฝ๊ฒ ์ ๊ทผํด์ ์ฌ์ฉ ํ ์ ์๋ค..?
=> ์ฝ๋๊ฐ ๊น๋ํด์ง๋ค
const getweb = async()=>{
let web3 = await getWeb3()
let fruitsop = contract(FruitshopContract) // ์ด๋ ๊ฒ ๋ฐ๋ก ์จ์ฃผ๋ฉด
fruitshop.setProvider(web3.currentProvider) // ๋ฐ๋ก ๊ฐ์ ธ์์ ์ธ ์ ์๋ค๋๊ฒ ๊ฐ์๋ฐ...
let instance = await fruitshop.deployed()
console.log(instance)
}
๊ณผ์ฐ instance ๊ฐ์ด console์ ์ฐํ๋์ง
๋ฆฌ์กํธ๋ฅผ ์คํ์์ผ๋ณธ๋ค!
5-b. WEB3 ๋ฅผ ํตํด์ ๋ฉํ๋ง์คํฌ ์ฃผ์ ๊ฐ์ ธ์ค๊ธฐ
const getweb = async()=>{
let web3 = await getWeb3()
let fruitsop = contract(FruitshopContract) // ์ด๋ ๊ฒ ๋ฐ๋ก ์จ์ฃผ๋ฉด
fruitshop.setProvider(web3.currentProvider) // ๋ฐ๋ก ๊ฐ์ ธ์์ ์ธ ์ ์๋ค๋๊ฒ ๊ฐ์๋ฐ...
let instance = await fruitshop.deployed()
//๊ณ์ ๊ฐ์ ธ์ค๊ธฐ
let accounts = await web3.eth.getAccounts()
console.log(instance)
console.log(accounts) // ๋ฉํ๋ง์คํฌ์ ์๋ ์ฃผ์๋ ๊ฐ์์ง ๋น๊ตํด๋ณด๊ธฐ
}
์ฝ์์ ์ฐ์ accounts ์ ์ค์ ๋ฉํ๋ง์คํฌ ๊ณ์ ์ฃผ์์ ๊ฐ์์ง ๋น๊ตํด๋ณด๊ธฐ
1 -> ์ฝ์์ ์ฐ์ accounts
2 -> ์ค์ ๋ฉํ๋ง์คํฌ์ ๋ค์ด๊ฐ์๋ ์ฃผ์ (๊ฐ์ธํค). ์ด๊ฑฐ๋ ์ ๊ธฐ ๊ณ์ ๋ช ๋๋ฅด๋ฉด ๋ณต์ฌ ๋จ
๋น๊ตํด์ ๊ฐ์ผ๋ฉด ์ ๊ฐ์ ธ์จ๊ฒ~
instance / accounts ์ด๋์ ์ฌ์ฉํด์ผ ํ ๊น?
buyApple/ sellApple ํจ์์์ ์ฌ์ฉํ๋ค.
๊ทผ๋ฐ ์ด instance๋ ์ง์ญ๋ณ์๋ก, ํด๋น ํจ์ ์์์๋ง ์ด์ฉ ๊ฐ๋ฅํจ.
์ด๋ป๊ฒ instance๋ฅผ buyApple/ sellApple ํจ์์์ ์ด์ฉํ ์ ์์๊น?
6. instance ์ํ๋ก ์ ์ฅํ๊ธฐ
์ํ๋ ๊ฐ์ฒด๋ฅผ ์ ์ฅ ํ ์ ์๋์ง?
=> ์ ์ฅ ํ ์๋ ์์ง๋ง useState๋ฅผ ์ด์ฉํ๋ฉด ๋ณต์กํด์ง.
์ฝ๊ฒ ์ฌ์ฉํ๋ ค๋ฉด useReducer๋ก ์ ์ฅํด์ ์ํ๋ฅผ ์ฌ์ฉํ๋๋ก ํ ๊ฒ์~!
a. instance
b. accounts
c. web3 (์๋ util์ด๋ผ๋ ์์ฑ์ ์ฌ์ฉํ๊ธฐ ์ํด ๊ฐ์ ธ์ค๋ ๊ฒ์)
์ด๋ ๊ฒ ์ธ๊ฐ์ง๋ฅผ reducer์ ๋ด์์ ์ฌ์ฉํด๋ณด๋๋ก ํ๊ฒ ์!
๐น instance / accounts / web3 -> reducer๋ก ์ํ์ ์ ์ฅํ๊ธฐ
import React, { Component, useEffect , useReducer } from "react";
const App= ()=>{
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, // instance:action.instance ์ด๊ฑธ ์ค์ฌ์ ์
account // ๊ทผ๋ฐ ๋น๊ตฌ์กฐํ ๋น๋ฌธ ์จ์ ์ด๋ป๊ฒ ์ด๋ ๊ฒ ์ค์ด๋๋๊ฑด์ง ๋ชจ๋ฅด๊ฒ ...
}
}
}
let InitActions = {
type:"INIT",
web3,
instance,
account:account[0] //์๋ ๋ฐฐ์ด๋ก ๋ด๊ฒจ์์ด์ ์๋ง ๋ฐ๊ฟ์ฃผ๊ธฐ
}
dispatch (InitActions)
//๋ด์ฉ์ ๋ณด๋ผ ๋
//dispatch({type:"INIT"}) //action.type์ด 'INIT'์ธ ์ผ์ด์ค์ ๋ด๊ธด ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด์ค๋
//๊ทผ๋ฐ ์ด๋ ๊ฒ ์ฐ๋ฉด ๋ณต์กํด์ง๋ค๊ณ ์์์ฒ๋ผ let InitialActions ๋ง๋ค์ด์ ์ฝ๋ ๋ฐ๊พธ์ฌ.
// ์ด๊ฒ ๋ ๋ณต์กํ์ง ์๋์ฌ..??
}
์ํผ ์ด๋ ๊ฒ ํด์ฃผ๋ฉด
instance / account / web3 ๋ฅผ ์ ์ญ์์ ์ฌ์ฉํ ์ ์๋ ์ํ๋ก ๋ง๋ค์ด ์ค ๊ฒ์!
- 5๊ต์ -
๐น (์ด์ด์) instance / account / web3๊ฐ ์ํ์ ์ ์ฅ์ด ์ ๋์๋์ง ํ์ธํ๊ธฐ
react devtool - component ํ์ธ
์๋ ๊ทผ๋ฐ accounts๊ฐ undefined๊ฐ ๋จ๋ฉด ์๋๋๋ฐ ์ ์ธ๋๊ฐ ๋จ์ง
-> ์คํ์์... account ๊ฐ์ ์ ์ธํด์ค๋ accounts ๋ผ๊ณ ํด์ ์๋ชป ๋ ๊ฒ์..
=> ์ด์ instance / account / web3 ๋ฅผ buyApple / sellApple ํจ์์์ ์ฌ์ฉํ ์ ์๊ฒ ๋์๋ฐ!
๐น ์ฌ์ฉํ๊ธฐ
const buyApple = async()=>{
let {instance,account} = state; //๋น๊ตฌ์กฐ ํ ๋น๋ฌธ์ด์ฌ
await instance.buyApple({
from : account, //๋ด๊ฐ ์ํํ
๋ณด๋ผ๊ฑด๋ฐ
value:1000000000000000000, //๋จ์๊ฐ wei // ์ด๋งํผ์ ๋ณด๋ผ๊ฑฐ์ผ
gas:90000, //๊ฐ์ค๋ ์ด๋งํผ์ผ๋ก ํ ๊ฑฐ์ผ
}) //์๋ ๊ทธ๋ฅ ์ธ์์ผ ํ๋ ๊ตฌ๋ฌธ์ด๋ผ๊ณ ํจ.. ๊ดํธ ์์ ๊ฐ์ฒด๋ก ๋ด๋๊ฑฐ
setMyApple(prev=>prev+1);
}
> npm run start
ํ๋ฉด์์ ์ด๋๋ฆฌ์์ผ๋ก ์ฌ๊ณผ ์ฌ๋๊ฒ์..
๋ด๊ฐ ์ด๋๋ฅผ ์ฃผ๊ณ ์ฌ๊ณผ๋ฅผ ์๋๋ฐ
๊ทธ ์ํ์์ ์๋ก๊ณ ์นจ์ ํ๋ฉด ์ฌ๊ณผ๊ฐ ์ฌ๋ผ์ง.
์ด๋ถ๋ถ์ ๊ณ ์ณ์ฃผ๊ธฐ ์ํด
7. ํ์ฌ ๋ด๊ฐ ๊ฐ์ง๊ณ ์๋ ์ฌ๊ณผ๋ฅผ return ํด์ฃผ๋ ํจ์ ๋ง๋ค๊ธฐ
const getApple = async(instance)=>{ //์ธ์๊ฐ์ผ๋ก ๋ฐ์์ค์ผ instance ์ฌ์ฉ ๊ฐ๋ฅ
if(instance == null) return
let {instance} = state;
let result = await instance.getMyApple();
//์ํ๋ฅผ ๋ฐ๊ฟ๊ฒ์ด์ผ ๋ญ๋ก? ๋ธ๋ก์ฒด์ธ์์ ๋ฐ์์จ ํ์ฌ ๋ด ์ฌ๊ณผ๋ฅผ ๋ฐ์์จ ๊ฒฐ๊ณผ๊ฐ์ผ๋ก
setApple(result.toNumber())//๋ฐ์์ฌ ๋ string ๊ฐ์ด๋ฏ๋ก int๋ก ๋ฐ๊ฟ์ฃผ๊ธฐ
}
// ํด๋น ํจ์๋ฅผ getweb ํจ์ ์์์ ํธ์ถํด์ฃผ๊ธฐ (getweb์ useEffect์์ ํธ์ถ๋๋ฏ๋ก)
const getweb = ()=>{
...
getApple(instance) // ์ธ์๊ฐ์ผ๋ก ๋๊ฒจ์ค์ผ instance๊ฐ์ ๋ฐ์์ฌ ์ ์์
}
โโ web3.utils ์ฌ์ฉํ๊ธฐ
const buyApple = async()=>{
let {instance,account, web3} = state; //๋น๊ตฌ์กฐ ํ ๋น๋ฌธ์ด์ฌ
await instance.buyApple({
from : account,
value: web3.utils.toWei("10","ether"),
// ์ธ์๊ฐ์ผ๋ก "์ซ์" , "๋จ์" ๋ฐ์์ -> ํด๋น ์ซ์์ ํด๋น ๋จ์๋งํผ์ wei ๋จ์๋ก ๋ณํํด์ค
// ๊ธ๊น 10ether๊ฐ ๋ช wei์ผ? ํ๋ ๋งค์๋๋ผ๊ณ ํ ์์์
gas:90000,
})
setMyApple(prev=>prev+1);
}
8. ์ฌ๊ณผ๋ฅผ ํ๋ ํจ์ ๋ง๋ค๊ธฐ
const sellApple = async()=>{
let { instance,account,web3 }=state
//์ปจํธ๋ํธ์์ sellApple์ ์ธ์๊ฐ์ผ๋ก ๊ฐ๊ฒฉ์ ๋ฐ์์คฌ์์ผ๋๊น ์ฌ๊ธฐ๋ ์ธ์๋ฅผ ๋ฃ์ด์ค
await instance.sellApple(web3.utils.toWei("10","ether"),{//์ธ์๋ก ๋ณด๋ผ ํ ํฐ์ ๋ฃ์ด์ค๊ฒ.๋จ์wei
from:account,
gas:90000,
}) // buyApple ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์ฐ๋ ๋ฌธ๋ฒ ์ธ์ฐ๊ธฐ!
setApple(0)
}