Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable RPC #75

Merged
merged 13 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/breezy-mangos-retire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fireblocks/recovery-utility': patch
---

Fix typo
5 changes: 5 additions & 0 deletions .changeset/chilly-paws-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fireblocks/e2e-tests': patch
---

Added support for testing configurable rpc
5 changes: 5 additions & 0 deletions .changeset/funny-badgers-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fireblocks/e2e-tests': minor
---

Created more descriptive error types
5 changes: 5 additions & 0 deletions .changeset/hungry-ears-repair.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fireblocks/asset-config': minor
---

Fixed standard explorer URL and disabled EOS, XDB and XEC asset transfer
7 changes: 7 additions & 0 deletions .changeset/late-months-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@fireblocks/recovery-shared': minor
'@fireblocks/recovery-utility': patch
'@fireblocks/recovery-relay': patch
---

Updated settings schema for configurable RPC
5 changes: 5 additions & 0 deletions .changeset/pretty-tools-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fireblocks/asset-config': patch
---

Fixed address validation for TRX & ADA_TEST
5 changes: 5 additions & 0 deletions .changeset/silent-colts-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fireblocks/e2e-tests': patch
---

Added support for configurable rpc test and error types
5 changes: 5 additions & 0 deletions .changeset/strong-pumas-fly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fireblocks/recovery-relay': minor
---

Added default RPC URLs
5 changes: 5 additions & 0 deletions .changeset/sweet-pumas-float.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fireblocks/e2e-tests': patch
---

Updated possible test assets
5 changes: 5 additions & 0 deletions .changeset/tame-boats-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fireblocks/e2e-tests': patch
---

Updated launch timeout
6 changes: 6 additions & 0 deletions .changeset/ten-cups-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@fireblocks/wallet-derivation': minor
'@fireblocks/recovery-utility': minor
---

Fixed ETC withdrawal
5 changes: 5 additions & 0 deletions .changeset/ten-fans-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fireblocks/recovery-relay': patch
---

Updated relay UI for configurable RPC
5 changes: 5 additions & 0 deletions .changeset/tidy-shirts-mix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fireblocks/recovery-relay': patch
---

Updated wallets to use configurable RPCs
5 changes: 5 additions & 0 deletions apps/recovery-relay/components/Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ export const Layout = ({ children }: Props) => {
icon: ImportExport,
disabled: !hasExtendedPublicKeys,
},
{
label: 'Settings',
path: '/settings',
icon: Settings,
},
// {
// label: 'Settings',
// path: '/settings',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,77 @@ import {
sanatize,
useOfflineQuery,
} from '@fireblocks/recovery-shared';
import { AssetConfig } from '@fireblocks/asset-config';
import { AssetConfig, getAssetConfig, isNativeAssetId } from '@fireblocks/asset-config';
import { LOGGER_NAME_RELAY } from '@fireblocks/recovery-shared/constants';
import { useWorkspace } from '../../../context/Workspace';
import { Derivation, AccountData } from '../../../lib/wallets';
import { LateInitConnectedWallet } from '../../../lib/wallets/LateInitConnectedWallet';
import { useSettings } from '../../../context/Settings';

const logger = getLogger(LOGGER_NAME_RELAY);

const getRPCKey = (
assetId: string,
RPCs: Record<
string,
{
enabled: boolean;
allowedEmptyValue: boolean;
name: string;
url?: string | null | undefined;
}
>,
): string | undefined => {
if (assetId === '') {
return undefined;
}
let baseAsset = assetId;
if (!isNativeAssetId(baseAsset)) {
const assetConfig = getAssetConfig(baseAsset);
if (assetConfig === undefined) {
logger.error(`Unknown asset: ${baseAsset}`);
return undefined;
}
baseAsset = assetConfig.nativeAsset;
}
if (!Object.keys(RPCs).includes(baseAsset)) {
logger.error(`Unknown base asset Id: ${baseAsset}`);
return undefined;
}
return baseAsset;
};

export const getAssetURL = (
assetId: string,
RPCs: Record<
string,
{
enabled: boolean;
allowedEmptyValue: boolean;
name: string;
url?: string | null | undefined;
}
>,
): string | null | undefined => {
const rpcKey = getRPCKey(assetId, RPCs);
if (rpcKey === undefined) {
return undefined;
}

const assetRPCData = RPCs[rpcKey];
const { url } = assetRPCData;
logger.info(`RPC URL for ${rpcKey} is ${assetRPCData.enabled ? 'enabled' : 'disabled'} and is ${url}`);

if (assetRPCData.allowedEmptyValue && (url === null || url === undefined)) {
return null;
}
if (!assetRPCData.enabled) {
// If not enabled we shouldn't be getting a request to the relay for it regardless.
return undefined;
}
return url;
};

const getWallet = (accounts: Map<number, VaultAccount<Derivation>>, accountId?: number, assetId?: string) => {
if (typeof accountId === 'undefined' || typeof assetId === 'undefined') {
return undefined;
Expand Down Expand Up @@ -54,6 +117,7 @@ type Props = {

export const CreateTransaction = ({ asset, inboundRelayParams, setSignTxResponseUrl }: Props) => {
const { accounts } = useWorkspace();
const { saveSettings, RPCs } = useSettings();

const { accountId } = inboundRelayParams;
const { id: txId, to: toAddress } = inboundRelayParams.newTx;
Expand Down Expand Up @@ -87,15 +151,6 @@ export const CreateTransaction = ({ asset, inboundRelayParams, setSignTxResponse

const derivation = wallet?.derivations?.get(fromAddress);

// const balanceQueryKey = ['balance', accountId, asset?.id, fromAddress];

// const balanceQuery = useOfflineQuery({
// queryKey: balanceQueryKey,
// enabled: !!derivation,
// queryFn: async () => derivation!.getBalance?.(),
// onError: (err: Error) => console.error('Failed to query balance', err),
// });

// TODO: Show both original balance and adjusted balance in create tx UI

const prepareQueryKey = ['prepare', fromAddress, values.memo];
Expand All @@ -105,6 +160,12 @@ export const CreateTransaction = ({ asset, inboundRelayParams, setSignTxResponse
enabled: !!derivation,
queryFn: async () => {
logger.debug(`Querying prepare transaction ${toAddress}`);
const rpcUrl = getAssetURL(derivation?.assetId ?? '', RPCs);
if (rpcUrl === undefined) {
logger.error(`Unknown URL for ${derivation?.assetId ?? '<empty>'}`);
throw new Error(`No RPC Url for: ${derivation?.assetId}`);
}
if (rpcUrl !== null) derivation!.setRPCUrl(rpcUrl);
return await derivation!.prepare?.(toAddress, values.memo);
},
onSuccess: (prepare: AccountData) => {
Expand Down Expand Up @@ -288,7 +349,14 @@ export const CreateTransaction = ({ asset, inboundRelayParams, setSignTxResponse
id='endpoint'
label={(derivation as LateInitConnectedWallet).getLateInitLabel()}
onChange={async (e) => {
(derivation as LateInitConnectedWallet).updateDataEndpoint(e.target.value as string);
const url = e.target.value as string;
(derivation as LateInitConnectedWallet).updateDataEndpoint(url);
const rpcKey = getRPCKey(derivation.assetId ?? '', RPCs);
if (rpcKey !== undefined && !rpcKey.includes('HBAR')) {
RPCs[rpcKey].url = url;
await saveSettings({ RPCs });
}

await prepareQuery.refetch();
}}
/>
Expand Down
15 changes: 12 additions & 3 deletions apps/recovery-relay/components/WithdrawModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import { getDerivableAssetConfig } from '@fireblocks/asset-config';
import { LOGGER_NAME_RELAY } from '@fireblocks/recovery-shared/constants';
import { sanatize } from '@fireblocks/recovery-shared/lib/sanatize';
import { useWorkspace } from '../../context/Workspace';
import { CreateTransaction } from './CreateTransaction';
import { CreateTransaction, getAssetURL } from './CreateTransaction';
import { LateInitConnectedWallet } from '../../lib/wallets/LateInitConnectedWallet';
import { useSettings } from '../../context/Settings';

const logger = getLogger(LOGGER_NAME_RELAY);

Expand All @@ -40,6 +41,7 @@ const getAssetId = (inboundRelayParams?: RelayRequestParams) => {

export const WithdrawModal = () => {
const { accounts, inboundRelayParams, getOutboundRelayUrl, setInboundRelayUrl, resetInboundRelayUrl } = useWorkspace();
const { RPCs } = useSettings();

const action = inboundRelayParams?.action;

Expand Down Expand Up @@ -127,8 +129,15 @@ export const WithdrawModal = () => {

const derivation = wallet?.derivations?.get(inboundRelayParams?.signedTx.from);

if (derivation?.isLateInit()) {
(derivation as LateInitConnectedWallet).updateDataEndpoint(inboundRelayParams.endpoint!);
const rpcUrl = getAssetURL(derivation?.assetId ?? '', RPCs);
if (rpcUrl === undefined) {
throw new Error(`No RPC URL for asset ${derivation?.assetId}`);
} else if (rpcUrl === null) {
if (derivation?.isLateInit()) {
(derivation as LateInitConnectedWallet).updateDataEndpoint(inboundRelayParams.endpoint!);
}
} else {
derivation?.setRPCUrl(rpcUrl);
}

const signedTxHex = inboundRelayParams?.signedTx.hex;
Expand Down
26 changes: 8 additions & 18 deletions apps/recovery-relay/context/Settings.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
import { getLogger, useWrappedState } from '@fireblocks/recovery-shared';
import { getLogger, RelaySettingsInput, settingsInput, useWrappedState } from '@fireblocks/recovery-shared';
import { LOGGER_NAME_RELAY } from '@fireblocks/recovery-shared/constants';
import { createContext, useContext, useEffect, ReactNode } from 'react';
import { z } from 'zod';
import { defaultRPCs } from '../lib/defaultRPCs';

export const settingsInput = z.object({
rpcURLs: z.array(
z.object({
assetId: z.string(),
rpcURL: z.string(),
}),
),
});
export type SettingsInput = z.infer<(typeof settingsInput)['RELAY']>;

export type SettingsInput = z.infer<typeof settingsInput>;

type Settings = z.infer<typeof settingsInput>;

interface ISettingsContext extends Settings {
saveSettings: (settings: Settings) => Promise<void>;
interface ISettingsContext extends RelaySettingsInput {
saveSettings: (settings: RelaySettingsInput) => Promise<void>;
}

const defaultValue: ISettingsContext = {
rpcURLs: [],
saveSettings: async () => undefined,
RPCs: defaultRPCs,
};

const logger = getLogger(LOGGER_NAME_RELAY);
Expand All @@ -36,7 +26,7 @@ type Props = {
};

export const SettingsProvider = ({ children }: Props) => {
const [settings, setSettings] = useWrappedState<Settings>('relay-settings', defaultValue);
const [settings, setSettings] = useWrappedState<RelaySettingsInput>('relay-settings', defaultValue);

useEffect(() => {
const storedSettings = window.localStorage.getItem('settings');
Expand All @@ -46,7 +36,7 @@ export const SettingsProvider = ({ children }: Props) => {
}
}, []);

const saveSettings = async (data: Settings) => {
const saveSettings = async (data: RelaySettingsInput) => {
logger.info('Storing new settings', data);
window.localStorage.setItem('settings', JSON.stringify(data));
};
Expand Down
Loading