@puppet.fund/operator 0.1.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.
@@ -0,0 +1,176 @@
1
+ import { E as TOKEN_ID, S as CHAIN_TOKEN_MAP, d as applyFactor, f as ARBITRUM_MARKET_LIST, l as selectGmxMarket, n as GMX_INCREASE_TYPES, p as GMX_V2_CONTRACT_MAP, r as GMX_ORDER_TYPE, s as buildGmxOrderCalls, t as GMX_DECREASE_SWAP_TYPE, u as getPositionPnlUsd } from "../gmx-DwTiknYm.js";
2
+ import { encodeFunctionData, formatUnits, isAddressEqual, parseUnits } from "viem";
3
+ import { encodeAbiParameters as encodeAbiParameters$1, keccak256 as keccak256$1, parseAbiParameters } from "viem/utils";
4
+ //#region ../sdk/dist/esm/gmx/gmxUtils.js
5
+ function hashData(types, values) {
6
+ return keccak256$1(encodeAbiParameters$1(parseAbiParameters(types), values));
7
+ }
8
+ //#endregion
9
+ //#region ../sdk/dist/esm/gmx/datastore.js
10
+ const datastoreAddress = GMX_V2_CONTRACT_MAP.GmxDatastore.address;
11
+ const datastoreAbi = GMX_V2_CONTRACT_MAP.GmxDatastore.abi;
12
+ function getDatastoreUint(client, key) {
13
+ return client.readContract({
14
+ address: datastoreAddress,
15
+ abi: datastoreAbi,
16
+ functionName: "getUint",
17
+ args: [key]
18
+ });
19
+ }
20
+ function getDatastoreUintByName(client, key) {
21
+ return getDatastoreUint(client, hashData(["string"], [key]));
22
+ }
23
+ async function getGasLimitsConfig(client) {
24
+ const [estimatedGasFeeBaseAmount, estimatedGasFeePerOraclePrice, estimatedGasFeeMultiplierFactor, increaseOrderGasLimit, decreaseOrderGasLimit, singleSwapGasLimit] = await Promise.all([
25
+ getDatastoreUintByName(client, "ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1"),
26
+ getDatastoreUintByName(client, "ESTIMATED_GAS_FEE_PER_ORACLE_PRICE"),
27
+ getDatastoreUintByName(client, "ESTIMATED_GAS_FEE_MULTIPLIER_FACTOR"),
28
+ getDatastoreUintByName(client, "INCREASE_ORDER_GAS_LIMIT"),
29
+ getDatastoreUintByName(client, "DECREASE_ORDER_GAS_LIMIT"),
30
+ getDatastoreUintByName(client, "SINGLE_SWAP_GAS_LIMIT")
31
+ ]);
32
+ return {
33
+ estimatedGasFeeBaseAmount,
34
+ estimatedGasFeePerOraclePrice,
35
+ estimatedGasFeeMultiplierFactor,
36
+ increaseOrderGasLimit,
37
+ decreaseOrderGasLimit,
38
+ singleSwapGasLimit
39
+ };
40
+ }
41
+ function calculateExecutionFee(gasLimitsConfig, gasPrice, actionGasLimit, oraclePriceCount = 3n) {
42
+ return (gasLimitsConfig.estimatedGasFeeBaseAmount + gasLimitsConfig.estimatedGasFeePerOraclePrice * oraclePriceCount + applyFactor(gasLimitsConfig.estimatedGasFeeMultiplierFactor, actionGasLimit)) * gasPrice;
43
+ }
44
+ //#endregion
45
+ //#region src/gmx/index.ts
46
+ const ROUTER = GMX_V2_CONTRACT_MAP.GmxExchangeRouter.address;
47
+ const ROUTER_ABI = GMX_V2_CONTRACT_MAP.GmxExchangeRouter.abi;
48
+ const READER = GMX_V2_CONTRACT_MAP.GmxReaderV2.address;
49
+ const READER_ABI = GMX_V2_CONTRACT_MAP.GmxReaderV2.abi;
50
+ const DATA_STORE = GMX_V2_CONTRACT_MAP.GmxDatastore.address;
51
+ const usd = (amount) => parseUnits(String(amount), 30);
52
+ const weth = (amount) => parseUnits(String(amount), 18);
53
+ const formatUsd = (amount) => formatUnits(amount, 30);
54
+ const formatWeth = (amount) => formatUnits(amount, 18);
55
+ const gmxPrice = (usdPerToken, indexTokenDecimals) => {
56
+ const decimals = 30 - indexTokenDecimals;
57
+ return parseUnits(typeof usdPerToken === "number" ? usdPerToken.toFixed(Math.min(decimals, 8)) : usdPerToken, decimals);
58
+ };
59
+ const GMX_BASE_TOKEN_ID = TOKEN_ID.WETH;
60
+ const acceptablePrice = (spotUsd, isLong, isIncrease, slippageBps, indexTokenDecimals = 18) => gmxPrice(spotUsd * (isIncrease === isLong ? 1 + slippageBps / 1e4 : 1 - slippageBps / 1e4), indexTokenDecimals);
61
+ function dominantPosition(positions, market) {
62
+ let best = null;
63
+ for (const p of positions) {
64
+ if (!isAddressEqual(p.addresses.market, market) || p.numbers.sizeInUsd === 0n) continue;
65
+ if (!best || p.numbers.sizeInUsd > best.numbers.sizeInUsd) best = p;
66
+ }
67
+ return best;
68
+ }
69
+ function positionMetrics(p, markPrice, longToken, shortTokenDecimals = 6) {
70
+ const sizeUsd = p.numbers.sizeInUsd;
71
+ const collateralUsd = isAddressEqual(p.addresses.collateralToken, longToken) ? p.numbers.collateralAmount * markPrice : p.numbers.collateralAmount * 10n ** BigInt(30 - shortTokenDecimals);
72
+ const marginUsd = collateralUsd + getPositionPnlUsd(p.flags.isLong, sizeUsd, p.numbers.sizeInTokens, markPrice);
73
+ return {
74
+ isLong: p.flags.isLong,
75
+ sizeUsd,
76
+ collateralUsd,
77
+ marginUsd,
78
+ leverage: collateralUsd > 0n ? Number(sizeUsd) / Number(collateralUsd) : Number.POSITIVE_INFINITY,
79
+ effLeverage: marginUsd > 0n ? Number(sizeUsd) / Number(marginUsd) : Number.POSITIVE_INFINITY
80
+ };
81
+ }
82
+ function gmxOperator(core, opts = {}) {
83
+ if (!isAddressEqual(core.token, CHAIN_TOKEN_MAP[42161].WETH)) throw new Error("gmxOperator needs a WETH-based core — create it with baseTokenId GMX_BASE_TOKEN_ID");
84
+ const { operate, publicClient, token, fund } = core;
85
+ const executionFeeBufferBps = opts.executionFeeBufferBps ?? 2000n;
86
+ let gasLimitsConfig = null;
87
+ async function quoteExecutionFee(orderType) {
88
+ if (!gasLimitsConfig) gasLimitsConfig = await getGasLimitsConfig(publicClient);
89
+ const gasPrice = await publicClient.getGasPrice();
90
+ const actionGasLimit = GMX_INCREASE_TYPES.has(orderType) ? gasLimitsConfig.increaseOrderGasLimit : gasLimitsConfig.decreaseOrderGasLimit;
91
+ return calculateExecutionFee(gasLimitsConfig, gasPrice, actionGasLimit) * (10000n + executionFeeBufferBps) / 10000n;
92
+ }
93
+ async function createOrder(p) {
94
+ const { callList, amountOut } = buildGmxOrderCalls(p, {
95
+ master: fund,
96
+ baseToken: token,
97
+ executionFee: p.executionFee ?? await quoteExecutionFee(p.orderType)
98
+ });
99
+ const [balance, signed] = await Promise.all([core.getFundBalance(), core.getFundSignedBalance()]);
100
+ if (balance < amountOut) throw new Error(`fund balance ${balance} below required ${amountOut} — allocate more on the site or size down`);
101
+ const surplus = balance > signed ? balance - signed : 0n;
102
+ return operate(callList, [{
103
+ tokenId: core.baseTokenId,
104
+ token,
105
+ amountIn: surplus,
106
+ amountOut
107
+ }]);
108
+ }
109
+ return {
110
+ GMX_ORDER_TYPE,
111
+ GMX_DECREASE_SWAP_TYPE,
112
+ markets: ARBITRUM_MARKET_LIST,
113
+ getMarket(indexToken) {
114
+ return selectGmxMarket(token, indexToken);
115
+ },
116
+ getPositions(account = fund) {
117
+ return publicClient.readContract({
118
+ address: READER,
119
+ abi: READER_ABI,
120
+ functionName: "getAccountPositions",
121
+ args: [
122
+ DATA_STORE,
123
+ account,
124
+ 0n,
125
+ 1000n
126
+ ]
127
+ });
128
+ },
129
+ getOrders(account = fund) {
130
+ return publicClient.readContract({
131
+ address: READER,
132
+ abi: READER_ABI,
133
+ functionName: "getAccountOrders",
134
+ args: [
135
+ DATA_STORE,
136
+ account,
137
+ 0n,
138
+ 1000n
139
+ ]
140
+ });
141
+ },
142
+ createOrder,
143
+ cancelOrder(key) {
144
+ return operate([call(ROUTER, encodeFunctionData({
145
+ abi: ROUTER_ABI,
146
+ functionName: "cancelOrder",
147
+ args: [key]
148
+ }), 1000000n)]);
149
+ },
150
+ updateOrder(p) {
151
+ return operate([call(ROUTER, encodeFunctionData({
152
+ abi: ROUTER_ABI,
153
+ functionName: "updateOrder",
154
+ args: [
155
+ p.key,
156
+ p.sizeDeltaUsd,
157
+ p.acceptablePrice ?? 0n,
158
+ p.triggerPrice ?? 0n,
159
+ p.minOutputAmount ?? 0n,
160
+ 0n,
161
+ p.autoCancel ?? false
162
+ ]
163
+ }), 1000000n)]);
164
+ }
165
+ };
166
+ }
167
+ function call(target, callData, gasLimit) {
168
+ return {
169
+ target,
170
+ value: 0n,
171
+ gasLimit,
172
+ callData
173
+ };
174
+ }
175
+ //#endregion
176
+ export { GMX_BASE_TOKEN_ID, GMX_DECREASE_SWAP_TYPE, GMX_ORDER_TYPE, acceptablePrice, calculateExecutionFee, dominantPosition, formatUsd, formatWeth, getGasLimitsConfig, getPositionPnlUsd, gmxOperator, gmxPrice, positionMetrics, usd, weth };