open-index/open-npm huggingface dataset:
npm package: @stove-labs/arbitrage-bot-accountant
Description: accounting for tezos balances
Author: dexterslabor
Latest version: 1.2.0

> This repository is related to the core library of the [arbitrage bot](../../arbitrage-bot/).

The accountant is a plugin that retrieves balances for any given native or token contract. This is used to keep track of balance changes before and after arbitrage is performed.

## Learning resource

### Challenge

Every token contract follows its own implementation of a token standard. Therefore it is not a viable approach to read the account ballance entry from a ledger `Big_map`, because we would need to be aware of each and every token implementation.

### Solution

Tezos token FA1.2 [TZIP-7](https://gitlab.com/tezos/tzip/-/blob/master/proposals/tzip-7/tzip-7.md) and FA2[TZIP-12](https://gitlab.com/tezos/tzip/-/blob/master/proposals/tzip-12/tzip-12.md) have on-chain [`view entrypoints`](https://gitlab.com/tezos/tzip/-/blob/master/proposals/tzip-4/tzip-4.md#view-entrypoints) that usually get called by other smart contracts to get the `total_supply` of `token_balance` for a given account address. The result is returned through an operation as callback to the caller. 

Fortunately, recent protocol upgrades on Tezos have provided a way to call those `view entrypoints` through the node without the need of injecting any on-chain operation when using the `run_view` endpoint. `Taquito SDK` abstracts this and makes this feature easily available to dApp developers.

### Implementation

```typescript
// src/accountant.ts

// FA1.2 getBalance as defined in TZIP-7
await tokenContractInstance.views.getBalance(botAddress).read()

// FA2 balance_of as defined in TZIP-12
await tokenContractInstance.views.balance_of(
  [
    { owner: botAddress, token_id: tokenId },
  ]
).read()
```
npm package: @stove-labs/arbitrage-bot-cli
Description: command line interface for the arbitrage bot
Author: dexterslabor
Latest version: 1.2.0

# Usage

```
npm i
npm run build
```

<img width="700" alt="help" src="https://user-images.githubusercontent.com/8685779/203302073-96233b2b-63f1-44ab-86b0-c0349e09fc5b.png">

```
npm run cli -h
```

<img width="700" alt="start help" src="https://user-images.githubusercontent.com/8685779/203302392-5daa8e8a-d7ad-453a-b673-81d76d7183d3.png">


```
npm run cli start -h
npm run cli XTZ kUSD
```
npm package: @stove-labs/arbitrage-bot-reporter
Description: console reporter for the arbitrage bot
Author: dexterslabor
Latest version: 1.2.0

# `@stove-labs/arbitrage-bot-reporter`

This plugin is low-level package for reporting events in cli using [listr2](https://github.com/cenk1cenk2/listr2).
## Usage

```ts
import { ConsoleReporterPlugin } from '../src/consoleReporterPlugin';
import { Listr } from 'listr2';

const reporter = new ConsoleReporterPlugin();

new Listr(
  [
    {
      task: async (_, task): Promise<void> => {
        // This try-catch block is here because an Error messes up the formatting
        try {
          // fetch prices from exchanges
          reportFetchPricesStart(task);
          const prices = await exchangeManager.fetchPrices(
            baseToken,
            quoteToken
          );
          reportFetchPricesEnd(task, prices);

          // find arbitrage, calculate profit opportunity
          reportFindProfitOpportunityStart(task);
          const profitOpportunity: ProfitOpportunity =
            plugins.profitFinder.findProfits(prices);
          reportFindProfitOpportunityEnd(task, profitOpportunity);
          // restart lifecycle if no profit was found
          if (!hasPositiveProfit(task, profitOpportunity)) return;

          // execute swaps for arbitrage
          reportSwapStart(task);
          const swapResults: SwapResult[] =
            await plugins.swapExecutionManager.executeSwaps(
              profitOpportunity.swaps
            );
          reportSwapEnd(task, swapResults);
        } catch (e) {
          task.output = '';
          throw e;
        }
      },
      retry: NUMBER_OF_RETRIES,
    },
  ],
  {
    concurrent: false,
    exitOnError: true,
  }
).run();

const reportFetchPricesStart = (task) => {
  task.title =
    reporter.report({
      type: 'LIFECYCLE_START',
    }) + reporter.report({ type: 'PRICES_FETCHED' });
};

const reportFetchPricesEnd = (task, prices: ExchangePrice[]) => {
  task.title =
    reporter.report({
      type: 'LIFECYCLE_START',
    }) +
    reporter.report({
      type: 'PRICES_FETCHED',
      prices,
    });
};

const reportFindProfitOpportunityStart = (task) => {
  task.output = reporter.report({ type: 'PROFIT_FOUND' });
};

const reportFindProfitOpportunityEnd = (task, profitOpportunity) => {
  task.title +=
    '\n' +
    reporter.report({
      type: 'PROFIT_FOUND',
      profitOpportunity,
    });
};

const reportSwapStart = (task) => {
  task.output = reporter.report({ type: 'SWAPS_DONE' });
};

const reportSwapEnd = (task, swapResults: SwapResult[]) => {
  task.title +=
    '\n' +
    reporter.report({
      type: 'SWAPS_DONE',
      swapResults,
    });
};
```
npm package: @stove-labs/arbitrage-bot-swap-execution
Description: Swap execution plugin to execute swaps on exchanges
Author: dexterslabor
Latest version: 1.2.0

# Arbitrage Bot Swap Execution Plugin

> This repository is related to the core library of the [arbitrage bot](../../arbitrage-bot/).

The swap execution plugin is responsible to group swaps transactions and token approvals wherever possible in batches. For example in Tezos, when operations are grouped with the `batch` call, they are executed `atomically`. That means that if one operation fails, the whole stack fails and reverts. This is especially handy for arbitrage done completely on Tezos, because it poses a risk free approach if the net profit condition is not met.

## Dependency

We use the TypeScript/JavaScript SDK `@taquito/taquito` to interact with the Tezos node.

## Learning resource

```typescript
// this is a typical batch operation if arbitrage is done between 2 DEXs on Tezos
const batchParameters = [
    xtzToTokenExchange1, // swap 1
    approveTokenSpendingExchange2,
    tokenToXtzExchange2, // swap 2
    revokeTokenSpendingExchange2
]
```

```typescript
// src/swapExecution.ts

// retrieve all operation parameters and save in the batchParameters array
for await (const operationParameters of swaps.map((swap) =>
            this.getExchangePluginBySwap(swap).forgeOperation(
            swap,
            botAddress
            )
        )) {
            batchParameters = [...batchParameters, ...operationParameters];
        }
```

⚠️ It is important to note that arbitrage is a competitive field and many other bots could go for the same arbitrage opportunity. The node operator (usually) orders operations by baker fee. However, for batch operations only the operation fee of the first operation is taken into account. That's why the `totalEstOpCost * multiplier` is applied to the first operation *only* of the batch. Leaving the fee for all the other operations would be a waste.

```typescript
// src/handleTezosSwapExecution.ts

// estimate operation cost for the batch operation
const estimates = await tezos.estimate.batch(batchParameters);
const totalEstOpCost = estimates.reduce(
    (sum, current) => sum + current.suggestedFeeMutez,
    0
);

let multiplier = ecosystemKey.multiplier || 1;

// increase operation cost/fee if necessary to stay competitive in regards to other swaps in the block
// (inflated) fee is only applied to the first operation in the batch!
batchParameters[0].fee = new BigNumber(totalEstOpCost * multiplier)
    .integerValue()
    .toNumber();
```
npm package: @stove-labs/arbitrage-bot-trigger-chain
Description: trigger plugin that follows a chaining approach for the arbitrage lifecycle
Author: dexterslabor
Latest version: 1.2.0

> This repository is related to the core library of the [arbitrage bot](../../arbitrage-bot/).

## Learning resource

### Challenge

The most straightforward approach would be to subscribe to new blocks of a blockchain and use that as trigger for the lifecycle. However, this increases complexity and reduces control over the flow if blockchains with various block times are targeted and centralized exchanges come into play.
Another approach would be a simple `setTimeout` to a predefined time-interval/delay at which the lifcycle is triggered. Also this is not viable, because it interrupt pending operations in case those take longer than the time-interval/delay.

### Solution

This trigger builds on top of a time based `delay` (defined in milliseconds), by extending it with a *debounce* and *schedule* functionality. It basically chains lifecycles, but waits with the callback as long as the user defined `delay`.

### Implementation

Review `src/triggerChainPlugin.ts` for a detailed overview.
npm package: @stove-labs/tezos-dex-quipuswap
Description: plugin for the tezos DEX quipuswap
Author: dexterslabor
Latest version: 1.2.0

> This repository is related to the core library of the [arbitrage bot](../../../arbitrage-bot/).

## Learning resource

### Fetching the XTZ and token balance of the DEX

Our goal it to retrieve the `XTZ` and `token balance` from the DEX. With this information we can calculate: 
* `Spot price` by dividing one another 
* Trade amounts for a swap that takes into account the depth of liquidity (`calculateAmountOutExactIn`) 

#### Challenge

The storage structure differs for every DEX and their implementation, therefore this needs to be done case by case. 

> We can't follow the naive approach of fetching XTZ balance for a given contract address, because some of the XTZ might be reserved for future stake reward payouts!

#### Solution

We analyze the storage structure of the DEX smart contract and implement methods to retrieve the respective fields `tez_pool` and `token_pool`.

```typescript
// Quipuswap v1 storage
export type Storage = {
    storage: {
        tez_pool: nat;
        token_address: address;
        token_pool: nat;
        ...
    };
    dex_lambdas: BigMap<string, string>;
    ...
};
```

#### Implementation

```typescript
// src/exchangeQuipuswapPlugin.ts

async getContractInstance(exchangeAddress: string) {
  return await this.tezos.contract.at<QuipuswapDexTezTokenContractType>(
    exchangeAddress
  );
}

async getStorage(exchangeAddress: string) {
  const contractInstance = await this.getContractInstance(exchangeAddress);
  return contractInstance.storage();
}
```

```typescript
// fetch XTZ balance
await getStorage().storage.tez_pool.toFixed();
// fetch Token balance
await getStorage().storage.storage.token_pool.toFixed()
```

### Fetching the fee

The fee is hardcoded in `lambdas` and can't be read easily from storage. That's why we have it in `src/constants.ts`.