@stryke-xyz/premarket-sdk 1.2.2 → 1.2.4
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/cjs/api/README.md +296 -0
- package/dist/cjs/config/README.md +112 -0
- package/dist/cjs/config/index.js +4 -4
- package/dist/cjs/exchange/README.md +280 -0
- package/dist/cjs/registry/README.md +150 -0
- package/dist/cjs/shared/README.md +235 -0
- package/dist/cjs/shared/utils.js +1 -0
- package/dist/cjs/sync/README.md +215 -0
- package/dist/cjs/sync/clients/base-client.js +518 -0
- package/dist/cjs/sync/redis-ws-client.js +235 -0
- package/dist/cjs/utils/README.md +89 -0
- package/dist/cjs/vault/README.md +268 -0
- package/dist/esm/api/README.md +296 -0
- package/dist/esm/config/README.md +112 -0
- package/dist/esm/config/index.js +4 -4
- package/dist/esm/exchange/README.md +280 -0
- package/dist/esm/registry/README.md +150 -0
- package/dist/esm/shared/README.md +235 -0
- package/dist/esm/shared/utils.js +0 -0
- package/dist/esm/sync/README.md +215 -0
- package/dist/esm/sync/clients/base-client.js +508 -0
- package/dist/esm/sync/redis-ws-client.js +225 -0
- package/dist/esm/utils/README.md +89 -0
- package/dist/esm/vault/README.md +268 -0
- package/dist/types/shared/utils.d.ts +0 -0
- package/dist/types/sync/clients/base-client.d.ts +56 -0
- package/dist/types/sync/redis-ws-client.d.ts +21 -0
- package/package.json +58 -58
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
function _class_call_check(instance, Constructor) {
|
|
2
|
+
if (!(instance instanceof Constructor)) {
|
|
3
|
+
throw new TypeError("Cannot call a class as a function");
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
function _defineProperties(target, props) {
|
|
7
|
+
for(var i = 0; i < props.length; i++){
|
|
8
|
+
var descriptor = props[i];
|
|
9
|
+
descriptor.enumerable = descriptor.enumerable || false;
|
|
10
|
+
descriptor.configurable = true;
|
|
11
|
+
if ("value" in descriptor) descriptor.writable = true;
|
|
12
|
+
Object.defineProperty(target, descriptor.key, descriptor);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function _create_class(Constructor, protoProps, staticProps) {
|
|
16
|
+
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
17
|
+
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
18
|
+
return Constructor;
|
|
19
|
+
}
|
|
20
|
+
function _define_property(obj, key, value) {
|
|
21
|
+
if (key in obj) {
|
|
22
|
+
Object.defineProperty(obj, key, {
|
|
23
|
+
value: value,
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
writable: true
|
|
27
|
+
});
|
|
28
|
+
} else {
|
|
29
|
+
obj[key] = value;
|
|
30
|
+
}
|
|
31
|
+
return obj;
|
|
32
|
+
}
|
|
33
|
+
function scheduleDeferred(callback) {
|
|
34
|
+
return setTimeout(callback, 1000);
|
|
35
|
+
}
|
|
36
|
+
export var RedisWsClient = /*#__PURE__*/ function() {
|
|
37
|
+
"use strict";
|
|
38
|
+
function RedisWsClient(url) {
|
|
39
|
+
_class_call_check(this, RedisWsClient);
|
|
40
|
+
_define_property(this, "url", void 0);
|
|
41
|
+
_define_property(this, "ws", void 0);
|
|
42
|
+
_define_property(this, "handlers", void 0);
|
|
43
|
+
_define_property(this, "heartbeat", void 0);
|
|
44
|
+
_define_property(this, "reconnectTimeout", void 0);
|
|
45
|
+
_define_property(this, "shouldReconnect", void 0);
|
|
46
|
+
this.url = url;
|
|
47
|
+
this.handlers = new Map();
|
|
48
|
+
this.reconnectTimeout = null;
|
|
49
|
+
this.shouldReconnect = true;
|
|
50
|
+
this.connect();
|
|
51
|
+
}
|
|
52
|
+
_create_class(RedisWsClient, [
|
|
53
|
+
{
|
|
54
|
+
key: "connect",
|
|
55
|
+
value: function connect() {
|
|
56
|
+
var _this = this;
|
|
57
|
+
if (!this.shouldReconnect) return;
|
|
58
|
+
this.ws = new WebSocket(this.url);
|
|
59
|
+
this.ws.onopen = function() {
|
|
60
|
+
_this.startHeartbeat();
|
|
61
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
62
|
+
try {
|
|
63
|
+
// Re-subscribe to all channels after reconnection
|
|
64
|
+
for(var _iterator = _this.handlers.keys()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
65
|
+
var channel = _step.value;
|
|
66
|
+
_this.subscribeInternal(channel);
|
|
67
|
+
}
|
|
68
|
+
} catch (err) {
|
|
69
|
+
_didIteratorError = true;
|
|
70
|
+
_iteratorError = err;
|
|
71
|
+
} finally{
|
|
72
|
+
try {
|
|
73
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
74
|
+
_iterator.return();
|
|
75
|
+
}
|
|
76
|
+
} finally{
|
|
77
|
+
if (_didIteratorError) {
|
|
78
|
+
throw _iteratorError;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
this.ws.onmessage = function(event) {
|
|
84
|
+
var message = event.data;
|
|
85
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
86
|
+
try {
|
|
87
|
+
// Redis messages come directly as strings from the bridge
|
|
88
|
+
// Since we subscribe to one channel per client instance in practice,
|
|
89
|
+
// we can call all handlers
|
|
90
|
+
for(var _iterator = _this.handlers.values()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
91
|
+
var handlers = _step.value;
|
|
92
|
+
handlers.forEach(function(fn) {
|
|
93
|
+
return fn(message);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
_didIteratorError = true;
|
|
98
|
+
_iteratorError = err;
|
|
99
|
+
} finally{
|
|
100
|
+
try {
|
|
101
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
102
|
+
_iterator.return();
|
|
103
|
+
}
|
|
104
|
+
} finally{
|
|
105
|
+
if (_didIteratorError) {
|
|
106
|
+
throw _iteratorError;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
this.ws.onclose = function() {
|
|
112
|
+
return _this.reconnect();
|
|
113
|
+
};
|
|
114
|
+
this.ws.onerror = function() {
|
|
115
|
+
return _this.ws.close();
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
key: "reconnect",
|
|
121
|
+
value: function reconnect() {
|
|
122
|
+
var _this = this;
|
|
123
|
+
if (!this.shouldReconnect) return;
|
|
124
|
+
this.stopHeartbeat();
|
|
125
|
+
this.clearReconnectTimeout();
|
|
126
|
+
this.reconnectTimeout = scheduleDeferred(function() {
|
|
127
|
+
_this.reconnectTimeout = null;
|
|
128
|
+
_this.connect();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
key: "startHeartbeat",
|
|
134
|
+
value: function startHeartbeat() {
|
|
135
|
+
var _this = this;
|
|
136
|
+
this.heartbeat = setInterval(function() {
|
|
137
|
+
if (_this.ws.readyState === WebSocket.OPEN) {
|
|
138
|
+
_this.ws.send(JSON.stringify({
|
|
139
|
+
type: "ping"
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
}, 20000);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
key: "stopHeartbeat",
|
|
147
|
+
value: function stopHeartbeat() {
|
|
148
|
+
if (this.heartbeat) clearInterval(this.heartbeat);
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
key: "clearReconnectTimeout",
|
|
153
|
+
value: function clearReconnectTimeout() {
|
|
154
|
+
if (this.reconnectTimeout) {
|
|
155
|
+
clearTimeout(this.reconnectTimeout);
|
|
156
|
+
this.reconnectTimeout = null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
key: "subscribe",
|
|
162
|
+
value: function subscribe(channel, handler) {
|
|
163
|
+
if (!this.handlers.has(channel)) {
|
|
164
|
+
this.handlers.set(channel, new Set());
|
|
165
|
+
this.subscribeInternal(channel);
|
|
166
|
+
}
|
|
167
|
+
this.handlers.get(channel).add(handler);
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
key: "unsubscribe",
|
|
172
|
+
value: function unsubscribe(channel, handler) {
|
|
173
|
+
var handlers = this.handlers.get(channel);
|
|
174
|
+
if (!handlers) return;
|
|
175
|
+
if (handler) {
|
|
176
|
+
handlers.delete(handler);
|
|
177
|
+
if (handlers.size === 0) {
|
|
178
|
+
this.handlers.delete(channel);
|
|
179
|
+
this.unsubscribeInternal(channel);
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
this.handlers.delete(channel);
|
|
183
|
+
this.unsubscribeInternal(channel);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
key: "subscribeInternal",
|
|
189
|
+
value: function subscribeInternal(channel) {
|
|
190
|
+
if (this.ws.readyState === WebSocket.OPEN) {
|
|
191
|
+
this.ws.send(JSON.stringify({
|
|
192
|
+
type: "subscribe",
|
|
193
|
+
channel: channel
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
key: "unsubscribeInternal",
|
|
200
|
+
value: function unsubscribeInternal(channel) {
|
|
201
|
+
if (this.ws.readyState === WebSocket.OPEN) {
|
|
202
|
+
this.ws.send(JSON.stringify({
|
|
203
|
+
type: "unsubscribe",
|
|
204
|
+
channel: channel
|
|
205
|
+
}));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
key: "close",
|
|
211
|
+
value: function close() {
|
|
212
|
+
this.shouldReconnect = false;
|
|
213
|
+
this.stopHeartbeat();
|
|
214
|
+
this.clearReconnectTimeout();
|
|
215
|
+
if (this.ws) {
|
|
216
|
+
this.ws.onclose = null;
|
|
217
|
+
}
|
|
218
|
+
if (this.ws) {
|
|
219
|
+
this.ws.close();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
]);
|
|
224
|
+
return RedisWsClient;
|
|
225
|
+
}();
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Utilities Guide
|
|
2
|
+
|
|
3
|
+
The `utils` folder contains small reusable helpers that do not belong to one
|
|
4
|
+
domain module but are still part of the SDK's public surface.
|
|
5
|
+
|
|
6
|
+
## Source map
|
|
7
|
+
|
|
8
|
+
- [`mul-div.ts`](./mul-div.ts) provides deterministic multiply-divide math with
|
|
9
|
+
optional rounding up
|
|
10
|
+
- [`rand-bigint.ts`](./rand-bigint.ts) provides secure random bigint generation
|
|
11
|
+
- [`orderUtils.ts`](./orderUtils.ts) provides token-pair helpers and a
|
|
12
|
+
signature-verification shortcut
|
|
13
|
+
|
|
14
|
+
## `mulDiv` and `Rounding`
|
|
15
|
+
|
|
16
|
+
`mulDiv(a, b, x, rounding?)` performs integer multiplication and division in one
|
|
17
|
+
step using `bigint` arithmetic.
|
|
18
|
+
|
|
19
|
+
Public exports:
|
|
20
|
+
|
|
21
|
+
- `Rounding`
|
|
22
|
+
- `Ceil`
|
|
23
|
+
- `Floor`
|
|
24
|
+
- `mulDiv(a, b, x, rounding?)`
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { Rounding, mulDiv } from "@stryke-xyz/premarket-sdk";
|
|
28
|
+
|
|
29
|
+
const floorValue = mulDiv(10n, 3n, 4n);
|
|
30
|
+
const ceilValue = mulDiv(10n, 3n, 4n, Rounding.Ceil);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This helper is especially relevant to the [Vault guide](../vault/README.md),
|
|
34
|
+
where collateral previews need deterministic rounding behavior.
|
|
35
|
+
|
|
36
|
+
## `randBigInt`
|
|
37
|
+
|
|
38
|
+
`randBigInt(max)` returns a cryptographically secure random bigint in the range
|
|
39
|
+
`[0, max]`.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { randBigInt } from "@stryke-xyz/premarket-sdk";
|
|
43
|
+
|
|
44
|
+
const salt = randBigInt((1n << 96n) - 1n);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Implementation notes:
|
|
48
|
+
|
|
49
|
+
- it requires `globalThis.crypto.getRandomValues`
|
|
50
|
+
- it throws if no secure random source is available
|
|
51
|
+
- it is used by the exchange order builder for default salts
|
|
52
|
+
|
|
53
|
+
## Order utility helpers
|
|
54
|
+
|
|
55
|
+
[`orderUtils.ts`](./orderUtils.ts) exports a few low-level helpers that are
|
|
56
|
+
useful when app code needs token-id normalization or direct signature recovery.
|
|
57
|
+
|
|
58
|
+
Public exports:
|
|
59
|
+
|
|
60
|
+
- `optionPrmToPrmTokenId(tokenId)`
|
|
61
|
+
- `prmToOptionPrmTokenId(prmTokenId)`
|
|
62
|
+
- `isComplementaryOptionTokenPair(tokenIdA, tokenIdB)`
|
|
63
|
+
- `verifyOrderSignature(order, signature, chainId, exchangeAddress)`
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import {
|
|
67
|
+
isComplementaryOptionTokenPair,
|
|
68
|
+
verifyOrderSignature,
|
|
69
|
+
} from "@stryke-xyz/premarket-sdk";
|
|
70
|
+
|
|
71
|
+
const complementary = isComplementaryOptionTokenPair(100n, 101n);
|
|
72
|
+
const signer = await verifyOrderSignature(
|
|
73
|
+
order,
|
|
74
|
+
signature,
|
|
75
|
+
4326,
|
|
76
|
+
exchangeAddress,
|
|
77
|
+
);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Relationship to the domain modules:
|
|
81
|
+
|
|
82
|
+
- the token-id helpers overlap conceptually with the [Vault guide](../vault/README.md)
|
|
83
|
+
and [Exchange guide](../exchange/README.md)
|
|
84
|
+
- `verifyOrderSignature` is a thin convenience wrapper around exchange
|
|
85
|
+
EIP-712 signer recovery
|
|
86
|
+
|
|
87
|
+
When you want the richer context and invariants, prefer the domain guides. When
|
|
88
|
+
you want the smallest possible helper for a utility task, this module is the
|
|
89
|
+
right place.
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# Vault Guide
|
|
2
|
+
|
|
3
|
+
The `vault` module documents the SDK surface built around
|
|
4
|
+
`OptionMarketVault`. It covers token-id derivation, collateral and settlement
|
|
5
|
+
math, role constants, and transaction builders for mint, redeem, withdraw,
|
|
6
|
+
rollover, and related flows.
|
|
7
|
+
|
|
8
|
+
## Source map
|
|
9
|
+
|
|
10
|
+
- [`index.ts`](./index.ts) re-exports the public vault surface
|
|
11
|
+
- [`types.ts`](./types.ts) defines vault-level structs used across helpers
|
|
12
|
+
- [`token-ids.ts`](./token-ids.ts) derives `PRM` and `oPRM` token ids
|
|
13
|
+
- [`collateral.ts`](./collateral.ts) mirrors collateral and payoff math
|
|
14
|
+
- [`transactions.ts`](./transactions.ts) builds calldata and transaction envelopes
|
|
15
|
+
- [`constants.ts`](./constants.ts) exports precision constants and role enums
|
|
16
|
+
|
|
17
|
+
## What this module is for
|
|
18
|
+
|
|
19
|
+
In plain language:
|
|
20
|
+
|
|
21
|
+
- it tells integrators how option position tokens are identified
|
|
22
|
+
- it lets frontends and services estimate collateral, fees, and payouts without
|
|
23
|
+
re-implementing Solidity math
|
|
24
|
+
- it gives callers ABI-backed transaction builders for the public vault flows
|
|
25
|
+
|
|
26
|
+
## Vault concepts
|
|
27
|
+
|
|
28
|
+
The vault mints paired ERC-6909 position ids:
|
|
29
|
+
|
|
30
|
+
- `PRM`
|
|
31
|
+
- the collateral-side position token
|
|
32
|
+
- always even
|
|
33
|
+
- `oPRM`
|
|
34
|
+
- the option claim token
|
|
35
|
+
- always odd
|
|
36
|
+
|
|
37
|
+
The pairing rule is simple and intentional:
|
|
38
|
+
|
|
39
|
+
- `oPrmTokenId = prmTokenId | 1`
|
|
40
|
+
- `optionPrmToPrm(tokenId)` clears the low bit and returns the canonical `PRM`
|
|
41
|
+
id whether the input is already `PRM` or `oPRM`
|
|
42
|
+
|
|
43
|
+
This convention is used throughout the SDK and should be treated as canonical.
|
|
44
|
+
|
|
45
|
+
## Public types
|
|
46
|
+
|
|
47
|
+
The main type definitions live in [`types.ts`](./types.ts):
|
|
48
|
+
|
|
49
|
+
- `VaultInstrument`
|
|
50
|
+
- `{ marketId, tick, isCall }`
|
|
51
|
+
- used when minting or describing a strike-side instrument
|
|
52
|
+
- `VaultMarket`
|
|
53
|
+
- bigint-based market shape matching the vault and registry configuration
|
|
54
|
+
- `PrmInfo`
|
|
55
|
+
- metadata associated with a minted `PRM` family
|
|
56
|
+
- `TokenIdParams`
|
|
57
|
+
- the full parameter set needed to derive a token id
|
|
58
|
+
|
|
59
|
+
[`collateral.ts`](./collateral.ts) also exports calculation-specific types:
|
|
60
|
+
|
|
61
|
+
- `MarketParams`
|
|
62
|
+
- `InstrumentParams`
|
|
63
|
+
- `SpreadBounds`
|
|
64
|
+
|
|
65
|
+
These smaller helper types are useful when callers only need the math helpers
|
|
66
|
+
and not the full market struct.
|
|
67
|
+
|
|
68
|
+
## Precision constants and roles
|
|
69
|
+
|
|
70
|
+
[`constants.ts`](./constants.ts) exposes the shared vault constants:
|
|
71
|
+
|
|
72
|
+
- `VAULT_TOKEN_PRECISION = 1e18`
|
|
73
|
+
- `FEE_BPS_PRECISION = 1e6`
|
|
74
|
+
- `PNL_PRECISION = 1e18`
|
|
75
|
+
- `Role`
|
|
76
|
+
- typed enum for vault role ids
|
|
77
|
+
- `ROLE_NAMES`
|
|
78
|
+
- a friendly lookup from numeric role to display label
|
|
79
|
+
|
|
80
|
+
Use these constants instead of hardcoding precision values in app code.
|
|
81
|
+
|
|
82
|
+
## Token-id helpers
|
|
83
|
+
|
|
84
|
+
[`token-ids.ts`](./token-ids.ts) is the public source of truth for position-id
|
|
85
|
+
derivation.
|
|
86
|
+
|
|
87
|
+
Public helpers:
|
|
88
|
+
|
|
89
|
+
- `getPrmTokenId(params)`
|
|
90
|
+
- derives the even `PRM` token id from vault address, instrument, expiry, and
|
|
91
|
+
`chainId`
|
|
92
|
+
- `getOptionPrmTokenId(params)`
|
|
93
|
+
- derives the odd `oPRM` token id
|
|
94
|
+
- `prmToOptionTokenId(prmTokenId)`
|
|
95
|
+
- `optionPrmToPrm(oPrmTokenId)`
|
|
96
|
+
- `isPrmToken(tokenId)`
|
|
97
|
+
- `isOptionPrmToken(tokenId)`
|
|
98
|
+
- `getPositionId(tokenId, userAddress)`
|
|
99
|
+
- stable string key for app-side storage keyed by token and user
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import {
|
|
103
|
+
getOptionPrmTokenId,
|
|
104
|
+
optionPrmToPrm,
|
|
105
|
+
} from "@stryke-xyz/premarket-sdk";
|
|
106
|
+
|
|
107
|
+
const oPrmTokenId = getOptionPrmTokenId({
|
|
108
|
+
vaultAddress: "0xVault",
|
|
109
|
+
marketId: 12n,
|
|
110
|
+
tick: 1500n,
|
|
111
|
+
isCall: true,
|
|
112
|
+
expiry: 1_735_689_600n,
|
|
113
|
+
chainId: 4326,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const prmTokenId = optionPrmToPrm(oPrmTokenId);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Implementation detail worth remembering:
|
|
120
|
+
|
|
121
|
+
- `getPrmTokenId` hashes the vault address, instrument fields, expiry, and
|
|
122
|
+
`chainId`, then left-shifts once to force even parity
|
|
123
|
+
|
|
124
|
+
## Collateral and settlement math
|
|
125
|
+
|
|
126
|
+
[`collateral.ts`](./collateral.ts) mirrors the important deterministic math used
|
|
127
|
+
by the vault contract. This makes it safe to pre-compute values in the UI or a
|
|
128
|
+
backend without sacrificing contract parity.
|
|
129
|
+
|
|
130
|
+
Public helpers:
|
|
131
|
+
|
|
132
|
+
- `getSpreadWidth(market)`
|
|
133
|
+
- `getSpreadBounds(instrument, market)`
|
|
134
|
+
- `calculateCollateralAmount(prmAmount, instrument, market)`
|
|
135
|
+
- `calculatePrmAmount(collateralAmount, instrument, market)`
|
|
136
|
+
- `calculateSpreadProfit(instrument, market, finalTick, positionSize)`
|
|
137
|
+
- `calculateSpreadLoss(instrument, market, finalTick, positionSize)`
|
|
138
|
+
- `calculateWithdrawableCollateral(instrument, market, finalTick, positionSize)`
|
|
139
|
+
- `getCollateralPerPosition(instrument, market)`
|
|
140
|
+
- `calculateDepositFees(collateralAmount, depositFeeBps, feeBpsPrecision?)`
|
|
141
|
+
- `calculateRedeemFees(profitAmount, redeemFeeBps, feeBpsPrecision?)`
|
|
142
|
+
- `isInTheMoney(instrument, market, finalTick)`
|
|
143
|
+
- `calculateMoneyness(instrument, market, finalTick)`
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import {
|
|
147
|
+
calculateCollateralAmount,
|
|
148
|
+
calculateWithdrawableCollateral,
|
|
149
|
+
} from "@stryke-xyz/premarket-sdk";
|
|
150
|
+
|
|
151
|
+
const collateral = calculateCollateralAmount(
|
|
152
|
+
1_000_000_000_000_000_000n,
|
|
153
|
+
{ marketId: 1n, tick: 1500n, isCall: true },
|
|
154
|
+
{
|
|
155
|
+
tickSize: 100n,
|
|
156
|
+
tickSpacing: 100n,
|
|
157
|
+
tokensPerTickSize: 1_000_000n,
|
|
158
|
+
isCollateralScaled: false,
|
|
159
|
+
},
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
const withdrawable = calculateWithdrawableCollateral(
|
|
163
|
+
{ marketId: 1n, tick: 1500n, isCall: true },
|
|
164
|
+
{
|
|
165
|
+
tickSize: 100n,
|
|
166
|
+
tickSpacing: 100n,
|
|
167
|
+
tokensPerTickSize: 1_000_000n,
|
|
168
|
+
isCollateralScaled: false,
|
|
169
|
+
},
|
|
170
|
+
1_600n,
|
|
171
|
+
1_000_000_000_000_000_000n,
|
|
172
|
+
);
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Important behavior captured by the SDK:
|
|
176
|
+
|
|
177
|
+
- spread width falls back to `1` when `tickSpacing <= tickSize`
|
|
178
|
+
- strike-scaled collateral uses `instrument.tick`
|
|
179
|
+
- collateral calculation rounds up when the final division is not exact
|
|
180
|
+
- inverse `PRM` previews use floor division
|
|
181
|
+
- payoff and withdraw math use deterministic `bigint` arithmetic throughout
|
|
182
|
+
|
|
183
|
+
## Transaction builders
|
|
184
|
+
|
|
185
|
+
[`transactions.ts`](./transactions.ts) contains ABI-backed transaction builders.
|
|
186
|
+
These return a lightweight `TransactionCall`:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
export interface TransactionCall {
|
|
190
|
+
to: `0x${string}`;
|
|
191
|
+
value?: bigint;
|
|
192
|
+
data: Hex;
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### User-facing lifecycle builders
|
|
197
|
+
|
|
198
|
+
- `buildMintTransaction(vaultAddress, instrument, amount)`
|
|
199
|
+
- `buildWithdrawTransaction(vaultAddress, prmTokenId, amount, receiver)`
|
|
200
|
+
- `buildRedeemTransaction(vaultAddress, oPrmTokenId, receiver)`
|
|
201
|
+
- `buildUnwindTransaction(vaultAddress, prmTokenId, amount, receiver)`
|
|
202
|
+
- `buildRolloverTransaction(vaultAddress, oldPrmTokenId)`
|
|
203
|
+
- `buildApproveTransaction(tokenAddress, spender, amount?)`
|
|
204
|
+
- `buildBatchedMintTransactions(collateralTokenAddress, vaultAddress, instrument, collateralAmount, prmAmount)`
|
|
205
|
+
- `buildSetOperatorTransaction(vaultAddress, operator, approved)`
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
import {
|
|
209
|
+
buildApproveTransaction,
|
|
210
|
+
buildMintTransaction,
|
|
211
|
+
} from "@stryke-xyz/premarket-sdk";
|
|
212
|
+
|
|
213
|
+
const approve = buildApproveTransaction(collateralToken, vaultAddress);
|
|
214
|
+
const mint = buildMintTransaction(
|
|
215
|
+
vaultAddress,
|
|
216
|
+
{ marketId: 12n, tick: 1500n, isCall: true },
|
|
217
|
+
1_000_000_000_000_000_000n,
|
|
218
|
+
);
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Restricted and role-gated builders
|
|
222
|
+
|
|
223
|
+
These functions are exported because they are part of the SDK, but they belong
|
|
224
|
+
to operational or keeper-style flows rather than ordinary end-user integrations:
|
|
225
|
+
|
|
226
|
+
- `buildDelegateRedeemTransaction`
|
|
227
|
+
- `buildDelegateRolloverTransaction`
|
|
228
|
+
- `buildDelegateWithdrawTransaction`
|
|
229
|
+
- `buildFillMarketDeliveryTransaction`
|
|
230
|
+
- `buildSetRolloverEnabledTransaction`
|
|
231
|
+
- `buildSetRoleTransaction`
|
|
232
|
+
- `buildUpdateFinalTickTransaction`
|
|
233
|
+
- `buildUpdateMarketExpiryTransaction`
|
|
234
|
+
- `buildUpdateMarketExpiryFromMarketTransaction`
|
|
235
|
+
|
|
236
|
+
They should usually be used by privileged services, market operators, or
|
|
237
|
+
automation code that already understands the relevant role checks.
|
|
238
|
+
|
|
239
|
+
## Typical integration patterns
|
|
240
|
+
|
|
241
|
+
### 1. Preview before mint
|
|
242
|
+
|
|
243
|
+
Use the math helpers and token-id helpers together:
|
|
244
|
+
|
|
245
|
+
1. derive the target `PRM` or `oPRM` id
|
|
246
|
+
2. compute required collateral with `calculateCollateralAmount`
|
|
247
|
+
3. build `approve` and `mint` calls
|
|
248
|
+
|
|
249
|
+
### 2. Display settlement outcomes
|
|
250
|
+
|
|
251
|
+
Use:
|
|
252
|
+
|
|
253
|
+
- `isInTheMoney`
|
|
254
|
+
- `calculateSpreadProfit`
|
|
255
|
+
- `calculateRedeemFees`
|
|
256
|
+
- `calculateWithdrawableCollateral`
|
|
257
|
+
|
|
258
|
+
This gives UI code a contract-aligned preview for both option holders and
|
|
259
|
+
collateral providers.
|
|
260
|
+
|
|
261
|
+
### 3. Build sponsored or batched flows
|
|
262
|
+
|
|
263
|
+
`buildBatchedMintTransactions` is especially helpful when a frontend or relayer
|
|
264
|
+
needs to bundle approval and minting into one user operation or multicall-like
|
|
265
|
+
flow.
|
|
266
|
+
|
|
267
|
+
For market configuration and market serialization, continue with the
|
|
268
|
+
[Registry guide](../registry/README.md).
|
|
File without changes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { SyncStatus } from "../types.js";
|
|
2
|
+
import { RedisWsClient } from "../redis-ws-client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Base abstract class for sync clients
|
|
5
|
+
* @template TMessage - The message type (e.g., SequencedMessage, BalanceUpdateMessage)
|
|
6
|
+
* @template TChange - The change type (e.g., OrderChange, BalanceData[])
|
|
7
|
+
* @template TData - The data type stored in the map (e.g., StoredOrder, string)
|
|
8
|
+
* @template TConfig - The config type (must have redisUrl and channel)
|
|
9
|
+
*/
|
|
10
|
+
export declare abstract class BaseSyncClient<TMessage extends {
|
|
11
|
+
seq: number;
|
|
12
|
+
previousSeq: number;
|
|
13
|
+
}, TChange, TData, TConfig extends {
|
|
14
|
+
redisUrl: string;
|
|
15
|
+
channel: string;
|
|
16
|
+
}> {
|
|
17
|
+
protected wsClient: RedisWsClient | null;
|
|
18
|
+
protected config: TConfig;
|
|
19
|
+
protected status: SyncStatus;
|
|
20
|
+
protected lastSeq: number;
|
|
21
|
+
protected incomingQueue: TMessage[];
|
|
22
|
+
protected isProcessing: boolean;
|
|
23
|
+
protected statusListeners: Set<(status: SyncStatus) => void>;
|
|
24
|
+
protected changeListeners: Set<(change: TChange) => void>;
|
|
25
|
+
protected dataMap: Map<string, TData>;
|
|
26
|
+
protected snapshotListeners: Set<(data: TData[]) => void>;
|
|
27
|
+
constructor(config: TConfig);
|
|
28
|
+
/** Opens the websocket subscription, fetches a fresh snapshot, and starts replaying queued messages. */
|
|
29
|
+
connect(): Promise<void>;
|
|
30
|
+
protected enqueueMessage(message: TMessage): void;
|
|
31
|
+
protected processQueue(): Promise<void>;
|
|
32
|
+
protected fullResync(): Promise<void>;
|
|
33
|
+
protected setStatus(status: SyncStatus): void;
|
|
34
|
+
/** Returns the current connection lifecycle state. */
|
|
35
|
+
getStatus(): SyncStatus;
|
|
36
|
+
/** Returns true once the client has finished its initial snapshot sync. */
|
|
37
|
+
isSynced(): boolean;
|
|
38
|
+
/** Returns the most recent successfully applied sequence id. */
|
|
39
|
+
getLastSequence(): number;
|
|
40
|
+
/** Returns the number of queued messages waiting to be processed. */
|
|
41
|
+
getBufferedCount(): number;
|
|
42
|
+
/** Registers a listener for connection status changes. */
|
|
43
|
+
onStatus(callback: (status: SyncStatus) => void): () => void;
|
|
44
|
+
/** Registers a listener for individual applied change events. */
|
|
45
|
+
onChange(callback: (change: TChange) => void): () => void;
|
|
46
|
+
/** Registers a listener for full snapshot updates. */
|
|
47
|
+
onSnapshot(callback: (data: TData[]) => void): () => void;
|
|
48
|
+
protected notifySnapshotListeners(data: TData[]): void;
|
|
49
|
+
/** Closes the websocket connection and clears queued messages. */
|
|
50
|
+
disconnect(): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Abstract methods to be implemented by child classes
|
|
53
|
+
*/
|
|
54
|
+
protected abstract fetchSnapshot(): Promise<void>;
|
|
55
|
+
protected abstract applyMessage(message: TMessage): Promise<void> | void;
|
|
56
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type Handler<T = any> = (data: T) => void;
|
|
2
|
+
export declare class RedisWsClient {
|
|
3
|
+
private url;
|
|
4
|
+
private ws;
|
|
5
|
+
private handlers;
|
|
6
|
+
private heartbeat?;
|
|
7
|
+
private reconnectTimeout;
|
|
8
|
+
private shouldReconnect;
|
|
9
|
+
constructor(url: string);
|
|
10
|
+
private connect;
|
|
11
|
+
private reconnect;
|
|
12
|
+
private startHeartbeat;
|
|
13
|
+
private stopHeartbeat;
|
|
14
|
+
private clearReconnectTimeout;
|
|
15
|
+
subscribe<T>(channel: string, handler: Handler<T>): void;
|
|
16
|
+
unsubscribe(channel: string, handler?: Handler): void;
|
|
17
|
+
private subscribeInternal;
|
|
18
|
+
private unsubscribeInternal;
|
|
19
|
+
close(): void;
|
|
20
|
+
}
|
|
21
|
+
export {};
|