diff --git a/frontend/src/app/[username]/index.tsx b/frontend/src/app/[username]/index.tsx index e7fbe92..4b25181 100644 --- a/frontend/src/app/[username]/index.tsx +++ b/frontend/src/app/[username]/index.tsx @@ -71,10 +71,10 @@ export default function Profile() { lucid.wallet().address().then(console.log); const requestData = { asset_name: Buffer.from('WST', 'utf8').toString('hex'), // Convert "WST" to hex - issuer: mintAccount.address, + issuer: mintAccount.regular_address, quantity: sendTokenAmount, recipient: sendRecipientAddress, - sender: accountInfo.address, + sender: accountInfo.regular_address, submit_failing_tx: overrideTx }; try { @@ -91,7 +91,7 @@ export default function Profile() { const tx = await lucid.fromTx(response.data.cborHex); const txId = await signAndSentTx(lucid, tx); await updateAccountBalance(sendRecipientAddress); - await updateAccountBalance(accountInfo.address); + await updateAccountBalance(accountInfo.regular_address); changeAlertInfo({severity: 'success', message: 'Transaction sent successfully!', open: true, link: `${demoEnv.explorer_url}/${txId}`}); } catch (error) { console.error('Send failed:', error); @@ -101,7 +101,7 @@ export default function Profile() { const updateAccountBalance = async (address: string) => { const newAccountBalance = await getWalletBalance(demoEnv, address); const walletKey = (Object.keys(accounts) as (keyof Accounts)[]).find( - (key) => accounts[key].address === address + (key) => accounts[key].regular_address === address ); if (walletKey) { changeWalletAccountDetails(walletKey, { @@ -136,9 +136,9 @@ export default function Profile() { const receiveContent = ; @@ -150,7 +150,7 @@ export default function Profile() { {getUserAccountDetails()?.balance.wst} WST {getUserAccountDetails()?.balance.ada} Ada { (getUserAccountDetails()?.balance.adaOnlyOutputs === 0) && (({getUserAccountDetails()?.balance.adaOnlyOutputs} collateral UTxOs))} - {getUserAccountDetails()?.address.slice(0,15)} + {getUserAccountDetails()?.regular_address.slice(0,15)}
{ return response?.data; } +async function getProgrammableTokenAddress(regular_address: string) { + const response = await axios.get(`/api/v1/query/address/${regular_address}`, + { + headers: { + 'Content-Type': 'application/json;charset=utf-8', + }, + }); + return response?.data; +} + + export default function ClientLayout({ children }: { children: React.ReactNode }) { const { mintAccount, accounts, changeMintAccountDetails, changeWalletAccountDetails, setLucidInstance } = useStore(); const [demoEnv, setDemoEnv] = useState(previewEnv); @@ -39,14 +50,17 @@ export default function ClientLayout({ children }: { children: React.ReactNode } setDemoEnv(demoEnv); // retrieve wallet info - const mintAuthorityWallet = await getWalletFromSeed(demoEnv.mint_authority); - const walletA = await getWalletFromSeed(demoEnv.user_a); - const walletB = await getWalletFromSeed(demoEnv.user_b); + const mintAuthorityWallet = await getWalletFromSeed(demoEnv, demoEnv.mint_authority); + const walletA = await getWalletFromSeed(demoEnv, demoEnv.user_a); + const walletB = await getWalletFromSeed(demoEnv, demoEnv.user_b); + const walletATokenAddr = await getProgrammableTokenAddress(walletA.address); + const walletBTokenAddr = await getProgrammableTokenAddress(walletB.address); + const mintAuthorityTokenAddr = await getProgrammableTokenAddress(mintAuthorityWallet.address); // Update Zustand store with the initialized wallet information - changeMintAccountDetails({ ...mintAccount, address: mintAuthorityWallet.address}); - changeWalletAccountDetails('alice', { ...accounts.alice, address: walletA.address},); - changeWalletAccountDetails('bob', { ...accounts.bob, address: walletB.address}); + changeMintAccountDetails({ ...mintAccount, regular_address: mintAuthorityWallet.address, programmable_token_address: mintAuthorityTokenAddr}); + changeWalletAccountDetails('alice', { ...accounts.alice, regular_address: walletA.address, programmable_token_address: walletATokenAddr},); + changeWalletAccountDetails('bob', { ...accounts.bob, regular_address: walletB.address, programmable_token_address: walletBTokenAddr}); const initialLucid = await makeLucid(demoEnv); setLucidInstance(initialLucid); @@ -59,7 +73,7 @@ export default function ClientLayout({ children }: { children: React.ReactNode } fetchUserWallets(); },[]); - if(accounts.bob.address === '') { + if(accounts.bob.regular_address === '') { return
; diff --git a/frontend/src/app/components/WSTTable.tsx b/frontend/src/app/components/WSTTable.tsx index 612c7f6..86344c7 100644 --- a/frontend/src/app/components/WSTTable.tsx +++ b/frontend/src/app/components/WSTTable.tsx @@ -57,18 +57,23 @@ export default function WSTTable() { - Address + Regular Address + Programmable Address Address Status Address Balance { - accountArray.filter((acct) => acct.address !== "").map((acct, i) => ( + accountArray.filter((acct) => acct.regular_address !== "").map((acct, i) => ( - {`${acct?.address.slice(0,15)}...${acct?.address.slice(104,108)}`} - copyToClipboard(acct.address)} icon={}/> + {`${acct?.regular_address.slice(0,15)}...${acct?.regular_address.slice(104,108)}`} + copyToClipboard(acct.regular_address)} icon={}/> + + + {`${acct?.programmable_token_address.slice(0,15)}...${acct?.programmable_token_address.slice(104,108)}`} + copyToClipboard(acct.programmable_token_address)} icon={}/> {acct.status} diff --git a/frontend/src/app/mint-authority/page.tsx b/frontend/src/app/mint-authority/page.tsx index 3183c9e..f846c9d 100644 --- a/frontend/src/app/mint-authority/page.tsx +++ b/frontend/src/app/mint-authority/page.tsx @@ -51,9 +51,9 @@ export default function Home() { }, [demoEnv]); const fetchUserDetails = async () => { - const mintBalance = await getWalletBalance(demoEnv, mintAccount.address); - const userABalance = await getWalletBalance(demoEnv, accounts.alice.address); - const userBBalance = await getWalletBalance(demoEnv, accounts.bob.address); + const mintBalance = await getWalletBalance(demoEnv, mintAccount.regular_address); + const userABalance = await getWalletBalance(demoEnv, accounts.alice.regular_address); + const userBBalance = await getWalletBalance(demoEnv, accounts.bob.regular_address); // Update Zustand store with the initialized wallet information await changeMintAccountDetails({ ...mintAccount, balance: mintBalance}); @@ -66,11 +66,11 @@ export default function Home() { const { accounts, changeWalletAccountDetails } = useStore.getState(); Object.entries(accounts).map(async ([key, account]) => { - if (!account.address || account.address.trim() === "") { + if (!account.regular_address || account.regular_address.trim() === "") { // console.log(`${key} has no address yet, skipping`); return; } - const credential : LucidCredential = await paymentCredentialOf(account.address); + const credential : LucidCredential = await paymentCredentialOf(account.regular_address); if(blacklist.includes(credential.hash)) { // console.log('a match was found', key as keyof typeof accounts); changeWalletAccountDetails(key as keyof typeof accounts, { ...account, status: 'Frozen',}); @@ -92,7 +92,7 @@ export default function Home() { lucid.selectWallet.fromSeed(demoEnv.mint_authority); const requestData = { asset_name: Buffer.from('WST', 'utf8').toString('hex'), // Convert "WST" to hex - issuer: mintAccount.address, + issuer: mintAccount.regular_address, quantity: mintTokensAmount, recipient: mintRecipientAddress }; @@ -125,10 +125,10 @@ export default function Home() { changeAlertInfo({severity: 'info', message: 'Transaction processing', open: true, link: ''}); const requestData = { asset_name: Buffer.from('WST', 'utf8').toString('hex'), // Convert "WST" to hex - issuer: mintAccount.address, + issuer: mintAccount.regular_address, quantity: sendTokensAmount, recipient: sendRecipientAddress, - sender: mintAccount.address, + sender: mintAccount.regular_address, }; try { const response = await axios.post( @@ -145,7 +145,7 @@ export default function Home() { const txId = await signAndSentTx(lucid, tx); const newAccountBalance = await getWalletBalance(demoEnv, sendRecipientAddress); const recipientWalletKey = (Object.keys(accounts) as (keyof Accounts)[]).find( - (key) => accounts[key].address === sendRecipientAddress + (key) => accounts[key].regular_address === sendRecipientAddress ); if (recipientWalletKey) { changeWalletAccountDetails(recipientWalletKey, { @@ -165,7 +165,7 @@ export default function Home() { lucid.selectWallet.fromSeed(demoEnv.mint_authority); changeAlertInfo({severity: 'info', message: 'Freeze request processing', open: true, link: ''}); const requestData = { - issuer: mintAccount.address, + issuer: mintAccount.regular_address, blacklist_address: freezeAccountNumber, reason: freezeReason, }; @@ -185,7 +185,7 @@ export default function Home() { console.log(txId); changeAlertInfo({severity: 'success', message: 'Address successfully frozen', open: true, link: `${demoEnv.explorer_url}/${txId}`}); const frozenWalletKey = (Object.keys(accounts) as (keyof Accounts)[]).find( - (key) => accounts[key].address === freezeAccountNumber + (key) => accounts[key].regular_address === freezeAccountNumber ); if (frozenWalletKey) { changeWalletAccountDetails(frozenWalletKey, { @@ -212,7 +212,7 @@ export default function Home() { lucid.selectWallet.fromSeed(demoEnv.mint_authority); changeAlertInfo({severity: 'info', message: 'Unfreeze request processing', open: true, link: ''}); const requestData = { - issuer: mintAccount.address, + issuer: mintAccount.regular_address, blacklist_address: unfreezeAccountNumber, reason: "(unfreeze)" }; @@ -231,7 +231,7 @@ export default function Home() { const txId = await signAndSentTx(lucid, tx); changeAlertInfo({severity: 'success', message: 'Address successfully unfrozen', open: true, link: `${demoEnv.explorer_url}/${txId}`}); const unfrozenWalletKey = (Object.keys(accounts) as (keyof Accounts)[]).find( - (key) => accounts[key].address === freezeAccountNumber + (key) => accounts[key].regular_address === freezeAccountNumber ); if (unfrozenWalletKey) { changeWalletAccountDetails(unfrozenWalletKey, { @@ -258,7 +258,7 @@ export default function Home() { lucid.selectWallet.fromSeed(demoEnv.mint_authority); changeAlertInfo({severity: 'info', message: 'WST seizure processing', open: true, link: ''}); const requestData = { - issuer: mintAccount.address, + issuer: mintAccount.regular_address, target: seizeAccountNumber, reason: seizeReason, }; @@ -277,7 +277,7 @@ export default function Home() { const txId = await signAndSentTx(lucid, tx); const newAccountBalance = await getWalletBalance(demoEnv, seizeAccountNumber); const seizeWalletKey = (Object.keys(accounts) as (keyof Accounts)[]).find( - (key) => accounts[key].address === seizeAccountNumber + (key) => accounts[key].regular_address === seizeAccountNumber ); if (seizeWalletKey) { changeWalletAccountDetails(seizeWalletKey, { @@ -374,7 +374,7 @@ maxRows={3} const receiveContent = @@ -390,7 +390,7 @@ maxRows={3} {mintAccount.balance.wst} WST {mintAccount.balance.ada} Ada { (mintAccount.balance.adaOnlyOutputs === 0) && (({mintAccount.balance.adaOnlyOutputs} collateral UTxOs))} - UserID: {mintAccount.address.slice(0,15)} + UserID: {mintAccount.regular_address.slice(0,15)}
((set) => ({ mintAccount: { name: 'Mint Authority', - address: 'addr_test1qq986m3uel86pl674mkzneqtycyg7csrdgdxj6uf7v7kd857kquweuh5kmrj28zs8czrwkl692jm67vna2rf7xtafhpqk3hecm', + regular_address: '', + programmable_token_address: '', balance: {ada: 0, wst: 0, adaOnlyOutputs: 0}, }, accounts: { alice: { - address: '', + regular_address: '', + programmable_token_address: '', balance: {ada: 0, wst: 0, adaOnlyOutputs: 0}, status: 'Active', }, bob: { - address: '', + regular_address: '', + programmable_token_address: '', balance: {ada: 0, wst: 0, adaOnlyOutputs: 0}, status: 'Active', }, walletUser: { - address: '', + regular_address: '', + programmable_token_address: '', balance: {ada: 0, wst: 0, adaOnlyOutputs: 0}, status: 'Active', }, @@ -83,7 +87,7 @@ const useStore = create((set) => ({ firstAccessibleTab = 'Wallet'; break; case 'Connected Wallet': - if (useStore.getState().accounts.walletUser.address === useStore.getState().mintAccount.address) + if (useStore.getState().accounts.walletUser.regular_address === useStore.getState().mintAccount.regular_address) firstAccessibleTab = 'Mint Actions'; else firstAccessibleTab = 'Wallet'; diff --git a/frontend/src/app/store/types.ts b/frontend/src/app/store/types.ts index b33988f..9863724 100644 --- a/frontend/src/app/store/types.ts +++ b/frontend/src/app/store/types.ts @@ -3,7 +3,8 @@ export type MenuTab = 'Mint Actions' | 'Addresses' | 'Wallet'; import { Network } from "@lucid-evolution/lucid"; export type AccountInfo = { - address: string, + regular_address: string, + programmable_token_address: string, balance: WalletBalance, status?: 'Active' | 'Frozen', }; diff --git a/frontend/src/app/utils/walletUtils.ts b/frontend/src/app/utils/walletUtils.ts index c2ef608..8a18c0b 100644 --- a/frontend/src/app/utils/walletUtils.ts +++ b/frontend/src/app/utils/walletUtils.ts @@ -19,9 +19,9 @@ export async function makeLucid(demoEnvironment: DemoEnvironment) { return lucid; } -export async function getWalletFromSeed(mnemonic: string) { +export async function getWalletFromSeed(demoEnvironment: DemoEnvironment, mnemonic: string) { try { - const wallet = walletFromSeed(mnemonic, {password: '', addressType: 'Base', accountIndex: 0, network: "Preview"}); + const wallet = walletFromSeed(mnemonic, {password: '', addressType: 'Base', accountIndex: 0, network: demoEnvironment.network }); return wallet; } catch (error) { console.error('Failed to initialize KeyAgent:', error); @@ -54,7 +54,7 @@ export async function getWalletBalance(demoEnv: DemoEnvironment, address: string return {wst: stableBalance, ada: response.data.user_lovelace / 1000000, adaOnlyOutputs: response.data.ada_only_outputs }; } catch (error) { - console.error('Failed to get balance', error); + console.warn('Failed to get balance', error); return { wst: 0, ada: 0, adaOnlyOutputs: 0}; } } @@ -227,6 +227,7 @@ export function adjustMintOutput(demoEnv: DemoEnvironment, tx: CML.Transaction, export async function deriveProgrammableAddress(demoEnv: DemoEnvironment, lucid: LucidEvolution, userAddress: Address){ const network = lucid.config().network!; + console.log("Network", network, demoEnv.network); // user's payment credential const ownerCred : LucidCredential = paymentCredentialOf(userAddress); diff --git a/src/exe/calculate-hashes/Main.hs b/src/exe/calculate-hashes/Main.hs new file mode 100644 index 0000000..e261afa --- /dev/null +++ b/src/exe/calculate-hashes/Main.hs @@ -0,0 +1,79 @@ +{-# LANGUAGE OverloadedStrings #-} +{-| Calculate the script hashes for a WST deployment +-} +module Main (main) where + +import Cardano.Api.Shelley qualified as C +import Cardano.Ledger.BaseTypes qualified as Ledger +import Data.Aeson qualified as Aeson +import Data.ByteString.Lazy qualified as BSL +import Data.Proxy (Proxy (..)) +import Data.Text qualified as Text +import System.Environment qualified +import System.Exit (exitFailure) +import Wst.Offchain.Env (DirectoryScriptRoot (..)) +import Wst.Offchain.Env qualified as Env + +main :: IO () +main = System.Environment.getArgs >>= \case + [fp, addr] -> do + putStrLn $ "Calculating hashes using " <> fp <> " with adddress " <> addr + operator <- decodeAddress addr + (nid, pkh) <- paymentHashAndNetworkId operator + dirEnv <- Env.mkDirectoryEnv <$> loadFromFile fp + let transferLogicEnv = Env.mkTransferLogicEnv + $ Env.BlacklistTransferLogicScriptRoot + (srTarget $ Env.dsScriptRoot dirEnv) + dirEnv + pkh + + printAssetId dirEnv transferLogicEnv "WST" + printTransferLogicAddress nid transferLogicEnv + printBaseCredential dirEnv + _ -> do + putStrLn "Usage: calculate-hashes DEPLOYMENT_ROOT_FILE_PATH ISSUER_ADDRESS" + exitFailure + +loadFromFile :: FilePath -> IO DirectoryScriptRoot +loadFromFile fp = do + fmap Aeson.decode (BSL.readFile fp) >>= \case + Nothing -> error "failed to decode JSON" + Just a -> pure a + +decodeAddress :: String -> IO (C.Address C.ShelleyAddr) +decodeAddress str = case C.deserialiseAddress (C.proxyToAsType Proxy) (Text.pack str) of + Nothing -> error "failed to deserialise address" + Just a -> pure a + +paymentHashAndNetworkId :: C.Address C.ShelleyAddr -> IO (C.NetworkId, C.Hash C.PaymentKey) +paymentHashAndNetworkId = \case + (C.ShelleyAddress network (C.fromShelleyPaymentCredential -> C.PaymentCredentialByKey pkh) _) -> pure (fromLedgerNetwork network, pkh) + _ -> error "expected public key address" + +printAssetId :: Env.DirectoryEnv -> Env.TransferLogicEnv -> C.AssetName -> IO () +printAssetId dirEnv transferLogicEnv = + print . Env.programmableTokenAssetId dirEnv transferLogicEnv + +printTransferLogicAddress :: C.NetworkId -> Env.TransferLogicEnv -> IO () +printTransferLogicAddress nid env = do + let spendingScript = Env.tleBlacklistSpendingScript env + spendingHash = C.hashScript $ C.PlutusScript C.PlutusScriptV3 spendingScript + addr = C.makeShelleyAddressInEra C.ShelleyBasedEraConway nid (C.PaymentCredentialByScript spendingHash) C.NoStakeAddress + print $ C.serialiseAddress addr + +fromLedgerNetwork :: Ledger.Network -> C.NetworkId +fromLedgerNetwork = \case + Ledger.Mainnet -> C.Mainnet + Ledger.Testnet -> C.Testnet (C.NetworkMagic 42) -- ??? + +printBaseCredential :: Env.DirectoryEnv -> IO () +printBaseCredential = + print . Env.programmableLogicBaseCredential + +-- token_name +-- prog_logic_base_hash + + -- spendingScript <- asks (Env.tleBlacklistSpendingScript . Env.transferLogicEnv) + -- let policyId = scriptPolicyIdV3 mintingScript + -- spendingHash = C.hashScript $ C.PlutusScript C.PlutusScriptV3 spendingScript + -- addr = C.makeShelleyAddressInEra C.shelleyBasedEra nid (C.PaymentCredentialByScript spendingHash) C.NoStakeAddress diff --git a/src/lib/Wst/Cli.hs b/src/lib/Wst/Cli.hs index 7e9edda..fd7a9f2 100644 --- a/src/lib/Wst/Cli.hs +++ b/src/lib/Wst/Cli.hs @@ -51,7 +51,9 @@ runCommand com = do -- TODO: status check (call the query endpoints and print out a summary of the results) logInfo "Manage" StartServer options -> - Server.staticFilesFromEnv options >>= startServer env' + Server.staticFilesFromEnv options >>= + Server.demoFileFromEnv >>= + startServer env' case result of Left err -> runLoggerLoggingT env $ logError (fromString $ show err) Right a -> pure a diff --git a/src/lib/Wst/Cli/Command.hs b/src/lib/Wst/Cli/Command.hs index 3e3326e..91e39b4 100644 --- a/src/lib/Wst/Cli/Command.hs +++ b/src/lib/Wst/Cli/Command.hs @@ -66,6 +66,7 @@ parseServerArgs = ServerArgs <$> option auto (help "The port" <> value 8080 <> long "port" <> short 'p') <*> optional (strOption (help "Folder to serve static files from" <> long "static-files")) + <*> optional (strOption (help "JSON file with demo environment" <> long "demo-environment")) parseTxIn :: Parser TxIn parseTxIn = diff --git a/src/lib/Wst/Server.hs b/src/lib/Wst/Server.hs index a36e642..aeb55dd 100644 --- a/src/lib/Wst/Server.hs +++ b/src/lib/Wst/Server.hs @@ -8,6 +8,7 @@ module Wst.Server( runServer, ServerArgs(..), staticFilesFromEnv, + demoFileFromEnv, CombinedAPI, defaultServerArgs ) where @@ -28,6 +29,7 @@ import Data.Aeson.Types (KeyValue) import Data.Data (Proxy (..)) import Data.List (nub) import Data.Map qualified as Map +import Data.Maybe (fromMaybe) import Network.Wai.Handler.Warp qualified as Warp import Network.Wai.Middleware.Cors import PlutusTx.Prelude qualified as P @@ -45,6 +47,7 @@ import Wst.Offchain.Env qualified as Env import Wst.Offchain.Query (UTxODat (uDatum)) import Wst.Offchain.Query qualified as Query import Wst.Server.DemoEnvironment (DemoEnvRoute, runDemoEnvRoute) +import Wst.Server.DemoEnvironment qualified as DemoEnvironment import Wst.Server.Types (APIInEra, AddVKeyWitnessArgs (..), BlacklistNodeArgs (..), BuildTxAPI, IssueProgrammableTokenArgs (..), QueryAPI, @@ -63,7 +66,8 @@ type CombinedAPI = data ServerArgs = ServerArgs { saPort :: !Int - , saStaticFiles :: Maybe FilePath + , saStaticFiles :: Maybe FilePath + , saDemoEnvironmentFile :: Maybe FilePath } deriving stock (Eq, Show) @@ -77,20 +81,31 @@ staticFilesFromEnv sa@ServerArgs{saStaticFiles} = case saStaticFiles of files' <- liftIO (System.Environment.lookupEnv "WST_STATIC_FILES") pure sa{saStaticFiles = files'} +demoFileFromEnv :: MonadIO m => ServerArgs -> m ServerArgs +demoFileFromEnv sa@ServerArgs{saDemoEnvironmentFile} = case saDemoEnvironmentFile of + Just _ -> pure sa + Nothing -> do + files' <- liftIO (System.Environment.lookupEnv "WST_DEMO_ENV") + pure sa{saDemoEnvironmentFile = files'} + defaultServerArgs :: ServerArgs defaultServerArgs = ServerArgs { saPort = 8080 , saStaticFiles = Nothing + , saDemoEnvironmentFile = Nothing } runServer :: (Env.HasRuntimeEnv env, Env.HasDirectoryEnv env, HasLogger env) => env -> ServerArgs -> IO () -runServer env ServerArgs{saPort, saStaticFiles} = do +runServer env ServerArgs{saPort, saStaticFiles, saDemoEnvironmentFile} = do let bf = Blockfrost.projectId $ Env.envBlockfrost $ Env.runtimeEnv env - app = cors (const $ Just simpleCorsResourcePolicy) + demoEnv <- + fromMaybe (DemoEnvironment.previewNetworkDemoEnvironment bf) + <$> traverse DemoEnvironment.loadFromFile saDemoEnvironmentFile + let app = cors (const $ Just simpleCorsResourcePolicy) $ case saStaticFiles of Nothing -> serve (Proxy @APIInEra) (server env) - Just fp -> serve (Proxy @CombinedAPI) (server env :<|> runDemoEnvRoute bf :<|> serveDirectoryWebApp fp) + Just fp -> serve (Proxy @CombinedAPI) (server env :<|> runDemoEnvRoute demoEnv :<|> serveDirectoryWebApp fp) port = saPort Warp.run port app diff --git a/src/lib/Wst/Server/DemoEnvironment.hs b/src/lib/Wst/Server/DemoEnvironment.hs index 1cb79fe..469552b 100644 --- a/src/lib/Wst/Server/DemoEnvironment.hs +++ b/src/lib/Wst/Server/DemoEnvironment.hs @@ -7,13 +7,17 @@ module Wst.Server.DemoEnvironment( DemoEnvRoute, DemoEnvironment(..), runDemoEnvRoute, - previewNetworkDemoEnvironment + previewNetworkDemoEnvironment, + loadFromFile, + writeToFile, ) where import Cardano.Api qualified as C import Control.Lens ((&), (?~)) import Data.Aeson (FromJSON (..), ToJSON (..)) +import Data.Aeson qualified as Aeson import Data.Aeson qualified as JSON +import Data.ByteString.Lazy qualified as BSL import Data.OpenApi (OpenApiType (OpenApiString), ToParamSchema (..), ToSchema (..)) import Data.OpenApi.Lens qualified as L @@ -32,8 +36,8 @@ import Wst.Server.Types (SerialiseAddress (..)) -} type DemoEnvRoute = "api" :> "v1" :> "demo-environment" :> Get '[JSON] DemoEnvironment -runDemoEnvRoute :: Applicative m => Text -> ServerT DemoEnvRoute m -runDemoEnvRoute = pure . previewNetworkDemoEnvironment +runDemoEnvRoute :: Applicative m => DemoEnvironment -> ServerT DemoEnvRoute m +runDemoEnvRoute = pure {-| Seed phrase -} @@ -110,3 +114,13 @@ previewNetworkDemoEnvironment daBlockfrostKey jsonOptions2 :: JSON.Options jsonOptions2 = JSON.customJsonOptions 2 + +loadFromFile :: FilePath -> IO DemoEnvironment +loadFromFile fp = do + putStrLn $ "Loading demo env from file: " <> fp + fmap Aeson.decode (BSL.readFile fp) >>= \case + Nothing -> error "failed to decode JSON" + Just a -> pure a + +writeToFile :: FilePath -> DemoEnvironment -> IO () +writeToFile fp = BSL.writeFile fp . Aeson.encode diff --git a/src/wst-poc.cabal b/src/wst-poc.cabal index 7e4bb42..13a8b77 100644 --- a/src/wst-poc.cabal +++ b/src/wst-poc.cabal @@ -100,6 +100,7 @@ library , blockfrost-api , blockfrost-client , blockfrost-client-core + , bytestring , cardano-api , cardano-ledger-shelley , containers @@ -149,6 +150,20 @@ executable convert-key , convex-wallet , text +executable calculate-hashes + import: lang + main-is: Main.hs + hs-source-dirs: exe/calculate-hashes + ghc-options: -threaded -rtsopts -O2 -with-rtsopts=-N + build-depends: + , aeson + , base + , bytestring + , cardano-api + , cardano-ledger-core + , text + , wst-poc + executable export-smart-tokens import: lang main-is: Main.hs