Skip to content

Commit 7c15fce

Browse files
committed
feat(sdk-coin-flrp): enhance transaction builders and utils with new methods
Ticket: WIN-7770
1 parent 9fa37a3 commit 7c15fce

File tree

4 files changed

+136
-64
lines changed

4 files changed

+136
-64
lines changed

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

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import {
3535
FLARE_ATOMIC_PARSED_PREFIX,
3636
HEX_ENCODING,
3737
} from './constants';
38-
import { createFlexibleHexRegex } from './utils';
38+
import utils, { createFlexibleHexRegex } from './utils';
3939

4040
/**
4141
* Flare P-chain atomic transaction builder with FlareJS credential support.
@@ -420,4 +420,58 @@ export abstract class AtomicTransactionBuilder {
420420
);
421421
}
422422
}
423+
424+
/**
425+
* Threshold is an int that names the number of unique signatures required to spend the output.
426+
* Must be less than or equal to the length of Addresses.
427+
* @param {number}
428+
*/
429+
threshold(value: number): this {
430+
this.validateThreshold(value);
431+
this.transaction._threshold = value;
432+
return this;
433+
}
434+
435+
/**
436+
* Validates the threshold
437+
* @param threshold
438+
*/
439+
validateThreshold(threshold: number): void {
440+
if (!threshold || threshold !== 2) {
441+
throw new BuildTransactionError('Invalid transaction: threshold must be set to 2');
442+
}
443+
}
444+
445+
/**
446+
* fromPubKey is a list of unique addresses that correspond to the private keys that can be used to spend this output.
447+
* @param {string | string[]} senderPubKey
448+
*/
449+
// TODO: check the format of the public keys
450+
fromPubKey(senderPubKey: string | string[]): this {
451+
const pubKeys = senderPubKey instanceof Array ? senderPubKey : [senderPubKey];
452+
this.transaction._fromAddresses = pubKeys.map(utils.parseAddress).toString().split(',');
453+
return this;
454+
}
455+
456+
/**
457+
* Locktime is a long that contains the unix timestamp that this output can be spent after.
458+
* The unix timestamp is specific to the second.
459+
* @param value
460+
*/
461+
locktime(value: number): this {
462+
const locktime = BigInt(value);
463+
this.validateLocktime(locktime);
464+
this.transaction._locktime = locktime;
465+
return this;
466+
}
467+
468+
/**
469+
* Validates locktime
470+
* @param locktime
471+
*/
472+
validateLocktime(locktime: bigint): void {
473+
if (!locktime || locktime < 0n) {
474+
throw new BuildTransactionError('Invalid transaction: locktime must be 0 or higher');
475+
}
476+
}
423477
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export { KeyPair } from './keyPair';
55
export { Utils };
66
export { TransactionBuilderFactory } from './transactionBuilderFactory';
77
export { Transaction } from './transaction';
8+
export { TransactionBuilder } from './transactionBuilder';
89
export { AtomicTransactionBuilder } from './atomicTransactionBuilder';
910
export { AtomicInCTransactionBuilder } from './atomicInCTransactionBuilder';
1011
export { ImportInCTxBuilder } from './importInCTxBuilder';
Lines changed: 57 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,11 @@
11
import { BaseCoin as CoinConfig } from '@bitgo/statics';
2-
import { NotImplementedError, TransactionType } from '@bitgo/sdk-core';
32
import { AtomicTransactionBuilder } from './atomicTransactionBuilder';
4-
5-
// Placeholder builders - basic implementations for testing
6-
export class ExportTxBuilder extends AtomicTransactionBuilder {
7-
protected get transactionType(): TransactionType {
8-
return TransactionType.Export;
9-
}
10-
11-
constructor(coinConfig: Readonly<CoinConfig>) {
12-
super(coinConfig);
13-
// Don't throw error, allow placeholder functionality
14-
}
15-
}
16-
17-
export class ImportTxBuilder extends AtomicTransactionBuilder {
18-
protected get transactionType(): TransactionType {
19-
return TransactionType.Import;
20-
}
21-
22-
constructor(coinConfig: Readonly<CoinConfig>) {
23-
super(coinConfig);
24-
// Don't throw error, allow placeholder functionality
25-
}
26-
}
27-
28-
export class ValidatorTxBuilder extends AtomicTransactionBuilder {
29-
protected get transactionType(): TransactionType {
30-
return TransactionType.AddValidator;
31-
}
32-
33-
constructor(coinConfig: Readonly<CoinConfig>) {
34-
super(coinConfig);
35-
// Don't throw error, allow placeholder functionality
36-
}
37-
}
38-
39-
export class DelegatorTxBuilder extends AtomicTransactionBuilder {
40-
protected get transactionType(): TransactionType {
41-
return TransactionType.AddDelegator;
42-
}
43-
44-
constructor(coinConfig: Readonly<CoinConfig>) {
45-
super(coinConfig);
46-
// Don't throw error, allow placeholder functionality
47-
}
48-
}
3+
import { ImportInCTxBuilder } from './importInCTxBuilder';
4+
import { ValidatorTxBuilder } from './validatorTxBuilder';
5+
import { PermissionlessValidatorTxBuilder } from './permissionlessValidatorTxBuilder';
6+
import { ExportInCTxBuilder } from './exportInCTxBuilder';
7+
import { ExportInPTxBuilder } from './exportInPTxBuilder';
8+
import { ImportInPTxBuilder } from './importInPTxBuilder';
499

5010
/**
5111
* Factory for Flare P-chain transaction builders
@@ -70,7 +30,7 @@ export class TransactionBuilderFactory {
7030

7131
// Create a mock export builder for now
7232
// In the future, this will parse the transaction and determine the correct type
73-
const builder = new ExportTxBuilder(this._coinConfig);
33+
const builder = new ExportInPTxBuilder(this._coinConfig);
7434

7535
// Initialize with the hex data (placeholder)
7636
builder.initBuilder({ txHex });
@@ -79,21 +39,56 @@ export class TransactionBuilderFactory {
7939
}
8040

8141
/**
82-
* Create a transaction builder for a specific type
83-
* @param type - Transaction type
42+
* Initialize Validator builder
43+
*
44+
* @returns {ValidatorTxBuilder} the builder initialized
8445
*/
85-
getBuilder(type: TransactionType): AtomicTransactionBuilder {
86-
switch (type) {
87-
case TransactionType.Export:
88-
return new ExportTxBuilder(this._coinConfig);
89-
case TransactionType.Import:
90-
return new ImportTxBuilder(this._coinConfig);
91-
case TransactionType.AddValidator:
92-
return new ValidatorTxBuilder(this._coinConfig);
93-
case TransactionType.AddDelegator:
94-
return new DelegatorTxBuilder(this._coinConfig);
95-
default:
96-
throw new NotImplementedError(`Transaction type ${type} not supported`);
97-
}
46+
getValidatorBuilder(): ValidatorTxBuilder {
47+
return new ValidatorTxBuilder(this._coinConfig);
48+
}
49+
50+
/**
51+
* Initialize Permissionless Validator builder
52+
*
53+
* @returns {PermissionlessValidatorTxBuilder} the builder initialized
54+
*/
55+
getPermissionlessValidatorTxBuilder(): PermissionlessValidatorTxBuilder {
56+
return new PermissionlessValidatorTxBuilder(this._coinConfig);
57+
}
58+
59+
/**
60+
* Export Cross chain transfer
61+
*
62+
* @returns {ExportInPTxBuilder} the builder initialized
63+
*/
64+
getExportBuilder(): ExportInPTxBuilder {
65+
return new ExportInPTxBuilder(this._coinConfig);
66+
}
67+
68+
/**
69+
* Import Cross chain transfer
70+
*
71+
* @returns {ImportInPTxBuilder} the builder initialized
72+
*/
73+
getImportBuilder(): ImportInPTxBuilder {
74+
return new ImportInPTxBuilder(this._coinConfig);
75+
}
76+
77+
/**
78+
* Import in C chain Cross chain transfer
79+
*
80+
* @returns {ImportInCTxBuilder} the builder initialized
81+
*/
82+
getImportInCBuilder(): ImportInCTxBuilder {
83+
return new ImportInCTxBuilder(this._coinConfig);
84+
}
85+
86+
/**
87+
* Export in C chain Cross chain transfer
88+
*
89+
* @returns {ExportInCTxBuilder} the builder initialized
90+
*/
91+
getExportInCBuilder(): ExportInCTxBuilder {
92+
return new ExportInCTxBuilder(this._coinConfig);
9893
}
9994
}

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { TransferableOutput } from '@flarenetwork/flarejs';
2-
import { bech32 } from 'bech32';
2+
import * as bech32 from 'bech32';
33
import bs58 from 'bs58';
44
import {
55
BaseUtils,
@@ -53,6 +53,27 @@ export class Utils implements BaseUtils {
5353
return `${prefix}-${bech32.encode(hrp, words)}`;
5454
};
5555

56+
/**
57+
* Convert a NodeID string to a Buffer. This is a Flare-specific implementation
58+
* that doesn't rely on the Avalanche dependency.
59+
*
60+
* NodeIDs in Flare follow the format: NodeID-<base58_string>
61+
*
62+
* @param {string} nodeID - The NodeID string to convert
63+
* @returns {Buffer} - The decoded NodeID as a Buffer
64+
*/
65+
public NodeIDStringToBuffer = (nodeID: string): Buffer => {
66+
// Remove 'NodeID-' prefix if present
67+
const cleanNodeID = nodeID.startsWith('NodeID-') ? nodeID.slice(7) : nodeID;
68+
69+
try {
70+
// Decode base58 string to buffer
71+
return Buffer.from(bs58.decode(cleanNodeID));
72+
} catch (error) {
73+
throw new Error(`Invalid NodeID format: ${error instanceof Error ? error.message : String(error)}`);
74+
}
75+
};
76+
5677
public includeIn(walletAddresses: string[], otxoOutputAddresses: string[]): boolean {
5778
return walletAddresses.map((a) => otxoOutputAddresses.includes(a)).reduce((a, b) => a && b, true);
5879
}
@@ -126,6 +147,7 @@ export class Utils implements BaseUtils {
126147
}
127148
}
128149

150+
// TODO add test cases for this method
129151
public parseAddress = (address: string): Buffer => {
130152
return this.stringToAddress(address);
131153
};

0 commit comments

Comments
 (0)