Add oracle rates
This commit is contained in:
@@ -17,6 +17,7 @@ import { useNavigation } from '../../hooks/useNavigation.js';
|
||||
import { useAppContext, useStatus } from '../../hooks/useAppContext.js';
|
||||
import { useBlockableInput, useIsInputCaptured } from '../../hooks/useInputLayer.js';
|
||||
import { useInvitations } from '../../hooks/useInvitations.js';
|
||||
import { useSatoshisConversion } from '../../hooks/useSatoshisConversion.js';
|
||||
import { colors, logoSmall, formatSatoshis } from '../../theme.js';
|
||||
import { copyToClipboard } from '../../utils/clipboard.js';
|
||||
import type { Invitation } from '../../../services/invitation.js';
|
||||
@@ -88,6 +89,8 @@ export function InvitationScreen(): React.ReactElement {
|
||||
const { setStatus } = useStatus();
|
||||
|
||||
const invitations = useInvitations();
|
||||
const { currencyCode, formattedFiatPerBchRate, formatSatoshisToFiat } =
|
||||
useSatoshisConversion('USD');
|
||||
|
||||
// ── UI state ─────────────────────────────────────────────────────────────
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
@@ -494,6 +497,44 @@ export function InvitationScreen(): React.ReactElement {
|
||||
const roleInfoRaw = userRole && selectedTemplate?.roles?.[userRole];
|
||||
const roleInfo = roleInfoRaw && typeof roleInfoRaw === 'object' ? roleInfoRaw : null;
|
||||
|
||||
const getFiatSuffix = (satoshis: bigint): string => {
|
||||
const fiatValue = formatSatoshisToFiat(satoshis);
|
||||
return fiatValue ? ` (~${fiatValue})` : '';
|
||||
};
|
||||
|
||||
const parseNumberishToBigInt = (value: unknown): bigint | null => {
|
||||
if (typeof value === 'bigint') {
|
||||
return value;
|
||||
}
|
||||
|
||||
const asString = String(value).trim();
|
||||
if (!/^[-]?\d+$/.test(asString)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return BigInt(asString);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const isSatoshisVariable = (variableIdentifier: string): boolean => {
|
||||
const templateVariable = selectedTemplate?.variables?.[variableIdentifier];
|
||||
const templateType = templateVariable?.type?.toLowerCase();
|
||||
const templateHint = templateVariable?.hint?.toLowerCase();
|
||||
const identifier = variableIdentifier.toLowerCase();
|
||||
|
||||
if (templateHint?.includes('satoshi')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (
|
||||
templateType === 'integer' &&
|
||||
(identifier.includes('satoshi') || identifier.includes('amount'))
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box flexDirection="column">
|
||||
{/* Type & Status */}
|
||||
@@ -514,6 +555,11 @@ export function InvitationScreen(): React.ReactElement {
|
||||
<Text color={colors.textMuted}>
|
||||
Action: {action?.name ?? selectedInvitation.data.actionIdentifier}
|
||||
</Text>
|
||||
{formattedFiatPerBchRate && (
|
||||
<Text color={colors.textMuted}>
|
||||
1 BCH = {formattedFiatPerBchRate}
|
||||
</Text>
|
||||
)}
|
||||
{action?.description && (
|
||||
<Text color={colors.textMuted} dimColor>{action.description}</Text>
|
||||
)}
|
||||
@@ -542,6 +588,11 @@ export function InvitationScreen(): React.ReactElement {
|
||||
inputs.map((input, idx) => {
|
||||
const isUserInput = input.entityIdentifier === userEntityId;
|
||||
const inputTemplate = selectedTemplate?.inputs?.[input.inputIdentifier ?? ''];
|
||||
const inputSatoshis = (
|
||||
'valueSatoshis' in input && input.valueSatoshis !== undefined
|
||||
)
|
||||
? parseNumberishToBigInt(input.valueSatoshis)
|
||||
: null;
|
||||
return (
|
||||
<Text
|
||||
key={`input-${idx}`}
|
||||
@@ -550,6 +601,7 @@ export function InvitationScreen(): React.ReactElement {
|
||||
{' '}{isUserInput ? '• ' : '○ '}
|
||||
{inputTemplate?.name ?? input.inputIdentifier ?? `Input ${idx}`}
|
||||
{input.roleIdentifier && ` (${input.roleIdentifier})`}
|
||||
{inputSatoshis !== null && ` ${formatSatoshis(inputSatoshis)}${getFiatSuffix(inputSatoshis)}`}
|
||||
</Text>
|
||||
);
|
||||
})
|
||||
@@ -564,6 +616,9 @@ export function InvitationScreen(): React.ReactElement {
|
||||
outputs.map((output, idx) => {
|
||||
const isUserOutput = output.entityIdentifier === userEntityId;
|
||||
const outputTemplate = selectedTemplate?.outputs?.[output.outputIdentifier ?? ''];
|
||||
const outputSatoshis = output.valueSatoshis !== undefined
|
||||
? parseNumberishToBigInt(output.valueSatoshis)
|
||||
: null;
|
||||
return (
|
||||
<Text
|
||||
key={`output-${idx}`}
|
||||
@@ -571,7 +626,7 @@ export function InvitationScreen(): React.ReactElement {
|
||||
>
|
||||
{' '}{isUserOutput ? '• ' : '○ '}
|
||||
{outputTemplate?.name ?? output.outputIdentifier ?? `Output ${idx}`}
|
||||
{output.valueSatoshis !== undefined && ` (${formatSatoshis(output.valueSatoshis)})`}
|
||||
{outputSatoshis !== null && ` (${formatSatoshis(outputSatoshis)}${getFiatSuffix(outputSatoshis)})`}
|
||||
</Text>
|
||||
);
|
||||
})
|
||||
@@ -591,6 +646,9 @@ export function InvitationScreen(): React.ReactElement {
|
||||
const displayValue = typeof variable.value === 'bigint'
|
||||
? variable.value.toString()
|
||||
: String(variable.value);
|
||||
const parsedVariableSatoshis = isSatoshisVariable(variable.variableIdentifier)
|
||||
? parseNumberishToBigInt(variable.value)
|
||||
: null;
|
||||
return (
|
||||
<Text
|
||||
key={`var-${idx}`}
|
||||
@@ -598,6 +656,8 @@ export function InvitationScreen(): React.ReactElement {
|
||||
>
|
||||
{' '}{isUserVariable ? '• ' : '○ '}
|
||||
{varTemplate?.name ?? variable.variableIdentifier}: {displayValue}
|
||||
{parsedVariableSatoshis !== null &&
|
||||
` (${formatSatoshis(parsedVariableSatoshis)}${getFiatSuffix(parsedVariableSatoshis)})`}
|
||||
{varTemplate?.description && (
|
||||
<Text color={colors.textMuted} dimColor> - {varTemplate.description}</Text>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user