Skip to content

Commit 892361f

Browse files
j-muellerchoener
andauthored
Mainnet readiness (#77)
* Add DemoEnvironment type * More informative response for user-funds query * Show real Ada balance and collateral UTxOs in frontend * Fixes building the frontend * Add missing adaOnlyOutputs * Label * Complete parameterisation * Fix npm export * Cosmetic changes * Move compiled scripts to generated folder * ? * Update compiled scripts * Fix CI --------- Co-authored-by: Christian Hoener zu Siederdissen <[email protected]>
1 parent 435646a commit 892361f

File tree

108 files changed

+918
-245
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+918
-245
lines changed

.github/workflows/ci-compiled-scripts.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ jobs:
4444
- name: check compiled scripts are consistent
4545
# git diff --quiet implies --exit-code
4646
run: |
47-
cabal run export-smart-tokens 08a8d0bb8717839931b0a594f7c28b0a3b7c78f6e9172e977e250eab7637d879.0 '"addr_test1qq986m3uel86pl674mkzneqtycyg7csrdgdxj6uf7v7kd857kquweuh5kmrj28zs8czrwkl692jm67vna2rf7xtafhpqk3hecm"'
47+
cabal run export-smart-tokens ./generated/scripts/unapplied
48+
cabal run export-smart-tokens ./generated/scripts/preview 08a8d0bb8717839931b0a594f7c28b0a3b7c78f6e9172e977e250eab7637d879.0 '"addr_test1qq986m3uel86pl674mkzneqtycyg7csrdgdxj6uf7v7kd857kquweuh5kmrj28zs8czrwkl692jm67vna2rf7xtafhpqk3hecm"'
49+
cabal run export-smart-tokens ./generated/scripts/mainnet b1977c1eb33590ca1311384ab68cd36209832213ad4483feb8a1b7cb64828946.0 '"addr_test1qq986m3uel86pl674mkzneqtycyg7csrdgdxj6uf7v7kd857kquweuh5kmrj28zs8czrwkl692jm67vna2rf7xtafhpqk3hecm"'
4850
cabal run write-openapi-schema -- generated/openapi/schema.json
4951
git diff --quiet

.github/workflows/ci-nix.yaml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,3 @@ jobs:
5454
run: nix build --accept-flake-config .#wst-poc-cli
5555
- name: nix flake check
5656
run: nix flake --accept-flake-config check
57-
- name: check compiled scripts are consistent
58-
# git diff --quiet implies --exit-code
59-
run: |
60-
nix run --accept-flake-config .#export-smart-tokens 08a8d0bb8717839931b0a594f7c28b0a3b7c78f6e9172e977e250eab7637d879.0 '"addr_test1qq986m3uel86pl674mkzneqtycyg7csrdgdxj6uf7v7kd857kquweuh5kmrj28zs8czrwkl692jm67vna2rf7xtafhpqk3hecm"'
61-
git diff --quiet
62-

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ get-protocol-parameters.sh
3232
protocol-parameters-mainnet.json
3333
.pre-commit-config.yaml
3434
tags
35+
/mainnet

fix-cabal-fmt.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#! /bin/bash
2+
3+
fd --extension cabal --exclude 'dist-newstyle/*' --exclude 'dist/*' --exclude '.stack-work/*' --exec bash -c "cabal-fmt --inplace {}"

fix-fourmolu.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#! /bin/bash
2+
3+
fd --extension hs --exclude 'dist-newstyle/*' --exclude 'dist/*' --exclude '.stack-work/*' --exec bash -c "fourmolu --quiet --mode inplace {}"

frontend/src/app/[username]/index.tsx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22
//React imports
3-
import React, { useEffect, useState } from 'react';
3+
import React, { useContext, useEffect, useState } from 'react';
44

55
//Axios imports
66
import axios from 'axios';
@@ -15,11 +15,13 @@ import { getWalletBalance, signAndSentTx } from '../utils/walletUtils';
1515
import WalletCard from '../components/Card';
1616
import WSTTextField from '../components/WSTTextField';
1717
import CopyTextField from '../components/CopyTextField';
18+
import DemoEnvironmentContext from '../context/demoEnvironmentContext';
1819

1920
export default function Profile() {
2021
const { lucid, currentUser, mintAccount, changeAlertInfo, changeWalletAccountDetails } = useStore();
2122
const accounts = useStore((state) => state.accounts);
2223
const [overrideTx, setOverrideTx] = useState<boolean>(false);
24+
const demoEnv = useContext(DemoEnvironmentContext);
2325

2426
useEffect(() => {
2527
useStore.getState();
@@ -34,6 +36,16 @@ export default function Profile() {
3436
};
3537
};
3638

39+
const getUserMnemonic = () => {
40+
switch (currentUser) {
41+
case "Alice": return demoEnv.user_a;
42+
case "Bob": return demoEnv.user_b;
43+
case "Mint Authority": return demoEnv.mint_authority;
44+
case "Connected Wallet": return ""; //TODO: this seems to be broken
45+
};
46+
47+
}
48+
3749
// temp state for each text field
3850
const [sendTokenAmount, setMintTokens] = useState(0);
3951
const [sendRecipientAddress, setsendRecipientAddress] = useState('address');
@@ -55,13 +67,14 @@ export default function Profile() {
5567
console.error("No valid send address found! Cannot send.");
5668
return;
5769
}
58-
lucid.selectWallet.fromSeed(accountInfo.mnemonic);
70+
lucid.selectWallet.fromSeed(getUserMnemonic());
71+
lucid.wallet().address().then(console.log);
5972
const requestData = {
6073
asset_name: Buffer.from('WST', 'utf8').toString('hex'), // Convert "WST" to hex
61-
issuer: mintAccount.address,
74+
issuer: mintAccount.regular_address,
6275
quantity: sendTokenAmount,
6376
recipient: sendRecipientAddress,
64-
sender: accountInfo.address,
77+
sender: accountInfo.regular_address,
6578
submit_failing_tx: overrideTx
6679
};
6780
try {
@@ -78,17 +91,17 @@ export default function Profile() {
7891
const tx = await lucid.fromTx(response.data.cborHex);
7992
const txId = await signAndSentTx(lucid, tx);
8093
await updateAccountBalance(sendRecipientAddress);
81-
await updateAccountBalance(accountInfo.address);
82-
changeAlertInfo({severity: 'success', message: 'Transaction sent successfully!', open: true, link: `https://preview.cexplorer.io/tx/${txId}`});
94+
await updateAccountBalance(accountInfo.regular_address);
95+
changeAlertInfo({severity: 'success', message: 'Transaction sent successfully!', open: true, link: `${demoEnv.explorer_url}/${txId}`});
8396
} catch (error) {
8497
console.error('Send failed:', error);
8598
}
8699
};
87100

88101
const updateAccountBalance = async (address: string) => {
89-
const newAccountBalance = await getWalletBalance(address);
102+
const newAccountBalance = await getWalletBalance(demoEnv, address);
90103
const walletKey = (Object.keys(accounts) as (keyof Accounts)[]).find(
91-
(key) => accounts[key].address === address
104+
(key) => accounts[key].regular_address === address
92105
);
93106
if (walletKey) {
94107
changeWalletAccountDetails(walletKey, {
@@ -123,9 +136,9 @@ export default function Profile() {
123136

124137
const receiveContent = <Box>
125138
<CopyTextField
126-
value={getUserAccountDetails()?.address ?? ''}
139+
value={getUserAccountDetails()?.regular_address ?? ''}
127140
fullWidth={true}
128-
label="Your Address"
141+
label="Regular Address"
129142
/>
130143
</Box>;
131144

@@ -135,9 +148,9 @@ export default function Profile() {
135148
<Box>
136149
<Typography variant='h4'>Address Balance</Typography>
137150
<Typography variant='h1'>{getUserAccountDetails()?.balance.wst} WST</Typography>
138-
<Typography variant='h5'>{getUserAccountDetails()?.balance.ada} Ada</Typography>
151+
<Typography variant='h5'>{getUserAccountDetails()?.balance.ada} Ada { (getUserAccountDetails()?.balance.adaOnlyOutputs === 0) && (<span>({getUserAccountDetails()?.balance.adaOnlyOutputs} collateral UTxOs)</span>)}</Typography>
139152
</Box>
140-
<Typography variant='h5'>{getUserAccountDetails()?.address.slice(0,15)}</Typography>
153+
<Typography variant='h5'>{getUserAccountDetails()?.regular_address.slice(0,15)}</Typography>
141154
</Box>
142155
<div className="cardWrapperParent">
143156
<WalletCard tabs={[

frontend/src/app/clientLayout.tsx

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22
//React imports
3-
import React, { useEffect } from "react";
3+
import React, { useEffect, useState } from "react";
44

55
//Mui imports
66
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
@@ -13,24 +13,56 @@ import { makeLucid, getWalletFromSeed } from "./utils/walletUtils";
1313
import useStore from './store/store';
1414
import WSTAppBar from "./components/WSTAppBar";
1515
import AlertBar from './components/AlertBar';
16+
import { DemoEnvironment, previewEnv } from "./store/types";
17+
import axios from "axios";
18+
import DemoEnvironmentContext from "./context/demoEnvironmentContext";
19+
20+
async function loadDemoEnvironment(): Promise<DemoEnvironment> {
21+
const response = await axios.get<DemoEnvironment>("/api/v1/demo-environment",
22+
{
23+
headers: {
24+
'Content-Type': 'application/json;charset=utf-8',
25+
},
26+
});
27+
return response?.data;
28+
}
29+
30+
async function getProgrammableTokenAddress(regular_address: string) {
31+
const response = await axios.get<string>(`/api/v1/query/address/${regular_address}`,
32+
{
33+
headers: {
34+
'Content-Type': 'application/json;charset=utf-8',
35+
},
36+
});
37+
return response?.data;
38+
}
39+
1640

1741
export default function ClientLayout({ children }: { children: React.ReactNode }) {
1842
const { mintAccount, accounts, changeMintAccountDetails, changeWalletAccountDetails, setLucidInstance } = useStore();
43+
const [demoEnv, setDemoEnv] = useState<DemoEnvironment>(previewEnv);
1944

2045
useEffect(() => {
2146
const fetchUserWallets = async () => {
2247
try {
48+
const demoEnv = await loadDemoEnvironment();
49+
console.log("DemoEnvironment:", demoEnv);
50+
setDemoEnv(demoEnv);
51+
2352
// retrieve wallet info
24-
const mintAuthorityWallet = await getWalletFromSeed(mintAccount.mnemonic);
25-
const walletA = await getWalletFromSeed(accounts.alice.mnemonic);
26-
const walletB = await getWalletFromSeed(accounts.bob.mnemonic);
53+
const mintAuthorityWallet = await getWalletFromSeed(demoEnv, demoEnv.mint_authority);
54+
const walletA = await getWalletFromSeed(demoEnv, demoEnv.user_a);
55+
const walletB = await getWalletFromSeed(demoEnv, demoEnv.user_b);
56+
const walletATokenAddr = await getProgrammableTokenAddress(walletA.address);
57+
const walletBTokenAddr = await getProgrammableTokenAddress(walletB.address);
58+
const mintAuthorityTokenAddr = await getProgrammableTokenAddress(mintAuthorityWallet.address);
2759

2860
// Update Zustand store with the initialized wallet information
29-
changeMintAccountDetails({ ...mintAccount, address: mintAuthorityWallet.address});
30-
changeWalletAccountDetails('alice', { ...accounts.alice, address: walletA.address},);
31-
changeWalletAccountDetails('bob', { ...accounts.bob, address: walletB.address});
61+
changeMintAccountDetails({ ...mintAccount, regular_address: mintAuthorityWallet.address, programmable_token_address: mintAuthorityTokenAddr});
62+
changeWalletAccountDetails('alice', { ...accounts.alice, regular_address: walletA.address, programmable_token_address: walletATokenAddr},);
63+
changeWalletAccountDetails('bob', { ...accounts.bob, regular_address: walletB.address, programmable_token_address: walletBTokenAddr});
3264

33-
const initialLucid = await makeLucid();
65+
const initialLucid = await makeLucid(demoEnv);
3466
setLucidInstance(initialLucid);
3567
console.log('Wallets initialized');
3668
} catch (error) {
@@ -41,7 +73,7 @@ export default function ClientLayout({ children }: { children: React.ReactNode }
4173
fetchUserWallets();
4274
},[]);
4375

44-
if(accounts.bob.address === '') {
76+
if(accounts.bob.regular_address === '') {
4577
return <div className="mainLoadingContainer">
4678
<div className="mainLoader" />
4779
</div>;
@@ -50,12 +82,14 @@ export default function ClientLayout({ children }: { children: React.ReactNode }
5082
return (
5183
<AppRouterCacheProvider>
5284
<ThemeModeProvider>
85+
<DemoEnvironmentContext.Provider value={demoEnv}>
5386
<main>
5487
<WSTAppBar />
5588
<NavDrawer />
5689
<div className="contentSection">{children}</div>
5790
<AlertBar/>
5891
</main>
92+
</DemoEnvironmentContext.Provider>
5993
</ThemeModeProvider>
6094
</AppRouterCacheProvider>
6195
);

frontend/src/app/components/ProfileSwitcher.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
1616
import useStore from '../store/store';
1717
import { UserName } from '../store/types';
1818
import { selectLucidWallet, getWalletBalance } from '../utils/walletUtils';
19+
import DemoEnvironmentContext from '../context/demoEnvironmentContext';
1920

2021
export default function ProfileSwitcher() {
2122
const [anchorEl, setAnchorEl] = React.useState<HTMLElement | null>(null);
2223
const { currentUser, accounts, changeWalletAccountDetails } = useStore();
2324
const lucid = useStore(state => state.lucid);
2425
const changeUserAccount = useStore(state => state.changeUserAccount);
2526
const router = useRouter();
27+
const demoContext = React.useContext(DemoEnvironmentContext);
2628

2729
React.useEffect(() => {
2830
// Check the current path and redirect if the currentUser doesn't match
@@ -62,10 +64,10 @@ export default function ProfileSwitcher() {
6264
const handleWalletConnect = async (user: UserName) => {
6365
await selectLucidWallet(lucid, "Lace");
6466
const userAddress = await lucid.wallet().address();
65-
const userBalance = await getWalletBalance(userAddress);
67+
const userBalance = await getWalletBalance(demoContext, userAddress);
6668
changeWalletAccountDetails('walletUser', {
6769
...accounts.walletUser,
68-
address: userAddress,
70+
regular_address: userAddress,
6971
balance: userBalance,
7072
});
7173
handleSelect(user);

frontend/src/app/components/WSTAppBar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ export default function WSTAppBar() {
1919
src="/assets/WST_logo.png"
2020
width={53}
2121
height={39}
22-
alt="Logo for Wyoming Stable Token"
22+
alt="Logo for WST"
2323
/>
24-
<Typography variant='h3'>Wyoming Stable Token</Typography>
24+
<Typography variant='h3'>CIP-0143 Progammable Token Demo</Typography>
2525
</Box>
2626
<ProfileSwitcher />
2727
</Toolbar>

frontend/src/app/components/WSTTable.tsx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,22 @@ import ContentCopyIcon from '@mui/icons-material/ContentCopy';
1616

1717
//Local Imports
1818
import useStore from '../store/store';
19-
import { useEffect } from "react";
19+
import { useContext, useEffect } from "react";
2020
import IconButton from './WSTIconButton';
21+
import DemoEnvironmentContext from "../context/demoEnvironmentContext";
2122

22-
const progLogicBase : LucidCredential = {
23-
type: "Script",
24-
hash: "fca77bcce1e5e73c97a0bfa8c90f7cd2faff6fd6ed5b6fec1c04eefa"
25-
}
26-
27-
const stableCoin : Unit = toUnit("b34a184f1f2871aa4d33544caecefef5242025f45c3fa5213d7662a9", "575354")
2823

2924

3025
export default function WSTTable() {
3126
const { lucid, accounts } = useStore();
3227
const accountArray = Object.values(accounts);
28+
const demoEnv = useContext(DemoEnvironmentContext);
29+
const stableCoin : Unit = toUnit(demoEnv.minting_policy, demoEnv.token_name);
30+
31+
const progLogicBase : LucidCredential = {
32+
type: "Script",
33+
hash: demoEnv.prog_logic_base_hash
34+
}
3335

3436
const getAccounts = async () => {
3537
const progUTxOs : UTxO[] = await lucid.utxosAtWithUnit(progLogicBase, stableCoin);
@@ -55,18 +57,23 @@ export default function WSTTable() {
5557
<Table size="small" aria-label="simple table" stickyHeader>
5658
<TableHead>
5759
<TableRow>
58-
<TableCell>Address</TableCell>
60+
<TableCell>Regular Address</TableCell>
61+
<TableCell>Programmable Address</TableCell>
5962
<TableCell>Address Status</TableCell>
6063
<TableCell align="right">Address Balance</TableCell>
6164
</TableRow>
6265
</TableHead>
6366
<TableBody>
6467
{
65-
accountArray.filter((acct) => acct.address !== "").map((acct, i) => (
68+
accountArray.filter((acct) => acct.regular_address !== "").map((acct, i) => (
6669
<TableRow key={i}>
6770
<TableCell>
68-
{`${acct?.address.slice(0,15)}...${acct?.address.slice(104,108)}`}
69-
<IconButton onClick={() => copyToClipboard(acct.address)} icon={<ContentCopyIcon />}/>
71+
{`${acct?.regular_address.slice(0,15)}...${acct?.regular_address.slice(104,108)}`}
72+
<IconButton onClick={() => copyToClipboard(acct.regular_address)} icon={<ContentCopyIcon />}/>
73+
</TableCell>
74+
<TableCell>
75+
{`${acct?.programmable_token_address.slice(0,15)}...${acct?.programmable_token_address.slice(104,108)}`}
76+
<IconButton onClick={() => copyToClipboard(acct.programmable_token_address)} icon={<ContentCopyIcon />}/>
7077
</TableCell>
7178
<TableCell sx={{color: acct.status === 'Frozen' ? 'error.main' : 'success.main', fontWeight: '500'}}>
7279
{acct.status}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { createContext } from "react";
2+
import { DemoEnvironment, previewEnv } from "../store/types";
3+
4+
const DemoEnvironmentContext = createContext<DemoEnvironment>(previewEnv);
5+
6+
export default DemoEnvironmentContext;

frontend/src/app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import "./styles/globals.css";
66
import ClientLayout from "./clientLayout";
77

88
export const metadata: Metadata = {
9-
title: "Wyoming Stable Token",
9+
title: "WST - Programmable token demonstration",
1010
description: "Created by the djed team at IOG",
1111
};
1212

0 commit comments

Comments
 (0)