jaspervault_cli 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.
- package/README.md +138 -0
- package/config/chains.json +104 -0
- package/dist/bin/jv.d.ts +2 -0
- package/dist/bin/jv.js +29 -0
- package/dist/bin/jv.js.map +1 -0
- package/dist/src/client.d.ts +18 -0
- package/dist/src/client.js +128 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/commands/connect.d.ts +22 -0
- package/dist/src/commands/connect.js +128 -0
- package/dist/src/commands/connect.js.map +1 -0
- package/dist/src/commands/deposit.d.ts +59 -0
- package/dist/src/commands/deposit.js +261 -0
- package/dist/src/commands/deposit.js.map +1 -0
- package/dist/src/commands/init.d.ts +4 -0
- package/dist/src/commands/init.js +97 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/job.d.ts +2 -0
- package/dist/src/commands/job.js +20 -0
- package/dist/src/commands/job.js.map +1 -0
- package/dist/src/commands/limit-order.d.ts +2 -0
- package/dist/src/commands/limit-order.js +51 -0
- package/dist/src/commands/limit-order.js.map +1 -0
- package/dist/src/commands/order.d.ts +2 -0
- package/dist/src/commands/order.js +110 -0
- package/dist/src/commands/order.js.map +1 -0
- package/dist/src/commands/orders.d.ts +2 -0
- package/dist/src/commands/orders.js +72 -0
- package/dist/src/commands/orders.js.map +1 -0
- package/dist/src/commands/sl.d.ts +2 -0
- package/dist/src/commands/sl.js +67 -0
- package/dist/src/commands/sl.js.map +1 -0
- package/dist/src/commands/tp.d.ts +2 -0
- package/dist/src/commands/tp.js +67 -0
- package/dist/src/commands/tp.js.map +1 -0
- package/dist/src/commands/vault.d.ts +24 -0
- package/dist/src/commands/vault.js +249 -0
- package/dist/src/commands/vault.js.map +1 -0
- package/dist/src/services/chain-config.d.ts +57 -0
- package/dist/src/services/chain-config.js +96 -0
- package/dist/src/services/chain-config.js.map +1 -0
- package/dist/src/services/key-manager.d.ts +23 -0
- package/dist/src/services/key-manager.js +79 -0
- package/dist/src/services/key-manager.js.map +1 -0
- package/dist/src/services/order-signer.d.ts +24 -0
- package/dist/src/services/order-signer.js +162 -0
- package/dist/src/services/order-signer.js.map +1 -0
- package/dist/src/services/price-service.d.ts +14 -0
- package/dist/src/services/price-service.js +47 -0
- package/dist/src/services/price-service.js.map +1 -0
- package/dist/src/services/subgraph-client.d.ts +53 -0
- package/dist/src/services/subgraph-client.js +120 -0
- package/dist/src/services/subgraph-client.js.map +1 -0
- package/dist/src/services/vault-profile.d.ts +15 -0
- package/dist/src/services/vault-profile.js +56 -0
- package/dist/src/services/vault-profile.js.map +1 -0
- package/dist/src/templates/skill-body.d.ts +11 -0
- package/dist/src/templates/skill-body.js +233 -0
- package/dist/src/templates/skill-body.js.map +1 -0
- package/dist/src/types.d.ts +212 -0
- package/dist/src/types.js +3 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/config.d.ts +7 -0
- package/dist/src/utils/config.js +14 -0
- package/dist/src/utils/config.js.map +1 -0
- package/dist/src/utils/endpoints.d.ts +8 -0
- package/dist/src/utils/endpoints.js +13 -0
- package/dist/src/utils/endpoints.js.map +1 -0
- package/dist/src/utils/output.d.ts +14 -0
- package/dist/src/utils/output.js +50 -0
- package/dist/src/utils/output.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname = dirname(__filename);
|
|
6
|
+
/** Resolve path to chains.json relative to package root (cli/). */
|
|
7
|
+
const getConfigPath = () => {
|
|
8
|
+
// Dev (tsx): src/services/chain-config.ts -> ../../ = cli/
|
|
9
|
+
// Built: dist/src/services/chain-config.js -> ../../../ = cli/
|
|
10
|
+
const candidates = [
|
|
11
|
+
join(__dirname, '..', '..', 'config', 'chains.json'),
|
|
12
|
+
join(__dirname, '..', '..', '..', 'config', 'chains.json'),
|
|
13
|
+
];
|
|
14
|
+
for (const p of candidates) {
|
|
15
|
+
if (existsSync(p))
|
|
16
|
+
return p;
|
|
17
|
+
}
|
|
18
|
+
throw new Error(`chains.json not found. Tried: ${candidates.join(', ')}. Run from CLI package root.`);
|
|
19
|
+
};
|
|
20
|
+
let cachedConfig = null;
|
|
21
|
+
function loadConfig() {
|
|
22
|
+
if (!cachedConfig) {
|
|
23
|
+
const path = getConfigPath();
|
|
24
|
+
const raw = readFileSync(path, 'utf-8');
|
|
25
|
+
cachedConfig = JSON.parse(raw);
|
|
26
|
+
}
|
|
27
|
+
return cachedConfig;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get network configuration, with RPC URL override via env vars.
|
|
31
|
+
* JV_BASE_RPC_URL for base_uat, JV_JASPERVAULT_RPC_URL for jaspervault.
|
|
32
|
+
*/
|
|
33
|
+
export function getNetworkConfig(network) {
|
|
34
|
+
const config = loadConfig();
|
|
35
|
+
const net = config.networks[network];
|
|
36
|
+
if (!net) {
|
|
37
|
+
throw new Error(`Unknown network: ${network}. Supported: ${Object.keys(config.networks).join(', ')}`);
|
|
38
|
+
}
|
|
39
|
+
let rpcUrl = net.rpcUrl;
|
|
40
|
+
if (network === 'base_uat' && process.env.JV_BASE_RPC_URL) {
|
|
41
|
+
rpcUrl = process.env.JV_BASE_RPC_URL;
|
|
42
|
+
}
|
|
43
|
+
if (network === 'jaspervault' && process.env.JV_JASPERVAULT_RPC_URL) {
|
|
44
|
+
rpcUrl = process.env.JV_JASPERVAULT_RPC_URL;
|
|
45
|
+
}
|
|
46
|
+
return { ...net, rpcUrl };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get token config for a symbol within a network.
|
|
50
|
+
*/
|
|
51
|
+
export function getTokenConfig(network, symbol) {
|
|
52
|
+
const net = getNetworkConfig(network);
|
|
53
|
+
const sym = symbol.toUpperCase();
|
|
54
|
+
const tok = net.tokens?.[sym];
|
|
55
|
+
if (!tok) {
|
|
56
|
+
throw new Error(`Token ${symbol} not found for network ${network}. Supported: ${Object.keys(net.tokens || {}).join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
return tok;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get writer address for a symbol and side within a network.
|
|
62
|
+
*/
|
|
63
|
+
export function getWriterAddress(network, symbol, side) {
|
|
64
|
+
const net = getNetworkConfig(network);
|
|
65
|
+
const sym = symbol.toUpperCase();
|
|
66
|
+
const writers = net.writers?.[sym];
|
|
67
|
+
if (!writers) {
|
|
68
|
+
throw new Error(`Writer not configured for ${symbol} on ${network}. Supported: ${Object.keys(net.writers || {}).join(', ')}`);
|
|
69
|
+
}
|
|
70
|
+
return writers[side];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get Warp Route token configuration.
|
|
74
|
+
* Token: jbtc | jusdc | cbbtc | usdc
|
|
75
|
+
*/
|
|
76
|
+
export function getWarpConfig(token) {
|
|
77
|
+
const config = loadConfig();
|
|
78
|
+
const t = config.warpRoutes[token.toLowerCase()];
|
|
79
|
+
if (!t) {
|
|
80
|
+
throw new Error(`Unknown token: ${token}. Supported: jbtc, jusdc, cbbtc, usdc`);
|
|
81
|
+
}
|
|
82
|
+
return t;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get Base chain RPC URL for deposit (source chain).
|
|
86
|
+
*/
|
|
87
|
+
export function getBaseRpcUrl() {
|
|
88
|
+
return process.env.JV_BASE_RPC_URL || loadConfig().defaultBaseRpc;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get JasperVault chain RPC URL for deposit (destination chain, vault address computation).
|
|
92
|
+
*/
|
|
93
|
+
export function getJaspervaultRpcUrl() {
|
|
94
|
+
return process.env.JV_JASPERVAULT_RPC_URL || loadConfig().defaultJaspervaultRpc;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=chain-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain-config.js","sourceRoot":"","sources":["../../../src/services/chain-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface DelegationKeys {
|
|
2
|
+
delegationPrivateKey: string;
|
|
3
|
+
delegationAddress: string;
|
|
4
|
+
createdAt: string;
|
|
5
|
+
network?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Load delegation key from env var, file, or return null (caller can generate).
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadDelegationKey(): DelegationKeys | null;
|
|
11
|
+
/**
|
|
12
|
+
* Load delegation key, or generate a new one if not found.
|
|
13
|
+
* Returns { privateKey, address } for immediate use.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadOrGenerateDelegationKey(network?: string): {
|
|
16
|
+
privateKey: string;
|
|
17
|
+
address: string;
|
|
18
|
+
wasGenerated: boolean;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Save delegation key to ~/.jaspervault/keys.json with mode 0600.
|
|
22
|
+
*/
|
|
23
|
+
export declare function saveDelegationKey(privateKey: string, address: string, network?: string): void;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Wallet } from 'ethers';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, chmodSync, writeFileSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
function getKeysDir() {
|
|
5
|
+
return join(process.env.HOME || process.env.USERPROFILE || '', '.jaspervault');
|
|
6
|
+
}
|
|
7
|
+
function getKeysFile() {
|
|
8
|
+
return join(getKeysDir(), 'keys.json');
|
|
9
|
+
}
|
|
10
|
+
function ensureKeysDir() {
|
|
11
|
+
const dir = getKeysDir();
|
|
12
|
+
if (!existsSync(dir)) {
|
|
13
|
+
mkdirSync(dir, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Load delegation key from env var, file, or return null (caller can generate).
|
|
18
|
+
*/
|
|
19
|
+
export function loadDelegationKey() {
|
|
20
|
+
const fromEnv = process.env.JV_DELEGATION_KEY;
|
|
21
|
+
if (fromEnv && fromEnv.trim().length > 0) {
|
|
22
|
+
const w = new Wallet(fromEnv.trim());
|
|
23
|
+
return {
|
|
24
|
+
delegationPrivateKey: fromEnv.trim(),
|
|
25
|
+
delegationAddress: w.address,
|
|
26
|
+
createdAt: new Date().toISOString(),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (existsSync(getKeysFile())) {
|
|
30
|
+
const raw = readFileSync(getKeysFile(), 'utf-8');
|
|
31
|
+
const data = JSON.parse(raw);
|
|
32
|
+
if (data.delegationPrivateKey && data.delegationAddress) {
|
|
33
|
+
return data;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Load delegation key, or generate a new one if not found.
|
|
40
|
+
* Returns { privateKey, address } for immediate use.
|
|
41
|
+
*/
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- network kept for API consistency with callers
|
|
43
|
+
export function loadOrGenerateDelegationKey(network) {
|
|
44
|
+
const existing = loadDelegationKey();
|
|
45
|
+
if (existing) {
|
|
46
|
+
return {
|
|
47
|
+
privateKey: existing.delegationPrivateKey,
|
|
48
|
+
address: existing.delegationAddress,
|
|
49
|
+
wasGenerated: false,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const wallet = Wallet.createRandom();
|
|
53
|
+
return {
|
|
54
|
+
privateKey: wallet.privateKey,
|
|
55
|
+
address: wallet.address,
|
|
56
|
+
wasGenerated: true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Save delegation key to ~/.jaspervault/keys.json with mode 0600.
|
|
61
|
+
*/
|
|
62
|
+
export function saveDelegationKey(privateKey, address, network) {
|
|
63
|
+
ensureKeysDir();
|
|
64
|
+
const data = {
|
|
65
|
+
delegationPrivateKey: privateKey,
|
|
66
|
+
delegationAddress: address,
|
|
67
|
+
createdAt: new Date().toISOString(),
|
|
68
|
+
...(network && { network }),
|
|
69
|
+
};
|
|
70
|
+
const file = getKeysFile();
|
|
71
|
+
writeFileSync(file, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
72
|
+
try {
|
|
73
|
+
chmodSync(file, 0o600);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// chmod may fail on some Windows setups; ignore
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=key-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-manager.js","sourceRoot":"","sources":["../../../src/services/key-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
import type { SignData, ManagedOrder, OrderIntentParams, TpSlIntentParams } from '../types.js';
|
|
3
|
+
import type { VaultProfile } from '../types.js';
|
|
4
|
+
export interface WriterIndices {
|
|
5
|
+
settingsIndex: string;
|
|
6
|
+
productTypeIndex: string;
|
|
7
|
+
offerID: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Build SignData from order intent, profile, and network config.
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildSignData(intent: OrderIntentParams | TpSlIntentParams, profile: VaultProfile, network: string): Promise<SignData>;
|
|
13
|
+
/**
|
|
14
|
+
* Sign SignData using delegation wallet (ABI-encode + keccak256 + signMessage).
|
|
15
|
+
*/
|
|
16
|
+
export declare function signSignData(signData: SignData, delegationWallet: ethers.Wallet): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Fetch settingsIndex, productTypeIndex, offerID from chain.
|
|
19
|
+
*/
|
|
20
|
+
export declare function fetchWriterIndices(writerAddress: string, orderType: number, underlyingAsset: string, provider: ethers.Provider, optionModuleV2Address: string): Promise<WriterIndices>;
|
|
21
|
+
/**
|
|
22
|
+
* Build ManagedOrder from SignData and writer indices.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildManagedOrder(signData: SignData, writerIndices: WriterIndices, holder: string, quantity?: string): ManagedOrder;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
import { getNetworkConfig, getTokenConfig, getWriterAddress } from './chain-config.js';
|
|
3
|
+
import { getPositionAccountFromProfile } from './vault-profile.js';
|
|
4
|
+
const MAX_UINT256 = '115792089237316195423570985008687907853269984665640564039457584007913129639935';
|
|
5
|
+
const PERPS_THRESHOLD = 10n ** 12n;
|
|
6
|
+
const GET_MANAGED_OPTIONS_SETTINGS_ABI = [
|
|
7
|
+
'function getManagedOptionsSettings(address _vault) view returns (tuple(bool isOpen, uint8 orderType, address writer, address lockAsset, address underlyingAsset, uint8 lockAssetType, uint256 underlyingNftID, uint8 liquidateMode, address strikeAsset, uint256 maximum, uint8 premiumOracleType, address[] premiumAssets, uint64[] productTypes, uint256[] premiumFloorAMMs, uint256[] premiumRates, uint256 maxUnderlyingAssetAmount, uint256 minUnderlyingAssetAmount, uint256 minQuantity, uint256 offerID)[])',
|
|
8
|
+
];
|
|
9
|
+
/**
|
|
10
|
+
* Build SignData from order intent, profile, and network config.
|
|
11
|
+
*/
|
|
12
|
+
export async function buildSignData(intent, profile, network) {
|
|
13
|
+
const net = getNetworkConfig(network);
|
|
14
|
+
const isTpSl = 'orderID' in intent && intent.orderID && 'price' in intent;
|
|
15
|
+
const baseIntent = intent;
|
|
16
|
+
const marginAccount = profile.marginAccount ?? baseIntent.marginAccount;
|
|
17
|
+
if (!marginAccount && !isTpSl) {
|
|
18
|
+
throw new Error('marginAccount required. Run vault init or pass --margin-account.');
|
|
19
|
+
}
|
|
20
|
+
const recipient = marginAccount;
|
|
21
|
+
const symbol = baseIntent.symbol?.toUpperCase() ?? intent.symbol.toUpperCase();
|
|
22
|
+
const side = baseIntent.side ?? intent.side ?? 'long';
|
|
23
|
+
const orderType = side === 'long' ? 0 : 1;
|
|
24
|
+
const ttl = baseIntent.ttlSeconds ?? intent.ttlSeconds ?? 3600;
|
|
25
|
+
const expireTime = Math.floor(Date.now() / 1000) + ttl;
|
|
26
|
+
const tokenConfig = getTokenConfig(network, symbol);
|
|
27
|
+
const marginAssetConfig = net.marginAsset;
|
|
28
|
+
if (!marginAssetConfig) {
|
|
29
|
+
throw new Error(`marginAsset not configured for network ${network}`);
|
|
30
|
+
}
|
|
31
|
+
let targetPrice;
|
|
32
|
+
let marginAmount;
|
|
33
|
+
let productType;
|
|
34
|
+
let orderID;
|
|
35
|
+
let writerSide;
|
|
36
|
+
let signOrderType;
|
|
37
|
+
if (isTpSl) {
|
|
38
|
+
const tpSlIntent = intent;
|
|
39
|
+
orderID = Number(tpSlIntent.orderID);
|
|
40
|
+
targetPrice = ethers.parseUnits(tpSlIntent.price, 18).toString();
|
|
41
|
+
marginAmount = '0';
|
|
42
|
+
productType = (100 * 10 ** 12).toString();
|
|
43
|
+
writerSide = tpSlIntent.side === 'short' ? 'long' : 'short';
|
|
44
|
+
signOrderType = 1;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const orderIntent = intent;
|
|
48
|
+
const positionAccount = orderIntent.positionAccount ?? getPositionAccountFromProfile(profile, orderIntent.side);
|
|
49
|
+
if (!positionAccount) {
|
|
50
|
+
throw new Error(`positionAccount required for ${orderIntent.side}. Run vault init or pass --position-account.`);
|
|
51
|
+
}
|
|
52
|
+
orderID = orderIntent.orderID ?? 0;
|
|
53
|
+
if (orderIntent.limitPrice) {
|
|
54
|
+
targetPrice = ethers.parseUnits(orderIntent.limitPrice, 18).toString();
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
targetPrice = orderType === 0 ? MAX_UINT256 : '0';
|
|
58
|
+
}
|
|
59
|
+
marginAmount = ethers.parseUnits(orderIntent.marginAmount, marginAssetConfig.decimals).toString();
|
|
60
|
+
productType = (orderIntent.leverage * 10 ** 12).toString();
|
|
61
|
+
writerSide = side;
|
|
62
|
+
signOrderType = orderType;
|
|
63
|
+
}
|
|
64
|
+
const writerAddress = getWriterAddress(network, symbol, writerSide);
|
|
65
|
+
return {
|
|
66
|
+
limitType: 0,
|
|
67
|
+
orderID,
|
|
68
|
+
orderType: signOrderType,
|
|
69
|
+
productType,
|
|
70
|
+
targetPrice,
|
|
71
|
+
expireTime,
|
|
72
|
+
wallet: profile.eoa,
|
|
73
|
+
writer: writerAddress,
|
|
74
|
+
recipient,
|
|
75
|
+
chainId: net.chainId,
|
|
76
|
+
marginAsset: marginAssetConfig.address,
|
|
77
|
+
marginAmount,
|
|
78
|
+
underlyingAsset: tokenConfig.address,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Sign SignData using delegation wallet (ABI-encode + keccak256 + signMessage).
|
|
83
|
+
*/
|
|
84
|
+
export async function signSignData(signData, delegationWallet) {
|
|
85
|
+
const encodedData = ethers.AbiCoder.defaultAbiCoder().encode([
|
|
86
|
+
'uint8',
|
|
87
|
+
'uint64',
|
|
88
|
+
'uint8',
|
|
89
|
+
'uint64',
|
|
90
|
+
'uint256',
|
|
91
|
+
'uint256',
|
|
92
|
+
'address',
|
|
93
|
+
'address',
|
|
94
|
+
'address',
|
|
95
|
+
'uint256',
|
|
96
|
+
'address',
|
|
97
|
+
'uint256',
|
|
98
|
+
'address',
|
|
99
|
+
], [
|
|
100
|
+
signData.limitType,
|
|
101
|
+
signData.orderID,
|
|
102
|
+
signData.orderType,
|
|
103
|
+
signData.productType,
|
|
104
|
+
signData.targetPrice,
|
|
105
|
+
signData.expireTime,
|
|
106
|
+
signData.wallet,
|
|
107
|
+
signData.writer,
|
|
108
|
+
signData.recipient,
|
|
109
|
+
signData.chainId,
|
|
110
|
+
signData.marginAsset,
|
|
111
|
+
signData.marginAmount,
|
|
112
|
+
signData.underlyingAsset,
|
|
113
|
+
]);
|
|
114
|
+
const messageHash = ethers.keccak256(encodedData);
|
|
115
|
+
return delegationWallet.signMessage(ethers.getBytes(messageHash));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Fetch settingsIndex, productTypeIndex, offerID from chain.
|
|
119
|
+
*/
|
|
120
|
+
export async function fetchWriterIndices(writerAddress, orderType, underlyingAsset, provider, optionModuleV2Address) {
|
|
121
|
+
const contract = new ethers.Contract(optionModuleV2Address, GET_MANAGED_OPTIONS_SETTINGS_ABI, provider);
|
|
122
|
+
const settings = (await contract.getManagedOptionsSettings(writerAddress));
|
|
123
|
+
const targetOrderType = BigInt(orderType);
|
|
124
|
+
const targetUnderlying = underlyingAsset.toLowerCase();
|
|
125
|
+
for (let i = 0; i < settings.length; i++) {
|
|
126
|
+
const setting = settings[i];
|
|
127
|
+
if (BigInt(setting.orderType) !== targetOrderType)
|
|
128
|
+
continue;
|
|
129
|
+
if (setting.underlyingAsset.toLowerCase() !== targetUnderlying)
|
|
130
|
+
continue;
|
|
131
|
+
for (let j = 0; j < setting.productTypes.length; j++) {
|
|
132
|
+
const pt = setting.productTypes[j];
|
|
133
|
+
if (pt >= PERPS_THRESHOLD) {
|
|
134
|
+
return {
|
|
135
|
+
settingsIndex: String(i),
|
|
136
|
+
productTypeIndex: String(j),
|
|
137
|
+
offerID: String(setting.offerID),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
throw new Error(`No perps product type found for writer ${writerAddress}, orderType ${orderType}, underlyingAsset ${underlyingAsset}`);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Build ManagedOrder from SignData and writer indices.
|
|
146
|
+
*/
|
|
147
|
+
export function buildManagedOrder(signData, writerIndices, holder, quantity = '0') {
|
|
148
|
+
return {
|
|
149
|
+
holder,
|
|
150
|
+
quantity,
|
|
151
|
+
writer: signData.writer,
|
|
152
|
+
recipient: signData.recipient,
|
|
153
|
+
settingsIndex: writerIndices.settingsIndex,
|
|
154
|
+
productTypeIndex: writerIndices.productTypeIndex,
|
|
155
|
+
oracleIndex: '0',
|
|
156
|
+
nftFreeOption: ethers.ZeroAddress,
|
|
157
|
+
optionSourceType: '0',
|
|
158
|
+
liquidationToEOA: false,
|
|
159
|
+
offerID: writerIndices.offerID,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=order-signer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"order-signer.js","sourceRoot":"","sources":["../../../src/services/order-signer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch current price for a symbol from Quote Center API.
|
|
3
|
+
* Returns price as bigint in 18 decimals.
|
|
4
|
+
*/
|
|
5
|
+
export declare function fetchCurrentPrice(symbol: string, network: string): Promise<bigint>;
|
|
6
|
+
/**
|
|
7
|
+
* Calculate quantity from margin and price.
|
|
8
|
+
* Margin is the actual collateral (user notional / leverage already applied upstream).
|
|
9
|
+
* scaleFactor = 10^(18 - marginDecimals)
|
|
10
|
+
* marginScaled = marginAmount * scaleFactor
|
|
11
|
+
* quantity = (marginScaled * 10^18) / currentPrice
|
|
12
|
+
* Returns quantity as string in 18 decimals (wei).
|
|
13
|
+
*/
|
|
14
|
+
export declare function calculateQuantity(marginAmount: string, currentPrice: bigint, marginDecimals: number): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getNetworkConfig } from './chain-config.js';
|
|
2
|
+
const SPOT_PRICE_PATH = '/api/v4/indexPrice';
|
|
3
|
+
/**
|
|
4
|
+
* Fetch current price for a symbol from Quote Center API.
|
|
5
|
+
* Returns price as bigint in 18 decimals.
|
|
6
|
+
*/
|
|
7
|
+
export async function fetchCurrentPrice(symbol, network) {
|
|
8
|
+
const net = getNetworkConfig(network);
|
|
9
|
+
const baseUrl = process.env.QUOTE_CENTER_URL ??
|
|
10
|
+
net.quoteCenterUrl ??
|
|
11
|
+
'https://uat-jasperquotecenterv2.fly.dev';
|
|
12
|
+
const chainId = net.chainId;
|
|
13
|
+
const url = new URL(`${baseUrl}${SPOT_PRICE_PATH}`);
|
|
14
|
+
url.searchParams.set('symbol', symbol.toUpperCase());
|
|
15
|
+
url.searchParams.set('timestamp', '0');
|
|
16
|
+
url.searchParams.set('chain_id', chainId.toString());
|
|
17
|
+
const response = await fetch(url.toString(), {
|
|
18
|
+
method: 'GET',
|
|
19
|
+
headers: { accept: 'application/json' },
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
const text = await response.text();
|
|
23
|
+
throw new Error(`Failed to fetch price for ${symbol}: HTTP ${response.status} - ${text}`);
|
|
24
|
+
}
|
|
25
|
+
const data = (await response.json());
|
|
26
|
+
const priceItem = Array.isArray(data.data) ? data.data[0] : data.data;
|
|
27
|
+
if (!priceItem || !priceItem.price) {
|
|
28
|
+
throw new Error(`No price data for ${symbol} from Quote Center API`);
|
|
29
|
+
}
|
|
30
|
+
return BigInt(priceItem.price);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Calculate quantity from margin and price.
|
|
34
|
+
* Margin is the actual collateral (user notional / leverage already applied upstream).
|
|
35
|
+
* scaleFactor = 10^(18 - marginDecimals)
|
|
36
|
+
* marginScaled = marginAmount * scaleFactor
|
|
37
|
+
* quantity = (marginScaled * 10^18) / currentPrice
|
|
38
|
+
* Returns quantity as string in 18 decimals (wei).
|
|
39
|
+
*/
|
|
40
|
+
export function calculateQuantity(marginAmount, currentPrice, marginDecimals) {
|
|
41
|
+
const marginBigInt = BigInt(marginAmount);
|
|
42
|
+
const scaleFactor = BigInt(10) ** BigInt(18 - marginDecimals);
|
|
43
|
+
const marginScaled = marginBigInt * scaleFactor;
|
|
44
|
+
const quantity = (marginScaled * BigInt(10) ** BigInt(18)) / currentPrice;
|
|
45
|
+
return quantity.toString();
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=price-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"price-service.js","sourceRoot":"","sources":["../../../src/services/price-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAiBrD,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAE7C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAc,EACd,OAAe;IAEf,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,OAAO,GACX,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAC5B,GAAG,CAAC,cAAc;QAClB,yCAAyC,CAAC;IAC5C,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAE5B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,OAAO,GAAG,eAAe,EAAE,CAAC,CAAC;IACpD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IACrD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IACvC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAErD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;QAC3C,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;KACxC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,6BAA6B,MAAM,UAAU,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,CACzE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA6B,CAAC;IACjE,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAEtE,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,wBAAwB,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,YAAoB,EACpB,YAAoB,EACpB,cAAsB;IAEtB,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,EAAE,GAAG,cAAc,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG,YAAY,GAAG,WAAW,CAAC;IAEhD,MAAM,QAAQ,GACZ,CAAC,YAAY,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,YAAY,CAAC;IAE3D,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface SubgraphOrder {
|
|
2
|
+
id: string;
|
|
3
|
+
holder: string;
|
|
4
|
+
writer?: string;
|
|
5
|
+
recipient?: string;
|
|
6
|
+
transactionHash?: string;
|
|
7
|
+
lockAmount: string;
|
|
8
|
+
quantity: string;
|
|
9
|
+
initialQuantity?: string;
|
|
10
|
+
strikeAmount: string;
|
|
11
|
+
entryPrice: string;
|
|
12
|
+
underlyingAsset: string;
|
|
13
|
+
lockAsset?: string;
|
|
14
|
+
strikeAsset?: string;
|
|
15
|
+
marginAsset?: string;
|
|
16
|
+
positionSide: 'LONG' | 'SHORT';
|
|
17
|
+
productType?: string;
|
|
18
|
+
marginDeposited?: string;
|
|
19
|
+
totalFreeAmount?: string;
|
|
20
|
+
createdAt?: string;
|
|
21
|
+
lastModifiedAt?: string;
|
|
22
|
+
expirationDate?: string;
|
|
23
|
+
lockDate?: string;
|
|
24
|
+
settingsIndex?: string;
|
|
25
|
+
productTypeIndex?: string;
|
|
26
|
+
liquidationToEOA?: boolean;
|
|
27
|
+
optionSourceType?: number;
|
|
28
|
+
isActive: boolean;
|
|
29
|
+
blockNumber?: string;
|
|
30
|
+
leverage?: string;
|
|
31
|
+
operationCount?: string;
|
|
32
|
+
perpsOptions?: Array<{
|
|
33
|
+
id: string;
|
|
34
|
+
orderID: string;
|
|
35
|
+
hedgeOrderID: string;
|
|
36
|
+
status: number;
|
|
37
|
+
quantity: string;
|
|
38
|
+
expirationDate: string;
|
|
39
|
+
optionType: number;
|
|
40
|
+
}>;
|
|
41
|
+
}
|
|
42
|
+
export interface OrderStats {
|
|
43
|
+
total: number;
|
|
44
|
+
active: number;
|
|
45
|
+
closed: number;
|
|
46
|
+
}
|
|
47
|
+
export declare class SubgraphClient {
|
|
48
|
+
private client;
|
|
49
|
+
constructor(endpoint: string);
|
|
50
|
+
queryOrderById(orderId: string): Promise<SubgraphOrder | null>;
|
|
51
|
+
queryOrdersByRecipient(recipient: string, first?: number, skip?: number): Promise<SubgraphOrder[]>;
|
|
52
|
+
queryOrderStats(recipient: string): Promise<OrderStats>;
|
|
53
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { GraphQLClient } from 'graphql-request';
|
|
2
|
+
const GET_ORDER_BY_ID = `
|
|
3
|
+
query GetOrderById($orderID: BigInt!) {
|
|
4
|
+
perpsOrder(id: $orderID) {
|
|
5
|
+
id
|
|
6
|
+
holder
|
|
7
|
+
writer
|
|
8
|
+
recipient
|
|
9
|
+
isActive
|
|
10
|
+
underlyingAsset
|
|
11
|
+
marginAsset
|
|
12
|
+
lockAsset
|
|
13
|
+
strikeAsset
|
|
14
|
+
positionSide
|
|
15
|
+
quantity
|
|
16
|
+
initialQuantity
|
|
17
|
+
strikeAmount
|
|
18
|
+
entryPrice
|
|
19
|
+
lockAmount
|
|
20
|
+
productType
|
|
21
|
+
marginDeposited
|
|
22
|
+
totalFreeAmount
|
|
23
|
+
createdAt
|
|
24
|
+
lastModifiedAt
|
|
25
|
+
expirationDate
|
|
26
|
+
lockDate
|
|
27
|
+
leverage
|
|
28
|
+
operationCount
|
|
29
|
+
transactionHash
|
|
30
|
+
blockNumber
|
|
31
|
+
perpsOptions {
|
|
32
|
+
id
|
|
33
|
+
orderID
|
|
34
|
+
hedgeOrderID
|
|
35
|
+
status
|
|
36
|
+
quantity
|
|
37
|
+
expirationDate
|
|
38
|
+
optionType
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
const GET_ORDERS_BY_RECIPIENT = `
|
|
44
|
+
query GetOrdersByRecipient($recipient: String!, $first: Int!, $skip: Int!) {
|
|
45
|
+
perpsOrders(
|
|
46
|
+
where: { recipient: $recipient }
|
|
47
|
+
first: $first
|
|
48
|
+
skip: $skip
|
|
49
|
+
orderBy: createdAt
|
|
50
|
+
orderDirection: desc
|
|
51
|
+
) {
|
|
52
|
+
id
|
|
53
|
+
holder
|
|
54
|
+
writer
|
|
55
|
+
recipient
|
|
56
|
+
transactionHash
|
|
57
|
+
lockAmount
|
|
58
|
+
quantity
|
|
59
|
+
initialQuantity
|
|
60
|
+
strikeAmount
|
|
61
|
+
entryPrice
|
|
62
|
+
underlyingAsset
|
|
63
|
+
lockAsset
|
|
64
|
+
strikeAsset
|
|
65
|
+
marginAsset
|
|
66
|
+
positionSide
|
|
67
|
+
productType
|
|
68
|
+
marginDeposited
|
|
69
|
+
totalFreeAmount
|
|
70
|
+
createdAt
|
|
71
|
+
lastModifiedAt
|
|
72
|
+
expirationDate
|
|
73
|
+
lockDate
|
|
74
|
+
leverage
|
|
75
|
+
operationCount
|
|
76
|
+
isActive
|
|
77
|
+
blockNumber
|
|
78
|
+
perpsOptions {
|
|
79
|
+
id
|
|
80
|
+
orderID
|
|
81
|
+
hedgeOrderID
|
|
82
|
+
status
|
|
83
|
+
quantity
|
|
84
|
+
expirationDate
|
|
85
|
+
optionType
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
`;
|
|
90
|
+
const GET_ORDER_STATS_BY_RECIPIENT = `
|
|
91
|
+
query GetOrderStatsByRecipient($recipient: String!) {
|
|
92
|
+
total: perpsOrders(where: { recipient: $recipient }) {
|
|
93
|
+
id
|
|
94
|
+
}
|
|
95
|
+
active: perpsOrders(where: { recipient: $recipient, isActive: true }) {
|
|
96
|
+
id
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
`;
|
|
100
|
+
export class SubgraphClient {
|
|
101
|
+
client;
|
|
102
|
+
constructor(endpoint) {
|
|
103
|
+
this.client = new GraphQLClient(endpoint);
|
|
104
|
+
}
|
|
105
|
+
async queryOrderById(orderId) {
|
|
106
|
+
const data = await this.client.request(GET_ORDER_BY_ID, { orderID: orderId });
|
|
107
|
+
return data.perpsOrder;
|
|
108
|
+
}
|
|
109
|
+
async queryOrdersByRecipient(recipient, first = 20, skip = 0) {
|
|
110
|
+
const data = await this.client.request(GET_ORDERS_BY_RECIPIENT, { recipient, first, skip });
|
|
111
|
+
return data.perpsOrders;
|
|
112
|
+
}
|
|
113
|
+
async queryOrderStats(recipient) {
|
|
114
|
+
const data = await this.client.request(GET_ORDER_STATS_BY_RECIPIENT, { recipient });
|
|
115
|
+
const total = data.total.length;
|
|
116
|
+
const active = data.active.length;
|
|
117
|
+
return { total, active, closed: total - active };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=subgraph-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subgraph-client.js","sourceRoot":"","sources":["../../../src/services/subgraph-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA4ChD,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCvB,CAAC;AAEF,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8C/B,CAAC;AAEF,MAAM,4BAA4B,GAAG;;;;;;;;;CASpC,CAAC;AAQF,MAAM,OAAO,cAAc;IACjB,MAAM,CAAgB;IAE9B,YAAY,QAAgB;QAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAAe;QAClC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CACpC,eAAe,EACf,EAAE,OAAO,EAAE,OAAO,EAAE,CACrB,CAAC;QACF,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,sBAAsB,CAC1B,SAAiB,EACjB,QAAgB,EAAE,EAClB,OAAe,CAAC;QAEhB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CACpC,uBAAuB,EACvB,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAC3B,CAAC;QACF,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,SAAiB;QACrC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAGnC,4BAA4B,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAClC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,GAAG,MAAM,EAAE,CAAC;IACnD,CAAC;CACF"}
|