Fix sats out

This commit is contained in:
2026-01-30 02:16:30 +00:00
parent 28af0c0df3
commit adf3996dc4
2 changed files with 76 additions and 24 deletions

View File

@@ -189,11 +189,22 @@ export function TransactionScreen(): React.ReactElement {
// Extract transaction data from invitation
const commits = invitation?.commits ?? [];
const inputs: Array<{ txid: string; index: number; value?: bigint }> = [];
const outputs: Array<{ value: bigint; lockingBytecode: string }> = [];
const inputs: Array<{ txid: string; index: number; value?: bigint; inputIdentifier?: string }> = [];
const outputs: Array<{ value?: bigint; lockingBytecode: string; outputIdentifier?: string; isTemplate: boolean }> = [];
const variables: Array<{ id: string; value: string }> = [];
// Parse commits for inputs and outputs
// Parse commits for inputs, outputs, and variables
for (const commit of commits) {
// Extract variables (to help understand output values)
if (commit.data?.variables) {
for (const variable of commit.data.variables) {
variables.push({
id: variable.variableIdentifier,
value: String(variable.value),
});
}
}
if (commit.data?.inputs) {
for (const input of commit.data.inputs) {
// Convert Uint8Array to hex string if needed
@@ -201,13 +212,17 @@ export function TransactionScreen(): React.ReactElement {
? typeof input.outpointTransactionHash === 'string'
? input.outpointTransactionHash
: Buffer.from(input.outpointTransactionHash).toString('hex')
: 'unknown';
: undefined;
inputs.push({
txid: txidHex,
index: input.outpointIndex ?? 0,
value: undefined, // libauth Input doesn't have valueSatoshis directly
});
// Skip inputs that are just placeholders (no txid)
if (txidHex) {
inputs.push({
txid: txidHex,
index: input.outpointIndex ?? 0,
value: undefined, // Will be looked up from UTXO data
inputIdentifier: (input as any).inputIdentifier,
});
}
}
}
if (commit.data?.outputs) {
@@ -217,20 +232,45 @@ export function TransactionScreen(): React.ReactElement {
? typeof output.lockingBytecode === 'string'
? output.lockingBytecode
: Buffer.from(output.lockingBytecode).toString('hex')
: 'unknown';
: undefined;
// Check if this is a template-defined output (has outputIdentifier but no direct value)
const isTemplateOutput = !!(output as any).outputIdentifier && !output.valueSatoshis;
outputs.push({
value: output.valueSatoshis ?? 0n,
lockingBytecode: lockingBytecodeHex,
value: output.valueSatoshis,
lockingBytecode: lockingBytecodeHex ?? '(pending)',
outputIdentifier: (output as any).outputIdentifier,
isTemplate: isTemplateOutput,
});
}
}
}
// Calculate totals
const totalIn = inputs.reduce((sum, i) => sum + (i.value ?? 0n), 0n);
const totalOut = outputs.reduce((sum, o) => sum + o.value, 0n);
const fee = totalIn - totalOut;
// Try to resolve template output values from variables
const resolvedOutputs = outputs.map(output => {
if (output.isTemplate && output.outputIdentifier) {
// Look for a matching variable (e.g., requestSatoshisOutput -> requestedSatoshis)
const satoshiVar = variables.find(v =>
v.id.toLowerCase().includes('satoshi') ||
v.id.toLowerCase().includes('amount')
);
if (satoshiVar) {
return {
...output,
value: BigInt(satoshiVar.value),
resolvedFrom: satoshiVar.id,
};
}
}
return output;
});
// Calculate totals (only for resolved values)
const totalOut = resolvedOutputs.reduce((sum, o) => sum + (o.value ?? 0n), 0n);
// Note: We can't calculate totalIn without UTXO lookup, so fee is unknown
const hasUnresolvedOutputs = resolvedOutputs.some(o => o.value === undefined);
const hasUnresolvedInputs = inputs.length > 0; // Input values are always unknown from commit data
return (
<Box flexDirection="column" flexGrow={1}>
@@ -251,10 +291,16 @@ export function TransactionScreen(): React.ReactElement {
<Text color={colors.primary} bold> Transaction Summary </Text>
{invitation ? (
<Box flexDirection="column" marginTop={1}>
<Text color={colors.text}>Inputs: {inputs.length} | Outputs: {outputs.length} | Commits: {commits.length}</Text>
<Text color={colors.success}>Total In: {formatSatoshis(totalIn)}</Text>
<Text color={colors.warning}>Total Out: {formatSatoshis(totalOut)}</Text>
<Text color={colors.info}>Fee: {formatSatoshis(fee)}</Text>
<Text color={colors.text}>Inputs: {inputs.length} | Outputs: {resolvedOutputs.length} | Commits: {commits.length}</Text>
{hasUnresolvedInputs && (
<Text color={colors.textMuted}>Total In: (requires UTXO lookup)</Text>
)}
<Text color={colors.warning}>Total Out: {formatSatoshis(totalOut)}{hasUnresolvedOutputs ? ' (partial)' : ''}</Text>
{hasUnresolvedInputs ? (
<Text color={colors.textMuted}>Fee: (calculated at broadcast)</Text>
) : (
<Text color={colors.info}>Fee: {formatSatoshis(0n)}</Text>
)}
</Box>
) : (
<Text color={colors.textMuted}>Loading...</Text>
@@ -301,15 +347,21 @@ export function TransactionScreen(): React.ReactElement {
>
<Text color={colors.primary} bold> Outputs </Text>
<Box flexDirection="column" marginTop={1}>
{outputs.length === 0 ? (
{resolvedOutputs.length === 0 ? (
<Text color={colors.textMuted}>No outputs</Text>
) : (
outputs.map((output, index) => (
resolvedOutputs.map((output, index) => (
<Box key={index} flexDirection="column" marginBottom={1}>
<Text color={colors.text}>
{index + 1}. {formatSatoshis(output.value)}
{index + 1}. {output.value !== undefined ? formatSatoshis(output.value) : '(pending)'}
{output.outputIdentifier && (
<Text color={colors.info}> [{output.outputIdentifier}]</Text>
)}
</Text>
<Text color={colors.textMuted}> {formatHex(output.lockingBytecode, 20)}</Text>
<Text color={colors.textMuted}> {output.lockingBytecode !== '(pending)' ? formatHex(output.lockingBytecode, 20) : '(pending)'}</Text>
{(output as any).resolvedFrom && (
<Text color={colors.textMuted} dimColor> (from ${(output as any).resolvedFrom})</Text>
)}
</Box>
))
)}