컨트랙트 배포, 연동
remix를 사용하여 컨트랙트를 만들고 web3 provider로 environment 설정을 변경하고 vsc에서 가나슈를 실행하여 연동 시켜주면 가나슈 계정들을 remix에서 확인이 가능하다. 그리고나서 컨트랙트를 deploy한 후에 컨트랙트 주소를 복사하여 작성한 html파일 속에 넣어준다. 아래는 순서대로 작성한 컨트랙트 파일, HTML 파일이다.
pragma solidity 0.8.6;
contract Hello
{
function getBlockNumber() public view returns (uint)
{
return block.number;
}
}
contract Bal {
constructor() payable {
}
function chkBalance() public view returns(uint) {
return address(this).balance;
}
}
contract counter {
uint count;
constructor(uint _count) {
count = _count;
}
function increment() public returns(uint) {
return count ++;
}
function getCount() public view returns(uint) {
return count;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script type="text/javascript" src="./bignumber.min.js"></script>
<script type="text/javascript" src="./web3.js"></script>
<script type="text/javascript">
if (typeof web3 !== "undefined") {
web3 = new Web3(web3.currentProvider);
} else {
// set the provider you want from Web3.providers
web3 = new Web3(
new Web3.providers.HttpProvider("http://localhost:8545")
);
}
console.log(web3);
if (web3.isConnected()) {
console.log("connected");
} else {
console.log("not connected");
}
web3.eth.defaultAccount = web3.eth.accounts[0];
let abi = [{
"inputs": [],
"name": "getBlockNumber",
"outputs": [{
"internalType": "uint256",
"name": "",
"type": "uint256"
}],
"stateMutability": "view",
"type": "function"
}]
let abi2 = [{
"inputs": [],
"stateMutability": "payable",
"type": "constructor"
},
{
"inputs": [],
"name": "chkBalance",
"outputs": [{
"internalType": "uint256",
"name": "",
"type": "uint256"
}],
"stateMutability": "view",
"type": "function"
}
]
let abi3 = [{
"inputs": [{
"internalType": "uint256",
"name": "_count",
"type": "uint256"
}],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "getCount",
"outputs": [{
"internalType": "uint256",
"name": "",
"type": "uint256"
}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "increment",
"outputs": [{
"internalType": "uint256",
"name": "",
"type": "uint256"
}],
"stateMutability": "nonpayable",
"type": "function"
}
]
contractAddress = "1번 컨트랙트 주소"
let smartContract = web3.eth.contract(abi).at(contractAddress)
console.log(smartContract)
smartContract.getBlockNumber.call(function (error, result) {
console.log(result.toNumber())
document.getElementById("scBlock").value = result.toNumber()
})
contractAddress2 = "2번 컨트랙트 주소"
let smartContract2 = web3.eth.contract(abi2).at(contractAddress2)
console.log(smartContract2)
smartContract2.chkBalance.call(function (error, result) {
console.log(result.toNumber())
document.getElementById("balance").value = result.toNumber()
})
contractAddress3 = "3번 컨트랙트 주소"
let smartContract3 = web3.eth.contract(abi3).at(contractAddress3)
console.log(smartContract3)
function getCount() {
smartContract3.getCount.call(function (err, result) {
console.log(result)
document.getElementById("readCount").value = result
})
}
function inc() {
smartContract3.increment.sendTransaction(function (err, hash) {
console.log(hash)
});
}
</script>
</head>
<body>
<p>Contract info</p>
<label for="">Hello contract's Block Num</label>
<input type="text" id="scBlock" value="">
<br>
<label for="">balance contract's remaining balance</label>
<input type="text" id="balance" value="">
<br>
<label for="">Count contract</label>
<button onclick="getCount()">view count</button>
<button onclick="inc()">count + 1</button>
<input type="text" id="readCount" value="">
</body>
</html>
이제 html파일을 브라우저로 열고 확인하면 컨트랙트와 관련된 정보가 연결된 것을 볼 수 있다.
컨트랙트 별로 abi는 별개로 형성되므로 3가지 컨트랙트의 주소는 물론 각각의 abi를 모두 적어주어야한다.
배포가 완료된 컨트랙트의 주소는 contractAddress= "주소" 부분에 적고,
abi 부분의 코드는 remix의 컴파일러 탭에서 abi버튼을 클릭하여 복사해서 붙여넣기 하면된다. 컨트랙트 안에 들어있는 함수를 호출하는 방법은 익숙해질 필요가 있는데 view 속성들 같은 경우는 call방식으로 바로바로 실행이 되지만, count++을 시켜주는 increment함수와 같은 경우에는 누군가가 해당 명령을 실행하여 가나슈(체인)상에 변화를 줘야하므로 html 윗부분에 아래와 같은
web3.eth.defaultAccount = web3.eth.accounts[0];
default 계정을 설정해주어야 한다.
이렇게 하면 간단하게 3개의 컨트랙트를 하나의 html파일을 통해서 구현해 볼 수 있고, 브라우저를 통해 웹에서의 사용이 가능하다.
컨트랙트 연결 활용 연습
pragma solidity 0.8.6;
contract HKbank {
mapping (address => uint) balanceAccount;
function deposit(uint amount) public{
balanceAccount[msg.sender] += amount;
}
function getBalance() public view returns (uint) {
return balanceAccount[msg.sender];
}
}
contract EventContract {
string fName;
uint age;
event Instructor(
string name,
uint age
);
function setInstructor(string memory _fName, uint _age) public {
fName = _fName;
age = _age;
emit Instructor(_fName, _age); // Add this
}
function getInstructor() view public returns (string memory, uint) {
return (fName, age);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script type="text/javascript" src="./bignumber.min.js"></script>
<script type="text/javascript" src="./web3.js"></script>
<script type="text/javascript">
if (typeof web3 !== "undefined") {
web3 = new Web3(web3.currentProvider);
} else {
// set the provider you want from Web3.providers
web3 = new Web3(
new Web3.providers.HttpProvider("http://localhost:8545")
);
}
console.log(web3);
if (web3.isConnected()) {
console.log("connected");
} else {
console.log("not connected");
}
web3.eth.defaultAccount = web3.eth.accounts[0];
let abi = [{
"inputs": [{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}],
"name": "deposit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "getBalance",
"outputs": [{
"internalType": "uint256",
"name": "",
"type": "uint256"
}],
"stateMutability": "view",
"type": "function"
}
]
let abi2 = [{
"anonymous": false,
"inputs": [{
"indexed": false,
"internalType": "string",
"name": "name",
"type": "string"
},
{
"indexed": false,
"internalType": "uint256",
"name": "age",
"type": "uint256"
}
],
"name": "Instructor",
"type": "event"
},
{
"inputs": [],
"name": "getInstructor",
"outputs": [{
"internalType": "string",
"name": "",
"type": "string"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{
"internalType": "string",
"name": "_fName",
"type": "string"
},
{
"internalType": "uint256",
"name": "_age",
"type": "uint256"
}
],
"name": "setInstructor",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
contractAddress = "0x3E596A17baFBaA1B124CD94C7DEa8CB274EFa59B"
let smartContract = web3.eth.contract(abi).at(contractAddress)
console.log(smartContract)
smartContract.getBalance.call(function (err, result) {
console.log(result)
document.getElementById("bank_balance").value = result
})
function deposit() {
let A;
A = document.getElementById("deposit_amount").value
console.log(A)
smartContract.deposit(A).sendTransaction(function (err, hash) {
console.log(hash)
document.getElementById("deposit_amount").value = ""
})
}
contractAddress2 = "0x9b8404D99b3d6486225AD572a230E5E5E324b357"
let contract = web3.eth.contract(abi2).at(contractAddress2)
let instructorEvent = contract.Instructor();
instructorEvent.watch(function (error, result) {
console.log(result.args);
})
function setInstructor() {
contract.setInstructor.sendTransaction("hyun", 11, {
from: web3.eth.accounts[0]
}, function (err, hash) {});
}
function getInstructor() {
contract.getInstructor.call(function (err, result) {});
console.log(result)
}
</script>
</head>
<body>
<p>HK bank Contract</p>
<div>
<label for="">Current Balance</label>
<input type="text" id="bank_balance" value="">
<button onclick="deposit()">Deposit</button>
<input type="text" id="deposit_amount" value="" placeholder="Deposit amount">
</div>
<div>
<button onclick="setInstructor()">setInstructor</button>
<button onclick="getInstructor()">getInstructor</button>
</div>
</body>
</html>
마찬가지로 두개의 컨트랙트를 하나의 html파일을 통해 확인해 볼 수 있다.
이런식으로 컨트랙트를 작성하고 배포하는 연습, 해당 컨트랙트를 배포한 곳의 네트워크와 html파일을 연동시키고, 웹 영역에서 컨트랙트로부터 받아온 데이터들을 활용하는 연습 들을 통해 Dapp 개발을 간접적으로 체험할 수 있다.
cf). event 속성에 담을 값은 자유지만 event로 지정했다면 event명은 필수적으로 부여되어야 한다.