DEV Community

Cover image for วิธีใช้ MetaMask API: เชื่อมต่อ dApp กับกระเป๋าเงิน Ethereum
Thanawat Wongchai
Thanawat Wongchai

Posted on • Originally published at apidog.com

วิธีใช้ MetaMask API: เชื่อมต่อ dApp กับกระเป๋าเงิน Ethereum

MetaMask เป็นประตูสู่โลกของ Ethereum สำหรับผู้ใช้หลายสิบล้านคน หากคุณกำลังพัฒนา dApp หรือแอปที่ต้องเชื่อมต่อกับกระเป๋าเงิน Ethereum, MetaMask API คือจุดเชื่อมต่อสำคัญระหว่าง UI ของคุณกับคีย์การลงนามของผู้ใช้ ภายใต้ชื่อ “MetaMask API” มีทั้งผู้ให้บริการ window.ethereum ตามมาตรฐาน EIP-1193 ที่ถูก inject ในเบราว์เซอร์ และ MetaMask SDK สำหรับใช้งานกับมือถือ, React Native, Node.js หากคุณเข้าใจวิธีใช้งานผู้ให้บริการนี้ คุณจะสามารถรวมกระเป๋าเงินบนเว็บทุกรูปแบบได้ถึง 80% แล้ว

ทดลองใช้ Apidog วันนี้

คู่มือฉบับนี้สรุปวิธีการตรวจจับผู้ให้บริการ, ขอเชื่อมต่อบัญชี, อ่านข้อมูลเชน, ลงนามข้อความด้วย personal_sign และ EIP-712, ส่งธุรกรรม, เพิ่ม/เปลี่ยนเชน และการใช้งาน MetaMask SDK สำหรับแอปนอกเบราว์เซอร์ พร้อมตัวอย่างโค้ดแต่ละขั้นตอน นอกจากนี้ยังแนะนำการใช้ ethers.js v6, viem เป็น wrapper ระดับสูง และ Apidog สำหรับทดสอบ/ดีบัก JSON-RPC โดยไม่ต้องสร้าง frontend ชั่วคราว

หากคุณสร้างแอปเกี่ยวกับกระเป๋าเงิน ควรบุ๊กมาร์กหน้านี้และคู่มือ API กระเป๋าเงินคริปโตที่ดีที่สุด เพื่อเข้าใจภาพรวมของผู้ให้บริการแต่ละตัว

สรุป

  • MetaMask API = ผู้ให้บริการ EIP-1193 ผ่าน window.ethereum + MetaMask SDK สำหรับมือถือ/Node
  • เริ่มต้นด้วย eth_requestAccounts เพื่อขอเชื่อมต่อ, ฟัง event accountsChanged และ chainChanged
  • ลงนามข้อความด้วย personal_sign, ข้อมูลแบบ struct ด้วย eth_signTypedData_v4 (EIP-712)
  • เปลี่ยน/เพิ่มเชนด้วย wallet_switchEthereumChain (EIP-3326), wallet_addEthereumChain (EIP-3085)
  • ไลบรารีระดับสูง (ethers.js v6, viem, wagmi) เป็น wrapper ของ provider; Snaps ขยาย MetaMask เอง
  • ใช้ Apidog ทดสอบ JSON-RPC endpoint, จำลอง/ตรวจสอบธุรกรรม, แก้ไขปัญหาการลงนามก่อนเผยแพร่

MetaMask API คืออะไร?

MetaMask API คืออินเทอร์เฟซที่ MetaMask เปิดเผยให้เว็บและแอปสามารถโต้ตอบกับ Ethereum/EVM chain ได้ ในเบราว์เซอร์จะ inject window.ethereum ตามมาตรฐาน EIP-1193 ซึ่งเป็นมาตรฐานเดียวกับที่ใช้ในกระเป๋าเงินอื่นๆ เช่น Coinbase Wallet, Rabby, Frame จึงสามารถใช้โค้ดเดียวกันได้

ถ้าอยู่นอกเบราว์เซอร์ (React Native, Node.js, Electron ฯลฯ) ให้ใช้ MetaMask SDK ที่จำลอง provider แบบเดียวกัน รองรับ deep-link/QR code บนมือถือ โดยยังสื่อสารผ่าน EIP-1193 เช่นเดิม โค้ดแอปจึงเปลี่ยนแปลงน้อยมาก

MetaMask ยังมี Snaps สำหรับขยาย wallet ด้วยเชนใหม่, RPC methods, หรือ account types ที่กำหนดเอง (อยู่นอกขอบเขตบทความนี้)

การยืนยันตัวตนและการตั้งค่า

MetaMask provider ไม่ต้องใช้ API key การยืนยันตัวตนคือให้ผู้ใช้อนุมัติแต่ละ request ใน UI ของ wallet คุณต้อง:

  1. ตรวจจับ provider
  2. ฟัง event สำคัญ

ตรวจจับ provider ด้วย @metamask/detect-provider:

// Vanilla JS detection
import detectEthereumProvider from '@metamask/detect-provider';

const provider = await detectEthereumProvider({ mustBeMetaMask: true });

if (!provider) {
  alert('Please install MetaMask');
} else {
  console.log('MetaMask detected');
}
Enter fullscreen mode Exit fullscreen mode

หลังจากได้ provider แล้ว ให้ set event listener ก่อนขอข้อมูลใด ๆ

window.ethereum.on('accountsChanged', (accounts) => {
  if (accounts.length === 0) {
    console.log('User disconnected');
  } else {
    console.log('Active account:', accounts[0]);
  }
});

window.ethereum.on('chainChanged', (chainId) => {
  // Best practice: reload the page on chain change
  window.location.reload();
});
Enter fullscreen mode Exit fullscreen mode

หากใช้ React, wagmi จะจัดการทั้งหมดนี้ให้โดยอัตโนมัติ

เอนด์พอยต์หลัก

ทุกเมธอดเรียกผ่าน window.ethereum.request({ method, params }) (JSON-RPC method + params) ครอบคลุม dApp ส่วนใหญ่

ร้องขอบัญชีและอ่านเชน

// ขอเชื่อมต่อบัญชี
const accounts = await window.ethereum.request({
  method: 'eth_requestAccounts',
});
const account = accounts[0];

// อ่าน chain ปัจจุบัน
const chainId = await window.ethereum.request({
  method: 'eth_chainId',
});

console.log(account, chainId); // '0x...' '0x1' (Ethereum mainnet)
Enter fullscreen mode Exit fullscreen mode

ตัวอย่าง JSON-RPC ดิบ (run บนโหนดเอง):

curl https://mainnet.infura.io/v3/YOUR_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'
Enter fullscreen mode Exit fullscreen mode

ถ้าแค่ read อย่างเดียว ไม่ต้องใช้ MetaMask ก็ได้ — ใช้ node provider อย่าง Alchemy หรือ Infura แทน ดู คู่มือ Alchemy API

ลงนามข้อความง่ายๆ

personal_sign ใช้ลงนามข้อความแบบ text ที่มนุษย์อ่านได้

const message = 'Sign in to Apidog at ' + new Date().toISOString();
const signature = await window.ethereum.request({
  method: 'personal_sign',
  params: [message, account],
});
Enter fullscreen mode Exit fullscreen mode

ลงนามข้อมูลที่มีโครงสร้างด้วย EIP-712

ใช้ eth_signTypedData_v4 สำหรับข้อมูลที่มีหลายฟิลด์ (เช่น permit, login challenge)

const typedData = {
  domain: { name: 'Apidog Demo', version: '1', chainId: 1 },
  types: {
    EIP712Domain: [
      { name: 'name', type: 'string' },
      { name: 'version', type: 'string' },
      { name: 'chainId', type: 'uint256' },
    ],
    Login: [
      { name: 'wallet', type: 'address' },
      { name: 'nonce', type: 'uint256' },
    ],
  },
  primaryType: 'Login',
  message: { wallet: account, nonce: 42 },
};

const sig = await window.ethereum.request({
  method: 'eth_signTypedData_v4',
  params: [account, JSON.stringify(typedData)],
});
Enter fullscreen mode Exit fullscreen mode

ส่งธุรกรรม

eth_sendTransaction ให้ MetaMask จัดการ nonce/gas ให้อัตโนมัติ

const txHash = await window.ethereum.request({
  method: 'eth_sendTransaction',
  params: [{
    from: account,
    to: '0xRecipientAddressHere',
    value: '0x38d7ea4c68000', // 0.001 ETH in wei, hex
  }],
});
Enter fullscreen mode Exit fullscreen mode

เปลี่ยนหรือเพิ่มเชน

เปลี่ยนเชน/เพิ่มเชนใหม่ (EIP-3326, EIP-3085):

// เปลี่ยนเป็น Polygon (chainId 137 = 0x89)
try {
  await window.ethereum.request({
    method: 'wallet_switchEthereumChain',
    params: [{ chainId: '0x89' }],
  });
} catch (err) {
  if (err.code === 4902) {
    // Chain not added yet
    await window.ethereum.request({
      method: 'wallet_addEthereumChain',
      params: [{
        chainId: '0x89',
        chainName: 'Polygon',
        rpcUrls: ['https://polygon-rpc.com'],
        nativeCurrency: { name: 'MATIC', symbol: 'MATIC', decimals: 18 },
      }],
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

React กับ MetaMask SDK

รวม MetaMask SDK กับ React ได้สะดวก รองรับทั้ง desktop extension, mobile deep-link, in-app browser

import { MetaMaskProvider, useSDK } from '@metamask/sdk-react';

function Connect() {
  const { sdk, connected, account } = useSDK();
  return (
    <button onClick={() => sdk?.connect()}>
      {connected ? account : 'Connect MetaMask'}
    </button>
  );
}

export default function App() {
  return (
    <MetaMaskProvider sdkOptions={{ dappMetadata: { name: 'My dApp' } }}>
      <Connect />
    </MetaMaskProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

ใน production, ควร wrap provider ด้วย ethers.js v6 หรือ viem เพื่อใช้ contract typed, decode ABI, error ที่ดีขึ้น แต่ยังสื่อสารกับ MetaMask API เดิม ถ้าต้องการ login ทางเลือก เช่น email/social ให้ดู คู่มือ Privy API

ข้อผิดพลาดที่พบบ่อยและข้อจำกัดอัตรา (Rate Limits)

MetaMask คืนค่า error code มาตรฐาน JSON-RPC ที่เจอบ่อย:

  • 4001: ผู้ใช้ปฏิเสธคำขอ — แจ้งเตือนผู้ใช้และอย่าลองใหม่อัตโนมัติ
  • 4100: ไม่ได้รับอนุญาต — ยังไม่ได้เชื่อมต่อบัญชี, ต้อง eth_requestAccounts ก่อน
  • 4200: เมธอดไม่รองรับ — ตรวจสอบว่าเป็น MetaMask ก่อนเรียกเมธอดเฉพาะ
  • 4902: เชนนี้ยังไม่ได้เพิ่ม — ดำเนินการ wallet_addEthereumChain
  • -32002: มี request รอดำเนินการ — debounce ปุ่มฝั่งคุณ

Provider ไม่จำกัดอัตรา (rate limit) แต่ RPC node มี ถ้าใช้ Infura/Alchemy จะขึ้นกับ package ที่ใช้ สำหรับ dApp ที่มี on-ramp/off-ramp fiat เช่น แปลง ETH → USD, ดู API on-ramp และ off-ramp ของเงินเฟียต

ราคา MetaMask API

MetaMask extension และ SDK ใช้ฟรี ไม่มีค่าใช้จ่ายต่อการเชื่อมต่อ, ลงนาม, หรือธุรกรรม MetaMask มีรายได้จากค่าธรรมเนียมใน wallet (swap, MetaMask Card) ไม่ใช่นักพัฒนา dApp

ค่าใช้จ่ายเกิดจาก RPC node ที่ dApp เรียกใช้ เช่น Alchemy/Infura — แพ็กเกจฟรีเหมาะกับแอปเล็ก dApp จริงจังมักเสียระหว่าง $49–$299/เดือน

การทดสอบ MetaMask API ด้วย Apidog

การ sign ผ่านเบราว์เซอร์ debug ยาก เพราะต้องผ่าน extension/page/mobile deep-link ใช้ Apidog เพื่อเรียก JSON-RPC endpoint ตรง, ตรวจสอบ eth_chainId, eth_getBalance, และบันทึก action เป็น test collection ได้

สามารถ import spec JSON-RPC, ตั้งค่า node URL เป็น environment variable, นำกลับมาใช้กับทุก chain ที่ EVM-compatible ได้ Apidog ยัง mock response ได้ — dev frontend สามารถใช้ eth_sendTransaction ปลอมสร้างแอปแม้ smart contract ยังไม่ deploy สำหรับ CI เรียก collection เดิมผ่าน CLI ได้ ถ้ามี breaking response จะทำให้ build fail หากเคยเจอปัญหา Postman sync ทีม, ดู คู่มือทดสอบ API โดยไม่ต้องใช้ Postman

ดาวน์โหลด Apidog เพื่อเริ่มต้นใช้งาน

คำถามที่พบบ่อย

MetaMask API ใช้งานได้บนมือถือหรือไม่?

ได้, ใช้ MetaMask SDK ซึ่ง deep-link ไปแอปมือถือสำหรับ sign พื้นผิว provider เหมือน extension โค้ดยังคงเหมือนเดิม ดูเปรียบเทียบกับ SDK อื่นใน API กระเป๋าเงินคริปโตที่ดีที่สุด

ความแตกต่าง eth_sign, personal_sign, eth_signTypedData_v4 คือ?

eth_sign ลงนาม byte ดิบ (อันตราย), MetaMask จะแจ้งเตือน

personal_sign มี prefix ข้อความสำหรับมนุษย์

eth_signTypedData_v4 ลงนาม struct (EIP-712), UI แสดง field ชัดเจน

แนะนำใช้สองตัวหลัง, หลีกเลี่ยง eth_sign

ต้องใช้ API key แยกจาก MetaMask หรือไม่?

ไม่ต้อง MetaMask provider ฟรีและไม่ต้องใช้ key แต่ต้องมี RPC node (Alchemy/Infura) สำหรับ read ข้อมูลนอก wallet ซึ่งต้องใช้ key ของ provider นั้น

ethers.js หรือ viem ใช้กับ MetaMask ได้ไหม?

ได้, ทั้งคู่ wrap window.ethereum

ethers.js v6: BrowserProvider(window.ethereum)

viem: createWalletClient({ transport: custom(window.ethereum) })

dApp ส่วนใหญ่ใช้สองตัวนี้

ถ้าผู้ใช้ติดตั้งหลาย wallet?

MetaMask ใช้ EIP-6963 ให้ dApp ตรวจจับ wallet ทั้งหมด ไม่ต้องแย่ง window.ethereum

wagmi/RainbowKit จัดการอัตโนมัติ

MetaMask Snaps พร้อมใช้งานจริงหรือยัง?

พร้อมแล้ว เปิดตัวทั่วไปในปี 2024 ใช้งานจริงสำหรับ non-EVM chain, custom transaction insight, hardware wallet integrations

Top comments (0)