Skip to content

Commit

Permalink
Fix: exchange rate cors (#212)
Browse files Browse the repository at this point in the history
  • Loading branch information
rickimoore committed Aug 25, 2023
1 parent cab5283 commit 290bdb6
Show file tree
Hide file tree
Showing 17 changed files with 104 additions and 44 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/main.js
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"main": "src/main.ts",
"main": "src/main.js",
"description": "Electron Forge & Create React App Template",
"license": "APACHE2",
"author": "Sigma Prime",
Expand Down
7 changes: 3 additions & 4 deletions src/components/AccountEarnings/AccountEarning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ import { EARNINGS_OPTIONS } from '../../constants/constants'
import { formatLocalCurrency } from '../../utilities/formatLocalCurrency'
import Spinner from '../Spinner/Spinner'
import { useRecoilValue } from 'recoil'
import { selectEthExchangeRates } from '../../recoil/selectors/selectEthExchangeRates'
import EarningsLayout from './EarningsLayout'
import { selectCurrencyPrefix } from '../../recoil/selectors/selectCurrencyPrefix'
import { activeCurrency } from '../../recoil/atoms'
import { activeCurrency, exchangeRates } from '../../recoil/atoms'
import CurrencySelect from '../CurrencySelect/CurrencySelect'
import useEarningsEstimate from '../../hooks/useEarningsEstimate'
import Tooltip from '../ToolTip/Tooltip'
Expand All @@ -30,11 +29,11 @@ const AccountEarning = () => {
const currency = useRecoilValue(activeCurrency)
const { estimate, totalEarnings, estimateSelection, selectEstimate } = useEarningsEstimate()
const { formattedPrefix } = useRecoilValue(selectCurrencyPrefix)
const { rates } = useRecoilValue(selectEthExchangeRates)
const data = useRecoilValue(exchangeRates)

const { estimatedApr, textColor } = useEpochAprEstimate()

const activeRate = rates[currency]
const activeRate = data?.rates[currency]
const formattedRate = activeRate ? Number(activeRate) : 0
const totalBalance = formattedRate * totalEarnings
const estimatedRateConversion = formattedRate * estimate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import ValidatorIncomeSummary from '../ValidatorIncomeSummary/ValidatorIncomeSum
import { ValidatorInfo } from '../../types/validator'
import { FC } from 'react'
import { useRecoilValue } from 'recoil'
import { selectEthExchangeRates } from '../../recoil/selectors/selectEthExchangeRates'
import { useTranslation } from 'react-i18next'
import { exchangeRates } from '../../recoil/atoms'

export interface BasicValidatorMetricsProps {
validator: ValidatorInfo
}

const BasicValidatorMetrics: FC<BasicValidatorMetricsProps> = ({ validator }) => {
const { t } = useTranslation()
const { rates } = useRecoilValue(selectEthExchangeRates)
const activeRate = rates.USD
const data = useRecoilValue(exchangeRates)
const activeRate = data?.rates.USD
const { balance } = validator

return (
Expand Down
2 changes: 1 addition & 1 deletion src/components/CurrencySelect/CurrencySelect.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const mockSetState = jest.fn()

describe('Currency select component', () => {
beforeEach(() => {
mockedRecoilValue.mockReturnValue({ rates: '', currencies: mockCurrencies })
mockedRecoilValue.mockReturnValue({ rates: {}, currencies: mockCurrencies })
})
it('should render correct list', () => {
mockedRecoilState.mockReturnValue(['', mockSetState])
Expand Down
15 changes: 8 additions & 7 deletions src/components/CurrencySelect/CurrencySelect.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { CURRENCIES } from '../../constants/constants'
import { useRecoilState, useRecoilValue } from 'recoil'
import { selectEthExchangeRates } from '../../recoil/selectors/selectEthExchangeRates'
import SelectDropDown, { OptionType } from '../SelectDropDown/SelectDropDown'
import { useTranslation } from 'react-i18next'
import { activeCurrency } from '../../recoil/atoms'
import { activeCurrency, exchangeRates } from '../../recoil/atoms'
import useLocalStorage from '../../hooks/useLocalStorage'
import { ActiveCurrencyStorage } from '../../types/storage'
import { Storage } from '../../constants/enums'

const CurrencySelect = () => {
const { t } = useTranslation()
const { currencies } = useRecoilValue(selectEthExchangeRates)
const data = useRecoilValue(exchangeRates)
const [currency, setCurrency] = useRecoilState(activeCurrency)
const [, storeActiveCurrency] = useLocalStorage<ActiveCurrencyStorage>(
Storage.CURRENCY,
Expand All @@ -22,10 +21,12 @@ const CurrencySelect = () => {
setCurrency(option as string)
}

const currencyOptions = [...currencies]
.filter((currency) => CURRENCIES.includes(currency))
.sort()
.map((currency) => ({ title: currency }))
const currencyOptions = data
? [...data.currencies]
.filter((currency) => CURRENCIES.includes(currency))
.sort()
.map((currency) => ({ title: currency }))
: []

return (
<SelectDropDown
Expand Down
2 changes: 1 addition & 1 deletion src/components/SelectDropDown/SelectDropDown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const SelectDropDown: FC<SelectDropDownProps> = ({
return options.filter((option) => {
const { value, title } = option
const isValue = value?.toLocaleString().toLowerCase().includes(formattedQuery)
const isTitle = title.toLowerCase().includes(formattedQuery)
const isTitle = title?.toLowerCase().includes(formattedQuery)
const isExcluded = value === activeSelection?.value
return !(isExcluded && excludeSelection) && (isTitle || isValue || !query)
})
Expand Down
7 changes: 3 additions & 4 deletions src/components/ValidatorModal/views/ValidatorDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useRecoilValue } from 'recoil'
import { processingBlsValidators } from '../../../recoil/atoms'
import { exchangeRates, processingBlsValidators } from '../../../recoil/atoms'
import { selectValidatorDetail } from '../../../recoil/selectors/selectValidatorDetails'
import Typography from '../../Typography/Typography'
import { selectEthExchangeRates } from '../../../recoil/selectors/selectEthExchangeRates'
import { formatLocalCurrency } from '../../../utilities/formatLocalCurrency'
import Status from '../../Status/Status'
import { useTranslation } from 'react-i18next'
Expand All @@ -27,7 +26,7 @@ const ValidatorDetails = () => {
const validator = useRecoilValue(selectValidatorDetail)
const processingValidators = useRecoilValue(processingBlsValidators)
const { index, balance, status, withdrawalAddress } = validator || {}
const { rates } = useRecoilValue(selectEthExchangeRates)
const data = useRecoilValue(exchangeRates)
const { avgTargetEffectiveness, avgHitEffectiveness } = useValidatorEffectiveness([String(index)])

const isProcessing = Boolean(
Expand All @@ -46,7 +45,7 @@ const ValidatorDetails = () => {

const { isLoading, graffiti, updateGraffiti } = useValidatorGraffiti(validator)

const usdBalance = (balance || 0) * (rates['USD'] || 0)
const usdBalance = (balance || 0) * (data?.rates['USD'] || 0)

return validator ? (
<div className='w-full relative'>
Expand Down
1 change: 1 addition & 0 deletions src/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export const SigPGithubUrl = 'https://github.com/sigp'
export const SigPTwitter = 'https://twitter.com/sigp_io'
export const SigPIoUrl = 'https://sigmaprime.io/'
export const WithdrawalInfoLink = 'https://launchpad.ethereum.org/en/withdrawals'
export const CoinbaseExchangeRateUrl = 'https://api.coinbase.com/v2/exchange-rates?currency=ETH'

export const DEFAULT_VALIDATOR_COUNT = {
active_exiting: 0,
Expand Down
31 changes: 31 additions & 0 deletions src/hooks/useExchangeRatePolling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useSetRecoilState } from 'recoil'
import { exchangeRates } from '../recoil/atoms'
import usePollApi from './usePollApi'
import { PollingOptions } from '../types'
import { CoinbaseExchangeRateUrl } from '../constants/constants'
import { useEffect } from 'react'

const useExchangeRatePolling = (options?: PollingOptions) => {
const { time = 60 * 1000, isReady = true } = options || {}

const setExchangeRate = useSetRecoilState(exchangeRates)

const { data } = usePollApi({
key: 'exchangeRate',
time,
isReady,
url: CoinbaseExchangeRateUrl,
})

useEffect(() => {
if (data) {
const rates = data.data.rates
setExchangeRate({
rates,
currencies: Object.keys(rates),
})
}
}, [data])
}

export default useExchangeRatePolling
2 changes: 1 addition & 1 deletion src/locales/translations/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"confirmPassword": "Confirm Password",
"helloUser": "Hello {{user}},",
"lighthouseVersion": "Lighthouse Version",
"lighthouseUiVersion": "Lighthouse UI Version",
"lighthouseUiVersion": "Siren Version",
"sessionAuth": "Session Auth",
"configure": "Configure",
"continue": "Continue",
Expand Down
37 changes: 31 additions & 6 deletions src/main.ts → src/main.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,48 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { app, BrowserWindow } = require('electron')
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path')
// eslint-disable-next-line @typescript-eslint/no-var-requires
const url = require('url')
// eslint-disable-next-line @typescript-eslint/no-var-requires
const isDev = require('electron-is-dev')

const createWindow = () => {
function UpsertKeyValue(obj, keyToChange, value) {
const keyToChangeLower = keyToChange.toLowerCase()
for (const key of Object.keys(obj)) {
if (key.toLowerCase() === keyToChangeLower) {
// Reassign old key
obj[key] = value
// Done
return
}
}
// Insert at end instead
obj[keyToChange] = value
}

// Create the browser window.
const mainWindow = new BrowserWindow({
icon: './assets/images/sigma.png',
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
// webSecurity: false
},
})

mainWindow.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => {
const { requestHeaders } = details
UpsertKeyValue(requestHeaders, 'Access-Control-Allow-Origin', ['*'])
callback({ requestHeaders })
})

mainWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => {
const { responseHeaders } = details
UpsertKeyValue(responseHeaders, 'Access-Control-Allow-Origin', ['*'])
UpsertKeyValue(responseHeaders, 'Access-Control-Allow-Headers', ['*'])
callback({
responseHeaders,
})
})

mainWindow.maximize()

// and load the index.html of the app.
Expand Down
7 changes: 6 additions & 1 deletion src/recoil/atoms.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { atom } from 'recoil'
import { AppView, ContentView, OnboardView, SetupSteps, UiMode } from '../constants/enums'
import { ActiveDevice, AlertMessage, DeviceList, ValAliases } from '../types'
import { ActiveDevice, AlertMessage, DeviceList, EthExchangeRates, ValAliases } from '../types'
import { BeaconSyncResult, HealthDiagnosticResult, ValidatorSyncResult } from '../types/diagnostic'
import { BeaconValidatorResult, ValidatorCache } from '../types/validator'
import { BeaconValidatorMetricResults } from '../types/beacon'
Expand Down Expand Up @@ -85,6 +85,11 @@ export const validatorPeerCount = atom<number | undefined>({
default: undefined,
})

export const exchangeRates = atom<EthExchangeRates | undefined>({
key: 'exchangeRates',
default: undefined,
})

export const activeCurrency = atom<string>({
key: 'activeCurrency',
default: undefined,
Expand Down
15 changes: 0 additions & 15 deletions src/recoil/selectors/selectEthExchangeRates.ts

This file was deleted.

9 changes: 9 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,12 @@ export enum ToastType {
ERROR = 'error',
SUCCESS = 'success',
}

export type Rates = {
[currency: string]: number
}

export type EthExchangeRates = {
rates: Rates
currencies: string[]
}
2 changes: 2 additions & 0 deletions src/wrappers/MainPollingWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import useValidatorCachePolling from '../hooks/useValidatorCachePolling'
import { FC, ReactElement, useEffect, useState } from 'react'
import { useRecoilValue } from 'recoil'
import { beaconNetworkError, validatorNetworkError } from '../recoil/atoms'
import useExchangeRatePolling from '../hooks/useExchangeRatePolling'

export interface MainPollingWrapperProps {
children: ReactElement | ReactElement[]
Expand All @@ -16,6 +17,7 @@ const MainPollingWrapper: FC<MainPollingWrapperProps> = ({ children }) => {
const isBnModal = useRecoilValue(beaconNetworkError)
const isVcModal = useRecoilValue(validatorNetworkError)

useExchangeRatePolling({ isReady })
useValidatorInfoPolling({ isReady: isReady && !isBnModal })
useValidatorHealthPolling({ isReady: isReady && !isVcModal })
useBeaconHealthPolling({ isReady: isReady && !isBnModal })
Expand Down
2 changes: 2 additions & 0 deletions src/wrappers/ValidatorPollingWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import useValidatorMetrics from '../hooks/useValidatorMetrics'
import { FC, ReactElement, useEffect, useState } from 'react'
import { useRecoilValue } from 'recoil'
import { beaconNetworkError } from '../recoil/atoms'
import useExchangeRatePolling from '../hooks/useExchangeRatePolling'

export interface ValidatorPollingWrapperProps {
children: ReactElement | ReactElement[]
Expand All @@ -13,6 +14,7 @@ const ValidatorPollingWrapper: FC<ValidatorPollingWrapperProps> = ({ children })
const [isReady, setReady] = useState(false)
const isBn = useRecoilValue(beaconNetworkError)

useExchangeRatePolling({ isReady })
useValidatorInfoPolling({ isReady: isReady && !isBn })
useValidatorCachePolling({ isReady: isReady && !isBn })
useValidatorMetrics()
Expand Down

0 comments on commit 290bdb6

Please sign in to comment.