이 글에서는 solidity 문법을 다루지는 않으며, 배포된 solidity의 Contract 함수를 web3에서 호출하는 방법을 포스팅합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// SPDX-License-Identifier GPL-30
pragma solidity >= 0.7.0 < 0.9.0;
contract Hello {
uint public num = 0;
string public hi = "hello solidity!!";
function addNumAndX(uint x) public {
num += x;
}
function hello() public view returns(string memory) {
return hi;
}
function getNum() public view returns(uint) {
return num;
}
}
|
cs |
우선 solidity를 이렇게 작성해줍니다. 저는 Remix에서 작성하였습니다.
그 다음 compiler에서 컴파일을 해준 후에
deploy에서 배포를 해야합니다.
아래의 Deploy 버튼을 누르기 전, 환경을 "Injected Provider - MetaMask"로 변경합니다.
그리고 Deploy 버튼을 누릅니다.
그러면 해당 Contract를 배포하기 위한 가스비를 지불하는 창이 뜹니다.
위 창은 크롬의 MetaMask 확장 프로그램입니다.
배포가 완료되면 아래의 Deployed Contracts에 해당 컨트랙트가 뜹니다.
이제 우측 복사 버튼을 눌러 컨트랙트 주소를 가져올 수 있습니다.
이제 React로 넘어갑니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
import {Component} from 'react';
import Web3 from 'web3';
class App extends Component {
constructor(props) {
super(props);
const contractAddress = '0xaFA55F3E3DB63C536581762ceb3149aD3349913d';
const abi = [
{
"inputs": [
{
"internalType": "uint256",
"name": "x",
"type": "uint256"
}
],
"name": "addNumAndX",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "getNum",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "hello",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "hi",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "num",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
];
this.fromAddress = '0xE8Ed81Ae938Ede438501d12d87324AB1428A251a';
this.web3 = new Web3(Web3.givenProvider || 'ws://some.local-or-remote.node:8546'); this.contract = new this.web3.eth.Contract(abi, contractAddress);
}
}
|
cs |
web3 모듈을 가져와서 사용하고, abi, contractAddress를 이용하여 contract를 가져옵니다.
여기서 abi는 Contract 함수와 매개변수들의 정보가 담겨있는 JSON 형식의 리스트입니다.
Remix의 compiler 메뉴 밑에 해당 컨트랙트의 ABI를 복사할 수 있습니다.
그대로 가져와서 React 코드에 붙여줍니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
render() {
return (
<div className="App">
<button onClick={this.connectWallet.bind(this)}>connectWallet</button>
<br/>
<button onClick={this.hello.bind(this)}>hello</button>
<br/>
<button onClick={this.addNumAndX.bind(this)}>addNumAndX</button>
<br/>
<button onClick={this.getNum.bind(this)}>getNum</button>
<br/>
</div>
);
}
|
cs |
화면에는 버튼을 놓았습니다.
각각 connectWallet, hello, addNumAndX, getNum 함수를 호출하는 버튼입니다.
함수에서는 constructor의 this를 사용할 수 없어 bind(this)로 this를 사용할 수 있도록 넘겨주었습니다.
이제 메소드입니다.
1
2
3
4
5
6
|
connectWallet() {
this.web3.eth.requestAccounts().then((res) => {
console.log(res);
});
}
|
cs |
지갑연결을 요청하는 코드입니다.
MetaMask가 설치되어있다면 문제없이 작동됩니다.
res는 지갑 주소가 array 형식으로 담겨있습니다.
1
2
3
4
5
6
|
hello() {
this.contract.methods.hello().call((err, res) => {
console.log(res);
});
}
|
cs |
다음은 Contract의 hello 함수를 호출하는 부분입니다.
string을 return받는 역할만 있어 가스비를 지출하지 않으며, call을 이용하여 호출할 수 있습니다.
res는 string입니다.
1
2
3
4
5
6
|
getNum() {
this.contract.methods.getNum().call((err, res) => {
console.log(res);
});
}
|
cs |
다음은 변수 num의 값을 가져오기 위한 getNum 함수 호출입니다.
hello 함수와 동일하게 call을 이용하여 호출합니다.
res는 uint입니다.
1
2
3
4
5
6
7
8
9
10
11
|
addNumAndX() {
let x = 2;
this.contract.methods.addNumAndX(x).send({from: this.fromAddress})
.on('receipt', function (res) {
console.log(res);
})
.on('error', function (err) {
console.log(err);
});
}
|
cs |
다음은 num에 x만큼 더하는 로직이 있는 addNumAndX 함수 호출입니다.
다른 함수와는 다르게 값을 변경하는 로직이 포함돼서 그런지 가스비를 요구하고 있습니다.
이 코드에서는 지불할 ETH가 0이지만 형식적으로 지불은 해야합니다.
가스비 지불을 위해 call 대신 send를 사용하였으며, 지불할 주소를 from에 작성하면 호출할 수 있습니다.
'receipt'을 감지하면 가스비 지불이 완료되었고, 트랜잭션 내역을 확인할 수 있습니다.
transactionHash를 통해 etherscan에서도 확인이 가능합니다.
그리고 getNum 함수를 다시 호출하면 값이 변경된 것을 확인할 수 있습니다.
다른 로직들은 [web3 공식문서]에서 확인해주시면 됩니다.
아래는 전체 코드입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
import {Component} from 'react';
import Web3 from 'web3';
class App extends Component {
constructor(props) {
super(props);
const contractAddress = '0xaFA55F3E3DB63C536581762ceb3149aD3349913d';
const abi = [
{
"inputs": [
{
"internalType": "uint256",
"name": "x",
"type": "uint256"
}
],
"name": "addNumAndX",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "getNum",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "hello",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "hi",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "num",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
];
this.web3 = new Web3(Web3.givenProvider || 'ws://some.local-or-remote.node:8546');
this.fromAddress = '0xE8Ed81Ae938Ede438501d12d87324AB1428A251a';
this.contract = new this.web3.eth.Contract(abi, contractAddress);
}
connectWallet() {
this.web3.eth.requestAccounts().then((res) => {
console.log(res);
});
}
hello() {
this.contract.methods.hello().call((err, res) => {
console.log(res);
});
}
addNumAndX() {
let x = 2;
this.contract.methods.addNumAndX(x).send({from: this.fromAddress})
.on('receipt', function (res) {
console.log(res);
})
.on('error', function (err) {
console.log(err);
});
}
getNum() {
this.contract.methods.getNum().call((err, res) => {
console.log(res);
});
}
render() {
return (
<div className="App">
<button onClick={this.connectWallet.bind(this)}>connectWallet</button>
<br/>
<button onClick={this.hello.bind(this)}>hello</button>
<br/>
<button onClick={this.addNumAndX.bind(this)}>addNumAndX</button>
<br/>
<button onClick={this.getNum.bind(this)}>getNum</button>
<br/>
</div>
);
}
}
export default App;
|
cs |
'Etc' 카테고리의 다른 글
AWS S3로 React 배포하기 (0) | 2023.02.02 |
---|---|
GitHub Actions를 이용한 Slack Notification (0) | 2023.01.30 |
GitLab -> GitHub Mirroring (0) | 2022.06.12 |
Unity Script로 카메라 Culling Mask 기능 사용하기 (2) | 2021.10.29 |
Unity 카메라 Culling Mask (0) | 2021.10.29 |