2. Smart contract deployment, transaction execution

์ด์ „ ํŠœํ† ๋ฆฌ์–ผ์ธ [Development environment setup and smart contract writing / debugging]์—์„œ ๊ฐ„๋‹จํ•œ ๋ฉ”์‹œ์ง€ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๊ณ  ํ…Œ์ŠคํŠธํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ๋ฉ”์‹œ์ง€ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ์ด๋”๋ฆฌ์›€ ํ™˜๊ฒฝ์— ๋ฐฐํฌํ•ด๋ณด๊ณ  Call์„ ํ†ตํ•ด ํŠธ๋žœ์žญ์…˜์„ ์‹คํ–‰ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿ“˜

์ž‘์„ฑํ•œ ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๊ฐ€ ์—†๋‚˜์š”?

์•„๋ž˜ ๋งํฌ๋ฅผ ํ†ตํ•ด Development environment setup and smart contract writing / debugging ํŠœํ† ๋ฆฌ์–ผ์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐ„๋‹จํ•œ ๋ฉ”์‹œ์ง€ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์„ธ์š”!

Development environment setup and smart contract writing / debugging Tutorial


์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ๋ฐฐํฌ

์ž‘์„ฑํ•œ ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๋ธ”๋ก์ฒด์ธ ํ™˜๊ฒฝ์— ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” EOA๋ฅผ ์ด์šฉํ•ด ๋ธ”๋ก์ฒด์ธ ๋„คํŠธ์›Œํฌ์— ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ๋ฐฐํฌ ํŠธ๋žœ์žญ์…˜์„ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๋ฐฐํฌ๋ฅผ ์œ„ํ•ด์„œ๋Š” ์•„๋ž˜ 3๊ฐ€์ง€๊ฐ€ ์ค€๋น„๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. ๋ฐฐํฌํ•  ๋ธ”๋ก์ฒด์ธ ๋„คํŠธ์›Œํฌ์˜ ๋…ธ๋“œ ์—ฐ๊ฒฐ
    • ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ๋ฐฐํฌ ํŠธ๋žœ์žญ์…˜์„ ๊ฒ€์ฆํ•˜๊ณ  ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•  ๋ธ”๋ก์ฒด์ธ ๋„คํŠธ์›Œํฌ ๋…ธ๋“œ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ฐฐํฌ ํŠธ๋žœ์žญ์…˜์„ ์‹คํ–‰ํ•  EOA
    • ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ๋ฐฐํฌ ํŠธ๋žœ์žญ์…˜์„ ์‹คํ–‰ํ•  ๊ณ„์ •์œผ๋กœ ๋ฐฐํฌ์— ํ•„์š”ํ•œ ABI, ๋ฐ”์ดํŠธ์ฝ”๋“œ ๋“ฑ์„ ์ด์šฉํ•ด ํŠธ๋žœ์žญ์…˜์„ ๋งŒ๋“ค๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฐฐํฌ ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ˆ˜๋ฃŒ
    • ๋ธ”๋ก์ฒด์ธ ๋„คํŠธ์›Œํฌ์—์„œ ํŠธ๋žœ์žญ์…˜์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜์ˆ˜๋ฃŒ์ธ ๊ฐ€์Šค๋น„๋ฅผ ์ง€๋ถˆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ณธ ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ์ด๋”๋ฆฌ์›€ Holesky ๋„คํŠธ์›Œํฌ์— ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๋ฐฐํฌํ•˜๊ณ  ํ˜ธ์ถœํ•ด๋ณด๋Š” ๊ณผ์ •์„ ์ง„ํ–‰ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!


๋…ธ๋“œ ์—ฐ๊ฒฐํ•˜๊ธฐ

๋จผ์ € ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ๋ฐฐํฌ ํŠธ๋žœ์žญ์…˜์„ ์ „์†กํ•˜๊ธฐ ์œ„ํ•œ ๋…ธ๋“œ๋ฅผ ์ค€๋น„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ง์ ‘ ๋…ธ๋“œ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ๋…ธ๋“œ๋ฅผ ์šด์˜ํ•˜๊ฑฐ๋‚˜, ๋…ธ๋“œ Provider ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ ๋…ธ๋“œ Endpoint๋ฅผ ํš๋“ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์•ˆ์ •์ ์ธ Node Provider Service ์ค‘ ํ•˜๋‚˜์ธ Nodit์„ ์ด์šฉํ•ด ์ด๋”๋ฆฌ์›€ Holesky์˜ ๋…ธ๋“œ๋ฅผ ์‰ฝ๊ณ  ๊ฐ„ํŽธํ•˜๊ฒŒ ์—ฐ๊ฒฐํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ๋งํฌ๋ฅผ ํด๋ฆญํ•ด Nodit ์ฝ˜์†” ํšŒ์›๊ฐ€์ž… ๋ฐ ์˜จ๋ณด๋”ฉ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•ด ๋ณด์„ธ์š”!


ํšŒ์›๊ฐ€์ž… ๋ฐ ์˜จ๋ณด๋”ฉ์„ ์™„๋ฃŒํ–ˆ๋‹ค๋ฉด ์ฝ˜์†”์—์„œ ์•„๋ž˜ ์‚ฌ์ง„๊ณผ ๊ฐ™์ด ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋…ธ๋“œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ณ  [HTTPS Endpoint] ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด ํŠน์ • ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-11 แ„‹แ…ฉแ„’แ…ฎ 1.46.21.png

๋งŒ์•ฝ ์—ฐ๊ฒฐํ•˜๋ ค๋Š” ๋…ธ๋“œ๊ฐ€ ์—†๋‹ค๋ฉด ์ขŒ์ธก ๋ฉ”๋‰ด์˜ [Nodes] ํƒญ์„ ํด๋ฆญํ•ด ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋…ธ๋“œ๊ฐ€ ๋ฌด์—‡์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ด ๋ณด์„ธ์š”!

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-11 แ„‹แ…ฉแ„’แ…ฎ 2.32.49.png

ํŠธ๋žœ์žญ์…˜์„ ์‹คํ–‰ํ•  EOA ์ƒ์„ฑ

Metamask๋ฅผ ์ด์šฉํ•œ EOA ์ƒ์„ฑ ๋ฐฉ๋ฒ•

Metamask๋ฅผ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋จผ์ € Metamask๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ๋งํฌ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์„ค์น˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์„ค์น˜๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด Nodit ์ฝ˜์†”์— ๋กœ๊ทธ์ธํ•˜์—ฌ ์•„๋ž˜ ์‚ฌ์ง„๊ณผ ๊ฐ™์ด ํ”„๋กœ์ ํŠธ์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-11 แ„‹แ…ฉแ„’แ…ฎ 2.49.39.png

[ํ”„๋กœ์ ํŠธ Overview] ํ™”๋ฉด์—์„œ [Connected Nodes] ์˜์—ญ์—์„œ ์ด๋”๋ฆฌ์›€ Holesky ๋ฐ•์Šค์˜ [Metamask] ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ์†์‰ฝ๊ฒŒ Metamask์™€ ๋ธ”๋ก์ฒด์ธ ๋„คํŠธ์›Œํฌ๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ Wallet ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์•„๋‹ˆ๋ผ ์ง์ ‘์ ์œผ๋กœ ๋…ธ๋“œ์™€ ์—ฐ๊ฒฐํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด [HTTPS Endpoint] ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-10 แ„‹แ…ฉแ„’แ…ฎ 1.53.22.png

๋งŒ์•ฝ Nodit ์ฝ˜์†”์—์„œ ์ด๋”๋ฆฌ์›€ Holesky ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ, ์ขŒ์ธก ๋ฉ”๋‰ด ์ค‘ [Nodes] ํƒญ์„ ํด๋ฆญํ•˜์—ฌ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•œ EOA ์ƒ์„ฑ ๋ฐฉ๋ฒ•

Metamask์™€ ๊ฐ™์ด Wallet ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•ด EOA๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ํ„ฐ๋ฏธ๋„์— ์ž…๋ ฅํ•˜์—ฌ ethers.js ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

$ npm install ethers

ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ TS ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ ํ›„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•˜๋ฉด Wallet ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// createEoa.ts

import { ethers } from "ethers";
const myWallet = ethers.Wallet.createRandom();
console.log(myWallet); 
$ ts-node createEoa.ts
//response

Wallet {
  _isSigner: true,
  _signingKey: [Function (anonymous)],
  address: '0xc675Dda1d2d545E20AAC8640f2BaA402D8a05887',
  _mnemonic: [Function (anonymous)],
  provider: null
}

Metamask๋กœ ์ƒ์„ฑํ•œ ๊ณ„์ •์—์„œ ๋‹ˆ๋ชจ๋‹‰์„ ์ถ”์ถœํ•ด ์ด์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค! ์•„๋ž˜ ์‚ฌ์ง„์— ๋”ฐ๋ผ ๋‹ˆ๋ชจ๋‹‰์„ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โ—๏ธ

๋‹ˆ๋ชจ๋‹‰๊ณผ Private Key๋Š” ์ ˆ๋Œ€ ์œ ์ถœ๋˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค!

๋‹ˆ๋ชจ๋‹‰์ด๋‚˜ Private Key๊ฐ€ ์œ ์ถœ๋  ๊ฒฝ์šฐ ํ•ด๋‹น ๊ณ„์ •์ด ๋ณด์œ ํ•œ ๋ชจ๋“  ์ž์‚ฐ์˜ ๊ถŒํ•œ์„ ํƒˆ์ทจ๋‹นํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ ˆ๋Œ€ ์œ ์ถœ๋˜์ง€ ์•Š๋„๋ก ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์•ˆ์ „ํ•˜๊ฒŒ ํŠœํ† ๋ฆฌ์–ผ์„ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํŠœํ† ๋ฆฌ์–ผ์šฉ EOA๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•ด ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅ ๋“œ๋ฆฝ๋‹ˆ๋‹ค.


  1. Metamask๋ฅผ ์ผœ๊ณ  ์šฐ์ธก ์ƒ๋‹จ์˜ ๋ฉ”๋‰ด๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-11 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 11.25.44.png
  1. ๋ฉ”๋‰ด ์ค‘ Settings์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-11 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 11.26.30.png
  1. Security & privacy ๋ฉ”๋‰ด๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-11 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 11.26.54.png
  1. Security ํƒญ์—์„œ [Reveal Secret Recovery Phrase] ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด ๋‹ˆ๋ชจ๋‹‰์„ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-11 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 11.27.28.png

์ดํ›„ ์ถ”์ถœํ•œ ๋‹ˆ๋ชจ๋‹‰์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ์— ์ฒจ๋ถ€ํ•˜์—ฌ Metamask ๊ณ„์ •์„ ์ฝ”๋“œ์— ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const mnemonic = "your_mnemonic_words"
const walletFromMnemonic = ethers.Wallet.fromMnemonic(mnemonic);

ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ˆ˜๋ฃŒ ๋ฐ›๊ธฐ

์ด์ œ ๋ธ”๋ก์ฒด์ธ ๋…ธ๋“œ์™€ EOA๊ฐ€ ์ค€๋น„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ ํŠธ๋žœ์žญ์…˜ ์‹คํ–‰ ์‹œ ํ•„์š”ํ•œ ์ˆ˜์ˆ˜๋ฃŒ์ธ ๊ฐ€์Šค๋น„๋งŒ ์žˆ์œผ๋ฉด ํŠธ๋žœ์žญ์…˜์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ Faucet์ด๋ผ๊ณ  ๋ถ€๋ฅด๋ฉฐ ์ธํ„ฐ๋„ท์—์„œ โ€œEthereum Holesky faucetโ€์„ ๊ฒ€์ƒ‰ํ•ด ๋‹ค์–‘ํ•œ Faucet ์ œ๊ณต์ž์˜ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ๋ฐฐํฌ

์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•œ ๋ชจ๋“  ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค! ์ด์ œ ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ์ด๋”๋ฆฌ์›€ Holesky์— ๋ฐฐํฌํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Ethers.js ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•ด EOA๋ฅผ ์ƒ์„ฑํ•œ ๋’ค ํ•ด๋‹น EOA๋ฅผ ์ด์šฉํ•ด ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๋ฐฐํฌํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์šฐ์„  ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ์ปดํŒŒ์ผํ•˜๊ณ  ๋ฐ˜ํ™˜๋ฐ›์€ ABI์™€ bytecode๋ฅผ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ์ €์žฅํ•ด ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

// data.ts

export const abi = [
  {
    inputs: [],
    stateMutability: "nonpayable",
    type: "constructor",
  },
...
];

export const bytecode = "your_bytecode";


Ethers.js๋ฅผ ์ด์šฉํ•ด ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๋ฐฐํฌํ•  ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

//deployContract.ts

import { ethers } from "ethers";
import { abi, bytecode } from "./data";

const provider = new ethers.providers.JsonRpcProvider(
  "https://ethereum-holesky.nodit.io/your_node_api_key"
);

const mnemonic = "your_memonic_words";
const accountFromMnemonic = ethers.Wallet.fromMnemonic(mnemonic);
const connectWalletToProvider = accountFromMnemonic.connect(provider);
const contractFactory = new ethers.ContractFactory(
  abi,
  bytecode,
  connectWalletToProvider
);

(async () => {
  try {
    const deployingContract = await contractFactory.deploy();
    await deployingContract.deployed();
    console.log(deployingContract.address);
  } catch (error) {
    console.error(error);
  }
})();


์ฝ”๋“œ์˜ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Nodit์ด ์ œ๊ณตํ•˜๋Š” ์ด๋”๋ฆฌ์›€ Holesky ๋…ธ๋“œ๋ฅผ HTTP Endpoint๋ฅผ ์ด์šฉํ•˜์—ฌ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” provider ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

const provider = new ethers.providers.JsonRpcProvider(
  "https://ethereum-holesky.nodit.io/your_node_api_key"
);

๋‹ˆ๋ชจ๋‹‰ ๋‹จ์–ด๋“ค์„ ์ด์šฉํ•ด Wallet ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ provider ์ธ์Šคํ„ด์Šค๋ฅผ ์ด์šฉํ•ด ์ด๋”๋ฆฌ์›€ Holesky ๋…ธ๋“œ์— ์—ฐ๊ฒฐํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

const mnemonic = "your_memonic_words";
const accountFromMnemonic = ethers.Wallet.fromMnemonic(mnemonic);
const connectWalletToProvider = accountFromMnemonic.connect(provider);

ABI์™€ bytecode ๊ทธ๋ฆฌ๊ณ  ๋…ธ๋“œ์™€ ์—ฐ๊ฒฐ๋œ ์ง€๊ฐ‘์„ ์ด์šฉํ•ด ์ปจํŠธ๋ž™ํŠธ ๋ฐฐํฌ ํŠธ๋žœ์žญ์…˜์— ํŠนํ™”๋œ ContractFactory ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

const contractFactory = new ethers.ContractFactory(
  abi,
  bytecode,
  connectWalletToProvider
);

์ฆ‰์‹œ์‹คํ–‰ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ์ปจํŠธ๋ž™ํŠธ ๋ฐฐํฌ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. contractFactory์˜ deploy ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ deployed ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ๋ธ”๋ก์ฒด์ธ ๋„คํŠธ์›Œํฌ ์ƒ์—์„œ ๋ฐฐํฌ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค. console.log๋ฅผ ์ด์šฉํ•ด ๋ฐฐํฌ๊ฐ€ ์™„๋ฃŒ๋œ ํ›„ ์ปจํŠธ๋ž™ํŠธ์˜ ์ฃผ์†Œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(async () => {
  try {
    const deployingContract = await contractFactory.deploy();
    await deployingContract.deployed();
    console.log(deployingContract.address);
  } catch (error) {
    console.error(error);
  }
})();


ํ„ฐ๋ฏธ๋„์— ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๋ฐฐํฌํ•ด ๋ณด์„ธ์š”! ๊ทธ๋ฆฌ๊ณ  Etherscan์—์„œ ์ปจํŠธ๋ž™ํŠธ ์ฃผ์†Œ๋ฅผ ๊ฒ€์ƒ‰ํ•ด ๋ณด์„ธ์š”!

$ts-node deployContract.ts

์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ํ˜ธ์ถœ

๋ฐฐํฌ๋œ ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ์˜ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด ๊ฒฐ๊ณผ๊ฐ€ ํ…Œ์ŠคํŠธ์—์„œ ์ง„ํ–‰ํ•œ ๋‚ด์šฉ๊ณผ ๋™์ผํ•œ์ง€ ํ™•์ธํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ฐฐํฌํ•œ ์ปจํŠธ๋ž™ํŠธ์— ์ž‘์„ฑ๋œ ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. getMessage
    • ํ˜„์žฌ ๋ฉ”์‹œ์ง€๋ฅผ ์กฐํšŒํ•œ๋‹ค.
  2. setMessage
    • ํ˜„์žฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ•œ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.
  3. initMessage
    • ํ˜„์žฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋นˆ string ๋ฌธ์ž์—ด๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

๋ฐฐํฌ ์‹œ constructor ํ•จ์ˆ˜์—์„œ โ€œHello World! This is Nodit!โ€ ์ด๋ผ๋Š” ๋ฌธ์ž์—ด์„ ํ˜„์žฌ ๋ฉ”์‹œ์ง€๋กœ ์„ค์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— getMessage ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ ๋™์ผํ•œ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ฐ˜ํ™˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


getMessage ํ˜ธ์ถœ

getMessage๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ „์ฒด ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

//getMessage.ts

import { ethers } from "ethers";
import { abi, bytecode } from "./data";

const provider = new ethers.providers.JsonRpcProvider(
  "https://ethereum-holesky.nodit.io/your_nodit_api_key"
);
const contractAddress = "your_contract_address";

(async () => {
  try {
    const contract = new ethers.Contract(contractAddress, abi, provider);
    const getMessage = await contract.getMessage();
    console.log(getMessage);
  } catch (error) {
    console.error(error);
  }
})();

์ปจํŠธ๋ž™ํŠธ์˜ ์ฃผ์†Œ์™€ abi ๊ทธ๋ฆฌ๊ณ  ๋…ธ๋“œ์™€์˜ ์—ฐ๊ฒฐ์„ ์œ„ํ•ด provider ์ธ์Šคํ„ด์Šค๋ฅผ ์ด์šฉํ•ด ์ƒˆ๋กœ์šด Contract ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

const contract = new ethers.Contract(contractAddress, abi, provider);

Contract ์ธ์Šคํ„ด์Šค๋Š” abi์™€ ์ปจํŠธ๋ž™ํŠธ ์ฃผ์†Œ๋กœ ํŠน์ •๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ์ปจํŠธ๋ž™ํŠธ์— ์ž‘์„ฑ๋œ ํ•จ์ˆ˜๋ฅผ ํŠน์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ์— ์ž‘์„ฑ๋œ ํ•จ์ˆ˜์™€ ๋™์ผํ•œ ์ด๋ฆ„์œผ๋กœ ์›ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const getMessage = await contract.getMessage();
console.log(getMessage);

์ด์ œ ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”! constructor ํ•จ์ˆ˜์— ์ž…๋ ฅํ•œ ๋ฉ”์‹œ์ง€์™€ ๋™์ผํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

$ ts-node getMessage.ts
Hello World! This is Nodit!

setMessage ํ˜ธ์ถœ

setMessage ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ „์ฒด ์ฝ”๋“œ ์—ญ์‹œ getMessage ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ฝ”๋“œ์™€ ์œ ์‚ฌํ•˜๊ฒŒ ์ž‘์„ฑํ•ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

//setMessage.ts

import { ethers } from "ethers";
import { abi, bytecode } from "./data";

const provider = new ethers.providers.JsonRpcProvider(
  "https://ethereum-holesky.nodit.io/your_nodit_api_key"
);
const contractAddress = "your_contract_address";

const mnemonic =
  "your_mnemonic_words";
const accountFromMnemonic = ethers.Wallet.fromMnemonic(mnemonic);
const connectWalletToProvider = accountFromMnemonic.connect(provider);

(async () => {
  try {
    const contract = new ethers.Contract(
      contractAddress,
      abi,
      connectWalletToProvider
    );
    const setMessage = await contract.setMessage(
      "Nodit is one of the best Node Provider Service in the world!"
    );
    await setMessage.wait();
  } catch (error) {
    console.error(error);
  }
})();


์•ž์„œ ์„ค๋ช…ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” provider ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ์ด์šฉํ•ด Wallet ์ธ์Šคํ„ด์Šค๋ฅผ ๋…ธ๋“œ์— ์—ฐ๊ฒฐํ•ด ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

const provider = new ethers.providers.JsonRpcProvider(
  "https://ethereum-holesky.nodit.io/your_nodit_api_key"
);
const contractAddress = "your_contract_address";

const mnemonic =
  "your_mnemonic_words";
const accountFromMnemonic = ethers.Wallet.fromMnemonic(mnemonic);
const connectWalletToProvider = accountFromMnemonic.connect(provider);

getMessage์™€ ๊ฐ™์ด Contract ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋‚˜ ์ธ์ž๋กœ provider ์ธ์Šคํ„ด์Šค๊ฐ€ ์•„๋‹Œ provider๊ฐ€ ์—ฐ๊ฒฐ๋œ Wallet ์ธ์Šคํ„ด์Šค๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

const contract = new ethers.Contract(
  contractAddress,
  abi,
  connectWalletToProvider
);

์ธ์ž๋กœ ๋ณ€๊ฒฝํ•  ๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ•˜๊ณ  Contract ์ธ์Šคํ„ด์Šค๋ฅผ ์ด์šฉํ•ด setMessage๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํŠธ๋žœ์žญ์…˜ ์‹คํ–‰ ํ›„ ํŠธ๋žœ์žญ์…˜์ด ์ฒ˜๋ฆฌ๋  ๋•Œ ๊นŒ์ง€ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค.

const setMessage = await contract.setMessage(
  "Nodit is one of the best Node Provider Service in the world!"
);
await setMessage.wait();


์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”! setMessage ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ts-node setMessage.ts

๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ getMessage๋ฅผ ํ˜ธ์ถœํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”. ๋ฉ”์‹œ์ง€๊ฐ€ ๋ณ€๊ฒฝ๋œ๊ฒŒ ๋ณด์ด์‹œ๋‚˜์š”?

Nodit is one of the best Node Provider Service in the world!

initMessage ํ˜ธ์ถœ

๋งˆ์ง€๋ง‰์œผ๋กœ initMessage ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด ํ˜„์žฌ ์ €์žฅ๋œ ๋ฌธ์ž์—ด์„ ์ดˆ๊ธฐํ™” ํ•ฉ๋‹ˆ๋‹ค. initMessage์˜ ๊ฒฝ์šฐ, setMessage์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํŠธ๋žœ์žญ์…˜์„ ์ด์šฉํ•ด ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•œ ์ฝ”๋“œ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// initMessage.ts

import { ethers } from "ethers";
import { abi, bytecode } from "./data";

const provider = new ethers.providers.JsonRpcProvider(
  "https://ethereum-holesky.nodit.io/your_nodit_api_key"
);
const contractAddress = "your_contract_address";

const mnemonic =
  "your_mnemonic_words";
const accountFromMnemonic = ethers.Wallet.fromMnemonic(mnemonic);
const connectWalletToProvider = accountFromMnemonic.connect(provider);

(async () => {
  try {
    const contract = new ethers.Contract(
      contractAddress,
      abi,
      connectWalletToProvider
    );
    const initMessage = await contract.initMessage();
    await initMessage.wait();
  } catch (error) {
    console.error(error);
  }
})();

์œ„์™€ ๊ฐ™์ด ์ž‘์„ฑํ•œ ํ›„ ํŒŒ์ผ์„ ์‹คํ–‰ํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ์ดˆ๊ธฐํ™” ํ•ด ๋ณด์„ธ์š”! ๊ทธ๋ฆฌ๊ณ  getMessage๋ฅผ ์ด์šฉํ•ด ๊ฐ’์„ ํ™•์ธํ•ด ๋ณด์„ธ์š”!


์ง€๊ธˆ๊นŒ์ง€ ๊ฐ„๋‹จํ•œ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์ด๋ฅผ ๋ธ”๋ก์ฒด์ธ ๋„คํŠธ์›Œํฌ์— ๋ฐฐํฌํ•˜๊ณ  ์‹ค์ œ ํ˜ธ์ถœํ•ด ๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์ ธ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๋ธ”๋ก์ฒด์ธ์—์„œ ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ดํ•ด๊ฐ€ ๋˜์…จ๋‚˜์š”?

๋‹ค์Œ ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” Nodit์—์„œ ์ œ๊ณตํ•˜๋Š” API๋ฅผ ์ด์šฉํ•ด ์ด๋ฒˆ ํŠœํ† ๋ฆฌ์–ผ์„ ์ง„ํ–‰ํ•˜๋ฉฐ ๋ฐœ์ƒํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ด ํ™•์ธํ•ด ๋ณด๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!