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
8 changes: 6 additions & 2 deletions modules/express/test/unit/clientRoutes/externalSign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ describe('External signer', () => {
envStub.restore();
});

it('should read an encrypted prv from signerFileSystemPath and pass it to PaillierModulus, K, MuDelta, and S share generators', async () => {
it('should read an encrypted prv from signerFileSystemPath and pass it to PaillierModulus, K, MuDelta, and S share generators', async function () {
// This test performs multiple MPC ECDSA rounds and can exceed Mocha's default 60s timeout on CI
this.timeout(180000);
const walletID = '62fe536a6b4cf70007acb48c0e7bb0b0';
const user = keyShareOneEcdsa; // await mpcEcdsa.keyShare(1, 2, 3);
const backup = keyShareTwoEcdsa; // await mpcEcdsa.keyShare(2, 2, 3);
Expand Down Expand Up @@ -497,7 +499,9 @@ describe('External signer', () => {
envStub.restore();
});

it('should read an encrypted prv from signerFileSystemPath and pass it to MPCv2Round1, MPCv2Round2 and MPCv2Round3 share generators', async () => {
it('should read an encrypted prv from signerFileSystemPath and pass it to MPCv2Round1, MPCv2Round2 and MPCv2Round3 share generators', async function () {
// MPCv2 DKLS flow is CPU-heavy; extend timeout for CI stability
this.timeout(180000);
const walletID = '62fe536a6b4cf70007acb48c0e7bb0b0';
const tMessage = 'testMessage';
const derivationPath = 'm/0';
Expand Down
5 changes: 5 additions & 0 deletions modules/sdk-coin-flrp/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
.idea
public
dist

7 changes: 7 additions & 0 deletions modules/sdk-coin-flrp/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../.eslintrc.json",
"rules": {
"@typescript-eslint/explicit-module-boundary-types": "error",
"indent": "off"
}
}
3 changes: 3 additions & 0 deletions modules/sdk-coin-flrp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
.idea/
dist/
8 changes: 8 additions & 0 deletions modules/sdk-coin-flrp/.mocharc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require: 'tsx'
timeout: '60000'
reporter: 'min'
reporter-option:
- 'cdn=true'
- 'json=false'
exit: true
spec: ['test/unit/**/*.ts']
12 changes: 12 additions & 0 deletions modules/sdk-coin-flrp/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
!dist/
.idea/
.prettierrc.yml
tsconfig.json
src/
test/
scripts/
.nyc_output
CODEOWNERS
node_modules/
.prettierignore
.mocharc.js
2 changes: 2 additions & 0 deletions modules/sdk-coin-flrp/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.nyc_output/
dist/
3 changes: 3 additions & 0 deletions modules/sdk-coin-flrp/.prettierrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
printWidth: 120
singleQuote: true
trailingComma: 'es5'
Empty file.
62 changes: 62 additions & 0 deletions modules/sdk-coin-flrp/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"name": "@bitgo/sdk-coin-flrp",
"version": "1.0.0",
"description": "BitGo's SDK coin library for flrp coin",
"main": "./dist/src/index.js",
"types": "./dist/src/index.d.ts",
"scripts": {
"build": "yarn tsc --build --incremental --verbose .",
"fmt": "prettier --write .",
"check-fmt": "prettier --check .",
"clean": "rm -r ./dist",
"lint": "eslint --quiet .",
"prepare": "npm run build",
"test": "npm run coverage",
"coverage": "nyc -- npm run unit-test",
"unit-test": "mocha"
},
"scriptsComment": {
"build": "Need to re-add unit-test: 'nyc -- mocha' and test 'npm run unit-test', removed to green build and will add tests as implemented"
},
"repository": {
"type": "git",
"url": "https://github.com/BitGo/BitGoJS.git",
"directory": "modules/sdk-coin-flrp"
},
"author": "BitGo SDK Team <sdkteam@bitgo.com>",
"license": "MIT",
"engines": {
"node": ">=20 <23"
},
"lint-staged": {
"*.{js,ts}": [
"yarn prettier --write",
"yarn eslint --fix"
]
},
"publishConfig": {
"access": "public"
},
"nyc": {
"extension": [
".ts"
]
},
"devDependencies": {
"chai": "^4.4.1",
"@types/chai": "^4.3.16",
"@types/bn.js": "^5.2.0",
"@bitgo/sdk-test": "^9.0.5",
"@bitgo/sdk-api": "^1.67.0"
},
"dependencies": {
"@bitgo/sdk-core": "^36.5.0",
"@bitgo/secp256k1": "^1.5.0",
"@bitgo/statics": "^57.5.0",
"@flarenetwork/flarejs": "4.1.0-rc0",
"@noble/curves": "1.8.1",
"create-hash": "^1.2.0",
"safe-buffer": "^5.2.1"
},
"gitHead": "18e460ddf02de2dbf13c2aa243478188fb539f0c"
}
229 changes: 229 additions & 0 deletions modules/sdk-coin-flrp/src/flrp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import {
BaseCoin,
BitGoBase,
VerifyAddressOptions,
ParsedTransaction,
ParseTransactionOptions,
KeyPair,
SignTransactionOptions,
SignedTransaction,
InitiateRecoveryOptions,
SupplementGenerateWalletOptions,
KeychainsTriplet,
TransactionPrebuild,
PresignTransactionOptions,
FeeEstimateOptions,
DeriveKeyWithSeedOptions,
AuditKeyParams,
PopulatedIntent,
PrebuildTransactionWithIntentOptions,
TokenTransferRecipientParams,
BuildNftTransferDataOptions,
BaseBroadcastTransactionOptions,
BaseBroadcastTransactionResult,
MPCAlgorithm,
Wallet,
IInscriptionBuilder,
ExtraPrebuildParamsOptions,
ValidMofNOptions,
VerifyTransactionOptions,
ITransactionExplanation,
RecoverTokenTransaction,
RecoverWalletTokenOptions,
PrecreateBitGoOptions,
IWallet,
} from '@bitgo/sdk-core';
import { BaseCoin as StaticsBaseCoin, CoinFamily } from '@bitgo/statics';
import { Hash } from 'crypto';

export class Flrp extends BaseCoin {
protected readonly _staticsCoin: Readonly<StaticsBaseCoin>;

protected constructor(bitgo: BitGoBase, staticsCoin?: Readonly<StaticsBaseCoin>) {
super(bitgo);
if (!staticsCoin) {
throw new Error('missing required constructor parameter staticsCoin');
}
this._staticsCoin = staticsCoin;
}

static createInstance(bitgo: BitGoBase, staticsCoin?: Readonly<StaticsBaseCoin>): BaseCoin {
return new Flrp(bitgo, staticsCoin);
}

getChain(): string {
return this._staticsCoin.name;
}
getFamily(): CoinFamily {
return this._staticsCoin.family as CoinFamily;
}
getFullName(): string {
return this._staticsCoin.fullName;
}
getBaseFactor(): number | string {
return Math.pow(10, this._staticsCoin.decimalPlaces);
}

// TODO WIN-6321, 6322, 6318: All below methods will be implemented in coming ticket
// Feature flags
supportsTss(): boolean {
return false;
}
supportsMessageSigning(): boolean {
return false;
}
supportsSigningTypedData(): boolean {
return false;
}
supportsBlockTarget(): boolean {
return false;
}
supportsLightning(): boolean {
return false;
}
supportsBlsDkg(): boolean {
return false;
}
isEVM(): boolean {
return false;
}

// Conversions (placeholder)
// Use BaseCoin default conversions (baseUnitsToBigUnits / bigUnitsToBaseUnits)

// Key methods (stubs)
generateKeyPair(): KeyPair {
throw new Error('generateKeyPair not implemented');
}
generateRootKeyPair(): KeyPair {
throw new Error('generateRootKeyPair not implemented');
}
keyIdsForSigning(): number[] {
return [0, 1, 2];
}
isValidPub(_pub: string): boolean {
return false;
}
isValidAddress(_address: string): boolean {
return false;
}
isValidMofNSetup(_params: ValidMofNOptions): boolean {
return false;
}
canonicalAddress(address: string): string {
return address;
}
checkRecipient(_recipient: { address: string; amount: string | number }): void {
/* no-op */
}

// Verification
async verifyAddress(_params: VerifyAddressOptions): Promise<boolean> {
throw new Error('verifyAddress not implemented');
}
async isWalletAddress(_params: VerifyAddressOptions): Promise<boolean> {
throw new Error('isWalletAddress not implemented');
}
async verifyTransaction(_params: VerifyTransactionOptions): Promise<boolean> {
throw new Error('verifyTransaction not implemented');
}

// Tx lifecycle
async signTransaction(_params: SignTransactionOptions): Promise<SignedTransaction> {
// TODO WIN-6320: implement signTransaction
throw new Error('signTransaction not implemented');
}
async explainTransaction(
_options: Record<string, unknown>
): Promise<ITransactionExplanation<unknown, string | number> | undefined> {
// TODO WIN-6320: implement signTransaction
throw new Error('explainTransaction not implemented');
}
async parseTransaction(_params: ParseTransactionOptions): Promise<ParsedTransaction> {
// TODO WIN-6320: implement signTransaction
throw new Error('parseTransaction not implemented');
}
async presignTransaction(_params: PresignTransactionOptions): Promise<PresignTransactionOptions> {
// TODO WIN-6320: implement signTransaction
throw new Error('presignTransaction not implemented');
}
async postProcessPrebuild(prebuild: TransactionPrebuild): Promise<TransactionPrebuild> {
// TODO WIN-6320: implement signTransaction
return prebuild;
}
async getExtraPrebuildParams(_buildParams: ExtraPrebuildParamsOptions): Promise<Record<string, unknown>> {
// TODO WIN-6320: implement signTransaction
return {};
}
async feeEstimate(_params: FeeEstimateOptions): Promise<unknown> {
// TODO WIN-6320: implement signTransaction
throw new Error('feeEstimate not implemented');
}
async broadcastTransaction(_params: BaseBroadcastTransactionOptions): Promise<BaseBroadcastTransactionResult> {
// TODO WIN-6320: implement signTransaction
throw new Error('broadcastTransaction not implemented');
}

// Wallet helpers
async supplementGenerateWallet(
_walletParams: SupplementGenerateWalletOptions,
_keychains: KeychainsTriplet
): Promise<Record<string, unknown>> {
return {};
}
newWalletObject(walletParams: unknown): IWallet {
return walletParams as IWallet;
}
preCreateBitGo(_params: PrecreateBitGoOptions): void {
/* no-op */
}
initiateRecovery(_params: InitiateRecoveryOptions): never {
throw new Error('initiateRecovery not implemented');
}

// Signing helpers
async signMessage(_key: { prv: string }, _message: string): Promise<Buffer> {
throw new Error('signMessage not implemented');
}
async createKeySignatures(
_prv: string,
_backup: { pub: string },
_bitgo: { pub: string }
): Promise<{ backup: string; bitgo: string }> {
throw new Error('createKeySignatures not implemented');
}
async getSignablePayload(_serializedTx: string): Promise<Buffer> {
throw new Error('getSignablePayload not implemented');
}
getMPCAlgorithm(): MPCAlgorithm {
return 'ecdsa';
}

// Token / NFT / inscription / recovery placeholders
recoverToken(_params: RecoverWalletTokenOptions): Promise<RecoverTokenTransaction> {
throw new Error('recoverToken not implemented');
}
buildNftTransferData(_params: BuildNftTransferDataOptions): string | TokenTransferRecipientParams {
throw new Error('buildNftTransferData not implemented');
}
getInscriptionBuilder(_wallet: Wallet): IInscriptionBuilder {
throw new Error('getInscriptionBuilder not implemented');
}

// Misc
getHashFunction(): Hash {
throw new Error('getHashFunction not implemented');
}
deriveKeyWithSeed(_params: DeriveKeyWithSeedOptions): { key: string; derivationPath: string } {
throw new Error('deriveKeyWithSeed not implemented');
}
setCoinSpecificFieldsInIntent(_intent: PopulatedIntent, _params: PrebuildTransactionWithIntentOptions): void {
/* no-op */
}
assertIsValidKey(_params: AuditKeyParams): void {
/* no-op */
}
auditDecryptedKey(): void {
/* no-op */
}
}
32 changes: 32 additions & 0 deletions modules/sdk-coin-flrp/src/iface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {
SignTransactionOptions,
TransactionPrebuild as BaseTransactionPrebuild,
TransactionRecipient,
TransactionFee,
} from '@bitgo/sdk-core';

export { TransactionFee };
export interface ExplainTransactionOptions {
txHex?: string;
halfSigned?: {
txHex: string;
};
publicKeys?: string[];
}

export interface TxInfo {
recipients: TransactionRecipient[];
from: string;
txid: string;
}

export interface FlrpSignTransactionOptions extends SignTransactionOptions {
txPrebuild: TransactionPrebuild;
prv: string | string[];
pubKeys?: string[];
}
export interface TransactionPrebuild extends BaseTransactionPrebuild {
txHex: string;
txInfo: TxInfo;
source: string;
}
Loading