mirror of
https://github.com/RoboSats/robosats.git
synced 2025-07-29 15:11:39 +00:00
Federation coordinators list refactor
This commit is contained in:
@ -25,7 +25,7 @@ const MakerPage = (): JSX.Element => {
|
|||||||
|
|
||||||
const matches = useMemo(() => {
|
const matches = useMemo(() => {
|
||||||
return filterOrders({
|
return filterOrders({
|
||||||
orders: Object.values(federation.book),
|
federation,
|
||||||
baseFilter: {
|
baseFilter: {
|
||||||
currency: fav.currency === 0 ? 1 : fav.currency,
|
currency: fav.currency === 0 ? 1 : fav.currency,
|
||||||
type: fav.type,
|
type: fav.type,
|
||||||
|
@ -26,7 +26,7 @@ import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageCon
|
|||||||
const RobotPage = (): JSX.Element => {
|
const RobotPage = (): JSX.Element => {
|
||||||
const { torStatus, windowSize, settings, page, client } = useContext<UseAppStoreType>(AppContext);
|
const { torStatus, windowSize, settings, page, client } = useContext<UseAppStoreType>(AppContext);
|
||||||
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||||
const { federation, sortedCoordinators } = useContext<UseFederationStoreType>(FederationContext);
|
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const urlToken = settings.selfhostedClient ? params.token : null;
|
const urlToken = settings.selfhostedClient ? params.token : null;
|
||||||
@ -64,7 +64,7 @@ const RobotPage = (): JSX.Element => {
|
|||||||
setInputToken(token);
|
setInputToken(token);
|
||||||
genKey(token)
|
genKey(token)
|
||||||
.then((key) => {
|
.then((key) => {
|
||||||
garage.createRobot(token, sortedCoordinators, {
|
garage.createRobot(token, Object.keys(federation.coordinators), {
|
||||||
token,
|
token,
|
||||||
pubKey: key.publicKeyArmored,
|
pubKey: key.publicKeyArmored,
|
||||||
encPrivKey: key.encryptedPrivateKeyArmored,
|
encPrivKey: key.encryptedPrivateKeyArmored,
|
||||||
|
@ -350,8 +350,9 @@ const BookControl = ({
|
|||||||
<FlagWithProps code='ANY' />
|
<FlagWithProps code='ANY' />
|
||||||
</div>
|
</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{Object.values(federation.coordinators).map((coordinator) =>
|
{Object.values(federation.coordinators)
|
||||||
coordinator.enabled ? (
|
.filter((coord) => coord.enabled)
|
||||||
|
.map((coordinator) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={coordinator.shortAlias}
|
key={coordinator.shortAlias}
|
||||||
value={coordinator.shortAlias}
|
value={coordinator.shortAlias}
|
||||||
@ -367,10 +368,7 @@ const BookControl = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
) : (
|
))}
|
||||||
<></>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</Select>
|
</Select>
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>
|
||||||
|
@ -895,7 +895,7 @@ const BookTable = ({
|
|||||||
const filteredOrders = useMemo(() => {
|
const filteredOrders = useMemo(() => {
|
||||||
return showControls
|
return showControls
|
||||||
? filterOrders({
|
? filterOrders({
|
||||||
orders,
|
federation,
|
||||||
baseFilter: fav,
|
baseFilter: fav,
|
||||||
paymentMethods,
|
paymentMethods,
|
||||||
})
|
})
|
||||||
|
@ -21,8 +21,7 @@ const FederationTable = ({
|
|||||||
fillContainer = false,
|
fillContainer = false,
|
||||||
}: FederationTableProps): JSX.Element => {
|
}: FederationTableProps): JSX.Element => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { federation, sortedCoordinators, federationUpdatedAt } =
|
const { federation, federationUpdatedAt } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
useContext<UseFederationStoreType>(FederationContext);
|
|
||||||
const { setOpen, settings } = useContext<UseAppStoreType>(AppContext);
|
const { setOpen, settings } = useContext<UseAppStoreType>(AppContext);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [pageSize, setPageSize] = useState<number>(0);
|
const [pageSize, setPageSize] = useState<number>(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 (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={
|
sx={
|
||||||
@ -235,7 +226,7 @@ const FederationTable = ({
|
|||||||
localeText={localeText}
|
localeText={localeText}
|
||||||
rowHeight={3.714 * theme.typography.fontSize}
|
rowHeight={3.714 * theme.typography.fontSize}
|
||||||
headerHeight={3.25 * theme.typography.fontSize}
|
headerHeight={3.25 * theme.typography.fontSize}
|
||||||
rows={Object.values(reorderedCoordinators)}
|
rows={Object.values(federation.coordinators)}
|
||||||
getRowId={(params: Coordinator) => params.shortAlias}
|
getRowId={(params: Coordinator) => params.shortAlias}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
checkboxSelection={false}
|
checkboxSelection={false}
|
||||||
|
@ -26,7 +26,7 @@ const SelectCoordinator: React.FC<SelectCoordinatorProps> = ({
|
|||||||
setCoordinator,
|
setCoordinator,
|
||||||
}) => {
|
}) => {
|
||||||
const { setOpen } = useContext<UseAppStoreType>(AppContext);
|
const { setOpen } = useContext<UseAppStoreType>(AppContext);
|
||||||
const { federation, sortedCoordinators } = useContext<UseFederationStoreType>(FederationContext);
|
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -109,18 +109,20 @@ const SelectCoordinator: React.FC<SelectCoordinatorProps> = ({
|
|||||||
onChange={handleCoordinatorChange}
|
onChange={handleCoordinatorChange}
|
||||||
disableUnderline
|
disableUnderline
|
||||||
>
|
>
|
||||||
{sortedCoordinators.map((shortAlias: string): JSX.Element | null => {
|
{Object.keys(federation.coordinators).map(
|
||||||
let row: JSX.Element | null = null;
|
(shortAlias: string): JSX.Element | null => {
|
||||||
const item = federation.getCoordinator(shortAlias);
|
let row: JSX.Element | null = null;
|
||||||
if (item.enabled === true) {
|
const item = federation.getCoordinator(shortAlias);
|
||||||
row = (
|
if (item.enabled === true) {
|
||||||
<MenuItem key={shortAlias} value={shortAlias}>
|
row = (
|
||||||
<Typography>{item.longAlias}</Typography>
|
<MenuItem key={shortAlias} value={shortAlias}>
|
||||||
</MenuItem>
|
<Typography>{item.longAlias}</Typography>
|
||||||
);
|
</MenuItem>
|
||||||
}
|
);
|
||||||
return row;
|
}
|
||||||
})}
|
return row;
|
||||||
|
},
|
||||||
|
)}
|
||||||
</Select>
|
</Select>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -27,7 +27,6 @@ export interface FederationContextProviderProps {
|
|||||||
|
|
||||||
export interface UseFederationStoreType {
|
export interface UseFederationStoreType {
|
||||||
federation: Federation;
|
federation: Federation;
|
||||||
sortedCoordinators: string[];
|
|
||||||
coordinatorUpdatedAt: string;
|
coordinatorUpdatedAt: string;
|
||||||
federationUpdatedAt: string;
|
federationUpdatedAt: string;
|
||||||
addNewCoordinator: (alias: string, url: string) => void;
|
addNewCoordinator: (alias: string, url: string) => void;
|
||||||
@ -35,7 +34,6 @@ export interface UseFederationStoreType {
|
|||||||
|
|
||||||
export const initialFederationContext: UseFederationStoreType = {
|
export const initialFederationContext: UseFederationStoreType = {
|
||||||
federation: new Federation('onion', new Settings(), ''),
|
federation: new Federation('onion', new Settings(), ''),
|
||||||
sortedCoordinators: [],
|
|
||||||
coordinatorUpdatedAt: '',
|
coordinatorUpdatedAt: '',
|
||||||
federationUpdatedAt: '',
|
federationUpdatedAt: '',
|
||||||
addNewCoordinator: () => {},
|
addNewCoordinator: () => {},
|
||||||
@ -50,7 +48,6 @@ export const FederationContextProvider = ({
|
|||||||
useContext<UseAppStoreType>(AppContext);
|
useContext<UseAppStoreType>(AppContext);
|
||||||
const { setMaker, garage } = useContext<UseGarageStoreType>(GarageContext);
|
const { setMaker, garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||||
const [federation] = useState(new Federation(origin, settings, hostUrl));
|
const [federation] = useState(new Federation(origin, settings, hostUrl));
|
||||||
const [sortedCoordinators, setSortedCoordinators] = useState(federationLottery(federation));
|
|
||||||
const [coordinatorUpdatedAt, setCoordinatorUpdatedAt] = useState<string>(
|
const [coordinatorUpdatedAt, setCoordinatorUpdatedAt] = useState<string>(
|
||||||
new Date().toISOString(),
|
new Date().toISOString(),
|
||||||
);
|
);
|
||||||
@ -58,7 +55,7 @@ export const FederationContextProvider = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMaker((maker) => {
|
setMaker((maker) => {
|
||||||
return { ...maker, coordinator: sortedCoordinators[0] };
|
return { ...maker, coordinator: Object.keys(federation.coordinators)[0] };
|
||||||
}); // default MakerForm coordinator is decided via sorted lottery
|
}); // default MakerForm coordinator is decided via sorted lottery
|
||||||
federation.registerHook('onFederationUpdate', () => {
|
federation.registerHook('onFederationUpdate', () => {
|
||||||
setFederationUpdatedAt(new Date().toISOString());
|
setFederationUpdatedAt(new Date().toISOString());
|
||||||
@ -122,7 +119,6 @@ export const FederationContextProvider = ({
|
|||||||
<FederationContext.Provider
|
<FederationContext.Provider
|
||||||
value={{
|
value={{
|
||||||
federation,
|
federation,
|
||||||
sortedCoordinators,
|
|
||||||
coordinatorUpdatedAt,
|
coordinatorUpdatedAt,
|
||||||
federationUpdatedAt,
|
federationUpdatedAt,
|
||||||
addNewCoordinator,
|
addNewCoordinator,
|
||||||
|
@ -66,7 +66,7 @@ export const GarageContextProvider = ({ children }: GarageContextProviderProps):
|
|||||||
// All garage data structured
|
// All garage data structured
|
||||||
const { settings, torStatus, open, page, client } = useContext<UseAppStoreType>(AppContext);
|
const { settings, torStatus, open, page, client } = useContext<UseAppStoreType>(AppContext);
|
||||||
const pageRef = useRef(page);
|
const pageRef = useRef(page);
|
||||||
const { federation, sortedCoordinators } = useContext<UseFederationStoreType>(FederationContext);
|
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
const [garage] = useState<Garage>(initialGarageContext.garage);
|
const [garage] = useState<Garage>(initialGarageContext.garage);
|
||||||
const [maker, setMaker] = useState<Maker>(initialGarageContext.maker);
|
const [maker, setMaker] = useState<Maker>(initialGarageContext.maker);
|
||||||
const [slotUpdatedAt, setSlotUpdatedAt] = useState<string>(new Date().toISOString());
|
const [slotUpdatedAt, setSlotUpdatedAt] = useState<string>(new Date().toISOString());
|
||||||
@ -83,7 +83,7 @@ export const GarageContextProvider = ({ children }: GarageContextProviderProps):
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMaker((maker) => {
|
setMaker((maker) => {
|
||||||
return { ...maker, coordinator: sortedCoordinators[0] };
|
return { ...maker, coordinator: Object.keys(federation.coordinators)[0] };
|
||||||
}); // default MakerForm coordinator is decided via sorted lottery
|
}); // default MakerForm coordinator is decided via sorted lottery
|
||||||
garage.registerHook('onSlotUpdate', onSlotUpdated);
|
garage.registerHook('onSlotUpdate', onSlotUpdated);
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
|
@ -126,7 +126,7 @@ export class Coordinator {
|
|||||||
this.longAlias = value.longAlias;
|
this.longAlias = value.longAlias;
|
||||||
this.shortAlias = value.shortAlias;
|
this.shortAlias = value.shortAlias;
|
||||||
this.description = value.description;
|
this.description = value.description;
|
||||||
this.federated = value.federated;
|
this.federated = value.federated ?? false;
|
||||||
this.motto = value.motto;
|
this.motto = value.motto;
|
||||||
this.color = value.color;
|
this.color = value.color;
|
||||||
this.size_limit = value.badges.isFounder ? 21 * 100000000 : calculateSizeLimit(established);
|
this.size_limit = value.badges.isFounder ? 21 * 100000000 : calculateSizeLimit(established);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { SimplePool, VerifiedEvent, Event } from 'nostr-tools';
|
|
||||||
import {
|
import {
|
||||||
Coordinator,
|
Coordinator,
|
||||||
type Exchange,
|
type Exchange,
|
||||||
@ -9,7 +8,7 @@ import {
|
|||||||
} from '.';
|
} from '.';
|
||||||
import defaultFederation from '../../static/federation.json';
|
import defaultFederation from '../../static/federation.json';
|
||||||
import { systemClient } from '../services/System';
|
import { systemClient } from '../services/System';
|
||||||
import { getHost } from '../utils';
|
import { federationLottery, getHost } from '../utils';
|
||||||
import { coordinatorDefaultValues } from './Coordinator.model';
|
import { coordinatorDefaultValues } from './Coordinator.model';
|
||||||
import { updateExchangeInfo } from './Exchange.model';
|
import { updateExchangeInfo } from './Exchange.model';
|
||||||
import eventToPublicOrder from '../utils/nostr';
|
import eventToPublicOrder from '../utils/nostr';
|
||||||
@ -20,19 +19,25 @@ type FederationHooks = 'onFederationUpdate';
|
|||||||
|
|
||||||
export class Federation {
|
export class Federation {
|
||||||
constructor(origin: Origin, settings: Settings, hostUrl: string) {
|
constructor(origin: Origin, settings: Settings, hostUrl: string) {
|
||||||
this.coordinators = Object.entries(defaultFederation).reduce(
|
const coordinators = Object.entries(defaultFederation).reduce(
|
||||||
(acc: Record<string, Coordinator>, [key, value]: [string, any]) => {
|
(acc: Record<string, Coordinator>, [key, value]: [string, any]) => {
|
||||||
if (getHost() !== '127.0.0.1:8000' && key === 'local') {
|
if (getHost() !== '127.0.0.1:8000' && key === 'local') {
|
||||||
// Do not add `Local Dev` unless it is running on localhost
|
// Do not add `Local Dev` unless it is running on localhost
|
||||||
return acc;
|
return acc;
|
||||||
} else {
|
} else {
|
||||||
acc[key] = new Coordinator(value, origin, settings, hostUrl);
|
acc[key] = new Coordinator(value, origin, settings, hostUrl);
|
||||||
|
acc[key].federated = true;
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.coordinators = {};
|
||||||
|
federationLottery().forEach((alias) => {
|
||||||
|
if (coordinators[alias]) this.coordinators[alias] = coordinators[alias];
|
||||||
|
});
|
||||||
|
|
||||||
this.exchange = {
|
this.exchange = {
|
||||||
...defaultExchange,
|
...defaultExchange,
|
||||||
totalCoordinators: Object.keys(this.coordinators).length,
|
totalCoordinators: Object.keys(this.coordinators).length,
|
||||||
@ -42,10 +47,10 @@ export class Federation {
|
|||||||
onFederationUpdate: [],
|
onFederationUpdate: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(defaultFederation).forEach((key) => {
|
Object.keys(this.coordinators).forEach((key) => {
|
||||||
if (key !== 'local' || getHost() === '127.0.0.1:8000') {
|
if (key !== 'local' || getHost() === '127.0.0.1:8000') {
|
||||||
// Do not add `Local Dev` unless it is running on localhost
|
// 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]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -11,14 +11,14 @@
|
|||||||
// donate to the development fund. This is the only way envisioned to incentivize
|
// donate to the development fund. This is the only way envisioned to incentivize
|
||||||
// donations to the development fund.
|
// 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)
|
// Create an array to store the coordinator short aliases and their corresponding weights (chance)
|
||||||
const coordinatorChance: Array<{ shortAlias: string; chance: number }> = [];
|
const coordinatorChance: Array<{ shortAlias: string; chance: number }> = [];
|
||||||
|
|
||||||
// Convert the `federation` object into an array of {shortAlias, chance}
|
// 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;
|
const chance = coor.badges.donatesToDevFund > 50 ? 50 : coor.badges?.donatesToDevFund;
|
||||||
coordinatorChance.push({ shortAlias: coor.shortAlias, chance });
|
coordinatorChance.push({ shortAlias: coor.shortAlias, chance });
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { type PublicOrder, type Favorites } from '../models';
|
import { type PublicOrder, type Favorites, Federation } from '../models';
|
||||||
|
|
||||||
interface AmountFilter {
|
interface AmountFilter {
|
||||||
amount: string;
|
amount: string;
|
||||||
@ -8,9 +8,9 @@ interface AmountFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface FilterOrders {
|
interface FilterOrders {
|
||||||
orders: PublicOrder[];
|
federation: Federation;
|
||||||
baseFilter: Favorites;
|
baseFilter: Favorites;
|
||||||
premium: number | null;
|
premium?: number | null;
|
||||||
amountFilter?: AmountFilter | null;
|
amountFilter?: AmountFilter | null;
|
||||||
paymentMethods?: string[];
|
paymentMethods?: string[];
|
||||||
}
|
}
|
||||||
@ -60,13 +60,17 @@ const filterByPremium = function (order: PublicOrder, premium: number): boolean
|
|||||||
};
|
};
|
||||||
|
|
||||||
const filterOrders = function ({
|
const filterOrders = function ({
|
||||||
orders,
|
federation,
|
||||||
baseFilter,
|
baseFilter,
|
||||||
premium = null,
|
premium = null,
|
||||||
paymentMethods = [],
|
paymentMethods = [],
|
||||||
amountFilter = null,
|
amountFilter = null,
|
||||||
}: FilterOrders): PublicOrder[] {
|
}: 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 typeChecks = order.type === baseFilter.type || baseFilter.type == null;
|
||||||
const modeChecks = baseFilter.mode === 'fiat' ? !(order.currency === 1000) : true;
|
const modeChecks = baseFilter.mode === 'fiat' ? !(order.currency === 1000) : true;
|
||||||
const premiumChecks = premium !== null ? filterByPremium(order, premium) : true;
|
const premiumChecks = premium !== null ? filterByPremium(order, premium) : true;
|
||||||
@ -77,6 +81,7 @@ const filterOrders = function ({
|
|||||||
const hostChecks =
|
const hostChecks =
|
||||||
baseFilter.coordinator !== 'any' ? filterByHost(order, baseFilter.coordinator) : true;
|
baseFilter.coordinator !== 'any' ? filterByHost(order, baseFilter.coordinator) : true;
|
||||||
return (
|
return (
|
||||||
|
coordinatorCheck &&
|
||||||
typeChecks &&
|
typeChecks &&
|
||||||
modeChecks &&
|
modeChecks &&
|
||||||
premiumChecks &&
|
premiumChecks &&
|
||||||
|
Reference in New Issue
Block a user