@lifi/perps-sdk 0.0.0-preview-5cdfc44 → 0.0.0-preview-b49efcc
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/README.md +22 -0
- package/dist/cjs/client/PerpsClient.d.ts +7 -3
- package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
- package/dist/cjs/client/PerpsClient.js +43 -47
- package/dist/cjs/client/PerpsClient.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +4 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/registry/assetRegistry.d.ts +2 -1
- package/dist/cjs/registry/assetRegistry.d.ts.map +1 -1
- package/dist/cjs/registry/assetRegistry.js +11 -1
- package/dist/cjs/registry/assetRegistry.js.map +1 -1
- package/dist/cjs/types/api.d.ts +2 -2
- package/dist/cjs/types/api.d.ts.map +1 -1
- package/dist/cjs/types/provider.d.ts +8 -2
- package/dist/cjs/types/provider.d.ts.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/client/PerpsClient.d.ts +54 -47
- package/dist/esm/client/PerpsClient.d.ts.map +1 -1
- package/dist/esm/client/PerpsClient.js +92 -102
- package/dist/esm/client/PerpsClient.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/registry/assetRegistry.d.ts +7 -1
- package/dist/esm/registry/assetRegistry.d.ts.map +1 -1
- package/dist/esm/registry/assetRegistry.js +14 -0
- package/dist/esm/registry/assetRegistry.js.map +1 -1
- package/dist/esm/types/api.d.ts +11 -13
- package/dist/esm/types/api.d.ts.map +1 -1
- package/dist/esm/types/provider.d.ts +33 -6
- package/dist/esm/types/provider.d.ts.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/types/client/PerpsClient.d.ts +54 -47
- package/dist/types/client/PerpsClient.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/registry/assetRegistry.d.ts +7 -1
- package/dist/types/registry/assetRegistry.d.ts.map +1 -1
- package/dist/types/types/api.d.ts +11 -13
- package/dist/types/types/api.d.ts.map +1 -1
- package/dist/types/types/provider.d.ts +33 -6
- package/dist/types/types/provider.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +2 -2
- package/src/client/PerpsClient.ts +130 -138
- package/src/index.ts +6 -1
- package/src/registry/assetRegistry.ts +16 -1
- package/src/types/api.ts +11 -13
- package/src/types/provider.ts +41 -6
- package/src/version.ts +1 -1
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
ActionParamsMap,
|
|
5
5
|
ActionResult,
|
|
6
6
|
ActionStep,
|
|
7
|
+
AvailableToTrade,
|
|
7
8
|
CreateActionResponse,
|
|
8
9
|
ExecuteActionResponse,
|
|
9
10
|
MarketRef,
|
|
@@ -16,19 +17,20 @@ import type {
|
|
|
16
17
|
PositionMarginConstraints,
|
|
17
18
|
Provider,
|
|
18
19
|
ProviderAction,
|
|
19
|
-
SetupAction,
|
|
20
20
|
SignedActionStep,
|
|
21
21
|
} from '@lifi/perps-types'
|
|
22
22
|
import {
|
|
23
23
|
ActionType,
|
|
24
24
|
META_PROVIDER,
|
|
25
25
|
PerpsErrorCode,
|
|
26
|
+
PerpsSigner,
|
|
26
27
|
SigningMethod,
|
|
27
28
|
} from '@lifi/perps-types'
|
|
28
29
|
import Big from 'big.js'
|
|
29
30
|
import type { Address } from 'viem'
|
|
30
31
|
import { PerpsError } from '../errors/PerpsError.js'
|
|
31
|
-
import { getAssetRegistry } from '../registry/assetRegistry.js'
|
|
32
|
+
import { getAssetRegistry, toAssetDisplay } from '../registry/assetRegistry.js'
|
|
33
|
+
import { getMarketRegistry } from '../registry/marketRegistry.js'
|
|
32
34
|
import { createAction } from '../services/createAction.js'
|
|
33
35
|
import { executeAction } from '../services/executeAction.js'
|
|
34
36
|
import { getAccount as fetchAccount } from '../services/getAccount.js'
|
|
@@ -87,23 +89,6 @@ import {
|
|
|
87
89
|
import { createPerpsClient } from './createPerpsClient.js'
|
|
88
90
|
import { requireProvider as resolveProvider } from './requireProvider.js'
|
|
89
91
|
|
|
90
|
-
/** Absent `sequence` sorts last, so an unordered step gates nothing. */
|
|
91
|
-
function sequenceOf(descriptor: ProviderAction): number {
|
|
92
|
-
return descriptor.sequence ?? Number.MAX_SAFE_INTEGER
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Whether the SDK can apply a preference without user input. Every declared
|
|
97
|
-
* parameter must carry a `default`, since the action's params object is only
|
|
98
|
-
* complete when each one has a value.
|
|
99
|
-
*/
|
|
100
|
-
function declaresDefault(descriptor: ProviderAction): boolean {
|
|
101
|
-
const params = descriptor.params ?? []
|
|
102
|
-
return (
|
|
103
|
-
params.length > 0 && params.every((param) => param.default !== undefined)
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
92
|
/**
|
|
108
93
|
* Look up an action's descriptor in the provider's metadata. Throws if the
|
|
109
94
|
* action isn't declared — defensive: better to fail loudly than to mis-sign.
|
|
@@ -112,9 +97,11 @@ function findActionDescriptor(
|
|
|
112
97
|
metadata: Provider,
|
|
113
98
|
action: ActionType
|
|
114
99
|
): ProviderAction {
|
|
115
|
-
const descriptor = [
|
|
116
|
-
|
|
117
|
-
|
|
100
|
+
const descriptor = [
|
|
101
|
+
...metadata.setup,
|
|
102
|
+
...metadata.options,
|
|
103
|
+
...metadata.actions,
|
|
104
|
+
].find((d) => d.type === action)
|
|
118
105
|
if (!descriptor) {
|
|
119
106
|
throw new PerpsError(
|
|
120
107
|
PerpsErrorCode.SDKError,
|
|
@@ -467,7 +454,7 @@ export class PerpsClient {
|
|
|
467
454
|
/**
|
|
468
455
|
* Fetch the user's account state from the backend and attach the
|
|
469
456
|
* SDK-projected `settings` array — one `AccountConfigSetting` per
|
|
470
|
-
* descriptor on `Provider.setup`. Callers read
|
|
457
|
+
* descriptor on `Provider.setup` + `Provider.options`. Callers read
|
|
471
458
|
* `result.settings` directly without re-deriving values from the typed
|
|
472
459
|
* `AccountConfig`.
|
|
473
460
|
*
|
|
@@ -484,7 +471,11 @@ export class PerpsClient {
|
|
|
484
471
|
fetchAccount(this.sdkClient, params),
|
|
485
472
|
this.getProviderMetadata(params.provider),
|
|
486
473
|
])
|
|
487
|
-
const settings = plugin.projectConfig(
|
|
474
|
+
const settings = plugin.projectConfig(
|
|
475
|
+
response.config,
|
|
476
|
+
metadata.setup,
|
|
477
|
+
metadata.options
|
|
478
|
+
)
|
|
488
479
|
return { ...response, settings }
|
|
489
480
|
}
|
|
490
481
|
|
|
@@ -509,6 +500,58 @@ export class PerpsClient {
|
|
|
509
500
|
})
|
|
510
501
|
}
|
|
511
502
|
|
|
503
|
+
/**
|
|
504
|
+
* The amounts `params.address` can still buy and sell on one market, in
|
|
505
|
+
* that market's margin asset. The order panel reads this per-market figure;
|
|
506
|
+
* account displays read the account-scoped
|
|
507
|
+
* {@link AccountSummary.availableMargin} instead.
|
|
508
|
+
*
|
|
509
|
+
* Providers that read a per-market figure answer it directly. For every
|
|
510
|
+
* other provider this falls back to the account summary, so both sides
|
|
511
|
+
* equal `availableMargin` and the asset is the market's quote asset.
|
|
512
|
+
*
|
|
513
|
+
* @throws {PerpsError} When the provider plugin is not registered, or the
|
|
514
|
+
* market is unknown to the provider's market registry.
|
|
515
|
+
* @public
|
|
516
|
+
*/
|
|
517
|
+
async getAvailableToTrade(
|
|
518
|
+
params: {
|
|
519
|
+
provider: string
|
|
520
|
+
address: Address
|
|
521
|
+
marketId: string
|
|
522
|
+
},
|
|
523
|
+
options?: SDKRequestOptions
|
|
524
|
+
): Promise<AvailableToTrade> {
|
|
525
|
+
const plugin = this.requireProvider(params.provider)
|
|
526
|
+
const perMarket = await plugin.getAvailableToTrade?.(
|
|
527
|
+
{ address: params.address, marketId: params.marketId },
|
|
528
|
+
options
|
|
529
|
+
)
|
|
530
|
+
if (perMarket !== undefined) {
|
|
531
|
+
return perMarket
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const registry = getMarketRegistry(this.sdkClient, params.provider)
|
|
535
|
+
await registry.sync()
|
|
536
|
+
const market = registry.require(params.marketId)
|
|
537
|
+
const account = await fetchAccount(
|
|
538
|
+
this.sdkClient,
|
|
539
|
+
{ provider: params.provider, address: params.address },
|
|
540
|
+
options
|
|
541
|
+
)
|
|
542
|
+
const { availableMargin } = plugin.getAccountSummary(
|
|
543
|
+
account,
|
|
544
|
+
account.positions
|
|
545
|
+
)
|
|
546
|
+
return {
|
|
547
|
+
providerId: market.providerId,
|
|
548
|
+
marketId: market.id,
|
|
549
|
+
asset: toAssetDisplay(market.quoteAsset),
|
|
550
|
+
buy: availableMargin,
|
|
551
|
+
sell: availableMargin,
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
512
555
|
/**
|
|
513
556
|
* Resolve the exact venue-owned margin requirements for `position`.
|
|
514
557
|
* Returns `undefined` when the position has no individual margin adjustment.
|
|
@@ -648,16 +691,15 @@ export class PerpsClient {
|
|
|
648
691
|
}
|
|
649
692
|
|
|
650
693
|
/**
|
|
651
|
-
* Return the setup
|
|
652
|
-
* self-describing list. Trading is gated on `isReady === true`.
|
|
653
|
-
* `checklist` carries the renderable onboarding list: every
|
|
654
|
-
*
|
|
655
|
-
*
|
|
694
|
+
* Return the unsatisfied entries on `Provider.setup` for this account as a
|
|
695
|
+
* flat, self-describing list. Trading is gated on `isReady === true`.
|
|
696
|
+
* `checklist` carries the renderable onboarding list: every USER-signed
|
|
697
|
+
* descriptor with its satisfied state, with not-required conditional steps
|
|
698
|
+
* omitted.
|
|
656
699
|
*
|
|
657
|
-
* `
|
|
658
|
-
*
|
|
659
|
-
*
|
|
660
|
-
* applies the descriptor's declared default while it stays unsatisfied.
|
|
700
|
+
* `Provider.options` descriptors are NEVER returned here — options are
|
|
701
|
+
* post-setup tunables and never gate trading. Option state is surfaced
|
|
702
|
+
* separately via `getAccount().settings`.
|
|
661
703
|
*
|
|
662
704
|
* @public
|
|
663
705
|
*/
|
|
@@ -689,12 +731,12 @@ export class PerpsClient {
|
|
|
689
731
|
)
|
|
690
732
|
|
|
691
733
|
const plugin = this.sdkClient.getProvider(provider)
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
const
|
|
697
|
-
(descriptor) => descriptor
|
|
734
|
+
const internalTypes = new Set(plugin?.internalSetupActions ?? [])
|
|
735
|
+
const isInternal = (descriptor: ProviderAction): boolean =>
|
|
736
|
+
internalTypes.has(descriptor.type) &&
|
|
737
|
+
!descriptor.signers.includes(PerpsSigner.USER)
|
|
738
|
+
const visibleSetup = pendingSetup.filter(
|
|
739
|
+
(descriptor) => !isInternal(descriptor)
|
|
698
740
|
)
|
|
699
741
|
|
|
700
742
|
// The backend filters already-satisfied setup actions and returns typed
|
|
@@ -703,7 +745,7 @@ export class PerpsClient {
|
|
|
703
745
|
const actions = await this.buildProviderSetupActions(
|
|
704
746
|
provider,
|
|
705
747
|
address,
|
|
706
|
-
|
|
748
|
+
visibleSetup
|
|
707
749
|
)
|
|
708
750
|
|
|
709
751
|
// A staged step is one the build produced actions for — a pending
|
|
@@ -711,8 +753,10 @@ export class PerpsClient {
|
|
|
711
753
|
// (backend-gated) or not applicable to this account.
|
|
712
754
|
const stagedTypes = new Set(actions.map((step) => step.action))
|
|
713
755
|
const conditionalTypes = new Set(plugin?.conditionalSetupActions ?? [])
|
|
756
|
+
const sequenceOf = (descriptor: ProviderAction): number =>
|
|
757
|
+
descriptor.sequence ?? Number.MAX_SAFE_INTEGER
|
|
714
758
|
const checklist = metadata.setup
|
|
715
|
-
.filter((descriptor) => descriptor.
|
|
759
|
+
.filter((descriptor) => descriptor.signers.includes(PerpsSigner.USER))
|
|
716
760
|
.filter(
|
|
717
761
|
(descriptor) =>
|
|
718
762
|
!conditionalTypes.has(descriptor.type) ||
|
|
@@ -721,21 +765,14 @@ export class PerpsClient {
|
|
|
721
765
|
.sort((a, b) => sequenceOf(a) - sequenceOf(b))
|
|
722
766
|
.map((descriptor) => ({
|
|
723
767
|
descriptor,
|
|
724
|
-
satisfied:
|
|
725
|
-
descriptor.kind === 'preference'
|
|
726
|
-
? satisfiedSetup.has(descriptor.type)
|
|
727
|
-
: !stagedTypes.has(descriptor.type),
|
|
768
|
+
satisfied: !stagedTypes.has(descriptor.type),
|
|
728
769
|
}))
|
|
729
770
|
|
|
730
|
-
await this.
|
|
771
|
+
await this.drainInternalSetup(
|
|
731
772
|
provider,
|
|
732
773
|
address,
|
|
733
|
-
pendingSetup.filter(
|
|
734
|
-
|
|
735
|
-
descriptor.kind === 'automatic' ||
|
|
736
|
-
(descriptor.kind === 'preference' && declaresDefault(descriptor))
|
|
737
|
-
),
|
|
738
|
-
stageable.filter((descriptor) => stagedTypes.has(descriptor.type))
|
|
774
|
+
pendingSetup.filter(isInternal),
|
|
775
|
+
visibleSetup.filter((descriptor) => stagedTypes.has(descriptor.type))
|
|
739
776
|
)
|
|
740
777
|
|
|
741
778
|
return {
|
|
@@ -761,34 +798,43 @@ export class PerpsClient {
|
|
|
761
798
|
return new Set()
|
|
762
799
|
}
|
|
763
800
|
const account = await plugin.getAccount({ address })
|
|
764
|
-
const settings = plugin.projectConfig(
|
|
801
|
+
const settings = plugin.projectConfig(
|
|
802
|
+
account.config,
|
|
803
|
+
metadata.setup,
|
|
804
|
+
metadata.options
|
|
805
|
+
)
|
|
806
|
+
const setupTypes = new Set(
|
|
807
|
+
metadata.setup.map((descriptor) => descriptor.type)
|
|
808
|
+
)
|
|
765
809
|
return new Set(
|
|
766
810
|
settings
|
|
767
|
-
.filter((setting) => setting.satisfied)
|
|
811
|
+
.filter((setting) => setting.satisfied && setupTypes.has(setting.type))
|
|
768
812
|
.map((setting) => setting.type)
|
|
769
813
|
)
|
|
770
814
|
}
|
|
771
815
|
|
|
772
816
|
/**
|
|
773
|
-
* Drain the pending setup steps the
|
|
774
|
-
* `
|
|
775
|
-
*
|
|
776
|
-
*
|
|
777
|
-
*
|
|
778
|
-
*
|
|
779
|
-
*
|
|
780
|
-
*
|
|
781
|
-
*
|
|
817
|
+
* Drain the pending setup steps the provider declares as internal via
|
|
818
|
+
* `PerpsProviderPlugin.internalSetupActions`. Each step is built, signed,
|
|
819
|
+
* and executed in place with the provider's own credentials. A step is
|
|
820
|
+
* deferred while any staged user-facing step with a lower `sequence` is
|
|
821
|
+
* outstanding — it cannot succeed before its prerequisite (e.g. SET_REFERRAL
|
|
822
|
+
* authenticates with the credential REGISTER_API_KEY installs) and each
|
|
823
|
+
* doomed attempt is venue traffic. A drain failure is swallowed so it never
|
|
824
|
+
* blocks setup — the step stays unsatisfied and is retried on a later
|
|
825
|
+
* `checkSetup`.
|
|
782
826
|
*/
|
|
783
|
-
private async
|
|
827
|
+
private async drainInternalSetup(
|
|
784
828
|
provider: string,
|
|
785
829
|
address: Address,
|
|
786
|
-
|
|
787
|
-
stagedVisible:
|
|
830
|
+
internalPending: ProviderAction[],
|
|
831
|
+
stagedVisible: ProviderAction[]
|
|
788
832
|
): Promise<void> {
|
|
789
|
-
|
|
833
|
+
const sequenceOf = (descriptor: ProviderAction): number =>
|
|
834
|
+
descriptor.sequence ?? Number.MAX_SAFE_INTEGER
|
|
835
|
+
for (const descriptor of internalPending) {
|
|
790
836
|
// A tie (equal sequences, or both absent) declares no order, so the
|
|
791
|
-
//
|
|
837
|
+
// internal step defers to the next checkSetup rather than racing.
|
|
792
838
|
const blocked = stagedVisible.some(
|
|
793
839
|
(staged) => sequenceOf(staged) <= sequenceOf(descriptor)
|
|
794
840
|
)
|
|
@@ -816,7 +862,7 @@ export class PerpsClient {
|
|
|
816
862
|
}
|
|
817
863
|
} catch (error) {
|
|
818
864
|
console.debug(
|
|
819
|
-
`[perps-sdk] setup step '${descriptor.type}' for '${provider}' did not
|
|
865
|
+
`[perps-sdk] internal setup step '${descriptor.type}' for '${provider}' did not complete; will retry on the next checkSetup.`,
|
|
820
866
|
error
|
|
821
867
|
)
|
|
822
868
|
}
|
|
@@ -868,9 +914,7 @@ export class PerpsClient {
|
|
|
868
914
|
|
|
869
915
|
/**
|
|
870
916
|
* Build the unsigned setup `ActionStep`s still outstanding for an account,
|
|
871
|
-
* ordered by descriptor `sequence`.
|
|
872
|
-
* `automatic` step drains inside {@link checkSetup} and a `preference`
|
|
873
|
-
* carries the user's own selection. The backend filters already-satisfied
|
|
917
|
+
* ordered by descriptor `sequence`. The backend filters already-satisfied
|
|
874
918
|
* setup; each plugin contributes its own signer-bearing request fields and
|
|
875
919
|
* any local-state params (e.g. Lighter's known pubkey).
|
|
876
920
|
*
|
|
@@ -885,7 +929,7 @@ export class PerpsClient {
|
|
|
885
929
|
const actions = await this.buildProviderSetupActions(
|
|
886
930
|
provider,
|
|
887
931
|
address,
|
|
888
|
-
metadata.setup
|
|
932
|
+
metadata.setup
|
|
889
933
|
)
|
|
890
934
|
return { actions }
|
|
891
935
|
}
|
|
@@ -939,45 +983,6 @@ export class PerpsClient {
|
|
|
939
983
|
return { results: { results } }
|
|
940
984
|
}
|
|
941
985
|
|
|
942
|
-
/**
|
|
943
|
-
* The lowest-`sequence` visible setup step that runs before `descriptor` and
|
|
944
|
-
* is not satisfied, or `undefined` when nothing blocks it. A `preference`
|
|
945
|
-
* reads its satisfied state from the plugin projection; an `approval` is
|
|
946
|
-
* satisfied once the provider stages no action for it, so only the earlier
|
|
947
|
-
* steps are staged here.
|
|
948
|
-
*/
|
|
949
|
-
private async findBlockingSetupStep(
|
|
950
|
-
provider: string,
|
|
951
|
-
address: Address,
|
|
952
|
-
descriptor: SetupAction
|
|
953
|
-
): Promise<SetupAction | undefined> {
|
|
954
|
-
const metadata = await this.getProviderMetadata(provider)
|
|
955
|
-
const earlier = metadata.setup
|
|
956
|
-
.filter(
|
|
957
|
-
(d) => d.kind !== 'automatic' && sequenceOf(d) < sequenceOf(descriptor)
|
|
958
|
-
)
|
|
959
|
-
.sort((a, b) => sequenceOf(a) - sequenceOf(b))
|
|
960
|
-
if (earlier.length === 0) {
|
|
961
|
-
return undefined
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
const satisfiedSetup = await this.resolveSatisfiedSetup(provider, address)
|
|
965
|
-
const pending = earlier.filter((d) => !satisfiedSetup.has(d.type))
|
|
966
|
-
if (pending.length === 0) {
|
|
967
|
-
return undefined
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
const stageable = pending.filter((d) => d.kind === 'approval')
|
|
971
|
-
const staged =
|
|
972
|
-
stageable.length === 0
|
|
973
|
-
? []
|
|
974
|
-
: await this.buildProviderSetupActions(provider, address, stageable)
|
|
975
|
-
const stagedTypes = new Set(staged.map((action) => action.action))
|
|
976
|
-
return pending.find(
|
|
977
|
-
(d) => d.kind === 'preference' || stagedTypes.has(d.type)
|
|
978
|
-
)
|
|
979
|
-
}
|
|
980
|
-
|
|
981
986
|
/**
|
|
982
987
|
* Sign and submit one pre-staged setup `ActionStep` end-to-end.
|
|
983
988
|
*
|
|
@@ -991,8 +996,7 @@ export class PerpsClient {
|
|
|
991
996
|
* retries with a fresh step.
|
|
992
997
|
*
|
|
993
998
|
* @throws {PerpsError} When the step's action is not in the provider's
|
|
994
|
-
* `setup` descriptors
|
|
995
|
-
* checklist is still unsatisfied.
|
|
999
|
+
* `setup` descriptors.
|
|
996
1000
|
* @public
|
|
997
1001
|
*/
|
|
998
1002
|
async executeProviderSetupAction(params: {
|
|
@@ -1011,18 +1015,6 @@ export class PerpsClient {
|
|
|
1011
1015
|
)
|
|
1012
1016
|
}
|
|
1013
1017
|
|
|
1014
|
-
const blocking = await this.findBlockingSetupStep(
|
|
1015
|
-
provider,
|
|
1016
|
-
address,
|
|
1017
|
-
descriptor
|
|
1018
|
-
)
|
|
1019
|
-
if (blocking) {
|
|
1020
|
-
throw new PerpsError(
|
|
1021
|
-
PerpsErrorCode.SDKError,
|
|
1022
|
-
`Setup step '${step.action}' for '${provider}' is blocked: '${blocking.type}' runs first and is not satisfied.`
|
|
1023
|
-
)
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
1018
|
const signed = await this.signProviderSetupAction(provider, address, step)
|
|
1027
1019
|
|
|
1028
1020
|
// A client-executed setup action (Lighter SET_REFERRAL) produces no
|
|
@@ -1041,19 +1033,19 @@ export class PerpsClient {
|
|
|
1041
1033
|
}
|
|
1042
1034
|
|
|
1043
1035
|
/**
|
|
1044
|
-
* Sign and submit a single
|
|
1045
|
-
* as Lighter `ACCOUNT_TYPE` or Hyperliquid `ACCOUNT_MODE`)
|
|
1046
|
-
* throwing on a venue rejection.
|
|
1036
|
+
* Sign and submit a single provider-option change (a `Provider.options`
|
|
1037
|
+
* tunable such as Lighter `ACCOUNT_TYPE` or Hyperliquid `ACCOUNT_MODE`)
|
|
1038
|
+
* end-to-end, throwing on a venue rejection.
|
|
1047
1039
|
*
|
|
1048
|
-
*
|
|
1049
|
-
* trades, but unlike a trade
|
|
1050
|
-
*
|
|
1051
|
-
*
|
|
1052
|
-
*
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
1055
|
-
*
|
|
1056
|
-
*
|
|
1040
|
+
* Options are dispatched through the same {@link execute} pipeline as
|
|
1041
|
+
* trades, but unlike a trade an option change is a single mandatory action:
|
|
1042
|
+
* a per-action `success: false` (returned as a 200 OK) means the user's
|
|
1043
|
+
* selection was rejected and must surface, not be silently dropped. This
|
|
1044
|
+
* wrapper inspects the result and throws a {@link PerpsError} carrying the
|
|
1045
|
+
* venue `error`, giving options the same throw contract that setup has via
|
|
1046
|
+
* {@link executeProviderSetupAction}. The only structural difference is that
|
|
1047
|
+
* an option carries `params` (the selected value) rather than a pre-staged
|
|
1048
|
+
* step.
|
|
1057
1049
|
*
|
|
1058
1050
|
* `execute` itself is unchanged — it still returns results without throwing,
|
|
1059
1051
|
* which the trade hooks rely on for partial-fill handling.
|
package/src/index.ts
CHANGED
|
@@ -19,7 +19,11 @@ export { PerpsClient } from './client/PerpsClient.js'
|
|
|
19
19
|
export { PerpsErrorMessage } from './errors/constants.js'
|
|
20
20
|
export { PerpsError } from './errors/PerpsError.js'
|
|
21
21
|
// Registries
|
|
22
|
-
export {
|
|
22
|
+
export {
|
|
23
|
+
AssetRegistry,
|
|
24
|
+
getAssetRegistry,
|
|
25
|
+
toAssetDisplay,
|
|
26
|
+
} from './registry/assetRegistry.js'
|
|
23
27
|
export type { DefaultMarketProvider } from './registry/marketRegistry.js'
|
|
24
28
|
export {
|
|
25
29
|
DEFAULT_MARKET_ID,
|
|
@@ -152,6 +156,7 @@ export type {
|
|
|
152
156
|
ProviderAccountExistsParams,
|
|
153
157
|
ProviderGetAccountParams,
|
|
154
158
|
ProviderGetActivityParams,
|
|
159
|
+
ProviderGetAvailableToTradeParams,
|
|
155
160
|
ProviderGetDepositFlowParams,
|
|
156
161
|
ProviderGetFillsParams,
|
|
157
162
|
ProviderGetMarketSettingsParams,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Asset, AssetsResponse } from '@lifi/perps-types'
|
|
1
|
+
import type { Asset, AssetDisplay, AssetsResponse } from '@lifi/perps-types'
|
|
2
2
|
import { PerpsErrorCode } from '@lifi/perps-types'
|
|
3
3
|
import { PerpsError } from '../errors/PerpsError.js'
|
|
4
4
|
import { buildUrl, request } from '../transport/request.js'
|
|
@@ -59,6 +59,21 @@ export class AssetRegistry extends ReferenceDataRegistry<Asset> {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Project an {@link Asset} to the identity and labels a display needs.
|
|
64
|
+
*
|
|
65
|
+
* @public
|
|
66
|
+
*/
|
|
67
|
+
export const toAssetDisplay = (asset: Asset): AssetDisplay => ({
|
|
68
|
+
providerId: asset.providerId,
|
|
69
|
+
id: asset.id,
|
|
70
|
+
displaySymbol: asset.displaySymbol,
|
|
71
|
+
logoURI: asset.logoURI,
|
|
72
|
+
...(asset.displayName === undefined
|
|
73
|
+
? {}
|
|
74
|
+
: { displayName: asset.displayName }),
|
|
75
|
+
})
|
|
76
|
+
|
|
62
77
|
const registries = new WeakMap<PerpsSDKClient, Map<string, AssetRegistry>>()
|
|
63
78
|
|
|
64
79
|
/**
|
package/src/types/api.ts
CHANGED
|
@@ -15,7 +15,7 @@ import type {
|
|
|
15
15
|
OrderSide,
|
|
16
16
|
OrderType,
|
|
17
17
|
PortfolioHistoryRange,
|
|
18
|
-
|
|
18
|
+
ProviderAction,
|
|
19
19
|
SignedActionStep,
|
|
20
20
|
TimeInForce,
|
|
21
21
|
TriggerOrderInput,
|
|
@@ -318,7 +318,7 @@ export interface GetPortfolioHistoryParams {
|
|
|
318
318
|
*/
|
|
319
319
|
export interface SetupChecklistItem {
|
|
320
320
|
/** The `Provider.setup` descriptor for this step. */
|
|
321
|
-
descriptor:
|
|
321
|
+
descriptor: ProviderAction
|
|
322
322
|
/** Whether the step is already satisfied for this account. */
|
|
323
323
|
satisfied: boolean
|
|
324
324
|
}
|
|
@@ -331,10 +331,8 @@ export interface SetupChecklistItem {
|
|
|
331
331
|
* to the provider's `setup` descriptor, which declares the step's signer and
|
|
332
332
|
* scheme), so no signer-role partition is exposed here.
|
|
333
333
|
*
|
|
334
|
-
* `
|
|
335
|
-
*
|
|
336
|
-
* does not gate trading, and the user re-enters it through
|
|
337
|
-
* `PerpsClient.executeProviderOption`.
|
|
334
|
+
* `Provider.options` items are NEVER included here — they don't gate trading
|
|
335
|
+
* and are surfaced separately via `getAccount().settings`.
|
|
338
336
|
*
|
|
339
337
|
* @public
|
|
340
338
|
*/
|
|
@@ -351,9 +349,9 @@ export interface ProviderSetup {
|
|
|
351
349
|
/** Whether all setup items are already satisfied (ready to trade) */
|
|
352
350
|
isReady: boolean
|
|
353
351
|
/**
|
|
354
|
-
* The renderable onboarding list: every
|
|
355
|
-
*
|
|
356
|
-
*
|
|
352
|
+
* The renderable onboarding list: every USER-signed setup descriptor with
|
|
353
|
+
* its satisfied state, ordered by `sequence`. SDK-internal steps and
|
|
354
|
+
* conditional steps that staged no work for this account (see
|
|
357
355
|
* `PerpsProviderPlugin.conditionalSetupActions`) are omitted. Consumers
|
|
358
356
|
* render this list directly instead of joining `Provider.setup` metadata
|
|
359
357
|
* with the staged `setup` steps.
|
|
@@ -385,14 +383,14 @@ export interface ExecuteProviderSetupResult {
|
|
|
385
383
|
* backend's `AccountResponse` with a single SDK-projected `settings` array.
|
|
386
384
|
*
|
|
387
385
|
* `settings` contains exactly one `AccountConfigSetting` per descriptor on
|
|
388
|
-
* `Provider.setup
|
|
389
|
-
* `setting.type === descriptor.type` and read
|
|
390
|
-
* each `Param` the descriptor declared.
|
|
386
|
+
* `Provider.setup` + `Provider.options` (in that order). Index the
|
|
387
|
+
* projection by `setting.type === descriptor.type` and read
|
|
388
|
+
* `setting.values[i].value` for each `Param` the descriptor declared.
|
|
391
389
|
*
|
|
392
390
|
* @public
|
|
393
391
|
*/
|
|
394
392
|
export interface GetAccountResult extends AccountResponse {
|
|
395
|
-
/** SDK-projected current state of every
|
|
393
|
+
/** SDK-projected current state of every setup + options descriptor. */
|
|
396
394
|
settings: AccountConfigSetting[]
|
|
397
395
|
}
|
|
398
396
|
|
package/src/types/provider.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
ActionType,
|
|
9
9
|
ActivitiesResponse,
|
|
10
10
|
ActivityType,
|
|
11
|
+
AvailableToTrade,
|
|
11
12
|
FillsResponse,
|
|
12
13
|
Market,
|
|
13
14
|
MarketRef,
|
|
@@ -22,9 +23,9 @@ import type {
|
|
|
22
23
|
Position,
|
|
23
24
|
PositionMarginConstraints,
|
|
24
25
|
PositionsResponse,
|
|
26
|
+
ProviderAction,
|
|
25
27
|
Quote,
|
|
26
28
|
QuoteSide,
|
|
27
|
-
SetupAction,
|
|
28
29
|
SignedActionStep,
|
|
29
30
|
SigningMethod,
|
|
30
31
|
TradeType,
|
|
@@ -216,6 +217,17 @@ export interface ProviderGetMarketSettingsParams {
|
|
|
216
217
|
market: MarketRef
|
|
217
218
|
}
|
|
218
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Read params for {@link PerpsProviderPlugin.getAvailableToTrade}.
|
|
222
|
+
*
|
|
223
|
+
* @public
|
|
224
|
+
*/
|
|
225
|
+
export interface ProviderGetAvailableToTradeParams {
|
|
226
|
+
address: Address
|
|
227
|
+
/** The market's opaque `Market.id` (not a display symbol). */
|
|
228
|
+
marketId: string
|
|
229
|
+
}
|
|
230
|
+
|
|
219
231
|
/**
|
|
220
232
|
* Read params for {@link PerpsProvider.getOrders}.
|
|
221
233
|
*
|
|
@@ -349,6 +361,17 @@ export interface PerpsProviderPlugin {
|
|
|
349
361
|
*/
|
|
350
362
|
readonly type: string
|
|
351
363
|
|
|
364
|
+
/**
|
|
365
|
+
* Setup actions the provider completes on its own, without surfacing a card
|
|
366
|
+
* to the caller. `PerpsClient.checkSetup` drains each such pending step in
|
|
367
|
+
* place — building, signing, and executing it with the provider's own
|
|
368
|
+
* credentials — and omits it from the returned `setup` list. A descriptor
|
|
369
|
+
* whose `signers` include {@link PerpsSigner.USER} is never treated as
|
|
370
|
+
* internal, even when named here. Omit when the provider has no
|
|
371
|
+
* self-completed setup steps.
|
|
372
|
+
*/
|
|
373
|
+
readonly internalSetupActions?: readonly ActionType[]
|
|
374
|
+
|
|
352
375
|
/**
|
|
353
376
|
* Setup actions that stage work only when the account needs remediation
|
|
354
377
|
* (e.g. Hyperliquid's REVOKE_AGENT frees an agent slot only when every
|
|
@@ -431,6 +454,19 @@ export interface PerpsProviderPlugin {
|
|
|
431
454
|
options?: SDKRequestOptions
|
|
432
455
|
): Promise<MarketSettings | undefined>
|
|
433
456
|
|
|
457
|
+
/**
|
|
458
|
+
* The amounts the account can still buy and sell on one market, in that
|
|
459
|
+
* market's margin asset. Optional because venues expose this unevenly:
|
|
460
|
+
* Hyperliquid reads it directly (`activeAssetData`), other venues publish
|
|
461
|
+
* only an account-scoped figure. `undefined` means the venue has nothing
|
|
462
|
+
* to read for this market, and the caller falls back to the account
|
|
463
|
+
* summary.
|
|
464
|
+
*/
|
|
465
|
+
getAvailableToTrade?(
|
|
466
|
+
params: ProviderGetAvailableToTradeParams,
|
|
467
|
+
options?: SDKRequestOptions
|
|
468
|
+
): Promise<AvailableToTrade | undefined>
|
|
469
|
+
|
|
434
470
|
getOrders(
|
|
435
471
|
params: ProviderGetOrdersParams,
|
|
436
472
|
options?: SDKRequestOptions
|
|
@@ -540,11 +576,9 @@ export interface PerpsProviderPlugin {
|
|
|
540
576
|
|
|
541
577
|
/**
|
|
542
578
|
* Project a typed {@link AccountConfig} against the provider's `setup`
|
|
543
|
-
* descriptors into `AccountConfigSetting[]`. Used by
|
|
579
|
+
* + `options` descriptors into `AccountConfigSetting[]`. Used by
|
|
544
580
|
* `PerpsClient.getAccount` to attach a `settings` array to the response —
|
|
545
|
-
* one entry per descriptor, in `setup` order.
|
|
546
|
-
* carries a boolean `satisfied`, because `PerpsClient.checkSetup` reads a
|
|
547
|
-
* preference's satisfied state from this projection alone.
|
|
581
|
+
* one entry per descriptor, in `setup`-then-`options` order.
|
|
548
582
|
*
|
|
549
583
|
* Implementations receive the union-typed `AccountConfig` and narrow on
|
|
550
584
|
* `config.provider` themselves; the dispatcher in `PerpsClient` does not
|
|
@@ -552,7 +586,8 @@ export interface PerpsProviderPlugin {
|
|
|
552
586
|
*/
|
|
553
587
|
projectConfig(
|
|
554
588
|
config: AccountConfig,
|
|
555
|
-
setup:
|
|
589
|
+
setup: ProviderAction[],
|
|
590
|
+
options: ProviderAction[]
|
|
556
591
|
): AccountConfigSetting[]
|
|
557
592
|
|
|
558
593
|
/**
|
package/src/version.ts
CHANGED