@pear-protocol/exchanges-sdk 0.17.0 → 0.18.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.
- package/README.md +30 -0
- package/dist/client/lighter/rest.js +12 -1
- package/dist/helper/hyperliquid/helper.js +64 -3
- package/dist/helper/index.js +2 -0
- package/dist/helper/lighter/helper.js +39 -15
- package/dist/helper/lighter/subaccount.helper.js +118 -0
- package/dist/helper/subaccount.types.js +1 -0
- package/dist/index.d.ts +269 -49
- package/dist/sdk.js +28 -6
- package/dist/status/hyperliquid/status.js +3 -3
- package/dist/syncer/base.js +1 -21
- package/dist/syncer/hyperliquid/syncer.js +2 -1
- package/dist/syncer/lighter/syncer.js +4 -4
- package/dist/tracker/base.js +4 -0
- package/dist/tracker/equity.js +13 -0
- package/dist/tracker/hyperliquid/balance.js +29 -5
- package/dist/tracker/hyperliquid/decimal.js +5 -1
- package/dist/tracker/hyperliquid/mapper.js +69 -1
- package/dist/tracker/hyperliquid/tracker.js +52 -24
- package/dist/tracker/index.js +24 -1
- package/dist/tracker/lighter/mapper.js +20 -1
- package/dist/tracker/lighter/tracker.js +29 -14
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
Unified SDK for account state (balance, positions, per-asset leverage) across supported derivative exchanges — as a live WebSocket subscription or a stateless one-shot snapshot.
|
|
4
4
|
|
|
5
|
+
## Public trading equity
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
const trader = await sdk.core.traders.public(tradeAccountId);
|
|
9
|
+
const equity = await exchanges.tradingEquity(trader);
|
|
10
|
+
console.log(equity.tradingEquityUsd, equity.timestamp);
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Pass the returned public identity directly; only `connector` and `exchangeIdentifier` are used.
|
|
14
|
+
This read supports Hyperliquid, Lighter, and Lighter RHC without credentials or starting a stream.
|
|
15
|
+
It includes unrealized PnL and spot holdings, excludes staking and vault deposits, and rejects
|
|
16
|
+
failed reads or unpriceable holdings. Equity refreshes do not reload the public trader resources.
|
|
17
|
+
|
|
18
|
+
The same public identity can create a tracker for explicit REST snapshots:
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
const tracker = exchanges.createTracker(trader, { access: 'public' });
|
|
22
|
+
const snapshot = await tracker.snapshot();
|
|
23
|
+
const equity = await tracker.tradingEquity();
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Public Lighter trackers support REST reads only. Private account streams and tier reads still
|
|
27
|
+
require an authenticated connection. Existing `createTracker(connection)` calls keep their behavior.
|
|
28
|
+
|
|
5
29
|
## Supported Exchanges
|
|
6
30
|
|
|
7
31
|
| Exchange | Connector | Market |
|
|
@@ -279,6 +303,8 @@ tracker.trackBalance((balance) => {
|
|
|
279
303
|
|
|
280
304
|
On the three venues whose pools are separate *and* whose account-level figures cover one currency only — Binance single-asset, OKX Spot and OKX Futures — the core scalars carry the venue's own figure when exactly one pool holds a non-zero balance, and `null` once two or more do. They are never summed across pools. Hyperliquid splits by mode: Standard and Unified report `poolsShared: false` with one row per collateral token, while Portfolio Margin reports `true` — it lends against every holding at that coin's LTV, so the rows are holdings in one pool. All three keep their scalars in every case: `availableMargin` is already a per-asset floor.
|
|
281
305
|
|
|
306
|
+
**Hyperliquid also lists the whole spot wallet.** Every Hyperliquid variant carries `spotHoldings`: one row per coin the venue lists, in every mode, including coins no perp dex settles in (which `perCollateral` leaves out in Standard and Unified). A row carries `asset`, `token`, and the venue's signed `total`, `hold` and `entryNotional`. `entryNotional` is what the holding cost, not what it is worth, and is `null` when the venue sends none. Rows are never priced: value the wallet with the variant's equity scalar.
|
|
307
|
+
|
|
282
308
|
#### Narrowing on `accountMode`
|
|
283
309
|
|
|
284
310
|
Fields beyond the core belong to a variant. Switch on the tag to reach them, and write no `default:` clause — then a mode added in a later release fails the build here instead of silently returning `undefined`.
|
|
@@ -386,3 +412,7 @@ await tracker.disconnect(); // closes the WebSocket opened by start()
|
|
|
386
412
|
```
|
|
387
413
|
|
|
388
414
|
Credentials and the trade account are fetched automatically on `connect`; Hyperliquid and Lighter account identifiers come from `connection.account.exchangeIdentifier`.
|
|
415
|
+
|
|
416
|
+
Pear returns the public trader identity only while its owner enables `sharingEnabled` in
|
|
417
|
+
trade account settings. Disabling it hides future Pear reads; the exchange public APIs
|
|
418
|
+
remain address-based and independent of Pear consent.
|
|
@@ -221,6 +221,17 @@ async function fetchAccountMetadata(accountIndex, authToken, connector, demo = f
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
__name(fetchAccountMetadata, "fetchAccountMetadata");
|
|
224
|
+
async function fetchAccountMetadataByL1Address(l1Address, authToken, demo = false, connector = "lighter") {
|
|
225
|
+
const response = await proxyFetch(`${getLighterBaseUrl(connector, demo)}/api/v1/accountMetadata?by=l1_address&value=${encodeURIComponent(l1Address)}`, {
|
|
226
|
+
headers: {
|
|
227
|
+
accept: "application/json",
|
|
228
|
+
authorization: authToken
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
const data = await readLighterResponse(response, "/accountMetadata");
|
|
232
|
+
return data.account_metadatas ?? [];
|
|
233
|
+
}
|
|
234
|
+
__name(fetchAccountMetadataByL1Address, "fetchAccountMetadataByL1Address");
|
|
224
235
|
async function fetchOrderBookDetails(authToken, connector, demo = false) {
|
|
225
236
|
const response = await authenticatedLighterFetch(`${getLighterBaseUrl(connector, demo)}/api/v1/orderBookDetails`, authToken);
|
|
226
237
|
const data = await readLighterResponse(response, "/orderBookDetails");
|
|
@@ -525,4 +536,4 @@ function readReferralAmount(value) {
|
|
|
525
536
|
}
|
|
526
537
|
__name(readReferralAmount, "readReferralAmount");
|
|
527
538
|
|
|
528
|
-
export { LighterRequestError, createDepositIntentAddress, fetchAccount, fetchAccountLimits, fetchAccountMetadata, fetchAccountsByL1Address, fetchApiKeys, fetchAssetDetails, fetchDepositHistory, fetchDepositNetworks, fetchOrderBookDetails, fetchPositionFundingSince, fetchPublicAccount, fetchPublicOrderBookDetails, fetchTradesSince, fetchUserReferrals, fetchWithdrawHistory, submitReferralCode };
|
|
539
|
+
export { LighterRequestError, createDepositIntentAddress, fetchAccount, fetchAccountLimits, fetchAccountMetadata, fetchAccountMetadataByL1Address, fetchAccountsByL1Address, fetchApiKeys, fetchAssetDetails, fetchDepositHistory, fetchDepositNetworks, fetchOrderBookDetails, fetchPositionFundingSince, fetchPublicAccount, fetchPublicOrderBookDetails, fetchTradesSince, fetchUserReferrals, fetchWithdrawHistory, submitReferralCode };
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { HttpTransport } from '@nktkas/hyperliquid';
|
|
2
|
+
import { subAccountTransfer, createSubAccount } from '@nktkas/hyperliquid/api/exchange';
|
|
1
3
|
import { fetchInfo, fetchUserRole } from '../../client/hyperliquid/rest';
|
|
4
|
+
import { parseCollateralAmount } from '../subaccount.helper';
|
|
2
5
|
|
|
3
6
|
var __defProp = Object.defineProperty;
|
|
4
7
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
@@ -14,14 +17,63 @@ function createHyperliquidHelper(demo = false) {
|
|
|
14
17
|
const role = await fetchUserRole(userAddress, demo);
|
|
15
18
|
return role.role !== "missing";
|
|
16
19
|
},
|
|
17
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Creates a named subaccount under the signer's main account. This is an L1 action pinned to
|
|
22
|
+
* chainId 1337, which browser wallets reject, so the signer is normally the approved agent key.
|
|
23
|
+
*/
|
|
24
|
+
async createSubAccount(wallet, params) {
|
|
25
|
+
const transport = new HttpTransport({
|
|
26
|
+
isTestnet: demo
|
|
27
|
+
});
|
|
28
|
+
const response = await createSubAccount({
|
|
29
|
+
transport,
|
|
30
|
+
wallet
|
|
31
|
+
}, params);
|
|
32
|
+
return {
|
|
33
|
+
subAccountAddress: response.response.data
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
/** Moves perpetual USDC between a main account and one of its subaccounts. */
|
|
37
|
+
async transferSubAccount(wallet, params) {
|
|
38
|
+
const usd = parseCollateralAmount(params.amount, "USDC");
|
|
39
|
+
const transport = new HttpTransport({
|
|
40
|
+
isTestnet: demo
|
|
41
|
+
});
|
|
42
|
+
await subAccountTransfer({
|
|
43
|
+
transport,
|
|
44
|
+
wallet
|
|
45
|
+
}, {
|
|
46
|
+
subAccountUser: params.subAccountAddress,
|
|
47
|
+
isDeposit: isMainToSubAccount(params.direction),
|
|
48
|
+
usd
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
/** Lists a main account's existing subaccounts for transfer-destination selection. */
|
|
52
|
+
async listSubAccounts(userAddress) {
|
|
53
|
+
const subAccounts = await fetchInfo({
|
|
54
|
+
type: "subAccounts",
|
|
55
|
+
user: userAddress
|
|
56
|
+
}, demo);
|
|
57
|
+
return (subAccounts ?? []).map((subAccount) => ({
|
|
58
|
+
name: subAccount.name,
|
|
59
|
+
subAccountUser: subAccount.subAccountUser
|
|
60
|
+
}));
|
|
61
|
+
},
|
|
62
|
+
/** Checks ownership and expiry for named and unnamed API wallets. */
|
|
18
63
|
async checkApiWallet(params) {
|
|
19
64
|
const agents = await fetchInfo({
|
|
20
65
|
type: "extraAgents",
|
|
21
66
|
user: params.userAddress
|
|
22
67
|
}, demo);
|
|
23
|
-
const
|
|
24
|
-
|
|
68
|
+
const matchingAgent = agents.find((candidate) => candidate.address.toLowerCase() === params.agentWalletAddress.toLowerCase());
|
|
69
|
+
if (matchingAgent) {
|
|
70
|
+
return matchingAgent.validUntil === null || matchingAgent.validUntil > Date.now();
|
|
71
|
+
}
|
|
72
|
+
const { userState } = await fetchInfo({
|
|
73
|
+
type: "webData3",
|
|
74
|
+
user: params.userAddress
|
|
75
|
+
}, demo);
|
|
76
|
+
return userState.agentAddress?.toLowerCase() === params.agentWalletAddress.toLowerCase() && (userState.agentValidUntil === null || userState.agentValidUntil > Date.now());
|
|
25
77
|
},
|
|
26
78
|
/** Checks that the approval covers the exact builder fee requested by orders. */
|
|
27
79
|
async checkBuilderFeeApproval(userAddress, builderAddress, requiredFeeTenthsBps) {
|
|
@@ -39,5 +91,14 @@ function createHyperliquidHelper(demo = false) {
|
|
|
39
91
|
};
|
|
40
92
|
}
|
|
41
93
|
__name(createHyperliquidHelper, "createHyperliquidHelper");
|
|
94
|
+
function isMainToSubAccount(direction) {
|
|
95
|
+
switch (direction) {
|
|
96
|
+
case "main-to-subaccount":
|
|
97
|
+
return true;
|
|
98
|
+
case "subaccount-to-main":
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
__name(isMainToSubAccount, "isMainToSubAccount");
|
|
42
103
|
|
|
43
104
|
export { createHyperliquidHelper };
|
package/dist/helper/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isAddress, parseUnits } from 'viem';
|
|
2
|
-
import { fetchApiKeys, fetchAccount, fetchPublicAccount,
|
|
2
|
+
import { fetchApiKeys, fetchAccount, fetchPublicAccount, fetchAccountMetadataByL1Address } from '../../client/lighter/rest';
|
|
3
3
|
import { LIGHTER_QUOTE_ASSETS } from '../../tracker/lighter/const';
|
|
4
4
|
import { parseCollateralAmount } from '../subaccount.helper';
|
|
5
5
|
import { resolveAssetDecimals } from './asset-decimals.helper';
|
|
@@ -8,9 +8,10 @@ import { createDepositAddressForRoute, depositThroughRoute } from './deposit.hel
|
|
|
8
8
|
import { writeWithdraw } from './ethereum';
|
|
9
9
|
import { readWithdrawHistory, readDepositHistory } from './history.helper';
|
|
10
10
|
import { selectLighterMiscRoutes } from './misc-routes.helper';
|
|
11
|
-
import {
|
|
11
|
+
import { readOnboardingStatus } from './onboarding.helper';
|
|
12
12
|
import { readUserReferrals, applyReferralCode } from './referral.helper';
|
|
13
13
|
import { depositUsdgOnRobinhoodChain, createRhcDepositAddress } from './rhc-deposit.helper';
|
|
14
|
+
import { lookupLighterAccount, transferLighterSubAccount, setLighterSubAccountMetadata, createNamedLighterSubAccount, createLighterSubAccount } from './subaccount.helper';
|
|
14
15
|
import { MIN_LIGHTER_FAST_WITHDRAW_COLLATERAL } from './types';
|
|
15
16
|
|
|
16
17
|
var __defProp = Object.defineProperty;
|
|
@@ -84,6 +85,40 @@ function buildSharedLighterHelper(sdk, connector, demo) {
|
|
|
84
85
|
const collateralSymbol = LIGHTER_QUOTE_ASSETS[connector];
|
|
85
86
|
const minFastWithdraw = MIN_LIGHTER_FAST_WITHDRAW_COLLATERAL[connector];
|
|
86
87
|
return {
|
|
88
|
+
/** Fetches full account metadata across an L1 address's account family, keyed by account index. */
|
|
89
|
+
async fetchAccountMetadata(params) {
|
|
90
|
+
if (demo) {
|
|
91
|
+
throw new Error("Lighter demo account metadata is unavailable because backend signing is mainnet-only");
|
|
92
|
+
}
|
|
93
|
+
const { token } = await misc.createAuthToken({
|
|
94
|
+
accountIndex: params.accountIndex,
|
|
95
|
+
apiKeyIndex: params.apiKeyIndex,
|
|
96
|
+
apiPrivateKey: params.apiPrivateKey
|
|
97
|
+
});
|
|
98
|
+
const metadatas = await fetchAccountMetadataByL1Address(params.l1Address, token, demo, connector);
|
|
99
|
+
return {
|
|
100
|
+
accounts: Object.fromEntries(metadatas.map((metadata) => [
|
|
101
|
+
metadata.account_index,
|
|
102
|
+
metadata
|
|
103
|
+
]))
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
/** Creates a Lighter subaccount from the main account's API credentials. */
|
|
107
|
+
async createSubAccount(params) {
|
|
108
|
+
return createLighterSubAccount(sdk, params, connector, demo);
|
|
109
|
+
},
|
|
110
|
+
/** Creates, discovers, and names a Lighter subaccount before reporting completion. */
|
|
111
|
+
async createNamedSubAccount(params) {
|
|
112
|
+
return createNamedLighterSubAccount(sdk, params, connector, demo);
|
|
113
|
+
},
|
|
114
|
+
/** Sets a Lighter subaccount's display name and description. */
|
|
115
|
+
async setSubAccountMetadata(params) {
|
|
116
|
+
return setLighterSubAccountMetadata(sdk, params, connector, demo);
|
|
117
|
+
},
|
|
118
|
+
/** Moves perpetual collateral between a Lighter main account and one of its subaccounts. */
|
|
119
|
+
async transferSubAccount(params) {
|
|
120
|
+
return transferLighterSubAccount(sdk, params, connector, demo);
|
|
121
|
+
},
|
|
87
122
|
/** Reports whether an L1 address still needs its first deposit before it owns a Lighter account. */
|
|
88
123
|
async checkOnboarding(l1Address) {
|
|
89
124
|
if (!isAddress(l1Address)) {
|
|
@@ -91,20 +126,9 @@ function buildSharedLighterHelper(sdk, connector, demo) {
|
|
|
91
126
|
}
|
|
92
127
|
return readOnboardingStatus(l1Address, connector, demo);
|
|
93
128
|
},
|
|
129
|
+
/** Reads the selected deployment's account family. */
|
|
94
130
|
async lookupAccount(l1Address) {
|
|
95
|
-
|
|
96
|
-
if (data.code === LIGHTER_ACCOUNT_NOT_REGISTERED_CODE) {
|
|
97
|
-
throw new Error("Account not registered on Lighter");
|
|
98
|
-
}
|
|
99
|
-
const accounts = data.sub_accounts ?? [];
|
|
100
|
-
const main = accounts.find((s) => s.account_type === 0);
|
|
101
|
-
if (!main) {
|
|
102
|
-
throw new Error("Main account not found for this address");
|
|
103
|
-
}
|
|
104
|
-
return {
|
|
105
|
-
mainAccountIndex: main.index,
|
|
106
|
-
subAccountIndexes: accounts.filter((s) => s.account_type !== 0).map((s) => s.index)
|
|
107
|
-
};
|
|
131
|
+
return lookupLighterAccount(l1Address, connector, demo);
|
|
108
132
|
},
|
|
109
133
|
async checkIntegratorApproval(accountIndex, integratorAccountIndex, requirements, authToken) {
|
|
110
134
|
if (requirements) validateApprovalRequirements(requirements);
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { fetchAccountsByL1Address } from '../../client/lighter/rest';
|
|
2
|
+
import { LIGHTER_QUOTE_ASSETS } from '../../tracker/lighter/const';
|
|
3
|
+
import { parseCollateralAmount } from '../subaccount.helper';
|
|
4
|
+
import { selectLighterMiscRoutes } from './misc-routes.helper';
|
|
5
|
+
import { LIGHTER_ACCOUNT_NOT_REGISTERED_CODE } from './onboarding.helper';
|
|
6
|
+
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
const NEW_SUBACCOUNT_POLL_INTERVAL_MS = 1500;
|
|
10
|
+
const NEW_SUBACCOUNT_POLL_ATTEMPTS = 8;
|
|
11
|
+
async function createNamedLighterSubAccount(sdk, params, connector, demo) {
|
|
12
|
+
if (demo) {
|
|
13
|
+
throw new Error("Lighter demo subaccount creation is unavailable because backend signing is mainnet-only");
|
|
14
|
+
}
|
|
15
|
+
const family = await lookupLighterAccount(params.l1Address, connector, demo);
|
|
16
|
+
const knownIndexes = new Set(family.subAccountIndexes);
|
|
17
|
+
const result = await createLighterSubAccount(sdk, params, connector, demo);
|
|
18
|
+
const subAccountIndex = await resolveNewLighterSubAccountIndex(params.l1Address, knownIndexes, connector, demo);
|
|
19
|
+
await setLighterSubAccountMetadata(sdk, {
|
|
20
|
+
...params,
|
|
21
|
+
subAccountIndex
|
|
22
|
+
}, connector, demo);
|
|
23
|
+
return {
|
|
24
|
+
...result,
|
|
25
|
+
subAccountIndex
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
__name(createNamedLighterSubAccount, "createNamedLighterSubAccount");
|
|
29
|
+
async function createLighterSubAccount(sdk, params, connector, demo) {
|
|
30
|
+
if (demo) {
|
|
31
|
+
throw new Error("Lighter demo subaccount creation is unavailable because backend signing is mainnet-only");
|
|
32
|
+
}
|
|
33
|
+
return selectLighterMiscRoutes(sdk, connector).createSubAccount({
|
|
34
|
+
accountIndex: params.mainAccountIndex,
|
|
35
|
+
apiKeyIndex: params.apiKeyIndex,
|
|
36
|
+
apiPrivateKey: params.apiPrivateKey
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
__name(createLighterSubAccount, "createLighterSubAccount");
|
|
40
|
+
async function setLighterSubAccountMetadata(sdk, params, connector, demo) {
|
|
41
|
+
if (demo) {
|
|
42
|
+
throw new Error("Lighter demo subaccount metadata is unavailable because backend signing is mainnet-only");
|
|
43
|
+
}
|
|
44
|
+
await selectLighterMiscRoutes(sdk, connector).setSubAccountMetadata({
|
|
45
|
+
mainAccountIndex: params.mainAccountIndex,
|
|
46
|
+
subAccountIndex: params.subAccountIndex,
|
|
47
|
+
apiKeyIndex: params.apiKeyIndex,
|
|
48
|
+
apiPrivateKey: params.apiPrivateKey,
|
|
49
|
+
name: params.name,
|
|
50
|
+
description: params.description
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
__name(setLighterSubAccountMetadata, "setLighterSubAccountMetadata");
|
|
54
|
+
async function transferLighterSubAccount(sdk, params, connector, demo) {
|
|
55
|
+
if (demo) {
|
|
56
|
+
throw new Error("Lighter demo subaccount transfers are unavailable because backend signing is mainnet-only");
|
|
57
|
+
}
|
|
58
|
+
const accounts = resolveTransferAccounts(params.mainAccountIndex, params.subAccountIndex, params.direction);
|
|
59
|
+
const amount = parseCollateralAmount(params.amount, LIGHTER_QUOTE_ASSETS[connector]);
|
|
60
|
+
return selectLighterMiscRoutes(sdk, connector).transferSubAccount({
|
|
61
|
+
l1Address: params.l1Address,
|
|
62
|
+
fromAccountIndex: accounts.fromAccountIndex,
|
|
63
|
+
toAccountIndex: accounts.toAccountIndex,
|
|
64
|
+
amount,
|
|
65
|
+
apiKeyIndex: params.apiKeyIndex,
|
|
66
|
+
apiPrivateKey: params.apiPrivateKey
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
__name(transferLighterSubAccount, "transferLighterSubAccount");
|
|
70
|
+
async function lookupLighterAccount(l1Address, connector, demo) {
|
|
71
|
+
const data = await fetchAccountsByL1Address(l1Address, connector, demo);
|
|
72
|
+
if (data.code === LIGHTER_ACCOUNT_NOT_REGISTERED_CODE) {
|
|
73
|
+
throw new Error("Account not registered on Lighter");
|
|
74
|
+
}
|
|
75
|
+
const accounts = data.sub_accounts ?? [];
|
|
76
|
+
const main = accounts.find((account) => account.account_type === 0);
|
|
77
|
+
if (!main) {
|
|
78
|
+
throw new Error("Main account not found for this address");
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
mainAccountIndex: main.index,
|
|
82
|
+
subAccountIndexes: accounts.filter((account) => account.account_type === 1).map((account) => account.index)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
__name(lookupLighterAccount, "lookupLighterAccount");
|
|
86
|
+
function resolveTransferAccounts(mainAccountIndex, subAccountIndex, direction) {
|
|
87
|
+
switch (direction) {
|
|
88
|
+
case "main-to-subaccount":
|
|
89
|
+
return {
|
|
90
|
+
fromAccountIndex: mainAccountIndex,
|
|
91
|
+
toAccountIndex: subAccountIndex
|
|
92
|
+
};
|
|
93
|
+
case "subaccount-to-main":
|
|
94
|
+
return {
|
|
95
|
+
fromAccountIndex: subAccountIndex,
|
|
96
|
+
toAccountIndex: mainAccountIndex
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
__name(resolveTransferAccounts, "resolveTransferAccounts");
|
|
101
|
+
async function resolveNewLighterSubAccountIndex(l1Address, knownIndexes, connector, demo) {
|
|
102
|
+
for (let attempt = 0; attempt < NEW_SUBACCOUNT_POLL_ATTEMPTS; attempt += 1) {
|
|
103
|
+
const lookup = await lookupLighterAccount(l1Address, connector, demo);
|
|
104
|
+
const newIndexes = lookup.subAccountIndexes.filter((index) => !knownIndexes.has(index));
|
|
105
|
+
if (newIndexes.length > 1) {
|
|
106
|
+
throw new Error("Subaccount created, but multiple new accounts appeared. Refresh and set its name manually.");
|
|
107
|
+
}
|
|
108
|
+
const [newIndex] = newIndexes;
|
|
109
|
+
if (newIndex !== void 0) {
|
|
110
|
+
return newIndex;
|
|
111
|
+
}
|
|
112
|
+
await new Promise((resolve) => setTimeout(resolve, NEW_SUBACCOUNT_POLL_INTERVAL_MS));
|
|
113
|
+
}
|
|
114
|
+
throw new Error("Subaccount created, but its index is not visible yet. Refresh and set its name shortly.");
|
|
115
|
+
}
|
|
116
|
+
__name(resolveNewLighterSubAccountIndex, "resolveNewLighterSubAccountIndex");
|
|
117
|
+
|
|
118
|
+
export { createLighterSubAccount, createNamedLighterSubAccount, lookupLighterAccount, setLighterSubAccountMetadata, transferLighterSubAccount };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|