[BlockChain]이더리움 블록체인_web3.js 이더리움송금하기

2 minute read

이제부터 본격적으로 Web3.js 개발하는 방법에 대해서 포스팅할 예정입니다. 사실 Nodejs 서버 Web개발자라면 DAPP을 만드는 건 정말 쉬울 것 같아요. JavaScript만 다룰 줄 안다면 DAPP은 개발할 수 있습니다.

DAPP 정의(분산된 어플리케이션)

DAPP은 안정성과 보안성 뿐 만 아니라 더 중요한 가치는 서비스를 이용하는 모든 사람들에게 그 보상이 지급된다는 점이죠.

기존에 우리가 서비스를 이용하기 위해서 가치를 지불했다면, 이제는 자신이 주체가되어 가치를 얻을 수 있다는 점이 가장 큰 차이고 각광받는 이유라고 생각이 듭니다.

DAPP 프로세스

Image Alt 텍스트

DAPP은 총 4개의 계층으로 나누어집니다.

이더리움 블록체인 네트워크와 통신하기 위해서 MetaMask, Infura라는 인터페이스가 존재하고 DAPP을 개발하는 개발자들은 Web3 API를 사용하여 웹과 모바일을 개발할 수 있습니다.

단 Web3 API는 현재 JAVAScript만 지원하고 있기 때문에 웹서버 개발시에는 JavaScript로 개발하는 것이 블록체인 개발에 있어 좀 더 수월하게 개발할 수 있습니다.

개발환경

윈도우 VMware를 이용한 OS 환경 — Linux 우분투 16.04 / 개발 툴 — ATOM

이번에 해볼 내용은 DAPP에 대한 프로젝트 구성과 Web3를 이용해서 이더리움을 직접 송금하는 것에 대해 포스팅하겠습니다.

DAPP 프로젝트 구성

제가 기존 DAPP을 개발한 AD_Token의 프로젝트입니다.

프로젝트 구성요소는 크게 3가지로 나누어 집니다. Contract, View, Routers Image Alt 텍스트

  1. Contract — Solidity를 이용하여 스마트컨트랙트에 기능에 대한 소스를 작성합니다. 컴파일시 Solidity 언어를 solc 모듈을 이용하여 ABI 바이트 코드와 JSON 형식으로 만들 것입니다.

  2. View — 웹페이지에 보여지는 화면을 작성합니다. (html) nodejs에서 많이 사용하는 ejs모듈을 사용했지만 코드는 html/css 로 이루어져 있습니다.

  3. Routers/Moudle — 웹페이지의 동적기능을 자바스크립트 코드를 작성합니다. web3, database, file 등 모듈에 대한 기능을 작성하는 부분입니다.

Web3 객체 생성

가장먼저 Web3로 기본 객체를 생성합니다. nodejs로 웹 서버를 구성하는 것과 마찬가지로 통신 객체를 설정해야합니다.

Image Alt 텍스트

Ropsten의 infura API를 사용하여 통신 Provider를 설정한 객체입니다. Private 블록체인으로 연결하고 싶다면 localhost:8545로 객체를 연동하면 됩니다.(https://ropsten.infura.io/vs/APIKEY에서 -> http://localhost:8545로 바꾸면 됩니다.) => INFURA PRIVATE KEY 얻기

Nodejs에서는 이처럼 require이라는 함수를 이용하여 해당 모듈 객체를 호출 할 수 있습니다.

Web3 트랜잭션 실행

위에 객체까지 준비가되었다면 그러면 이제부터 Nodejs를 이용해서 A계좌에서 B계좌로 0.01Ether 을 직접 송금을 해보겠습니다. 단 send에는 이더리움이 있어야 합니다. Metamask로 하면 roptsen테스트에서 얻을 수 있습니다.

const send_account = "Send_Account";
const receive_account = "Receive_account";
const privateKey = Buffer.from('PrivateKey','hex');

먼저 send_account(보내는 계좌), receive_account(받는계좌) 두개를 설정하세요. 이계좌번호는 저같은경우 Metamask를 통해서 생성하였습니다. (여기서 GasLimit와 Gasprice는 테스트이기 때문에 임의로 지정하였습니다.)

web3.eth.getTransactionCount(send_account, (err,txCount)=>{

  const txObject ={
    nonce: web3.utils.toHex(txCount),
    gasLimit: web3.utils.toHex(100000),
    gasPrice: web3.utils.toHex(web3.utils.toWei('10','gwei')),
    to: receive_account,
    value: '0x2386f26fc10000'
  };

  const tx = new Tx(txObject);
  tx.sign(privateKey);

  const serializedTx = tx.serialize();
  const raw = '0x' + serializedTx.toString('hex');

  web3.eth.sendSignedTransaction(raw)
     .once('transactionHash', (hash) => {
       console.info('transactionHash', 'https://ropsten.etherscan.io/tx/' + hash);
     })
     .once('receipt', (receipt) => {
       console.info('receipt', receipt);
    }).on('error', console.error);
  });
})
  • web.eth.getTransactionCount => 여기서 getTransactionCount는 nonce값을 구하는 함수입니다. txCount가 nonce값이죠.

  • txObject => 이 object에는 Nonce, gasLimt, gasPrice, to(받는계좌), value(이더리움 값) 값이 들어갑니다. 그 외에도 object에 담을 변수가 더들어가지만 송금자체적으로는 이렇게만 들어가도 됩니다.

  • tx.sign => 객체를 담은 후 제일 중요한 개인키를 이용한 sign이 들어갑니다. 이더리움 테스트넷과 메인넷에는 필수로 sign객체를 만들어야하죠.

  • web3.eth.sendSignedTransaction => 위의 객체를 모두 설정하였다면 sign된 트랜잭션을 이더리움에 보내는 함수입니다. hash, receipt가 리턴되는데요. 여기서 hash는 트랜잭션 전송한 hash값입니다. 이 hash값을 이용해 이더스캔에서 조회가 가능하죠. receipt는 이더리움 전송한 내역들을 보여지게 됩니다.

로그로 찍은 receipt입니다. 사용된 가스양, 계산된 가스양, 해쉬값, 등등이 나오게 됩니다. 이상없이 전송되면 위그림같은 로그가 나오게 되죠.

Web3로 이더리움 전송확인

이상없이 이더리움이 전송된 것을 확인할 수 있습니다.

var express = require('express');
var app = express();
var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.WebsocketProvider('wss://ropsten.infura.io/ws'));
var Tx = require('ethereumjs-tx');

const send_account    = "0x82Ff486364ebDbEe1b34b7538ceD72448d9b38cb";
const receive_account = "0xf2a58d3F268642f7f5416F4248f4Fb2623a5D929";
const privateKey = Buffer.from('privateKey', 'hex');

//메인홈페이지
app.get('/main', function(req,res){

  web3.eth.getTransactionCount(send_account, (err, txCount) => {

  const txObject = {
    nonce:    web3.utils.toHex(txCount),
    gasLimit: web3.utils.toHex(1000000), // Raise the gas limit to a much higher amount
    gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')),
    to: receive_account,
    value :  '0x2386f26fc10000' //0.01이더 전송 to_hex
  };

  const tx = new Tx(txObject);
  tx.sign(privateKey);

  const serializedTx = tx.serialize();
  const raw = '0x' + serializedTx.toString('hex');

  web3.eth.sendSignedTransaction(raw)
     .once('transactionHash', (hash) => {
       console.info('transactionHash', 'https://ropsten.etherscan.io/tx/' + hash);
     })
     .once('receipt', (receipt) => {
       console.info('receipt', receipt);
    }).on('error', console.error);
  });

});
//app을 listen
app.listen(4000, function(){
  console.log('Connected memo, 4000 port!');
});