티스토리 뷰
0. 이전 게시글
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. 전체 코드