From 276f91d2e27b63022be643af876180dbe1c8711a Mon Sep 17 00:00:00 2001 From: Ha Quang Minh Date: Tue, 26 Nov 2024 14:57:16 +0700 Subject: [PATCH] fix dex v2 worker --- examples/dex-v2-worker-example.ts | 3 -- src/dex-v2-worker.ts | 73 ++++++++++++++----------------- src/types/order.ts | 56 +++++++++++++++++++++--- 3 files changed, 85 insertions(+), 47 deletions(-) diff --git a/examples/dex-v2-worker-example.ts b/examples/dex-v2-worker-example.ts index c06ff5e..f94d69e 100644 --- a/examples/dex-v2-worker-example.ts +++ b/examples/dex-v2-worker-example.ts @@ -3,7 +3,6 @@ import { Network } from "@minswap/lucid-cardano"; import { BlockfrostAdapter, NetworkId } from "../src"; import { DexV2Worker } from "../src/dex-v2-worker"; -import { NetworkEnvironment } from "../src/types/network"; import { getBackendLucidInstance } from "../src/utils/lucid"; async function main(): Promise { @@ -29,8 +28,6 @@ async function main(): Promise { ); const worker = new DexV2Worker({ - networkEnv: NetworkEnvironment.TESTNET_PREPROD, - networkId: NetworkId.TESTNET, lucid, blockfrostAdapter, privateKey: diff --git a/src/dex-v2-worker.ts b/src/dex-v2-worker.ts index 693bb4b..4a24b40 100644 --- a/src/dex-v2-worker.ts +++ b/src/dex-v2-worker.ts @@ -1,33 +1,24 @@ -import { Lucid } from "@minswap/lucid-cardano"; +import { Data, Lucid } from "@minswap/lucid-cardano"; import { BlockfrostAdapter, DexV2, DexV2Constant, OrderV2 } from "."; -import { NetworkEnvironment, NetworkId } from "./types/network"; import { runRecurringJob } from "./utils/job"; type DexV2WorkerConstructor = { - networkEnv: NetworkEnvironment; - networkId: NetworkId; lucid: Lucid; blockfrostAdapter: BlockfrostAdapter; privateKey: string; }; export class DexV2Worker { - private readonly networkEnv: NetworkEnvironment; - private readonly networkId: NetworkId; private readonly lucid: Lucid; private readonly blockfrostAdapter: BlockfrostAdapter; private readonly privateKey: string; constructor({ - networkEnv, - networkId, lucid, blockfrostAdapter, privateKey, }: DexV2WorkerConstructor) { - this.networkEnv = networkEnv; - this.networkId = networkId; this.lucid = lucid; this.blockfrostAdapter = blockfrostAdapter; this.privateKey = privateKey; @@ -42,11 +33,10 @@ export class DexV2Worker { } async runWorker(): Promise { + console.info("start run dex v2 worker"); const { orders: allOrders } = await this.blockfrostAdapter.getAllV2Orders(); const currentSlot = await this.blockfrostAdapter.currentSlot(); const currentTime = this.lucid.utils.slotToUnixTime(currentSlot); - const expiredOrders: OrderV2.State[] = []; - const mapDatum: Record = {}; for (const order of allOrders) { const orderDatum = order.datum; const expiredOptions = orderDatum.expiredOptions; @@ -62,46 +52,51 @@ export class DexV2Worker { continue; } + const mapDatum: Record = {}; const receiverDatum = orderDatum.refundReceiverDatum; + let rawDatum: string | undefined = undefined; if (receiverDatum.type === OrderV2.ExtraDatumType.INLINE_DATUM) { - let rawDatum: string | undefined = undefined; try { rawDatum = await this.blockfrostAdapter.getDatumByDatumHash( receiverDatum.hash ); + mapDatum[receiverDatum.hash] = rawDatum; // eslint-disable-next-line unused-imports/no-unused-vars } catch (_err) { continue; } - mapDatum[receiverDatum.hash] = rawDatum; } - expiredOrders.push(order); - if (expiredOrders.length === 20) { - break; - } - } - if (expiredOrders.length > 0) { - const orderUtxos = await this.lucid.utxosByOutRef( - expiredOrders.map((state) => ({ - txHash: state.txIn.txHash, - outputIndex: state.txIn.index, - })) - ); - const txComplete = await new DexV2( - this.lucid, - this.blockfrostAdapter - ).cancelExpiredOrders({ - orderUtxos: orderUtxos, - currentSlot, - extraDatumMap: mapDatum, - }); - const signedTx = await txComplete - .signWithPrivateKey(this.privateKey) - .complete(); + const orderUtxos = await this.lucid.utxosByOutRef([ + { + txHash: order.txIn.txHash, + outputIndex: order.txIn.index, + }, + ]); + if (orderUtxos.length === 0) { + continue; + } + try { + orderUtxos[0].datum = Data.to(OrderV2.Datum.toPlutusData(orderDatum)); + const txComplete = await new DexV2( + this.lucid, + this.blockfrostAdapter + ).cancelExpiredOrders({ + orderUtxos: orderUtxos, + currentSlot, + extraDatumMap: mapDatum, + }); + const signedTx = await txComplete + .signWithPrivateKey(this.privateKey) + .complete(); - const txId = await signedTx.submit(); - console.info(`Transaction submitted successfully: ${txId}`); + const txId = await signedTx.submit(); + console.info(`Transaction submitted successfully: ${txId}`); + break; + } catch (err) { + console.error(err); + continue; + } } } } diff --git a/src/types/order.ts b/src/types/order.ts index eea9334..27c6ad0 100644 --- a/src/types/order.ts +++ b/src/types/order.ts @@ -1,4 +1,5 @@ import { Address, Constr, Data } from "@minswap/lucid-cardano"; +import invariant from "@minswap/tiny-invariant"; import { AddressPlutusData } from "./address.internal"; import { Asset } from "./asset"; @@ -479,6 +480,11 @@ export namespace OrderV2 { export namespace AuthorizationMethod { export function fromPlutusData(data: Constr): AuthorizationMethod { let type: AuthorizationMethodType; + if (data.fields.length !== 1) { + throw Error( + `Field length of AuthorizationMethod must be in 1, actual: ${data.fields.length}` + ); + } switch (data.index) { case AuthorizationMethodType.SIGNATURE: { type = AuthorizationMethodType.SIGNATURE; @@ -1091,17 +1097,29 @@ export namespace OrderV2 { export function fromPlutusData(data: Constr): ExtraDatum { switch (data.index) { case ExtraDatumType.NO_DATUM: { + invariant( + data.fields.length === 0, + `Field Length of ExtraDatum.NO_DATUM must be 0, actually ${data.fields.length}` + ); return { type: ExtraDatumType.NO_DATUM, }; } case ExtraDatumType.DATUM_HASH: { + invariant( + data.fields.length === 1, + `Field Length of ExtraDatum.DATUM_HASH must be 1, actually ${data.fields.length}` + ); return { type: ExtraDatumType.DATUM_HASH, hash: data.fields[0] as string, }; } case ExtraDatumType.INLINE_DATUM: { + invariant( + data.fields.length === 1, + `Field Length of ExtraDatum.INLINE_DATUM must be 1, actually ${data.fields.length}` + ); return { type: ExtraDatumType.INLINE_DATUM, hash: data.fields[0] as string, @@ -1152,20 +1170,46 @@ export namespace OrderV2 { `Index of Order Datum must be 0, actual: ${data.index}` ); } + if (data.fields.length !== 9) { + throw new Error( + `Fields Length of Order Datum must be 9, actual: ${data.index}` + ); + } const maybeExpiry = data.fields[8] as Constr; let expiry: bigint[] | undefined; switch (maybeExpiry.index) { case 0: { - expiry = maybeExpiry.fields as bigint[]; - if (expiry.length !== 2) { + if (maybeExpiry.fields.length !== 1) { throw new Error( - `Order Expiry list must have 2 elements, actual: ${expiry.length}` + `Order maybeExpiry length must have 1 field, actual: ${maybeExpiry.fields.length}` ); } + const expiryOptions = maybeExpiry.fields[0] as Constr; + switch (expiryOptions.index) { + case 0: { + expiry = expiryOptions.fields as bigint[]; + if (expiry.length !== 2) { + throw new Error( + `Order Expiry list must have 2 elements, actual: ${expiry.length}` + ); + } + break; + } + default: { + throw new Error( + `Index of Expiry Options must have 1, actual: ${expiryOptions.index}` + ); + } + } break; } case 1: { expiry = undefined; + if (maybeExpiry.fields.length === 0) { + throw new Error( + `Order undefined Expiry must have 0 elements, actual: ${maybeExpiry.fields.length}` + ); + } break; } default: { @@ -1216,8 +1260,10 @@ export namespace OrderV2 { datum.maxBatcherFee, datum.expiredOptions ? new Constr(0, [ - datum.expiredOptions.expiredTime, - datum.expiredOptions.maxCancellationTip, + new Constr(0, [ + datum.expiredOptions.expiredTime, + datum.expiredOptions.maxCancellationTip, + ]), ]) : new Constr(1, []), ]);