Skip to content

Commit

Permalink
Merge pull request #18 from IntersectMBO/v0.1
Browse files Browse the repository at this point in the history
Version `0.1`
  • Loading branch information
elenabardho authored Jan 17, 2025
2 parents 9222ca1 + c0c9320 commit 383786d
Show file tree
Hide file tree
Showing 7 changed files with 1,183 additions and 80 deletions.
5 changes: 4 additions & 1 deletion src/.env.example
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
BLOCKFROST_API=
BLOCKFROST_SANCHONET_API=
BLOCKFROST_PREVIEW_API=
BLOCKFROST_PREPROD_API=
BLOCKFROST_MAINNET_API=
5 changes: 5 additions & 0 deletions src/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,14 @@ yarn-error.log*
# local env files
.env*.local

.env

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

#test files
test.js
177 changes: 177 additions & 0 deletions src/app/components/transaction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
"use client";

import { useState } from "react";
import { useWallet } from "@meshsdk/react";
import { BlockfrostProvider, deserializeAddress } from "@meshsdk/core";
import { Button, TextField, Box, Typography, Container ,Table, TableBody, TableCell, TableContainer, TableRow, Paper } from "@mui/material";
import * as CLS from "@emurgo/cardano-serialization-lib-browser";
import ReactJsonPretty from 'react-json-pretty';

const decodeTransaction = (unsignedTransactionHex: string) => {
try {
const unsignedTransaction = CLS.Transaction.from_hex(unsignedTransactionHex);
console.log("signers list", unsignedTransaction.body().required_signers()?.to_json());
return unsignedTransaction;
} catch (error) {
console.error("Error decoding transaction:", error);
return null;
}
};

export const TransactionButton = () => {
const [message, setMessage] = useState("");
const [unsignedTransactionHex, setUnsignedTransactionHex] = useState("");
const [unsignedTransaction, setUnsignedTransaction] = useState<CLS.Transaction | null>(null);
const { wallet, connected, name, connect, disconnect } = useWallet();
const [signature, setsignature] = useState<string>("");
const [isPartOfSigners, setIsPartOfSigners] = useState(false);


const checkTransaction = async () => {
if (!connected) {
setMessage("Please connect your wallet first.");
return;
}

const network = await wallet.getNetworkId();
console.log("Connected wallet network ID:", network);
console.log("isPartOfSigners:", isPartOfSigners);

const unsignedTransaction= decodeTransaction(unsignedTransactionHex);
console.log("local unsignedTransaction:", unsignedTransaction);
setUnsignedTransaction( unsignedTransaction);

console.log("unsignedTransaction:", unsignedTransaction);

const changeAddress = await wallet.getChangeAddress();
const paymentCred=deserializeAddress(changeAddress).pubKeyHash;
const stakeCred=deserializeAddress(changeAddress).stakeCredentialHash;

console.log("Payment Credential:", paymentCred);
console.log("Stake Credential:", stakeCred);
const requiredSigners = unsignedTransaction?.body().required_signers();

console.log("Required signers in the transaction:", requiredSigners?.to_json());

if (!requiredSigners || requiredSigners.len() === 0) {
console.log("No required signers in the transaction.");
return "No required signers in the transaction.";

}else if (requiredSigners?.to_json().includes(stakeCred) || requiredSigners?.to_json().includes(paymentCred)){
console.log("Required signers in the transaction:", requiredSigners?.to_json());
setIsPartOfSigners(true);

return "Required signers in the transaction.";
}


};

const signTransaction = async () => {
console.log("isPartOfSigners:", isPartOfSigners);
try {
if (isPartOfSigners) {
const signedTx = await wallet.signTx(unsignedTransactionHex, true);
console.log("Transaction signed successfully:", signedTx);
const signature = await decodeTransaction(signedTx);
setsignature(signature?.witness_set().vkeys()?.get(0)?.signature()?.to_hex() || '');
console.log("signature:", signature?.witness_set().vkeys()?.get(0).signature().to_hex());
}
else {throw new Error("You are not part of the required signers.");}
} catch (error) {
console.error("Error signing transaction:", error);
setMessage("Transaction signing failed. Check the console for more details.");
}
};

return (

<Container maxWidth="md" sx={{ mt: 4 }}>
{/* Transaction Input & Button */}
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<TextField
type="string"
label="Enter Hex Encoded Transaction"
variant="outlined"
fullWidth
value={unsignedTransactionHex}
onChange={(e) => setUnsignedTransactionHex(e.target.value)}
/>
<Button
variant="contained"
color="success"
onClick={checkTransaction}
sx={{ whiteSpace: "nowrap", px: 3 }}
>
Check Transaction
</Button>
</Box>

{/* Transaction Details */}
<Box sx={{ mt: 3 }}>
<Typography variant="h6">Transaction Details</Typography>
<p>
<span style={{ fontWeight: "bold" }}>Wallet needs to sign?: </span>
{isPartOfSigners ? "✅" : "❌"}
</p>
<Box
sx={{
backgroundColor: "#f5f5f5",
padding: 2,
borderRadius: 1,
maxHeight: "400px",
overflowY: "auto",
marginTop: 2,
boxShadow: 1,
}}
>
<ReactJsonPretty data={unsignedTransaction ? unsignedTransaction.to_json() : {}} />
</Box>
</Box>

{/* Sign Button - Aligned to Right */}
<Box sx={{ display: "flex", justifyContent: "flex-end", mt: 3 }}>
<Button
variant="contained"
color="success"
onClick={signTransaction}
sx={{ whiteSpace: "nowrap", px: 3 }}
>
Sign Transaction
</Button>
</Box>

{/* Signature Display */}
{signature && (
<Box sx={{ mt: 3 }}>
<Typography variant="h6">Signature</Typography>
<Box
sx={{
backgroundColor: "#e8f5e9",
padding: 2,
borderRadius: 1,
whiteSpace: "pre-wrap",
wordWrap: "break-word",
boxShadow: 2,
maxHeight: "250px",
overflowY: "auto",
}}
>
<Typography component="pre">{signature}</Typography>
</Box>
</Box>
)}

{/* Error Message Display */}
{message && (
<Typography variant="body1" color="error" sx={{ mt: 2 }}>
{message}
</Typography>
)}
</Container>


);
};


44 changes: 41 additions & 3 deletions src/app/components/wallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ import { useEffect, useState } from "react";
import "../globals.css"; // Import the CSS file
import "@meshsdk/react/styles.css"
import { useWallet } from "@meshsdk/react";
import { deserializeAddress } from "@meshsdk/core";
import { Container, Table, TableBody, TableCell, TableContainer, TableRow, Paper } from "@mui/material";


export const Wallet = () => {
const [WalletComponent, setWalletComponent] = useState<any | null>(null);

const [paymentCred, setPaymentCred] = useState<string | null>(null);
const [stakeCred, setStakeCred] = useState<string | null>(null);

useEffect(() => {
const run = async () => {
try {
Expand All @@ -27,11 +32,25 @@ export const Wallet = () => {
const handleWalletConnection = async () => {
if (connected) {
console.log("Wallet connected:", name);
const pubKey = await wallet.getRegisteredPubStakeKeys();
console.log("Public key:", pubKey);
const changeAddress = await wallet.getChangeAddress();

setPaymentCred(deserializeAddress(changeAddress).pubKeyHash);

setStakeCred(deserializeAddress(changeAddress).stakeCredentialHash);

console.log("Payment Credential:", paymentCred);
console.log("Stake Credential:", stakeCred);
}else{
console.log("Wallet not connected.");
setPaymentCred(null);
setStakeCred(null);
}
};

handleWalletConnection();
}, [connected, name, wallet]);
}, [wallet,connected, name, ,paymentCred, stakeCred]);

return <WalletComponent />;
};
Expand All @@ -41,9 +60,28 @@ export const Wallet = () => {
}

return (
<div className="wallet-container">

<Container maxWidth="md">
<div className="wallet-container" style={{ display: "flex", flexDirection: "column", alignItems: "center" }} >
<WalletWrapper />
</div>
{/* Credentials Table */}
<TableContainer sx={{ mb: 3 }}>
<Table>
<TableBody>
<TableRow>
<TableCell sx={{ fontWeight: "bold" }}>Payment Credential</TableCell>
<TableCell>{paymentCred || "Not Available"}</TableCell>
</TableRow>
<TableRow>
<TableCell sx={{ fontWeight: "bold" }}>Stake Credential</TableCell>
<TableCell>{stakeCred || "Not Available"}</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>

</Container>
);
};

Expand Down
25 changes: 19 additions & 6 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
import { Wallet } from "./components/wallet";
import { TransactionButton } from "./components/transaction";
import { Container, Typography, Box } from "@mui/material";

export default function Home() {
return (
<main>
<h1 className="font-bold uppercase mr-auto">Credential Manager App</h1>
<div className="ml-auto">
<Wallet />
</div>
</main>
// <main>
// <h1 className="font-bold uppercase mr-auto">Credential Manager App</h1>
// <div className="ml-auto">
// <Wallet />
// <TransactionButton />
// </div>
// </main>
<Container maxWidth="md" sx={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-start", minHeight: "100vh" }}>
<Typography variant="h4" component="h1" fontWeight="bold" textTransform="uppercase" mb={3} textAlign="center">
Credential Manager App
</Typography>

<Box display="flex" flexDirection="column" alignItems="center" gap={2} width="100%">
<Wallet />
<TransactionButton />
</Box>
</Container>
);
}
Loading

0 comments on commit 383786d

Please sign in to comment.