diff --git a/README.md b/README.md index 91f2e2b..fe5f1c3 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ await window.ethereum.request({ snapId: 'npm:@cosmsnap/snap', request: { method: 'addChain', - param: { + params: { chain_info: JSON.stringify(chainInfo), } }, @@ -106,7 +106,7 @@ const chain = await window.ethereum.request({ snapId: 'npm:@cosmsnap/snap', request: { method: 'deleteChain', - param: { + params: { chain_id: 'cosmoshub-4', } }, @@ -142,7 +142,48 @@ const address = await window.ethereum.request({ snapId: 'npm:@cosmsnap/snap', request: { method: 'transact', - param: { + params: { + chain_id: 'cosmoshub-4', + msgs: JSON.stringify(msgs), + // Optional: Uses default fees for chain if not specified + fees: JSON.stringify(fees) + } + }, + }, +}); +``` + +## Sign Transaction +This will sign the transaction and return the transaction bytes. +NOTE: This does not broadcast the transaction. +```javascript +const msgs = [ + { + typeUrl: "/cosmos.bank.v1beta1.MsgSend", + value: { + fromAddress: senderAddress, + toAddress: recipientAddress, + amount: [{ + denom: "uatom", + amount: "500000" + }], + }, + } +]; +const fees = { + amount: [{ + denom: "uatom", + amount: "500" + }], + gas: "200000" +}; +const address = await window.ethereum.request({ + method: 'wallet_invokeSnap', + params: { + snapId: 'npm:@cosmsnap/snap', + request: { + method: 'signTx', + params: { chain_id: 'cosmoshub-4', msgs: JSON.stringify(msgs), // Optional: Uses default fees for chain if not specified @@ -161,7 +202,7 @@ const address = await window.ethereum.request({ snapId: 'npm:@cosmsnap/snap', request: { method: 'addAddress', - param: { + params: { chain_id: 'cosmoshub-4', address: 'cosmos123456789', name: 'John Cosmos' @@ -208,7 +249,7 @@ const address = await window.ethereum.request({ snapId: 'npm:@cosmsnap/snap', request: { method: 'getChainAddress', - param: { + params: { chain_id: 'cosmoshub-4', } }, diff --git a/packages/snap/README.md b/packages/snap/README.md index 1202a88..14b335e 100644 --- a/packages/snap/README.md +++ b/packages/snap/README.md @@ -63,7 +63,7 @@ await window.ethereum.request({ snapId: 'npm:@cosmsnap/snap', request: { method: 'addChain', - param: { + params: { chain_info: JSON.stringify(chainInfo), } }, @@ -92,7 +92,7 @@ const chain = await window.ethereum.request({ snapId: 'npm:@cosmsnap/snap', request: { method: 'deleteChain', - param: { + params: { chain_id: 'cosmoshub-4', } }, @@ -101,6 +101,7 @@ const chain = await window.ethereum.request({ ``` ## Send Transaction +This will sign and broadcast the transaction. ```javascript const msgs = [ { @@ -128,7 +129,48 @@ const address = await window.ethereum.request({ snapId: 'npm:@cosmsnap/snap', request: { method: 'transact', - param: { + params: { + chain_id: 'cosmoshub-4', + msgs: JSON.stringify(msgs), + // Optional: Uses default fees for chain if not specified + fees: JSON.stringify(fees) + } + }, + }, +}); +``` + +## Sign Transaction +This will sign the transaction and return the transaction bytes. +NOTE: This does not broadcast the transaction. +```javascript +const msgs = [ + { + typeUrl: "/cosmos.bank.v1beta1.MsgSend", + value: { + fromAddress: senderAddress, + toAddress: recipientAddress, + amount: [{ + denom: "uatom", + amount: "500000" + }], + }, + } +]; +const fees = { + amount: [{ + denom: "uatom", + amount: "500" + }], + gas: "200000" +}; +const address = await window.ethereum.request({ + method: 'wallet_invokeSnap', + params: { + snapId: 'npm:@cosmsnap/snap', + request: { + method: 'signTx', + params: { chain_id: 'cosmoshub-4', msgs: JSON.stringify(msgs), // Optional: Uses default fees for chain if not specified @@ -147,7 +189,7 @@ const address = await window.ethereum.request({ snapId: 'npm:@cosmsnap/snap', request: { method: 'addAddress', - param: { + params: { chain_id: 'cosmoshub-4', address: 'cosmos123456789', name: 'John Cosmos' @@ -194,7 +236,7 @@ const address = await window.ethereum.request({ snapId: 'npm:@cosmsnap/snap', request: { method: 'getChainAddress', - param: { + params: { chain_id: 'cosmoshub-4', } }, diff --git a/packages/snap/package.json b/packages/snap/package.json index 01e5b56..395ebde 100644 --- a/packages/snap/package.json +++ b/packages/snap/package.json @@ -1,6 +1,6 @@ { "name": "@cosmsnap/snap", - "version": "0.1.6", + "version": "0.1.7", "description": "The Cosmos extension for your Metamask wallet.", "repository": { "type": "git", diff --git a/packages/snap/snap.manifest.json b/packages/snap/snap.manifest.json index 9a8931d..a444060 100644 --- a/packages/snap/snap.manifest.json +++ b/packages/snap/snap.manifest.json @@ -1,13 +1,13 @@ { - "version": "0.1.6", - "description": "Cosmos Metamask Snap that adds Cosmos support to Metamask.", - "proposedName": "Cosmos Metamask Snap", + "version": "0.1.7", + "description": "Cosmos Extension that adds Cosmos support to Metamask.", + "proposedName": "Cosmos Extension", "repository": { "type": "git", "url": "https://github.com/cosmos/snap.git" }, "source": { - "shasum": "z5MiND1FM0FftB3U1mnaXtDh2sOwXOWQAH57NrUZ7i4=", + "shasum": "vTr7wXctqn/NZmTVkjwj2nJYkPM9GEYvrnRAswshDxY=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/snap/src/constants.ts b/packages/snap/src/constants.ts index e87a275..71d19ee 100644 --- a/packages/snap/src/constants.ts +++ b/packages/snap/src/constants.ts @@ -12,3 +12,7 @@ export const U_MULTIPLIER = 1000000; // This is the default gas in {denom} (note not in u{denom}) export const DEFAULT_AVG_GAS = 0.05; + +export const COIN_TYPES = [ + 118, 564, 60, 459, 529, 330, 494, 639, 483, 4444, 701, 990, 394, 852, 7777777, 880, 931, 371, 370, 505, 234, 5555 +] diff --git a/packages/snap/src/index.ts b/packages/snap/src/index.ts index 53183e6..a33e40c 100644 --- a/packages/snap/src/index.ts +++ b/packages/snap/src/index.ts @@ -5,8 +5,8 @@ import { Chain, Chains, Fees } from "./types/chains"; import { Address } from "./types/address"; import { ChainState, AddressState } from "./state"; import { Result } from "./types/result"; -import { submitTransaction } from "./transaction"; -import { DEFAULT_FEES } from "./constants"; +import { signTx, submitTransaction } from "./transaction"; +import { COIN_TYPES, DEFAULT_FEES } from "./constants"; /** * Handle incoming JSON-RPC requests, sent through `wallet_invokeSnap`. @@ -61,6 +61,27 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ if (!confirmation) { throw new Error("Initialize Cosmos chain support was denied."); } + // Make sure not initialized already + let checkInit = await snap.request({ + method: "snap_manageState", + params: { operation: "get" }, + }); + if (checkInit != null && checkInit.initialized) { + await snap.request({ + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Already Initialized"), + text( + "The Cosmos Snap has already been initialized." + ), + ]), + }, + }); + throw new Error("The Cosmos Snap has already been initialized."); + }; + let chainList = await initializeChains(); let chains = new Chains(chainList); // Initialize with initial state @@ -136,8 +157,8 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ divider(), heading("Transaction"), text(JSON.stringify(messages, null, 2)), - heading("Fees Amount"), - text(`${fees}`), + heading("Gas & Fees"), + text(`${JSON.stringify(fees)}`), ]), }, }); @@ -199,6 +220,81 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ statusCode: 500, }; } + case "signTx": + // Sign a transaction with the wallet + if ( + !( + request.params != null && + typeof request.params == "object" && + "msgs" in request.params && + "chain_id" in request.params && + typeof request.params.msgs == "string" && + typeof request.params.chain_id == "string" + ) + ) { + throw new Error("Invalid transact request"); + } + + //Calculate fees for transaction + let feesTx: Fees = DEFAULT_FEES; + + if (request.params.fees) { + if (typeof request.params.fees == "string") { + feesTx = JSON.parse(request.params.fees); + } + } + + //Get messages if any from JSON string + let messagesTx; + + if (request.params.msgs) { + if (typeof request.params.msgs == "string") { + messagesTx = JSON.parse(request.params.msgs); + } + } + + // Ensure user confirms transaction + confirmation = await snap.request({ + method: "snap_dialog", + params: { + type: "confirmation", + content: panel([ + heading("Confirm Transaction"), + divider(), + heading("Chain"), + text(`${request.params.chain_id}`), + divider(), + heading("Transaction"), + text(JSON.stringify(messagesTx, null, 2)), + heading("Gas & Fees"), + text(`${JSON.stringify(feesTx)}`), + ]), + }, + }); + + if (!confirmation) { + throw new Error("Transaction was denied."); + } + + let resultTx = await signTx( + request.params.chain_id, + messagesTx, + feesTx + ); + + if (typeof resultTx === "undefined") { + return { + data: {}, + success: false, + statusCode: 500, + }; + } + + return { + data: resultTx, + success: true, + statusCode: 201, + }; case "addChain": if ( !( @@ -244,7 +340,6 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ // Ensure chain id doesn't already exist let get_chain = await ChainState.getChain(new_chain.chain_id); - if (get_chain != null) { await snap.request({ method: "snap_dialog", @@ -261,6 +356,23 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ ); } + // Ensure the coin type is supported (NOTE: 60 is blocked by Metamask) + if (!COIN_TYPES.includes(new_chain.slip44)) { + await snap.request({ + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Error Occured"), + text(`Coin type ${new_chain.slip44} is not supported.`), + ]), + }, + }); + throw new Error( + `Coin type ${new_chain.slip44} is not supported.` + ); + } + let new_chains = await ChainState.addChain(new_chain); await snap.request({ diff --git a/packages/snap/src/transaction.ts b/packages/snap/src/transaction.ts index d59f8b6..ab70bf7 100644 --- a/packages/snap/src/transaction.ts +++ b/packages/snap/src/transaction.ts @@ -1,5 +1,7 @@ import { DeliverTxResponse, SigningStargateClient } from "@cosmjs/stargate"; import { DirectSecp256k1Wallet } from "@cosmjs/proto-signing"; +import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx"; +import { HttpEndpoint } from "@cosmjs/stargate"; import { Fees } from "./types/chains"; import { ChainState } from "./state"; import { heading, panel, text } from "@metamask/snaps-ui"; @@ -101,3 +103,98 @@ export const submitTransaction = async ( }); } }; + +/** + * signTx Signs a transaction (direct) for the chain specified and returns the signed transaction. + * + * @param chain_id The id of the chain to submit the tx to + * @param msgs List of messages to submit to the chain + * @param fees Optional fees to include in transaction + * @returns The Tx Response or undefined if failed. + * @throws If an error occurs. + */ +export const signTx = async ( + chain_id: string, + msgs: any[], + fees: Fees | null = null +): Promise => { + try { + // get the chain from state + let chain = await ChainState.getChain(chain_id); + if (chain == null) { + throw new Error( + `Chain ${chain_id} not found. Please go to ${WALLET_URL} to add it!` + ); + } + + // if fees are not specified then just use default fees + gas + let avg_gas_price = chain.fees.fee_tokens[0].average_gas_price + ? chain.fees.fee_tokens[0].average_gas_price + : DEFAULT_AVG_GAS; + let ugas = avg_gas_price * U_MULTIPLIER; + if (fees == null) { + fees = { + amount: [ + { denom: chain.fees.fee_tokens[0].denom, amount: DEFAULT_FEES.gas }, + ], + gas: ugas.toString(), + }; + } + + // get signer info + let node = await snap.request({ + method: "snap_getBip44Entropy", + params: { + coinType: Number(chain.slip44), + }, + }); + + if (typeof node.privateKey === "undefined") { + throw Error("Private key from node is undefined"); + } + + // Create bytes key + let pk = node.privateKey; + if (pk.startsWith("0x")) { + pk = pk.substring(2); + } + + // create the wallet + let wallet = await DirectSecp256k1Wallet.fromKey( + Uint8Array.from(Buffer.from(pk, "hex")), + chain.bech32_prefix + ); + let address = (await wallet.getAccounts())[0].address; + + // build signing client + const client = await SigningStargateClient.connectWithSigner( + chain.apis.rpc[0].address, + wallet + ); + + // check chain id matches + if ((await client.getChainId()) != chain_id) { + throw new Error("CLIENT ERROR: Mismatching Chain Id"); + } + + // get the signed tx and return it + let result = await client.sign(address, msgs, fees, ""); + + // compose the tx bytes + let tx = TxRaw.encode(result).finish(); + + return tx + } catch (err: any) { + console.error("Error During Broadcast: ", err.message); + await snap.request({ + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Transaction Failed To Broadcast"), + text(err.message), + ]), + }, + }); + } +}; diff --git a/packages/snap/src/types/chains.ts b/packages/snap/src/types/chains.ts index d59f918..1e96826 100644 --- a/packages/snap/src/types/chains.ts +++ b/packages/snap/src/types/chains.ts @@ -1,3 +1,5 @@ +import { HttpEndpoint } from "@cosmjs/stargate"; + export interface Chain { chain_name: string; chain_id: string; @@ -15,6 +17,7 @@ export interface Chain { grpc: Api[]; }; explorers: Explorer[]; + address: string | undefined; } export interface Explorer { @@ -25,7 +28,7 @@ export interface Explorer { } export interface Api { - address: string; + address: string | HttpEndpoint; provider?: string; } diff --git a/packages/ui/package.json b/packages/ui/package.json index 23499c9..9d285e3 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -14,12 +14,18 @@ "prepack": "svelte-kit sync" }, "devDependencies": { + "@fullhuman/postcss-purgecss": "^5.0.0", "@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/kit": "^1.5.0", + "flowbite-svelte": "^0.44.4", + "flowbite-svelte-icons": "^0.4.3", + "postcss": "latest", + "postcss-load-config": "^4.0.1", "prettier": "^2.8.0", "prettier-plugin-svelte": "^2.8.1", "svelte": "^3.54.0", "svelte-check": "^3.0.1", + "tailwindcss": "latest", "tslib": "^2.4.1", "typescript": "^5.0.0", "vite": "^4.3.0", @@ -29,15 +35,13 @@ "dependencies": { "@cosmjs/crypto": "^0.31.1", "@cosmjs/stargate": "^0.31.1", - "@fullhuman/postcss-purgecss": "^5.0.0", "@metamask/detect-provider": "^2.0.0", - "flowbite-svelte": "^0.44.4", - "flowbite-svelte-icons": "^0.4.3", + "@sveltejs/adapter-node": "^1.3.1", + "autoprefixer": "latest", "gridjs": "^6.0.6", "gridjs-svelte": "^2.1.1", - "postcss": "^8.4.27", "svelte-ace": "^1.0.21", "svelte-jsoneditor": "^0.18.3", - "tailwindcss": "^3.3.3" + "svelte-preprocess": "^5.0.4" } } diff --git a/packages/ui/postcss.config.cjs b/packages/ui/postcss.config.cjs index 7e0fc4b..b86ae1c 100644 --- a/packages/ui/postcss.config.cjs +++ b/packages/ui/postcss.config.cjs @@ -1,11 +1,7 @@ +// postcss.config.cjs module.exports = { - plugins: [ - require('tailwindcss'), - ...(process.env.NODE_ENV === 'production' - ? [require('@fullhuman/postcss-purgecss')({ - content: ['./src/**/*.svelte', './src/**/*.html'], - defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || [], - })] - : []), - ], -}; \ No newline at end of file + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} \ No newline at end of file diff --git a/packages/ui/src/app.css b/packages/ui/src/app.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/packages/ui/src/app.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/packages/ui/src/app.html b/packages/ui/src/app.html index 46d1577..847fb01 100644 --- a/packages/ui/src/app.html +++ b/packages/ui/src/app.html @@ -4,11 +4,13 @@ + %sveltekit.head%
%sveltekit.body%
+ \ No newline at end of file diff --git a/packages/ui/src/components/AddAddress.svelte b/packages/ui/src/components/AddAddress.svelte index c51a206..ce7a11c 100644 --- a/packages/ui/src/components/AddAddress.svelte +++ b/packages/ui/src/components/AddAddress.svelte @@ -1,7 +1,18 @@
@@ -23,21 +34,22 @@
Name
- +
Address
- +
Chain
- + {#each $chains as chain} + + {/each}
- diff --git a/packages/ui/src/components/AddChain.svelte b/packages/ui/src/components/AddChain.svelte index b540c2c..e3d4a25 100644 --- a/packages/ui/src/components/AddChain.svelte +++ b/packages/ui/src/components/AddChain.svelte @@ -1,10 +1,11 @@ @@ -14,7 +15,7 @@
- Add new chain + {edit ? "Edit chain" : "Add new chain"}
$state.openAddChainPopup = false} class="clear" src="https://anima-uploads.s3.amazonaws.com/projects/64863aebc1255e7dd4fb600b/releases/64ef9c2985c1bf1a9cb5beba/img/clear@2x.png" alt="clear"> @@ -28,7 +29,7 @@
@@ -43,7 +44,7 @@ backdrop-filter: blur(15px) brightness(100%); background-color: #05000bbf; left: 0; - position: absolute; + position: fixed; top: 0; width: 100vw; min-height: 100vh; diff --git a/packages/ui/src/components/Alert.svelte b/packages/ui/src/components/Alert.svelte new file mode 100644 index 0000000..707942d --- /dev/null +++ b/packages/ui/src/components/Alert.svelte @@ -0,0 +1,24 @@ + + + + + \ No newline at end of file diff --git a/packages/ui/src/components/Balance.svelte b/packages/ui/src/components/Balance.svelte index 90637f1..499a8cd 100644 --- a/packages/ui/src/components/Balance.svelte +++ b/packages/ui/src/components/Balance.svelte @@ -13,7 +13,6 @@ await copyToClipboard(chainAddress); $state.showAlert = true; $state.alertText = "Address Copied to Clipboard" - console.log($state); } diff --git a/packages/ui/src/components/Confirm.svelte b/packages/ui/src/components/Confirm.svelte new file mode 100644 index 0000000..e747a0a --- /dev/null +++ b/packages/ui/src/components/Confirm.svelte @@ -0,0 +1,37 @@ + + + + + \ No newline at end of file diff --git a/packages/ui/src/components/Info.svelte b/packages/ui/src/components/Info.svelte new file mode 100644 index 0000000..b6ac87f --- /dev/null +++ b/packages/ui/src/components/Info.svelte @@ -0,0 +1,24 @@ + + + + + + \ No newline at end of file diff --git a/packages/ui/src/components/Transfer.svelte b/packages/ui/src/components/Transfer.svelte index 5017acc..dbeade8 100644 --- a/packages/ui/src/components/Transfer.svelte +++ b/packages/ui/src/components/Transfer.svelte @@ -1,7 +1,10 @@
@@ -12,8 +15,9 @@ Source Chain
@@ -27,10 +31,12 @@
Destination Chain +
diff --git a/packages/ui/src/routes/+layout.svelte b/packages/ui/src/routes/+layout.svelte index ea1caa9..401b5b4 100644 --- a/packages/ui/src/routes/+layout.svelte +++ b/packages/ui/src/routes/+layout.svelte @@ -4,8 +4,14 @@ import { page } from '$app/stores'; import { goto } from "$app/navigation"; import { onMount } from "svelte"; + import { fetchChains } from "../store/chains"; + import Alert from "../components/Alert.svelte"; + import "../app.css"; + import { getAddressBook } from "../store/addressbook"; - onMount(() => { + onMount(async () => { + fetchChains(); + getAddressBook(); if (!$state.connected) { goto("/"); } else { @@ -19,6 +25,7 @@ +
+
@@ -17,33 +30,39 @@
-
-
-
- Mask group -
-
- Johnny Bravo -
-
-
-
- cosmos1vhw8...2tqftrg +
+ {#each $addressbook as address} +
+
+
+ Mask group +
+
+ {address.name} +
+
+
+
+ {address.address} +
+ + copyAddress(address.address)} + class="content_copy cursor-pointer" + src="https://anima-uploads.s3.amazonaws.com/projects/64863aebc1255e7dd4fb600b/releases/64e66782179fd75deb1bab46/img/content-copy-12@2x.png" + alt="content_copy" + /> +
- content_copy
-
+ {/each}
@@ -53,6 +72,10 @@ box-sizing: border-box; } +#items-div::-webkit-scrollbar { + display: none; +} + .inter-medium-white-12px { color: var(--white); font-family: var(--font-family-inter); @@ -103,18 +126,18 @@ .group-4405 { display: flex; flex-direction: column; - width: 153px; + width: 100%; } .group-4400 { display: flex; - width: 151px; + width: 100%; } .group-4537 { display: flex; gap: 10px; - width: 153px; + width: 100%; align-items: center; } @@ -126,6 +149,9 @@ .cosmos1vhw82tqftrg { line-height: normal; + text-overflow: ellipsis; /* enables ellipsis */ + white-space: nowrap; /* keeps the text in a single line */ + overflow: hidden; /* keeps the element from overflowing its parent */ } .name-2 { @@ -140,12 +166,13 @@ border-color: var(--white-2); border-radius: 12px; width: 100%; - max-width: 450px; + max-width: 500px; display: flex; flex-direction: column; justify-content: flex-start; align-items: center; padding: 20px; + max-height: 480px; } .chain-management { diff --git a/packages/ui/src/routes/api/balances/+server.js b/packages/ui/src/routes/api/balances/+server.js new file mode 100644 index 0000000..db30dfd --- /dev/null +++ b/packages/ui/src/routes/api/balances/+server.js @@ -0,0 +1,39 @@ +import { json } from '@sveltejs/kit'; + +export async function POST({ request }) { + + let { chains } = await request.json(); + + /** + * Fetches the balance for a given chain. + * + * @param {import('../../../../../snap/src/types/chains').Chain} chain - The chain for which to fetch the balance. + * @returns {Promise} - A promise resolving to an object containing the chain and its balance. + */ + const fetchBalance = async (chain) => { + try { + const url = `${chain.apis.rest[0].address}/cosmos/bank/v1beta1/balances/${chain.address}`; + const response = await fetch(url); + const data = await response.json(); + return { ...chain, balances: data.balances }; + } catch (err) { + console.error(err); + return { ...chain, balances: [] }; + } + }; + + try { + // Fetch balances for all chains. + const balances = await Promise.all(chains.map(fetchBalance)); + return json({ + status: 200, + body: { balances } + }); + } catch (error) { + console.error(error); + return json({ + status: 500, + body: { error } + }); + } +} \ No newline at end of file diff --git a/packages/ui/src/routes/dashboard/+page.svelte b/packages/ui/src/routes/dashboard/+page.svelte index f51503b..5cb73da 100644 --- a/packages/ui/src/routes/dashboard/+page.svelte +++ b/packages/ui/src/routes/dashboard/+page.svelte @@ -1,76 +1,34 @@ -
@@ -78,17 +36,19 @@ Chains
- {#each balancesOld as balance} -
- -
+ {#each $balances as b} + {#each b['balances'] as amount} +
+ +
+ {/each} {/each}
diff --git a/packages/ui/src/routes/settings/+page.svelte b/packages/ui/src/routes/settings/+page.svelte index edc6b58..a081211 100644 --- a/packages/ui/src/routes/settings/+page.svelte +++ b/packages/ui/src/routes/settings/+page.svelte @@ -1,13 +1,35 @@ -
@@ -16,24 +38,31 @@
- +
- {#each chains as chain} + {#each $chains as chain}
- + {#if chain.logo_URIs} + + {:else} + + {/if}
{chain.pretty_name}
- createdelete_outline + + editChain(chain.chain_id)} class="create cursor-pointer" src="https://anima-uploads.s3.amazonaws.com/projects/64863aebc1255e7dd4fb600b/releases/64a710c1420c7281d1d60ffb/img/create.svg" alt="create"> + + deleteChainFromSnap(chain.chain_id)} class="delete_outline cursor-pointer" src="https://anima-uploads.s3.amazonaws.com/projects/64863aebc1255e7dd4fb600b/releases/64a710c1420c7281d1d60ffb/img/delete-outline.svg" alt="delete_outline">
diff --git a/packages/ui/src/store/addressbook.ts b/packages/ui/src/store/addressbook.ts new file mode 100644 index 0000000..870a56a --- /dev/null +++ b/packages/ui/src/store/addressbook.ts @@ -0,0 +1,12 @@ +import { writable } from 'svelte/store'; +import type { Address } from '../../../snap/src/types/address'; +import { getAddresses } from '../utils/snap'; + +export const addressbook = writable([]); + +export async function getAddressBook() { + const allAddresses = await getAddresses(); + addressbook.set(allAddresses); + + return allAddresses +} \ No newline at end of file diff --git a/packages/ui/src/store/balances.js b/packages/ui/src/store/balances.js deleted file mode 100644 index e5183c8..0000000 --- a/packages/ui/src/store/balances.js +++ /dev/null @@ -1,22 +0,0 @@ -import { writable } from 'svelte/store'; -import { getAllBalances } from '../utils/balances'; - -/** - * @type {import('../utils/query').ChainBalances[] | undefined} - */ -let initialBalance = []; - -const balances = writable(initialBalance); - -export const fetchAllBalances = async () => { - try { - const balancesAll = await getAllBalances(); - - balances.set(balancesAll); - } catch (error) { - console.error("Error fetching balances:", error); - throw error - } -}; - -export default balances; \ No newline at end of file diff --git a/packages/ui/src/store/balances.ts b/packages/ui/src/store/balances.ts new file mode 100644 index 0000000..d2b4ca6 --- /dev/null +++ b/packages/ui/src/store/balances.ts @@ -0,0 +1,9 @@ +import { writable } from 'svelte/store'; +import type { Chain } from '../../../snap/src/types/chains'; +import type { Coin } from '@cosmjs/stargate'; + +interface ChainBalances extends Chain { + balances: Coin[]; +} + +export const balances = writable([]); \ No newline at end of file diff --git a/packages/ui/src/store/chains.ts b/packages/ui/src/store/chains.ts index 4db97bb..85e01dc 100644 --- a/packages/ui/src/store/chains.ts +++ b/packages/ui/src/store/chains.ts @@ -1,15 +1,21 @@ import { writable } from 'svelte/store'; -import { type ChainClient, createAllChains } from '../utils/chains'; +import { getChainAddresses, getChains } from '../utils/snap'; +import type { Chain } from '../../../snap/src/types/chains'; -export const chains = writable<(ChainClient | null)[]>([]); +export const chains = writable([]); -export const fetchAllClients = async () => { - try { - const clients = await createAllChains(); - - chains.set(clients); - } catch (error) { - console.error('Error fetching all clients:', error); - chains.set([]); +export async function fetchChains() { + const allAddresses = await getChainAddresses(); + const allChains = await getChains(); + for (let i = 0; i < allChains.length; i++) { + let item = allAddresses.filter(item => item.chain_id === allChains[i].chain_id); + if (item.length == 0) { + throw new Error(`Address not found for chain ${allChains[i].chain_id}`) } -}; \ No newline at end of file + allChains[i].address = item[0].address + } + + chains.set(allChains); + + return allChains +} \ No newline at end of file diff --git a/packages/ui/src/store/state.js b/packages/ui/src/store/state.js index cca28a7..456be1e 100644 --- a/packages/ui/src/store/state.js +++ b/packages/ui/src/store/state.js @@ -4,6 +4,7 @@ export const state = writable({ connected: false, openAddAddressPopup: false, openAddChainPopup: false, + confirmDeleteChainPopup: false, alertText: "", showAlert: false }); \ No newline at end of file diff --git a/packages/ui/src/utils/balances.ts b/packages/ui/src/utils/balances.ts deleted file mode 100644 index d861a8a..0000000 --- a/packages/ui/src/utils/balances.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { getChainAddresses, getChains, snapId } from './snap'; -import { queryBalances } from './query'; -import type { ChainBalances } from './query'; - -export const getAllBalances = async (): Promise => { - let addressesP = getChainAddresses(); - - let chainsP = getChains(); - - let [addresses, chains] = await Promise.all([addressesP, chainsP]); - - let balancesP = chains.map(chain => queryBalances(chain.apis.rpc[0].address, addresses.filter(item => item.chain_id === chain.chain_id)[0].address, chain.chain_id)); - - let balances = Promise.all(balancesP); - - return balances -}; \ No newline at end of file diff --git a/packages/ui/src/utils/chains.ts b/packages/ui/src/utils/chains.ts index 39a9021..5cf18de 100644 --- a/packages/ui/src/utils/chains.ts +++ b/packages/ui/src/utils/chains.ts @@ -3,7 +3,6 @@ import type { Chain } from "../../../snap/src/types/chains"; import { getChainAddresses, getChains } from "./snap"; export interface ChainClient extends Chain { - address: string | null; client: StargateClient | null; } diff --git a/packages/ui/src/utils/query.ts b/packages/ui/src/utils/query.ts deleted file mode 100644 index f97be42..0000000 --- a/packages/ui/src/utils/query.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { StargateClient, type Coin } from "@cosmjs/stargate" - -export interface ChainBalances { - chain_id: string; - balances: readonly Coin[]; -} - -export const queryBalances = async (rpcEndpoint: string, targetAddress: string, chain_id: string): Promise => { - const client = await StargateClient.connect(rpcEndpoint); - - const balance = await client.getAllBalances(targetAddress); - - return { chain_id, balances: balance }; -}; - -export const queryBalance = async (rpcEndpoint: string, targetAddress: string, denom: string): Promise => { - const client = await StargateClient.connect(rpcEndpoint); - - const balance = await client.getBalance(targetAddress, denom); - - return balance; -}; \ No newline at end of file diff --git a/packages/ui/src/utils/snap.ts b/packages/ui/src/utils/snap.ts index b8f02d0..b78d428 100644 --- a/packages/ui/src/utils/snap.ts +++ b/packages/ui/src/utils/snap.ts @@ -1,3 +1,4 @@ +import type { Address } from '../../../snap/src/types/address'; import type { Chain, CosmosAddress } from '../../../snap/src/types/chains'; export const snapId = import.meta.env.VITE_SNAP_ID ?? `local:http://localhost:8080`; @@ -58,6 +59,52 @@ export const getChainAddresses = async (): Promise => { return result.data.addresses; }; +export const getAddresses = async (): Promise => { + const result = await window.ethereum.request({ + method: 'wallet_invokeSnap', + params: { + snapId, + request: { + method: 'getAddresses', + }, + }, + }); + console.log(result); + return result.data; +}; + +export const addAddressToBook = async (chain_id: string, address: string, name: string) => { + await window.ethereum.request({ + method: 'wallet_invokeSnap', + params: { + snapId, + request: { + method: 'addAddress', + params: { + chain_id, + address, + name + } + }, + }, + }); +}; + +export const deleteChain = async (chain_id: string) => { + await window.ethereum.request({ + method: 'wallet_invokeSnap', + params: { + snapId, + request: { + method: 'deleteChain', + params: { + chain_id, + } + }, + } + }) +}; + export const installSnap = async () => { try { await window.ethereum.request({ diff --git a/packages/ui/tailwind.config.cjs b/packages/ui/tailwind.config.cjs new file mode 100644 index 0000000..ceb520e --- /dev/null +++ b/packages/ui/tailwind.config.cjs @@ -0,0 +1,8 @@ +// tailwind.config.cjs +module.exports = { + content: ['./src/**/*.{html,js,svelte,ts}'], + theme: { + extend: {}, + }, + plugins: [], +} \ No newline at end of file diff --git a/packages/ui/tailwind.config.js b/packages/ui/tailwind.config.js deleted file mode 100644 index 1666737..0000000 --- a/packages/ui/tailwind.config.js +++ /dev/null @@ -1,30 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -const config = { - content: ['./src/**/*.{html,js,svelte,ts}', './node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}'], - - plugins: [require('flowbite/plugin')], - - darkMode: 'class', - - theme: { - extend: { - colors: { - // flowbite-svelte - primary: { - 50: '#FFF5F2', - 100: '#FFF1EE', - 200: '#FFE4DE', - 300: '#FFD5CC', - 400: '#FFBCAD', - 500: '#FE795D', - 600: '#EF562F', - 700: '#EB4F27', - 800: '#CC4522', - 900: '#A5371B' - } - } - } - } -}; - -module.exports = config; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 21dc0b5..f48e5b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3016,6 +3016,74 @@ __metadata: languageName: node linkType: hard +"@rollup/plugin-commonjs@npm:^25.0.0": + version: 25.0.4 + resolution: "@rollup/plugin-commonjs@npm:25.0.4" + dependencies: + "@rollup/pluginutils": ^5.0.1 + commondir: ^1.0.1 + estree-walker: ^2.0.2 + glob: ^8.0.3 + is-reference: 1.2.1 + magic-string: ^0.27.0 + peerDependencies: + rollup: ^2.68.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 073b92b765a1f8ab8db8e1aa216c1950e62f6c0c41210d10bb7530c4fc63670a16c19c0bbbf73e2752467c4468ad4c8134cf4724924388c3eed83df45630fda6 + languageName: node + linkType: hard + +"@rollup/plugin-json@npm:^6.0.0": + version: 6.0.0 + resolution: "@rollup/plugin-json@npm:6.0.0" + dependencies: + "@rollup/pluginutils": ^5.0.1 + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 77cfc941edaf77a5307977704ffaba706d83bea66f265b2b68f14be2a0af6d08b0fb1b04fdd773146c84cc70938ff64b00ae946808fd6ac057058af824d78128 + languageName: node + linkType: hard + +"@rollup/plugin-node-resolve@npm:^15.0.1": + version: 15.2.1 + resolution: "@rollup/plugin-node-resolve@npm:15.2.1" + dependencies: + "@rollup/pluginutils": ^5.0.1 + "@types/resolve": 1.20.2 + deepmerge: ^4.2.2 + is-builtin-module: ^3.2.1 + is-module: ^1.0.0 + resolve: ^1.22.1 + peerDependencies: + rollup: ^2.78.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: e8f706db6ab826e80d1c9a85d2d1e736f2f78a34ea5d49dd0004d6603249a504696967674b2f021cd144536b88d24ffa058383f08b61b4b665be3c7bfacc006a + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^5.0.1": + version: 5.0.4 + resolution: "@rollup/pluginutils@npm:5.0.4" + dependencies: + "@types/estree": ^1.0.0 + estree-walker: ^2.0.2 + picomatch: ^2.3.1 + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 893d5805ac4121fc704926963a0ae4e79e9e2bc8d736c3b28499ab69a404cce5119ca3a4e0c3d3a81d62f1beb3966f35285c36935d94b061794f26e94fed4cd1 + languageName: node + linkType: hard + "@scure/base@npm:^1.0.0, @scure/base@npm:^1.1.1, @scure/base@npm:~1.1.0": version: 1.1.1 resolution: "@scure/base@npm:1.1.1" @@ -3071,6 +3139,20 @@ __metadata: languageName: node linkType: hard +"@sveltejs/adapter-node@npm:^1.3.1": + version: 1.3.1 + resolution: "@sveltejs/adapter-node@npm:1.3.1" + dependencies: + "@rollup/plugin-commonjs": ^25.0.0 + "@rollup/plugin-json": ^6.0.0 + "@rollup/plugin-node-resolve": ^15.0.1 + rollup: ^3.7.0 + peerDependencies: + "@sveltejs/kit": ^1.0.0 + checksum: acb93a885b8c89ef1a39c29a2b2ad92986578844f314a1030b8ce08628d5ff1ace14daac5d42a46b62a246aa33f234747ebb889a7e5fed338dc5d248f7686988 + languageName: node + linkType: hard + "@sveltejs/kit@npm:^1.5.0": version: 1.20.1 resolution: "@sveltejs/kit@npm:1.20.1" @@ -3319,6 +3401,13 @@ __metadata: languageName: node linkType: hard +"@types/resolve@npm:1.20.2": + version: 1.20.2 + resolution: "@types/resolve@npm:1.20.2" + checksum: 61c2cad2499ffc8eab36e3b773945d337d848d3ac6b7b0a87c805ba814bc838ef2f262fc0f109bfd8d2e0898ff8bd80ad1025f9ff64f1f71d3d4294c9f14e5f6 + languageName: node + linkType: hard + "@types/secp256k1@npm:^4.0.1": version: 4.0.3 resolution: "@types/secp256k1@npm:4.0.3" @@ -3905,6 +3994,24 @@ __metadata: languageName: node linkType: hard +"autoprefixer@npm:latest": + version: 10.4.15 + resolution: "autoprefixer@npm:10.4.15" + dependencies: + browserslist: ^4.21.10 + caniuse-lite: ^1.0.30001520 + fraction.js: ^4.2.0 + normalize-range: ^0.1.2 + picocolors: ^1.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.1.0 + bin: + autoprefixer: bin/autoprefixer + checksum: d490b14fb098c043e109fc13cd23628f146af99a493d35b9df3a26f8ec0b4dd8937c5601cdbaeb465b98ea31d3ea05aa7184711d4d93dfb52358d073dcb67032 + languageName: node + linkType: hard + "ava@npm:^5.3.0": version: 5.3.0 resolution: "ava@npm:5.3.0" @@ -4331,6 +4438,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.21.10": + version: 4.21.10 + resolution: "browserslist@npm:4.21.10" + dependencies: + caniuse-lite: ^1.0.30001517 + electron-to-chromium: ^1.4.477 + node-releases: ^2.0.13 + update-browserslist-db: ^1.0.11 + bin: + browserslist: cli.js + checksum: 1e27c0f111a35d1dd0e8fc2c61781b0daefabc2c9471b0b10537ce54843014bceb2a1ce4571af1a82b2bf1e6e6e05d38865916689a158f03bc2c7a4ec2577db8 + languageName: node + linkType: hard + "browserslist@npm:^4.21.3, browserslist@npm:^4.21.5": version: 4.21.7 resolution: "browserslist@npm:4.21.7" @@ -4406,6 +4527,13 @@ __metadata: languageName: node linkType: hard +"builtin-modules@npm:^3.3.0": + version: 3.3.0 + resolution: "builtin-modules@npm:3.3.0" + checksum: db021755d7ed8be048f25668fe2117620861ef6703ea2c65ed2779c9e3636d5c3b82325bd912244293959ff3ae303afa3471f6a15bf5060c103e4cc3a839749d + languageName: node + linkType: hard + "builtin-status-codes@npm:^3.0.0": version: 3.0.0 resolution: "builtin-status-codes@npm:3.0.0" @@ -4525,6 +4653,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001517, caniuse-lite@npm:^1.0.30001520": + version: 1.0.30001527 + resolution: "caniuse-lite@npm:1.0.30001527" + checksum: 7ad99d78d1a30d494471c8a9ead3fc40a816ee61b16fef330bba5bdae5d7ebaa965becc8cd09c7aa6240125ce790a5213a40cd240ceaa211508744ed86b79783 + languageName: node + linkType: hard + "cbor@npm:^8.1.0": version: 8.1.0 resolution: "cbor@npm:8.1.0" @@ -4815,6 +4950,13 @@ __metadata: languageName: node linkType: hard +"commondir@npm:^1.0.1": + version: 1.0.1 + resolution: "commondir@npm:1.0.1" + checksum: 59715f2fc456a73f68826285718503340b9f0dd89bfffc42749906c5cf3d4277ef11ef1cca0350d0e79204f00f1f6d83851ececc9095dc88512a697ac0b9bdcb + languageName: node + linkType: hard + "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -4958,19 +5100,23 @@ __metadata: "@fullhuman/postcss-purgecss": ^5.0.0 "@metamask/detect-provider": ^2.0.0 "@sveltejs/adapter-auto": ^2.0.0 + "@sveltejs/adapter-node": ^1.3.1 "@sveltejs/kit": ^1.5.0 + autoprefixer: latest flowbite-svelte: ^0.44.4 flowbite-svelte-icons: ^0.4.3 gridjs: ^6.0.6 gridjs-svelte: ^2.1.1 - postcss: ^8.4.27 + postcss: latest + postcss-load-config: ^4.0.1 prettier: ^2.8.0 prettier-plugin-svelte: ^2.8.1 svelte: ^3.54.0 svelte-ace: ^1.0.21 svelte-check: ^3.0.1 svelte-jsoneditor: ^0.18.3 - tailwindcss: ^3.3.3 + svelte-preprocess: ^5.0.4 + tailwindcss: latest tslib: ^2.4.1 typescript: ^5.0.0 vite: ^4.3.0 @@ -5165,7 +5311,7 @@ __metadata: languageName: node linkType: hard -"deepmerge@npm:^4.3.1": +"deepmerge@npm:^4.2.2, deepmerge@npm:^4.3.1": version: 4.3.1 resolution: "deepmerge@npm:4.3.1" checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052 @@ -5421,6 +5567,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.4.477": + version: 1.4.508 + resolution: "electron-to-chromium@npm:1.4.508" + checksum: 4475eb18f5805d43f84d9542364045a39b183a14cd9f4626e0951ea61d0fa4f84a5ed579c2c32189f9af4a27a31041d09fed78f60930ac36b3baa08547dd3aa6 + languageName: node + linkType: hard + "elliptic@npm:^6.5.3, elliptic@npm:^6.5.4": version: 6.5.4 resolution: "elliptic@npm:6.5.4" @@ -5969,6 +6122,13 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^2.0.2": + version: 2.0.2 + resolution: "estree-walker@npm:2.0.2" + checksum: 6151e6f9828abe2259e57f5fd3761335bb0d2ebd76dc1a01048ccee22fabcfef3c0859300f6d83ff0d1927849368775ec5a6d265dde2f6de5a1be1721cd94efc + languageName: node + linkType: hard + "estree-walker@npm:^3.0.0, estree-walker@npm:^3.0.3": version: 3.0.3 resolution: "estree-walker@npm:3.0.3" @@ -6326,6 +6486,13 @@ __metadata: languageName: node linkType: hard +"fraction.js@npm:^4.2.0": + version: 4.3.6 + resolution: "fraction.js@npm:4.3.6" + checksum: e96ae77e64ebfd442d3a5a01a3f0637b0663fc2440bcf2841b3ad9341ba24c81fb2e3e7142e43ef7d088558c6b3f8609df135b201adc7a1c674aea6a71384162 + languageName: node + linkType: hard + "fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -7053,6 +7220,15 @@ __metadata: languageName: node linkType: hard +"is-builtin-module@npm:^3.2.1": + version: 3.2.1 + resolution: "is-builtin-module@npm:3.2.1" + dependencies: + builtin-modules: ^3.3.0 + checksum: e8f0ffc19a98240bda9c7ada84d846486365af88d14616e737d280d378695c8c448a621dcafc8332dbf0fcd0a17b0763b845400709963fa9151ddffece90ae88 + languageName: node + linkType: hard + "is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.2.7": version: 1.2.7 resolution: "is-callable@npm:1.2.7" @@ -7176,6 +7352,13 @@ __metadata: languageName: node linkType: hard +"is-module@npm:^1.0.0": + version: 1.0.0 + resolution: "is-module@npm:1.0.0" + checksum: 8cd5390730c7976fb4e8546dd0b38865ee6f7bacfa08dfbb2cc07219606755f0b01709d9361e01f13009bbbd8099fa2927a8ed665118a6105d66e40f1b838c3f + languageName: node + linkType: hard + "is-negative-zero@npm:^2.0.2": version: 2.0.2 resolution: "is-negative-zero@npm:2.0.2" @@ -7227,6 +7410,15 @@ __metadata: languageName: node linkType: hard +"is-reference@npm:1.2.1": + version: 1.2.1 + resolution: "is-reference@npm:1.2.1" + dependencies: + "@types/estree": "*" + checksum: e7b48149f8abda2c10849ea51965904d6a714193d68942ad74e30522231045acf06cbfae5a4be2702fede5d232e61bf50b3183acdc056e6e3afe07fcf4f4b2bc + languageName: node + linkType: hard + "is-reference@npm:^3.0.0, is-reference@npm:^3.0.1": version: 3.0.1 resolution: "is-reference@npm:3.0.1" @@ -8294,6 +8486,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.13": + version: 2.0.13 + resolution: "node-releases@npm:2.0.13" + checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 + languageName: node + linkType: hard + "nofilter@npm:^3.1.0": version: 3.1.0 resolution: "nofilter@npm:3.1.0" @@ -8319,6 +8518,13 @@ __metadata: languageName: node linkType: hard +"normalize-range@npm:^0.1.2": + version: 0.1.2 + resolution: "normalize-range@npm:0.1.2" + checksum: 9b2f14f093593f367a7a0834267c24f3cb3e887a2d9809c77d8a7e5fd08738bcd15af46f0ab01cc3a3d660386f015816b5c922cea8bf2ee79777f40874063184 + languageName: node + linkType: hard + "npm-normalize-package-bin@npm:^3.0.0": version: 3.0.1 resolution: "npm-normalize-package-bin@npm:3.0.1" @@ -8835,7 +9041,7 @@ __metadata: languageName: node linkType: hard -"postcss-value-parser@npm:^4.0.0": +"postcss-value-parser@npm:^4.0.0, postcss-value-parser@npm:^4.2.0": version: 4.2.0 resolution: "postcss-value-parser@npm:4.2.0" checksum: 819ffab0c9d51cf0acbabf8996dffbfafbafa57afc0e4c98db88b67f2094cb44488758f06e5da95d7036f19556a4a732525e84289a425f4f6fd8e412a9d7442f @@ -8853,7 +9059,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.4.27, postcss@npm:^8.4.4": +"postcss@npm:^8.4.4": version: 8.4.27 resolution: "postcss@npm:8.4.27" dependencies: @@ -8864,6 +9070,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:latest": + version: 8.4.29 + resolution: "postcss@npm:8.4.29" + dependencies: + nanoid: ^3.3.6 + picocolors: ^1.0.0 + source-map-js: ^1.0.2 + checksum: dd6daa25e781db9ae5b651d9b7bfde0ec6e60e86a37da69a18eb4773d5ddd51e28fc4ff054fbdc04636a31462e6bf09a1e50986f69ac52b10d46b7457cd36d12 + languageName: node + linkType: hard + "preact@npm:^10.11.3": version: 10.17.1 resolution: "preact@npm:10.17.1" @@ -9435,6 +9652,20 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^3.7.0": + version: 3.28.1 + resolution: "rollup@npm:3.28.1" + dependencies: + fsevents: ~2.3.2 + dependenciesMeta: + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 1fcab0929c16130218447c76c19b56ccc0e677110552462297e3679188fc70185a6ec418cef8ce138ec9fb78fd5188537a3f5d28762788e8c88b12a7fb8ba0fb + languageName: node + linkType: hard + "run-applescript@npm:^5.0.0": version: 5.0.0 resolution: "run-applescript@npm:5.0.0" @@ -10272,7 +10503,7 @@ __metadata: languageName: node linkType: hard -"svelte-preprocess@npm:^5.0.3": +"svelte-preprocess@npm:^5.0.3, svelte-preprocess@npm:^5.0.4": version: 5.0.4 resolution: "svelte-preprocess@npm:5.0.4" dependencies: @@ -10469,7 +10700,7 @@ __metadata: languageName: node linkType: hard -"tailwindcss@npm:^3.3.3": +"tailwindcss@npm:latest": version: 3.3.3 resolution: "tailwindcss@npm:3.3.3" dependencies: