From 38c6b2806f7325f9307dd757fcec4984a39552a1 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Tue, 24 Mar 2026 17:35:32 +0100 Subject: [PATCH 1/8] feat: implement internal balance tracking and accounting --- contracts/src/lib.rs | 1 + contracts/src/treasury.rs | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 contracts/src/treasury.rs diff --git a/contracts/src/lib.rs b/contracts/src/lib.rs index cc5c254..c4307fc 100644 --- a/contracts/src/lib.rs +++ b/contracts/src/lib.rs @@ -3,3 +3,4 @@ pub mod escrow; pub mod subscription; pub mod payment_intent; +pub mod treasury; diff --git a/contracts/src/treasury.rs b/contracts/src/treasury.rs new file mode 100644 index 0000000..90fe139 --- /dev/null +++ b/contracts/src/treasury.rs @@ -0,0 +1,63 @@ +#![no_std] +use soroban_sdk::{contract, contractimpl, contracttype, Address, Env}; + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum DataKey { + Balance(Address), +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TreasuryBalance { + pub available_balance: i128, + pub reserved_balance: i128, +} + +#[contract] +pub struct TreasuryContract; + +#[contractimpl] +impl TreasuryContract { + pub fn mint(env: Env, admin: Address, to: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { + panic!("amount must be positive"); + } + + let key = DataKey::Balance(to.clone()); + let mut balance = env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance.available_balance = balance.available_balance.checked_add(amount).expect("overflow"); + + env.storage().persistent().set(&key, &balance); + } + + pub fn burn(env: Env, admin: Address, from: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { + panic!("amount must be positive"); + } + + let key = DataKey::Balance(from.clone()); + let mut balance = env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance.available_balance = balance.available_balance.checked_sub(amount).expect("underflow"); + + env.storage().persistent().set(&key, &balance); + } + + pub fn get_balance(env: Env, id: Address) -> TreasuryBalance { + let key = DataKey::Balance(id); + env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }) + } +} From 995c1d5c4e4dc7d7c189ddc7efe791e86f3a62ee Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Tue, 24 Mar 2026 19:01:17 +0100 Subject: [PATCH 2/8] fix: implement internal balance tracking for treasury --- contracts/src/treasury.rs | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/contracts/src/treasury.rs b/contracts/src/treasury.rs index 90fe139..e707af9 100644 --- a/contracts/src/treasury.rs +++ b/contracts/src/treasury.rs @@ -60,4 +60,87 @@ impl TreasuryContract { reserved_balance: 0, }) } + + pub fn transfer(env: Env, admin: Address, from: Address, to: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + if from == to { return; } + + let key_from = DataKey::Balance(from.clone()); + let mut balance_from = env.storage().persistent().get::<_, TreasuryBalance>(&key_from).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_from.available_balance = balance_from.available_balance.checked_sub(amount).expect("insufficient available balance"); + env.storage().persistent().set(&key_from, &balance_from); + + let key_to = DataKey::Balance(to.clone()); + let mut balance_to = env.storage().persistent().get::<_, TreasuryBalance>(&key_to).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_to.available_balance = balance_to.available_balance.checked_add(amount).expect("overflow"); + env.storage().persistent().set(&key_to, &balance_to); + } + + pub fn reserve(env: Env, admin: Address, from: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + + let key = DataKey::Balance(from.clone()); + let mut balance = env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance.available_balance = balance.available_balance.checked_sub(amount).expect("insufficient available balance"); + balance.reserved_balance = balance.reserved_balance.checked_add(amount).expect("overflow"); + + env.storage().persistent().set(&key, &balance); + } + + pub fn release(env: Env, admin: Address, from: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + + let key = DataKey::Balance(from.clone()); + let mut balance = env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance.reserved_balance = balance.reserved_balance.checked_sub(amount).expect("insufficient reserved balance"); + balance.available_balance = balance.available_balance.checked_add(amount).expect("overflow"); + + env.storage().persistent().set(&key, &balance); + } + + pub fn transfer_reserved(env: Env, admin: Address, from: Address, to: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + + let key_from = DataKey::Balance(from.clone()); + let mut balance_from = env.storage().persistent().get::<_, TreasuryBalance>(&key_from).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_from.reserved_balance = balance_from.reserved_balance.checked_sub(amount).expect("insufficient reserved balance"); + env.storage().persistent().set(&key_from, &balance_from); + + if from != to { + let key_to = DataKey::Balance(to.clone()); + let mut balance_to = env.storage().persistent().get::<_, TreasuryBalance>(&key_to).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_to.available_balance = balance_to.available_balance.checked_add(amount).expect("overflow"); + env.storage().persistent().set(&key_to, &balance_to); + } else { + balance_from.available_balance = balance_from.available_balance.checked_add(amount).expect("overflow"); + env.storage().persistent().set(&key_from, &balance_from); + } } From 55bdbccaf6c3b8bce8952061056da271f28c61f6 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Tue, 24 Mar 2026 21:38:35 +0100 Subject: [PATCH 3/8] feat: implement API key generation and hashing service --- apps/api/src/apikeys/apikeys.controller.ts | 14 +++++++++ apps/api/src/apikeys/apikeys.module.ts | 10 ++++++ apps/api/src/apikeys/apikeys.service.ts | 36 ++++++++++++++++++++++ apps/api/src/app.module.ts | 2 ++ 4 files changed, 62 insertions(+) create mode 100644 apps/api/src/apikeys/apikeys.controller.ts create mode 100644 apps/api/src/apikeys/apikeys.module.ts create mode 100644 apps/api/src/apikeys/apikeys.service.ts diff --git a/apps/api/src/apikeys/apikeys.controller.ts b/apps/api/src/apikeys/apikeys.controller.ts new file mode 100644 index 0000000..46b284a --- /dev/null +++ b/apps/api/src/apikeys/apikeys.controller.ts @@ -0,0 +1,14 @@ +import { Controller, Post, Request } from '@nestjs/common'; +import { ApikeysService } from './apikeys.service'; + +@Controller('apikeys') +export class ApikeysController { + constructor(private readonly apikeysService: ApikeysService) {} + + @Post() + async createApiKey(@Request() req: any) { + // Assuming merchant ID is available from auth context, e.g., req.user?.id + const merchantId = req.user?.id || 'merchant-123'; + return this.apikeysService.generateApiKey(merchantId); + } +} diff --git a/apps/api/src/apikeys/apikeys.module.ts b/apps/api/src/apikeys/apikeys.module.ts new file mode 100644 index 0000000..77fdf2b --- /dev/null +++ b/apps/api/src/apikeys/apikeys.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ApikeysService } from './apikeys.service'; +import { ApikeysController } from './apikeys.controller'; + +@Module({ + controllers: [ApikeysController], + providers: [ApikeysService], + exports: [ApikeysService], +}) +export class ApikeysModule {} diff --git a/apps/api/src/apikeys/apikeys.service.ts b/apps/api/src/apikeys/apikeys.service.ts new file mode 100644 index 0000000..356d177 --- /dev/null +++ b/apps/api/src/apikeys/apikeys.service.ts @@ -0,0 +1,36 @@ +import { Injectable } from '@nestjs/common'; +import * as crypto from 'crypto'; + +export interface ApiKeyRecord { + id: string; + merchantId: string; + key_hash: string; + createdAt: Date; +} + +@Injectable() +export class ApikeysService { + // TODO: Replace with actual database interaction + private readonly database: ApiKeyRecord[] = []; + + async generateApiKey(merchantId: string): Promise<{ plaintextKey: string }> { + // Generate 32-byte cryptographically random key + const rawKey = crypto.randomBytes(32).toString('hex'); + const plaintextKey = `sp_live_${rawKey}`; + + // Store only the SHA256 hash of the key in the database (key_hash) + const key_hash = crypto.createHash('sha256').update(plaintextKey).digest('hex'); + + const record: ApiKeyRecord = { + id: crypto.randomUUID(), + merchantId, + key_hash, + createdAt: new Date(), + }; + + this.database.push(record); + + // Response: Return the plaintext key only once to the merchant + return { plaintextKey }; + } +} diff --git a/apps/api/src/app.module.ts b/apps/api/src/app.module.ts index 72888f2..6045c36 100644 --- a/apps/api/src/app.module.ts +++ b/apps/api/src/app.module.ts @@ -6,6 +6,7 @@ import { AppService } from './app.service'; import { HealthModule } from './health/health.module'; import { TreasuryModule } from './treasury/treasury.module'; import { AuthModule } from './auth/auth.module'; +import { ApikeysModule } from './apikeys/apikeys.module'; import { JwtAuthGuard } from './auth/guards/jwt-auth.guard'; import { ThrottlerRedisGuard } from './rate-limiter/guards/throttler-redis.guard'; @@ -14,6 +15,7 @@ import { ThrottlerRedisGuard } from './rate-limiter/guards/throttler-redis.guard HealthModule, TreasuryModule, AuthModule, + ApikeysModule, ThrottlerModule.forRoot({ throttlers: [ { name: 'short', ttl: 60000, limit: 100 }, From 68f5f4bd21058b9ab46b504a8b748d3fafaeec76 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Tue, 24 Mar 2026 19:01:17 +0100 Subject: [PATCH 4/8] fix: implement internal balance tracking for treasury --- contracts/src/treasury.rs | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/contracts/src/treasury.rs b/contracts/src/treasury.rs index 90fe139..e707af9 100644 --- a/contracts/src/treasury.rs +++ b/contracts/src/treasury.rs @@ -60,4 +60,87 @@ impl TreasuryContract { reserved_balance: 0, }) } + + pub fn transfer(env: Env, admin: Address, from: Address, to: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + if from == to { return; } + + let key_from = DataKey::Balance(from.clone()); + let mut balance_from = env.storage().persistent().get::<_, TreasuryBalance>(&key_from).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_from.available_balance = balance_from.available_balance.checked_sub(amount).expect("insufficient available balance"); + env.storage().persistent().set(&key_from, &balance_from); + + let key_to = DataKey::Balance(to.clone()); + let mut balance_to = env.storage().persistent().get::<_, TreasuryBalance>(&key_to).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_to.available_balance = balance_to.available_balance.checked_add(amount).expect("overflow"); + env.storage().persistent().set(&key_to, &balance_to); + } + + pub fn reserve(env: Env, admin: Address, from: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + + let key = DataKey::Balance(from.clone()); + let mut balance = env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance.available_balance = balance.available_balance.checked_sub(amount).expect("insufficient available balance"); + balance.reserved_balance = balance.reserved_balance.checked_add(amount).expect("overflow"); + + env.storage().persistent().set(&key, &balance); + } + + pub fn release(env: Env, admin: Address, from: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + + let key = DataKey::Balance(from.clone()); + let mut balance = env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance.reserved_balance = balance.reserved_balance.checked_sub(amount).expect("insufficient reserved balance"); + balance.available_balance = balance.available_balance.checked_add(amount).expect("overflow"); + + env.storage().persistent().set(&key, &balance); + } + + pub fn transfer_reserved(env: Env, admin: Address, from: Address, to: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + + let key_from = DataKey::Balance(from.clone()); + let mut balance_from = env.storage().persistent().get::<_, TreasuryBalance>(&key_from).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_from.reserved_balance = balance_from.reserved_balance.checked_sub(amount).expect("insufficient reserved balance"); + env.storage().persistent().set(&key_from, &balance_from); + + if from != to { + let key_to = DataKey::Balance(to.clone()); + let mut balance_to = env.storage().persistent().get::<_, TreasuryBalance>(&key_to).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_to.available_balance = balance_to.available_balance.checked_add(amount).expect("overflow"); + env.storage().persistent().set(&key_to, &balance_to); + } else { + balance_from.available_balance = balance_from.available_balance.checked_add(amount).expect("overflow"); + env.storage().persistent().set(&key_from, &balance_from); + } } From 9e71422a196e63f036e9471483de03236592177a Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Fri, 27 Mar 2026 16:10:54 +0100 Subject: [PATCH 5/8] fix: resolve lint error in ApikeysController by providing explicit type for Request --- apps/api/src/apikeys/apikeys.controller.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/api/src/apikeys/apikeys.controller.ts b/apps/api/src/apikeys/apikeys.controller.ts index 46b284a..1eb151c 100644 --- a/apps/api/src/apikeys/apikeys.controller.ts +++ b/apps/api/src/apikeys/apikeys.controller.ts @@ -1,12 +1,18 @@ import { Controller, Post, Request } from '@nestjs/common'; import { ApikeysService } from './apikeys.service'; +interface AuthenticatedRequest extends Request { + user?: { + id: string; + }; +} + @Controller('apikeys') export class ApikeysController { constructor(private readonly apikeysService: ApikeysService) {} @Post() - async createApiKey(@Request() req: any) { + async createApiKey(@Request() req: AuthenticatedRequest) { // Assuming merchant ID is available from auth context, e.g., req.user?.id const merchantId = req.user?.id || 'merchant-123'; return this.apikeysService.generateApiKey(merchantId); From 8ba2eff1d6f488b7ceee68c1c58071e435bfdd8e Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Sun, 29 Mar 2026 03:23:39 +0100 Subject: [PATCH 6/8] fix: resolve frontend linting errors and warnings --- apps/frontend/src/app/checkout/page.tsx | 4 ++-- apps/frontend/src/app/components/ui/ImageWithFallback.tsx | 2 ++ apps/frontend/src/app/dashboard/page.tsx | 2 +- apps/frontend/src/app/dashboard/subscriptions/page.tsx | 2 +- apps/frontend/src/app/dashboard/treasury/page.tsx | 2 +- apps/frontend/src/app/dashboard/webhooks/page.tsx | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/frontend/src/app/checkout/page.tsx b/apps/frontend/src/app/checkout/page.tsx index 98dbd5b..95cb110 100644 --- a/apps/frontend/src/app/checkout/page.tsx +++ b/apps/frontend/src/app/checkout/page.tsx @@ -511,7 +511,7 @@ export default function PaymentCheckout() { onClick={handleBankPayment} className="w-full bg-white hover:bg-zinc-100 text-black h-14 rounded-xl mt-6 text-base transition-all duration-200 shadow-lg shadow-white/10" > - I've Completed the Transfer + I've Completed the Transfer

@@ -611,7 +611,7 @@ export default function PaymentCheckout() { onClick={handleCryptoDetection} className="w-full bg-white hover:bg-zinc-100 text-black h-14 rounded-xl mt-6 text-base transition-all duration-200 shadow-lg shadow-white/10" > - I've Sent the Payment + I've Sent the Payment

diff --git a/apps/frontend/src/app/components/ui/ImageWithFallback.tsx b/apps/frontend/src/app/components/ui/ImageWithFallback.tsx index 0e26139..710fbff 100644 --- a/apps/frontend/src/app/components/ui/ImageWithFallback.tsx +++ b/apps/frontend/src/app/components/ui/ImageWithFallback.tsx @@ -18,10 +18,12 @@ export function ImageWithFallback(props: React.ImgHTMLAttributes

+ {/* eslint-disable-next-line @next/next/no-img-element */} Error loading image
) : ( + /* eslint-disable-next-line @next/next/no-img-element */ {alt} ) } diff --git a/apps/frontend/src/app/dashboard/page.tsx b/apps/frontend/src/app/dashboard/page.tsx index 68a7042..9358b54 100644 --- a/apps/frontend/src/app/dashboard/page.tsx +++ b/apps/frontend/src/app/dashboard/page.tsx @@ -211,7 +211,7 @@ export default function OverviewPage() { diff --git a/apps/frontend/src/app/dashboard/subscriptions/page.tsx b/apps/frontend/src/app/dashboard/subscriptions/page.tsx index cf1fb17..94f1a1b 100644 --- a/apps/frontend/src/app/dashboard/subscriptions/page.tsx +++ b/apps/frontend/src/app/dashboard/subscriptions/page.tsx @@ -1,7 +1,7 @@ 'use client'; import { motion } from "motion/react"; -import { Plus, RefreshCw, CheckCircle2, AlertCircle } from "lucide-react"; + const subscriptions = [ { id: "sub_1a2b3c4d", customer: "Acme Corp", plan: "Enterprise", amount: "999.00", interval: "Monthly", status: "active", nextBilling: "2026-04-03" }, diff --git a/apps/frontend/src/app/dashboard/treasury/page.tsx b/apps/frontend/src/app/dashboard/treasury/page.tsx index ac6b6c8..e6c2c1f 100644 --- a/apps/frontend/src/app/dashboard/treasury/page.tsx +++ b/apps/frontend/src/app/dashboard/treasury/page.tsx @@ -1,7 +1,7 @@ 'use client'; import { motion } from "motion/react"; -import { Coins, TrendingUp, TrendingDown, Eye, AlertTriangle, CheckCircle2 } from "lucide-react"; + const mirrorAssets = [ { diff --git a/apps/frontend/src/app/dashboard/webhooks/page.tsx b/apps/frontend/src/app/dashboard/webhooks/page.tsx index 6b34a0c..65a1c39 100644 --- a/apps/frontend/src/app/dashboard/webhooks/page.tsx +++ b/apps/frontend/src/app/dashboard/webhooks/page.tsx @@ -1,7 +1,7 @@ 'use client'; import { motion } from "motion/react"; -import { Plus, CheckCircle2, AlertCircle, Activity } from "lucide-react"; + const webhooks = [ { id: "wh_1a2b3c", endpoint: "https://api.acmecorp.com/webhooks", events: ["payment.completed", "settlement.pending"], status: "active", lastTriggered: "2m ago", hash: "0x7a8f9b...4e5d" }, From c269b74683d0cea6c70f9e51297f48542194662a Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Sun, 29 Mar 2026 03:35:43 +0100 Subject: [PATCH 7/8] Fix linting errors: escape apostrophes, fix impure Math.random, use Next.js Image --- apps/frontend/src/app/checkout/page.tsx | 4 ++-- apps/frontend/src/app/components/ui/ImageWithFallback.tsx | 7 +++---- apps/frontend/src/app/dashboard/page.tsx | 5 ++++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/frontend/src/app/checkout/page.tsx b/apps/frontend/src/app/checkout/page.tsx index 95cb110..820ffd6 100644 --- a/apps/frontend/src/app/checkout/page.tsx +++ b/apps/frontend/src/app/checkout/page.tsx @@ -511,7 +511,7 @@ export default function PaymentCheckout() { onClick={handleBankPayment} className="w-full bg-white hover:bg-zinc-100 text-black h-14 rounded-xl mt-6 text-base transition-all duration-200 shadow-lg shadow-white/10" > - I've Completed the Transfer + I've Completed the Transfer

@@ -611,7 +611,7 @@ export default function PaymentCheckout() { onClick={handleCryptoDetection} className="w-full bg-white hover:bg-zinc-100 text-black h-14 rounded-xl mt-6 text-base transition-all duration-200 shadow-lg shadow-white/10" > - I've Sent the Payment + I've Sent the Payment

diff --git a/apps/frontend/src/app/components/ui/ImageWithFallback.tsx b/apps/frontend/src/app/components/ui/ImageWithFallback.tsx index 710fbff..c3d7280 100644 --- a/apps/frontend/src/app/components/ui/ImageWithFallback.tsx +++ b/apps/frontend/src/app/components/ui/ImageWithFallback.tsx @@ -1,4 +1,5 @@ import React, { useState } from 'react' +import Image from 'next/image' const ERROR_IMG_SRC = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iODgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBvcGFjaXR5PSIuMyIgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIzLjciPjxyZWN0IHg9IjE2IiB5PSIxNiIgd2lkdGg9IjU2IiBoZWlnaHQ9IjU2IiByeD0iNiIvPjxwYXRoIGQ9Im0xNiA1OCAxNi0xOCAzMiAzMiIvPjxjaXJjbGUgY3g9IjUzIiBjeT0iMzUiIHI9IjciLz48L3N2Zz4KCg==' @@ -10,7 +11,7 @@ export function ImageWithFallback(props: React.ImgHTMLAttributes

- {/* eslint-disable-next-line @next/next/no-img-element */} Error loading image
) : ( - /* eslint-disable-next-line @next/next/no-img-element */ - {alt} + {alt} ) } diff --git a/apps/frontend/src/app/dashboard/page.tsx b/apps/frontend/src/app/dashboard/page.tsx index 9358b54..96cbb2e 100644 --- a/apps/frontend/src/app/dashboard/page.tsx +++ b/apps/frontend/src/app/dashboard/page.tsx @@ -1,5 +1,6 @@ 'use client'; +import { useMemo } from 'react'; import { motion } from "motion/react"; import { TrendingUp, @@ -49,6 +50,8 @@ const assets = [ { symbol: "sETH", balance: "145.2341", usd: "232,251.75", change: "-1.2%" }, ]; +const barWidths = useMemo(() => assets.map(() => Math.random() * 40 + 60), []); + const transactions = [ { id: "pay_9k2j3n4k5j6h", @@ -211,7 +214,7 @@ export default function OverviewPage() { From 02fa21d580f173dfa53a40d1698e5b892c3e618b Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Sun, 29 Mar 2026 03:45:28 +0100 Subject: [PATCH 8/8] Fix apostrophe escaping to use ' instead of ' --- apps/frontend/src/app/checkout/page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/app/checkout/page.tsx b/apps/frontend/src/app/checkout/page.tsx index 95cb110..820ffd6 100644 --- a/apps/frontend/src/app/checkout/page.tsx +++ b/apps/frontend/src/app/checkout/page.tsx @@ -511,7 +511,7 @@ export default function PaymentCheckout() { onClick={handleBankPayment} className="w-full bg-white hover:bg-zinc-100 text-black h-14 rounded-xl mt-6 text-base transition-all duration-200 shadow-lg shadow-white/10" > - I've Completed the Transfer + I've Completed the Transfer

@@ -611,7 +611,7 @@ export default function PaymentCheckout() { onClick={handleCryptoDetection} className="w-full bg-white hover:bg-zinc-100 text-black h-14 rounded-xl mt-6 text-base transition-all duration-200 shadow-lg shadow-white/10" > - I've Sent the Payment + I've Sent the Payment