@swarm-tips/client 0.2.0 → 0.2.1
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/SBOM.spdx.json +5 -5
- package/dist/coordination-game/solana.d.ts +17 -1
- package/dist/coordination-game/solana.js +49 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/shillbot/api.d.ts +4 -0
- package/dist/shillbot/api.js +25 -2
- package/dist/swarm/index.js +1 -1
- package/package.json +1 -1
package/SBOM.spdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"spdxVersion": "SPDX-2.3",
|
|
3
3
|
"dataLicense": "CC0-1.0",
|
|
4
4
|
"SPDXID": "SPDXRef-DOCUMENT",
|
|
5
|
-
"name": "@swarm-tips/client-0.2.
|
|
6
|
-
"documentNamespace": "https://swarm.tips/sbom/client/0.2.
|
|
5
|
+
"name": "@swarm-tips/client-0.2.1",
|
|
6
|
+
"documentNamespace": "https://swarm.tips/sbom/client/0.2.1",
|
|
7
7
|
"creationInfo": {
|
|
8
|
-
"created": "2026-09-08T06:
|
|
8
|
+
"created": "2026-09-08T06:45:33.630Z",
|
|
9
9
|
"creators": [
|
|
10
10
|
"Tool: sdk/client/scripts/generate-sbom.mjs",
|
|
11
11
|
"Organization: Swarm Tips"
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
{
|
|
16
16
|
"name": "@swarm-tips/client",
|
|
17
17
|
"SPDXID": "SPDXRef-Package",
|
|
18
|
-
"versionInfo": "0.2.
|
|
19
|
-
"downloadLocation": "https://www.npmjs.com/package/@swarm-tips/client/v/0.2.
|
|
18
|
+
"versionInfo": "0.2.1",
|
|
19
|
+
"downloadLocation": "https://www.npmjs.com/package/@swarm-tips/client/v/0.2.1",
|
|
20
20
|
"filesAnalyzed": false,
|
|
21
21
|
"licenseConcluded": "MIT",
|
|
22
22
|
"licenseDeclared": "MIT"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BN, Program } from "@coral-xyz/anchor";
|
|
2
|
-
import { Connection, Keypair, PublicKey, Transaction,
|
|
2
|
+
import { Connection, Keypair, PublicKey, Transaction, TransactionInstruction, type Commitment, type VersionedTransaction } from "@solana/web3.js";
|
|
3
3
|
import { type CoordinationGame } from "../contracts/index.js";
|
|
4
4
|
import { type GlobalConfigData, type TournamentData } from "./protocol.js";
|
|
5
5
|
export interface SolanaWalletSigner {
|
|
@@ -19,6 +19,9 @@ export interface CoordinationGameSolanaClientOptions {
|
|
|
19
19
|
tournamentId?: bigint;
|
|
20
20
|
commitment?: Commitment;
|
|
21
21
|
}
|
|
22
|
+
export declare const SESSION_FEE_HEADROOM_LAMPORTS = 10000000;
|
|
23
|
+
export declare function sessionFundLamports(stakeLamports: bigint): number;
|
|
24
|
+
export declare function sessionBalanceFloor(stakeLamports: bigint): number;
|
|
22
25
|
export declare function generateSessionKeypair(): Keypair;
|
|
23
26
|
export declare function readStoredSession(storage: SolanaSessionStorage, walletAddress: string, now?: () => number): Keypair | null;
|
|
24
27
|
export declare function storeSession(storage: SolanaSessionStorage, session: Keypair, walletAddress: string, now?: () => number): void;
|
|
@@ -40,6 +43,19 @@ export declare class CoordinationGameSolanaClient {
|
|
|
40
43
|
fetchTournament(tournamentId?: bigint): Promise<TournamentData | null>;
|
|
41
44
|
fetchGlobalConfig(): Promise<GlobalConfigData>;
|
|
42
45
|
buildCreatePlayerSessionInstruction(sessionPublicKey: PublicKey): Promise<TransactionInstruction>;
|
|
46
|
+
buildSessionSetupTransaction(input: {
|
|
47
|
+
sessionPublicKey: PublicKey;
|
|
48
|
+
lamports: number;
|
|
49
|
+
memoNonce?: string;
|
|
50
|
+
}): Promise<Transaction>;
|
|
51
|
+
waitForSignature(signature: string, options?: {
|
|
52
|
+
attempts?: number;
|
|
53
|
+
intervalMs?: number;
|
|
54
|
+
sleep?: (ms: number) => Promise<void>;
|
|
55
|
+
}): Promise<void>;
|
|
56
|
+
fetchPlayerProfiles(tournamentId?: bigint): Promise<Array<{
|
|
57
|
+
account: unknown;
|
|
58
|
+
}>>;
|
|
43
59
|
depositStake(tournament: PublicKey, session?: Keypair | null): Promise<string>;
|
|
44
60
|
buildCreateGameTransaction(input: {
|
|
45
61
|
stake: BN;
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { AnchorProvider, Program } from "@coral-xyz/anchor";
|
|
2
2
|
import { Buffer } from "buffer";
|
|
3
|
-
import
|
|
3
|
+
import bs58 from "bs58";
|
|
4
|
+
import { Connection, Keypair, PublicKey, SystemProgram, Transaction, TransactionInstruction, } from "@solana/web3.js";
|
|
4
5
|
import { COORDINATION_GAME_IDL } from "../contracts/index.js";
|
|
5
6
|
import { SwarmClientError } from "../errors.js";
|
|
6
|
-
import { decodeGlobalConfig, decodeTournament, escrowPda, gameCounterPda, gamePda, globalConfigPda, playerProfilePda, playerSessionPda, tournamentPda, } from "./protocol.js";
|
|
7
|
+
import { decodeGlobalConfig, decodeTournament, escrowPda, gameCounterPda, gamePda, globalConfigPda, playerProfilePda, playerSessionPda, tournamentPda, u64LE, } from "./protocol.js";
|
|
7
8
|
const SESSION_STORAGE_KEY = "coordination-session";
|
|
8
9
|
const SESSION_TTL_MS = 24 * 60 * 60 * 1000;
|
|
10
|
+
const MEMO_PROGRAM_ID = new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr");
|
|
11
|
+
export const SESSION_FEE_HEADROOM_LAMPORTS = 10_000_000;
|
|
12
|
+
export function sessionFundLamports(stakeLamports) {
|
|
13
|
+
return Number(stakeLamports) + SESSION_FEE_HEADROOM_LAMPORTS;
|
|
14
|
+
}
|
|
15
|
+
export function sessionBalanceFloor(stakeLamports) {
|
|
16
|
+
return Number(stakeLamports) + SESSION_FEE_HEADROOM_LAMPORTS / 2;
|
|
17
|
+
}
|
|
9
18
|
function walletForSession(session) {
|
|
10
19
|
return {
|
|
11
20
|
publicKey: session.publicKey,
|
|
@@ -105,6 +114,44 @@ export class CoordinationGameSolanaClient {
|
|
|
105
114
|
const wallet = this.requireWallet();
|
|
106
115
|
return this.program(wallet).methods.createPlayerSession().accountsPartial({ sessionKey: sessionPublicKey }).instruction();
|
|
107
116
|
}
|
|
117
|
+
async buildSessionSetupTransaction(input) {
|
|
118
|
+
const wallet = this.requireWallet();
|
|
119
|
+
const transaction = new Transaction().add(SystemProgram.transfer({
|
|
120
|
+
fromPubkey: wallet.publicKey,
|
|
121
|
+
toPubkey: input.sessionPublicKey,
|
|
122
|
+
lamports: input.lamports,
|
|
123
|
+
}));
|
|
124
|
+
if (input.memoNonce) {
|
|
125
|
+
transaction.add(new TransactionInstruction({
|
|
126
|
+
keys: [],
|
|
127
|
+
programId: MEMO_PROGRAM_ID,
|
|
128
|
+
data: Buffer.from(input.memoNonce, "utf8"),
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
const authority = playerSessionPda(wallet.publicKey, input.sessionPublicKey)[0];
|
|
132
|
+
if ((await this.connection.getAccountInfo(authority)) === null) {
|
|
133
|
+
transaction.add(await this.buildCreatePlayerSessionInstruction(input.sessionPublicKey));
|
|
134
|
+
}
|
|
135
|
+
return transaction;
|
|
136
|
+
}
|
|
137
|
+
async waitForSignature(signature, options = {}) {
|
|
138
|
+
const sleep = options.sleep ?? ((ms) => new Promise((resolve) => globalThis.setTimeout(resolve, ms)));
|
|
139
|
+
const attempts = options.attempts ?? 6;
|
|
140
|
+
for (let index = 0; index < attempts; index += 1) {
|
|
141
|
+
await sleep(options.intervalMs ?? 1_500);
|
|
142
|
+
const status = await this.connection.getSignatureStatus(signature);
|
|
143
|
+
const confirmation = status.value?.confirmationStatus;
|
|
144
|
+
if (confirmation === "confirmed" || confirmation === "finalized")
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
throw new SwarmClientError({ code: "TIMEOUT", operation: "solana.waitForSignature", message: `transaction ${signature} did not confirm after ${attempts} polls`, retryable: true });
|
|
148
|
+
}
|
|
149
|
+
async fetchPlayerProfiles(tournamentId = this.tournamentId) {
|
|
150
|
+
const profiles = await this.program().account.playerProfile.all([{
|
|
151
|
+
memcmp: { offset: 40, bytes: bs58.encode(u64LE(tournamentId)) },
|
|
152
|
+
}]);
|
|
153
|
+
return profiles;
|
|
154
|
+
}
|
|
108
155
|
async depositStake(tournament, session) {
|
|
109
156
|
const wallet = this.requireWallet();
|
|
110
157
|
const escrow = escrowPda(this.tournamentId, wallet.publicKey)[0];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** The unified client package version. Functional APIs live in typed subpaths. */
|
|
2
|
-
export declare const CLIENT_VERSION: "0.2.
|
|
2
|
+
export declare const CLIENT_VERSION: "0.2.1";
|
|
3
3
|
export declare const CLIENT_MANIFEST_SCHEMA: "swarm.client-manifest/v1";
|
|
4
4
|
export { SwarmClientError } from "./errors.js";
|
|
5
5
|
export type { SwarmClientErrorCode, SwarmClientErrorOptions } from "./errors.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** The unified client package version. Functional APIs live in typed subpaths. */
|
|
2
|
-
export const CLIENT_VERSION = "0.2.
|
|
2
|
+
export const CLIENT_VERSION = "0.2.1";
|
|
3
3
|
export const CLIENT_MANIFEST_SCHEMA = "swarm.client-manifest/v1";
|
|
4
4
|
export { SwarmClientError } from "./errors.js";
|
package/dist/shillbot/api.d.ts
CHANGED
|
@@ -57,6 +57,7 @@ export interface PreparedTransactionExpectation {
|
|
|
57
57
|
escrowLamports?: bigint;
|
|
58
58
|
allowedProgramIds?: string[];
|
|
59
59
|
}
|
|
60
|
+
export declare function permittedPreparedProgramIds(action: Action, network: "mainnet" | "devnet"): string[];
|
|
60
61
|
/**
|
|
61
62
|
* Fail-closed local validation for a server-prepared Shillbot transaction.
|
|
62
63
|
* The network is an explicit part of the expectation; callers must construct
|
|
@@ -69,4 +70,7 @@ export declare function signBroadcastPreparedTransaction(input: {
|
|
|
69
70
|
expected: PreparedTransactionExpectation;
|
|
70
71
|
sign: WalletSignCallback;
|
|
71
72
|
confirmation?: BlockhashWithExpiryBlockHeight;
|
|
73
|
+
timeoutMs?: number;
|
|
74
|
+
setTimeout?: typeof globalThis.setTimeout;
|
|
75
|
+
clearTimeout?: typeof globalThis.clearTimeout;
|
|
72
76
|
}): Promise<string>;
|
package/dist/shillbot/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Buffer } from "buffer";
|
|
2
|
-
import { ComputeBudgetProgram, SystemProgram } from "@solana/web3.js";
|
|
2
|
+
import { ComputeBudgetProgram, Secp256k1Program, SystemProgram } from "@solana/web3.js";
|
|
3
3
|
import { HttpClient } from "../http.js";
|
|
4
4
|
import { SwarmClientError } from "../errors.js";
|
|
5
5
|
import { SHILLBOT_PROGRAM_ID, inspectTransaction, shillbotInstructionDiscriminator, signAndBroadcast, } from "./index.js";
|
|
@@ -28,6 +28,15 @@ export class ShillbotApiClient {
|
|
|
28
28
|
buildFinalize(id) { return this.post(`/tasks/${encodeURIComponent(id)}/build-finalize`); }
|
|
29
29
|
confirmTask(id, body) { return this.post(`/tasks/${encodeURIComponent(id)}/confirm`, body); }
|
|
30
30
|
}
|
|
31
|
+
const SWITCHBOARD_PROGRAM_IDS = {
|
|
32
|
+
mainnet: "SBondMDrcV3K4kxZR1HNVT7osZxAHVHgYXL5Ze1oMUv",
|
|
33
|
+
devnet: "Aio4gaXjXzJNVLtzwtNVmSqGKpANtXhybbkhtAC94ji2",
|
|
34
|
+
};
|
|
35
|
+
export function permittedPreparedProgramIds(action, network) {
|
|
36
|
+
return action === "verify"
|
|
37
|
+
? [SWITCHBOARD_PROGRAM_IDS[network], Secp256k1Program.programId.toBase58()]
|
|
38
|
+
: [];
|
|
39
|
+
}
|
|
31
40
|
function lifecycleName(action) {
|
|
32
41
|
if (action === "create")
|
|
33
42
|
return "create_task";
|
|
@@ -67,6 +76,7 @@ export function validatePreparedTransaction(encoded, expected) {
|
|
|
67
76
|
shillbotId,
|
|
68
77
|
ComputeBudgetProgram.programId.toBase58(),
|
|
69
78
|
SystemProgram.programId.toBase58(),
|
|
79
|
+
...permittedPreparedProgramIds(expected.action, expected.network),
|
|
70
80
|
...(expected.allowedProgramIds ?? []),
|
|
71
81
|
]);
|
|
72
82
|
const unrelated = inspected.instructions.find((instruction) => !alwaysAllowed.has(instruction.program_id));
|
|
@@ -87,5 +97,18 @@ export function validatePreparedTransaction(encoded, expected) {
|
|
|
87
97
|
}
|
|
88
98
|
export async function signBroadcastPreparedTransaction(input) {
|
|
89
99
|
validatePreparedTransaction(input.transaction, input.expected);
|
|
90
|
-
|
|
100
|
+
const timeoutMs = input.timeoutMs ?? 60_000;
|
|
101
|
+
let timeout;
|
|
102
|
+
try {
|
|
103
|
+
return await Promise.race([
|
|
104
|
+
signAndBroadcast(input.connection, input.transaction, input.sign, input.confirmation),
|
|
105
|
+
new Promise((_, reject) => {
|
|
106
|
+
timeout = (input.setTimeout ?? globalThis.setTimeout)(() => reject(new SwarmClientError({ code: "TIMEOUT", operation: "shillbot.signBroadcastPreparedTransaction", message: `Transaction did not confirm within ${timeoutMs}ms`, retryable: true })), timeoutMs);
|
|
107
|
+
}),
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
if (timeout !== undefined)
|
|
112
|
+
(input.clearTimeout ?? globalThis.clearTimeout)(timeout);
|
|
113
|
+
}
|
|
91
114
|
}
|
package/dist/swarm/index.js
CHANGED
|
@@ -49,7 +49,7 @@ export class SwarmClient {
|
|
|
49
49
|
async toolCount() {
|
|
50
50
|
const headers = { "Content-Type": "application/json", Accept: "application/json, text/event-stream" };
|
|
51
51
|
try {
|
|
52
|
-
const init = await this.fetchImpl(`${this.baseUrl}/mcp`, { method: "POST", headers, body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2025-03-26", capabilities: {}, clientInfo: { name: "swarm-client", version: "0.2.
|
|
52
|
+
const init = await this.fetchImpl(`${this.baseUrl}/mcp`, { method: "POST", headers, body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2025-03-26", capabilities: {}, clientInfo: { name: "swarm-client", version: "0.2.1" } } }) });
|
|
53
53
|
if (!init.ok)
|
|
54
54
|
return null;
|
|
55
55
|
const session = init.headers.get("mcp-session-id");
|