@signals-protocol/v1-sdk 1.0.0 → 1.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.
- package/dist/clmsr-sdk.js +47 -17
- package/dist/fees.d.ts +15 -2
- package/dist/fees.js +120 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/types.d.ts +11 -1
- package/dist/types.js +4 -0
- package/package.json +1 -1
package/dist/clmsr-sdk.js
CHANGED
|
@@ -99,7 +99,7 @@ class CLMSRSDK {
|
|
|
99
99
|
// cost는 micro USDC, quantity도 micro USDC이므로 결과는 USDC/USDC = 비율
|
|
100
100
|
const averagePrice = cost.div(normalizedQuantity);
|
|
101
101
|
const formattedAveragePrice = new big_js_1.default(averagePrice.toFixed(6, big_js_1.default.roundDown)); // 6자리 정밀도로 충분
|
|
102
|
-
const feeOverlay = this.computeFeeOverlay("BUY", cost, normalizedQuantity, lowerTick, upperTick, market.feePolicyDescriptor);
|
|
102
|
+
const feeOverlay = this.computeFeeOverlay("BUY", cost, normalizedQuantity, lowerTick, upperTick, market.feePolicyDescriptor, market.endTimestamp);
|
|
103
103
|
const result = {
|
|
104
104
|
cost,
|
|
105
105
|
averagePrice: formattedAveragePrice,
|
|
@@ -128,7 +128,7 @@ class CLMSRSDK {
|
|
|
128
128
|
calculateDecreaseProceeds(position, sellQuantity, distribution, market) {
|
|
129
129
|
const normalizedSellQuantity = MathUtils.formatUSDC(new big_js_1.default(sellQuantity));
|
|
130
130
|
const baseResult = this._calcSellProceeds(position.lowerTick, position.upperTick, normalizedSellQuantity, position.quantity, distribution, market);
|
|
131
|
-
const feeOverlay = this.computeFeeOverlay("SELL", baseResult.proceeds, normalizedSellQuantity, position.lowerTick, position.upperTick, market.feePolicyDescriptor);
|
|
131
|
+
const feeOverlay = this.computeFeeOverlay("SELL", baseResult.proceeds, normalizedSellQuantity, position.lowerTick, position.upperTick, market.feePolicyDescriptor, market.endTimestamp);
|
|
132
132
|
return {
|
|
133
133
|
proceeds: baseResult.proceeds,
|
|
134
134
|
averagePrice: baseResult.averagePrice,
|
|
@@ -244,7 +244,7 @@ class CLMSRSDK {
|
|
|
244
244
|
return this._calculateQuantityFromNetCost(lowerTick, upperTick, targetSpend, distribution, market);
|
|
245
245
|
}
|
|
246
246
|
const zeroBase = MathUtils.formatUSDC(new big_js_1.default(0));
|
|
247
|
-
const minSpend = this._computeTotalSpendWithFees(zeroBase, zeroBase, lowerTick, upperTick, descriptor);
|
|
247
|
+
const minSpend = this._computeTotalSpendWithFees(zeroBase, zeroBase, lowerTick, upperTick, descriptor, market.endTimestamp);
|
|
248
248
|
if (targetSpend.lt(minSpend)) {
|
|
249
249
|
throw new types_1.ValidationError("Target cost is below the minimum spend achievable after fees");
|
|
250
250
|
}
|
|
@@ -263,7 +263,7 @@ class CLMSRSDK {
|
|
|
263
263
|
netGuess = new big_js_1.default(0);
|
|
264
264
|
}
|
|
265
265
|
let bestResult = this._calculateQuantityFromNetCost(lowerTick, upperTick, netGuess, distribution, market);
|
|
266
|
-
let bestDiff = this._computeTotalSpendWithFees(bestResult.actualCost, bestResult.quantity, lowerTick, upperTick, descriptor).minus(targetSpend);
|
|
266
|
+
let bestDiff = this._computeTotalSpendWithFees(bestResult.actualCost, bestResult.quantity, lowerTick, upperTick, descriptor, market.endTimestamp).minus(targetSpend);
|
|
267
267
|
if (bestDiff.abs().lte(INVERSE_SPEND_TOLERANCE)) {
|
|
268
268
|
return bestResult;
|
|
269
269
|
}
|
|
@@ -290,7 +290,7 @@ class CLMSRSDK {
|
|
|
290
290
|
}
|
|
291
291
|
seen.add(key);
|
|
292
292
|
const boundaryCandidate = this._calculateQuantityFromNetCost(lowerTick, upperTick, boundary, distribution, market);
|
|
293
|
-
const boundaryTotal = this._computeTotalSpendWithFees(boundaryCandidate.actualCost, boundaryCandidate.quantity, lowerTick, upperTick, descriptor);
|
|
293
|
+
const boundaryTotal = this._computeTotalSpendWithFees(boundaryCandidate.actualCost, boundaryCandidate.quantity, lowerTick, upperTick, descriptor, market.endTimestamp);
|
|
294
294
|
const boundaryDiff = boundaryTotal.minus(targetSpend);
|
|
295
295
|
if (boundaryDiff.abs().lt(bestDiff.abs())) {
|
|
296
296
|
bestResult = boundaryCandidate;
|
|
@@ -300,7 +300,7 @@ class CLMSRSDK {
|
|
|
300
300
|
break;
|
|
301
301
|
}
|
|
302
302
|
const candidate = this._calculateQuantityFromNetCost(lowerTick, upperTick, MathUtils.formatUSDC(midFormatted), distribution, market);
|
|
303
|
-
const totalSpend = this._computeTotalSpendWithFees(candidate.actualCost, candidate.quantity, lowerTick, upperTick, descriptor);
|
|
303
|
+
const totalSpend = this._computeTotalSpendWithFees(candidate.actualCost, candidate.quantity, lowerTick, upperTick, descriptor, market.endTimestamp);
|
|
304
304
|
const diff = totalSpend.minus(targetSpend);
|
|
305
305
|
if (diff.abs().lt(bestDiff.abs())) {
|
|
306
306
|
bestResult = candidate;
|
|
@@ -368,7 +368,7 @@ class CLMSRSDK {
|
|
|
368
368
|
// Calculate fee information for the final result
|
|
369
369
|
const formattedActualCost = MathUtils.formatUSDC(actualCost);
|
|
370
370
|
const formattedQuantity = MathUtils.formatUSDC(quantity);
|
|
371
|
-
const feeOverlay = this.computeFeeOverlay("BUY", formattedActualCost, formattedQuantity, lowerTick, upperTick, market.feePolicyDescriptor);
|
|
371
|
+
const feeOverlay = this.computeFeeOverlay("BUY", formattedActualCost, formattedQuantity, lowerTick, upperTick, market.feePolicyDescriptor, market.endTimestamp);
|
|
372
372
|
return {
|
|
373
373
|
quantity: formattedQuantity,
|
|
374
374
|
actualCost: formattedActualCost,
|
|
@@ -377,10 +377,10 @@ class CLMSRSDK {
|
|
|
377
377
|
feeInfo: feeOverlay.info,
|
|
378
378
|
};
|
|
379
379
|
}
|
|
380
|
-
_computeTotalSpendWithFees(baseAmount, quantity, lowerTick, upperTick, descriptor) {
|
|
380
|
+
_computeTotalSpendWithFees(baseAmount, quantity, lowerTick, upperTick, descriptor, endTimestamp) {
|
|
381
381
|
const formattedBase = MathUtils.formatUSDC(baseAmount);
|
|
382
382
|
const formattedQuantity = MathUtils.formatUSDC(quantity);
|
|
383
|
-
const feeOverlay = this.computeFeeOverlay("BUY", formattedBase, formattedQuantity, lowerTick, upperTick, descriptor);
|
|
383
|
+
const feeOverlay = this.computeFeeOverlay("BUY", formattedBase, formattedQuantity, lowerTick, upperTick, descriptor, endTimestamp);
|
|
384
384
|
return MathUtils.formatUSDC(formattedBase.plus(feeOverlay.amount));
|
|
385
385
|
}
|
|
386
386
|
/**
|
|
@@ -457,7 +457,7 @@ class CLMSRSDK {
|
|
|
457
457
|
}
|
|
458
458
|
let baseGuess = MathUtils.formatUSDC(initialGuess);
|
|
459
459
|
let bestResult = this._calculateQuantityFromBaseProceeds(position, baseGuess, distribution, market);
|
|
460
|
-
let bestNet = this._computeNetProceedsAfterFees(bestResult.actualProceeds, bestResult.quantity, position.lowerTick, position.upperTick, descriptor);
|
|
460
|
+
let bestNet = this._computeNetProceedsAfterFees(bestResult.actualProceeds, bestResult.quantity, position.lowerTick, position.upperTick, descriptor, market.endTimestamp);
|
|
461
461
|
let bestDiff = bestNet.minus(targetNetProceeds);
|
|
462
462
|
if (bestDiff.abs().lte(INVERSE_SPEND_TOLERANCE)) {
|
|
463
463
|
return bestResult;
|
|
@@ -487,7 +487,7 @@ class CLMSRSDK {
|
|
|
487
487
|
}
|
|
488
488
|
seen.add(key);
|
|
489
489
|
const boundaryCandidate = this._calculateQuantityFromBaseProceeds(position, boundary, distribution, market);
|
|
490
|
-
const boundaryNet = this._computeNetProceedsAfterFees(boundaryCandidate.actualProceeds, boundaryCandidate.quantity, position.lowerTick, position.upperTick, descriptor);
|
|
490
|
+
const boundaryNet = this._computeNetProceedsAfterFees(boundaryCandidate.actualProceeds, boundaryCandidate.quantity, position.lowerTick, position.upperTick, descriptor, market.endTimestamp);
|
|
491
491
|
const boundaryDiff = boundaryNet.minus(targetNetProceeds);
|
|
492
492
|
if (boundaryDiff.abs().lt(bestDiff.abs())) {
|
|
493
493
|
bestResult = boundaryCandidate;
|
|
@@ -497,7 +497,7 @@ class CLMSRSDK {
|
|
|
497
497
|
break;
|
|
498
498
|
}
|
|
499
499
|
const candidate = this._calculateQuantityFromBaseProceeds(position, MathUtils.formatUSDC(midFormatted), distribution, market);
|
|
500
|
-
const candidateNet = this._computeNetProceedsAfterFees(candidate.actualProceeds, candidate.quantity, position.lowerTick, position.upperTick, descriptor);
|
|
500
|
+
const candidateNet = this._computeNetProceedsAfterFees(candidate.actualProceeds, candidate.quantity, position.lowerTick, position.upperTick, descriptor, market.endTimestamp);
|
|
501
501
|
const diff = candidateNet.minus(targetNetProceeds);
|
|
502
502
|
if (diff.abs().lt(bestDiff.abs())) {
|
|
503
503
|
bestResult = candidate;
|
|
@@ -799,7 +799,7 @@ class CLMSRSDK {
|
|
|
799
799
|
console.warn("calculateQuantityFromProceeds: verification failed, using target proceeds as approximation", error);
|
|
800
800
|
}
|
|
801
801
|
// Calculate fee information
|
|
802
|
-
const feeOverlay = this.computeFeeOverlay("SELL", actualProceeds, formattedQuantity, position.lowerTick, position.upperTick, market.feePolicyDescriptor);
|
|
802
|
+
const feeOverlay = this.computeFeeOverlay("SELL", actualProceeds, formattedQuantity, position.lowerTick, position.upperTick, market.feePolicyDescriptor, market.endTimestamp);
|
|
803
803
|
return {
|
|
804
804
|
quantity: formattedQuantity,
|
|
805
805
|
actualProceeds: MathUtils.formatUSDC(actualProceeds),
|
|
@@ -830,13 +830,13 @@ class CLMSRSDK {
|
|
|
830
830
|
averagePrice: formattedAveragePrice,
|
|
831
831
|
};
|
|
832
832
|
}
|
|
833
|
-
_computeNetProceedsAfterFees(baseProceeds, quantity, lowerTick, upperTick, descriptor) {
|
|
833
|
+
_computeNetProceedsAfterFees(baseProceeds, quantity, lowerTick, upperTick, descriptor, endTimestamp) {
|
|
834
834
|
const formattedBase = MathUtils.formatUSDC(baseProceeds);
|
|
835
835
|
const formattedQuantity = MathUtils.formatUSDC(quantity);
|
|
836
|
-
const feeOverlay = this.computeFeeOverlay("SELL", formattedBase, formattedQuantity, lowerTick, upperTick, descriptor);
|
|
836
|
+
const feeOverlay = this.computeFeeOverlay("SELL", formattedBase, formattedQuantity, lowerTick, upperTick, descriptor, endTimestamp);
|
|
837
837
|
return MathUtils.formatUSDC(formattedBase.minus(feeOverlay.amount));
|
|
838
838
|
}
|
|
839
|
-
computeFeeOverlay(side, baseAmount, quantity, lowerTick, upperTick, descriptor) {
|
|
839
|
+
computeFeeOverlay(side, baseAmount, quantity, lowerTick, upperTick, descriptor, endTimestamp) {
|
|
840
840
|
const makeZeroOverlay = (descriptorString, policyName) => ({
|
|
841
841
|
amount: MathUtils.formatUSDC(new big_js_1.default(0)),
|
|
842
842
|
rate: new big_js_1.default(0),
|
|
@@ -854,7 +854,15 @@ class CLMSRSDK {
|
|
|
854
854
|
const quantityInt = bigToBigInt(quantity);
|
|
855
855
|
const trader = ZERO_ADDRESS;
|
|
856
856
|
const marketId = 0;
|
|
857
|
-
|
|
857
|
+
let context = ZERO_CONTEXT;
|
|
858
|
+
if (resolved.descriptor?.policy === "theta-time") {
|
|
859
|
+
if (endTimestamp === undefined || endTimestamp === null) {
|
|
860
|
+
throw new types_1.ValidationError("ThetaTime fee policy requires market.endTimestamp");
|
|
861
|
+
}
|
|
862
|
+
const endTs = BigInt(endTimestamp);
|
|
863
|
+
const hex = endTs.toString(16).padStart(64, "0");
|
|
864
|
+
context = `0x${hex}`;
|
|
865
|
+
}
|
|
858
866
|
const feeBigInt = side === "BUY"
|
|
859
867
|
? (0, fees_1.quoteOpenFee)(resolved.policy, {
|
|
860
868
|
trader,
|
|
@@ -895,6 +903,28 @@ class CLMSRSDK {
|
|
|
895
903
|
},
|
|
896
904
|
};
|
|
897
905
|
}
|
|
906
|
+
if (parsedDescriptor?.policy === "theta-time") {
|
|
907
|
+
const baseBps = new big_js_1.default(parsedDescriptor.baseBps.toString());
|
|
908
|
+
const thetaMaxBps = new big_js_1.default(parsedDescriptor.thetaMaxBps.toString());
|
|
909
|
+
const windowSec = new big_js_1.default(parsedDescriptor.windowSec.toString());
|
|
910
|
+
const beta = new big_js_1.default(parsedDescriptor.beta.toString());
|
|
911
|
+
const rate = baseAmount.gt(0) && feeAmount.gt(0)
|
|
912
|
+
? feeAmount.div(baseAmount)
|
|
913
|
+
: new big_js_1.default(0);
|
|
914
|
+
return {
|
|
915
|
+
amount: feeAmount,
|
|
916
|
+
rate,
|
|
917
|
+
info: {
|
|
918
|
+
policy: types_1.FeePolicyKind.ThetaTime,
|
|
919
|
+
descriptor: descriptorString,
|
|
920
|
+
name: policyName,
|
|
921
|
+
baseBps,
|
|
922
|
+
thetaMaxBps,
|
|
923
|
+
windowSec,
|
|
924
|
+
beta,
|
|
925
|
+
},
|
|
926
|
+
};
|
|
927
|
+
}
|
|
898
928
|
if (parsedDescriptor?.policy === "percentage") {
|
|
899
929
|
const bps = new big_js_1.default(parsedDescriptor.bps.toString());
|
|
900
930
|
const rate = bps.div(new big_js_1.default("10000"));
|
package/dist/fees.d.ts
CHANGED
|
@@ -24,12 +24,21 @@ export interface CustomFeePolicyConfig {
|
|
|
24
24
|
bps: BigNumberish;
|
|
25
25
|
name?: string;
|
|
26
26
|
}
|
|
27
|
+
export interface ThetaTimeFeePolicyConfig {
|
|
28
|
+
baseBps: BigNumberish;
|
|
29
|
+
thetaMaxBps: BigNumberish;
|
|
30
|
+
windowSec: BigNumberish;
|
|
31
|
+
beta: BigNumberish;
|
|
32
|
+
name?: string;
|
|
33
|
+
}
|
|
27
34
|
export declare function createPercentageFeePolicy(config: PercentageFeePolicyConfig): FeePolicy;
|
|
28
35
|
export declare function createCustomFeePolicy(config: CustomFeePolicyConfig): FeePolicy;
|
|
29
|
-
export
|
|
36
|
+
export declare function createThetaTimeFeePolicy(config: ThetaTimeFeePolicyConfig): FeePolicy;
|
|
37
|
+
export type FeePolicyName = "Null" | "Percentage" | "Custom" | "ThetaTime";
|
|
30
38
|
export declare function getFeePolicy(name: "Null"): FeePolicy;
|
|
31
39
|
export declare function getFeePolicy(name: "Percentage", config: PercentageFeePolicyConfig): FeePolicy;
|
|
32
40
|
export declare function getFeePolicy(name: "Custom", config: CustomFeePolicyConfig): FeePolicy;
|
|
41
|
+
export declare function getFeePolicy(name: "ThetaTime", config: ThetaTimeFeePolicyConfig): FeePolicy;
|
|
33
42
|
export interface PreviewOpenFeeArgs {
|
|
34
43
|
trader: string;
|
|
35
44
|
marketId: BigNumberish;
|
|
@@ -49,9 +58,13 @@ export interface PreviewSellFeeArgs {
|
|
|
49
58
|
context?: Bytes32Like;
|
|
50
59
|
}
|
|
51
60
|
interface ParsedFeePolicyDescriptor {
|
|
52
|
-
policy: "null" | "percentage" | "custom";
|
|
61
|
+
policy: "null" | "percentage" | "custom" | "theta-time";
|
|
53
62
|
name?: string;
|
|
54
63
|
bps?: bigint;
|
|
64
|
+
baseBps?: bigint;
|
|
65
|
+
thetaMaxBps?: bigint;
|
|
66
|
+
windowSec?: bigint;
|
|
67
|
+
beta?: bigint;
|
|
55
68
|
descriptor: string;
|
|
56
69
|
}
|
|
57
70
|
export interface EncodePercentageFeePolicyDescriptorParams {
|
package/dist/fees.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.NullFeePolicy = void 0;
|
|
4
4
|
exports.createPercentageFeePolicy = createPercentageFeePolicy;
|
|
5
5
|
exports.createCustomFeePolicy = createCustomFeePolicy;
|
|
6
|
+
exports.createThetaTimeFeePolicy = createThetaTimeFeePolicy;
|
|
6
7
|
exports.getFeePolicy = getFeePolicy;
|
|
7
8
|
exports.resolveFeePolicyWithMetadata = resolveFeePolicyWithMetadata;
|
|
8
9
|
exports.encodePercentageFeePolicyDescriptor = encodePercentageFeePolicyDescriptor;
|
|
@@ -11,6 +12,8 @@ exports.quoteSellFee = quoteSellFee;
|
|
|
11
12
|
const ethers_1 = require("ethers");
|
|
12
13
|
const ZERO_CONTEXT = `0x${"00".repeat(32)}`;
|
|
13
14
|
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
15
|
+
const WAD = 1000000000000000000n;
|
|
16
|
+
const BPS_DENOM = 10000n;
|
|
14
17
|
function toBigInt(value) {
|
|
15
18
|
return (0, ethers_1.toBigInt)(value);
|
|
16
19
|
}
|
|
@@ -23,6 +26,34 @@ function normalizeTrader(trader) {
|
|
|
23
26
|
}
|
|
24
27
|
return trader;
|
|
25
28
|
}
|
|
29
|
+
function decodeEndTimestamp(context) {
|
|
30
|
+
const normalized = normalizeContext(context);
|
|
31
|
+
if (normalized === ZERO_CONTEXT)
|
|
32
|
+
return null;
|
|
33
|
+
try {
|
|
34
|
+
return BigInt(normalized);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function powWad(xWad, exp) {
|
|
41
|
+
if (exp < 1n)
|
|
42
|
+
return WAD;
|
|
43
|
+
let result = WAD;
|
|
44
|
+
let base = xWad;
|
|
45
|
+
let e = exp;
|
|
46
|
+
while (e > 0n) {
|
|
47
|
+
if (e & 1n) {
|
|
48
|
+
result = (result * base) / WAD;
|
|
49
|
+
}
|
|
50
|
+
e >>= 1n;
|
|
51
|
+
if (e > 0n) {
|
|
52
|
+
base = (base * base) / WAD;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
26
57
|
function normalizeMarketId(marketId) {
|
|
27
58
|
if (marketId === undefined || marketId === null) {
|
|
28
59
|
return 0n;
|
|
@@ -39,7 +70,7 @@ function createPercentageFeePolicy(config) {
|
|
|
39
70
|
return {
|
|
40
71
|
name: policyName,
|
|
41
72
|
quote: ({ baseAmount6 }) => {
|
|
42
|
-
return (baseAmount6 * bps) /
|
|
73
|
+
return (baseAmount6 * bps) / BPS_DENOM;
|
|
43
74
|
},
|
|
44
75
|
};
|
|
45
76
|
}
|
|
@@ -49,7 +80,46 @@ function createCustomFeePolicy(config) {
|
|
|
49
80
|
return {
|
|
50
81
|
name: policyName,
|
|
51
82
|
quote: ({ baseAmount6 }) => {
|
|
52
|
-
return (baseAmount6 * bps) /
|
|
83
|
+
return (baseAmount6 * bps) / BPS_DENOM;
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function createThetaTimeFeePolicy(config) {
|
|
88
|
+
const baseBps = toBigInt(config.baseBps);
|
|
89
|
+
const thetaMaxBps = toBigInt(config.thetaMaxBps);
|
|
90
|
+
const windowSec = toBigInt(config.windowSec);
|
|
91
|
+
const beta = toBigInt(config.beta);
|
|
92
|
+
const policyName = config.name ?? "ThetaTimeFeePolicy";
|
|
93
|
+
const baseRateWad = (baseBps * WAD) / BPS_DENOM;
|
|
94
|
+
const thetaMaxRateWad = (thetaMaxBps * WAD) / BPS_DENOM;
|
|
95
|
+
if (windowSec <= 0n) {
|
|
96
|
+
throw new Error("ThetaTime fee policy requires windowSec > 0");
|
|
97
|
+
}
|
|
98
|
+
if (beta < 1n) {
|
|
99
|
+
throw new Error("ThetaTime fee policy requires beta >= 1");
|
|
100
|
+
}
|
|
101
|
+
if (baseBps + thetaMaxBps > BPS_DENOM) {
|
|
102
|
+
throw new Error("ThetaTime fee policy requires baseBps + thetaMaxBps <= 10000");
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
name: policyName,
|
|
106
|
+
quote: ({ baseAmount6, context }) => {
|
|
107
|
+
if (baseAmount6 === 0n)
|
|
108
|
+
return 0n;
|
|
109
|
+
const endTimestamp = decodeEndTimestamp(context);
|
|
110
|
+
if (endTimestamp === null) {
|
|
111
|
+
throw new Error("ThetaTime fee policy requires endTimestamp context");
|
|
112
|
+
}
|
|
113
|
+
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
114
|
+
const tau = endTimestamp > now ? endTimestamp - now : 0n;
|
|
115
|
+
let thetaRateWad = 0n;
|
|
116
|
+
if (tau < windowSec) {
|
|
117
|
+
const xWad = ((windowSec - tau) * WAD) / windowSec;
|
|
118
|
+
const xPow = powWad(xWad, beta);
|
|
119
|
+
thetaRateWad = (thetaMaxRateWad * xPow) / WAD;
|
|
120
|
+
}
|
|
121
|
+
const totalRateWad = baseRateWad + thetaRateWad;
|
|
122
|
+
return (baseAmount6 * totalRateWad) / WAD;
|
|
53
123
|
},
|
|
54
124
|
};
|
|
55
125
|
}
|
|
@@ -57,6 +127,7 @@ const FeePolicies = Object.freeze({
|
|
|
57
127
|
Null: exports.NullFeePolicy,
|
|
58
128
|
Percentage: (config) => createPercentageFeePolicy(config),
|
|
59
129
|
Custom: (config) => createCustomFeePolicy(config),
|
|
130
|
+
ThetaTime: (config) => createThetaTimeFeePolicy(config),
|
|
60
131
|
});
|
|
61
132
|
function getFeePolicy(name, config) {
|
|
62
133
|
if (name === "Null") {
|
|
@@ -74,6 +145,12 @@ function getFeePolicy(name, config) {
|
|
|
74
145
|
}
|
|
75
146
|
return createCustomFeePolicy(config);
|
|
76
147
|
}
|
|
148
|
+
if (name === "ThetaTime") {
|
|
149
|
+
if (!config) {
|
|
150
|
+
throw new Error("ThetaTime fee policy requires configuration");
|
|
151
|
+
}
|
|
152
|
+
return createThetaTimeFeePolicy(config);
|
|
153
|
+
}
|
|
77
154
|
throw new Error(`Unsupported fee policy: ${name}`);
|
|
78
155
|
}
|
|
79
156
|
function buildQuoteParams(side, args) {
|
|
@@ -166,6 +243,34 @@ function parseFeePolicyDescriptor(descriptor) {
|
|
|
166
243
|
descriptor,
|
|
167
244
|
};
|
|
168
245
|
}
|
|
246
|
+
if (normalizedPolicy === "theta-time") {
|
|
247
|
+
const baseBps = parseBigIntParam(paramBag.baseBps, "baseBps", {
|
|
248
|
+
required: true,
|
|
249
|
+
});
|
|
250
|
+
const thetaMaxBps = parseBigIntParam(paramBag.thetaMaxBps, "thetaMaxBps", {
|
|
251
|
+
required: true,
|
|
252
|
+
});
|
|
253
|
+
const windowSec = parseBigIntParam(paramBag.windowSec, "windowSec", {
|
|
254
|
+
required: true,
|
|
255
|
+
});
|
|
256
|
+
const beta = parseBigIntParam(paramBag.beta, "beta", {
|
|
257
|
+
required: true,
|
|
258
|
+
});
|
|
259
|
+
const name = typeof paramBag.name === "string"
|
|
260
|
+
? paramBag.name
|
|
261
|
+
: typeof parsed.name === "string"
|
|
262
|
+
? parsed.name
|
|
263
|
+
: undefined;
|
|
264
|
+
return {
|
|
265
|
+
policy: "theta-time",
|
|
266
|
+
name,
|
|
267
|
+
baseBps,
|
|
268
|
+
thetaMaxBps,
|
|
269
|
+
windowSec,
|
|
270
|
+
beta,
|
|
271
|
+
descriptor,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
169
274
|
throw new Error(`Unsupported fee policy '${policy}' in descriptor`);
|
|
170
275
|
}
|
|
171
276
|
function resolveFeePolicyWithMetadata(input) {
|
|
@@ -195,6 +300,19 @@ function resolveFeePolicyWithMetadata(input) {
|
|
|
195
300
|
descriptor: parsed,
|
|
196
301
|
};
|
|
197
302
|
}
|
|
303
|
+
if (parsed.policy === "theta-time") {
|
|
304
|
+
const thetaPolicy = createThetaTimeFeePolicy({
|
|
305
|
+
baseBps: parsed.baseBps,
|
|
306
|
+
thetaMaxBps: parsed.thetaMaxBps,
|
|
307
|
+
windowSec: parsed.windowSec,
|
|
308
|
+
beta: parsed.beta,
|
|
309
|
+
name: parsed.name,
|
|
310
|
+
});
|
|
311
|
+
return {
|
|
312
|
+
policy: thetaPolicy,
|
|
313
|
+
descriptor: parsed,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
198
316
|
const percentagePolicy = createPercentageFeePolicy({
|
|
199
317
|
bps: parsed.bps,
|
|
200
318
|
name: parsed.name,
|
package/dist/index.d.ts
CHANGED
|
@@ -9,4 +9,4 @@ export { WADAmount, USDCAmount, Quantity, Tick, MarketDistributionRaw, MarketRaw
|
|
|
9
9
|
export * as MathUtils from "./utils/math";
|
|
10
10
|
export { toWAD, toMicroUSDC } from "./clmsr-sdk";
|
|
11
11
|
export { createCLMSRSDK, createSignalsSDK } from "./clmsr-sdk";
|
|
12
|
-
export declare const VERSION = "1.
|
|
12
|
+
export declare const VERSION = "1.1.0";
|
package/dist/index.js
CHANGED
|
@@ -62,4 +62,4 @@ var clmsr_sdk_4 = require("./clmsr-sdk");
|
|
|
62
62
|
Object.defineProperty(exports, "createCLMSRSDK", { enumerable: true, get: function () { return clmsr_sdk_4.createCLMSRSDK; } });
|
|
63
63
|
Object.defineProperty(exports, "createSignalsSDK", { enumerable: true, get: function () { return clmsr_sdk_4.createSignalsSDK; } });
|
|
64
64
|
// Version (keep in sync with package.json)
|
|
65
|
-
exports.VERSION = "1.
|
|
65
|
+
exports.VERSION = "1.1.0";
|
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
|
-
|
|
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
|
}),
|