# Bitcoin

## What is JellySwap?

JellySwap is a cross-chain atomic swap protocol that supports many different blockchains. The Bitcoin package is used to interact with the Bitcoin Hash Time Locked Contracts and to handle blockchain events. The main components of the module are **Providers, Contract, Event, Adapter and Config.**

## Install package

Using **yarn**

```
$ yarn add @jelly-swap/bitcoin
```

Using **npm**

```bash
$ npm install @jelly-swap/bitcoin
```

## Importing

JavaScript (ES3)

```javascript
const jellyBtc = require('@jelly-swap/bitcoin');
```

JavaScript (ES6) / TypeScript

```javascript
import * as jellyBtc from '@jelly-swap/bitcoin';
```

## Config Module

This module contains the main configuration for the whole package

```javascript
const config = jellyBtc.Config();

//Expected output
{ 
  network: 'BTC',
  explorer: 'https://blockstream.info/testnet/tx/',
  providerUrl: 'https://spacejelly.network/bitpay/api/BTC/testnet',
  receiverAddress: 'tb1qc4mwllgvmy0xqsdexpm5v8g74ldmv698whnyrw',
  expiration: 10800,
  decimals: 8,
  unix: true,
  apiProviderUrl: 'https://spacejelly.network/btc/api/v1/btc' 
}
```

## Provider Module

A Provider abstracts a connection to the Bitcoin blockchain, for issuing queries and sending signed state changing transactions.

**BitcoinProvider** - allows you to connect to Bitcoin nodes you control or have access to, including mainnet, testnets, etc.

```javascript
const btcProvider = new jellyBtc.Providers.BitcoinProvider(
  "https://spacejelly.network/btc/api/v1/btc"
);
```

## Contract Module

Create **contract** instance:

```javascript
const btcContract = new jellyBtc.Contract(
  btcWallet,
  network?,
  "https://spacejelly.network/btc/api/v1/btc"?
);
```

| parameter | type             | description                                                             |
| --------- | ---------------- | ----------------------------------------------------------------------- |
| btcWallet | BtcWallet object | A bitcoin wallet object, with network, mnemonic, type & provider.       |
| network   | Network object   | Can be mainnet, testnet or regtest (optional).                          |
| provider  | object           | Provider instance that will be used for transaction signing (optional). |

### **subscribe**

```javascript
await btcContract.subscribe(onEvent, filter?);
```

| parameter | type     | description                                   |
| --------- | -------- | --------------------------------------------- |
| onEvent   | function | Called when an event is received.             |
| filter    | function | Used to filter any received event (optional). |

### **getPastEvents**

Returns past blockchain events.

```javascript
const pastEvents = await btcContract.getPastEvents(eventType, filter?, currentBlock?);
```

| parameter    | type             | description                                                                                                               |
| ------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------- |
| eventType    | string           | Can be 'new', 'withdraw' or 'refund'. If not passed all events will be returned.                                          |
| filter       | function         | Filter the received events (optional). If not passed all events will be returned.                                         |
| currentBlock | number or string | Read events up to the currentBlock (optional). If not passed the currentBlock will be assigned to the latest mined block. |

### **getCurrentBlock**&#x20;

Returns the latest block.

```javascript
const currentBlock = await btcContract.getCurrentBlock();
```

###

### **getBalance**&#x20;

Returns the balance of the given address.

```javascript
const balance = await btcContract.getBalance(address, network);
```

| parameter | type           | description                    |
| --------- | -------------- | ------------------------------ |
| address   | string         | Bitcoin Public Address.        |
| network   | Network Object | Can be any testnet or mainnet. |

### **newContract**

Creates and broadcasts a new swap transaction.

```javascript
const transactionHashSwap = await btcContract.newContract(swap);
```

| parameter | type         | description              |
| --------- | ------------ | ------------------------ |
| swap      | ContractSwap | Input data for the swap. |

### **withdraw**

Creates and broadcasts a withdraw transaction.

```javascript
const transactionHashWithdraw = await btcContract.withdraw(withdraw);
```

| parameter | type             | description                  |
| --------- | ---------------- | ---------------------------- |
| withdraw  | ContractWithdraw | Input data for the withdraw. |

### **refund**&#x20;

Creates and broadcasts a refund transaction.

```javascript
const transactionHashRefund = await btcContract.refund(contractRefund);
```

| parameter      | type           | description                |
| -------------- | -------------- | -------------------------- |
| contractRefund | ContractRefund | Input data for the refund. |

## **Event module**

**Event module** is used to read **past blockchain events** and **subscribe for new ones**

Initialize **event** module:

```javascript
const btcEvents = new jellyBtc.Event(btcContract);
```

| parameter   | type            | description                |
| ----------- | --------------- | -------------------------- |
| btcContract | BitcoinContract | Bitcoin contract instance. |

### **getPast**

Returns past blockchain events.

```javascript
const pastEvents = await btcEvents.getPast(eventType, filter?, currentBlock?);
```

| parameter    | type             | description                                                                                                               |
| ------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------- |
| eventType    | string           | Can be 'new', 'withdraw' or 'refund'. If not passed all events will be returned.                                          |
| filter       | function         | Filter the received events (optional). If not passed all events will be returned.                                         |
| currentBlock | number or string | Read events up to the currentBlock (optional). If not passed the currentBlock will be assigned to the latest mined block. |

### **subscribe**

```javascript
await btcEvents.subscribe(onEvent, filter?);
```

| parameter | type     | description                                                |
| --------- | -------- | ---------------------------------------------------------- |
| onEvent   | function | Called when an event is received.                          |
| filter    | function | Used to filter any received event. Optional.Adapter module |

## Adapter module

The Adapter module is used to **format the client data and prepare the input** for the swaps.

Initialize **adapter** module:

```javascript
const btcAdapter = new jellyBtc.Adapter();
```

###

### generateId

Generate swap id based on the input parameters. The same id will be generated by the Solidity Contract.

```javascript
const id = btcAdapter.generateId(input);
```

| parameter | type         | description              |
| --------- | ------------ | ------------------------ |
| input     | ContractSwap | Input data for the swap. |

###

### addressValid

Checks if the passed address is valid or not.

```javascript
const isAddressValid = btcAdapter.addressValid(address);
```

| parameter | type | description               |
| --------- | ---- | ------------------------- |
| address   | any  | True if address is valid. |

###

### parseAddress

Returns the address in lower case.

```javascript
const addressParsed = btcAdapter.parseAddress(address);
```

| parameter | type | description            |
| --------- | ---- | ---------------------- |
| address   | any  | Address in lower case. |

### **parseToNative**

Parse **BTC** amount to **satoshi** amount i.e. **0.1** to **10000000**

```javascript
const result = btcAdapter.parseToNative(amount);
```

| parameter | type | description                                  |
| --------- | ---- | -------------------------------------------- |
| amount    | any  | String representation of the satoshi amount. |

###

### **parseFromNative**

Parse **satoshi** amount to **BTC** amount i.e. **10000000** to **0.1**

```javascript
const result = btcAdapter.parseFromNative(amount);
```

| parameter | type | description                              |
| --------- | ---- | ---------------------------------------- |
| amount    | any  | String representation of the BTC amount. |

###

### formatInput

Returns object of type UserInputSwap.

```javascript
const swapInput = btcAdapter.formatInput(data, receiver);
```

| parameter | type          | description                                                                          |
| --------- | ------------- | ------------------------------------------------------------------------------------ |
| data      | UserInputSwap | User input data.                                                                     |
| receiver  | string        | Address of the receiver (optional). If not passed uses the receiver from the config. |

## Example

```javascript
const jellyBtc = require("@jelly-swap/bitcoin");
const { Wallet, Networks } = require("@jelly-swap/btc-wallet");

const btcProvider = new jellyBtc.Providers.BitcoinProvider(
  "https://spacejelly.network/btc/api/v1/btc"
);

const network = Networks.bitcoin;

const btcWallet = new Wallet(
  network,
  "witch collapse practice feed shame open despair creek road again ice least",
  "bech32",
  btcProvider
);

const btcContract = new jellyBtc.Contract(
  btcWallet,
  network,
  "https://spacejelly.network/btc/api/v1/btc"
);

const adapter = new jellyBtc.Adapter();

const subscribeFilter = type => {
  const address = "bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4";

  switch (type) {
    case "new": {
      return () => {
        return {
          type: "getSwapsByAddressAndBlock",
          address
        };
      };
    }

    case "withdraw": {
      return () => {
        return {
          type: "getWithdrawByReceiverAndBlock",
          address
        };
      };
    }

    default: {
      break;
    }
  }
};

const swapsFilter = type => {
  const address = "bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4";

  switch (type) {
    case "new": {
      return () => {
        return {
          type: "getSwapsByAddress",
          address
        };
      };
    }

    case "withdraw": {
      return () => {
        return {
          type: "getWithdrawByReceiver",
          address
        };
      };
    }

    default: {
      break;
    }
  }
};

async function start() {
  // Subscribe for contract events and pass handle function
  await btcContract.subscribe(() => {}, subscribeFilter);

  // Get past blockchain events
  const swaps = await btcContract.getPastEvents("new", swapsFilter("new"));
  console.log(swaps);
  //...
  // { blockHeight: 616793,
  //   transactionHash: 'd15d985165708af57d08d17986bde6140ed655e49fa420fbc7e39a258900d6c1',
  //   id: '0x47b3f15cf1837a8f293df06d5846514f413025b8c978031e62a59400d0d1c22e',
  //   status: 3,
  //   inputAmount: 221300,
  //   sender: 'bc1qwjeylyfrkn8sckwux789dqtscafujhgy4xcddg',
  //   receiver: 'bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4',
  //   refundAddress: 'bc1qwjeylyfrkn8sckwux789dqtscafujhgy4xcddg',
  //   network: 'BTC',
  //   outputNetwork: 'ETH',
  //   outputAddress: '0xb2cB83E2E367682B2C0d3AAF04131Dd94C41A1A9',
  //   outputAmount: '100000000000000000',
  //   expiration: 1581341813,
  //   hashLock: '0x6a98ad2137e52aaf0eb29f44fc97084bf45a33115a0850c4355a1dcfba95c1d6',
  //   _id: '5e41475f84702846cfe3a4e3',
  //   createdAt: '2020-02-10T12:28:48.794Z',
  //   withdrawTxHash: 'a0aadca779be5e5a9775da357634a3655fc049244a255376bf1f58976d868606' },
  //...

  const withdraws = await btcContract.getPastEvents(
    "withdraw",
    swapsFilter("withdraw")
  );
  console.log(withdraws);
  //...
  // [ { blockHeight: 616794,
  //   transactionHash: 'a0aadca779be5e5a9775da357634a3655fc049244a255376bf1f58976d868606',
  //   id: '0x47b3f15cf1837a8f293df06d5846514f413025b8c978031e62a59400d0d1c22e',
  //   secret: '0xce79be42bd15a541845c6f3e6d24e053460a8062e74082440f768705b6fa2b6a',
  //   hashLock: '0x6a98ad2137e52aaf0eb29f44fc97084bf45a33115a0850c4355a1dcfba95c1d6',
  //   sender: 'bc1qwjeylyfrkn8sckwux789dqtscafujhgy4xcddg',
  //   receiver: 'bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4',
  //   network: 'BTC',
  //   _id: '5e4148ea84702846cfe3a4e4',
  //   createdAt: '2020-02-10T12:13:30.057Z' } ]
  //...

  const refunds = await btcContract.getPastEvents(
    "refund",
    swapsFilter("refund")
  );
  console.log(refunds);
  //...
  // [ { blockHeight: 616794,
  //   transactionHash: 'a0aadca779be5e5a9775da357634a3655fc049244a255376bf1f58976d868606',
  //   id: '0x47b3f15cf1837a8f293df06d5846514f413025b8c978031e62a59400d0d1c22e',
  //   secret: '0xce79be42bd15a541845c6f3e6d24e053460a8062e74082440f768705b6fa2b6a',
  //   hashLock: '0x6a98ad2137e52aaf0eb29f44fc97084bf45a33115a0850c4355a1dcfba95c1d6',
  //   sender: 'bc1qwjeylyfrkn8sckwux789dqtscafujhgy4xcddg',
  //   receiver: 'bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4',
  //   network: 'BTC',
  //   _id: '5e4148ea84702846cfe3a4e4',
  //   createdAt: '2020-02-10T12:13:30.057Z' } ]
  //...

  const currentBlock = await btcProvider.getBlockHeight();
  console.log(currentBlock);
  //616241
  
  const balance = await btcContract.getBalance(
    "bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4",
    network
  );
  console.log(adapter.parseFromNative(balance));
  //0.00183863

  // ================ SWAP ================
  const userInputSwap = {
    inputAmount: "0.00001",
    network: "BTC",
    outputAddress: "0xD6Ff8542eC1606772fF29946218a624b08A1D51E",
    outputAmount: "0.0004488",
    outputNetwork: "ETH",
    secret:
      "pond cram isolate chair float moon tongue firm spirit hand peace together",
    sender: "bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4"
  };

  const swap = adapter.formatInput(userInputSwap);
  console.log(swap);
  // { inputAmount: '1000',
  // network: 'BTC',
  // outputAddress: '0xD6Ff8542eC1606772fF29946218a624b08A1D51E',
  // outputAmount: '0.0004488',
  // outputNetwork: 'ETH',
  // secret: 'pond cram isolate chair float moon tongue firm spirit hand peace together',
  // sender: 'bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4',
  // hashLock: '0x4af116ee28ecde1d2b71e49fb964fe76a20c694c94f6895c1baa8ed1d1b06dda',
  // receiver: 'tb1qc4mwllgvmy0xqsdexpm5v8g74ldmv698whnyrw',
  // expiration: 1581359277 }

  const swapHash = await btcContract.newContract(swap);
  console.log(swapHash);
  //5013c0b0005af10cd9db82e63a18e8bc248c843993f9433fcf00d3611663dc56

  // ================ REFUND ================
  const refund = {
    id: "5e41738da5d71552f72e2faf"
  };

  try {
    const refundHash = await btcContract.refund(refund);
    console.log(refundHash);
    //5013c0b0005af10cd9db82e63a18e8bc248c843993f9433fcf00d3611663dc56
  } catch (e) {
    console.log("Refund Error. Check timestamp and id params.");
  }

  // ================ WITHDRAW ================
  const withdraw = {
    id: "5e41738da5d71552f72e2faf",
    secret: "c5f715ae9c3f79aed4af080f881385e22cec3ecb2811740e7018daea79dcc15c"
  };

  try {
    const withdrawHash = await btcContract.withdraw(withdraw);
    console.log(withdrawHash);
    //5013c0b0005af10cd9db82e63a18e8bc248c843993f9433fcf00d3611663dc56
  } catch (e) {
    console.log("Withdraw Error. Check timestamp, id and secret params.");
  }
}

```
