Skip to content

Commit d9434aa

Browse files
ArunBala-Bitgobitgobot
authored andcommitted
fix(sdk-coin-flrp): subtract minImportToPFee from ExportInC outputAmount
For C→P imports, the wallet platform shows the ExportInC transaction as the pending import amount on the FLRP (P-chain) wallet before the ImportInP is confirmed. The ExportInC exportedOutputs hold the gross P-chain UTXO amount (which includes the import fee premium), causing the pending display to show a higher amount than the actual P-chain credit delivered by the ImportInP. Fix: in `Flrp.explainTransaction`, when the transaction is a C-chain export (ExportInC), subtract the network's `minImportToPFee` from the `outputAmount` and each output's amount. This yields the minimum expected net P-chain receipt, aligning the pending display with the confirmed P-chain balance and resolving the amount discrepancy reported in CECHO-1450. The `verifyTransaction` path continues to use the gross UTXO amount for validation (via `tx.explainTransaction()` directly), so existing export validation logic is unaffected. Ticket: CECHO-1450 Session-Id: 53bbdb3d-3f67-4bc4-b5cd-a8be1b2d8857 Task-Id: 99e7fafb-287d-487c-b5fb-9c7f4c2f28f7
1 parent d426bd5 commit d9434aa

2 files changed

Lines changed: 42 additions & 2 deletions

File tree

modules/sdk-coin-flrp/src/flrp.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,30 @@ export class Flrp extends BaseCoin {
428428
}
429429
try {
430430
const txBuilder = this.getBuilder().from(txHex);
431-
const tx = await txBuilder.build();
432-
return tx.explainTransaction();
431+
const tx = (await txBuilder.build()) as FlrpLib.Transaction;
432+
const explanation = tx.explainTransaction();
433+
434+
// For a C→P export (ExportInC viewed from the FLRP P-chain perspective), the
435+
// exportedOutputs contain the P-chain UTXO amount, which is the gross amount
436+
// BEFORE the import fee is deducted. The platform uses this explanation to show
437+
// the "pending import amount" before the ImportInP is confirmed. To avoid
438+
// displaying a higher-than-actual amount, subtract the minimum import-to-P fee
439+
// so the displayed amount reflects the expected net P-chain receipt.
440+
if (tx.isTransactionForCChain && explanation.type === TransactionType.Export) {
441+
const minImportToPFee = BigInt((this._staticsCoin.network as FlareNetwork).minImportToPFee);
442+
const adjustedOutputs = explanation.outputs.map((o) => ({
443+
...o,
444+
amount: (BigInt(o.amount) - minImportToPFee).toString(),
445+
}));
446+
const adjustedOutputAmount = (BigInt(explanation.outputAmount) - minImportToPFee).toString();
447+
return {
448+
...explanation,
449+
outputs: adjustedOutputs,
450+
outputAmount: adjustedOutputAmount,
451+
};
452+
}
453+
454+
return explanation;
433455
} catch (e) {
434456
throw new Error(`Invalid transaction: ${e.message}`);
435457
}

modules/sdk-coin-flrp/test/unit/flrp.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,24 @@ describe('Flrp test cases', function () {
295295
txExplain.changeOutputs.should.be.empty();
296296
});
297297

298+
it('should subtract minImportToPFee from ExportInC outputAmount to show expected net P-chain receipt', async () => {
299+
// The ExportInC UTXO amount is the gross amount going to P-chain. The actual P-chain
300+
// credit will be UTXO - importFee. We subtract minImportToPFee to show the minimum
301+
// net amount the user will receive on P-chain, preventing the pending display from
302+
// showing an inflated amount compared to the confirmed P-chain balance.
303+
const minImportToPFee = BigInt('1261000'); // from FlarePTestnet.minImportToPFee
304+
const expectedAdjustedAmount = (BigInt(EXPORT_IN_C.amount) - minImportToPFee).toString();
305+
306+
// Should work for both unsigned (pending) and signed ExportInC hex
307+
const unsignedExplain = await basecoin.explainTransaction({ txHex: EXPORT_IN_C.unsignedHex });
308+
unsignedExplain.outputAmount.should.equal(expectedAdjustedAmount);
309+
unsignedExplain.outputs[0].amount.should.equal(expectedAdjustedAmount);
310+
311+
const signedExplain = await basecoin.explainTransaction({ txHex: EXPORT_IN_C.signedHex });
312+
signedExplain.outputAmount.should.equal(expectedAdjustedAmount);
313+
signedExplain.outputs[0].amount.should.equal(expectedAdjustedAmount);
314+
});
315+
298316
it('should fail when transaction hex is not provided', async () => {
299317
await basecoin.explainTransaction({}).should.be.rejectedWith('missing transaction hex');
300318
});

0 commit comments

Comments
 (0)