一、總覽:6 步閉環
- 用户點擊按鈕
- 前端組裝交易數據(calldata)
- 錢包簽名 → 生成 SignedTx
- 節點廣播 → 網絡挖礦打包
- 鏈上執行合約邏輯 → 更新狀態
- 前端監聽事件 / 讀鏈回顯 → UI 刷新
二、各層角色與工具
|
層級
|
作用
|
常用庫 / 對象
|
|
錢包
|
私鑰保管 + 簽名
|
MetaMask、WalletConnect、Coinbase Wallet
|
|
前端運行時
|
提供 Provider / Signer
|
ethers.js v6、web3.js、viem
|
|
RPC 節點
|
廣播 & 查詢
|
Infura、Alchemy、QuickNode、本地 Hardhat
|
|
鏈上
|
執行字節碼
|
EVM
|
|
事件日誌
|
通知前端
|
ethers.on(event, handler)
|
三、最小可運行範例(React + ethers v6)
① 連接錢包 → 拿到 signer
const provider = new ethers.BrowserProvider(window.ethereum);
await provider.send('eth_requestAccounts', []); // 彈出 MetaMask
const signer = await provider.getSigner(); // 得到可簽名對象
② 創建合約實例
const pool = new ethers.Contract(
'0xEDb4C07B6AfFb61C2A2fa22cBb30552b4F7748f4', // 代理地址
STAKE_ABI, // 邏輯 ABI
signer // 必須帶簽名能力
);
③ 寫操作:質押 0.1 ETH
const tx = await pool.depositEth(0, { value: ethers.parseEther('0.1') });
console.log('txHash', tx.hash);
await tx.wait(); // 等待鏈上確認
console.log('區塊號', tx.blockNumber);
④ 讀操作:查詢已質押
const [amountWei] = await pool.users(0, signer.address);
console.log('已質押', ethers.formatEther(amountWei), 'ETH');
⑤ 監聽事件(可選)
pool.on('Staked', (user, poolId, amount, stakedAt, unlockTime) => {
if (user === signer.address) {
console.log('我剛質押了', ethers.formatEther(amount), 'ETH');
}
});
四、交易生命週期拆解
- 構造調用數據
depositEth(0)→ ABI 編碼 →calldata = 0x441a3e70... - 錢包簽名
MetaMask 把 calldata + gasPrice / gasLimit / nonce / chainId 打包 → 私鑰簽名 → 得到 rawSignedTx - 廣播與挖礦
前端通過eth_sendRawTransaction把簽名交易發給 RPC → 節點 mempool → 礦工打包 → 出塊 - EVM 執行
節點執行合約字節碼:更新 storage(_amountTotal、unclaimedRewards…)、 emit 事件日誌 - 回執與事件
交易回執(receipt)包含:status / gasUsed / logs → 前端await tx.wait()拿到回執 → 解析日誌 → UI 刷新
五、常見坑速查
|
現象
|
原因
|
修復
|
|
contract runner does not support sending transactions
|
給了 provider 沒給 signer
|
|
|
revert: Not enough unlocked stakes
|
鎖倉期未滿
|
等 |
|
insufficient funds
|
錢包 ETH 不夠付 gas + value
|
減少金額或領測試幣
|
|
gas estimation failed
|
參數傳錯/合約內部 revert
|
用 |
六、進階交互模式
- 離線簽名 → 用 Wallet #signTransaction,適合後端批處理
- EIP-712 結構化簽名 → 減少誤導,提高可讀性
- ** multicall ** → 把多筆只讀調用打包,一次 RPC 返回
- 事件掃描 → 用
queryFilter拉歷史日誌,做分頁/圖表 - Gas 策略 → EIP-1559 動態 maxFeePerGas,或手動加速取消
七、一句話總結
Web3 前端與合約交互 = 用 ethers/js 把用户操作編碼成 calldata → 讓錢包簽名 → 通過 RPC 廣播 → 鏈上執行後讀回 events / storage → 刷新 UI。