Merge branch 'main' into update-order-nav-bar-on-time

This commit is contained in:
KoalaSat 2024-06-16 22:38:35 +00:00 committed by GitHub
commit 34738e8a51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
46 changed files with 160 additions and 2076 deletions

View File

@ -1,5 +1,6 @@
import json import json
from decimal import Decimal
from django.core.validators import MinValueValidator from django.core.validators import MinValueValidator
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
@ -18,7 +19,7 @@ class Currency(models.Model):
decimal_places=4, decimal_places=4,
default=None, default=None,
null=True, null=True,
validators=[MinValueValidator(0)], validators=[MinValueValidator(Decimal(0))],
) )
timestamp = models.DateTimeField(default=timezone.now) timestamp = models.DateTimeField(default=timezone.now)

View File

@ -1,5 +1,6 @@
import uuid import uuid
from decimal import Decimal
from decouple import config from decouple import config
from django.core.validators import MaxValueValidator, MinValueValidator from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models from django.db import models
@ -27,21 +28,24 @@ class MarketTick(models.Model):
decimal_places=2, decimal_places=2,
default=None, default=None,
null=True, null=True,
validators=[MinValueValidator(0)], validators=[MinValueValidator(Decimal(0))],
) )
volume = models.DecimalField( volume = models.DecimalField(
max_digits=8, max_digits=8,
decimal_places=8, decimal_places=8,
default=None, default=None,
null=True, null=True,
validators=[MinValueValidator(0)], validators=[MinValueValidator(Decimal(0))],
) )
premium = models.DecimalField( premium = models.DecimalField(
max_digits=5, max_digits=5,
decimal_places=2, decimal_places=2,
default=None, default=None,
null=True, null=True,
validators=[MinValueValidator(-100), MaxValueValidator(999)], validators=[
MinValueValidator(Decimal(-100)),
MaxValueValidator(Decimal(999))
],
blank=True, blank=True,
) )
currency = models.ForeignKey("api.Currency", null=True, on_delete=models.SET_NULL) currency = models.ForeignKey("api.Currency", null=True, on_delete=models.SET_NULL)
@ -52,7 +56,10 @@ class MarketTick(models.Model):
max_digits=4, max_digits=4,
decimal_places=4, decimal_places=4,
default=0, default=0,
validators=[MinValueValidator(0), MaxValueValidator(1)], validators=[
MinValueValidator(Decimal(0)),
MaxValueValidator(Decimal(1))
],
) )
def log_a_tick(order): def log_a_tick(order):

View File

@ -1,3 +1,4 @@
from decimal import Decimal
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator from django.core.validators import MaxValueValidator, MinValueValidator
@ -58,7 +59,10 @@ class OnchainPayment(models.Model):
default=2.05, default=2.05,
null=False, null=False,
blank=False, blank=False,
validators=[MinValueValidator(1), MaxValueValidator(999)], validators=[
MinValueValidator(Decimal(1)),
MaxValueValidator(Decimal(999))
],
) )
mining_fee_rate = models.DecimalField( mining_fee_rate = models.DecimalField(
max_digits=6, max_digits=6,
@ -66,7 +70,10 @@ class OnchainPayment(models.Model):
default=2.05, default=2.05,
null=False, null=False,
blank=False, blank=False,
validators=[MinValueValidator(1), MaxValueValidator(999)], validators=[
MinValueValidator(Decimal(1)),
MaxValueValidator(Decimal(999))
],
) )
mining_fee_sats = models.PositiveBigIntegerField(default=0, null=False, blank=False) mining_fee_sats = models.PositiveBigIntegerField(default=0, null=False, blank=False)

View File

@ -1,6 +1,7 @@
# We use custom seeded UUID generation during testing # We use custom seeded UUID generation during testing
import uuid import uuid
from decimal import Decimal
from decouple import config from decouple import config
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -90,7 +91,10 @@ class Order(models.Model):
decimal_places=2, decimal_places=2,
default=0, default=0,
null=True, null=True,
validators=[MinValueValidator(-100), MaxValueValidator(999)], validators=[
MinValueValidator(Decimal(-100)),
MaxValueValidator(Decimal(999))
],
blank=True, blank=True,
) )
# explicit # explicit
@ -135,8 +139,8 @@ class Order(models.Model):
default=settings.DEFAULT_BOND_SIZE, default=settings.DEFAULT_BOND_SIZE,
null=False, null=False,
validators=[ validators=[
MinValueValidator(settings.MIN_BOND_SIZE), # 2 % MinValueValidator(Decimal(settings.MIN_BOND_SIZE)), # 2 %
MaxValueValidator(settings.MAX_BOND_SIZE), # 15 % MaxValueValidator(Decimal(settings.MAX_BOND_SIZE)), # 15 %
], ],
blank=False, blank=False,
) )
@ -147,8 +151,8 @@ class Order(models.Model):
decimal_places=6, decimal_places=6,
null=True, null=True,
validators=[ validators=[
MinValueValidator(-90), MinValueValidator(Decimal(-90)),
MaxValueValidator(90), MaxValueValidator(Decimal(90)),
], ],
blank=True, blank=True,
) )
@ -157,8 +161,8 @@ class Order(models.Model):
decimal_places=6, decimal_places=6,
null=True, null=True,
validators=[ validators=[
MinValueValidator(-180), MinValueValidator(Decimal(-180)),
MaxValueValidator(180), MaxValueValidator(Decimal(180)),
], ],
blank=True, blank=True,
) )

View File

@ -1,7 +1,7 @@
openapi: 3.0.3 openapi: 3.0.3
info: info:
title: RoboSats REST API title: RoboSats REST API
version: 0.6.0 version: 0.6.2
x-logo: x-logo:
url: https://raw.githubusercontent.com/Reckless-Satoshi/robosats/main/frontend/static/assets/images/robosats-0.1.1-banner.png url: https://raw.githubusercontent.com/Reckless-Satoshi/robosats/main/frontend/static/assets/images/robosats-0.1.1-banner.png
backgroundColor: '#FFFFFF' backgroundColor: '#FFFFFF'

View File

@ -79,7 +79,7 @@
"eslint-plugin-react": "^7.34.0", "eslint-plugin-react": "^7.34.0",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"jest": "^29.6.1", "jest": "^29.6.1",
"prettier": "^3.2.5", "prettier": "^3.3.2",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.4.2", "typescript": "^5.4.2",
"webpack": "^5.89.0", "webpack": "^5.89.0",
@ -15096,9 +15096,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.2.5", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
"dev": true, "dev": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"

View File

@ -41,7 +41,7 @@
"eslint-plugin-react": "^7.34.0", "eslint-plugin-react": "^7.34.0",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"jest": "^29.6.1", "jest": "^29.6.1",
"prettier": "^3.2.5", "prettier": "^3.3.2",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.4.2", "typescript": "^5.4.2",
"webpack": "^5.89.0", "webpack": "^5.89.0",

View File

@ -44,7 +44,7 @@ const RobotPage = (): JSX.Element => {
const token = urlToken ?? garage.currentSlot; const token = urlToken ?? garage.currentSlot;
if (token !== undefined && token !== null && page === 'robot') { if (token !== undefined && token !== null && page === 'robot') {
setInputToken(token); setInputToken(token);
if (window.NativeRobosats === undefined || torStatus === 'ON') { if (window.NativeRobosats === undefined || torStatus === 'ON' || !settings.useProxy) {
getGenerateRobot(token); getGenerateRobot(token);
setView('profile'); setView('profile');
} }
@ -83,7 +83,7 @@ const RobotPage = (): JSX.Element => {
garage.deleteSlot(); garage.deleteSlot();
}; };
if (!(window.NativeRobosats === undefined) && !(torStatus === 'ON')) { if (settings.useProxy && !(window.NativeRobosats === undefined) && !(torStatus === 'ON')) {
return ( return (
<Paper <Paper
elevation={12} elevation={12}

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import useAutocomplete from '@mui/base/useAutocomplete'; import { useAutocomplete } from '@mui/base/useAutocomplete';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import { import {
Button, Button,

View File

@ -90,12 +90,6 @@ const MakerForm = ({
const minRangeAmountMultiple = 1.6; const minRangeAmountMultiple = 1.6;
const amountSafeThresholds = [1.03, 0.98]; const amountSafeThresholds = [1.03, 0.98];
useEffect(() => {
// Why?
// const slot = garage.getSlot();
// if (slot?.token) void federation.fetchRobot(garage, slot?.token);
}, [garage.currentSlot]);
useEffect(() => { useEffect(() => {
setCurrencyCode(currencyDict[fav.currency === 0 ? 1 : fav.currency]); setCurrencyCode(currencyDict[fav.currency === 0 ? 1 : fav.currency]);
}, [coordinatorUpdatedAt]); }, [coordinatorUpdatedAt]);

View File

@ -178,7 +178,7 @@ const OrderDetails = ({
: coordinator.info?.taker_fee ?? 0; : coordinator.info?.taker_fee ?? 0;
const defaultRoutingBudget = 0.001; const defaultRoutingBudget = 0.001;
const btc_now = order.satoshis_now / 100000000; const btc_now = order.satoshis_now / 100000000;
const rate = order.amount > 0 ? order.amount / btc_now : Number(order.max_amount) / btc_now; const rate = Number(order.max_amount ?? order.amount) / btc_now;
if (isBuyer) { if (isBuyer) {
if (order.amount > 0) { if (order.amount > 0) {

View File

@ -1,4 +1,4 @@
import React, { useContext } from 'react'; import React, { useContext, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { type UseAppStoreType, AppContext } from '../../contexts/AppContext'; import { type UseAppStoreType, AppContext } from '../../contexts/AppContext';
import { import {
@ -28,17 +28,19 @@ import {
QrCode, QrCode,
} from '@mui/icons-material'; } from '@mui/icons-material';
import { systemClient } from '../../services/System'; import { systemClient } from '../../services/System';
import { TorIcon } from '../Icons';
import SwapCalls from '@mui/icons-material/SwapCalls'; import SwapCalls from '@mui/icons-material/SwapCalls';
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext'; import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
import { GarageContext, UseGarageStoreType } from '../../contexts/GarageContext';
interface SettingsFormProps { interface SettingsFormProps {
dense?: boolean; dense?: boolean;
} }
const SettingsForm = ({ dense = false }: SettingsFormProps): JSX.Element => { const SettingsForm = ({ dense = false }: SettingsFormProps): JSX.Element => {
const { fav, setFav, origin, hostUrl, settings, setSettings } = const { fav, setFav, settings, setSettings } = useContext<UseAppStoreType>(AppContext);
useContext<UseAppStoreType>(AppContext);
const { federation } = useContext<UseFederationStoreType>(FederationContext); const { federation } = useContext<UseFederationStoreType>(FederationContext);
const { garage } = useContext<UseGarageStoreType>(GarageContext);
const theme = useTheme(); const theme = useTheme();
const { t } = useTranslation(); const { t } = useTranslation();
const fontSizes = [ const fontSizes = [
@ -237,6 +239,29 @@ const SettingsForm = ({ dense = false }: SettingsFormProps): JSX.Element => {
</ToggleButton> </ToggleButton>
</ToggleButtonGroup> </ToggleButtonGroup>
</ListItem> </ListItem>
{window.NativeRobosats !== undefined && (
<ListItem>
<ListItemIcon>
<TorIcon />
</ListItemIcon>
<ToggleButtonGroup
exclusive={true}
value={settings.useProxy}
onChange={(_e, useProxy) => {
setSettings({ ...settings, useProxy });
systemClient.setItem('settings_use_proxy', String(useProxy));
}}
>
<ToggleButton value={true} color='primary'>
{t('Build-in')}
</ToggleButton>
<ToggleButton value={false} color='secondary'>
{t('Disabled')}
</ToggleButton>
</ToggleButtonGroup>
</ListItem>
)}
</List> </List>
</Grid> </Grid>
</Grid> </Grid>

View File

@ -55,10 +55,10 @@ const TorIndicator = ({
}; };
const TorConnectionBadge = (): JSX.Element => { const TorConnectionBadge = (): JSX.Element => {
const { torStatus } = useContext<UseAppStoreType>(AppContext); const { torStatus, settings } = useContext<UseAppStoreType>(AppContext);
const { t } = useTranslation(); const { t } = useTranslation();
if (window?.NativeRobosats == null) { if (window?.NativeRobosats == null || !settings.useProxy) {
return <></>; return <></>;
} }

View File

@ -222,6 +222,7 @@ export const SuccessfulPrompt = ({
takerSummary={order.taker_summary} takerSummary={order.taker_summary}
platformSummary={order.platform_summary} platformSummary={order.platform_summary}
orderId={order.id} orderId={order.id}
coordinatorLongAlias={federation.getCoordinator(order.shortAlias)?.longAlias}
/> />
</Grid> </Grid>
) : ( ) : (

View File

@ -43,6 +43,7 @@ interface Props {
makerHashId: string; makerHashId: string;
takerHashId: string; takerHashId: string;
currencyCode: string; currencyCode: string;
coordinatorLongAlias: string;
makerSummary: TradeRobotSummary; makerSummary: TradeRobotSummary;
takerSummary: TradeRobotSummary; takerSummary: TradeRobotSummary;
platformSummary: TradeCoordinatorSummary; platformSummary: TradeCoordinatorSummary;
@ -54,6 +55,7 @@ const TradeSummary = ({
makerHashId, makerHashId,
takerHashId, takerHashId,
currencyCode, currencyCode,
coordinatorLongAlias,
makerSummary, makerSummary,
takerSummary, takerSummary,
platformSummary, platformSummary,
@ -72,6 +74,7 @@ const TradeSummary = ({
const onClickExport = function (): void { const onClickExport = function (): void {
const summary = { const summary = {
coordinator: coordinatorLongAlias,
order_id: orderId, order_id: orderId,
currency: currencyCode, currency: currencyCode,
maker: makerSummary, maker: makerSummary,

View File

@ -111,12 +111,14 @@ export const FederationContextProvider = ({
}, []); }, []);
useEffect(() => { useEffect(() => {
// On bitcoin network change we reset book, limits and federation info and fetch everything again if (window.NativeRobosats === undefined || torStatus === 'ON' || !settings.useProxy) {
if (window.NativeRobosats === undefined || torStatus === 'ON') {
void federation.updateUrl(origin, settings, hostUrl); void federation.updateUrl(origin, settings, hostUrl);
void federation.update(); void federation.update();
const token = garage.getSlot()?.getRobot()?.token;
if (token) void federation.fetchRobot(garage, token);
} }
}, [settings.network, torStatus]); }, [settings.network, settings.useProxy, torStatus]);
const onOrderReceived = (order: Order): void => { const onOrderReceived = (order: Order): void => {
let newDelay = defaultDelay; let newDelay = defaultDelay;
@ -178,15 +180,6 @@ export const FederationContextProvider = ({
if (page === 'offers') void federation.updateBook(); if (page === 'offers') void federation.updateBook();
}, [page]); }, [page]);
// use effects to fetchRobots on app start and network change
useEffect(() => {
const slot = garage.getSlot();
const robot = slot?.getRobot();
if (robot && garage.currentSlot && slot?.token && robot.encPrivKey && robot.pubKey) {
void federation.fetchRobot(garage, slot.token);
}
}, [settings.network]);
// use effects to fetchRobots on Profile open // use effects to fetchRobots on Profile open
useEffect(() => { useEffect(() => {
const slot = garage.getSlot(); const slot = garage.getSlot();

View File

@ -145,7 +145,7 @@ export class Coordinator {
public loadingInfo: boolean = false; public loadingInfo: boolean = false;
public limits: LimitList = {}; public limits: LimitList = {};
public loadingLimits: boolean = false; public loadingLimits: boolean = false;
public loadingRobot: boolean = true; public loadingRobot: string | null;
updateUrl = (origin: Origin, settings: Settings, hostUrl: string): void => { updateUrl = (origin: Origin, settings: Settings, hostUrl: string): void => {
if (settings.selfhostedClient && this.shortAlias !== 'local') { if (settings.selfhostedClient && this.shortAlias !== 'local') {
@ -185,6 +185,7 @@ export class Coordinator {
if (this.loadingBook) return; if (this.loadingBook) return;
this.loadingBook = true; this.loadingBook = true;
this.book = [];
apiClient apiClient
.get(this.url, `${this.basePath}/api/book/`) .get(this.url, `${this.basePath}/api/book/`)
@ -297,7 +298,7 @@ export class Coordinator {
}; };
fetchRobot = async (garage: Garage, token: string): Promise<Robot | null> => { fetchRobot = async (garage: Garage, token: string): Promise<Robot | null> => {
if (!this.enabled || !token) return null; if (!this.enabled || !token || this.loadingRobot === token) return null;
const robot = garage?.getSlot(token)?.getRobot() ?? null; const robot = garage?.getSlot(token)?.getRobot() ?? null;
const authHeaders = robot?.getAuthHeaders(); const authHeaders = robot?.getAuthHeaders();
@ -308,6 +309,8 @@ export class Coordinator {
if (!hasEnoughEntropy) return null; if (!hasEnoughEntropy) return null;
this.loadingRobot = token;
garage.updateRobot(token, this.shortAlias, { loading: true }); garage.updateRobot(token, this.shortAlias, { loading: true });
const newAttributes = await apiClient const newAttributes = await apiClient
@ -330,7 +333,8 @@ export class Coordinator {
}) })
.catch((e) => { .catch((e) => {
console.log(e); console.log(e);
}); })
.finally(() => (this.loadingRobot = null));
garage.updateRobot(token, this.shortAlias, { garage.updateRobot(token, this.shortAlias, {
...newAttributes, ...newAttributes,

View File

@ -100,7 +100,7 @@ export class Federation {
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length; this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
this.updateEnabledCoordinators(); this.updateEnabledCoordinators();
for (const coor of Object.values(this.coordinators)) { for (const coor of Object.values(this.coordinators)) {
await coor.update(() => { coor.update(() => {
this.exchange.onlineCoordinators = this.exchange.onlineCoordinators + 1; this.exchange.onlineCoordinators = this.exchange.onlineCoordinators + 1;
this.onCoordinatorSaved(); this.onCoordinatorSaved();
}); });
@ -109,10 +109,11 @@ export class Federation {
updateBook = async (): Promise<void> => { updateBook = async (): Promise<void> => {
this.loading = true; this.loading = true;
this.book = [];
this.triggerHook('onCoordinatorUpdate'); this.triggerHook('onCoordinatorUpdate');
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length; this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
for (const coor of Object.values(this.coordinators)) { for (const coor of Object.values(this.coordinators)) {
await coor.updateBook(() => { coor.updateBook(() => {
this.onCoordinatorSaved(); this.onCoordinatorSaved();
}); });
} }

View File

@ -1,5 +1,6 @@
import i18n from '../i18n/Web'; import i18n from '../i18n/Web';
import { systemClient } from '../services/System'; import { systemClient } from '../services/System';
import { apiClient } from '../services/api';
import { getHost } from '../utils'; import { getHost } from '../utils';
export type Language = export type Language =
@ -42,8 +43,13 @@ class BaseSettings {
: i18n.resolvedLanguage.substring(0, 2); : i18n.resolvedLanguage.substring(0, 2);
const networkCookie = systemClient.getItem('settings_network'); const networkCookie = systemClient.getItem('settings_network');
this.network = networkCookie !== '' ? networkCookie : 'mainnet'; this.network = networkCookie && networkCookie !== '' ? networkCookie : 'mainnet';
this.host = getHost(); this.host = getHost();
const useProxy = systemClient.getItem('settings_use_proxy');
this.useProxy = window.NativeRobosats !== undefined && useProxy !== 'false';
apiClient.useProxy = this.useProxy;
} }
public frontend: 'basic' | 'pro' = 'basic'; public frontend: 'basic' | 'pro' = 'basic';
@ -56,6 +62,7 @@ class BaseSettings {
public host?: string; public host?: string;
public unsafeClient: boolean = false; public unsafeClient: boolean = false;
public selfhostedClient: boolean = false; public selfhostedClient: boolean = false;
public useProxy: boolean;
} }
export default BaseSettings; export default BaseSettings;

View File

@ -28,7 +28,7 @@ class SystemNativeClient implements SystemClient {
}; };
public setCookie: (key: string, value: string) => void = (key, value) => { public setCookie: (key: string, value: string) => void = (key, value) => {
delete window.NativeRobosats?.cookies[key]; window.NativeRobosats?.loadCookie({ key, value });
void window.NativeRobosats?.postMessage({ void window.NativeRobosats?.postMessage({
category: 'system', category: 'system',
type: 'setCookie', type: 'setCookie',

View File

@ -1,8 +1,12 @@
import { type ApiClient, type Auth } from '..'; import { type ApiClient, type Auth } from '..';
import { systemClient } from '../../System'; import { systemClient } from '../../System';
import ApiWebClient from '../ApiWebClient';
class ApiNativeClient implements ApiClient { class ApiNativeClient implements ApiClient {
private assetsCache: Record<string, string> = {}; public useProxy = true;
private webClient: ApiClient = new ApiWebClient();
private readonly assetsPromises = new Map<string, Promise<string | undefined>>(); private readonly assetsPromises = new Map<string, Promise<string | undefined>>();
private readonly getHeaders: (auth?: Auth) => HeadersInit = (auth) => { private readonly getHeaders: (auth?: Auth) => HeadersInit = (auth) => {
@ -51,6 +55,7 @@ class ApiNativeClient implements ApiClient {
public delete: (baseUrl: string, path: string, auth?: Auth) => Promise<object | undefined> = public delete: (baseUrl: string, path: string, auth?: Auth) => Promise<object | undefined> =
async (baseUrl, path, auth) => { async (baseUrl, path, auth) => {
if (!this.proxy) this.webClient.delete(baseUrl, path, auth);
return await window.NativeRobosats?.postMessage({ return await window.NativeRobosats?.postMessage({
category: 'http', category: 'http',
type: 'delete', type: 'delete',
@ -66,6 +71,7 @@ class ApiNativeClient implements ApiClient {
body: object, body: object,
auth?: Auth, auth?: Auth,
) => Promise<object | undefined> = async (baseUrl, path, body, auth) => { ) => Promise<object | undefined> = async (baseUrl, path, body, auth) => {
if (!this.proxy) this.webClient.post(baseUrl, path, body, auth);
return await window.NativeRobosats?.postMessage({ return await window.NativeRobosats?.postMessage({
category: 'http', category: 'http',
type: 'post', type: 'post',
@ -81,6 +87,7 @@ class ApiNativeClient implements ApiClient {
path, path,
auth, auth,
) => { ) => {
if (!this.proxy) this.webClient.get(baseUrl, path, auth);
return await window.NativeRobosats?.postMessage({ return await window.NativeRobosats?.postMessage({
category: 'http', category: 'http',
type: 'get', type: 'get',

View File

@ -1,6 +1,8 @@
import { type ApiClient, type Auth } from '..'; import { type ApiClient, type Auth } from '..';
class ApiWebClient implements ApiClient { class ApiWebClient implements ApiClient {
public useProxy = false;
private readonly getHeaders: (auth?: Auth) => HeadersInit = (auth) => { private readonly getHeaders: (auth?: Auth) => HeadersInit = (auth) => {
let headers = { let headers = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View File

@ -7,6 +7,7 @@ export interface Auth {
} }
export interface ApiClient { export interface ApiClient {
useProxy: boolean;
post: (baseUrl: string, path: string, body: object, auth?: Auth) => Promise<object | undefined>; post: (baseUrl: string, path: string, body: object, auth?: Auth) => Promise<object | undefined>;
put: (baseUrl: string, path: string, body: object, auth?: Auth) => Promise<object | undefined>; put: (baseUrl: string, path: string, body: object, auth?: Auth) => Promise<object | undefined>;
get: (baseUrl: string, path: string, auth?: Auth) => Promise<object | undefined>; get: (baseUrl: string, path: string, auth?: Auth) => Promise<object | undefined>;

View File

@ -45,7 +45,6 @@ export default function federationLottery(federation: Federation): string[] {
// federation[shortAlias] = { badges:{ donatesToDevFund }}; // federation[shortAlias] = { badges:{ donatesToDevFund }};
// } // }
// console.log(federation)
// return federation; // return federation;
// } // }
@ -58,5 +57,4 @@ export default function federationLottery(federation: Federation): string[] {
// results.push(rankedCoordinators); // results.push(rankedCoordinators);
// } // }
// console.log(results)
// } // }

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "La teva última ordre #{{orderID}}", "Your last order #{{orderID}}": "La teva última ordre #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Fosc", "Dark": "Fosc",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Clar", "Light": "Clar",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Tvá poslední nabídka #{{orderID}}", "Your last order #{{orderID}}": "Tvá poslední nabídka #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Dark", "Dark": "Dark",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Light", "Light": "Light",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Deine letzte Order #{{orderID}}", "Your last order #{{orderID}}": "Deine letzte Order #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Dark", "Dark": "Dark",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Light", "Light": "Light",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Your last order #{{orderID}}", "Your last order #{{orderID}}": "Your last order #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Dark", "Dark": "Dark",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Light", "Light": "Light",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Tu última orden #{{orderID}}", "Your last order #{{orderID}}": "Tu última orden #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Oscuro", "Dark": "Oscuro",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Claro", "Light": "Claro",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Zure azken eskaera #{{orderID}}", "Your last order #{{orderID}}": "Zure azken eskaera #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Dark", "Dark": "Dark",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Light", "Light": "Light",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Votre dernière commande #{{orderID}}", "Your last order #{{orderID}}": "Votre dernière commande #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Sombre", "Dark": "Sombre",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Light", "Light": "Light",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Il tuo ultimo ordine #{{orderID}}", "Your last order #{{orderID}}": "Il tuo ultimo ordine #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Scuro", "Dark": "Scuro",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Chiaro", "Light": "Chiaro",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "前回のオーダー #{{orderID}}", "Your last order #{{orderID}}": "前回のオーダー #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "ダーク", "Dark": "ダーク",
"Disabled": "Disabled",
"Fiat": "フィアット", "Fiat": "フィアット",
"Light": "ライト", "Light": "ライト",
"Mainnet": "メインネット", "Mainnet": "メインネット",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Your last order #{{orderID}}", "Your last order #{{orderID}}": "Your last order #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Dark", "Dark": "Dark",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Light", "Light": "Light",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Sua última ordem #{{orderID}}", "Your last order #{{orderID}}": "Sua última ordem #{{orderID}}",
"finished order": "ordem finalizada", "finished order": "ordem finalizada",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Dark", "Dark": "Dark",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Light", "Light": "Light",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Ваш последний ордер #{{orderID}}", "Your last order #{{orderID}}": "Ваш последний ордер #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Темный", "Dark": "Темный",
"Disabled": "Disabled",
"Fiat": "Фиат", "Fiat": "Фиат",
"Light": "Светлый", "Light": "Светлый",
"Mainnet": "Основная сеть", "Mainnet": "Основная сеть",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Din senaste order #{{orderID}}", "Your last order #{{orderID}}": "Din senaste order #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Dark", "Dark": "Dark",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Light", "Light": "Light",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "Amri yako ya mwisho #{{orderID}}", "Your last order #{{orderID}}": "Amri yako ya mwisho #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Giza", "Dark": "Giza",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Nuru", "Light": "Nuru",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "รายการล่าสุดของคุณ #{{orderID}}", "Your last order #{{orderID}}": "รายการล่าสุดของคุณ #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "Dark", "Dark": "Dark",
"Disabled": "Disabled",
"Fiat": "Fiat", "Fiat": "Fiat",
"Light": "Light", "Light": "Light",
"Mainnet": "Mainnet", "Mainnet": "Mainnet",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "你的上一笔交易 #{{orderID}}", "Your last order #{{orderID}}": "你的上一笔交易 #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "深色", "Dark": "深色",
"Disabled": "Disabled",
"Fiat": "法币", "Fiat": "法币",
"Light": "浅色", "Light": "浅色",
"Mainnet": "主网", "Mainnet": "主网",

View File

@ -489,7 +489,9 @@
"Your last order #{{orderID}}": "你的上一筆交易 #{{orderID}}", "Your last order #{{orderID}}": "你的上一筆交易 #{{orderID}}",
"finished order": "finished order", "finished order": "finished order",
"#43": "Phrases in components/SettingsForm/index.tsx", "#43": "Phrases in components/SettingsForm/index.tsx",
"Build-in": "Build-in",
"Dark": "深色", "Dark": "深色",
"Disabled": "Disabled",
"Fiat": "法幣", "Fiat": "法幣",
"Light": "淺色", "Light": "淺色",
"Mainnet": "主網", "Mainnet": "主網",

View File

@ -71,6 +71,7 @@ const App = () => {
loadCookie('settings_mode'); loadCookie('settings_mode');
loadCookie('settings_light_qr'); loadCookie('settings_light_qr');
loadCookie('settings_network'); loadCookie('settings_network');
loadCookie('settings_use_proxy');
loadCookie('garage_slots').then(() => injectMessageResolve(responseId)); loadCookie('garage_slots').then(() => injectMessageResolve(responseId));
}; };

View File

@ -6,7 +6,7 @@
"packages": { "packages": {
"": { "": {
"name": "robosats", "name": "robosats",
"version": "0.6.1", "version": "0.6.2",
"dependencies": { "dependencies": {
"@react-native-clipboard/clipboard": "^1.13.2", "@react-native-clipboard/clipboard": "^1.13.2",
"@react-native-community/netinfo": "^11.3.0", "@react-native-community/netinfo": "^11.3.0",
@ -37,7 +37,7 @@
"eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-hooks": "^4.6.2",
"jest": "^29.7.0", "jest": "^29.7.0",
"metro-react-native-babel-preset": "^0.75.1", "metro-react-native-babel-preset": "^0.75.1",
"prettier": "^3.2.5", "prettier": "^3.3.2",
"react-test-renderer": "18.2.0", "react-test-renderer": "18.2.0",
"typescript": "^5.4.5" "typescript": "^5.4.5"
} }
@ -12714,9 +12714,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.2.5", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
"dev": true, "dev": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"

View File

@ -41,7 +41,7 @@
"eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-hooks": "^4.6.2",
"jest": "^29.7.0", "jest": "^29.7.0",
"metro-react-native-babel-preset": "^0.75.1", "metro-react-native-babel-preset": "^0.75.1",
"prettier": "^3.2.5", "prettier": "^3.3.2",
"react-test-renderer": "18.2.0", "react-test-renderer": "18.2.0",
"typescript": "^5.4.5" "typescript": "^5.4.5"
}, },

7
tests/README.md Normal file
View File

@ -0,0 +1,7 @@
# Run e2e tests
```
docker compose -f docker-tests.yml --env-file tests/compose.env up -d
docker exec coordinator coverage run manage.py test
docker exec coordinator coverage report
```

File diff suppressed because it is too large Load Diff