· 大約1個月 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 paymentRequirements = payInfo
const accept = payInfo.accepts[0]
const { payTo, asset, maxAmountRequired, network } = accept
console.log("🧾 支付要求:", paymentRequirements)
console.log("🧾 scheme 来自后端:", accept.scheme) // 应该是 "exact"
// 3️⃣ 连接钱包
const [from] = await window.ethereum.request({
method: "eth_requestAccounts"
})
// 4️⃣ 生成 nonce
const nonce = `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`
// 5️⃣ 构造并发送交易
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
const txHash = await window.ethereum.request({
method: "eth_sendTransaction",
params: [{ from, to: asset, data }]
})
console.log("💸 交易哈希:", txHash)
// 6️⃣ 时间戳
const timestamp = Math.floor(Date.now() / 1000)
const validAfter = timestamp - 300
const validBefore = timestamp + 600
// 7️⃣ 构造 Payment Payload(注意结构!)
const paymentPayload = {
x402Version: 1,
scheme: accept.scheme || "exact", // ✅ 从后端获取或使用 "exact"
network: network,
payload: {
authorization: {
from: from,
to: payTo,
value: maxAmountRequired,
validAfter: validAfter,
validBefore: validBefore,
nonce: nonce,
asset: asset,
txHash: txHash
}
}
}
// 8️⃣ 调试日志
console.log("=" .repeat(50))
console.log("🔍 支付数据结构检查")
console.log("=" .repeat(50))
console.log("paymentPayload:", JSON.stringify(paymentPayload, null, 2))
console.log("✅ scheme 值:", paymentPayload.scheme)
console.log("✅ network 值:", paymentPayload.network)
if (!paymentPayload.scheme) {
throw new Error("scheme 字段缺失!")
}
// 9️⃣ 构造验证请求
const verifyRequest = {
x402Version: 1,
paymentPayload: paymentPayload,
paymentRequirements: paymentRequirements
}
console.log("verifyRequest.paymentPayload.scheme:", verifyRequest.paymentPayload.scheme)
// 🔟 编码
const verifyRequestString = JSON.stringify(verifyRequest)
console.log("编码前 JSON:", verifyRequestString.substring(0, 200) + "...")
const encoded = btoa(verifyRequestString)
// 验证解码
const decoded = JSON.parse(atob(encoded))
console.log("解码后 scheme:", decoded.paymentPayload.scheme)
console.log("=" .repeat(50))
if (!decoded.paymentPayload.scheme) {
throw new Error("编码后 scheme 丢失!")
}
// 1️⃣1️⃣ 发送验证
const verifyRes = await fetch(this.urlValue, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-PAYMENT": encoded
},
body: JSON.stringify({})
})
console.log("📬 响应状态:", verifyRes.status)
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)
}
} }
與您的關注者分享。
回覆