@lifi/perps-sdk 10.0.2 → 10.2.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 (85) hide show
  1. package/dist/cjs/client/PerpsClient.d.ts +7 -3
  2. package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
  3. package/dist/cjs/client/PerpsClient.js +90 -16
  4. package/dist/cjs/client/PerpsClient.js.map +1 -1
  5. package/dist/cjs/index.d.ts +5 -1
  6. package/dist/cjs/index.d.ts.map +1 -1
  7. package/dist/cjs/index.js +7 -3
  8. package/dist/cjs/index.js.map +1 -1
  9. package/dist/cjs/services/getReferralActivity.d.ts +11 -0
  10. package/dist/cjs/services/getReferralActivity.d.ts.map +1 -0
  11. package/dist/cjs/services/getReferralActivity.js +13 -0
  12. package/dist/cjs/services/getReferralActivity.js.map +1 -0
  13. package/dist/cjs/services/getReferralStatus.d.ts +10 -0
  14. package/dist/cjs/services/getReferralStatus.d.ts.map +1 -0
  15. package/dist/cjs/services/getReferralStatus.js +12 -0
  16. package/dist/cjs/services/getReferralStatus.js.map +1 -0
  17. package/dist/cjs/types/api.d.ts +17 -1
  18. package/dist/cjs/types/api.d.ts.map +1 -1
  19. package/dist/cjs/types/provider.d.ts +1 -0
  20. package/dist/cjs/types/provider.d.ts.map +1 -1
  21. package/dist/cjs/utils/setupActions.d.ts.map +1 -1
  22. package/dist/cjs/utils/setupActions.js.map +1 -1
  23. package/dist/cjs/utils/switchChain.d.ts +1 -0
  24. package/dist/cjs/utils/switchChain.d.ts.map +1 -1
  25. package/dist/cjs/utils/switchChain.js +9 -5
  26. package/dist/cjs/utils/switchChain.js.map +1 -1
  27. package/dist/cjs/version.d.ts +1 -1
  28. package/dist/cjs/version.js +1 -1
  29. package/dist/esm/client/PerpsClient.d.ts +61 -9
  30. package/dist/esm/client/PerpsClient.d.ts.map +1 -1
  31. package/dist/esm/client/PerpsClient.js +152 -25
  32. package/dist/esm/client/PerpsClient.js.map +1 -1
  33. package/dist/esm/index.d.ts +5 -1
  34. package/dist/esm/index.d.ts.map +1 -1
  35. package/dist/esm/index.js +2 -0
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/services/getReferralActivity.d.ts +38 -0
  38. package/dist/esm/services/getReferralActivity.d.ts.map +1 -0
  39. package/dist/esm/services/getReferralActivity.js +30 -0
  40. package/dist/esm/services/getReferralActivity.js.map +1 -0
  41. package/dist/esm/services/getReferralStatus.d.ts +45 -0
  42. package/dist/esm/services/getReferralStatus.d.ts.map +1 -0
  43. package/dist/esm/services/getReferralStatus.js +34 -0
  44. package/dist/esm/services/getReferralStatus.js.map +1 -0
  45. package/dist/esm/types/api.d.ts +48 -1
  46. package/dist/esm/types/api.d.ts.map +1 -1
  47. package/dist/esm/types/provider.d.ts +9 -0
  48. package/dist/esm/types/provider.d.ts.map +1 -1
  49. package/dist/esm/utils/setupActions.d.ts +4 -3
  50. package/dist/esm/utils/setupActions.d.ts.map +1 -1
  51. package/dist/esm/utils/setupActions.js +4 -3
  52. package/dist/esm/utils/setupActions.js.map +1 -1
  53. package/dist/esm/utils/switchChain.d.ts +7 -2
  54. package/dist/esm/utils/switchChain.d.ts.map +1 -1
  55. package/dist/esm/utils/switchChain.js +16 -9
  56. package/dist/esm/utils/switchChain.js.map +1 -1
  57. package/dist/esm/version.d.ts +1 -1
  58. package/dist/esm/version.js +1 -1
  59. package/dist/types/client/PerpsClient.d.ts +61 -9
  60. package/dist/types/client/PerpsClient.d.ts.map +1 -1
  61. package/dist/types/index.d.ts +5 -1
  62. package/dist/types/index.d.ts.map +1 -1
  63. package/dist/types/services/getReferralActivity.d.ts +38 -0
  64. package/dist/types/services/getReferralActivity.d.ts.map +1 -0
  65. package/dist/types/services/getReferralStatus.d.ts +45 -0
  66. package/dist/types/services/getReferralStatus.d.ts.map +1 -0
  67. package/dist/types/types/api.d.ts +48 -1
  68. package/dist/types/types/api.d.ts.map +1 -1
  69. package/dist/types/types/provider.d.ts +9 -0
  70. package/dist/types/types/provider.d.ts.map +1 -1
  71. package/dist/types/utils/setupActions.d.ts +4 -3
  72. package/dist/types/utils/setupActions.d.ts.map +1 -1
  73. package/dist/types/utils/switchChain.d.ts +7 -2
  74. package/dist/types/utils/switchChain.d.ts.map +1 -1
  75. package/dist/types/version.d.ts +1 -1
  76. package/package.json +2 -2
  77. package/src/client/PerpsClient.ts +203 -30
  78. package/src/index.ts +8 -0
  79. package/src/services/getReferralActivity.ts +51 -0
  80. package/src/services/getReferralStatus.ts +57 -0
  81. package/src/types/api.ts +57 -0
  82. package/src/types/provider.ts +10 -0
  83. package/src/utils/setupActions.ts +4 -3
  84. package/src/utils/switchChain.ts +17 -9
  85. package/src/version.ts +1 -1
@@ -8,6 +8,7 @@ import type {
8
8
  ExecuteActionResponse,
9
9
  MarketRef,
10
10
  MarketSettings,
11
+ MetaActionType,
11
12
  Position,
12
13
  PositionMarginConstraints,
13
14
  Provider,
@@ -16,6 +17,7 @@ import type {
16
17
  } from '@lifi/perps-types'
17
18
  import {
18
19
  ActionType,
20
+ META_PROVIDER,
19
21
  PerpsErrorCode,
20
22
  PerpsSigner,
21
23
  SigningMethod,
@@ -32,6 +34,8 @@ import type {
32
34
  BuildProviderSetupParams,
33
35
  CancelOrdersParams,
34
36
  CancelTwapOrderParams,
37
+ CreateReferralCodeActionParams,
38
+ ExecuteMetaActionParams,
35
39
  ExecuteProviderSetupParams,
36
40
  ExecuteProviderSetupResult,
37
41
  GetAccountResult,
@@ -45,6 +49,7 @@ import type {
45
49
  PlaceTwapOrderParams,
46
50
  ProviderSetup,
47
51
  SendAssetActionParams,
52
+ SubmitOnboardingParams,
48
53
  WithdrawParams,
49
54
  } from '../types/api.js'
50
55
  import type { PerpsClientSigner, SwitchChainHook } from '../types/config.js'
@@ -57,7 +62,9 @@ import type {
57
62
  SignActionsContext,
58
63
  } from '../types/provider.js'
59
64
  import type { WithdrawableBalance } from '../types/withdrawal.js'
65
+ import { signTypedDataWithSigner } from '../utils/signTypedData.js'
60
66
  import {
67
+ eip712DomainChainId,
61
68
  switchSigningChain,
62
69
  userEip712TargetChainId,
63
70
  } from '../utils/switchChain.js'
@@ -292,6 +299,28 @@ export class PerpsClient {
292
299
  return switchSigningChain(wallet, targetChainId, this._switchChain)
293
300
  }
294
301
 
302
+ /**
303
+ * Resolve the wallet that signs a meta action's steps. Meta actions carry no
304
+ * provider descriptor, so the target chain comes from the step's EIP-712
305
+ * domain. The switch is transient — `sdkClient.userWallet` is never mutated.
306
+ */
307
+ private async resolveMetaSigningWallet(
308
+ actions: ActionStep[]
309
+ ): Promise<PerpsClientSigner> {
310
+ const wallet = this.sdkClient.userWallet
311
+ if (!wallet) {
312
+ throw new PerpsError(
313
+ PerpsErrorCode.SDKError,
314
+ 'No user wallet configured; call setUserWallet() before signing a meta action.'
315
+ )
316
+ }
317
+ const targetChainId = eip712DomainChainId(actions)
318
+ if (targetChainId === undefined) {
319
+ return wallet
320
+ }
321
+ return switchSigningChain(wallet, targetChainId, this._switchChain)
322
+ }
323
+
295
324
  /**
296
325
  * Assemble the per-call context the provider plugin needs in order to sign:
297
326
  * the end-user's wallet and the descriptor's declared `signers`. Core
@@ -553,6 +582,9 @@ export class PerpsClient {
553
582
  /**
554
583
  * Return the unsatisfied entries on `Provider.setup` for this account as a
555
584
  * flat, self-describing list. Trading is gated on `isReady === true`.
585
+ * `checklist` carries the renderable onboarding list: every USER-signed
586
+ * descriptor with its satisfied state, with not-required conditional steps
587
+ * omitted.
556
588
  *
557
589
  * `Provider.options` descriptors are NEVER returned here — options are
558
590
  * post-setup tunables and never gate trading. Option state is surfaced
@@ -574,7 +606,12 @@ export class PerpsClient {
574
606
  // SIWE-first providers (Ondo) are the exception: they cannot reliably probe
575
607
  // account existence before the user signs in, so setup must still stage.
576
608
  if (!hasSiweSetup && !(await this.accountExists(provider, address))) {
577
- return { accountExists: false, setup: [], isReady: false }
609
+ return {
610
+ accountExists: false,
611
+ setup: [],
612
+ isReady: false,
613
+ checklist: [],
614
+ }
578
615
  }
579
616
 
580
617
  const satisfiedSetup = await this.resolveSatisfiedSetup(provider, address)
@@ -582,13 +619,13 @@ export class PerpsClient {
582
619
  (descriptor) => !satisfiedSetup.has(descriptor.type)
583
620
  )
584
621
 
585
- const hiddenSetup = await this.resolveInternalSetup(
586
- provider,
587
- address,
588
- pendingSetup
589
- )
622
+ const plugin = this.sdkClient.getProvider(provider)
623
+ const internalTypes = new Set(plugin?.internalSetupActions ?? [])
624
+ const isInternal = (descriptor: ProviderAction): boolean =>
625
+ internalTypes.has(descriptor.type) &&
626
+ !descriptor.signers.includes(PerpsSigner.USER)
590
627
  const visibleSetup = pendingSetup.filter(
591
- (descriptor) => !hiddenSetup.has(descriptor.type)
628
+ (descriptor) => !isInternal(descriptor)
592
629
  )
593
630
 
594
631
  // The backend filters already-satisfied setup actions and returns typed
@@ -600,10 +637,38 @@ export class PerpsClient {
600
637
  visibleSetup
601
638
  )
602
639
 
640
+ // A staged step is one the build produced actions for — a pending
641
+ // descriptor the backend staged nothing for is either satisfied
642
+ // (backend-gated) or not applicable to this account.
643
+ const stagedTypes = new Set(actions.map((step) => step.action))
644
+ const conditionalTypes = new Set(plugin?.conditionalSetupActions ?? [])
645
+ const sequenceOf = (descriptor: ProviderAction): number =>
646
+ descriptor.sequence ?? Number.MAX_SAFE_INTEGER
647
+ const checklist = metadata.setup
648
+ .filter((descriptor) => descriptor.signers.includes(PerpsSigner.USER))
649
+ .filter(
650
+ (descriptor) =>
651
+ !conditionalTypes.has(descriptor.type) ||
652
+ stagedTypes.has(descriptor.type)
653
+ )
654
+ .sort((a, b) => sequenceOf(a) - sequenceOf(b))
655
+ .map((descriptor) => ({
656
+ descriptor,
657
+ satisfied: !stagedTypes.has(descriptor.type),
658
+ }))
659
+
660
+ await this.drainInternalSetup(
661
+ provider,
662
+ address,
663
+ pendingSetup.filter(isInternal),
664
+ visibleSetup.filter((descriptor) => stagedTypes.has(descriptor.type))
665
+ )
666
+
603
667
  return {
604
668
  accountExists: true,
605
669
  setup: actions,
606
670
  isReady: actions.length === 0,
671
+ checklist,
607
672
  }
608
673
  }
609
674
 
@@ -639,33 +704,32 @@ export class PerpsClient {
639
704
 
640
705
  /**
641
706
  * Drain the pending setup steps the provider declares as internal via
642
- * `PerpsProviderPlugin.internalSetupActions`, returning the set of action
643
- * types to omit from the caller-facing setup list. Each such step is built,
644
- * signed, and executed in place with the provider's own credentials. A
645
- * descriptor whose `signers` include {@link PerpsSigner.USER} is left to
646
- * render as a normal step. A drain failure is swallowed so it never blocks
647
- * setup — the step stays unsatisfied and is retried on a later `checkSetup`.
707
+ * `PerpsProviderPlugin.internalSetupActions`. Each step is built, signed,
708
+ * and executed in place with the provider's own credentials. A step is
709
+ * deferred while any staged user-facing step with a lower `sequence` is
710
+ * outstanding — it cannot succeed before its prerequisite (e.g. SET_REFERRAL
711
+ * authenticates with the credential REGISTER_API_KEY installs) and each
712
+ * doomed attempt is venue traffic. A drain failure is swallowed so it never
713
+ * blocks setup — the step stays unsatisfied and is retried on a later
714
+ * `checkSetup`.
648
715
  */
649
- private async resolveInternalSetup(
716
+ private async drainInternalSetup(
650
717
  provider: string,
651
718
  address: Address,
652
- pending: ProviderAction[]
653
- ): Promise<Set<ActionType>> {
654
- const plugin = this.sdkClient.getProvider(provider)
655
- const internal = plugin?.internalSetupActions
656
- if (!internal || internal.length === 0) {
657
- return new Set()
658
- }
659
- const internalTypes = new Set(internal)
660
- const hidden = new Set<ActionType>()
661
- for (const descriptor of pending) {
662
- if (
663
- !internalTypes.has(descriptor.type) ||
664
- descriptor.signers.includes(PerpsSigner.USER)
665
- ) {
719
+ internalPending: ProviderAction[],
720
+ stagedVisible: ProviderAction[]
721
+ ): Promise<void> {
722
+ const sequenceOf = (descriptor: ProviderAction): number =>
723
+ descriptor.sequence ?? Number.MAX_SAFE_INTEGER
724
+ for (const descriptor of internalPending) {
725
+ // A tie (equal sequences, or both absent) declares no order, so the
726
+ // internal step defers to the next checkSetup rather than racing.
727
+ const blocked = stagedVisible.some(
728
+ (staged) => sequenceOf(staged) <= sequenceOf(descriptor)
729
+ )
730
+ if (blocked) {
666
731
  continue
667
732
  }
668
- hidden.add(descriptor.type)
669
733
  try {
670
734
  const steps = await this.buildProviderSetupActions(provider, address, [
671
735
  descriptor,
@@ -692,7 +756,6 @@ export class PerpsClient {
692
756
  )
693
757
  }
694
758
  }
695
- return hidden
696
759
  }
697
760
 
698
761
  /**
@@ -1126,4 +1189,114 @@ export class PerpsClient {
1126
1189
 
1127
1190
  return { results }
1128
1191
  }
1192
+
1193
+ /**
1194
+ * Accept the current terms and, when a code is supplied and the backend
1195
+ * accepts it, attach that internal referral code — in one signature.
1196
+ * Convenience wrapper over {@link executeMetaAction} with
1197
+ * `ActionType.META_ONBOARD`.
1198
+ *
1199
+ * Resolves to `{ results: [] }` when the backend requires no consent from
1200
+ * this address.
1201
+ *
1202
+ * @throws {PerpsError} When no user wallet is configured, or the action
1203
+ * cannot be signed/submitted.
1204
+ * @public
1205
+ */
1206
+ async submitOnboarding(
1207
+ params: SubmitOnboardingParams
1208
+ ): Promise<ExecuteActionResponse> {
1209
+ const { address, ...onboard } = params
1210
+ return this.executeMetaAction({
1211
+ address,
1212
+ action: ActionType.META_ONBOARD,
1213
+ params: onboard,
1214
+ })
1215
+ }
1216
+
1217
+ /**
1218
+ * Reserve the shareable internal referral code `address` owns. Convenience
1219
+ * wrapper over {@link executeMetaAction} with
1220
+ * `ActionType.META_CREATE_REFERRAL_CODE`.
1221
+ *
1222
+ * @throws {PerpsError} When no user wallet is configured, or the action
1223
+ * cannot be signed/submitted.
1224
+ * @public
1225
+ */
1226
+ async createReferralCode(
1227
+ params: CreateReferralCodeActionParams
1228
+ ): Promise<ExecuteActionResponse> {
1229
+ const { address, ...createCode } = params
1230
+ return this.executeMetaAction({
1231
+ address,
1232
+ action: ActionType.META_CREATE_REFERRAL_CODE,
1233
+ params: createCode,
1234
+ })
1235
+ }
1236
+
1237
+ /**
1238
+ * Execute a provider-independent action through the same
1239
+ * createAction/executeAction pipeline {@link execute} uses. Meta actions are
1240
+ * dispatched with the {@link META_PROVIDER} sentinel: they have no venue
1241
+ * plugin and no `ProviderAction` descriptor, so the step is signed as EIP-712
1242
+ * typed data with the configured user wallet.
1243
+ *
1244
+ * The backend returns at most one step. Resolves to `{ results: [] }` when it
1245
+ * returns none, meaning no consent is outstanding for this address.
1246
+ *
1247
+ * @throws {PerpsError} When no user wallet is configured, the backend returns
1248
+ * more than one step or a non-EIP-712 step, or the submitted step reports a
1249
+ * failed result. A signature refusal from the wallet client propagates as
1250
+ * the wallet's own error.
1251
+ * @public
1252
+ */
1253
+ async executeMetaAction<T extends MetaActionType>(
1254
+ params: ExecuteMetaActionParams<T>
1255
+ ): Promise<ExecuteActionResponse> {
1256
+ const { address, action } = params
1257
+ const { actions } = await createAction(this.sdkClient, {
1258
+ provider: META_PROVIDER,
1259
+ address,
1260
+ action,
1261
+ params: params.params,
1262
+ })
1263
+
1264
+ if (actions.length === 0) {
1265
+ return { results: [] }
1266
+ }
1267
+ if (actions.length > 1) {
1268
+ throw new PerpsError(
1269
+ PerpsErrorCode.SDKError,
1270
+ `Action '${action}' returned ${actions.length} steps; a meta action carries at most one.`
1271
+ )
1272
+ }
1273
+
1274
+ const [step] = actions
1275
+ if (!('typedData' in step)) {
1276
+ throw new PerpsError(
1277
+ PerpsErrorCode.SDKError,
1278
+ `Action '${action}' returned a step without typedData; meta actions are signed as EIP-712 typed data.`
1279
+ )
1280
+ }
1281
+
1282
+ const wallet = await this.resolveMetaSigningWallet(actions)
1283
+ const signature = await signTypedDataWithSigner(wallet, step.typedData)
1284
+
1285
+ const response = await executeAction(this.sdkClient, {
1286
+ provider: META_PROVIDER,
1287
+ address,
1288
+ action,
1289
+ actions: [{ ...step, signature }],
1290
+ })
1291
+
1292
+ const failure = response.results.find((r) => !r.success)
1293
+ if (failure) {
1294
+ throw new PerpsError(
1295
+ failure.errorCode ?? PerpsErrorCode.ExchangeRejected,
1296
+ failure.error
1297
+ )
1298
+ }
1299
+
1300
+ return response
1301
+ }
1129
1302
  }
package/src/index.ts CHANGED
@@ -65,6 +65,10 @@ export { getPositions } from './services/getPositions.js'
65
65
  export { getProviders } from './services/getProviders.js'
66
66
  export type { GetQuoteParams } from './services/getQuote.js'
67
67
  export { getQuote } from './services/getQuote.js'
68
+ export type { GetReferralActivityParams } from './services/getReferralActivity.js'
69
+ export { getReferralActivity } from './services/getReferralActivity.js'
70
+ export type { GetReferralStatusParams } from './services/getReferralStatus.js'
71
+ export { getReferralStatus } from './services/getReferralStatus.js'
68
72
  export { getTermsAcceptance } from './services/getTermsAcceptance.js'
69
73
  export { resolveQuote, resolveQuoteMarket } from './services/resolveQuote.js'
70
74
  export {
@@ -99,6 +103,8 @@ export type {
99
103
  BuildProviderSetupParams,
100
104
  CancelOrdersParams,
101
105
  CancelTwapOrderParams as ClientCancelTwapOrderParams,
106
+ CreateReferralCodeActionParams,
107
+ ExecuteMetaActionParams,
102
108
  GetAccountResult,
103
109
  GetDepositFlowParams,
104
110
  GetSetupParams,
@@ -111,6 +117,8 @@ export type {
111
117
  PlaceTwapOrderParams as ClientPlaceTwapOrderParams,
112
118
  ProviderSetup,
113
119
  SendAssetActionParams,
120
+ SetupChecklistItem,
121
+ SubmitOnboardingParams,
114
122
  WithdrawParams,
115
123
  } from './types/api.js'
116
124
  export type {
@@ -0,0 +1,51 @@
1
+ import type { ReferralActivityResponse } from '@lifi/perps-types'
2
+ import type { Address } from 'viem'
3
+ import { buildUrl, request } from '../transport/request.js'
4
+ import type { SDKRequestOptions } from '../types/config.js'
5
+ import type { PerpsSDKClient } from '../types/provider.js'
6
+
7
+ /**
8
+ * Parameters for {@link getReferralActivity}.
9
+ *
10
+ * @public
11
+ */
12
+ export interface GetReferralActivityParams {
13
+ address: Address
14
+ /** Maximum items returned; backend defaults and caps apply. */
15
+ limit?: number
16
+ /** Opaque pagination cursor from the previous response. */
17
+ cursor?: string
18
+ }
19
+
20
+ /**
21
+ * Get the addresses attached to `address`'s owned internal referral code, with
22
+ * the executed notional recorded against each attachment. Provider-independent
23
+ * — reads from the platform `meta` surface, not a venue plugin.
24
+ *
25
+ * An address that owns no code resolves to `items: []` with `hasMore: false`
26
+ * and no cursor.
27
+ *
28
+ * @throws {PerpsError} On backend error responses, network, or parsing errors.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const client = createPerpsClient({ apiKey: 'your-api-key' })
33
+ * const { items, pagination } = await getReferralActivity(client, {
34
+ * address: '0x1234...',
35
+ * limit: 50,
36
+ * })
37
+ * ```
38
+ * @public
39
+ */
40
+ export async function getReferralActivity(
41
+ client: PerpsSDKClient,
42
+ params: GetReferralActivityParams,
43
+ options?: SDKRequestOptions
44
+ ): Promise<ReferralActivityResponse> {
45
+ const url = buildUrl(`${client.config.apiUrl}/meta/referral/activity`, {
46
+ address: params.address,
47
+ limit: params.limit,
48
+ cursor: params.cursor,
49
+ })
50
+ return request<ReferralActivityResponse>(client.config, url, {}, options)
51
+ }
@@ -0,0 +1,57 @@
1
+ import type { ReferralStatus } from '@lifi/perps-types'
2
+ import type { Address } from 'viem'
3
+ import { buildUrl, request } from '../transport/request.js'
4
+ import type { SDKRequestOptions } from '../types/config.js'
5
+ import type { PerpsSDKClient } from '../types/provider.js'
6
+
7
+ /**
8
+ * Parameters for {@link getReferralStatus}.
9
+ *
10
+ * @public
11
+ */
12
+ export interface GetReferralStatusParams {
13
+ address: Address
14
+ /**
15
+ * Candidate internal referral code to validate in the same read. The
16
+ * response carries the backend's verdict on `candidate`, and reflects the
17
+ * candidate in `onboarding.referralCode` when it is attachable.
18
+ */
19
+ code?: string
20
+ }
21
+
22
+ /**
23
+ * Get an address's onboarding and internal-referral state: terms acceptance,
24
+ * the code attached to it, the code it owns, whether it may create one, the
25
+ * verdict on a candidate code, and the one onboarding step it must sign next.
26
+ * Provider-independent — reads from the platform `meta` surface, not a venue
27
+ * plugin.
28
+ *
29
+ * An address the backend holds no record for resolves to a well-formed
30
+ * payload with `termsAccepted: false` and the optional state fields absent.
31
+ *
32
+ * @throws {PerpsError} On backend error responses, network, or parsing errors.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const client = createPerpsClient({ apiKey: 'your-api-key' })
37
+ * const status = await getReferralStatus(client, {
38
+ * address: '0x1234...',
39
+ * code: 'ABC123',
40
+ * })
41
+ * if (status.onboarding) {
42
+ * // one signature is outstanding; submit it via PerpsClient.submitOnboarding
43
+ * }
44
+ * ```
45
+ * @public
46
+ */
47
+ export async function getReferralStatus(
48
+ client: PerpsSDKClient,
49
+ params: GetReferralStatusParams,
50
+ options?: SDKRequestOptions
51
+ ): Promise<ReferralStatus> {
52
+ const url = buildUrl(`${client.config.apiUrl}/meta/referral`, {
53
+ address: params.address,
54
+ code: params.code,
55
+ })
56
+ return request<ReferralStatus>(client.config, url, {}, options)
57
+ }
package/src/types/api.ts CHANGED
@@ -2,14 +2,19 @@ import type {
2
2
  AccountConfigSetting,
3
3
  AccountResponse,
4
4
  CancelTwapOrderParams as ActionCancelTwapOrderParams,
5
+ CreateReferralCodeParams as ActionCreateReferralCodeParams,
6
+ ActionParamsMap,
5
7
  PlaceTwapOrderParams as ActionPlaceTwapOrderParams,
6
8
  ActionStep,
7
9
  ExecuteActionResponse,
8
10
  MarginMode,
9
11
  MarketRef,
12
+ MetaActionType,
10
13
  ModifyOrderInput,
14
+ OnboardParams,
11
15
  OrderSide,
12
16
  OrderType,
17
+ ProviderAction,
13
18
  SignedActionStep,
14
19
  TimeInForce,
15
20
  TriggerOrderInput,
@@ -283,6 +288,19 @@ export interface GetWithdrawableBalancesParams {
283
288
  address: Address
284
289
  }
285
290
 
291
+ /**
292
+ * One entry on {@link ProviderSetup.checklist}: a user-facing setup
293
+ * descriptor plus its satisfied state for the queried account.
294
+ *
295
+ * @public
296
+ */
297
+ export interface SetupChecklistItem {
298
+ /** The `Provider.setup` descriptor for this step. */
299
+ descriptor: ProviderAction
300
+ /** Whether the step is already satisfied for this account. */
301
+ satisfied: boolean
302
+ }
303
+
286
304
  /**
287
305
  * Result from {@link PerpsClient.checkSetup}.
288
306
  *
@@ -308,6 +326,15 @@ export interface ProviderSetup {
308
326
  setup: ActionStep[]
309
327
  /** Whether all setup items are already satisfied (ready to trade) */
310
328
  isReady: boolean
329
+ /**
330
+ * The renderable onboarding list: every USER-signed setup descriptor with
331
+ * its satisfied state, ordered by `sequence`. SDK-internal steps and
332
+ * conditional steps that staged no work for this account (see
333
+ * `PerpsProviderPlugin.conditionalSetupActions`) are omitted. Consumers
334
+ * render this list directly instead of joining `Provider.setup` metadata
335
+ * with the staged `setup` steps.
336
+ */
337
+ checklist: SetupChecklistItem[]
311
338
  }
312
339
 
313
340
  /**
@@ -344,3 +371,33 @@ export interface GetAccountResult extends AccountResponse {
344
371
  /** SDK-projected current state of every setup + options descriptor. */
345
372
  settings: AccountConfigSetting[]
346
373
  }
374
+
375
+ /**
376
+ * Parameters for {@link PerpsClient.submitOnboarding}.
377
+ *
378
+ * @public
379
+ */
380
+ export interface SubmitOnboardingParams extends OnboardParams {
381
+ address: Address
382
+ }
383
+
384
+ /**
385
+ * Parameters for {@link PerpsClient.createReferralCode}.
386
+ *
387
+ * @public
388
+ */
389
+ export interface CreateReferralCodeActionParams
390
+ extends ActionCreateReferralCodeParams {
391
+ address: Address
392
+ }
393
+
394
+ /**
395
+ * Parameters for {@link PerpsClient.executeMetaAction}.
396
+ *
397
+ * @public
398
+ */
399
+ export interface ExecuteMetaActionParams<T extends MetaActionType> {
400
+ address: Address
401
+ action: T
402
+ params: ActionParamsMap[T]
403
+ }
@@ -358,6 +358,16 @@ export interface PerpsProviderPlugin {
358
358
  */
359
359
  readonly internalSetupActions?: readonly ActionType[]
360
360
 
361
+ /**
362
+ * Setup actions that stage work only when the account needs remediation
363
+ * (e.g. Hyperliquid's REVOKE_AGENT frees an agent slot only when every
364
+ * named slot is taken). When such a step stages no actions,
365
+ * `PerpsClient.checkSetup` omits it from `ProviderSetup.checklist` instead
366
+ * of rendering it as satisfied. Omit when every setup step is
367
+ * unconditional.
368
+ */
369
+ readonly conditionalSetupActions?: readonly ActionType[]
370
+
361
371
  /**
362
372
  * Inject the runtime {@link PerpsSDKClient} into the plugin once, during
363
373
  * {@link createPerpsClient}. The plugin captures it (config, fetch, retry,
@@ -8,9 +8,10 @@ import { PerpsSigner } from '@lifi/perps-types'
8
8
  * them inline, so surfacing them would render inert cards the user can't act on.
9
9
  *
10
10
  * Membership is a property of the descriptor's `signers` alone, independent of
11
- * any account: use this to build the onboarding list, then layer each entry's
12
- * satisfied/unsatisfied state on top from a live `checkSetup` so the tick never
13
- * goes stale.
11
+ * any account. When an account is available, prefer `ProviderSetup.checklist`
12
+ * from `checkSetup` for the onboarding list — it applies this filter, omits
13
+ * not-required conditional steps, and carries each entry's satisfied state.
14
+ * This function remains the static, account-free projection.
14
15
  *
15
16
  * @param setup The provider's `setup` descriptors, in their declared order.
16
17
  * @public
@@ -8,12 +8,26 @@ import { getChainId } from 'viem/actions'
8
8
  import { PerpsError } from '../errors/PerpsError.js'
9
9
  import type { PerpsClientSigner, SwitchChainHook } from '../types/config.js'
10
10
 
11
+ /**
12
+ * The chain `actions` are signed on: the first numeric
13
+ * `typedData.domain.chainId` across the batch, or `undefined` when no step
14
+ * carries one.
15
+ */
16
+ export function eip712DomainChainId(actions: ActionStep[]): number | undefined {
17
+ for (const step of actions) {
18
+ const chainId = (step as Eip712ActionStep).typedData?.domain?.chainId
19
+ if (typeof chainId === 'number') {
20
+ return chainId
21
+ }
22
+ }
23
+ return undefined
24
+ }
25
+
11
26
  /**
12
27
  * The chain a batch of `actions` must be signed on, or `undefined` when no
13
28
  * wallet chain switch applies. Only USER-signed EIP-712 batches carry a target
14
29
  * (agent-signed batches sign with a chain-bound keypair; other schemes are not
15
- * EIP-712). Reads the first numeric `typedData.domain.chainId`; a batch whose
16
- * steps omit `chainId` yields `undefined`.
30
+ * EIP-712).
17
31
  */
18
32
  export function userEip712TargetChainId(
19
33
  descriptor: ProviderAction,
@@ -25,13 +39,7 @@ export function userEip712TargetChainId(
25
39
  ) {
26
40
  return undefined
27
41
  }
28
- for (const step of actions) {
29
- const chainId = (step as Eip712ActionStep).typedData?.domain?.chainId
30
- if (typeof chainId === 'number') {
31
- return chainId
32
- }
33
- }
34
- return undefined
42
+ return eip712DomainChainId(actions)
35
43
  }
36
44
 
37
45
  /**
package/src/version.ts CHANGED
@@ -10,4 +10,4 @@ export const name = '@lifi/perps-sdk'
10
10
  *
11
11
  * @public
12
12
  */
13
- export const version = '10.0.2'
13
+ export const version = '10.2.0'