diff --git a/app/api/aave/route.tsx b/app/api/aave/route.tsx index 27a5c3b..cc80818 100644 --- a/app/api/aave/route.tsx +++ b/app/api/aave/route.tsx @@ -221,6 +221,96 @@ export async function POST(request: Request) { } } + if (action === 'repay') { + try { + const amountToRepay = parseUnits(amount, 6); + + // First, approve USDC spend + const approveContract = await wallet.invokeContract({ + contractAddress: USDC_ADDRESS, + method: "approve", + args: { + spender: AAVE_POOL_ADDRESS, + value: amountToRepay.toString() + }, + abi: usdcAbi, + }); + + const approveTx = await approveContract.wait(); + if (!approveTx) { + throw new Error('Failed to approve USDC spend'); + } + + console.log('USDC spend approved for repayment:', approveTx); + + // Now, repay the loan + const repayContract = await wallet.invokeContract({ + contractAddress: AAVE_POOL_ADDRESS, + method: "repay", + args: { + asset: USDC_ADDRESS, + amount: amountToRepay.toString(), + interestRateMode: "2", + onBehalfOf: address.getId() + }, + abi: aaveAbi, + }); + + const repayTx = await repayContract.wait(); + if (!repayTx) { + throw new Error('Failed to repay USDC to Aave'); + } + + console.log('USDC repaid to Aave:', repayTx); + + return NextResponse.json({success: true, txHash: repayTx.getTransactionHash()}); + } catch (error) { + console.error('Failed to repay loan:', error); + return NextResponse.json({ + error: 'Failed to repay loan', + details: error instanceof Error ? error.message : String(error) + }, {status: 500}); + } + } + + if (action === 'withdraw') { + try { + const amountToWithdraw = parseUnits(amount, 6); // Assuming USDC has 6 decimals + + console.log('Attempting to withdraw:', { + asset: USDC_ADDRESS, + amount: amountToWithdraw.toString(), + to: address.getId() + }); + + const withdrawContract = await wallet.invokeContract({ + contractAddress: AAVE_POOL_ADDRESS, + method: "withdraw", + args: { + asset: USDC_ADDRESS, + amount: amountToWithdraw.toString(), + to: address.getId() + }, + abi: aaveAbi, + }); + + const withdrawTx = await withdrawContract.wait(); + if (!withdrawTx) { + throw new Error('Failed to withdraw USDC from Aave'); + } + + console.log('Withdraw transaction sent, hash:', withdrawTx.getTransactionHash()); + + return NextResponse.json({ success: true, txHash: withdrawTx.getTransactionHash() }); + } catch (error) { + console.error('Failed to withdraw:', error); + return NextResponse.json({ + error: 'Failed to withdraw', + details: error instanceof Error ? error.message : String(error) + }, { status: 500 }); + } + } + return NextResponse.json({ error: 'Invalid action' }, { status: 400 }); } diff --git a/app/usdcflow/page.tsx b/app/usdcflow/page.tsx index 3653e3f..0d7e110 100644 --- a/app/usdcflow/page.tsx +++ b/app/usdcflow/page.tsx @@ -12,17 +12,25 @@ export default function AaveInteraction() { const [accountData, setAccountData] = useState(null); const [supplyAmount, setSupplyAmount] = useState(''); const [borrowAmount, setBorrowAmount] = useState(''); + const [repayAmount, setRepayAmount] = useState(''); + const [withdrawAmount, setWithdrawAmount] = useState(''); const [isLoading, setIsLoading] = useState(true); const [isSupplying, setIsSupplying] = useState(false); const [isBorrowing, setIsBorrowing] = useState(false); + const [isRepaying, setIsRepaying] = useState(false); + const [isWithdrawing, setIsWithdrawing] = useState(false); const [error, setError] = useState(''); const [supplyOutput, setSupplyOutput] = useState<{ amount: string, txHash: string } | null>(null); const [borrowOutput, setBorrowOutput] = useState<{ amount: string, txHash: string } | null>(null); + const [repayOutput, setRepayOutput] = useState<{ amount: string, txHash: string } | null>(null); + const [withdrawOutput, setWithdrawOutput] = useState<{ amount: string, txHash: string } | null>(null); const clearTransactionData = () => { setSupplyOutput(null); setBorrowOutput(null); + setRepayOutput(null); + setWithdrawOutput(null); setError(''); }; @@ -85,6 +93,51 @@ export default function AaveInteraction() { } }; + const repayToAave = async () => { + if (!repayAmount) return; + clearTransactionData(); + setIsRepaying(true); + try { + const response = await fetch('/api/aave', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'repay', amount: repayAmount}), + }); + if (!response.ok) throw new Error('Failed to repay loan'); + const data = await response.json(); + setRepayOutput({ amount: repayAmount, txHash: data.txHash }); + getUserAccountData(); + } catch (err) { + console.error('Failed to repay loan:', err); + setError('Failed to repay loan. Please try again.'); + } finally { + setIsRepaying(false); + } + }; + + const withdrawFromAave = async () => { + if (!withdrawAmount) return; + clearTransactionData(); + setIsWithdrawing(true); + try { + const response = await fetch('/api/aave', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'withdraw', amount: withdrawAmount}), + }); + if (!response.ok) throw new Error('Failed to withdraw assets'); + const data = await response.json(); + setWithdrawOutput({ amount: withdrawAmount, txHash: data.txHash }); + getUserAccountData(); + } catch (err) { + console.error('Failed to withdraw from Aave:', err); + setError('Failed to withdraw assets. Please try again.'); + } finally { + setIsWithdrawing(false); + } + }; + + const closeIntro = () => { setShowIntro(false); }; @@ -164,23 +217,23 @@ export default function AaveInteraction() { {error} )} - {accountData && (

Wallet Address: {accountData.walletAddress}

Wallet Balance: {parseFloat(accountData.usdcBalance).toFixed(2)} USDC

-

Total Deposited: {accountData.totalDeposited} USDC

-

Total Debt: {accountData.totalDebtBase} USDC

+

Total Supplied: {accountData.totalDeposited} USDC

+

Total Borrowed: {accountData.totalDebtBase} USDC

Available to borrow: {accountData.availableBorrowsBase} USDC

)} -
- +
+ Supply Assets @@ -195,9 +248,9 @@ export default function AaveInteraction() { }} className="mb-4" /> - {supplyOutput && ( @@ -220,9 +273,9 @@ export default function AaveInteraction() { onChange={(e) => setBorrowAmount(e.target.value)} className="mb-4" /> - {borrowOutput && ( @@ -232,6 +285,60 @@ export default function AaveInteraction() { )} + + + + Repay Assets + + + setRepayAmount(e.target.value)} + className="mb-4" + /> + + + {repayOutput && ( + +

Repaid Amount: {repayOutput.amount} USDC

+

Transaction Hash: {repayOutput.txHash}

+
+ )} +
+ + + Withdraw Assets + + + setWithdrawAmount(e.target.value)} + className="mb-4" + /> + + + {withdrawOutput && ( + +

Withdrawn Amount: {withdrawOutput.amount} USDC

+

Transaction Hash: {withdrawOutput.txHash}

+
+ )} +
)} diff --git a/vercel.json b/vercel.json index 9ca7fe2..70ff585 100644 --- a/vercel.json +++ b/vercel.json @@ -8,7 +8,7 @@ "value": "usdcflow.xyz" } ], - "destination": "/usdcflow/:path*" + "destination": "https://www.cdp-sdk.xyz/usdcflow" } ] } \ No newline at end of file