@parchment-trade/sdk 0.0.0-stage → 1.0.0

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 +192 -2
  3. package/REFERENCE.md +338 -0
  4. package/SECURITY.md +23 -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 +55 -4
@@ -0,0 +1,611 @@
1
+ import { fromBase64, normalizeSuiAddress, toBase64, toHex } from "@mysten/sui/utils";
2
+ import { ParchmentApiError } from "../../general/utils/errors.js";
3
+ import { PARCHMENT_BASE_MODULES, PARCHMENT_CORE_MODULES, PARCHMENT_TRADE_MODULES } from "./packageIds.js";
4
+ export const UNCHECKED_TX = "unchecked";
5
+ const ROLE_MODULES = {
6
+ core: PARCHMENT_CORE_MODULES,
7
+ trade: PARCHMENT_TRADE_MODULES,
8
+ base: PARCHMENT_BASE_MODULES,
9
+ game: [],
10
+ mint: [],
11
+ oracle: ["adapter"],
12
+ token: ["tokenomics", "staking", "parchment"],
13
+ lazerIntegration: ["price_feed_storage"],
14
+ };
15
+ const FRAMEWORK = normalizeSuiAddress("0x2");
16
+ const ZERO_COIN = ["framework", "coin", "zero"];
17
+ const ONE_STEP_PRELUDE = [
18
+ ["lazerIntegration", "price_feed_storage", "update_price_feed"],
19
+ ["oracle", "adapter", "quote"],
20
+ ["trade", "oracle", "begin_price"],
21
+ ];
22
+ const call = (role, module, fn) => [role, module, fn];
23
+ const only = (role, module, fn) => ({ actions: [{ call: call(role, module, fn) }] });
24
+ function oneStep(action, bind, receiptAt, lossMint, updateOptional) {
25
+ const update = (at) => (updateOptional ? { at, update: "updateBase64", optional: true } : { at, update: "updateBase64" });
26
+ const actions = [
27
+ { call: call("lazerIntegration", "price_feed_storage", "update_price_feed"), bind: [update(5)] },
28
+ { call: call("oracle", "adapter", "quote"), bind: [update(2)] },
29
+ { call: call("trade", "oracle", "begin_price"), bind: [{ at: 1, object: "marketId" }, { at: 2, resultOf: 1 }] },
30
+ { call: action, bind: [...bind, { at: receiptAt, resultOf: 2 }] },
31
+ ];
32
+ if (lossMint) {
33
+ actions.push({ call: call("token", "tokenomics", "mint_on_loss"), bind: [{ at: 2, object: "accountId" }, { at: 3, resultOf: 3 }], times: [0, 1] });
34
+ }
35
+ return { actions };
36
+ }
37
+ const gameRoute = (fn, more = []) => ({
38
+ actions: [{ call: call("trade", "game", fn), bind: [{ at: 1, object: "accountId" }, { at: 2, object: "accountCapId" }, ...more] }],
39
+ });
40
+ const syncLocked = (owner) => ({
41
+ call: call("token", "staking", "sync_locked"), bind: [{ at: 2, address: owner }], times: [0, 1],
42
+ });
43
+ const adminRoute = (role, module, fn, capAt, more = []) => ({
44
+ actions: [{ call: call(role, module, fn), bind: [{ at: capAt, object: "authorityCapId" }, ...more] }],
45
+ });
46
+ const ROUTES = {
47
+ "open-account": only("core", "exchange", "open_account"),
48
+ deposit: {
49
+ actions: [{ call: call("core", "exchange", "deposit"), bind: [{ at: 2, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 4, object: "coin" }] }],
50
+ },
51
+ withdraw: {
52
+ actions: [{ call: call("core", "exchange", "withdraw"), bind: [{ at: 2, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 4, u64: "amount" }] }],
53
+ },
54
+ "request-open": {
55
+ actions: [
56
+ {
57
+ call: call("trade", "order", "request_open"),
58
+ bind: [
59
+ { at: 1, object: "marketId" },
60
+ { at: 2, object: "accountId" },
61
+ { at: 3, object: "accountCapId" },
62
+ { at: 5, u64: "margin" },
63
+ { at: 6, u64: "leverage" },
64
+ { at: 7, bool: "isLong" },
65
+ { at: 8, u64: "minFactorBps", fallback: 0n },
66
+ { at: 9, u128: "acceptablePriceWad" },
67
+ { at: 10, optionU32: "builderId", unverifiable: "builderCode" },
68
+ { at: 11, coinOrZero: "topUp" },
69
+ ],
70
+ },
71
+ ],
72
+ extras: [ZERO_COIN],
73
+ },
74
+ "request-open-as-delegate": {
75
+ actions: [
76
+ {
77
+ call: call("trade", "order", "request_open_as_delegate"),
78
+ bind: [
79
+ { at: 1, object: "marketId" },
80
+ { at: 2, object: "accountId" },
81
+ { at: 4, u64: "margin" },
82
+ { at: 5, u64: "leverage" },
83
+ { at: 6, bool: "isLong" },
84
+ { at: 7, u64: "minFactorBps", fallback: 0n },
85
+ { at: 8, u128: "acceptablePriceWad" },
86
+ { at: 9, optionU32: "builderId", unverifiable: "builderCode" },
87
+ ],
88
+ },
89
+ ],
90
+ },
91
+ "request-close": {
92
+ actions: [
93
+ {
94
+ call: call("trade", "order", "request_close"),
95
+ bind: [
96
+ { at: 1, object: "marketId" },
97
+ { at: 2, object: "accountId" },
98
+ { at: 3, object: "accountCapId" },
99
+ { at: 5, u64: "positionId" },
100
+ { at: 6, u128: "acceptablePriceWad", fallback: 0n },
101
+ { at: 7, coinOrZero: "topUp" },
102
+ ],
103
+ },
104
+ ],
105
+ extras: [ZERO_COIN],
106
+ },
107
+ "request-close-as-delegate": {
108
+ actions: [
109
+ {
110
+ call: call("trade", "order", "request_close_as_delegate"),
111
+ bind: [{ at: 1, object: "marketId" }, { at: 2, object: "accountId" }, { at: 4, u64: "positionId" }, { at: 5, u128: "acceptablePriceWad", fallback: 0n }],
112
+ },
113
+ ],
114
+ },
115
+ "cancel-order": {
116
+ actions: [{ call: call("trade", "order", "cancel"), bind: [{ at: 1, object: "accountId" }, { at: 2, object: "accountCapId" }, { at: 4, object: "orderId" }] }],
117
+ },
118
+ "cancel-order-as-delegate": {
119
+ actions: [{ call: call("trade", "order", "cancel_as_delegate"), bind: [{ at: 1, object: "accountId" }, { at: 3, object: "orderId" }] }],
120
+ },
121
+ "expire-order": {
122
+ actions: [
123
+ {
124
+ call: call("trade", "order", "expire"),
125
+ bind: [{ at: 1, object: "marketId", optional: true }, { at: 2, object: "accountId" }, { at: 4, object: "orderId" }],
126
+ },
127
+ ],
128
+ extras: [["oracle", "adapter", "quote"], ["trade", "oracle", "begin_expiry_price"]],
129
+ },
130
+ "emergency-close": oneStep(call("trade", "order", "emergency_close"), [{ at: 1, object: "marketId" }, { at: 2, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 5, object: "orderId" }], 6, true, true),
131
+ "emergency-close-as-delegate": oneStep(call("trade", "order", "emergency_close_as_delegate"), [{ at: 1, object: "marketId" }, { at: 2, object: "accountId" }, { at: 4, object: "orderId" }], 5, true, true),
132
+ "close-retired": oneStep(call("trade", "trade", "close_retired"), [{ at: 1, object: "marketId" }, { at: 2, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 5, u64: "positionId" }], 6, true, true),
133
+ "close-retired-as-delegate": oneStep(call("trade", "trade", "close_retired_as_delegate"), [{ at: 1, object: "marketId" }, { at: 2, object: "accountId" }, { at: 4, u64: "positionId" }], 5, true, true),
134
+ liquidate: oneStep(call("trade", "trade", "liquidate"), [{ at: 1, object: "marketId" }, { at: 3, u64: "positionId" }], 4, false, false),
135
+ "liquidate-retired": oneStep(call("trade", "trade", "liquidate_retired"), [{ at: 1, object: "marketId" }, { at: 3, u64: "positionId" }], 4, false, false),
136
+ sweep: oneStep(call("trade", "trade", "sweep"), [{ at: 1, object: "marketId" }, { at: 4, u64: "maxEntries" }], 3, false, false),
137
+ "sweep-surplus": {
138
+ actions: [
139
+ { call: call("core", "exchange", "begin_reserve_check") },
140
+ { call: call("trade", "trade", "check_market"), bind: [{ at: 0, resultOf: 0 }], times: [0, 64] },
141
+ { call: call("core", "exchange", "sweep_surplus"), bind: [{ at: 2, resultOf: 0 }] },
142
+ ],
143
+ extras: ONE_STEP_PRELUDE,
144
+ },
145
+ "grant-delegate": {
146
+ actions: [
147
+ {
148
+ call: call("core", "exchange", "grant_delegate"),
149
+ bind: [{ at: 1, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 4, address: "delegate" }, { at: 5, u64: "expiryMs" }],
150
+ },
151
+ ],
152
+ },
153
+ "revoke-delegate": {
154
+ actions: [{ call: call("core", "exchange", "revoke_delegate"), bind: [{ at: 1, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 4, address: "delegate" }] }],
155
+ },
156
+ "grant-close-delegate": {
157
+ actions: [
158
+ {
159
+ call: call("core", "exchange", "grant_close_delegate"),
160
+ bind: [{ at: 1, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 4, address: { triggerDelegate: true } }],
161
+ times: [0, 1],
162
+ },
163
+ ],
164
+ },
165
+ "grant-session-and-trigger": {
166
+ actions: [
167
+ {
168
+ call: call("core", "exchange", "grant_delegate"),
169
+ bind: [{ at: 1, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 4, address: "sessionDelegate" }, { at: 5, u64: "expiryMs" }],
170
+ },
171
+ {
172
+ call: call("core", "exchange", "grant_close_delegate"),
173
+ bind: [{ at: 1, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 4, address: { triggerDelegate: true } }],
174
+ times: [0, 1],
175
+ },
176
+ ],
177
+ },
178
+ "release-unlocked": {
179
+ actions: [
180
+ { call: call("trade", "locked_mint", "release_unlocked"), bind: [{ at: 1, address: { field: "who", fallback: "sender" } }] },
181
+ syncLocked({ field: "who", fallback: "sender" }),
182
+ ],
183
+ },
184
+ "exit-early": { actions: [{ call: call("trade", "locked_mint", "exit_early") }, syncLocked({ sender: true })] },
185
+ "exit-early-bounded": {
186
+ actions: [
187
+ { call: call("trade", "locked_mint", "exit_early_bounded"), bind: [{ at: 2, u64s: "unlocks" }, { at: 3, u64: "maxPenalty" }] },
188
+ syncLocked({ sender: true }),
189
+ ],
190
+ },
191
+ harvest: { actions: [{ call: call("trade", "harvest", "harvest"), bind: [{ at: 3, u64: "maxEntries" }] }] },
192
+ "claim-pending-mint": {
193
+ actions: [
194
+ { call: call("trade", "fees", "claim_pending_ticket"), bind: [{ at: 2, object: "accountId" }, { at: 3, object: "accountCapId" }] },
195
+ { call: call("token", "tokenomics", "mint_on_loss"), bind: [{ at: 2, object: "accountId" }, { at: 3, resultOf: 0 }] },
196
+ ],
197
+ },
198
+ stake: { actions: [{ call: call("token", "staking", "stake"), bind: [{ at: 2, object: "coin" }] }] },
199
+ unstake: { actions: [{ call: call("token", "staking", "unstake"), bind: [{ at: 2, u64: "amount" }] }] },
200
+ claim: only("token", "staking", "claim"),
201
+ "bind-referrer": { actions: [{ call: call("token", "staking", "bind_referrer"), bind: [{ at: 2, address: "referrer" }] }] },
202
+ "bind-trading-referrer": {
203
+ actions: [
204
+ {
205
+ call: call("trade", "referral", "bind_referrer"),
206
+ bind: [{ at: 2, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 4, address: "referrer" }],
207
+ },
208
+ ],
209
+ },
210
+ "transfer-account": {
211
+ actions: [
212
+ {
213
+ call: call("trade", "account_transfer", "transfer_account"),
214
+ bind: [{ at: 2, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 4, address: "recipient" }],
215
+ },
216
+ ],
217
+ },
218
+ "claim-daily": gameRoute("claim_daily"),
219
+ "open-crate": gameRoute("open_crate"),
220
+ "open-crates": gameRoute("open_crates", [{ at: 4, u64: "count" }]),
221
+ "claim-quest": gameRoute("claim_quest", [{ at: 4, u8: "questId" }]),
222
+ "collect-mint": gameRoute("collect_mint"),
223
+ "create-builder": {
224
+ actions: [
225
+ {
226
+ call: call("trade", "builder", "create_builder"),
227
+ bind: [{ at: 2, utf8: "code" }, { at: 3, address: "payout" }, { at: 4, u16: "feeBps" }, { at: 5, splitOf: "coin" }],
228
+ },
229
+ ],
230
+ splits: 1,
231
+ },
232
+ "set-builder-payout": {
233
+ actions: [{ call: call("trade", "builder", "set_builder_payout"), bind: [{ at: 2, u32: "builderId" }, { at: 3, address: "newPayout" }] }],
234
+ },
235
+ "set-builder-fee": { actions: [{ call: call("trade", "builder", "set_builder_fee"), bind: [{ at: 2, u32: "builderId" }, { at: 3, u16: "feeBps" }] }] },
236
+ "pause-builder": { actions: [{ call: call("trade", "builder", "pause_builder"), bind: [{ at: 2, u32: "builderId" }] }] },
237
+ "resume-builder": { actions: [{ call: call("trade", "builder", "resume_builder"), bind: [{ at: 2, u32: "builderId" }] }] },
238
+ "transfer-builder": { actions: [{ call: call("trade", "builder", "transfer_owner"), bind: [{ at: 2, u32: "builderId" }, { at: 3, address: "newOwner" }] }] },
239
+ "approve-builder": {
240
+ actions: [
241
+ {
242
+ call: call("trade", "builder", "approve_builder"),
243
+ bind: [{ at: 2, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 4, u32: "builderId" }, { at: 5, u16: "maxFeeBps" }],
244
+ },
245
+ ],
246
+ },
247
+ "revoke-builder-approval": {
248
+ actions: [
249
+ {
250
+ call: call("trade", "builder", "revoke_builder_approval"),
251
+ bind: [{ at: 2, object: "accountId" }, { at: 3, object: "accountCapId" }, { at: 4, u32: "builderId" }],
252
+ },
253
+ ],
254
+ },
255
+ "register-builder": adminRoute("trade", "builder", "register_builder", 2, [
256
+ { at: 3, utf8: "code" },
257
+ { at: 4, address: "payout" },
258
+ { at: 5, address: "owner" },
259
+ { at: 6, u16: "feeBps" },
260
+ ]),
261
+ "set-builder-create-fee": adminRoute("core", "config", "set_builder_create_fee", 1, [{ at: 2, u64: "amount" }]),
262
+ "install-treasury": adminRoute("token", "parchment", "install_treasury", 2, [{ at: 3, object: "treasuryCap" }]),
263
+ "auth-register": adminRoute("trade", "auth", "register", 2),
264
+ "game-attach": adminRoute("trade", "game_book", "attach", 2),
265
+ };
266
+ const REVOKE_SESSION_AND_TRIGGER = call("core", "exchange", "revoke_delegate");
267
+ const REVOKE_ROUTE = "revoke-session-and-trigger";
268
+ function namedDelegates(body) {
269
+ const session = bodyAddress(body.sessionDelegate);
270
+ const trigger = bodyAddress(body.triggerDelegate);
271
+ if (session === null || trigger === null)
272
+ return null;
273
+ return session === trigger ? [session] : [session, trigger];
274
+ }
275
+ function ids(list) {
276
+ return new Set((list ?? []).map((id) => normalizeSuiAddress(id)));
277
+ }
278
+ function roleOf(trusted, pkg, module, fn) {
279
+ const id = normalizeSuiAddress(pkg);
280
+ if (id === FRAMEWORK && module === "coin" && fn === "zero")
281
+ return "framework";
282
+ for (const role of Object.keys(ROLE_MODULES)) {
283
+ if (ids(trusted[role]).has(id) && ROLE_MODULES[role].includes(module))
284
+ return role;
285
+ }
286
+ return null;
287
+ }
288
+ function inputOf(data, arg) {
289
+ if (arg?.$kind !== "Input" || typeof arg.Input !== "number")
290
+ return null;
291
+ return data.inputs[arg.Input] ?? null;
292
+ }
293
+ function objectIdOf(data, arg) {
294
+ const input = inputOf(data, arg);
295
+ const id = input?.Object?.SharedObject?.objectId ?? input?.Object?.ImmOrOwnedObject?.objectId ?? input?.UnresolvedObject?.objectId;
296
+ return id ? normalizeSuiAddress(id) : null;
297
+ }
298
+ function pureBytes(data, arg) {
299
+ const input = inputOf(data, arg);
300
+ return input?.$kind === "Pure" && input.Pure ? fromBase64(input.Pure.bytes) : null;
301
+ }
302
+ function bcsBytes(bytes) {
303
+ return bcsVector(bytes.length, bytes);
304
+ }
305
+ function bcsVector(length, bytes) {
306
+ const prefix = [];
307
+ let n = length;
308
+ do {
309
+ prefix.push((n & 0x7f) | (n > 0x7f ? 0x80 : 0));
310
+ n >>>= 7;
311
+ } while (n > 0);
312
+ const out = new Uint8Array(prefix.length + bytes.length);
313
+ out.set(prefix);
314
+ out.set(bytes, prefix.length);
315
+ return out;
316
+ }
317
+ export function updateArgBase64(updateBase64) {
318
+ if (typeof updateBase64 !== "string" || updateBase64.length === 0)
319
+ return null;
320
+ try {
321
+ const bytes = fromBase64(updateBase64);
322
+ return bytes.length === 0 ? null : toBase64(bcsBytes(bytes));
323
+ }
324
+ catch {
325
+ return null;
326
+ }
327
+ }
328
+ function sameBytes(a, b) {
329
+ return a.length === b.length && a.every((x, i) => x === b[i]);
330
+ }
331
+ function littleEndian(bytes) {
332
+ let value = 0n;
333
+ for (let i = bytes.length - 1; i >= 0; i--)
334
+ value = (value << 8n) | BigInt(bytes[i]);
335
+ return value;
336
+ }
337
+ function bodyInt(value) {
338
+ if (typeof value === "bigint")
339
+ return value;
340
+ if (typeof value === "string" && /^\d+n?$/.test(value))
341
+ return BigInt(value.replace(/n$/, ""));
342
+ return null;
343
+ }
344
+ function bodyAddress(value) {
345
+ if (typeof value !== "string")
346
+ return null;
347
+ try {
348
+ return normalizeSuiAddress(value);
349
+ }
350
+ catch {
351
+ return null;
352
+ }
353
+ }
354
+ function bodyObject(value) {
355
+ if (value && typeof value === "object" && typeof value.objectId === "string") {
356
+ return bodyAddress(value.objectId);
357
+ }
358
+ return bodyAddress(value);
359
+ }
360
+ function bindingViolation(data, args, binding, body, sender, trust, zeroCoins, actionAt) {
361
+ const arg = args[binding.at];
362
+ if (arg === undefined)
363
+ return `argument ${binding.at} is missing`;
364
+ if ("resultOf" in binding) {
365
+ const from = actionAt[binding.resultOf];
366
+ const index = arg.$kind === "Result" ? arg.Result : arg.$kind === "NestedResult" && arg.NestedResult?.[1] === 0 ? arg.NestedResult[0] : undefined;
367
+ return from !== null && from !== undefined && index === from ? null : `argument ${binding.at} is not the result of the route's earlier call`;
368
+ }
369
+ if ("object" in binding) {
370
+ if (binding.optional && body[binding.object] === undefined)
371
+ return null;
372
+ const want = bodyObject(body[binding.object]);
373
+ if (want === null)
374
+ return `request has no ${binding.object}`;
375
+ return objectIdOf(data, arg) === want ? null : `argument ${binding.at} is not the requested ${binding.object}`;
376
+ }
377
+ if ("coinOrZero" in binding) {
378
+ const want = body[binding.coinOrZero] === undefined ? null : bodyObject(body[binding.coinOrZero]);
379
+ if (want !== null)
380
+ return objectIdOf(data, arg) === want ? null : `argument ${binding.at} is not the requested ${binding.coinOrZero} coin`;
381
+ return arg.$kind === "Result" && typeof arg.Result === "number" && zeroCoins.has(arg.Result) ? null : `argument ${binding.at} is not a zero coin`;
382
+ }
383
+ if ("update" in binding || "utf8" in binding) {
384
+ const field = "update" in binding ? binding.update : binding.utf8;
385
+ const raw = body[field];
386
+ let want = null;
387
+ if (typeof raw === "string" && raw.length > 0) {
388
+ try {
389
+ want = "update" in binding ? fromBase64(raw) : new TextEncoder().encode(raw);
390
+ }
391
+ catch {
392
+ want = null;
393
+ }
394
+ }
395
+ if (want === null || want.length === 0) {
396
+ if ("update" in binding && binding.optional && (raw === undefined || raw === null)) {
397
+ return trust.acceptServiceOracleUpdate === true
398
+ ? null
399
+ : `request has no ${field}: pass the signed update (or set txTrust.acceptServiceOracleUpdate to take the service's)`;
400
+ }
401
+ return `request has no ${field}`;
402
+ }
403
+ const bytes = pureBytes(data, arg);
404
+ return bytes !== null && sameBytes(bytes, bcsBytes(want)) ? null : `argument ${binding.at} is not the requested ${field}`;
405
+ }
406
+ if ("splitOf" in binding) {
407
+ const want = bodyObject(body[binding.splitOf]);
408
+ if (want === null)
409
+ return `request has no ${binding.splitOf}`;
410
+ const index = arg.$kind === "Result" ? arg.Result : arg.$kind === "NestedResult" && arg.NestedResult?.[1] === 0 ? arg.NestedResult[0] : undefined;
411
+ const split = index === undefined ? undefined : data.commands[index];
412
+ const from = split?.$kind === "SplitCoins" && split.SplitCoins.amounts.length === 1 ? split.SplitCoins.coin : undefined;
413
+ return from !== undefined && objectIdOf(data, from) === want ? null : `argument ${binding.at} is not split from the requested ${binding.splitOf}`;
414
+ }
415
+ if ("u8" in binding || "u16" in binding || "u32" in binding || "u64" in binding || "u128" in binding) {
416
+ const [field, width] = "u8" in binding ? [binding.u8, 1]
417
+ : "u16" in binding ? [binding.u16, 2]
418
+ : "u32" in binding ? [binding.u32, 4]
419
+ : "u64" in binding ? [binding.u64, 8]
420
+ : [binding.u128, 16];
421
+ const raw = body[field];
422
+ const fallback = "fallback" in binding ? binding.fallback : undefined;
423
+ const want = raw === undefined ? (fallback ?? null) : bodyInt(raw);
424
+ if (want === null)
425
+ return `request has no ${field}`;
426
+ const bytes = pureBytes(data, arg);
427
+ return bytes !== null && bytes.length === width && littleEndian(bytes) === want ? null : `argument ${binding.at} is not the requested ${field}`;
428
+ }
429
+ if ("u64s" in binding) {
430
+ const raw = body[binding.u64s];
431
+ const want = Array.isArray(raw) ? raw.map(bodyInt) : null;
432
+ if (want === null || want.some((v) => v === null || v > 0xffffffffffffffffn))
433
+ return `request has no ${binding.u64s}`;
434
+ const bytes = pureBytes(data, arg);
435
+ const words = new Uint8Array(want.length * 8);
436
+ want.forEach((v, i) => {
437
+ for (let b = 0; b < 8; b++)
438
+ words[i * 8 + b] = Number((v >> BigInt(8 * b)) & 0xffn);
439
+ });
440
+ return bytes !== null && sameBytes(bytes, bcsVector(want.length, words)) ? null : `argument ${binding.at} is not the requested ${binding.u64s}`;
441
+ }
442
+ if ("optionU32" in binding) {
443
+ const bytes = pureBytes(data, arg);
444
+ const some = bytes !== null && bytes.length === 5 && bytes[0] === 1 ? littleEndian(bytes.subarray(1)) : null;
445
+ const none = bytes !== null && bytes.length === 1 && bytes[0] === 0;
446
+ const raw = body[binding.optionU32];
447
+ if (raw === undefined) {
448
+ if (body[binding.unverifiable] !== undefined)
449
+ return `a ${binding.unverifiable} without ${binding.optionU32} cannot be checked; pass ${binding.optionU32}`;
450
+ return none ? null : `argument ${binding.at} names a ${binding.optionU32} the request does not`;
451
+ }
452
+ const want = bodyInt(raw);
453
+ if (want === null)
454
+ return `request has no ${binding.optionU32}`;
455
+ return some === want ? null : `argument ${binding.at} is not the requested ${binding.optionU32}`;
456
+ }
457
+ if ("bool" in binding) {
458
+ const want = body[binding.bool];
459
+ if (typeof want !== "boolean")
460
+ return `request has no ${binding.bool}`;
461
+ const bytes = pureBytes(data, arg);
462
+ return bytes !== null && bytes.length === 1 && bytes[0] === (want ? 1 : 0) ? null : `argument ${binding.at} is not the requested ${binding.bool}`;
463
+ }
464
+ const spec = binding.address;
465
+ let want;
466
+ let label;
467
+ if (typeof spec === "string") {
468
+ want = bodyAddress(body[spec]);
469
+ label = spec;
470
+ }
471
+ else if ("sender" in spec) {
472
+ want = normalizeSuiAddress(sender);
473
+ label = "sender";
474
+ }
475
+ else if ("triggerDelegate" in spec) {
476
+ want = trust.triggerDelegate ? normalizeSuiAddress(trust.triggerDelegate) : null;
477
+ label = "pinned trigger delegate";
478
+ if (want === null)
479
+ return "txTrust.triggerDelegate is not pinned";
480
+ }
481
+ else {
482
+ want = body[spec.field] === undefined ? normalizeSuiAddress(sender) : bodyAddress(body[spec.field]);
483
+ label = spec.field;
484
+ }
485
+ if (want === null)
486
+ return `request has no ${label}`;
487
+ const bytes = pureBytes(data, arg);
488
+ const got = bytes !== null && bytes.length === 32 ? normalizeSuiAddress(toHex(bytes)) : null;
489
+ return got === want ? null : `argument ${binding.at} is not the ${label}`;
490
+ }
491
+ export function txIntentViolation(route, tx, body, sender, trust, held) {
492
+ const data = tx.getData();
493
+ const intent = route === REVOKE_ROUTE
494
+ ? { actions: [{ call: REVOKE_SESSION_AND_TRIGGER, bind: [{ at: 1, object: "accountId" }, { at: 3, object: "accountCapId" }], times: [1, 2] }] }
495
+ : ROUTES[route];
496
+ if (!intent)
497
+ return `no intent check for transactions/${route}`;
498
+ let mustRevoke = [];
499
+ if (route === REVOKE_ROUTE) {
500
+ const named = namedDelegates(body);
501
+ if (named === null)
502
+ return "request has no sessionDelegate and triggerDelegate";
503
+ const live = held === undefined ? null : new Set(held.map((a) => normalizeSuiAddress(a)));
504
+ mustRevoke = live === null ? named : named.filter((a) => live.has(a));
505
+ if (mustRevoke.length === 0)
506
+ return "neither named delegate holds a grant on the account";
507
+ }
508
+ const counts = intent.actions.map(() => 0);
509
+ const actionAt = intent.actions.map(() => null);
510
+ const zeroCoins = new Set();
511
+ let splits = 0;
512
+ const revoked = [];
513
+ const bound = (bindings, args, what) => {
514
+ for (const binding of bindings) {
515
+ const violation = bindingViolation(data, args, binding, body, sender, trust, zeroCoins, actionAt);
516
+ if (violation)
517
+ return `${what} ${violation}`;
518
+ }
519
+ return null;
520
+ };
521
+ for (const [index, command] of data.commands.entries()) {
522
+ if (command.$kind === "SplitCoins") {
523
+ if (++splits > (intent.splits ?? 0) || command.SplitCoins.amounts.length !== 1)
524
+ return `unexpected SplitCoins for ${route}`;
525
+ continue;
526
+ }
527
+ if (command.$kind === "TransferObjects") {
528
+ const to = pureBytes(data, command.TransferObjects.address);
529
+ if (to === null || to.length !== 32 || normalizeSuiAddress(toHex(to)) !== normalizeSuiAddress(sender))
530
+ return `TransferObjects to someone other than the sender for ${route}`;
531
+ continue;
532
+ }
533
+ if (command.$kind !== "MoveCall")
534
+ return `unexpected ${command.$kind} for ${route}`;
535
+ const { package: pkg, module, function: fn, arguments: args } = command.MoveCall;
536
+ const role = roleOf(trust.packages, pkg, module, fn);
537
+ if (role === null)
538
+ return `call to untrusted ${pkg}::${module}::${fn}`;
539
+ const key = `${role}:${module}::${fn}`;
540
+ const sameKey = (c) => `${c[0]}:${c[1]}::${c[2]}` === key;
541
+ const action = intent.actions.findIndex((a) => sameKey(a.call));
542
+ if (action === -1) {
543
+ const extra = (intent.extras ?? []).find((e) => sameKey("call" in e ? e.call : e));
544
+ if (extra === undefined)
545
+ return `unexpected call to ${module}::${fn} for ${route}`;
546
+ if ("bind" in extra) {
547
+ const violation = bound(extra.bind, args, `${module}::${fn}`);
548
+ if (violation)
549
+ return violation;
550
+ }
551
+ if (role === "framework")
552
+ zeroCoins.add(index);
553
+ continue;
554
+ }
555
+ counts[action]++;
556
+ const violation = bound(intent.actions[action].bind ?? [], args, `${module}::${fn}`);
557
+ if (violation)
558
+ return violation;
559
+ actionAt[action] = index;
560
+ if (route === REVOKE_ROUTE) {
561
+ const bytes = pureBytes(data, args[4]);
562
+ const who = bytes !== null && bytes.length === 32 ? normalizeSuiAddress(toHex(bytes)) : null;
563
+ if (who === null || !mustRevoke.includes(who) || revoked.includes(who)) {
564
+ return "revoke_delegate argument 4 is not a held delegate named in the request";
565
+ }
566
+ revoked.push(who);
567
+ }
568
+ }
569
+ for (const [i, action] of intent.actions.entries()) {
570
+ const [min, max] = action.times ?? [1, 1];
571
+ if (counts[i] < min || counts[i] > max)
572
+ return `${action.call[1]}::${action.call[2]} appears ${counts[i]} times for ${route}`;
573
+ }
574
+ const kept = mustRevoke.filter((a) => !revoked.includes(a));
575
+ if (kept.length > 0)
576
+ return `revoke-session-and-trigger leaves ${kept.join(", ")} granted`;
577
+ return null;
578
+ }
579
+ export function untrustedConfigPackages(config, trusted) {
580
+ const out = [];
581
+ const check = (list, allowed) => {
582
+ const set = ids(allowed);
583
+ for (const id of list)
584
+ if (id && !set.has(normalizeSuiAddress(id)))
585
+ out.push(normalizeSuiAddress(id));
586
+ };
587
+ check([config.packageId, ...(config.packageIds ?? [])], trusted.core);
588
+ check([config.tradePackageId, ...(config.tradePackageIds ?? [])], trusted.trade);
589
+ check([config.basePackageId, ...(config.basePackageIds ?? [])], trusted.base);
590
+ check([config.gamePackageId, ...(config.gamePackageIds ?? [])], trusted.game);
591
+ check([config.mintPackageId, ...(config.mintPackageIds ?? [])], trusted.mint);
592
+ if (trusted.oracle)
593
+ check([config.oraclePackageId], trusted.oracle);
594
+ if (trusted.token)
595
+ check([config.tokenPackageId], trusted.token);
596
+ if (trusted.lazerIntegration)
597
+ check([config.lazerIntegrationPackageId], trusted.lazerIntegration);
598
+ return out;
599
+ }
600
+ export function txRoute(url) {
601
+ return url.replace(/^\/*transactions\//, "").replace(/[?#].*$/, "");
602
+ }
603
+ export async function assertTxIntent(url, body, tx, sender, trust) {
604
+ const route = txRoute(url);
605
+ const named = route === REVOKE_ROUTE ? namedDelegates(body) : null;
606
+ const accountId = bodyAddress(body.accountId);
607
+ const held = named !== null && accountId !== null && trust.heldDelegates ? await trust.heldDelegates(accountId, named) : undefined;
608
+ const violation = txIntentViolation(route, tx, body, sender, trust, held);
609
+ if (violation !== null)
610
+ throw new ParchmentApiError(0, "intent_mismatch", `transaction does not match the request: ${violation}`);
611
+ }
@@ -0,0 +1,2 @@
1
+ export type { CallerConfig, ParchmentOptions, RequestOptions, RequestOptionsUpdate } from "./general/types/index.js";
2
+ export type * from "./packages/parchment/parchmentTypes.js";
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};