[Example] ERC20 Watcher

ERC20 Watcherโ€Œ

ERC20 Watcher๋Š” ์ด๋ฒคํŠธ๋ฅผ ๊ตฌ๋…ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ„๋‹จํ•œ ๋Œ€์‹œ๋ณด๋“œ์ž…๋‹ˆ๋‹ค. ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ํ†ตํ•ด Tether ERC20 ํ† ํฐ์˜ ์ด๋ฒคํŠธ๋ฅผ ๋Œ€์‹œ๋ณด๋“œ์— ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Project Structure

./sample-erc20-watcher
sample-erc20-watcher/
โ”œโ”€โ”€ /config
โ”œโ”€โ”€ /contracts # ERC20 contract files
โ”œโ”€โ”€ /public
โ”œโ”€โ”€ /src # frontend code
โ”œโ”€โ”€ .env # configuration file
โ”œโ”€โ”€ henesis.yaml # configuration file for integration
โ”œโ”€โ”€ index.js # API server code
โ”œโ”€โ”€ jsconfig.json
โ”œโ”€โ”€ package.json
...
  • API ์„œ๋ฒ„๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ด๋ค„์ ธ์žˆ์Šต๋‹ˆ๋‹ค.

    • GET /api/events : ๋ชจ๋“  ์ด๋ฒคํŠธ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • Frontend

    • API ์„œ๋ฒ„์˜ GET /api/events ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ง€์†์ ์œผ๋กœ ํด๋งํ•˜์—ฌ ์ด๋ฒคํŠธ ์ •๋ณด๋ฅผ ๊ตฌ๋…ํ•ฉ๋‹ˆ๋‹ค.

Step by Step

  1. โ€‹Henesis CLI ์„ค์น˜

  2. Sample repository ๊ฐ€์ ธ์˜ค๊ธฐ

    git clone https://github.com/HAECHI-LABS/sample-erc20-watcher
  3. dependency ์„ค์น˜

    npm install
  4. ๋กœ๊ทธ์ธ(์•„์ง ํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด)

    henesis login
  5. Integration ๋ฐฐํฌ

    henesis integration:deploy
  6. Integration Id์™€ Client Id ํ™•์ธ

    • Integration Id: henesis integration:status

    • Client Id: henesis account:describenpm ru

  7. .env ์— CLIENT_ID INTEGRATION_ID ๋ณ€๊ฒฝ

    CLIENT_ID=<your client id>
    INTEGRATION_ID=<your integration id>
  8. ์†Œ์Šค ์ฝ”๋“œ ๋นŒ๋“œ

    npm run build:standalone
  9. API ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ €์—์„œ http://locahost:3000 ํƒ์ƒ‰

    node index

์ž‘๋™์›๋ฆฌ

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ๋‘ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด ์žˆ์Šต๋‹ˆ๋‹ค.

Integration ๋ฐฐํฌ

Step 5์— henesis integration:deploy ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜๋ฉด henesis.yaml ์— ์žˆ๋Š” ์„ค์ • ํŒŒ์ผ๋Œ€๋กœ Integration์ด ๋ฐฐํฌ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ henesis.yaml ์„ ์ ์ ˆํ•˜๊ฒŒ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค(์ฐธ๊ณ ).

henesis.yaml
version: v1
name: tether-tuto
โ€‹
filters:
contracts:
- address: '0xdac17f958d2ee523a2206206994597c13d831ec7'
path: ./contracts/TetherToken.sol
name: TetherToken
compilerVersion: 0.4.18
โ€‹
blockchain:
platform: ethereum
network: mainnet
threshold: 5
interval: 1000
โ€‹
provider:
type: webSocket

Subscribing Event with Henesis SDK

์ด๋ฒˆ ํŠœํ† ๋ฆฌ์–ผ์—์„œ ์ค‘์š”ํ•œ ๋˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„์€ index.js ์ž…๋‹ˆ๋‹ค. ์ด๊ณณ์—์„œ Henesis SDK๋ฅผ ์ด์šฉํ•˜์—ฌ ์ด๋ฒคํŠธ๋ฅผ ๊ตฌ๋…ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํžˆ ์‚ดํŽด๋ด…์‹œ๋‹ค.

  • Client Id๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๊ตฌ๋…์„ ์œ„ํ•œ Henesis ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

index.js
import { EventStreamer } from '@haechi-labs/henesis-sdk-js'
...
async function henesis() {
// create henesis instance
const eventStreamer = new EventStreamer(CLIENT_ID);
}
  • ์ƒˆ๋กœ ์ƒ์„ฑํ•œ ์ธ์Šคํ„ด์Šค์˜ henesis#subscribe ๋ฅผ ์ด์šฉํ•˜์—ฌ subscription ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    • subscriptionId ์€ ์œ ์ผํ•œ ๊ฐ’์ด์•ผ ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์žŠ์ง€ ๋งˆ์„ธ์š”(์ฐธ๊ณ ).

index.js
import { EventStreamer } from '@haechi-labs/henesis-sdk-js'
โ€‹
async function henesis( ) {
...
// subscribe "streamedBlock", then create subscription object.
const subscription = await eventStreamer.subscribe(
"streamedBlock",
{
integrationId:INTEGRATION_ID,
subscriptionId: "your-subscription-id"
ackTimeout: 30 * 1000 // optional. (default: 10000, unit: ms)
}
);
}
โ€‹
  • ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด event๋ฅผ ๋“ฃ๊ณ  ํŒŒ์‹ฑํ•˜์—ฌ ์›ํ•˜๋Š” ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์ฐธ์กฐ).

index.js
import Henesis from '@haechi-labs/henesis-sdk-js'
โ€‹
async function henesis( ) {
...
subscription.on('message', async message => {
// In case of disconnection due to network abnormalities (such as Wi-Fi problem), up to one duplicated message can be delivered.
// You can check message duplication with messageId or block number.
if (getBlockNumber(message) > processedBlockNumber) {
const events = messageToEvents(message);
// processing events
// For example, you can save events to your database.
events.forEach(event => model.push(event));
//console.log(JSON.stringify(events, undefined, 2));
console.log(`data received, event:${events}`);
// You need to remember the processed index(messageId or block number) of the message you received.
setProcessedBlockNumber(message);
}
message.ack(); // (MUST) Send an ACK message even if duplicated message!!
});
subscription.on('error', err => {
console.error(err);
});
โ€‹
subscription.on('close', err => {
console.error(err);
});
...
}