@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.
- package/LICENSE +202 -0
- package/README.md +193 -2
- package/REFERENCE.md +338 -0
- package/SECURITY.md +25 -0
- package/dist/general/providers/index.d.ts +2 -0
- package/dist/general/providers/index.js +2 -0
- package/dist/general/providers/parchment.d.ts +1 -0
- package/dist/general/providers/parchment.js +1 -0
- package/dist/general/providers/parchmentSdk.d.ts +23 -0
- package/dist/general/providers/parchmentSdk.js +11 -0
- package/dist/general/types/configTypes.d.ts +62 -0
- package/dist/general/types/configTypes.js +1 -0
- package/dist/general/types/index.d.ts +1 -0
- package/dist/general/types/index.js +1 -0
- package/dist/general/utils/address.d.ts +49 -0
- package/dist/general/utils/address.js +110 -0
- package/dist/general/utils/caller.d.ts +58 -0
- package/dist/general/utils/caller.js +182 -0
- package/dist/general/utils/errors.d.ts +16 -0
- package/dist/general/utils/errors.js +26 -0
- package/dist/general/utils/index.d.ts +4 -0
- package/dist/general/utils/index.js +4 -0
- package/dist/general/utils/jsBigInt.d.ts +26 -0
- package/dist/general/utils/jsBigInt.js +74 -0
- package/dist/general/utils/txShape.d.ts +8 -0
- package/dist/general/utils/txShape.js +39 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/packages/index.d.ts +11 -0
- package/dist/packages/index.js +5 -0
- package/dist/packages/parchment/abortCodes.d.ts +196 -0
- package/dist/packages/parchment/abortCodes.js +522 -0
- package/dist/packages/parchment/batchClose.d.ts +268 -0
- package/dist/packages/parchment/batchClose.js +524 -0
- package/dist/packages/parchment/eventGuard.d.ts +106 -0
- package/dist/packages/parchment/eventGuard.js +119 -0
- package/dist/packages/parchment/gameCounterEvents.d.ts +59 -0
- package/dist/packages/parchment/gameCounterEvents.js +56 -0
- package/dist/packages/parchment/index.d.ts +52 -0
- package/dist/packages/parchment/index.js +30 -0
- package/dist/packages/parchment/liquidationCredit.d.ts +28 -0
- package/dist/packages/parchment/liquidationCredit.js +25 -0
- package/dist/packages/parchment/lockedMintEvents.d.ts +42 -0
- package/dist/packages/parchment/lockedMintEvents.js +46 -0
- package/dist/packages/parchment/monitoring.d.ts +369 -0
- package/dist/packages/parchment/monitoring.js +259 -0
- package/dist/packages/parchment/notes.d.ts +6 -0
- package/dist/packages/parchment/notes.js +1 -0
- package/dist/packages/parchment/onboarding.d.ts +50 -0
- package/dist/packages/parchment/onboarding.js +48 -0
- package/dist/packages/parchment/orderEffects.d.ts +207 -0
- package/dist/packages/parchment/orderEffects.js +268 -0
- package/dist/packages/parchment/orderParams.d.ts +72 -0
- package/dist/packages/parchment/orderParams.js +71 -0
- package/dist/packages/parchment/packageIds.d.ts +53 -0
- package/dist/packages/parchment/packageIds.js +149 -0
- package/dist/packages/parchment/parchment.d.ts +442 -0
- package/dist/packages/parchment/parchment.js +975 -0
- package/dist/packages/parchment/parchmentAccount.d.ts +189 -0
- package/dist/packages/parchment/parchmentAccount.js +273 -0
- package/dist/packages/parchment/parchmentMarket.d.ts +58 -0
- package/dist/packages/parchment/parchmentMarket.js +86 -0
- package/dist/packages/parchment/parchmentTypes.d.ts +2031 -0
- package/dist/packages/parchment/parchmentTypes.js +65 -0
- package/dist/packages/parchment/publicInts.d.ts +45 -0
- package/dist/packages/parchment/publicInts.js +383 -0
- package/dist/packages/parchment/reconcileEvents.d.ts +24 -0
- package/dist/packages/parchment/reconcileEvents.js +30 -0
- package/dist/packages/parchment/retainedFee.d.ts +43 -0
- package/dist/packages/parchment/retainedFee.js +68 -0
- package/dist/packages/parchment/sessionClose.d.ts +68 -0
- package/dist/packages/parchment/sessionClose.js +50 -0
- package/dist/packages/parchment/sessionKey.d.ts +78 -0
- package/dist/packages/parchment/sessionKey.js +154 -0
- package/dist/packages/parchment/slippage.d.ts +23 -0
- package/dist/packages/parchment/slippage.js +27 -0
- package/dist/packages/parchment/sponsor.d.ts +39 -0
- package/dist/packages/parchment/sponsor.js +48 -0
- package/dist/packages/parchment/stakingCalls.d.ts +33 -0
- package/dist/packages/parchment/stakingCalls.js +21 -0
- package/dist/packages/parchment/stakingEvents.d.ts +53 -0
- package/dist/packages/parchment/stakingEvents.js +71 -0
- package/dist/packages/parchment/triggerCalls.d.ts +46 -0
- package/dist/packages/parchment/triggerCalls.js +36 -0
- package/dist/packages/parchment/triggerEvents.d.ts +22 -0
- package/dist/packages/parchment/triggerEvents.js +33 -0
- package/dist/packages/parchment/triggers.d.ts +113 -0
- package/dist/packages/parchment/triggers.js +183 -0
- package/dist/packages/parchment/txBodies.d.ts +111 -0
- package/dist/packages/parchment/txBodies.js +683 -0
- package/dist/packages/parchment/txIntent.d.ts +99 -0
- package/dist/packages/parchment/txIntent.js +611 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +1 -0
- package/package.json +58 -4
|
@@ -0,0 +1,975 @@
|
|
|
1
|
+
import { I64_MAX, U64_MAX, baseUnit, equityRange, historyCursor, i64Ms, idCursor, limitParam, normalizeAddress } from "../../general/utils/address.js";
|
|
2
|
+
import { PUBLIC_INTS } from "./publicInts.js";
|
|
3
|
+
import { monitoringPath, monitoringView, stakingHistoryPath, stakingHistoryView, statsActivityPath, statsActivityView, } from "./monitoring.js";
|
|
4
|
+
import { Caller, requestTimeoutMs } from "../../general/utils/caller.js";
|
|
5
|
+
import { decodeJsBigInts } from "../../general/utils/jsBigInt.js";
|
|
6
|
+
import { ParchmentApiError } from "../../general/utils/errors.js";
|
|
7
|
+
import { requireSplitPackageIds } from "./packageIds.js";
|
|
8
|
+
import { UNCHECKED_TX, untrustedConfigPackages } from "./txIntent.js";
|
|
9
|
+
import { ParchmentAccount } from "./parchmentAccount.js";
|
|
10
|
+
import { ParchmentMarket } from "./parchmentMarket.js";
|
|
11
|
+
import { LEADERBOARD_METRICS, LEADERBOARD_PERIODS, LOCKED_LEDGER_STATUSES, PARCHMENT_CANDLES_BATCH_MAX_MARKETS } from "./parchmentTypes.js";
|
|
12
|
+
import { sponsorBody } from "./sponsor.js";
|
|
13
|
+
import { bindReferrerTxBody, bindTradingReferrerTxBody, transferAccountTxBody, builderCode, claimQuestTxBody, claimTxBody, exitEarlyBoundedTxBody, exitEarlyTxBody, releaseUnlockedTxBody, closePreviewBody, depositTxBody, gameTxBody, openCratesTxBody, grantDelegateTxBody, grantCloseDelegateTxBody, grantSessionAndTriggerTxBody, revokeSessionAndTriggerTxBody, installTreasuryTxBody, authRegisterTxBody, liquidateTxBody, sweepTxBody, sweepSurplusTxBody, claimPendingMintTxBody, lpHarvestTxBody, openAccountTxBody, openPreviewBody, registerBuilderTxBody, createBuilderTxBody, setBuilderCreateFeeTxBody, setBuilderFeeTxBody, builderOwnerTxBody, transferBuilderTxBody, approveBuilderTxBody, revokeBuilderApprovalTxBody, revokeDelegateTxBody, setBuilderPayoutTxBody, stakeTxBody, unstakeTxBody, withdrawTxBody, cancelOrderTxBody, emergencyCloseAsDelegateTxBody, closeRetiredTxBody, closeRetiredAsDelegateTxBody, emergencyCloseTxBody, expireOrderTxBody, orderRefTxBody, requestCloseAsDelegateTxBody, requestCloseTxBody, requestOpenAsDelegateTxBody, requestOpenTxBody, } from "./txBodies.js";
|
|
14
|
+
import { signTriggerProof, triggerRequestBody } from "./triggers.js";
|
|
15
|
+
function int(value, field) {
|
|
16
|
+
if (typeof value !== "bigint")
|
|
17
|
+
throw new ParchmentApiError(0, "bad_body", `${field} must be an integer`);
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
function intOrNull(value, field) {
|
|
21
|
+
return value === null || value === undefined ? null : int(value, field);
|
|
22
|
+
}
|
|
23
|
+
function decimalText(value, field) {
|
|
24
|
+
if (typeof value !== "string")
|
|
25
|
+
throw new ParchmentApiError(0, "bad_body", `${field} must be a decimal string`);
|
|
26
|
+
return baseUnit(value, field);
|
|
27
|
+
}
|
|
28
|
+
const BUILDER_STATUSES = ["active", "paused", "suspended", "tombstoned"];
|
|
29
|
+
function builderView(data) {
|
|
30
|
+
if ((data?.code !== null && typeof data?.code !== "string") ||
|
|
31
|
+
typeof data.active !== "boolean" ||
|
|
32
|
+
typeof data.selfServe !== "boolean" ||
|
|
33
|
+
typeof data.revokeOpen !== "boolean" ||
|
|
34
|
+
!BUILDER_STATUSES.includes(data.status)) {
|
|
35
|
+
throw new ParchmentApiError(0, "bad_body", "builder response is incomplete");
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
id: int(data.id, "id"),
|
|
39
|
+
code: data.code,
|
|
40
|
+
payout: data.payout === null || data.payout === undefined ? null : servedAddress(data.payout),
|
|
41
|
+
owner: data.owner === null || data.owner === undefined ? null : servedAddress(data.owner),
|
|
42
|
+
active: data.active,
|
|
43
|
+
status: data.status,
|
|
44
|
+
selfServe: data.selfServe,
|
|
45
|
+
feeBps: int(data.feeBps, "feeBps"),
|
|
46
|
+
revokeOpen: data.revokeOpen,
|
|
47
|
+
pending: int(data.pending, "pending"),
|
|
48
|
+
totalEarned: int(data.totalEarned, "totalEarned"),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function choice(value, allowed, field, code) {
|
|
52
|
+
const text = typeof value === "string" ? value.trim() : value;
|
|
53
|
+
if (!allowed.includes(text)) {
|
|
54
|
+
throw new ParchmentApiError(0, code, `${field} must be ${allowed.join(", ")}`);
|
|
55
|
+
}
|
|
56
|
+
return text;
|
|
57
|
+
}
|
|
58
|
+
function intList(value, field) {
|
|
59
|
+
return list(value, field, int);
|
|
60
|
+
}
|
|
61
|
+
function servedAddress(value) {
|
|
62
|
+
if (typeof value === "string") {
|
|
63
|
+
try {
|
|
64
|
+
return normalizeAddress(value);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
throw new ParchmentApiError(0, "bad_body", "response address is missing or malformed");
|
|
70
|
+
}
|
|
71
|
+
function bool(value, field) {
|
|
72
|
+
if (typeof value !== "boolean")
|
|
73
|
+
throw new ParchmentApiError(0, "bad_body", `${field} must be a boolean`);
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
function textOrNull(value, field) {
|
|
77
|
+
if (value === null || value === undefined)
|
|
78
|
+
return null;
|
|
79
|
+
if (typeof value !== "string")
|
|
80
|
+
throw new ParchmentApiError(0, "bad_body", `${field} must be a string`);
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
function orderCursor(value) {
|
|
84
|
+
if (value === undefined || value === null || (typeof value === "string" && value.trim() === ""))
|
|
85
|
+
return undefined;
|
|
86
|
+
const cursor = typeof value === "string" ? value.trim() : "";
|
|
87
|
+
if (!/^[A-Za-z0-9:._-]{1,128}$/.test(cursor)) {
|
|
88
|
+
throw new ParchmentApiError(0, "bad_request", "cursor is not a valid orders page token");
|
|
89
|
+
}
|
|
90
|
+
return cursor;
|
|
91
|
+
}
|
|
92
|
+
function triggerCursor(value) {
|
|
93
|
+
if (value === undefined || value === null || (typeof value === "string" && value.trim() === ""))
|
|
94
|
+
return undefined;
|
|
95
|
+
const cursor = typeof value === "string" ? value.trim() : "";
|
|
96
|
+
if (!/^[A-Za-z0-9:]{1,200}$/.test(cursor)) {
|
|
97
|
+
throw new ParchmentApiError(0, "bad_request", "cursor is not a valid triggers page token");
|
|
98
|
+
}
|
|
99
|
+
return cursor;
|
|
100
|
+
}
|
|
101
|
+
function addressCursor(value, field) {
|
|
102
|
+
if (value === undefined || value === null || (typeof value === "string" && value.trim() === ""))
|
|
103
|
+
return undefined;
|
|
104
|
+
if (typeof value !== "string")
|
|
105
|
+
throw new ParchmentApiError(0, "bad_request", `${field} must be an address`);
|
|
106
|
+
try {
|
|
107
|
+
return normalizeAddress(value);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
throw new ParchmentApiError(0, "bad_request", `${field} must be an address`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function batchMarketIds(marketIds) {
|
|
114
|
+
if (!Array.isArray(marketIds))
|
|
115
|
+
throw new ParchmentApiError(0, "bad_request", "marketIds must be a list of market ids");
|
|
116
|
+
const ids = [...new Set(marketIds.map((id) => normalizeAddress(id)))];
|
|
117
|
+
if (ids.length === 0)
|
|
118
|
+
throw new ParchmentApiError(0, "bad_request", "marketIds must name at least one market");
|
|
119
|
+
if (ids.length > PARCHMENT_CANDLES_BATCH_MAX_MARKETS) {
|
|
120
|
+
throw new ParchmentApiError(0, "too_many_markets", `marketIds names ${ids.length} markets; at most ${PARCHMENT_CANDLES_BATCH_MAX_MARKETS}`);
|
|
121
|
+
}
|
|
122
|
+
return ids;
|
|
123
|
+
}
|
|
124
|
+
function candlesBatchSeries(item, field) {
|
|
125
|
+
if (typeof item?.marketId !== "string")
|
|
126
|
+
throw new ParchmentApiError(0, "bad_body", `${field}.marketId must be a string`);
|
|
127
|
+
if (Array.isArray(item.candles))
|
|
128
|
+
return { marketId: item.marketId, candles: item.candles };
|
|
129
|
+
const error = item.error;
|
|
130
|
+
if (typeof error?.code !== "string" || typeof error.message !== "string") {
|
|
131
|
+
throw new ParchmentApiError(0, "bad_body", `${field} needs candles or an error with code and message`);
|
|
132
|
+
}
|
|
133
|
+
return { marketId: item.marketId, error: { code: error.code, message: error.message } };
|
|
134
|
+
}
|
|
135
|
+
function list(value, field, each) {
|
|
136
|
+
if (!Array.isArray(value))
|
|
137
|
+
throw new ParchmentApiError(0, "bad_body", `${field} must be a list`);
|
|
138
|
+
return value.map((item, index) => each(item, `${field}[${index}]`));
|
|
139
|
+
}
|
|
140
|
+
function feeAchievement(data, field) {
|
|
141
|
+
return {
|
|
142
|
+
id: int(data?.id, `${field}.id`),
|
|
143
|
+
name: textOrNull(data?.name, `${field}.name`),
|
|
144
|
+
feesRequired: int(data?.feesRequired, `${field}.feesRequired`),
|
|
145
|
+
feesNeeded: int(data?.feesNeeded, `${field}.feesNeeded`),
|
|
146
|
+
xp: int(data?.xp, `${field}.xp`),
|
|
147
|
+
mintAmount: int(data?.mintAmount, `${field}.mintAmount`),
|
|
148
|
+
eligibleMint: int(data?.eligibleMint, `${field}.eligibleMint`),
|
|
149
|
+
mintAtUnlock: int(data?.mintAtUnlock, `${field}.mintAtUnlock`),
|
|
150
|
+
active: bool(data?.active, `${field}.active`),
|
|
151
|
+
unlocked: bool(data?.unlocked, `${field}.unlocked`),
|
|
152
|
+
...(data?.unlockable === undefined ? {} : { unlockable: bool(data.unlockable, `${field}.unlockable`) }),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function gameView(data) {
|
|
156
|
+
const view = {
|
|
157
|
+
walletAddress: servedAddress(data.walletAddress),
|
|
158
|
+
xp: int(data.xp, "xp"),
|
|
159
|
+
seasonXp: int(data.seasonXp, "seasonXp"),
|
|
160
|
+
seasonId: int(data.seasonId, "seasonId"),
|
|
161
|
+
tier: int(data.tier, "tier"),
|
|
162
|
+
streak: int(data.streak, "streak"),
|
|
163
|
+
winStreak: int(data.winStreak, "winStreak"),
|
|
164
|
+
crates: int(data.crates, "crates"),
|
|
165
|
+
trades: int(data.trades, "trades"),
|
|
166
|
+
};
|
|
167
|
+
for (const key of ["achievements", "questsDone", "cosmetics"]) {
|
|
168
|
+
if (data[key] !== undefined)
|
|
169
|
+
view[key] = intList(data[key], key);
|
|
170
|
+
}
|
|
171
|
+
for (const key of ["minted", "mintedToday", "pendingMint", "feeCredit", "feeCreditUsed", "achievementMintFractionBps"]) {
|
|
172
|
+
if (data[key] !== undefined)
|
|
173
|
+
view[key] = int(data[key], key);
|
|
174
|
+
}
|
|
175
|
+
if (data.lastDailyDay !== undefined)
|
|
176
|
+
view.lastDailyDay = intOrNull(data.lastDailyDay, "lastDailyDay");
|
|
177
|
+
if (data.dailyClaimedToday !== undefined)
|
|
178
|
+
view.dailyClaimedToday = bool(data.dailyClaimedToday, "dailyClaimedToday");
|
|
179
|
+
if (data.feeAchievements !== undefined) {
|
|
180
|
+
view.feeAchievements = list(data.feeAchievements, "feeAchievements", feeAchievement);
|
|
181
|
+
}
|
|
182
|
+
if (data.lockedLedgerStatus !== undefined) {
|
|
183
|
+
if (!LOCKED_LEDGER_STATUSES.includes(data.lockedLedgerStatus)) {
|
|
184
|
+
throw new ParchmentApiError(0, "bad_body", "lockedLedgerStatus must be current, rebuilding or failed");
|
|
185
|
+
}
|
|
186
|
+
view.lockedLedgerStatus = data.lockedLedgerStatus;
|
|
187
|
+
}
|
|
188
|
+
for (const key of [
|
|
189
|
+
"lockedBalance",
|
|
190
|
+
"lockWindowBalance",
|
|
191
|
+
"nextUnlockMs",
|
|
192
|
+
"vestingBalance",
|
|
193
|
+
"releasableNow",
|
|
194
|
+
"earlyExitPaidNow",
|
|
195
|
+
"earlyExitPenaltyNow",
|
|
196
|
+
]) {
|
|
197
|
+
if (data[key] !== undefined)
|
|
198
|
+
view[key] = intOrNull(data[key], key);
|
|
199
|
+
}
|
|
200
|
+
if (data.earlyExitUnlocks !== undefined) {
|
|
201
|
+
view.earlyExitUnlocks = data.earlyExitUnlocks === null ? null : intList(data.earlyExitUnlocks, "earlyExitUnlocks");
|
|
202
|
+
}
|
|
203
|
+
return view;
|
|
204
|
+
}
|
|
205
|
+
function dripView(data) {
|
|
206
|
+
const out = {};
|
|
207
|
+
for (const key of ["parchDripRemaining", "parchDripNow", "parchDripLastMs", "parchDripEndMs", "totalWeight", "lockedWeight", "lockedOwedTotal"]) {
|
|
208
|
+
if (data[key] !== undefined)
|
|
209
|
+
out[key] = int(data[key], key);
|
|
210
|
+
}
|
|
211
|
+
if (data.lockedWeightBps !== undefined)
|
|
212
|
+
out.lockedWeightBps = intOrNull(data.lockedWeightBps, "lockedWeightBps");
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
function lockedYieldView(data) {
|
|
216
|
+
const out = {};
|
|
217
|
+
for (const key of ["lockedWeight", "lockedSyncedBalance", "lockedPending", "lockedOwed", "totalWeight"]) {
|
|
218
|
+
if (data[key] !== undefined && data[key] !== null)
|
|
219
|
+
out[key] = int(data[key], key);
|
|
220
|
+
}
|
|
221
|
+
return out;
|
|
222
|
+
}
|
|
223
|
+
function definitionsView(data) {
|
|
224
|
+
return {
|
|
225
|
+
quests: list(data?.quests, "quests", (q, f) => ({
|
|
226
|
+
id: int(q?.id, `${f}.id`),
|
|
227
|
+
name: textOrNull(q?.name, `${f}.name`),
|
|
228
|
+
kind: int(q?.kind, `${f}.kind`),
|
|
229
|
+
param: int(q?.param, `${f}.param`),
|
|
230
|
+
xp: int(q?.xp, `${f}.xp`),
|
|
231
|
+
cosmetic: intOrNull(q?.cosmetic, `${f}.cosmetic`),
|
|
232
|
+
active: bool(q?.active, `${f}.active`),
|
|
233
|
+
startMs: int(q?.startMs, `${f}.startMs`),
|
|
234
|
+
endMs: int(q?.endMs, `${f}.endMs`),
|
|
235
|
+
seasonId: int(q?.seasonId, `${f}.seasonId`),
|
|
236
|
+
})),
|
|
237
|
+
achievements: list(data?.achievements, "achievements", (a, f) => ({
|
|
238
|
+
id: int(a?.id, `${f}.id`),
|
|
239
|
+
name: textOrNull(a?.name, `${f}.name`),
|
|
240
|
+
kind: int(a?.kind, `${f}.kind`),
|
|
241
|
+
param: int(a?.param, `${f}.param`),
|
|
242
|
+
xp: int(a?.xp, `${f}.xp`),
|
|
243
|
+
mintAmount: int(a?.mintAmount, `${f}.mintAmount`),
|
|
244
|
+
cosmetic: intOrNull(a?.cosmetic, `${f}.cosmetic`),
|
|
245
|
+
active: bool(a?.active, `${f}.active`),
|
|
246
|
+
})),
|
|
247
|
+
cosmetics: list(data?.cosmetics, "cosmetics", (c, f) => ({
|
|
248
|
+
id: int(c?.id, `${f}.id`),
|
|
249
|
+
name: textOrNull(c?.name, `${f}.name`) ?? "",
|
|
250
|
+
})),
|
|
251
|
+
achievementMintFractionBps: int(data?.achievementMintFractionBps, "achievementMintFractionBps"),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function statsView(data, field) {
|
|
255
|
+
return {
|
|
256
|
+
trades: int(data?.trades, `${field}.trades`),
|
|
257
|
+
closes: int(data?.closes, `${field}.closes`),
|
|
258
|
+
wins: int(data?.wins, `${field}.wins`),
|
|
259
|
+
volume: int(data?.volume, `${field}.volume`),
|
|
260
|
+
pnl: int(data?.pnl, `${field}.pnl`),
|
|
261
|
+
winRateBps: intOrNull(data?.winRateBps, `${field}.winRateBps`),
|
|
262
|
+
xp: int(data?.xp, `${field}.xp`),
|
|
263
|
+
tier: int(data?.tier, `${field}.tier`),
|
|
264
|
+
winStreak: int(data?.winStreak, `${field}.winStreak`),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function leaderboardRow(data, field) {
|
|
268
|
+
const row = {
|
|
269
|
+
rank: int(data?.rank, `${field}.rank`),
|
|
270
|
+
walletAddress: servedAddress(data?.walletAddress),
|
|
271
|
+
value: int(data?.value, `${field}.value`),
|
|
272
|
+
};
|
|
273
|
+
if (data?.stats !== undefined)
|
|
274
|
+
row.stats = statsView(data.stats, `${field}.stats`);
|
|
275
|
+
return row;
|
|
276
|
+
}
|
|
277
|
+
function feedEntry(data, field) {
|
|
278
|
+
const entry = {
|
|
279
|
+
walletAddress: servedAddress(data?.walletAddress),
|
|
280
|
+
marketId: servedAddress(data?.marketId),
|
|
281
|
+
positionId: int(data?.positionId, `${field}.positionId`),
|
|
282
|
+
pnl: int(data?.pnl, `${field}.pnl`),
|
|
283
|
+
notional: int(data?.notional, `${field}.notional`),
|
|
284
|
+
atMs: int(data?.atMs, `${field}.atMs`),
|
|
285
|
+
};
|
|
286
|
+
if (data?.side !== undefined) {
|
|
287
|
+
if (data.side !== null && data.side !== "long" && data.side !== "short") {
|
|
288
|
+
throw new ParchmentApiError(0, "bad_body", `${field}.side must be long or short`);
|
|
289
|
+
}
|
|
290
|
+
entry.side = data.side;
|
|
291
|
+
}
|
|
292
|
+
if (data?.isLong !== undefined)
|
|
293
|
+
entry.isLong = data.isLong === null ? null : bool(data.isLong, `${field}.isLong`);
|
|
294
|
+
if (data?.leverage !== undefined)
|
|
295
|
+
entry.leverage = intOrNull(data.leverage, `${field}.leverage`);
|
|
296
|
+
if (data?.kind !== undefined)
|
|
297
|
+
entry.kind = textOrNull(data.kind, `${field}.kind`) ?? undefined;
|
|
298
|
+
if (data?.exitWad !== undefined)
|
|
299
|
+
entry.exitWad = intOrNull(data.exitWad, `${field}.exitWad`);
|
|
300
|
+
return entry;
|
|
301
|
+
}
|
|
302
|
+
function feedView(data, field) {
|
|
303
|
+
if (!Array.isArray(data?.entries)) {
|
|
304
|
+
throw new ParchmentApiError(0, "bad_body", `${field} entries must be a list`);
|
|
305
|
+
}
|
|
306
|
+
return { entries: data.entries.map((entry, index) => feedEntry(entry, `${field}[${index}]`)) };
|
|
307
|
+
}
|
|
308
|
+
function msParam(value) {
|
|
309
|
+
if (value === undefined)
|
|
310
|
+
return undefined;
|
|
311
|
+
const text = typeof value === "string" ? value.trim()
|
|
312
|
+
: typeof value === "bigint" || (typeof value === "number" && Number.isSafeInteger(value)) ? value.toString() : "";
|
|
313
|
+
if (!/^[0-9]{1,19}$/.test(text) || BigInt(text) > I64_MAX) {
|
|
314
|
+
throw new ParchmentApiError(0, "bad_time", "nowMs must be 0..=9223372036854775807 ms");
|
|
315
|
+
}
|
|
316
|
+
return text;
|
|
317
|
+
}
|
|
318
|
+
function query(pairs) {
|
|
319
|
+
const params = new URLSearchParams();
|
|
320
|
+
for (const [key, value] of Object.entries(pairs)) {
|
|
321
|
+
if (value !== undefined)
|
|
322
|
+
params.set(key, value);
|
|
323
|
+
}
|
|
324
|
+
const text = params.toString();
|
|
325
|
+
return text ? `?${text}` : "";
|
|
326
|
+
}
|
|
327
|
+
export class Parchment extends Caller {
|
|
328
|
+
static async create(options) {
|
|
329
|
+
return new Parchment(options);
|
|
330
|
+
}
|
|
331
|
+
constructor(options) {
|
|
332
|
+
options = mergeRequestOptions(options, options);
|
|
333
|
+
super(options, "parchment");
|
|
334
|
+
requestTimeoutMs(options.timeoutMs);
|
|
335
|
+
}
|
|
336
|
+
withRequestOptions(options) {
|
|
337
|
+
return new Parchment(mergeRequestOptions(this.config, options));
|
|
338
|
+
}
|
|
339
|
+
async getConfig() {
|
|
340
|
+
const config = await this.fetchApi("config", PUBLIC_INTS.config);
|
|
341
|
+
const trust = this.config.txTrust;
|
|
342
|
+
if (trust && trust !== UNCHECKED_TX) {
|
|
343
|
+
const untrusted = untrustedConfigPackages(config, trust.packages);
|
|
344
|
+
if (untrusted.length > 0) {
|
|
345
|
+
throw new ParchmentApiError(0, "untrusted_package", `config names package ids outside txTrust: ${untrusted.join(", ")}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return requireSplitPackageIds(config);
|
|
349
|
+
}
|
|
350
|
+
getLimits() {
|
|
351
|
+
return this.fetchApi("limits", PUBLIC_INTS.none);
|
|
352
|
+
}
|
|
353
|
+
async getMarkets() {
|
|
354
|
+
const markets = await this.fetchApiField("markets", "markets", PUBLIC_INTS.markets);
|
|
355
|
+
return { markets: markets.map((market) => new ParchmentMarket(this.config, market)) };
|
|
356
|
+
}
|
|
357
|
+
async getMarket(input) {
|
|
358
|
+
const market = await this.fetchApiField(`markets/${normalizeAddress(input.marketId)}`, "market", PUBLIC_INTS.market);
|
|
359
|
+
return new ParchmentMarket(this.config, market);
|
|
360
|
+
}
|
|
361
|
+
async getPriceHistory(input) {
|
|
362
|
+
const qs = query({
|
|
363
|
+
fromMs: input.fromMs === undefined ? undefined : i64Ms(input.fromMs, "fromMs"),
|
|
364
|
+
toMs: input.toMs === undefined ? undefined : i64Ms(input.toMs, "toMs"),
|
|
365
|
+
limit: limitParam(input.limit),
|
|
366
|
+
});
|
|
367
|
+
return this.fetchApi(`markets/${normalizeAddress(input.marketId)}/prices${qs}`, PUBLIC_INTS.priceHistory);
|
|
368
|
+
}
|
|
369
|
+
async getCandles(input) {
|
|
370
|
+
const qs = query({
|
|
371
|
+
resolution: input.resolution,
|
|
372
|
+
fromMs: input.fromMs === undefined ? undefined : i64Ms(input.fromMs, "fromMs"),
|
|
373
|
+
toMs: input.toMs === undefined ? undefined : i64Ms(input.toMs, "toMs"),
|
|
374
|
+
limit: limitParam(input.limit),
|
|
375
|
+
});
|
|
376
|
+
return this.fetchApi(`markets/${normalizeAddress(input.marketId)}/candles${qs}`, PUBLIC_INTS.candles);
|
|
377
|
+
}
|
|
378
|
+
async getCandlesBatch(input) {
|
|
379
|
+
const qs = query({
|
|
380
|
+
resolution: input.resolution,
|
|
381
|
+
markets: batchMarketIds(input.marketIds).join(","),
|
|
382
|
+
fromMs: input.fromMs === undefined ? undefined : i64Ms(input.fromMs, "fromMs"),
|
|
383
|
+
toMs: input.toMs === undefined ? undefined : i64Ms(input.toMs, "toMs"),
|
|
384
|
+
limit: limitParam(input.limit),
|
|
385
|
+
});
|
|
386
|
+
const data = await this.fetchApi(`markets/candles${qs}`, PUBLIC_INTS.candlesBatch);
|
|
387
|
+
if (typeof data?.resolution !== "string")
|
|
388
|
+
throw new ParchmentApiError(0, "bad_body", "resolution must be a string");
|
|
389
|
+
return {
|
|
390
|
+
resolution: data.resolution,
|
|
391
|
+
serverTimeMs: int(data.serverTimeMs, "serverTimeMs"),
|
|
392
|
+
series: list(data.series, "series", candlesBatchSeries),
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
getPrices() {
|
|
396
|
+
return this.fetchApi("prices", PUBLIC_INTS.prices);
|
|
397
|
+
}
|
|
398
|
+
pricesStreamUrl(input = {}) {
|
|
399
|
+
const ids = input.marketIds?.map((id) => normalizeAddress(id));
|
|
400
|
+
return this.urlForApiCall(`prices/stream${query({ markets: ids?.length ? ids.join(",") : undefined })}`);
|
|
401
|
+
}
|
|
402
|
+
tradesStreamUrl(input = {}) {
|
|
403
|
+
return this.urlForApiCall(`trades/stream${query({ after: input.after?.toString() })}`);
|
|
404
|
+
}
|
|
405
|
+
async getAccount(input) {
|
|
406
|
+
const qs = query({
|
|
407
|
+
limit: limitParam(input.limit),
|
|
408
|
+
accountsCursor: addressCursor(input.accountsCursor, "accountsCursor"),
|
|
409
|
+
positionsCursor: idCursor(input.positionsCursor, "positionsCursor"),
|
|
410
|
+
claimsCursor: idCursor(input.claimsCursor, "claimsCursor"),
|
|
411
|
+
});
|
|
412
|
+
const data = await this.fetchApi(`accounts/${normalizeAddress(input.walletAddress)}${qs}`, PUBLIC_INTS.account);
|
|
413
|
+
return new ParchmentAccount(this.config, data);
|
|
414
|
+
}
|
|
415
|
+
async getPositions(input) {
|
|
416
|
+
const qs = query({ cursor: idCursor(input.cursor, "cursor"), limit: limitParam(input.limit) });
|
|
417
|
+
return this.fetchApi(`accounts/${normalizeAddress(input.walletAddress)}/positions${qs}`, PUBLIC_INTS.positions);
|
|
418
|
+
}
|
|
419
|
+
async getEquityHistory(input) {
|
|
420
|
+
return this.fetchApi(`accounts/${normalizeAddress(input.walletAddress)}/equity${query({ range: equityRange(input.range) })}`, PUBLIC_INTS.equityHistory);
|
|
421
|
+
}
|
|
422
|
+
async getHistory(input) {
|
|
423
|
+
const qs = query({
|
|
424
|
+
cursor: historyCursor(input.cursor),
|
|
425
|
+
limit: limitParam(input.limit),
|
|
426
|
+
});
|
|
427
|
+
return this.fetchApi(`accounts/${normalizeAddress(input.walletAddress)}/history${qs}`, PUBLIC_INTS.history);
|
|
428
|
+
}
|
|
429
|
+
getLp() {
|
|
430
|
+
return this.fetchApi("lp", PUBLIC_INTS.lp);
|
|
431
|
+
}
|
|
432
|
+
async getStakingPool() {
|
|
433
|
+
const data = await this.fetchApi("staking", PUBLIC_INTS.stakingPool);
|
|
434
|
+
if (data === null)
|
|
435
|
+
return null;
|
|
436
|
+
return {
|
|
437
|
+
poolId: servedAddress(data.poolId),
|
|
438
|
+
configId: data.configId === null ? null : servedAddress(data.configId),
|
|
439
|
+
totalStaked: int(data.totalStaked, "totalStaked"),
|
|
440
|
+
accRewardPerShare: decimalText(data.accRewardPerShare, "accRewardPerShare"),
|
|
441
|
+
streamRemaining: int(data.streamRemaining, "streamRemaining"),
|
|
442
|
+
streamLastMs: int(data.streamLastMs, "streamLastMs"),
|
|
443
|
+
streamEndMs: int(data.streamEndMs, "streamEndMs"),
|
|
444
|
+
streamVestedNow: int(data.streamVestedNow, "streamVestedNow"),
|
|
445
|
+
rewardStreamMs: int(data.rewardStreamMs, "rewardStreamMs"),
|
|
446
|
+
minStakeLockMs: int(data.minStakeLockMs, "minStakeLockMs"),
|
|
447
|
+
rewards: int(data.rewards, "rewards"),
|
|
448
|
+
referralReserve: int(data.referralReserve, "referralReserve"),
|
|
449
|
+
nowMs: int(data.nowMs, "nowMs"),
|
|
450
|
+
...dripView(data),
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
async getStaker(input) {
|
|
454
|
+
const data = await this.fetchApi(`staking/${normalizeAddress(input.walletAddress)}`, PUBLIC_INTS.staker);
|
|
455
|
+
if (typeof data.locked !== "boolean") {
|
|
456
|
+
throw new ParchmentApiError(0, "bad_body", "locked must be a boolean");
|
|
457
|
+
}
|
|
458
|
+
return {
|
|
459
|
+
owner: servedAddress(data.owner),
|
|
460
|
+
staked: int(data.staked, "staked"),
|
|
461
|
+
rewardDebt: decimalText(data.rewardDebt, "rewardDebt"),
|
|
462
|
+
stakedAtMs: int(data.stakedAtMs, "stakedAtMs"),
|
|
463
|
+
unlockAtMs: int(data.unlockAtMs, "unlockAtMs"),
|
|
464
|
+
locked: data.locked,
|
|
465
|
+
pendingReward: int(data.pendingReward, "pendingReward"),
|
|
466
|
+
...(data.parchPending === undefined || data.parchPending === null ? {} : { parchPending: int(data.parchPending, "parchPending") }),
|
|
467
|
+
...(data.pendingRewardExact === undefined || data.pendingRewardExact === null
|
|
468
|
+
? {}
|
|
469
|
+
: { pendingRewardExact: bool(data.pendingRewardExact, "pendingRewardExact") }),
|
|
470
|
+
...lockedYieldView(data),
|
|
471
|
+
nowMs: int(data.nowMs, "nowMs"),
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
async getQueue() {
|
|
475
|
+
const data = await this.fetchApi("queue", PUBLIC_INTS.queue);
|
|
476
|
+
return {
|
|
477
|
+
length: int(data.length, "length"),
|
|
478
|
+
totalOwed: int(data.totalOwed, "totalOwed"),
|
|
479
|
+
lpCash: intOrNull(data.lpCash, "lpCash"),
|
|
480
|
+
instantlyPayable: intOrNull(data.instantlyPayable, "instantlyPayable"),
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
async getAccountQueue(input) {
|
|
484
|
+
const data = await this.fetchApi(`accounts/${normalizeAddress(input.walletAddress)}/queue`, PUBLIC_INTS.accountQueue);
|
|
485
|
+
if (typeof data.hasClaim !== "boolean") {
|
|
486
|
+
throw new ParchmentApiError(0, "bad_body", "hasClaim must be a boolean");
|
|
487
|
+
}
|
|
488
|
+
return {
|
|
489
|
+
hasClaim: data.hasClaim,
|
|
490
|
+
net: int(data.net, "net"),
|
|
491
|
+
owner: servedAddress(data.owner),
|
|
492
|
+
rank: intOrNull(data.rank, "rank"),
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
async getReferrals(input) {
|
|
496
|
+
const qs = query({
|
|
497
|
+
limit: limitParam(input.limit),
|
|
498
|
+
directCursor: addressCursor(input.directCursor, "directCursor"),
|
|
499
|
+
secondLevelCursor: addressCursor(input.secondLevelCursor, "secondLevelCursor"),
|
|
500
|
+
});
|
|
501
|
+
return this.fetchApi(`referrals/${normalizeAddress(input.walletAddress)}${qs}`, PUBLIC_INTS.referrals);
|
|
502
|
+
}
|
|
503
|
+
async getTradingReferral(input) {
|
|
504
|
+
const data = await this.fetchApi(`accounts/${normalizeAddress(input.walletAddress)}/trading-referral`, PUBLIC_INTS.tradingReferral);
|
|
505
|
+
if (data.referrer !== null && typeof data.referrer !== "string") {
|
|
506
|
+
throw new ParchmentApiError(0, "bad_body", "referrer must be an address or null");
|
|
507
|
+
}
|
|
508
|
+
return {
|
|
509
|
+
referrer: data.referrer === null ? null : servedAddress(data.referrer),
|
|
510
|
+
refereeCount: int(data.refereeCount, "refereeCount"),
|
|
511
|
+
totalEarned: int(data.totalEarned, "totalEarned"),
|
|
512
|
+
pending: int(data.pending, "pending"),
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
async getBuilder(input) {
|
|
516
|
+
const code = builderCode(input.code, input.code === "" ? "bad_request" : "bad_code");
|
|
517
|
+
if (code === "." || code === "..")
|
|
518
|
+
throw new ParchmentApiError(0, "bad_request", "invalid builder code");
|
|
519
|
+
const data = await this.fetchApi(`builders/${encodeURIComponent(code)}`, PUBLIC_INTS.builder);
|
|
520
|
+
return builderView(data);
|
|
521
|
+
}
|
|
522
|
+
async getOwnedBuilders(input) {
|
|
523
|
+
const data = await this.fetchApi(`accounts/${normalizeAddress(input.walletAddress)}/builders`, PUBLIC_INTS.builders);
|
|
524
|
+
if (!Array.isArray(data))
|
|
525
|
+
throw new ParchmentApiError(0, "bad_body", "builder list is not a list");
|
|
526
|
+
return data.map(builderView);
|
|
527
|
+
}
|
|
528
|
+
async getBuilderAllowance(input) {
|
|
529
|
+
const data = await this.fetchApi(`accounts/${normalizeAddress(input.walletAddress)}/builder-allowance`, PUBLIC_INTS.builderAllowance);
|
|
530
|
+
return {
|
|
531
|
+
created: int(data.created, "created"),
|
|
532
|
+
limit: int(data.limit, "limit"),
|
|
533
|
+
remaining: int(data.remaining, "remaining"),
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
async getBuilderApprovals(input) {
|
|
537
|
+
const data = await this.fetchApi(`accounts/${normalizeAddress(input.accountId)}/builder-approvals`, PUBLIC_INTS.builderApprovals);
|
|
538
|
+
if (!Array.isArray(data))
|
|
539
|
+
throw new ParchmentApiError(0, "bad_body", "approval list is not a list");
|
|
540
|
+
return data.map((a) => ({
|
|
541
|
+
accountId: servedAddress(a.accountId),
|
|
542
|
+
builderId: int(a.builderId, "builderId"),
|
|
543
|
+
maxFeeBps: int(a.maxFeeBps, "maxFeeBps"),
|
|
544
|
+
}));
|
|
545
|
+
}
|
|
546
|
+
async getAccountBuilder(input) {
|
|
547
|
+
const data = await this.fetchApi(`accounts/${normalizeAddress(input.walletAddress)}/builder`, PUBLIC_INTS.builder);
|
|
548
|
+
if (data === null)
|
|
549
|
+
return null;
|
|
550
|
+
return builderView(data);
|
|
551
|
+
}
|
|
552
|
+
async getGameDefinitions() {
|
|
553
|
+
return definitionsView(await this.fetchApi("game/definitions", PUBLIC_INTS.gameDefinitions));
|
|
554
|
+
}
|
|
555
|
+
async getGame(input) {
|
|
556
|
+
const data = await this.fetchApi(`game/${normalizeAddress(input.walletAddress)}`, PUBLIC_INTS.game);
|
|
557
|
+
return gameView(data);
|
|
558
|
+
}
|
|
559
|
+
async getLeaderboard(input) {
|
|
560
|
+
const period = choice(input.period, LEADERBOARD_PERIODS, "period", "bad_period");
|
|
561
|
+
const by = choice(input.by, LEADERBOARD_METRICS, "by", "bad_metric");
|
|
562
|
+
const owner = input.walletAddress === undefined ? undefined : normalizeAddress(input.walletAddress);
|
|
563
|
+
const cursor = idCursor(input.cursor, "cursor", U64_MAX, "bad_cursor");
|
|
564
|
+
const limit = limitParam(input.limit);
|
|
565
|
+
const nowMs = msParam(input.nowMs);
|
|
566
|
+
const data = await this.fetchApi(`leaderboards${query({ period, by, owner, cursor, limit, nowMs })}`, PUBLIC_INTS.leaderboard);
|
|
567
|
+
if (!Array.isArray(data?.rows)) {
|
|
568
|
+
throw new ParchmentApiError(0, "bad_body", "rows must be a list");
|
|
569
|
+
}
|
|
570
|
+
return {
|
|
571
|
+
period,
|
|
572
|
+
by,
|
|
573
|
+
rows: data.rows.map((row, index) => leaderboardRow(row, `rows[${index}]`)),
|
|
574
|
+
viewer: data.viewer == null ? null : leaderboardRow(data.viewer, "viewer"),
|
|
575
|
+
nextCursor: intOrNull(data.nextCursor, "nextCursor"),
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
async getWhaleFeed(input = {}) {
|
|
579
|
+
const qs = query({ limit: limitParam(input.limit) });
|
|
580
|
+
return feedView(await this.fetchApi(`feed/whales${qs}`, PUBLIC_INTS.feed), "whales");
|
|
581
|
+
}
|
|
582
|
+
async getRektFeed(input = {}) {
|
|
583
|
+
const qs = query({ limit: limitParam(input.limit) });
|
|
584
|
+
return feedView(await this.fetchApi(`feed/rekt${qs}`, PUBLIC_INTS.feed), "rekt");
|
|
585
|
+
}
|
|
586
|
+
async getPnlCard(input) {
|
|
587
|
+
const raw = typeof input.positionId === "bigint" ? input.positionId.toString()
|
|
588
|
+
: typeof input.positionId === "string" ? input.positionId.trim() : "";
|
|
589
|
+
if (raw.length === 0)
|
|
590
|
+
throw new ParchmentApiError(0, "position_required", "positionId is required");
|
|
591
|
+
if (!/^[0-9]+$/.test(raw)) {
|
|
592
|
+
throw new ParchmentApiError(0, "bad_position", "positionId must be a base-unit integer");
|
|
593
|
+
}
|
|
594
|
+
if (raw.length > 39 || BigInt(raw) > (1n << 128n) - 1n) {
|
|
595
|
+
throw new ParchmentApiError(0, "bad_position", "positionId is not an unsigned integer");
|
|
596
|
+
}
|
|
597
|
+
const positionId = raw;
|
|
598
|
+
const data = await this.fetchApi(`cards/pnl${query({ positionId })}`, PUBLIC_INTS.pnlCard);
|
|
599
|
+
if (typeof data?.isLong !== "boolean") {
|
|
600
|
+
throw new ParchmentApiError(0, "bad_body", "isLong must be a boolean");
|
|
601
|
+
}
|
|
602
|
+
return {
|
|
603
|
+
positionId: int(data.positionId, "positionId"),
|
|
604
|
+
walletAddress: servedAddress(data.walletAddress),
|
|
605
|
+
marketId: servedAddress(data.marketId),
|
|
606
|
+
pnl: int(data.pnl, "pnl"),
|
|
607
|
+
pnlPct: int(data.pnlPct, "pnlPct"),
|
|
608
|
+
isLong: data.isLong,
|
|
609
|
+
...(typeof data.settled === "boolean" ? { settled: data.settled } : {}),
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
getProtocol() {
|
|
613
|
+
return this.fetchApi("protocol", PUBLIC_INTS.protocol);
|
|
614
|
+
}
|
|
615
|
+
async getRecentPositions(input = {}) {
|
|
616
|
+
const qs = query({ limit: limitParam(input.limit) });
|
|
617
|
+
const data = await this.fetchApi(`positions/recent${qs}`, PUBLIC_INTS.recentPositions);
|
|
618
|
+
if (!Array.isArray(data?.entries))
|
|
619
|
+
throw new ParchmentApiError(0, "bad_body", "entries must be a list");
|
|
620
|
+
return data.entries.map((e) => ({
|
|
621
|
+
...e,
|
|
622
|
+
walletAddress: servedAddress(e.walletAddress),
|
|
623
|
+
marketId: e.marketId === null ? null : servedAddress(e.marketId),
|
|
624
|
+
}));
|
|
625
|
+
}
|
|
626
|
+
getMarketStats() {
|
|
627
|
+
return this.fetchApi("markets/stats", PUBLIC_INTS.marketStats);
|
|
628
|
+
}
|
|
629
|
+
async getMonitoring(input = {}) {
|
|
630
|
+
return monitoringView(await this.fetchApi(monitoringPath(input.days), PUBLIC_INTS.none));
|
|
631
|
+
}
|
|
632
|
+
async getStatsActivity(input = {}) {
|
|
633
|
+
return statsActivityView(await this.fetchApi(statsActivityPath(input.days), PUBLIC_INTS.none));
|
|
634
|
+
}
|
|
635
|
+
async getStakingHistory(input) {
|
|
636
|
+
return stakingHistoryView(await this.fetchApi(stakingHistoryPath(input.days), PUBLIC_INTS.none));
|
|
637
|
+
}
|
|
638
|
+
getLpQueue() {
|
|
639
|
+
return this.fetchApi("lp/queue", PUBLIC_INTS.lpQueue);
|
|
640
|
+
}
|
|
641
|
+
async getOrders(owner, input = {}) {
|
|
642
|
+
const qs = query({
|
|
643
|
+
status: input.status,
|
|
644
|
+
limit: limitParam(input.limit),
|
|
645
|
+
cursor: orderCursor(input.cursor),
|
|
646
|
+
});
|
|
647
|
+
return this.fetchApi(`accounts/${normalizeAddress(owner)}/orders${qs}`, PUBLIC_INTS.orders);
|
|
648
|
+
}
|
|
649
|
+
async getOrder(orderId, signal) {
|
|
650
|
+
const id = normalizeAddress(orderId);
|
|
651
|
+
const order = await this.fetchApiField(`orders/${id}`, "order", PUBLIC_INTS.order, signal);
|
|
652
|
+
return checkedOrder(order, id);
|
|
653
|
+
}
|
|
654
|
+
async waitForOrder(orderId, { timeoutMs = 10_000, pollMs = 500, signal: callerSignal } = {}) {
|
|
655
|
+
normalizeAddress(orderId);
|
|
656
|
+
const clientSignal = this.config.signal;
|
|
657
|
+
const signal = clientSignal && callerSignal ? AbortSignal.any([callerSignal, clientSignal]) : (callerSignal ?? clientSignal);
|
|
658
|
+
signal?.throwIfAborted();
|
|
659
|
+
const pollInterval = Number.isFinite(pollMs) && pollMs > 0 ? pollMs : 500;
|
|
660
|
+
if (Number.isNaN(timeoutMs))
|
|
661
|
+
timeoutMs = 10_000;
|
|
662
|
+
const deadline = Date.now() + timeoutMs;
|
|
663
|
+
const timeout = new AbortController();
|
|
664
|
+
const timer = setTimeout(() => timeout.abort(), Math.min(Math.max(0, timeoutMs), 2_147_483_647));
|
|
665
|
+
const stop = signal ? AbortSignal.any([signal, timeout.signal]) : timeout.signal;
|
|
666
|
+
let lastError;
|
|
667
|
+
try {
|
|
668
|
+
for (;;) {
|
|
669
|
+
try {
|
|
670
|
+
const order = await this.getOrder(orderId, stop);
|
|
671
|
+
if (order.status !== "pending")
|
|
672
|
+
return order;
|
|
673
|
+
lastError = undefined;
|
|
674
|
+
}
|
|
675
|
+
catch (error) {
|
|
676
|
+
signal?.throwIfAborted();
|
|
677
|
+
if (!timeout.signal.aborted)
|
|
678
|
+
lastError = error;
|
|
679
|
+
}
|
|
680
|
+
const timedOut = () => {
|
|
681
|
+
const suffix = lastError instanceof Error ? ` (last error: ${lastError.message})` : "";
|
|
682
|
+
return new Error(`Timed out after ${timeoutMs} ms waiting for order ${orderId} to leave pending${suffix}`);
|
|
683
|
+
};
|
|
684
|
+
const remaining = deadline - Date.now();
|
|
685
|
+
if (remaining <= 0 || timeout.signal.aborted)
|
|
686
|
+
throw timedOut();
|
|
687
|
+
const hint = lastError instanceof ParchmentApiError ? (lastError.retryAfterMs ?? 0) : 0;
|
|
688
|
+
if (hint >= remaining)
|
|
689
|
+
throw timedOut();
|
|
690
|
+
await sleep(Math.min(Math.max(pollInterval, hint), remaining), stop);
|
|
691
|
+
signal?.throwIfAborted();
|
|
692
|
+
if (deadline - Date.now() <= 0 || timeout.signal.aborted)
|
|
693
|
+
throw timedOut();
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
finally {
|
|
697
|
+
clearTimeout(timer);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
getPreviewOpen(input) {
|
|
701
|
+
return this.fetchApi("previews/open", PUBLIC_INTS.previewOpen, openPreviewBody(input));
|
|
702
|
+
}
|
|
703
|
+
getPreviewClose(input) {
|
|
704
|
+
return this.fetchApi("previews/close", PUBLIC_INTS.previewClose, closePreviewBody(input));
|
|
705
|
+
}
|
|
706
|
+
getOpenAccountTx(input) {
|
|
707
|
+
return this.fetchApiTxObject("transactions/open-account", openAccountTxBody(input));
|
|
708
|
+
}
|
|
709
|
+
getDepositTx(input) {
|
|
710
|
+
return this.fetchApiTxObject("transactions/deposit", depositTxBody(input));
|
|
711
|
+
}
|
|
712
|
+
getWithdrawTx(input) {
|
|
713
|
+
return this.fetchApiTxObject("transactions/withdraw", withdrawTxBody(input));
|
|
714
|
+
}
|
|
715
|
+
getRequestOpenTx(input) {
|
|
716
|
+
return this.fetchApiTxObject("transactions/request-open", requestOpenTxBody(input));
|
|
717
|
+
}
|
|
718
|
+
getRequestOpenAsDelegateTx(input) {
|
|
719
|
+
return this.fetchApiTxObject("transactions/request-open-as-delegate", requestOpenAsDelegateTxBody(input));
|
|
720
|
+
}
|
|
721
|
+
getRequestCloseTx(input) {
|
|
722
|
+
return this.fetchApiTxObject("transactions/request-close", requestCloseTxBody(input));
|
|
723
|
+
}
|
|
724
|
+
getRequestCloseAsDelegateTx(input) {
|
|
725
|
+
return this.fetchApiTxObject("transactions/request-close-as-delegate", requestCloseAsDelegateTxBody(input));
|
|
726
|
+
}
|
|
727
|
+
getCancelOrderTx(input) {
|
|
728
|
+
return this.fetchApiTxObject("transactions/cancel-order", cancelOrderTxBody(input));
|
|
729
|
+
}
|
|
730
|
+
getCancelOrderAsDelegateTx(input) {
|
|
731
|
+
return this.fetchApiTxObject("transactions/cancel-order-as-delegate", orderRefTxBody(input));
|
|
732
|
+
}
|
|
733
|
+
getExpireOrderTx(input) {
|
|
734
|
+
return this.fetchApiTxObject("transactions/expire-order", expireOrderTxBody(input));
|
|
735
|
+
}
|
|
736
|
+
getEmergencyCloseTx(input) {
|
|
737
|
+
return this.fetchApiTxObject("transactions/emergency-close", emergencyCloseTxBody(input));
|
|
738
|
+
}
|
|
739
|
+
getEmergencyCloseAsDelegateTx(input) {
|
|
740
|
+
return this.fetchApiTxObject("transactions/emergency-close-as-delegate", emergencyCloseAsDelegateTxBody(input));
|
|
741
|
+
}
|
|
742
|
+
getCloseRetiredTx(input) {
|
|
743
|
+
return this.fetchApiTxObject("transactions/close-retired", closeRetiredTxBody(input));
|
|
744
|
+
}
|
|
745
|
+
getCloseRetiredAsDelegateTx(input) {
|
|
746
|
+
return this.fetchApiTxObject("transactions/close-retired-as-delegate", closeRetiredAsDelegateTxBody(input));
|
|
747
|
+
}
|
|
748
|
+
getLiquidateTx(input) {
|
|
749
|
+
const path = input.retired ? "transactions/liquidate-retired" : "transactions/liquidate";
|
|
750
|
+
return this.fetchApiTxObject(path, liquidateTxBody(input));
|
|
751
|
+
}
|
|
752
|
+
getSweepTx(input) {
|
|
753
|
+
return this.fetchApiTxObject("transactions/sweep", sweepTxBody(input));
|
|
754
|
+
}
|
|
755
|
+
getSweepSurplusTx(input) {
|
|
756
|
+
return this.fetchApiTxObject("transactions/sweep-surplus", sweepSurplusTxBody(input));
|
|
757
|
+
}
|
|
758
|
+
getClaimPendingMintTx(input) {
|
|
759
|
+
return this.fetchApiTxObject("transactions/claim-pending-mint", claimPendingMintTxBody(input));
|
|
760
|
+
}
|
|
761
|
+
getHarvestTx(input) {
|
|
762
|
+
return this.fetchApiTxObject("transactions/harvest", lpHarvestTxBody(input));
|
|
763
|
+
}
|
|
764
|
+
getBindReferrerTx(input) {
|
|
765
|
+
return this.fetchApiTxObject("transactions/bind-referrer", bindReferrerTxBody(input));
|
|
766
|
+
}
|
|
767
|
+
getBindTradingReferrerTx(input) {
|
|
768
|
+
return this.fetchApiTxObject("transactions/bind-trading-referrer", bindTradingReferrerTxBody(input));
|
|
769
|
+
}
|
|
770
|
+
async getTransferAccountTx(input) {
|
|
771
|
+
return this.fetchApiTxObject("transactions/transfer-account", transferAccountTxBody(input));
|
|
772
|
+
}
|
|
773
|
+
getStakeTx(input) {
|
|
774
|
+
return this.fetchApiTxObject("transactions/stake", stakeTxBody(input));
|
|
775
|
+
}
|
|
776
|
+
getUnstakeTx(input) {
|
|
777
|
+
return this.fetchApiTxObject("transactions/unstake", unstakeTxBody(input));
|
|
778
|
+
}
|
|
779
|
+
getClaimTx(input) {
|
|
780
|
+
return this.fetchApiTxObject("transactions/claim", claimTxBody(input));
|
|
781
|
+
}
|
|
782
|
+
async getReleaseUnlockedTx(input) {
|
|
783
|
+
const built = await this.fetchApiTxObject("transactions/release-unlocked", releaseUnlockedTxBody(input));
|
|
784
|
+
return input.syncLocked ? this.appendSyncLocked(built, input.who ?? input.walletAddress) : built;
|
|
785
|
+
}
|
|
786
|
+
async getExitEarlyTx(input) {
|
|
787
|
+
const built = await this.fetchApiTxObject("transactions/exit-early", exitEarlyTxBody(input));
|
|
788
|
+
return input.syncLocked ? this.appendSyncLocked(built, input.walletAddress) : built;
|
|
789
|
+
}
|
|
790
|
+
async getExitEarlyBoundedTx(input) {
|
|
791
|
+
const built = await this.fetchApiTxObject("transactions/exit-early-bounded", exitEarlyBoundedTxBody(input));
|
|
792
|
+
return input.syncLocked ? this.appendSyncLocked(built, input.walletAddress) : built;
|
|
793
|
+
}
|
|
794
|
+
getGrantDelegateTx(input) {
|
|
795
|
+
return this.fetchApiTxObject("transactions/grant-delegate", grantDelegateTxBody(input));
|
|
796
|
+
}
|
|
797
|
+
getRevokeDelegateTx(input) {
|
|
798
|
+
return this.fetchApiTxObject("transactions/revoke-delegate", revokeDelegateTxBody(input));
|
|
799
|
+
}
|
|
800
|
+
getGrantSessionAndTriggerTx(input) {
|
|
801
|
+
return this.fetchApiTxObject("transactions/grant-session-and-trigger", grantSessionAndTriggerTxBody(input));
|
|
802
|
+
}
|
|
803
|
+
getRevokeSessionAndTriggerTx(input) {
|
|
804
|
+
return this.fetchApiTxObject("transactions/revoke-session-and-trigger", revokeSessionAndTriggerTxBody(input));
|
|
805
|
+
}
|
|
806
|
+
getGrantCloseDelegateTx(input) {
|
|
807
|
+
return this.fetchApiTxObject("transactions/grant-close-delegate", grantCloseDelegateTxBody(input));
|
|
808
|
+
}
|
|
809
|
+
async getTriggers(input) {
|
|
810
|
+
const qs = query({ cursor: triggerCursor(input.cursor), limit: limitParam(input.limit) });
|
|
811
|
+
return this.fetchApi(`accounts/${normalizeAddress(input.walletAddress)}/triggers${qs}`, PUBLIC_INTS.triggers);
|
|
812
|
+
}
|
|
813
|
+
async setTriggers(input, signer, nowMs) {
|
|
814
|
+
const proof = await signTriggerProof(signer, input, nowMs);
|
|
815
|
+
return this.fetchApi("triggers", PUBLIC_INTS.trigger, triggerRequestBody(proof));
|
|
816
|
+
}
|
|
817
|
+
getRegisterBuilderTx(input) {
|
|
818
|
+
return this.fetchApiTxObject("transactions/register-builder", registerBuilderTxBody(input));
|
|
819
|
+
}
|
|
820
|
+
getSetBuilderPayoutTx(input) {
|
|
821
|
+
return this.fetchApiTxObject("transactions/set-builder-payout", setBuilderPayoutTxBody(input));
|
|
822
|
+
}
|
|
823
|
+
getCreateBuilderTx(input) {
|
|
824
|
+
return this.fetchApiTxObject("transactions/create-builder", createBuilderTxBody(input));
|
|
825
|
+
}
|
|
826
|
+
getSetBuilderCreateFeeTx(input) {
|
|
827
|
+
return this.fetchApiTxObject("transactions/set-builder-create-fee", setBuilderCreateFeeTxBody(input));
|
|
828
|
+
}
|
|
829
|
+
getSetBuilderFeeTx(input) {
|
|
830
|
+
return this.fetchApiTxObject("transactions/set-builder-fee", setBuilderFeeTxBody(input));
|
|
831
|
+
}
|
|
832
|
+
getPauseBuilderTx(input) {
|
|
833
|
+
return this.fetchApiTxObject("transactions/pause-builder", builderOwnerTxBody(input));
|
|
834
|
+
}
|
|
835
|
+
getResumeBuilderTx(input) {
|
|
836
|
+
return this.fetchApiTxObject("transactions/resume-builder", builderOwnerTxBody(input));
|
|
837
|
+
}
|
|
838
|
+
getTransferBuilderTx(input) {
|
|
839
|
+
return this.fetchApiTxObject("transactions/transfer-builder", transferBuilderTxBody(input));
|
|
840
|
+
}
|
|
841
|
+
getApproveBuilderTx(input) {
|
|
842
|
+
return this.fetchApiTxObject("transactions/approve-builder", approveBuilderTxBody(input));
|
|
843
|
+
}
|
|
844
|
+
getRevokeBuilderApprovalTx(input) {
|
|
845
|
+
return this.fetchApiTxObject("transactions/revoke-builder-approval", revokeBuilderApprovalTxBody(input));
|
|
846
|
+
}
|
|
847
|
+
getInstallTreasuryTx(input) {
|
|
848
|
+
return this.fetchApiTxObject("transactions/install-treasury", installTreasuryTxBody(input));
|
|
849
|
+
}
|
|
850
|
+
getAuthRegisterTx(input) {
|
|
851
|
+
return this.fetchApiTxObject("transactions/auth-register", authRegisterTxBody(input));
|
|
852
|
+
}
|
|
853
|
+
getGameAttachTx(input) {
|
|
854
|
+
return this.fetchApiTxObject("transactions/game-attach", authRegisterTxBody(input));
|
|
855
|
+
}
|
|
856
|
+
async sponsorTransaction(input, signal) {
|
|
857
|
+
const body = sponsorBody(input);
|
|
858
|
+
const data = await this.fetchApi("sponsor", PUBLIC_INTS.sponsored, body, signal);
|
|
859
|
+
for (const field of ["txBytesBase64", "sponsorSignature"]) {
|
|
860
|
+
if (typeof data?.[field] !== "string" || data[field].length === 0) {
|
|
861
|
+
throw new ParchmentApiError(0, "bad_tx", `sponsor response has no ${field}`);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
return data;
|
|
865
|
+
}
|
|
866
|
+
getClaimDailyTx(input) {
|
|
867
|
+
return this.fetchApiTxObject("transactions/claim-daily", gameTxBody(input));
|
|
868
|
+
}
|
|
869
|
+
getOpenCrateTx(input) {
|
|
870
|
+
return this.fetchApiTxObject("transactions/open-crate", gameTxBody(input));
|
|
871
|
+
}
|
|
872
|
+
getOpenCratesTx(input) {
|
|
873
|
+
return this.fetchApiTxObject("transactions/open-crates", openCratesTxBody(input));
|
|
874
|
+
}
|
|
875
|
+
getClaimQuestTx(input) {
|
|
876
|
+
return this.fetchApiTxObject("transactions/claim-quest", claimQuestTxBody(input));
|
|
877
|
+
}
|
|
878
|
+
getCollectMintTx(input) {
|
|
879
|
+
return this.fetchApiTxObject("transactions/collect-mint", gameTxBody(input));
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
function mergeRequestOptions(config, options) {
|
|
883
|
+
const out = { ...config };
|
|
884
|
+
for (const key of ["timeoutMs", "signal"]) {
|
|
885
|
+
const value = options[key];
|
|
886
|
+
if (value === null)
|
|
887
|
+
delete out[key];
|
|
888
|
+
else if (value !== undefined)
|
|
889
|
+
out[key] = value;
|
|
890
|
+
}
|
|
891
|
+
return out;
|
|
892
|
+
}
|
|
893
|
+
function sleep(ms, signal) {
|
|
894
|
+
return new Promise((resolve) => {
|
|
895
|
+
if (signal.aborted)
|
|
896
|
+
return resolve();
|
|
897
|
+
const timer = setTimeout(done, ms);
|
|
898
|
+
function done() {
|
|
899
|
+
clearTimeout(timer);
|
|
900
|
+
signal.removeEventListener("abort", done);
|
|
901
|
+
resolve();
|
|
902
|
+
}
|
|
903
|
+
signal.addEventListener("abort", done, { once: true });
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
export function parseLivePrice(data) {
|
|
907
|
+
let value;
|
|
908
|
+
try {
|
|
909
|
+
value = JSON.parse(data);
|
|
910
|
+
}
|
|
911
|
+
catch {
|
|
912
|
+
throw new ParchmentApiError(0, "bad_body", "live price is not JSON");
|
|
913
|
+
}
|
|
914
|
+
const v = value;
|
|
915
|
+
if (!v || typeof v !== "object" || typeof v.marketId !== "string" || (v.symbol !== null && typeof v.symbol !== "string")) {
|
|
916
|
+
throw new ParchmentApiError(0, "bad_body", "live price needs marketId and symbol");
|
|
917
|
+
}
|
|
918
|
+
if (v.priceWad == null || v.timestampMs == null) {
|
|
919
|
+
throw new ParchmentApiError(0, "bad_body", "live price needs priceWad and timestampMs");
|
|
920
|
+
}
|
|
921
|
+
return decodeJsBigInts(v, PUBLIC_INTS.livePrice);
|
|
922
|
+
}
|
|
923
|
+
const TRADE_ACTIONS = ["open", "close", "liquidate"];
|
|
924
|
+
const TRADE_SIDES = ["long", "short", null];
|
|
925
|
+
export function parseTrade(data) {
|
|
926
|
+
let value;
|
|
927
|
+
try {
|
|
928
|
+
value = JSON.parse(data);
|
|
929
|
+
}
|
|
930
|
+
catch {
|
|
931
|
+
throw new ParchmentApiError(0, "bad_body", "trade is not JSON");
|
|
932
|
+
}
|
|
933
|
+
const v = value;
|
|
934
|
+
if (!v ||
|
|
935
|
+
typeof v !== "object" ||
|
|
936
|
+
!TRADE_ACTIONS.includes(v.action) ||
|
|
937
|
+
!TRADE_SIDES.includes(v.side) ||
|
|
938
|
+
typeof v.marketId !== "string" ||
|
|
939
|
+
typeof v.owner !== "string" ||
|
|
940
|
+
(v.symbol !== null && typeof v.symbol !== "string")) {
|
|
941
|
+
throw new ParchmentApiError(0, "bad_body", "trade needs action, side, marketId, owner and symbol");
|
|
942
|
+
}
|
|
943
|
+
if (v.id == null || v.positionId == null || v.notional == null || v.margin == null || v.timestampMs == null || v.pnl === undefined) {
|
|
944
|
+
throw new ParchmentApiError(0, "bad_body", "trade needs id, positionId, notional, margin, pnl and timestampMs");
|
|
945
|
+
}
|
|
946
|
+
return decodeJsBigInts(v, PUBLIC_INTS.trade);
|
|
947
|
+
}
|
|
948
|
+
const ORDER_KINDS = ["open", "close"];
|
|
949
|
+
const ORDER_STATUSES = [
|
|
950
|
+
"pending",
|
|
951
|
+
"filled",
|
|
952
|
+
"liquidated",
|
|
953
|
+
"cancelled",
|
|
954
|
+
"expired",
|
|
955
|
+
"refunded",
|
|
956
|
+
"void",
|
|
957
|
+
"emergency_closed",
|
|
958
|
+
"unknown",
|
|
959
|
+
];
|
|
960
|
+
function isAddress(value) {
|
|
961
|
+
return typeof value === "string" && /^0x[0-9a-fA-F]{1,64}$/.test(value);
|
|
962
|
+
}
|
|
963
|
+
function checkedOrder(order, orderId) {
|
|
964
|
+
const v = order;
|
|
965
|
+
if (typeof v !== "object" || v === null || !isAddress(v.orderId) || normalizeAddress(v.orderId) !== orderId) {
|
|
966
|
+
throw new ParchmentApiError(0, "bad_body", `order response is not order ${orderId}`);
|
|
967
|
+
}
|
|
968
|
+
if (!isAddress(v.accountId) || !isAddress(v.owner) || !isAddress(v.marketId)) {
|
|
969
|
+
throw new ParchmentApiError(0, "bad_body", "order needs accountId, owner and marketId");
|
|
970
|
+
}
|
|
971
|
+
if (!ORDER_KINDS.includes(v.kind) || !ORDER_STATUSES.includes(v.status)) {
|
|
972
|
+
throw new ParchmentApiError(0, "bad_body", "order has no known kind or status");
|
|
973
|
+
}
|
|
974
|
+
return order;
|
|
975
|
+
}
|