Skip to content

Commit df8e16d

Browse files
committed
feat(sdk-coin-flrp): add sourceChain and destinationChain properties
Ticket: WIN-8413
1 parent 82d9eca commit df8e16d

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

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

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,96 @@ export class Transaction extends BaseTransaction {
254254
signatures: this.signature,
255255
outputs: this.outputs,
256256
changeOutputs: this.changeOutputs,
257+
sourceChain: this.sourceChain,
258+
destinationChain: this.destinationChain,
257259
};
258260
}
259261

262+
/**
263+
* Get the source chain id or undefined if it's not a cross chain transfer.
264+
*/
265+
get sourceChain(): string | undefined {
266+
const tx = (this._flareTransaction as UnsignedTx).getTx();
267+
268+
switch (this.type) {
269+
case TransactionType.Import:
270+
if (this.isTransactionForCChain) {
271+
// C-chain Import: source is the chain we're importing FROM (P-chain)
272+
const importTx = tx as evmSerial.ImportTx;
273+
return this.blockchainIDtoAlias(Buffer.from(importTx.sourceChain.toBytes()));
274+
} else {
275+
// P-chain Import: source is the chain we're importing FROM (C-chain)
276+
const pvmImportTx = tx as pvmSerial.ImportTx;
277+
return this.blockchainIDtoAlias(Buffer.from(pvmImportTx.sourceChain.toBytes()));
278+
}
279+
280+
case TransactionType.Export:
281+
if (this.isTransactionForCChain) {
282+
// C-chain Export: source is C-chain (the blockchain ID)
283+
const exportTx = tx as evmSerial.ExportTx;
284+
return this.blockchainIDtoAlias(Buffer.from(exportTx.blockchainId.toBytes()));
285+
} else {
286+
// P-chain Export: source is P-chain (the blockchain ID from baseTx)
287+
const pvmExportTx = tx as pvmSerial.ExportTx;
288+
return this.blockchainIDtoAlias(Buffer.from(pvmExportTx.baseTx.BlockchainId.toBytes()));
289+
}
290+
291+
default:
292+
return undefined;
293+
}
294+
}
295+
296+
/**
297+
* Get the destination chain id or undefined if it's not a cross chain transfer.
298+
*/
299+
get destinationChain(): string | undefined {
300+
const tx = (this._flareTransaction as UnsignedTx).getTx();
301+
302+
switch (this.type) {
303+
case TransactionType.Import:
304+
if (this.isTransactionForCChain) {
305+
// C-chain Import: destination is C-chain (the blockchain ID)
306+
const importTx = tx as evmSerial.ImportTx;
307+
return this.blockchainIDtoAlias(Buffer.from(importTx.blockchainId.toBytes()));
308+
} else {
309+
// P-chain Import: destination is P-chain (the blockchain ID from baseTx)
310+
const pvmImportTx = tx as pvmSerial.ImportTx;
311+
return this.blockchainIDtoAlias(Buffer.from(pvmImportTx.baseTx.BlockchainId.toBytes()));
312+
}
313+
314+
case TransactionType.Export:
315+
if (this.isTransactionForCChain) {
316+
// C-chain Export: destination is P-chain (the destination chain)
317+
const exportTx = tx as evmSerial.ExportTx;
318+
return this.blockchainIDtoAlias(Buffer.from(exportTx.destinationChain.toBytes()));
319+
} else {
320+
// P-chain Export: destination is C-chain (the destination chain)
321+
const pvmExportTx = tx as pvmSerial.ExportTx;
322+
return this.blockchainIDtoAlias(Buffer.from(pvmExportTx.destination.toBytes()));
323+
}
324+
325+
default:
326+
return undefined;
327+
}
328+
}
329+
330+
/**
331+
* Convert a blockchainId buffer to string and return P or C alias if it matches any of those chains.
332+
* @param {Buffer} blockchainIDBuffer
333+
* @return {string} blockchainID or alias if exists.
334+
* @private
335+
*/
336+
private blockchainIDtoAlias(blockchainIDBuffer: Buffer): string {
337+
const blockchainId = utils.cb58Encode(blockchainIDBuffer);
338+
if (blockchainId === this._network.cChainBlockchainID) {
339+
return 'C';
340+
}
341+
if (blockchainId === this._network.blockchainID) {
342+
return 'P';
343+
}
344+
return blockchainId;
345+
}
346+
260347
setTransaction(tx: Tx): void {
261348
this._flareTransaction = tx as UnsignedTx;
262349
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import 'should';
2+
import { coins } from '@bitgo/statics';
3+
import { TransactionBuilderFactory, TxData } from '../../../src/lib';
4+
import { EXPORT_IN_P } from '../../resources/transactionData/exportInP';
5+
import { IMPORT_IN_P } from '../../resources/transactionData/importInP';
6+
import { IMPORT_IN_C } from '../../resources/transactionData/importInC';
7+
import { EXPORT_IN_C } from '../../resources/transactionData/exportInC';
8+
9+
describe('Flrp Transaction Builder Factory', () => {
10+
const factory = new TransactionBuilderFactory(coins.get('tflrp'));
11+
12+
describe('Cross chain transfer has source and destination chains', () => {
13+
// P-chain Export to C-chain: source is P, destination is C
14+
const p2cExportTxs = [EXPORT_IN_P.unsignedHex, EXPORT_IN_P.halfSigntxHex, EXPORT_IN_P.fullSigntxHex];
15+
16+
// C-chain Import from P-chain: source is P, destination is C
17+
const p2cImportTxs = [IMPORT_IN_C.unsignedHex, IMPORT_IN_C.halfSigntxHex, IMPORT_IN_C.fullSigntxHex];
18+
19+
// P-chain Import from C-chain: source is C, destination is P
20+
const c2pImportTxs = [IMPORT_IN_P.unsignedHex, IMPORT_IN_P.halfSigntxHex, IMPORT_IN_P.fullSigntxHex];
21+
22+
// C-chain Export to P-chain: source is C, destination is P
23+
const c2pExportTxs = [EXPORT_IN_C.unsignedHex, EXPORT_IN_C.signedHex];
24+
25+
async function toJson(txHex: string): Promise<TxData> {
26+
const txBuilder = factory.from(txHex);
27+
const tx = await txBuilder.build();
28+
return tx.toJson();
29+
}
30+
31+
describe('P to C chain transfers', () => {
32+
it('Should have sourceChain P and destinationChain C for Export from P-chain', async () => {
33+
for (const rawTx of p2cExportTxs) {
34+
const txJson = await toJson(rawTx);
35+
txJson.sourceChain!.should.equal('P');
36+
txJson.destinationChain!.should.equal('C');
37+
}
38+
});
39+
40+
it('Should have sourceChain P and destinationChain C for Import to C-chain', async () => {
41+
for (const rawTx of p2cImportTxs) {
42+
const txJson = await toJson(rawTx);
43+
txJson.sourceChain!.should.equal('P');
44+
txJson.destinationChain!.should.equal('C');
45+
}
46+
});
47+
});
48+
49+
describe('C to P chain transfers', () => {
50+
it('Should have sourceChain C and destinationChain P for Import to P-chain', async () => {
51+
for (const rawTx of c2pImportTxs) {
52+
const txJson = await toJson(rawTx);
53+
txJson.sourceChain!.should.equal('C');
54+
txJson.destinationChain!.should.equal('P');
55+
}
56+
});
57+
58+
it('Should have sourceChain C and destinationChain P for Export from C-chain', async () => {
59+
for (const rawTx of c2pExportTxs) {
60+
const txJson = await toJson(rawTx);
61+
txJson.sourceChain!.should.equal('C');
62+
txJson.destinationChain!.should.equal('P');
63+
}
64+
});
65+
});
66+
});
67+
});

0 commit comments

Comments
 (0)