From 18c9233204b659129b175eee9c4422ab10447731 Mon Sep 17 00:00:00 2001 From: Polybius93 Date: Wed, 29 May 2024 21:28:02 +0200 Subject: [PATCH] feat: modify package.json --- .prettierrc.js | 19 +++ .prettierrc.json | 19 --- package.json | 9 +- src/constants/ethereum-constants.ts | 6 +- src/dlc-handlers/ledger-dlc-handler.ts | 96 +++++++++++---- src/dlc-handlers/private-key-dlc-handler.ts | 45 +++++-- .../software-wallet-dlc-handler.ts | 63 +++++++--- src/functions/bitcoin-functions.ts | 116 ++++++++++++++---- src/functions/ethereum-functions.ts | 39 ++++-- src/functions/psbt-functions.ts | 34 +++-- src/index.ts | 3 +- src/ledger-functions.ts | 2 +- src/models/bitcoin-models.ts | 1 - src/models/ethereum-models.ts | 1 - src/models/index.ts | 4 + src/network-handlers/ethereum-handler.ts | 23 +++- .../read-only-ethereum-handler.ts | 21 ++-- src/query-handlers/attestor-handler.ts | 34 ++--- src/test.ts | 35 ++++-- src/utilities/index.ts | 3 +- 20 files changed, 408 insertions(+), 165 deletions(-) create mode 100644 .prettierrc.js delete mode 100644 .prettierrc.json diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..3a35ba3 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,19 @@ +export default { + printWidth: 100, + tabWidth: 2, + useTabs: false, + semi: true, + trailingComma: "es5", + singleQuote: true, + arrowParens: "avoid", + plugins: ["@trivago/prettier-plugin-sort-imports"], + importOrder: [ + "^react", + "", + "^@shared/(.*)$", + "^@(app|content-script|inpage|background)/(.*)$", + "^[./]", + ], + importOrderSeparation: true, + importOrderSortSpecifiers: true, +}; diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index 937af61..0000000 --- a/.prettierrc.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "printWidth": 100, - "trailingComma": "es5", - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": true, - "arrowParens": "avoid", - "plugins": ["@trivago/prettier-plugin-sort-imports"], - "importOrder": [ - "^react", - "", - "^@shared/(.*)$", - "^@(app|content-script|inpage|background)/(.*)$", - "^[./]" - ], - "importOrderSeparation": true, - "importOrderSortSpecifiers": true -} diff --git a/package.json b/package.json index beebb99..daf675f 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "description": "", "main": "dist/index.js", "types": "dist/index.d.ts", + "files": ["dist"], "exports": { ".": "./dist/index.js", "./utilities": "./dist/utilities/index.js", @@ -16,12 +17,11 @@ "build": "tsc", "start": "node dist/test.js", "test": "ts-node index.ts", - "lint": "concurrently -g 'yarn lint:eslint' 'yarn lint:prettier' 'yarn run lint:unused-exports' 'yarn run lint:typecheck'", + "lint": "concurrently -g 'yarn lint:eslint' 'yarn lint:prettier' 'yarn run lint:typecheck'", "lint:eslint": "eslint \"src/**/*.{js,ts}\"", "lint:eslint:fix": "eslint --fix \"src/**/*.{js,ts}\"", - "lint:prettier": "prettier --check \"src/**/*.{js,ts}\" \"*.{js,json}\"", - "lint:prettier:fix": "prettier --write \"src/**/*.{ts}\" *.js", - "lint:unused-exports": "ts-unused-exports tsconfig.json --ignoreFiles=tests", + "lint:prettier": "prettier --check \"{src,tests}/**/*.ts\" \"*.js\"", + "lint:prettier:fix": "prettier --write \"{src,tests}/**/*.ts\" *.js", "lint:typecheck": "tsc --noEmit" }, "keywords": [], @@ -39,7 +39,6 @@ "typescript-eslint": "^7.7.0", "@ledgerhq/hw-transport-node-hid": "^6.28.6", "@ledgerhq/hw-transport-webusb": "^6.28.6", - "ts-unused-exports": "^10.0.1", "typecheck": "^0.1.2", "prettier-eslint": "^16.3.0", "lint": "^0.8.19", diff --git a/src/constants/ethereum-constants.ts b/src/constants/ethereum-constants.ts index e74c9ad..d14634d 100644 --- a/src/constants/ethereum-constants.ts +++ b/src/constants/ethereum-constants.ts @@ -1,5 +1,4 @@ /** @format */ - import { EthereumNetwork, EthereumNetworkID } from '../models/ethereum-models.js'; export const ethereumArbitrumSepolia: EthereumNetwork = { @@ -16,7 +15,10 @@ export const ethereumArbitrum: EthereumNetwork = { defaultNodeURL: 'https://arb1.arbitrum.io/rpc', }; -export const supportedEthereumNetworks: EthereumNetwork[] = [ethereumArbitrumSepolia, ethereumArbitrum]; +export const supportedEthereumNetworks: EthereumNetwork[] = [ + ethereumArbitrumSepolia, + ethereumArbitrum, +]; export const hexChainIDs: { [key in EthereumNetworkID]: string } = { [EthereumNetworkID.ArbitrumSepolia]: '0x66eee', diff --git a/src/dlc-handlers/ledger-dlc-handler.ts b/src/dlc-handlers/ledger-dlc-handler.ts index cbd5b3e..4f42f9f 100644 --- a/src/dlc-handlers/ledger-dlc-handler.ts +++ b/src/dlc-handlers/ledger-dlc-handler.ts @@ -1,10 +1,10 @@ /** @format */ - import { Transaction } from '@scure/btc-signer'; import { P2Ret, P2TROut, p2wpkh } from '@scure/btc-signer/payment'; import { Network, Psbt } from 'bitcoinjs-lib'; import { bitcoin, regtest, testnet } from 'bitcoinjs-lib/src/networks.js'; import { AppClient, DefaultWalletPolicy, WalletPolicy } from 'ledger-bitcoin'; + import { createBitcoinInputSigningConfiguration, createTaprootMultisigPayment, @@ -14,7 +14,6 @@ import { getInputByPaymentTypeArray, getUnspendableKeyCommittedToUUID, } from '../functions/bitcoin-functions.js'; -import { RawVault } from '../models/ethereum-models.js'; import { addNativeSegwitSignaturesToPSBT, addTaprootInputSignaturesToPSBT, @@ -25,8 +24,9 @@ import { updateNativeSegwitInputs, updateTaprootInputs, } from '../functions/psbt-functions.js'; -import { truncateAddress } from '../utilities/index.js'; import { PaymentInformation } from '../models/bitcoin-models.js'; +import { RawVault } from '../models/ethereum-models.js'; +import { truncateAddress } from '../utilities/index.js'; interface LedgerPolicyInformation { nativeSegwitWalletPolicy: DefaultWalletPolicy; @@ -55,15 +55,22 @@ export class LedgerDLCHandler { switch (bitcoinNetwork) { case bitcoin: this.bitcoinBlockchainAPI = 'https://mempool.space/api'; - this.bitcoinBlockchainFeeRecommendationAPI = 'https://mempool.space/api/v1/fees/recommended'; + this.bitcoinBlockchainFeeRecommendationAPI = + 'https://mempool.space/api/v1/fees/recommended'; break; case testnet: this.bitcoinBlockchainAPI = 'https://mempool.space/testnet/api'; - this.bitcoinBlockchainFeeRecommendationAPI = 'https://mempool.space/testnet/api/v1/fees/recommended'; + this.bitcoinBlockchainFeeRecommendationAPI = + 'https://mempool.space/testnet/api/v1/fees/recommended'; break; case regtest: - if (bitcoinBlockchainAPI === undefined || bitcoinBlockchainFeeRecommendationAPI === undefined) { - throw new Error('Regtest requires a Bitcoin Blockchain API and a Bitcoin Blockchain Fee Recommendation API'); + if ( + bitcoinBlockchainAPI === undefined || + bitcoinBlockchainFeeRecommendationAPI === undefined + ) { + throw new Error( + 'Regtest requires a Bitcoin Blockchain API and a Bitcoin Blockchain Fee Recommendation API' + ); } this.bitcoinBlockchainAPI = bitcoinBlockchainAPI; this.bitcoinBlockchainFeeRecommendationAPI = bitcoinBlockchainFeeRecommendationAPI; @@ -155,7 +162,13 @@ export class LedgerDLCHandler { const nativeSegwitWalletPolicy = new DefaultWalletPolicy('wpkh(@0/**)', nativeSegwitKeyinfo); - const nativeSegwitAddress = await this.ledgerApp.getWalletAddress(nativeSegwitWalletPolicy, null, 0, 0, false); + const nativeSegwitAddress = await this.ledgerApp.getWalletAddress( + nativeSegwitWalletPolicy, + null, + 0, + 0, + false + ); const nativeSegwitDerivedPublicKey = deriveUnhardenedPublicKey( nativeSegwitExtendedPublicKey, @@ -164,13 +177,21 @@ export class LedgerDLCHandler { const nativeSegwitPayment = p2wpkh(nativeSegwitDerivedPublicKey, this.bitcoinNetwork); if (nativeSegwitPayment.address !== nativeSegwitAddress) { - throw new Error(`[Ledger] Recreated Native Segwit Address does not match the Ledger Native Segwit Address`); + throw new Error( + `[Ledger] Recreated Native Segwit Address does not match the Ledger Native Segwit Address` + ); } const unspendablePublicKey = getUnspendableKeyCommittedToUUID(vaultUUID, this.bitcoinNetwork); - const unspendableDerivedPublicKey = deriveUnhardenedPublicKey(unspendablePublicKey, this.bitcoinNetwork); + const unspendableDerivedPublicKey = deriveUnhardenedPublicKey( + unspendablePublicKey, + this.bitcoinNetwork + ); - const attestorDerivedPublicKey = deriveUnhardenedPublicKey(attestorGroupPublicKey, this.bitcoinNetwork); + const attestorDerivedPublicKey = deriveUnhardenedPublicKey( + attestorGroupPublicKey, + this.bitcoinNetwork + ); const taprootExtendedPublicKey = await this.ledgerApp.getExtendedPubkey( `m/86'/${networkIndex}'/${this.walletAccountIndex}'` @@ -178,7 +199,10 @@ export class LedgerDLCHandler { const ledgerTaprootKeyInfo = `[${this.masterFingerprint}/86'/${networkIndex}'/${this.walletAccountIndex}']${taprootExtendedPublicKey}`; - const taprootDerivedPublicKey = deriveUnhardenedPublicKey(taprootExtendedPublicKey, this.bitcoinNetwork); + const taprootDerivedPublicKey = deriveUnhardenedPublicKey( + taprootExtendedPublicKey, + this.bitcoinNetwork + ); const descriptors = taprootDerivedPublicKey.toString('hex') < attestorDerivedPublicKey.toString('hex') @@ -191,7 +215,9 @@ export class LedgerDLCHandler { [unspendablePublicKey, ...descriptors] ); - const [, taprootMultisigPolicyHMac] = await this.ledgerApp.registerWallet(taprootMultisigAccountPolicy); + const [, taprootMultisigPolicyHMac] = await this.ledgerApp.registerWallet( + taprootMultisigAccountPolicy + ); const taprootMultisigAddress = await this.ledgerApp.getWalletAddress( taprootMultisigAccountPolicy, @@ -212,7 +238,11 @@ export class LedgerDLCHandler { throw new Error(`Recreated Multisig Address does not match the Ledger Multisig Address`); } - this.setPolicyInformation(nativeSegwitWalletPolicy, taprootMultisigAccountPolicy, taprootMultisigPolicyHMac); + this.setPolicyInformation( + nativeSegwitWalletPolicy, + taprootMultisigAccountPolicy, + taprootMultisigPolicyHMac + ); this.setPaymentInformation( nativeSegwitPayment, nativeSegwitDerivedPublicKey, @@ -224,19 +254,30 @@ export class LedgerDLCHandler { } } - async createFundingPSBT(vault: RawVault, feeRateMultiplier?: number, customFeeRate?: bigint): Promise { + async createFundingPSBT( + vault: RawVault, + feeRateMultiplier?: number, + customFeeRate?: bigint + ): Promise { try { const { nativeSegwitPayment, nativeSegwitDerivedPublicKey, taprootMultisigPayment } = this.getPaymentInformation(); - if (taprootMultisigPayment.address === undefined || nativeSegwitPayment.address === undefined) { + if ( + taprootMultisigPayment.address === undefined || + nativeSegwitPayment.address === undefined + ) { throw new Error('Payment Address is undefined'); } const feeRate = - customFeeRate ?? BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); + customFeeRate ?? + BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); - const addressBalance = await getBalance(nativeSegwitPayment.address, this.bitcoinBlockchainAPI); + const addressBalance = await getBalance( + nativeSegwitPayment.address, + this.bitcoinBlockchainAPI + ); if (BigInt(addressBalance) < vault.valueLocked.toBigInt()) { throw new Error('Insufficient Funds'); @@ -292,14 +333,16 @@ export class LedgerDLCHandler { customFeeRate?: bigint ): Promise { try { - const { nativeSegwitPayment, taprootMultisigPayment, taprootDerivedPublicKey } = this.getPaymentInformation(); + const { nativeSegwitPayment, taprootMultisigPayment, taprootDerivedPublicKey } = + this.getPaymentInformation(); if (nativeSegwitPayment.address === undefined) { throw new Error('Could not get Addresses from Payments'); } const feeRate = - customFeeRate ?? BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); + customFeeRate ?? + BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); const closingPSBT = createClosingTransaction( vault.valueLocked.toBigInt(), @@ -345,15 +388,22 @@ export class LedgerDLCHandler { async signPSBT(psbt: Psbt, transactionType: 'funding' | 'closing'): Promise { try { - const { nativeSegwitWalletPolicy, taprootMultisigWalletPolicy, taprootMultisigWalletPolicyHMac } = - this.getPolicyInformation(); + const { + nativeSegwitWalletPolicy, + taprootMultisigWalletPolicy, + taprootMultisigWalletPolicyHMac, + } = this.getPolicyInformation(); let signatures; let transaction: Transaction; switch (transactionType) { case 'funding': - signatures = await this.ledgerApp.signPsbt(psbt.toBase64(), nativeSegwitWalletPolicy, null); + signatures = await this.ledgerApp.signPsbt( + psbt.toBase64(), + nativeSegwitWalletPolicy, + null + ); addNativeSegwitSignaturesToPSBT(psbt, signatures); transaction = Transaction.fromPSBT(psbt.toBuffer()); transaction.finalize(); diff --git a/src/dlc-handlers/private-key-dlc-handler.ts b/src/dlc-handlers/private-key-dlc-handler.ts index 874e6e2..bf4edaa 100644 --- a/src/dlc-handlers/private-key-dlc-handler.ts +++ b/src/dlc-handlers/private-key-dlc-handler.ts @@ -1,11 +1,11 @@ /** @format */ - import { Transaction, p2wpkh } from '@scure/btc-signer'; import { P2Ret, P2TROut } from '@scure/btc-signer/payment'; import { Signer } from '@scure/btc-signer/transaction'; import { BIP32Interface } from 'bip32'; import { Network } from 'bitcoinjs-lib'; import { bitcoin, regtest, testnet } from 'bitcoinjs-lib/src/networks.js'; + import { createTaprootMultisigPayment, deriveUnhardenedKeyPairFromRootPrivateKey, @@ -14,9 +14,9 @@ import { getFeeRate, getUnspendableKeyCommittedToUUID, } from '../functions/bitcoin-functions.js'; -import { RawVault } from '../models/ethereum-models.js'; import { createClosingTransaction, createFundingTransaction } from '../functions/psbt-functions.js'; import { RequiredPayment } from '../models/bitcoin-models.js'; +import { RawVault } from '../models/ethereum-models.js'; interface RequiredKeyPair { nativeSegwitDerivedKeyPair: BIP32Interface; @@ -40,15 +40,22 @@ export class PrivateKeyDLCHandler { switch (bitcoinNetwork) { case bitcoin: this.bitcoinBlockchainAPI = 'https://mempool.space/api'; - this.bitcoinBlockchainFeeRecommendationAPI = 'https://mempool.space/api/v1/fees/recommended'; + this.bitcoinBlockchainFeeRecommendationAPI = + 'https://mempool.space/api/v1/fees/recommended'; break; case testnet: this.bitcoinBlockchainAPI = 'https://mempool.space/testnet/api'; - this.bitcoinBlockchainFeeRecommendationAPI = 'https://mempool.space/testnet/api/v1/fees/recommended'; + this.bitcoinBlockchainFeeRecommendationAPI = + 'https://mempool.space/testnet/api/v1/fees/recommended'; break; case regtest: - if (bitcoinBlockchainAPI === undefined || bitcoinBlockchainFeeRecommendationAPI === undefined) { - throw new Error('Regtest requires a Bitcoin Blockchain API and a Bitcoin Blockchain Fee Recommendation API'); + if ( + bitcoinBlockchainAPI === undefined || + bitcoinBlockchainFeeRecommendationAPI === undefined + ) { + throw new Error( + 'Regtest requires a Bitcoin Blockchain API and a Bitcoin Blockchain Fee Recommendation API' + ); } this.bitcoinBlockchainAPI = bitcoinBlockchainAPI; this.bitcoinBlockchainFeeRecommendationAPI = bitcoinBlockchainFeeRecommendationAPI; @@ -125,11 +132,20 @@ export class PrivateKeyDLCHandler { private handlePayment(vaultUUID: string, attestorGroupPublicKey: string): RequiredPayment { try { const unspendablePublicKey = getUnspendableKeyCommittedToUUID(vaultUUID, this.bitcoinNetwork); - const unspendableDerivedPublicKey = deriveUnhardenedPublicKey(unspendablePublicKey, this.bitcoinNetwork); + const unspendableDerivedPublicKey = deriveUnhardenedPublicKey( + unspendablePublicKey, + this.bitcoinNetwork + ); - const attestorDerivedPublicKey = deriveUnhardenedPublicKey(attestorGroupPublicKey, this.bitcoinNetwork); + const attestorDerivedPublicKey = deriveUnhardenedPublicKey( + attestorGroupPublicKey, + this.bitcoinNetwork + ); - const nativeSegwitPayment = p2wpkh(this.derivedKeyPair.nativeSegwitDerivedKeyPair.publicKey, this.bitcoinNetwork); + const nativeSegwitPayment = p2wpkh( + this.derivedKeyPair.nativeSegwitDerivedKeyPair.publicKey, + this.bitcoinNetwork + ); console.log(nativeSegwitPayment.address); const taprootMultisigPayment = createTaprootMultisigPayment( unspendableDerivedPublicKey, @@ -155,7 +171,10 @@ export class PrivateKeyDLCHandler { feeRateMultiplier?: number, customFeeRate?: bigint ): Promise { - const { nativeSegwitPayment, taprootMultisigPayment } = this.handlePayment(vault.uuid, attestorGroupPublicKey); + const { nativeSegwitPayment, taprootMultisigPayment } = this.handlePayment( + vault.uuid, + attestorGroupPublicKey + ); if (nativeSegwitPayment.address === undefined || taprootMultisigPayment.address === undefined) { throw new Error('Could not get Addresses from Payments'); @@ -168,7 +187,8 @@ export class PrivateKeyDLCHandler { } const feeRate = - customFeeRate ?? BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); + customFeeRate ?? + BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); const fundingPSBT = await createFundingTransaction( vault.valueLocked.toBigInt(), @@ -201,7 +221,8 @@ export class PrivateKeyDLCHandler { } const feeRate = - customFeeRate ?? BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); + customFeeRate ?? + BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); const closingPSBT = createClosingTransaction( vault.valueLocked.toBigInt(), diff --git a/src/dlc-handlers/software-wallet-dlc-handler.ts b/src/dlc-handlers/software-wallet-dlc-handler.ts index b79fcf0..bfe2218 100644 --- a/src/dlc-handlers/software-wallet-dlc-handler.ts +++ b/src/dlc-handlers/software-wallet-dlc-handler.ts @@ -1,8 +1,9 @@ /** @format */ - import { Transaction, p2wpkh } from '@scure/btc-signer'; +import { P2Ret, P2TROut } from '@scure/btc-signer/payment'; import { Network } from 'bitcoinjs-lib'; import { bitcoin, regtest, testnet } from 'bitcoinjs-lib/src/networks.js'; + import { createTaprootMultisigPayment, deriveUnhardenedPublicKey, @@ -10,10 +11,9 @@ import { getFeeRate, getUnspendableKeyCommittedToUUID, } from '../functions/bitcoin-functions.js'; +import { createClosingTransaction, createFundingTransaction } from '../functions/psbt-functions.js'; import { RequiredPayment } from '../models/bitcoin-models.js'; -import { P2Ret, P2TROut } from '@scure/btc-signer/payment'; import { RawVault } from '../models/ethereum-models.js'; -import { createClosingTransaction, createFundingTransaction } from '../functions/psbt-functions.js'; export class SoftwareWalletDLCHandler { private nativeSegwitDerivedPublicKey: string; @@ -33,15 +33,22 @@ export class SoftwareWalletDLCHandler { switch (bitcoinNetwork) { case bitcoin: this.bitcoinBlockchainAPI = 'https://mempool.space/api'; - this.bitcoinBlockchainFeeRecommendationAPI = 'https://mempool.space/api/v1/fees/recommended'; + this.bitcoinBlockchainFeeRecommendationAPI = + 'https://mempool.space/api/v1/fees/recommended'; break; case testnet: this.bitcoinBlockchainAPI = 'https://mempool.space/testnet/api'; - this.bitcoinBlockchainFeeRecommendationAPI = 'https://mempool.space/testnet/api/v1/fees/recommended'; + this.bitcoinBlockchainFeeRecommendationAPI = + 'https://mempool.space/testnet/api/v1/fees/recommended'; break; case regtest: - if (bitcoinBlockchainAPI === undefined || bitcoinBlockchainFeeRecommendationAPI === undefined) { - throw new Error('Regtest requires a Bitcoin Blockchain API and a Bitcoin Blockchain Fee Recommendation API'); + if ( + bitcoinBlockchainAPI === undefined || + bitcoinBlockchainFeeRecommendationAPI === undefined + ) { + throw new Error( + 'Regtest requires a Bitcoin Blockchain API and a Bitcoin Blockchain Fee Recommendation API' + ); } this.bitcoinBlockchainAPI = bitcoinBlockchainAPI; this.bitcoinBlockchainFeeRecommendationAPI = bitcoinBlockchainFeeRecommendationAPI; @@ -97,12 +104,21 @@ export class SoftwareWalletDLCHandler { async createPayment(vaultUUID: string, attestorGroupPublicKey: string): Promise { try { - const nativeSegwitPayment = p2wpkh(Buffer.from(this.nativeSegwitDerivedPublicKey, 'hex'), this.bitcoinNetwork); + const nativeSegwitPayment = p2wpkh( + Buffer.from(this.nativeSegwitDerivedPublicKey, 'hex'), + this.bitcoinNetwork + ); const unspendablePublicKey = getUnspendableKeyCommittedToUUID(vaultUUID, this.bitcoinNetwork); - const unspendableDerivedPublicKey = deriveUnhardenedPublicKey(unspendablePublicKey, this.bitcoinNetwork); + const unspendableDerivedPublicKey = deriveUnhardenedPublicKey( + unspendablePublicKey, + this.bitcoinNetwork + ); - const attestorDerivedPublicKey = deriveUnhardenedPublicKey(attestorGroupPublicKey, this.bitcoinNetwork); + const attestorDerivedPublicKey = deriveUnhardenedPublicKey( + attestorGroupPublicKey, + this.bitcoinNetwork + ); const taprootMultisigPayment = createTaprootMultisigPayment( unspendableDerivedPublicKey, @@ -117,18 +133,29 @@ export class SoftwareWalletDLCHandler { } } - async createFundingPSBT(vault: RawVault, feeRateMultiplier?: number, customFeeRate?: bigint): Promise { + async createFundingPSBT( + vault: RawVault, + feeRateMultiplier?: number, + customFeeRate?: bigint + ): Promise { try { const { nativeSegwitPayment, taprootMultisigPayment } = this.getPaymentInformation(); - if (taprootMultisigPayment.address === undefined || nativeSegwitPayment.address === undefined) { + if ( + taprootMultisigPayment.address === undefined || + nativeSegwitPayment.address === undefined + ) { throw new Error('Payment Address is undefined'); } const feeRate = - customFeeRate ?? BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); + customFeeRate ?? + BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); - const addressBalance = await getBalance(nativeSegwitPayment.address, this.bitcoinBlockchainAPI); + const addressBalance = await getBalance( + nativeSegwitPayment.address, + this.bitcoinBlockchainAPI + ); if (BigInt(addressBalance) < vault.valueLocked.toBigInt()) { throw new Error('Insufficient Funds'); @@ -159,12 +186,16 @@ export class SoftwareWalletDLCHandler { try { const { nativeSegwitPayment, taprootMultisigPayment } = this.getPaymentInformation(); - if (taprootMultisigPayment.address === undefined || nativeSegwitPayment.address === undefined) { + if ( + taprootMultisigPayment.address === undefined || + nativeSegwitPayment.address === undefined + ) { throw new Error('Payment Address is undefined'); } const feeRate = - customFeeRate ?? BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); + customFeeRate ?? + BigInt(await getFeeRate(this.bitcoinBlockchainFeeRecommendationAPI, feeRateMultiplier)); const closingTransaction = createClosingTransaction( vault.valueLocked.toBigInt(), diff --git a/src/functions/bitcoin-functions.ts b/src/functions/bitcoin-functions.ts index e7b095a..e04c475 100644 --- a/src/functions/bitcoin-functions.ts +++ b/src/functions/bitcoin-functions.ts @@ -1,15 +1,31 @@ /** @format */ -import { Address, OutScript, Transaction, p2ms, p2pk, p2tr, p2tr_ns, p2wpkh } from '@scure/btc-signer'; +import { + Address, + OutScript, + Transaction, + p2ms, + p2pk, + p2tr, + p2tr_ns, + p2wpkh, +} from '@scure/btc-signer'; import { P2Ret, P2TROut } from '@scure/btc-signer/payment'; import { TransactionInput } from '@scure/btc-signer/psbt'; import { BIP32Factory, BIP32Interface } from 'bip32'; import { Network } from 'bitcoinjs-lib'; import { bitcoin, regtest, testnet } from 'bitcoinjs-lib/src/networks.js'; import * as ellipticCurveCryptography from 'tiny-secp256k1'; -import { BitcoinInputSigningConfig, FeeRates, PaymentTypes, UTXO } from '../models/bitcoin-models.js'; + +import { + BitcoinInputSigningConfig, + FeeRates, + PaymentTypes, + UTXO, +} from '../models/bitcoin-models.js'; import { createRangeFromLength, isDefined, isUndefined } from '../utilities/index.js'; -const TAPROOT_UNSPENDABLE_KEY_HEX = '0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0'; +const TAPROOT_UNSPENDABLE_KEY_HEX = + '0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0'; const ECDSA_PUBLIC_KEY_LENGTH = 33; const bip32 = BIP32Factory(ellipticCurveCryptography); @@ -20,7 +36,10 @@ const bip32 = BIP32Factory(ellipticCurveCryptography); * @param bitcoinNetwork - The Bitcoin Network to use. * @returns The Public Key derived at the Unhardened Path. */ -export function deriveUnhardenedPublicKey(extendedPublicKey: string, bitcoinNetwork: Network): Buffer { +export function deriveUnhardenedPublicKey( + extendedPublicKey: string, + bitcoinNetwork: Network +): Buffer { return bip32.fromBase58(extendedPublicKey, bitcoinNetwork).derivePath('0/0').publicKey; } @@ -42,9 +61,13 @@ export function deriveUnhardenedKeyPairFromRootPrivateKey( case bitcoin: switch (paymentType) { case 'p2wpkh': - return bip32.fromBase58(rootPrivateKey, bitcoinNetwork).derivePath(`m/84'/0'/${accountIndex}'/0/0`); + return bip32 + .fromBase58(rootPrivateKey, bitcoinNetwork) + .derivePath(`m/84'/0'/${accountIndex}'/0/0`); case 'p2tr': - return bip32.fromBase58(rootPrivateKey, bitcoinNetwork).derivePath(`m/86'/0'/${accountIndex}'/0/0`); + return bip32 + .fromBase58(rootPrivateKey, bitcoinNetwork) + .derivePath(`m/86'/0'/${accountIndex}'/0/0`); default: throw new Error('Unsupported Payment Type'); } @@ -52,9 +75,13 @@ export function deriveUnhardenedKeyPairFromRootPrivateKey( case regtest: switch (paymentType) { case 'p2wpkh': - return bip32.fromBase58(rootPrivateKey, bitcoinNetwork).derivePath(`m/84'/1'/${accountIndex}'/0/0`); + return bip32 + .fromBase58(rootPrivateKey, bitcoinNetwork) + .derivePath(`m/84'/1'/${accountIndex}'/0/0`); case 'p2tr': - return bip32.fromBase58(rootPrivateKey, bitcoinNetwork).derivePath(`m/86'/1'/${accountIndex}'/0/0`); + return bip32 + .fromBase58(rootPrivateKey, bitcoinNetwork) + .derivePath(`m/86'/1'/${accountIndex}'/0/0`); default: throw new Error('Unsupported Payment Type'); } @@ -108,7 +135,10 @@ function checkFeeRate(feeRate: number | undefined): number { * * @returns A promise that resolves to the hour fee rate. */ -export async function getFeeRate(bitcoinBlockchainAPIFeeURL: string, feeRateMultiplier?: number): Promise { +export async function getFeeRate( + bitcoinBlockchainAPIFeeURL: string, + feeRateMultiplier?: number +): Promise { const response = await fetch(bitcoinBlockchainAPIFeeURL); if (!response.ok) { @@ -135,7 +165,10 @@ export async function getFeeRate(bitcoinBlockchainAPIFeeURL: string, feeRateMult * @param bitcoinNativeSegwitTransaction - The User's Native Segwit Payment Transaction. * @returns A Promise that resolves to the UTXOs of the User's Native Segwit Address. */ -export async function getUTXOs(bitcoinNativeSegwitTransaction: P2Ret, bitcoinBlockchainAPIURL: string): Promise { +export async function getUTXOs( + bitcoinNativeSegwitTransaction: P2Ret, + bitcoinBlockchainAPIURL: string +): Promise { const utxoEndpoint = `${bitcoinBlockchainAPIURL}/address/${bitcoinNativeSegwitTransaction.address}/utxo`; const utxoResponse = await fetch(utxoEndpoint); @@ -169,7 +202,10 @@ export async function getUTXOs(bitcoinNativeSegwitTransaction: P2Ret, bitcoinBlo * @param bitcoinAddress - The User's Bitcoin Address. * @returns A Promise that resolves to the Balance of the User's Bitcoin Address. */ -export async function getBalance(bitcoinAddress: string, bitcoinBlockchainAPIURL: string): Promise { +export async function getBalance( + bitcoinAddress: string, + bitcoinBlockchainAPIURL: string +): Promise { const utxoResponse = await fetch(`${bitcoinBlockchainAPIURL}/address/${bitcoinAddress}/utxo`); if (!utxoResponse.ok) { @@ -189,7 +225,10 @@ export async function getBalance(bitcoinAddress: string, bitcoinBlockchainAPIURL * @param bitcoinNetwork - The Bitcoin Network to use. * @returns The Fee Recipient's Address. */ -export function getFeeRecipientAddressFromPublicKey(feePublicKey: string, bitcoinNetwork: Network): string { +export function getFeeRecipientAddressFromPublicKey( + feePublicKey: string, + bitcoinNetwork: Network +): string { const feePublicKeyBuffer = Buffer.from(feePublicKey, 'hex'); const { address } = p2wpkh(feePublicKeyBuffer, bitcoinNetwork); if (!address) throw new Error('Could not create Fee Address from Public Key'); @@ -202,7 +241,10 @@ export function getFeeRecipientAddressFromPublicKey(feePublicKey: string, bitcoi * @param transaction - The Transaction to broadcast. * @returns A Promise that resolves to the Response from the Broadcast Request. */ -export async function broadcastTransaction(transaction: string, bitcoinBlockchainAPIURL: string): Promise { +export async function broadcastTransaction( + transaction: string, + bitcoinBlockchainAPIURL: string +): Promise { try { const response = await fetch(`${bitcoinBlockchainAPIURL}/tx`, { method: 'POST', @@ -227,11 +269,16 @@ export async function broadcastTransaction(transaction: string, bitcoinBlockchai * @param bitcoinNetwork - The Bitcoin Network to use. * @returns The Unspendable Key Committed to the Vault UUID. */ -export function getUnspendableKeyCommittedToUUID(vaultUUID: string, bitcoinNetwork: Network): string { +export function getUnspendableKeyCommittedToUUID( + vaultUUID: string, + bitcoinNetwork: Network +): string { const publicKeyBuffer = Buffer.from(TAPROOT_UNSPENDABLE_KEY_HEX, 'hex'); const chainCodeBuffer = Buffer.from(vaultUUID.slice(2), 'hex'); - const unspendablePublicKey = bip32.fromPublicKey(publicKeyBuffer, chainCodeBuffer, bitcoinNetwork).toBase58(); + const unspendablePublicKey = bip32 + .fromPublicKey(publicKeyBuffer, chainCodeBuffer, bitcoinNetwork) + .toBase58(); return unspendablePublicKey; } @@ -242,13 +289,25 @@ export function getUnspendableKeyCommittedToUUID(vaultUUID: string, bitcoinNetwo * @param input - The Input. * @param bitcoinNetwork - The Bitcoin Network to use. */ -function getInputPaymentType(index: number, input: TransactionInput, bitcoinNetwork: Network): PaymentTypes { +function getInputPaymentType( + index: number, + input: TransactionInput, + bitcoinNetwork: Network +): PaymentTypes { const bitcoinAddress = getBitcoinInputAddress(index, input, bitcoinNetwork); if (bitcoinAddress === '') throw new Error('Bitcoin Address is empty'); - if (bitcoinAddress.startsWith('bc1p') || bitcoinAddress.startsWith('tb1p') || bitcoinAddress.startsWith('bcrt1p')) + if ( + bitcoinAddress.startsWith('bc1p') || + bitcoinAddress.startsWith('tb1p') || + bitcoinAddress.startsWith('bcrt1p') + ) return 'p2tr'; - if (bitcoinAddress.startsWith('bc1q') || bitcoinAddress.startsWith('tb1q') || bitcoinAddress.startsWith('bcrt1q')) + if ( + bitcoinAddress.startsWith('bc1q') || + bitcoinAddress.startsWith('tb1q') || + bitcoinAddress.startsWith('bcrt1q') + ) return 'p2wpkh'; throw new Error('Unable to infer payment type from BitcoinAddress'); } @@ -259,8 +318,13 @@ function getInputPaymentType(index: number, input: TransactionInput, bitcoinNetw * @param input - The Input. * @param bitcoinNetwork - The Bitcoin Network to use. */ -function getBitcoinInputAddress(index: number, input: TransactionInput, bitcoinNetwork: Network): string { - if (isDefined(input.witnessUtxo)) return getAddressFromOutScript(input.witnessUtxo.script, bitcoinNetwork); +function getBitcoinInputAddress( + index: number, + input: TransactionInput, + bitcoinNetwork: Network +): string { + if (isDefined(input.witnessUtxo)) + return getAddressFromOutScript(input.witnessUtxo.script, bitcoinNetwork); if (isDefined(input.nonWitnessUtxo)) return getAddressFromOutScript(input.nonWitnessUtxo.outputs[index]?.script, bitcoinNetwork); return ''; @@ -320,7 +384,7 @@ export function createBitcoinInputSigningConfiguration( const transaction = Transaction.fromPSBT(psbt); const indexesToSign = createRangeFromLength(transaction.inputsLength); - return indexesToSign.map((inputIndex) => { + return indexesToSign.map(inputIndex => { const input = transaction.getInput(inputIndex); if (isUndefined(input.index)) throw new Error('Input must have an index for payment type'); @@ -356,10 +420,13 @@ export function getInputByPaymentTypeArray( ): [BitcoinInputSigningConfig, PaymentTypes][] { const transaction = Transaction.fromPSBT(psbt); - return signingConfiguration.map((config) => { + return signingConfiguration.map(config => { const inputIndex = transaction.getInput(config.index).index; if (isUndefined(inputIndex)) throw new Error('Input must have an index for payment type'); - return [config, getInputPaymentType(inputIndex, transaction.getInput(config.index), bitcoinNetwork)]; + return [ + config, + getInputPaymentType(inputIndex, transaction.getInput(config.index), bitcoinNetwork), + ]; }); } @@ -368,6 +435,7 @@ export function getInputByPaymentTypeArray( * @param publicKey - The ECDSA Public Key. */ export function ecdsaPublicKeyToSchnorr(publicKey: Buffer): Buffer { - if (publicKey.byteLength !== ECDSA_PUBLIC_KEY_LENGTH) throw new Error('Invalid Public Key Length'); + if (publicKey.byteLength !== ECDSA_PUBLIC_KEY_LENGTH) + throw new Error('Invalid Public Key Length'); return publicKey.subarray(1); } diff --git a/src/functions/ethereum-functions.ts b/src/functions/ethereum-functions.ts index 39a3f13..2b3f96c 100644 --- a/src/functions/ethereum-functions.ts +++ b/src/functions/ethereum-functions.ts @@ -1,5 +1,6 @@ /** @format */ import { Contract, Wallet, providers } from 'ethers'; + import { EthereumError } from '../models/errors.js'; import { DLCEthereumContracts, @@ -31,7 +32,9 @@ export async function fetchEthereumDeploymentPlan( } } -export function getProvider(rpcEndpoint: string): providers.JsonRpcProvider | providers.WebSocketProvider { +export function getProvider( + rpcEndpoint: string +): providers.JsonRpcProvider | providers.WebSocketProvider { if (rpcEndpoint.startsWith('http') || rpcEndpoint.startsWith('https')) { return new providers.JsonRpcProvider(rpcEndpoint); } else if (rpcEndpoint.startsWith('ws') || rpcEndpoint.startsWith('wss')) { @@ -47,15 +50,23 @@ export function getEthereumontract( signerOrProvider: Wallet | providers.JsonRpcSigner | providers.JsonRpcProvider ): Contract { try { - const contractDeploymentPlan = ethereumDeploymentPlans.find((plan) => plan.contract.name === contractName); + const contractDeploymentPlan = ethereumDeploymentPlans.find( + plan => plan.contract.name === contractName + ); if (!contractDeploymentPlan) { throw new Error(`${contractName} Contract not found in Deployment Plans`); } - return new Contract(contractDeploymentPlan.contract.address, contractDeploymentPlan.contract.abi, signerOrProvider); + return new Contract( + contractDeploymentPlan.contract.address, + contractDeploymentPlan.contract.abi, + signerOrProvider + ); } catch (error: any) { - throw new EthereumError(`Could not find ${contractName} Contract in Deployment Plans: ${error}`); + throw new EthereumError( + `Could not find ${contractName} Contract in Deployment Plans: ${error}` + ); } } @@ -65,7 +76,11 @@ export function getEthereumContracts( readOnlyProvider: providers.JsonRpcProvider ): DLCEthereumContracts { const protocolContract = getEthereumontract(ethereumDeploymentPlans, 'TokenManager', signer); - const readOnlyProtocolContract = getEthereumontract(ethereumDeploymentPlans, 'TokenManager', readOnlyProvider); + const readOnlyProtocolContract = getEthereumontract( + ethereumDeploymentPlans, + 'TokenManager', + readOnlyProvider + ); const dlcManagerContract = getEthereumontract(ethereumDeploymentPlans, 'DLCManager', signer); const dlcBTCContract = getEthereumontract(ethereumDeploymentPlans, 'DLCBTC', signer); @@ -76,8 +91,16 @@ export function getReadOnlyEthereumContracts( ethereumDeploymentPlans: EthereumDeploymentPlan[], readOnlyProvider: providers.JsonRpcProvider ): { protocolContract: Contract; dlcManagerContract: Contract; dlcBTCContract: Contract } { - const protocolContract = getEthereumontract(ethereumDeploymentPlans, 'TokenManager', readOnlyProvider); - const dlcManagerContract = getEthereumontract(ethereumDeploymentPlans, 'DLCManager', readOnlyProvider); + const protocolContract = getEthereumontract( + ethereumDeploymentPlans, + 'TokenManager', + readOnlyProvider + ); + const dlcManagerContract = getEthereumontract( + ethereumDeploymentPlans, + 'DLCManager', + readOnlyProvider + ); const dlcBTCContract = getEthereumontract(ethereumDeploymentPlans, 'DLCBTC', readOnlyProvider); return { protocolContract, dlcManagerContract, dlcBTCContract }; @@ -85,7 +108,7 @@ export function getReadOnlyEthereumContracts( export async function getLockedBTCBalance(userVaults: RawVault[]): Promise { try { - const fundedVaults = userVaults.filter((vault) => vault.status === VaultState.Funded); + const fundedVaults = userVaults.filter(vault => vault.status === VaultState.Funded); const totalCollateral = fundedVaults.reduce( (sum: number, vault: RawVault) => sum + vault.valueLocked.toNumber(), 0 diff --git a/src/functions/psbt-functions.ts b/src/functions/psbt-functions.ts index bbac6f9..f3f0e81 100644 --- a/src/functions/psbt-functions.ts +++ b/src/functions/psbt-functions.ts @@ -1,13 +1,17 @@ /** @format */ import { hexToBytes } from '@noble/hashes/utils'; import { p2wpkh, selectUTXO } from '@scure/btc-signer'; +import { P2Ret, P2TROut } from '@scure/btc-signer/payment'; import { Network, Psbt } from 'bitcoinjs-lib'; import { PartialSignature } from 'ledger-bitcoin/build/main/lib/appClient.js'; -import { P2Ret, P2TROut } from '@scure/btc-signer/payment'; import { BitcoinInputSigningConfig, PaymentTypes } from '../models/bitcoin-models.js'; import { reverseBytes } from '../utilities/index.js'; -import { ecdsaPublicKeyToSchnorr, getFeeRecipientAddressFromPublicKey, getUTXOs } from './bitcoin-functions.js'; +import { + ecdsaPublicKeyToSchnorr, + getFeeRecipientAddressFromPublicKey, + getUTXOs, +} from './bitcoin-functions.js'; /** * Creates a Funding Transaction to fund the Multisig Transaction. @@ -146,11 +150,15 @@ export async function updateNativeSegwitInputs( try { await addNativeSegwitUTXOLedgerProps(psbt, inputsToUpdate, bitcoinBlockchainAPIURL); } catch (e) { - // eslint-disable-next-line no-console - console.error('Error adding UTXO Ledger Props:', e); + // Intentionally Ignored } - await addNativeSegwitBip32Derivation(psbt, masterFingerprint, nativeSegwitPublicKey, inputsToUpdate); + await addNativeSegwitBip32Derivation( + psbt, + masterFingerprint, + nativeSegwitPublicKey, + inputsToUpdate + ); return psbt; } @@ -232,8 +240,10 @@ async function addNativeSegwitUTXOLedgerProps( bitcoinBlockchainAPIURL: string ): Promise { const inputTransactionHexes = await Promise.all( - psbt.txInputs.map(async (input) => - (await fetch(`${bitcoinBlockchainAPIURL}/tx/${reverseBytes(input.hash).toString('hex')}/hex`)).text() + psbt.txInputs.map(async input => + ( + await fetch(`${bitcoinBlockchainAPIURL}/tx/${reverseBytes(input.hash).toString('hex')}/hex`) + ).text() ) ); @@ -281,7 +291,10 @@ async function addNativeSegwitBip32Derivation( * @param signatures - An array of tuples containing the index of the input and the PartialSignature. * @returns The updated PSBT. */ -export function addNativeSegwitSignaturesToPSBT(psbt: Psbt, signatures: [number, PartialSignature][]): void { +export function addNativeSegwitSignaturesToPSBT( + psbt: Psbt, + signatures: [number, PartialSignature][] +): void { signatures.forEach(([index, signature]) => psbt.updateInput(index, { partialSig: [signature] })); } @@ -291,7 +304,10 @@ export function addNativeSegwitSignaturesToPSBT(psbt: Psbt, signatures: [number, * @param signatures - An array of tuples containing the index of the input and the PartialSignature. * @returns The updated PSBT. */ -export function addTaprootInputSignaturesToPSBT(psbt: Psbt, signatures: [number, PartialSignature][]): void { +export function addTaprootInputSignaturesToPSBT( + psbt: Psbt, + signatures: [number, PartialSignature][] +): void { signatures.forEach(([index, signature]) => psbt.updateInput(index, { tapScriptSig: [ diff --git a/src/index.ts b/src/index.ts index 630beef..84322d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,6 @@ /** @format */ - -import { PrivateKeyDLCHandler } from './dlc-handlers/private-key-dlc-handler.js'; import { LedgerDLCHandler } from './dlc-handlers/ledger-dlc-handler.js'; +import { PrivateKeyDLCHandler } from './dlc-handlers/private-key-dlc-handler.js'; import { SoftwareWalletDLCHandler } from './dlc-handlers/software-wallet-dlc-handler.js'; import { EthereumHandler } from './network-handlers/ethereum-handler.js'; import { ReadOnlyEthereumHandler } from './network-handlers/read-only-ethereum-handler.js'; diff --git a/src/ledger-functions.ts b/src/ledger-functions.ts index a9f14f6..1397993 100644 --- a/src/ledger-functions.ts +++ b/src/ledger-functions.ts @@ -1,7 +1,7 @@ /** @format */ - import Transport from '@ledgerhq/hw-transport-node-hid'; import { AppClient } from 'ledger-bitcoin'; + import { LEDGER_APPS_MAP } from './constants/ledger-constants.js'; import { delay } from './utilities/index.js'; diff --git a/src/models/bitcoin-models.ts b/src/models/bitcoin-models.ts index 137d440..eb7b8bf 100644 --- a/src/models/bitcoin-models.ts +++ b/src/models/bitcoin-models.ts @@ -1,5 +1,4 @@ /** @format */ - import { P2Ret, P2TROut } from '@scure/btc-signer/payment'; interface TransactionStatus { diff --git a/src/models/ethereum-models.ts b/src/models/ethereum-models.ts index 2442106..b05d460 100644 --- a/src/models/ethereum-models.ts +++ b/src/models/ethereum-models.ts @@ -1,5 +1,4 @@ /** @format */ - import { BigNumber, Contract } from 'ethers'; export interface EthereumNetwork { diff --git a/src/models/index.ts b/src/models/index.ts index 735c9bc..9992519 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,6 +1,10 @@ /** @format */ +// ts-unused-exports:disable-next-line export { Network } from 'bitcoinjs-lib/src/networks.js'; +// ts-unused-exports:disable-next-line export * from '../models/bitcoin-models.js'; +// ts-unused-exports:disable-next-line export * from '../models/errors.js'; +// ts-unused-exports:disable-next-line export * from '../models/ethereum-models.js'; diff --git a/src/network-handlers/ethereum-handler.ts b/src/network-handlers/ethereum-handler.ts index 180fdbe..943c508 100644 --- a/src/network-handlers/ethereum-handler.ts +++ b/src/network-handlers/ethereum-handler.ts @@ -1,9 +1,13 @@ /** @format */ - import { Wallet, providers } from 'ethers'; + import { getEthereumContracts, getProvider } from '../functions/ethereum-functions.js'; import { EthereumError } from '../models/errors.js'; -import { DLCEthereumContracts, EthereumDeploymentPlan, RawVault } from '../models/ethereum-models.js'; +import { + DLCEthereumContracts, + EthereumDeploymentPlan, + RawVault, +} from '../models/ethereum-models.js'; export class EthereumHandler { private ethereumContracts: DLCEthereumContracts; @@ -23,7 +27,11 @@ export class EthereumHandler { signer = ethereumPrivateKeyOrProvider; } - this.ethereumContracts = getEthereumContracts(ethereumDeploymentPlans, signer, readOnlyProvider); + this.ethereumContracts = getEthereumContracts( + ethereumDeploymentPlans, + signer, + readOnlyProvider + ); } async getAllVaults(): Promise { @@ -36,7 +44,8 @@ export class EthereumHandler { } async getRawVault(vaultUUID: string): Promise { - const vault: RawVault = await this.ethereumContracts.readOnlyProtocolContract.getVault(vaultUUID); + const vault: RawVault = + await this.ethereumContracts.readOnlyProtocolContract.getVault(vaultUUID); if (!vault) throw new Error('Vault not found'); return vault; } @@ -44,7 +53,8 @@ export class EthereumHandler { async setupVault(bitcoinDepositAmount: number): Promise { try { await this.ethereumContracts.protocolContract.callStatic.setupVault(bitcoinDepositAmount); - const transaction = await this.ethereumContracts.protocolContract.setupVault(bitcoinDepositAmount); + const transaction = + await this.ethereumContracts.protocolContract.setupVault(bitcoinDepositAmount); return await transaction.wait(); } catch (error: any) { throw new EthereumError(`Could not setup Vault: ${error}`); @@ -72,7 +82,8 @@ export class EthereumHandler { async getAttestorGroupPublicKey(): Promise { try { - const attestorGroupPubKey = await this.ethereumContracts.dlcManagerContract.attestorGroupPubKey(); + const attestorGroupPubKey = + await this.ethereumContracts.dlcManagerContract.attestorGroupPubKey(); if (!attestorGroupPubKey) throw new Error('Could not get Attestor Group Public Key'); return attestorGroupPubKey; } catch (error) { diff --git a/src/network-handlers/read-only-ethereum-handler.ts b/src/network-handlers/read-only-ethereum-handler.ts index 83c05ec..0694bac 100644 --- a/src/network-handlers/read-only-ethereum-handler.ts +++ b/src/network-handlers/read-only-ethereum-handler.ts @@ -1,6 +1,6 @@ /** @format */ - import { Event } from 'ethers'; + import { getProvider, getReadOnlyEthereumContracts } from '../functions/ethereum-functions.js'; import { EthereumError } from '../models/errors.js'; import { @@ -14,12 +14,16 @@ export class ReadOnlyEthereumHandler { private ethereumContracts: DLCReadOnlyEthereumContracts; constructor(ethereumDeploymentPlans: EthereumDeploymentPlan[], rpcEndpoint: string) { - this.ethereumContracts = getReadOnlyEthereumContracts(ethereumDeploymentPlans, getProvider(rpcEndpoint)); + this.ethereumContracts = getReadOnlyEthereumContracts( + ethereumDeploymentPlans, + getProvider(rpcEndpoint) + ); } async getAttestorGroupPublicKey(): Promise { try { - const attestorGroupPubKey = await this.ethereumContracts.dlcManagerContract.attestorGroupPubKey(); + const attestorGroupPubKey = + await this.ethereumContracts.dlcManagerContract.attestorGroupPubKey(); if (!attestorGroupPubKey) throw new Error('Could not get Attestor Group Public Key'); return attestorGroupPubKey; } catch (error) { @@ -50,11 +54,12 @@ export class ReadOnlyEthereumHandler { const fundedVaults: RawVault[] = []; while (true) { - const fetchedVaults: RawVault[] = await this.ethereumContracts.dlcManagerContract.getAllDLCs( - totalFetched, - totalFetched + amount - ); - fundedVaults.push(...fetchedVaults.filter((vault) => vault.status === VaultState.Funded)); + const fetchedVaults: RawVault[] = + await this.ethereumContracts.dlcManagerContract.getAllDLCs( + totalFetched, + totalFetched + amount + ); + fundedVaults.push(...fetchedVaults.filter(vault => vault.status === VaultState.Funded)); totalFetched += amount; if (fetchedVaults.length !== amount) break; } diff --git a/src/query-handlers/attestor-handler.ts b/src/query-handlers/attestor-handler.ts index 700cd9f..d6440a4 100644 --- a/src/query-handlers/attestor-handler.ts +++ b/src/query-handlers/attestor-handler.ts @@ -1,13 +1,15 @@ /** @format */ - import { AttestorError } from '../models/errors.js'; export class AttestorHandler { private attestorRootURLs: string[]; private ethereumChainID: string; - constructor(attestorRootURLs: string[], ethereumChainID: 'evm-arbitrum' | 'evm-arbsepolia' | 'evm-localhost') { - this.attestorRootURLs = attestorRootURLs; + constructor( + attestorRootURLs: string[], + ethereumChainID: 'evm-arbitrum' | 'evm-arbsepolia' | 'evm-localhost' + ) { + this.attestorRootURLs = attestorRootURLs; this.ethereumChainID = ethereumChainID; } @@ -17,29 +19,29 @@ export class AttestorHandler { closingPSBT: string, userNativeSegwitAddress: string ): Promise { - const createPSBTEndpoints = this.attestorRootURLs.map((url) => `${url}/app/create-psbt-event`); + const createPSBTEndpoints = this.attestorRootURLs.map(url => `${url}/app/create-psbt-event`); const body = JSON.stringify({ - uuid: vaultUUID, - funding_transaction: fundingTransaction, - closing_psbt: closingPSBT, - mint_address: userNativeSegwitAddress, - chain: this.ethereumChainID, - }); - - const requests = createPSBTEndpoints.map(async (url) => + uuid: vaultUUID, + funding_transaction: fundingTransaction, + closing_psbt: closingPSBT, + mint_address: userNativeSegwitAddress, + chain: this.ethereumChainID, + }); + + const requests = createPSBTEndpoints.map(async url => fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, - body + body, }) - .then((response) => (response.ok ? true : response.statusText)) - .catch((error) => error.message) + .then(response => (response.ok ? true : response.statusText)) + .catch(error => error.message) ); const responses = await Promise.all(requests); - const failedResponses = responses.filter((response) => response !== true); + const failedResponses = responses.filter(response => response !== true); if (failedResponses.length === createPSBTEndpoints.length) { throw new AttestorError( diff --git a/src/test.ts b/src/test.ts index 76d2662..e47ade5 100644 --- a/src/test.ts +++ b/src/test.ts @@ -1,7 +1,8 @@ /** @format */ - import { bytesToHex } from '@noble/hashes/utils'; import { regtest } from 'bitcoinjs-lib/src/networks.js'; +import { Event } from 'ethers'; + import { ethereumArbitrumSepolia } from './constants/ethereum-constants.js'; import { PrivateKeyDLCHandler } from './dlc-handlers/private-key-dlc-handler.js'; import { broadcastTransaction } from './functions/bitcoin-functions.js'; @@ -13,18 +14,19 @@ import { shiftValue } from './utilities/index.js'; async function runFlowWithPrivateKey() { const exampleNetwork = regtest; const exampleBitcoinBlockchainAPI = 'https://devnet.dlc.link/electrs'; - const exampleBitcoinBlockchainFeeRecommendationAPI = 'https://devnet.dlc.link/electrs/fee-estimates'; + const exampleBitcoinBlockchainFeeRecommendationAPI = + 'https://devnet.dlc.link/electrs/fee-estimates'; const exampleAttestorURLs = [ 'http://devnet.dlc.link/attestor-1', 'http://devnet.dlc.link/attestor-2', 'http://devnet.dlc.link/attestor-3', ]; const examplePrivateKey = - 'tprv8ZgxMBicQKsPeJ7iQfVEb34R3JoSyJ1J9z6wv1yXJkd1NMTRbmQiLkcZXgqQ277LMtszhnp2L2VmmHhFzoLD12fjyXcAvfnvs6qTJMMcKFq'; + ''; const exampleBitcoinAmount = 0.01; const ethereumPrivateKey = ''; - const deploymentPlansPromises = ['TokenManager', 'DLCManager', 'DLCBTC'].map((contractName) => { + const deploymentPlansPromises = ['TokenManager', 'DLCManager', 'DLCBTC'].map(contractName => { return fetchEthereumDeploymentPlan( contractName, ethereumArbitrumSepolia, @@ -46,13 +48,22 @@ async function runFlowWithPrivateKey() { if (!ethereumPrivateKey) { throw new Error('Ethereum Private Key not set'); } - const ethereumHandler = new EthereumHandler(deploymentPlans, ethereumPrivateKey, rpcEndpoint, readOnlyRPCEndpoint); + const ethereumHandler = new EthereumHandler( + deploymentPlans, + ethereumPrivateKey, + rpcEndpoint, + readOnlyRPCEndpoint + ); - const setupVaultTransactionReceipt = await ethereumHandler.setupVault(shiftValue(exampleBitcoinAmount)); + const setupVaultTransactionReceipt = await ethereumHandler.setupVault( + shiftValue(exampleBitcoinAmount) + ); if (!setupVaultTransactionReceipt) { throw new Error('Could not setup Vault'); } - const vaultUUID = setupVaultTransactionReceipt.events.find((event: any) => event.event === 'SetupVault').args[0]; + const vaultUUID = setupVaultTransactionReceipt.events.find( + (event: Event) => event.event === 'SetupVault' + ).args[0]; // Setup DLC Handler (with Private Key) const dlcHandler = new PrivateKeyDLCHandler( @@ -78,10 +89,11 @@ async function runFlowWithPrivateKey() { // Create Closing Transaction const closingTransaction = await dlcHandler.createClosingPSBT(vault, fundingTransaction.id, 2); - console.log('address', dlcHandler.payment?.nativeSegwitPayment.address); // Sign Closing Transaction const partiallySignedClosingTransaction = dlcHandler.signPSBT(closingTransaction, 'closing'); - const partiallySignedClosingTransactionHex = bytesToHex(partiallySignedClosingTransaction.toPSBT()); + const partiallySignedClosingTransactionHex = bytesToHex( + partiallySignedClosingTransaction.toPSBT() + ); const nativeSegwitAddress = dlcHandler.getVaultRelatedAddress('p2wpkh'); @@ -96,7 +108,10 @@ async function runFlowWithPrivateKey() { ); // Broadcast Funding Transaction - const fundingTransactionID = await broadcastTransaction(fundingTransaction.hex, exampleBitcoinBlockchainAPI); + const fundingTransactionID = await broadcastTransaction( + fundingTransaction.hex, + exampleBitcoinBlockchainAPI + ); console.log('Funding Transaction ID:', fundingTransactionID); console.log('Success'); diff --git a/src/utilities/index.ts b/src/utilities/index.ts index c053af9..3542722 100644 --- a/src/utilities/index.ts +++ b/src/utilities/index.ts @@ -1,5 +1,4 @@ /** @format */ - import { Decimal } from 'decimal.js'; export function shiftValue(value: number): number { @@ -48,7 +47,7 @@ export function isDefined(argument: T | undefined): argument is T { } export async function delay(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); + return new Promise(resolve => setTimeout(resolve, ms)); } export function reverseBytes(bytes: Buffer): Buffer;