Skip to content
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
26 changes: 24 additions & 2 deletions modules/sdk-coin-flrp/src/flrp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,30 @@ export class Flrp extends BaseCoin {
}
try {
const txBuilder = this.getBuilder().from(txHex);
const tx = await txBuilder.build();
return tx.explainTransaction();
const tx = (await txBuilder.build()) as FlrpLib.Transaction;
const explanation = tx.explainTransaction();

// For a C→P export (ExportInC viewed from the FLRP P-chain perspective), the
// exportedOutputs contain the P-chain UTXO amount, which is the gross amount
// BEFORE the import fee is deducted. The platform uses this explanation to show
// the "pending import amount" before the ImportInP is confirmed. To avoid
// displaying a higher-than-actual amount, subtract the minimum import-to-P fee
// so the displayed amount reflects the expected net P-chain receipt.
if (tx.isTransactionForCChain && explanation.type === TransactionType.Export) {
const minImportToPFee = BigInt((this._staticsCoin.network as FlareNetwork).minImportToPFee);
const adjustedOutputs = explanation.outputs.map((o) => ({
...o,
amount: (BigInt(o.amount) - minImportToPFee).toString(),
}));
const adjustedOutputAmount = (BigInt(explanation.outputAmount) - minImportToPFee).toString();
return {
...explanation,
outputs: adjustedOutputs,
outputAmount: adjustedOutputAmount,
};
}

return explanation;
} catch (e) {
throw new Error(`Invalid transaction: ${e.message}`);
}
Expand Down
18 changes: 18 additions & 0 deletions modules/sdk-coin-flrp/test/unit/flrp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,24 @@ describe('Flrp test cases', function () {
txExplain.changeOutputs.should.be.empty();
});

it('should subtract minImportToPFee from ExportInC outputAmount to show expected net P-chain receipt', async () => {
// The ExportInC UTXO amount is the gross amount going to P-chain. The actual P-chain
// credit will be UTXO - importFee. We subtract minImportToPFee to show the minimum
// net amount the user will receive on P-chain, preventing the pending display from
// showing an inflated amount compared to the confirmed P-chain balance.
const minImportToPFee = BigInt('1261000'); // from FlarePTestnet.minImportToPFee
const expectedAdjustedAmount = (BigInt(EXPORT_IN_C.amount) - minImportToPFee).toString();

// Should work for both unsigned (pending) and signed ExportInC hex
const unsignedExplain = await basecoin.explainTransaction({ txHex: EXPORT_IN_C.unsignedHex });
unsignedExplain.outputAmount.should.equal(expectedAdjustedAmount);
unsignedExplain.outputs[0].amount.should.equal(expectedAdjustedAmount);

const signedExplain = await basecoin.explainTransaction({ txHex: EXPORT_IN_C.signedHex });
signedExplain.outputAmount.should.equal(expectedAdjustedAmount);
signedExplain.outputs[0].amount.should.equal(expectedAdjustedAmount);
});

it('should fail when transaction hex is not provided', async () => {
await basecoin.explainTransaction({}).should.be.rejectedWith('missing transaction hex');
});
Expand Down
Loading