· about 1 month ago
import { Controller } from "@hotwired/stimulus"
export default class extends Controller { static values = { url: String }
async pay() { if (!window.ethereum) { alert("⚠️ 请先安装钱包") return }
try {
// 1️⃣ 请求资源
const res = await fetch(this.urlValue)
const payInfo = await res.json()
if (res.status !== 402) {
alert("✅ 已解锁或无需支付")
return
}
// 2️⃣ 从返回中取出支付信息
const accept = payInfo.accepts[0]
const { payTo, asset, maxAmountRequired, network } = accept
console.log("🧾 支付信息:", accept)
console.log("💰 需支付金额(最小单位):", maxAmountRequired)
// 3️⃣ 连接钱包
const [from] = await window.ethereum.request({
method: "eth_requestAccounts"
})
// 4️⃣ 构造 ERC20 transfer data
// ✅ 直接使用 maxAmountRequired(已经是最小单位)
const amountInUnits = BigInt(maxAmountRequired)
const selector = "0xa9059cbb"
const toPadded = payTo.replace(/^0x/, "").padStart(64, "0")
const amountHex = amountInUnits.toString(16).padStart(64, "0")
const data = selector + toPadded + amountHex
console.log("📦 交易 data:", data)
console.log("📊 金额 hex:", amountHex, "=", amountInUnits.toString(), "最小单位")
// 5️⃣ 发交易
const txHash = await window.ethereum.request({
method: "eth_sendTransaction",
params: [{
from,
to: asset, // ✅ USDC 合约地址
data
}]
})
console.log("💸 TxHash:", txHash)
// 6️⃣ 构造 X-PAYMENT payload
const paymentPayload = {
x402Version: 1,
scheme: "exact",
network: network || "base-sepolia",
payload: {
authorization: {
from,
to: payTo,
value: maxAmountRequired, // ✅ 保持原始值
txHash,
timestamp: Math.floor(Date.now() / 1000)
}
}
}
const encoded = btoa(JSON.stringify(paymentPayload))
console.log("🔐 Payment Payload:", paymentPayload)
// 7️⃣ 验证支付
const verifyRes = await fetch(this.urlValue, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-PAYMENT": encoded
},
body: JSON.stringify({})
})
if (verifyRes.ok) {
const data = await verifyRes.json()
alert("✅ 支付成功!内容已解锁")
console.log("📄 内容:", data)
window.location.reload()
} else {
const err = await verifyRes.text()
console.error("❌ 支付验证失败:", err)
alert(`❌ 支付验证失败: ${err}`)
}
} catch (e) {
console.error("💥 出错:", e)
alert("💥 支付失败: " + e.message)
}
} }
Share with your followers.
Reply