robosats/frontend/src/models/Coordinator.model.ts

306 lines
8.0 KiB
TypeScript
Raw Normal View History

2024-08-15 14:26:04 +00:00
import { type LimitList, type PublicOrder, type Settings } from '.';
2024-04-30 14:01:54 +00:00
import { roboidentitiesClient } from '../services/Roboidentities/Web';
import { apiClient } from '../services/api';
import { compareUpdateLimit } from './Limit.model';
export interface Contact {
nostr?: string | undefined;
pgp?: string | undefined;
fingerprint?: string | undefined;
email?: string | undefined;
telegram?: string | undefined;
reddit?: string | undefined;
matrix?: string | undefined;
simplex?: string | undefined;
twitter?: string | undefined;
website?: string | undefined;
}
export interface Version {
major: number;
minor: number;
patch: number;
}
export interface Badges {
isFounder?: boolean | undefined;
donatesToDevFund: number;
hasGoodOpSec?: boolean | undefined;
robotsLove?: boolean | undefined;
hasLargeLimits?: boolean | undefined;
}
export interface Info {
num_public_buy_orders: number;
num_public_sell_orders: number;
book_liquidity: number;
active_robots_today: number;
last_day_nonkyc_btc_premium: number;
last_day_volume: number;
lifetime_volume: number;
lnd_version?: string;
cln_version?: string;
robosats_running_commit_hash: string;
alternative_site: string;
alternative_name: string;
node_alias: string;
node_id: string;
version: Version;
maker_fee: number;
taker_fee: number;
bond_size: number;
min_order_size: number;
max_order_size: number;
swap_enabled: boolean;
max_swap: number;
current_swap_fee_rate: number;
network: 'mainnet' | 'testnet' | undefined;
openUpdateClient: boolean;
notice_severity: 'none' | 'warning' | 'error' | 'success' | 'info';
notice_message: string;
loading: boolean;
}
export type Origin = 'onion' | 'i2p' | 'clearnet';
export const coordinatorDefaultValues = {
longAlias: '',
shortAlias: '',
description: '',
motto: '',
color: '#000',
size_limit: 21 * 100000000,
established: new Date(),
policies: {},
contact: {
email: '',
telegram: '',
simplex: '',
matrix: '',
website: '',
nostr: '',
pgp: '',
fingerprint: '',
},
badges: {
isFounder: false,
donatesToDevFund: 0,
hasGoodOpSec: false,
robotsLove: false,
hasLargeLimits: false,
},
mainnet: undefined,
testnet: undefined,
mainnetNodesPubkeys: '',
testnetNodesPubkeys: '',
federated: true,
};
export interface Origins {
clearnet: Origin | undefined;
onion: Origin | undefined;
i2p: Origin | undefined;
}
function calculateSizeLimit(inputDate: Date): number {
const now = new Date();
const numDifficultyAdjustments = Math.ceil(
(now.getTime() - inputDate.getTime()) / (1000 * 60 * 60 * 24 * 14),
);
let value = 250000;
for (let i = 1; i < numDifficultyAdjustments; i++) {
value *= 1.3;
if (i >= 12) {
// after 12 difficulty adjustments (6 weeks) limit becomes 21 BTC (mature coordinator)
return 21 * 100000000;
}
}
return value;
}
export class Coordinator {
2024-03-28 22:21:15 +00:00
constructor(value: any, origin: Origin, settings: Settings, hostUrl: string) {
const established = new Date(value.established);
this.longAlias = value.longAlias;
this.shortAlias = value.shortAlias;
this.description = value.description;
2024-10-18 10:36:26 +00:00
this.federated = value.federated ?? false;
this.motto = value.motto;
this.color = value.color;
this.size_limit = value.badges.isFounder ? 21 * 100000000 : calculateSizeLimit(established);
this.established = established;
this.policies = value.policies;
this.contact = value.contact;
this.badges = value.badges;
this.mainnet = value.mainnet;
this.testnet = value.testnet;
this.mainnetNodesPubkeys = value.mainnetNodesPubkeys;
this.testnetNodesPubkeys = value.testnetNodesPubkeys;
this.url = '';
this.basePath = '';
2024-03-28 22:21:15 +00:00
this.updateUrl(origin, settings, hostUrl);
}
// These properties are loaded from federation.json
public longAlias: string;
public shortAlias: string;
public federated: boolean;
public enabled?: boolean = true;
public description: string;
public motto: string;
public color: string;
public size_limit: number;
public established: Date;
public policies: Record<string, string> = {};
public contact: Contact | undefined;
public badges: Badges;
public mainnet: Origins;
public testnet: Origins;
public mainnetNodesPubkeys: string[] | undefined;
public testnetNodesPubkeys: string[] | undefined;
public url: string;
public basePath: string;
// These properties are fetched from coordinator API
2024-09-12 08:10:27 +00:00
public book: Record<string, PublicOrder> = {};
public loadingBook: boolean = false;
public info?: Info | undefined = undefined;
public loadingInfo: boolean = false;
public limits: LimitList = {};
public loadingLimits: boolean = false;
2024-03-28 22:21:15 +00:00
updateUrl = (origin: Origin, settings: Settings, hostUrl: string): void => {
if (settings.selfhostedClient && this.shortAlias !== 'local') {
this.url = hostUrl;
this.basePath = `/${settings.network}/${this.shortAlias}`;
} else {
this.url = String(this[settings.network][origin]);
this.basePath = '';
}
};
2024-10-11 13:57:42 +00:00
generateAllMakerAvatars = async (): Promise<void> => {
for (const order of Object.values(this.book)) {
2024-08-10 15:54:13 +00:00
void roboidentitiesClient.generateRobohash(order.maker_hash_id, 'small');
2024-04-28 12:34:32 +00:00
}
2023-12-02 11:31:21 +00:00
};
2023-11-02 14:15:18 +00:00
loadBook = (onDataLoad: () => void = () => {}): void => {
2023-12-22 12:58:59 +00:00
if (!this.enabled) return;
if (this.url === '') return;
if (this.loadingBook) return;
2024-10-11 13:57:42 +00:00
this.loadingBook = true;
this.book = {};
apiClient
.get(this.url, `${this.basePath}/api/book/`)
.then((data) => {
if (!data?.not_found) {
this.book = (data as PublicOrder[]).reduce<Record<string, PublicOrder>>((book, order) => {
order.coordinatorShortAlias = this.shortAlias;
return { ...book, [this.shortAlias + order.id]: order };
}, {});
void this.generateAllMakerAvatars();
onDataLoad();
} else {
onDataLoad();
}
})
.catch((e) => {
console.log(e);
})
.finally(() => {
this.loadingBook = false;
});
};
2023-11-02 14:15:18 +00:00
loadLimits = (onDataLoad: () => void = () => {}): void => {
2023-12-22 12:58:59 +00:00
if (!this.enabled) return;
if (this.url === '') return;
if (this.loadingLimits) return;
this.loadingLimits = true;
apiClient
.get(this.url, `${this.basePath}/api/limits/`)
.then((data) => {
if (data !== null) {
const newLimits = data as LimitList;
for (const currency in this.limits) {
newLimits[currency] = compareUpdateLimit(this.limits[currency], newLimits[currency]);
}
this.limits = newLimits;
onDataLoad();
}
})
.catch((e) => {
console.log(e);
})
.finally(() => {
this.loadingLimits = false;
});
};
2023-11-02 14:15:18 +00:00
loadInfo = (onDataLoad: () => void = () => {}): void => {
2023-12-22 12:58:59 +00:00
if (!this.enabled) return;
if (this.url === '') return;
if (this.loadingInfo) return;
this.loadingInfo = true;
apiClient
.get(this.url, `${this.basePath}/api/info/`)
.then((data) => {
if (data !== null) {
this.info = data as Info;
onDataLoad();
}
})
.catch((e) => {
console.log(e);
})
.finally(() => {
this.loadingInfo = false;
});
};
2023-11-02 14:15:18 +00:00
enable = (onEnabled: () => void = () => {}): void => {
this.enabled = true;
2024-10-17 09:14:52 +00:00
void this.loadLimits(() => {
2023-11-01 12:18:00 +00:00
onEnabled();
});
};
2023-11-02 14:15:18 +00:00
disable = (): void => {
this.enabled = false;
this.info = undefined;
this.limits = {};
2024-09-12 08:10:27 +00:00
this.book = {};
};
2023-11-02 14:15:18 +00:00
getBaseUrl = (): string => {
return this.url + this.basePath;
};
getEndpoint = (
network: 'mainnet' | 'testnet',
origin: Origin,
selfHosted: boolean,
hostUrl: string,
): { url: string; basePath: string } => {
if (selfHosted && this.shortAlias !== 'local') {
return { url: hostUrl, basePath: `/${network}/${this.shortAlias}` };
} else {
return { url: String(this[network][origin]), basePath: '' };
}
};
Add Nav Bar, Settings Page, large refactor (#308) commit a5b63aed93e084fae19d9e444e06238a52f24f3a Author: Reckless_Satoshi <reckless.satoshi@protonmail.com> Date: Sun Oct 30 10:46:05 2022 -0700 Small fixes commit d64adfc2bf9b9c31dca47ab113c06a1268c347c6 Author: Reckless_Satoshi <reckless.satoshi@protonmail.com> Date: Sun Oct 30 06:02:06 2022 -0700 wip work on federation settings commit ca35d6b3d2776812b07109e197d2e1d46f9f4e81 Author: Reckless_Satoshi <reckless.satoshi@protonmail.com> Date: Sun Oct 30 04:05:33 2022 -0700 Refactor confirmation Dialogs commit c660a5b0d1345d4996efb10cb8999987689bede9 Author: Reckless_Satoshi <reckless.satoshi@protonmail.com> Date: Sat Oct 29 13:36:59 2022 -0700 refactor login (clean separation robot/info. Style navbar. commit b9dc7f7c95a683e3aca024ec6d7857176b4e3a25 Author: Reckless_Satoshi <reckless.satoshi@protonmail.com> Date: Fri Oct 28 09:54:38 2022 -0700 Add size slider and settings widget commit 20b2b3dcd6838b129741705f1c65d445271e231d Author: Reckless_Satoshi <reckless.satoshi@protonmail.com> Date: Fri Oct 28 05:41:48 2022 -0700 Add show more and Dialogs commit da8b70091b5f28139cdec1a8895f4563d64d8e88 Author: Reckless_Satoshi <reckless.satoshi@protonmail.com> Date: Thu Oct 27 16:26:07 2022 -0700 Add sliding pages commit 6dd90aa1182a7a5e0f0189d1467ba474b68c28c2 Author: Reckless_Satoshi <reckless.satoshi@protonmail.com> Date: Thu Oct 27 06:34:58 2022 -0700 Add settings forms commit d3d0f3ee1a52bbf1829714050cc798d2542af8f6 Author: Reckless_Satoshi <reckless.satoshi@protonmail.com> Date: Wed Oct 26 04:16:06 2022 -0700 Refactor utils
2022-10-30 19:13:01 +00:00
}
export default Coordinator;