[Solidity+Go] geth로 스마트 컨트랙트 배포하기 - 5. 이벤트 구독

geth로 스마트 컨트랙트 배포하기 · 5/7
  1. 1. 초기 구성
  2. 2. 스마트 컨트랙트로 Go 코드 생성
  3. 3. 생성된 Go 코드로 스마트 컨트랙트 배포
  4. 4. 배포된 스마트 컨트랙트와 상호작용
  5. 5. 이벤트 구독
  6. 6. 메타데이터를 사용한 standard json input 생성
  7. 7. standard json input을 사용해 배포한 컨트랙트 검증

1. .env 파일 업데이트

PRIVATE_KEY=<YOUR_PRIVATE_KEY>
RPC_ENDPOINT=http://localhost:8545
RPC_WS_ENDPOINT=ws://localhost:8545

 이벤트 구독을 위해서는 웹소켓 주소가 필요


2. 코드 작성

cmd/subscribe/main.go

package main

import (
	"context"
	"fmt"
	token "go-ethereum-example/gen"
	"os"

	_ "github.com/joho/godotenv/autoload"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Connect to Ethereum client with RPC endpoint
	client, err := ethclient.DialContext(ctx, os.Getenv("RPC_WS_ENDPOINT"))
	handleError(err)

	defer client.Close()

	fmt.Println("Successfully connected to Ethereum client")

	// Change these addresses to match your contract!
	contractAddress := common.HexToAddress("0x5FbDB2315678afecb367f032d93F642f64180aa3")

	// Create an instance of the contract, specifying its address
	tokenInstance, err := token.NewToken(contractAddress, client)
	handleError(err)

	transferChan := make(chan *token.TokenTransfer)

	// Subscribe to Transfer events
	sub, err := tokenInstance.WatchTransfer(&bind.WatchOpts{}, transferChan, nil, nil)
	handleError(err)

	defer sub.Unsubscribe()

	fmt.Println("Successfully subscribed to Transfer events")

	for {
		select {
		case err := <-sub.Err():
			handleError(err)
		case transfer := <-transferChan:
			fmt.Printf("Transfer event received: from=%s to=%s value=%d\n", transfer.From.Hex(), transfer.To.Hex(), transfer.Value)
		}
	}
}

func handleError(err error) {
	if err != nil {
		panic(err)
	}
}

테스트넷 RPC 클라이언트 연결

// Connect to Ethereum client with RPC endpoint
client, err := ethclient.DialContext(ctx, os.Getenv("RPC_WS_ENDPOINT"))
handleError(err)

defer client.Close()

fmt.Println("Successfully connected to Ethereum client")

 웹소켓을 통해 클라이언트 연결

배포된 스마트 컨트랙트의 인스턴스 생성

// Change these addresses to match your contract!
contractAddress := common.HexToAddress("0x5FbDB2315678afecb367f032d93F642f64180aa3")

// Create an instance of the contract, specifying its address
tokenInstance, err := token.NewToken(contractAddress, client)
handleError(err)

이벤트 구독

transferChan := make(chan *token.TokenTransfer)

// Subscribe to Transfer events
sub, err := tokenInstance.WatchTransfer(&bind.WatchOpts{}, transferChan, nil, nil)
handleError(err)

defer sub.Unsubscribe()

fmt.Println("Successfully subscribed to Transfer events")

WatchTransfer 메서드의 인수로 구독 옵션, 이벤트를 받을 채널, 그리고 세 번째부터는 이벤트에서 indexed로 지정된 값들을 필터링하기 위한 값들을 지정할 수 있다. 여기서는 굳이 필요하지 않으므로 nil을 넘겨준다.

이벤트 받기

for {
	select {
	case err := <-sub.Err():
		handleError(err)
	case transfer := <-transferChan:
		fmt.Printf("Transfer event received: from=%s to=%s value=%d\n", transfer.From.Hex(), transfer.To.Hex(), transfer.Value)
	}
}

3. 코드 실행

이벤트 구독

$ go run ./cmd/subscribe/
Successfully connected to Ethereum client
Successfully subscribed to Transfer events

이벤트 발생

$ go run ./cmd/interact/

발생한 이벤트 출력

Transfer event received: from=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 to=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 value=1000000

4. 전체 코드