From d4a6ccdb36b84bdc02c8f52f78e8f086965aa5f0 Mon Sep 17 00:00:00 2001
From: mtyszczak <mateusz.tyszczak@gmail.com>
Date: Wed, 8 Jan 2025 12:37:13 +0100
Subject: [PATCH] Add internal market filter and provider

---
 .../filters/internal-market-filter.ts         | 34 +++++++
 .../providers/feed-price-provider.ts          |  2 +-
 .../providers/internal-market-provider.ts     | 95 +++++++++++++++++++
 src/queen.ts                                  |  9 ++
 4 files changed, 139 insertions(+), 1 deletion(-)
 create mode 100644 src/chain-observers/filters/internal-market-filter.ts
 create mode 100644 src/chain-observers/providers/internal-market-provider.ts

diff --git a/src/chain-observers/filters/internal-market-filter.ts b/src/chain-observers/filters/internal-market-filter.ts
new file mode 100644
index 0000000..8f2d1a9
--- /dev/null
+++ b/src/chain-observers/filters/internal-market-filter.ts
@@ -0,0 +1,34 @@
+import type { WorkerBee } from "../../bot";
+import { OperationClassifier } from "../classifiers";
+import type { TRegisterEvaluationContext } from "../classifiers/collector-classifier-base";
+import type { DataEvaluationContext } from "../factories/data-evaluation-context";
+import { FilterBase } from "./filter-base";
+
+export class InternalMarketFilter extends FilterBase {
+  public constructor(
+    worker: WorkerBee
+  ) {
+    super(worker);
+  }
+
+  public usedContexts(): Array<TRegisterEvaluationContext> {
+    return [
+      OperationClassifier
+    ];
+  }
+
+  public async match(data: DataEvaluationContext): Promise<boolean> {
+    const { operationsPerType } = await data.get(OperationClassifier);
+
+    for(const {} of (operationsPerType.limit_order_create2 ?? []))
+      return true;
+
+    for(const {} of (operationsPerType.limit_order_cancel ?? []))
+      return true;
+
+    for(const {} of (operationsPerType.limit_order_create ?? []))
+      return true;
+
+    return false;
+  }
+}
diff --git a/src/chain-observers/providers/feed-price-provider.ts b/src/chain-observers/providers/feed-price-provider.ts
index 4e413c3..a927d75 100644
--- a/src/chain-observers/providers/feed-price-provider.ts
+++ b/src/chain-observers/providers/feed-price-provider.ts
@@ -1,5 +1,5 @@
 import { price } from "@hiveio/wax";
-import { WorkerBeeIterable } from "src/types/iterator";
+import { WorkerBeeIterable } from "../../types/iterator";
 import { FeedPriceClassifier } from "../classifiers";
 import { TRegisterEvaluationContext } from "../classifiers/collector-classifier-base";
 import { DataEvaluationContext } from "../factories/data-evaluation-context";
diff --git a/src/chain-observers/providers/internal-market-provider.ts b/src/chain-observers/providers/internal-market-provider.ts
new file mode 100644
index 0000000..1d12c2a
--- /dev/null
+++ b/src/chain-observers/providers/internal-market-provider.ts
@@ -0,0 +1,95 @@
+import { price, type asset } from "@hiveio/wax";
+import { WorkerBeeIterable } from "../../types/iterator";
+import { TRegisterEvaluationContext } from "../classifiers/collector-classifier-base";
+import { OperationClassifier, IOperationTransactionPair } from "../classifiers/operation-classifier";
+import { DataEvaluationContext } from "../factories/data-evaluation-context";
+import { ProviderBase } from "./provider-base";
+
+export interface IInternalMarketOperationBase {
+  owner: string;
+  orderId: number;
+}
+
+export interface IInternalMarketCancelOperation extends IInternalMarketOperationBase {
+  cancel: true;
+}
+
+export interface IInternalMarketCreateOperation extends IInternalMarketOperationBase {
+  cancel: false;
+  amountToSell: asset;
+  filled: boolean;
+  exchangeRate: price;
+  expiration: Date;
+}
+
+export type TInternalMarketOperation = IInternalMarketCancelOperation | IInternalMarketCreateOperation;
+
+export interface IInternalMarketProviderData {
+  internalMarketOperations: WorkerBeeIterable<IOperationTransactionPair<TInternalMarketOperation>>;
+};
+
+export class InternalMarketProvider extends ProviderBase {
+  public usedContexts(): Array<TRegisterEvaluationContext> {
+    return [
+      OperationClassifier
+    ]
+  }
+
+  public async provide(data: DataEvaluationContext): Promise<IInternalMarketProviderData> {
+    const operations = await data.get(OperationClassifier);
+
+    const orderCreate = operations.operationsPerType["limit_order_create"];
+    const orderCreate2 = operations.operationsPerType["limit_order_create2"];
+    const orderCancel = operations.operationsPerType["limit_order_cancel"];
+
+    const internalMarketOperations: IOperationTransactionPair<TInternalMarketOperation>[] = [];
+
+    if(orderCancel)
+      for(const op of orderCancel)
+        internalMarketOperations.push({
+          operation: {
+            cancel: true,
+            owner: op.operation.owner,
+            orderId: op.operation.orderid
+          },
+          transaction: op.transaction
+        });
+
+    if(orderCreate)
+      for(const op of orderCreate)
+        internalMarketOperations.push({
+          operation: {
+            cancel: false,
+            owner: op.operation.owner,
+            orderId: op.operation.orderid,
+            amountToSell: op.operation.amount_to_sell!,
+            filled: op.operation.fill_or_kill,
+            exchangeRate: {
+              base: op.operation.amount_to_sell,
+              quote: op.operation.min_to_receive
+            },
+            expiration: new Date(`${op.operation.expiration}Z`)
+          },
+          transaction: op.transaction
+        });
+
+    if(orderCreate2)
+      for(const op of orderCreate2)
+        internalMarketOperations.push({
+          operation: {
+            cancel: false,
+            owner: op.operation.owner,
+            orderId: op.operation.orderid,
+            amountToSell: op.operation.amount_to_sell!,
+            filled: op.operation.fill_or_kill,
+            exchangeRate: op.operation.exchange_rate!,
+            expiration: new Date(`${op.operation.expiration}Z`)
+          },
+          transaction: op.transaction
+        });
+
+    return {
+      internalMarketOperations: new WorkerBeeIterable(internalMarketOperations)
+    };
+  }
+}
diff --git a/src/queen.ts b/src/queen.ts
index 9fb9337..7b1c8dc 100644
--- a/src/queen.ts
+++ b/src/queen.ts
@@ -14,6 +14,7 @@ import { FeedPriceNoChangeFilter } from "./chain-observers/filters/feed-price-no
 import type { FilterBase } from "./chain-observers/filters/filter-base";
 import { FollowFilter } from "./chain-observers/filters/follow-filter";
 import { ImpactedAccountFilter } from "./chain-observers/filters/impacted-account-filter";
+import { InternalMarketFilter } from "./chain-observers/filters/internal-market-filter";
 import { BlockChangedFilter } from "./chain-observers/filters/new-block-filter";
 import { PostFilter } from "./chain-observers/filters/post-filter";
 import { PostMentionFilter } from "./chain-observers/filters/post-mention";
@@ -27,6 +28,7 @@ import { BlockHeaderProvider } from "./chain-observers/providers/block-header-pr
 import { BlockProvider } from "./chain-observers/providers/block-provider";
 import { ExchangeTransferProvider } from "./chain-observers/providers/exchange-transfer-provider";
 import { FeedPriceProvider } from "./chain-observers/providers/feed-price-provider";
+import { InternalMarketProvider } from "./chain-observers/providers/internal-market-provider";
 import { MentionedAccountProvider } from "./chain-observers/providers/mention-provider";
 import { ProviderBase } from "./chain-observers/providers/provider-base";
 import { RcAccountProvider } from "./chain-observers/providers/rc-account-provider";
@@ -190,6 +192,13 @@ export class QueenBee<TPreviousSubscriberData extends object = {}> {
     return this;
   }
 
+  public onInternalMarketOperation(): QueenBee<TPreviousSubscriberData & Awaited<ReturnType<InternalMarketProvider["provide"]>>> {
+    this.operands.push(new InternalMarketFilter(this.worker));
+    this.providers.push(new InternalMarketProvider());
+
+    return this;
+  }
+
   public onBlock(): QueenBee<TPreviousSubscriberData & Awaited<ReturnType<BlockHeaderProvider["provide"]>>> {
     this.operands.push(new BlockChangedFilter(this.worker));
     this.providers.push(new BlockHeaderProvider());
-- 
GitLab