@signals-protocol/v1-sdk 1.2.0 → 1.4.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/dist/fees.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BigNumberish } from "ethers";
1
+ type BigNumberish = string | number | bigint;
2
2
  export type TradeSide = "BUY" | "SELL";
3
3
  export type Bytes32Like = `0x${string}`;
4
4
  interface FeeQuoteParams {
package/dist/fees.js CHANGED
@@ -9,13 +9,14 @@ exports.resolveFeePolicyWithMetadata = resolveFeePolicyWithMetadata;
9
9
  exports.encodePercentageFeePolicyDescriptor = encodePercentageFeePolicyDescriptor;
10
10
  exports.quoteOpenFee = quoteOpenFee;
11
11
  exports.quoteSellFee = quoteSellFee;
12
- const ethers_1 = require("ethers");
13
12
  const ZERO_CONTEXT = `0x${"00".repeat(32)}`;
14
13
  const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
15
14
  const WAD = 1000000000000000000n;
16
15
  const BPS_DENOM = 10000n;
17
16
  function toBigInt(value) {
18
- return (0, ethers_1.toBigInt)(value);
17
+ if (typeof value === "bigint")
18
+ return value;
19
+ return BigInt(value);
19
20
  }
20
21
  function normalizeContext(context) {
21
22
  return (context ?? ZERO_CONTEXT);
package/dist/index.d.ts CHANGED
@@ -10,4 +10,4 @@ export * as MathUtils from "./utils/math";
10
10
  export { toWAD, toMicroUSDC } from "./clmsr-sdk";
11
11
  export { createCLMSRSDK, createSignalsSDK } from "./clmsr-sdk";
12
12
  export * from "./share";
13
- export declare const VERSION = "1.2.0";
13
+ export declare const VERSION = "1.4.0";
package/dist/index.js CHANGED
@@ -67,4 +67,4 @@ Object.defineProperty(exports, "createSignalsSDK", { enumerable: true, get: func
67
67
  // Share image VNode templates
68
68
  __exportStar(require("./share"), exports);
69
69
  // Version (keep in sync with package.json)
70
- exports.VERSION = "1.2.0";
70
+ exports.VERSION = "1.4.0";
@@ -1,5 +1,6 @@
1
- export type { SatoriNode, PositionImageInput, DistributionImageInput, PriceTick, BarCategory, } from "./types";
1
+ export type { SatoriNode, PositionImageInput, ProfileImageInput, ProfileChartPosition, DistributionImageInput, PriceTick, BarCategory, } from "./types";
2
2
  export { buildPositionVNode } from "./position-image";
3
+ export { buildProfileVNode } from "./profile-image";
3
4
  export { buildDistributionVNode } from "./distribution-image";
4
5
  export { buildBrandVNode } from "./brand-image";
5
6
  export { h } from "./h";
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.formatDistributionPriceRange = exports.getPeakRange = exports.formatXTick = exports.generateXAxisTicks = exports.getSqrtHeight = exports.getBarCategory = exports.getPnlColor = exports.formatUsdPnl = exports.percForm = exports.formatPriceRange = exports.formatPrice = exports.formatUSDC = exports.buildLogoStrokeSVG = exports.SIGNALS_LOGO_URI = exports.h = exports.buildBrandVNode = exports.buildDistributionVNode = exports.buildPositionVNode = void 0;
3
+ exports.formatDistributionPriceRange = exports.getPeakRange = exports.formatXTick = exports.generateXAxisTicks = exports.getSqrtHeight = exports.getBarCategory = exports.getPnlColor = exports.formatUsdPnl = exports.percForm = exports.formatPriceRange = exports.formatPrice = exports.formatUSDC = exports.buildLogoStrokeSVG = exports.SIGNALS_LOGO_URI = exports.h = exports.buildBrandVNode = exports.buildDistributionVNode = exports.buildProfileVNode = exports.buildPositionVNode = void 0;
4
4
  // VNode builders
5
5
  var position_image_1 = require("./position-image");
6
6
  Object.defineProperty(exports, "buildPositionVNode", { enumerable: true, get: function () { return position_image_1.buildPositionVNode; } });
7
+ var profile_image_1 = require("./profile-image");
8
+ Object.defineProperty(exports, "buildProfileVNode", { enumerable: true, get: function () { return profile_image_1.buildProfileVNode; } });
7
9
  var distribution_image_1 = require("./distribution-image");
8
10
  Object.defineProperty(exports, "buildDistributionVNode", { enumerable: true, get: function () { return distribution_image_1.buildDistributionVNode; } });
9
11
  var brand_image_1 = require("./brand-image");
@@ -0,0 +1,2 @@
1
+ import type { ProfileImageInput, SatoriNode } from "./types";
2
+ export declare function buildProfileVNode(input: ProfileImageInput): SatoriNode;
@@ -0,0 +1,552 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildProfileVNode = buildProfileVNode;
4
+ const h_1 = require("./h");
5
+ const assets_1 = require("./assets");
6
+ const CARD_WIDTH = 1200;
7
+ const CARD_HEIGHT = 630;
8
+ const OUTER_PADDING = 24;
9
+ const CARD_PADDING_X = 32;
10
+ const CARD_PADDING_Y = 28;
11
+ const CHART_WIDTH = CARD_WIDTH - OUTER_PADDING * 2 - CARD_PADDING_X * 2;
12
+ const CHART_HEIGHT = 228;
13
+ const PLOT_LEFT = 56;
14
+ const PLOT_RIGHT = 18;
15
+ const PLOT_TOP = 14;
16
+ const PLOT_BOTTOM = 24;
17
+ const BAND_WIDTH = 18;
18
+ const OG_THEMES = {
19
+ light: {
20
+ pageBg: "#eef7ff", // bg-surface-soft
21
+ card: "#FFFFFF", // bg-card
22
+ ink: "#242424", // text-primary
23
+ inkMuted: "#737373", // text-secondary
24
+ border: "#EDEDED", // border-default
25
+ primary: "#1444c2", // brand-primary
26
+ positive: "#00BF40", // status-positive
27
+ negative: "#FF4343", // status-negative
28
+ bitcoin: "#F7931A", // bitcoin-accent
29
+ neutralBg: "#F4F4F4", // surface-muted
30
+ },
31
+ dark: {
32
+ pageBg: "#0F0F11", // bg-surface-soft
33
+ card: "#18181B", // bg-card
34
+ ink: "#E4E4E7", // text-primary
35
+ inkMuted: "#A1A1AA", // text-secondary
36
+ border: "#27272A", // border-default
37
+ primary: "#5B8DEF", // brand-primary
38
+ positive: "#4ADE80", // status-positive
39
+ negative: "#F87171", // status-negative
40
+ bitcoin: "#F7931A", // bitcoin-accent
41
+ neutralBg: "#27272A", // surface-muted
42
+ },
43
+ };
44
+ const TIER_ACCENT_COLORS = {
45
+ BRONZE: "#C7742A",
46
+ SILVER: "#BFC6CE",
47
+ GOLD: "#F3BC3C",
48
+ PLATINUM: "#63CBB2",
49
+ DIAMOND: "#5EC0F2",
50
+ };
51
+ function shortenAddress(address) {
52
+ return `${address.slice(0, 6)}…${address.slice(-4)}`;
53
+ }
54
+ function resolveDisplayName(displayName) {
55
+ const resolved = displayName?.trim();
56
+ return resolved ? resolved : null;
57
+ }
58
+ function formatProfilePnl(value) {
59
+ const sign = value >= 0 ? "+" : "-";
60
+ return `${sign}$${Math.abs(value).toFixed(2)}`;
61
+ }
62
+ function formatProfileRoi(value) {
63
+ return `${value >= 0 ? "+" : ""}${value.toFixed(1)}%`;
64
+ }
65
+ function formatBestMult(value) {
66
+ if (value == null || value <= 1)
67
+ return "—";
68
+ return `${value.toFixed(2)}×`;
69
+ }
70
+ function getSignedValueColor(value, theme) {
71
+ if (value > 0)
72
+ return theme.positive;
73
+ if (value < 0)
74
+ return theme.negative;
75
+ return theme.inkMuted;
76
+ }
77
+ function normalizeStatus(status) {
78
+ if (status === "OPEN" ||
79
+ status === "WIN" ||
80
+ status === "LOSS" ||
81
+ status === "CLOSED") {
82
+ return status;
83
+ }
84
+ if (status === "PENDING") {
85
+ return "OPEN";
86
+ }
87
+ return null;
88
+ }
89
+ function normalizePositions(positions) {
90
+ const normalized = [];
91
+ positions.forEach((position) => {
92
+ const status = normalizeStatus(position.status);
93
+ if (status == null)
94
+ return;
95
+ normalized.push({
96
+ ...position,
97
+ status,
98
+ });
99
+ });
100
+ return normalized;
101
+ }
102
+ function buildMainText(input) {
103
+ if (input.hideWallet)
104
+ return "A Signals trader";
105
+ return resolveDisplayName(input.displayName) ?? shortenAddress(input.address);
106
+ }
107
+ function buildSubline(input) {
108
+ const callCopy = `${input.totalCalls} BTC range calls`;
109
+ if (input.hideWallet)
110
+ return callCopy;
111
+ const parts = [];
112
+ if (resolveDisplayName(input.displayName) !== null) {
113
+ parts.push(shortenAddress(input.address));
114
+ }
115
+ if (input.twitter) {
116
+ parts.push(`@${input.twitter}`);
117
+ }
118
+ parts.push(callCopy);
119
+ return parts.join(" · ");
120
+ }
121
+ function getPriceTickStep(span) {
122
+ const target = span / 4;
123
+ const candidates = [
124
+ 500,
125
+ 1000,
126
+ 2500,
127
+ 5000,
128
+ 10000,
129
+ 25000,
130
+ 50000,
131
+ 100000,
132
+ 250000,
133
+ 500000,
134
+ 1000000,
135
+ ];
136
+ return candidates.find((step) => step >= target) ?? 1000000;
137
+ }
138
+ function getExpandedPriceBounds(min, max) {
139
+ const span = max - min;
140
+ const step = getPriceTickStep(span);
141
+ return {
142
+ min: Math.floor(min / step) * step,
143
+ max: Math.ceil(max / step) * step,
144
+ step,
145
+ };
146
+ }
147
+ function getPriceTicks(min, max, step) {
148
+ const ticks = [];
149
+ for (let tick = min; tick <= max + step / 2; tick += step) {
150
+ ticks.push(tick);
151
+ if (ticks.length >= 6)
152
+ break;
153
+ }
154
+ return ticks.length > 0 ? ticks : [min, max];
155
+ }
156
+ function formatAxisLabel(value) {
157
+ if (Math.abs(value) >= 1000) {
158
+ return `$${Math.round(value / 1000)}k`;
159
+ }
160
+ return `$${Math.round(value)}`;
161
+ }
162
+ function computePriceBounds(btcHistory, positions) {
163
+ let rawMin = Infinity;
164
+ let rawMax = -Infinity;
165
+ let hasPrices = false;
166
+ btcHistory.forEach((point) => {
167
+ if (point.close < rawMin)
168
+ rawMin = point.close;
169
+ if (point.close > rawMax)
170
+ rawMax = point.close;
171
+ hasPrices = true;
172
+ });
173
+ positions.forEach((position) => {
174
+ if (position.lowerPrice < rawMin)
175
+ rawMin = position.lowerPrice;
176
+ if (position.lowerPrice > rawMax)
177
+ rawMax = position.lowerPrice;
178
+ if (position.upperPrice < rawMin)
179
+ rawMin = position.upperPrice;
180
+ if (position.upperPrice > rawMax)
181
+ rawMax = position.upperPrice;
182
+ hasPrices = true;
183
+ if (position.settlementPrice != null) {
184
+ if (position.settlementPrice < rawMin)
185
+ rawMin = position.settlementPrice;
186
+ if (position.settlementPrice > rawMax)
187
+ rawMax = position.settlementPrice;
188
+ }
189
+ });
190
+ if (!hasPrices)
191
+ return null;
192
+ const span = rawMax - rawMin;
193
+ const padding = span === 0 ? 500 : span * 0.1;
194
+ return {
195
+ min: rawMin - padding,
196
+ max: rawMax + padding,
197
+ };
198
+ }
199
+ function computeTimeBounds(btcHistory, positions) {
200
+ let min = Infinity;
201
+ let max = -Infinity;
202
+ let hasTimes = false;
203
+ if (btcHistory.length > 0) {
204
+ const first = btcHistory[0].t;
205
+ const last = btcHistory[btcHistory.length - 1].t;
206
+ min = Math.min(first, last);
207
+ max = Math.max(first, last);
208
+ hasTimes = true;
209
+ }
210
+ positions.forEach((position) => {
211
+ if (position.marketEndTimestampMs < min)
212
+ min = position.marketEndTimestampMs;
213
+ if (position.marketEndTimestampMs > max)
214
+ max = position.marketEndTimestampMs;
215
+ hasTimes = true;
216
+ });
217
+ if (!hasTimes)
218
+ return null;
219
+ return {
220
+ min,
221
+ max,
222
+ };
223
+ }
224
+ function buildHistoryPath(btcHistory, scaleX, scaleY) {
225
+ return btcHistory
226
+ .map((point, index) => {
227
+ const command = index === 0 ? "M" : "L";
228
+ return `${command} ${scaleX(point.t).toFixed(2)} ${scaleY(point.close).toFixed(2)}`;
229
+ })
230
+ .join(" ");
231
+ }
232
+ function buildChartArea(theme, btcHistory, positions) {
233
+ const normalizedPositions = normalizePositions(positions);
234
+ const renderablePositions = normalizedPositions.filter((position) => position.status !== "CLOSED");
235
+ const sortedHistory = [...btcHistory].sort((a, b) => a.t - b.t);
236
+ if (btcHistory.length === 0 && renderablePositions.length === 0) {
237
+ return (0, h_1.h)("div", {
238
+ style: {
239
+ width: CHART_WIDTH,
240
+ height: CHART_HEIGHT,
241
+ display: "flex",
242
+ alignItems: "center",
243
+ justifyContent: "center",
244
+ background: theme.neutralBg,
245
+ border: `1px solid ${theme.border}`,
246
+ borderRadius: 20,
247
+ color: theme.inkMuted,
248
+ fontSize: 16,
249
+ fontWeight: 500,
250
+ overflow: "hidden",
251
+ },
252
+ }, "BTC history unavailable");
253
+ }
254
+ const bounds = computePriceBounds(sortedHistory, renderablePositions);
255
+ const timeBounds = computeTimeBounds(sortedHistory, renderablePositions);
256
+ if (!bounds || !timeBounds) {
257
+ return (0, h_1.h)("div", {
258
+ style: {
259
+ width: CHART_WIDTH,
260
+ height: CHART_HEIGHT,
261
+ display: "flex",
262
+ background: theme.neutralBg,
263
+ border: `1px solid ${theme.border}`,
264
+ borderRadius: 20,
265
+ },
266
+ });
267
+ }
268
+ const plotWidth = CHART_WIDTH - PLOT_LEFT - PLOT_RIGHT;
269
+ const plotHeight = CHART_HEIGHT - PLOT_TOP - PLOT_BOTTOM;
270
+ const timeMin = timeBounds.min;
271
+ const timeMax = timeBounds.max;
272
+ const priceBounds = getExpandedPriceBounds(bounds.min, bounds.max);
273
+ const scaleX = (value) => {
274
+ if (timeMin === timeMax) {
275
+ return PLOT_LEFT + plotWidth / 2;
276
+ }
277
+ return PLOT_LEFT + ((value - timeMin) / (timeMax - timeMin)) * plotWidth;
278
+ };
279
+ const scaleY = (value) => {
280
+ if (priceBounds.max === priceBounds.min) {
281
+ return PLOT_TOP + plotHeight / 2;
282
+ }
283
+ return (PLOT_TOP +
284
+ (1 -
285
+ (value - priceBounds.min) / (priceBounds.max - priceBounds.min)) *
286
+ plotHeight);
287
+ };
288
+ const priceTicks = getPriceTicks(priceBounds.min, priceBounds.max, priceBounds.step);
289
+ const hasOpenPositions = renderablePositions.some((position) => position.status === "OPEN");
290
+ const svgChildren = [];
291
+ if (hasOpenPositions) {
292
+ svgChildren.push((0, h_1.h)("defs", null, (0, h_1.h)("pattern", {
293
+ id: "profile-open-band",
294
+ width: 8,
295
+ height: 8,
296
+ patternUnits: "userSpaceOnUse",
297
+ }, (0, h_1.h)("path", {
298
+ d: "M-2 8 L8 -2 M0 10 L10 0 M2 12 L12 2",
299
+ stroke: theme.bitcoin,
300
+ strokeWidth: 2,
301
+ }))));
302
+ }
303
+ priceTicks.forEach((tick) => {
304
+ const y = scaleY(tick);
305
+ svgChildren.push((0, h_1.h)("line", {
306
+ x1: PLOT_LEFT,
307
+ x2: PLOT_LEFT + plotWidth,
308
+ y1: y,
309
+ y2: y,
310
+ stroke: theme.border,
311
+ strokeDasharray: "2 3",
312
+ strokeWidth: 1,
313
+ }));
314
+ });
315
+ renderablePositions.forEach((position) => {
316
+ const topPrice = Math.max(position.lowerPrice, position.upperPrice);
317
+ const bottomPrice = Math.min(position.lowerPrice, position.upperPrice);
318
+ const x = scaleX(position.marketEndTimestampMs) - BAND_WIDTH / 2;
319
+ const top = scaleY(topPrice);
320
+ const bottom = scaleY(bottomPrice);
321
+ const height = Math.max(bottom - top, 6);
322
+ if (position.status === "OPEN") {
323
+ svgChildren.push((0, h_1.h)("rect", {
324
+ x,
325
+ y: top,
326
+ width: BAND_WIDTH,
327
+ height,
328
+ rx: 6,
329
+ fill: "url(#profile-open-band)",
330
+ stroke: theme.bitcoin,
331
+ strokeWidth: 2,
332
+ }));
333
+ return;
334
+ }
335
+ const fill = position.status === "WIN" ? theme.primary : theme.negative;
336
+ const fillOpacity = position.status === "WIN" ? 0.55 : 0.28;
337
+ svgChildren.push((0, h_1.h)("rect", {
338
+ x,
339
+ y: top,
340
+ width: BAND_WIDTH,
341
+ height,
342
+ rx: 6,
343
+ fill,
344
+ fillOpacity,
345
+ stroke: fill,
346
+ strokeOpacity: 0.9,
347
+ }));
348
+ });
349
+ if (sortedHistory.length === 1) {
350
+ svgChildren.push((0, h_1.h)("circle", {
351
+ cx: scaleX(sortedHistory[0].t),
352
+ cy: scaleY(sortedHistory[0].close),
353
+ r: 5,
354
+ fill: theme.ink,
355
+ }));
356
+ }
357
+ else if (sortedHistory.length > 1) {
358
+ svgChildren.push((0, h_1.h)("path", {
359
+ d: buildHistoryPath(sortedHistory, scaleX, scaleY),
360
+ fill: "none",
361
+ stroke: theme.ink,
362
+ strokeWidth: 2,
363
+ strokeLinecap: "round",
364
+ strokeLinejoin: "round",
365
+ }));
366
+ }
367
+ renderablePositions.forEach((position) => {
368
+ if ((position.status === "WIN" || position.status === "LOSS") &&
369
+ position.settlementPrice != null) {
370
+ svgChildren.push((0, h_1.h)("circle", {
371
+ cx: scaleX(position.marketEndTimestampMs),
372
+ cy: scaleY(position.settlementPrice),
373
+ r: 4.5,
374
+ fill: position.status === "WIN" ? theme.primary : theme.negative,
375
+ }));
376
+ }
377
+ });
378
+ const labelNodes = priceTicks.map((tick) => (0, h_1.h)("div", {
379
+ style: {
380
+ position: "absolute",
381
+ left: 12,
382
+ top: scaleY(tick) - 9,
383
+ display: "flex",
384
+ fontSize: 13,
385
+ fontWeight: 500,
386
+ color: theme.inkMuted,
387
+ background: theme.card,
388
+ padding: "0 4px",
389
+ },
390
+ }, formatAxisLabel(tick)));
391
+ return (0, h_1.h)("div", {
392
+ style: {
393
+ width: CHART_WIDTH,
394
+ height: CHART_HEIGHT,
395
+ display: "flex",
396
+ position: "relative",
397
+ overflow: "hidden",
398
+ background: theme.neutralBg,
399
+ border: `1px solid ${theme.border}`,
400
+ borderRadius: 20,
401
+ },
402
+ }, (0, h_1.h)("svg", {
403
+ width: CHART_WIDTH,
404
+ height: CHART_HEIGHT,
405
+ viewBox: `0 0 ${CHART_WIDTH} ${CHART_HEIGHT}`,
406
+ style: {
407
+ position: "absolute",
408
+ inset: 0,
409
+ display: "flex",
410
+ pointerEvents: "none",
411
+ },
412
+ }, ...svgChildren), ...labelNodes);
413
+ }
414
+ function buildStatCard(label, value, valueColor, theme) {
415
+ return (0, h_1.h)("div", {
416
+ style: {
417
+ flex: 1,
418
+ display: "flex",
419
+ flexDirection: "column",
420
+ padding: "16px 18px",
421
+ borderRadius: 18,
422
+ border: `1px solid ${theme.border}`,
423
+ background: theme.neutralBg,
424
+ },
425
+ }, (0, h_1.h)("div", {
426
+ style: {
427
+ display: "flex",
428
+ fontSize: 14,
429
+ fontWeight: 500,
430
+ color: theme.inkMuted,
431
+ marginBottom: 10,
432
+ },
433
+ }, label), (0, h_1.h)("div", {
434
+ style: {
435
+ display: "flex",
436
+ fontSize: 28,
437
+ lineHeight: 1.1,
438
+ fontWeight: 700,
439
+ color: valueColor,
440
+ },
441
+ }, value));
442
+ }
443
+ function buildProfileVNode(input) {
444
+ const theme = OG_THEMES[input.theme];
445
+ const accent = TIER_ACCENT_COLORS[input.tier];
446
+ const mainText = buildMainText(input);
447
+ const subline = buildSubline(input);
448
+ const pnlValue = input.hideAmounts ? "••••" : formatProfilePnl(input.totalPnl);
449
+ const roiValue = formatProfileRoi(input.roi);
450
+ const bestMultValue = formatBestMult(input.bestMult);
451
+ return (0, h_1.h)("div", {
452
+ style: {
453
+ width: CARD_WIDTH,
454
+ height: CARD_HEIGHT,
455
+ display: "flex",
456
+ padding: OUTER_PADDING,
457
+ fontFamily: "Inter",
458
+ background: `linear-gradient(135deg, ${theme.pageBg}, ${theme.card})`,
459
+ },
460
+ }, (0, h_1.h)("div", {
461
+ style: {
462
+ flex: 1,
463
+ display: "flex",
464
+ flexDirection: "column",
465
+ padding: `${CARD_PADDING_Y}px ${CARD_PADDING_X}px`,
466
+ background: theme.card,
467
+ border: `1px solid ${theme.border}`,
468
+ borderRadius: 24,
469
+ },
470
+ }, (0, h_1.h)("div", {
471
+ style: {
472
+ display: "flex",
473
+ alignItems: "center",
474
+ justifyContent: "space-between",
475
+ },
476
+ }, (0, h_1.h)("div", {
477
+ style: {
478
+ display: "flex",
479
+ alignItems: "center",
480
+ gap: 10,
481
+ },
482
+ }, (0, h_1.h)("img", {
483
+ src: assets_1.SIGNALS_LOGO_URI,
484
+ width: 34,
485
+ height: 32,
486
+ style: { display: "flex" },
487
+ }), (0, h_1.h)("div", {
488
+ style: {
489
+ display: "flex",
490
+ fontSize: 28,
491
+ fontWeight: 700,
492
+ color: theme.primary,
493
+ },
494
+ }, "Signals")), (0, h_1.h)("div", {
495
+ style: {
496
+ display: "flex",
497
+ fontSize: 18,
498
+ fontWeight: 700,
499
+ letterSpacing: "0.04em",
500
+ textTransform: "uppercase",
501
+ color: accent,
502
+ },
503
+ }, input.tier)), (0, h_1.h)("div", {
504
+ style: {
505
+ flex: 1,
506
+ display: "flex",
507
+ flexDirection: "column",
508
+ marginTop: 20,
509
+ },
510
+ }, (0, h_1.h)("div", {
511
+ style: {
512
+ display: "flex",
513
+ flexDirection: "column",
514
+ },
515
+ }, (0, h_1.h)("div", {
516
+ style: {
517
+ display: "flex",
518
+ fontSize: 52,
519
+ lineHeight: 1.05,
520
+ fontWeight: 700,
521
+ color: theme.ink,
522
+ marginBottom: 10,
523
+ },
524
+ }, mainText), (0, h_1.h)("div", {
525
+ style: {
526
+ display: "flex",
527
+ fontSize: 20,
528
+ fontWeight: 500,
529
+ color: theme.inkMuted,
530
+ },
531
+ }, subline)), (0, h_1.h)("div", {
532
+ style: {
533
+ display: "flex",
534
+ marginTop: 24,
535
+ },
536
+ }, buildChartArea(theme, input.btcHistory, input.positions)), (0, h_1.h)("div", {
537
+ style: {
538
+ display: "flex",
539
+ gap: 16,
540
+ marginTop: 20,
541
+ },
542
+ }, buildStatCard("P&L", pnlValue, getSignedValueColor(input.totalPnl, theme), theme), buildStatCard("ROI", roiValue, getSignedValueColor(input.roi, theme), theme), buildStatCard("Best call", bestMultValue, theme.primary, theme)), (0, h_1.h)("div", {
543
+ style: {
544
+ display: "flex",
545
+ justifyContent: "flex-end",
546
+ marginTop: 16,
547
+ fontSize: 13,
548
+ fontWeight: 500,
549
+ color: theme.inkMuted,
550
+ },
551
+ }, "signals.wtf · Pick your range"))));
552
+ }
@@ -22,6 +22,39 @@ export interface PositionImageInput {
22
22
  /** Current position value in USDC (NOT raw). null = use max payout fallback. */
23
23
  currentValue: number | null;
24
24
  }
25
+ export interface ProfileChartPosition {
26
+ lowerPrice: number;
27
+ upperPrice: number;
28
+ settlementPrice: number | null;
29
+ status: "OPEN" | "WIN" | "LOSS" | "CLOSED";
30
+ marketEndTimestampMs: number;
31
+ }
32
+ export interface ProfileImageInput {
33
+ displayName: string | null;
34
+ address: string;
35
+ twitter: string | null;
36
+ tier: "BRONZE" | "SILVER" | "GOLD" | "PLATINUM" | "DIAMOND";
37
+ totalCalls: number;
38
+ totalPnl: number;
39
+ roi: number;
40
+ bestMult: number | null;
41
+ /**
42
+ * BTC daily close timeline.
43
+ *
44
+ * Must be sorted ascending by `t` (UNIX ms). Adapters should pass
45
+ * ordered data, and the builder defensively re-sorts a shallow copy
46
+ * before rendering so chart bounds and SVG path order stay correct
47
+ * even if input arrives out of order.
48
+ */
49
+ btcHistory: Array<{
50
+ t: number;
51
+ close: number;
52
+ }>;
53
+ positions: ProfileChartPosition[];
54
+ theme: "light" | "dark";
55
+ hideWallet: boolean;
56
+ hideAmounts: boolean;
57
+ }
25
58
  export type BarCategory = "peak" | "high" | "mid" | "low";
26
59
  export interface PriceTick {
27
60
  tick: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signals-protocol/v1-sdk",
3
- "version": "1.2.0",
3
+ "version": "1.4.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",
@@ -13,6 +13,7 @@
13
13
  "test:watch": "jest --watch",
14
14
  "npm:auth": "node scripts/write-npmrc.js",
15
15
  "publish:package": "NPM_CONFIG_USERCONFIG=.npmrc.auth npm publish",
16
+ "prepack": "yarn rebuild",
16
17
  "lint": "eslint src/**/*.ts",
17
18
  "format": "prettier --write src/**/*.ts",
18
19
  "clean": "rm -rf dist",
@@ -44,8 +45,7 @@
44
45
  "typescript": "^5.0.0"
45
46
  },
46
47
  "dependencies": {
47
- "big.js": "^6.2.1",
48
- "ethers": "^6.14.3"
48
+ "big.js": "^6.2.1"
49
49
  },
50
50
  "files": [
51
51
  "dist"