@parchment-trade/sdk 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +193 -2
  3. package/REFERENCE.md +338 -0
  4. package/SECURITY.md +25 -0
  5. package/dist/general/providers/index.d.ts +2 -0
  6. package/dist/general/providers/index.js +2 -0
  7. package/dist/general/providers/parchment.d.ts +1 -0
  8. package/dist/general/providers/parchment.js +1 -0
  9. package/dist/general/providers/parchmentSdk.d.ts +23 -0
  10. package/dist/general/providers/parchmentSdk.js +11 -0
  11. package/dist/general/types/configTypes.d.ts +62 -0
  12. package/dist/general/types/configTypes.js +1 -0
  13. package/dist/general/types/index.d.ts +1 -0
  14. package/dist/general/types/index.js +1 -0
  15. package/dist/general/utils/address.d.ts +49 -0
  16. package/dist/general/utils/address.js +110 -0
  17. package/dist/general/utils/caller.d.ts +58 -0
  18. package/dist/general/utils/caller.js +182 -0
  19. package/dist/general/utils/errors.d.ts +16 -0
  20. package/dist/general/utils/errors.js +26 -0
  21. package/dist/general/utils/index.d.ts +4 -0
  22. package/dist/general/utils/index.js +4 -0
  23. package/dist/general/utils/jsBigInt.d.ts +26 -0
  24. package/dist/general/utils/jsBigInt.js +74 -0
  25. package/dist/general/utils/txShape.d.ts +8 -0
  26. package/dist/general/utils/txShape.js +39 -0
  27. package/dist/index.d.ts +4 -0
  28. package/dist/index.js +4 -0
  29. package/dist/packages/index.d.ts +11 -0
  30. package/dist/packages/index.js +5 -0
  31. package/dist/packages/parchment/abortCodes.d.ts +196 -0
  32. package/dist/packages/parchment/abortCodes.js +522 -0
  33. package/dist/packages/parchment/batchClose.d.ts +268 -0
  34. package/dist/packages/parchment/batchClose.js +524 -0
  35. package/dist/packages/parchment/eventGuard.d.ts +106 -0
  36. package/dist/packages/parchment/eventGuard.js +119 -0
  37. package/dist/packages/parchment/gameCounterEvents.d.ts +59 -0
  38. package/dist/packages/parchment/gameCounterEvents.js +56 -0
  39. package/dist/packages/parchment/index.d.ts +52 -0
  40. package/dist/packages/parchment/index.js +30 -0
  41. package/dist/packages/parchment/liquidationCredit.d.ts +28 -0
  42. package/dist/packages/parchment/liquidationCredit.js +25 -0
  43. package/dist/packages/parchment/lockedMintEvents.d.ts +42 -0
  44. package/dist/packages/parchment/lockedMintEvents.js +46 -0
  45. package/dist/packages/parchment/monitoring.d.ts +369 -0
  46. package/dist/packages/parchment/monitoring.js +259 -0
  47. package/dist/packages/parchment/notes.d.ts +6 -0
  48. package/dist/packages/parchment/notes.js +1 -0
  49. package/dist/packages/parchment/onboarding.d.ts +50 -0
  50. package/dist/packages/parchment/onboarding.js +48 -0
  51. package/dist/packages/parchment/orderEffects.d.ts +207 -0
  52. package/dist/packages/parchment/orderEffects.js +268 -0
  53. package/dist/packages/parchment/orderParams.d.ts +72 -0
  54. package/dist/packages/parchment/orderParams.js +71 -0
  55. package/dist/packages/parchment/packageIds.d.ts +53 -0
  56. package/dist/packages/parchment/packageIds.js +149 -0
  57. package/dist/packages/parchment/parchment.d.ts +442 -0
  58. package/dist/packages/parchment/parchment.js +975 -0
  59. package/dist/packages/parchment/parchmentAccount.d.ts +189 -0
  60. package/dist/packages/parchment/parchmentAccount.js +273 -0
  61. package/dist/packages/parchment/parchmentMarket.d.ts +58 -0
  62. package/dist/packages/parchment/parchmentMarket.js +86 -0
  63. package/dist/packages/parchment/parchmentTypes.d.ts +2031 -0
  64. package/dist/packages/parchment/parchmentTypes.js +65 -0
  65. package/dist/packages/parchment/publicInts.d.ts +45 -0
  66. package/dist/packages/parchment/publicInts.js +383 -0
  67. package/dist/packages/parchment/reconcileEvents.d.ts +24 -0
  68. package/dist/packages/parchment/reconcileEvents.js +30 -0
  69. package/dist/packages/parchment/retainedFee.d.ts +43 -0
  70. package/dist/packages/parchment/retainedFee.js +68 -0
  71. package/dist/packages/parchment/sessionClose.d.ts +68 -0
  72. package/dist/packages/parchment/sessionClose.js +50 -0
  73. package/dist/packages/parchment/sessionKey.d.ts +78 -0
  74. package/dist/packages/parchment/sessionKey.js +154 -0
  75. package/dist/packages/parchment/slippage.d.ts +23 -0
  76. package/dist/packages/parchment/slippage.js +27 -0
  77. package/dist/packages/parchment/sponsor.d.ts +39 -0
  78. package/dist/packages/parchment/sponsor.js +48 -0
  79. package/dist/packages/parchment/stakingCalls.d.ts +33 -0
  80. package/dist/packages/parchment/stakingCalls.js +21 -0
  81. package/dist/packages/parchment/stakingEvents.d.ts +53 -0
  82. package/dist/packages/parchment/stakingEvents.js +71 -0
  83. package/dist/packages/parchment/triggerCalls.d.ts +46 -0
  84. package/dist/packages/parchment/triggerCalls.js +36 -0
  85. package/dist/packages/parchment/triggerEvents.d.ts +22 -0
  86. package/dist/packages/parchment/triggerEvents.js +33 -0
  87. package/dist/packages/parchment/triggers.d.ts +113 -0
  88. package/dist/packages/parchment/triggers.js +183 -0
  89. package/dist/packages/parchment/txBodies.d.ts +111 -0
  90. package/dist/packages/parchment/txBodies.js +683 -0
  91. package/dist/packages/parchment/txIntent.d.ts +99 -0
  92. package/dist/packages/parchment/txIntent.js +611 -0
  93. package/dist/types.d.ts +2 -0
  94. package/dist/types.js +1 -0
  95. package/package.json +58 -4
@@ -0,0 +1,48 @@
1
+ import { bcs } from "@mysten/sui/bcs";
2
+ import { deriveObjectID, normalizeSuiAddress } from "@mysten/sui/utils";
3
+ function obj(tx, o) {
4
+ return typeof o === "string" ? tx.object(o) : o;
5
+ }
6
+ export function addOneSignatureOnboardingCalls(tx, input) {
7
+ const exchange = obj(tx, input.exchange);
8
+ const config = obj(tx, input.config);
9
+ const [account, cap, receipt] = tx.moveCall({
10
+ target: `${input.packageId}::exchange::new_account`,
11
+ typeArguments: [input.coinType],
12
+ arguments: [exchange, config],
13
+ });
14
+ if (input.deposit !== undefined) {
15
+ tx.moveCall({
16
+ target: `${input.packageId}::exchange::deposit`,
17
+ typeArguments: [input.coinType],
18
+ arguments: [exchange, config, account, cap, obj(tx, input.deposit)],
19
+ });
20
+ }
21
+ if (input.delegate) {
22
+ tx.moveCall({
23
+ target: `${input.packageId}::exchange::${input.delegate.closeDelegate === undefined ? "grant_delegate" : "grant_session_and_close_delegate"}`,
24
+ typeArguments: [input.coinType],
25
+ arguments: [
26
+ exchange,
27
+ account,
28
+ config,
29
+ cap,
30
+ tx.pure.address(input.delegate.address),
31
+ tx.pure.u64(BigInt(input.delegate.expiryMs)),
32
+ ...(input.delegate.closeDelegate === undefined ? [] : [tx.pure.address(input.delegate.closeDelegate)]),
33
+ tx.object.clock(),
34
+ ],
35
+ });
36
+ }
37
+ tx.moveCall({
38
+ target: `${input.packageId}::exchange::share_account`,
39
+ typeArguments: [input.coinType],
40
+ arguments: [account, cap, receipt],
41
+ });
42
+ }
43
+ const ACCOUNT_KEY = bcs.struct("AccountKey", { owner: bcs.Address, nonce: bcs.u64() });
44
+ export function deriveAccountId(input) {
45
+ const keyType = `${normalizeSuiAddress(input.originalPackageId)}::account::AccountKey`;
46
+ const key = ACCOUNT_KEY.serialize({ owner: input.owner, nonce: BigInt(input.nonce ?? 0) }).toBytes();
47
+ return deriveObjectID(normalizeSuiAddress(input.exchangeId), keyType, key);
48
+ }
@@ -0,0 +1,207 @@
1
+ import type { ApiParchmentConfigResponse, Order, OrderKind, OrderRefundReason, OrderStatus } from "./parchmentTypes.js";
2
+ /** An order created by a request-open / request-close transaction. */
3
+ export interface RequestedOrderRef {
4
+ /** `OrderRequest` object id (0x + 64 hex). Pass it to `getOrder` / `waitForOrder`. */
5
+ orderId: string;
6
+ /** From the event; null when only the created object was found. */
7
+ kind: OrderKind | null;
8
+ }
9
+ /**
10
+ * One event as either client reports it: `@mysten/sui` 2.x core results (`eventType`, BCS bytes,
11
+ * `json`) or 1.x JSON-RPC `SuiEvent` (`type`, `bcs` a base64 or base58 string per `bcsEncoding`,
12
+ * `parsedJson`).
13
+ */
14
+ export interface ParchmentExecutedEventLike {
15
+ eventType?: string;
16
+ type?: string;
17
+ bcs?: Uint8Array | string | null;
18
+ bcsEncoding?: "base64" | "base58" | string;
19
+ json?: Record<string, unknown> | null;
20
+ parsedJson?: unknown;
21
+ }
22
+ /**
23
+ * The parts of an executed-transaction result this module reads. Both result shapes are covered:
24
+ * `@mysten/sui` 2.x core results (`events[].eventType` + `bcs`/`json`, `effects.changedObjects`,
25
+ * `objectTypes`) and 1.x JSON-RPC responses (`events[].type` + string `bcs` / `parsedJson`,
26
+ * `objectChanges`, effects with `created` refs). A 2.x `{ $kind: "Transaction", Transaction }`
27
+ * wrapper is unwrapped. JSON-RPC effects carry no object types, so there a created order is found
28
+ * from `objectChanges` (request it with `showObjectChanges`). An `objectTypes` that is still a
29
+ * promise (1.x experimental core results) is not awaited and is ignored.
30
+ */
31
+ export interface ParchmentExecutedTxLike {
32
+ events?: ReadonlyArray<ParchmentExecutedEventLike> | null;
33
+ effects?: {
34
+ /** 2.x core effects. */
35
+ changedObjects?: ReadonlyArray<{
36
+ objectId: string;
37
+ idOperation?: string;
38
+ }>;
39
+ /** 1.x JSON-RPC effects (untyped refs; not read). */
40
+ created?: ReadonlyArray<{
41
+ reference: {
42
+ objectId: string;
43
+ };
44
+ }> | null;
45
+ } | null;
46
+ objectTypes?: Record<string, string> | PromiseLike<Record<string, string>> | null;
47
+ objectChanges?: ReadonlyArray<{
48
+ type: string;
49
+ objectId?: string;
50
+ objectType?: string;
51
+ }> | null;
52
+ }
53
+ /**
54
+ * The Parchment package ids an executed tx's types are matched against: `/v1/config`'s fields
55
+ * (pass the config response). Events (`events` module) must come from a core `parchment` package
56
+ * (`packageId` / `packageIds`); the created `order::OrderRequest` object from a `parchment_trade`
57
+ * package (`tradePackageId` / `tradePackageIds`). Without a scope any package matches, which is
58
+ * only safe for a tx you built yourself. With or without a scope only the exact forms are read:
59
+ * `P::events::E` / `P::events::Event<P::events::E>` and a top-level `T::order::OrderRequest<...>`;
60
+ * a type wrapping them (e.g. `0xEVIL::fake::Wrapper<P::events::E>`) never matches.
61
+ */
62
+ export type ParchmentPackageScope = Partial<Pick<ApiParchmentConfigResponse, "packageId" | "packageIds" | "tradePackageId" | "tradePackageIds">>;
63
+ /**
64
+ * BCS layout of `parchment::events::OrderRequestedEventV1`, field for field in `events.move`
65
+ * order. `events::Event<T>` is a one-field positional wrapper, so its BCS is exactly T's.
66
+ */
67
+ export declare const ORDER_REQUESTED_EVENT_BCS: import("@mysten/sui/bcs").BcsStruct<{
68
+ order_id: import("@mysten/sui/bcs").BcsType<string, string | Uint8Array<ArrayBufferLike>, "bytes[32]">;
69
+ account_id: import("@mysten/sui/bcs").BcsType<string, string | Uint8Array<ArrayBufferLike>, "bytes[32]">;
70
+ owner: import("@mysten/sui/bcs").BcsType<string, string | Uint8Array<ArrayBufferLike>, "bytes[32]">;
71
+ requester: import("@mysten/sui/bcs").BcsType<string, string | Uint8Array<ArrayBufferLike>, "bytes[32]">;
72
+ market_id: import("@mysten/sui/bcs").BcsType<string, string | Uint8Array<ArrayBufferLike>, "bytes[32]">;
73
+ kind: import("@mysten/sui/bcs").BcsType<number, number, "u8">;
74
+ is_long: import("@mysten/sui/bcs").BcsType<boolean, boolean, "bool">;
75
+ margin: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
76
+ leverage: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
77
+ position_id: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
78
+ acceptable_price_wad: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u128">;
79
+ min_factor_bps: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
80
+ max_fee_bps: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
81
+ exec_fee: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
82
+ requested_ms: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
83
+ fill_deadline_ms: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
84
+ cancel_after_ms: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
85
+ emergency_after_ms: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
86
+ /** Close requests: the exec fee part not escrowed (free balance was short), taken from a filled close's payout. */
87
+ fee_owed: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
88
+ }, string>;
89
+ /** BCS layout of `parchment::events::OrderFinalizedEventV1`, in `events.move` field order. */
90
+ export declare const ORDER_FINALIZED_EVENT_BCS: import("@mysten/sui/bcs").BcsStruct<{
91
+ order_id: import("@mysten/sui/bcs").BcsType<string, string | Uint8Array<ArrayBufferLike>, "bytes[32]">;
92
+ account_id: import("@mysten/sui/bcs").BcsType<string, string | Uint8Array<ArrayBufferLike>, "bytes[32]">;
93
+ owner: import("@mysten/sui/bcs").BcsType<string, string | Uint8Array<ArrayBufferLike>, "bytes[32]">;
94
+ market_id: import("@mysten/sui/bcs").BcsType<string, string | Uint8Array<ArrayBufferLike>, "bytes[32]">;
95
+ kind: import("@mysten/sui/bcs").BcsType<number, number, "u8">;
96
+ outcome: import("@mysten/sui/bcs").BcsType<number, number, "u8">;
97
+ position_id: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
98
+ price_wad: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u128">;
99
+ price_ts_ms: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
100
+ refund: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
101
+ exec_fee: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
102
+ finalized_ms: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
103
+ sender: import("@mysten/sui/bcs").BcsType<string, string | Uint8Array<ArrayBufferLike>, "bytes[32]">;
104
+ /** The escrowed exec fee returned to free balance (refund outcomes, an expiry with no in-window storage write); 0 when paid. */
105
+ exec_fee_refunded: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
106
+ }, string>;
107
+ export type OrderRequestedEventV1 = ReturnType<typeof ORDER_REQUESTED_EVENT_BCS.parse>;
108
+ export type OrderFinalizedEventV1 = ReturnType<typeof ORDER_FINALIZED_EVENT_BCS.parse>;
109
+ /** Decode an `OrderRequestedEventV1` (or its `Event<…>` wrapper) from BCS; null if it doesn't fit. */
110
+ export declare function decodeOrderRequestedEvent(bytes: Uint8Array): OrderRequestedEventV1 | null;
111
+ /** Decode an `OrderFinalizedEventV1` (or its `Event<…>` wrapper) from BCS; null if it doesn't fit. */
112
+ export declare function decodeOrderFinalizedEvent(bytes: Uint8Array): OrderFinalizedEventV1 | null;
113
+ /**
114
+ * Orders created by an executed request-open / request-close transaction, in event order.
115
+ *
116
+ * Reads `OrderRequestedEventV1`: BCS decoded with the full `events.move` layout (rejected unless
117
+ * it fits exactly), otherwise the JSON by field name. When the result carries no events, falls
118
+ * back to created `…::order::OrderRequest<…>` objects (needs `objectTypes` or `objectChanges`).
119
+ * Returns `[]` when nothing matched, e.g. a failed tx or a result fetched without events/types.
120
+ * Pass `scope` (the `/v1/config` response) to ignore look-alike types from other packages; see
121
+ * {@link ParchmentPackageScope}.
122
+ */
123
+ export declare function requestedOrdersFromTx(result: ParchmentExecutedTxLike | {
124
+ Transaction: ParchmentExecutedTxLike;
125
+ }, scope?: ParchmentPackageScope): RequestedOrderRef[];
126
+ /**
127
+ * The single order id created by a request transaction, or null when there is none or more than
128
+ * one. See {@link requestedOrdersFromTx}.
129
+ */
130
+ export declare function requestedOrderIdFromTx(result: ParchmentExecutedTxLike | {
131
+ Transaction: ParchmentExecutedTxLike;
132
+ }, scope?: ParchmentPackageScope): string | null;
133
+ /**
134
+ * Clock ms strictly after which `expire-order` is allowed, mirroring `order::expires_after_ms`:
135
+ * `fillDeadlineMs` for opens and for closes with emergency close disabled; otherwise
136
+ * `emergencyAfterMs + (fillDeadlineMs - requestedMs)`. Emergency close counts as disabled only for
137
+ * u64::MAX, as on chain. Null when a needed field is missing
138
+ * (the indexer saw the final event first).
139
+ */
140
+ export declare function orderExpiresAfterMs(order: Pick<Order, "kind" | "requestedMs" | "fillDeadlineMs" | "emergencyAfterMs">): bigint | null;
141
+ /** `order::MIN_CANCEL_DELAY_MS`: cancel is never allowed before `requestedMs + 5 s`. */
142
+ export declare const MIN_CANCEL_DELAY_MS = 5000n;
143
+ /**
144
+ * Clock ms from which `cancel-order` is allowed, mirroring the `order::cancel_after_ms` view:
145
+ * `max(cancelAfterMs, requestedMs + MIN_CANCEL_DELAY_MS)`. `cancelAfterMs` is the stored value
146
+ * (the order's / event's `cancelAfterMs`); without it, `requestedMs + cancelDelayMs` (the
147
+ * market's `OrderParamsV1.cancelDelayMs`). Null when `requestedMs` or both inputs are missing.
148
+ */
149
+ export declare function effectiveCancelAfterMs(order: {
150
+ requestedMs: string | number | bigint | null;
151
+ cancelAfterMs?: string | number | bigint | null;
152
+ cancelDelayMs?: string | number | bigint | null;
153
+ }): bigint | null;
154
+ /**
155
+ * `OrderFinalizedEventV1.outcome` -> the service's `status` / `reason`, from the `OUTCOME_*`
156
+ * constants in `order.move` (same mapping as the service's `order_status`). Outcome 1 on a close
157
+ * is a liquidate-on-close fill; 11 is `emergency_close`; 10 is a close whose position was gone;
158
+ * 12 is reserved (the signed-band close refund, no longer emitted).
159
+ * 13 (`session`) is an order refunded because its equity market was being force-closed at session end
160
+ * (open or close filled while the session close was pending, or a close whose position the force close took).
161
+ * 14 (`retry`, the served wire name; `OUTCOME_REFUND_LIQ_PAUSED`; no pause emits it despite the name) is a fill refunded because the
162
+ * account's liquidation backlog exceeded the per-fill cleanup cap, or the keeper's cleanup refund when that cleanup
163
+ * is on a killed market: escrow and exec fee refunded, and a later try succeeds.
164
+ * 15 (`revoked`, `OUTCOME_REFUND_REVOKED`) is a delegate request whose requester is no longer a live
165
+ * delegate of the right type at the order's cancel point: escrow refunded, exec fee kept like a cancel
166
+ * (earlier contracts also refunded the fee), the order does not open or close.
167
+ * 9 (`risk`) covers every open-fill risk rung: market risk params, the account notional cap, and
168
+ * an order whose own notional exceeds `max_tx_notional`.
169
+ */
170
+ export declare const ORDER_OUTCOMES: Readonly<Record<number, {
171
+ name: string;
172
+ status: OrderStatus;
173
+ reason: OrderRefundReason | null;
174
+ }>>;
175
+ /** Readable copy for outcome 13 (`OUTCOME_SESSION_CLOSED`, `refunded` / `session`). */
176
+ export declare const ORDER_REFUND_SESSION_MESSAGE = "Refunded: session closed";
177
+ /** Status and refund reason for an on-chain outcome code; `unknown` for a code this SDK predates. */
178
+ export declare function orderOutcome(outcome: number): {
179
+ status: OrderStatus;
180
+ reason: OrderRefundReason | null;
181
+ };
182
+ /** An order finalized by an executed fill / cancel / expire / emergency-close transaction. */
183
+ export interface FinalizedOrderRef {
184
+ orderId: string;
185
+ kind: OrderKind | null;
186
+ /** Raw `OUTCOME_*` code. */
187
+ outcome: number;
188
+ status: OrderStatus;
189
+ reason: OrderRefundReason | null;
190
+ positionId: string;
191
+ /** Fill / reference mid (WAD); "0" for cancel and expire. */
192
+ priceWad: string;
193
+ priceTsMs: string;
194
+ /** Escrow returned to free balance; "0" for a filled order. */
195
+ refund: string;
196
+ execFee: string;
197
+ /** Escrowed exec fee returned to free balance; "0" when the fee was paid. An EXPIRED order refunds it unless a keeper missed an in-window storage write. */
198
+ execFeeRefunded: string;
199
+ }
200
+ /**
201
+ * Orders finalized by an executed transaction, in event order. Reads `OrderFinalizedEventV1`:
202
+ * BCS decoded with the full `events.move` layout, otherwise the JSON by field name (`pos0`
203
+ * wrapper or inline). Events that fit neither are skipped.
204
+ */
205
+ export declare function finalizedOrdersFromTx(result: ParchmentExecutedTxLike | {
206
+ Transaction: ParchmentExecutedTxLike;
207
+ }, scope?: ParchmentPackageScope): FinalizedOrderRef[];
@@ -0,0 +1,268 @@
1
+ import { bcs } from "@mysten/sui/bcs";
2
+ import { fromBase58, fromBase64, normalizeSuiAddress } from "@mysten/sui/utils";
3
+ import { isEmergencyAfterDisabled } from "./orderParams.js";
4
+ function eventBcs(event) {
5
+ const raw = event.bcs;
6
+ if (raw == null)
7
+ return null;
8
+ if (typeof raw !== "string")
9
+ return raw.length > 0 ? raw : null;
10
+ try {
11
+ const bytes = event.bcsEncoding === "base58" ? fromBase58(raw) : fromBase64(raw);
12
+ return bytes.length > 0 ? bytes : null;
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ }
18
+ const ADDR = "0x[0-9a-fA-F]{1,64}";
19
+ function eventType(name) {
20
+ return new RegExp(`^(?:(${ADDR})::events::Event<(${ADDR})::events::${name}>|(${ADDR})::events::${name})$`);
21
+ }
22
+ const REQUESTED_EVENT = eventType("OrderRequestedEventV1");
23
+ const FINALIZED_EVENT = eventType("OrderFinalizedEventV1");
24
+ const ORDER_TYPE = new RegExp(`^(${ADDR})::order::OrderRequest(<.*>)$`);
25
+ function idSet(one, many) {
26
+ const out = new Set();
27
+ for (const id of [one, ...(many ?? [])])
28
+ if (id)
29
+ out.add(normalizeSuiAddress(id));
30
+ return out;
31
+ }
32
+ function inPackages(ids, allowed) {
33
+ return !allowed || ids.every((id) => allowed.has(normalizeSuiAddress(id)));
34
+ }
35
+ function isCoreEvent(type, pattern, allowed) {
36
+ const m = pattern.exec(type);
37
+ return !!m && inPackages(m.slice(1).filter((id) => !!id), allowed);
38
+ }
39
+ function oneTypeArgList(args) {
40
+ let depth = 0;
41
+ for (let i = 0; i < args.length; i++) {
42
+ if (args[i] === "<")
43
+ depth++;
44
+ else if (args[i] === ">" && --depth === 0 && i !== args.length - 1)
45
+ return false;
46
+ if (depth < 0)
47
+ return false;
48
+ }
49
+ return depth === 0;
50
+ }
51
+ function isOrderRequestType(type, allowed) {
52
+ const m = ORDER_TYPE.exec(type);
53
+ return !!m && oneTypeArgList(m[2]) && inPackages([m[1]], allowed);
54
+ }
55
+ function scopeSets(scope) {
56
+ if (!scope)
57
+ return { core: null, trade: null };
58
+ return { core: idSet(scope.packageId, scope.packageIds), trade: idSet(scope.tradePackageId, scope.tradePackageIds) };
59
+ }
60
+ export const ORDER_REQUESTED_EVENT_BCS = bcs.struct("OrderRequestedEventV1", {
61
+ order_id: bcs.Address,
62
+ account_id: bcs.Address,
63
+ owner: bcs.Address,
64
+ requester: bcs.Address,
65
+ market_id: bcs.Address,
66
+ kind: bcs.u8(),
67
+ is_long: bcs.bool(),
68
+ margin: bcs.u64(),
69
+ leverage: bcs.u64(),
70
+ position_id: bcs.u64(),
71
+ acceptable_price_wad: bcs.u128(),
72
+ min_factor_bps: bcs.u64(),
73
+ max_fee_bps: bcs.u64(),
74
+ exec_fee: bcs.u64(),
75
+ requested_ms: bcs.u64(),
76
+ fill_deadline_ms: bcs.u64(),
77
+ cancel_after_ms: bcs.u64(),
78
+ emergency_after_ms: bcs.u64(),
79
+ fee_owed: bcs.u64(),
80
+ });
81
+ export const ORDER_FINALIZED_EVENT_BCS = bcs.struct("OrderFinalizedEventV1", {
82
+ order_id: bcs.Address,
83
+ account_id: bcs.Address,
84
+ owner: bcs.Address,
85
+ market_id: bcs.Address,
86
+ kind: bcs.u8(),
87
+ outcome: bcs.u8(),
88
+ position_id: bcs.u64(),
89
+ price_wad: bcs.u128(),
90
+ price_ts_ms: bcs.u64(),
91
+ refund: bcs.u64(),
92
+ exec_fee: bcs.u64(),
93
+ finalized_ms: bcs.u64(),
94
+ sender: bcs.Address,
95
+ exec_fee_refunded: bcs.u64(),
96
+ });
97
+ function decodeExact(layout, bytes) {
98
+ try {
99
+ const value = layout.parse(bytes);
100
+ return layout.serialize(value).toBytes().length === bytes.length ? value : null;
101
+ }
102
+ catch {
103
+ return null;
104
+ }
105
+ }
106
+ export function decodeOrderRequestedEvent(bytes) {
107
+ return decodeExact(ORDER_REQUESTED_EVENT_BCS, bytes);
108
+ }
109
+ export function decodeOrderFinalizedEvent(bytes) {
110
+ return decodeExact(ORDER_FINALIZED_EVENT_BCS, bytes);
111
+ }
112
+ export function requestedOrdersFromTx(result, scope) {
113
+ const tx = "Transaction" in result && result.Transaction ? result.Transaction : result;
114
+ const { core, trade } = scopeSets(scope);
115
+ const isOrderType = (type) => isOrderRequestType(type, trade);
116
+ const fromEvents = [];
117
+ for (const event of tx.events ?? []) {
118
+ const type = event.eventType ?? event.type ?? "";
119
+ if (!isCoreEvent(type, REQUESTED_EVENT, core))
120
+ continue;
121
+ const ref = eventRef(event);
122
+ if (ref)
123
+ fromEvents.push(ref);
124
+ }
125
+ if (fromEvents.length > 0)
126
+ return fromEvents;
127
+ const ids = new Set();
128
+ for (const change of tx.objectChanges ?? []) {
129
+ if (change.type === "created" && change.objectId && isOrderType(change.objectType ?? "")) {
130
+ ids.add(normalizeSuiAddress(change.objectId));
131
+ }
132
+ }
133
+ const types = plainObjectTypes(tx.objectTypes);
134
+ for (const change of tx.effects?.changedObjects ?? []) {
135
+ if (change.idOperation === "Created" && isOrderType(types[change.objectId] ?? "")) {
136
+ ids.add(normalizeSuiAddress(change.objectId));
137
+ }
138
+ }
139
+ return [...ids].map((orderId) => ({ orderId, kind: null }));
140
+ }
141
+ export function requestedOrderIdFromTx(result, scope) {
142
+ const orders = requestedOrdersFromTx(result, scope);
143
+ return orders.length === 1 ? orders[0].orderId : null;
144
+ }
145
+ function plainObjectTypes(types) {
146
+ if (!types || typeof types.then === "function")
147
+ return {};
148
+ return types;
149
+ }
150
+ function eventRef(event) {
151
+ const bytes = eventBcs(event);
152
+ const decoded = bytes ? decodeOrderRequestedEvent(bytes) : null;
153
+ if (decoded)
154
+ return { orderId: normalizeSuiAddress(decoded.order_id), kind: kindOf(decoded.kind) };
155
+ const json = (event.json ?? event.parsedJson);
156
+ const inner = (json && typeof json.pos0 === "object" && json.pos0 !== null ? json.pos0 : json);
157
+ const id = inner?.order_id;
158
+ if (typeof id !== "string" || !/^0x[0-9a-fA-F]{1,64}$/.test(id))
159
+ return null;
160
+ return { orderId: normalizeSuiAddress(id), kind: kindOf(jsonInt(inner?.kind)) };
161
+ }
162
+ function jsonInt(v) {
163
+ if (typeof v === "number")
164
+ return Number.isSafeInteger(v) && v >= 0 ? v : NaN;
165
+ return typeof v === "string" && /^\d+$/.test(v) ? Number(v) : NaN;
166
+ }
167
+ function kindOf(raw) {
168
+ return raw === 0 ? "open" : raw === 1 ? "close" : null;
169
+ }
170
+ export function orderExpiresAfterMs(order) {
171
+ if (order.fillDeadlineMs === null)
172
+ return null;
173
+ const deadline = order.fillDeadlineMs;
174
+ if (order.kind === "open")
175
+ return deadline;
176
+ if (order.emergencyAfterMs === null || order.requestedMs === null)
177
+ return null;
178
+ if (isEmergencyAfterDisabled(order.emergencyAfterMs))
179
+ return deadline;
180
+ return order.emergencyAfterMs + (deadline - order.requestedMs);
181
+ }
182
+ export const MIN_CANCEL_DELAY_MS = 5000n;
183
+ export function effectiveCancelAfterMs(order) {
184
+ if (order.requestedMs === null || order.requestedMs === undefined)
185
+ return null;
186
+ const requested = BigInt(order.requestedMs);
187
+ let stored;
188
+ if (order.cancelAfterMs !== null && order.cancelAfterMs !== undefined)
189
+ stored = BigInt(order.cancelAfterMs);
190
+ else if (order.cancelDelayMs !== null && order.cancelDelayMs !== undefined)
191
+ stored = requested + BigInt(order.cancelDelayMs);
192
+ else
193
+ return null;
194
+ const floor = requested + MIN_CANCEL_DELAY_MS;
195
+ return stored > floor ? stored : floor;
196
+ }
197
+ export const ORDER_OUTCOMES = {
198
+ 0: { name: "OUTCOME_FILLED", status: "filled", reason: null },
199
+ 1: { name: "OUTCOME_LIQUIDATED", status: "liquidated", reason: null },
200
+ 2: { name: "OUTCOME_CANCELLED", status: "cancelled", reason: null },
201
+ 3: { name: "OUTCOME_EXPIRED", status: "expired", reason: null },
202
+ 5: { name: "OUTCOME_REFUND_PAUSED", status: "refunded", reason: "paused" },
203
+ 6: { name: "OUTCOME_REFUND_KILLED", status: "refunded", reason: "killed" },
204
+ 7: { name: "OUTCOME_REFUND_CLOSED", status: "refunded", reason: "closed" },
205
+ 8: { name: "OUTCOME_REFUND_FEE", status: "refunded", reason: "fee" },
206
+ 9: { name: "OUTCOME_REFUND_RISK", status: "refunded", reason: "risk" },
207
+ 10: { name: "OUTCOME_VOID", status: "void", reason: null },
208
+ 11: { name: "OUTCOME_EMERGENCY_CLOSED", status: "emergency_closed", reason: null },
209
+ 12: { name: "OUTCOME_REFUND_BAND", status: "refunded", reason: "band" },
210
+ 13: { name: "OUTCOME_SESSION_CLOSED", status: "refunded", reason: "session" },
211
+ 14: { name: "OUTCOME_REFUND_LIQ_PAUSED", status: "refunded", reason: "retry" },
212
+ 15: { name: "OUTCOME_REFUND_REVOKED", status: "refunded", reason: "revoked" },
213
+ };
214
+ export const ORDER_REFUND_SESSION_MESSAGE = "Refunded: session closed";
215
+ export function orderOutcome(outcome) {
216
+ const known = Object.prototype.hasOwnProperty.call(ORDER_OUTCOMES, outcome) ? ORDER_OUTCOMES[outcome] : undefined;
217
+ return known ? { status: known.status, reason: known.reason } : { status: "unknown", reason: null };
218
+ }
219
+ export function finalizedOrdersFromTx(result, scope) {
220
+ const tx = "Transaction" in result && result.Transaction ? result.Transaction : result;
221
+ const { core } = scopeSets(scope);
222
+ const out = [];
223
+ for (const event of tx.events ?? []) {
224
+ const type = event.eventType ?? event.type ?? "";
225
+ if (!isCoreEvent(type, FINALIZED_EVENT, core))
226
+ continue;
227
+ const bytes = eventBcs(event);
228
+ const ev = (bytes ? decodeOrderFinalizedEvent(bytes) : null) ?? finalizedFromJson(event.json ?? event.parsedJson);
229
+ if (!ev)
230
+ continue;
231
+ out.push({
232
+ orderId: normalizeSuiAddress(ev.order_id),
233
+ kind: kindOf(Number(ev.kind)),
234
+ outcome: Number(ev.outcome),
235
+ ...orderOutcome(Number(ev.outcome)),
236
+ positionId: String(ev.position_id),
237
+ priceWad: String(ev.price_wad),
238
+ priceTsMs: String(ev.price_ts_ms),
239
+ refund: String(ev.refund),
240
+ execFee: String(ev.exec_fee),
241
+ execFeeRefunded: String(ev.exec_fee_refunded),
242
+ });
243
+ }
244
+ return out;
245
+ }
246
+ function finalizedFromJson(raw) {
247
+ const json = raw;
248
+ const inner = (json && typeof json.pos0 === "object" && json.pos0 !== null ? json.pos0 : json);
249
+ if (!inner || typeof inner.order_id !== "string" || !/^0x[0-9a-fA-F]{1,64}$/.test(inner.order_id))
250
+ return null;
251
+ const u = (k) => {
252
+ const v = inner[k];
253
+ if (typeof v === "string")
254
+ return /^\d+$/.test(v) ? v : null;
255
+ return typeof v === "number" && Number.isSafeInteger(v) && v >= 0 ? String(v) : null;
256
+ };
257
+ const outcome = jsonInt(inner.outcome);
258
+ const kind = jsonInt(inner.kind);
259
+ const fields = ["position_id", "price_wad", "price_ts_ms", "refund", "exec_fee", "exec_fee_refunded"].map(u);
260
+ if (!Number.isInteger(outcome) || !Number.isInteger(kind) || fields.some((f) => f === null))
261
+ return null;
262
+ const [position_id, price_wad, price_ts_ms, refund, exec_fee, exec_fee_refunded] = fields;
263
+ return {
264
+ order_id: inner.order_id, account_id: String(inner.account_id ?? ""), owner: String(inner.owner ?? ""),
265
+ market_id: String(inner.market_id ?? ""), kind, outcome, position_id, price_wad, price_ts_ms, refund, exec_fee,
266
+ finalized_ms: String(inner.finalized_ms ?? "0"), sender: String(inner.sender ?? ""), exec_fee_refunded,
267
+ };
268
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * BCS layout of `parchment::market::OrderParamsV1`, field for field in `market.move` order. This is
3
+ * the return value of `market::order_params<C>(&Market<C>)` (e.g. from a dev-inspect) and the
4
+ * `order` field of the market's `MarketStateV1`.
5
+ */
6
+ export declare const ORDER_PARAMS_V1_BCS: import("@mysten/sui/bcs").BcsStruct<{
7
+ fill_window_ms: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
8
+ fill_deadline_ms: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
9
+ cancel_delay_ms: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
10
+ emergency_after_ms: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
11
+ exec_fee: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
12
+ one_step_spread_bps: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
13
+ signed_window_ms: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u64">;
14
+ }, string>;
15
+ /** A market's two-step order parameters. All values are u64s as decimal strings. */
16
+ export interface OrderParamsV1 {
17
+ /** W: the request-side window (D and the cancel delay are bounded by it). Fills read S. */
18
+ fillWindowMs: string;
19
+ /** D: a fill must land by requestedMs + D (clock). */
20
+ fillDeadlineMs: string;
21
+ /**
22
+ * Cancel is allowed from `max(requestedMs + this, requestedMs + 5 s)`: the chain floors it at
23
+ * `order::MIN_CANCEL_DELAY_MS` (5 s). See `effectiveCancelAfterMs`.
24
+ */
25
+ cancelDelayMs: string;
26
+ /** Close-request age before `order::emergency_close`; u64::MAX disables it. */
27
+ emergencyAfterMs: string;
28
+ /**
29
+ * Execution fee in collateral base units. Kept on fills, cancel, expiry and most refunds; returned
30
+ * with the escrow on REFUND_PAUSED (5) / REFUND_KILLED (6), SESSION_CLOSED (13, incl. expiry of a
31
+ * session-closed order) and REFUND_LIQ_PAUSED (14).
32
+ */
33
+ execFee: string;
34
+ /** Floor spread for the one-step user paths (emergency close). */
35
+ oneStepSpreadBps: string;
36
+ /**
37
+ * S (verify-in-fill): the keeper fills at the signed Lazer price whose feed update timestamp is in
38
+ * (requestedMs, requestedMs + S].
39
+ */
40
+ signedWindowMs: string;
41
+ }
42
+ /** `emergencyAfterMs` value that disables the emergency close. */
43
+ export declare const EMERGENCY_CLOSE_DISABLED_MS = "18446744073709551615";
44
+ /**
45
+ * Decode `OrderParamsV1` BCS (exactly 56 bytes). Null when the bytes don't fit the layout exactly,
46
+ * which means the on-chain struct changed.
47
+ */
48
+ export declare function decodeOrderParams(bytes: Uint8Array): OrderParamsV1 | null;
49
+ /**
50
+ * Read `OrderParamsV1` from its JSON rendering (snake_case keys, u64s as strings or numbers), e.g.
51
+ * the `order` field of a fetched `MarketStateV1`. A `{ fields: … }` wrapper (JSON-RPC
52
+ * `showContent`) is unwrapped. Null when a field is missing or not a u64.
53
+ */
54
+ export declare function orderParamsFromJson(json: unknown): OrderParamsV1 | null;
55
+ /**
56
+ * True when an `emergencyAfterMs` value means "emergency close disabled": exactly u64::MAX, as
57
+ * `order::expires_after_ms` checks. Accepts a decimal string, a number or a bigint; a number cannot
58
+ * hold u64::MAX exactly, and anything unparseable is false.
59
+ */
60
+ export declare function isEmergencyAfterDisabled(value: string | number | bigint): boolean;
61
+ /** True when the market has the emergency close disabled (`emergency_after_ms == u64::MAX`). */
62
+ export declare function emergencyCloseDisabled(params: {
63
+ emergencyAfterMs: string | number | bigint;
64
+ }): boolean;
65
+ /**
66
+ * Whether an account with `pendingOpenOrders` live OPEN requests may place another open under the
67
+ * admin-set cap `maxPendingOrders` (`getConfig().maxPendingOrders`, the account record's
68
+ * `pendingOpenOrders`). Mirrors `order.move`'s opens-only `pending_open_orders(account) < max_pending_orders`
69
+ * check; an open past it aborts `order::ETooManyOrders` (11). Closes are never capped: do not gate
70
+ * close requests on this. Null when either value is missing (an older service that does not serve them).
71
+ */
72
+ export declare function hasPendingOrderSlot(maxPendingOrders: bigint | null | undefined, pendingOpenOrders: bigint | null | undefined): boolean | null;
@@ -0,0 +1,71 @@
1
+ import { bcs } from "@mysten/sui/bcs";
2
+ export const ORDER_PARAMS_V1_BCS = bcs.struct("OrderParamsV1", {
3
+ fill_window_ms: bcs.u64(),
4
+ fill_deadline_ms: bcs.u64(),
5
+ cancel_delay_ms: bcs.u64(),
6
+ emergency_after_ms: bcs.u64(),
7
+ exec_fee: bcs.u64(),
8
+ one_step_spread_bps: bcs.u64(),
9
+ signed_window_ms: bcs.u64(),
10
+ });
11
+ export const EMERGENCY_CLOSE_DISABLED_MS = "18446744073709551615";
12
+ export function decodeOrderParams(bytes) {
13
+ if (bytes.length !== 56)
14
+ return null;
15
+ const raw = ORDER_PARAMS_V1_BCS.parse(bytes);
16
+ return {
17
+ fillWindowMs: raw.fill_window_ms,
18
+ fillDeadlineMs: raw.fill_deadline_ms,
19
+ cancelDelayMs: raw.cancel_delay_ms,
20
+ emergencyAfterMs: raw.emergency_after_ms,
21
+ execFee: raw.exec_fee,
22
+ oneStepSpreadBps: raw.one_step_spread_bps,
23
+ signedWindowMs: raw.signed_window_ms,
24
+ };
25
+ }
26
+ export function orderParamsFromJson(json) {
27
+ let obj = json;
28
+ if (obj && typeof obj === "object" && typeof obj.fields === "object" && obj.fields !== null) {
29
+ obj = obj.fields;
30
+ }
31
+ if (!obj || typeof obj !== "object")
32
+ return null;
33
+ const u64 = (key) => {
34
+ const camel = key.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
35
+ const v = obj[key] ?? obj[camel];
36
+ const s = typeof v === "number" && Number.isSafeInteger(v) ? String(v) : typeof v === "string" ? v : null;
37
+ return s !== null && /^\d{1,20}$/.test(s) && BigInt(s) <= BigInt(EMERGENCY_CLOSE_DISABLED_MS) ? BigInt(s).toString() : null;
38
+ };
39
+ const fillWindowMs = u64("fill_window_ms");
40
+ const fillDeadlineMs = u64("fill_deadline_ms");
41
+ const cancelDelayMs = u64("cancel_delay_ms");
42
+ const emergencyAfterMs = u64("emergency_after_ms");
43
+ const execFee = u64("exec_fee");
44
+ const oneStepSpreadBps = u64("one_step_spread_bps");
45
+ const signedWindowMs = u64("signed_window_ms");
46
+ if (fillWindowMs === null || fillDeadlineMs === null || cancelDelayMs === null ||
47
+ emergencyAfterMs === null || execFee === null || oneStepSpreadBps === null || signedWindowMs === null) {
48
+ return null;
49
+ }
50
+ return { fillWindowMs, fillDeadlineMs, cancelDelayMs, emergencyAfterMs, execFee, oneStepSpreadBps, signedWindowMs };
51
+ }
52
+ export function isEmergencyAfterDisabled(value) {
53
+ if (typeof value === "number")
54
+ return false;
55
+ try {
56
+ return BigInt(value) === BigInt(EMERGENCY_CLOSE_DISABLED_MS);
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
62
+ export function emergencyCloseDisabled(params) {
63
+ return isEmergencyAfterDisabled(params.emergencyAfterMs);
64
+ }
65
+ export function hasPendingOrderSlot(maxPendingOrders, pendingOpenOrders) {
66
+ if (maxPendingOrders === null || maxPendingOrders === undefined)
67
+ return null;
68
+ if (pendingOpenOrders === null || pendingOpenOrders === undefined)
69
+ return null;
70
+ return pendingOpenOrders < maxPendingOrders;
71
+ }