"use client";
import { useState, useEffect, useCallback, useMemo } from "react";
import { useBaseAccountSdk, useWallets } from "@privy-io/react-auth";
import {
requestSpendPermission,
prepareSpendCallData,
fetchPermissions,
getPermissionStatus,
type SpendPermission,
} from "@base-org/account/spend-permission/browser";
import { base } from "@privy-io/chains";
export const SpendPermissions = () => {
const { baseAccountSdk } = useBaseAccountSdk();
const { wallets } = useWallets();
const [permissions, setPermissions] = useState<SpendPermission[]>([]);
const [selectedPermission, setSelectedPermission] = useState<SpendPermission | null>(null);
const [loading, setLoading] = useState(false);
// 설정
const spenderAddress = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045";
const tokenAddress = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"; // Base의 USDC
// Base Account 지갑 찾기
const baseAccount = useMemo(() => {
return wallets.find((wallet) => wallet.walletClientType === 'base_account');
}, [wallets]);
const provider = baseAccountSdk?.getProvider();
const account = baseAccount?.address;
const loadPermissions = useCallback(async () => {
if (!account || !provider || !spenderAddress) return;
try {
setLoading(true);
const fetchedPermissions = await fetchPermissions({
account,
chainId: base.id,
spender: spenderAddress,
provider,
});
setPermissions(fetchedPermissions);
} catch (error) {
console.error("Failed to load permissions:", error);
} finally {
setLoading(false);
}
}, [account, provider, spenderAddress]);
const handleRequestSpendPermission = async () => {
if (!account || !provider || !spenderAddress || !tokenAddress) return;
try {
setLoading(true);
const permission = await requestSpendPermission({
account,
spender: spenderAddress,
token: tokenAddress,
chainId: base.id,
allowance: BigInt(1) * BigInt(10 ** 6), // 1 USDC (소수점 6자리)
periodInDays: 1, // 1일
provider,
});
setPermissions([...permissions, permission]);
} catch (error) {
console.error("Failed to create Spend Permission:", error);
} finally {
setLoading(false);
}
};
const handleUseSpendPermission = async () => {
if (!selectedPermission || !provider || !spenderAddress) return;
try {
setLoading(true);
// 퍼미션 상태 확인
const { isActive, remainingSpend } = await getPermissionStatus(selectedPermission);
if (!isActive) {
console.error("Selected permission is not active");
return;
}
const spendAmount = BigInt(100) * BigInt(10 ** 6); // 100 USDC
if (remainingSpend < spendAmount) {
console.error("Insufficient remaining allowance");
return;
}
// 스펜드 콜 준비
const spendCalls = await prepareSpendCallData(selectedPermission, spendAmount);
console.log("Spend calls prepared:", spendCalls);
} catch (error) {
console.error("Failed to use Spend Permission:", error);
} finally {
setLoading(false);
}
};
return (
<div className="space-y-4">
<div className="flex gap-4">
<button
onClick={handleRequestSpendPermission}
disabled={loading || !account}
className="px-4 py-2 bg-blue-600 text-white rounded disabled:opacity-50"
>
스펜드 퍼미션 생성
</button>
<button
onClick={loadPermissions}
disabled={loading || !account}
className="px-4 py-2 bg-green-600 text-white rounded disabled:opacity-50"
>
퍼미션 불러오기
</button>
<button
onClick={handleUseSpendPermission}
disabled={loading || !selectedPermission}
className="px-4 py-2 bg-purple-600 text-white rounded disabled:opacity-50"
>
퍼미션 사용
</button>
</div>
{/* 설정 표시 */}
<div className="p-4 rounded-lg">
<h4 className="font-semibold mb-3">설정</h4>
<div className="text-sm space-y-1">
<div><strong>지출자:</strong> {spenderAddress}</div>
<div><strong>토큰:</strong> {tokenAddress} (USDC)</div>
<div><strong>한도:</strong> 하루 $1 USDC</div>
</div>
</div>
{/* 퍼미션 목록 */}
{permissions.length > 0 && (
<div className="p-4 rounded-lg">
<h4 className="font-semibold mb-3">기존 퍼미션</h4>
<div className="space-y-2">
{permissions.map((permission, index) => (
<div
key={index}
className={`p-3 border rounded-md cursor-pointer ${
selectedPermission === permission
? "border-blue-500"
: "border-gray-300"
}`}
onClick={() => setSelectedPermission(permission)}
>
<div className="text-sm">
<div><strong>지출자:</strong> {permission.permission.spender?.slice(0, 10)}...</div>
<div><strong>토큰:</strong> {permission.permission.token?.slice(0, 10)}...</div>
<div><strong>한도:</strong> {permission.permission.allowance?.toString()}</div>
</div>
</div>
))}
</div>
</div>
)}
</div>
);
};