BlockChain
(BlockChain) JS에서 Solidity 및 Smart Contract 실행
JJeongHyun
2023. 2. 28. 19:07
반응형
JavaScript 환경에서 solidity 언어로 작성한 코드로 스마트 컨트랙트를 발생시키려고 한다
이에 우리는 3개의 라이브러리를 require 해준다
const solc = require("solc");
const fs = require("fs");
const path = require("path");
- solc 라이브러리 : solidity 코드를 bytecode로 반환하는 컴파일 라이브러리
- fs 라이브러리 : FileSystem, 파일에 접근하여 데이터를 가져오거나 생성 및 수정 등 기능을 제공 JS 내장 라이브러리
- path 라이브러리 : 경로에 대한 편의 기능을 제공하는 JS 내장 라이브러리
그리곤, 파일 이름을 매개변수로 받아 컴파일 해주는 메서드를 클래스 내에 static 형식으로 생성
// compiler.js 내 Compiler 클래스
static compile(_fileName) {
const contractPath = path.join(__dirname, "contracts", _fileName);
const data = JSON.stringify({
language: "Solidity",
sources: {
[_fileName]: {
content: fs.readFileSync(contractPath, "utf-8"),
},
},
settings: {
outputSelection: {
"*": {
"*": ["*"],
},
},
},
});
const compiled = solc.compile(data);
return Compiler.writeOutput(JSON.parse(compiled));
}
- const contractPath = path.join(__dirname, "contracts", _fileName)
- 현재 문서 경로에서 contracts 폴더, _fileName까지의 경로를 합쳐서 contractPath라는 변수에 저장
- const data = JSON.stringify({...})
- solc를 사용하여 솔리디티 코드를 컴파일 시 사용할 설정
- language : "Solidity"
- 언어 설정은 Solidity
- sources : {}
- 파일로 생성되는 solidity 객체의 이름은 [_fileName], 파일 내용은 contractPath를 utf-8로 전환하여 파일을 읽는 내용으로 설정
- settings : {}
- 추가적인 설정은 가져올 정보 설정과 파일이름, 가져올 데이터의 키와 값을 모든 설정
- const compiled = solc.compile(data)
- data를 solidity 컴파일 후 compiled 변수에 저장
- return Compiler.writeOutput(JSON.parse(compiled))
- JSON 형식으로 반환된 값을 객체화 하여 writeOutput 매개변수로 넘겨준다
// compiler.js 내 Compiler 클래스
static writeOutput(_compiled) {
const result = {};
for (const contractFileName in _compiled.contracts) {
const [contractName] = contractFileName.split(".");
const contract = _compiled.contracts[contractFileName][contractName];
const abi = contract.abi;
const bytecode = contract.evm.bytecode.object;
const tempObj = { abi, bytecode };
const buildPath = path.join(__dirname, "build", `${contractName}.json`);
fs.writeFileSync(buildPath, JSON.stringify(tempObj));
result[contractName] = tempObj;
}
return result;
}
- 컴파일된 solidity 객체에서 abi값과 bytecode 값을 가져온다.
- abi : Application Binary Interface의 약자로 스마트 컨트랙트 내의 함수와 매개변수 등을 JSON 형식으로 표기
- bytecode : 트랜잭션에 저장되는 코드이며 Receipt 내의 CA(contractAddress)로 접근할 수 있다
- const [contractName] = contractFileName.split(".");
const contract = _compiled.contracts[contractFileName][contractName]
const abi = contract.abi;
const bytecode = contract.evm.bytecode.object;
- 현재 주소에서 build라는 폴더에 contractName의 JSON형식 파일에 경로를 연결하고 tempObj객체를 JSON 형식화해서 JSON 파일을 생성한다
- const tempObj = { abi, bytecode };
const buildPath = path.join(__dirname, "build", `${contractName}. json`);
fs.writeFileSync(buildPath, JSON.stringify(tempObj));
- const tempObj = { abi, bytecode };
- 빈 객체에 contractName으로 키의 값으로 abi, bytecode를 객체화해서 정의한다
- const result = {};
result[contractName]=tempObj;
- const result = {};
// web3.js
const web3 = require("web3");
let instance;
class Client {
constructor(_url) {
if (instance) return instance;
this.web3 = new web3(_url);
instance = this;
}
}
module.exports = Client;
// index.js
const client = new Client("http://127.0.0.1:8545");
const txObj = { data: bytecode };
const contract = new client.web3.eth.Contract(abi);
async function init() {
const instance = await contract.deploy(txObj).send({
from: "0xeD4e7b4e1C87D3F728dF323869b14ecCE0272840",
gas: 1000000,
});
console.log(instance.options.address); // CA
}
init();
- web3 통신으로 ganache 서버에 접속
- 트랜잭션 객체에 bytecode로 정의
- contract 변수에 새로운 Contract를 생성하여 abi 전달
- contractAddress에 접근하기 위해서 init() 함수 생성 및 호출
// index.js
async function test() {
const accounts = await client.web3.eth.getAccounts();
const ca = init() 실행 후 나온 contractAddress 주소 삽입;
const deployed = new client.web3.eth.Contract(abi, ca);
let text = await deployed.methods.getText().call();
await deployed.methods.setText("수정하고 싶은 텍스트").send({ from: accounts[1] });
text = await deployed.methods.getText().call();
const balance = await client.web3.eth.getBalance(accounts[1]);
console.log("보낸 녀석의 잔액 : ", balance);
// 보낸 녀석의 잔액 : 99999990768025909829
// 보낸 녀석의 잔액 : 999999818450504472886
}
test();
- ganache 서버에 web3 통신으로 계정을 가져온다
- const accounts = await client.web3.eth.getAccounts();
- init() 함수로 나온 contractAddress값을 ca라고 정의한다
- const ca = "contractAddress 값"
- 컨트랙트를 생성하고 CA에 연결한다
- const deployed = new client.web3.eth.Contract(abi, ca);
- 컨트랙트를 실행하고 해당 계정의 잔액을 확인하여 변동사항을 확인한다
- let text = await deployed.methods.getText().call();
await deployed methods.setText("바꿀내용").send({from:accounts[1]})
const balance = await client.web3.eth.getBalance(accounts[1]);
- let text = await deployed.methods.getText().call();