Web3Auth SDKバージョン違いで送金できないトラブルを防止
はじめに
Web3Authを使ってPolygon Amoyテストネットでウォレット開発をしていたところ、SDKバージョンの違いで作成したウォレットアドレスが異なるという問題に直面しました。
この記事では、以下の内容を解説します:
- 🔍 Web3Auth SDKバージョンによるウォレットアドレスの違い
- 🔑 古いバージョンで作成したウォレットから秘密鍵を取り出す方法
- 💸 異なるバージョン間での送金テスト方法
- ⚡ Polygon Amoyでのガス最適化
対象読者
- Web3Authを使ったウォレット開発をしている方
- Polygon Amoyテストネットで開発している方
- SDKバージョン移行で困っている方
問題の発生
状況
古い実装 (Torus SDK v1.21.0)
<script src="https://cdn.jsdelivr.net/npm/@toruslabs/torus-embed@1.21.0/dist/torus.min.js"></script>
<script>
const torus = new window.Torus();
await torus.init({
network: { host: "mumbai" }
});
await torus.login();
</script>
生成されたアドレス: 0x588**************************faD8Fd
新しい実装 (Web3Auth v9)
<script src="https://cdn.jsdelivr.net/npm/@web3auth/base@9/dist/base.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@web3auth/ethereum-provider@9/dist/ethereumProvider.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@web3auth/modal@9/dist/modal.umd.min.js"></script>
<script>
const web3auth = new window.Modal.Web3Auth({
clientId: "YOUR_CLIENT_ID",
web3AuthNetwork: "sapphire_devnet",
chainConfig: {
chainNamespace: "eip155",
chainId: "0x13882", // Polygon Amoy
rpcTarget: "https://rpc-amoy.polygon.technology"
}
});
await web3auth.initModal();
await web3auth.connect();
</script>
生成されたアドレス: 0x42**********************fc660cb
❌ 問題点
同じGoogleアカウントでログインしても、アドレスが異なる!
旧アドレスには 0.1 POL の残高があるのに、新アドレスでは使えない...
解決方法
方法1: Web3Auth Walletで秘密鍵を取得 (推奨)
Web3Authには公式ウォレットUIがあり、ここから秘密鍵をエクスポートできます。
手順
1. Web3Auth Walletにアクセス
https://wallet.web3auth.io/
2. ログイン
- 同じSNSアカウント(Google等)でログイン
-
重要: ログイン時にTestnet/Mainnetトグルを確認
- Testnetで作成したウォレット → Testnetモードでログイン
- Mainnetで作成したウォレット → Mainnetモードでログイン
3. 秘密鍵をエクスポート
- ログイン後、右上のアカウントアイコンをクリック
- Account → Settingsを開く
- Private KeyセクションでShow Private Keyをクリック
- 確認ダイアログで承認
- 秘密鍵(64文字の16進数)が表示される
例: a1b2c3d4e5f6...
4. MetaMaskにインポート
- MetaMaskを開く
- アカウントメニュー → アカウントをインポート
- 秘密鍵を選択
- コピーした秘密鍵を貼り付け
- インポートをクリック
5. Polygon Amoyネットワークを追加
MetaMaskにPolygon Amoyが未登録の場合:
// 手動追加の設定値
Network Name: Polygon Amoy Testnet
RPC URL: https://rpc-amoy.polygon.technology
Chain ID: 80002
Currency Symbol: POL
Block Explorer: https://amoy.polygonscan.com/
または、以下のリンクで自動追加:
https://chainlist.org/?search=amoy
方法2: 古いSDKで秘密鍵を取得
Torus SDK v1.21.0を使っている場合、コード上で秘密鍵を取得できます。
// Torus SDK v1.21.0
const torus = new window.Torus();
await torus.init({ network: { host: "mumbai" } });
await torus.login();
// 秘密鍵を取得
const privateKey = await torus.getPrivateKey();
console.log("Private Key:", privateKey);
⚠️ セキュリティ注意:
- 秘密鍵は絶対に他人に見せない
- GitHubなどに公開しない
- 本番環境では絶対にconsole.logしない
この方法は、Github Copilotで提案されましたが、実際はエラーが出て取り出せませんでした。
方法1で、成功しました。
同じGoogleなどのSNSのアカウントでテストしていてもSDKのバージョンの違いで、ウォレットのアドレスが異なることがあります。
Polygon Amoyでの送金実装
MATICからPOLへのリブランド
2024年9月、PolygonのネイティブトークンがMATICからPOLにリブランドされました。
| 項目 | 旧名称 | 新名称 |
|---|---|---|
| トークン名 | MATIC | POL |
| コントラクト | 同一 | 同一 |
| 互換性 | - | 完全互換 |
コード上は同じですが、表記はPOLに統一しましょう。
EIP-1559対応のガス計算
Polygon AmoyはEIP-1559に対応しているため、適切なガス価格設定が必要です。
ガス料金取得関数
async function getFees(provider) {
// ベースフィーをノードから取得
const gasPriceHex = await provider.request({
method: "eth_gasPrice"
});
// 優先手数料(Tip)のデフォルト: 1 gwei
let tipHex = "0x3b9aca00"; // 1 gwei
try {
const r = await provider.request({
method: "eth_maxPriorityFeePerGas"
});
if (typeof r === "string") tipHex = r;
} catch (_) {}
const base = BigInt(gasPriceHex);
const tip = BigInt(tipHex);
// maxFeePerGas = ベースフィー × 1.1 (安全マージン)
const maxFee = (base * 11n) / 10n;
return {
maxFeePerGas: "0x" + maxFee.toString(16),
maxPriorityFeePerGas: "0x" + tip.toString(16),
};
}
POL送金の実装
async function sendPOL(provider, userAddress, toAddress, amount) {
// 送金額をweiに変換
const valueInWei = Math.round(amount * 1e18);
const value = "0x" + valueInWei.toString(16);
console.log(`💸 送金額: ${amount} POL`);
console.log(`💸 送金額 (wei): ${valueInWei}`);
console.log(`💸 送金額 (hex): ${value}`);
// ガス料金を取得
const fee = await getFees(provider);
console.log(`✅ ガス料金取得完了:`, fee);
// ガスリミット: POL送金は21,000 × 2 = 42,000 (安全マージン)
const gas = "0xA410"; // 42,000 gas
// トランザクション構築
const tx = {
from: userAddress,
to: toAddress,
value,
gas,
...fee
};
console.log("⏳ POL送金中...", JSON.stringify(tx));
// 送信
const hash = await provider.request({
method: "eth_sendTransaction",
params: [tx]
});
console.log(`✅ POL送金完了: ${hash}`);
console.log(`🌐 https://amoy.polygonscan.com/tx/${hash}`);
return hash;
}
ガスリミットの決定
Polygon Amoyではeth_estimateGasが不安定なため、固定値を推奨します:
| トランザクション種類 | 標準ガス | 推奨設定 | 理由 |
|---|---|---|---|
| POL送金 | 21,000 | 42,000 (×2) | 標準的な転送 |
| ERC20送金 | 65,000 | 97,500 (×1.5) | コントラクト実行 |
| コントラクト操作 | 変動 | 見積もり×2 | 複雑な処理 |
// POL送金
const gas = "0xA410"; // 42,000 (21,000 × 2)
// ERC20トークン送金
const gas = "0x17CDC"; // 97,500 (65,000 × 1.5)
エラーと対処法
よくあるエラー
1. gas required exceeds allowance
原因: ガスリミットが不足している
解決策:
// ❌ 不足する例
const gas = "0x5208"; // 21,000のみ
// ✅ 十分な例
const gas = "0xA410"; // 42,000 (×2)
2. insufficient funds for gas * price + value
原因: 残高不足
解決策:
- Faucetで残高を補充: https://faucet.polygon.technology/
- または送金額を減らす
// 必要残高の計算
const required = sendAmount + (gasLimit × maxFeePerGas);
console.log(`必要残高: ${required} wei`);
3. nonce too low
原因: 同じnonceで複数回送信した
解決策:
// nonceを明示的に取得
const nonce = await provider.request({
method: "eth_getTransactionCount",
params: [userAddress, "latest"]
});
const tx = { from, to, value, gas, ...fee, nonce };
テストネット情報
Polygon Amoy
| 項目 | 設定値 |
|---|---|
| Network Name | Polygon Amoy Testnet |
| RPC URL | https://rpc-amoy.polygon.technology |
| Chain ID | 80002 (0x13882) |
| Currency | POL |
| Explorer | https://amoy.polygonscan.com/ |
Faucet情報
公式Faucet
https://faucet.polygon.technology/
- 取得量: 0.2 POL
- 制限: 24時間に1回
- 認証: Twitter/GitHub
代替Faucet
-
Chainlink Faucet
- https://faucets.chain.link/polygon-amoy
- 0.1 POL/24時間
-
Alchemy Faucet
完全な実装例
HTML + JavaScript実装
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web3Auth POL送金デモ</title>
</head>
<body>
<h1>Web3Auth + Polygon Amoy</h1>
<button id="btnInit">初期化</button>
<button id="btnLogin">ログイン</button>
<button id="btnSend">0.001 POL送金</button>
<div id="info"></div>
<!-- Web3Auth v9 -->
<script src="https://cdn.jsdelivr.net/npm/@web3auth/base@9/dist/base.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@web3auth/ethereum-provider@9/dist/ethereumProvider.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@web3auth/modal@9/dist/modal.umd.min.js"></script>
<script>
let web3auth;
let provider;
let userAddress;
const CLIENT_ID = "YOUR_WEB3AUTH_CLIENT_ID"; // 要設定
// 初期化
document.getElementById('btnInit').onclick = async () => {
try {
const chainConfig = {
chainNamespace: "eip155",
chainId: "0x13882", // Polygon Amoy
rpcTarget: "https://rpc-amoy.polygon.technology",
displayName: "Polygon Amoy Testnet",
blockExplorer: "https://amoy.polygonscan.com/",
ticker: "POL",
tickerName: "POL"
};
const privateKeyProvider = new window.EthereumProvider.EthereumPrivateKeyProvider({
config: { chainConfig }
});
web3auth = new window.Modal.Web3Auth({
clientId: CLIENT_ID,
web3AuthNetwork: "sapphire_devnet",
privateKeyProvider
});
await web3auth.initModal();
console.log("✅ 初期化完了");
} catch (e) {
console.error("❌ 初期化エラー:", e);
}
};
// ログイン
document.getElementById('btnLogin').onclick = async () => {
try {
provider = await web3auth.connect();
const accounts = await provider.request({ method: "eth_accounts" });
userAddress = accounts[0];
const balanceHex = await provider.request({
method: "eth_getBalance",
params: [userAddress, "latest"]
});
const balance = parseInt(balanceHex, 16) / 1e18;
document.getElementById('info').innerHTML = ``;
console.log("✅ ログイン完了");
} catch (e) {
console.error("❌ ログインエラー:", e);
}
};
// ガス料金取得
async function getFees(provider) {
const gasPriceHex = await provider.request({ method: "eth_gasPrice" });
let tipHex = "0x3b9aca00"; // 1 gwei
try {
const r = await provider.request({ method: "eth_maxPriorityFeePerGas" });
if (typeof r === "string") tipHex = r;
} catch (_) {}
const base = BigInt(gasPriceHex);
const tip = BigInt(tipHex);
const maxFee = (base * 11n) / 10n;
return {
maxFeePerGas: "0x" + maxFee.toString(16),
maxPriorityFeePerGas: "0x" + tip.toString(16),
};
}
// 送金
document.getElementById('btnSend').onclick = async () => {
try {
const to = prompt("送金先アドレス:");
if (!to) return;
const amount = 0.001;
const value = "0x" + Math.round(amount * 1e18).toString(16);
const fee = await getFees(provider);
const gas = "0xA410"; // 42,000
const tx = { from: userAddress, to, value, gas, ...fee };
console.log("⏳ 送金中...", tx);
const hash = await provider.request({
method: "eth_sendTransaction",
params: [tx]
});
console.log(`✅ 送金完了: ${hash}`);
alert(`送金完了!\nhttps://amoy.polygonscan.com/tx/${hash}`);
} catch (e) {
console.error("❌ 送金エラー:", e);
alert("送金失敗: " + e.message);
}
};
</script>
</body>
</html>
まとめ
チェックリスト
- Web3Auth Client IDを取得
- 正しいSDKバージョンを使用(v9推奨)
- Polygon Amoyネットワーク設定
- EIP-1559対応のガス計算実装
- 固定ガスリミット設定(POL: 42,000, ERC20: 97,500)
- エラーハンドリング実装
- テストネットトークン取得(Faucet)
ベストプラクティス
✅ DO (推奨)
- 最新のSDKを使用 (Web3Auth v9)
- 固定ガスリミットで安定動作
- EIP-1559対応のガス計算
- 詳細ログでデバッグしやすく
- 秘密鍵は安全に管理
❌ DON'T (非推奨)
古いTorus SDKの継続使用eth_estimateGasに全面依存ガスリミットを21,000固定秘密鍵をコンソールに出力本番環境でTestnet設定
参考リンク
公式ドキュメント
ツール
GitHub
おわりに
Web3AuthのSDKバージョン違いによるウォレットアドレスの違いは、開発中によく遭遇する問題です。
この記事が、同じ問題で困っている方の助けになれば幸いです!
Discussion