Skip to content

Commit bcca766

Browse files
authored
Merge pull request #13 from TaskOpenSystem/landing
Fix listing area unable to scroll
2 parents ea78dc5 + dd8ce85 commit bcca766

7 files changed

Lines changed: 417 additions & 61 deletions

File tree

app/marketplace/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default function MarketplaceLayout({
1212
<MarketplaceFilterProvider>
1313
<div className="flex min-h-screen w-full flex-row overflow-hidden font-sans antialiased selection:bg-accent-lime selection:text-ink">
1414
<MarketplaceSidebar />
15-
<main className="flex-1 flex flex-col h-screen overflow-hidden relative bg-background-light">
15+
<main className="flex-1 flex flex-col h-screen overflow-y-auto relative bg-background-light">
1616
{children}
1717
</main>
1818
</div>

app/marketplace/my-data/page.tsx

Lines changed: 81 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';
1010
import { Transaction } from '@mysten/sui/transactions';
1111
import { marketplaceConfig, MIST_PER_SUI } from '@/config/marketplace';
1212
import { getMarketplaceTarget } from '@/lib/marketplace';
13+
import { encryptFile, isSealAvailable, uint8ArrayToBase64 } from '@/lib/seal';
1314

1415
// Type for Walrus write files flow
1516
interface WalrusWriteFlow {
@@ -81,6 +82,7 @@ export default function MyDataPage() {
8182
previewSizeBytes: 1024 * 1024,
8283
});
8384

85+
8486
const flowRef = useRef<Awaited<ReturnType<typeof createFlow>> | null>(null);
8587

8688
const addLog = (step: string, status: TransactionLog['status'], message: string, details?: string) => {
@@ -151,20 +153,49 @@ export default function MyDataPage() {
151153
return;
152154
}
153155

154-
addLog('encode', 'processing', 'Encoding file...');
155-
156-
const fileBytes = await file.arrayBuffer();
157-
const uint8Array = new Uint8Array(fileBytes);
156+
// Step 0: Encrypt with Seal (if available)
157+
let dataToUpload: Uint8Array;
158+
let encryptedObj: string;
159+
160+
if (isSealAvailable()) {
161+
addLog('encode', 'processing', 'Encrypting with Seal (purchase-based access)...');
162+
163+
// Use seller address as policy ID - only buyers with PurchaseReceipt can decrypt
164+
console.log('[Seal] Encrypting file with purchase-based access');
165+
166+
try {
167+
const { encryptedBlob, policyId } = await encryptFile(file, account.address);
168+
const encryptedArrayBuffer = await encryptedBlob.arrayBuffer();
169+
dataToUpload = new Uint8Array(encryptedArrayBuffer);
170+
171+
// Store policy ID as the encrypted object reference
172+
encryptedObj = policyId;
173+
setEncryptedObject(encryptedObj);
174+
175+
addLog('encode', 'success', 'File encrypted (only buyers can decrypt)');
176+
console.log('[Seal] Encryption complete, encrypted size:', dataToUpload.length);
177+
} catch (sealError) {
178+
console.error('[Seal] Encryption failed:', sealError);
179+
addLog('encode', 'error', `Seal encryption failed: ${sealError instanceof Error ? sealError.message : 'Unknown error'}`);
180+
setUploadError('Failed to encrypt with Seal. Check console for details.');
181+
setIsProcessing(false);
182+
return;
183+
}
184+
} else {
185+
// Fallback: no encryption (store raw data)
186+
addLog('encode', 'processing', 'Encoding file (Seal not configured)...');
187+
const fileBytes = await file.arrayBuffer();
188+
dataToUpload = new Uint8Array(fileBytes);
189+
encryptedObj = bytesToHex(dataToUpload).slice(0, 128);
190+
setEncryptedObject(encryptedObj);
191+
addLog('encode', 'success', 'File encoded (no encryption)');
192+
}
158193

159-
// Step 1: Create flow and encode
160-
const flow = await createFlow(uint8Array, file.name);
194+
// Step 1: Create flow and encode with encrypted data
195+
const flow = await createFlow(dataToUpload, file.name);
161196
flowRef.current = flow;
162197
await flow.encode();
163-
addLog('encode', 'success', 'File encoded');
164-
165-
// Generate encrypted object from file content (first 64 bytes as hex)
166-
const encryptedObj = bytesToHex(uint8Array).slice(0, 128);
167-
setEncryptedObject(encryptedObj);
198+
addLog('encode', 'success', 'Walrus encoding complete');
168199

169200
// Step 2: Register blob on-chain
170201
setCurrentStep('register');
@@ -471,7 +502,7 @@ export default function MyDataPage() {
471502
</div>
472503
<span className="material-symbols-outlined text-5xl text-gray-600">dataset</span>
473504
<span className="absolute top-3 left-3 rounded bg-accent-lime text-ink px-2 py-0.5 text-[10px] font-bold border border-ink">ACTIVE</span>
474-
505+
475506
{/* Explorer Links */}
476507
<div className="absolute top-3 right-3 flex gap-1">
477508
<a
@@ -482,10 +513,10 @@ export default function MyDataPage() {
482513
title="View on SuiScan"
483514
>
484515
<svg className="w-4 h-4" viewBox="0 0 234 234" fill="none">
485-
<path d="M0 100C0 65 0 47.5 6.8 33C12.7 21.3 22.3 11.8 34 5.8C47.3 0 64.7 0 99.5 0H133.8C168.6 0 186 0 199.3 6.8C211 12.8 220.6 22.3 226.5 34C233.3 47.4 233.3 64.9 233.3 99.8V134.2C233.3 169.1 233.3 186.6 226.5 199.9C220.6 211.6 211 221.2 199.3 227.2C186 234 168.6 234 133.8 234H99.5C64.7 234 47.3 234 34 227.2C22.3 221.2 12.7 211.7 6.8 200C0 186.6 0 169.1 0 134.2V100Z" fill="#4C72FF"/>
486-
<path d="M177 87C178.7 85.9 180.8 85.6 182.4 86.3C183.2 86.6 183.9 87.1 184.3 87.8C184.7 88.5 185 89.4 184.9 90.2L181.4 148.2C181 155.7 178.2 163.4 173.6 170.4C160.4 190.4 133.2 200 112.8 191.8C107.1 189.5 102.5 186 99.2 181.7C100 181.8 100.8 181.7 101.5 181.7C122.4 181.7 143.5 170.3 155.1 152.7C160.7 144.1 164 134.7 164.6 125.6L166.5 93.3L177 87Z" fill="white"/>
487-
<path d="M150 63.6C151.7 62.5 153.8 62.3 155.5 62.9C156.3 63.3 156.9 63.8 157.4 64.5C157.9 65.2 158.1 66.1 158 66.9L154.5 125C154 132.5 151.3 140.1 146.7 147.1C133.5 167.2 106.3 176.7 85.9 168.5C80.1 166.2 75.6 162.7 72.3 158.4C73.1 158.4 73.9 158.4 74.6 158.4C95.6 158.4 116.6 147.1 128.2 129.4C133.9 120.8 137.1 111.4 137.7 102.3L139.6 70L150 63.6Z" fill="white"/>
488-
<path d="M123 40.3C124.7 39.2 126.8 39 128.5 39.6C129.2 39.9 129.9 40.5 130.3 41.2C130.8 41.9 131 42.7 130.9 43.5L127.4 101.6C127 109.1 124.2 116.7 119.6 123.7C106.4 143.8 79.2 153.3 58.8 145.1C38.5 136.9 32.7 114 45.9 93.9C50.5 86.9 57.1 80.7 64.6 76.1L123 40.3Z" fill="white"/>
516+
<path d="M0 100C0 65 0 47.5 6.8 33C12.7 21.3 22.3 11.8 34 5.8C47.3 0 64.7 0 99.5 0H133.8C168.6 0 186 0 199.3 6.8C211 12.8 220.6 22.3 226.5 34C233.3 47.4 233.3 64.9 233.3 99.8V134.2C233.3 169.1 233.3 186.6 226.5 199.9C220.6 211.6 211 221.2 199.3 227.2C186 234 168.6 234 133.8 234H99.5C64.7 234 47.3 234 34 227.2C22.3 221.2 12.7 211.7 6.8 200C0 186.6 0 169.1 0 134.2V100Z" fill="#4C72FF" />
517+
<path d="M177 87C178.7 85.9 180.8 85.6 182.4 86.3C183.2 86.6 183.9 87.1 184.3 87.8C184.7 88.5 185 89.4 184.9 90.2L181.4 148.2C181 155.7 178.2 163.4 173.6 170.4C160.4 190.4 133.2 200 112.8 191.8C107.1 189.5 102.5 186 99.2 181.7C100 181.8 100.8 181.7 101.5 181.7C122.4 181.7 143.5 170.3 155.1 152.7C160.7 144.1 164 134.7 164.6 125.6L166.5 93.3L177 87Z" fill="white" />
518+
<path d="M150 63.6C151.7 62.5 153.8 62.3 155.5 62.9C156.3 63.3 156.9 63.8 157.4 64.5C157.9 65.2 158.1 66.1 158 66.9L154.5 125C154 132.5 151.3 140.1 146.7 147.1C133.5 167.2 106.3 176.7 85.9 168.5C80.1 166.2 75.6 162.7 72.3 158.4C73.1 158.4 73.9 158.4 74.6 158.4C95.6 158.4 116.6 147.1 128.2 129.4C133.9 120.8 137.1 111.4 137.7 102.3L139.6 70L150 63.6Z" fill="white" />
519+
<path d="M123 40.3C124.7 39.2 126.8 39 128.5 39.6C129.2 39.9 129.9 40.5 130.3 41.2C130.8 41.9 131 42.7 130.9 43.5L127.4 101.6C127 109.1 124.2 116.7 119.6 123.7C106.4 143.8 79.2 153.3 58.8 145.1C38.5 136.9 32.7 114 45.9 93.9C50.5 86.9 57.1 80.7 64.6 76.1L123 40.3Z" fill="white" />
489520
</svg>
490521
</a>
491522
<a
@@ -496,22 +527,22 @@ export default function MyDataPage() {
496527
title="View on SuiVision"
497528
>
498529
<svg className="w-4 h-4" viewBox="0 0 24 24" fill="none">
499-
<path d="M0 6C0 2.68629 2.68629 0 6 0H18C21.3137 0 24 2.68629 24 6V18C24 21.3137 21.3137 24 18 24H6C2.68629 24 0 21.3137 0 18V6Z" fill="#4DA2FF"/>
500-
<path d="M6.99748 5.28362L6.99748 11.0148L8.71768 12.0008L6.99731 12.987L6.99731 18.7182L11.9972 21.584L16.9971 18.7182L16.9971 12.9866L15.2769 12.0007L16.9973 11.0147L16.9973 5.28308L11.997 2.41732L6.99748 5.28362ZM11.6464 3.42366L11.6464 7.94789L7.69961 10.2105L7.69961 5.68623L11.6464 3.42366ZM12.3482 20.5781L12.3482 16.0535L16.2954 13.7912L16.2954 18.3159L12.3482 20.5781ZM15.9441 13.1879L11.9973 15.4501L8.05048 13.1879L9.41994 12.4031L11.9973 13.8803L14.575 12.4031L15.9441 13.1879ZM11.9973 10.1208L9.41964 11.5982L8.05048 10.8134L11.9973 8.55113L15.9445 10.8134L14.575 11.5982L11.9973 10.1208Z" fill="white"/>
530+
<path d="M0 6C0 2.68629 2.68629 0 6 0H18C21.3137 0 24 2.68629 24 6V18C24 21.3137 21.3137 24 18 24H6C2.68629 24 0 21.3137 0 18V6Z" fill="#4DA2FF" />
531+
<path d="M6.99748 5.28362L6.99748 11.0148L8.71768 12.0008L6.99731 12.987L6.99731 18.7182L11.9972 21.584L16.9971 18.7182L16.9971 12.9866L15.2769 12.0007L16.9973 11.0147L16.9973 5.28308L11.997 2.41732L6.99748 5.28362ZM11.6464 3.42366L11.6464 7.94789L7.69961 10.2105L7.69961 5.68623L11.6464 3.42366ZM12.3482 20.5781L12.3482 16.0535L16.2954 13.7912L16.2954 18.3159L12.3482 20.5781ZM15.9441 13.1879L11.9973 15.4501L8.05048 13.1879L9.41994 12.4031L11.9973 13.8803L14.575 12.4031L15.9441 13.1879ZM11.9973 10.1208L9.41964 11.5982L8.05048 10.8134L11.9973 8.55113L15.9445 10.8134L14.575 11.5982L11.9973 10.1208Z" fill="white" />
501532
</svg>
502533
</a>
503534
</div>
504535
</div>
505-
536+
506537
{/* Content */}
507538
<div className="p-4 flex flex-col flex-1">
508539
<h3 className="text-base font-bold text-ink mb-1 line-clamp-2">{listing.name}</h3>
509-
540+
510541
{/* Object ID */}
511542
<p className="text-[10px] text-gray-400 font-mono mb-1 truncate" title={listing.id}>
512543
ID: {listing.id.slice(0, 8)}...{listing.id.slice(-6)}
513544
</p>
514-
545+
515546
{/* Blob ID with Walrus link */}
516547
<div className="flex items-center gap-1 mb-3">
517548
<p className="text-[10px] text-gray-400 font-mono truncate flex-1" title={listing.blobId}>
@@ -525,15 +556,15 @@ export default function MyDataPage() {
525556
title="View on WalrusScan"
526557
>
527558
<svg className="w-3 h-3" viewBox="0 0 24 24" fill="none">
528-
<circle cx="12" cy="10" r="8" fill="#36B5A8"/>
529-
<ellipse cx="12" cy="22" rx="6" ry="2" fill="#36B5A8" opacity="0.5"/>
530-
<circle cx="9" cy="8" r="1.5" fill="white"/>
531-
<circle cx="15" cy="8" r="1.5" fill="white"/>
532-
<path d="M9 13C9 13 10.5 15 12 15C13.5 15 15 13 15 13" stroke="white" strokeWidth="1.5" strokeLinecap="round"/>
559+
<circle cx="12" cy="10" r="8" fill="#36B5A8" />
560+
<ellipse cx="12" cy="22" rx="6" ry="2" fill="#36B5A8" opacity="0.5" />
561+
<circle cx="9" cy="8" r="1.5" fill="white" />
562+
<circle cx="15" cy="8" r="1.5" fill="white" />
563+
<path d="M9 13C9 13 10.5 15 12 15C13.5 15 15 13 15 13" stroke="white" strokeWidth="1.5" strokeLinecap="round" />
533564
</svg>
534565
</a>
535566
</div>
536-
567+
537568
{/* Stats */}
538569
<div className="grid grid-cols-2 gap-4 py-3 border-t border-gray-200">
539570
<div>
@@ -545,7 +576,7 @@ export default function MyDataPage() {
545576
<p className="text-sm font-bold text-accent-lime">{formatSize(Number(listing.totalSize))}</p>
546577
</div>
547578
</div>
548-
579+
549580
{/* Actions */}
550581
<div className="flex gap-2 mt-auto pt-3 border-t border-gray-200">
551582
<button className="flex-1 h-9 rounded-lg border-2 border-ink bg-white text-ink text-sm font-bold hover:bg-gray-50 transition-colors">
@@ -725,6 +756,28 @@ export default function MyDataPage() {
725756
<span>{formatSize(totalSizeBytes)}</span>
726757
</div>
727758
</div>
759+
760+
{/* Seal Encryption Notice */}
761+
<div className="pt-4 border-t border-gray-200">
762+
<label className="block text-sm font-bold text-gray-500 uppercase mb-2 flex items-center gap-2">
763+
<span className="material-symbols-outlined text-base">lock</span>
764+
Purchase-Based Encryption (Seal)
765+
</label>
766+
<p className="text-xs text-gray-500 mb-2">
767+
Data is encrypted with Seal threshold encryption. Only users who purchase this dataset will be able to decrypt it.
768+
</p>
769+
{!isSealAvailable() && (
770+
<p className="text-xs text-amber-600 bg-amber-50 p-2 rounded-lg border border-amber-200">
771+
⚠️ Seal not configured. Set NEXT_PUBLIC_PACKAGE_ID to enable encryption.
772+
</p>
773+
)}
774+
{isSealAvailable() && (
775+
<p className="text-xs text-green-600 bg-green-50 p-2 rounded-lg border border-green-200 flex items-center gap-1">
776+
<span className="material-symbols-outlined text-sm">check_circle</span>
777+
Seal encryption enabled - data will be protected
778+
</p>
779+
)}
780+
</div>
728781
</div>
729782

730783
<div className="space-y-4">

0 commit comments

Comments
 (0)