Skip to content

Commit

Permalink
Merge branch '82-bitcoin-abstract-network' into 'dev'
Browse files Browse the repository at this point in the history
Resolve "Bitcoin: Abstract Network"

Closes #82

See merge request ergo/rosen-bridge/rosen-chains!89
  • Loading branch information
vorujack committed Feb 12, 2024
2 parents daf9e51 + 606c2f7 commit 1afb500
Show file tree
Hide file tree
Showing 15 changed files with 3,449 additions and 1,168 deletions.
4,136 changes: 2,973 additions & 1,163 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
]
},
"scripts": {
"lint": "npm run lint --workspaces",
"test": "npm run test --workspaces",
"coverage": "npm run coverage --workspaces",
"build": "npm run build --workspaces",
"type-check": "npm run type-check --workspaces",
"coverage": "npm run coverage --workspaces",
"lint": "npm run lint --workspaces",
"prepare": "husky install",
"release": "npm run release --workspaces",
"prepare": "husky install"
"test": "npm run test --workspaces",
"type-check": "npm run type-check --workspaces"
},
"devDependencies": {
"husky": "^8.0.1",
Expand Down
1 change: 1 addition & 0 deletions packages/chains/bitcoin/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
24 changes: 24 additions & 0 deletions packages/chains/bitcoin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# @rosen-chains/bitcoin

## Table of contents

- [Introduction](#introduction)
- [Installation](#installation)

## Introduction

this project contains bitcoin chain for Rosen-bridge

## Installation

npm:

```sh
npm i @rosen-chains/bitcoin
```

yarn:

```sh
yarn add @rosen-chains/bitcoin
```
230 changes: 230 additions & 0 deletions packages/chains/bitcoin/lib/BitcoinChain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import { AbstractLogger } from '@rosen-bridge/logger-interface';
import { Fee } from '@rosen-bridge/minimum-fee';
import {
AbstractUtxoChain,
BoxInfo,
ConfirmationStatus,
EventTrigger,
PaymentOrder,
PaymentTransaction,
SigningStatus,
TransactionAssetBalance,
TransactionType,
} from '@rosen-chains/abstract-chain';
import AbstractBitcoinNetwork from './network/AbstractBitcoinNetwork';
import BitcoinTransaction from './BitcoinTransaction';
import { BitcoinConfigs, BitcoinUtxo } from './types';

class BitcoinChain extends AbstractUtxoChain<BitcoinUtxo> {
declare network: AbstractBitcoinNetwork;
declare configs: BitcoinConfigs;
feeRatioDivisor: bigint;
protected signFunction: (txHash: Uint8Array) => Promise<string>;

constructor(
network: AbstractBitcoinNetwork,
configs: BitcoinConfigs,
feeRatioDivisor: bigint,
signFunction: (txHash: Uint8Array) => Promise<string>,
logger?: AbstractLogger
) {
super(network, configs, logger);
this.feeRatioDivisor = feeRatioDivisor;
this.signFunction = signFunction;
}

/**
* generates unsigned PaymentTransaction for payment order
* @param eventId the id of event
* @param txType transaction type
* @param order the payment order (list of single payments)
* @param unsignedTransactions ongoing unsigned PaymentTransactions (used for preventing double spend)
* @param serializedSignedTransactions the serialized string of ongoing signed transactions (used for chaining transaction)
* @returns the generated PaymentTransaction
*/
generateTransaction = (
eventId: string,
txType: TransactionType,
order: PaymentOrder,
unsignedTransactions: PaymentTransaction[],
serializedSignedTransactions: string[],
...extra: Array<any>
): Promise<BitcoinTransaction> => {
throw Error(`not implemented`);
};

/**
* gets input and output assets of a PaymentTransaction
* @param transaction the PaymentTransaction
* @returns an object containing the amount of input and output assets
*/
getTransactionAssets = (
transaction: PaymentTransaction
): Promise<TransactionAssetBalance> => {
throw Error(`not implemented`);
};

/**
* extracts payment order of a PaymentTransaction
* @param transaction the PaymentTransaction
* @returns the transaction payment order (list of single payments)
*/
extractTransactionOrder = (transaction: PaymentTransaction): PaymentOrder => {
throw Error(`not implemented`);
};

/**
* verifies transaction fee for a PaymentTransaction
* @param transaction the PaymentTransaction
* @returns true if the transaction fee is verified
*/
verifyTransactionFee = (transaction: PaymentTransaction): boolean => {
throw Error(`not implemented`);
};

/**
* verifies no token burned in a PaymentTransaction
* @param transaction the PaymentTransaction
* @returns true if no token burned
*/
verifyNoTokenBurned = async (
transaction: PaymentTransaction
): Promise<boolean> => {
// Bitcoin has no token and BTC cannot be burned
return true;
};

/**
* verifies additional conditions for a PaymentTransaction
* @param transaction the PaymentTransaction
* @returns true if the transaction is verified
*/
verifyTransactionExtraConditions = (
transaction: PaymentTransaction
): boolean => {
throw Error(`not implemented`);
};

/**
* verifies an event data with its corresponding lock transaction
* @param event the event trigger model
* @param feeConfig minimum fee and rsn ratio config for the event
* @returns true if the event is verified
*/
verifyEvent = (event: EventTrigger, feeConfig: Fee): Promise<boolean> => {
throw Error(`not implemented`);
};

/**
* checks if a transaction is still valid and can be sent to the network
* @param transaction the transaction
* @param signingStatus
* @returns true if the transaction is still valid
*/
isTxValid = (
transaction: PaymentTransaction,
signingStatus: SigningStatus = SigningStatus.Signed
): Promise<boolean> => {
throw Error(`not implemented`);
};

/**
* requests the corresponding signer service to sign the transaction
* @param transaction the transaction
* @param requiredSign the required number of sign
* @returns the signed transaction
*/
signTransaction = (
transaction: PaymentTransaction,
requiredSign: number
): Promise<PaymentTransaction> => {
throw Error(`not implemented`);
};

/**
* extracts confirmation status for a transaction
* @param transactionId the transaction id
* @param transactionType type of the transaction
* @returns the transaction confirmation status
*/
getTxConfirmationStatus = (
transactionId: string,
transactionType: TransactionType
): Promise<ConfirmationStatus> => {
throw Error(`not implemented`);
};

/**
* submits a transaction to the blockchain
* @param transaction the transaction
*/
submitTransaction = (transaction: PaymentTransaction): Promise<void> => {
throw Error(`not implemented`);
};

/**
* checks if a transaction is in mempool (returns false if the chain has no mempool)
* @param transactionId the transaction id
* @returns true if the transaction is in mempool
*/
isTxInMempool = (transactionId: string): Promise<boolean> => {
throw Error(`not implemented`);
};

/**
* gets the minimum amount of native token for transferring asset
* @returns the minimum amount
*/
getMinimumNativeToken = (): bigint => this.configs.minBoxValue;

/**
* gets the RWT token id
* @returns RWT token id
*/
getRWTToken = (): string => this.configs.rwtId;

/**
* converts json representation of the payment transaction to PaymentTransaction
* @returns PaymentTransaction object
*/
PaymentTransactionFromJson = (jsonString: string): PaymentTransaction => {
throw Error(`not implemented`);
};

/**
* generates PaymentTransaction object from raw tx json string
* @param rawTxJsonString
* @returns PaymentTransaction object
*/
rawTxToPaymentTransaction = (
rawTxJsonString: string
): Promise<PaymentTransaction> => {
throw Error(`not implemented`);
};

/**
* generates mapping from input box id to serialized string of output box (filtered by address, containing the token)
* @param address the address
* @param tokenId the token id
* @returns a Map from input box id to serialized string of output box
*/
getMempoolBoxMapping = async (
address: string,
tokenId?: string
): Promise<Map<string, BitcoinUtxo | undefined>> => {
// chaining transaction won't be done in BitcoinChain
// due to heavy size of transaction in mempool
return new Map<string, BitcoinUtxo | undefined>();
};

/**
* extracts box id and assets of a box
* @param box the box
* @returns an object containing the box id and assets
*/
protected getBoxInfo = (box: BitcoinUtxo): BoxInfo => {
throw Error(`not implemented`);
};
}

export default BitcoinChain;
60 changes: 60 additions & 0 deletions packages/chains/bitcoin/lib/BitcoinTransaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {
PaymentTransaction,
TransactionType,
} from '@rosen-chains/abstract-chain';
import { BITCOIN_CHAIN } from './constants';
import { BitcoinTransactionJsonModel } from './types';

class BitcoinTransaction extends PaymentTransaction {
inputUtxos: Array<string>;

constructor(
txId: string,
eventId: string,
txBytes: Uint8Array,
txType: TransactionType,
inputUtxos: Array<string>
) {
super(BITCOIN_CHAIN, txId, eventId, txBytes, txType);
this.inputUtxos = inputUtxos;
}

/**
* converts json representation of the payment transaction to BitcoinTransaction
* @returns BitcoinTransaction object
*/
static fromJson = (jsonString: string): BitcoinTransaction => {
const obj = JSON.parse(jsonString) as BitcoinTransactionJsonModel;
return new BitcoinTransaction(
obj.txId,
obj.eventId,
Buffer.from(obj.txBytes, 'hex'),
obj.txType as TransactionType,
obj.inputUtxos
);
};

/**
* converts BitcoinTransaction to json
* @returns json representation of the payment transaction
*/
toJson = (): string => {
return JSON.stringify({
network: this.network,
eventId: this.eventId,
txBytes: this.getTxHexString(),
txId: this.txId,
txType: this.txType,
inputUtxos: this.inputUtxos,
});
};

/**
* @returns transaction hex string
*/
getTxHexString = () => {
return Buffer.from(this.txBytes).toString('hex');
};
}

export default BitcoinTransaction;
1 change: 1 addition & 0 deletions packages/chains/bitcoin/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const BITCOIN_CHAIN = 'bitcoin';
5 changes: 5 additions & 0 deletions packages/chains/bitcoin/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { default as BitcoinChain } from './BitcoinChain';
export { default as AbstractBitcoinNetwork } from './network/AbstractBitcoinNetwork';
export { default as BitcoinTransaction } from './BitcoinTransaction';
export * from './types';
export * from './constants';
38 changes: 38 additions & 0 deletions packages/chains/bitcoin/lib/network/AbstractBitcoinNetwork.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { AbstractUtxoChainNetwork } from '@rosen-chains/abstract-chain';
import { Psbt } from 'bitcoinjs-lib';
import { BitcoinTx, BitcoinUtxo } from '../types';

abstract class AbstractBitcoinNetwork extends AbstractUtxoChainNetwork<
BitcoinTx,
BitcoinUtxo
> {
// TODO: uncomment this line (local:ergo/rosen-bridge/utils#169)
// abstract extractor: BitcoinRosenExtractor;

/**
* submits a transaction
* @param transaction the transaction
*/
abstract submitTransaction: (transaction: Psbt) => Promise<void>;

/**
* gets a utxo from the network
* @param boxId the id of Utxo (txId + . + index)
* @returns the utxo in BitcoinUtxo format
*/
abstract getUtxo: (boxId: string) => Promise<BitcoinUtxo>;

/**
* gets current fee ratio of the network
* @returns
*/
abstract getFeeRatio: () => Promise<bigint>;

/**
* gets id of transactions in mempool
* @returns
*/
abstract getMempoolTxIds: () => Promise<Array<string>>;
}

export default AbstractBitcoinNetwork;
Loading

0 comments on commit 1afb500

Please sign in to comment.