スマート・コントラクトとのやり取り
常に独自のスマート・コントラクトを記述してデプロイする必要はありません。開発者としては、他の人がすでにイーサリアムネットワークにデプロイしたスマート・コントラクトとやり取りしたい場合がほとんどです。
このページでは、スマート・コントラクトとやり取りするための2つの基本的な方法(データの読み取りと書き込み)と、その両方を行うために必要なツールについて説明します。
前提条件
以下について理解している必要があります。
スマート・コントラクトとやり取りする2つの方法
スマート・コントラクトとのやり取りは、2つのカテゴリに分類されます。
コントラクトからの読み取り
読み取りは無料の操作であり、トランザクションを作成せず、ブロックチェーン上の状態を変更することもありません。
コントラクトから読み取る場合、単にすでに存在するデータをクエリしているだけです。例:
- ERC-20トークンの残高の確認
- 分散型取引所からの現在の価格の読み取り
- NFTの所有者の取得
読み取りは状態を変更しないため、ガスを消費せず、ETHを必要とせずに誰でも実行できます。
コントラクトへの書き込み
書き込みは状態を変更する操作であり、トランザクションを必要とし、ガスを消費します。
コントラクトに書き込む場合、ブロックチェーンの状態を変更する関数をトリガーします。例:
- トークンの送金
- 分散型取引所でのトークンのスワップ
- NFTのミンティング
書き込みには常に以下が必要です。
- ガス代として十分なETHを持つ外部所有アカウント(EOA)
- アカウントの秘密鍵によって署名されたトランザクション
- トランザクションがマイニングされ、ブロックに含まれること
アカウント抽象化を使用すると、スマート・コントラクトアカウントも書き込みを開始でき、ペイマスターがユーザーの代わりにガス代を負担できるため、ETHを保持するEOAは厳密には必要ありません。
コントラクトABIの理解
スマート・コントラクトとやり取りするには、アプリケーションがコントラクトに何ができるかを知る必要があります。ここで**アプリケーション・バイナリ・インターフェース(ABI)**の出番となります。
ABIは、以下を記述するJSONドキュメントです。
- コントラクトが公開するすべての関数(名前、入力、出力)
- コントラクトが発行できるすべてのイベント
- コントラクトと通信する際のデータのエンコードおよびデコード方法
ABIはコントラクトの取扱説明書と考えてください。これがないと、アプリケーションはどの関数が存在するのか、どのようなパラメータを期待しているのかを知ることができません。
コントラクトのABIを見つける場所
- Etherscan上の検証済みコントラクト - Etherscan (新しいタブで開く)は、検証済みのソースコードのABIを自動的に公開します。
- 開発者から - 多くのプロジェクトは、ドキュメントやnpmパッケージでABIを公開しています。
- ソースからの生成 - Solidityのソースコードがある場合は、それをコンパイルしてABIを生成できます。
コントラクトとやり取りするためのツールとライブラリ
開発者は通常、Webアプリ、バックエンド、またはスクリプトからコントラクトとやり取りするために、JavaScript/TypeScriptライブラリを使用します。
クライアントライブラリ(JavaScript/TypeScript)
- Viem (新しいタブで開く) - ファーストクラスの型安全性を備えた、イーサリアム向けのモダンで軽量なTypeScriptインターフェース
- ethers.js (新しいタブで開く) - イーサリアムブロックチェーンとやり取りするための実戦テスト済みのライブラリ
- Web3.js (新しいタブで開く) - オリジナルのイーサリアムJavaScript API
バックエンドライブラリ
- ethers.js (新しいタブで開く) - サーバーサイドスクリプトやボット向けにNode.jsでも動作します。
- Web3.py (新しいタブで開く) - イーサリアムとやり取りするためのPythonライブラリ
- go-ethereum (新しいタブで開く) - Gethチームによる公式のGoライブラリ
例:Viemを使用したトークン残高の読み取り
import { createPublicClient, http, formatUnits } from 'viem'
import { mainnet } from 'viem/chains'
// USDCのコントラクトアドレスとABI(balanceOf用の一部)
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
const abi = [{
name: 'balanceOf',
type: 'function',
stateMutability: 'view',
inputs: [{ name: 'account', type: 'address' }],
outputs: [{ name: '', type: 'uint256' }],
}] as const
const client = createPublicClient({ chain: mainnet, transport: http() })
const balance = await client.readContract({
address: USDC,
abi,
functionName: 'balanceOf',
args: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'], // vitalik.eth
})
console.log(formatUnits(balance, 6)) // USDCの小数点以下は6桁
例:ethers.jsを使用したトランザクションの送信
const { ethers } = require('ethers')
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL)
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
// ERC-20のtransferのABI
const abi = ['function transfer(address to, uint256 amount) returns (bool)']
const contract = new ethers.Contract(tokenAddress, abi, wallet)
const tx = await contract.transfer(recipient, ethers.parseUnits('10', 18))
await tx.wait() // トランザクションがマイニングされるのを待つ
console.log(`Transferred! TX: ${tx.hash}`)
イベントとログ
スマート・コントラクトは、何かが起こったことを知らせるためにイベントを発行できます。アプリケーションはこれらのイベントをリッスンして、リアルタイムで反応することができます。
import { createPublicClient, http, parseAbiItem } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ chain: mainnet, transport: http() })
// USDCのTransferイベントを監視する
const unwatch = client.watchEvent({
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
onLogs: (logs) => console.log(logs),
})
トランザクションのシミュレーション
トランザクションを送信する前に、それをシミュレーションして、ガスを消費することなく成功するかどうかを確認し、その戻り値を見ることができます。これは、エラーを早期に発見したり、結果をプレビューしたりするのに役立ちます。
ほとんどのクライアントライブラリは、eth_callを通じてこれをサポートしています。
// Viemを使用する場合
const result = await client.simulateContract({
address: contractAddress,
abi,
functionName: 'swap',
args: [amountIn],
account: userAddress,
})
ウォレットと署名
分散型アプリケーション (dapp) では、ユーザーのウォレット(メタマスク、Rainbow、WalletConnectなど)が署名を処理します。秘密鍵を直接管理することはありません。
ウォレットライブラリと接続ツールはこれを抽象化するため、アプリケーションロジックの構築に集中できます。
関連チュートリアル
参考文献
- Viemドキュメント:コントラクトへの読み取りと書き込み (新しいタブで開く)
- ethers.jsドキュメント:コントラクト (新しいタブで開く)
- Solidity ABI仕様 (新しいタブで開く)
- ABIとは何か? - Alchemy (新しいタブで開く)