From d5bbc43b521ad08fb552e117a6e47d0d638f8a70 Mon Sep 17 00:00:00 2001
From: "2569718930@qq.com" <2569718930@qq.com>
Date: Fri, 13 Mar 2026 05:25:46 +0800
Subject: [PATCH] feat: add AccountCenter component for user authentication,
subscription, and payment management.
---
frontend/components/account/AccountCenter.tsx | 84 +++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git a/frontend/components/account/AccountCenter.tsx b/frontend/components/account/AccountCenter.tsx
index b8f4fe75..f1e7d23e 100644
--- a/frontend/components/account/AccountCenter.tsx
+++ b/frontend/components/account/AccountCenter.tsx
@@ -81,6 +81,8 @@ type CreatedIntent = {
to: string;
data: string;
value: string;
+ amount_units: string;
+ token_address: string;
};
};
@@ -132,6 +134,27 @@ function shortAddress(address: string) {
return `${text.slice(0, 8)}...${text.slice(-6)}`;
}
+function toPaddedHex(value: bigint) {
+ return value.toString(16).padStart(64, "0");
+}
+
+function toPaddedAddress(address: string) {
+ return String(address || "")
+ .toLowerCase()
+ .replace(/^0x/, "")
+ .padStart(64, "0");
+}
+
+function buildAllowanceCalldata(owner: string, spender: string) {
+ // allowance(address owner, address spender)
+ return `0xdd62ed3e${toPaddedAddress(owner)}${toPaddedAddress(spender)}`;
+}
+
+function buildApproveCalldata(spender: string, amount: bigint) {
+ // approve(address spender, uint256 amount)
+ return `0x095ea7b3${toPaddedAddress(spender)}${toPaddedHex(amount)}`;
+}
+
function InfoItem({ icon: Icon, label, value, status = "default" }: InfoItemProps) {
return (
@@ -324,6 +347,30 @@ export function AccountCenter() {
} catch {}
};
+ const waitForReceipt = async (
+ txHash: string,
+ timeoutMs = 120000,
+ pollMs = 3000,
+ ) => {
+ const eth = window.ethereum;
+ if (!eth) {
+ throw new Error("MetaMask not found");
+ }
+ const started = Date.now();
+ while (Date.now() - started < timeoutMs) {
+ const receipt = (await eth.request({
+ method: "eth_getTransactionReceipt",
+ params: [txHash],
+ })) as { status?: string } | null;
+ if (receipt && receipt.status) {
+ if (receipt.status === "0x1") return receipt;
+ throw new Error(`transaction reverted: ${txHash}`);
+ }
+ await new Promise((resolve) => setTimeout(resolve, pollMs));
+ }
+ throw new Error(`transaction confirmation timeout: ${txHash}`);
+ };
+
const planList = paymentConfig?.plans || [];
const selectedPlan = planList.find((p) => p.plan_code === selectedPlanCode) || planList[0];
const paymentFeatureReady = Boolean(paymentConfig?.enabled && paymentConfig?.configured);
@@ -448,6 +495,43 @@ export function AccountCenter() {
}
setLastIntentId(intentId);
+ const tokenAddress = String(txPayload.token_address || "").toLowerCase();
+ const amountUnits = BigInt(String(txPayload.amount_units || "0"));
+ if (!tokenAddress.startsWith("0x") || amountUnits <= 0n) {
+ throw new Error("intent token/amount invalid");
+ }
+
+ const allowanceHex = (await eth.request({
+ method: "eth_call",
+ params: [
+ {
+ to: tokenAddress,
+ data: buildAllowanceCalldata(payingWallet, txPayload.to),
+ },
+ "latest",
+ ],
+ })) as string;
+ const allowance = BigInt(String(allowanceHex || "0x0"));
+
+ if (allowance < amountUnits) {
+ setPaymentInfo("检测到授权不足,正在发起 USDC 授权...");
+ const approveHash = (await eth.request({
+ method: "eth_sendTransaction",
+ params: [
+ {
+ from: payingWallet,
+ to: tokenAddress,
+ data: buildApproveCalldata(txPayload.to, amountUnits),
+ value: "0x0",
+ },
+ ],
+ })) as string;
+ await waitForReceipt(String(approveHash || ""));
+ setPaymentInfo("USDC 授权成功,正在发起支付...");
+ } else {
+ setPaymentInfo("授权额度充足,正在发起支付...");
+ }
+
const txHash = (await eth.request({
method: "eth_sendTransaction",
params: [