From b08087986c809a074e33529f54e47a0e54221c05 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 16 Nov 2023 12:45:00 -0800 Subject: [PATCH 01/50] feat: begin fedimint cards --- .gitignore | 5 ++-- .../src/views/home/account/AccountInfo.tsx | 26 ++++++++++++++++--- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 03b17961..4729ac5e 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,5 @@ lerna-debug.log* # config files config.yaml - -# For Dev -local_data +data +data/* diff --git a/src/client/src/views/home/account/AccountInfo.tsx b/src/client/src/views/home/account/AccountInfo.tsx index c341942a..00652a8f 100644 --- a/src/client/src/views/home/account/AccountInfo.tsx +++ b/src/client/src/views/home/account/AccountInfo.tsx @@ -1,6 +1,6 @@ import React from 'react'; import styled from 'styled-components'; -import { Zap, Anchor, Pocket } from 'react-feather'; +import { Zap, Anchor, Pocket, Book } from 'react-feather'; import { useNodeBalances } from '../../../hooks/UseNodeBalances'; import Big from 'big.js'; import { renderLine } from '../../../components/generic/helpers'; @@ -20,7 +20,7 @@ const S = { grid: styled.div` display: grid; grid-gap: 16px; - grid-template-columns: 1fr 1fr; + grid-template-columns: 1fr 1fr 1fr; @media (${mediaWidths.mobile}) { display: block; @@ -92,13 +92,19 @@ export const AccountInfo = () => { - Bitcoin + Lightning +
+ +
+
+ + Onchain Bitcoin
- Lightning + Fedimint Ecash
@@ -137,6 +143,18 @@ export const AccountInfo = () => { {renderLine('Force Closures', )} + + + + + Fedimint eCash + + + {renderLine('Available', )} + {renderLine('Not Available', )} + {renderLine('Pending', )} + + ); From f6945d952ef23c6dfab6659bb8439e6cf3cd4438 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 16 Nov 2023 15:31:36 -0800 Subject: [PATCH 02/50] feat: add fedmint lightning gateway config option to thunderhub configs --- src/client/src/api/GatewayApi.ts | 145 +++++++++++ src/client/src/api/types.ts | 57 +++++ .../src/views/home/account/AccountButtons.tsx | 36 ++- .../home/account/pegInEcash/PegInEcash.tsx | 133 ++++++++++ .../home/account/pegOutEcash/PegOutEcash.tsx | 228 ++++++++++++++++++ src/server/config/configuration.ts | 12 + 6 files changed, 609 insertions(+), 2 deletions(-) create mode 100644 src/client/src/api/GatewayApi.ts create mode 100644 src/client/src/api/types.ts create mode 100644 src/client/src/views/home/account/pegInEcash/PegInEcash.tsx create mode 100644 src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts new file mode 100644 index 00000000..e7d33616 --- /dev/null +++ b/src/client/src/api/GatewayApi.ts @@ -0,0 +1,145 @@ +import { GatewayInfo, Federation } from './types'; + +const SESSION_STORAGE_KEY = 'gateway-ui-key'; + +// GatewayApi is an implementation of the ApiInterface +export class GatewayApi { + private baseUrl: string | undefined = process.env.REACT_APP_FM_GATEWAY_API; + + // Tests a provided password, or the one in the environment config, or the one in session storage + testPassword = async (password?: string): Promise => { + const tempPassword = + password || + this.getPassword() || + process.env.REACT_APP_FM_GATEWAY_PASSWORD; + + if (!tempPassword) { + return false; + } + + // Replace with temp password to check. + sessionStorage.setItem(SESSION_STORAGE_KEY, tempPassword); + + try { + await this.fetchInfo(); + return true; + } catch (err) { + // TODO: make sure error is auth error, not unrelated + console.error(err); + this.clearPassword(); + return false; + } + }; + + private getPassword = (): string | null => { + return sessionStorage.getItem(SESSION_STORAGE_KEY); + }; + + clearPassword = () => { + sessionStorage.removeItem(SESSION_STORAGE_KEY); + }; + + private post = async (api: string, body: unknown): Promise => { + if (this.baseUrl === undefined) { + throw new Error( + 'Misconfigured Gateway API. Make sure FM_GATEWAY_API is configured appropriately' + ); + } + + const password = this.getPassword(); + if (!password) { + throw new Error( + 'Misconfigured Gateway API. Make sure gateway password is configured appropriately' + ); + } + + return fetch(`${this.baseUrl}/${api}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${password}`, + }, + body: JSON.stringify(body), + }); + }; + + fetchInfo = async (): Promise => { + try { + const res: Response = await this.post('info', null); + + if (res.ok) { + const info: GatewayInfo = await res.json(); + return Promise.resolve(info); + } + + throw responseToError(res); + } catch (error) { + return Promise.reject({ message: 'Error fetching gateway info', error }); + } + }; + + fetchAddress = async (federationId: string): Promise => { + try { + const res: Response = await this.post('address', { + federation_id: federationId, + }); + + if (res.ok) { + const address: string = (await res.text()).replace(/"/g, '').trim(); + return Promise.resolve(address); + } + + throw responseToError(res); + } catch (error) { + return Promise.reject({ + message: 'Error fetching deposit address', + error, + }); + } + }; + + connectFederation = async (inviteCode: string): Promise => { + try { + const res: Response = await this.post('connect-fed', { + invite_code: inviteCode, + }); + + if (res.ok) { + const federation: Federation = await res.json(); + return Promise.resolve(federation); + } + + throw responseToError(res); + } catch (error) { + return Promise.reject({ message: 'Error connecting federation', error }); + } + }; + + requestWithdrawal = async ( + federationId: string, + amountSat: number, + address: string + ): Promise => { + try { + const res: Response = await this.post('withdraw', { + federation_id: federationId, + amount: amountSat, + address, + }); + + if (res.ok) { + const txid: string = await res.text(); + console.log('txid', txid); + return Promise.resolve(txid); + } + + throw responseToError(res); + } catch (error) { + return Promise.reject({ message: 'Error requesting withdrawal', error }); + } + }; +} + +const responseToError = (res: Response): Error => { + return new Error(`Status : ${res.status} \nReason : ${res.statusText}\n`); +}; diff --git a/src/client/src/api/types.ts b/src/client/src/api/types.ts new file mode 100644 index 00000000..e98b5753 --- /dev/null +++ b/src/client/src/api/types.ts @@ -0,0 +1,57 @@ +interface Fees { + base_msat: number; + proportional_millionths: number; +} + +export enum ModuleKind { + Ln = 'ln', + Mint = 'mint', + Wallet = 'wallet', +} + +interface FedimintModule { + config: string; + kind: ModuleKind; + version: number; +} + +interface ApiEndpoint { + name: string; + url: string; +} + +export type MetaConfig = { federation_name?: string }; + +export interface ClientConfig { + consensus_version: number; + epoch_pk: string; + federation_id: string; + api_endpoints: Record; + modules: Record; + meta: MetaConfig; +} + +export interface Federation { + federation_id: string; + balance_msat: number; + config: ClientConfig; +} + +export interface GatewayInfo { + federations: Federation[]; + fees: Fees; + lightning_alias: string; + lightning_pub_key: string; + version_hash: string; + network?: Network; +} + +// Type adaptation from https://docs.rs/bitcoin/latest/bitcoin/network/enum.Network.html +export enum Network { + Bitcoin = 'main', + Testnet = 'test', + Signet = 'signet', + Regtest = 'regtest', +} + +export type TransactionId = string; diff --git a/src/client/src/views/home/account/AccountButtons.tsx b/src/client/src/views/home/account/AccountButtons.tsx index 86f488b7..54526508 100644 --- a/src/client/src/views/home/account/AccountButtons.tsx +++ b/src/client/src/views/home/account/AccountButtons.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Anchor, X, Zap } from 'react-feather'; +import { Anchor, X, Zap, Book } from 'react-feather'; import { ColorButton } from '../../../components/buttons/colorButton/ColorButton'; import { Card } from '../../../components/generic/Styled'; import { mediaWidths } from '../../../styles/Themes'; @@ -8,6 +8,8 @@ import { CreateInvoiceCard } from './createInvoice/CreateInvoice'; import { PayCard } from './pay/Payment'; import { ReceiveOnChainCard } from './receiveOnChain/ReceiveOnChain'; import { SendOnChainCard } from './sendOnChain/SendOnChain'; +import { PegInEcashCard } from './pegInEcash/PegInEcash'; +import { PegOutEcashCard } from './pegOutEcash/PegOutEcash'; const SECTION_COLOR = '#FFD300'; @@ -15,7 +17,7 @@ const S = { grid: styled.div` display: grid; grid-gap: 8px; - grid-template-columns: 1fr 1fr 1fr 1fr; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; margin-bottom: 32px; @media (${mediaWidths.mobile}) { @@ -37,6 +39,10 @@ export const AccountButtons = () => { return setState('none')} />; case 'receive_chain': return ; + case 'pegin_ecash': + return ; + case 'pegout_ecash': + return setState('none')} />; default: return null; } @@ -95,6 +101,32 @@ export const AccountButtons = () => { )} Receive + + setState(state === 'pegin_ecash' ? 'none' : 'pegin_ecash') + } + > + {state === 'pegin_ecash' ? ( + + ) : ( + + )} + Peg In + + + setState(state === 'pegout_ecash' ? 'none' : 'pegout_ecash') + } + > + {state === 'pegout_ecash' ? ( + + ) : ( + + )} + Peg Out + {state !== 'none' && {renderContent()}} diff --git a/src/client/src/views/home/account/pegInEcash/PegInEcash.tsx b/src/client/src/views/home/account/pegInEcash/PegInEcash.tsx new file mode 100644 index 00000000..c388be3f --- /dev/null +++ b/src/client/src/views/home/account/pegInEcash/PegInEcash.tsx @@ -0,0 +1,133 @@ +import React, { useState, useEffect } from 'react'; +import styled from 'styled-components'; +import { toast } from 'react-toastify'; +import CopyToClipboard from 'react-copy-to-clipboard'; +import { useCreateAddressMutation } from '../../../../graphql/mutations/__generated__/createAddress.generated'; +import { QRCodeSVG } from 'qrcode.react'; +import { Copy } from 'react-feather'; +import { getErrorContent } from '../../../../utils/error'; +import { ColorButton } from '../../../../components/buttons/colorButton/ColorButton'; +import { mediaWidths } from '../../../../styles/Themes'; +import { SmallSelectWithValue } from '../../../../components/select'; +import { + ResponsiveLine, + SubTitle, +} from '../../../../components/generic/Styled'; + +const S = { + row: styled.div` + display: grid; + align-items: center; + gap: 16px; + grid-template-columns: 1fr 2fr; + + @media (${mediaWidths.mobile}) { + width: 100%; + display: block; + } + `, +}; + +const Responsive = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + + @media (${mediaWidths.mobile}) { + flex-direction: column; + } +`; + +const WrapRequest = styled.div` + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + margin: 24px; + font-size: 14px; +`; + +const QRWrapper = styled.div` + width: 280px; + height: 280px; + margin: 16px; + background: white; + padding: 16px; +`; + +const Column = styled.div` + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +`; + +const options = [ + { label: 'p2tr (Default)', value: 'p2tr' }, + { label: 'p2wpkh (Segwit)', value: 'p2wpkh' }, + { label: 'np2wpkh (Nested Segwit)', value: 'np2wpkh' }, +]; + +export const PegInEcashCard = () => { + const [type, setType] = useState(options[0]); + const [received, setReceived] = useState(false); + + const [createAddress, { data, loading }] = useCreateAddressMutation({ + onError: error => toast.error(getErrorContent(error)), + }); + + useEffect(() => { + data && data.createAddress && setReceived(true); + }, [data]); + + return ( + <> + {data && data.createAddress ? ( + + + + + + {data.createAddress} + toast.success('Address Copied')} + > + + + Copy + + + + + ) : ( + <> + + + Address Type: + setType((e[0] || options[1]) as any)} + options={options} + value={type} + isClearable={false} + /> + + createAddress({ variables: { type: type.value } })} + disabled={received} + withMargin={'0 0 0 16px'} + mobileMargin={'16px 0 0'} + arrow={true} + loading={loading} + mobileFullWidth={true} + > + Create Address + + + + )} + + ); +}; diff --git a/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx new file mode 100644 index 00000000..3e76fefc --- /dev/null +++ b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx @@ -0,0 +1,228 @@ +import React, { useState, useEffect } from 'react'; +import { toast } from 'react-toastify'; +import { usePayAddressMutation } from '../../../../graphql/mutations/__generated__/sendToAddress.generated'; +import { InputWithDeco } from '../../../../components/input/InputWithDeco'; +import { useBitcoinFees } from '../../../../hooks/UseBitcoinFees'; +import { + Separation, + SingleLine, + SubTitle, +} from '../../../../components/generic/Styled'; +import { getErrorContent } from '../../../../utils/error'; +import { Input } from '../../../../components/input'; +import { + MultiButton, + SingleButton, +} from '../../../../components/buttons/multiButton/MultiButton'; +import { Price, getPrice } from '../../../../components/price/Price'; +import { useConfigState } from '../../../../context/ConfigContext'; +import Modal from '../../../../components/modal/ReactModal'; +import { ColorButton } from '../../../../components/buttons/colorButton/ColorButton'; +import { renderLine } from '../../../../components/generic/helpers'; +import { usePriceState } from '../../../../context/PriceContext'; + +export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { + const { fast, halfHour, hour, minimum, dontShow } = useBitcoinFees(); + const { currency, displayValues, fetchFees } = useConfigState(); + const priceContext = usePriceState(); + const format = getPrice(currency, displayValues, priceContext); + + const [modalOpen, setModalOpen] = useState(false); + + const [address, setAddress] = useState(''); + const [tokens, setTokens] = useState(0); + const [type, setType] = useState(dontShow || !fetchFees ? 'fee' : 'none'); + const [amount, setAmount] = useState(0); + const [sendAll, setSendAll] = useState(false); + + const canSend = address !== '' && (sendAll || tokens > 0) && amount > 0; + + const [payAddress, { loading }] = usePayAddressMutation({ + onError: error => toast.error(getErrorContent(error)), + onCompleted: () => { + toast.success('Payment Sent!'); + setOpen(); + }, + refetchQueries: ['GetNodeInfo', 'GetBalances'], + }); + + useEffect(() => { + if (type === 'none' && amount === 0) { + setAmount(fast); + } + }, [type, amount, fast]); + + const feeFormat = (amount: number): JSX.Element | string => { + if (type === 'fee' || type === 'none') { + return format({ amount }); + } + return `${amount} blocks`; + }; + + const typeAmount = () => { + switch (type) { + case 'none': + case 'fee': + return { fee: amount }; + case 'target': + return { target: amount }; + default: + return {}; + } + }; + + const tokenAmount = sendAll ? { sendAll } : { tokens }; + + const renderButton = ( + onClick: () => void, + text: string, + selected: boolean + ) => ( + + {text} + + ); + + return ( + <> + setAddress(value)} + /> + + + + {renderButton(() => setSendAll(true), 'Yes', sendAll)} + {renderButton(() => setSendAll(false), 'No', !sendAll)} + + + {!sendAll && ( + setTokens(Number(value))} + /> + )} + + + + {fetchFees && + !dontShow && + renderButton( + () => { + setType('none'); + setAmount(fast); + }, + 'Auto', + type === 'none' + )} + {renderButton( + () => { + setType('fee'); + setAmount(0); + }, + 'Fee (Sats/Byte)', + type === 'fee' + )} + {renderButton( + () => { + setType('target'); + setAmount(0); + }, + 'Target Confirmations', + type === 'target' + )} + + + + {'(~'} + {feeFormat(amount * 223)} + {')'} + + ) + } + > + {type !== 'none' ? ( + 0 ? amount : undefined} + maxWidth={'500px'} + placeholder={type === 'target' ? 'Blocks' : 'Sats/Byte'} + type={'number'} + withMargin={'0 0 0 8px'} + onChange={e => setAmount(Number(e.target.value))} + /> + ) : ( + + {renderButton( + () => setAmount(fast), + `Fastest (${fast} sats)`, + amount === fast + )} + {halfHour !== fast && + renderButton( + () => setAmount(halfHour), + `Half Hour (${halfHour} sats)`, + amount === halfHour + )} + {renderButton( + () => setAmount(hour), + `Hour (${hour} sats)`, + amount === hour + )} + + )} + + {!dontShow && renderLine('Minimum', `${minimum} sat/vByte`)} + + { + setModalOpen(true); + }} + > + Send + + setModalOpen(false)}> + + Send to Address + + {renderLine('Amount:', sendAll ? 'All' : )} + {renderLine('Address:', address)} + {renderLine( + 'Fee:', + type === 'target' ? `${amount} Blocks` : `${amount} Sats/Byte` + )} + + payAddress({ + variables: { address, ...typeAmount(), ...tokenAmount }, + }) + } + disabled={!canSend} + withMargin={'16px 0 0'} + fullWidth={true} + arrow={true} + loading={loading} + > + Send To Address + + + + ); +}; diff --git a/src/server/config/configuration.ts b/src/server/config/configuration.ts index 33319353..214d3342 100644 --- a/src/server/config/configuration.ts +++ b/src/server/config/configuration.ts @@ -50,6 +50,11 @@ type AmbossConfig = { disableBalancePushes: boolean; }; +type FedimintGatewayConfig = { + apiUrl: string; + password: string; +}; + type ConfigType = { basePath: string; isProduction: boolean; @@ -69,6 +74,7 @@ type ConfigType = { headers: Headers; subscriptions: SubscriptionsConfig; amboss: AmbossConfig; + fedimintGateway: FedimintGatewayConfig; }; export default (): ConfigType => { @@ -137,6 +143,11 @@ export default (): ConfigType => { disableBalancePushes: process.env.DISABLE_BALANCE_PUSHES === 'true', }; + const fedimintGateway = { + apiUrl: process.env.FM_GATEWAY_API || '', + password: process.env.FM_GATEWAY_PASSWORD || '', + }; + const config: ConfigType = { logJson: process.env.LOG_JSON === 'true', masterPasswordOverride: process.env.MASTER_PASSWORD_OVERRIDE || '', @@ -156,6 +167,7 @@ export default (): ConfigType => { yamlEnvs, subscriptions, amboss, + fedimintGateway, }; if (!isProduction) { From 1e2ae26ec13b98eba4b90b6db66151082dcf2601 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 16 Nov 2023 20:43:39 -0800 Subject: [PATCH 03/50] feat: connect to federation card --- src/client/src/api/GatewayApi.ts | 6 +- src/client/src/api/GatewayApiProvider.tsx | 21 +++++ .../src/views/home/account/AccountInfo.tsx | 16 +--- .../account/gateway/FedimintGatewayCard.tsx | 88 +++++++++++++++++++ 4 files changed, 114 insertions(+), 17 deletions(-) create mode 100644 src/client/src/api/GatewayApiProvider.tsx create mode 100644 src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts index e7d33616..d987ffad 100644 --- a/src/client/src/api/GatewayApi.ts +++ b/src/client/src/api/GatewayApi.ts @@ -4,14 +4,12 @@ const SESSION_STORAGE_KEY = 'gateway-ui-key'; // GatewayApi is an implementation of the ApiInterface export class GatewayApi { - private baseUrl: string | undefined = process.env.REACT_APP_FM_GATEWAY_API; + private baseUrl: string | undefined = process.env.FM_GATEWAY_API; // Tests a provided password, or the one in the environment config, or the one in session storage testPassword = async (password?: string): Promise => { const tempPassword = - password || - this.getPassword() || - process.env.REACT_APP_FM_GATEWAY_PASSWORD; + password || this.getPassword() || process.env.FM_GATEWAY_PASSWORD; if (!tempPassword) { return false; diff --git a/src/client/src/api/GatewayApiProvider.tsx b/src/client/src/api/GatewayApiProvider.tsx new file mode 100644 index 00000000..dacef0ac --- /dev/null +++ b/src/client/src/api/GatewayApiProvider.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { GatewayApi } from './GatewayApi'; + +interface ApiContextProps { + // API to interact with the Gateway server + gateway: GatewayApi; +} + +export const ApiContext = React.createContext({ + gateway: new GatewayApi(), +}); + +export const ApiProvider = React.memo(function ApiProvider({ + props, + children, +}: { + props: ApiContextProps; + children: React.ReactNode; +}): JSX.Element { + return {children}; +}); diff --git a/src/client/src/views/home/account/AccountInfo.tsx b/src/client/src/views/home/account/AccountInfo.tsx index 00652a8f..b642ff0c 100644 --- a/src/client/src/views/home/account/AccountInfo.tsx +++ b/src/client/src/views/home/account/AccountInfo.tsx @@ -1,6 +1,6 @@ import React from 'react'; import styled from 'styled-components'; -import { Zap, Anchor, Pocket, Book } from 'react-feather'; +import { Zap, Anchor, Pocket } from 'react-feather'; import { useNodeBalances } from '../../../hooks/UseNodeBalances'; import Big from 'big.js'; import { renderLine } from '../../../components/generic/helpers'; @@ -15,6 +15,7 @@ import { } from '../../../components/generic/Styled'; import { Price } from '../../../components/price/Price'; import { mediaWidths } from '../../../styles/Themes'; +import { FedimintGatewayCard } from './gateway/FedimintGatewayCard'; const S = { grid: styled.div` @@ -143,18 +144,7 @@ export const AccountInfo = () => { {renderLine('Force Closures', )} - - - - - Fedimint eCash - - - {renderLine('Available', )} - {renderLine('Not Available', )} - {renderLine('Pending', )} - - + ); diff --git a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx new file mode 100644 index 00000000..3adc847b --- /dev/null +++ b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx @@ -0,0 +1,88 @@ +import React, { useState } from 'react'; +import { ApiContext } from '../../../../api/GatewayApiProvider'; +import { + Card, + CardWithTitle, + Separation, + SingleLine, + SubTitle, +} from '../../../../components/generic/Styled'; +import { Anchor } from 'react-feather'; +import { renderLine } from '../../../../components/generic/helpers'; +import { GatewayInfo } from '../../../../api/types'; +import { toast } from 'react-toastify'; +import { Input } from '../../../../components/input'; +import { ColorButton } from '../../../../components/buttons/colorButton/ColorButton'; + +export const FedimintGatewayCard = () => { + const { gateway } = React.useContext(ApiContext); + const [gatewayInfo, setGatewayInfo] = useState({ + federations: [], + fees: { + base_msat: 0, + proportional_millionths: 0, + }, + lightning_alias: '', + lightning_pub_key: '', + version_hash: '', + }); + const [inviteCode, setInviteCode] = useState(''); + + const handleEnter = () => { + gateway + .connectFederation(inviteCode) + .then(() => { + toast.success('Successfully connected to federation!'); + setInviteCode(''); + gateway + .fetchInfo() + .then(setGatewayInfo) + .catch(({ message, error }) => { + console.log(error); + toast.error(message); + }); + }) + .catch(({ message, error }) => { + console.log(error); + toast.error(message); + }); + }; + + return ( + + + + + Fedimint Ecash + + + {gatewayInfo.federations.length === 0 ? ( + <> +
+ + {renderLine('Connect to a Federation', ' ')} + +
+ + setInviteCode(e.target.value)} + /> + + Connect + + + + ) : ( + <>{renderLine('Alias', gatewayInfo.federations[0].federation_id)} + )} +
+
+ ); +}; From bf3e1aaff3b12b51cd8579d0b602182e5af3d9af Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 17 Nov 2023 16:07:27 -0800 Subject: [PATCH 04/50] feat: refactor to gateway context pattern --- src/client/next.config.js | 2 + src/client/src/api/GatewayApi.ts | 2 + src/client/src/api/GatewayApiProvider.tsx | 21 ----- src/client/src/api/types.ts | 26 ++++++ src/client/src/context/ContextProvider.tsx | 5 +- src/client/src/context/GatewayContext.tsx | 87 +++++++++++++++++++ src/client/src/hooks/UseGatewayEcashTotal.tsx | 14 +++ .../src/hooks/UseGatewayFederations.tsx | 11 +++ .../src/views/home/account/AccountInfo.tsx | 33 ++++--- .../account/gateway/FedimintGatewayCard.tsx | 77 ++++++++-------- .../home/account/pegInEcash/PegInEcash.tsx | 75 +++++++++------- .../home/account/pegOutEcash/PegOutEcash.tsx | 81 +++++++++++------ .../views/home/quickActions/QuickActions.tsx | 4 +- 13 files changed, 306 insertions(+), 132 deletions(-) delete mode 100644 src/client/src/api/GatewayApiProvider.tsx create mode 100644 src/client/src/context/GatewayContext.tsx create mode 100644 src/client/src/hooks/UseGatewayEcashTotal.tsx create mode 100644 src/client/src/hooks/UseGatewayFederations.tsx diff --git a/src/client/next.config.js b/src/client/next.config.js index 29589dc1..ce51dcaa 100644 --- a/src/client/next.config.js +++ b/src/client/next.config.js @@ -28,5 +28,7 @@ module.exports = { disableLnMarkets: process.env.DISABLE_LNMARKETS === 'true', noVersionCheck: process.env.NO_VERSION_CHECK === 'true', logoutUrl: process.env.LOGOUT_URL || '', + fmGatewayUrl: process.env.FM_GATEWAY_URL || '', + fmGatewayPassword: process.env.FM_GATEWAY_PASSWORD || '', }, }; diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts index d987ffad..3a407b76 100644 --- a/src/client/src/api/GatewayApi.ts +++ b/src/client/src/api/GatewayApi.ts @@ -141,3 +141,5 @@ export class GatewayApi { const responseToError = (res: Response): Error => { return new Error(`Status : ${res.status} \nReason : ${res.statusText}\n`); }; + +export const gatewayApi = new GatewayApi(); diff --git a/src/client/src/api/GatewayApiProvider.tsx b/src/client/src/api/GatewayApiProvider.tsx deleted file mode 100644 index dacef0ac..00000000 --- a/src/client/src/api/GatewayApiProvider.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import { GatewayApi } from './GatewayApi'; - -interface ApiContextProps { - // API to interact with the Gateway server - gateway: GatewayApi; -} - -export const ApiContext = React.createContext({ - gateway: new GatewayApi(), -}); - -export const ApiProvider = React.memo(function ApiProvider({ - props, - children, -}: { - props: ApiContextProps; - children: React.ReactNode; -}): JSX.Element { - return {children}; -}); diff --git a/src/client/src/api/types.ts b/src/client/src/api/types.ts index e98b5753..8a13441b 100644 --- a/src/client/src/api/types.ts +++ b/src/client/src/api/types.ts @@ -55,3 +55,29 @@ export enum Network { } export type TransactionId = string; + +export const dummyFederation = { + federation_id: 'test_federation_id', + balance_msat: 1000, + config: { + consensus_version: 1, + epoch_pk: 'test_epoch_pk', + federation_id: 'test_federation_id', + api_endpoints: { + 0: { + name: 'test_api_endpoint_name', + url: 'test_api_endpoint_url', + }, + }, + modules: { + 0: { + config: 'test_module_config', + kind: ModuleKind.Ln, + version: 1, + }, + }, + meta: { + federation_name: 'test_federation_name', + }, + }, +}; diff --git a/src/client/src/context/ContextProvider.tsx b/src/client/src/context/ContextProvider.tsx index a446a5d2..6b3c1a38 100644 --- a/src/client/src/context/ContextProvider.tsx +++ b/src/client/src/context/ContextProvider.tsx @@ -4,6 +4,7 @@ import { ChatProvider } from './ChatContext'; import { RebalanceProvider } from './RebalanceContext'; import { DashProvider } from './DashContext'; import { NotificationProvider } from './NotificationContext'; +import { GatewayProvider } from './GatewayContext'; export const ContextProvider: React.FC<{ children?: ReactNode }> = ({ children, @@ -12,7 +13,9 @@ export const ContextProvider: React.FC<{ children?: ReactNode }> = ({ - {children} + + {children} + diff --git a/src/client/src/context/GatewayContext.tsx b/src/client/src/context/GatewayContext.tsx new file mode 100644 index 00000000..9fda1f74 --- /dev/null +++ b/src/client/src/context/GatewayContext.tsx @@ -0,0 +1,87 @@ +import React, { + createContext, + useContext, + useReducer, + ReactNode, + useEffect, +} from 'react'; +import { GatewayInfo } from '../api/types'; +import { gatewayApi } from '../api/GatewayApi'; + +type State = { + gatewayInfo: GatewayInfo | null; + loading: boolean; + error: string | null; +}; + +type ActionType = + | { + type: 'connected'; + state: GatewayInfo; + } + | { + type: 'error'; + state: string; + }; + +type Dispatch = (action: ActionType) => void; + +export const StateContext = createContext(undefined); +export const DispatchContext = createContext(undefined); + +const initialState: State = { + gatewayInfo: null, + loading: true, + error: null, +}; + +const stateReducer = (state: State, action: ActionType): State => { + switch (action.type) { + case 'connected': + return { ...state, gatewayInfo: action.state, loading: false }; + case 'error': + return { ...state, error: action.state, loading: false }; + default: + return state; + } +}; + +const GatewayProvider: React.FC<{ children?: ReactNode }> = ({ children }) => { + const [state, dispatch] = useReducer(stateReducer, initialState); + + useEffect(() => { + gatewayApi + .fetchInfo() + .then(info => { + dispatch({ type: 'connected', state: info }); + }) + .catch(({ error }) => { + console.log('fetchInfo rejected', error); + dispatch({ type: 'connected', state: error.message }); + }); + }, []); + + return ( + + {children} + + ); +}; + +const useGatewayState = () => { + const context = useContext(StateContext); + if (context === undefined) { + throw new Error('useGatewayState must be used within a GatewayProvider'); + } + return context; +}; + +const useGatewayDispatch = () => { + const context = useContext(DispatchContext); + if (context === undefined) { + throw new Error('useGatewayDispatch must be used within a GatewayProvider'); + } + return context; +}; + +export { GatewayProvider, useGatewayState, useGatewayDispatch }; diff --git a/src/client/src/hooks/UseGatewayEcashTotal.tsx b/src/client/src/hooks/UseGatewayEcashTotal.tsx new file mode 100644 index 00000000..e26fce90 --- /dev/null +++ b/src/client/src/hooks/UseGatewayEcashTotal.tsx @@ -0,0 +1,14 @@ +import Big from 'big.js'; +import { useGatewayState } from '../context/GatewayContext'; + +export const useGatewayEcashTotal = () => { + const { gatewayInfo } = useGatewayState(); + + if (!gatewayInfo) { + return new Big(0).toString(); + } + + return gatewayInfo.federations + .reduce((acc, federation) => acc.add(federation.balance_msat), new Big(0)) + .toString(); +}; diff --git a/src/client/src/hooks/UseGatewayFederations.tsx b/src/client/src/hooks/UseGatewayFederations.tsx new file mode 100644 index 00000000..b1a1bcff --- /dev/null +++ b/src/client/src/hooks/UseGatewayFederations.tsx @@ -0,0 +1,11 @@ +import { useGatewayState } from '../context/GatewayContext'; + +export const useGatewayFederations = () => { + const { gatewayInfo } = useGatewayState(); + + if (!gatewayInfo) { + return []; + } + + return gatewayInfo.federations; +}; diff --git a/src/client/src/views/home/account/AccountInfo.tsx b/src/client/src/views/home/account/AccountInfo.tsx index b642ff0c..826eddcf 100644 --- a/src/client/src/views/home/account/AccountInfo.tsx +++ b/src/client/src/views/home/account/AccountInfo.tsx @@ -16,12 +16,16 @@ import { import { Price } from '../../../components/price/Price'; import { mediaWidths } from '../../../styles/Themes'; import { FedimintGatewayCard } from './gateway/FedimintGatewayCard'; +import { useGatewayEcashTotal } from '../../../hooks/UseGatewayEcashTotal'; +import { useGatewayState } from '../../../context/GatewayContext'; +import { GatewayInfo } from '../../../api/types'; const S = { - grid: styled.div` + grid: styled.div<{ gatewayInfo?: GatewayInfo | null }>` display: grid; grid-gap: 16px; - grid-template-columns: 1fr 1fr 1fr; + grid-template-columns: ${({ gatewayInfo }) => + gatewayInfo ? '1fr 1fr 1fr' : '1fr 1fr'}; @media (${mediaWidths.mobile}) { display: block; @@ -47,12 +51,15 @@ const sectionColor = '#FFD300'; export const AccountInfo = () => { const { onchain, lightning } = useNodeBalances(); + const { gatewayInfo } = useGatewayState(); + const totalFedimintEcash = useGatewayEcashTotal(); const totalAmount = new Big(onchain.confirmed) .add(onchain.pending) .add(onchain.closing) .add(lightning.confirmed) .add(lightning.pending) + .add(totalFedimintEcash) .toString(); const totalChain = new Big(onchain.confirmed).add(onchain.pending).toString(); @@ -75,7 +82,9 @@ export const AccountInfo = () => { return ( <> - Resume + + Network: {gatewayInfo ? gatewayInfo.network : 'Bitcoin'}{' '} + {
- - Fedimint Ecash -
- -
-
+ {gatewayInfo && ( + + Fedimint Ecash +
+ +
+
+ )} - + @@ -144,7 +155,7 @@ export const AccountInfo = () => { {renderLine('Force Closures', )} - + {gatewayInfo ? : null} ); diff --git a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx index 3adc847b..bfed00fb 100644 --- a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx +++ b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx @@ -1,71 +1,60 @@ import React, { useState } from 'react'; -import { ApiContext } from '../../../../api/GatewayApiProvider'; import { Card, CardWithTitle, + OverflowText, Separation, SingleLine, SubTitle, } from '../../../../components/generic/Styled'; -import { Anchor } from 'react-feather'; +import { Sun } from 'react-feather'; import { renderLine } from '../../../../components/generic/helpers'; -import { GatewayInfo } from '../../../../api/types'; import { toast } from 'react-toastify'; import { Input } from '../../../../components/input'; import { ColorButton } from '../../../../components/buttons/colorButton/ColorButton'; +import { Price } from '../../../../components/price/Price'; +import { useGatewayDispatch } from '../../../../context/GatewayContext'; +import { gatewayApi } from '../../../../api/GatewayApi'; +import { GatewayInfo } from '../../../../api/types'; + +interface FedimintGatewayCardProps { + gatewayInfo: GatewayInfo; +} -export const FedimintGatewayCard = () => { - const { gateway } = React.useContext(ApiContext); - const [gatewayInfo, setGatewayInfo] = useState({ - federations: [], - fees: { - base_msat: 0, - proportional_millionths: 0, - }, - lightning_alias: '', - lightning_pub_key: '', - version_hash: '', - }); +export const FedimintGatewayCard = ({ + gatewayInfo, +}: FedimintGatewayCardProps) => { + const gatewayDispath = useGatewayDispatch(); const [inviteCode, setInviteCode] = useState(''); const handleEnter = () => { - gateway - .connectFederation(inviteCode) - .then(() => { - toast.success('Successfully connected to federation!'); - setInviteCode(''); - gateway - .fetchInfo() - .then(setGatewayInfo) - .catch(({ message, error }) => { - console.log(error); - toast.error(message); - }); - }) - .catch(({ message, error }) => { - console.log(error); - toast.error(message); - }); + gatewayApi.connectFederation(inviteCode).then(() => { + gatewayApi + .fetchInfo() + .then(info => gatewayDispath({ type: 'connected', state: info })) + .catch(({ error }) => { + toast.error(error.message); + }); + }); }; return ( - + Fedimint Ecash {gatewayInfo.federations.length === 0 ? ( <> -
- - {renderLine('Connect to a Federation', ' ')} - + {/* TODO: Left Align the Text */} +
+ {'Connect to a Federation'}
setInviteCode(e.target.value)} /> @@ -80,7 +69,17 @@ export const FedimintGatewayCard = () => { ) : ( - <>{renderLine('Alias', gatewayInfo.federations[0].federation_id)} +
+ {renderLine( + 'Amount', + + )} + {renderLine( + 'Federation', + gatewayInfo.federations[0].config.meta.federation_name + )} + {renderLine('ID', gatewayInfo.federations[0].federation_id)} +
)} diff --git a/src/client/src/views/home/account/pegInEcash/PegInEcash.tsx b/src/client/src/views/home/account/pegInEcash/PegInEcash.tsx index c388be3f..11a15d8a 100644 --- a/src/client/src/views/home/account/pegInEcash/PegInEcash.tsx +++ b/src/client/src/views/home/account/pegInEcash/PegInEcash.tsx @@ -1,11 +1,9 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState } from 'react'; import styled from 'styled-components'; import { toast } from 'react-toastify'; import CopyToClipboard from 'react-copy-to-clipboard'; -import { useCreateAddressMutation } from '../../../../graphql/mutations/__generated__/createAddress.generated'; import { QRCodeSVG } from 'qrcode.react'; import { Copy } from 'react-feather'; -import { getErrorContent } from '../../../../utils/error'; import { ColorButton } from '../../../../components/buttons/colorButton/ColorButton'; import { mediaWidths } from '../../../../styles/Themes'; import { SmallSelectWithValue } from '../../../../components/select'; @@ -13,6 +11,9 @@ import { ResponsiveLine, SubTitle, } from '../../../../components/generic/Styled'; +import { Federation } from '../../../../api/types'; +import { gatewayApi } from '../../../../api/GatewayApi'; +import { useGatewayFederations } from '../../../../hooks/UseGatewayFederations'; const S = { row: styled.div` @@ -64,35 +65,30 @@ const Column = styled.div` align-items: center; `; -const options = [ - { label: 'p2tr (Default)', value: 'p2tr' }, - { label: 'p2wpkh (Segwit)', value: 'p2wpkh' }, - { label: 'np2wpkh (Nested Segwit)', value: 'np2wpkh' }, -]; - export const PegInEcashCard = () => { - const [type, setType] = useState(options[0]); - const [received, setReceived] = useState(false); - - const [createAddress, { data, loading }] = useCreateAddressMutation({ - onError: error => toast.error(getErrorContent(error)), - }); + const federations: Federation[] = useGatewayFederations(); + const [selectedFederation, setSelectedFederation] = + useState(null); + const [address, setAddress] = useState(''); - useEffect(() => { - data && data.createAddress && setReceived(true); - }, [data]); + const handleFetchPegInAddress = () => { + if (!selectedFederation) return; + gatewayApi.fetchAddress(selectedFederation.federation_id).then(address => { + setAddress(address); + }); + }; return ( <> - {data && data.createAddress ? ( + {address !== '' ? ( - + - {data.createAddress} + {address} toast.success('Address Copied')} > @@ -106,24 +102,37 @@ export const PegInEcashCard = () => { <> - Address Type: - setType((e[0] || options[1]) as any)} - options={options} - value={type} - isClearable={false} - /> + Into Federation: + {federations.length > 0 && ( + setSelectedFederation(e[0] as any)} + options={federations.map(f => ({ + label: + f.config.meta.federation_name || + 'No connected Federations', + value: f.federation_id || 'No connected Federations', + }))} + value={{ + label: + federations[0].config.meta.federation_name || + 'No connected Federations', + value: + federations[0].federation_id || + 'No connected Federations', + }} + isClearable={false} + /> + )} createAddress({ variables: { type: type.value } })} - disabled={received} + onClick={() => handleFetchPegInAddress()} + disabled={false} withMargin={'0 0 0 16px'} mobileMargin={'16px 0 0'} arrow={true} - loading={loading} mobileFullWidth={true} > - Create Address + Create Peg In Address diff --git a/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx index 3e76fefc..95df48ef 100644 --- a/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx +++ b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx @@ -1,6 +1,5 @@ import React, { useState, useEffect } from 'react'; import { toast } from 'react-toastify'; -import { usePayAddressMutation } from '../../../../graphql/mutations/__generated__/sendToAddress.generated'; import { InputWithDeco } from '../../../../components/input/InputWithDeco'; import { useBitcoinFees } from '../../../../hooks/UseBitcoinFees'; import { @@ -8,7 +7,6 @@ import { SingleLine, SubTitle, } from '../../../../components/generic/Styled'; -import { getErrorContent } from '../../../../utils/error'; import { Input } from '../../../../components/input'; import { MultiButton, @@ -20,6 +18,10 @@ import Modal from '../../../../components/modal/ReactModal'; import { ColorButton } from '../../../../components/buttons/colorButton/ColorButton'; import { renderLine } from '../../../../components/generic/helpers'; import { usePriceState } from '../../../../context/PriceContext'; +import { Federation, dummyFederation } from '../../../../api/types'; +import { SmallSelectWithValue } from '../../../../components/select'; +import { useGatewayFederations } from '../../../../hooks/UseGatewayFederations'; +import { gatewayApi } from '../../../../api/GatewayApi'; export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { const { fast, halfHour, hour, minimum, dontShow } = useBitcoinFees(); @@ -34,17 +36,26 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { const [type, setType] = useState(dontShow || !fetchFees ? 'fee' : 'none'); const [amount, setAmount] = useState(0); const [sendAll, setSendAll] = useState(false); + const federations: Federation[] = useGatewayFederations(); + const [selectedFederation, setSelectedFederation] = useState(dummyFederation); const canSend = address !== '' && (sendAll || tokens > 0) && amount > 0; - const [payAddress, { loading }] = usePayAddressMutation({ - onError: error => toast.error(getErrorContent(error)), - onCompleted: () => { - toast.success('Payment Sent!'); + const handlePegOut = ( + federationId: string, + tokenAmount: { sendAll?: boolean; tokens?: number }, + address: string + ) => { + const amountSat = + sendAll && selectedFederation.balance_msat + ? selectedFederation.balance_msat + : tokenAmount.tokens || 0; + + gatewayApi.requestWithdrawal(federationId, amountSat, address).then(() => { + toast.success('Withdrawal request sent'); setOpen(); - }, - refetchQueries: ['GetNodeInfo', 'GetBalances'], - }); + }); + }; useEffect(() => { if (type === 'none' && amount === 0) { @@ -59,17 +70,17 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { return `${amount} blocks`; }; - const typeAmount = () => { - switch (type) { - case 'none': - case 'fee': - return { fee: amount }; - case 'target': - return { target: amount }; - default: - return {}; - } - }; + // const typeAmount = () => { + // switch (type) { + // case 'none': + // case 'fee': + // return { fee: amount }; + // case 'target': + // return { target: amount }; + // default: + // return {}; + // } + // }; const tokenAmount = sendAll ? { sendAll } : { tokens }; @@ -86,12 +97,32 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { return ( <> setAddress(value)} /> + + + setSelectedFederation((e[0] || dummyFederation) as any) + } + options={federations.map(f => ({ + label: f.config.meta.federation_name || 'No connected Federations', + value: f.federation_id || 'No connected Federations', + }))} + value={{ + label: + federations[0].config.meta.federation_name || + 'No connected Federations', + value: federations[0].federation_id || 'No connected Federations', + }} + isClearable={false} + maxWidth={'500px'} + /> + + {renderButton(() => setSendAll(true), 'Yes', sendAll)} @@ -190,7 +221,7 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { { setModalOpen(true); @@ -210,15 +241,13 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { )} - payAddress({ - variables: { address, ...typeAmount(), ...tokenAmount }, - }) + handlePegOut(selectedFederation.federation_id, tokenAmount, address) } disabled={!canSend} withMargin={'16px 0 0'} fullWidth={true} arrow={true} - loading={loading} + loading={false} > Send To Address diff --git a/src/client/src/views/home/quickActions/QuickActions.tsx b/src/client/src/views/home/quickActions/QuickActions.tsx index d36b872e..0dcbe79b 100644 --- a/src/client/src/views/home/quickActions/QuickActions.tsx +++ b/src/client/src/views/home/quickActions/QuickActions.tsx @@ -29,7 +29,8 @@ export const QuickCard = styled.div` border-radius: 4px; border: 1px solid ${cardBorderColor}; height: 100px; - width: 100px; + flex-grow: 1; + flex: 1 0 auto; display: flex; flex-direction: column; justify-content: center; @@ -61,6 +62,7 @@ export const QuickTitle = styled.div` const QuickRow = styled.div` display: flex; flex-wrap: wrap; + justify-content: space-between; `; export const QuickActions = () => { From caf995b8cd20623339e4d76e8acf3bb4ab8ef7ba Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 17 Nov 2023 17:49:26 -0800 Subject: [PATCH 05/50] fix: minor run fixes --- src/client/src/hooks/UseGatewayEcashTotal.tsx | 2 +- .../src/views/home/account/AccountInfo.tsx | 2 +- .../gateway/.FedimintGatewayCard.tsx.swp | Bin 0 -> 12288 bytes .../account/gateway/FedimintGatewayCard.tsx | 7 +++---- 4 files changed, 5 insertions(+), 6 deletions(-) create mode 100644 src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp diff --git a/src/client/src/hooks/UseGatewayEcashTotal.tsx b/src/client/src/hooks/UseGatewayEcashTotal.tsx index e26fce90..ce010cf6 100644 --- a/src/client/src/hooks/UseGatewayEcashTotal.tsx +++ b/src/client/src/hooks/UseGatewayEcashTotal.tsx @@ -4,7 +4,7 @@ import { useGatewayState } from '../context/GatewayContext'; export const useGatewayEcashTotal = () => { const { gatewayInfo } = useGatewayState(); - if (!gatewayInfo) { + if (!gatewayInfo || !gatewayInfo.federations) { return new Big(0).toString(); } diff --git a/src/client/src/views/home/account/AccountInfo.tsx b/src/client/src/views/home/account/AccountInfo.tsx index 826eddcf..d5e2ef99 100644 --- a/src/client/src/views/home/account/AccountInfo.tsx +++ b/src/client/src/views/home/account/AccountInfo.tsx @@ -83,7 +83,7 @@ export const AccountInfo = () => { <> - Network: {gatewayInfo ? gatewayInfo.network : 'Bitcoin'}{' '} + Network: {gatewayInfo?.network ? gatewayInfo.network : 'Bitcoin'}{' '} diff --git a/src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp b/src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp new file mode 100644 index 0000000000000000000000000000000000000000..8bcdd22863f83ad35d13ae1a2bd1eb2636104c2b GIT binary patch literal 12288 zcmeI2O^6&t6vr#Uuc$E+ji8`Z)A&B2R!(StV+DoPIGzxrdQW@abxDydeUyQmgzHgmEdzfA@BUL#$Vn_cklb2kV}!jrHXI%c@B2T>@xFCMA4<$ zb8$3#*bX9(1tSe#RSuoS$m_OwC=;hCWUE_u>Oy*v2xk-7Z8RJdg+7l}MG||C7YNv9 zU)KfSNSs#G<_`0`sEgtzlYE11Ij6WU+9H&v^ZNxB`?gFrNBTFnMuA&ffxYC(!*khI ze|+j7ePI6!x3(N+^hN=rfKk9GU=%P47zK<1MuA&Q0omC_Uc;Do7vo+luDeFA#jUv* z1&jhl0i%FXz$jo8FbWt2i~>dhqkvJsDDXd2fcb zkHP!k3fKlcuna2T=lclx47?5;@cUjuJ_MJ63yy+^!1a3x`5XKNz5`!^cfn;)11@+B z{BjQ=*TCmMf>mIHDewq503HN;z@K*$@+-IoJ^|Yx0WX0=;8F0~9zs3^F}Mg$fjO`X z{B##$0B->aPJ@HspF0Wp5qu4;Ud<#9l09U~W z;BD|GP&&T>%*QBT6fg?(73du$luoN(l)8>O!L)|sQL91*{8(047MFLh?iCez8(*vs z>Qqr0b9I#Jj0kzfT3WPbXmMU@DQrY`gQJc~5rxV5>ILogqVR`2k94Fw-@uO-g$>cP z+gvi;XUN)|sHTIDg;QHa1l9~0ln)0!R5214Bsmugk5krG$H8jp4dSY^fQ25v*iM-2 zQD;~wO0DCWi~kmg3#n-$w*p>EQ`%;6Q-t%>s&+Q1;z)kAXs%SUuo=EfwLqkbEKXIjz-d)EaZ? zYGWH2!iYpFMs$ykn-CuUj?sk6rG5t$Zc7BurM=FAE+1PglxF36OyiMv0_O2n6kuuA zrp~cMa+>!5nSDMr5}~^kcDlpLyOZY8b;fom7Vz119yfw$W0h~pW2sflC6y6nRNEju z*BP=LietihoPA0yL^}7hx(u&IC1vUyqN`^Y&(6~`ydmlFKr}-tTb!y;=pjef#vQDt zNt?_Lc-WM!Y?iC^S#7bqE4;(DKeSS03x6Cq0(5U|&{fqla}!6Y&aG z#N3ggjlIJ}xGJyaL&?4lrP!FuZX6QG!oIyx=Qu7v_~6p)TWkg zJN+Nl5ssS8#DeRxQPDdlXkwcpCYb0Ap=VK13bmsH$Skpuox*k@zttV(&(56!_98?X zW{0#p>H+Iyrg~c~X;0|A@1dSOwi3r1Jj3+oneH{qrZ@8^RLa#`WqYyTD(1|SvssyF zZ0UA`*P*^~e~R!$8+4P09OHIcJm~OvXxdb|DJ9FhYH;jV9;2tS{3c#k)SH73drHfU qrrv)B&yDP^pEK2+p8M7P(EDLoFwFedimint Ecash - {gatewayInfo.federations.length === 0 ? ( + {!gatewayInfo.federations || gatewayInfo.federations.length === 0 ? ( <> {/* TODO: Left Align the Text */} -
- {'Connect to a Federation'} +
+ {'Connect to a Federation'}
Date: Fri, 17 Nov 2023 19:52:34 -0800 Subject: [PATCH 06/50] feat: add nix flake --- flake.nix | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index b9a59cd0..9871f8ea 100644 --- a/flake.nix +++ b/flake.nix @@ -2,14 +2,26 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; flake-utils.url = "github:numtide/flake-utils"; + fedimint = { + url = + "github:fedimint/fedimint?rev=f58f1913e62b6529a2ff36ec5c89a3852aba7ca7"; + }; }; outputs = { self, nixpkgs, flake-utils, fedimint }: flake-utils.lib.eachDefaultSystem (system: - let pkgs = import nixpkgs { inherit system; }; + let + pkgs = import nixpkgs { inherit system; }; + fmLib = fedimint.lib.${system}; in { devShells = fmLib.devShells // { default = fmLib.devShells.default.overrideAttrs (prev: { - nativeBuildInputs = [ pkgs.nodejs ] ++ prev.nativeBuildInputs; + nativeBuildInputs = [ + pkgs.mprocs + pkgs.nodejs + fedimint.packages.${system}.devimint + fedimint.packages.${system}.gateway-pkgs + fedimint.packages.${system}.fedimint-pkgs + ] ++ prev.nativeBuildInputs; shellHook = '' npm install ''; From af8feba84381e7deb630be8328b94f704e85562d Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Mon, 20 Nov 2023 07:25:26 -0800 Subject: [PATCH 07/50] fix: local_data dir for dev --- .gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4729ac5e..03b17961 100644 --- a/.gitignore +++ b/.gitignore @@ -44,5 +44,6 @@ lerna-debug.log* # config files config.yaml -data -data/* + +# For Dev +local_data From f241ee832ca4e9ce11dbc671bb5bff83343b2cc1 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Mon, 20 Nov 2023 07:25:26 -0800 Subject: [PATCH 08/50] devimint setup scripts fix: local_data dir for dev fix: yaml config file write to temp --- mprocs-nix-gateway.yml | 30 +++++++++++++++++ package.json | 3 +- scripts/mprocs-nix-gateway.sh | 37 +++++++++++++++++++++ scripts/mprocs-nix-guardian.sh | 21 ++++++++++++ scripts/mprocs-nix.sh | 43 +++++++++++++++++++++++++ scripts/mprocs-user-shell.sh | 41 +++++++++++++++++++++++ scripts/replace-react-env.js | 59 ++++++++++++++++++++++++++++++++++ 7 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 mprocs-nix-gateway.yml create mode 100644 scripts/mprocs-nix-gateway.sh create mode 100644 scripts/mprocs-nix-guardian.sh create mode 100755 scripts/mprocs-nix.sh create mode 100644 scripts/mprocs-user-shell.sh create mode 100644 scripts/replace-react-env.js diff --git a/mprocs-nix-gateway.yml b/mprocs-nix-gateway.yml new file mode 100644 index 00000000..2f2f1811 --- /dev/null +++ b/mprocs-nix-gateway.yml @@ -0,0 +1,30 @@ +procs: + user: + shell: bash --init-file scripts/mprocs-user-shell.sh + stop: SIGKILL + thunderhub: + shell: bash --init-file scripts/mprocs-nix-gateway.sh + stop: SIGKILL + env: + PORT: '3000' + BROWSER: none + fedimint0: + shell: tail -n +0 -F $FM_LOGS_DIR/fedimintd-0.log + fedimint1: + shell: tail -n +0 -F $FM_LOGS_DIR/fedimintd-1.log + fedimint2: + shell: tail -n +0 -F $FM_LOGS_DIR/fedimintd-2.log + fedimint3: + shell: tail -n +0 -F $FM_LOGS_DIR/fedimintd-3.log + cln-gw: + shell: tail -n +0 -F $FM_LOGS_DIR/gatewayd-cln.log + lnd-gw: + shell: tail -n +0 -F $FM_LOGS_DIR/gatewayd-lnd.log + cln: + shell: tail -n +0 -F $FM_LOGS_DIR/lightningd.log + lnd: + shell: tail -n +0 -F $FM_LOGS_DIR/lnd.log + bitcoind: + shell: tail -n +0 -F $FM_LOGS_DIR/bitcoind.log + devimint: + shell: tail -n +0 -F $FM_LOGS_DIR/devimint.log diff --git a/package.json b/package.json index d306c8d1..4d92b229 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "update": "sh ./scripts/updateToLatest.sh", "build:image": "docker build --pull --rm -f Dockerfile -t thunderhub:testing '.'", "build:image:base": "docker build --pull --rm -f Dockerfile --build-arg BASE_PATH=/thub -t thunderhub:testing .", - "prepare": "husky install" + "prepare": "husky install", + "nix-gateway": "./scripts/mprocs-nix.sh dev-fed mprocs-nix-gateway.yml" }, "dependencies": { "@apollo/client": "^3.8.8", diff --git a/scripts/mprocs-nix-gateway.sh b/scripts/mprocs-nix-gateway.sh new file mode 100644 index 00000000..e6616bbd --- /dev/null +++ b/scripts/mprocs-nix-gateway.sh @@ -0,0 +1,37 @@ +# shellcheck shell=bash + +set -eo pipefail + +eval "$(devimint env)" + +echo Waiting for devimint to start up fedimint and gateway + +STATUS="$(devimint wait)" +if [ "$STATUS" = "ERROR" ] +then + echo "fedimint didn't start correctly" + echo "See other panes for errors" + exit 1 +fi + +TEMP_FILE=$(mktemp) +FM_LND_RPC_STRIPPED=$(echo $FM_LND_RPC_ADDR | sed 's/http[s]\?:\/\///') + +cat << EOF > "$TEMP_FILE" +masterPassword: password +accounts: + - name: test-regtest + serverUrl: $FM_LND_RPC_STRIPPED + macaroonPath: $FM_LND_MACAROON + certificatePath: $FM_LND_TLS_CERT +EOF + +echo $TEMP_FILE +# ----------- +# Fedimint Config +# ----------- +export ACCOUNT_CONFIG_PATH=$TEMP_FILE +export FM_GATEWAY_URL=$FM_GATEWAY_API_ADDR +export FM_GATEWAY_PASSWORD=$FM_GATEWAY_PASSWORD + +npm run start:dev diff --git a/scripts/mprocs-nix-guardian.sh b/scripts/mprocs-nix-guardian.sh new file mode 100644 index 00000000..6cfc17ec --- /dev/null +++ b/scripts/mprocs-nix-guardian.sh @@ -0,0 +1,21 @@ +# shellcheck shell=bash + +set -eo pipefail + +eval "$(devimint env)" + +echo Waiting for devimint to start up fedimint and gateway + +STATUS="$(devimint wait)" +if [ "$STATUS" = "ERROR" ] +then + echo "fedimint didn't start correctly" + echo "See other panes for errors" + exit 1 +fi + +# Conigure UI env from devimint env +CONFIG_PORT=$(($FM_PORT_FEDIMINTD_BASE + 1)) # Fedimintd 0 config AOU port is always base + 1 +export REACT_APP_FM_CONFIG_API="ws://127.0.0.1:$CONFIG_PORT" + +yarn dev:guardian-ui diff --git a/scripts/mprocs-nix.sh b/scripts/mprocs-nix.sh new file mode 100755 index 00000000..80ab44a3 --- /dev/null +++ b/scripts/mprocs-nix.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +if [[ -z "${IN_NIX_SHELL:-}" ]]; then + echo "Run "nix develop" first" + exit 1 +fi + +DEVIMINT_COMMAND=$1 +MPROCS_PATH=$2 + +export FM_TEST_DIR="$TMP/fm-$(LC_ALL=C tr -dc A-Za-z0-9 /dev/null & +echo $! >> $FM_PID_FILE + + +# Function for killing processes stored in FM_PID_FILE in reverse-order they were created in +function kill_fedimint_processes { + echo "Killing fedimint processes" + PIDS=$(cat $FM_PID_FILE | sed '1!G;h;$!d') # sed reverses order + if [ -n "$PIDS" ] + then + kill $PIDS 2>/dev/null + fi + rm -f $FM_PID_FILE +} + +trap kill_fedimint_processes EXIT + +echo "PATH: $MPROCS_PATH" +mprocs -c $MPROCS_PATH diff --git a/scripts/mprocs-user-shell.sh b/scripts/mprocs-user-shell.sh new file mode 100644 index 00000000..5a14e079 --- /dev/null +++ b/scripts/mprocs-user-shell.sh @@ -0,0 +1,41 @@ +# shellcheck shell=bash + +eval "$(devimint env)" + +echo Waiting for devimint to start up fedimint + +STATUS="$(devimint wait)" +if [ "$STATUS" = "ERROR" ] +then + echo "fedimint didn't start correctly" + echo "See other panes for errors" + exit 1 +fi + +alias lightning-cli="\$FM_LIGHTNING_CLI" +alias lncli="\$FM_LNCLI" +alias bitcoin-cli="\$FM_BTC_CLIENT" +alias fedimint-cli="\$FM_MINT_CLIENT" +alias gateway-cln="\$FM_GWCLI_CLN" +alias gateway-lnd="\$FM_GWCLI_LND" + +eval "$(fedimint-cli completion bash)" || true +eval "$(gateway-cli completion bash)" || true + +echo Done! +echo +echo "This shell provides the following aliases:" +echo "" +echo " fedimint-cli - cli client to interact with the federation" +echo " lightning-cli - cli client for Core Lightning" +echo " lncli - cli client for LND" +echo " bitcoin-cli - cli client for bitcoind" +echo " gateway-cln - cli client for the CLN gateway" +echo " gateway-lnd - cli client for the LND gateway" +echo +echo "Use '--help' on each command for more information" +echo "" +echo "Important mprocs key sequences:" +echo "" +echo " ctrl+a - switching between panels" +echo " ctrl+a q - quit mprocs" diff --git a/scripts/replace-react-env.js b/scripts/replace-react-env.js new file mode 100644 index 00000000..4388c21e --- /dev/null +++ b/scripts/replace-react-env.js @@ -0,0 +1,59 @@ +const fs = require('fs'); +const path = require('path'); + +const targetDir = process.argv[2]; + +if (!targetDir) { + console.log('Please provide a directory path.'); + process.exit(1); +} + +/** + * Give a file path, replace all {{REACT_APP_ENV}} in its contents with + * their actual environment variable value. + */ +function processFile(filePath) { + const content = fs.readFileSync(filePath, 'utf8'); + const envVariableRegex = /\{\{REACT_APP_([^}]+)\}\}/g; + const matches = content.match(envVariableRegex); + + if (!matches) { + return; + } + + let replacedContent = content; + matches.forEach((match) => { + // Trim off {{ and }} from match + const variableName = match.slice(2, -2); + const envValue = process.env[variableName] || ''; + replacedContent = replacedContent.replace(match, envValue); + }); + + fs.writeFileSync(filePath, replacedContent, 'utf8'); +} + +function processDirectory(directoryPath) { + const files = fs.readdirSync(directoryPath); + + files.forEach((file) => { + const filePath = path.join(directoryPath, file); + const stats = fs.statSync(filePath); + + if (stats.isDirectory()) { + processDirectory(filePath); + } else { + processFile(filePath); + } + }); +} + +try { + processDirectory(targetDir); + console.log('Environment variables replaced successfully.'); +} catch (error) { + console.error( + 'An error occurred while replacing environment variables:', + error + ); + process.exit(1); +} From bbd527dedac4e3a5ea832fe370f30b27a113332b Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 23 Nov 2023 14:42:53 -0800 Subject: [PATCH 09/50] fix: fix gateway password and url assignment from publicRuntimeConfig --- .direnv/flake-profile | 1 + .direnv/flake-profile-1-link | 1 + .envrc | 1 + scripts/mprocs-nix-gateway.sh | 3 +- src/client/next.config.js | 2 +- src/client/src/api/GatewayApi.ts | 51 ++++--------------- .../account/gateway/FedimintGatewayCard.tsx | 9 +++- 7 files changed, 23 insertions(+), 45 deletions(-) create mode 120000 .direnv/flake-profile create mode 120000 .direnv/flake-profile-1-link create mode 100644 .envrc diff --git a/.direnv/flake-profile b/.direnv/flake-profile new file mode 120000 index 00000000..0c05709d --- /dev/null +++ b/.direnv/flake-profile @@ -0,0 +1 @@ +flake-profile-1-link \ No newline at end of file diff --git a/.direnv/flake-profile-1-link b/.direnv/flake-profile-1-link new file mode 120000 index 00000000..3a6b04ce --- /dev/null +++ b/.direnv/flake-profile-1-link @@ -0,0 +1 @@ +/nix/store/xnjqp9yyak09ca78kr0in3v60fw1lqgk-nix-shell-env \ No newline at end of file diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..3550a30f --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/scripts/mprocs-nix-gateway.sh b/scripts/mprocs-nix-gateway.sh index e6616bbd..1bd376bc 100644 --- a/scripts/mprocs-nix-gateway.sh +++ b/scripts/mprocs-nix-gateway.sh @@ -26,12 +26,11 @@ accounts: certificatePath: $FM_LND_TLS_CERT EOF -echo $TEMP_FILE # ----------- # Fedimint Config # ----------- export ACCOUNT_CONFIG_PATH=$TEMP_FILE -export FM_GATEWAY_URL=$FM_GATEWAY_API_ADDR +export FM_GATEWAY_API=$FM_GATEWAY_API_ADDR export FM_GATEWAY_PASSWORD=$FM_GATEWAY_PASSWORD npm run start:dev diff --git a/src/client/next.config.js b/src/client/next.config.js index ce51dcaa..dd08183b 100644 --- a/src/client/next.config.js +++ b/src/client/next.config.js @@ -28,7 +28,7 @@ module.exports = { disableLnMarkets: process.env.DISABLE_LNMARKETS === 'true', noVersionCheck: process.env.NO_VERSION_CHECK === 'true', logoutUrl: process.env.LOGOUT_URL || '', - fmGatewayUrl: process.env.FM_GATEWAY_URL || '', + fmGatewayUrl: process.env.FM_GATEWAY_API || '', fmGatewayPassword: process.env.FM_GATEWAY_PASSWORD || '', }, }; diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts index 3a407b76..09f9beba 100644 --- a/src/client/src/api/GatewayApi.ts +++ b/src/client/src/api/GatewayApi.ts @@ -1,41 +1,16 @@ +// import { publicRuntimeConfig } from '../../next.config'; +// import { publicRuntimeConfig } from '../../next.config'; +import getConfig from 'next/config'; import { GatewayInfo, Federation } from './types'; -const SESSION_STORAGE_KEY = 'gateway-ui-key'; +// const SESSION_STORAGE_KEY = 'gateway-ui-key'; + +const { publicRuntimeConfig } = getConfig(); // GatewayApi is an implementation of the ApiInterface export class GatewayApi { - private baseUrl: string | undefined = process.env.FM_GATEWAY_API; - - // Tests a provided password, or the one in the environment config, or the one in session storage - testPassword = async (password?: string): Promise => { - const tempPassword = - password || this.getPassword() || process.env.FM_GATEWAY_PASSWORD; - - if (!tempPassword) { - return false; - } - - // Replace with temp password to check. - sessionStorage.setItem(SESSION_STORAGE_KEY, tempPassword); - - try { - await this.fetchInfo(); - return true; - } catch (err) { - // TODO: make sure error is auth error, not unrelated - console.error(err); - this.clearPassword(); - return false; - } - }; - - private getPassword = (): string | null => { - return sessionStorage.getItem(SESSION_STORAGE_KEY); - }; - - clearPassword = () => { - sessionStorage.removeItem(SESSION_STORAGE_KEY); - }; + private baseUrl: string | undefined = publicRuntimeConfig.fmGatewayUrl; + private password: string | undefined = publicRuntimeConfig.fmGatewayPassword; private post = async (api: string, body: unknown): Promise => { if (this.baseUrl === undefined) { @@ -44,18 +19,11 @@ export class GatewayApi { ); } - const password = this.getPassword(); - if (!password) { - throw new Error( - 'Misconfigured Gateway API. Make sure gateway password is configured appropriately' - ); - } - return fetch(`${this.baseUrl}/${api}`, { method: 'POST', headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${password}`, + Authorization: `Bearer ${this.password}`, }, body: JSON.stringify(body), }); @@ -72,6 +40,7 @@ export class GatewayApi { throw responseToError(res); } catch (error) { + console.log(`baseUrl`, this.baseUrl); return Promise.reject({ message: 'Error fetching gateway info', error }); } }; diff --git a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx index ace9cd2f..4fbc76c6 100644 --- a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx +++ b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx @@ -37,6 +37,10 @@ export const FedimintGatewayCard = ({ }); }; + const formatFederationId = (id: string) => { + return `${id.slice(0, 6)}...${id.slice(-6)}`; + }; + return ( @@ -77,7 +81,10 @@ export const FedimintGatewayCard = ({ 'Federation', gatewayInfo.federations[0].config.meta.federation_name )} - {renderLine('ID', gatewayInfo.federations[0].federation_id)} + {renderLine( + 'ID', + formatFederationId(gatewayInfo.federations[0].federation_id) + )}
)}
From 1503034ffd086cdfa64433277c85deb6bb0ad492 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 23 Nov 2023 15:11:32 -0800 Subject: [PATCH 10/50] fix: fix peg out command --- .../src/views/home/account/AccountButtons.tsx | 20 +++++----- .../home/account/pegOutEcash/PegOutEcash.tsx | 37 ++++++++++--------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/client/src/views/home/account/AccountButtons.tsx b/src/client/src/views/home/account/AccountButtons.tsx index 54526508..9aa8aba5 100644 --- a/src/client/src/views/home/account/AccountButtons.tsx +++ b/src/client/src/views/home/account/AccountButtons.tsx @@ -39,10 +39,10 @@ export const AccountButtons = () => { return setState('none')} />; case 'receive_chain': return ; - case 'pegin_ecash': - return ; case 'pegout_ecash': return setState('none')} />; + case 'pegin_ecash': + return ; default: return null; } @@ -102,30 +102,30 @@ export const AccountButtons = () => { Receive
- setState(state === 'pegin_ecash' ? 'none' : 'pegin_ecash') + setState(state === 'pegout_ecash' ? 'none' : 'pegout_ecash') } > - {state === 'pegin_ecash' ? ( + {state === 'pegout_ecash' ? ( ) : ( )} - Peg In + Peg Out - setState(state === 'pegout_ecash' ? 'none' : 'pegout_ecash') + setState(state === 'pegin_ecash' ? 'none' : 'pegin_ecash') } > - {state === 'pegout_ecash' ? ( + {state === 'pegin_ecash' ? ( ) : ( )} - Peg Out + Peg In {state !== 'none' && {renderContent()}} diff --git a/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx index 95df48ef..c43f60f9 100644 --- a/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx +++ b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx @@ -18,7 +18,7 @@ import Modal from '../../../../components/modal/ReactModal'; import { ColorButton } from '../../../../components/buttons/colorButton/ColorButton'; import { renderLine } from '../../../../components/generic/helpers'; import { usePriceState } from '../../../../context/PriceContext'; -import { Federation, dummyFederation } from '../../../../api/types'; +import { Federation } from '../../../../api/types'; import { SmallSelectWithValue } from '../../../../components/select'; import { useGatewayFederations } from '../../../../hooks/UseGatewayFederations'; import { gatewayApi } from '../../../../api/GatewayApi'; @@ -36,25 +36,32 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { const [type, setType] = useState(dontShow || !fetchFees ? 'fee' : 'none'); const [amount, setAmount] = useState(0); const [sendAll, setSendAll] = useState(false); + const [selectedFederation, setSelectedFederation] = useState(0); const federations: Federation[] = useGatewayFederations(); - const [selectedFederation, setSelectedFederation] = useState(dummyFederation); const canSend = address !== '' && (sendAll || tokens > 0) && amount > 0; const handlePegOut = ( - federationId: string, + federationIdx: number, tokenAmount: { sendAll?: boolean; tokens?: number }, address: string ) => { - const amountSat = - sendAll && selectedFederation.balance_msat - ? selectedFederation.balance_msat - : tokenAmount.tokens || 0; + const amountSat = sendAll + ? federations[selectedFederation].balance_msat + : tokenAmount.tokens || 0; - gatewayApi.requestWithdrawal(federationId, amountSat, address).then(() => { - toast.success('Withdrawal request sent'); - setOpen(); - }); + console.log('selectedFederation', selectedFederation); + console.log('amountSat', amountSat); + gatewayApi + .requestWithdrawal( + federations[federationIdx].federation_id, + amountSat, + address + ) + .then(() => { + toast.success('Withdrawal request sent'); + setOpen(); + }); }; useEffect(() => { @@ -105,9 +112,7 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { - setSelectedFederation((e[0] || dummyFederation) as any) - } + callback={e => setSelectedFederation(Number(e))} options={federations.map(f => ({ label: f.config.meta.federation_name || 'No connected Federations', value: f.federation_id || 'No connected Federations', @@ -240,9 +245,7 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { type === 'target' ? `${amount} Blocks` : `${amount} Sats/Byte` )} - handlePegOut(selectedFederation.federation_id, tokenAmount, address) - } + onClick={() => handlePegOut(selectedFederation, tokenAmount, address)} disabled={!canSend} withMargin={'16px 0 0'} fullWidth={true} From ea65031f319964dcbdb6806b7688558fe988de3a Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 24 Nov 2023 14:23:58 -0800 Subject: [PATCH 11/50] fix: peg in ecash card --- .../views/home/account/pegInEcash/PegInEcash.tsx | 15 +++++++++------ .../home/account/pegOutEcash/PegOutEcash.tsx | 6 +++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/client/src/views/home/account/pegInEcash/PegInEcash.tsx b/src/client/src/views/home/account/pegInEcash/PegInEcash.tsx index 11a15d8a..cf96da9d 100644 --- a/src/client/src/views/home/account/pegInEcash/PegInEcash.tsx +++ b/src/client/src/views/home/account/pegInEcash/PegInEcash.tsx @@ -67,15 +67,18 @@ const Column = styled.div` export const PegInEcashCard = () => { const federations: Federation[] = useGatewayFederations(); - const [selectedFederation, setSelectedFederation] = - useState(null); + const [selectedFederation, setSelectedFederation] = useState(0); const [address, setAddress] = useState(''); const handleFetchPegInAddress = () => { - if (!selectedFederation) return; - gatewayApi.fetchAddress(selectedFederation.federation_id).then(address => { - setAddress(address); - }); + gatewayApi + .fetchAddress(federations[selectedFederation].federation_id) + .then(address => { + setAddress(address); + }) + .catch(e => { + toast.error('Error fetching peg out address', e); + }); }; return ( diff --git a/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx index c43f60f9..2c4b6dfe 100644 --- a/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx +++ b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx @@ -49,9 +49,6 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { const amountSat = sendAll ? federations[selectedFederation].balance_msat : tokenAmount.tokens || 0; - - console.log('selectedFederation', selectedFederation); - console.log('amountSat', amountSat); gatewayApi .requestWithdrawal( federations[federationIdx].federation_id, @@ -61,6 +58,9 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { .then(() => { toast.success('Withdrawal request sent'); setOpen(); + }) + .catch(e => { + toast.error('Error sending withdrawal request', e); }); }; From 8872b236527a7472399c4ccbe2984a7528e93e82 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Tue, 28 Nov 2023 11:42:34 -0800 Subject: [PATCH 12/50] feat: fedimint 0.2 api updates --- .direnv/flake-profile | 1 - .direnv/flake-profile-1-link | 1 - flake.lock | 129 ++++++------------------------- flake.nix | 2 +- src/client/src/api/GatewayApi.ts | 9 ++- 5 files changed, 31 insertions(+), 111 deletions(-) delete mode 120000 .direnv/flake-profile delete mode 120000 .direnv/flake-profile-1-link diff --git a/.direnv/flake-profile b/.direnv/flake-profile deleted file mode 120000 index 0c05709d..00000000 --- a/.direnv/flake-profile +++ /dev/null @@ -1 +0,0 @@ -flake-profile-1-link \ No newline at end of file diff --git a/.direnv/flake-profile-1-link b/.direnv/flake-profile-1-link deleted file mode 120000 index 3a6b04ce..00000000 --- a/.direnv/flake-profile-1-link +++ /dev/null @@ -1 +0,0 @@ -/nix/store/xnjqp9yyak09ca78kr0in3v60fw1lqgk-nix-shell-env \ No newline at end of file diff --git a/flake.lock b/flake.lock index c4f8c2bc..1792105c 100644 --- a/flake.lock +++ b/flake.lock @@ -43,27 +43,24 @@ }, "crane": { "inputs": { - "flake-compat": "flake-compat", - "flake-utils": "flake-utils_3", "nixpkgs": [ "fedimint", "flakebox", "nixpkgs" - ], - "rust-overlay": "rust-overlay" + ] }, "locked": { - "lastModified": 1697596235, - "narHash": "sha256-4VTrrTdoA1u1wyf15krZCFl3c29YLesSNioYEgfb2FY=", - "owner": "dpc", + "lastModified": 1699217310, + "narHash": "sha256-xpW3VFUG7yE6UE6Wl0dhqencuENSkV7qpnpe9I8VbPw=", + "owner": "ipetkov", "repo": "crane", - "rev": "c97a0c0d83bfdf01c29113c5592a3defc27cb315", + "rev": "d535642bbe6f377077f7c23f0febb78b1463f449", "type": "github" }, "original": { - "owner": "dpc", + "owner": "ipetkov", "repo": "crane", - "rev": "c97a0c0d83bfdf01c29113c5592a3defc27cb315", + "rev": "d535642bbe6f377077f7c23f0febb78b1463f449", "type": "github" } }, @@ -101,17 +98,17 @@ "nixpkgs-unstable": "nixpkgs-unstable_2" }, "locked": { - "lastModified": 1699573846, - "narHash": "sha256-4xKNhUE7e3GjjMbNib35B7eJWjuDIbYtwoHBOWYtqFA=", + "lastModified": 1701034148, + "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", "owner": "fedimint", "repo": "fedimint", - "rev": "f58f1913e62b6529a2ff36ec5c89a3852aba7ca7", + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", "type": "github" }, "original": { "owner": "fedimint", "repo": "fedimint", - "rev": "f58f1913e62b6529a2ff36ec5c89a3852aba7ca7", + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", "type": "github" } }, @@ -138,22 +135,6 @@ "type": "github" } }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, "flake-utils": { "locked": { "lastModified": 1676283394, @@ -188,24 +169,6 @@ } }, "flake-utils_3": { - "inputs": { - "systems": "systems_3" - }, - "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_4": { "inputs": { "systems": [ "fedimint", @@ -227,9 +190,9 @@ "type": "github" } }, - "flake-utils_5": { + "flake-utils_4": { "inputs": { - "systems": "systems_5" + "systems": "systems_4" }, "locked": { "lastModified": 1694529238, @@ -250,23 +213,23 @@ "android-nixpkgs": "android-nixpkgs", "crane": "crane", "fenix": "fenix", - "flake-utils": "flake-utils_4", + "flake-utils": "flake-utils_3", "nixpkgs": "nixpkgs", "nixpkgs-unstable": "nixpkgs-unstable", - "systems": "systems_4" + "systems": "systems_3" }, "locked": { - "lastModified": 1697820035, - "narHash": "sha256-l+rxi/P5qt+Ud+qQCyOiKB001P/A3J0Hsh7PNg7FyWM=", + "lastModified": 1699681206, + "narHash": "sha256-vg/aDhDPV8QUi2rE3O5C/FgSaxOPZRsuRNvto5aY/JM=", "owner": "rustshop", "repo": "flakebox", - "rev": "0d866b57cd09e30e8385150e846885236ea33bdb", + "rev": "390c23bc911b354f16db4d925dbe9b1f795308ed", "type": "github" }, "original": { "owner": "rustshop", "repo": "flakebox", - "rev": "0d866b57cd09e30e8385150e846885236ea33bdb", + "rev": "390c23bc911b354f16db4d925dbe9b1f795308ed", "type": "github" } }, @@ -320,17 +283,17 @@ }, "nixpkgs-unstable_2": { "locked": { - "lastModified": 1697059129, - "narHash": "sha256-9NJcFF9CEYPvHJ5ckE8kvINvI84SZZ87PvqMbH6pro0=", + "lastModified": 1700794826, + "narHash": "sha256-RyJTnTNKhO0yqRpDISk03I/4A67/dp96YRxc86YOPgU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5e4c2ada4fcd54b99d56d7bd62f384511a7e2593", + "rev": "5a09cb4b393d58f9ed0d9ca1555016a8543c2ac8", "type": "github" }, "original": { "owner": "NixOS", + "ref": "nixos-unstable", "repo": "nixpkgs", - "rev": "5e4c2ada4fcd54b99d56d7bd62f384511a7e2593", "type": "github" } }, @@ -369,7 +332,7 @@ "root": { "inputs": { "fedimint": "fedimint", - "flake-utils": "flake-utils_5", + "flake-utils": "flake-utils_4", "nixpkgs": "nixpkgs_3" } }, @@ -390,35 +353,6 @@ "type": "github" } }, - "rust-overlay": { - "inputs": { - "flake-utils": [ - "fedimint", - "flakebox", - "crane", - "flake-utils" - ], - "nixpkgs": [ - "fedimint", - "flakebox", - "crane", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1695003086, - "narHash": "sha256-d1/ZKuBRpxifmUf7FaedCqhy0lyVbqj44Oc2s+P5bdA=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "b87a14abea512d956f0b89d0d8a1e9b41f3e20ff", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, "systems": { "locked": { "lastModified": 1681028828, @@ -478,21 +412,6 @@ "repo": "default", "type": "github" } - }, - "systems_5": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 9871f8ea..4288e3c5 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,7 @@ flake-utils.url = "github:numtide/flake-utils"; fedimint = { url = - "github:fedimint/fedimint?rev=f58f1913e62b6529a2ff36ec5c89a3852aba7ca7"; + "github:fedimint/fedimint?rev=f47e6638c98c75a8c146144a69d236b4763848bf"; }; }; outputs = { self, nixpkgs, flake-utils, fedimint }: diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts index 09f9beba..f307aec1 100644 --- a/src/client/src/api/GatewayApi.ts +++ b/src/client/src/api/GatewayApi.ts @@ -19,6 +19,12 @@ export class GatewayApi { ); } + if (this.password === undefined) { + throw new Error( + 'Misconfigured Gateway API. Make sure gateway password is configured appropriately' + ); + } + return fetch(`${this.baseUrl}/${api}`, { method: 'POST', headers: { @@ -40,7 +46,6 @@ export class GatewayApi { throw responseToError(res); } catch (error) { - console.log(`baseUrl`, this.baseUrl); return Promise.reject({ message: 'Error fetching gateway info', error }); } }; @@ -110,5 +115,3 @@ export class GatewayApi { const responseToError = (res: Response): Error => { return new Error(`Status : ${res.status} \nReason : ${res.statusText}\n`); }; - -export const gatewayApi = new GatewayApi(); From 3b7ce5d78bfcd06148741321360f5d888f5a892f Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Tue, 28 Nov 2023 11:49:42 -0800 Subject: [PATCH 13/50] fix: missing export gatewayApi --- src/client/src/api/GatewayApi.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts index f307aec1..abdbfd3f 100644 --- a/src/client/src/api/GatewayApi.ts +++ b/src/client/src/api/GatewayApi.ts @@ -8,7 +8,7 @@ import { GatewayInfo, Federation } from './types'; const { publicRuntimeConfig } = getConfig(); // GatewayApi is an implementation of the ApiInterface -export class GatewayApi { +class GatewayApi { private baseUrl: string | undefined = publicRuntimeConfig.fmGatewayUrl; private password: string | undefined = publicRuntimeConfig.fmGatewayPassword; @@ -115,3 +115,5 @@ export class GatewayApi { const responseToError = (res: Response): Error => { return new Error(`Status : ${res.status} \nReason : ${res.statusText}\n`); }; + +export const gatewayApi = new GatewayApi(); From fbb2e001291c28e339e008d00825067cdd3f4b87 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Tue, 28 Nov 2023 12:08:54 -0800 Subject: [PATCH 14/50] fix: updates --- .../src/components/buttons/colorButton/ColorButton.tsx | 2 +- src/client/src/views/home/account/AccountButtons.tsx | 6 +++--- .../src/views/home/account/gateway/FedimintGatewayCard.tsx | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/client/src/components/buttons/colorButton/ColorButton.tsx b/src/client/src/components/buttons/colorButton/ColorButton.tsx index cdae81a4..2021dc0e 100644 --- a/src/client/src/components/buttons/colorButton/ColorButton.tsx +++ b/src/client/src/components/buttons/colorButton/ColorButton.tsx @@ -27,7 +27,7 @@ interface GeneralProps { const GeneralButton = styled.button` min-height: 38px; display: flex; - justify-content: center; + justify-content: space-evenly; align-items: center; cursor: pointer; outline: none; diff --git a/src/client/src/views/home/account/AccountButtons.tsx b/src/client/src/views/home/account/AccountButtons.tsx index 9aa8aba5..9a920447 100644 --- a/src/client/src/views/home/account/AccountButtons.tsx +++ b/src/client/src/views/home/account/AccountButtons.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Anchor, X, Zap, Book } from 'react-feather'; +import { Anchor, X, Zap, Sun } from 'react-feather'; import { ColorButton } from '../../../components/buttons/colorButton/ColorButton'; import { Card } from '../../../components/generic/Styled'; import { mediaWidths } from '../../../styles/Themes'; @@ -110,7 +110,7 @@ export const AccountButtons = () => { {state === 'pegout_ecash' ? ( ) : ( - + )} Peg Out @@ -123,7 +123,7 @@ export const AccountButtons = () => { {state === 'pegin_ecash' ? ( ) : ( - + )} Peg In
diff --git a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx index 4fbc76c6..6f2e8a9b 100644 --- a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx +++ b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx @@ -20,6 +20,8 @@ interface FedimintGatewayCardProps { gatewayInfo: GatewayInfo; } +const sectionColor = '#FFD300'; + export const FedimintGatewayCard = ({ gatewayInfo, }: FedimintGatewayCardProps) => { @@ -45,7 +47,7 @@ export const FedimintGatewayCard = ({ - + Fedimint Ecash From dbd75662f51b77a4d700c30792b41f98f6f9eae3 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Tue, 28 Nov 2023 12:13:53 -0800 Subject: [PATCH 15/50] fix: amount or all updates for withdrawAll --- src/client/src/api/GatewayApi.ts | 2 +- .../src/views/home/account/pegOutEcash/PegOutEcash.tsx | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts index abdbfd3f..72a56ad8 100644 --- a/src/client/src/api/GatewayApi.ts +++ b/src/client/src/api/GatewayApi.ts @@ -89,7 +89,7 @@ class GatewayApi { requestWithdrawal = async ( federationId: string, - amountSat: number, + amountSat: number | 'all', address: string ): Promise => { try { diff --git a/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx index 2c4b6dfe..e9d3d871 100644 --- a/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx +++ b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx @@ -46,9 +46,7 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { tokenAmount: { sendAll?: boolean; tokens?: number }, address: string ) => { - const amountSat = sendAll - ? federations[selectedFederation].balance_msat - : tokenAmount.tokens || 0; + const amountSat = sendAll ? 'all' : tokenAmount.tokens || 0; gatewayApi .requestWithdrawal( federations[federationIdx].federation_id, @@ -238,7 +236,7 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { Send to Address - {renderLine('Amount:', sendAll ? 'All' : )} + {renderLine('Amount:', sendAll ? 'all' : )} {renderLine('Address:', address)} {renderLine( 'Fee:', From 4da427c471340591c3b77d9e31488757951733d1 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Tue, 28 Nov 2023 13:47:01 -0800 Subject: [PATCH 16/50] feat: add fedimints tabs and info --- src/client/pages/fedimints.tsx | 116 ++++++++++++++++++ src/client/src/api/types.ts | 7 +- .../src/layouts/navigation/Navigation.tsx | 3 + src/client/src/views/fedimints/AddMint.tsx | 70 +++++++++++ 4 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 src/client/pages/fedimints.tsx create mode 100644 src/client/src/views/fedimints/AddMint.tsx diff --git a/src/client/pages/fedimints.tsx b/src/client/pages/fedimints.tsx new file mode 100644 index 00000000..94c70403 --- /dev/null +++ b/src/client/pages/fedimints.tsx @@ -0,0 +1,116 @@ +import React, { useMemo } from 'react'; +import { GridWrapper } from '../src/components/gridWrapper/GridWrapper'; +import { NextPageContext } from 'next'; +import { getProps } from '../src/utils/ssr'; +import { + CardWithTitle, + SubTitle, + Card, + DarkSubTitle, +} from '../src/components/generic/Styled'; +import { AddMint } from '../src/views/fedimints/AddMint'; +import Table from '../src/components/table'; +import { useGatewayFederations } from '../src/hooks/UseGatewayFederations'; +import { Federation } from '../src/api/types'; +import { CellContext } from '@tanstack/react-table'; + +const FedimintsView = () => { + const federations = useGatewayFederations(); + + const tableData = useMemo(() => { + const federationData = federations || []; + + return federationData.map(f => { + return { + ...f, + alias: f.federation_id, + }; + }); + }, [federations]); + + const columns = useMemo( + () => [ + { + header: 'Federation Name', + accessorKey: 'federation_name', + cell: (props: CellContext) => ( +
+ {props.row.original.config.meta.federation_name || '-'} +
+ ), + }, + { + header: 'Federation ID', + accessorKey: 'federation_id', + cell: (props: CellContext) => ( +
+ {`${props.row.original.federation_id.slice( + 0, + 6 + )}...${props.row.original.federation_id.slice(-6)}`} +
+ ), + }, + { + header: 'Balance (msat)', + accessorKey: 'balance_msat', + cell: (props: CellContext) => ( +
+ {props.row.original.balance_msat} +
+ ), + }, + { + header: 'Consensus Version', + accessorKey: 'consensus_version', + cell: (props: CellContext) => ( +
+ {props.row.original.config.consensus_version.major + + '.' + + props.row.original.config.consensus_version.minor} +
+ ), + }, + ], + [] + ); + + if (!federations || !federations?.length) { + return ( + + No Connected Federations! + + ); + } + + return ( + + Fedimints + + 1 ? 'federations' : 'federation' + } + /> + + + ); +}; + +const Wrapped = () => ( + + + + +); + +export default Wrapped; + +export async function getServerSideProps(context: NextPageContext) { + return await getProps(context); +} diff --git a/src/client/src/api/types.ts b/src/client/src/api/types.ts index 8a13441b..2092adb8 100644 --- a/src/client/src/api/types.ts +++ b/src/client/src/api/types.ts @@ -22,8 +22,13 @@ interface ApiEndpoint { export type MetaConfig = { federation_name?: string }; +export type ConsensusVersion = { + major: number; + minor: number; +}; + export interface ClientConfig { - consensus_version: number; + consensus_version: ConsensusVersion; epoch_pk: string; federation_id: string; api_endpoints: Record; diff --git a/src/client/src/layouts/navigation/Navigation.tsx b/src/client/src/layouts/navigation/Navigation.tsx index 4fdd8e7f..59216dda 100644 --- a/src/client/src/layouts/navigation/Navigation.tsx +++ b/src/client/src/layouts/navigation/Navigation.tsx @@ -2,6 +2,7 @@ import React, { FC, SVGAttributes } from 'react'; import styled, { css } from 'styled-components'; import { Home, + Sun, Cpu, Server, Settings, @@ -123,6 +124,7 @@ const BurgerNav = styled.a` `; const HOME = '/'; +const FEDIMINTS = '/fedimints'; const DASHBOARD = '/dashboard'; const PEERS = '/peers'; const CHANNEL = '/channels'; @@ -180,6 +182,7 @@ export const Navigation = ({ isBurger, setOpen }: NavigationProps) => { const renderLinks = () => ( {renderNavButton('Home', HOME, Home, sidebar)} + {renderNavButton('Fedimints', FEDIMINTS, Sun, sidebar)} {renderNavButton('Dashboard', DASHBOARD, Grid, sidebar)} {renderNavButton('Peers', PEERS, Users, sidebar)} {renderNavButton('Channels', CHANNEL, Cpu, sidebar)} diff --git a/src/client/src/views/fedimints/AddMint.tsx b/src/client/src/views/fedimints/AddMint.tsx new file mode 100644 index 00000000..f814f652 --- /dev/null +++ b/src/client/src/views/fedimints/AddMint.tsx @@ -0,0 +1,70 @@ +import React, { useState } from 'react'; +import { X } from 'react-feather'; +import { toast } from 'react-toastify'; +import { InputWithDeco } from '../../components/input/InputWithDeco'; +import { + CardWithTitle, + SubTitle, + Card, + SingleLine, + DarkSubTitle, + Separation, +} from '../../components/generic/Styled'; +import { ColorButton } from '../../components/buttons/colorButton/ColorButton'; +import { gatewayApi } from '../../api/GatewayApi'; +import { useGatewayDispatch } from '../../context/GatewayContext'; + +export const AddMint = () => { + const gatewayDispatch = useGatewayDispatch(); + const [isAdding, setIsAdding] = useState(false); + const [inviteCode, setInviteCode] = useState(''); + + const handleEnter = () => { + gatewayApi.connectFederation(inviteCode).then(() => { + gatewayApi + .fetchInfo() + .then(info => gatewayDispatch({ type: 'connected', state: info })) + .catch(({ error }) => { + toast.error(error.message); + }); + }); + }; + + return ( + + Mint Management + + + Connect to a new Federation + setIsAdding(prev => !prev)} + > + {isAdding ? : 'Add'} + + + {isAdding && ( + <> + + + setInviteCode(value)} + placeholder={'Paste Invite Code'} + /> +
+ + Connect + + + + )} + + + ); +}; From 2b6d8132f1dc13835fd22d30a7b86438ed5792de Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Wed, 29 Nov 2023 17:58:20 -0800 Subject: [PATCH 17/50] feat: network specific quick actions --- src/client/pages/index.tsx | 4 +- .../src/views/home/account/AccountInfo.tsx | 3 +- src/client/src/views/home/account/network.tsx | 30 ++++ .../home/quickActions/MainnetQuickActions.tsx | 146 ++++++++++++++++ .../quickActions/MutinynetQuickActions.tsx | 144 ++++++++++++++++ .../views/home/quickActions/QuickActions.tsx | 163 +++--------------- .../home/quickActions/RegtestQuickActions.tsx | 126 ++++++++++++++ .../home/quickActions/lnmarkets/index.tsx | 2 +- 8 files changed, 470 insertions(+), 148 deletions(-) create mode 100644 src/client/src/views/home/account/network.tsx create mode 100644 src/client/src/views/home/quickActions/MainnetQuickActions.tsx create mode 100644 src/client/src/views/home/quickActions/MutinynetQuickActions.tsx create mode 100644 src/client/src/views/home/quickActions/RegtestQuickActions.tsx diff --git a/src/client/pages/index.tsx b/src/client/pages/index.tsx index 79ea8981..7e9bdb5b 100644 --- a/src/client/pages/index.tsx +++ b/src/client/pages/index.tsx @@ -7,10 +7,9 @@ import { MempoolReport } from '../src/views/home/reports/mempool'; import { LiquidityGraph } from '../src/views/home/reports/liquidReport/LiquidityGraph'; import { AccountButtons } from '../src/views/home/account/AccountButtons'; import { AccountInfo } from '../src/views/home/account/AccountInfo'; -import { QuickActions } from '../src/views/home/quickActions/QuickActions'; -import { FlowBox } from '../src/views/home/reports/flow'; import { ForwardBox } from '../src/views/home/reports/forwardReport'; import { ConnectCard } from '../src/views/home/connect/Connect'; +import { QuickActions } from '../src/views/home/quickActions/QuickActions'; const HomeView = () => ( <> @@ -19,7 +18,6 @@ const HomeView = () => ( - diff --git a/src/client/src/views/home/account/AccountInfo.tsx b/src/client/src/views/home/account/AccountInfo.tsx index d5e2ef99..c72a9cd2 100644 --- a/src/client/src/views/home/account/AccountInfo.tsx +++ b/src/client/src/views/home/account/AccountInfo.tsx @@ -19,6 +19,7 @@ import { FedimintGatewayCard } from './gateway/FedimintGatewayCard'; import { useGatewayEcashTotal } from '../../../hooks/UseGatewayEcashTotal'; import { useGatewayState } from '../../../context/GatewayContext'; import { GatewayInfo } from '../../../api/types'; +import { getNetworkIndicator } from './network'; const S = { grid: styled.div<{ gatewayInfo?: GatewayInfo | null }>` @@ -83,7 +84,7 @@ export const AccountInfo = () => { <> - Network: {gatewayInfo?.network ? gatewayInfo.network : 'Bitcoin'}{' '} + Network: {getNetworkIndicator(gatewayInfo?.network || 'bitcoin')} diff --git a/src/client/src/views/home/account/network.tsx b/src/client/src/views/home/account/network.tsx new file mode 100644 index 00000000..ef402490 --- /dev/null +++ b/src/client/src/views/home/account/network.tsx @@ -0,0 +1,30 @@ +import React from 'react'; + +export const getNetworkIndicator = (network: string) => { + let color: string; + let name: string; + + switch (network) { + case 'bitcoin': + color = 'orange'; + name = 'Mainnet'; + break; + case 'testnet': + color = 'limegreen'; + name = 'Testnet'; + break; + case 'signet': + color = 'purple'; + name = 'Signet'; + break; + case 'regtest': + color = 'skyblue'; + name = 'Regtest'; + break; + default: + color = 'gray'; + name = 'Unknown'; + } + + return {name}; +}; diff --git a/src/client/src/views/home/quickActions/MainnetQuickActions.tsx b/src/client/src/views/home/quickActions/MainnetQuickActions.tsx new file mode 100644 index 00000000..c29577fe --- /dev/null +++ b/src/client/src/views/home/quickActions/MainnetQuickActions.tsx @@ -0,0 +1,146 @@ +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { X, Layers, GitBranch, Command, Zap } from 'react-feather'; +import { + CardWithTitle, + SubTitle, + CardTitle, + SmallButton, + Card, +} from '../../../components/generic/Styled'; +import { + unSelectedNavButton, + cardColor, + cardBorderColor, + mediaWidths, +} from '../../../styles/Themes'; +import { DecodeCard } from './decode/Decode'; +import { SupportCard } from './donate/DonateCard'; +import { SupportBar } from './donate/DonateContent'; +import { OpenChannel } from './openChannel'; +import { LnUrlCard } from './lnurl'; +import { LnMarketsCard } from './lnmarkets'; +import { AmbossCard } from './amboss/AmbossCard'; +import { LightningAddressCard } from './lightningAddress/LightningAddress'; + +export const QuickCard = styled.div` + background: ${cardColor}; + box-shadow: 0 8px 16px -8px rgba(0, 0, 0, 0.1); + border-radius: 4px; + border: 1px solid ${cardBorderColor}; + height: 100px; + flex-grow: 1; + flex: 1 0 auto; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-bottom: 25px; + padding: 10px; + margin-right: 10px; + cursor: pointer; + color: #69c0ff; + + @media (${mediaWidths.mobile}) { + padding: 4px; + height: 80px; + width: 80px; + } + + &:hover { + border: 1px solid #69c0ff; + } +`; + +export const QuickTitle = styled.div` + font-size: 12px; + color: ${unSelectedNavButton}; + margin-top: 10px; + text-align: center; +`; + +const QuickRow = styled.div` + display: flex; + flex-wrap: wrap; + justify-content: space-between; +`; + +export const MainnetQuickActions = () => { + const [openCard, setOpenCard] = useState('none'); + + const getTitle = () => { + switch (openCard) { + case 'decode': + return 'Decode a Lightning Request'; + case 'open_channel': + return 'Open a Channel'; + case 'ln_url': + return 'Use lnurl'; + case 'lightning_address': + return 'Pay to a Lightning Address'; + default: + return 'Mainnet Quick Actions'; + } + }; + + const renderContent = () => { + switch (openCard) { + case 'support': + return ( + + + + ); + case 'decode': + return ; + case 'ln_url': + return ; + case 'lightning_address': + return ; + case 'open_channel': + return ( + + + + ); + default: + return ( + + setOpenCard('support')} /> + + setOpenCard('lightning_address')}> + + Address + + setOpenCard('open_channel')}> + + Open + + setOpenCard('decode')}> + + Decode + + setOpenCard('ln_url')}> + + LNURL + + + + ); + } + }; + + return ( + + + {getTitle()} + {openCard !== 'none' && ( + setOpenCard('none')}> + + + )} + + {renderContent()} + + ); +}; diff --git a/src/client/src/views/home/quickActions/MutinynetQuickActions.tsx b/src/client/src/views/home/quickActions/MutinynetQuickActions.tsx new file mode 100644 index 00000000..5bbacbf4 --- /dev/null +++ b/src/client/src/views/home/quickActions/MutinynetQuickActions.tsx @@ -0,0 +1,144 @@ +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { X, Layers, GitBranch, Command, Zap } from 'react-feather'; +import { + CardWithTitle, + SubTitle, + CardTitle, + SmallButton, + Card, +} from '../../../components/generic/Styled'; +import { + unSelectedNavButton, + cardColor, + cardBorderColor, + mediaWidths, +} from '../../../styles/Themes'; +import { DecodeCard } from './decode/Decode'; +import { SupportCard } from './donate/DonateCard'; +import { SupportBar } from './donate/DonateContent'; +import { OpenChannel } from './openChannel'; +import { LnUrlCard } from './lnurl'; +import { LightningAddressCard } from './lightningAddress/LightningAddress'; + +export const QuickCard = styled.div` + background: ${cardColor}; + box-shadow: 0 8px 16px -8px rgba(0, 0, 0, 0.1); + border-radius: 4px; + border: 1px solid ${cardBorderColor}; + height: 100px; + flex-grow: 1; + flex: 1 0 auto; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-bottom: 25px; + padding: 10px; + margin-right: 10px; + cursor: pointer; + color: #69c0ff; + + @media (${mediaWidths.mobile}) { + padding: 4px; + height: 80px; + width: 80px; + } + + &:hover { + border: 1px solid #69c0ff; + } +`; + +export const QuickTitle = styled.div` + font-size: 12px; + color: ${unSelectedNavButton}; + margin-top: 10px; + text-align: center; +`; + +const QuickRow = styled.div` + display: flex; + flex-wrap: wrap; + justify-content: space-between; +`; + +export const MutinynetQuickActions = () => { + const [openCard, setOpenCard] = useState('none'); + + const getTitle = () => { + switch (openCard) { + case 'decode': + return 'Decode a Lightning Request'; + case 'open_channel': + return 'Open Outbound Channel'; + case 'request_channel': + return 'Request Inbound Channel'; + case 'ln_url': + return 'Use lnurl'; + case 'lightning_address': + return 'Pay to a Lightning Address'; + default: + return 'Mutinynet Quick Actions'; + } + }; + + const renderContent = () => { + switch (openCard) { + case 'support': + return ( + + + + ); + case 'decode': + return ; + case 'ln_url': + return ; + case 'lightning_address': + return ; + case 'open_channel': + return ( + + + + ); + default: + return ( + + setOpenCard('support')} /> + setOpenCard('lightning_address')}> + + Address + + setOpenCard('open_channel')}> + + Open + + setOpenCard('decode')}> + + Decode + + setOpenCard('ln_url')}> + + LNURL + + + ); + } + }; + + return ( + + + {getTitle()} + {openCard !== 'none' && ( + setOpenCard('none')}> + + + )} + + {renderContent()} + + ); +}; diff --git a/src/client/src/views/home/quickActions/QuickActions.tsx b/src/client/src/views/home/quickActions/QuickActions.tsx index 0dcbe79b..4ddf0c3d 100644 --- a/src/client/src/views/home/quickActions/QuickActions.tsx +++ b/src/client/src/views/home/quickActions/QuickActions.tsx @@ -1,146 +1,23 @@ -import React, { useState } from 'react'; -import styled from 'styled-components'; -import { X, Layers, GitBranch, Command, Zap } from 'react-feather'; -import { - CardWithTitle, - SubTitle, - CardTitle, - SmallButton, - Card, -} from '../../../components/generic/Styled'; -import { - unSelectedNavButton, - cardColor, - cardBorderColor, - mediaWidths, -} from '../../../styles/Themes'; -import { DecodeCard } from './decode/Decode'; -import { SupportCard } from './donate/DonateCard'; -import { SupportBar } from './donate/DonateContent'; -import { OpenChannel } from './openChannel'; -import { LnUrlCard } from './lnurl'; -import { LnMarketsCard } from './lnmarkets'; -import { AmbossCard } from './amboss/AmbossCard'; -import { LightningAddressCard } from './lightningAddress/LightningAddress'; - -export const QuickCard = styled.div` - background: ${cardColor}; - box-shadow: 0 8px 16px -8px rgba(0, 0, 0, 0.1); - border-radius: 4px; - border: 1px solid ${cardBorderColor}; - height: 100px; - flex-grow: 1; - flex: 1 0 auto; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin-bottom: 25px; - padding: 10px; - margin-right: 10px; - cursor: pointer; - color: #69c0ff; - - @media (${mediaWidths.mobile}) { - padding: 4px; - height: 80px; - width: 80px; - } - - &:hover { - border: 1px solid #69c0ff; - } -`; - -export const QuickTitle = styled.div` - font-size: 12px; - color: ${unSelectedNavButton}; - margin-top: 10px; - text-align: center; -`; - -const QuickRow = styled.div` - display: flex; - flex-wrap: wrap; - justify-content: space-between; -`; +import React from 'react'; +import { useGatewayState } from '../../../context/GatewayContext'; +import { MutinynetQuickActions } from './MutinynetQuickActions'; +import { MainnetQuickActions } from './MainnetQuickActions'; +import { RegtestQuickActions } from './RegtestQuickActions'; +import { Network } from '../../../api/types'; export const QuickActions = () => { - const [openCard, setOpenCard] = useState('none'); - - const getTitle = () => { - switch (openCard) { - case 'decode': - return 'Decode a Lightning Request'; - case 'open_channel': - return 'Open a Channel'; - case 'ln_url': - return 'Use lnurl'; - case 'lightning_address': - return 'Pay to a Lightning Address'; - default: - return 'Quick Actions'; - } - }; - - const renderContent = () => { - switch (openCard) { - case 'support': - return ( - - - - ); - case 'decode': - return ; - case 'ln_url': - return ; - case 'lightning_address': - return ; - case 'open_channel': - return ( - - - - ); - default: - return ( - - setOpenCard('support')} /> - - setOpenCard('lightning_address')}> - - Address - - setOpenCard('open_channel')}> - - Open - - setOpenCard('decode')}> - - Decode - - setOpenCard('ln_url')}> - - LNURL - - - - ); - } - }; - - return ( - - - {getTitle()} - {openCard !== 'none' && ( - setOpenCard('none')}> - - - )} - - {renderContent()} - - ); + const { gatewayInfo } = useGatewayState(); + + switch (gatewayInfo?.network) { + case Network.Signet: + return ; + case Network.Bitcoin: + return ; + case Network.Regtest: + return ; + // case Network.Testnet: + // return ; + default: + return null; + } }; diff --git a/src/client/src/views/home/quickActions/RegtestQuickActions.tsx b/src/client/src/views/home/quickActions/RegtestQuickActions.tsx new file mode 100644 index 00000000..2958e4b6 --- /dev/null +++ b/src/client/src/views/home/quickActions/RegtestQuickActions.tsx @@ -0,0 +1,126 @@ +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { X } from 'react-feather'; +import { + CardWithTitle, + SubTitle, + CardTitle, + SmallButton, + Card, +} from '../../../components/generic/Styled'; +import { + unSelectedNavButton, + cardColor, + cardBorderColor, + mediaWidths, +} from '../../../styles/Themes'; +import { DecodeCard } from './decode/Decode'; +import { SupportCard } from './donate/DonateCard'; +import { SupportBar } from './donate/DonateContent'; +import { OpenChannel } from './openChannel'; +import { LnUrlCard } from './lnurl'; +import { LightningAddressCard } from './lightningAddress/LightningAddress'; + +export const QuickCard = styled.div` + background: ${cardColor}; + box-shadow: 0 8px 16px -8px rgba(0, 0, 0, 0.1); + border-radius: 4px; + border: 1px solid ${cardBorderColor}; + height: 100px; + flex-grow: 1; + flex: 1 0 auto; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-bottom: 25px; + padding: 10px; + margin-right: 10px; + cursor: pointer; + color: #69c0ff; + + @media (${mediaWidths.mobile}) { + padding: 4px; + height: 80px; + width: 80px; + } + + &:hover { + border: 1px solid #69c0ff; + } +`; + +export const QuickTitle = styled.div` + font-size: 12px; + color: ${unSelectedNavButton}; + margin-top: 10px; + text-align: center; +`; + +const QuickRow = styled.div` + display: flex; + flex-wrap: wrap; + justify-content: space-between; +`; + +export const RegtestQuickActions = () => { + const [openCard, setOpenCard] = useState('none'); + + const getTitle = () => { + switch (openCard) { + case 'decode': + return 'Decode a Lightning Request'; + case 'open_channel': + return 'Open Outbound Channel'; + case 'ln_url': + return 'Use lnurl'; + case 'lightning_address': + return 'Pay to a Lightning Address'; + default: + return 'Regtest Quick Actions'; + } + }; + + const renderContent = () => { + switch (openCard) { + case 'support': + return ( + + + + ); + case 'decode': + return ; + case 'ln_url': + return ; + case 'lightning_address': + return ; + case 'open_channel': + return ( + + + + ); + default: + return ( + + setOpenCard('support')} /> + + ); + } + }; + + return ( + + + {getTitle()} + {openCard !== 'none' && ( + setOpenCard('none')}> + + + )} + + {renderContent()} + + ); +}; diff --git a/src/client/src/views/home/quickActions/lnmarkets/index.tsx b/src/client/src/views/home/quickActions/lnmarkets/index.tsx index 29869478..049cb544 100644 --- a/src/client/src/views/home/quickActions/lnmarkets/index.tsx +++ b/src/client/src/views/home/quickActions/lnmarkets/index.tsx @@ -11,7 +11,7 @@ import { useLnMarketsLoginMutation } from '../../../../graphql/mutations/__gener import { useGetLnMarketsStatusQuery } from '../../../../graphql/queries/__generated__/getLnMarketsStatus.generated'; import { getErrorContent } from '../../../../utils/error'; import getConfig from 'next/config'; -import { QuickCard, QuickTitle } from '../QuickActions'; +import { QuickCard, QuickTitle } from '../MainnetQuickActions'; const { publicRuntimeConfig } = getConfig(); const { disableLnMarkets } = publicRuntimeConfig; From 375a861a9a58cf2f7cc4ba75d25cce33d4aa9768 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 30 Nov 2023 13:09:58 -0800 Subject: [PATCH 18/50] fix: hold --- flake.lock | 8 ++++---- .../layouts/navigation/nodeInfo/NodeInfo.tsx | 19 ++++++++++++++++--- .../dashboard/widgets/lightning/balances.tsx | 14 ++++++++++++++ .../views/dashboard/widgets/widgetList.tsx | 9 +++++++++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 1792105c..b45f9da9 100644 --- a/flake.lock +++ b/flake.lock @@ -98,17 +98,17 @@ "nixpkgs-unstable": "nixpkgs-unstable_2" }, "locked": { - "lastModified": 1701034148, - "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", + "lastModified": 1701251322, + "narHash": "sha256-og7C8Q19KsHf4HCsgiI1CbNEWk4kUcArtiitWteTXpw=", "owner": "fedimint", "repo": "fedimint", - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", + "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", "type": "github" }, "original": { "owner": "fedimint", "repo": "fedimint", - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", + "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", "type": "github" } }, diff --git a/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx b/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx index d8606ee1..21bcdf62 100644 --- a/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx +++ b/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Zap, Anchor, Circle } from 'react-feather'; +import { Zap, Anchor, Circle, Sun } from 'react-feather'; import { Tooltip as ReactTooltip } from 'react-tooltip'; import styled from 'styled-components'; import { getPrice, Price } from '../../../components/price/Price'; @@ -16,6 +16,7 @@ import { } from '../../../components/generic/Styled'; import { useConfigState } from '../../../context/ConfigContext'; import { usePriceState } from '../../../context/PriceContext'; +import { useGatewayEcashTotal } from '../../../hooks/UseGatewayEcashTotal'; const Closed = styled.div` display: flex; @@ -45,8 +46,8 @@ const Info = styled.div<{ bottomColor: string }>` const Balance = styled.div` display: flex; - justify-content: center; - align-items: center; + justify-content: space-between; + align-items: space-between; margin: 2px 0; padding: 0 5px; cursor: default; @@ -78,6 +79,7 @@ export const NodeInfo = ({ isOpen, isBurger }: NodeInfoProps) => { } = useNodeInfo(); const { onchain, lightning } = useNodeBalances(); + const totalFedimintEcash = useGatewayEcashTotal(); const { currency, displayValues } = useConfigState(); const priceContext = usePriceState(); @@ -128,6 +130,10 @@ export const NodeInfo = ({ isOpen, isBurger }: NodeInfoProps) => { /> + + + + ); } @@ -179,6 +185,9 @@ export const NodeInfo = ({ isOpen, isBurger }: NodeInfoProps) => { {renderLine('Closed Channels', closedChannelCount)} {renderLine('Peers', peersCount)} + + {renderLine('Fedimint Balance', totalFedimintEcash)} + ); } @@ -199,6 +208,10 @@ export const NodeInfo = ({ isOpen, isBurger }: NodeInfoProps) => { + + + + { ); }; + +export const FedimintBalance = () => { + const totalFedimintEcash = useGatewayEcashTotal(); + + return ( + + Fedimint Balance + + + + + ); +}; diff --git a/src/client/src/views/dashboard/widgets/widgetList.tsx b/src/client/src/views/dashboard/widgets/widgetList.tsx index c8447f0f..e6199e90 100644 --- a/src/client/src/views/dashboard/widgets/widgetList.tsx +++ b/src/client/src/views/dashboard/widgets/widgetList.tsx @@ -3,6 +3,7 @@ import { MempoolWidget } from './external/mempool'; import { ChainBalance, ChannelBalance, + FedimintBalance, TotalBalance, } from './lightning/balances'; import { ChannelListWidget } from './lightning/channels'; @@ -111,6 +112,14 @@ export const widgetList: WidgetProps[] = [ component: ChainBalance, default: { ...defaultProps, w: 2, h: 3 }, }, + { + id: 6, + name: 'Fedimint Balance', + group: 'Lightning', + subgroup: 'Info', + component: FedimintBalance, + default: { ...defaultProps, w: 2, h: 3 }, + }, { id: 7, name: 'Alias', From d0d6328ef8bdc10047a0800eba73ecd3225848e9 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 30 Nov 2023 14:26:57 -0800 Subject: [PATCH 19/50] feat: skyler updates --- flake.lock | 8 +- .../buttons/colorButton/ColorButton.tsx | 3 +- src/client/src/components/generic/Styled.tsx | 8 ++ .../src/layouts/navigation/Navigation.tsx | 1 + .../layouts/navigation/nodeInfo/NodeInfo.tsx | 16 ++-- src/client/src/utils/helpers.tsx | 5 +- .../src/views/home/account/AccountButtons.tsx | 6 +- .../src/views/home/account/AccountInfo.tsx | 81 +++++++++---------- .../account/gateway/FedimintGatewayCard.tsx | 5 +- 9 files changed, 67 insertions(+), 66 deletions(-) diff --git a/flake.lock b/flake.lock index b45f9da9..1792105c 100644 --- a/flake.lock +++ b/flake.lock @@ -98,17 +98,17 @@ "nixpkgs-unstable": "nixpkgs-unstable_2" }, "locked": { - "lastModified": 1701251322, - "narHash": "sha256-og7C8Q19KsHf4HCsgiI1CbNEWk4kUcArtiitWteTXpw=", + "lastModified": 1701034148, + "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", "owner": "fedimint", "repo": "fedimint", - "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", "type": "github" }, "original": { "owner": "fedimint", "repo": "fedimint", - "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", "type": "github" } }, diff --git a/src/client/src/components/buttons/colorButton/ColorButton.tsx b/src/client/src/components/buttons/colorButton/ColorButton.tsx index 2021dc0e..9c386baf 100644 --- a/src/client/src/components/buttons/colorButton/ColorButton.tsx +++ b/src/client/src/components/buttons/colorButton/ColorButton.tsx @@ -27,7 +27,8 @@ interface GeneralProps { const GeneralButton = styled.button` min-height: 38px; display: flex; - justify-content: space-evenly; + justify-content: center; + gap: 8px; align-items: center; cursor: pointer; outline: none; diff --git a/src/client/src/components/generic/Styled.tsx b/src/client/src/components/generic/Styled.tsx index d2a96c3c..6c98fddb 100644 --- a/src/client/src/components/generic/Styled.tsx +++ b/src/client/src/components/generic/Styled.tsx @@ -154,6 +154,14 @@ export const RightAlign = styled.div` align-items: center; `; +export const LeftAlign = styled.div` + width: 100%; + display: flex; + justify-content: flex-start; + align-items: center; + gap: 8px; +`; + export const ColumnLine = styled.div` display: flex; flex-direction: column; diff --git a/src/client/src/layouts/navigation/Navigation.tsx b/src/client/src/layouts/navigation/Navigation.tsx index 59216dda..4d2a1850 100644 --- a/src/client/src/layouts/navigation/Navigation.tsx +++ b/src/client/src/layouts/navigation/Navigation.tsx @@ -200,6 +200,7 @@ export const Navigation = ({ isBurger, setOpen }: NavigationProps) => { const renderBurger = () => ( {renderBurgerNav('Home', HOME, Home)} + {renderBurgerNav('Fedimints', FEDIMINTS, Sun)} {renderBurgerNav('Dashboard', DASHBOARD, Grid)} {renderBurgerNav('Peers', PEERS, Users)} {renderBurgerNav('Channels', CHANNEL, Cpu)} diff --git a/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx b/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx index 21bcdf62..a948d14b 100644 --- a/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx +++ b/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Zap, Anchor, Circle, Sun } from 'react-feather'; +import { Zap, Link, Circle, Sun } from 'react-feather'; import { Tooltip as ReactTooltip } from 'react-tooltip'; import styled from 'styled-components'; import { getPrice, Price } from '../../../components/price/Price'; @@ -47,7 +47,8 @@ const Info = styled.div<{ bottomColor: string }>` const Balance = styled.div` display: flex; justify-content: space-between; - align-items: space-between; + align-items: center; + width: 100%; margin: 2px 0; padding: 0 5px; cursor: default; @@ -120,14 +121,11 @@ export const NodeInfo = ({ isOpen, isBurger }: NodeInfoProps) => { size={18} color={channelPending === 0 ? '#FFD300' : '#652EC7'} fill={channelPending === 0 ? '#FFD300' : '#652EC7'} - /> + />{' '} - + @@ -160,7 +158,7 @@ export const NodeInfo = ({ isOpen, isBurger }: NodeInfoProps) => { color={channelPending === 0 ? '#FFD300' : '#652EC7'} /> - @@ -205,7 +203,7 @@ export const NodeInfo = ({ isOpen, isBurger }: NodeInfoProps) => { - + diff --git a/src/client/src/utils/helpers.tsx b/src/client/src/utils/helpers.tsx index 02ac3eb1..8850c3a0 100644 --- a/src/client/src/utils/helpers.tsx +++ b/src/client/src/utils/helpers.tsx @@ -1,5 +1,5 @@ import numeral from 'numeral'; -import { SatoshiSymbol } from '../components/satoshi/Satoshi'; +// import { SatoshiSymbol } from '../components/satoshi/Satoshi'; import { unSelectedNavButton } from '../styles/Themes'; import styled from 'styled-components'; @@ -87,8 +87,7 @@ export const getValue = ({ return ( <> - {breakAmount} - + {breakAmount} {'sats'} ); } diff --git a/src/client/src/views/home/account/AccountButtons.tsx b/src/client/src/views/home/account/AccountButtons.tsx index 9a920447..588c4a14 100644 --- a/src/client/src/views/home/account/AccountButtons.tsx +++ b/src/client/src/views/home/account/AccountButtons.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Anchor, X, Zap, Sun } from 'react-feather'; +import { Link, X, Zap, Sun } from 'react-feather'; import { ColorButton } from '../../../components/buttons/colorButton/ColorButton'; import { Card } from '../../../components/generic/Styled'; import { mediaWidths } from '../../../styles/Themes'; @@ -84,7 +84,7 @@ export const AccountButtons = () => { {state === 'send_chain' ? ( ) : ( - + )} Send @@ -97,7 +97,7 @@ export const AccountButtons = () => { {state === 'receive_chain' ? ( ) : ( - + )} Receive diff --git a/src/client/src/views/home/account/AccountInfo.tsx b/src/client/src/views/home/account/AccountInfo.tsx index c72a9cd2..f191b32c 100644 --- a/src/client/src/views/home/account/AccountInfo.tsx +++ b/src/client/src/views/home/account/AccountInfo.tsx @@ -1,6 +1,6 @@ import React from 'react'; import styled from 'styled-components'; -import { Zap, Anchor, Pocket } from 'react-feather'; +import { Zap, Link } from 'react-feather'; import { useNodeBalances } from '../../../hooks/UseNodeBalances'; import Big from 'big.js'; import { renderLine } from '../../../components/generic/helpers'; @@ -9,14 +9,14 @@ import { CardWithTitle, SubTitle, Separation, - DarkSubTitle, - ResponsiveLine, - SingleLine, + // DarkSubTitle, + // ResponsiveLine, + LeftAlign, } from '../../../components/generic/Styled'; import { Price } from '../../../components/price/Price'; import { mediaWidths } from '../../../styles/Themes'; import { FedimintGatewayCard } from './gateway/FedimintGatewayCard'; -import { useGatewayEcashTotal } from '../../../hooks/UseGatewayEcashTotal'; +// import { useGatewayEcashTotal } from '../../../hooks/UseGatewayEcashTotal'; import { useGatewayState } from '../../../context/GatewayContext'; import { GatewayInfo } from '../../../api/types'; import { getNetworkIndicator } from './network'; @@ -34,39 +34,40 @@ const S = { `, }; -const Tile = styled.div<{ startTile?: boolean }>` - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: ${({ startTile }) => (startTile ? 'flex-start' : 'flex-end')}; +// const Tile = styled.div` +// display: flex; +// flex-direction: column; +// justify-content: space-between; +// align-items: ${({ startTile }: { startTile?: boolean }) => +// startTile ? 'flex-start' : 'flex-end'}; - @media (${mediaWidths.mobile}) { - width: 100%; - flex-direction: row; - align-items: flex-end; - margin: 0 0 8px; - } -`; +// @media (${mediaWidths.mobile}) { +// width: 100%; +// flex-direction: row; +// align-items: flex-end; +// margin: 0 0 8px; +// } +// `; const sectionColor = '#FFD300'; export const AccountInfo = () => { const { onchain, lightning } = useNodeBalances(); const { gatewayInfo } = useGatewayState(); - const totalFedimintEcash = useGatewayEcashTotal(); + // const totalFedimintEcash = useGatewayEcashTotal(); - const totalAmount = new Big(onchain.confirmed) - .add(onchain.pending) - .add(onchain.closing) - .add(lightning.confirmed) - .add(lightning.pending) - .add(totalFedimintEcash) - .toString(); + // const totalAmount = new Big(onchain.confirmed) + // .add(onchain.pending) + // .add(onchain.closing) + // .add(lightning.confirmed) + // .add(lightning.pending) + // .add(totalFedimintEcash) + // .toString(); - const totalChain = new Big(onchain.confirmed).add(onchain.pending).toString(); - const totalLightning = new Big(lightning.confirmed) - .add(lightning.pending) - .toString(); + // const totalChain = new Big(onchain.confirmed).add(onchain.pending).toString(); + // const totalLightning = new Big(lightning.confirmed) + // .add(lightning.pending) + // .toString(); const activeLightning = new Big(lightning.active) .sub(lightning.commit) @@ -86,16 +87,8 @@ export const AccountInfo = () => { Network: {getNetworkIndicator(gatewayInfo?.network || 'bitcoin')} - + {/* - Total
@@ -123,18 +116,18 @@ export const AccountInfo = () => { )} - + */} - + Lightning - + {renderLine('Available', )} {renderLine('Not Available', )} @@ -143,13 +136,13 @@ export const AccountInfo = () => { - - + Bitcoin - + {renderLine('Available', )} {renderLine('Pending', )} diff --git a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx index 6f2e8a9b..6599bb0e 100644 --- a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx +++ b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import { Card, CardWithTitle, + LeftAlign, Separation, SingleLine, SubTitle, @@ -46,10 +47,10 @@ export const FedimintGatewayCard = ({ return ( - + Fedimint Ecash - + {!gatewayInfo.federations || gatewayInfo.federations.length === 0 ? ( <> From 875633823ff96d84e686fa075895f413ca3d061e Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 1 Dec 2023 18:38:47 -0800 Subject: [PATCH 20/50] feat: bump fedimint version for multifederation support --- flake.lock | 7 +- flake.nix | 5 +- src/client/src/api/GatewayApi.ts | 1 - src/client/src/api/types.ts | 5 +- src/client/src/styles/Themes.ts | 2 + .../src/views/home/account/AccountButtons.tsx | 2 +- .../src/views/home/account/AccountInfo.tsx | 31 +---- .../gateway/.FedimintGatewayCard.tsx.swp | Bin 12288 -> 0 bytes .../home/account/pegInEcash/PegInEcash.tsx | 27 ++-- .../home/account/pegOutEcash/PegOutEcash.tsx | 125 +----------------- 10 files changed, 26 insertions(+), 179 deletions(-) delete mode 100644 src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp diff --git a/flake.lock b/flake.lock index 1792105c..741e3941 100644 --- a/flake.lock +++ b/flake.lock @@ -98,17 +98,16 @@ "nixpkgs-unstable": "nixpkgs-unstable_2" }, "locked": { - "lastModified": 1701034148, - "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", + "lastModified": 1701469066, + "narHash": "sha256-3pt8qUfaUvQRl1gWY2Qkk4MRBbzpYtId/rdTitLffBQ=", "owner": "fedimint", "repo": "fedimint", - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", + "rev": "f316e987aaf1a81b1626f7e418318ca683e0a47a", "type": "github" }, "original": { "owner": "fedimint", "repo": "fedimint", - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 4288e3c5..25dc8dfd 100644 --- a/flake.nix +++ b/flake.nix @@ -2,10 +2,7 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; flake-utils.url = "github:numtide/flake-utils"; - fedimint = { - url = - "github:fedimint/fedimint?rev=f47e6638c98c75a8c146144a69d236b4763848bf"; - }; + fedimint = { url = "github:fedimint/fedimint?branch=releases/0.2"; }; }; outputs = { self, nixpkgs, flake-utils, fedimint }: flake-utils.lib.eachDefaultSystem (system: diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts index 72a56ad8..7800b019 100644 --- a/src/client/src/api/GatewayApi.ts +++ b/src/client/src/api/GatewayApi.ts @@ -101,7 +101,6 @@ class GatewayApi { if (res.ok) { const txid: string = await res.text(); - console.log('txid', txid); return Promise.resolve(txid); } diff --git a/src/client/src/api/types.ts b/src/client/src/api/types.ts index 2092adb8..16d4867d 100644 --- a/src/client/src/api/types.ts +++ b/src/client/src/api/types.ts @@ -53,14 +53,15 @@ export interface GatewayInfo { // Type adaptation from https://docs.rs/bitcoin/latest/bitcoin/network/enum.Network.html export enum Network { - Bitcoin = 'main', - Testnet = 'test', + Bitcoin = 'bitcoin', + Testnet = 'testnet', Signet = 'signet', Regtest = 'regtest', } export type TransactionId = string; +// For testing export const dummyFederation = { federation_id: 'test_federation_id', balance_msat: 1000, diff --git a/src/client/src/styles/Themes.ts b/src/client/src/styles/Themes.ts index e00c4577..89e2bf0f 100644 --- a/src/client/src/styles/Themes.ts +++ b/src/client/src/styles/Themes.ts @@ -43,9 +43,11 @@ export const fontColors = { export const mediaDimensions = { mobile: 700, + modifiedMobile: 950, }; export const mediaWidths = { mobile: `max-width: ${mediaDimensions.mobile}px`, + modifiedMobile: `max-width: ${mediaDimensions.modifiedMobile}px`, }; // --------------------------------------- diff --git a/src/client/src/views/home/account/AccountButtons.tsx b/src/client/src/views/home/account/AccountButtons.tsx index 588c4a14..24afcd3d 100644 --- a/src/client/src/views/home/account/AccountButtons.tsx +++ b/src/client/src/views/home/account/AccountButtons.tsx @@ -20,7 +20,7 @@ const S = { grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; margin-bottom: 32px; - @media (${mediaWidths.mobile}) { + @media (${mediaWidths.modifiedMobile}) { grid-template-columns: 1fr 1fr; } `, diff --git a/src/client/src/views/home/account/AccountInfo.tsx b/src/client/src/views/home/account/AccountInfo.tsx index f191b32c..bac53d3f 100644 --- a/src/client/src/views/home/account/AccountInfo.tsx +++ b/src/client/src/views/home/account/AccountInfo.tsx @@ -28,46 +28,17 @@ const S = { grid-template-columns: ${({ gatewayInfo }) => gatewayInfo ? '1fr 1fr 1fr' : '1fr 1fr'}; - @media (${mediaWidths.mobile}) { + @media (${mediaWidths.modifiedMobile}) { display: block; } `, }; -// const Tile = styled.div` -// display: flex; -// flex-direction: column; -// justify-content: space-between; -// align-items: ${({ startTile }: { startTile?: boolean }) => -// startTile ? 'flex-start' : 'flex-end'}; - -// @media (${mediaWidths.mobile}) { -// width: 100%; -// flex-direction: row; -// align-items: flex-end; -// margin: 0 0 8px; -// } -// `; - const sectionColor = '#FFD300'; export const AccountInfo = () => { const { onchain, lightning } = useNodeBalances(); const { gatewayInfo } = useGatewayState(); - // const totalFedimintEcash = useGatewayEcashTotal(); - - // const totalAmount = new Big(onchain.confirmed) - // .add(onchain.pending) - // .add(onchain.closing) - // .add(lightning.confirmed) - // .add(lightning.pending) - // .add(totalFedimintEcash) - // .toString(); - - // const totalChain = new Big(onchain.confirmed).add(onchain.pending).toString(); - // const totalLightning = new Big(lightning.confirmed) - // .add(lightning.pending) - // .toString(); const activeLightning = new Big(lightning.active) .sub(lightning.commit) diff --git a/src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp b/src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp deleted file mode 100644 index 8bcdd22863f83ad35d13ae1a2bd1eb2636104c2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2O^6&t6vr#Uuc$E+ji8`Z)A&B2R!(StV+DoPIGzxrdQW@abxDydeUyQmgzHgmEdzfA@BUL#$Vn_cklb2kV}!jrHXI%c@B2T>@xFCMA4<$ zb8$3#*bX9(1tSe#RSuoS$m_OwC=;hCWUE_u>Oy*v2xk-7Z8RJdg+7l}MG||C7YNv9 zU)KfSNSs#G<_`0`sEgtzlYE11Ij6WU+9H&v^ZNxB`?gFrNBTFnMuA&ffxYC(!*khI ze|+j7ePI6!x3(N+^hN=rfKk9GU=%P47zK<1MuA&Q0omC_Uc;Do7vo+luDeFA#jUv* z1&jhl0i%FXz$jo8FbWt2i~>dhqkvJsDDXd2fcb zkHP!k3fKlcuna2T=lclx47?5;@cUjuJ_MJ63yy+^!1a3x`5XKNz5`!^cfn;)11@+B z{BjQ=*TCmMf>mIHDewq503HN;z@K*$@+-IoJ^|Yx0WX0=;8F0~9zs3^F}Mg$fjO`X z{B##$0B->aPJ@HspF0Wp5qu4;Ud<#9l09U~W z;BD|GP&&T>%*QBT6fg?(73du$luoN(l)8>O!L)|sQL91*{8(047MFLh?iCez8(*vs z>Qqr0b9I#Jj0kzfT3WPbXmMU@DQrY`gQJc~5rxV5>ILogqVR`2k94Fw-@uO-g$>cP z+gvi;XUN)|sHTIDg;QHa1l9~0ln)0!R5214Bsmugk5krG$H8jp4dSY^fQ25v*iM-2 zQD;~wO0DCWi~kmg3#n-$w*p>EQ`%;6Q-t%>s&+Q1;z)kAXs%SUuo=EfwLqkbEKXIjz-d)EaZ? zYGWH2!iYpFMs$ykn-CuUj?sk6rG5t$Zc7BurM=FAE+1PglxF36OyiMv0_O2n6kuuA zrp~cMa+>!5nSDMr5}~^kcDlpLyOZY8b;fom7Vz119yfw$W0h~pW2sflC6y6nRNEju z*BP=LietihoPA0yL^}7hx(u&IC1vUyqN`^Y&(6~`ydmlFKr}-tTb!y;=pjef#vQDt zNt?_Lc-WM!Y?iC^S#7bqE4;(DKeSS03x6Cq0(5U|&{fqla}!6Y&aG z#N3ggjlIJ}xGJyaL&?4lrP!FuZX6QG!oIyx=Qu7v_~6p)TWkg zJN+Nl5ssS8#DeRxQPDdlXkwcpCYb0Ap=VK13bmsH$Skpuox*k@zttV(&(56!_98?X zW{0#p>H+Iyrg~c~X;0|A@1dSOwi3r1Jj3+oneH{qrZ@8^RLa#`WqYyTD(1|SvssyF zZ0UA`*P*^~e~R!$8+4P09OHIcJm~OvXxdb|DJ9FhYH;jV9;2tS{3c#k)SH73drHfU qrrv)B&yDP^pEK2+p8M7P(EDLoFw { const [selectedFederation, setSelectedFederation] = useState(0); const [address, setAddress] = useState(''); + const options = federations.map(f => ({ + label: f.config.meta.federation_name || 'No connected Federations', + value: f.federation_id || 'No connected Federations', + })); + const handleFetchPegInAddress = () => { gatewayApi .fetchAddress(federations[selectedFederation].federation_id) @@ -108,21 +113,13 @@ export const PegInEcashCard = () => { Into Federation: {federations.length > 0 && ( setSelectedFederation(e[0] as any)} - options={federations.map(f => ({ - label: - f.config.meta.federation_name || - 'No connected Federations', - value: f.federation_id || 'No connected Federations', - }))} - value={{ - label: - federations[0].config.meta.federation_name || - 'No connected Federations', - value: - federations[0].federation_id || - 'No connected Federations', - }} + callback={e => + setSelectedFederation( + federations.findIndex(f => f.federation_id === e[0].value) + ) + } + options={options} + value={options[selectedFederation]} isClearable={false} /> )} diff --git a/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx index e9d3d871..a780760e 100644 --- a/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx +++ b/src/client/src/views/home/account/pegOutEcash/PegOutEcash.tsx @@ -1,45 +1,34 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState } from 'react'; import { toast } from 'react-toastify'; import { InputWithDeco } from '../../../../components/input/InputWithDeco'; -import { useBitcoinFees } from '../../../../hooks/UseBitcoinFees'; import { Separation, SingleLine, SubTitle, } from '../../../../components/generic/Styled'; -import { Input } from '../../../../components/input'; import { MultiButton, SingleButton, } from '../../../../components/buttons/multiButton/MultiButton'; -import { Price, getPrice } from '../../../../components/price/Price'; -import { useConfigState } from '../../../../context/ConfigContext'; +import { Price } from '../../../../components/price/Price'; import Modal from '../../../../components/modal/ReactModal'; import { ColorButton } from '../../../../components/buttons/colorButton/ColorButton'; import { renderLine } from '../../../../components/generic/helpers'; -import { usePriceState } from '../../../../context/PriceContext'; import { Federation } from '../../../../api/types'; import { SmallSelectWithValue } from '../../../../components/select'; import { useGatewayFederations } from '../../../../hooks/UseGatewayFederations'; import { gatewayApi } from '../../../../api/GatewayApi'; export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { - const { fast, halfHour, hour, minimum, dontShow } = useBitcoinFees(); - const { currency, displayValues, fetchFees } = useConfigState(); - const priceContext = usePriceState(); - const format = getPrice(currency, displayValues, priceContext); - const [modalOpen, setModalOpen] = useState(false); const [address, setAddress] = useState(''); const [tokens, setTokens] = useState(0); - const [type, setType] = useState(dontShow || !fetchFees ? 'fee' : 'none'); - const [amount, setAmount] = useState(0); const [sendAll, setSendAll] = useState(false); const [selectedFederation, setSelectedFederation] = useState(0); const federations: Federation[] = useGatewayFederations(); - const canSend = address !== '' && (sendAll || tokens > 0) && amount > 0; + const canSend = address !== '' && (sendAll || tokens > 0); const handlePegOut = ( federationIdx: number, @@ -62,31 +51,6 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { }); }; - useEffect(() => { - if (type === 'none' && amount === 0) { - setAmount(fast); - } - }, [type, amount, fast]); - - const feeFormat = (amount: number): JSX.Element | string => { - if (type === 'fee' || type === 'none') { - return format({ amount }); - } - return `${amount} blocks`; - }; - - // const typeAmount = () => { - // switch (type) { - // case 'none': - // case 'fee': - // return { fee: amount }; - // case 'target': - // return { target: amount }; - // default: - // return {}; - // } - // }; - const tokenAmount = sendAll ? { sendAll } : { tokens }; const renderButton = ( @@ -142,85 +106,6 @@ export const PegOutEcashCard = ({ setOpen }: { setOpen: () => void }) => { inputCallback={value => setTokens(Number(value))} /> )} - - - - {fetchFees && - !dontShow && - renderButton( - () => { - setType('none'); - setAmount(fast); - }, - 'Auto', - type === 'none' - )} - {renderButton( - () => { - setType('fee'); - setAmount(0); - }, - 'Fee (Sats/Byte)', - type === 'fee' - )} - {renderButton( - () => { - setType('target'); - setAmount(0); - }, - 'Target Confirmations', - type === 'target' - )} - - - - {'(~'} - {feeFormat(amount * 223)} - {')'} - - ) - } - > - {type !== 'none' ? ( - 0 ? amount : undefined} - maxWidth={'500px'} - placeholder={type === 'target' ? 'Blocks' : 'Sats/Byte'} - type={'number'} - withMargin={'0 0 0 8px'} - onChange={e => setAmount(Number(e.target.value))} - /> - ) : ( - - {renderButton( - () => setAmount(fast), - `Fastest (${fast} sats)`, - amount === fast - )} - {halfHour !== fast && - renderButton( - () => setAmount(halfHour), - `Half Hour (${halfHour} sats)`, - amount === halfHour - )} - {renderButton( - () => setAmount(hour), - `Hour (${hour} sats)`, - amount === hour - )} - - )} - - {!dontShow && renderLine('Minimum', `${minimum} sat/vByte`)} - void }) => { {renderLine('Amount:', sendAll ? 'all' : )} {renderLine('Address:', address)} - {renderLine( - 'Fee:', - type === 'target' ? `${amount} Blocks` : `${amount} Sats/Byte` - )} handlePegOut(selectedFederation, tokenAmount, address)} disabled={!canSend} From 2149c7be2e98e8517510ea1b895128d8961ccc07 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 1 Dec 2023 19:59:16 -0800 Subject: [PATCH 21/50] fix: multifederation and leave button --- src/client/pages/fedimints.tsx | 44 ++++++++++++------- .../account/gateway/FedimintGatewayCard.tsx | 16 ++----- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/client/pages/fedimints.tsx b/src/client/pages/fedimints.tsx index 94c70403..7a5ecc89 100644 --- a/src/client/pages/fedimints.tsx +++ b/src/client/pages/fedimints.tsx @@ -8,11 +8,14 @@ import { Card, DarkSubTitle, } from '../src/components/generic/Styled'; +import { X } from 'react-feather'; import { AddMint } from '../src/views/fedimints/AddMint'; import Table from '../src/components/table'; import { useGatewayFederations } from '../src/hooks/UseGatewayFederations'; import { Federation } from '../src/api/types'; import { CellContext } from '@tanstack/react-table'; +import { toast } from 'react-toastify'; +import { Price } from '../src/components/price/Price'; const FedimintsView = () => { const federations = useGatewayFederations(); @@ -40,34 +43,45 @@ const FedimintsView = () => { ), }, { - header: 'Federation ID', - accessorKey: 'federation_id', + header: 'Balance', + accessorKey: 'balance_msat', cell: (props: CellContext) => (
- {`${props.row.original.federation_id.slice( - 0, - 6 - )}...${props.row.original.federation_id.slice(-6)}`} +
), }, { - header: 'Balance (msat)', - accessorKey: 'balance_msat', + header: 'Suported Modules', + accessorKey: 'modules', cell: (props: CellContext) => (
- {props.row.original.balance_msat} + {Object.values(props.row.original.config.modules) + .map(module => module.kind) + .join(', ')}
), }, { - header: 'Consensus Version', - accessorKey: 'consensus_version', + header: 'Leave', + accessorKey: 'leave', cell: (props: CellContext) => ( -
- {props.row.original.config.consensus_version.major + - '.' + - props.row.original.config.consensus_version.minor} +
{ + if (props.row.original.balance_msat > 0) { + toast.error("Can't leave a federation you've got sats in!"); + } else { + toast.warn('Not implemented yet!'); + } + }} + > +
), }, diff --git a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx index 6599bb0e..4c1486da 100644 --- a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx +++ b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx @@ -40,10 +40,6 @@ export const FedimintGatewayCard = ({ }); }; - const formatFederationId = (id: string) => { - return `${id.slice(0, 6)}...${id.slice(-6)}`; - }; - return ( @@ -75,18 +71,14 @@ export const FedimintGatewayCard = ({ ) : ( -
+
{renderLine( - 'Amount', + 'Total Amount', )} {renderLine( - 'Federation', - gatewayInfo.federations[0].config.meta.federation_name - )} - {renderLine( - 'ID', - formatFederationId(gatewayInfo.federations[0].federation_id) + 'Connected Federations', + gatewayInfo.federations.length )}
)} From 480543d0cee2bed00094d8f91f5f76dd16bf7b24 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 16 Nov 2023 12:45:00 -0800 Subject: [PATCH 22/50] feat: begin fedimint cards --- .gitignore | 5 ++--- src/client/src/views/home/account/AccountInfo.tsx | 12 ++++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 03b17961..4729ac5e 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,5 @@ lerna-debug.log* # config files config.yaml - -# For Dev -local_data +data +data/* diff --git a/src/client/src/views/home/account/AccountInfo.tsx b/src/client/src/views/home/account/AccountInfo.tsx index bac53d3f..b4557a2e 100644 --- a/src/client/src/views/home/account/AccountInfo.tsx +++ b/src/client/src/views/home/account/AccountInfo.tsx @@ -78,6 +78,18 @@ export const AccountInfo = () => {
+ + Fedimint Ecash +
+ +
+
+ + Onchain Bitcoin +
+ +
+
{gatewayInfo && ( Fedimint Ecash From e69553f242ceba2f0e03a0cd7d2c7d45dc4bb617 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 16 Nov 2023 20:43:39 -0800 Subject: [PATCH 23/50] feat: connect to federation card --- src/client/src/api/GatewayApi.ts | 72 +++++++++++++++ src/client/src/api/GatewayApiProvider.tsx | 21 +++++ .../account/gateway/FedimintGatewayCard.tsx | 92 +++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 src/client/src/api/GatewayApiProvider.tsx diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts index 7800b019..d452d456 100644 --- a/src/client/src/api/GatewayApi.ts +++ b/src/client/src/api/GatewayApi.ts @@ -8,9 +8,81 @@ import { GatewayInfo, Federation } from './types'; const { publicRuntimeConfig } = getConfig(); // GatewayApi is an implementation of the ApiInterface +<<<<<<< HEAD class GatewayApi { private baseUrl: string | undefined = publicRuntimeConfig.fmGatewayUrl; private password: string | undefined = publicRuntimeConfig.fmGatewayPassword; +||||||| parent of 9e521814 (feat: connect to federation card) +export class GatewayApi { + private baseUrl: string | undefined = process.env.REACT_APP_FM_GATEWAY_API; + + // Tests a provided password, or the one in the environment config, or the one in session storage + testPassword = async (password?: string): Promise => { + const tempPassword = + password || + this.getPassword() || + process.env.REACT_APP_FM_GATEWAY_PASSWORD; + + if (!tempPassword) { + return false; + } + + // Replace with temp password to check. + sessionStorage.setItem(SESSION_STORAGE_KEY, tempPassword); + + try { + await this.fetchInfo(); + return true; + } catch (err) { + // TODO: make sure error is auth error, not unrelated + console.error(err); + this.clearPassword(); + return false; + } + }; + + private getPassword = (): string | null => { + return sessionStorage.getItem(SESSION_STORAGE_KEY); + }; + + clearPassword = () => { + sessionStorage.removeItem(SESSION_STORAGE_KEY); + }; +======= +export class GatewayApi { + private baseUrl: string | undefined = process.env.FM_GATEWAY_API; + + // Tests a provided password, or the one in the environment config, or the one in session storage + testPassword = async (password?: string): Promise => { + const tempPassword = + password || this.getPassword() || process.env.FM_GATEWAY_PASSWORD; + + if (!tempPassword) { + return false; + } + + // Replace with temp password to check. + sessionStorage.setItem(SESSION_STORAGE_KEY, tempPassword); + + try { + await this.fetchInfo(); + return true; + } catch (err) { + // TODO: make sure error is auth error, not unrelated + console.error(err); + this.clearPassword(); + return false; + } + }; + + private getPassword = (): string | null => { + return sessionStorage.getItem(SESSION_STORAGE_KEY); + }; + + clearPassword = () => { + sessionStorage.removeItem(SESSION_STORAGE_KEY); + }; +>>>>>>> 9e521814 (feat: connect to federation card) private post = async (api: string, body: unknown): Promise => { if (this.baseUrl === undefined) { diff --git a/src/client/src/api/GatewayApiProvider.tsx b/src/client/src/api/GatewayApiProvider.tsx new file mode 100644 index 00000000..dacef0ac --- /dev/null +++ b/src/client/src/api/GatewayApiProvider.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { GatewayApi } from './GatewayApi'; + +interface ApiContextProps { + // API to interact with the Gateway server + gateway: GatewayApi; +} + +export const ApiContext = React.createContext({ + gateway: new GatewayApi(), +}); + +export const ApiProvider = React.memo(function ApiProvider({ + props, + children, +}: { + props: ApiContextProps; + children: React.ReactNode; +}): JSX.Element { + return {children}; +}); diff --git a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx index 4c1486da..fe67cfb3 100644 --- a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx +++ b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx @@ -1,3 +1,4 @@ +<<<<<<< HEAD import React, { useState } from 'react'; import { Card, @@ -86,3 +87,94 @@ export const FedimintGatewayCard = ({
); }; +||||||| parent of 9e521814 (feat: connect to federation card) +======= +import React, { useState } from 'react'; +import { ApiContext } from '../../../../api/GatewayApiProvider'; +import { + Card, + CardWithTitle, + Separation, + SingleLine, + SubTitle, +} from '../../../../components/generic/Styled'; +import { Anchor } from 'react-feather'; +import { renderLine } from '../../../../components/generic/helpers'; +import { GatewayInfo } from '../../../../api/types'; +import { toast } from 'react-toastify'; +import { Input } from '../../../../components/input'; +import { ColorButton } from '../../../../components/buttons/colorButton/ColorButton'; + +export const FedimintGatewayCard = () => { + const { gateway } = React.useContext(ApiContext); + const [gatewayInfo, setGatewayInfo] = useState({ + federations: [], + fees: { + base_msat: 0, + proportional_millionths: 0, + }, + lightning_alias: '', + lightning_pub_key: '', + version_hash: '', + }); + const [inviteCode, setInviteCode] = useState(''); + + const handleEnter = () => { + gateway + .connectFederation(inviteCode) + .then(() => { + toast.success('Successfully connected to federation!'); + setInviteCode(''); + gateway + .fetchInfo() + .then(setGatewayInfo) + .catch(({ message, error }) => { + console.log(error); + toast.error(message); + }); + }) + .catch(({ message, error }) => { + console.log(error); + toast.error(message); + }); + }; + + return ( + + + + + Fedimint Ecash + + + {gatewayInfo.federations.length === 0 ? ( + <> +
+ + {renderLine('Connect to a Federation', ' ')} + +
+ + setInviteCode(e.target.value)} + /> + + Connect + + + + ) : ( + <>{renderLine('Alias', gatewayInfo.federations[0].federation_id)} + )} +
+
+ ); +}; +>>>>>>> 9e521814 (feat: connect to federation card) From 2609def5729142d2174ec6969b22626827396424 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 17 Nov 2023 16:07:27 -0800 Subject: [PATCH 24/50] feat: refactor to gateway context pattern --- src/client/src/api/GatewayApiProvider.tsx | 21 ----- src/client/src/api/types.ts | 30 ++++++ .../account/gateway/FedimintGatewayCard.tsx | 92 ------------------- 3 files changed, 30 insertions(+), 113 deletions(-) delete mode 100644 src/client/src/api/GatewayApiProvider.tsx diff --git a/src/client/src/api/GatewayApiProvider.tsx b/src/client/src/api/GatewayApiProvider.tsx deleted file mode 100644 index dacef0ac..00000000 --- a/src/client/src/api/GatewayApiProvider.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import { GatewayApi } from './GatewayApi'; - -interface ApiContextProps { - // API to interact with the Gateway server - gateway: GatewayApi; -} - -export const ApiContext = React.createContext({ - gateway: new GatewayApi(), -}); - -export const ApiProvider = React.memo(function ApiProvider({ - props, - children, -}: { - props: ApiContextProps; - children: React.ReactNode; -}): JSX.Element { - return {children}; -}); diff --git a/src/client/src/api/types.ts b/src/client/src/api/types.ts index 16d4867d..575d4670 100644 --- a/src/client/src/api/types.ts +++ b/src/client/src/api/types.ts @@ -60,6 +60,7 @@ export enum Network { } export type TransactionId = string; +<<<<<<< HEAD // For testing export const dummyFederation = { @@ -87,3 +88,32 @@ export const dummyFederation = { }, }, }; +||||||| parent of 17bf936c (feat: refactor to gateway context pattern) +======= + +export const dummyFederation = { + federation_id: 'test_federation_id', + balance_msat: 1000, + config: { + consensus_version: 1, + epoch_pk: 'test_epoch_pk', + federation_id: 'test_federation_id', + api_endpoints: { + 0: { + name: 'test_api_endpoint_name', + url: 'test_api_endpoint_url', + }, + }, + modules: { + 0: { + config: 'test_module_config', + kind: ModuleKind.Ln, + version: 1, + }, + }, + meta: { + federation_name: 'test_federation_name', + }, + }, +}; +>>>>>>> 17bf936c (feat: refactor to gateway context pattern) diff --git a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx index fe67cfb3..4c1486da 100644 --- a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx +++ b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx @@ -1,4 +1,3 @@ -<<<<<<< HEAD import React, { useState } from 'react'; import { Card, @@ -87,94 +86,3 @@ export const FedimintGatewayCard = ({ ); }; -||||||| parent of 9e521814 (feat: connect to federation card) -======= -import React, { useState } from 'react'; -import { ApiContext } from '../../../../api/GatewayApiProvider'; -import { - Card, - CardWithTitle, - Separation, - SingleLine, - SubTitle, -} from '../../../../components/generic/Styled'; -import { Anchor } from 'react-feather'; -import { renderLine } from '../../../../components/generic/helpers'; -import { GatewayInfo } from '../../../../api/types'; -import { toast } from 'react-toastify'; -import { Input } from '../../../../components/input'; -import { ColorButton } from '../../../../components/buttons/colorButton/ColorButton'; - -export const FedimintGatewayCard = () => { - const { gateway } = React.useContext(ApiContext); - const [gatewayInfo, setGatewayInfo] = useState({ - federations: [], - fees: { - base_msat: 0, - proportional_millionths: 0, - }, - lightning_alias: '', - lightning_pub_key: '', - version_hash: '', - }); - const [inviteCode, setInviteCode] = useState(''); - - const handleEnter = () => { - gateway - .connectFederation(inviteCode) - .then(() => { - toast.success('Successfully connected to federation!'); - setInviteCode(''); - gateway - .fetchInfo() - .then(setGatewayInfo) - .catch(({ message, error }) => { - console.log(error); - toast.error(message); - }); - }) - .catch(({ message, error }) => { - console.log(error); - toast.error(message); - }); - }; - - return ( - - - - - Fedimint Ecash - - - {gatewayInfo.federations.length === 0 ? ( - <> -
- - {renderLine('Connect to a Federation', ' ')} - -
- - setInviteCode(e.target.value)} - /> - - Connect - - - - ) : ( - <>{renderLine('Alias', gatewayInfo.federations[0].federation_id)} - )} -
-
- ); -}; ->>>>>>> 9e521814 (feat: connect to federation card) From ee0e1feb701d8b0093df72c8e39f432881a6753f Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 17 Nov 2023 17:49:26 -0800 Subject: [PATCH 25/50] fix: minor run fixes --- .../gateway/.FedimintGatewayCard.tsx.swp | Bin 0 -> 12288 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp diff --git a/src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp b/src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp new file mode 100644 index 0000000000000000000000000000000000000000..8bcdd22863f83ad35d13ae1a2bd1eb2636104c2b GIT binary patch literal 12288 zcmeI2O^6&t6vr#Uuc$E+ji8`Z)A&B2R!(StV+DoPIGzxrdQW@abxDydeUyQmgzHgmEdzfA@BUL#$Vn_cklb2kV}!jrHXI%c@B2T>@xFCMA4<$ zb8$3#*bX9(1tSe#RSuoS$m_OwC=;hCWUE_u>Oy*v2xk-7Z8RJdg+7l}MG||C7YNv9 zU)KfSNSs#G<_`0`sEgtzlYE11Ij6WU+9H&v^ZNxB`?gFrNBTFnMuA&ffxYC(!*khI ze|+j7ePI6!x3(N+^hN=rfKk9GU=%P47zK<1MuA&Q0omC_Uc;Do7vo+luDeFA#jUv* z1&jhl0i%FXz$jo8FbWt2i~>dhqkvJsDDXd2fcb zkHP!k3fKlcuna2T=lclx47?5;@cUjuJ_MJ63yy+^!1a3x`5XKNz5`!^cfn;)11@+B z{BjQ=*TCmMf>mIHDewq503HN;z@K*$@+-IoJ^|Yx0WX0=;8F0~9zs3^F}Mg$fjO`X z{B##$0B->aPJ@HspF0Wp5qu4;Ud<#9l09U~W z;BD|GP&&T>%*QBT6fg?(73du$luoN(l)8>O!L)|sQL91*{8(047MFLh?iCez8(*vs z>Qqr0b9I#Jj0kzfT3WPbXmMU@DQrY`gQJc~5rxV5>ILogqVR`2k94Fw-@uO-g$>cP z+gvi;XUN)|sHTIDg;QHa1l9~0ln)0!R5214Bsmugk5krG$H8jp4dSY^fQ25v*iM-2 zQD;~wO0DCWi~kmg3#n-$w*p>EQ`%;6Q-t%>s&+Q1;z)kAXs%SUuo=EfwLqkbEKXIjz-d)EaZ? zYGWH2!iYpFMs$ykn-CuUj?sk6rG5t$Zc7BurM=FAE+1PglxF36OyiMv0_O2n6kuuA zrp~cMa+>!5nSDMr5}~^kcDlpLyOZY8b;fom7Vz119yfw$W0h~pW2sflC6y6nRNEju z*BP=LietihoPA0yL^}7hx(u&IC1vUyqN`^Y&(6~`ydmlFKr}-tTb!y;=pjef#vQDt zNt?_Lc-WM!Y?iC^S#7bqE4;(DKeSS03x6Cq0(5U|&{fqla}!6Y&aG z#N3ggjlIJ}xGJyaL&?4lrP!FuZX6QG!oIyx=Qu7v_~6p)TWkg zJN+Nl5ssS8#DeRxQPDdlXkwcpCYb0Ap=VK13bmsH$Skpuox*k@zttV(&(56!_98?X zW{0#p>H+Iyrg~c~X;0|A@1dSOwi3r1Jj3+oneH{qrZ@8^RLa#`WqYyTD(1|SvssyF zZ0UA`*P*^~e~R!$8+4P09OHIcJm~OvXxdb|DJ9FhYH;jV9;2tS{3c#k)SH73drHfU qrrv)B&yDP^pEK2+p8M7P(EDLoFw Date: Mon, 20 Nov 2023 07:25:26 -0800 Subject: [PATCH 26/50] fix: local_data dir for dev --- .gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4729ac5e..03b17961 100644 --- a/.gitignore +++ b/.gitignore @@ -44,5 +44,6 @@ lerna-debug.log* # config files config.yaml -data -data/* + +# For Dev +local_data From 140f09f7c8d814ed38705071b1a5f4fc3bb9b26d Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Mon, 20 Nov 2023 07:25:26 -0800 Subject: [PATCH 27/50] devimint setup scripts fix: local_data dir for dev fix: yaml config file write to temp --- scripts/mprocs-nix-gateway.sh | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/scripts/mprocs-nix-gateway.sh b/scripts/mprocs-nix-gateway.sh index 1bd376bc..e5b1d565 100644 --- a/scripts/mprocs-nix-gateway.sh +++ b/scripts/mprocs-nix-gateway.sh @@ -1,3 +1,4 @@ +<<<<<<< HEAD # shellcheck shell=bash set -eo pipefail @@ -34,3 +35,43 @@ export FM_GATEWAY_API=$FM_GATEWAY_API_ADDR export FM_GATEWAY_PASSWORD=$FM_GATEWAY_PASSWORD npm run start:dev +||||||| parent of 3c08692a (devimint setup scripts) +======= +# shellcheck shell=bash + +set -eo pipefail + +eval "$(devimint env)" + +echo Waiting for devimint to start up fedimint and gateway + +STATUS="$(devimint wait)" +if [ "$STATUS" = "ERROR" ] +then + echo "fedimint didn't start correctly" + echo "See other panes for errors" + exit 1 +fi + +TEMP_FILE=$(mktemp) +FM_LND_RPC_STRIPPED=$(echo $FM_LND_RPC_ADDR | sed 's/http[s]\?:\/\///') + +cat << EOF > "$TEMP_FILE" +masterPassword: password +accounts: + - name: test-regtest + serverUrl: $FM_LND_RPC_STRIPPED + macaroonPath: $FM_LND_MACAROON + certificatePath: $FM_LND_TLS_CERT +EOF + +echo $TEMP_FILE +# ----------- +# Fedimint Config +# ----------- +export ACCOUNT_CONFIG_PATH=$TEMP_FILE +export FM_GATEWAY_URL=$FM_GATEWAY_API_ADDR +export FM_GATEWAY_PASSWORD=$FM_GATEWAY_PASSWORD + +npm run start:dev +>>>>>>> 3c08692a (devimint setup scripts) From c8330cfbdf8c1a2d258d9d100174a0b708a31641 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 23 Nov 2023 14:42:53 -0800 Subject: [PATCH 28/50] fix: fix gateway password and url assignment from publicRuntimeConfig --- .direnv/flake-profile | 1 + .direnv/flake-profile-1-link | 1 + scripts/mprocs-nix-gateway.sh | 3 +- src/client/src/api/GatewayApi.ts | 72 ------------------- .../account/gateway/FedimintGatewayCard.tsx | 4 ++ 5 files changed, 7 insertions(+), 74 deletions(-) create mode 120000 .direnv/flake-profile create mode 120000 .direnv/flake-profile-1-link diff --git a/.direnv/flake-profile b/.direnv/flake-profile new file mode 120000 index 00000000..0c05709d --- /dev/null +++ b/.direnv/flake-profile @@ -0,0 +1 @@ +flake-profile-1-link \ No newline at end of file diff --git a/.direnv/flake-profile-1-link b/.direnv/flake-profile-1-link new file mode 120000 index 00000000..3a6b04ce --- /dev/null +++ b/.direnv/flake-profile-1-link @@ -0,0 +1 @@ +/nix/store/xnjqp9yyak09ca78kr0in3v60fw1lqgk-nix-shell-env \ No newline at end of file diff --git a/scripts/mprocs-nix-gateway.sh b/scripts/mprocs-nix-gateway.sh index e5b1d565..6389de2c 100644 --- a/scripts/mprocs-nix-gateway.sh +++ b/scripts/mprocs-nix-gateway.sh @@ -65,12 +65,11 @@ accounts: certificatePath: $FM_LND_TLS_CERT EOF -echo $TEMP_FILE # ----------- # Fedimint Config # ----------- export ACCOUNT_CONFIG_PATH=$TEMP_FILE -export FM_GATEWAY_URL=$FM_GATEWAY_API_ADDR +export FM_GATEWAY_API=$FM_GATEWAY_API_ADDR export FM_GATEWAY_PASSWORD=$FM_GATEWAY_PASSWORD npm run start:dev diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts index d452d456..7800b019 100644 --- a/src/client/src/api/GatewayApi.ts +++ b/src/client/src/api/GatewayApi.ts @@ -8,81 +8,9 @@ import { GatewayInfo, Federation } from './types'; const { publicRuntimeConfig } = getConfig(); // GatewayApi is an implementation of the ApiInterface -<<<<<<< HEAD class GatewayApi { private baseUrl: string | undefined = publicRuntimeConfig.fmGatewayUrl; private password: string | undefined = publicRuntimeConfig.fmGatewayPassword; -||||||| parent of 9e521814 (feat: connect to federation card) -export class GatewayApi { - private baseUrl: string | undefined = process.env.REACT_APP_FM_GATEWAY_API; - - // Tests a provided password, or the one in the environment config, or the one in session storage - testPassword = async (password?: string): Promise => { - const tempPassword = - password || - this.getPassword() || - process.env.REACT_APP_FM_GATEWAY_PASSWORD; - - if (!tempPassword) { - return false; - } - - // Replace with temp password to check. - sessionStorage.setItem(SESSION_STORAGE_KEY, tempPassword); - - try { - await this.fetchInfo(); - return true; - } catch (err) { - // TODO: make sure error is auth error, not unrelated - console.error(err); - this.clearPassword(); - return false; - } - }; - - private getPassword = (): string | null => { - return sessionStorage.getItem(SESSION_STORAGE_KEY); - }; - - clearPassword = () => { - sessionStorage.removeItem(SESSION_STORAGE_KEY); - }; -======= -export class GatewayApi { - private baseUrl: string | undefined = process.env.FM_GATEWAY_API; - - // Tests a provided password, or the one in the environment config, or the one in session storage - testPassword = async (password?: string): Promise => { - const tempPassword = - password || this.getPassword() || process.env.FM_GATEWAY_PASSWORD; - - if (!tempPassword) { - return false; - } - - // Replace with temp password to check. - sessionStorage.setItem(SESSION_STORAGE_KEY, tempPassword); - - try { - await this.fetchInfo(); - return true; - } catch (err) { - // TODO: make sure error is auth error, not unrelated - console.error(err); - this.clearPassword(); - return false; - } - }; - - private getPassword = (): string | null => { - return sessionStorage.getItem(SESSION_STORAGE_KEY); - }; - - clearPassword = () => { - sessionStorage.removeItem(SESSION_STORAGE_KEY); - }; ->>>>>>> 9e521814 (feat: connect to federation card) private post = async (api: string, body: unknown): Promise => { if (this.baseUrl === undefined) { diff --git a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx index 4c1486da..3ca293c2 100644 --- a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx +++ b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx @@ -40,6 +40,10 @@ export const FedimintGatewayCard = ({ }); }; + const formatFederationId = (id: string) => { + return `${id.slice(0, 6)}...${id.slice(-6)}`; + }; + return ( From a19629cb3c090d8fa70fb83abeda7024969d965b Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 23 Nov 2023 15:11:32 -0800 Subject: [PATCH 29/50] fix: fix peg out command --- .../src/views/home/account/AccountButtons.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/client/src/views/home/account/AccountButtons.tsx b/src/client/src/views/home/account/AccountButtons.tsx index 24afcd3d..7784d68e 100644 --- a/src/client/src/views/home/account/AccountButtons.tsx +++ b/src/client/src/views/home/account/AccountButtons.tsx @@ -114,6 +114,7 @@ export const AccountButtons = () => { )} Peg Out +<<<<<<< HEAD @@ -127,6 +128,22 @@ export const AccountButtons = () => { )} Peg In +||||||| parent of 51c324fe (fix: fix peg out command) +======= + + setState(state === 'pegin_ecash' ? 'none' : 'pegin_ecash') + } + > + {state === 'pegin_ecash' ? ( + + ) : ( + + )} + Peg In + +>>>>>>> 51c324fe (fix: fix peg out command) {state !== 'none' && {renderContent()}} From 5b53e64d63cf719378f2a176ec2179f1bb0420f2 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Tue, 28 Nov 2023 11:42:34 -0800 Subject: [PATCH 30/50] feat: fedimint 0.2 api updates --- .direnv/flake-profile | 1 - .direnv/flake-profile-1-link | 1 - flake.lock | 20 ++++++++++++++++++++ src/client/src/api/GatewayApi.ts | 2 -- 4 files changed, 20 insertions(+), 4 deletions(-) delete mode 120000 .direnv/flake-profile delete mode 120000 .direnv/flake-profile-1-link diff --git a/.direnv/flake-profile b/.direnv/flake-profile deleted file mode 120000 index 0c05709d..00000000 --- a/.direnv/flake-profile +++ /dev/null @@ -1 +0,0 @@ -flake-profile-1-link \ No newline at end of file diff --git a/.direnv/flake-profile-1-link b/.direnv/flake-profile-1-link deleted file mode 120000 index 3a6b04ce..00000000 --- a/.direnv/flake-profile-1-link +++ /dev/null @@ -1 +0,0 @@ -/nix/store/xnjqp9yyak09ca78kr0in3v60fw1lqgk-nix-shell-env \ No newline at end of file diff --git a/flake.lock b/flake.lock index 741e3941..df6d828e 100644 --- a/flake.lock +++ b/flake.lock @@ -98,16 +98,36 @@ "nixpkgs-unstable": "nixpkgs-unstable_2" }, "locked": { +<<<<<<< HEAD "lastModified": 1701469066, "narHash": "sha256-3pt8qUfaUvQRl1gWY2Qkk4MRBbzpYtId/rdTitLffBQ=", +||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) + "lastModified": 1699573846, + "narHash": "sha256-4xKNhUE7e3GjjMbNib35B7eJWjuDIbYtwoHBOWYtqFA=", +======= + "lastModified": 1701034148, + "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", +>>>>>>> 8bdccdae (feat: fedimint 0.2 api updates) "owner": "fedimint", "repo": "fedimint", +<<<<<<< HEAD "rev": "f316e987aaf1a81b1626f7e418318ca683e0a47a", +||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) + "rev": "f58f1913e62b6529a2ff36ec5c89a3852aba7ca7", +======= + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", +>>>>>>> 8bdccdae (feat: fedimint 0.2 api updates) "type": "github" }, "original": { "owner": "fedimint", "repo": "fedimint", +<<<<<<< HEAD +||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) + "rev": "f58f1913e62b6529a2ff36ec5c89a3852aba7ca7", +======= + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", +>>>>>>> 8bdccdae (feat: fedimint 0.2 api updates) "type": "github" } }, diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts index 7800b019..3bd20e8e 100644 --- a/src/client/src/api/GatewayApi.ts +++ b/src/client/src/api/GatewayApi.ts @@ -114,5 +114,3 @@ class GatewayApi { const responseToError = (res: Response): Error => { return new Error(`Status : ${res.status} \nReason : ${res.statusText}\n`); }; - -export const gatewayApi = new GatewayApi(); From cfdf4ae53ca563830dd89b28d95c3f7252887c33 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Tue, 28 Nov 2023 11:49:42 -0800 Subject: [PATCH 31/50] fix: missing export gatewayApi --- src/client/src/api/GatewayApi.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client/src/api/GatewayApi.ts b/src/client/src/api/GatewayApi.ts index 3bd20e8e..7800b019 100644 --- a/src/client/src/api/GatewayApi.ts +++ b/src/client/src/api/GatewayApi.ts @@ -114,3 +114,5 @@ class GatewayApi { const responseToError = (res: Response): Error => { return new Error(`Status : ${res.status} \nReason : ${res.statusText}\n`); }; + +export const gatewayApi = new GatewayApi(); From 70ce4b6c215ca0bafe26ad22c419811bae2b9afb Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Tue, 28 Nov 2023 12:08:54 -0800 Subject: [PATCH 32/50] fix: updates --- .../src/views/home/account/AccountButtons.tsx | 82 ++++++++----------- .../account/gateway/FedimintGatewayCard.tsx | 4 - 2 files changed, 36 insertions(+), 50 deletions(-) diff --git a/src/client/src/views/home/account/AccountButtons.tsx b/src/client/src/views/home/account/AccountButtons.tsx index 7784d68e..42633437 100644 --- a/src/client/src/views/home/account/AccountButtons.tsx +++ b/src/client/src/views/home/account/AccountButtons.tsx @@ -10,14 +10,16 @@ import { ReceiveOnChainCard } from './receiveOnChain/ReceiveOnChain'; import { SendOnChainCard } from './sendOnChain/SendOnChain'; import { PegInEcashCard } from './pegInEcash/PegInEcash'; import { PegOutEcashCard } from './pegOutEcash/PegOutEcash'; +import { useGatewayState } from '../../../context/GatewayContext'; const SECTION_COLOR = '#FFD300'; const S = { - grid: styled.div` + grid: styled.div<{ federations: number }>` display: grid; grid-gap: 8px; - grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; + grid-template-columns: ${({ federations }) => + federations > 0 ? '1fr 1fr 1fr 1fr 1fr 1fr' : '1fr 1fr 1fr 1fr'}; margin-bottom: 32px; @media (${mediaWidths.modifiedMobile}) { @@ -28,6 +30,7 @@ const S = { export const AccountButtons = () => { const [state, setState] = useState('none'); + const { gatewayInfo } = useGatewayState(); const renderContent = () => { switch (state) { @@ -50,7 +53,7 @@ export const AccountButtons = () => { return ( <> - + setState(state === 'send_ln' ? 'none' : 'send_ln')} @@ -101,49 +104,36 @@ export const AccountButtons = () => { )} Receive - - setState(state === 'pegout_ecash' ? 'none' : 'pegout_ecash') - } - > - {state === 'pegout_ecash' ? ( - - ) : ( - - )} - Peg Out - -<<<<<<< HEAD - - setState(state === 'pegin_ecash' ? 'none' : 'pegin_ecash') - } - > - {state === 'pegin_ecash' ? ( - - ) : ( - - )} - Peg In - -||||||| parent of 51c324fe (fix: fix peg out command) -======= - - setState(state === 'pegin_ecash' ? 'none' : 'pegin_ecash') - } - > - {state === 'pegin_ecash' ? ( - - ) : ( - - )} - Peg In - ->>>>>>> 51c324fe (fix: fix peg out command) + {gatewayInfo?.federations && gatewayInfo?.federations.length > 0 && ( + + setState(state === 'pegout_ecash' ? 'none' : 'pegout_ecash') + } + > + {state === 'pegout_ecash' ? ( + + ) : ( + + )} + Peg Out + + )} + {gatewayInfo?.federations && gatewayInfo?.federations.length > 0 && ( + + setState(state === 'pegin_ecash' ? 'none' : 'pegin_ecash') + } + > + {state === 'pegin_ecash' ? ( + + ) : ( + + )} + Peg In + + )} {state !== 'none' && {renderContent()}} diff --git a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx index 3ca293c2..4c1486da 100644 --- a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx +++ b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx @@ -40,10 +40,6 @@ export const FedimintGatewayCard = ({ }); }; - const formatFederationId = (id: string) => { - return `${id.slice(0, 6)}...${id.slice(-6)}`; - }; - return ( From edbb90eecc7d9c677febd00aacd2d4f73e3fcd79 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 30 Nov 2023 13:09:58 -0800 Subject: [PATCH 33/50] fix: hold --- flake.lock | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/flake.lock b/flake.lock index df6d828e..8a9bfd54 100644 --- a/flake.lock +++ b/flake.lock @@ -98,6 +98,7 @@ "nixpkgs-unstable": "nixpkgs-unstable_2" }, "locked": { +<<<<<<< HEAD <<<<<<< HEAD "lastModified": 1701469066, "narHash": "sha256-3pt8qUfaUvQRl1gWY2Qkk4MRBbzpYtId/rdTitLffBQ=", @@ -108,8 +109,16 @@ "lastModified": 1701034148, "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", >>>>>>> 8bdccdae (feat: fedimint 0.2 api updates) +||||||| parent of d29320cb (fix: hold) + "lastModified": 1701034148, + "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", +======= + "lastModified": 1701251322, + "narHash": "sha256-og7C8Q19KsHf4HCsgiI1CbNEWk4kUcArtiitWteTXpw=", +>>>>>>> d29320cb (fix: hold) "owner": "fedimint", "repo": "fedimint", +<<<<<<< HEAD <<<<<<< HEAD "rev": "f316e987aaf1a81b1626f7e418318ca683e0a47a", ||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) @@ -117,17 +126,28 @@ ======= "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", >>>>>>> 8bdccdae (feat: fedimint 0.2 api updates) +||||||| parent of d29320cb (fix: hold) + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", +======= + "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", +>>>>>>> d29320cb (fix: hold) "type": "github" }, "original": { "owner": "fedimint", "repo": "fedimint", <<<<<<< HEAD +<<<<<<< HEAD ||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) "rev": "f58f1913e62b6529a2ff36ec5c89a3852aba7ca7", ======= "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", >>>>>>> 8bdccdae (feat: fedimint 0.2 api updates) +||||||| parent of d29320cb (fix: hold) + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", +======= + "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", +>>>>>>> d29320cb (fix: hold) "type": "github" } }, From ad437e700b46330c9b4e40d7a1a818b0538eaaaa Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 30 Nov 2023 14:26:57 -0800 Subject: [PATCH 34/50] feat: skyler updates --- flake.lock | 20 +++++++++++++++++++ .../src/views/home/account/AccountInfo.tsx | 15 ++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/flake.lock b/flake.lock index 8a9bfd54..b397d488 100644 --- a/flake.lock +++ b/flake.lock @@ -99,6 +99,7 @@ }, "locked": { <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD "lastModified": 1701469066, "narHash": "sha256-3pt8qUfaUvQRl1gWY2Qkk4MRBbzpYtId/rdTitLffBQ=", @@ -116,9 +117,17 @@ "lastModified": 1701251322, "narHash": "sha256-og7C8Q19KsHf4HCsgiI1CbNEWk4kUcArtiitWteTXpw=", >>>>>>> d29320cb (fix: hold) +||||||| parent of 7f9cb0f7 (feat: skyler updates) + "lastModified": 1701251322, + "narHash": "sha256-og7C8Q19KsHf4HCsgiI1CbNEWk4kUcArtiitWteTXpw=", +======= + "lastModified": 1701034148, + "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", +>>>>>>> 7f9cb0f7 (feat: skyler updates) "owner": "fedimint", "repo": "fedimint", <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD "rev": "f316e987aaf1a81b1626f7e418318ca683e0a47a", ||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) @@ -131,6 +140,11 @@ ======= "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", >>>>>>> d29320cb (fix: hold) +||||||| parent of 7f9cb0f7 (feat: skyler updates) + "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", +======= + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", +>>>>>>> 7f9cb0f7 (feat: skyler updates) "type": "github" }, "original": { @@ -138,6 +152,7 @@ "repo": "fedimint", <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) "rev": "f58f1913e62b6529a2ff36ec5c89a3852aba7ca7", ======= @@ -148,6 +163,11 @@ ======= "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", >>>>>>> d29320cb (fix: hold) +||||||| parent of 7f9cb0f7 (feat: skyler updates) + "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", +======= + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", +>>>>>>> 7f9cb0f7 (feat: skyler updates) "type": "github" } }, diff --git a/src/client/src/views/home/account/AccountInfo.tsx b/src/client/src/views/home/account/AccountInfo.tsx index b4557a2e..9c285a14 100644 --- a/src/client/src/views/home/account/AccountInfo.tsx +++ b/src/client/src/views/home/account/AccountInfo.tsx @@ -34,6 +34,21 @@ const S = { `, }; +// const Tile = styled.div` +// display: flex; +// flex-direction: column; +// justify-content: space-between; +// align-items: ${({ startTile }: { startTile?: boolean }) => +// startTile ? 'flex-start' : 'flex-end'}; + +// @media (${mediaWidths.mobile}) { +// width: 100%; +// flex-direction: row; +// align-items: flex-end; +// margin: 0 0 8px; +// } +// `; + const sectionColor = '#FFD300'; export const AccountInfo = () => { From 5a4e38040321aaeb449e43509c3e11d74812542d Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 1 Dec 2023 18:38:47 -0800 Subject: [PATCH 35/50] feat: bump fedimint version for multifederation support --- flake.lock | 19 ++++++++++++++++++ src/client/src/api/types.ts | 1 + .../src/views/home/account/AccountInfo.tsx | 15 -------------- .../gateway/.FedimintGatewayCard.tsx.swp | Bin 12288 -> 0 bytes 4 files changed, 20 insertions(+), 15 deletions(-) delete mode 100644 src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp diff --git a/flake.lock b/flake.lock index b397d488..af44e9ea 100644 --- a/flake.lock +++ b/flake.lock @@ -100,6 +100,7 @@ "locked": { <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD "lastModified": 1701469066, "narHash": "sha256-3pt8qUfaUvQRl1gWY2Qkk4MRBbzpYtId/rdTitLffBQ=", @@ -124,10 +125,18 @@ "lastModified": 1701034148, "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", >>>>>>> 7f9cb0f7 (feat: skyler updates) +||||||| parent of 02175d04 (feat: bump fedimint version for multifederation support) + "lastModified": 1701034148, + "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", +======= + "lastModified": 1701469066, + "narHash": "sha256-3pt8qUfaUvQRl1gWY2Qkk4MRBbzpYtId/rdTitLffBQ=", +>>>>>>> 02175d04 (feat: bump fedimint version for multifederation support) "owner": "fedimint", "repo": "fedimint", <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD "rev": "f316e987aaf1a81b1626f7e418318ca683e0a47a", ||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) @@ -145,6 +154,11 @@ ======= "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", >>>>>>> 7f9cb0f7 (feat: skyler updates) +||||||| parent of 02175d04 (feat: bump fedimint version for multifederation support) + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", +======= + "rev": "f316e987aaf1a81b1626f7e418318ca683e0a47a", +>>>>>>> 02175d04 (feat: bump fedimint version for multifederation support) "type": "github" }, "original": { @@ -153,6 +167,7 @@ <<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) "rev": "f58f1913e62b6529a2ff36ec5c89a3852aba7ca7", ======= @@ -168,6 +183,10 @@ ======= "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", >>>>>>> 7f9cb0f7 (feat: skyler updates) +||||||| parent of 02175d04 (feat: bump fedimint version for multifederation support) + "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", +======= +>>>>>>> 02175d04 (feat: bump fedimint version for multifederation support) "type": "github" } }, diff --git a/src/client/src/api/types.ts b/src/client/src/api/types.ts index 575d4670..1a3c18f7 100644 --- a/src/client/src/api/types.ts +++ b/src/client/src/api/types.ts @@ -91,6 +91,7 @@ export const dummyFederation = { ||||||| parent of 17bf936c (feat: refactor to gateway context pattern) ======= +// For testing export const dummyFederation = { federation_id: 'test_federation_id', balance_msat: 1000, diff --git a/src/client/src/views/home/account/AccountInfo.tsx b/src/client/src/views/home/account/AccountInfo.tsx index 9c285a14..b4557a2e 100644 --- a/src/client/src/views/home/account/AccountInfo.tsx +++ b/src/client/src/views/home/account/AccountInfo.tsx @@ -34,21 +34,6 @@ const S = { `, }; -// const Tile = styled.div` -// display: flex; -// flex-direction: column; -// justify-content: space-between; -// align-items: ${({ startTile }: { startTile?: boolean }) => -// startTile ? 'flex-start' : 'flex-end'}; - -// @media (${mediaWidths.mobile}) { -// width: 100%; -// flex-direction: row; -// align-items: flex-end; -// margin: 0 0 8px; -// } -// `; - const sectionColor = '#FFD300'; export const AccountInfo = () => { diff --git a/src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp b/src/client/src/views/home/account/gateway/.FedimintGatewayCard.tsx.swp deleted file mode 100644 index 8bcdd22863f83ad35d13ae1a2bd1eb2636104c2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2O^6&t6vr#Uuc$E+ji8`Z)A&B2R!(StV+DoPIGzxrdQW@abxDydeUyQmgzHgmEdzfA@BUL#$Vn_cklb2kV}!jrHXI%c@B2T>@xFCMA4<$ zb8$3#*bX9(1tSe#RSuoS$m_OwC=;hCWUE_u>Oy*v2xk-7Z8RJdg+7l}MG||C7YNv9 zU)KfSNSs#G<_`0`sEgtzlYE11Ij6WU+9H&v^ZNxB`?gFrNBTFnMuA&ffxYC(!*khI ze|+j7ePI6!x3(N+^hN=rfKk9GU=%P47zK<1MuA&Q0omC_Uc;Do7vo+luDeFA#jUv* z1&jhl0i%FXz$jo8FbWt2i~>dhqkvJsDDXd2fcb zkHP!k3fKlcuna2T=lclx47?5;@cUjuJ_MJ63yy+^!1a3x`5XKNz5`!^cfn;)11@+B z{BjQ=*TCmMf>mIHDewq503HN;z@K*$@+-IoJ^|Yx0WX0=;8F0~9zs3^F}Mg$fjO`X z{B##$0B->aPJ@HspF0Wp5qu4;Ud<#9l09U~W z;BD|GP&&T>%*QBT6fg?(73du$luoN(l)8>O!L)|sQL91*{8(047MFLh?iCez8(*vs z>Qqr0b9I#Jj0kzfT3WPbXmMU@DQrY`gQJc~5rxV5>ILogqVR`2k94Fw-@uO-g$>cP z+gvi;XUN)|sHTIDg;QHa1l9~0ln)0!R5214Bsmugk5krG$H8jp4dSY^fQ25v*iM-2 zQD;~wO0DCWi~kmg3#n-$w*p>EQ`%;6Q-t%>s&+Q1;z)kAXs%SUuo=EfwLqkbEKXIjz-d)EaZ? zYGWH2!iYpFMs$ykn-CuUj?sk6rG5t$Zc7BurM=FAE+1PglxF36OyiMv0_O2n6kuuA zrp~cMa+>!5nSDMr5}~^kcDlpLyOZY8b;fom7Vz119yfw$W0h~pW2sflC6y6nRNEju z*BP=LietihoPA0yL^}7hx(u&IC1vUyqN`^Y&(6~`ydmlFKr}-tTb!y;=pjef#vQDt zNt?_Lc-WM!Y?iC^S#7bqE4;(DKeSS03x6Cq0(5U|&{fqla}!6Y&aG z#N3ggjlIJ}xGJyaL&?4lrP!FuZX6QG!oIyx=Qu7v_~6p)TWkg zJN+Nl5ssS8#DeRxQPDdlXkwcpCYb0Ap=VK13bmsH$Skpuox*k@zttV(&(56!_98?X zW{0#p>H+Iyrg~c~X;0|A@1dSOwi3r1Jj3+oneH{qrZ@8^RLa#`WqYyTD(1|SvssyF zZ0UA`*P*^~e~R!$8+4P09OHIcJm~OvXxdb|DJ9FhYH;jV9;2tS{3c#k)SH73drHfU qrrv)B&yDP^pEK2+p8M7P(EDLoFw Date: Tue, 5 Dec 2023 11:51:27 -0800 Subject: [PATCH 36/50] bump fedimint versioning --- flake.lock | 86 +++--------------------------------------------------- flake.nix | 5 +++- 2 files changed, 8 insertions(+), 83 deletions(-) diff --git a/flake.lock b/flake.lock index af44e9ea..9436ce51 100644 --- a/flake.lock +++ b/flake.lock @@ -98,95 +98,17 @@ "nixpkgs-unstable": "nixpkgs-unstable_2" }, "locked": { -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD - "lastModified": 1701469066, - "narHash": "sha256-3pt8qUfaUvQRl1gWY2Qkk4MRBbzpYtId/rdTitLffBQ=", -||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) - "lastModified": 1699573846, - "narHash": "sha256-4xKNhUE7e3GjjMbNib35B7eJWjuDIbYtwoHBOWYtqFA=", -======= - "lastModified": 1701034148, - "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", ->>>>>>> 8bdccdae (feat: fedimint 0.2 api updates) -||||||| parent of d29320cb (fix: hold) - "lastModified": 1701034148, - "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", -======= - "lastModified": 1701251322, - "narHash": "sha256-og7C8Q19KsHf4HCsgiI1CbNEWk4kUcArtiitWteTXpw=", ->>>>>>> d29320cb (fix: hold) -||||||| parent of 7f9cb0f7 (feat: skyler updates) - "lastModified": 1701251322, - "narHash": "sha256-og7C8Q19KsHf4HCsgiI1CbNEWk4kUcArtiitWteTXpw=", -======= - "lastModified": 1701034148, - "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", ->>>>>>> 7f9cb0f7 (feat: skyler updates) -||||||| parent of 02175d04 (feat: bump fedimint version for multifederation support) - "lastModified": 1701034148, - "narHash": "sha256-e2+nccJSCqprcE5Tr9/6UU7ctYcozk1xglGTa9jbEBs=", -======= - "lastModified": 1701469066, - "narHash": "sha256-3pt8qUfaUvQRl1gWY2Qkk4MRBbzpYtId/rdTitLffBQ=", ->>>>>>> 02175d04 (feat: bump fedimint version for multifederation support) + "lastModified": 1701787679, + "narHash": "sha256-s8yXBMiaT75022xyyvHNp3U2c9rwYLBzZEm0wIJx8r0=", "owner": "fedimint", "repo": "fedimint", -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD - "rev": "f316e987aaf1a81b1626f7e418318ca683e0a47a", -||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) - "rev": "f58f1913e62b6529a2ff36ec5c89a3852aba7ca7", -======= - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", ->>>>>>> 8bdccdae (feat: fedimint 0.2 api updates) -||||||| parent of d29320cb (fix: hold) - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", -======= - "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", ->>>>>>> d29320cb (fix: hold) -||||||| parent of 7f9cb0f7 (feat: skyler updates) - "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", -======= - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", ->>>>>>> 7f9cb0f7 (feat: skyler updates) -||||||| parent of 02175d04 (feat: bump fedimint version for multifederation support) - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", -======= - "rev": "f316e987aaf1a81b1626f7e418318ca683e0a47a", ->>>>>>> 02175d04 (feat: bump fedimint version for multifederation support) + "rev": "24113a64b270bf2ecb49b8f4554ba975025711db", "type": "github" }, "original": { "owner": "fedimint", "repo": "fedimint", -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -||||||| parent of 8bdccdae (feat: fedimint 0.2 api updates) - "rev": "f58f1913e62b6529a2ff36ec5c89a3852aba7ca7", -======= - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", ->>>>>>> 8bdccdae (feat: fedimint 0.2 api updates) -||||||| parent of d29320cb (fix: hold) - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", -======= - "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", ->>>>>>> d29320cb (fix: hold) -||||||| parent of 7f9cb0f7 (feat: skyler updates) - "rev": "bbe587845935517df8a36b9b2a6b98fa4bc1e19e", -======= - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", ->>>>>>> 7f9cb0f7 (feat: skyler updates) -||||||| parent of 02175d04 (feat: bump fedimint version for multifederation support) - "rev": "f47e6638c98c75a8c146144a69d236b4763848bf", -======= ->>>>>>> 02175d04 (feat: bump fedimint version for multifederation support) + "rev": "24113a64b270bf2ecb49b8f4554ba975025711db", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 25dc8dfd..8ce4c041 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,10 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; flake-utils.url = "github:numtide/flake-utils"; - fedimint = { url = "github:fedimint/fedimint?branch=releases/0.2"; }; + fedimint = { + url = + "github:fedimint/fedimint?rev=24113a64b270bf2ecb49b8f4554ba975025711db"; + }; }; outputs = { self, nixpkgs, flake-utils, fedimint }: flake-utils.lib.eachDefaultSystem (system: From abc888aebf7bc9562941441bb1de772da09c539b Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 8 Dec 2023 10:39:40 -0800 Subject: [PATCH 37/50] feat: docker hub publishing updates --- .github/workflows/fedimint-docker.yml | 59 +++++++++++++++++++ Dockerfile | 8 +++ src/client/pages/fedimints.tsx | 1 - src/client/src/components/chart/BarChart.tsx | 2 +- .../components/chart/HorizontalBarChart.tsx | 2 +- .../src/components/table/DebouncedInput.tsx | 2 +- .../src/views/home/account/AccountInfo.tsx | 2 +- src/client/src/views/home/account/network.tsx | 1 - 8 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/fedimint-docker.yml diff --git a/.github/workflows/fedimint-docker.yml b/.github/workflows/fedimint-docker.yml new file mode 100644 index 00000000..70b8e9de --- /dev/null +++ b/.github/workflows/fedimint-docker.yml @@ -0,0 +1,59 @@ +name: fedimint-thunderhub + +on: + push: + branches: + - master + tags: ['v*'] + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + images: | + fedimintui/fedimint-thunderhub + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha + + - name: Login to Docker Hub + if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') + uses: docker/login-action@v2 + with: + username: fedimintui + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Build and push gateway-ui + uses: docker/build-push-action@v4 + with: + file: Dockerfile + push: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Checkout repository content + if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') + uses: actions/checkout@v4 + + # This workflow requires the repository content to be locally available to read the README + - name: Update the Docker Hub description + if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') + uses: peter-evans/dockerhub-description@v3 + with: + username: fedimintui + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + repository: fedimintui/fedimint-thunderhub + readme-filepath: ./README.md diff --git a/Dockerfile b/Dockerfile index ed5be7a9..bfe52f36 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,6 +29,10 @@ ENV BASE_PATH=${BASE_PATH} ARG NODE_ENV="production" ENV NODE_ENV=${NODE_ENV} ENV NEXT_TELEMETRY_DISABLED=1 +ARG FM_GATEWAY_API="" +ENV FM_GATEWAY_API=${FM_GATEWAY_API} +ARG FM_GATEWAY_PASSWORD="" +ENV FM_GATEWAY_PASSWORD=${FM_GATEWAY_PASSWORD} # Build the NestJS and NextJS application COPY . . @@ -51,6 +55,10 @@ ENV BASE_PATH=${BASE_PATH} ARG NODE_ENV="production" ENV NODE_ENV=${NODE_ENV} ENV NEXT_TELEMETRY_DISABLED=1 +ARG FM_GATEWAY_API="" +ENV FM_GATEWAY_API=${FM_GATEWAY_API} +ARG FM_GATEWAY_PASSWORD="" +ENV FM_GATEWAY_PASSWORD=${FM_GATEWAY_PASSWORD} COPY --from=build /app/package.json ./ COPY --from=build /app/node_modules/ ./node_modules diff --git a/src/client/pages/fedimints.tsx b/src/client/pages/fedimints.tsx index 7a5ecc89..37dddf27 100644 --- a/src/client/pages/fedimints.tsx +++ b/src/client/pages/fedimints.tsx @@ -71,7 +71,6 @@ const FedimintsView = () => { display: 'flex', whiteSpace: 'nowrap', cursor: 'pointer', - justifyContent: 'center', }} onClick={() => { if (props.row.original.balance_msat > 0) { diff --git a/src/client/src/components/chart/BarChart.tsx b/src/client/src/components/chart/BarChart.tsx index 096c7db6..4e90ba03 100644 --- a/src/client/src/components/chart/BarChart.tsx +++ b/src/client/src/components/chart/BarChart.tsx @@ -58,7 +58,7 @@ export const BarChart = ({ const dates = data.map((d: any) => d.date); return { dates, series }; - }, [data, title]); + }, [data, title, dataKey]); const option = useMemo(() => { const fontColor = themeContext?.mode === 'light' ? 'black' : 'white'; diff --git a/src/client/src/components/chart/HorizontalBarChart.tsx b/src/client/src/components/chart/HorizontalBarChart.tsx index 12cb5ba0..0231284f 100644 --- a/src/client/src/components/chart/HorizontalBarChart.tsx +++ b/src/client/src/components/chart/HorizontalBarChart.tsx @@ -136,7 +136,7 @@ export const HorizontalBarChart = ({ legend: { show: true }, series: seriesData, }; - }, [colorRange, themeContext, seriesData, yLabels]); + }, [colorRange, themeContext, seriesData, yLabels, maxValue]); if (!keys.length) return null; diff --git a/src/client/src/components/table/DebouncedInput.tsx b/src/client/src/components/table/DebouncedInput.tsx index d3c268e8..18b0e064 100644 --- a/src/client/src/components/table/DebouncedInput.tsx +++ b/src/client/src/components/table/DebouncedInput.tsx @@ -27,7 +27,7 @@ export function DebouncedInput({ }, debounce); return () => clearTimeout(timeout); - }, [value]); + }, [value, debounce, onChange]); return ( { <> - Network: {getNetworkIndicator(gatewayInfo?.network || 'bitcoin')} + Network: {getNetworkIndicator(gatewayInfo?.network || 'unknown')} {/* diff --git a/src/client/src/views/home/account/network.tsx b/src/client/src/views/home/account/network.tsx index ef402490..49fba345 100644 --- a/src/client/src/views/home/account/network.tsx +++ b/src/client/src/views/home/account/network.tsx @@ -3,7 +3,6 @@ import React from 'react'; export const getNetworkIndicator = (network: string) => { let color: string; let name: string; - switch (network) { case 'bitcoin': color = 'orange'; From 90af3210259a354e51ee466ca2dd313630e2fd28 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 14 Dec 2023 10:57:44 -0500 Subject: [PATCH 38/50] fix: docker workflow releases only --- .github/workflows/fedimint-docker.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/fedimint-docker.yml b/.github/workflows/fedimint-docker.yml index 70b8e9de..6bbfe998 100644 --- a/.github/workflows/fedimint-docker.yml +++ b/.github/workflows/fedimint-docker.yml @@ -2,8 +2,6 @@ name: fedimint-thunderhub on: push: - branches: - - master tags: ['v*'] jobs: @@ -36,7 +34,7 @@ jobs: username: fedimintui password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - - name: Build and push gateway-ui + - name: Build and push uses: docker/build-push-action@v4 with: file: Dockerfile From 607e9ecc5966864c07edcb8af8748a672de04275 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 14 Dec 2023 11:17:39 -0500 Subject: [PATCH 39/50] fix: merge marker --- src/client/src/api/types.ts | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/src/client/src/api/types.ts b/src/client/src/api/types.ts index 1a3c18f7..16d4867d 100644 --- a/src/client/src/api/types.ts +++ b/src/client/src/api/types.ts @@ -60,7 +60,6 @@ export enum Network { } export type TransactionId = string; -<<<<<<< HEAD // For testing export const dummyFederation = { @@ -88,33 +87,3 @@ export const dummyFederation = { }, }, }; -||||||| parent of 17bf936c (feat: refactor to gateway context pattern) -======= - -// For testing -export const dummyFederation = { - federation_id: 'test_federation_id', - balance_msat: 1000, - config: { - consensus_version: 1, - epoch_pk: 'test_epoch_pk', - federation_id: 'test_federation_id', - api_endpoints: { - 0: { - name: 'test_api_endpoint_name', - url: 'test_api_endpoint_url', - }, - }, - modules: { - 0: { - config: 'test_module_config', - kind: ModuleKind.Ln, - version: 1, - }, - }, - meta: { - federation_name: 'test_federation_name', - }, - }, -}; ->>>>>>> 17bf936c (feat: refactor to gateway context pattern) From 13e0f42f6c2b640029077c3a12d53baab3062b21 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 14 Dec 2023 14:16:49 -0500 Subject: [PATCH 40/50] fix: network indicator --- .../src/views/home/account/AccountInfo.tsx | 4 +- .../views/home/account/NetworkIndicator.tsx | 47 +++++++++++++++++++ src/client/src/views/home/account/network.tsx | 29 ------------ 3 files changed, 49 insertions(+), 31 deletions(-) create mode 100644 src/client/src/views/home/account/NetworkIndicator.tsx delete mode 100644 src/client/src/views/home/account/network.tsx diff --git a/src/client/src/views/home/account/AccountInfo.tsx b/src/client/src/views/home/account/AccountInfo.tsx index 4055b15b..82738148 100644 --- a/src/client/src/views/home/account/AccountInfo.tsx +++ b/src/client/src/views/home/account/AccountInfo.tsx @@ -19,7 +19,7 @@ import { FedimintGatewayCard } from './gateway/FedimintGatewayCard'; // import { useGatewayEcashTotal } from '../../../hooks/UseGatewayEcashTotal'; import { useGatewayState } from '../../../context/GatewayContext'; import { GatewayInfo } from '../../../api/types'; -import { getNetworkIndicator } from './network'; +import { NetworkIndicator } from './NetworkIndicator'; const S = { grid: styled.div<{ gatewayInfo?: GatewayInfo | null }>` @@ -56,7 +56,7 @@ export const AccountInfo = () => { <> - Network: {getNetworkIndicator(gatewayInfo?.network || 'unknown')} + {/* diff --git a/src/client/src/views/home/account/NetworkIndicator.tsx b/src/client/src/views/home/account/NetworkIndicator.tsx new file mode 100644 index 00000000..a3f5369b --- /dev/null +++ b/src/client/src/views/home/account/NetworkIndicator.tsx @@ -0,0 +1,47 @@ +import React, { FC } from 'react'; + +interface NetworkIndicatorProps { + network: string; + // bitcoinRpcUrl: string; +} + +const getNetworkDetails = ( + network: string + // isMutinynet: boolean +) => { + const networkDetails: { [key: string]: { color: string; name: string } } = { + bitcoin: { color: '#FF9900', name: 'Mainnet' }, + main: { color: '#FF9900', name: 'Mainnet' }, + testnet: { color: '#6BED33', name: 'Testnet' }, + test: { color: '#6BED33', name: 'Testnet' }, + signet: { color: 'purple', name: 'Signet' }, + // isMutinynet + // ? { color: 'red', name: 'Mutinynet' } + // : { color: 'purple', name: 'Signet' }, + regtest: { color: '#33C6EC', name: 'Regtest' }, + default: { color: 'gray', name: 'Unknown' }, + }; + + return networkDetails[network] || networkDetails['default']; +}; + +// const isMutinynet = (bitcoinRpcUrl: string) => { +// try { +// const url = new URL(bitcoinRpcUrl); +// return url.host === 'mutinynet.com'; +// } catch (e) { +// return false; +// } +// }; + +export const NetworkIndicator: FC = ({ + network, + // bitcoinRpcUrl, +}) => { + const { color, name } = getNetworkDetails( + network + // isMutinynet(bitcoinRpcUrl) + ); + + return {name}; +}; diff --git a/src/client/src/views/home/account/network.tsx b/src/client/src/views/home/account/network.tsx deleted file mode 100644 index 49fba345..00000000 --- a/src/client/src/views/home/account/network.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; - -export const getNetworkIndicator = (network: string) => { - let color: string; - let name: string; - switch (network) { - case 'bitcoin': - color = 'orange'; - name = 'Mainnet'; - break; - case 'testnet': - color = 'limegreen'; - name = 'Testnet'; - break; - case 'signet': - color = 'purple'; - name = 'Signet'; - break; - case 'regtest': - color = 'skyblue'; - name = 'Regtest'; - break; - default: - color = 'gray'; - name = 'Unknown'; - } - - return {name}; -}; From 46e5f01fc2339ad51dd197b715919f85a44c1f98 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 14 Dec 2023 14:23:26 -0500 Subject: [PATCH 41/50] fix: show total fedimint ecash as sats --- src/client/src/hooks/UseGatewayEcashTotal.tsx | 3 ++- src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx | 4 ++-- .../src/views/home/account/gateway/FedimintGatewayCard.tsx | 7 +++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/client/src/hooks/UseGatewayEcashTotal.tsx b/src/client/src/hooks/UseGatewayEcashTotal.tsx index ce010cf6..0c9b0cd3 100644 --- a/src/client/src/hooks/UseGatewayEcashTotal.tsx +++ b/src/client/src/hooks/UseGatewayEcashTotal.tsx @@ -1,7 +1,7 @@ import Big from 'big.js'; import { useGatewayState } from '../context/GatewayContext'; -export const useGatewayEcashTotal = () => { +export const useGatewayEcashTotalSats = () => { const { gatewayInfo } = useGatewayState(); if (!gatewayInfo || !gatewayInfo.federations) { @@ -10,5 +10,6 @@ export const useGatewayEcashTotal = () => { return gatewayInfo.federations .reduce((acc, federation) => acc.add(federation.balance_msat), new Big(0)) + .div(1000) // Convert from millisatoshis to satoshis .toString(); }; diff --git a/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx b/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx index a948d14b..39bf76b3 100644 --- a/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx +++ b/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx @@ -16,7 +16,7 @@ import { } from '../../../components/generic/Styled'; import { useConfigState } from '../../../context/ConfigContext'; import { usePriceState } from '../../../context/PriceContext'; -import { useGatewayEcashTotal } from '../../../hooks/UseGatewayEcashTotal'; +import { useGatewayEcashTotalSats } from '../../../hooks/UseGatewayEcashTotal'; const Closed = styled.div` display: flex; @@ -80,7 +80,7 @@ export const NodeInfo = ({ isOpen, isBurger }: NodeInfoProps) => { } = useNodeInfo(); const { onchain, lightning } = useNodeBalances(); - const totalFedimintEcash = useGatewayEcashTotal(); + const totalFedimintEcash = useGatewayEcashTotalSats(); const { currency, displayValues } = useConfigState(); const priceContext = usePriceState(); diff --git a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx index 4c1486da..556dcff9 100644 --- a/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx +++ b/src/client/src/views/home/account/gateway/FedimintGatewayCard.tsx @@ -16,6 +16,7 @@ import { Price } from '../../../../components/price/Price'; import { useGatewayDispatch } from '../../../../context/GatewayContext'; import { gatewayApi } from '../../../../api/GatewayApi'; import { GatewayInfo } from '../../../../api/types'; +import { useGatewayEcashTotalSats } from '../../../../hooks/UseGatewayEcashTotal'; interface FedimintGatewayCardProps { gatewayInfo: GatewayInfo; @@ -28,6 +29,7 @@ export const FedimintGatewayCard = ({ }: FedimintGatewayCardProps) => { const gatewayDispath = useGatewayDispatch(); const [inviteCode, setInviteCode] = useState(''); + const totalFedimintEcash = useGatewayEcashTotalSats(); const handleEnter = () => { gatewayApi.connectFederation(inviteCode).then(() => { @@ -72,10 +74,7 @@ export const FedimintGatewayCard = ({ ) : (
- {renderLine( - 'Total Amount', - - )} + {renderLine('Total Amount', )} {renderLine( 'Connected Federations', gatewayInfo.federations.length From db91b63c608ef691920d175381a8cdaf5b814aac Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 14 Dec 2023 15:03:49 -0500 Subject: [PATCH 42/50] fix: thunderhub ui with sats only --- scripts/mprocs-nix-gateway.sh | 40 ------------------- .../views/home/account/NetworkIndicator.tsx | 6 ++- 2 files changed, 5 insertions(+), 41 deletions(-) diff --git a/scripts/mprocs-nix-gateway.sh b/scripts/mprocs-nix-gateway.sh index 6389de2c..1bd376bc 100644 --- a/scripts/mprocs-nix-gateway.sh +++ b/scripts/mprocs-nix-gateway.sh @@ -1,4 +1,3 @@ -<<<<<<< HEAD # shellcheck shell=bash set -eo pipefail @@ -35,42 +34,3 @@ export FM_GATEWAY_API=$FM_GATEWAY_API_ADDR export FM_GATEWAY_PASSWORD=$FM_GATEWAY_PASSWORD npm run start:dev -||||||| parent of 3c08692a (devimint setup scripts) -======= -# shellcheck shell=bash - -set -eo pipefail - -eval "$(devimint env)" - -echo Waiting for devimint to start up fedimint and gateway - -STATUS="$(devimint wait)" -if [ "$STATUS" = "ERROR" ] -then - echo "fedimint didn't start correctly" - echo "See other panes for errors" - exit 1 -fi - -TEMP_FILE=$(mktemp) -FM_LND_RPC_STRIPPED=$(echo $FM_LND_RPC_ADDR | sed 's/http[s]\?:\/\///') - -cat << EOF > "$TEMP_FILE" -masterPassword: password -accounts: - - name: test-regtest - serverUrl: $FM_LND_RPC_STRIPPED - macaroonPath: $FM_LND_MACAROON - certificatePath: $FM_LND_TLS_CERT -EOF - -# ----------- -# Fedimint Config -# ----------- -export ACCOUNT_CONFIG_PATH=$TEMP_FILE -export FM_GATEWAY_API=$FM_GATEWAY_API_ADDR -export FM_GATEWAY_PASSWORD=$FM_GATEWAY_PASSWORD - -npm run start:dev ->>>>>>> 3c08692a (devimint setup scripts) diff --git a/src/client/src/views/home/account/NetworkIndicator.tsx b/src/client/src/views/home/account/NetworkIndicator.tsx index a3f5369b..a07c6fef 100644 --- a/src/client/src/views/home/account/NetworkIndicator.tsx +++ b/src/client/src/views/home/account/NetworkIndicator.tsx @@ -43,5 +43,9 @@ export const NetworkIndicator: FC = ({ // isMutinynet(bitcoinRpcUrl) ); - return {name}; + return ( +
+ Network: {name} +
+ ); }; From eb9c73b376c191ddadacbd135b4f5b742f3537d5 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Thu, 21 Dec 2023 10:24:46 -0800 Subject: [PATCH 43/50] feat: docker compose mutinynet setup --- docker-compose.yaml | 105 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 docker-compose.yaml diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000..0f3abd27 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,105 @@ +# Important: 127.0.0.1 should be replaced by the external ip address of the machine +version: "3" + +services: + gatewayd: + image: fedimint/gatewayd:v0.2.1-rc2 + command: gatewayd lnd + environment: + # Path to folder containing gateway config and data files + - FM_GATEWAY_DATA_DIR=/gateway_data + # Gateway webserver listen address + - FM_GATEWAY_LISTEN_ADDR=0.0.0.0:8175 + # Public URL from which the webserver API is reachable + - FM_GATEWAY_API_ADDR=http://127.0.0.1:8175 + # Gateway webserver authentication password + - FM_GATEWAY_PASSWORD=thereisnosecondbest + # Configured gateway routing fees Format: , + - FM_GATEWAY_FEES=0,0 + # LND RPC address + - FM_LND_RPC_ADDR=https://lnd:10009 + # LND TLS cert file path + - FM_LND_TLS_CERT=/lnd_data/tls.cert + # LND macaroon file path + - FM_LND_MACAROON=/lnd_data/data/chain/bitcoin/signet/admin.macaroon + volumes: + - gateway_datadir:/gateway_data + - lnd_datadir:/lnd_data:ro + ports: + - "8175:8175" + - "8080:8080" + depends_on: + - lnd + restart: always + platform: linux/amd64 + + lnd: + image: lightninglabs/lnd:v0.17.3-beta + entrypoint: bash + command: + - -c + - lnd --bitcoin.active --bitcoin.signet --bitcoin.dnsseed=0 --bitcoin.node=bitcoind --protocol.wumbo-channels --bitcoind.rpchost=bitcoind --bitcoind.rpcuser=bitcoin --bitcoind.rpcpass=bitcoin --bitcoind.zmqpubrawblock=tcp://bitcoind:48332 --bitcoind.zmqpubrawtx=tcp://bitcoind:48333 --listen=0.0.0.0:9735 --rpclisten=0.0.0.0:10009 --restlisten=0.0.0.0:8080 --tlsextradomain=lnd --noseedbackup + ports: + - "10009:10009" + - "0.0.0.0:9735:9735" + volumes: + - lnd_datadir:/root/.lnd + depends_on: + - bitcoind + restart: always + + bitcoind: + image: fedimint/mutinynet-bitcoind:master + command: --rpcuser=bitcoin --rpcpassword=bitcoin -zmqpubrawblock=tcp://[::]:48332 -zmqpubrawtx=tcp://[::]:48333 + ports: + - 0.0.0.0:38333:38333 + volumes: + - "bitcoin_datadir:/root/.bitcoin" + restart: always + platform: linux/amd64 + + thunderhub_config_writer: + image: alpine:latest + command: + - sh + - -c + - | + cat < /thconfig/accounts.yaml + masterPassword: "thereisnosecondbest" + accounts: + - name: "main lnd" + serverUrl: "lnd:10009" + lndDir: "/root/.lnd" + network: signet + EOF + tail -f /dev/null + volumes: + - thunderhub_datadir:/thconfig + depends_on: + - lnd + restart: always + + thunderhub: + build: + context: . + dockerfile: Dockerfile + environment: + - ACCOUNT_CONFIG_PATH=/thconfig/accounts.yaml + - HOST=0.0.0.0 + - PORT=3002 + - FM_GATEWAY_API=http://143.198.55.236:8175 + - FM_GATEWAY_PASSWORD=thereisnosecondbest + ports: + - "0.0.0.0:3002:3002" + volumes: + - lnd_datadir:/root/.lnd + - thunderhub_datadir:/thconfig + depends_on: + - thunderhub_config_writer + restart: always + +volumes: + bitcoin_datadir: + lnd_datadir: + gateway_datadir: + thunderhub_datadir: From 75110e5e39cca7d85eccfd8c4305511a82b784d4 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Sat, 6 Jan 2024 19:33:30 -0800 Subject: [PATCH 44/50] chore: bump flake nix channel and fedimint version --- flake.lock | 16 ++++++++-------- flake.nix | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 9436ce51..d68559cd 100644 --- a/flake.lock +++ b/flake.lock @@ -98,17 +98,17 @@ "nixpkgs-unstable": "nixpkgs-unstable_2" }, "locked": { - "lastModified": 1701787679, - "narHash": "sha256-s8yXBMiaT75022xyyvHNp3U2c9rwYLBzZEm0wIJx8r0=", + "lastModified": 1704316564, + "narHash": "sha256-cuAIJniPQKXfwfl2RBon5iHAaB88GUBjQ1g0IpJwipk=", "owner": "fedimint", "repo": "fedimint", - "rev": "24113a64b270bf2ecb49b8f4554ba975025711db", + "rev": "a8422b84102ab5fc768307215d5b20d807143f27", "type": "github" }, "original": { "owner": "fedimint", "repo": "fedimint", - "rev": "24113a64b270bf2ecb49b8f4554ba975025711db", + "rev": "a8422b84102ab5fc768307215d5b20d807143f27", "type": "github" } }, @@ -315,16 +315,16 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1700097215, - "narHash": "sha256-ODQ3gBTv1iHd7lG21H+ErVISB5wVeOhd/dEogOqHs/I=", + "lastModified": 1704420045, + "narHash": "sha256-C36QmoJd5tdQ5R9MC1jM7fBkZW9zBUqbUCsgwS6j4QU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9fb122519e9cd465d532f736a98c1e1eb541ef6f", + "rev": "c1be43e8e837b8dbee2b3665a007e761680f0c3d", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.05", + "ref": "nixos-23.11", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 8ce4c041..71e28641 100644 --- a/flake.nix +++ b/flake.nix @@ -1,10 +1,10 @@ { inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; flake-utils.url = "github:numtide/flake-utils"; fedimint = { url = - "github:fedimint/fedimint?rev=24113a64b270bf2ecb49b8f4554ba975025711db"; + "github:fedimint/fedimint?rev=a8422b84102ab5fc768307215d5b20d807143f27"; }; }; outputs = { self, nixpkgs, flake-utils, fedimint }: From 31046a7a92eb9a072644daa3e9d4e111e5976e95 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Mon, 8 Jan 2024 14:45:56 -0800 Subject: [PATCH 45/50] updates --- docker-compose.yaml | 2 +- src/client/src/views/dashboard/widgets/lightning/balances.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 0f3abd27..a1195547 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,7 +3,7 @@ version: "3" services: gatewayd: - image: fedimint/gatewayd:v0.2.1-rc2 + image: fedimint/gatewayd:v0.2.1 command: gatewayd lnd environment: # Path to folder containing gateway config and data files diff --git a/src/client/src/views/dashboard/widgets/lightning/balances.tsx b/src/client/src/views/dashboard/widgets/lightning/balances.tsx index e60a9089..a7b018cf 100644 --- a/src/client/src/views/dashboard/widgets/lightning/balances.tsx +++ b/src/client/src/views/dashboard/widgets/lightning/balances.tsx @@ -3,7 +3,7 @@ import { useNodeBalances } from '../../../../hooks/UseNodeBalances'; import { unSelectedNavButton } from '../../../../styles/Themes'; import styled from 'styled-components'; import Big from 'big.js'; -import { useGatewayEcashTotal } from '../../../../hooks/UseGatewayEcashTotal'; +import { useGatewayEcashTotalSats } from '../../../../hooks/UseGatewayEcashTotal'; const S = { wrapper: styled.div` @@ -85,7 +85,7 @@ export const ChainBalance = () => { }; export const FedimintBalance = () => { - const totalFedimintEcash = useGatewayEcashTotal(); + const totalFedimintEcash = useGatewayEcashTotalSats(); return ( From cade383cf9c14b9dbb5b9063191c20a7be442672 Mon Sep 17 00:00:00 2001 From: Conner Ow Date: Mon, 8 Jan 2024 17:56:32 -0600 Subject: [PATCH 46/50] Fix docker-compose IP --- docker-compose.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index a1195547..a74bb171 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,5 +1,5 @@ # Important: 127.0.0.1 should be replaced by the external ip address of the machine -version: "3" +version: '3' services: gatewayd: @@ -26,8 +26,8 @@ services: - gateway_datadir:/gateway_data - lnd_datadir:/lnd_data:ro ports: - - "8175:8175" - - "8080:8080" + - '8175:8175' + - '8080:8080' depends_on: - lnd restart: always @@ -40,8 +40,8 @@ services: - -c - lnd --bitcoin.active --bitcoin.signet --bitcoin.dnsseed=0 --bitcoin.node=bitcoind --protocol.wumbo-channels --bitcoind.rpchost=bitcoind --bitcoind.rpcuser=bitcoin --bitcoind.rpcpass=bitcoin --bitcoind.zmqpubrawblock=tcp://bitcoind:48332 --bitcoind.zmqpubrawtx=tcp://bitcoind:48333 --listen=0.0.0.0:9735 --rpclisten=0.0.0.0:10009 --restlisten=0.0.0.0:8080 --tlsextradomain=lnd --noseedbackup ports: - - "10009:10009" - - "0.0.0.0:9735:9735" + - '10009:10009' + - '0.0.0.0:9735:9735' volumes: - lnd_datadir:/root/.lnd depends_on: @@ -54,7 +54,7 @@ services: ports: - 0.0.0.0:38333:38333 volumes: - - "bitcoin_datadir:/root/.bitcoin" + - 'bitcoin_datadir:/root/.bitcoin' restart: always platform: linux/amd64 @@ -87,10 +87,10 @@ services: - ACCOUNT_CONFIG_PATH=/thconfig/accounts.yaml - HOST=0.0.0.0 - PORT=3002 - - FM_GATEWAY_API=http://143.198.55.236:8175 + - FM_GATEWAY_API=http://127.0.0.1:8175 - FM_GATEWAY_PASSWORD=thereisnosecondbest ports: - - "0.0.0.0:3002:3002" + - '0.0.0.0:3002:3002' volumes: - lnd_datadir:/root/.lnd - thunderhub_datadir:/thconfig From 93c559f12232de280541eb435df09ddf5725863d Mon Sep 17 00:00:00 2001 From: Conner Ow Date: Mon, 8 Jan 2024 18:08:16 -0600 Subject: [PATCH 47/50] remove unnecessary diffs --- docker-compose.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index a74bb171..f25f3c9f 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,5 +1,5 @@ # Important: 127.0.0.1 should be replaced by the external ip address of the machine -version: '3' +version: "3" services: gatewayd: @@ -26,8 +26,8 @@ services: - gateway_datadir:/gateway_data - lnd_datadir:/lnd_data:ro ports: - - '8175:8175' - - '8080:8080' + - "8175:8175" + - "8080:8080" depends_on: - lnd restart: always @@ -40,8 +40,8 @@ services: - -c - lnd --bitcoin.active --bitcoin.signet --bitcoin.dnsseed=0 --bitcoin.node=bitcoind --protocol.wumbo-channels --bitcoind.rpchost=bitcoind --bitcoind.rpcuser=bitcoin --bitcoind.rpcpass=bitcoin --bitcoind.zmqpubrawblock=tcp://bitcoind:48332 --bitcoind.zmqpubrawtx=tcp://bitcoind:48333 --listen=0.0.0.0:9735 --rpclisten=0.0.0.0:10009 --restlisten=0.0.0.0:8080 --tlsextradomain=lnd --noseedbackup ports: - - '10009:10009' - - '0.0.0.0:9735:9735' + - "10009:10009" + - "0.0.0.0:9735:9735" volumes: - lnd_datadir:/root/.lnd depends_on: @@ -54,7 +54,7 @@ services: ports: - 0.0.0.0:38333:38333 volumes: - - 'bitcoin_datadir:/root/.bitcoin' + - "bitcoin_datadir:/root/.bitcoin" restart: always platform: linux/amd64 @@ -90,7 +90,7 @@ services: - FM_GATEWAY_API=http://127.0.0.1:8175 - FM_GATEWAY_PASSWORD=thereisnosecondbest ports: - - '0.0.0.0:3002:3002' + - "0.0.0.0:3002:3002" volumes: - lnd_datadir:/root/.lnd - thunderhub_datadir:/thconfig From 8bb29cca5b685de605a8a8abd05e85753ca0521a Mon Sep 17 00:00:00 2001 From: Conner Ow Date: Tue, 9 Jan 2024 14:38:48 -0600 Subject: [PATCH 48/50] Mutinynet Quick Actions --- src/client/pages/index.tsx | 32 ++-- src/client/src/api/FaucetApi.ts | 91 ++++++++++ src/client/src/components/logo/GhostIcon.tsx | 21 +++ .../home/faucetActions/FaucetActions.tsx | 132 ++++++++++++++ .../src/views/home/faucetActions/onchain.tsx | 55 ++++++ .../views/home/faucetActions/pay-invoice.tsx | 46 +++++ .../home/faucetActions/refund-faucet.tsx | 56 ++++++ .../home/faucetActions/request-channel.tsx | 133 ++++++++++++++ .../home/quickActions/MainnetQuickActions.tsx | 146 ---------------- .../quickActions/MutinynetQuickActions.tsx | 144 ---------------- .../views/home/quickActions/QuickActions.tsx | 163 +++++++++++++++--- .../home/quickActions/RegtestQuickActions.tsx | 126 -------------- .../quickActions/ghost/GhostQuickAction.tsx | 57 ++++++ .../home/quickActions/lnmarkets/index.tsx | 2 +- .../home/quickActions/openChannel/index.tsx | 7 +- 15 files changed, 759 insertions(+), 452 deletions(-) create mode 100644 src/client/src/api/FaucetApi.ts create mode 100644 src/client/src/components/logo/GhostIcon.tsx create mode 100644 src/client/src/views/home/faucetActions/FaucetActions.tsx create mode 100644 src/client/src/views/home/faucetActions/onchain.tsx create mode 100644 src/client/src/views/home/faucetActions/pay-invoice.tsx create mode 100644 src/client/src/views/home/faucetActions/refund-faucet.tsx create mode 100644 src/client/src/views/home/faucetActions/request-channel.tsx delete mode 100644 src/client/src/views/home/quickActions/MainnetQuickActions.tsx delete mode 100644 src/client/src/views/home/quickActions/MutinynetQuickActions.tsx delete mode 100644 src/client/src/views/home/quickActions/RegtestQuickActions.tsx create mode 100644 src/client/src/views/home/quickActions/ghost/GhostQuickAction.tsx diff --git a/src/client/pages/index.tsx b/src/client/pages/index.tsx index 7e9bdb5b..a2e88998 100644 --- a/src/client/pages/index.tsx +++ b/src/client/pages/index.tsx @@ -10,19 +10,27 @@ import { AccountInfo } from '../src/views/home/account/AccountInfo'; import { ForwardBox } from '../src/views/home/reports/forwardReport'; import { ConnectCard } from '../src/views/home/connect/Connect'; import { QuickActions } from '../src/views/home/quickActions/QuickActions'; +import { useGatewayState } from '../src/context/GatewayContext'; +import { Network } from '../src/api/types'; +import { FaucetActions } from '../src/views/home/faucetActions/FaucetActions'; -const HomeView = () => ( - <> - - - - - - - - - -); +const HomeView = () => { + const { gatewayInfo } = useGatewayState(); + + return ( + <> + + + + + + {gatewayInfo?.network === Network.Signet ? : null} + + + + + ); +}; const Wrapped = () => ( diff --git a/src/client/src/api/FaucetApi.ts b/src/client/src/api/FaucetApi.ts new file mode 100644 index 00000000..6ac94be6 --- /dev/null +++ b/src/client/src/api/FaucetApi.ts @@ -0,0 +1,91 @@ +// GatewayApi is an implementation of the ApiInterface +class FaucetApi { + private baseUrl: string | undefined = 'https://faucet.mutinynet.com/api'; + + private post = async (api: string, body: unknown): Promise => { + return fetch(`${this.baseUrl}/${api}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }); + }; + + onchain = async (body: { address: string; sats: number }) => { + try { + if (body.sats < 10000 || body.sats > 200000) + throw new Error('Amount must be between 10000 and 200000'); + + const res = await this.post('onchain', body); + + if (res.ok) { + const result = await res.json(); + return Promise.resolve(result); + } + + throw responseToError(res); + } catch (error) { + return Promise.reject({ + message: (error as Error).message, + error, + }); + } + }; + + payInvoice = async (body: { bolt11: string }) => { + try { + const res = await this.post('lightning', body); + + if (res.ok) { + const result = await res.json(); + return Promise.resolve(result); + } + + throw responseToError(res); + } catch (error) { + return Promise.reject({ message: (error as Error).message, error }); + } + }; + + refundFaucet = async (body: { amount_sats: number }) => { + try { + const res = await this.post('bolt11', body); + + if (res.ok) { + const result = await res.text(); + return Promise.resolve(result); + } + + throw responseToError(res); + } catch (error) { + return Promise.reject({ message: (error as Error).message, error }); + } + }; + + requestChannel = async (body: { + capacity: number; + push_amount: number; + pubkey: string; + host: string; + }) => { + try { + const res = await this.post('channel', body); + + if (res.ok) { + const result = await res.json(); + return Promise.resolve(result); + } + + throw responseToError(res); + } catch (error) { + return Promise.reject({ message: (error as Error).message, error }); + } + }; +} + +const responseToError = (res: Response): Error => { + return new Error(`Status : ${res.status} \nReason : ${res.statusText}\n`); +}; + +export const faucetApi = new FaucetApi(); diff --git a/src/client/src/components/logo/GhostIcon.tsx b/src/client/src/components/logo/GhostIcon.tsx new file mode 100644 index 00000000..20abaa4a --- /dev/null +++ b/src/client/src/components/logo/GhostIcon.tsx @@ -0,0 +1,21 @@ +import { forwardRef } from 'react'; + +export const GhostLogo = forwardRef( + ({ color = 'currentColor', size = 100, children, ...rest }, ref) => { + return ( + + {children} + + + ); + } +); + +GhostLogo.displayName = 'GhostLogo'; diff --git a/src/client/src/views/home/faucetActions/FaucetActions.tsx b/src/client/src/views/home/faucetActions/FaucetActions.tsx new file mode 100644 index 00000000..27401d24 --- /dev/null +++ b/src/client/src/views/home/faucetActions/FaucetActions.tsx @@ -0,0 +1,132 @@ +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { + X, + Link, + CloudLightning, + FastForward, + GitPullRequest, +} from 'react-feather'; +import { + CardWithTitle, + SubTitle, + CardTitle, + SmallButton, +} from '../../../components/generic/Styled'; +import { + unSelectedNavButton, + cardColor, + cardBorderColor, + mediaWidths, +} from '../../../styles/Themes'; +import { Onchain } from './onchain'; +import { RequestChannel } from './request-channel'; +import { RefundFaucet } from './refund-faucet'; +import { PayInvoice } from './pay-invoice'; + +export const QuickCard = styled.div` + background: ${cardColor}; + box-shadow: 0 8px 16px -8px rgba(0, 0, 0, 0.1); + border-radius: 4px; + border: 1px solid ${cardBorderColor}; + height: 100px; + width: 100px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 10px; + cursor: pointer; + color: #69c0ff; + + @media (${mediaWidths.mobile}) { + padding: 4px; + height: 80px; + width: 80px; + } + + &:hover { + border: 1px solid #69c0ff; + } +`; + +export const QuickTitle = styled.div` + font-size: 12px; + color: ${unSelectedNavButton}; + margin-top: 10px; + text-align: center; +`; + +const QuickRow = styled.div` + display: flex; + flex-wrap: wrap; + gap: 8px; + margin: 16px 0 32px; +`; + +export const FaucetActions = () => { + const [openCard, setOpenCard] = useState('none'); + + const getTitle = () => { + switch (openCard) { + case 'refund_faucet': + return 'Send your unused sats back to the Faucet'; + case 'pay_invoice': + return 'Pay an invoice with the Faucet'; + case 'request_channel': + return 'Request a channel from the Faucet'; + case 'onchain': + return 'Receive onchain sats from the Faucet'; + default: + return 'Mutinynet Faucet Actions'; + } + }; + + const renderContent = () => { + switch (openCard) { + case 'refund_faucet': + return ; + case 'request_channel': + return ; + case 'onchain': + return ; + case 'pay_invoice': + return ; + default: + return ( + + setOpenCard('onchain')}> + + Onchain + + setOpenCard('pay_invoice')}> + + Pay Invoice + + setOpenCard('refund_faucet')}> + + Refund Faucet + + setOpenCard('request_channel')}> + + Request Channel + + + ); + } + }; + + return ( + + + {getTitle()} + {openCard !== 'none' && ( + setOpenCard('none')}> + + + )} + + {renderContent()} + + ); +}; diff --git a/src/client/src/views/home/faucetActions/onchain.tsx b/src/client/src/views/home/faucetActions/onchain.tsx new file mode 100644 index 00000000..7b3dad34 --- /dev/null +++ b/src/client/src/views/home/faucetActions/onchain.tsx @@ -0,0 +1,55 @@ +import { useState } from 'react'; +import { toast } from 'react-toastify'; +import { Card } from '../../../components/generic/Styled'; +import { InputWithDeco } from '../../../components/input/InputWithDeco'; +import { ColorButton } from '../../../components/buttons/colorButton/ColorButton'; +import { faucetApi } from '../../../api/FaucetApi'; + +export const Onchain = () => { + const [loading, setLoading] = useState(false); + const [amount, setAmount] = useState(50000); + const [address, setAddress] = useState(''); + + const handleOnchain = async () => { + setLoading(true); + + try { + await faucetApi.onchain({ sats: amount, address }); + toast.success('Successfully Paid to Onchain Address'); + } catch (err) { + toast.error((err as Error).message); + } + setLoading(false); + }; + + return ( + <> + + setAmount(Number(value))} + onEnter={() => handleOnchain()} + placeholder="Amount in sats" + title="Amount (sats)" + inputType="number" + /> + setAddress(value)} + onEnter={() => handleOnchain()} + /> + handleOnchain()} + > + Make it Rain + + + + ); +}; diff --git a/src/client/src/views/home/faucetActions/pay-invoice.tsx b/src/client/src/views/home/faucetActions/pay-invoice.tsx new file mode 100644 index 00000000..3bd0d258 --- /dev/null +++ b/src/client/src/views/home/faucetActions/pay-invoice.tsx @@ -0,0 +1,46 @@ +import { useState } from 'react'; +import { toast } from 'react-toastify'; +import { Card } from '../../../components/generic/Styled'; +import { InputWithDeco } from '../../../components/input/InputWithDeco'; +import { ColorButton } from '../../../components/buttons/colorButton/ColorButton'; +import { faucetApi } from '../../../api/FaucetApi'; + +export const PayInvoice = () => { + const [loading, setLoading] = useState(false); + const [bolt11, setBolt11] = useState(''); + + const handlePayInvoice = async () => { + setLoading(true); + + try { + await faucetApi.payInvoice({ bolt11 }); + toast.success('Successfully Paid to Onchain Address'); + } catch (err) { + toast.error((err as Error).message); + } + setLoading(false); + }; + + return ( + <> + + setBolt11(value)} + onEnter={() => handlePayInvoice()} + placeholder="lnbt..." + title="Bolt11 Invoice" + /> + handlePayInvoice()} + > + Strike me now + + + + ); +}; diff --git a/src/client/src/views/home/faucetActions/refund-faucet.tsx b/src/client/src/views/home/faucetActions/refund-faucet.tsx new file mode 100644 index 00000000..2f3ec968 --- /dev/null +++ b/src/client/src/views/home/faucetActions/refund-faucet.tsx @@ -0,0 +1,56 @@ +import { useState } from 'react'; +import { toast } from 'react-toastify'; +import { Card } from '../../../components/generic/Styled'; +import { InputWithDeco } from '../../../components/input/InputWithDeco'; +import { ColorButton } from '../../../components/buttons/colorButton/ColorButton'; +import { faucetApi } from '../../../api/FaucetApi'; +import { usePayMutation } from '../../../graphql/mutations/__generated__/pay.generated'; + +export const RefundFaucet = () => { + const [loading, setLoading] = useState(false); + const [amount_sats, setAmount] = useState(50000); + + const [pay] = usePayMutation(); + + const handleRefundFaucet = async () => { + setLoading(true); + + try { + const request = await faucetApi.refundFaucet({ amount_sats }); + await pay({ + variables: { + request, + max_fee: 1000, + max_paths: 10, + }, + }); + } catch (err) { + toast.error((err as Error).message); + } + setLoading(false); + }; + + return ( + <> + + setAmount(Number(value))} + onEnter={() => handleRefundFaucet()} + placeholder="Amount in sats" + title="Amount (sats)" + inputType="number" + /> + handleRefundFaucet()} + > + Make it Rain + + + + ); +}; diff --git a/src/client/src/views/home/faucetActions/request-channel.tsx b/src/client/src/views/home/faucetActions/request-channel.tsx new file mode 100644 index 00000000..6bf81b0d --- /dev/null +++ b/src/client/src/views/home/faucetActions/request-channel.tsx @@ -0,0 +1,133 @@ +import { useEffect, useState } from 'react'; +import { toast } from 'react-toastify'; +import { Card } from '../../../components/generic/Styled'; +import { InputWithDeco } from '../../../components/input/InputWithDeco'; +import { ColorButton } from '../../../components/buttons/colorButton/ColorButton'; +import { faucetApi } from '../../../api/FaucetApi'; +import { useGetNodeInfoQuery } from '../../../graphql/queries/__generated__/getNodeInfo.generated'; +import { Container, IconStyle, Item } from '../quickActions/openChannel'; +import { Hexagon } from 'react-feather'; + +const signetNodes = [ + { + name: '025698cc9ac623f5d1ba', + pubkey: + '025698cc9ac623f5d1baf56310f2f1b62dfffee43ffcdb2c20ccb541f70497d540', + host: '54.158.203.78', + connectionString: + '025698cc9ac623f5d1baf56310f2f1b62dfffee43ffcdb2c20ccb541f70497d540@54.158.203.78:9739', + }, + { + name: 'mutiny-net-lnd', + pubkey: + '02465ed5be53d04fde66c9418ff14a5f2267723810176c9212b722e542dc1afb1b', + host: '45.79.52.207', + connectionString: + '02465ed5be53d04fde66c9418ff14a5f2267723810176c9212b722e542dc1afb1b@45.79.52.207:9735', + }, + { + name: 'GREENFELONY', + pubkey: + '0366abc8eb4da61e31a8d2c4520d31cabdf58cc5250f855657397f3dd62493938a', + host: '45.33.17.66', + connectionString: + '0366abc8eb4da61e31a8d2c4520d31cabdf58cc5250f855657397f3dd62493938a@45.33.17.66:39735', + }, +]; + +export const RequestChannel = () => { + const [loading, setLoading] = useState(false); + + const [capacity, setCapacity] = useState(50000); + const [push_amount, setPushAmount] = useState(25000); + const [pubkey, setPubkey] = useState(''); + const [host, setHost] = useState(''); + const [port, setPort] = useState(9735); + + const { data } = useGetNodeInfoQuery(); + + const handleRequestChannel = async () => { + setLoading(true); + + try { + await faucetApi.requestChannel({ + capacity, + push_amount, + pubkey, + host: host + ':' + port, + }); + toast.success('Channel Opened'); + } catch (err) { + toast.error((err as Error).message); + } + setLoading(false); + }; + + useEffect(() => { + if ( + data?.getNodeInfo?.public_key && + typeof data.getNodeInfo.public_key === 'string' && + pubkey.length === 0 + ) { + setPubkey(data.getNodeInfo.public_key); + } + }, [data, pubkey]); + + return ( + <> + + + {signetNodes.map((item, index) => ( + { + const [pubkey, host, port] = item.connectionString.split(/@|:/); + setPubkey(pubkey); + setHost(host); + setPort(Number(port)); + }} + > + + + + {item.name} + + ))} + + setCapacity(Number(value))} + onEnter={() => handleRequestChannel()} + placeholder="50000" + title="Capacity (sats)" + inputType="number" + /> + setPushAmount(Number(value))} + onEnter={() => handleRequestChannel()} + placeholder="25000" + title="Push Amount (Sats)" + inputType="number" + /> + setHost(value)} + onEnter={() => handleRequestChannel()} + placeholder="127.0.0.1" + title="Host" + /> + + handleRequestChannel()} + > + Gimme a lightning channel + + + + ); +}; diff --git a/src/client/src/views/home/quickActions/MainnetQuickActions.tsx b/src/client/src/views/home/quickActions/MainnetQuickActions.tsx deleted file mode 100644 index c29577fe..00000000 --- a/src/client/src/views/home/quickActions/MainnetQuickActions.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import React, { useState } from 'react'; -import styled from 'styled-components'; -import { X, Layers, GitBranch, Command, Zap } from 'react-feather'; -import { - CardWithTitle, - SubTitle, - CardTitle, - SmallButton, - Card, -} from '../../../components/generic/Styled'; -import { - unSelectedNavButton, - cardColor, - cardBorderColor, - mediaWidths, -} from '../../../styles/Themes'; -import { DecodeCard } from './decode/Decode'; -import { SupportCard } from './donate/DonateCard'; -import { SupportBar } from './donate/DonateContent'; -import { OpenChannel } from './openChannel'; -import { LnUrlCard } from './lnurl'; -import { LnMarketsCard } from './lnmarkets'; -import { AmbossCard } from './amboss/AmbossCard'; -import { LightningAddressCard } from './lightningAddress/LightningAddress'; - -export const QuickCard = styled.div` - background: ${cardColor}; - box-shadow: 0 8px 16px -8px rgba(0, 0, 0, 0.1); - border-radius: 4px; - border: 1px solid ${cardBorderColor}; - height: 100px; - flex-grow: 1; - flex: 1 0 auto; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin-bottom: 25px; - padding: 10px; - margin-right: 10px; - cursor: pointer; - color: #69c0ff; - - @media (${mediaWidths.mobile}) { - padding: 4px; - height: 80px; - width: 80px; - } - - &:hover { - border: 1px solid #69c0ff; - } -`; - -export const QuickTitle = styled.div` - font-size: 12px; - color: ${unSelectedNavButton}; - margin-top: 10px; - text-align: center; -`; - -const QuickRow = styled.div` - display: flex; - flex-wrap: wrap; - justify-content: space-between; -`; - -export const MainnetQuickActions = () => { - const [openCard, setOpenCard] = useState('none'); - - const getTitle = () => { - switch (openCard) { - case 'decode': - return 'Decode a Lightning Request'; - case 'open_channel': - return 'Open a Channel'; - case 'ln_url': - return 'Use lnurl'; - case 'lightning_address': - return 'Pay to a Lightning Address'; - default: - return 'Mainnet Quick Actions'; - } - }; - - const renderContent = () => { - switch (openCard) { - case 'support': - return ( - - - - ); - case 'decode': - return ; - case 'ln_url': - return ; - case 'lightning_address': - return ; - case 'open_channel': - return ( - - - - ); - default: - return ( - - setOpenCard('support')} /> - - setOpenCard('lightning_address')}> - - Address - - setOpenCard('open_channel')}> - - Open - - setOpenCard('decode')}> - - Decode - - setOpenCard('ln_url')}> - - LNURL - - - - ); - } - }; - - return ( - - - {getTitle()} - {openCard !== 'none' && ( - setOpenCard('none')}> - - - )} - - {renderContent()} - - ); -}; diff --git a/src/client/src/views/home/quickActions/MutinynetQuickActions.tsx b/src/client/src/views/home/quickActions/MutinynetQuickActions.tsx deleted file mode 100644 index 5bbacbf4..00000000 --- a/src/client/src/views/home/quickActions/MutinynetQuickActions.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import React, { useState } from 'react'; -import styled from 'styled-components'; -import { X, Layers, GitBranch, Command, Zap } from 'react-feather'; -import { - CardWithTitle, - SubTitle, - CardTitle, - SmallButton, - Card, -} from '../../../components/generic/Styled'; -import { - unSelectedNavButton, - cardColor, - cardBorderColor, - mediaWidths, -} from '../../../styles/Themes'; -import { DecodeCard } from './decode/Decode'; -import { SupportCard } from './donate/DonateCard'; -import { SupportBar } from './donate/DonateContent'; -import { OpenChannel } from './openChannel'; -import { LnUrlCard } from './lnurl'; -import { LightningAddressCard } from './lightningAddress/LightningAddress'; - -export const QuickCard = styled.div` - background: ${cardColor}; - box-shadow: 0 8px 16px -8px rgba(0, 0, 0, 0.1); - border-radius: 4px; - border: 1px solid ${cardBorderColor}; - height: 100px; - flex-grow: 1; - flex: 1 0 auto; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin-bottom: 25px; - padding: 10px; - margin-right: 10px; - cursor: pointer; - color: #69c0ff; - - @media (${mediaWidths.mobile}) { - padding: 4px; - height: 80px; - width: 80px; - } - - &:hover { - border: 1px solid #69c0ff; - } -`; - -export const QuickTitle = styled.div` - font-size: 12px; - color: ${unSelectedNavButton}; - margin-top: 10px; - text-align: center; -`; - -const QuickRow = styled.div` - display: flex; - flex-wrap: wrap; - justify-content: space-between; -`; - -export const MutinynetQuickActions = () => { - const [openCard, setOpenCard] = useState('none'); - - const getTitle = () => { - switch (openCard) { - case 'decode': - return 'Decode a Lightning Request'; - case 'open_channel': - return 'Open Outbound Channel'; - case 'request_channel': - return 'Request Inbound Channel'; - case 'ln_url': - return 'Use lnurl'; - case 'lightning_address': - return 'Pay to a Lightning Address'; - default: - return 'Mutinynet Quick Actions'; - } - }; - - const renderContent = () => { - switch (openCard) { - case 'support': - return ( - - - - ); - case 'decode': - return ; - case 'ln_url': - return ; - case 'lightning_address': - return ; - case 'open_channel': - return ( - - - - ); - default: - return ( - - setOpenCard('support')} /> - setOpenCard('lightning_address')}> - - Address - - setOpenCard('open_channel')}> - - Open - - setOpenCard('decode')}> - - Decode - - setOpenCard('ln_url')}> - - LNURL - - - ); - } - }; - - return ( - - - {getTitle()} - {openCard !== 'none' && ( - setOpenCard('none')}> - - - )} - - {renderContent()} - - ); -}; diff --git a/src/client/src/views/home/quickActions/QuickActions.tsx b/src/client/src/views/home/quickActions/QuickActions.tsx index 4ddf0c3d..7138cd0b 100644 --- a/src/client/src/views/home/quickActions/QuickActions.tsx +++ b/src/client/src/views/home/quickActions/QuickActions.tsx @@ -1,23 +1,146 @@ -import React from 'react'; -import { useGatewayState } from '../../../context/GatewayContext'; -import { MutinynetQuickActions } from './MutinynetQuickActions'; -import { MainnetQuickActions } from './MainnetQuickActions'; -import { RegtestQuickActions } from './RegtestQuickActions'; -import { Network } from '../../../api/types'; +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { X, Layers, GitBranch, Command, Zap } from 'react-feather'; +import { + CardWithTitle, + SubTitle, + CardTitle, + SmallButton, + Card, +} from '../../../components/generic/Styled'; +import { + unSelectedNavButton, + cardColor, + cardBorderColor, + mediaWidths, +} from '../../../styles/Themes'; +import { DecodeCard } from './decode/Decode'; +import { SupportCard } from './donate/DonateCard'; +import { SupportBar } from './donate/DonateContent'; +import { OpenChannel } from './openChannel'; +import { LnUrlCard } from './lnurl'; +import { LnMarketsCard } from './lnmarkets'; +import { AmbossCard } from './amboss/AmbossCard'; +import { LightningAddressCard } from './lightningAddress/LightningAddress'; +import { GhostCard } from './ghost/GhostQuickAction'; -export const QuickActions = () => { - const { gatewayInfo } = useGatewayState(); - - switch (gatewayInfo?.network) { - case Network.Signet: - return ; - case Network.Bitcoin: - return ; - case Network.Regtest: - return ; - // case Network.Testnet: - // return ; - default: - return null; +export const QuickCard = styled.div` + background: ${cardColor}; + box-shadow: 0 8px 16px -8px rgba(0, 0, 0, 0.1); + border-radius: 4px; + border: 1px solid ${cardBorderColor}; + height: 100px; + width: 100px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 10px; + cursor: pointer; + color: #69c0ff; + + @media (${mediaWidths.mobile}) { + padding: 4px; + height: 80px; + width: 80px; + } + + &:hover { + border: 1px solid #69c0ff; } +`; + +export const QuickTitle = styled.div` + font-size: 12px; + color: ${unSelectedNavButton}; + margin-top: 10px; + text-align: center; +`; + +const QuickRow = styled.div` + display: flex; + flex-wrap: wrap; + gap: 8px; + margin: 16px 0 32px; +`; + +export const QuickActions = () => { + const [openCard, setOpenCard] = useState('none'); + + const getTitle = () => { + switch (openCard) { + case 'decode': + return 'Decode a Lightning Request'; + case 'open_channel': + return 'Open a Channel'; + case 'ln_url': + return 'Use lnurl'; + case 'lightning_address': + return 'Pay to a Lightning Address'; + default: + return 'Quick Actions'; + } + }; + + const renderContent = () => { + switch (openCard) { + case 'support': + return ( + + + + ); + case 'decode': + return ; + case 'ln_url': + return ; + case 'lightning_address': + return ; + case 'open_channel': + return ( + + + + ); + default: + return ( + + + setOpenCard('support')} /> + + setOpenCard('lightning_address')}> + + Address + + setOpenCard('open_channel')}> + + Open + + setOpenCard('decode')}> + + Decode + + setOpenCard('ln_url')}> + + LNURL + + + + ); + } + }; + + return ( + + + {getTitle()} + {openCard !== 'none' && ( + setOpenCard('none')}> + + + )} + + {renderContent()} + + ); }; diff --git a/src/client/src/views/home/quickActions/RegtestQuickActions.tsx b/src/client/src/views/home/quickActions/RegtestQuickActions.tsx deleted file mode 100644 index 2958e4b6..00000000 --- a/src/client/src/views/home/quickActions/RegtestQuickActions.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import React, { useState } from 'react'; -import styled from 'styled-components'; -import { X } from 'react-feather'; -import { - CardWithTitle, - SubTitle, - CardTitle, - SmallButton, - Card, -} from '../../../components/generic/Styled'; -import { - unSelectedNavButton, - cardColor, - cardBorderColor, - mediaWidths, -} from '../../../styles/Themes'; -import { DecodeCard } from './decode/Decode'; -import { SupportCard } from './donate/DonateCard'; -import { SupportBar } from './donate/DonateContent'; -import { OpenChannel } from './openChannel'; -import { LnUrlCard } from './lnurl'; -import { LightningAddressCard } from './lightningAddress/LightningAddress'; - -export const QuickCard = styled.div` - background: ${cardColor}; - box-shadow: 0 8px 16px -8px rgba(0, 0, 0, 0.1); - border-radius: 4px; - border: 1px solid ${cardBorderColor}; - height: 100px; - flex-grow: 1; - flex: 1 0 auto; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin-bottom: 25px; - padding: 10px; - margin-right: 10px; - cursor: pointer; - color: #69c0ff; - - @media (${mediaWidths.mobile}) { - padding: 4px; - height: 80px; - width: 80px; - } - - &:hover { - border: 1px solid #69c0ff; - } -`; - -export const QuickTitle = styled.div` - font-size: 12px; - color: ${unSelectedNavButton}; - margin-top: 10px; - text-align: center; -`; - -const QuickRow = styled.div` - display: flex; - flex-wrap: wrap; - justify-content: space-between; -`; - -export const RegtestQuickActions = () => { - const [openCard, setOpenCard] = useState('none'); - - const getTitle = () => { - switch (openCard) { - case 'decode': - return 'Decode a Lightning Request'; - case 'open_channel': - return 'Open Outbound Channel'; - case 'ln_url': - return 'Use lnurl'; - case 'lightning_address': - return 'Pay to a Lightning Address'; - default: - return 'Regtest Quick Actions'; - } - }; - - const renderContent = () => { - switch (openCard) { - case 'support': - return ( - - - - ); - case 'decode': - return ; - case 'ln_url': - return ; - case 'lightning_address': - return ; - case 'open_channel': - return ( - - - - ); - default: - return ( - - setOpenCard('support')} /> - - ); - } - }; - - return ( - - - {getTitle()} - {openCard !== 'none' && ( - setOpenCard('none')}> - - - )} - - {renderContent()} - - ); -}; diff --git a/src/client/src/views/home/quickActions/ghost/GhostQuickAction.tsx b/src/client/src/views/home/quickActions/ghost/GhostQuickAction.tsx new file mode 100644 index 00000000..dd8ac457 --- /dev/null +++ b/src/client/src/views/home/quickActions/ghost/GhostQuickAction.tsx @@ -0,0 +1,57 @@ +import styled from 'styled-components'; +import { + cardBorderColor, + cardColor, + mediaWidths, + unSelectedNavButton, +} from '../../../../styles/Themes'; +import { GhostLogo } from '../../../../components/logo/GhostIcon'; +import { useRouter } from 'next/router'; + +const QuickTitle = styled.div` + font-size: 12px; + color: ${unSelectedNavButton}; + margin-top: 10px; +`; + +const QuickCard = styled.div` + background: ${cardColor}; + box-shadow: 0 8px 16px -8px rgba(0, 0, 0, 0.1); + border-radius: 4px; + border: 1px solid ${cardBorderColor}; + height: 100px; + width: 100px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 10px; + cursor: pointer; + color: #69c0ff; + + @media (${mediaWidths.mobile}) { + padding: 4px; + height: 80px; + width: 80px; + } + + &:hover { + background-color: black; + color: white; + + & ${QuickTitle} { + color: white; + } + } +`; + +export const GhostCard = () => { + const { push } = useRouter(); + + return ( + push('/amboss')}> + + Ghost + + ); +}; diff --git a/src/client/src/views/home/quickActions/lnmarkets/index.tsx b/src/client/src/views/home/quickActions/lnmarkets/index.tsx index 049cb544..29869478 100644 --- a/src/client/src/views/home/quickActions/lnmarkets/index.tsx +++ b/src/client/src/views/home/quickActions/lnmarkets/index.tsx @@ -11,7 +11,7 @@ import { useLnMarketsLoginMutation } from '../../../../graphql/mutations/__gener import { useGetLnMarketsStatusQuery } from '../../../../graphql/queries/__generated__/getLnMarketsStatus.generated'; import { getErrorContent } from '../../../../utils/error'; import getConfig from 'next/config'; -import { QuickCard, QuickTitle } from '../MainnetQuickActions'; +import { QuickCard, QuickTitle } from '../QuickActions'; const { publicRuntimeConfig } = getConfig(); const { disableLnMarkets } = publicRuntimeConfig; diff --git a/src/client/src/views/home/quickActions/openChannel/index.tsx b/src/client/src/views/home/quickActions/openChannel/index.tsx index 3f39e683..65cced86 100644 --- a/src/client/src/views/home/quickActions/openChannel/index.tsx +++ b/src/client/src/views/home/quickActions/openChannel/index.tsx @@ -31,12 +31,12 @@ import { BaseNode } from '../../../../graphql/types'; import { OpenChannelCard } from './OpenChannel'; import { OpenRecommended } from './OpenRecommended'; -const IconStyle = styled.div` +export const IconStyle = styled.div` margin-bottom: 8px; color: ${themeColors.blue2}; `; -const Item = styled.div` +export const Item = styled.div` font-size: 14px; display: flex; flex-direction: column; @@ -67,7 +67,7 @@ const Item = styled.div` } `; -const Container = styled.div` +export const Container = styled.div` display: flex; justify-content: center; flex-wrap: wrap; @@ -88,6 +88,7 @@ export const OpenChannel = ({ setOpenCard }: OpenChannelProps) => { if (!loading && data && data.getBaseNodes) { if (data.getBaseNodes.length > 0) { set(true); + console.log(data.getBaseNodes); } } }, [loading, data]); From a3ed8e48a2eda7db2870dc9a6cc0cf6cec0b58a6 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 19 Jan 2024 09:16:40 -0800 Subject: [PATCH 49/50] fix : no purple fedimint logo --- src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx b/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx index 39bf76b3..aea54d23 100644 --- a/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx +++ b/src/client/src/layouts/navigation/nodeInfo/NodeInfo.tsx @@ -129,7 +129,7 @@ export const NodeInfo = ({ isOpen, isBurger }: NodeInfoProps) => { - + @@ -207,7 +207,7 @@ export const NodeInfo = ({ isOpen, isBurger }: NodeInfoProps) => { - + Date: Fri, 19 Jan 2024 09:50:34 -0800 Subject: [PATCH 50/50] fix: tb1 placeholder --- src/client/src/views/home/faucetActions/onchain.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/src/views/home/faucetActions/onchain.tsx b/src/client/src/views/home/faucetActions/onchain.tsx index 7b3dad34..256b8c6c 100644 --- a/src/client/src/views/home/faucetActions/onchain.tsx +++ b/src/client/src/views/home/faucetActions/onchain.tsx @@ -35,7 +35,7 @@ export const Onchain = () => { /> setAddress(value)} onEnter={() => handleOnchain()}