@signals-protocol/v1-sdk 1.0.0 → 1.2.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,337 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildPositionVNode = buildPositionVNode;
4
+ const h_1 = require("./h");
5
+ const assets_1 = require("./assets");
6
+ const format_1 = require("./format");
7
+ function buildPositionVNode(input) {
8
+ const { positionId, lowerTick, upperTick, currentQuantity, currentCost, totalQuantityBought, totalCosts, totalProceeds, outcome, closingPriceDate, isSettled, settlementTick, owner, theme, hideWallet, hideAmounts, currentValue, } = input;
9
+ const isDark = theme === "dark";
10
+ const isOpen = outcome === "OPEN";
11
+ // Entry: OPEN uses currentCost, settled uses totalCosts (currentCost is zeroed after claim)
12
+ const entry = isOpen ? Number(currentCost) / 1e6 : Number(totalCosts) / 1e6;
13
+ // PnL calculation:
14
+ // - LOSS: payout = 0
15
+ // - OPEN with currentValue: use SDK close proceeds
16
+ // - OPEN without currentValue: max payout fallback (currentQuantity)
17
+ // - WIN (settled): totalQuantityBought (full range payout)
18
+ // - CLOSED (early exit settled): totalProceeds
19
+ let value;
20
+ if (outcome === "LOSS") {
21
+ value = 0;
22
+ }
23
+ else if (isOpen && currentValue != null) {
24
+ value = currentValue;
25
+ }
26
+ else if (isOpen) {
27
+ value = Number(currentQuantity) / 1e6;
28
+ }
29
+ else if (outcome === "WIN") {
30
+ value = Number(totalQuantityBought) / 1e6;
31
+ }
32
+ else if (outcome === "CLOSED") {
33
+ value = Number(totalProceeds) / 1e6;
34
+ }
35
+ else {
36
+ value = 0;
37
+ }
38
+ // Snap sub-cent PnL to zero (floating-point noise from SDK calculations)
39
+ const rawPnl = value - entry;
40
+ const pnl = Math.abs(rawPnl) < 0.005 ? 0 : rawPnl;
41
+ const pnlPercent = entry > 0 ? pnl / entry : 0;
42
+ const payoutLabel = isOpen ? "Current Value" : "Payout";
43
+ const textPrimary = isDark ? "#ffffff" : "#000000";
44
+ const textSecondary = isDark
45
+ ? "rgba(255,255,255,0.70)"
46
+ : "rgba(0,0,0,0.60)";
47
+ const textMuted = isDark ? "rgba(255,255,255,0.65)" : "rgba(0,0,0,0.55)";
48
+ const pnlColor = (0, format_1.getPnlColor)(pnl, textMuted);
49
+ const payoutDisplayValue = outcome === "LOSS"
50
+ ? "$0.00"
51
+ : isOpen && currentValue != null
52
+ ? "$" +
53
+ currentValue.toLocaleString("en-US", {
54
+ minimumFractionDigits: 2,
55
+ maximumFractionDigits: 2,
56
+ })
57
+ : isOpen
58
+ ? (0, format_1.formatUSDC)(currentQuantity)
59
+ : outcome === "WIN"
60
+ ? (0, format_1.formatUSDC)(totalQuantityBought)
61
+ : (0, format_1.formatUSDC)(totalProceeds);
62
+ const children = [];
63
+ // Background gradient
64
+ children.push((0, h_1.h)("div", {
65
+ style: {
66
+ position: "absolute",
67
+ top: 0,
68
+ left: 0,
69
+ right: 0,
70
+ bottom: 0,
71
+ background: isDark
72
+ ? "linear-gradient(135deg, #0d1528, #0e1633)"
73
+ : "linear-gradient(135deg, #fbfdff, #f0f6ff)",
74
+ display: "flex",
75
+ },
76
+ }));
77
+ // Blue radial glow
78
+ children.push((0, h_1.h)("div", {
79
+ style: {
80
+ position: "absolute",
81
+ top: 0,
82
+ left: 0,
83
+ right: 0,
84
+ bottom: 0,
85
+ background: isDark
86
+ ? "radial-gradient(circle at 25% 20%, rgba(45,136,255,0.15), transparent 65%)"
87
+ : "radial-gradient(circle at 22% 18%, rgba(185,221,255,0.30), transparent 40%)",
88
+ display: "flex",
89
+ },
90
+ }));
91
+ // PnL glow
92
+ children.push((0, h_1.h)("div", {
93
+ style: {
94
+ position: "absolute",
95
+ top: 0,
96
+ left: 0,
97
+ right: 0,
98
+ bottom: 0,
99
+ background: pnl >= 0
100
+ ? isDark
101
+ ? "radial-gradient(circle at 85% 75%, rgba(0,191,64,0.25), transparent 45%)"
102
+ : "radial-gradient(circle at 85% 75%, rgba(88,230,131,0.30), transparent 45%)"
103
+ : isDark
104
+ ? "radial-gradient(circle at 85% 75%, rgba(239,68,68,0.25), transparent 45%)"
105
+ : "radial-gradient(circle at 85% 75%, rgba(252,165,165,0.30), transparent 45%)",
106
+ display: "flex",
107
+ },
108
+ }));
109
+ // LogoStrokeSVG watermark
110
+ children.push((0, h_1.h)("div", {
111
+ style: {
112
+ position: "absolute",
113
+ right: 8,
114
+ top: 8,
115
+ bottom: 8,
116
+ display: "flex",
117
+ },
118
+ }, (0, assets_1.buildLogoStrokeSVG)(614, theme)));
119
+ // Content
120
+ const contentChildren = [];
121
+ // Logo + "Signals"
122
+ contentChildren.push((0, h_1.h)("div", {
123
+ style: {
124
+ display: "flex",
125
+ alignItems: "center",
126
+ gap: 8,
127
+ marginBottom: 24,
128
+ },
129
+ }, (0, h_1.h)("img", {
130
+ src: assets_1.SIGNALS_LOGO_URI,
131
+ width: 34,
132
+ height: 32,
133
+ style: { display: "flex" },
134
+ }), (0, h_1.h)("span", {
135
+ style: {
136
+ fontSize: 28,
137
+ fontWeight: 700,
138
+ color: "#1444c2",
139
+ display: "flex",
140
+ },
141
+ }, "Signals")));
142
+ // Range section
143
+ const rangeItems = [
144
+ (0, h_1.h)("div", { style: { display: "flex", flexDirection: "column" } }, (0, h_1.h)("div", {
145
+ style: {
146
+ fontSize: 17,
147
+ color: textSecondary,
148
+ marginBottom: 4,
149
+ display: "flex",
150
+ },
151
+ }, "Range"), (0, h_1.h)("div", {
152
+ style: {
153
+ fontSize: 34,
154
+ fontWeight: 700,
155
+ color: textPrimary,
156
+ display: "flex",
157
+ },
158
+ }, (0, format_1.formatPriceRange)(lowerTick, upperTick))),
159
+ ];
160
+ if (isSettled && settlementTick != null) {
161
+ rangeItems.push((0, h_1.h)("div", { style: { display: "flex", flexDirection: "column" } }, (0, h_1.h)("div", {
162
+ style: {
163
+ fontSize: 17,
164
+ color: textSecondary,
165
+ marginBottom: 4,
166
+ display: "flex",
167
+ },
168
+ }, "Actual Price"), (0, h_1.h)("div", {
169
+ style: {
170
+ fontSize: 34,
171
+ fontWeight: 700,
172
+ color: textPrimary,
173
+ display: "flex",
174
+ },
175
+ }, (0, format_1.formatPrice)(settlementTick))));
176
+ }
177
+ contentChildren.push((0, h_1.h)("div", { style: { display: "flex", gap: 48, marginBottom: 20 } }, ...rangeItems));
178
+ // PnL (dominant)
179
+ const pnlChildren = [
180
+ (0, h_1.h)("div", {
181
+ style: {
182
+ fontSize: 17,
183
+ color: textSecondary,
184
+ marginBottom: 2,
185
+ display: "flex",
186
+ },
187
+ }, "PnL"),
188
+ ];
189
+ if (hideAmounts) {
190
+ pnlChildren.push((0, h_1.h)("div", {
191
+ style: {
192
+ fontSize: 90,
193
+ fontWeight: 700,
194
+ color: pnlColor,
195
+ lineHeight: 1,
196
+ display: "flex",
197
+ },
198
+ }, `${pnl > 0 ? "+" : pnl < 0 ? "-" : ""}${(0, format_1.percForm)(Math.abs(pnlPercent))}`));
199
+ }
200
+ else {
201
+ pnlChildren.push((0, h_1.h)("div", { style: { display: "flex", alignItems: "flex-end", gap: 8 } }, (0, h_1.h)("div", {
202
+ style: {
203
+ fontSize: 90,
204
+ fontWeight: 700,
205
+ color: pnlColor,
206
+ lineHeight: 1,
207
+ display: "flex",
208
+ },
209
+ }, (0, format_1.formatUsdPnl)(pnl)), (0, h_1.h)("div", {
210
+ style: {
211
+ fontSize: 34,
212
+ fontWeight: 700,
213
+ color: pnlColor,
214
+ marginBottom: 8,
215
+ display: "flex",
216
+ },
217
+ }, `(${(0, format_1.percForm)(pnlPercent)})`)));
218
+ }
219
+ contentChildren.push((0, h_1.h)("div", {
220
+ style: {
221
+ display: "flex",
222
+ flexDirection: "column",
223
+ marginBottom: 16,
224
+ },
225
+ }, ...pnlChildren));
226
+ // Date / Entry / Payout row
227
+ const infoItems = [
228
+ (0, h_1.h)("div", { style: { display: "flex", flexDirection: "column" } }, (0, h_1.h)("div", {
229
+ style: {
230
+ fontSize: 17,
231
+ color: textSecondary,
232
+ marginBottom: 4,
233
+ display: "flex",
234
+ },
235
+ }, "Date"), (0, h_1.h)("div", {
236
+ style: {
237
+ fontSize: 28,
238
+ fontWeight: 700,
239
+ color: textPrimary,
240
+ display: "flex",
241
+ },
242
+ }, closingPriceDate)),
243
+ ];
244
+ if (!hideAmounts) {
245
+ infoItems.push((0, h_1.h)("div", { style: { display: "flex", flexDirection: "column" } }, (0, h_1.h)("div", {
246
+ style: {
247
+ fontSize: 17,
248
+ color: textSecondary,
249
+ marginBottom: 4,
250
+ display: "flex",
251
+ },
252
+ }, "Entry"), (0, h_1.h)("div", {
253
+ style: {
254
+ fontSize: 28,
255
+ fontWeight: 700,
256
+ color: textPrimary,
257
+ display: "flex",
258
+ },
259
+ }, isOpen ? (0, format_1.formatUSDC)(currentCost) : (0, format_1.formatUSDC)(totalCosts))));
260
+ infoItems.push((0, h_1.h)("div", { style: { display: "flex", flexDirection: "column" } }, (0, h_1.h)("div", {
261
+ style: {
262
+ fontSize: 17,
263
+ color: textSecondary,
264
+ marginBottom: 4,
265
+ display: "flex",
266
+ },
267
+ }, payoutLabel), (0, h_1.h)("div", {
268
+ style: {
269
+ fontSize: 28,
270
+ fontWeight: 700,
271
+ color: textPrimary,
272
+ display: "flex",
273
+ },
274
+ }, payoutDisplayValue)));
275
+ }
276
+ contentChildren.push((0, h_1.h)("div", { style: { display: "flex", gap: 48, marginBottom: 12 } }, ...infoItems));
277
+ // Owner
278
+ if (!hideWallet && owner) {
279
+ contentChildren.push((0, h_1.h)("div", {
280
+ style: {
281
+ display: "flex",
282
+ flexDirection: "column",
283
+ marginBottom: 8,
284
+ },
285
+ }, (0, h_1.h)("div", {
286
+ style: {
287
+ fontSize: 17,
288
+ color: textSecondary,
289
+ marginBottom: 4,
290
+ display: "flex",
291
+ },
292
+ }, "Owner"), (0, h_1.h)("div", {
293
+ style: {
294
+ fontSize: 22,
295
+ fontWeight: 700,
296
+ color: textPrimary,
297
+ display: "flex",
298
+ },
299
+ }, owner.slice(0, 7))));
300
+ }
301
+ // Spacer
302
+ contentChildren.push((0, h_1.h)("div", { style: { flex: 1, display: "flex" } }));
303
+ // Footer
304
+ contentChildren.push((0, h_1.h)("div", {
305
+ style: {
306
+ display: "flex",
307
+ justifyContent: "space-between",
308
+ alignItems: "flex-end",
309
+ },
310
+ }, (0, h_1.h)("div", { style: { display: "flex", flexDirection: "column" } }, (0, h_1.h)("span", {
311
+ style: { fontSize: 17, color: textMuted, display: "flex" },
312
+ }, "@signalswtf"), (0, h_1.h)("span", {
313
+ style: { fontSize: 17, color: textMuted, display: "flex" },
314
+ }, "Range-Based Bitcoin Price Prediction Market")), (0, h_1.h)("span", {
315
+ style: { fontSize: 17, color: textMuted, display: "flex" },
316
+ }, `#${positionId}`)));
317
+ children.push((0, h_1.h)("div", {
318
+ style: {
319
+ display: "flex",
320
+ flexDirection: "column",
321
+ position: "relative",
322
+ width: "100%",
323
+ height: "100%",
324
+ padding: "32px 40px 28px",
325
+ },
326
+ }, ...contentChildren));
327
+ return (0, h_1.h)("div", {
328
+ style: {
329
+ width: 1200,
330
+ height: 630,
331
+ display: "flex",
332
+ fontFamily: "Inter",
333
+ position: "relative",
334
+ overflow: "hidden",
335
+ },
336
+ }, ...children);
337
+ }
@@ -0,0 +1,39 @@
1
+ export interface SatoriNode {
2
+ type: string;
3
+ props: Record<string, unknown>;
4
+ }
5
+ export interface PositionImageInput {
6
+ positionId: number;
7
+ lowerTick: number;
8
+ upperTick: number;
9
+ currentQuantity: string;
10
+ currentCost: string;
11
+ totalQuantityBought: string;
12
+ totalCosts: string;
13
+ totalProceeds: string;
14
+ outcome: string;
15
+ closingPriceDate: string;
16
+ isSettled: boolean;
17
+ settlementTick: number | null;
18
+ owner: string;
19
+ theme: "light" | "dark";
20
+ hideWallet: boolean;
21
+ hideAmounts: boolean;
22
+ /** Current position value in USDC (NOT raw). null = use max payout fallback. */
23
+ currentValue: number | null;
24
+ }
25
+ export type BarCategory = "peak" | "high" | "mid" | "low";
26
+ export interface PriceTick {
27
+ tick: number;
28
+ factor: bigint;
29
+ price: number;
30
+ probability: number;
31
+ }
32
+ export interface DistributionImageInput {
33
+ distribution: PriceTick[];
34
+ minTick: number;
35
+ maxTick: number;
36
+ tickSpacing: number;
37
+ closingPriceDate: string;
38
+ currentPrice?: number;
39
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/types.d.ts CHANGED
@@ -24,6 +24,7 @@ export interface MarketRaw {
24
24
  minTick: number;
25
25
  maxTick: number;
26
26
  tickSpacing: number;
27
+ endTimestamp?: number | string;
27
28
  feePolicyDescriptor?: string;
28
29
  isSettled?: boolean;
29
30
  settlementValue?: string;
@@ -35,6 +36,7 @@ export interface Market {
35
36
  minTick: Tick;
36
37
  maxTick: Tick;
37
38
  tickSpacing: Tick;
39
+ endTimestamp?: number;
38
40
  feePolicyDescriptor?: string;
39
41
  isSettled?: boolean;
40
42
  settlementValue?: USDCAmount;
@@ -61,6 +63,7 @@ export declare const FeePolicyKind: {
61
63
  readonly Null: "null";
62
64
  readonly Percentage: "percentage";
63
65
  readonly Custom: "custom";
66
+ readonly ThetaTime: "theta-time";
64
67
  };
65
68
  export type FeePolicyKind = (typeof FeePolicyKind)[keyof typeof FeePolicyKind];
66
69
  interface BaseFeeInfo {
@@ -78,7 +81,14 @@ interface PercentageFeeInfo extends BaseFeeInfo {
78
81
  interface CustomFeeInfo extends BaseFeeInfo {
79
82
  policy: typeof FeePolicyKind.Custom;
80
83
  }
81
- export type FeeInfo = NullFeeInfo | PercentageFeeInfo | CustomFeeInfo;
84
+ interface ThetaTimeFeeInfo extends BaseFeeInfo {
85
+ policy: typeof FeePolicyKind.ThetaTime;
86
+ baseBps: Big;
87
+ thetaMaxBps: Big;
88
+ windowSec: Big;
89
+ beta: Big;
90
+ }
91
+ export type FeeInfo = NullFeeInfo | PercentageFeeInfo | CustomFeeInfo | ThetaTimeFeeInfo;
82
92
  /**
83
93
  * Convert raw GraphQL market data to SDK calculation format
84
94
  * @param raw Raw market data from GraphQL
package/dist/types.js CHANGED
@@ -14,6 +14,7 @@ exports.FeePolicyKind = {
14
14
  Null: "null",
15
15
  Percentage: "percentage",
16
16
  Custom: "custom",
17
+ ThetaTime: "theta-time",
17
18
  };
18
19
  // ============================================================================
19
20
  // DATA ADAPTERS (GraphQL ↔ SDK 타입 변환)
@@ -29,6 +30,9 @@ function mapMarket(raw) {
29
30
  minTick: raw.minTick,
30
31
  maxTick: raw.maxTick,
31
32
  tickSpacing: raw.tickSpacing,
33
+ ...(raw.endTimestamp !== undefined && {
34
+ endTimestamp: Number(raw.endTimestamp),
35
+ }),
32
36
  ...(raw.feePolicyDescriptor !== undefined && {
33
37
  feePolicyDescriptor: raw.feePolicyDescriptor,
34
38
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signals-protocol/v1-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Signals v1 SDK for CLMSR market calculations and utilities",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -9,7 +9,10 @@
9
9
  "build": "tsc",
10
10
  "dev": "tsc --watch",
11
11
  "test": "jest",
12
+ "test:cov": "jest --coverage",
12
13
  "test:watch": "jest --watch",
14
+ "npm:auth": "node scripts/write-npmrc.js",
15
+ "publish:package": "NPM_CONFIG_USERCONFIG=.npmrc.auth npm publish",
13
16
  "lint": "eslint src/**/*.ts",
14
17
  "format": "prettier --write src/**/*.ts",
15
18
  "clean": "rm -rf dist",