diff --git a/.changeset/late-oranges-fly.md b/.changeset/late-oranges-fly.md new file mode 100644 index 0000000..21aa078 --- /dev/null +++ b/.changeset/late-oranges-fly.md @@ -0,0 +1,5 @@ +--- +"@mangrovedao/mgv": patch +--- + +Added `getOrder` and `getOrders` diff --git a/src/actions/index.ts b/src/actions/index.ts index 227ea67..602074c 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -20,6 +20,13 @@ export type { WaitForLimitOrderUpdateResultParams, WaitForSetExpirationResultParams, WaitForRemoveLimitOrderResult, + OrderResult, + GetFullOfferParams, + GetSingleOrderParams, + GetSingleOrderArgs, + GetOrdersParamsSingleMarket, + GetOrdersParams, + GetOrdersArgs, } from './order/index.js' export { @@ -38,6 +45,8 @@ export { waitForLimitOrderUpdateResult, waitForSetExpirationResult, waitForRemoveLimitOrderResult, + getOrder, + getOrders, } from './order/index.js' export type { diff --git a/src/actions/order/index.ts b/src/actions/order/index.ts index f73e6b2..93ebab4 100644 --- a/src/actions/order/index.ts +++ b/src/actions/order/index.ts @@ -57,3 +57,18 @@ export { waitForSetExpirationResult, waitForRemoveLimitOrderResult, } from './results.js' + +export type { + OrderResult, + GetFullOfferParams, + GetSingleOrderParams, + GetSingleOrderArgs, + GetOrdersParamsSingleMarket, + GetOrdersParams, + GetOrdersArgs, +} from './view.js' + +export { + getOrder, + getOrders, +} from './view.js' diff --git a/src/actions/order/new.test.ts b/src/actions/order/new.test.ts index 914eb49..475a977 100644 --- a/src/actions/order/new.test.ts +++ b/src/actions/order/new.test.ts @@ -7,7 +7,7 @@ import { parseUnits, zeroAddress, } from 'viem' -import { afterEach, describe, expect, inject, it } from 'vitest' +import { describe, expect, inject, it } from 'vitest' import { limitOrderResultFromLogs } from '~mgv/lib/limit-order.js' import { tickFromVolumes } from '~mgv/lib/tick.js' import { getClient } from '~test/src/client.js' @@ -21,10 +21,6 @@ const { wethUSDC } = inject('markets') const client = getClient() describe('new order', () => { - afterEach(async () => { - await client.reset() - }) - it('get user router', async () => { const router = await getUserRouter(client, params, { user: client.account.address, diff --git a/src/actions/order/view.test.ts b/src/actions/order/view.test.ts new file mode 100644 index 0000000..7e078b6 --- /dev/null +++ b/src/actions/order/view.test.ts @@ -0,0 +1,321 @@ +import { parseUnits } from 'viem' +import { describe, expect, inject, it } from 'vitest' +import { limitOrderResultFromLogs } from '~mgv/lib/limit-order.js' +import { tickFromVolumes } from '~mgv/lib/tick.js' +import { getClient } from '~test/src/client.js' +import { BA, BS, Order } from '../../lib/enums.js' +import { getBook } from '../book.js' +import { getUserRouter } from '../smart-router.js' +import { simulateLimitOrder } from './new.js' +import { getOrder, getOrders } from './view.js' + +const client = getClient() +const params = inject('mangrove') +const { wethUSDC } = inject('markets') + +describe('view order', () => { + it('single order', async () => { + const router = await getUserRouter(client, params, { + user: client.account.address, + }) + + const book = await getBook(client, params, wethUSDC) + + const baseAmount = parseUnits('1', wethUSDC.base.decimals) + const quoteAmount = parseUnits('3000', wethUSDC.quote.decimals) + + const { request } = await simulateLimitOrder(client, params, wethUSDC, { + baseAmount, + quoteAmount, + restingOrderGasreq: 250_000n, + bs: BS.buy, + book, + orderType: Order.PO, + }) + const tx = await client.writeContract(request) + const receipt = await client.waitForTransactionReceipt({ hash: tx }) + const result = limitOrderResultFromLogs(params, wethUSDC, { + logs: receipt.logs, + user: client.account.address, + bs: BS.buy, + }) + expect(result.takerGave).toBe(0n) + expect(result.takerGot).toBe(0n) + expect(result.feePaid).toBe(0n) + expect(result.bounty).toBe(0n) + expect(result.takerGivesLogic).toBeUndefined() + expect(result.takerWantsLogic).toBeUndefined() + expect(result.offer).toBeDefined() + expect(result.offer!.id).toBe(1n) + expect(result.offer!.gives).toApproximateEqual(quoteAmount) + expect(result.offer!.wants).toApproximateEqual(baseAmount) + expect(result.offer!.tick).toBe( + -tickFromVolumes(quoteAmount, baseAmount, wethUSDC.tickSpacing), + ) + expect(result.offer!.gasprice).toBe(book.marketConfig.gasprice) + expect(result.offer!.gasreq).toBe(250_000n) + expect(result.offer!.expiry).toBeUndefined() + + const order = await getOrder(client, params, { + offerId: 1n, + market: wethUSDC, + user: client.account.address, + ba: BA.bids, + userRouter: router, + }) + + expect(order.id).toBe(1n) + + expect(order.offer.gives).toBe(result.offer!.gives) + expect(order.offer.tick).toBe(result.offer!.tick) + + expect(order.detail.gasreq).toBe(result.offer!.gasreq) + expect(order.detail.gasprice).toBe(result.offer!.gasprice) + expect(order.detail.kilo_offer_gasbase * 1_000n).toBe( + book.bidsConfig.offer_gasbase, + ) + expect(order.detail.maker).toAddressEqual(params.mgvOrder) + + expect(order.expiry).toBeUndefined() + expect(order.baseLogic).toBeUndefined() + expect(order.quoteLogic).toBeUndefined() + expect(order.provision).toBe( + (order.detail.gasreq + order.detail.kilo_offer_gasbase * 1_000n) * + order.detail.gasprice * + BigInt(1e6), + ) + + expect(order.isLive).toBe(true) + }) + + it('multiple orders', async () => { + const router = await getUserRouter(client, params, { + user: client.account.address, + }) + + const book = await getBook(client, params, wethUSDC) + + const baseAmount = parseUnits('1', wethUSDC.base.decimals) + const quoteAmount = parseUnits('3000', wethUSDC.quote.decimals) + + const { request } = await simulateLimitOrder(client, params, wethUSDC, { + baseAmount, + quoteAmount, + restingOrderGasreq: 250_000n, + bs: BS.buy, + book, + orderType: Order.PO, + }) + const tx = await client.writeContract(request) + const receipt = await client.waitForTransactionReceipt({ hash: tx }) + const result = limitOrderResultFromLogs(params, wethUSDC, { + logs: receipt.logs, + user: client.account.address, + bs: BS.buy, + }) + expect(result.takerGave).toBe(0n) + expect(result.takerGot).toBe(0n) + expect(result.feePaid).toBe(0n) + expect(result.bounty).toBe(0n) + expect(result.takerGivesLogic).toBeUndefined() + expect(result.takerWantsLogic).toBeUndefined() + expect(result.offer).toBeDefined() + expect(result.offer!.id).toBe(1n) + expect(result.offer!.gives).toApproximateEqual(quoteAmount) + expect(result.offer!.wants).toApproximateEqual(baseAmount) + expect(result.offer!.tick).toBe( + -tickFromVolumes(quoteAmount, baseAmount, wethUSDC.tickSpacing), + ) + expect(result.offer!.gasprice).toBe(book.marketConfig.gasprice) + expect(result.offer!.gasreq).toBe(250_000n) + expect(result.offer!.expiry).toBeUndefined() + + const orders = await getOrders(client, params, { + user: client.account.address, + userRouter: router, + orders: [ + { + market: wethUSDC, + ba: BA.bids, + offerId: 1n, + }, + { + market: wethUSDC, + ba: BA.bids, + offerId: 1n, + }, + { + market: wethUSDC, + ba: BA.bids, + offerId: 1n, + }, + ], + }) + + expect(orders.length).toBe(3) + + expect(orders[0]!.id).toBe(1n) + expect(orders[1]!.id).toBe(1n) + expect(orders[2]!.id).toBe(1n) + + expect(orders[0]!.offer.gives).toBe(result.offer!.gives) + expect(orders[1]!.offer.gives).toBe(result.offer!.gives) + expect(orders[2]!.offer.gives).toBe(result.offer!.gives) + expect(orders[0]!.offer.tick).toBe(result.offer!.tick) + expect(orders[1]!.offer.tick).toBe(result.offer!.tick) + expect(orders[2]!.offer.tick).toBe(result.offer!.tick) + + expect(orders[0]!.detail.gasreq).toBe(result.offer!.gasreq) + expect(orders[1]!.detail.gasreq).toBe(result.offer!.gasreq) + expect(orders[2]!.detail.gasreq).toBe(result.offer!.gasreq) + expect(orders[0]!.detail.gasprice).toBe(result.offer!.gasprice) + expect(orders[1]!.detail.gasprice).toBe(result.offer!.gasprice) + expect(orders[2]!.detail.gasprice).toBe(result.offer!.gasprice) + expect(orders[0]!.detail.kilo_offer_gasbase * 1_000n).toBe( + book.bidsConfig.offer_gasbase, + ) + expect(orders[1]!.detail.kilo_offer_gasbase * 1_000n).toBe( + book.bidsConfig.offer_gasbase, + ) + expect(orders[2]!.detail.kilo_offer_gasbase * 1_000n).toBe( + book.bidsConfig.offer_gasbase, + ) + expect(orders[0]!.detail.maker).toAddressEqual(params.mgvOrder) + expect(orders[1]!.detail.maker).toAddressEqual(params.mgvOrder) + expect(orders[2]!.detail.maker).toAddressEqual(params.mgvOrder) + + expect(orders[0]!.expiry).toBeUndefined() + expect(orders[1]!.expiry).toBeUndefined() + expect(orders[2]!.expiry).toBeUndefined() + + expect(orders[0]!.baseLogic).toBeUndefined() + expect(orders[1]!.baseLogic).toBeUndefined() + expect(orders[2]!.baseLogic).toBeUndefined() + + expect(orders[0]!.quoteLogic).toBeUndefined() + expect(orders[1]!.quoteLogic).toBeUndefined() + expect(orders[2]!.quoteLogic).toBeUndefined() + }) + + it('single order: with logic and expiry', async () => { + const router = await getUserRouter(client, params, { + user: client.account.address, + }) + + const book = await getBook(client, params, wethUSDC) + + const baseAmount = parseUnits('1', wethUSDC.base.decimals) + const quoteAmount = parseUnits('3000', wethUSDC.quote.decimals) + + const expiry = BigInt(Math.floor(Date.now() / 1000 + 60)) + + const { request } = await simulateLimitOrder(client, params, wethUSDC, { + baseAmount, + quoteAmount, + restingOrderGasreq: 250_000n, + bs: BS.buy, + book, + orderType: Order.PO, + takerGivesLogic: params.mgv, + takerWantsLogic: params.mgv, + expiryDate: expiry, + }) + const tx = await client.writeContract(request) + const receipt = await client.waitForTransactionReceipt({ hash: tx }) + const result = limitOrderResultFromLogs(params, wethUSDC, { + logs: receipt.logs, + user: client.account.address, + bs: BS.buy, + }) + + expect(result.takerGivesLogic!).toAddressEqual(params.mgv) + expect(result.takerWantsLogic!).toAddressEqual(params.mgv) + + const order = await getOrder(client, params, { + user: client.account.address, + market: wethUSDC, + ba: BA.bids, + offerId: 1n, + userRouter: router, + }) + + expect(order.id).toBe(1n) + expect(order.baseLogic).toBeDefined() + expect(order.quoteLogic).toBeDefined() + expect(order.expiry).toBeDefined() + + expect(order.baseLogic!).toAddressEqual(params.mgv) + expect(order.quoteLogic!).toAddressEqual(params.mgv) + expect(order.expiry).toBe(expiry) + }) + + it('multiple orders: with logic and expiry', async () => { + const router = await getUserRouter(client, params, { + user: client.account.address, + }) + + const book = await getBook(client, params, wethUSDC) + + const baseAmount = parseUnits('1', wethUSDC.base.decimals) + const quoteAmount = parseUnits('3000', wethUSDC.quote.decimals) + + const expiry = BigInt(Math.floor(Date.now() / 1000 + 60)) + + const { request } = await simulateLimitOrder(client, params, wethUSDC, { + baseAmount, + quoteAmount, + restingOrderGasreq: 250_000n, + bs: BS.buy, + book, + orderType: Order.PO, + takerGivesLogic: params.mgv, + takerWantsLogic: params.mgv, + expiryDate: expiry, + }) + const tx = await client.writeContract(request) + const receipt = await client.waitForTransactionReceipt({ hash: tx }) + const result = limitOrderResultFromLogs(params, wethUSDC, { + logs: receipt.logs, + user: client.account.address, + bs: BS.buy, + }) + + expect(result.takerGivesLogic!).toAddressEqual(params.mgv) + expect(result.takerWantsLogic!).toAddressEqual(params.mgv) + + const orders = await getOrders(client, params, { + user: client.account.address, + userRouter: router, + orders: [ + { + market: wethUSDC, + ba: BA.bids, + offerId: 1n, + }, + { + market: wethUSDC, + ba: BA.bids, + offerId: 1n, + }, + { + market: wethUSDC, + ba: BA.bids, + offerId: 1n, + }, + ], + }) + + expect(orders.length).toBe(3) + + for (const order of orders) { + expect(order.id).toBe(1n) + expect(order.baseLogic).toBeDefined() + expect(order.quoteLogic).toBeDefined() + expect(order.expiry).toBeDefined() + + expect(order.baseLogic!).toAddressEqual(params.mgv) + expect(order.quoteLogic!).toAddressEqual(params.mgv) + expect(order.expiry).toBe(expiry) + } + }) +}) diff --git a/src/actions/order/view.ts b/src/actions/order/view.ts new file mode 100644 index 0000000..d5f576d --- /dev/null +++ b/src/actions/order/view.ts @@ -0,0 +1,282 @@ +import { + type Address, + type Client, + type MulticallParameters, + isAddressEqual, + zeroAddress, +} from 'viem' +import { multicall } from 'viem/actions' +import { viewOfferParams } from '../../builder/offer/view.js' +import { + viewExpirationParams, + viewLimitOrderLogicsParams, + viewProvisionParams, +} from '../../builder/order/view.js' +import { BA } from '../../lib/enums.js' +import { rpcOfferToHumanOffer } from '../../lib/human-readable.js' +import { unpackOfferDetail } from '../../lib/offer-detail.js' +import { unpackOffer } from '../../lib/offer.js' +import { getSemibooksOLKeys } from '../../lib/ol-key.js' +import type { + MangroveActionsDefaultParams, + MarketParams, +} from '../../types/index.js' +import type { CompleteOffer, RpcCompleteOffer } from '../../types/lib.js' +import { getAction } from '../../utils/getAction.js' + +export type OrderResult = CompleteOffer & { + provision: bigint + isLive: boolean + expiry?: bigint | undefined + baseLogic?: Address | undefined + quoteLogic?: Address | undefined +} + +export type GetFullOfferParams = { + offer: RpcCompleteOffer + market: MarketParams + ba: BA + expiry: bigint + provision: bigint + baseLogic: Address + quoteLogic: Address +} + +export function getFullOffer(params: GetFullOfferParams): OrderResult { + const humanOffer = rpcOfferToHumanOffer({ + ba: params.ba, + ...params.offer.offer, + baseDecimals: params.market.base.decimals, + quoteDecimals: params.market.quote.decimals, + }) + return { + ...params.offer, + ...humanOffer, + expiry: params.expiry === 0n ? undefined : params.expiry, + provision: params.provision, + baseLogic: isAddressEqual(params.baseLogic, zeroAddress) + ? undefined + : params.baseLogic, + quoteLogic: isAddressEqual(params.quoteLogic, zeroAddress) + ? undefined + : params.quoteLogic, + isLive: + (params.expiry === 0n || + params.expiry > BigInt(Math.floor(Date.now() / 1000))) && + params.offer.offer.gives > 0n, + } +} + +export type GetSingleOrderParams = { + offerId: bigint + market: MarketParams + user: Address + userRouter: Address + ba: BA +} + +export type GetSingleOrderArgs = GetSingleOrderParams & + Omit + +export async function getOrder( + client: Client, + actionParams: MangroveActionsDefaultParams, + args: GetSingleOrderArgs, +): Promise { + const olKeys = getSemibooksOLKeys(args.market) + const olKey = BA.asks === args.ba ? olKeys.asksMarket : olKeys.bidsMarket + const [rawOffers, rawExpiry, rawProvision, rawBaseLogic, rawQuoteLogic] = + await getAction( + client, + multicall, + 'multicall', + )({ + contracts: [ + { + address: actionParams.mgv, + ...viewOfferParams({ + olKey, + offerId: args.offerId, + }), + }, + { + address: actionParams.mgvOrder, + ...viewExpirationParams({ + olKey, + offerId: args.offerId, + }), + }, + { + address: actionParams.mgvOrder, + ...viewProvisionParams({ + olKey, + offerId: args.offerId, + }), + }, + { + address: args.userRouter, + ...viewLimitOrderLogicsParams({ + olKey, + offerId: args.offerId, + user: args.user, + token: args.market.base.address, + }), + }, + { + address: args.userRouter, + ...viewLimitOrderLogicsParams({ + olKey, + offerId: args.offerId, + user: args.user, + token: args.market.quote.address, + }), + }, + ], + allowFailure: true, + ...args, + }) + + if (rawOffers.status === 'failure') throw new Error('Failed to get order') + + return getFullOffer({ + ...args, + offer: { + id: args.offerId, + offer: unpackOffer(rawOffers.result[0]), + detail: unpackOfferDetail(rawOffers.result[1]), + }, + expiry: rawExpiry.status === 'success' ? rawExpiry.result.date : 0n, + provision: rawProvision.status === 'success' ? rawProvision.result : 0n, + baseLogic: + rawBaseLogic.status === 'success' ? rawBaseLogic.result : zeroAddress, + quoteLogic: + rawQuoteLogic.status === 'success' ? rawQuoteLogic.result : zeroAddress, + }) +} + +export type GetOrdersParamsSingleMarket = { + market: MarketParams + offerId: bigint + ba: BA +} + +export type GetOrdersParams = { + orders: GetOrdersParamsSingleMarket[] + user: Address + userRouter: Address +} + +export type GetOrdersArgs = GetOrdersParams & + Omit + +export async function getOrders( + client: Client, + actionParams: MangroveActionsDefaultParams, + args: GetOrdersArgs, +): Promise { + const contracts = args.orders.flatMap((o) => { + const olKeys = getSemibooksOLKeys(o.market) + const olKey = BA.asks === o.ba ? olKeys.asksMarket : olKeys.bidsMarket + return [ + { + address: actionParams.mgv, + ...viewOfferParams({ + olKey, + offerId: o.offerId, + }), + }, + { + address: actionParams.mgvOrder, + ...viewExpirationParams({ + olKey, + offerId: o.offerId, + }), + }, + { + address: actionParams.mgvOrder, + ...viewProvisionParams({ + olKey, + offerId: o.offerId, + }), + }, + { + address: args.userRouter, + ...viewLimitOrderLogicsParams({ + olKey, + offerId: o.offerId, + user: args.user, + token: o.market.base.address, + }), + }, + { + address: args.userRouter, + ...viewLimitOrderLogicsParams({ + olKey, + offerId: o.offerId, + user: args.user, + token: o.market.quote.address, + }), + }, + ] as const satisfies MulticallParameters['contracts'] + }) + const result = await getAction( + client, + multicall, + 'multicall', + )({ + contracts, + allowFailure: true, + ...args, + }) + + // index 0 is the offer and details [bigint, bigint] + // index 1 is the expiry + // index 2 is the provision + // index 3 is the base logic + // index 4 is the quote logic + + if (result.length !== args.orders.length * 5) + throw new Error('Invalid result length') + + const orders: OrderResult[] = [] + + for (let i = 0; i < result.length; i += 5) { + const order = args.orders[i / 5]! + const [rawOffers, rawExpiry, rawProvision, rawBaseLogic, rawQuoteLogic] = + result.slice(i) + if (rawOffers?.status !== 'success') throw new Error('Failed to get order') + + orders.push( + getFullOffer({ + ...order, + offer: { + id: order.offerId, + offer: unpackOffer( + (rawOffers.result as unknown as readonly [bigint, bigint])[0], + ), + detail: unpackOfferDetail( + (rawOffers.result as unknown as readonly [bigint, bigint])[1], + ), + }, + expiry: + rawExpiry?.status === 'success' + ? ((rawExpiry.result as any).date as bigint) + : 0n, + provision: + rawProvision?.status === 'success' + ? (rawProvision.result as bigint) + : 0n, + baseLogic: + rawBaseLogic?.status === 'success' + ? (rawBaseLogic.result as Address) + : zeroAddress, + quoteLogic: + rawQuoteLogic?.status === 'success' + ? (rawQuoteLogic.result as Address) + : zeroAddress, + }), + ) + } + + return orders +} diff --git a/src/builder/index.ts b/src/builder/index.ts index 0f633f2..0186b31 100644 --- a/src/builder/index.ts +++ b/src/builder/index.ts @@ -75,6 +75,8 @@ export type { UpdateOrderParams, RawRemoveOrderParams, RemoveOrderParams, + ViewLimitOrderParams, + ViewLimitOrderLogicsParams, } from './order/index.js' export { @@ -88,6 +90,11 @@ export { retractOrderABI, rawRemoveOrderParams, removeOrderParams, + mgvOrderViewABI, + smartRouterViewABI, + viewExpirationParams, + viewProvisionParams, + viewLimitOrderLogicsParams, } from './order/index.js' // smart router diff --git a/src/builder/offer/view.ts b/src/builder/offer/view.ts new file mode 100644 index 0000000..7910b97 --- /dev/null +++ b/src/builder/offer/view.ts @@ -0,0 +1,28 @@ +import { type ContractFunctionParameters, parseAbi } from 'viem' +import type { OLKey } from '../../types/lib.js' +import { olKeyABIRaw } from '../structs.js' + +// given a market and offer id return: +// - offer +// - offer details + +export const mgvViewABI = parseAbi([ + olKeyABIRaw, + 'function offerData(OLKey memory olKey, uint offerId) external view returns (uint offer, uint offerDetail)', +]) + +export type ViewOfferParams = { + olKey: OLKey + offerId: bigint +} + +export function viewOfferParams(params: ViewOfferParams) { + return { + abi: mgvViewABI, + functionName: 'offerData', + args: [params.olKey, params.offerId], + } satisfies Omit< + ContractFunctionParameters, + 'address' + > +} diff --git a/src/builder/order/index.ts b/src/builder/order/index.ts index fa3059c..13fac8e 100644 --- a/src/builder/order/index.ts +++ b/src/builder/order/index.ts @@ -32,3 +32,16 @@ export { rawRemoveOrderParams, removeOrderParams, } from './remove.js' + +export type { + ViewLimitOrderParams, + ViewLimitOrderLogicsParams, +} from './view.js' + +export { + mgvOrderViewABI, + smartRouterViewABI, + viewExpirationParams, + viewProvisionParams, + viewLimitOrderLogicsParams, +} from './view.js' diff --git a/src/builder/order/view.ts b/src/builder/order/view.ts new file mode 100644 index 0000000..0645590 --- /dev/null +++ b/src/builder/order/view.ts @@ -0,0 +1,68 @@ +import { type Address, type ContractFunctionParameters, parseAbi } from 'viem' +import { hash } from '../../lib/ol-key.js' +import type { OLKey } from '../../types/lib.js' +import { olKeyABIRaw } from '../structs.js' + +export const mgvOrderViewABI = parseAbi([ + olKeyABIRaw, + 'struct Condition {uint160 date;uint96 volume;}', + 'function reneging(bytes32 olKeyHash, uint offerId) public view returns (Condition memory)', + 'function provisionOf(OLKey memory olKey, uint offerId) external view returns (uint provision)', +]) + +export const smartRouterViewABI = parseAbi([ + 'struct RoutingOrder {address token;bytes32 olKeyHash;uint offerId;address fundOwner;}', + 'function getLogic(RoutingOrder calldata routingOrder) external view returns (address)', +]) + +export type ViewLimitOrderParams = { + olKey: OLKey + offerId: bigint +} + +export function viewExpirationParams(params: ViewLimitOrderParams) { + return { + abi: mgvOrderViewABI, + functionName: 'reneging', + args: [hash(params.olKey), params.offerId], + } satisfies Omit< + ContractFunctionParameters, + 'address' + > +} + +export function viewProvisionParams(params: ViewLimitOrderParams) { + return { + abi: mgvOrderViewABI, + functionName: 'provisionOf', + args: [params.olKey, params.offerId], + } satisfies Omit< + ContractFunctionParameters, + 'address' + > +} + +export type ViewLimitOrderLogicsParams = { + olKey: OLKey + offerId: bigint + user: Address + token: Address +} + +export function viewLimitOrderLogicsParams(params: ViewLimitOrderLogicsParams) { + return { + abi: smartRouterViewABI, + functionName: 'getLogic', + args: [ + { + token: params.token, + olKeyHash: hash(params.olKey), + offerId: params.offerId, + fundOwner: params.user, + }, + ], + } satisfies Omit< + ContractFunctionParameters, + 'address' + > +} diff --git a/src/bundle/public/mangrove-actions.ts b/src/bundle/public/mangrove-actions.ts index 99e1883..d6bb63a 100644 --- a/src/bundle/public/mangrove-actions.ts +++ b/src/bundle/public/mangrove-actions.ts @@ -1,6 +1,13 @@ import type { Address, Client } from 'viem' import type { GetUserRouterArgs } from '../../actions/index.js' import { getUserRouter } from '../../actions/index.js' +import { + type GetOrdersArgs, + type GetSingleOrderArgs, + type OrderResult, + getOrder, + getOrders, +} from '../../actions/order/view.js' import { type DeployRouterArgs, type DeployRouterResult, @@ -21,6 +28,12 @@ export type MangroveActions = { /** Deploys the smart router instance for the given user */ simulateDeployRouter: (args: DeployRouterArgs) => Promise + + /** Get a single order details given its market, side, and id */ + getOrder: (args: GetSingleOrderArgs) => Promise + + /** Gets multiple orders details given their markets, sides, and ids */ + getOrders: (args: GetOrdersArgs) => Promise } export function mangroveActions(actionsParams: MangroveActionsDefaultParams) { @@ -28,5 +41,7 @@ export function mangroveActions(actionsParams: MangroveActionsDefaultParams) { getUserRouter: (args) => getUserRouter(client, actionsParams, args), simulateDeployRouter: (args) => simulateDeployRouter(client, actionsParams, args), + getOrder: (args) => getOrder(client, actionsParams, args), + getOrders: (args) => getOrders(client, actionsParams, args), }) } diff --git a/src/index.ts b/src/index.ts index e03c699..8e17a19 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,12 @@ export type { WaitForSetExpirationResultParams, WaitForRemoveLimitOrderResult, WaitForMarketOrderResultParams, + OrderResult, + GetSingleOrderParams, + GetSingleOrderArgs, + GetOrdersParamsSingleMarket, + GetOrdersParams, + GetOrdersArgs, } from './actions/index.js' // -- lib functions -- diff --git a/src/lib/human-readable.ts b/src/lib/human-readable.ts index 3cf7dab..a71d2cd 100644 --- a/src/lib/human-readable.ts +++ b/src/lib/human-readable.ts @@ -1,6 +1,6 @@ import { formatUnits } from 'viem' import type { MarketParams } from '../types/index.js' -import type { BA } from './enums.js' +import { BA } from './enums.js' import { inboundFromOutbound, outboundFromInbound, @@ -24,7 +24,7 @@ export function rpcOfferToHumanOffer({ baseDecimals: number quoteDecimals: number }) { - if (ba === 'asks') { + if (ba === BA.asks) { const volume = Number(formatUnits(gives, baseDecimals)) const total = Number( formatUnits(inboundFromOutbound(tick, gives), quoteDecimals),