diff --git a/frontend/src/basic/MakerPage/index.tsx b/frontend/src/basic/MakerPage/index.tsx index 1424b366..099d4c85 100644 --- a/frontend/src/basic/MakerPage/index.tsx +++ b/frontend/src/basic/MakerPage/index.tsx @@ -25,7 +25,7 @@ const MakerPage = (): JSX.Element => { const matches = useMemo(() => { return filterOrders({ - orders: Object.values(federation.book), + federation, baseFilter: { currency: fav.currency === 0 ? 1 : fav.currency, type: fav.type, diff --git a/frontend/src/basic/RobotPage/index.tsx b/frontend/src/basic/RobotPage/index.tsx index 6e0d6a72..3346586e 100644 --- a/frontend/src/basic/RobotPage/index.tsx +++ b/frontend/src/basic/RobotPage/index.tsx @@ -26,7 +26,7 @@ import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageCon const RobotPage = (): JSX.Element => { const { torStatus, windowSize, settings, page, client } = useContext(AppContext); const { garage } = useContext(GarageContext); - const { federation, sortedCoordinators } = useContext(FederationContext); + const { federation } = useContext(FederationContext); const { t } = useTranslation(); const params = useParams(); const urlToken = settings.selfhostedClient ? params.token : null; @@ -64,7 +64,7 @@ const RobotPage = (): JSX.Element => { setInputToken(token); genKey(token) .then((key) => { - garage.createRobot(token, sortedCoordinators, { + garage.createRobot(token, Object.keys(federation.coordinators), { token, pubKey: key.publicKeyArmored, encPrivKey: key.encryptedPrivateKeyArmored, diff --git a/frontend/src/components/BookTable/BookControl.tsx b/frontend/src/components/BookTable/BookControl.tsx index 44ba81a5..3aafbb55 100644 --- a/frontend/src/components/BookTable/BookControl.tsx +++ b/frontend/src/components/BookTable/BookControl.tsx @@ -350,8 +350,9 @@ const BookControl = ({ - {Object.values(federation.coordinators).map((coordinator) => - coordinator.enabled ? ( + {Object.values(federation.coordinators) + .filter((coord) => coord.enabled) + .map((coordinator) => ( - ) : ( - <> - ), - )} + ))} diff --git a/frontend/src/components/BookTable/index.tsx b/frontend/src/components/BookTable/index.tsx index 5835a8de..1401530d 100644 --- a/frontend/src/components/BookTable/index.tsx +++ b/frontend/src/components/BookTable/index.tsx @@ -895,7 +895,7 @@ const BookTable = ({ const filteredOrders = useMemo(() => { return showControls ? filterOrders({ - orders, + federation, baseFilter: fav, paymentMethods, }) diff --git a/frontend/src/components/FederationTable/index.tsx b/frontend/src/components/FederationTable/index.tsx index cd9c1bed..3f18b499 100644 --- a/frontend/src/components/FederationTable/index.tsx +++ b/frontend/src/components/FederationTable/index.tsx @@ -21,8 +21,7 @@ const FederationTable = ({ fillContainer = false, }: FederationTableProps): JSX.Element => { const { t } = useTranslation(); - const { federation, sortedCoordinators, federationUpdatedAt } = - useContext(FederationContext); + const { federation, federationUpdatedAt } = useContext(FederationContext); const { setOpen, settings } = useContext(AppContext); const theme = useTheme(); const [pageSize, setPageSize] = useState(0); @@ -214,14 +213,6 @@ const FederationTable = ({ } }; - const reorderedCoordinators = useMemo(() => { - return sortedCoordinators.reduce((coordinators, key) => { - coordinators[key] = federation.coordinators[key]; - - return coordinators; - }, {}); - }, [settings.network, federationUpdatedAt]); - return ( params.shortAlias} columns={columns} checkboxSelection={false} diff --git a/frontend/src/components/MakerForm/SelectCoordinator.tsx b/frontend/src/components/MakerForm/SelectCoordinator.tsx index 49bb1a1b..f1468875 100644 --- a/frontend/src/components/MakerForm/SelectCoordinator.tsx +++ b/frontend/src/components/MakerForm/SelectCoordinator.tsx @@ -26,7 +26,7 @@ const SelectCoordinator: React.FC = ({ setCoordinator, }) => { const { setOpen } = useContext(AppContext); - const { federation, sortedCoordinators } = useContext(FederationContext); + const { federation } = useContext(FederationContext); const theme = useTheme(); const { t } = useTranslation(); @@ -109,18 +109,20 @@ const SelectCoordinator: React.FC = ({ onChange={handleCoordinatorChange} disableUnderline > - {sortedCoordinators.map((shortAlias: string): JSX.Element | null => { - let row: JSX.Element | null = null; - const item = federation.getCoordinator(shortAlias); - if (item.enabled === true) { - row = ( - - {item.longAlias} - - ); - } - return row; - })} + {Object.keys(federation.coordinators).map( + (shortAlias: string): JSX.Element | null => { + let row: JSX.Element | null = null; + const item = federation.getCoordinator(shortAlias); + if (item.enabled === true) { + row = ( + + {item.longAlias} + + ); + } + return row; + }, + )} diff --git a/frontend/src/contexts/FederationContext.tsx b/frontend/src/contexts/FederationContext.tsx index 66b802ef..326e7659 100644 --- a/frontend/src/contexts/FederationContext.tsx +++ b/frontend/src/contexts/FederationContext.tsx @@ -27,7 +27,6 @@ export interface FederationContextProviderProps { export interface UseFederationStoreType { federation: Federation; - sortedCoordinators: string[]; coordinatorUpdatedAt: string; federationUpdatedAt: string; addNewCoordinator: (alias: string, url: string) => void; @@ -35,7 +34,6 @@ export interface UseFederationStoreType { export const initialFederationContext: UseFederationStoreType = { federation: new Federation('onion', new Settings(), ''), - sortedCoordinators: [], coordinatorUpdatedAt: '', federationUpdatedAt: '', addNewCoordinator: () => {}, @@ -50,7 +48,6 @@ export const FederationContextProvider = ({ useContext(AppContext); const { setMaker, garage } = useContext(GarageContext); const [federation] = useState(new Federation(origin, settings, hostUrl)); - const [sortedCoordinators, setSortedCoordinators] = useState(federationLottery(federation)); const [coordinatorUpdatedAt, setCoordinatorUpdatedAt] = useState( new Date().toISOString(), ); @@ -58,7 +55,7 @@ export const FederationContextProvider = ({ useEffect(() => { setMaker((maker) => { - return { ...maker, coordinator: sortedCoordinators[0] }; + return { ...maker, coordinator: Object.keys(federation.coordinators)[0] }; }); // default MakerForm coordinator is decided via sorted lottery federation.registerHook('onFederationUpdate', () => { setFederationUpdatedAt(new Date().toISOString()); @@ -122,7 +119,6 @@ export const FederationContextProvider = ({ (AppContext); const pageRef = useRef(page); - const { federation, sortedCoordinators } = useContext(FederationContext); + const { federation } = useContext(FederationContext); const [garage] = useState(initialGarageContext.garage); const [maker, setMaker] = useState(initialGarageContext.maker); const [slotUpdatedAt, setSlotUpdatedAt] = useState(new Date().toISOString()); @@ -83,7 +83,7 @@ export const GarageContextProvider = ({ children }: GarageContextProviderProps): useEffect(() => { setMaker((maker) => { - return { ...maker, coordinator: sortedCoordinators[0] }; + return { ...maker, coordinator: Object.keys(federation.coordinators)[0] }; }); // default MakerForm coordinator is decided via sorted lottery garage.registerHook('onSlotUpdate', onSlotUpdated); clearInterval(timer); diff --git a/frontend/src/models/Coordinator.model.ts b/frontend/src/models/Coordinator.model.ts index 28a6e8af..b9896f34 100644 --- a/frontend/src/models/Coordinator.model.ts +++ b/frontend/src/models/Coordinator.model.ts @@ -126,7 +126,7 @@ export class Coordinator { this.longAlias = value.longAlias; this.shortAlias = value.shortAlias; this.description = value.description; - this.federated = value.federated; + this.federated = value.federated ?? false; this.motto = value.motto; this.color = value.color; this.size_limit = value.badges.isFounder ? 21 * 100000000 : calculateSizeLimit(established); diff --git a/frontend/src/models/Federation.model.ts b/frontend/src/models/Federation.model.ts index 23a6e67e..51c4558a 100644 --- a/frontend/src/models/Federation.model.ts +++ b/frontend/src/models/Federation.model.ts @@ -1,4 +1,3 @@ -import { SimplePool, VerifiedEvent, Event } from 'nostr-tools'; import { Coordinator, type Exchange, @@ -9,7 +8,7 @@ import { } from '.'; import defaultFederation from '../../static/federation.json'; import { systemClient } from '../services/System'; -import { getHost } from '../utils'; +import { federationLottery, getHost } from '../utils'; import { coordinatorDefaultValues } from './Coordinator.model'; import { updateExchangeInfo } from './Exchange.model'; import eventToPublicOrder from '../utils/nostr'; @@ -20,19 +19,25 @@ type FederationHooks = 'onFederationUpdate'; export class Federation { constructor(origin: Origin, settings: Settings, hostUrl: string) { - this.coordinators = Object.entries(defaultFederation).reduce( + const coordinators = Object.entries(defaultFederation).reduce( (acc: Record, [key, value]: [string, any]) => { if (getHost() !== '127.0.0.1:8000' && key === 'local') { // Do not add `Local Dev` unless it is running on localhost return acc; } else { acc[key] = new Coordinator(value, origin, settings, hostUrl); - + acc[key].federated = true; return acc; } }, {}, ); + + this.coordinators = {}; + federationLottery().forEach((alias) => { + if (coordinators[alias]) this.coordinators[alias] = coordinators[alias]; + }); + this.exchange = { ...defaultExchange, totalCoordinators: Object.keys(this.coordinators).length, @@ -42,10 +47,10 @@ export class Federation { onFederationUpdate: [], }; - Object.keys(defaultFederation).forEach((key) => { + Object.keys(this.coordinators).forEach((key) => { if (key !== 'local' || getHost() === '127.0.0.1:8000') { // Do not add `Local Dev` unless it is running on localhost - this.addCoordinator(origin, settings, hostUrl, defaultFederation[key]); + this.addCoordinator(origin, settings, hostUrl, this.coordinators[key]); } }); diff --git a/frontend/src/utils/federationLottery.ts b/frontend/src/utils/federationLottery.ts index da49be3b..75d4775b 100644 --- a/frontend/src/utils/federationLottery.ts +++ b/frontend/src/utils/federationLottery.ts @@ -11,14 +11,14 @@ // donate to the development fund. This is the only way envisioned to incentivize // donations to the development fund. -import { type Federation } from '../models'; +import defaultFederation from '../../static/federation.json'; -export default function federationLottery(federation: Federation): string[] { +export default function federationLottery(): string[] { // Create an array to store the coordinator short aliases and their corresponding weights (chance) const coordinatorChance: Array<{ shortAlias: string; chance: number }> = []; // Convert the `federation` object into an array of {shortAlias, chance} - Object.values(federation.coordinators).forEach((coor) => { + Object.values(defaultFederation).forEach((coor) => { const chance = coor.badges.donatesToDevFund > 50 ? 50 : coor.badges?.donatesToDevFund; coordinatorChance.push({ shortAlias: coor.shortAlias, chance }); }); diff --git a/frontend/src/utils/filterOrders.ts b/frontend/src/utils/filterOrders.ts index c97ff1d8..1c5c057a 100644 --- a/frontend/src/utils/filterOrders.ts +++ b/frontend/src/utils/filterOrders.ts @@ -1,4 +1,4 @@ -import { type PublicOrder, type Favorites } from '../models'; +import { type PublicOrder, type Favorites, Federation } from '../models'; interface AmountFilter { amount: string; @@ -8,9 +8,9 @@ interface AmountFilter { } interface FilterOrders { - orders: PublicOrder[]; + federation: Federation; baseFilter: Favorites; - premium: number | null; + premium?: number | null; amountFilter?: AmountFilter | null; paymentMethods?: string[]; } @@ -60,13 +60,17 @@ const filterByPremium = function (order: PublicOrder, premium: number): boolean }; const filterOrders = function ({ - orders, + federation, baseFilter, premium = null, paymentMethods = [], amountFilter = null, }: FilterOrders): PublicOrder[] { - const filteredOrders = orders.filter((order) => { + const enabledCoordinators = Object.values(federation.coordinators) + .filter((coord) => coord.enabled) + .map((coord) => coord.shortAlias); + const filteredOrders = Object.values(federation.book).filter((order) => { + const coordinatorCheck = enabledCoordinators.includes(order.coordinatorShortAlias ?? ''); const typeChecks = order.type === baseFilter.type || baseFilter.type == null; const modeChecks = baseFilter.mode === 'fiat' ? !(order.currency === 1000) : true; const premiumChecks = premium !== null ? filterByPremium(order, premium) : true; @@ -77,6 +81,7 @@ const filterOrders = function ({ const hostChecks = baseFilter.coordinator !== 'any' ? filterByHost(order, baseFilter.coordinator) : true; return ( + coordinatorCheck && typeChecks && modeChecks && premiumChecks &&