Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Demo fixes #75

Merged
merged 18 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Regulated stablecoin POC

This is a proof-of-concept for a regulated stablecoin. It is NOT a finished product.
This is a proof-of-concept for a regulated token with freeze and seize capabilities.

![Screenshot of the UI showing the minting authority.](image.png)

# Overview

Expand All @@ -20,6 +22,7 @@ This repository contains
* A user interface that implements the use cases using browser-based wallets. Based on next.js and lucid.
* An OCI container image with the on-chain code, the off-chain code and the UI


With the container image it is possible to run the complete system locally with just a single command.
There is no need to install the build toolchain or to operate a cardano node or related infrastructure.
The image can even be used to interact with existing deployments of the POC.
Expand Down
5 changes: 2 additions & 3 deletions cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ source-repository-package

source-repository-package
type: git
-- location: https://github.com/j-mueller/sc-tools
location: https://github.com/amirmrad/sc-tools
tag: 6c63efe07015e87719d77fa3fabfe07f959c7227
location: https://github.com/j-mueller/sc-tools
tag: a3662e093f40082dd6fa525bb0640a10caa1bd70
subdir:
src/devnet
src/blockfrost
Expand Down
27 changes: 18 additions & 9 deletions frontend/src/app/[username]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React, { useEffect, useState } from 'react';
import axios from 'axios';

//Mui imports
import { Box, Typography } from '@mui/material';
import { Box, Checkbox, FormControlLabel, Typography } from '@mui/material';

//Local components
import useStore from '../store/store';
Expand All @@ -19,6 +19,7 @@ import CopyTextField from '../components/CopyTextField';
export default function Profile() {
const { lucid, currentUser, mintAccount, changeAlertInfo, changeWalletAccountDetails } = useStore();
const accounts = useStore((state) => state.accounts);
const [overrideTx, setOverrideTx] = useState<boolean>(false);

useEffect(() => {
useStore.getState();
Expand All @@ -27,8 +28,8 @@ export default function Profile() {

const getUserAccountDetails = () => {
switch (currentUser) {
case "User A": return accounts.userA;
case "User B": return accounts.userB;
case "Alice": return accounts.alice;
case "Bob": return accounts.bob;
case "Connected Wallet": return accounts.walletUser;
};
};
Expand All @@ -38,10 +39,10 @@ export default function Profile() {
const [sendRecipientAddress, setsendRecipientAddress] = useState('address');

const onSend = async () => {
if (getUserAccountDetails()?.status === 'Frozen') {
if (getUserAccountDetails()?.status === 'Frozen' && !overrideTx) {
changeAlertInfo({
severity: 'error',
message: 'Cannot send WST with frozen account.',
message: 'Cannot send WST with frozen address.',
open: true,
link: ''
});
Expand All @@ -51,7 +52,7 @@ export default function Profile() {
changeAlertInfo({severity: 'info', message: 'Transaction processing', open: true, link: ''});
const accountInfo = getUserAccountDetails();
if (!accountInfo) {
console.error("No valid send account found! Cannot send.");
console.error("No valid send address found! Cannot send.");
return;
}
lucid.selectWallet.fromSeed(accountInfo.mnemonic);
Expand All @@ -61,6 +62,7 @@ export default function Profile() {
quantity: sendTokenAmount,
recipient: sendRecipientAddress,
sender: accountInfo.address,
submit_failing_tx: overrideTx
};
try {
const response = await axios.post(
Expand All @@ -77,7 +79,7 @@ export default function Profile() {
const txId = await signAndSentTx(lucid, tx);
await updateAccountBalance(sendRecipientAddress);
await updateAccountBalance(accountInfo.address);
changeAlertInfo({severity: 'success', message: 'Transaction sent successfully!', open: true, link: `https://preview.cardanoscan.io/transaction/${txId.inputs[0].transaction_id}`});
changeAlertInfo({severity: 'success', message: 'Transaction sent successfully!', open: true, link: `https://preview.cexplorer.io/tx/${txId}`});
} catch (error) {
console.error('Send failed:', error);
}
Expand Down Expand Up @@ -111,6 +113,12 @@ export default function Profile() {
label="Recipient’s Address"
fullWidth={true}
/>
<FormControlLabel
control={<Checkbox size="small" checked={overrideTx} onChange={x => setOverrideTx(x.target.checked)} />}
label="⚠️ Force send failing transaction"
sx={{ mb: 2 }}
/>

</Box>;

const receiveContent = <Box>
Expand All @@ -125,8 +133,9 @@ export default function Profile() {
<div className="page">
<Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'end', marginBottom: '16px'}}>
<Box>
<Typography variant='h4'>Account Balance</Typography>
<Typography variant='h1'>{getUserAccountDetails()?.balance} WST</Typography>
<Typography variant='h4'>Address Balance</Typography>
<Typography variant='h1'>{getUserAccountDetails()?.balance.wst} WST</Typography>
<Typography variant='h5'>{getUserAccountDetails()?.balance.ada} Ada</Typography>
</Box>
<Typography variant='h5'>{getUserAccountDetails()?.address.slice(0,15)}</Typography>
</Box>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/[username]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import Profile from '.';

export async function generateStaticParams() {
return [
{ username: 'user-a' },
{ username: 'user-b' },
{ username: 'alice' },
{ username: 'bob' },
{ username: 'connected-wallet' } // connected wallet
]
}
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/app/clientLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ export default function ClientLayout({ children }: { children: React.ReactNode }
try {
// retrieve wallet info
const mintAuthorityWallet = await getWalletFromSeed(mintAccount.mnemonic);
const walletA = await getWalletFromSeed(accounts.userA.mnemonic);
const walletB = await getWalletFromSeed(accounts.userB.mnemonic);
const walletA = await getWalletFromSeed(accounts.alice.mnemonic);
const walletB = await getWalletFromSeed(accounts.bob.mnemonic);

// Update Zustand store with the initialized wallet information
changeMintAccountDetails({ ...mintAccount, address: mintAuthorityWallet.address});
changeWalletAccountDetails('userA', { ...accounts.userA, address: walletA.address},);
changeWalletAccountDetails('userB', { ...accounts.userB, address: walletB.address});
changeWalletAccountDetails('alice', { ...accounts.alice, address: walletA.address},);
changeWalletAccountDetails('bob', { ...accounts.bob, address: walletB.address});

const initialLucid = await makeLucid();
setLucidInstance(initialLucid);
Expand All @@ -41,7 +41,7 @@ export default function ClientLayout({ children }: { children: React.ReactNode }
fetchUserWallets();
},[]);

if(accounts.userB.address === '') {
if(accounts.bob.address === '') {
return <div className="mainLoadingContainer">
<div className="mainLoader" />
</div>;
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/components/NavDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const drawerWidth = 200;

const iconMapping = {
'Mint Actions': <ImportExportIcon />,
'Accounts': <FormatListBulletedIcon />,
'Addresses': <FormatListBulletedIcon />,
'Wallet': <AccountBalanceWalletIcon />
};

Expand All @@ -30,7 +30,7 @@ export default function NavDrawer() {

// Define list items based on the current user
const listItems: MenuTab[] = currentUser === 'Mint Authority' ?
['Mint Actions', 'Accounts'] :
['Mint Actions', 'Addresses'] :
['Wallet'];

const handleListItemClick = (item: MenuTab) => {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/components/ProfileSwitcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ export default function ProfileSwitcher() {
onClose={handleClose}
>
<MenuItem onClick={() => handleSelect('Mint Authority')}>Mint Authority</MenuItem>
<MenuItem onClick={() => handleSelect('User A')}>User A</MenuItem>
<MenuItem onClick={() => handleSelect('User B')}>User B</MenuItem>
<MenuItem onClick={() => handleSelect('Alice')}>Alice</MenuItem>
<MenuItem onClick={() => handleSelect('Bob')}>Bob</MenuItem>
<MenuItem onClick={() => handleWalletConnect('Connected Wallet')}>Lace</MenuItem>
</Menu>
</>
Expand Down
12 changes: 9 additions & 3 deletions frontend/src/app/components/WSTTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import TableCell from "@mui/material/TableCell";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Paper from "@mui/material/Paper";
import ContentCopyIcon from '@mui/icons-material/ContentCopy';

//Local Imports
import useStore from '../store/store';
import { useEffect } from "react";
import IconButton from './WSTIconButton';

const progLogicBase : LucidCredential = {
type: "Script",
Expand Down Expand Up @@ -43,6 +45,9 @@ export default function WSTTable() {
getAccounts();
}, []);

const copyToClipboard = (str: string) => {
navigator.clipboard.writeText(str);
}

return (
<Box className="tableContainerBox">
Expand All @@ -51,8 +56,8 @@ export default function WSTTable() {
<TableHead>
<TableRow>
<TableCell>Address</TableCell>
<TableCell>Account Status</TableCell>
<TableCell align="right">Account Balance</TableCell>
<TableCell>Address Status</TableCell>
<TableCell align="right">Address Balance</TableCell>
</TableRow>
</TableHead>
<TableBody>
Expand All @@ -61,12 +66,13 @@ export default function WSTTable() {
<TableRow key={i}>
<TableCell>
{`${acct?.address.slice(0,15)}...${acct?.address.slice(104,108)}`}
<IconButton onClick={() => copyToClipboard(acct.address)} icon={<ContentCopyIcon />}/>
</TableCell>
<TableCell sx={{color: acct.status === 'Frozen' ? 'error.main' : 'success.main', fontWeight: '500'}}>
{acct.status}
</TableCell>
<TableCell align="right">
{`${acct?.balance} WST`}
{`${acct?.balance.wst} WST`}
</TableCell>
</TableRow>
))
Expand Down
Loading
Loading