Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9ce3b25
wallet test 01
QSchlegel Mar 5, 2025
917b432
t 02
QSchlegel Mar 7, 2025
eb0d4e5
Add files via upload
QSchlegel Feb 24, 2025
c2b880a
fix: address tx pagination
HinsonSIDAN Mar 3, 2025
1389cd3
remove koios from env
jinglescode Mar 6, 2025
ab7d513
Improved vote button. & Bug fix in proposal list.
QSchlegel Mar 10, 2025
1aa4a68
fix spam protction
QSchlegel Mar 10, 2025
bccea14
acct_shared_xvk import
QSchlegel Mar 12, 2025
8659320
ux improve
QSchlegel Mar 14, 2025
721e018
init sdk
QSchlegel Mar 19, 2025
0944838
step
QSchlegel Mar 24, 2025
39b523d
pull transactions every 15mins
jinglescode Mar 12, 2025
ba0aa47
fix build error, use const
jinglescode Mar 12, 2025
d15e81b
update mesh
jinglescode Mar 12, 2025
3f8e908
resolving ada handles to addresses
justinschreiner Mar 6, 2025
396f3cd
move to helper function and use meshsdk lookup
justinschreiner Mar 7, 2025
24b4550
cleaning up changes
justinschreiner Mar 7, 2025
2faf10b
Use get provider
QSchlegel Mar 10, 2025
f5ba5e3
putting recipient row in its own component file
justinschreiner Mar 11, 2025
4e38ec6
bandaid🩹
QSchlegel Mar 12, 2025
eeb9eea
cst fix 😅🙄
QSchlegel Mar 14, 2025
8839733
show description
QSchlegel Mar 20, 2025
0e675ae
wallet test 01
QSchlegel Mar 5, 2025
44a97f8
pl
QSchlegel Mar 26, 2025
4b2a451
new-wallet + multisigsdk
QSchlegel Apr 2, 2025
d1c9cb0
registration button
QSchlegel Apr 2, 2025
c2d63c5
fix up
QSchlegel Apr 2, 2025
ad06426
Merge branch 'main' into PoC/invite-wallet
QSchlegel Apr 2, 2025
9e71ecc
fix Wasm error
QSchlegel Apr 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isServer } from "@tanstack/react-query";

/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
Expand Down Expand Up @@ -29,6 +31,16 @@ const config = {
asyncWebAssembly: true,
layers: true,
};
// For server builds, place the WASM files one level up
config.output.webassemblyModuleFilename = isServer
? "../static/wasm/[modulehash].wasm"
: "static/wasm/[modulehash].wasm";

// Optional: add a rule to ensure WASM files are treated as assets
config.module.rules.push({
test: /\.wasm$/,
type: "asset/resource",
});
return config;
},
};
Expand Down
8 changes: 8 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
},
"dependencies": {
"@auth/prisma-adapter": "^1.6.0",
"@emurgo/cardano-serialization-lib-browser": "^14.1.1",
"@hookform/resolvers": "^3.9.0",
"@jinglescode/nostr-chat-plugin": "^0.0.11",
"@meshsdk/core": "^1.9.0-beta.18",
Expand Down Expand Up @@ -51,6 +52,7 @@
"@trpc/react-query": "^11.0.0-rc.446",
"@trpc/server": "^11.0.0-rc.446",
"@vercel/blob": "^0.23.4",
"blakejs": "^1.2.1",
"busboy": "^1.6.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
Expand Down
17 changes: 16 additions & 1 deletion src/components/common/overall-layout/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import React, { useEffect, useState } from "react";
import Link from "next/link";
import { api } from "@/utils/api";
import ConnectWallet from "../cardano-objects/connect-wallet";
Expand All @@ -25,6 +25,7 @@ import { publicRoutes } from "@/data/public-routes";
import Loading from "./loading";
import DialogReport from "./dialog-report";
import { useRouter } from "next/router";
import { Menu as MenuIcon } from "lucide-react";

export default function RootLayout({
children,
Expand All @@ -36,6 +37,7 @@ export default function RootLayout({
const router = useRouter();
const { appWallet } = useAppWallet();
const { generateNsec } = useNostrChat();
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);

const userAddress = useUserStore((state) => state.userAddress);
const setUserAddress = useUserStore((state) => state.setUserAddress);
Expand Down Expand Up @@ -88,6 +90,16 @@ export default function RootLayout({
return (
<div className="grid h-screen w-full overflow-hidden md:grid-cols-[220px_1fr] lg:grid-cols-[280px_1fr]">
{isLoading && <Loading />}
{mobileMenuOpen && (
<div className="fixed inset-0 z-30 flex">
<div className="w-64 bg-muted p-4">
<button className="mb-4" onClick={() => setMobileMenuOpen(false)}>Close</button>
<MenuWallets />
{router.pathname.includes("/wallets/[wallet]") && <MenuWallet />}
</div>
<div className="flex-1 bg-black opacity-50" onClick={() => setMobileMenuOpen(false)}></div>
</div>
)}

{/* Sidebar for larger screens */}
<aside className="hidden border-r bg-muted/40 md:block">
Expand All @@ -110,6 +122,9 @@ export default function RootLayout({
<div className="flex h-screen flex-col">
<header className="pointer-events-auto relative z-10 border-b bg-muted/40 px-4 lg:px-6">
<div className="flex h-14 items-center gap-4 lg:h-[60px]">
<button className="md:hidden" onClick={() => setMobileMenuOpen(true)}>
<MenuIcon className="h-6 w-6" />
</button>
{/* Wallet selection + breadcrumb row */}
{isLoggedIn && (
<div className="border-t border-border">
Expand Down
2 changes: 2 additions & 0 deletions src/components/common/overall-layout/wallet-data-loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export default function WalletDataLoader() {
}

async function getTransactionsOnChain() {

try {
if (appWallet) {
const maxPage = 4;
Expand Down Expand Up @@ -152,6 +153,7 @@ export default function WalletDataLoader() {
if (appWallet && prevWalletIdRef.current !== appWallet.id) {
refreshWallet();
prevWalletIdRef.current = appWallet.id;

}
}, [appWallet]);

Expand Down
71 changes: 33 additions & 38 deletions src/components/pages/homepage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import Link from "next/link";
import useUser from "@/hooks/useUser";
import { useRouter } from "next/router";
import { api } from "@/utils/api";
import CardUI from "@/components/common/card-content";
import RowLabelInfo from "@/components/common/row-label-info";
import Globe from "./globe";
import PageNewWalletInvite from "./wallets/invite";

export function PageHomepage() {
const { user } = useUser();
const router = useRouter();
const pathIsNewWallet = router.pathname == "/wallets/invite/[id]";
const pathIsNewWallet = router.pathname === "/wallets/invite/[id]";
const newWalletId = pathIsNewWallet ? (router.query.id as string) : undefined;

const { data: newWallet } = api.wallet.getNewWallet.useQuery(
Expand All @@ -22,45 +21,41 @@ export function PageHomepage() {
);

return (
<div className="h-screen w-full lg:grid lg:grid-cols-3">
<div className="flex items-center justify-center py-12">
<div className="mx-auto grid max-w-[500px] gap-6">
<div className="grid gap-2 text-center">
<div className="relative min-h-screen">
{/* Background Globe */}
<div className="absolute inset-0 -z-10 flex items-center justify-center">
<Globe />
</div>

{newWallet ? (
/* Render the invite page if a new wallet is found */
<PageNewWalletInvite />
) : (
/* Otherwise show the homepage */
<div className="container mx-auto px-4 py-8 relative z-10 flex flex-col items-center justify-center">
<div className="mx-auto grid max-w-[500px] gap-6 text-center">
<h1 className="text-3xl font-bold">Multisig Platform</h1>
<p className="text-balance text-muted-foreground">
Secure your treasury and participant in governance, as a team with
multi-signature
Secure your treasury and participate in governance as a team with multi-signature
</p>
{newWallet && (
<CardUI
title={`Invited as signer`}
description={`You have been invited to join this wallet as a signer, connect your wallet to accept the invitation`}
cardClassName="text-left mt-4"
>
<RowLabelInfo label="Name" value={newWallet.name} />
<RowLabelInfo label="About" value={newWallet.description} />
</CardUI>
)}
</div>
<div className="flex items-center justify-center">
{user ? (
<div className="flex gap-2">
<Button size="sm" asChild>
<Link href="/wallets/new-wallet">New Wallet</Link>
</Button>
<Button size="sm" asChild>
<Link href="/wallets">Your Wallets</Link>
</Button>
</div>
) : (
<ConnectWallet />
)}

<div>
{user ? (
<div className="flex gap-2 justify-center">
<Button size="sm" asChild>
<Link href="/wallets/new-wallet">New Wallet</Link>
</Button>
<Button size="sm" asChild>
<Link href="/wallets">Your Wallets</Link>
</Button>
</div>
) : (
<ConnectWallet />
)}
</div>
</div>
</div>
</div>
<div className="col-span-2">
<Globe />
</div>
)}
</div>
);
}
}
132 changes: 132 additions & 0 deletions src/components/pages/homepage/wallets/invite/cip146/146Import.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import React, { useRef, useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
//import { Bip32PublicKey, Address } from "@emurgo/cardano-serialization-lib-browser";
import { bech32 } from "bech32"; // used only for debugging the payload

interface ImportProps {
onImport: (accountKeyHex: string) => void;
}

const ImportComponent: React.FC<ImportProps> = ({ onImport }) => {
//const fileInputRef = useRef<HTMLInputElement>(null);
const [directInput, setDirectInput] = useState("");
const [errorMessage, setErrorMessage] = useState("");

// const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// const file = e.target.files?.[0];
// if (!file) return;
// const fileReader = new FileReader();
// fileReader.onload = (event) => {
// try {
// const importedData = JSON.parse(event.target?.result as string);
// // Check for our simple export format: directly exported account key.
// if (importedData.acct_shared_xsk) {
// onImport(importedData.acct_shared_xsk);
// return;
// }
// // Check for our multisig export format.
// if (
// importedData.wallet &&
// importedData.wallet.multiSig &&
// Array.isArray(importedData.wallet.multiSig) &&
// importedData.wallet.multiSig.length > 0
// ) {
// const ms = importedData.wallet.multiSig[0];
// if (ms.priv) {
// onImport(ms.priv);
// return;
// } else if (ms.pub) {
// onImport(ms.pub);
// return;
// }
// }
// setErrorMessage("Invalid file. Account key not found.");
// } catch (error) {
// console.error(error);
// setErrorMessage("Failed to import account key.");
// }
// };
// fileReader.readAsText(file);
// };

// const handleFileImport = () => {
// fileInputRef.current?.click();
// };

// const handleDirectImport = () => {
// if (!directInput.trim()) {
// setErrorMessage("Please enter an account key.");
// return;
// }
// setErrorMessage("");
// // Simply pass the direct input to the callback.
// onImport(directInput.trim());
// };

const importFromBech32 = () => {
if (!directInput.trim()) {
setErrorMessage("Please enter a Bech32 address.");
return;
}

const input = directInput.trim();
try {
// Only support extended account keys with prefix 'acct_shared_xvk'
if (!input.startsWith("acct_shared_xvk")) {
throw new Error("Unsupported Bech32 format. Expected extended account key with prefix acct_shared_xvk.");
}

// Manually decode the Bech32 string using the bech32 library
const decoded = bech32.decode(input, 200);
const dataBytes = new Uint8Array(bech32.fromWords(decoded.words));
const bytesToHex = (bytes: Uint8Array): string =>
bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
const pubKeyHex = bytesToHex(dataBytes);
// Validate the decoded key by parsing it with from_hex
//const bip32Pub = Bip32PublicKey.from_hex(pubKeyHex);

onImport(pubKeyHex);
setErrorMessage("");
} catch (error) {
console.error("Bech32 decoding error:", error);
setErrorMessage("Invalid Bech32 address: " );
}
};

return (
<div>
{/* <div className="flex gap-2">
<Button onClick={handleFileImport} variant="outline">
Import Account Key (File)
</Button>
<input
type="file"
accept=".json"
ref={fileInputRef}
onChange={handleFileChange}
style={{ display: "none" }}
/>
</div> */}
<div className="flex flex-col gap-1 mt-2">
<Label htmlFor="directKey">Paste account key (Bech32):</Label>
<Input
id="directKey"
type="text"
placeholder="Enter acct_shared_xvk"
value={directInput}
onChange={(e) => setDirectInput(e.target.value)}
/>
{errorMessage && <p className="text-red-500">{errorMessage}</p>}
<div className="flex gap-2">
<Button onClick={importFromBech32} variant="outline">
Import
</Button>
</div>
</div>
</div>
);
};

export default ImportComponent;
Loading