@acta-markets/ts-sdk 0.0.21-beta → 0.0.22-beta
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/ws/auth.js +14 -11
- package/dist/cjs/ws/client.js +59 -1
- package/dist/cjs/ws/client.test.js +1 -1
- package/dist/cjs/ws/index.js +1 -0
- package/dist/cjs/ws/referral.js +57 -0
- package/dist/cjs/ws/referral.test.js +55 -0
- package/dist/ws/auth.d.ts +10 -7
- package/dist/ws/auth.js +14 -11
- package/dist/ws/client.d.ts +17 -1
- package/dist/ws/client.js +59 -1
- package/dist/ws/client.test.js +1 -1
- package/dist/ws/index.d.ts +1 -0
- package/dist/ws/index.js +1 -0
- package/dist/ws/referral.d.ts +53 -0
- package/dist/ws/referral.js +51 -0
- package/dist/ws/referral.test.d.ts +1 -0
- package/dist/ws/referral.test.js +53 -0
- package/dist/ws/types.d.ts +120 -48
- package/package.json +1 -1
package/dist/cjs/ws/auth.js
CHANGED
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
* - Client signs UTF-8 bytes of that text and responds:
|
|
8
8
|
* `AuthChallenge { challenge, signature: base58(ed25519(utf8(challenge))), pubkey }`
|
|
9
9
|
*
|
|
10
|
+
* The same `signMessage` primitive is reused for any UTF-8-bytes signing
|
|
11
|
+
* (e.g. `acta:redeem:v1:{pubkey}:{code}` for invite redemption).
|
|
12
|
+
*
|
|
10
13
|
* Source of truth (server):
|
|
11
14
|
* - rust-backend/rfq-server/src/server/ws.rs
|
|
12
15
|
* - rust-backend/rfq-server/src/session/handler.rs
|
|
@@ -52,9 +55,9 @@ class KeypairAuthProvider {
|
|
|
52
55
|
async getPublicKey() {
|
|
53
56
|
return this.address;
|
|
54
57
|
}
|
|
55
|
-
async
|
|
56
|
-
const
|
|
57
|
-
const signatureBytes = await (0, keys_1.signBytes)(this.privateKey,
|
|
58
|
+
async signMessage(message) {
|
|
59
|
+
const messageBytes = utf8ToBytes(message);
|
|
60
|
+
const signatureBytes = await (0, keys_1.signBytes)(this.privateKey, messageBytes);
|
|
58
61
|
return bytesToBase58(signatureBytes);
|
|
59
62
|
}
|
|
60
63
|
}
|
|
@@ -76,10 +79,10 @@ class WalletAuthProvider {
|
|
|
76
79
|
throw new Error("Wallet not connected (missing public key)");
|
|
77
80
|
return pk;
|
|
78
81
|
}
|
|
79
|
-
async
|
|
80
|
-
const
|
|
82
|
+
async signMessage(message) {
|
|
83
|
+
const messageBytes = utf8ToBytes(message);
|
|
81
84
|
// Some wallet APIs expect a mutable `Uint8Array`; codecs return `ReadonlyUint8Array`.
|
|
82
|
-
const sig = await this.wallet.signMessage(new Uint8Array(
|
|
85
|
+
const sig = await this.wallet.signMessage(new Uint8Array(messageBytes));
|
|
83
86
|
return bytesToBase58(sig);
|
|
84
87
|
}
|
|
85
88
|
}
|
|
@@ -89,16 +92,16 @@ exports.WalletAuthProvider = WalletAuthProvider;
|
|
|
89
92
|
*/
|
|
90
93
|
class CustomAuthProvider {
|
|
91
94
|
getPublicKeyFn;
|
|
92
|
-
|
|
93
|
-
constructor(getPublicKey,
|
|
95
|
+
signMessageFn;
|
|
96
|
+
constructor(getPublicKey, signMessage) {
|
|
94
97
|
this.getPublicKeyFn = getPublicKey;
|
|
95
|
-
this.
|
|
98
|
+
this.signMessageFn = signMessage;
|
|
96
99
|
}
|
|
97
100
|
async getPublicKey() {
|
|
98
101
|
return this.getPublicKeyFn();
|
|
99
102
|
}
|
|
100
|
-
async
|
|
101
|
-
return this.
|
|
103
|
+
async signMessage(message) {
|
|
104
|
+
return this.signMessageFn(message);
|
|
102
105
|
}
|
|
103
106
|
}
|
|
104
107
|
exports.CustomAuthProvider = CustomAuthProvider;
|
package/dist/cjs/ws/client.js
CHANGED
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.ActaWsClient = void 0;
|
|
5
5
|
const flows_1 = require("./flows");
|
|
6
6
|
const wirePolicy_1 = require("./wirePolicy");
|
|
7
|
+
const referral_1 = require("./referral");
|
|
7
8
|
function toGenericServerError(err) {
|
|
8
9
|
const message = err instanceof Error ? err.message : String(err);
|
|
9
10
|
return { type: "generic", data: { code: "client_error", message } };
|
|
@@ -406,6 +407,51 @@ class ActaWsClient extends TypedEventEmitter {
|
|
|
406
407
|
logout() {
|
|
407
408
|
this.send({ type: "Logout" });
|
|
408
409
|
}
|
|
410
|
+
// ========================================================================
|
|
411
|
+
// Referral / invite
|
|
412
|
+
// ========================================================================
|
|
413
|
+
/**
|
|
414
|
+
* Redeem an invite code. Authentication is proven by the session;
|
|
415
|
+
* no additional signature is required. Validation runs client-side —
|
|
416
|
+
* invalid inputs throw `ReferralCodeError` without a round-trip.
|
|
417
|
+
*/
|
|
418
|
+
redeemInvite(rawCode) {
|
|
419
|
+
this.ensureAuthenticated();
|
|
420
|
+
const parsed = (0, referral_1.parseReferralCode)(rawCode);
|
|
421
|
+
if (!parsed.ok)
|
|
422
|
+
throw new referral_1.ReferralCodeError(parsed.error);
|
|
423
|
+
const requestId = this.nextRequestId();
|
|
424
|
+
this.send({
|
|
425
|
+
type: "RedeemInvite",
|
|
426
|
+
data: { request_id: requestId, code: parsed.code },
|
|
427
|
+
});
|
|
428
|
+
return requestId;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Claim a vanity referral code (one-shot per taker). Validation
|
|
432
|
+
* runs client-side — invalid inputs throw `ReferralCodeError`.
|
|
433
|
+
*/
|
|
434
|
+
async claimReferralCode(rawCode) {
|
|
435
|
+
this.ensureAuthenticated();
|
|
436
|
+
const parsed = (0, referral_1.parseReferralCode)(rawCode);
|
|
437
|
+
if (!parsed.ok)
|
|
438
|
+
throw new referral_1.ReferralCodeError(parsed.error);
|
|
439
|
+
const requestId = this.nextRequestId();
|
|
440
|
+
this.send({
|
|
441
|
+
type: "ClaimReferralCode",
|
|
442
|
+
data: { request_id: requestId, code: parsed.code },
|
|
443
|
+
});
|
|
444
|
+
return requestId;
|
|
445
|
+
}
|
|
446
|
+
getMyReferralInfo() {
|
|
447
|
+
this.ensureAuthenticated();
|
|
448
|
+
const requestId = this.nextRequestId();
|
|
449
|
+
this.send({
|
|
450
|
+
type: "GetMyReferralInfo",
|
|
451
|
+
data: { request_id: requestId },
|
|
452
|
+
});
|
|
453
|
+
return requestId;
|
|
454
|
+
}
|
|
409
455
|
getOrderStatus(orderIdHex) {
|
|
410
456
|
this.ensureAuthenticated();
|
|
411
457
|
const requestId = this.nextRequestId();
|
|
@@ -877,6 +923,18 @@ class ActaWsClient extends TypedEventEmitter {
|
|
|
877
923
|
this.emit("subscriptionUpdated", d);
|
|
878
924
|
}
|
|
879
925
|
break;
|
|
926
|
+
case "RequireInvite":
|
|
927
|
+
this.emit("requireInvite");
|
|
928
|
+
break;
|
|
929
|
+
case "InviteRedeemed":
|
|
930
|
+
this.emit("inviteRedeemed", message.data);
|
|
931
|
+
break;
|
|
932
|
+
case "ReferralCodeClaimed":
|
|
933
|
+
this.emit("referralCodeClaimed", message.data);
|
|
934
|
+
break;
|
|
935
|
+
case "MyReferralInfo":
|
|
936
|
+
this.emit("myReferralInfo", message.data);
|
|
937
|
+
break;
|
|
880
938
|
}
|
|
881
939
|
}
|
|
882
940
|
/** Taker-only: request current indicative prices for a market + position_type. */
|
|
@@ -902,7 +960,7 @@ class ActaWsClient extends TypedEventEmitter {
|
|
|
902
960
|
try {
|
|
903
961
|
const [pubkey, signature] = await Promise.all([
|
|
904
962
|
this.authProvider.getPublicKey(),
|
|
905
|
-
this.authProvider.
|
|
963
|
+
this.authProvider.signMessage(challenge),
|
|
906
964
|
]);
|
|
907
965
|
this.send({
|
|
908
966
|
type: "AuthChallenge",
|
|
@@ -53,7 +53,7 @@ function parseClientMessage(payload) {
|
|
|
53
53
|
function makeAuthProvider(pubkey = "pubkey", signature = "signature") {
|
|
54
54
|
return {
|
|
55
55
|
getPublicKey: jest.fn().mockResolvedValue(pubkey),
|
|
56
|
-
|
|
56
|
+
signMessage: jest.fn().mockResolvedValue(signature),
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
function makeHarness(overrides = {}) {
|
package/dist/cjs/ws/index.js
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Referral / invite redemption helpers.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the server-side validation defined in
|
|
6
|
+
* rust-backend/acta-types/src/invite.rs (ReferralCode::parse).
|
|
7
|
+
* Client-side validation must stay bit-identical to the server on
|
|
8
|
+
* the same input. A hardcoded fixture table is kept here and on the
|
|
9
|
+
* rust side; if either drifts, the cross-impl test will catch it.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ReferralCodeError = exports.REFERRAL_CODE_MAX_LEN = exports.REFERRAL_CODE_MIN_LEN = void 0;
|
|
13
|
+
exports.normalizeReferralCode = normalizeReferralCode;
|
|
14
|
+
exports.parseReferralCode = parseReferralCode;
|
|
15
|
+
exports.REFERRAL_CODE_MIN_LEN = 4;
|
|
16
|
+
exports.REFERRAL_CODE_MAX_LEN = 16;
|
|
17
|
+
class ReferralCodeError extends Error {
|
|
18
|
+
detail;
|
|
19
|
+
constructor(detail) {
|
|
20
|
+
super(detail.kind === "length"
|
|
21
|
+
? `code length must be between ${detail.min} and ${detail.max}`
|
|
22
|
+
: "code must contain only ASCII letters and digits");
|
|
23
|
+
this.detail = detail;
|
|
24
|
+
this.name = "ReferralCodeError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.ReferralCodeError = ReferralCodeError;
|
|
28
|
+
/**
|
|
29
|
+
* Trim + ASCII uppercase. No length or charset check. Useful for
|
|
30
|
+
* showing a live preview as the user types.
|
|
31
|
+
*/
|
|
32
|
+
function normalizeReferralCode(input) {
|
|
33
|
+
return input.trim().toUpperCase();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Parse + validate + normalize a user-supplied referral code.
|
|
37
|
+
* Mirrors `ReferralCode::parse` on the server. A successful result
|
|
38
|
+
* carries the canonical branded `ReferralCode`.
|
|
39
|
+
*/
|
|
40
|
+
function parseReferralCode(input) {
|
|
41
|
+
const normalized = normalizeReferralCode(input);
|
|
42
|
+
if (normalized.length < exports.REFERRAL_CODE_MIN_LEN ||
|
|
43
|
+
normalized.length > exports.REFERRAL_CODE_MAX_LEN) {
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
error: {
|
|
47
|
+
kind: "length",
|
|
48
|
+
min: exports.REFERRAL_CODE_MIN_LEN,
|
|
49
|
+
max: exports.REFERRAL_CODE_MAX_LEN,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (!/^[A-Z0-9]+$/.test(normalized)) {
|
|
54
|
+
return { ok: false, error: { kind: "charset" } };
|
|
55
|
+
}
|
|
56
|
+
return { ok: true, code: normalized };
|
|
57
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const referral_1 = require("./referral");
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// Cross-impl fixture.
|
|
6
|
+
//
|
|
7
|
+
// Bit-for-bit identical to the fixture in
|
|
8
|
+
// rust-backend/acta-types/src/invite.rs::tests
|
|
9
|
+
// If either side changes, update both.
|
|
10
|
+
// =============================================================================
|
|
11
|
+
const ACCEPT_FIXTURES = [
|
|
12
|
+
["NIKITA", "NIKITA"],
|
|
13
|
+
["nikita", "NIKITA"],
|
|
14
|
+
[" abc1 ", "ABC1"],
|
|
15
|
+
["ABCD", "ABCD"],
|
|
16
|
+
["1234567890ABCDEF", "1234567890ABCDEF"],
|
|
17
|
+
];
|
|
18
|
+
describe("parseReferralCode", () => {
|
|
19
|
+
test.each(ACCEPT_FIXTURES)("accepts %j → %j", (input, expected) => {
|
|
20
|
+
const res = (0, referral_1.parseReferralCode)(input);
|
|
21
|
+
expect(res.ok).toBe(true);
|
|
22
|
+
if (res.ok)
|
|
23
|
+
expect(res.code).toBe(expected);
|
|
24
|
+
});
|
|
25
|
+
test("rejects too short", () => {
|
|
26
|
+
const res = (0, referral_1.parseReferralCode)("abc");
|
|
27
|
+
expect(res.ok).toBe(false);
|
|
28
|
+
if (!res.ok)
|
|
29
|
+
expect(res.error.kind).toBe("length");
|
|
30
|
+
});
|
|
31
|
+
test("rejects too long", () => {
|
|
32
|
+
const res = (0, referral_1.parseReferralCode)("A".repeat(17));
|
|
33
|
+
expect(res.ok).toBe(false);
|
|
34
|
+
if (!res.ok)
|
|
35
|
+
expect(res.error.kind).toBe("length");
|
|
36
|
+
});
|
|
37
|
+
test("rejects non-ascii", () => {
|
|
38
|
+
const res = (0, referral_1.parseReferralCode)("абвгд");
|
|
39
|
+
expect(res.ok).toBe(false);
|
|
40
|
+
// Cyrillic passes length but fails charset.
|
|
41
|
+
if (!res.ok)
|
|
42
|
+
expect(res.error.kind).toBe("charset");
|
|
43
|
+
});
|
|
44
|
+
test("rejects punctuation", () => {
|
|
45
|
+
const res = (0, referral_1.parseReferralCode)("ABC-12");
|
|
46
|
+
expect(res.ok).toBe(false);
|
|
47
|
+
if (!res.ok)
|
|
48
|
+
expect(res.error.kind).toBe("charset");
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe("normalizeReferralCode", () => {
|
|
52
|
+
test("trims and uppercases", () => {
|
|
53
|
+
expect((0, referral_1.normalizeReferralCode)(" nikita ")).toBe("NIKITA");
|
|
54
|
+
});
|
|
55
|
+
});
|
package/dist/ws/auth.d.ts
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
* - Client signs UTF-8 bytes of that text and responds:
|
|
7
7
|
* `AuthChallenge { challenge, signature: base58(ed25519(utf8(challenge))), pubkey }`
|
|
8
8
|
*
|
|
9
|
+
* The same `signMessage` primitive is reused for any UTF-8-bytes signing
|
|
10
|
+
* (e.g. `acta:redeem:v1:{pubkey}:{code}` for invite redemption).
|
|
11
|
+
*
|
|
9
12
|
* Source of truth (server):
|
|
10
13
|
* - rust-backend/rfq-server/src/server/ws.rs
|
|
11
14
|
* - rust-backend/rfq-server/src/session/handler.rs
|
|
@@ -13,8 +16,8 @@
|
|
|
13
16
|
export interface AuthProvider {
|
|
14
17
|
/** Base58-encoded public key (address). */
|
|
15
18
|
getPublicKey(): Promise<string>;
|
|
16
|
-
/** Base58-encoded ed25519 signature over UTF-8 bytes of the
|
|
17
|
-
|
|
19
|
+
/** Base58-encoded ed25519 signature over UTF-8 bytes of the message. */
|
|
20
|
+
signMessage(message: string): Promise<string>;
|
|
18
21
|
}
|
|
19
22
|
/**
|
|
20
23
|
* Auth provider backed by a `CryptoKeyPair`.
|
|
@@ -31,7 +34,7 @@ export declare class KeypairAuthProvider implements AuthProvider {
|
|
|
31
34
|
/** Create from Solana CLI keypair JSON (array of numbers). */
|
|
32
35
|
static fromJson(json: number[] | string): Promise<KeypairAuthProvider>;
|
|
33
36
|
getPublicKey(): Promise<string>;
|
|
34
|
-
|
|
37
|
+
signMessage(message: string): Promise<string>;
|
|
35
38
|
}
|
|
36
39
|
/**
|
|
37
40
|
* Wallet-like provider (browser wallets, custom signers, etc.)
|
|
@@ -43,7 +46,7 @@ export declare class WalletAuthProvider implements AuthProvider {
|
|
|
43
46
|
private readonly wallet;
|
|
44
47
|
constructor(wallet: WalletLike);
|
|
45
48
|
getPublicKey(): Promise<string>;
|
|
46
|
-
|
|
49
|
+
signMessage(message: string): Promise<string>;
|
|
47
50
|
}
|
|
48
51
|
export type WalletLike = {
|
|
49
52
|
/** Preferred: base58 address string. */
|
|
@@ -60,8 +63,8 @@ export type WalletLike = {
|
|
|
60
63
|
*/
|
|
61
64
|
export declare class CustomAuthProvider implements AuthProvider {
|
|
62
65
|
private readonly getPublicKeyFn;
|
|
63
|
-
private readonly
|
|
64
|
-
constructor(getPublicKey: () => Promise<string>,
|
|
66
|
+
private readonly signMessageFn;
|
|
67
|
+
constructor(getPublicKey: () => Promise<string>, signMessage: (message: string) => Promise<string>);
|
|
65
68
|
getPublicKey(): Promise<string>;
|
|
66
|
-
|
|
69
|
+
signMessage(message: string): Promise<string>;
|
|
67
70
|
}
|
package/dist/ws/auth.js
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
* - Client signs UTF-8 bytes of that text and responds:
|
|
7
7
|
* `AuthChallenge { challenge, signature: base58(ed25519(utf8(challenge))), pubkey }`
|
|
8
8
|
*
|
|
9
|
+
* The same `signMessage` primitive is reused for any UTF-8-bytes signing
|
|
10
|
+
* (e.g. `acta:redeem:v1:{pubkey}:{code}` for invite redemption).
|
|
11
|
+
*
|
|
9
12
|
* Source of truth (server):
|
|
10
13
|
* - rust-backend/rfq-server/src/server/ws.rs
|
|
11
14
|
* - rust-backend/rfq-server/src/session/handler.rs
|
|
@@ -49,9 +52,9 @@ export class KeypairAuthProvider {
|
|
|
49
52
|
async getPublicKey() {
|
|
50
53
|
return this.address;
|
|
51
54
|
}
|
|
52
|
-
async
|
|
53
|
-
const
|
|
54
|
-
const signatureBytes = await signBytes(this.privateKey,
|
|
55
|
+
async signMessage(message) {
|
|
56
|
+
const messageBytes = utf8ToBytes(message);
|
|
57
|
+
const signatureBytes = await signBytes(this.privateKey, messageBytes);
|
|
55
58
|
return bytesToBase58(signatureBytes);
|
|
56
59
|
}
|
|
57
60
|
}
|
|
@@ -72,10 +75,10 @@ export class WalletAuthProvider {
|
|
|
72
75
|
throw new Error("Wallet not connected (missing public key)");
|
|
73
76
|
return pk;
|
|
74
77
|
}
|
|
75
|
-
async
|
|
76
|
-
const
|
|
78
|
+
async signMessage(message) {
|
|
79
|
+
const messageBytes = utf8ToBytes(message);
|
|
77
80
|
// Some wallet APIs expect a mutable `Uint8Array`; codecs return `ReadonlyUint8Array`.
|
|
78
|
-
const sig = await this.wallet.signMessage(new Uint8Array(
|
|
81
|
+
const sig = await this.wallet.signMessage(new Uint8Array(messageBytes));
|
|
79
82
|
return bytesToBase58(sig);
|
|
80
83
|
}
|
|
81
84
|
}
|
|
@@ -84,15 +87,15 @@ export class WalletAuthProvider {
|
|
|
84
87
|
*/
|
|
85
88
|
export class CustomAuthProvider {
|
|
86
89
|
getPublicKeyFn;
|
|
87
|
-
|
|
88
|
-
constructor(getPublicKey,
|
|
90
|
+
signMessageFn;
|
|
91
|
+
constructor(getPublicKey, signMessage) {
|
|
89
92
|
this.getPublicKeyFn = getPublicKey;
|
|
90
|
-
this.
|
|
93
|
+
this.signMessageFn = signMessage;
|
|
91
94
|
}
|
|
92
95
|
async getPublicKey() {
|
|
93
96
|
return this.getPublicKeyFn();
|
|
94
97
|
}
|
|
95
|
-
async
|
|
96
|
-
return this.
|
|
98
|
+
async signMessage(message) {
|
|
99
|
+
return this.signMessageFn(message);
|
|
97
100
|
}
|
|
98
101
|
}
|
package/dist/ws/client.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { AuthProvider } from "./auth";
|
|
3
3
|
import type { SignerLike } from "../chain/orders";
|
|
4
4
|
import type { Address } from "@solana/addresses";
|
|
5
|
-
import type { ActiveRfqInfo, ChainEventMessage, EarnSummaryData, TokenMarketsInfoData, GlobalStats, MarketDescriptorInfo, MarketInfo, MyActiveRfqInfo, MyActiveRfqsMessage, OrderStatusMessage, PositionInfo, QuoteAcknowledgedMessage, QuoteBestStatusMessage, QuoteCancelledMessage, QuoteMessage, QuoteRefreshRequestedMessage, QuoteOutbidMessage, QuoteReceivedMessage, QuoteSelectedMessage, QuotesUpdateMessage, RfqBroadcastMessage, RfqClosedMessage, RfqCreatedMessage, RfqSkippedMessage, RfqRequestMessage, RfqAvailableAgainMessage, QuoteExpiredMessage, QuoteFilledMessage, IndicativePricesMessage, IndicativePricesRequestMessage, IndicativePricesResponseMessage, GetIndicativePricesMessage, MakerBalancesMessage, MakerMarketsMessage, MakerPositionsMessage, MyCapsMessage, MyQuotesMessage, MyTradesMessage, RequestId, ServerError, ServerMessage, SnapshotMessage, StatsDelta, SubscriptionsMessage, TokenInfo, TradeInfo, UuidString, VersionMismatchMessage, WelcomeMessage, WsChannel } from "./types";
|
|
5
|
+
import type { ActiveRfqInfo, ChainEventMessage, EarnSummaryData, TokenMarketsInfoData, GlobalStats, MarketDescriptorInfo, MarketInfo, MyActiveRfqInfo, MyActiveRfqsMessage, OrderStatusMessage, PositionInfo, QuoteAcknowledgedMessage, QuoteBestStatusMessage, QuoteCancelledMessage, QuoteMessage, QuoteRefreshRequestedMessage, QuoteOutbidMessage, QuoteReceivedMessage, QuoteSelectedMessage, QuotesUpdateMessage, RfqBroadcastMessage, RfqClosedMessage, RfqCreatedMessage, RfqSkippedMessage, RfqRequestMessage, RfqAvailableAgainMessage, QuoteExpiredMessage, QuoteFilledMessage, IndicativePricesMessage, IndicativePricesRequestMessage, IndicativePricesResponseMessage, GetIndicativePricesMessage, MakerBalancesMessage, MakerMarketsMessage, MakerPositionsMessage, MyCapsMessage, MyQuotesMessage, MyTradesMessage, RequestId, ServerError, ServerMessage, SnapshotMessage, StatsDelta, SubscriptionsMessage, TokenInfo, TradeInfo, UuidString, VersionMismatchMessage, WelcomeMessage, WsChannel, InviteRedeemedData, ReferralCodeClaimedData, MyReferralInfoData } from "./types";
|
|
6
6
|
export type ConnectionState = "disconnected" | "connecting" | "authenticating" | "authenticated" | "error";
|
|
7
7
|
export type ClientRole = "taker" | "maker";
|
|
8
8
|
export type PendingMessagesOverflowPolicy = "drop_oldest" | "drop_newest" | "throw";
|
|
@@ -145,6 +145,10 @@ export type ActaWsClientEvents = {
|
|
|
145
145
|
positionSettled: (event: Extract<ChainEventMessage, {
|
|
146
146
|
event_type: "PositionSettled";
|
|
147
147
|
}>) => void;
|
|
148
|
+
requireInvite: () => void;
|
|
149
|
+
inviteRedeemed: (data: InviteRedeemedData) => void;
|
|
150
|
+
referralCodeClaimed: (data: ReferralCodeClaimedData) => void;
|
|
151
|
+
myReferralInfo: (data: MyReferralInfoData) => void;
|
|
148
152
|
};
|
|
149
153
|
type EventMap = Record<string, (...args: any[]) => void>;
|
|
150
154
|
declare class TypedEventEmitter<TEvents extends EventMap> {
|
|
@@ -277,6 +281,18 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
|
|
|
277
281
|
active_only?: boolean;
|
|
278
282
|
}): RequestId;
|
|
279
283
|
logout(): void;
|
|
284
|
+
/**
|
|
285
|
+
* Redeem an invite code. Authentication is proven by the session;
|
|
286
|
+
* no additional signature is required. Validation runs client-side —
|
|
287
|
+
* invalid inputs throw `ReferralCodeError` without a round-trip.
|
|
288
|
+
*/
|
|
289
|
+
redeemInvite(rawCode: string): RequestId;
|
|
290
|
+
/**
|
|
291
|
+
* Claim a vanity referral code (one-shot per taker). Validation
|
|
292
|
+
* runs client-side — invalid inputs throw `ReferralCodeError`.
|
|
293
|
+
*/
|
|
294
|
+
claimReferralCode(rawCode: string): Promise<RequestId>;
|
|
295
|
+
getMyReferralInfo(): RequestId;
|
|
280
296
|
getOrderStatus(orderIdHex: string): RequestId;
|
|
281
297
|
cancelRfq(rfqId: string): RequestId;
|
|
282
298
|
submitQuote(quote: QuoteMessage): void;
|
package/dist/ws/client.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Acta WebSocket client (rfq-server). */
|
|
2
2
|
import { buildSignedQuoteMessage, buildAcceptQuoteMessage } from "./flows";
|
|
3
3
|
import { assertWsU64Safe, validateQuantityBySizeRule } from "./wirePolicy";
|
|
4
|
+
import { parseReferralCode, ReferralCodeError } from "./referral";
|
|
4
5
|
function toGenericServerError(err) {
|
|
5
6
|
const message = err instanceof Error ? err.message : String(err);
|
|
6
7
|
return { type: "generic", data: { code: "client_error", message } };
|
|
@@ -403,6 +404,51 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
403
404
|
logout() {
|
|
404
405
|
this.send({ type: "Logout" });
|
|
405
406
|
}
|
|
407
|
+
// ========================================================================
|
|
408
|
+
// Referral / invite
|
|
409
|
+
// ========================================================================
|
|
410
|
+
/**
|
|
411
|
+
* Redeem an invite code. Authentication is proven by the session;
|
|
412
|
+
* no additional signature is required. Validation runs client-side —
|
|
413
|
+
* invalid inputs throw `ReferralCodeError` without a round-trip.
|
|
414
|
+
*/
|
|
415
|
+
redeemInvite(rawCode) {
|
|
416
|
+
this.ensureAuthenticated();
|
|
417
|
+
const parsed = parseReferralCode(rawCode);
|
|
418
|
+
if (!parsed.ok)
|
|
419
|
+
throw new ReferralCodeError(parsed.error);
|
|
420
|
+
const requestId = this.nextRequestId();
|
|
421
|
+
this.send({
|
|
422
|
+
type: "RedeemInvite",
|
|
423
|
+
data: { request_id: requestId, code: parsed.code },
|
|
424
|
+
});
|
|
425
|
+
return requestId;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Claim a vanity referral code (one-shot per taker). Validation
|
|
429
|
+
* runs client-side — invalid inputs throw `ReferralCodeError`.
|
|
430
|
+
*/
|
|
431
|
+
async claimReferralCode(rawCode) {
|
|
432
|
+
this.ensureAuthenticated();
|
|
433
|
+
const parsed = parseReferralCode(rawCode);
|
|
434
|
+
if (!parsed.ok)
|
|
435
|
+
throw new ReferralCodeError(parsed.error);
|
|
436
|
+
const requestId = this.nextRequestId();
|
|
437
|
+
this.send({
|
|
438
|
+
type: "ClaimReferralCode",
|
|
439
|
+
data: { request_id: requestId, code: parsed.code },
|
|
440
|
+
});
|
|
441
|
+
return requestId;
|
|
442
|
+
}
|
|
443
|
+
getMyReferralInfo() {
|
|
444
|
+
this.ensureAuthenticated();
|
|
445
|
+
const requestId = this.nextRequestId();
|
|
446
|
+
this.send({
|
|
447
|
+
type: "GetMyReferralInfo",
|
|
448
|
+
data: { request_id: requestId },
|
|
449
|
+
});
|
|
450
|
+
return requestId;
|
|
451
|
+
}
|
|
406
452
|
getOrderStatus(orderIdHex) {
|
|
407
453
|
this.ensureAuthenticated();
|
|
408
454
|
const requestId = this.nextRequestId();
|
|
@@ -874,6 +920,18 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
874
920
|
this.emit("subscriptionUpdated", d);
|
|
875
921
|
}
|
|
876
922
|
break;
|
|
923
|
+
case "RequireInvite":
|
|
924
|
+
this.emit("requireInvite");
|
|
925
|
+
break;
|
|
926
|
+
case "InviteRedeemed":
|
|
927
|
+
this.emit("inviteRedeemed", message.data);
|
|
928
|
+
break;
|
|
929
|
+
case "ReferralCodeClaimed":
|
|
930
|
+
this.emit("referralCodeClaimed", message.data);
|
|
931
|
+
break;
|
|
932
|
+
case "MyReferralInfo":
|
|
933
|
+
this.emit("myReferralInfo", message.data);
|
|
934
|
+
break;
|
|
877
935
|
}
|
|
878
936
|
}
|
|
879
937
|
/** Taker-only: request current indicative prices for a market + position_type. */
|
|
@@ -899,7 +957,7 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
899
957
|
try {
|
|
900
958
|
const [pubkey, signature] = await Promise.all([
|
|
901
959
|
this.authProvider.getPublicKey(),
|
|
902
|
-
this.authProvider.
|
|
960
|
+
this.authProvider.signMessage(challenge),
|
|
903
961
|
]);
|
|
904
962
|
this.send({
|
|
905
963
|
type: "AuthChallenge",
|
package/dist/ws/client.test.js
CHANGED
|
@@ -51,7 +51,7 @@ function parseClientMessage(payload) {
|
|
|
51
51
|
function makeAuthProvider(pubkey = "pubkey", signature = "signature") {
|
|
52
52
|
return {
|
|
53
53
|
getPublicKey: jest.fn().mockResolvedValue(pubkey),
|
|
54
|
-
|
|
54
|
+
signMessage: jest.fn().mockResolvedValue(signature),
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
57
|
function makeHarness(overrides = {}) {
|
package/dist/ws/index.d.ts
CHANGED
package/dist/ws/index.js
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Referral / invite redemption helpers.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the server-side validation defined in
|
|
5
|
+
* rust-backend/acta-types/src/invite.rs (ReferralCode::parse).
|
|
6
|
+
* Client-side validation must stay bit-identical to the server on
|
|
7
|
+
* the same input. A hardcoded fixture table is kept here and on the
|
|
8
|
+
* rust side; if either drifts, the cross-impl test will catch it.
|
|
9
|
+
*/
|
|
10
|
+
export declare const REFERRAL_CODE_MIN_LEN = 4;
|
|
11
|
+
export declare const REFERRAL_CODE_MAX_LEN = 16;
|
|
12
|
+
declare const brand: unique symbol;
|
|
13
|
+
/**
|
|
14
|
+
* A normalized, validated referral code. The only way to obtain one
|
|
15
|
+
* is through `parseReferralCode`, which enforces trim + ASCII
|
|
16
|
+
* uppercase and length/charset bounds identical to the server's
|
|
17
|
+
* `ReferralCode::parse`.
|
|
18
|
+
*/
|
|
19
|
+
export type ReferralCode = string & {
|
|
20
|
+
readonly [brand]: "ReferralCode";
|
|
21
|
+
};
|
|
22
|
+
export type ReferralCodeFormatError = {
|
|
23
|
+
kind: "length";
|
|
24
|
+
min: number;
|
|
25
|
+
max: number;
|
|
26
|
+
} | {
|
|
27
|
+
kind: "charset";
|
|
28
|
+
};
|
|
29
|
+
export declare class ReferralCodeError extends Error {
|
|
30
|
+
readonly detail: ReferralCodeFormatError;
|
|
31
|
+
constructor(detail: ReferralCodeFormatError);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Trim + ASCII uppercase. No length or charset check. Useful for
|
|
35
|
+
* showing a live preview as the user types.
|
|
36
|
+
*/
|
|
37
|
+
export declare function normalizeReferralCode(input: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Parse + validate + normalize a user-supplied referral code.
|
|
40
|
+
* Mirrors `ReferralCode::parse` on the server. A successful result
|
|
41
|
+
* carries the canonical branded `ReferralCode`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseReferralCode(input: string): {
|
|
44
|
+
ok: true;
|
|
45
|
+
code: ReferralCode;
|
|
46
|
+
} | {
|
|
47
|
+
ok: false;
|
|
48
|
+
error: ReferralCodeFormatError;
|
|
49
|
+
};
|
|
50
|
+
export type InviteErrorReason = "invalid_code" | "code_exhausted" | "code_expired" | "code_owner_inactive" | "code_owner_blacklisted" | "already_registered" | "internal_error";
|
|
51
|
+
export type ClaimErrorReason = "not_registered" | "invalid_format" | "code_taken" | "reserved" | "internal_error";
|
|
52
|
+
export type TakerStatus = "pending" | "active";
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Referral / invite redemption helpers.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the server-side validation defined in
|
|
5
|
+
* rust-backend/acta-types/src/invite.rs (ReferralCode::parse).
|
|
6
|
+
* Client-side validation must stay bit-identical to the server on
|
|
7
|
+
* the same input. A hardcoded fixture table is kept here and on the
|
|
8
|
+
* rust side; if either drifts, the cross-impl test will catch it.
|
|
9
|
+
*/
|
|
10
|
+
export const REFERRAL_CODE_MIN_LEN = 4;
|
|
11
|
+
export const REFERRAL_CODE_MAX_LEN = 16;
|
|
12
|
+
export class ReferralCodeError extends Error {
|
|
13
|
+
detail;
|
|
14
|
+
constructor(detail) {
|
|
15
|
+
super(detail.kind === "length"
|
|
16
|
+
? `code length must be between ${detail.min} and ${detail.max}`
|
|
17
|
+
: "code must contain only ASCII letters and digits");
|
|
18
|
+
this.detail = detail;
|
|
19
|
+
this.name = "ReferralCodeError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Trim + ASCII uppercase. No length or charset check. Useful for
|
|
24
|
+
* showing a live preview as the user types.
|
|
25
|
+
*/
|
|
26
|
+
export function normalizeReferralCode(input) {
|
|
27
|
+
return input.trim().toUpperCase();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parse + validate + normalize a user-supplied referral code.
|
|
31
|
+
* Mirrors `ReferralCode::parse` on the server. A successful result
|
|
32
|
+
* carries the canonical branded `ReferralCode`.
|
|
33
|
+
*/
|
|
34
|
+
export function parseReferralCode(input) {
|
|
35
|
+
const normalized = normalizeReferralCode(input);
|
|
36
|
+
if (normalized.length < REFERRAL_CODE_MIN_LEN ||
|
|
37
|
+
normalized.length > REFERRAL_CODE_MAX_LEN) {
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
error: {
|
|
41
|
+
kind: "length",
|
|
42
|
+
min: REFERRAL_CODE_MIN_LEN,
|
|
43
|
+
max: REFERRAL_CODE_MAX_LEN,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (!/^[A-Z0-9]+$/.test(normalized)) {
|
|
48
|
+
return { ok: false, error: { kind: "charset" } };
|
|
49
|
+
}
|
|
50
|
+
return { ok: true, code: normalized };
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { normalizeReferralCode, parseReferralCode } from "./referral";
|
|
2
|
+
// =============================================================================
|
|
3
|
+
// Cross-impl fixture.
|
|
4
|
+
//
|
|
5
|
+
// Bit-for-bit identical to the fixture in
|
|
6
|
+
// rust-backend/acta-types/src/invite.rs::tests
|
|
7
|
+
// If either side changes, update both.
|
|
8
|
+
// =============================================================================
|
|
9
|
+
const ACCEPT_FIXTURES = [
|
|
10
|
+
["NIKITA", "NIKITA"],
|
|
11
|
+
["nikita", "NIKITA"],
|
|
12
|
+
[" abc1 ", "ABC1"],
|
|
13
|
+
["ABCD", "ABCD"],
|
|
14
|
+
["1234567890ABCDEF", "1234567890ABCDEF"],
|
|
15
|
+
];
|
|
16
|
+
describe("parseReferralCode", () => {
|
|
17
|
+
test.each(ACCEPT_FIXTURES)("accepts %j → %j", (input, expected) => {
|
|
18
|
+
const res = parseReferralCode(input);
|
|
19
|
+
expect(res.ok).toBe(true);
|
|
20
|
+
if (res.ok)
|
|
21
|
+
expect(res.code).toBe(expected);
|
|
22
|
+
});
|
|
23
|
+
test("rejects too short", () => {
|
|
24
|
+
const res = parseReferralCode("abc");
|
|
25
|
+
expect(res.ok).toBe(false);
|
|
26
|
+
if (!res.ok)
|
|
27
|
+
expect(res.error.kind).toBe("length");
|
|
28
|
+
});
|
|
29
|
+
test("rejects too long", () => {
|
|
30
|
+
const res = parseReferralCode("A".repeat(17));
|
|
31
|
+
expect(res.ok).toBe(false);
|
|
32
|
+
if (!res.ok)
|
|
33
|
+
expect(res.error.kind).toBe("length");
|
|
34
|
+
});
|
|
35
|
+
test("rejects non-ascii", () => {
|
|
36
|
+
const res = parseReferralCode("абвгд");
|
|
37
|
+
expect(res.ok).toBe(false);
|
|
38
|
+
// Cyrillic passes length but fails charset.
|
|
39
|
+
if (!res.ok)
|
|
40
|
+
expect(res.error.kind).toBe("charset");
|
|
41
|
+
});
|
|
42
|
+
test("rejects punctuation", () => {
|
|
43
|
+
const res = parseReferralCode("ABC-12");
|
|
44
|
+
expect(res.ok).toBe(false);
|
|
45
|
+
if (!res.ok)
|
|
46
|
+
expect(res.error.kind).toBe("charset");
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe("normalizeReferralCode", () => {
|
|
50
|
+
test("trims and uppercases", () => {
|
|
51
|
+
expect(normalizeReferralCode(" nikita ")).toBe("NIKITA");
|
|
52
|
+
});
|
|
53
|
+
});
|
package/dist/ws/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Address } from "@solana/addresses";
|
|
2
|
+
import type { ClaimErrorReason, InviteErrorReason, TakerStatus } from "./referral";
|
|
2
3
|
export type UuidString = string;
|
|
3
4
|
export type RequestId = string;
|
|
4
5
|
export type PubkeyBase58 = string;
|
|
@@ -208,6 +209,40 @@ export type ClientMessage = {
|
|
|
208
209
|
request_id: RequestId;
|
|
209
210
|
channels: WsChannel[];
|
|
210
211
|
};
|
|
212
|
+
} | {
|
|
213
|
+
type: "RedeemInvite";
|
|
214
|
+
data: {
|
|
215
|
+
request_id: RequestId;
|
|
216
|
+
code: string;
|
|
217
|
+
};
|
|
218
|
+
} | {
|
|
219
|
+
type: "ClaimReferralCode";
|
|
220
|
+
data: {
|
|
221
|
+
request_id: RequestId;
|
|
222
|
+
code: string;
|
|
223
|
+
};
|
|
224
|
+
} | {
|
|
225
|
+
type: "GetMyReferralInfo";
|
|
226
|
+
data: {
|
|
227
|
+
request_id: RequestId;
|
|
228
|
+
};
|
|
229
|
+
};
|
|
230
|
+
export type InviteRedeemedData = {
|
|
231
|
+
request_id: RequestId;
|
|
232
|
+
referral_code: string;
|
|
233
|
+
};
|
|
234
|
+
export type ReferralCodeClaimedData = {
|
|
235
|
+
request_id: RequestId;
|
|
236
|
+
referral_code: string;
|
|
237
|
+
};
|
|
238
|
+
export type MyReferralInfoData = {
|
|
239
|
+
request_id: RequestId;
|
|
240
|
+
referral_code: string;
|
|
241
|
+
status: TakerStatus;
|
|
242
|
+
total_invited: number;
|
|
243
|
+
invited_this_period: number;
|
|
244
|
+
max_invites_per_period: number;
|
|
245
|
+
next_slot_frees_in_seconds: number;
|
|
211
246
|
};
|
|
212
247
|
export type GetMarketDescriptorsMessage = {
|
|
213
248
|
request_id: RequestId;
|
|
@@ -538,6 +573,17 @@ export type ServerMessage = {
|
|
|
538
573
|
underlying_mints?: string[];
|
|
539
574
|
quote_mints?: string[];
|
|
540
575
|
};
|
|
576
|
+
} | {
|
|
577
|
+
type: "RequireInvite";
|
|
578
|
+
} | {
|
|
579
|
+
type: "InviteRedeemed";
|
|
580
|
+
data: InviteRedeemedData;
|
|
581
|
+
} | {
|
|
582
|
+
type: "ReferralCodeClaimed";
|
|
583
|
+
data: ReferralCodeClaimedData;
|
|
584
|
+
} | {
|
|
585
|
+
type: "MyReferralInfo";
|
|
586
|
+
data: MyReferralInfoData;
|
|
541
587
|
};
|
|
542
588
|
export type MarketDescriptorInfo = {
|
|
543
589
|
market: MarketDescriptor;
|
|
@@ -577,128 +623,154 @@ export type QuoteRefreshRequestedMessage = {
|
|
|
577
623
|
reason: QuoteRefreshReason;
|
|
578
624
|
};
|
|
579
625
|
export type ServerError = {
|
|
580
|
-
type: "
|
|
626
|
+
type: "Unauthenticated";
|
|
581
627
|
data: {
|
|
582
628
|
action: AuthRequiredAction;
|
|
583
629
|
};
|
|
584
630
|
} | {
|
|
585
|
-
type: "
|
|
631
|
+
type: "Unauthorized";
|
|
586
632
|
data: {
|
|
587
633
|
role: UserRole;
|
|
588
634
|
action: AuthRequiredAction;
|
|
589
635
|
};
|
|
590
636
|
} | {
|
|
591
|
-
type: "
|
|
637
|
+
type: "RfqNotFound";
|
|
592
638
|
} | {
|
|
593
|
-
type: "
|
|
639
|
+
type: "RfqNotActive";
|
|
594
640
|
} | {
|
|
595
|
-
type: "
|
|
641
|
+
type: "RfqAlreadyLocked";
|
|
642
|
+
} | {
|
|
643
|
+
type: "InvalidState";
|
|
596
644
|
data: {
|
|
597
645
|
state: RfqStateError;
|
|
598
646
|
};
|
|
599
647
|
} | {
|
|
600
|
-
type: "
|
|
648
|
+
type: "QuoteLocked";
|
|
601
649
|
data: {
|
|
602
650
|
reason: QuoteLockedReason;
|
|
603
651
|
};
|
|
604
652
|
} | {
|
|
605
|
-
type: "
|
|
653
|
+
type: "QuoteNotFound";
|
|
606
654
|
} | {
|
|
607
|
-
type: "
|
|
655
|
+
type: "QuoteExpired";
|
|
608
656
|
} | {
|
|
609
|
-
type: "
|
|
657
|
+
type: "QuoteExpiryTooShort";
|
|
658
|
+
data: {
|
|
659
|
+
min_seconds: WsU32;
|
|
660
|
+
};
|
|
610
661
|
} | {
|
|
611
|
-
type: "
|
|
662
|
+
type: "InvalidStrike";
|
|
612
663
|
} | {
|
|
613
|
-
type: "
|
|
664
|
+
type: "InvalidValidUntil";
|
|
614
665
|
} | {
|
|
615
|
-
type: "
|
|
666
|
+
type: "OrderIdMismatch";
|
|
616
667
|
} | {
|
|
617
|
-
type: "
|
|
668
|
+
type: "UnknownOrder";
|
|
618
669
|
} | {
|
|
619
|
-
type: "
|
|
670
|
+
type: "SignatureTimeout";
|
|
671
|
+
} | {
|
|
672
|
+
type: "OracleNotReady";
|
|
673
|
+
} | {
|
|
674
|
+
type: "OraclePriceStale";
|
|
620
675
|
data: {
|
|
621
676
|
age_seconds: WsU64;
|
|
622
677
|
};
|
|
623
678
|
} | {
|
|
624
|
-
type: "
|
|
679
|
+
type: "OraclePriceNotReady";
|
|
625
680
|
} | {
|
|
626
|
-
type: "
|
|
681
|
+
type: "InvalidPositionType";
|
|
627
682
|
} | {
|
|
628
|
-
type: "
|
|
683
|
+
type: "InvalidMarket";
|
|
629
684
|
data: {
|
|
630
685
|
pubkey: string;
|
|
631
686
|
};
|
|
632
687
|
} | {
|
|
633
|
-
type: "
|
|
688
|
+
type: "MarketMetadataIncomplete";
|
|
634
689
|
data: {
|
|
635
690
|
details: string;
|
|
636
691
|
};
|
|
637
692
|
} | {
|
|
638
|
-
type: "
|
|
693
|
+
type: "TokenMetadataIncomplete";
|
|
639
694
|
data: {
|
|
640
695
|
details: string;
|
|
641
696
|
};
|
|
642
697
|
} | {
|
|
643
|
-
type: "
|
|
698
|
+
type: "RateLimit";
|
|
644
699
|
data: RateLimitReason;
|
|
645
700
|
} | {
|
|
646
|
-
type: "
|
|
701
|
+
type: "Cap";
|
|
702
|
+
data: CapErrorData;
|
|
703
|
+
} | {
|
|
704
|
+
type: "InternalError";
|
|
705
|
+
} | {
|
|
706
|
+
type: "KernelNotAvailable";
|
|
707
|
+
} | {
|
|
708
|
+
type: "DbDisabled";
|
|
647
709
|
data: {
|
|
710
|
+
feature: DbFeature;
|
|
711
|
+
};
|
|
712
|
+
} | {
|
|
713
|
+
type: "ServerShuttingDown";
|
|
714
|
+
} | {
|
|
715
|
+
type: "Generic";
|
|
716
|
+
data: {
|
|
717
|
+
code: ErrorCode;
|
|
718
|
+
message: ErrorMessage;
|
|
719
|
+
};
|
|
720
|
+
} | {
|
|
721
|
+
type: "InviteRequired";
|
|
722
|
+
} | {
|
|
723
|
+
type: "Invite";
|
|
724
|
+
data: InviteErrorReason;
|
|
725
|
+
} | {
|
|
726
|
+
type: "Claim";
|
|
727
|
+
data: ClaimErrorReason;
|
|
728
|
+
} | {
|
|
729
|
+
type: "generic";
|
|
730
|
+
data: {
|
|
731
|
+
code: ErrorCode;
|
|
732
|
+
message: ErrorMessage;
|
|
733
|
+
};
|
|
734
|
+
};
|
|
735
|
+
/**
|
|
736
|
+
* Externally-tagged union for rust's `CapError`. Only one key is
|
|
737
|
+
* present at a time. Lock-step with
|
|
738
|
+
* `rust-backend/acta-types/src/errors.rs::CapError`.
|
|
739
|
+
*/
|
|
740
|
+
export type CapErrorData = {
|
|
741
|
+
token_oi_cap_exceeded: {
|
|
648
742
|
underlying_mint: string;
|
|
649
743
|
current: WsU64;
|
|
650
744
|
limit: WsU64;
|
|
651
745
|
};
|
|
652
746
|
} | {
|
|
653
|
-
|
|
654
|
-
data: {
|
|
747
|
+
market_oi_cap_exceeded: {
|
|
655
748
|
market_id: string;
|
|
656
749
|
current: WsU64;
|
|
657
750
|
limit: WsU64;
|
|
658
751
|
};
|
|
659
752
|
} | {
|
|
660
|
-
|
|
661
|
-
data: {
|
|
753
|
+
maker_position_cap_exceeded: {
|
|
662
754
|
current: WsU32;
|
|
663
755
|
limit: WsU32;
|
|
664
756
|
};
|
|
665
757
|
} | {
|
|
666
|
-
|
|
667
|
-
data: {
|
|
758
|
+
maker_notional_cap_exceeded: {
|
|
668
759
|
underlying_mint: string;
|
|
669
760
|
current: WsU64;
|
|
670
761
|
limit: WsU64;
|
|
671
762
|
};
|
|
672
763
|
} | {
|
|
673
|
-
|
|
674
|
-
data: {
|
|
764
|
+
maker_insufficient_balance: {
|
|
675
765
|
available: WsU64;
|
|
676
766
|
required: WsU64;
|
|
677
767
|
};
|
|
678
768
|
} | {
|
|
679
|
-
|
|
680
|
-
data: {
|
|
769
|
+
quote_notional_cap_exceeded: {
|
|
681
770
|
quote_mint: string;
|
|
682
771
|
current: WsU64;
|
|
683
772
|
limit: WsU64;
|
|
684
773
|
};
|
|
685
|
-
} | {
|
|
686
|
-
type: "internal_error";
|
|
687
|
-
} | {
|
|
688
|
-
type: "kernel_not_available";
|
|
689
|
-
} | {
|
|
690
|
-
type: "db_disabled";
|
|
691
|
-
data: {
|
|
692
|
-
feature: DbFeature;
|
|
693
|
-
};
|
|
694
|
-
} | {
|
|
695
|
-
type: "server_shutting_down";
|
|
696
|
-
} | {
|
|
697
|
-
type: "generic";
|
|
698
|
-
data: {
|
|
699
|
-
code: ErrorCode;
|
|
700
|
-
message: ErrorMessage;
|
|
701
|
-
};
|
|
702
774
|
};
|
|
703
775
|
/** Confirms quote was received and validated. */
|
|
704
776
|
export type QuoteAcknowledgedMessage = {
|