このページは Claude Code (AI) を使って実際に作られたウォレットの解説です。
同じものをあなたも作れます。
このウォレットは Polygon チェーン上の JPYC(日本円ステーブルコイン)専用 の決済ウォレットです。 QRコードをスキャンするだけで送金できます。
通常の送金はユーザーがガス代(POL)を払う必要があります。このウォレットは EIP-3009 という仕組みで「署名だけ」で送金できます。
Claude Code などの AI コーディングアシスタントに以下の手順で頼むと作れます。
RELAYER_PRIVATE_KEY にリレイヤーウォレットの秘密鍵を登録。wrangler pages deploy public --project-name YOUR_PROJECT --branch main月1,000回送金しても 約70円。リレイヤーウォレットへの POL 補充は不定期で OK。
リレイヤーウォレットの秘密鍵は Cloudflare の環境変数(シークレット)に保管します。 絶対にコードや Git にコミットしないこと。リレイヤーウォレットには必要最小限の POL だけ入れておくこと。
このウォレットで使用している JPYC アドレスは
0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29(Polygon PoS)です。
公式サイト jpyc.co.jp で必ず確認してください。
署名時の EIP-712 domain name は "JPY Coin"、version は "1" です。 コントラクトアドレスが変わると domain も変わる可能性があるため、変更時は必ず確認してください。
Claude Code や ChatGPT に以下をコピペすると同様のものを作れます。
Polygon チェーンの JPYC (0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29) に特化した ガスレス決済ウォレットをHTML/JS で作ってください。 要件: - スマホ QR スキャンで送金(メイン機能) - EIP-3009 transferWithAuthorization でオフチェーン署名 - Cloudflare Pages Functions でリレイヤー(/api/relay) - MetaMask + WalletConnect v2 対応 - PWA 対応(ホーム画面に追加可能) - ガスレス(ユーザーは POL 不要) - リレイヤーウォレット: 0xYOUR_WALLET_ADDRESS - WalletConnect Project ID: YOUR_PROJECT_ID JPYC の EIP-712 domain: name: "JPY Coin", version: "1", chainId: 137
// functions/api/relay.js (Cloudflare Pages Functions)
import { ethers } from 'ethers';
export async function onRequestPost(context) {
const { env, request } = context;
const privKey = env.RELAYER_PRIVATE_KEY; // Cloudflare環境変数
const body = await request.json();
const { from, to, value, validAfter, validBefore, nonce, v, r, s } = body;
const provider = new ethers.JsonRpcProvider('https://polygon-rpc.com');
const relayer = new ethers.Wallet(privKey, provider);
const contract = new ethers.Contract(JPYC_ADDRESS, JPYC_ABI, relayer);
const tx = await contract.transferWithAuthorization(
from, to, value, validAfter, validBefore, nonce, v, r, s
);
return Response.json({ txHash: tx.hash });
}
// EIP-3009 署名(ethers.js v6)
const domain = {
name: 'JPY Coin', version: '1',
chainId: 137,
verifyingContract: '0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29'
};
const types = {
TransferWithAuthorization: [
{ name: 'from', type: 'address' },
{ name: 'to', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'validAfter', type: 'uint256' },
{ name: 'validBefore', type: 'uint256' },
{ name: 'nonce', type: 'bytes32' },
]
};
const message = {
from: account, to: recipientAddress,
value: ethers.parseUnits(amount, 18),
validAfter: 0,
validBefore: Math.floor(Date.now() / 1000) + 1800, // 30分
nonce: ethers.hexlify(ethers.randomBytes(32))
};
const sig = await signer.signTypedData(domain, types, message);
const { v, r, s } = ethers.Signature.from(sig);
# 送金先アドレスのみ 0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29 # 金額付き請求QR(jpyc: スキーム) jpyc:0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29?amount=1000 # URL パラメータでの受け渡し https://cryptoninjaswap.com/wallettools/jpyc-wallet?to=0xADDR&amount=1000