@acta-markets/ts-sdk 0.0.1-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/README.md +308 -0
- package/dist/actaClient.d.ts +46 -0
- package/dist/actaClient.js +99 -0
- package/dist/chain/client.d.ts +65 -0
- package/dist/chain/client.js +82 -0
- package/dist/chain/fetch.d.ts +204 -0
- package/dist/chain/fetch.js +392 -0
- package/dist/chain/fetch.test.d.ts +1 -0
- package/dist/chain/fetch.test.js +158 -0
- package/dist/chain/flows/index.d.ts +1 -0
- package/dist/chain/flows/index.js +1 -0
- package/dist/chain/flows/openPosition.d.ts +48 -0
- package/dist/chain/flows/openPosition.js +78 -0
- package/dist/chain/flows/openPosition.test.d.ts +1 -0
- package/dist/chain/flows/openPosition.test.js +43 -0
- package/dist/chain/helpers.d.ts +16 -0
- package/dist/chain/helpers.js +60 -0
- package/dist/chain/index.d.ts +9 -0
- package/dist/chain/index.js +9 -0
- package/dist/chain/instructions.admin.d.ts +44 -0
- package/dist/chain/instructions.admin.js +113 -0
- package/dist/chain/instructions.d.ts +5 -0
- package/dist/chain/instructions.js +5 -0
- package/dist/chain/instructions.maker.d.ts +34 -0
- package/dist/chain/instructions.maker.js +86 -0
- package/dist/chain/instructions.market.d.ts +39 -0
- package/dist/chain/instructions.market.js +107 -0
- package/dist/chain/instructions.oracle.d.ts +38 -0
- package/dist/chain/instructions.oracle.js +63 -0
- package/dist/chain/instructions.position.d.ts +82 -0
- package/dist/chain/instructions.position.js +240 -0
- package/dist/chain/instructions.resolve.test.d.ts +1 -0
- package/dist/chain/instructions.resolve.test.js +32 -0
- package/dist/chain/instructions.shared.d.ts +23 -0
- package/dist/chain/instructions.shared.js +55 -0
- package/dist/chain/orders.d.ts +40 -0
- package/dist/chain/orders.js +117 -0
- package/dist/chain/orders.test.d.ts +1 -0
- package/dist/chain/orders.test.js +67 -0
- package/dist/chain/signers.d.ts +9 -0
- package/dist/chain/signers.js +19 -0
- package/dist/chain/signers.test.d.ts +1 -0
- package/dist/chain/signers.test.js +13 -0
- package/dist/chain/token.d.ts +59 -0
- package/dist/chain/token.js +136 -0
- package/dist/chain/token.test.d.ts +1 -0
- package/dist/chain/token.test.js +69 -0
- package/dist/chain/tx.d.ts +72 -0
- package/dist/chain/tx.js +97 -0
- package/dist/cjs/actaClient.js +103 -0
- package/dist/cjs/chain/client.js +119 -0
- package/dist/cjs/chain/fetch.js +431 -0
- package/dist/cjs/chain/fetch.test.js +160 -0
- package/dist/cjs/chain/flows/index.js +17 -0
- package/dist/cjs/chain/flows/openPosition.js +81 -0
- package/dist/cjs/chain/flows/openPosition.test.js +45 -0
- package/dist/cjs/chain/helpers.js +67 -0
- package/dist/cjs/chain/index.js +48 -0
- package/dist/cjs/chain/instructions.admin.js +119 -0
- package/dist/cjs/chain/instructions.js +21 -0
- package/dist/cjs/chain/instructions.maker.js +92 -0
- package/dist/cjs/chain/instructions.market.js +112 -0
- package/dist/cjs/chain/instructions.oracle.js +70 -0
- package/dist/cjs/chain/instructions.position.js +247 -0
- package/dist/cjs/chain/instructions.resolve.test.js +34 -0
- package/dist/cjs/chain/instructions.shared.js +64 -0
- package/dist/cjs/chain/orders.js +126 -0
- package/dist/cjs/chain/orders.test.js +69 -0
- package/dist/cjs/chain/signers.js +22 -0
- package/dist/cjs/chain/signers.test.js +15 -0
- package/dist/cjs/chain/token.js +147 -0
- package/dist/cjs/chain/token.test.js +71 -0
- package/dist/cjs/chain/tx.js +103 -0
- package/dist/cjs/constants.js +6 -0
- package/dist/cjs/constants.test.js +31 -0
- package/dist/cjs/events.js +75 -0
- package/dist/cjs/events.test.js +384 -0
- package/dist/cjs/generated/accounts/config.js +79 -0
- package/dist/cjs/generated/accounts/index.js +28 -0
- package/dist/cjs/generated/accounts/maker.js +71 -0
- package/dist/cjs/generated/accounts/market.js +93 -0
- package/dist/cjs/generated/accounts/oracle.js +85 -0
- package/dist/cjs/generated/accounts/position.js +89 -0
- package/dist/cjs/generated/errors/actaContract.js +154 -0
- package/dist/cjs/generated/errors/index.js +24 -0
- package/dist/cjs/generated/index.js +28 -0
- package/dist/cjs/generated/instructions/changeOracleSource.js +81 -0
- package/dist/cjs/generated/instructions/closeMarket.js +83 -0
- package/dist/cjs/generated/instructions/closeOracle.js +79 -0
- package/dist/cjs/generated/instructions/createMarket.js +116 -0
- package/dist/cjs/generated/instructions/createOracle.js +99 -0
- package/dist/cjs/generated/instructions/depositFundsToPosition.js +101 -0
- package/dist/cjs/generated/instructions/depositPremium.js +96 -0
- package/dist/cjs/generated/instructions/finalizeMarket.js +91 -0
- package/dist/cjs/generated/instructions/index.js +43 -0
- package/dist/cjs/generated/instructions/initializeConfig.js +108 -0
- package/dist/cjs/generated/instructions/liquidatePosition.js +107 -0
- package/dist/cjs/generated/instructions/openPosition.js +154 -0
- package/dist/cjs/generated/instructions/registerMaker.js +90 -0
- package/dist/cjs/generated/instructions/setOracleConfig.js +80 -0
- package/dist/cjs/generated/instructions/settlePosition.js +104 -0
- package/dist/cjs/generated/instructions/topupFeeFund.js +96 -0
- package/dist/cjs/generated/instructions/updateConfig.js +86 -0
- package/dist/cjs/generated/instructions/updateMakerQuoteSigning.js +79 -0
- package/dist/cjs/generated/instructions/updateMarketOracles.js +96 -0
- package/dist/cjs/generated/instructions/updateOraclePrice.js +89 -0
- package/dist/cjs/generated/instructions/withdrawFromFeeFund.js +96 -0
- package/dist/cjs/generated/instructions/withdrawPremium.js +96 -0
- package/dist/cjs/generated/programs/actaContract.js +108 -0
- package/dist/cjs/generated/programs/index.js +24 -0
- package/dist/cjs/generated/shared/index.js +94 -0
- package/dist/cjs/generated/types/actaEvent.js +342 -0
- package/dist/cjs/generated/types/eventKind.js +45 -0
- package/dist/cjs/generated/types/index.js +27 -0
- package/dist/cjs/generated/types/positionStatus.js +31 -0
- package/dist/cjs/generated/types/positionType.js +28 -0
- package/dist/cjs/idl/acta_contract.json +2329 -0
- package/dist/cjs/idl/hash.js +4 -0
- package/dist/cjs/index.js +84 -0
- package/dist/cjs/nonce.js +93 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/types/index.js +18 -0
- package/dist/cjs/types/orderId.js +40 -0
- package/dist/cjs/types/orders.js +10 -0
- package/dist/cjs/ws/apy.js +106 -0
- package/dist/cjs/ws/apy.test.js +29 -0
- package/dist/cjs/ws/auth.js +104 -0
- package/dist/cjs/ws/client.handshake.integration.test.js +69 -0
- package/dist/cjs/ws/client.js +861 -0
- package/dist/cjs/ws/client.test.js +230 -0
- package/dist/cjs/ws/discovery.js +48 -0
- package/dist/cjs/ws/flows.js +101 -0
- package/dist/cjs/ws/flows.test.js +85 -0
- package/dist/cjs/ws/index.js +23 -0
- package/dist/cjs/ws/sponsoredTx.js +95 -0
- package/dist/cjs/ws/types.js +14 -0
- package/dist/cjs/ws/wirePolicy.js +34 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +3 -0
- package/dist/constants.test.d.ts +1 -0
- package/dist/constants.test.js +29 -0
- package/dist/events.d.ts +15 -0
- package/dist/events.js +64 -0
- package/dist/events.test.d.ts +1 -0
- package/dist/events.test.js +382 -0
- package/dist/generated/accounts/config.d.ts +47 -0
- package/dist/generated/accounts/config.js +68 -0
- package/dist/generated/accounts/index.d.ts +12 -0
- package/dist/generated/accounts/index.js +12 -0
- package/dist/generated/accounts/maker.d.ts +39 -0
- package/dist/generated/accounts/maker.js +60 -0
- package/dist/generated/accounts/market.d.ts +61 -0
- package/dist/generated/accounts/market.js +82 -0
- package/dist/generated/accounts/oracle.d.ts +53 -0
- package/dist/generated/accounts/oracle.js +74 -0
- package/dist/generated/accounts/position.d.ts +57 -0
- package/dist/generated/accounts/position.js +78 -0
- package/dist/generated/errors/actaContract.d.ts +103 -0
- package/dist/generated/errors/actaContract.js +149 -0
- package/dist/generated/errors/index.d.ts +8 -0
- package/dist/generated/errors/index.js +8 -0
- package/dist/generated/index.d.ts +12 -0
- package/dist/generated/index.js +12 -0
- package/dist/generated/instructions/changeOracleSource.d.ts +50 -0
- package/dist/generated/instructions/changeOracleSource.js +72 -0
- package/dist/generated/instructions/closeMarket.d.ts +58 -0
- package/dist/generated/instructions/closeMarket.js +74 -0
- package/dist/generated/instructions/closeOracle.d.ts +48 -0
- package/dist/generated/instructions/closeOracle.js +70 -0
- package/dist/generated/instructions/createMarket.d.ts +90 -0
- package/dist/generated/instructions/createMarket.js +107 -0
- package/dist/generated/instructions/createOracle.d.ts +71 -0
- package/dist/generated/instructions/createOracle.js +90 -0
- package/dist/generated/instructions/depositFundsToPosition.d.ts +73 -0
- package/dist/generated/instructions/depositFundsToPosition.js +92 -0
- package/dist/generated/instructions/depositPremium.d.ts +62 -0
- package/dist/generated/instructions/depositPremium.js +87 -0
- package/dist/generated/instructions/finalizeMarket.d.ts +63 -0
- package/dist/generated/instructions/finalizeMarket.js +82 -0
- package/dist/generated/instructions/index.d.ts +27 -0
- package/dist/generated/instructions/index.js +27 -0
- package/dist/generated/instructions/initializeConfig.d.ts +75 -0
- package/dist/generated/instructions/initializeConfig.js +99 -0
- package/dist/generated/instructions/liquidatePosition.d.ts +78 -0
- package/dist/generated/instructions/liquidatePosition.js +98 -0
- package/dist/generated/instructions/openPosition.d.ts +130 -0
- package/dist/generated/instructions/openPosition.js +145 -0
- package/dist/generated/instructions/registerMaker.d.ts +57 -0
- package/dist/generated/instructions/registerMaker.js +81 -0
- package/dist/generated/instructions/setOracleConfig.d.ts +53 -0
- package/dist/generated/instructions/setOracleConfig.js +71 -0
- package/dist/generated/instructions/settlePosition.d.ts +78 -0
- package/dist/generated/instructions/settlePosition.js +95 -0
- package/dist/generated/instructions/topupFeeFund.d.ts +67 -0
- package/dist/generated/instructions/topupFeeFund.js +87 -0
- package/dist/generated/instructions/updateConfig.d.ts +58 -0
- package/dist/generated/instructions/updateConfig.js +77 -0
- package/dist/generated/instructions/updateMakerQuoteSigning.d.ts +47 -0
- package/dist/generated/instructions/updateMakerQuoteSigning.js +70 -0
- package/dist/generated/instructions/updateMarketOracles.d.ts +65 -0
- package/dist/generated/instructions/updateMarketOracles.js +87 -0
- package/dist/generated/instructions/updateOraclePrice.d.ts +55 -0
- package/dist/generated/instructions/updateOraclePrice.js +80 -0
- package/dist/generated/instructions/withdrawFromFeeFund.d.ts +62 -0
- package/dist/generated/instructions/withdrawFromFeeFund.js +87 -0
- package/dist/generated/instructions/withdrawPremium.d.ts +62 -0
- package/dist/generated/instructions/withdrawPremium.js +87 -0
- package/dist/generated/programs/actaContract.d.ts +83 -0
- package/dist/generated/programs/actaContract.js +104 -0
- package/dist/generated/programs/index.d.ts +8 -0
- package/dist/generated/programs/index.js +8 -0
- package/dist/generated/shared/index.d.ts +49 -0
- package/dist/generated/shared/index.js +86 -0
- package/dist/generated/types/actaEvent.d.ts +249 -0
- package/dist/generated/types/actaEvent.js +335 -0
- package/dist/generated/types/eventKind.d.ts +33 -0
- package/dist/generated/types/eventKind.js +39 -0
- package/dist/generated/types/index.d.ts +11 -0
- package/dist/generated/types/index.js +11 -0
- package/dist/generated/types/positionStatus.d.ts +19 -0
- package/dist/generated/types/positionStatus.js +25 -0
- package/dist/generated/types/positionType.d.ts +16 -0
- package/dist/generated/types/positionType.js +22 -0
- package/dist/idl/acta_contract.json +2329 -0
- package/dist/idl/hash.d.ts +1 -0
- package/dist/idl/hash.js +1 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.js +34 -0
- package/dist/nonce.d.ts +29 -0
- package/dist/nonce.js +89 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/orderId.d.ts +13 -0
- package/dist/types/orderId.js +35 -0
- package/dist/types/orders.d.ts +9 -0
- package/dist/types/orders.js +9 -0
- package/dist/ws/apy.d.ts +79 -0
- package/dist/ws/apy.js +98 -0
- package/dist/ws/apy.test.d.ts +1 -0
- package/dist/ws/apy.test.js +27 -0
- package/dist/ws/auth.d.ts +67 -0
- package/dist/ws/auth.js +98 -0
- package/dist/ws/client.d.ts +263 -0
- package/dist/ws/client.handshake.integration.test.d.ts +1 -0
- package/dist/ws/client.handshake.integration.test.js +64 -0
- package/dist/ws/client.js +857 -0
- package/dist/ws/client.test.d.ts +1 -0
- package/dist/ws/client.test.js +228 -0
- package/dist/ws/discovery.d.ts +13 -0
- package/dist/ws/discovery.js +44 -0
- package/dist/ws/flows.d.ts +44 -0
- package/dist/ws/flows.js +96 -0
- package/dist/ws/flows.test.d.ts +1 -0
- package/dist/ws/flows.test.js +83 -0
- package/dist/ws/index.d.ts +7 -0
- package/dist/ws/index.js +7 -0
- package/dist/ws/sponsoredTx.d.ts +39 -0
- package/dist/ws/sponsoredTx.js +92 -0
- package/dist/ws/types.d.ts +900 -0
- package/dist/ws/types.js +13 -0
- package/dist/ws/wirePolicy.d.ts +12 -0
- package/dist/ws/wirePolicy.js +30 -0
- package/package.json +87 -0
package/dist/ws/auth.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket auth providers.
|
|
3
|
+
*
|
|
4
|
+
* RFQ WS auth handshake:
|
|
5
|
+
* - Server sends `AuthRequest { challenge: <human-readable text> }`
|
|
6
|
+
* - Client signs UTF-8 bytes of that text and responds:
|
|
7
|
+
* `AuthChallenge { challenge, signature: base58(ed25519(utf8(challenge))), pubkey }`
|
|
8
|
+
*
|
|
9
|
+
* Source of truth (server):
|
|
10
|
+
* - rust-backend/rfq-server/src/server/ws.rs
|
|
11
|
+
* - rust-backend/rfq-server/src/session/handler.rs
|
|
12
|
+
*/
|
|
13
|
+
import { getAddressFromPublicKey } from "@solana/addresses";
|
|
14
|
+
import { createKeyPairFromBytes, createKeyPairFromPrivateKeyBytes, signBytes, } from "@solana/keys";
|
|
15
|
+
import { getBase58Decoder } from "@solana/codecs-strings";
|
|
16
|
+
const bytesToBase58 = (() => {
|
|
17
|
+
const dec = getBase58Decoder();
|
|
18
|
+
return (bytes) => dec.decode(bytes);
|
|
19
|
+
})();
|
|
20
|
+
const utf8ToBytes = (value) => new TextEncoder().encode(value);
|
|
21
|
+
/**
|
|
22
|
+
* Auth provider backed by a `CryptoKeyPair`.
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
export class KeypairAuthProvider {
|
|
26
|
+
address;
|
|
27
|
+
privateKey;
|
|
28
|
+
constructor(args) {
|
|
29
|
+
this.address = args.address;
|
|
30
|
+
this.privateKey = args.privateKey;
|
|
31
|
+
}
|
|
32
|
+
/** Create from a Solana CLI-style 64-byte secret key array (private + public). */
|
|
33
|
+
static async fromSecretKeyBytes(secretKey64) {
|
|
34
|
+
const keyPair = await createKeyPairFromBytes(secretKey64);
|
|
35
|
+
const address = await getAddressFromPublicKey(keyPair.publicKey);
|
|
36
|
+
return new KeypairAuthProvider({ address, privateKey: keyPair.privateKey });
|
|
37
|
+
}
|
|
38
|
+
/** Create from a 32-byte private key. */
|
|
39
|
+
static async fromPrivateKeyBytes(privateKey32) {
|
|
40
|
+
const keyPair = await createKeyPairFromPrivateKeyBytes(privateKey32);
|
|
41
|
+
const address = await getAddressFromPublicKey(keyPair.publicKey);
|
|
42
|
+
return new KeypairAuthProvider({ address, privateKey: keyPair.privateKey });
|
|
43
|
+
}
|
|
44
|
+
/** Create from Solana CLI keypair JSON (array of numbers). */
|
|
45
|
+
static async fromJson(json) {
|
|
46
|
+
const arr = typeof json === "string" ? JSON.parse(json) : json;
|
|
47
|
+
return KeypairAuthProvider.fromSecretKeyBytes(Uint8Array.from(arr));
|
|
48
|
+
}
|
|
49
|
+
async getPublicKey() {
|
|
50
|
+
return this.address;
|
|
51
|
+
}
|
|
52
|
+
async signChallenge(challenge) {
|
|
53
|
+
const challengeBytes = utf8ToBytes(challenge);
|
|
54
|
+
const signatureBytes = await signBytes(this.privateKey, challengeBytes);
|
|
55
|
+
return bytesToBase58(signatureBytes);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Wallet-like provider (browser wallets, custom signers, etc.)
|
|
60
|
+
*
|
|
61
|
+
* We intentionally do NOT depend on @solana/web3.js types. Consumers can adapt their wallet
|
|
62
|
+
* implementation to this minimal interface.
|
|
63
|
+
*/
|
|
64
|
+
export class WalletAuthProvider {
|
|
65
|
+
wallet;
|
|
66
|
+
constructor(wallet) {
|
|
67
|
+
this.wallet = wallet;
|
|
68
|
+
}
|
|
69
|
+
async getPublicKey() {
|
|
70
|
+
const pk = this.wallet.publicKeyBase58 ?? this.wallet.publicKey?.toBase58?.();
|
|
71
|
+
if (!pk)
|
|
72
|
+
throw new Error("Wallet not connected (missing public key)");
|
|
73
|
+
return pk;
|
|
74
|
+
}
|
|
75
|
+
async signChallenge(challenge) {
|
|
76
|
+
const challengeBytes = utf8ToBytes(challenge);
|
|
77
|
+
// Some wallet APIs expect a mutable `Uint8Array`; codecs return `ReadonlyUint8Array`.
|
|
78
|
+
const sig = await this.wallet.signMessage(new Uint8Array(challengeBytes));
|
|
79
|
+
return bytesToBase58(sig);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Custom auth provider for fully custom integrations (hardware wallets, remote signers, etc.).
|
|
84
|
+
*/
|
|
85
|
+
export class CustomAuthProvider {
|
|
86
|
+
getPublicKeyFn;
|
|
87
|
+
signChallengeFn;
|
|
88
|
+
constructor(getPublicKey, signChallenge) {
|
|
89
|
+
this.getPublicKeyFn = getPublicKey;
|
|
90
|
+
this.signChallengeFn = signChallenge;
|
|
91
|
+
}
|
|
92
|
+
async getPublicKey() {
|
|
93
|
+
return this.getPublicKeyFn();
|
|
94
|
+
}
|
|
95
|
+
async signChallenge(challenge) {
|
|
96
|
+
return this.signChallengeFn(challenge);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/** Acta WebSocket client (rfq-server). */
|
|
2
|
+
import type { AuthProvider } from "./auth";
|
|
3
|
+
import type { SignerLike } from "../chain/orders";
|
|
4
|
+
import type { Address } from "@solana/addresses";
|
|
5
|
+
import type { ActiveRfqInfo, ChainEventMessage, GlobalStats, MarketDescriptorInfo, MarketInfo, MyActiveRfqInfo, MyActiveRfqsMessage, OrderStatusMessage, PositionInfo, QuoteAcknowledgedMessage, QuoteBestStatusMessage, QuoteCancelledMessage, QuoteMessage, QuoteRefreshRequestedMessage, QuoteOutbidMessage, QuoteReceivedMessage, QuoteSelectedMessage, QuotesUpdateMessage, RfqBroadcastMessage, RfqClosedMessage, RfqCreatedMessage, RfqRequestMessage, RfqAvailableAgainMessage, QuoteExpiredMessage, QuoteFilledMessage, IndicativePricesMessage, IndicativePricesRequestMessage, IndicativePricesResponseMessage, GetIndicativePricesMessage, ServerMessage, SnapshotMessage, StatsDelta, SubscriptionsMessage, TokenInfo, TradeInfo, UuidString, VersionMismatchMessage, WelcomeMessage, WsChannel } from "./types";
|
|
6
|
+
export type ConnectionState = "disconnected" | "connecting" | "authenticating" | "authenticated" | "error";
|
|
7
|
+
export type ClientRole = "taker" | "maker";
|
|
8
|
+
export type PendingMessagesOverflowPolicy = "drop_oldest" | "drop_newest" | "throw";
|
|
9
|
+
export type ActaWsClientOptions = {
|
|
10
|
+
/** Base server URL, e.g. `ws://localhost:8080` (client appends `/ws/{role}`) */
|
|
11
|
+
url: string;
|
|
12
|
+
role: ClientRole;
|
|
13
|
+
/** WS protocol version for Hello/Welcome negotiation (default "1.0.0"). */
|
|
14
|
+
protocolVersion?: string;
|
|
15
|
+
/** Optional feature flags to request in Hello. */
|
|
16
|
+
features?: string[];
|
|
17
|
+
/** Optional client name for Hello. */
|
|
18
|
+
clientName?: string;
|
|
19
|
+
/** Optional client version for Hello. */
|
|
20
|
+
clientVersion?: string;
|
|
21
|
+
/**
|
|
22
|
+
* If true (default), the client will automatically reconnect after disconnects/errors.
|
|
23
|
+
* Reconnect uses exponential backoff from `reconnectDelay` to `maxReconnectDelay`.
|
|
24
|
+
*/
|
|
25
|
+
autoReconnect?: boolean;
|
|
26
|
+
/** Base reconnect delay in ms (default 1000). */
|
|
27
|
+
reconnectDelay?: number;
|
|
28
|
+
/** Max reconnect delay in ms (default 30000). */
|
|
29
|
+
maxReconnectDelay?: number;
|
|
30
|
+
/** Backoff jitter ratio in [0..1] (default 0.2). */
|
|
31
|
+
reconnectJitterRatio?: number;
|
|
32
|
+
/** Ping interval in ms (default 30000). */
|
|
33
|
+
pingInterval?: number;
|
|
34
|
+
/** Max queued client messages before Welcome (default 100). */
|
|
35
|
+
maxPendingMessages?: number;
|
|
36
|
+
/** Queue overflow policy before Welcome (default "drop_oldest"). */
|
|
37
|
+
pendingMessagesOverflowPolicy?: PendingMessagesOverflowPolicy;
|
|
38
|
+
debug?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Optional socket factory for Node/browser portability.
|
|
41
|
+
* If omitted, global `WebSocket` will be used when available.
|
|
42
|
+
*/
|
|
43
|
+
makeSocket?: WebSocketFactory;
|
|
44
|
+
};
|
|
45
|
+
export type ClientState = {
|
|
46
|
+
stats: GlobalStats | null;
|
|
47
|
+
activeRfqs: Map<UuidString, ActiveRfqInfo>;
|
|
48
|
+
myActiveRfqs: Map<UuidString, MyActiveRfqInfo>;
|
|
49
|
+
positions: Map<string, PositionInfo>;
|
|
50
|
+
recentTrades: TradeInfo[];
|
|
51
|
+
markets: Map<string, MarketInfo>;
|
|
52
|
+
};
|
|
53
|
+
export type ActaWsClientEvents = {
|
|
54
|
+
[event: string]: (...args: any[]) => void;
|
|
55
|
+
connecting: () => void;
|
|
56
|
+
connected: () => void;
|
|
57
|
+
welcome: (msg: WelcomeMessage) => void;
|
|
58
|
+
versionMismatch: (msg: VersionMismatchMessage) => void;
|
|
59
|
+
authenticated: (sessionId: string) => void;
|
|
60
|
+
disconnected: (code: number, reason: string) => void;
|
|
61
|
+
error: (error: Error) => void;
|
|
62
|
+
stateChange: (state: ConnectionState) => void;
|
|
63
|
+
message: (message: ServerMessage) => void;
|
|
64
|
+
snapshot: (snapshot: SnapshotMessage) => void;
|
|
65
|
+
positions: (positions: PositionInfo[]) => void;
|
|
66
|
+
markets: (markets: MarketInfo[]) => void;
|
|
67
|
+
marketDescriptors: (markets: MarketDescriptorInfo[]) => void;
|
|
68
|
+
expiries: (expiriesTs: number[]) => void;
|
|
69
|
+
tokens: (args: {
|
|
70
|
+
underlyings: TokenInfo[];
|
|
71
|
+
quotesByUnderlying: Record<string, TokenInfo[]>;
|
|
72
|
+
}) => void;
|
|
73
|
+
statsUpdate: (stats: GlobalStats) => void;
|
|
74
|
+
subscriptions: (msg: SubscriptionsMessage) => void;
|
|
75
|
+
activeRfqs: (rfqs: ActiveRfqInfo[]) => void;
|
|
76
|
+
rfqBroadcast: (rfq: RfqBroadcastMessage) => void;
|
|
77
|
+
rfqCreated: (msg: RfqCreatedMessage) => void;
|
|
78
|
+
rfqClosed: (msg: RfqClosedMessage) => void;
|
|
79
|
+
quoteReceived: (quote: QuoteReceivedMessage) => void;
|
|
80
|
+
quotesUpdate: (update: QuotesUpdateMessage) => void;
|
|
81
|
+
quoteAcknowledged: (msg: QuoteAcknowledgedMessage) => void;
|
|
82
|
+
quoteBestStatus: (msg: QuoteBestStatusMessage) => void;
|
|
83
|
+
quoteOutbid: (msg: QuoteOutbidMessage) => void;
|
|
84
|
+
quoteRefreshRequested: (msg: QuoteRefreshRequestedMessage) => void;
|
|
85
|
+
quoteSelected: (msg: QuoteSelectedMessage) => void;
|
|
86
|
+
quoteFilled: (msg: QuoteFilledMessage) => void;
|
|
87
|
+
quoteCancelled: (msg: QuoteCancelledMessage) => void;
|
|
88
|
+
rfqAvailableAgain: (msg: RfqAvailableAgainMessage) => void;
|
|
89
|
+
quoteExpired: (msg: QuoteExpiredMessage) => void;
|
|
90
|
+
indicativePrices: (msg: IndicativePricesMessage) => void;
|
|
91
|
+
indicativePricesRequest: (msg: IndicativePricesRequestMessage) => void;
|
|
92
|
+
myActiveRfqs: (msg: MyActiveRfqsMessage) => void;
|
|
93
|
+
orderStatus: (msg: OrderStatusMessage) => void;
|
|
94
|
+
orderAccepted: (orderId: string) => void;
|
|
95
|
+
sponsoredTxToSign: (orderId: string, txBase64: string, signatureDeadline: number) => void;
|
|
96
|
+
orderSubmitted: (orderId: string, txSignature: string) => void;
|
|
97
|
+
orderConfirmed: (orderId: string, positionPda: string) => void;
|
|
98
|
+
orderFailed: (orderId: string, reason: string) => void;
|
|
99
|
+
tradeExecuted: (trade: TradeInfo, delta?: StatsDelta | null) => void;
|
|
100
|
+
positionUpdated: (position: PositionInfo, updateType: string) => void;
|
|
101
|
+
marketCreated: (market: MarketInfo) => void;
|
|
102
|
+
marketFinalized: (marketPda: string, settlementPrice: number) => void;
|
|
103
|
+
chainEvent: (event: ChainEventMessage) => void;
|
|
104
|
+
positionOpened: (event: Extract<ChainEventMessage, {
|
|
105
|
+
event_type: "PositionOpened";
|
|
106
|
+
}>) => void;
|
|
107
|
+
makerRegistered: (event: Extract<ChainEventMessage, {
|
|
108
|
+
event_type: "MakerRegistered";
|
|
109
|
+
}>) => void;
|
|
110
|
+
chainMarketCreated: (event: Extract<ChainEventMessage, {
|
|
111
|
+
event_type: "MarketCreated";
|
|
112
|
+
}>) => void;
|
|
113
|
+
chainMarketFinalized: (event: Extract<ChainEventMessage, {
|
|
114
|
+
event_type: "MarketFinalized";
|
|
115
|
+
}>) => void;
|
|
116
|
+
positionSettled: (event: Extract<ChainEventMessage, {
|
|
117
|
+
event_type: "PositionSettled";
|
|
118
|
+
}>) => void;
|
|
119
|
+
};
|
|
120
|
+
type EventMap = Record<string, (...args: any[]) => void>;
|
|
121
|
+
declare class TypedEventEmitter<TEvents extends EventMap> {
|
|
122
|
+
private readonly listeners;
|
|
123
|
+
on<K extends keyof TEvents>(event: K, listener: TEvents[K]): this;
|
|
124
|
+
once<K extends keyof TEvents>(event: K, listener: TEvents[K]): this;
|
|
125
|
+
off<K extends keyof TEvents>(event: K, listener: TEvents[K]): this;
|
|
126
|
+
removeAllListeners<K extends keyof TEvents>(event?: K): this;
|
|
127
|
+
protected emit<K extends keyof TEvents>(event: K, ...args: Parameters<TEvents[K]>): boolean;
|
|
128
|
+
}
|
|
129
|
+
export type WebSocketLike = {
|
|
130
|
+
readonly readyState: number;
|
|
131
|
+
onopen: ((ev: unknown) => void) | null;
|
|
132
|
+
onclose: ((ev: {
|
|
133
|
+
code?: number;
|
|
134
|
+
reason?: string;
|
|
135
|
+
} | unknown) => void) | null;
|
|
136
|
+
onerror: ((ev: unknown) => void) | null;
|
|
137
|
+
onmessage: ((ev: {
|
|
138
|
+
data: string;
|
|
139
|
+
}) => void) | null;
|
|
140
|
+
send(data: string): void;
|
|
141
|
+
close(code?: number, reason?: string): void;
|
|
142
|
+
};
|
|
143
|
+
export type WebSocketFactory = (url: string) => WebSocketLike;
|
|
144
|
+
export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents> {
|
|
145
|
+
private ws;
|
|
146
|
+
private options;
|
|
147
|
+
private authProvider;
|
|
148
|
+
private authRequested;
|
|
149
|
+
private startAuthSent;
|
|
150
|
+
private connectionState;
|
|
151
|
+
private sessionId;
|
|
152
|
+
private helloSent;
|
|
153
|
+
private welcomeReceived;
|
|
154
|
+
private pendingMessages;
|
|
155
|
+
private reconnectAttempts;
|
|
156
|
+
private reconnectTimer;
|
|
157
|
+
private pingTimer;
|
|
158
|
+
private shouldReconnect;
|
|
159
|
+
private subscribedChannels;
|
|
160
|
+
private subscribedMarkets;
|
|
161
|
+
private hasMarketScope;
|
|
162
|
+
readonly state: ClientState;
|
|
163
|
+
constructor(options: ActaWsClientOptions);
|
|
164
|
+
connectAnonymous(): void;
|
|
165
|
+
connect(authProvider: AuthProvider): void;
|
|
166
|
+
connectAndAuthenticate(authProvider: AuthProvider): void;
|
|
167
|
+
authenticate(authProvider: AuthProvider): Promise<void>;
|
|
168
|
+
disconnect(): void;
|
|
169
|
+
getConnectionState(): ConnectionState;
|
|
170
|
+
isAuthenticated(): boolean;
|
|
171
|
+
getSessionId(): string | null;
|
|
172
|
+
createRfq(request: Omit<RfqRequestMessage, "timeout_seconds"> & {
|
|
173
|
+
timeoutSeconds?: number;
|
|
174
|
+
clientRequestId?: string;
|
|
175
|
+
}): Promise<void>;
|
|
176
|
+
acceptQuote(rfqId: string, maker: Address<string>, orderIdHex: string): Promise<void>;
|
|
177
|
+
/**
|
|
178
|
+
* Convenience: build and send `AcceptQuote` from a raw 32-byte `orderId`.
|
|
179
|
+
*/
|
|
180
|
+
acceptQuoteByOrderId(args: {
|
|
181
|
+
rfqId: string;
|
|
182
|
+
maker: Address<string>;
|
|
183
|
+
orderId: Uint8Array;
|
|
184
|
+
}): Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* Submit a partially-signed sponsored transaction back to the server.
|
|
187
|
+
*
|
|
188
|
+
* `txBase64` must be a base64-encoded `VersionedTransaction` (v0) signed by the taker.
|
|
189
|
+
*/
|
|
190
|
+
submitSignedSponsoredTx(args: {
|
|
191
|
+
orderIdHex: string;
|
|
192
|
+
txBase64: string;
|
|
193
|
+
}): Promise<void>;
|
|
194
|
+
getPositions(): void;
|
|
195
|
+
getMarkets(): void;
|
|
196
|
+
getMarketDescriptors(args?: {
|
|
197
|
+
active_only?: boolean;
|
|
198
|
+
}): void;
|
|
199
|
+
getExpiries(args?: {
|
|
200
|
+
underlying_mint?: Address<string>;
|
|
201
|
+
quote_mint?: Address<string>;
|
|
202
|
+
is_put?: boolean | null;
|
|
203
|
+
}): void;
|
|
204
|
+
getTokens(args?: {
|
|
205
|
+
active_only?: boolean;
|
|
206
|
+
}): void;
|
|
207
|
+
getMyActiveRfqs(): void;
|
|
208
|
+
getActiveRfqs(): void;
|
|
209
|
+
getOrderStatus(orderIdHex: string): void;
|
|
210
|
+
cancelRfq(rfqId: string): void;
|
|
211
|
+
submitQuote(quote: QuoteMessage): void;
|
|
212
|
+
/**
|
|
213
|
+
* Convenience: sign 32-byte `orderId` and send `Quote`.
|
|
214
|
+
*
|
|
215
|
+
* Maker constructs the full on-chain order (incl. nonce), computes `orderId`,
|
|
216
|
+
* signs it, and sends the signature + orderId over WS.
|
|
217
|
+
*/
|
|
218
|
+
submitQuoteSigned(args: {
|
|
219
|
+
rfqId: string;
|
|
220
|
+
strike: number;
|
|
221
|
+
price: number;
|
|
222
|
+
validUntil: number;
|
|
223
|
+
nonce: number;
|
|
224
|
+
orderId: Uint8Array;
|
|
225
|
+
makerSigner: SignerLike;
|
|
226
|
+
}): Promise<void>;
|
|
227
|
+
cancelQuote(rfqId: string): void;
|
|
228
|
+
subscribe(channels: WsChannel[], markets?: string[]): void;
|
|
229
|
+
unsubscribe(channels: WsChannel[]): void;
|
|
230
|
+
ping(): void;
|
|
231
|
+
private doConnect;
|
|
232
|
+
private handleMessage;
|
|
233
|
+
/** Taker-only: request current indicative prices for a market + position_type. */
|
|
234
|
+
getIndicativePrices(req: GetIndicativePricesMessage): void;
|
|
235
|
+
/** Maker-only: respond to an indicative request (unsigned, non-binding). */
|
|
236
|
+
sendIndicativePricesResponse(resp: IndicativePricesResponseMessage): void;
|
|
237
|
+
private handleAuthRequest;
|
|
238
|
+
private sendStartAuth;
|
|
239
|
+
private sendHello;
|
|
240
|
+
private flushPendingMessages;
|
|
241
|
+
private handleAuthSuccess;
|
|
242
|
+
private handleAuthError;
|
|
243
|
+
private handleSnapshot;
|
|
244
|
+
private handleMyActiveRfqs;
|
|
245
|
+
private handleOrderStatus;
|
|
246
|
+
private handlePositions;
|
|
247
|
+
private handleMarkets;
|
|
248
|
+
private handleStatsUpdate;
|
|
249
|
+
private handleTradeExecuted;
|
|
250
|
+
private handlePositionUpdated;
|
|
251
|
+
private handleChainEvent;
|
|
252
|
+
private send;
|
|
253
|
+
private ensureAuthenticated;
|
|
254
|
+
private setConnectionState;
|
|
255
|
+
private startPingInterval;
|
|
256
|
+
private stopPingInterval;
|
|
257
|
+
private enqueuePendingMessage;
|
|
258
|
+
private stopAutoReconnect;
|
|
259
|
+
private scheduleReconnect;
|
|
260
|
+
private cleanup;
|
|
261
|
+
private log;
|
|
262
|
+
}
|
|
263
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import WebSocket from "ws";
|
|
2
|
+
import { ActaWsClient } from "./client";
|
|
3
|
+
const wsE2eUrl = process.env.ACTA_WS_E2E_URL;
|
|
4
|
+
const describeIfWsUrl = wsE2eUrl ? describe : describe.skip;
|
|
5
|
+
describeIfWsUrl("ws handshake integration (real backend)", () => {
|
|
6
|
+
jest.setTimeout(20_000);
|
|
7
|
+
it("performs Hello -> Welcome without VersionMismatch", async () => {
|
|
8
|
+
await new Promise((resolve, reject) => {
|
|
9
|
+
const client = new ActaWsClient({
|
|
10
|
+
url: wsE2eUrl,
|
|
11
|
+
role: "taker",
|
|
12
|
+
autoReconnect: false,
|
|
13
|
+
makeSocket: (url) => new WebSocket(url),
|
|
14
|
+
});
|
|
15
|
+
let settled = false;
|
|
16
|
+
let welcomeReceived = false;
|
|
17
|
+
const timeout = setTimeout(() => {
|
|
18
|
+
finish(new Error("Timed out waiting for Welcome"));
|
|
19
|
+
}, 15_000);
|
|
20
|
+
const finish = (err) => {
|
|
21
|
+
if (settled)
|
|
22
|
+
return;
|
|
23
|
+
settled = true;
|
|
24
|
+
clearTimeout(timeout);
|
|
25
|
+
try {
|
|
26
|
+
client.disconnect();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// ignore disconnect cleanup errors in tests
|
|
30
|
+
}
|
|
31
|
+
if (err) {
|
|
32
|
+
reject(err);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
resolve();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
client.on("welcome", (msg) => {
|
|
39
|
+
try {
|
|
40
|
+
expect(msg.protocol_version).toBe("1.0.0");
|
|
41
|
+
welcomeReceived = true;
|
|
42
|
+
finish();
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
finish(err);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
client.on("versionMismatch", (msg) => {
|
|
49
|
+
finish(new Error(`Unexpected VersionMismatch: requested=${msg.requested_version} server=${msg.server_version} min=${msg.min_supported_version}`));
|
|
50
|
+
});
|
|
51
|
+
client.on("error", (err) => {
|
|
52
|
+
if (!welcomeReceived) {
|
|
53
|
+
finish(err);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
client.on("disconnected", (code, reason) => {
|
|
57
|
+
if (!welcomeReceived) {
|
|
58
|
+
finish(new Error(`Disconnected before Welcome (${code} ${reason})`));
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
client.connectAnonymous();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|