@pear-protocol/exchanges-sdk 0.18.0 → 0.19.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 CHANGED
@@ -416,3 +416,46 @@ Credentials and the trade account are fetched automatically on `connect`; Hyperl
416
416
  Pear returns the public trader identity only while its owner enables `sharingEnabled` in
417
417
  trade account settings. Disabling it hides future Pear reads; the exchange public APIs
418
418
  remain address-based and independent of Pear consent.
419
+
420
+ ## Hyperliquid subaccount funding
421
+
422
+ ```typescript
423
+ import { createHyperliquidHelper } from '@pear-protocol/exchanges-sdk';
424
+
425
+ const helper = createHyperliquidHelper();
426
+ await helper.transferSubAccount(ownerWallet, {
427
+ subAccountAddress: '0x...',
428
+ direction: 'main-to-subaccount', // use 'subaccount-to-main' to return USDC
429
+ amount: '1.25',
430
+ });
431
+ ```
432
+
433
+ Supply the owning main account's wallet (a viem wallet client/account or an ethers signer) in both
434
+ directions. Every transfer uses owner-signed `sendAsset` with `sourceDex: "spot"` and
435
+ `destinationDex: "spot"`. An approved API agent cannot sign this action. Browser wallet clients use
436
+ their connected chain for EIP-712 signing.
437
+
438
+ For standard accounts, this moves the separate spot USDC balance and does not fund perpetual
439
+ collateral. Unified and portfolio-margin accounts use their shared spot balance. The helper checks
440
+ subaccount ownership before signing. It does not read or change either account's mode.
441
+
442
+ A newly created standard subaccount receives USDC in spot and cannot use that balance as perpetual
443
+ margin. Before trading perps, make a separate owner-signed
444
+ [`usdClassTransfer`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#transfer-from-spot-account-to-perp-account-and-vice-versa)
445
+ with `toPerp: true` and `subaccount:<address>` appended to the amount. The funding helper does not
446
+ submit this second action. A standard main account with USDC in perps must first move the intended
447
+ amount to spot before calling this helper.
448
+
449
+ The helper uses a fixed USDC token ID for the selected network without a metadata lookup, and the
450
+ amount stays an exact decimal string. Each successful transfer makes two information reads: the
451
+ signer's role and the subaccount's role and ownership. It then submits one transfer action.
452
+
453
+ Amounts must be positive decimal strings with at most six fractional digits and must fit the
454
+ existing safe integer micro-USDC limit (`9007199254.740991` USDC). The helper never rounds an amount.
455
+
456
+ Failures reach the caller without retries or fallback actions. After a timeout or connection loss,
457
+ check transfer history and balances before making another call; submission may have succeeded.
458
+
459
+ The routing and signing follow Hyperliquid's [Send Asset API](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#send-asset),
460
+ [account modes](https://hyperliquid.gitbook.io/hyperliquid-docs/trading/account-abstraction-modes),
461
+ and [official signing implementation](https://github.com/hyperliquid-dex/hyperliquid-python-sdk/blob/master/hyperliquid/utils/signing.py).
@@ -1,10 +1,16 @@
1
1
  import { HttpTransport } from '@nktkas/hyperliquid';
2
- import { subAccountTransfer, createSubAccount } from '@nktkas/hyperliquid/api/exchange';
2
+ import { sendAsset, createSubAccount } from '@nktkas/hyperliquid/api/exchange';
3
+ import { getWalletAddress } from '@nktkas/hyperliquid/signing';
4
+ import { formatUnits } from 'viem';
3
5
  import { fetchInfo, fetchUserRole } from '../../client/hyperliquid/rest';
4
6
  import { parseCollateralAmount } from '../subaccount.helper';
5
7
 
6
8
  var __defProp = Object.defineProperty;
7
9
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
10
+ const USDC_TOKENS = {
11
+ mainnet: "USDC:0x6d1e7cde53ba9467b783cb7c530ce054",
12
+ testnet: "USDC:0xeb62eee3685fc4c43992febcd9e75443"
13
+ };
8
14
  function createHyperliquidHelper(demo = false) {
9
15
  return {
10
16
  /**
@@ -33,19 +39,35 @@ function createHyperliquidHelper(demo = false) {
33
39
  subAccountAddress: response.response.data
34
40
  };
35
41
  },
36
- /** Moves perpetual USDC between a main account and one of its subaccounts. */
42
+ /** Moves spot USDC between owned accounts using the owning main wallet. */
37
43
  async transferSubAccount(wallet, params) {
38
44
  const usd = parseCollateralAmount(params.amount, "USDC");
45
+ const ownerAddress = await getWalletAddress(wallet);
46
+ const signerRole = await fetchUserRole(ownerAddress, demo);
47
+ if (signerRole.role === "agent") {
48
+ throw new Error("Spot subaccount transfers require the owner wallet; an approved agent cannot sign");
49
+ }
50
+ if (signerRole.role !== "user") {
51
+ throw new Error("Spot subaccount transfers require the owner wallet");
52
+ }
53
+ const subAccountRole = await fetchUserRole(params.subAccountAddress, demo);
54
+ if (subAccountRole.role !== "subAccount" || subAccountRole.data.master.toLowerCase() !== ownerAddress.toLowerCase()) {
55
+ throw new Error("Subaccount does not belong to the signing main account");
56
+ }
57
+ const isDeposit = isMainToSubAccount(params.direction);
39
58
  const transport = new HttpTransport({
40
59
  isTestnet: demo
41
60
  });
42
- await subAccountTransfer({
61
+ await sendAsset({
43
62
  transport,
44
63
  wallet
45
64
  }, {
46
- subAccountUser: params.subAccountAddress,
47
- isDeposit: isMainToSubAccount(params.direction),
48
- usd
65
+ destination: isDeposit ? params.subAccountAddress : ownerAddress,
66
+ sourceDex: "spot",
67
+ destinationDex: "spot",
68
+ token: demo ? USDC_TOKENS.testnet : USDC_TOKENS.mainnet,
69
+ amount: formatUnits(BigInt(usd), 6),
70
+ fromSubAccount: isDeposit ? "" : params.subAccountAddress
49
71
  });
50
72
  },
51
73
  /** Lists a main account's existing subaccounts for transfer-destination selection. */
package/dist/index.d.ts CHANGED
@@ -429,6 +429,7 @@ type SubAccountTransferDirection = 'main-to-subaccount' | 'subaccount-to-main';
429
429
  interface HyperliquidHelper {
430
430
  checkAccountActivation(userAddress: `0x${string}`): Promise<boolean>;
431
431
  createSubAccount(wallet: AbstractWallet, params: CreateHyperliquidSubAccountParams): Promise<CreateHyperliquidSubAccountResult>;
432
+ /** Transfers spot USDC in either direction; requires the owning main wallet, never an agent. */
432
433
  transferSubAccount(wallet: AbstractWallet, params: HyperliquidSubAccountTransferParams): Promise<void>;
433
434
  listSubAccounts(userAddress: `0x${string}`): Promise<HyperliquidSubAccountSummary[]>;
434
435
  checkApiWallet(params: CheckApiWalletParams): Promise<boolean>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/exchanges-sdk",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "Pear Protocol Exchanges SDK",
5
5
  "private": false,
6
6
  "type": "module",
@@ -28,8 +28,8 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@nktkas/hyperliquid": "0.33.2",
31
- "@pear-protocol/core-sdk": "^2.5.0",
32
- "@pear-protocol/types": "^2.12.0",
31
+ "@pear-protocol/core-sdk": "^2.8.0",
32
+ "@pear-protocol/types": "^2.15.0",
33
33
  "@pear-protocol/utils": "^1.3.0",
34
34
  "bignumber.js": "^11.1.1",
35
35
  "partysocket": "^1.0.3",