@dimcool/dimclaw 0.1.29 → 0.1.30
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/index.js +940 -119
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32839,6 +32839,16 @@ var Auth = class {
|
|
|
32839
32839
|
this.logger.debug("Token stored in storage", { tokenKey: TOKEN_KEY });
|
|
32840
32840
|
return response;
|
|
32841
32841
|
}
|
|
32842
|
+
async loginWithExternalSignature(address, signedMessage, options) {
|
|
32843
|
+
const response = await this.http.post("/auth/login-wallet", {
|
|
32844
|
+
signedMessage,
|
|
32845
|
+
address,
|
|
32846
|
+
referralCode: options?.referralCode,
|
|
32847
|
+
walletMeta: options?.walletMeta
|
|
32848
|
+
});
|
|
32849
|
+
this.storage.set(TOKEN_KEY, response.access_token);
|
|
32850
|
+
return response;
|
|
32851
|
+
}
|
|
32842
32852
|
logout() {
|
|
32843
32853
|
this.logger.debug("Auth.logout called");
|
|
32844
32854
|
const hadToken = this.storage.get(TOKEN_KEY) !== null;
|
|
@@ -32852,6 +32862,10 @@ var Auth = class {
|
|
|
32852
32862
|
});
|
|
32853
32863
|
return isAuth;
|
|
32854
32864
|
}
|
|
32865
|
+
async getSessionStats() {
|
|
32866
|
+
this.logger.debug("Auth.getSessionStats called");
|
|
32867
|
+
return this.http.get("/auth/sessions/stats");
|
|
32868
|
+
}
|
|
32855
32869
|
async getLatestSessions(limit) {
|
|
32856
32870
|
this.logger.debug("Auth.getLatestSessions called", { limit });
|
|
32857
32871
|
const params = new URLSearchParams();
|
|
@@ -33075,11 +33089,25 @@ var Users = class {
|
|
|
33075
33089
|
async removeFriend(userId) {
|
|
33076
33090
|
return this.http.delete(`/friends/${userId}`);
|
|
33077
33091
|
}
|
|
33078
|
-
async getIncomingFriendRequests() {
|
|
33079
|
-
|
|
33092
|
+
async getIncomingFriendRequests(opts) {
|
|
33093
|
+
const params = new URLSearchParams();
|
|
33094
|
+
if (opts?.limit !== void 0)
|
|
33095
|
+
params.append("limit", opts.limit.toString());
|
|
33096
|
+
if (opts?.cursor !== void 0) params.append("cursor", opts.cursor);
|
|
33097
|
+
const qs = params.toString();
|
|
33098
|
+
return this.http.get(
|
|
33099
|
+
qs ? `/friends/requests/incoming?${qs}` : "/friends/requests/incoming"
|
|
33100
|
+
);
|
|
33080
33101
|
}
|
|
33081
|
-
async getOutgoingFriendRequests() {
|
|
33082
|
-
|
|
33102
|
+
async getOutgoingFriendRequests(opts) {
|
|
33103
|
+
const params = new URLSearchParams();
|
|
33104
|
+
if (opts?.limit !== void 0)
|
|
33105
|
+
params.append("limit", opts.limit.toString());
|
|
33106
|
+
if (opts?.cursor !== void 0) params.append("cursor", opts.cursor);
|
|
33107
|
+
const qs = params.toString();
|
|
33108
|
+
return this.http.get(
|
|
33109
|
+
qs ? `/friends/requests/outgoing?${qs}` : "/friends/requests/outgoing"
|
|
33110
|
+
);
|
|
33083
33111
|
}
|
|
33084
33112
|
async acceptFriendRequest(userId) {
|
|
33085
33113
|
return this.http.post(
|
|
@@ -33166,6 +33194,9 @@ var FeatureFlags = class {
|
|
|
33166
33194
|
this.loaded = true;
|
|
33167
33195
|
return this.flags;
|
|
33168
33196
|
}
|
|
33197
|
+
async getAdminFeatureFlags() {
|
|
33198
|
+
return this.http.get("/feature-flags/admin");
|
|
33199
|
+
}
|
|
33169
33200
|
isEnabledFlag(name) {
|
|
33170
33201
|
const flag = this.flags.find((f) => f.name === name);
|
|
33171
33202
|
return flag?.enabled ?? false;
|
|
@@ -33185,10 +33216,11 @@ var FeatureFlags = class {
|
|
|
33185
33216
|
}
|
|
33186
33217
|
return flag;
|
|
33187
33218
|
}
|
|
33188
|
-
async createFeatureFlag(name, enabled) {
|
|
33219
|
+
async createFeatureFlag(name, enabled, description) {
|
|
33189
33220
|
const flag = await this.http.post("/feature-flags", {
|
|
33190
33221
|
name,
|
|
33191
|
-
enabled
|
|
33222
|
+
enabled,
|
|
33223
|
+
...description !== void 0 && { description }
|
|
33192
33224
|
});
|
|
33193
33225
|
this.flags.push(flag);
|
|
33194
33226
|
return flag;
|
|
@@ -33199,11 +33231,17 @@ var Lobbies = class {
|
|
|
33199
33231
|
this.http = http2;
|
|
33200
33232
|
this.logger = logger2;
|
|
33201
33233
|
}
|
|
33234
|
+
/** Called by SDK after the store is created so mutations can update state directly. */
|
|
33235
|
+
setLobbyStore(store) {
|
|
33236
|
+
this.lobbyStore = store;
|
|
33237
|
+
}
|
|
33202
33238
|
async createLobby(gameType, betAmount) {
|
|
33203
33239
|
return this.http.post("/lobbies", { gameType, betAmount });
|
|
33204
33240
|
}
|
|
33205
33241
|
async getLobby(lobbyId) {
|
|
33206
|
-
|
|
33242
|
+
const lobby = await this.http.get(`/lobbies/${lobbyId}`);
|
|
33243
|
+
this.lobbyStore?.setBaseState([lobby]);
|
|
33244
|
+
return lobby;
|
|
33207
33245
|
}
|
|
33208
33246
|
async inviteFriend(lobbyId, friendId) {
|
|
33209
33247
|
return this.http.post(`/lobbies/${lobbyId}/invite`, {
|
|
@@ -33214,7 +33252,9 @@ var Lobbies = class {
|
|
|
33214
33252
|
return this.http.post(`/lobbies/${lobbyId}/accept-invite`, {});
|
|
33215
33253
|
}
|
|
33216
33254
|
async joinLobby(lobbyId) {
|
|
33217
|
-
|
|
33255
|
+
const lobby = await this.http.post(`/lobbies/${lobbyId}/join`, {});
|
|
33256
|
+
this.lobbyStore?.setBaseState([lobby]);
|
|
33257
|
+
return lobby;
|
|
33218
33258
|
}
|
|
33219
33259
|
async removePlayer(lobbyId, userId) {
|
|
33220
33260
|
return this.http.delete(
|
|
@@ -33231,12 +33271,17 @@ var Lobbies = class {
|
|
|
33231
33271
|
return this.http.post(`/lobbies/${lobbyId}/join-queue`, {});
|
|
33232
33272
|
}
|
|
33233
33273
|
async cancelQueue(lobbyId) {
|
|
33234
|
-
|
|
33274
|
+
const lobby = await this.http.delete(`/lobbies/${lobbyId}/queue`);
|
|
33275
|
+
this.lobbyStore?.setBaseState([lobby]);
|
|
33276
|
+
return lobby;
|
|
33235
33277
|
}
|
|
33236
33278
|
async updateBetAmount(lobbyId, betAmount) {
|
|
33237
|
-
|
|
33238
|
-
|
|
33239
|
-
|
|
33279
|
+
const lobby = await this.http.patch(
|
|
33280
|
+
`/lobbies/${lobbyId}/bet-amount`,
|
|
33281
|
+
{ betAmount }
|
|
33282
|
+
);
|
|
33283
|
+
this.lobbyStore?.setBaseState([lobby]);
|
|
33284
|
+
return lobby;
|
|
33240
33285
|
}
|
|
33241
33286
|
async playSound(lobbyId, sound) {
|
|
33242
33287
|
return this.http.post(`/lobbies/${lobbyId}/sound`, {
|
|
@@ -33275,6 +33320,12 @@ var Games = class {
|
|
|
33275
33320
|
this.wallet = wallet;
|
|
33276
33321
|
this.logger = logger2;
|
|
33277
33322
|
}
|
|
33323
|
+
setGameStore(store) {
|
|
33324
|
+
this.gameStore = store;
|
|
33325
|
+
}
|
|
33326
|
+
setGameActionsStore(store) {
|
|
33327
|
+
this.gameActionsStore = store;
|
|
33328
|
+
}
|
|
33278
33329
|
async getAvailableGames() {
|
|
33279
33330
|
return this.http.get("/games/available");
|
|
33280
33331
|
}
|
|
@@ -33287,7 +33338,11 @@ var Games = class {
|
|
|
33287
33338
|
return this.http.get("/games/metrics");
|
|
33288
33339
|
}
|
|
33289
33340
|
async getGame(gameId) {
|
|
33290
|
-
|
|
33341
|
+
const existing = this.gameStore?.store.getState().gamesById[gameId];
|
|
33342
|
+
if (existing?.status === "completed") return existing;
|
|
33343
|
+
const game = await this.http.get(`/games/${gameId}`);
|
|
33344
|
+
this.gameStore?.setBaseState([game]);
|
|
33345
|
+
return game;
|
|
33291
33346
|
}
|
|
33292
33347
|
/**
|
|
33293
33348
|
* Get list of currently active (live) games. Public endpoint for spectating.
|
|
@@ -33314,7 +33369,13 @@ var Games = class {
|
|
|
33314
33369
|
* Get current game state with timer information
|
|
33315
33370
|
*/
|
|
33316
33371
|
async getGameState(gameId) {
|
|
33317
|
-
|
|
33372
|
+
const existing = this.gameActionsStore?.store.getState().statesByGameId[gameId];
|
|
33373
|
+
if (existing?.status === "completed") return existing;
|
|
33374
|
+
const state = await this.http.get(
|
|
33375
|
+
`/games/${gameId}/state`
|
|
33376
|
+
);
|
|
33377
|
+
this.gameActionsStore?.setBaseState(gameId, state);
|
|
33378
|
+
return state;
|
|
33318
33379
|
}
|
|
33319
33380
|
/**
|
|
33320
33381
|
* Request a rematch for a completed game
|
|
@@ -33350,8 +33411,18 @@ var Games = class {
|
|
|
33350
33411
|
{ amountMinor, signedTransaction }
|
|
33351
33412
|
);
|
|
33352
33413
|
}
|
|
33414
|
+
/**
|
|
33415
|
+
* Confirm a donation that was already sent by the client (signAndSendTransaction path).
|
|
33416
|
+
*/
|
|
33417
|
+
async confirmGameDonationSignature(gameId, amountMinor, signature) {
|
|
33418
|
+
return this.http.post(
|
|
33419
|
+
`/games/${gameId}/donate/confirm-signature`,
|
|
33420
|
+
{ amountMinor, signature }
|
|
33421
|
+
);
|
|
33422
|
+
}
|
|
33353
33423
|
/**
|
|
33354
33424
|
* One-call donation flow: prepare -> sign -> submit.
|
|
33425
|
+
* Automatically uses the right signing path (embedded vs injected wallet).
|
|
33355
33426
|
*/
|
|
33356
33427
|
async sendDonation(gameId, amountMinor) {
|
|
33357
33428
|
if (!this.wallet.hasSigner()) {
|
|
@@ -33360,16 +33431,10 @@ var Games = class {
|
|
|
33360
33431
|
);
|
|
33361
33432
|
}
|
|
33362
33433
|
const prepared = await this.prepareGameDonation(gameId, amountMinor);
|
|
33363
|
-
const
|
|
33364
|
-
|
|
33365
|
-
|
|
33366
|
-
|
|
33367
|
-
);
|
|
33368
|
-
const result = await this.donateToGame(
|
|
33369
|
-
gameId,
|
|
33370
|
-
amountMinor,
|
|
33371
|
-
signedTransaction
|
|
33372
|
-
);
|
|
33434
|
+
const result = await this.wallet.signAndDispatch(prepared.transaction, {
|
|
33435
|
+
onSigned: (signedTxBase64) => this.donateToGame(gameId, amountMinor, signedTxBase64),
|
|
33436
|
+
onSignedAndSent: (sig) => this.confirmGameDonationSignature(gameId, amountMinor, sig)
|
|
33437
|
+
});
|
|
33373
33438
|
return {
|
|
33374
33439
|
...result,
|
|
33375
33440
|
escrowAddress: prepared.escrowAddress,
|
|
@@ -33462,6 +33527,9 @@ var Chat = class {
|
|
|
33462
33527
|
this.logger = logger2;
|
|
33463
33528
|
this.retryOptions = { ...DEFAULT_RETRY_OPTIONS, ...retryOptions };
|
|
33464
33529
|
}
|
|
33530
|
+
setDmThreadsStore(store) {
|
|
33531
|
+
this.dmThreadsStore = store;
|
|
33532
|
+
}
|
|
33465
33533
|
encodeContextId(id) {
|
|
33466
33534
|
return encodeURIComponent(id);
|
|
33467
33535
|
}
|
|
@@ -33543,7 +33611,9 @@ var Chat = class {
|
|
|
33543
33611
|
return response;
|
|
33544
33612
|
}
|
|
33545
33613
|
async listDmThreads() {
|
|
33546
|
-
|
|
33614
|
+
const threads = await this.http.get("/chat/dm/threads");
|
|
33615
|
+
this.dmThreadsStore?.setBaseState(threads);
|
|
33616
|
+
return threads;
|
|
33547
33617
|
}
|
|
33548
33618
|
async getDmThread(dmKey) {
|
|
33549
33619
|
return this.http.get(
|
|
@@ -33631,21 +33701,32 @@ var Tips = class {
|
|
|
33631
33701
|
);
|
|
33632
33702
|
}
|
|
33633
33703
|
const { publicKey: senderAddress } = await this.wallet.loadWallet();
|
|
33634
|
-
const
|
|
33635
|
-
const
|
|
33636
|
-
|
|
33637
|
-
|
|
33638
|
-
|
|
33639
|
-
);
|
|
33640
|
-
const transfer = await this.wallet.
|
|
33641
|
-
signedTxBase64
|
|
33642
|
-
|
|
33643
|
-
|
|
33644
|
-
|
|
33645
|
-
|
|
33646
|
-
|
|
33647
|
-
|
|
33648
|
-
|
|
33704
|
+
const supportsPresign = !this.wallet.isSignAndSendMode();
|
|
33705
|
+
const prepared = await this.prepare({
|
|
33706
|
+
recipientUsername,
|
|
33707
|
+
amount,
|
|
33708
|
+
supportsPresign
|
|
33709
|
+
});
|
|
33710
|
+
const transfer = await this.wallet.signAndDispatch(prepared.transaction, {
|
|
33711
|
+
onSigned: (signedTxBase64) => this.wallet.submitTransfer(
|
|
33712
|
+
signedTxBase64,
|
|
33713
|
+
senderAddress,
|
|
33714
|
+
prepared.recipientAddress,
|
|
33715
|
+
prepared.amount,
|
|
33716
|
+
"USDC",
|
|
33717
|
+
false,
|
|
33718
|
+
prepared.recipientUsername
|
|
33719
|
+
),
|
|
33720
|
+
onSignedAndSent: (sig) => this.wallet.confirmTransferSignature(
|
|
33721
|
+
sig,
|
|
33722
|
+
senderAddress,
|
|
33723
|
+
prepared.recipientAddress,
|
|
33724
|
+
prepared.amount,
|
|
33725
|
+
"USDC",
|
|
33726
|
+
false,
|
|
33727
|
+
prepared.recipientUsername
|
|
33728
|
+
)
|
|
33729
|
+
});
|
|
33649
33730
|
const message = await this.chat.broadcastGlobalTip(
|
|
33650
33731
|
prepared.recipientUserId,
|
|
33651
33732
|
prepared.amount
|
|
@@ -33963,13 +34044,15 @@ var Wallet = class {
|
|
|
33963
34044
|
);
|
|
33964
34045
|
}
|
|
33965
34046
|
try {
|
|
34047
|
+
const supportsPresign = !this.isSignAndSendMode();
|
|
33966
34048
|
const response = await this.http.post(
|
|
33967
34049
|
"/wallets/transfer/prepare",
|
|
33968
34050
|
{
|
|
33969
34051
|
senderAddress,
|
|
33970
34052
|
recipient,
|
|
33971
34053
|
amount: amountMinor,
|
|
33972
|
-
token
|
|
34054
|
+
token,
|
|
34055
|
+
supportsPresign
|
|
33973
34056
|
}
|
|
33974
34057
|
);
|
|
33975
34058
|
this.logger.debug("Transfer prepared", {
|
|
@@ -34053,6 +34136,29 @@ var Wallet = class {
|
|
|
34053
34136
|
throw error;
|
|
34054
34137
|
}
|
|
34055
34138
|
}
|
|
34139
|
+
/**
|
|
34140
|
+
* Sign a prepared transaction and invoke the appropriate backend callback
|
|
34141
|
+
* based on the configured signer — without exposing the mode decision to callers.
|
|
34142
|
+
* - Embedded wallet (signAndSend): signs+sends, calls onSignedAndSent(signature)
|
|
34143
|
+
* - Injected wallet (signTransaction): signs locally, calls onSigned(signedTxBase64)
|
|
34144
|
+
*/
|
|
34145
|
+
async signAndDispatch(unsignedTxBase64, handlers) {
|
|
34146
|
+
if (!this.signer) {
|
|
34147
|
+
throw new Error(
|
|
34148
|
+
"No signer configured. Call setSigner() with a WalletSigner implementation first."
|
|
34149
|
+
);
|
|
34150
|
+
}
|
|
34151
|
+
const unsignedTx = Transaction.from(base64ToBytes(unsignedTxBase64));
|
|
34152
|
+
if (this.isSignAndSendMode()) {
|
|
34153
|
+
const sig = await this.signAndSendTransaction(unsignedTx);
|
|
34154
|
+
return handlers.onSignedAndSent(sig);
|
|
34155
|
+
}
|
|
34156
|
+
const signedTx = await this.signTransaction(unsignedTx);
|
|
34157
|
+
const signedBase64 = bytesToBase64(
|
|
34158
|
+
signedTx.serialize({ requireAllSignatures: false })
|
|
34159
|
+
);
|
|
34160
|
+
return handlers.onSigned(signedBase64);
|
|
34161
|
+
}
|
|
34056
34162
|
/**
|
|
34057
34163
|
* Full transfer flow in one call: prepare -> sign -> submit
|
|
34058
34164
|
* Recipient can be username, .sol domain, or Solana address (resolved by backend).
|
|
@@ -34134,12 +34240,32 @@ var Escrow = class {
|
|
|
34134
34240
|
* initializes depositStatus, and prepares the unsigned transaction in one call.
|
|
34135
34241
|
* Eliminates one HTTP round-trip vs startDeposits() + prepareDepositTransaction().
|
|
34136
34242
|
*/
|
|
34137
|
-
async prepareAndStartDeposit(lobbyId) {
|
|
34243
|
+
async prepareAndStartDeposit(lobbyId, supportsPresign) {
|
|
34244
|
+
const presign = supportsPresign ?? !this.wallet.isSignAndSendMode();
|
|
34138
34245
|
return this.http.post(
|
|
34139
34246
|
`/escrow/lobby/${lobbyId}/deposit/prepare-and-start`,
|
|
34140
|
-
{}
|
|
34247
|
+
{ supportsPresign: presign }
|
|
34141
34248
|
);
|
|
34142
34249
|
}
|
|
34250
|
+
/**
|
|
34251
|
+
* Sign and submit a prepared (unsigned) deposit transaction using the
|
|
34252
|
+
* configured signer. Automatically picks the right path:
|
|
34253
|
+
* - Embedded wallet: signAndSendTransaction → confirmDepositSignature
|
|
34254
|
+
* - Injected wallet: signTransaction → submitDeposit
|
|
34255
|
+
* Returns the on-chain signature.
|
|
34256
|
+
*/
|
|
34257
|
+
async signAndSubmitPreparedDeposit(lobbyId, unsignedTxBase64) {
|
|
34258
|
+
return this.wallet.signAndDispatch(unsignedTxBase64, {
|
|
34259
|
+
onSigned: async (signedTxBase64) => {
|
|
34260
|
+
const result = await this.submitDeposit(lobbyId, signedTxBase64);
|
|
34261
|
+
return result.signature;
|
|
34262
|
+
},
|
|
34263
|
+
onSignedAndSent: async (signature) => {
|
|
34264
|
+
await this.confirmDepositSignature(lobbyId, signature);
|
|
34265
|
+
return signature;
|
|
34266
|
+
}
|
|
34267
|
+
});
|
|
34268
|
+
}
|
|
34143
34269
|
/**
|
|
34144
34270
|
* Submit a signed deposit transaction
|
|
34145
34271
|
* The transaction will be submitted to the Solana network and confirmed
|
|
@@ -34182,7 +34308,11 @@ var Escrow = class {
|
|
|
34182
34308
|
"No signer configured. Use sdk.wallet.setSigner(...) first."
|
|
34183
34309
|
);
|
|
34184
34310
|
}
|
|
34185
|
-
const
|
|
34311
|
+
const supportsPresign = !this.wallet.isSignAndSendMode();
|
|
34312
|
+
const { transaction } = await this.prepareAndStartDeposit(
|
|
34313
|
+
lobbyId,
|
|
34314
|
+
supportsPresign
|
|
34315
|
+
);
|
|
34186
34316
|
const unsignedTx = Transaction.from(base64ToBytes(transaction));
|
|
34187
34317
|
let signature;
|
|
34188
34318
|
if (this.wallet.isSignAndSendMode()) {
|
|
@@ -34217,8 +34347,13 @@ var Escrow = class {
|
|
|
34217
34347
|
};
|
|
34218
34348
|
}
|
|
34219
34349
|
/**
|
|
34220
|
-
*
|
|
34221
|
-
*
|
|
34350
|
+
* Deposit for a lobby and wait until the calling user's own deposit is confirmed.
|
|
34351
|
+
* Ideal for agents: returns as soon as your deposit is on-chain without waiting
|
|
34352
|
+
* for the other player. The server auto-joins the queue when all players deposit.
|
|
34353
|
+
*
|
|
34354
|
+
* Confirmation is handled asynchronously by the transaction queue processor.
|
|
34355
|
+
* This method polls the deposit status endpoint until the signature appears as
|
|
34356
|
+
* confirmed (up to 60 seconds).
|
|
34222
34357
|
*
|
|
34223
34358
|
* Automatically uses signAndSendTransaction or signTransaction based on signer capability.
|
|
34224
34359
|
*/
|
|
@@ -34228,26 +34363,45 @@ var Escrow = class {
|
|
|
34228
34363
|
"No signer configured. Use sdk.wallet.setSigner(...) first."
|
|
34229
34364
|
);
|
|
34230
34365
|
}
|
|
34231
|
-
const
|
|
34366
|
+
const supportsPresign2 = !this.wallet.isSignAndSendMode();
|
|
34367
|
+
const { transaction } = await this.prepareAndStartDeposit(
|
|
34368
|
+
lobbyId,
|
|
34369
|
+
supportsPresign2
|
|
34370
|
+
);
|
|
34232
34371
|
const unsignedTx = Transaction.from(base64ToBytes(transaction));
|
|
34233
34372
|
let signature;
|
|
34234
34373
|
if (this.wallet.isSignAndSendMode()) {
|
|
34235
34374
|
signature = await this.wallet.signAndSendTransaction(unsignedTx);
|
|
34236
|
-
await this.
|
|
34237
|
-
`/escrow/lobby/${lobbyId}/deposit/confirm-signature?awaitConfirmation=true`,
|
|
34238
|
-
{ signature }
|
|
34239
|
-
);
|
|
34375
|
+
await this.confirmDepositSignature(lobbyId, signature);
|
|
34240
34376
|
} else {
|
|
34241
34377
|
const signedTx = await this.wallet.signTransaction(unsignedTx);
|
|
34242
34378
|
const signedBase64 = bytesToBase64(
|
|
34243
34379
|
signedTx.serialize({ requireAllSignatures: false })
|
|
34244
34380
|
);
|
|
34245
|
-
const
|
|
34246
|
-
|
|
34247
|
-
|
|
34248
|
-
|
|
34381
|
+
const submitResult = await this.submitDeposit(lobbyId, signedBase64);
|
|
34382
|
+
signature = submitResult.signature;
|
|
34383
|
+
}
|
|
34384
|
+
const MAX_WAIT_MS = 6e4;
|
|
34385
|
+
const POLL_INTERVAL_MS = 1e3;
|
|
34386
|
+
const startTime = Date.now();
|
|
34387
|
+
while (Date.now() - startTime < MAX_WAIT_MS) {
|
|
34388
|
+
const status = await this.getDepositStatus(lobbyId);
|
|
34389
|
+
const myDeposit = status.deposits.find(
|
|
34390
|
+
(d) => d.transactionHash === signature
|
|
34391
|
+
);
|
|
34392
|
+
if (myDeposit?.status === "confirmed") {
|
|
34393
|
+
return {
|
|
34394
|
+
signature,
|
|
34395
|
+
status: "confirmed",
|
|
34396
|
+
canProceedToQueue: status.canProceedToQueue
|
|
34397
|
+
};
|
|
34398
|
+
}
|
|
34399
|
+
if (status.allConfirmed && status.canProceedToQueue) {
|
|
34400
|
+
return { signature, status: "confirmed", canProceedToQueue: true };
|
|
34401
|
+
}
|
|
34402
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
34249
34403
|
}
|
|
34250
|
-
return { signature, status: "
|
|
34404
|
+
return { signature, status: "pending", canProceedToQueue: false };
|
|
34251
34405
|
}
|
|
34252
34406
|
async claimLobbyDepositRefund(lobbyId, depositSignature) {
|
|
34253
34407
|
return this.http.post(
|
|
@@ -34589,9 +34743,10 @@ var Support = class {
|
|
|
34589
34743
|
}
|
|
34590
34744
|
};
|
|
34591
34745
|
var Markets = class {
|
|
34592
|
-
constructor(http2, logger2) {
|
|
34746
|
+
constructor(http2, logger2, wallet) {
|
|
34593
34747
|
this.http = http2;
|
|
34594
34748
|
this.logger = logger2;
|
|
34749
|
+
this.wallet = wallet;
|
|
34595
34750
|
}
|
|
34596
34751
|
/**
|
|
34597
34752
|
* Get the prediction market state for a game.
|
|
@@ -34633,6 +34788,35 @@ var Markets = class {
|
|
|
34633
34788
|
{ signedTransaction, outcomeId, amountMinor }
|
|
34634
34789
|
);
|
|
34635
34790
|
}
|
|
34791
|
+
/**
|
|
34792
|
+
* Confirm a buy order that was already broadcast by the client (signAndSendTransaction path).
|
|
34793
|
+
*/
|
|
34794
|
+
async confirmBuyOrderSignature(gameId, depositSignature, outcomeId, amountMinor) {
|
|
34795
|
+
return this.http.post(
|
|
34796
|
+
`/games/${gameId}/market/orders/buy/confirm-signature`,
|
|
34797
|
+
{ depositSignature, outcomeId, amountMinor }
|
|
34798
|
+
);
|
|
34799
|
+
}
|
|
34800
|
+
/**
|
|
34801
|
+
* One-call buy order: prepare → sign → submit, automatically choosing
|
|
34802
|
+
* the right signing path (embedded vs injected wallet).
|
|
34803
|
+
*/
|
|
34804
|
+
async buy(gameId, outcomeId, amountMinor) {
|
|
34805
|
+
if (!this.wallet?.hasSigner()) {
|
|
34806
|
+
throw new Error(
|
|
34807
|
+
"No signer configured. Use sdk.wallet.setSigner(...) first."
|
|
34808
|
+
);
|
|
34809
|
+
}
|
|
34810
|
+
const { transaction } = await this.prepareBuyOrder(
|
|
34811
|
+
gameId,
|
|
34812
|
+
outcomeId,
|
|
34813
|
+
amountMinor
|
|
34814
|
+
);
|
|
34815
|
+
return this.wallet.signAndDispatch(transaction, {
|
|
34816
|
+
onSigned: (signedTxBase64) => this.submitBuyOrder(gameId, signedTxBase64, outcomeId, amountMinor),
|
|
34817
|
+
onSignedAndSent: (sig) => this.confirmBuyOrderSignature(gameId, sig, outcomeId, amountMinor)
|
|
34818
|
+
});
|
|
34819
|
+
}
|
|
34636
34820
|
/**
|
|
34637
34821
|
* Sell shares back to the AMM pool.
|
|
34638
34822
|
* @param gameId - The game ID
|
|
@@ -34681,6 +34865,20 @@ var Markets = class {
|
|
|
34681
34865
|
return this.http.get(`/games/admin/markets${qs ? `?${qs}` : ""}`);
|
|
34682
34866
|
}
|
|
34683
34867
|
};
|
|
34868
|
+
var NoopAnalyticsClient = class {
|
|
34869
|
+
userLoggedIn(_user, _meta) {
|
|
34870
|
+
}
|
|
34871
|
+
userLoggedOut() {
|
|
34872
|
+
}
|
|
34873
|
+
sessionRestored(_user) {
|
|
34874
|
+
}
|
|
34875
|
+
track(_event, _properties) {
|
|
34876
|
+
}
|
|
34877
|
+
setUserProperties(_properties) {
|
|
34878
|
+
}
|
|
34879
|
+
group(_groupType, _groupKey, _properties) {
|
|
34880
|
+
}
|
|
34881
|
+
};
|
|
34684
34882
|
var BaseWsTransport = class {
|
|
34685
34883
|
constructor() {
|
|
34686
34884
|
this.roomRefs = /* @__PURE__ */ new Map();
|
|
@@ -34768,21 +34966,35 @@ var _StandaloneWsTransport = class _StandaloneWsTransport2 extends BaseWsTranspo
|
|
|
34768
34966
|
this.accessToken = null;
|
|
34769
34967
|
this.reconnectAttempts = 0;
|
|
34770
34968
|
this.reconnectTimer = null;
|
|
34771
|
-
this.
|
|
34772
|
-
this.
|
|
34773
|
-
this.reconnectDelay = 1e3;
|
|
34774
|
-
this.reconnectDelayMax = 3e4;
|
|
34969
|
+
this.needsReconnect = false;
|
|
34970
|
+
this.visibilityHandler = null;
|
|
34775
34971
|
this.wildcardHandlers = /* @__PURE__ */ new Set();
|
|
34776
34972
|
this.eventHandlers = /* @__PURE__ */ new Map();
|
|
34777
34973
|
this.registeredEvents = /* @__PURE__ */ new Set();
|
|
34778
34974
|
this.wildcardRegistered = false;
|
|
34779
34975
|
this.url = url3;
|
|
34976
|
+
if (typeof document !== "undefined") {
|
|
34977
|
+
this.visibilityHandler = () => {
|
|
34978
|
+
if (document.visibilityState === "visible" && !this.connectionState.connected) {
|
|
34979
|
+
this.reconnectImmediately();
|
|
34980
|
+
}
|
|
34981
|
+
};
|
|
34982
|
+
document.addEventListener("visibilitychange", this.visibilityHandler);
|
|
34983
|
+
}
|
|
34780
34984
|
}
|
|
34781
34985
|
connect() {
|
|
34986
|
+
if (this.reconnectTimer !== null) {
|
|
34987
|
+
clearTimeout(this.reconnectTimer);
|
|
34988
|
+
this.reconnectTimer = null;
|
|
34989
|
+
}
|
|
34990
|
+
this.reconnectAttempts = 0;
|
|
34782
34991
|
this.ensureSocket();
|
|
34783
34992
|
}
|
|
34784
34993
|
disconnect() {
|
|
34785
|
-
this.
|
|
34994
|
+
if (this.visibilityHandler && typeof document !== "undefined") {
|
|
34995
|
+
document.removeEventListener("visibilitychange", this.visibilityHandler);
|
|
34996
|
+
this.visibilityHandler = null;
|
|
34997
|
+
}
|
|
34786
34998
|
if (!this.socket) return;
|
|
34787
34999
|
this.socket.disconnect();
|
|
34788
35000
|
this.socket = null;
|
|
@@ -34881,13 +35093,13 @@ var _StandaloneWsTransport = class _StandaloneWsTransport2 extends BaseWsTranspo
|
|
|
34881
35093
|
reconnection: false
|
|
34882
35094
|
});
|
|
34883
35095
|
socket.on("connect", () => {
|
|
34884
|
-
this.clearPeriodicReconnect();
|
|
34885
35096
|
this.updateConnectionState({
|
|
34886
35097
|
connected: true,
|
|
34887
35098
|
connecting: false,
|
|
34888
35099
|
error: null
|
|
34889
35100
|
});
|
|
34890
|
-
const wasReconnect = this.
|
|
35101
|
+
const wasReconnect = this.needsReconnect;
|
|
35102
|
+
this.needsReconnect = false;
|
|
34891
35103
|
this.reconnectAttempts = 0;
|
|
34892
35104
|
this.onReconnect();
|
|
34893
35105
|
if (wasReconnect) {
|
|
@@ -34898,6 +35110,7 @@ var _StandaloneWsTransport = class _StandaloneWsTransport2 extends BaseWsTranspo
|
|
|
34898
35110
|
});
|
|
34899
35111
|
socket.on("disconnect", (reason) => {
|
|
34900
35112
|
this.updateConnectionState({ connected: false, connecting: false });
|
|
35113
|
+
this.needsReconnect = true;
|
|
34901
35114
|
this.clearSocketForReconnect();
|
|
34902
35115
|
if (reason === "io server disconnect") {
|
|
34903
35116
|
this.handleAuthFailure("io server disconnect");
|
|
@@ -34907,6 +35120,7 @@ var _StandaloneWsTransport = class _StandaloneWsTransport2 extends BaseWsTranspo
|
|
|
34907
35120
|
});
|
|
34908
35121
|
socket.on("connect_error", (error) => {
|
|
34909
35122
|
const message = error?.message || "connect_error";
|
|
35123
|
+
this.needsReconnect = true;
|
|
34910
35124
|
this.clearSocketForReconnect();
|
|
34911
35125
|
if (message.includes("unauthorized") || message.includes("401")) {
|
|
34912
35126
|
this.handleAuthFailure(message);
|
|
@@ -34934,31 +35148,31 @@ var _StandaloneWsTransport = class _StandaloneWsTransport2 extends BaseWsTranspo
|
|
|
34934
35148
|
this.socket.removeAllListeners();
|
|
34935
35149
|
this.socket = null;
|
|
34936
35150
|
}
|
|
34937
|
-
|
|
34938
|
-
if (this.
|
|
34939
|
-
|
|
34940
|
-
this.
|
|
35151
|
+
reconnectImmediately() {
|
|
35152
|
+
if (this.reconnectTimer !== null) {
|
|
35153
|
+
clearTimeout(this.reconnectTimer);
|
|
35154
|
+
this.reconnectTimer = null;
|
|
34941
35155
|
}
|
|
34942
|
-
|
|
34943
|
-
|
|
34944
|
-
if (this.periodicReconnectInterval !== null) return;
|
|
34945
|
-
this.periodicReconnectInterval = setInterval(() => {
|
|
34946
|
-
if (this.connectionState.connected) return;
|
|
34947
|
-
this.reconnectAttempts = 0;
|
|
34948
|
-
this.ensureSocket();
|
|
34949
|
-
}, _StandaloneWsTransport2.PERIODIC_RECONNECT_MS);
|
|
35156
|
+
this.reconnectAttempts = 0;
|
|
35157
|
+
this.ensureSocket();
|
|
34950
35158
|
}
|
|
34951
35159
|
scheduleReconnect() {
|
|
34952
35160
|
if (this.reconnectTimer !== null) return;
|
|
34953
|
-
|
|
34954
|
-
this.startPeriodicReconnect();
|
|
34955
|
-
return;
|
|
34956
|
-
}
|
|
34957
|
-
const delay = Math.min(
|
|
34958
|
-
this.reconnectDelay * Math.pow(2, this.reconnectAttempts),
|
|
34959
|
-
this.reconnectDelayMax
|
|
34960
|
-
);
|
|
35161
|
+
const attempt = this.reconnectAttempts;
|
|
34961
35162
|
this.reconnectAttempts += 1;
|
|
35163
|
+
let delay;
|
|
35164
|
+
if (attempt < _StandaloneWsTransport2.FAST_RETRY_LIMIT) {
|
|
35165
|
+
delay = _StandaloneWsTransport2.FAST_RETRY_DELAY_MS;
|
|
35166
|
+
} else {
|
|
35167
|
+
const backoffAttempt = attempt - _StandaloneWsTransport2.FAST_RETRY_LIMIT;
|
|
35168
|
+
delay = Math.min(
|
|
35169
|
+
_StandaloneWsTransport2.FAST_RETRY_DELAY_MS * Math.pow(2, backoffAttempt),
|
|
35170
|
+
_StandaloneWsTransport2.MAX_BACKOFF_MS
|
|
35171
|
+
);
|
|
35172
|
+
if (attempt === _StandaloneWsTransport2.FAST_RETRY_LIMIT) {
|
|
35173
|
+
this.dispatchEvent("connection:slow-retry", { timestamp: Date.now() });
|
|
35174
|
+
}
|
|
35175
|
+
}
|
|
34962
35176
|
this.reconnectTimer = setTimeout(() => {
|
|
34963
35177
|
this.reconnectTimer = null;
|
|
34964
35178
|
this.ensureSocket();
|
|
@@ -35019,7 +35233,9 @@ var _StandaloneWsTransport = class _StandaloneWsTransport2 extends BaseWsTranspo
|
|
|
35019
35233
|
this.wildcardRegistered = true;
|
|
35020
35234
|
}
|
|
35021
35235
|
};
|
|
35022
|
-
_StandaloneWsTransport.
|
|
35236
|
+
_StandaloneWsTransport.FAST_RETRY_LIMIT = 60;
|
|
35237
|
+
_StandaloneWsTransport.FAST_RETRY_DELAY_MS = 1e3;
|
|
35238
|
+
_StandaloneWsTransport.MAX_BACKOFF_MS = 3e4;
|
|
35023
35239
|
var StandaloneWsTransport = _StandaloneWsTransport;
|
|
35024
35240
|
function createSdkStore(initial) {
|
|
35025
35241
|
const store = createStore()(subscribeWithSelector(() => initial));
|
|
@@ -35040,14 +35256,16 @@ function createLobbyStore(transport) {
|
|
|
35040
35256
|
depositStatusByLobbyId: {}
|
|
35041
35257
|
});
|
|
35042
35258
|
const setBaseState = (lobbies) => {
|
|
35043
|
-
|
|
35044
|
-
|
|
35045
|
-
|
|
35046
|
-
|
|
35047
|
-
|
|
35048
|
-
|
|
35049
|
-
|
|
35050
|
-
|
|
35259
|
+
store.updateState((state) => {
|
|
35260
|
+
const lobbiesById = { ...state.lobbiesById };
|
|
35261
|
+
for (const lobby of lobbies) {
|
|
35262
|
+
const existing = lobbiesById[lobby.id];
|
|
35263
|
+
if (!existing || lobby.updatedAt >= existing.updatedAt) {
|
|
35264
|
+
lobbiesById[lobby.id] = lobby;
|
|
35265
|
+
}
|
|
35266
|
+
}
|
|
35267
|
+
return { ...state, lobbiesById };
|
|
35268
|
+
});
|
|
35051
35269
|
};
|
|
35052
35270
|
const applyWsEvent = (event) => {
|
|
35053
35271
|
switch (event.event) {
|
|
@@ -35177,12 +35395,23 @@ function createGameStore(transport) {
|
|
|
35177
35395
|
gamesById: {},
|
|
35178
35396
|
spectatorCounts: {}
|
|
35179
35397
|
});
|
|
35398
|
+
const STATUS_RANK = {
|
|
35399
|
+
active: 0,
|
|
35400
|
+
completed: 1,
|
|
35401
|
+
abandoned: 1
|
|
35402
|
+
};
|
|
35180
35403
|
const setBaseState = (games) => {
|
|
35181
|
-
|
|
35182
|
-
|
|
35183
|
-
|
|
35184
|
-
|
|
35185
|
-
|
|
35404
|
+
store.updateState((state) => {
|
|
35405
|
+
const gamesById = { ...state.gamesById };
|
|
35406
|
+
for (const game of games) {
|
|
35407
|
+
const existing = gamesById[game.gameId];
|
|
35408
|
+
if (existing && STATUS_RANK[existing.status] > STATUS_RANK[game.status]) {
|
|
35409
|
+
continue;
|
|
35410
|
+
}
|
|
35411
|
+
gamesById[game.gameId] = game;
|
|
35412
|
+
}
|
|
35413
|
+
return { ...state, gamesById };
|
|
35414
|
+
});
|
|
35186
35415
|
};
|
|
35187
35416
|
const applyWsEvent = (event) => {
|
|
35188
35417
|
switch (event.event) {
|
|
@@ -35920,7 +36149,38 @@ function createNotificationsStore() {
|
|
|
35920
36149
|
appNotifications: []
|
|
35921
36150
|
}));
|
|
35922
36151
|
};
|
|
35923
|
-
|
|
36152
|
+
const markAsRead = (id) => {
|
|
36153
|
+
store.updateState((state) => ({
|
|
36154
|
+
...state,
|
|
36155
|
+
appNotifications: state.appNotifications.map(
|
|
36156
|
+
(n) => n.id === id ? { ...n, read: true } : n
|
|
36157
|
+
)
|
|
36158
|
+
}));
|
|
36159
|
+
};
|
|
36160
|
+
const markAllAsRead = () => {
|
|
36161
|
+
store.updateState((state) => ({
|
|
36162
|
+
...state,
|
|
36163
|
+
appNotifications: state.appNotifications.map((n) => ({
|
|
36164
|
+
...n,
|
|
36165
|
+
read: true
|
|
36166
|
+
}))
|
|
36167
|
+
}));
|
|
36168
|
+
};
|
|
36169
|
+
const dismiss = (id) => {
|
|
36170
|
+
store.updateState((state) => ({
|
|
36171
|
+
...state,
|
|
36172
|
+
appNotifications: state.appNotifications.filter((n) => n.id !== id)
|
|
36173
|
+
}));
|
|
36174
|
+
};
|
|
36175
|
+
return {
|
|
36176
|
+
store,
|
|
36177
|
+
applyWsEvent,
|
|
36178
|
+
setListFromApi,
|
|
36179
|
+
clear,
|
|
36180
|
+
markAsRead,
|
|
36181
|
+
markAllAsRead,
|
|
36182
|
+
dismiss
|
|
36183
|
+
};
|
|
35924
36184
|
}
|
|
35925
36185
|
function createFriendsStore() {
|
|
35926
36186
|
const store = createSdkStore({
|
|
@@ -36267,6 +36527,7 @@ var SDK = class {
|
|
|
36267
36527
|
constructor(config) {
|
|
36268
36528
|
const baseUrl = config.baseUrl || "http://localhost:3000";
|
|
36269
36529
|
const logger2 = config.logger || logger;
|
|
36530
|
+
this.analytics = config.analytics ?? new NoopAnalyticsClient();
|
|
36270
36531
|
this.http = config.httpClient || new HttpClient(
|
|
36271
36532
|
baseUrl,
|
|
36272
36533
|
config.storage,
|
|
@@ -36299,14 +36560,18 @@ var SDK = class {
|
|
|
36299
36560
|
this.referrals = new Referrals(this.http, logger2);
|
|
36300
36561
|
this.reports = new Reports(this.http, logger2);
|
|
36301
36562
|
this.support = new Support(this.http, logger2);
|
|
36302
|
-
this.markets = new Markets(this.http, logger2);
|
|
36563
|
+
this.markets = new Markets(this.http, logger2, this.wallet);
|
|
36303
36564
|
this.wsTransport = config.wsTransport || new StandaloneWsTransport(baseUrl);
|
|
36304
36565
|
this.wsTransport.setAppId(config.appId);
|
|
36305
36566
|
this.lobbyStore = createLobbyStore(this.wsTransport);
|
|
36567
|
+
this.lobbies.setLobbyStore(this.lobbyStore);
|
|
36306
36568
|
this.gameStore = createGameStore(this.wsTransport);
|
|
36569
|
+
this.games.setGameStore(this.gameStore);
|
|
36307
36570
|
this.gameActionsStore = createGameActionsStore(this.wsTransport);
|
|
36571
|
+
this.games.setGameActionsStore(this.gameActionsStore);
|
|
36308
36572
|
this.chatStore = createChatStore(this.wsTransport);
|
|
36309
36573
|
this.dmThreadsStore = createDmThreadsStore();
|
|
36574
|
+
this.chat.setDmThreadsStore(this.dmThreadsStore);
|
|
36310
36575
|
this.notificationsStore = createNotificationsStore();
|
|
36311
36576
|
this.friendsStore = createFriendsStore();
|
|
36312
36577
|
this.notifications = new Notifications(
|
|
@@ -36336,6 +36601,29 @@ var SDK = class {
|
|
|
36336
36601
|
this.wsTransport.connect();
|
|
36337
36602
|
await this.wsTransport.waitUntilConnected(timeoutMs);
|
|
36338
36603
|
}
|
|
36604
|
+
/**
|
|
36605
|
+
* Handle the full deposit-to-queue lifecycle for a lobby.
|
|
36606
|
+
*
|
|
36607
|
+
* After the deposit is confirmed, the backend may not have processed the
|
|
36608
|
+
* `lobby.deposit.allConfirmed` event yet, so the lobby can still be in
|
|
36609
|
+
* 'preparing' status. This method re-fetches the lobby and explicitly
|
|
36610
|
+
* joins the queue if needed, then pushes the latest state to the store
|
|
36611
|
+
* so the UI transitions immediately.
|
|
36612
|
+
*/
|
|
36613
|
+
async depositAndJoinQueue(lobbyId) {
|
|
36614
|
+
const result = await this.escrow.depositForLobby(lobbyId);
|
|
36615
|
+
if (!result.canProceedToQueue) {
|
|
36616
|
+
const lobby2 = await this.lobbies.getLobby(lobbyId);
|
|
36617
|
+
this.lobbyStore.setBaseState([lobby2]);
|
|
36618
|
+
return { ...result, lobby: lobby2 };
|
|
36619
|
+
}
|
|
36620
|
+
let lobby = await this.lobbies.getLobby(lobbyId);
|
|
36621
|
+
if (lobby.status === "preparing") {
|
|
36622
|
+
lobby = await this.lobbies.joinQueue(lobbyId);
|
|
36623
|
+
}
|
|
36624
|
+
this.lobbyStore.setBaseState([lobby]);
|
|
36625
|
+
return { ...result, lobby };
|
|
36626
|
+
}
|
|
36339
36627
|
};
|
|
36340
36628
|
var import_utils14 = __toESM2(require_dist(), 1);
|
|
36341
36629
|
var export_MICRO_UNITS = import_utils14.MICRO_UNITS;
|
|
@@ -36482,7 +36770,9 @@ var import_tweetnacl = __toESM(require_nacl_fast(), 1);
|
|
|
36482
36770
|
var DimAgentClient = class {
|
|
36483
36771
|
sdk;
|
|
36484
36772
|
agentConfig;
|
|
36773
|
+
externalSignerMode;
|
|
36485
36774
|
keypair;
|
|
36775
|
+
_externalAddress = null;
|
|
36486
36776
|
config;
|
|
36487
36777
|
authenticated = false;
|
|
36488
36778
|
userId = null;
|
|
@@ -36496,21 +36786,26 @@ var DimAgentClient = class {
|
|
|
36496
36786
|
constructor(config) {
|
|
36497
36787
|
this.config = config;
|
|
36498
36788
|
this.agentConfig = config.agentConfig;
|
|
36499
|
-
|
|
36500
|
-
|
|
36789
|
+
this.externalSignerMode = !config.walletPrivateKey;
|
|
36790
|
+
if (config.walletPrivateKey) {
|
|
36791
|
+
const secretKeyBytes = esm_default4.decode(config.walletPrivateKey);
|
|
36792
|
+
this.keypair = Keypair.fromSecretKey(secretKeyBytes);
|
|
36793
|
+
} else {
|
|
36794
|
+
this.keypair = null;
|
|
36795
|
+
}
|
|
36501
36796
|
this.sdk = new SDK({
|
|
36502
36797
|
appId: "dim-agents",
|
|
36503
36798
|
baseUrl: config.apiUrl || "https://api.dim.cool",
|
|
36504
36799
|
storage: new NodeStorage(),
|
|
36505
36800
|
autoPay: {
|
|
36506
|
-
enabled:
|
|
36801
|
+
enabled: !this.externalSignerMode,
|
|
36507
36802
|
maxAmountMinor: 25e3,
|
|
36508
36803
|
maxRetries: 1
|
|
36509
36804
|
}
|
|
36510
36805
|
});
|
|
36511
36806
|
}
|
|
36512
36807
|
get walletAddress() {
|
|
36513
|
-
return this.keypair
|
|
36808
|
+
return this.keypair?.publicKey.toBase58() ?? this._externalAddress ?? "";
|
|
36514
36809
|
}
|
|
36515
36810
|
get isAuthenticated() {
|
|
36516
36811
|
return this.authenticated;
|
|
@@ -36519,17 +36814,23 @@ var DimAgentClient = class {
|
|
|
36519
36814
|
return this.userId;
|
|
36520
36815
|
}
|
|
36521
36816
|
async authenticate() {
|
|
36817
|
+
if (!this.keypair) {
|
|
36818
|
+
throw new Error(
|
|
36819
|
+
"No keypair configured. Use dim_request_auth_message + dim_complete_login for external signer mode."
|
|
36820
|
+
);
|
|
36821
|
+
}
|
|
36822
|
+
const keypair = this.keypair;
|
|
36522
36823
|
this.sdk.wallet.setSigner({
|
|
36523
36824
|
address: this.walletAddress,
|
|
36524
36825
|
signMessage: async (message) => {
|
|
36525
36826
|
const signature = import_tweetnacl.default.sign.detached(
|
|
36526
36827
|
new TextEncoder().encode(message),
|
|
36527
|
-
|
|
36828
|
+
keypair.secretKey
|
|
36528
36829
|
);
|
|
36529
36830
|
return Buffer.from(signature).toString("base64");
|
|
36530
36831
|
},
|
|
36531
36832
|
signTransaction: async (transaction) => {
|
|
36532
|
-
transaction.partialSign(
|
|
36833
|
+
transaction.partialSign(keypair);
|
|
36533
36834
|
return transaction;
|
|
36534
36835
|
}
|
|
36535
36836
|
});
|
|
@@ -36583,10 +36884,45 @@ var DimAgentClient = class {
|
|
|
36583
36884
|
get pendingEventCount() {
|
|
36584
36885
|
return this.eventQueue.length;
|
|
36585
36886
|
}
|
|
36586
|
-
/** Get the Keypair for transaction signing. */
|
|
36887
|
+
/** Get the Keypair for transaction signing (keypair mode only). */
|
|
36587
36888
|
getKeypair() {
|
|
36889
|
+
if (!this.keypair) {
|
|
36890
|
+
throw new Error(
|
|
36891
|
+
"No keypair configured \u2014 running in external signer mode."
|
|
36892
|
+
);
|
|
36893
|
+
}
|
|
36588
36894
|
return this.keypair;
|
|
36589
36895
|
}
|
|
36896
|
+
/** Request the auth handshake message for a given address (external signer mode). */
|
|
36897
|
+
async requestAuthMessage(address) {
|
|
36898
|
+
return this.sdk.auth.generateHandshake(address);
|
|
36899
|
+
}
|
|
36900
|
+
/**
|
|
36901
|
+
* Complete authentication using an externally provided signature (external signer mode).
|
|
36902
|
+
* @param address - Solana wallet address (base58)
|
|
36903
|
+
* @param signatureBase58 - Detached ed25519 signature in base58 (from sign_solana_message)
|
|
36904
|
+
*/
|
|
36905
|
+
async completeAuth(address, signatureBase58) {
|
|
36906
|
+
const signatureBytes = esm_default4.decode(signatureBase58);
|
|
36907
|
+
const signedMessage = Buffer.from(signatureBytes).toString("base64");
|
|
36908
|
+
const response = await this.sdk.auth.loginWithExternalSignature(
|
|
36909
|
+
address,
|
|
36910
|
+
signedMessage,
|
|
36911
|
+
{
|
|
36912
|
+
referralCode: this.config.referralCode,
|
|
36913
|
+
walletMeta: { type: "phantom-embedded", provider: "injected" }
|
|
36914
|
+
}
|
|
36915
|
+
);
|
|
36916
|
+
this.sdk.wsTransport.setAccessToken(response.access_token);
|
|
36917
|
+
this._externalAddress = address;
|
|
36918
|
+
this.authenticated = true;
|
|
36919
|
+
this.userId = response.user.id;
|
|
36920
|
+
return {
|
|
36921
|
+
userId: response.user.id,
|
|
36922
|
+
username: response.user.username,
|
|
36923
|
+
accessToken: response.access_token
|
|
36924
|
+
};
|
|
36925
|
+
}
|
|
36590
36926
|
// ── Game chat cursors ────────────────────────────────────────────────
|
|
36591
36927
|
/** Get the last-seen chat timestamp for a game. */
|
|
36592
36928
|
getGameChatCursor(gameId) {
|
|
@@ -36714,6 +37050,77 @@ async function login(client) {
|
|
|
36714
37050
|
};
|
|
36715
37051
|
}
|
|
36716
37052
|
}
|
|
37053
|
+
async function requestAuthMessage(client, args) {
|
|
37054
|
+
try {
|
|
37055
|
+
const { message } = await client.requestAuthMessage(args.address);
|
|
37056
|
+
return {
|
|
37057
|
+
data: {
|
|
37058
|
+
message,
|
|
37059
|
+
address: args.address,
|
|
37060
|
+
nextStep: 'Sign this message with sign_solana_message (networkId: "solana:mainnet"), then call dim_complete_login with the address and the base58 signature.'
|
|
37061
|
+
}
|
|
37062
|
+
};
|
|
37063
|
+
} catch (error) {
|
|
37064
|
+
return {
|
|
37065
|
+
error: `Failed to get auth message: ${error instanceof Error ? error.message : String(error)}`,
|
|
37066
|
+
isError: true
|
|
37067
|
+
};
|
|
37068
|
+
}
|
|
37069
|
+
}
|
|
37070
|
+
async function completeLogin(client, args) {
|
|
37071
|
+
try {
|
|
37072
|
+
const result = await client.completeAuth(args.address, args.signature);
|
|
37073
|
+
client.startEventListeners();
|
|
37074
|
+
const nextSteps = [];
|
|
37075
|
+
if (result.username == null || result.username === "") {
|
|
37076
|
+
nextSteps.push("No username set \u2014 call dim_set_username to claim one");
|
|
37077
|
+
}
|
|
37078
|
+
nextSteps.push("Check your balance with dim_get_balance");
|
|
37079
|
+
nextSteps.push("Explore available games with dim_list_games");
|
|
37080
|
+
try {
|
|
37081
|
+
const summary = await client.sdk.referrals.getSummary();
|
|
37082
|
+
if (!summary.hasReferrer) {
|
|
37083
|
+
nextSteps.push(
|
|
37084
|
+
"No referrer yet \u2014 call dim_apply_referral_code for 10% fee discount"
|
|
37085
|
+
);
|
|
37086
|
+
}
|
|
37087
|
+
if (result.username) {
|
|
37088
|
+
nextSteps.push(
|
|
37089
|
+
`Share your referral code "${result.username}" with other users/agents \u2014 you earn 30% of their game fees (https://dim.cool/?ref=${result.username})`
|
|
37090
|
+
);
|
|
37091
|
+
}
|
|
37092
|
+
} catch {
|
|
37093
|
+
}
|
|
37094
|
+
const response = {
|
|
37095
|
+
success: true,
|
|
37096
|
+
userId: result.userId,
|
|
37097
|
+
username: result.username ?? null,
|
|
37098
|
+
walletAddress: client.walletAddress,
|
|
37099
|
+
walletNote: "DIM is noncustodial. Signing is handled by your external wallet for this session.",
|
|
37100
|
+
safetyRules: SAFETY_RULES,
|
|
37101
|
+
nextSteps
|
|
37102
|
+
};
|
|
37103
|
+
const ac = client.agentConfig;
|
|
37104
|
+
const dailyLimit = ac?.dailySpendLimit ?? 20;
|
|
37105
|
+
response.agentConfig = {
|
|
37106
|
+
autoAcceptFriendRequests: ac?.autoAcceptFriendRequests ?? false,
|
|
37107
|
+
autoReplyDms: ac?.autoReplyDms ?? false,
|
|
37108
|
+
autoPlayGames: ac?.autoPlayGames ?? false,
|
|
37109
|
+
maxBetPerGame: ac?.maxBetPerGame ?? 1,
|
|
37110
|
+
dailySpendLimit: dailyLimit,
|
|
37111
|
+
autoJoinGlobalChat: ac?.autoJoinGlobalChat ?? false,
|
|
37112
|
+
autoPromoteReferrals: ac?.autoPromoteReferrals ?? false,
|
|
37113
|
+
dailySpentSoFar: client.dailySpentDollars,
|
|
37114
|
+
dailyRemaining: dailyLimit - client.dailySpentDollars
|
|
37115
|
+
};
|
|
37116
|
+
return { data: response };
|
|
37117
|
+
} catch (error) {
|
|
37118
|
+
return {
|
|
37119
|
+
error: `Login failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
37120
|
+
isError: true
|
|
37121
|
+
};
|
|
37122
|
+
}
|
|
37123
|
+
}
|
|
36717
37124
|
async function getProfile(client) {
|
|
36718
37125
|
try {
|
|
36719
37126
|
if (!client.currentUserId) {
|
|
@@ -36842,10 +37249,19 @@ async function listFriends(client, args) {
|
|
|
36842
37249
|
};
|
|
36843
37250
|
}
|
|
36844
37251
|
}
|
|
36845
|
-
async function getIncomingFriendRequests(client) {
|
|
37252
|
+
async function getIncomingFriendRequests(client, args) {
|
|
36846
37253
|
try {
|
|
36847
|
-
const result = await client.sdk.users.getIncomingFriendRequests(
|
|
36848
|
-
|
|
37254
|
+
const result = await client.sdk.users.getIncomingFriendRequests({
|
|
37255
|
+
limit: args?.limit,
|
|
37256
|
+
cursor: args?.cursor
|
|
37257
|
+
});
|
|
37258
|
+
return {
|
|
37259
|
+
data: {
|
|
37260
|
+
items: result.items,
|
|
37261
|
+
nextCursor: result.nextCursor,
|
|
37262
|
+
hasMore: !!result.nextCursor
|
|
37263
|
+
}
|
|
37264
|
+
};
|
|
36849
37265
|
} catch (error) {
|
|
36850
37266
|
return {
|
|
36851
37267
|
error: `Failed to get requests: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -36966,6 +37382,42 @@ async function sendUsdc(client, args) {
|
|
|
36966
37382
|
const spendErr = client.checkSpendLimit(args.amount);
|
|
36967
37383
|
if (spendErr) return { error: spendErr, isError: true };
|
|
36968
37384
|
const amountMinor = Math.round(args.amount * 1e6);
|
|
37385
|
+
if (client.externalSignerMode) {
|
|
37386
|
+
const senderAddress = client.walletAddress;
|
|
37387
|
+
if (!senderAddress) {
|
|
37388
|
+
return {
|
|
37389
|
+
error: "Wallet address not set. Call dim_complete_login first.",
|
|
37390
|
+
isError: true
|
|
37391
|
+
};
|
|
37392
|
+
}
|
|
37393
|
+
const prepared = await client.sdk.wallet.prepareTransfer(
|
|
37394
|
+
senderAddress,
|
|
37395
|
+
args.recipient,
|
|
37396
|
+
amountMinor
|
|
37397
|
+
);
|
|
37398
|
+
return {
|
|
37399
|
+
data: {
|
|
37400
|
+
needsSigning: true,
|
|
37401
|
+
unsignedTx: prepared.transaction,
|
|
37402
|
+
fee: prepared.fee,
|
|
37403
|
+
totalAmount: prepared.totalAmount,
|
|
37404
|
+
recipientAddress: prepared.recipientAddress,
|
|
37405
|
+
ataCreated: prepared.ataCreated ?? false,
|
|
37406
|
+
confirmWith: {
|
|
37407
|
+
tool: "dim_confirm_send_usdc",
|
|
37408
|
+
params: {
|
|
37409
|
+
recipientAddress: prepared.recipientAddress,
|
|
37410
|
+
amount: amountMinor,
|
|
37411
|
+
fee: prepared.fee,
|
|
37412
|
+
token: "USDC",
|
|
37413
|
+
ataCreated: prepared.ataCreated ?? false,
|
|
37414
|
+
recipientInput: args.recipient
|
|
37415
|
+
}
|
|
37416
|
+
},
|
|
37417
|
+
hint: "Sign and broadcast unsignedTx with send_solana_transaction, then call dim_confirm_send_usdc with the signature and the confirmWith.params."
|
|
37418
|
+
}
|
|
37419
|
+
};
|
|
37420
|
+
}
|
|
36969
37421
|
const result = await client.sdk.wallet.send(args.recipient, amountMinor);
|
|
36970
37422
|
client.recordSpend(amountMinor);
|
|
36971
37423
|
return {
|
|
@@ -36986,11 +37438,74 @@ async function sendUsdc(client, args) {
|
|
|
36986
37438
|
};
|
|
36987
37439
|
}
|
|
36988
37440
|
}
|
|
37441
|
+
async function confirmSendUsdc(client, args) {
|
|
37442
|
+
try {
|
|
37443
|
+
const senderAddress = client.walletAddress;
|
|
37444
|
+
const result = await client.sdk.wallet.confirmTransferSignature(
|
|
37445
|
+
args.signature,
|
|
37446
|
+
senderAddress,
|
|
37447
|
+
args.recipientAddress,
|
|
37448
|
+
args.amount,
|
|
37449
|
+
args.token || "USDC",
|
|
37450
|
+
args.ataCreated,
|
|
37451
|
+
args.recipientInput
|
|
37452
|
+
);
|
|
37453
|
+
client.recordSpend(args.amount);
|
|
37454
|
+
return {
|
|
37455
|
+
data: {
|
|
37456
|
+
success: true,
|
|
37457
|
+
signature: result.signature,
|
|
37458
|
+
status: result.status,
|
|
37459
|
+
recipientAddress: args.recipientAddress
|
|
37460
|
+
}
|
|
37461
|
+
};
|
|
37462
|
+
} catch (error) {
|
|
37463
|
+
return {
|
|
37464
|
+
error: `Failed to confirm USDC transfer: ${error instanceof Error ? error.message : String(error)}`,
|
|
37465
|
+
isError: true
|
|
37466
|
+
};
|
|
37467
|
+
}
|
|
37468
|
+
}
|
|
36989
37469
|
async function tipUser(client, args) {
|
|
36990
37470
|
try {
|
|
36991
37471
|
const spendErr = client.checkSpendLimit(args.amount);
|
|
36992
37472
|
if (spendErr) return { error: spendErr, isError: true };
|
|
36993
37473
|
const amountMinor = Math.round(args.amount * 1e6);
|
|
37474
|
+
if (client.externalSignerMode) {
|
|
37475
|
+
const senderAddress = client.walletAddress;
|
|
37476
|
+
if (!senderAddress) {
|
|
37477
|
+
return {
|
|
37478
|
+
error: "Wallet address not set. Call dim_complete_login first.",
|
|
37479
|
+
isError: true
|
|
37480
|
+
};
|
|
37481
|
+
}
|
|
37482
|
+
const prepared = await client.sdk.tips.prepare({
|
|
37483
|
+
recipientUsername: args.recipientUsername,
|
|
37484
|
+
amount: amountMinor,
|
|
37485
|
+
supportsPresign: false
|
|
37486
|
+
});
|
|
37487
|
+
return {
|
|
37488
|
+
data: {
|
|
37489
|
+
needsSigning: true,
|
|
37490
|
+
unsignedTx: prepared.transaction,
|
|
37491
|
+
fee: prepared.fee,
|
|
37492
|
+
totalAmount: prepared.totalAmount,
|
|
37493
|
+
recipientAddress: prepared.recipientAddress,
|
|
37494
|
+
confirmWith: {
|
|
37495
|
+
tool: "dim_confirm_tip_user",
|
|
37496
|
+
params: {
|
|
37497
|
+
recipientAddress: prepared.recipientAddress,
|
|
37498
|
+
recipientUserId: prepared.recipientUserId,
|
|
37499
|
+
recipientUsername: prepared.recipientUsername,
|
|
37500
|
+
amount: prepared.amount,
|
|
37501
|
+
fee: prepared.fee,
|
|
37502
|
+
ataCreated: false
|
|
37503
|
+
}
|
|
37504
|
+
},
|
|
37505
|
+
hint: "Sign and broadcast unsignedTx with send_solana_transaction, then call dim_confirm_tip_user with the signature and the confirmWith.params."
|
|
37506
|
+
}
|
|
37507
|
+
};
|
|
37508
|
+
}
|
|
36994
37509
|
const result = await client.sdk.tips.send(
|
|
36995
37510
|
args.recipientUsername,
|
|
36996
37511
|
amountMinor
|
|
@@ -37013,6 +37528,38 @@ async function tipUser(client, args) {
|
|
|
37013
37528
|
};
|
|
37014
37529
|
}
|
|
37015
37530
|
}
|
|
37531
|
+
async function confirmTipUser(client, args) {
|
|
37532
|
+
try {
|
|
37533
|
+
const senderAddress = client.walletAddress;
|
|
37534
|
+
await client.sdk.wallet.confirmTransferSignature(
|
|
37535
|
+
args.signature,
|
|
37536
|
+
senderAddress,
|
|
37537
|
+
args.recipientAddress,
|
|
37538
|
+
args.amount,
|
|
37539
|
+
"USDC",
|
|
37540
|
+
args.ataCreated ?? false,
|
|
37541
|
+
args.recipientUsername
|
|
37542
|
+
);
|
|
37543
|
+
await client.sdk.tips.broadcast({
|
|
37544
|
+
recipientUserId: args.recipientUserId,
|
|
37545
|
+
amount: args.amount
|
|
37546
|
+
});
|
|
37547
|
+
client.recordSpend(args.amount);
|
|
37548
|
+
return {
|
|
37549
|
+
data: {
|
|
37550
|
+
success: true,
|
|
37551
|
+
signature: args.signature,
|
|
37552
|
+
recipient: args.recipientUsername,
|
|
37553
|
+
broadcastedToGlobalChat: true
|
|
37554
|
+
}
|
|
37555
|
+
};
|
|
37556
|
+
} catch (error) {
|
|
37557
|
+
return {
|
|
37558
|
+
error: `Failed to confirm tip: ${error instanceof Error ? error.message : String(error)}`,
|
|
37559
|
+
isError: true
|
|
37560
|
+
};
|
|
37561
|
+
}
|
|
37562
|
+
}
|
|
37016
37563
|
async function getWalletActivity(client, args) {
|
|
37017
37564
|
try {
|
|
37018
37565
|
const activity = await client.sdk.wallet.getActivity({
|
|
@@ -37119,6 +37666,7 @@ function buildRpsContext(state, agentUserId) {
|
|
|
37119
37666
|
roundHistory: state.roundHistory,
|
|
37120
37667
|
phase: roundState?.phase,
|
|
37121
37668
|
timeRemaining: roundState?.timeRemaining,
|
|
37669
|
+
...state.bufferEndsAt != null && { bufferEndsAt: state.bufferEndsAt },
|
|
37122
37670
|
moveFormat: 'dim_submit_action: gameType="rock-paper-scissors", action="play", payload={ action: "rock"|"paper"|"scissors" }'
|
|
37123
37671
|
};
|
|
37124
37672
|
}
|
|
@@ -37131,6 +37679,7 @@ function buildChessContext(state, agentUserId) {
|
|
|
37131
37679
|
yourColor,
|
|
37132
37680
|
whiteTimeMs: state.whiteTimeMs,
|
|
37133
37681
|
blackTimeMs: state.blackTimeMs,
|
|
37682
|
+
...state.bufferEndsAt != null && { bufferEndsAt: state.bufferEndsAt },
|
|
37134
37683
|
moveFormat: 'dim_submit_action: gameType="chess", action="move", payload={ from: "e2", to: "e4" }'
|
|
37135
37684
|
};
|
|
37136
37685
|
}
|
|
@@ -37340,6 +37889,23 @@ async function createLobby(client, args) {
|
|
|
37340
37889
|
}
|
|
37341
37890
|
async function depositForLobby(client, args) {
|
|
37342
37891
|
try {
|
|
37892
|
+
if (client.externalSignerMode) {
|
|
37893
|
+
const { transaction } = await client.sdk.escrow.prepareAndStartDeposit(
|
|
37894
|
+
args.lobbyId,
|
|
37895
|
+
false
|
|
37896
|
+
);
|
|
37897
|
+
return {
|
|
37898
|
+
data: {
|
|
37899
|
+
needsSigning: true,
|
|
37900
|
+
unsignedTx: transaction,
|
|
37901
|
+
confirmWith: {
|
|
37902
|
+
tool: "dim_confirm_lobby_deposit",
|
|
37903
|
+
params: { lobbyId: args.lobbyId }
|
|
37904
|
+
},
|
|
37905
|
+
hint: "Sign and broadcast unsignedTx with send_solana_transaction, then call dim_confirm_lobby_deposit with the lobbyId and signature."
|
|
37906
|
+
}
|
|
37907
|
+
};
|
|
37908
|
+
}
|
|
37343
37909
|
const result = await client.sdk.escrow.depositForLobbySync(args.lobbyId);
|
|
37344
37910
|
return {
|
|
37345
37911
|
data: {
|
|
@@ -37356,6 +37922,44 @@ async function depositForLobby(client, args) {
|
|
|
37356
37922
|
};
|
|
37357
37923
|
}
|
|
37358
37924
|
}
|
|
37925
|
+
async function confirmLobbyDeposit(client, args) {
|
|
37926
|
+
try {
|
|
37927
|
+
await client.sdk.escrow.confirmDepositSignature(
|
|
37928
|
+
args.lobbyId,
|
|
37929
|
+
args.signature
|
|
37930
|
+
);
|
|
37931
|
+
const MAX_WAIT_MS = 6e4;
|
|
37932
|
+
const POLL_INTERVAL_MS = 1e3;
|
|
37933
|
+
const startTime = Date.now();
|
|
37934
|
+
while (Date.now() - startTime < MAX_WAIT_MS) {
|
|
37935
|
+
const status = await client.sdk.escrow.getDepositStatus(args.lobbyId);
|
|
37936
|
+
if (status.canProceedToQueue) {
|
|
37937
|
+
return {
|
|
37938
|
+
data: {
|
|
37939
|
+
signature: args.signature,
|
|
37940
|
+
status: "confirmed",
|
|
37941
|
+
canProceedToQueue: true,
|
|
37942
|
+
hint: "Deposit confirmed. Call dim_join_queue to enter matchmaking."
|
|
37943
|
+
}
|
|
37944
|
+
};
|
|
37945
|
+
}
|
|
37946
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
37947
|
+
}
|
|
37948
|
+
return {
|
|
37949
|
+
data: {
|
|
37950
|
+
signature: args.signature,
|
|
37951
|
+
status: "pending",
|
|
37952
|
+
canProceedToQueue: false,
|
|
37953
|
+
hint: "Deposit submitted but not yet confirmed on-chain. Try dim_confirm_lobby_deposit again in a few seconds."
|
|
37954
|
+
}
|
|
37955
|
+
};
|
|
37956
|
+
} catch (error) {
|
|
37957
|
+
return {
|
|
37958
|
+
error: `Failed to confirm deposit: ${error instanceof Error ? error.message : String(error)}`,
|
|
37959
|
+
isError: true
|
|
37960
|
+
};
|
|
37961
|
+
}
|
|
37962
|
+
}
|
|
37359
37963
|
async function leaveLobby(client, args) {
|
|
37360
37964
|
try {
|
|
37361
37965
|
const result = await client.sdk.lobbies.leaveLobby(args.lobbyId);
|
|
@@ -37425,7 +38029,7 @@ async function joinQueue(client, args) {
|
|
|
37425
38029
|
gameId,
|
|
37426
38030
|
matched: !!matched,
|
|
37427
38031
|
...spectateUrl && { spectateUrl },
|
|
37428
|
-
hint: matched ? `Game
|
|
38032
|
+
hint: matched ? `Game matched! Call dim_game_loop with gameId "${gameId}" IMMEDIATELY \u2014 do NOT wait for user input. The game has a start buffer; dim_game_loop will block until your first turn begins.${spectateUrl ? ` Tell the user they can spectate at ${spectateUrl}` : ""}` : "No match found within timeout. Call dim_join_queue again to resume waiting."
|
|
37429
38033
|
}
|
|
37430
38034
|
};
|
|
37431
38035
|
} catch (error) {
|
|
@@ -37500,6 +38104,23 @@ async function donateToPot(client, args) {
|
|
|
37500
38104
|
const spendErr = client.checkSpendLimit(args.amount);
|
|
37501
38105
|
if (spendErr) return { error: spendErr, isError: true };
|
|
37502
38106
|
const amountMinor = Math.round(args.amount * 1e6);
|
|
38107
|
+
if (client.externalSignerMode) {
|
|
38108
|
+
const prepared = await client.sdk.games.prepareGameDonation(
|
|
38109
|
+
args.gameId,
|
|
38110
|
+
amountMinor
|
|
38111
|
+
);
|
|
38112
|
+
return {
|
|
38113
|
+
data: {
|
|
38114
|
+
needsSigning: true,
|
|
38115
|
+
unsignedTx: prepared.transaction,
|
|
38116
|
+
confirmWith: {
|
|
38117
|
+
tool: "dim_confirm_donate_to_pot",
|
|
38118
|
+
params: { gameId: args.gameId, amount: amountMinor }
|
|
38119
|
+
},
|
|
38120
|
+
hint: "Sign and broadcast unsignedTx with send_solana_transaction, then call dim_confirm_donate_to_pot with the signature."
|
|
38121
|
+
}
|
|
38122
|
+
};
|
|
38123
|
+
}
|
|
37503
38124
|
const result = await client.sdk.games.sendDonation(
|
|
37504
38125
|
args.gameId,
|
|
37505
38126
|
amountMinor
|
|
@@ -37523,6 +38144,29 @@ async function donateToPot(client, args) {
|
|
|
37523
38144
|
};
|
|
37524
38145
|
}
|
|
37525
38146
|
}
|
|
38147
|
+
async function confirmDonateToPot(client, args) {
|
|
38148
|
+
try {
|
|
38149
|
+
const result = await client.sdk.games.confirmGameDonationSignature(
|
|
38150
|
+
args.gameId,
|
|
38151
|
+
args.amount,
|
|
38152
|
+
args.signature
|
|
38153
|
+
);
|
|
38154
|
+
client.recordSpend(args.amount);
|
|
38155
|
+
return {
|
|
38156
|
+
data: {
|
|
38157
|
+
success: true,
|
|
38158
|
+
gameId: args.gameId,
|
|
38159
|
+
signature: result.signature,
|
|
38160
|
+
status: result.status
|
|
38161
|
+
}
|
|
38162
|
+
};
|
|
38163
|
+
} catch (error) {
|
|
38164
|
+
return {
|
|
38165
|
+
error: `Failed to confirm donation: ${error instanceof Error ? error.message : String(error)}`,
|
|
38166
|
+
isError: true
|
|
38167
|
+
};
|
|
38168
|
+
}
|
|
38169
|
+
}
|
|
37526
38170
|
async function getGame(client, args) {
|
|
37527
38171
|
try {
|
|
37528
38172
|
const game = await client.sdk.games.getGame(args.gameId);
|
|
@@ -37534,6 +38178,12 @@ async function getGame(client, args) {
|
|
|
37534
38178
|
};
|
|
37535
38179
|
}
|
|
37536
38180
|
}
|
|
38181
|
+
function isInStartingPhase(state) {
|
|
38182
|
+
const roundState = state.roundState;
|
|
38183
|
+
if (roundState?.phase === "starting") return true;
|
|
38184
|
+
if (state.status === "active" && state.currentPlayerId == null) return true;
|
|
38185
|
+
return false;
|
|
38186
|
+
}
|
|
37537
38187
|
async function gameLoop(client, args) {
|
|
37538
38188
|
try {
|
|
37539
38189
|
const { gameId } = args;
|
|
@@ -37551,7 +38201,7 @@ async function gameLoop(client, args) {
|
|
|
37551
38201
|
if (state?.status === "completed") {
|
|
37552
38202
|
return buildGameLoopReturn(client, gameId, state, "completed");
|
|
37553
38203
|
}
|
|
37554
|
-
if (state?.currentPlayerId === client.currentUserId) {
|
|
38204
|
+
if (state?.currentPlayerId === client.currentUserId && !isInStartingPhase(state)) {
|
|
37555
38205
|
return buildGameLoopReturn(client, gameId, state, "your-turn");
|
|
37556
38206
|
}
|
|
37557
38207
|
await raceTimeout(
|
|
@@ -38177,10 +38827,10 @@ async function checkNotifications(client) {
|
|
|
38177
38827
|
isError: true
|
|
38178
38828
|
};
|
|
38179
38829
|
}
|
|
38180
|
-
const [notifications, dmThreads,
|
|
38830
|
+
const [notifications, dmThreads, friendRequestsPage] = await Promise.all([
|
|
38181
38831
|
client.sdk.notifications.list({ page: 1, limit: 20 }),
|
|
38182
38832
|
client.sdk.chat.listDmThreads(),
|
|
38183
|
-
client.sdk.users.getIncomingFriendRequests()
|
|
38833
|
+
client.sdk.users.getIncomingFriendRequests({ limit: 20 })
|
|
38184
38834
|
]);
|
|
38185
38835
|
const unreadDms = dmThreads.filter(
|
|
38186
38836
|
(t) => (t.unreadCount ?? 0) > 0
|
|
@@ -38192,9 +38842,10 @@ async function checkNotifications(client) {
|
|
|
38192
38842
|
unreadNotificationCount: notifications.unreadCount,
|
|
38193
38843
|
notifications: notifications.notifications.filter((n) => !n.read),
|
|
38194
38844
|
unreadDmThreads: unreadDms,
|
|
38195
|
-
incomingFriendRequests:
|
|
38845
|
+
incomingFriendRequests: friendRequestsPage.items,
|
|
38846
|
+
hasMoreIncomingFriendRequests: !!friendRequestsPage.nextCursor,
|
|
38196
38847
|
pendingWsEvents: client.pendingEventCount,
|
|
38197
|
-
hint: "Use dim_get_pending_events to drain buffered real-time events."
|
|
38848
|
+
hint: "Use dim_get_pending_events to drain buffered real-time events. Use dim_get_incoming_friend_requests with cursor for more friend requests if hasMoreIncomingFriendRequests is true."
|
|
38198
38849
|
}
|
|
38199
38850
|
};
|
|
38200
38851
|
} catch (error) {
|
|
@@ -38610,6 +39261,36 @@ async function getMyStats(client) {
|
|
|
38610
39261
|
|
|
38611
39262
|
// ../dim-agent-core/src/tools/index.ts
|
|
38612
39263
|
var TOOL_DEFINITIONS = [
|
|
39264
|
+
// ── External signer mode (auth) ──────────────────────────────────────
|
|
39265
|
+
{
|
|
39266
|
+
name: "dim_request_auth_message",
|
|
39267
|
+
description: "External wallet login step 1: given a Solana wallet address, returns the message to sign. Sign it with sign_solana_message on your wallet MCP (e.g. Phantom), then call dim_complete_login.",
|
|
39268
|
+
params: {
|
|
39269
|
+
address: {
|
|
39270
|
+
type: "string",
|
|
39271
|
+
description: "Your Solana wallet address (base58)",
|
|
39272
|
+
required: true
|
|
39273
|
+
}
|
|
39274
|
+
},
|
|
39275
|
+
execute: (c, a) => requestAuthMessage(c, a)
|
|
39276
|
+
},
|
|
39277
|
+
{
|
|
39278
|
+
name: "dim_complete_login",
|
|
39279
|
+
description: "External wallet login step 2: provide the wallet address and base58 signature from sign_solana_message to complete authentication with DIM.",
|
|
39280
|
+
params: {
|
|
39281
|
+
address: {
|
|
39282
|
+
type: "string",
|
|
39283
|
+
description: "Your Solana wallet address (base58)",
|
|
39284
|
+
required: true
|
|
39285
|
+
},
|
|
39286
|
+
signature: {
|
|
39287
|
+
type: "string",
|
|
39288
|
+
description: "Base58-encoded signature returned by sign_solana_message",
|
|
39289
|
+
required: true
|
|
39290
|
+
}
|
|
39291
|
+
},
|
|
39292
|
+
execute: (c, a) => completeLogin(c, a)
|
|
39293
|
+
},
|
|
38613
39294
|
// ── Auth ─────────────────────────────────────────────────────────────
|
|
38614
39295
|
{
|
|
38615
39296
|
name: "dim_login",
|
|
@@ -38763,9 +39444,23 @@ var TOOL_DEFINITIONS = [
|
|
|
38763
39444
|
},
|
|
38764
39445
|
{
|
|
38765
39446
|
name: "dim_get_incoming_friend_requests",
|
|
38766
|
-
description: "List pending incoming friend requests.",
|
|
38767
|
-
params: {
|
|
38768
|
-
|
|
39447
|
+
description: "List pending incoming friend requests. Returns { items, nextCursor, hasMore }. Pass cursor from a previous response to page through results.",
|
|
39448
|
+
params: {
|
|
39449
|
+
limit: {
|
|
39450
|
+
type: "number",
|
|
39451
|
+
description: "Maximum number of requests to return (1\u2013100, default 50).",
|
|
39452
|
+
required: false
|
|
39453
|
+
},
|
|
39454
|
+
cursor: {
|
|
39455
|
+
type: "string",
|
|
39456
|
+
description: "Pagination cursor from a previous response nextCursor field. Omit for the first page.",
|
|
39457
|
+
required: false
|
|
39458
|
+
}
|
|
39459
|
+
},
|
|
39460
|
+
execute: (c, a) => getIncomingFriendRequests(
|
|
39461
|
+
c,
|
|
39462
|
+
a
|
|
39463
|
+
)
|
|
38769
39464
|
},
|
|
38770
39465
|
// ── Chat ─────────────────────────────────────────────────────────────
|
|
38771
39466
|
{
|
|
@@ -38891,6 +39586,90 @@ var TOOL_DEFINITIONS = [
|
|
|
38891
39586
|
},
|
|
38892
39587
|
execute: (c, a) => tipUser(c, a)
|
|
38893
39588
|
},
|
|
39589
|
+
{
|
|
39590
|
+
name: "dim_confirm_send_usdc",
|
|
39591
|
+
description: "External wallet: confirm a USDC transfer after signing and broadcasting the transaction. Provide the on-chain signature and the params from the confirmWith object returned by dim_send_usdc.",
|
|
39592
|
+
params: {
|
|
39593
|
+
signature: {
|
|
39594
|
+
type: "string",
|
|
39595
|
+
description: "On-chain transaction signature returned by send_solana_transaction",
|
|
39596
|
+
required: true
|
|
39597
|
+
},
|
|
39598
|
+
recipientAddress: {
|
|
39599
|
+
type: "string",
|
|
39600
|
+
description: "Recipient Solana address (from confirmWith.params)",
|
|
39601
|
+
required: true
|
|
39602
|
+
},
|
|
39603
|
+
amount: {
|
|
39604
|
+
type: "number",
|
|
39605
|
+
description: "Amount in USDC minor units (from confirmWith.params)",
|
|
39606
|
+
required: true
|
|
39607
|
+
},
|
|
39608
|
+
fee: {
|
|
39609
|
+
type: "number",
|
|
39610
|
+
description: "Fee in minor units (from confirmWith.params)"
|
|
39611
|
+
},
|
|
39612
|
+
token: {
|
|
39613
|
+
type: "string",
|
|
39614
|
+
description: "Token type: USDC or SOL (default: USDC)"
|
|
39615
|
+
},
|
|
39616
|
+
ataCreated: {
|
|
39617
|
+
type: "string",
|
|
39618
|
+
description: "Whether a new ATA was created (from confirmWith.params)"
|
|
39619
|
+
},
|
|
39620
|
+
recipientInput: {
|
|
39621
|
+
type: "string",
|
|
39622
|
+
description: "Original recipient input (from confirmWith.params)"
|
|
39623
|
+
}
|
|
39624
|
+
},
|
|
39625
|
+
execute: (c, a) => confirmSendUsdc(
|
|
39626
|
+
c,
|
|
39627
|
+
a
|
|
39628
|
+
)
|
|
39629
|
+
},
|
|
39630
|
+
{
|
|
39631
|
+
name: "dim_confirm_tip_user",
|
|
39632
|
+
description: "External wallet: confirm a tip after signing and broadcasting the transaction. Provide the on-chain signature and the params from the confirmWith object returned by dim_tip_user.",
|
|
39633
|
+
params: {
|
|
39634
|
+
signature: {
|
|
39635
|
+
type: "string",
|
|
39636
|
+
description: "On-chain transaction signature returned by send_solana_transaction",
|
|
39637
|
+
required: true
|
|
39638
|
+
},
|
|
39639
|
+
recipientAddress: {
|
|
39640
|
+
type: "string",
|
|
39641
|
+
description: "Recipient Solana address (from confirmWith.params)",
|
|
39642
|
+
required: true
|
|
39643
|
+
},
|
|
39644
|
+
recipientUserId: {
|
|
39645
|
+
type: "string",
|
|
39646
|
+
description: "Recipient user ID (from confirmWith.params)",
|
|
39647
|
+
required: true
|
|
39648
|
+
},
|
|
39649
|
+
recipientUsername: {
|
|
39650
|
+
type: "string",
|
|
39651
|
+
description: "Recipient username (from confirmWith.params)",
|
|
39652
|
+
required: true
|
|
39653
|
+
},
|
|
39654
|
+
amount: {
|
|
39655
|
+
type: "number",
|
|
39656
|
+
description: "Amount in USDC minor units (from confirmWith.params)",
|
|
39657
|
+
required: true
|
|
39658
|
+
},
|
|
39659
|
+
fee: {
|
|
39660
|
+
type: "number",
|
|
39661
|
+
description: "Fee in minor units (from confirmWith.params)"
|
|
39662
|
+
},
|
|
39663
|
+
ataCreated: {
|
|
39664
|
+
type: "string",
|
|
39665
|
+
description: "Whether a new ATA was created (from confirmWith.params)"
|
|
39666
|
+
}
|
|
39667
|
+
},
|
|
39668
|
+
execute: (c, a) => confirmTipUser(
|
|
39669
|
+
c,
|
|
39670
|
+
a
|
|
39671
|
+
)
|
|
39672
|
+
},
|
|
38894
39673
|
{
|
|
38895
39674
|
name: "dim_get_wallet_activity",
|
|
38896
39675
|
description: "Get recent wallet transaction activity (deposits, payouts, transfers, refunds) and your DIM wallet address. Highlights any claimable items.",
|
|
@@ -38987,6 +39766,23 @@ var TOOL_DEFINITIONS = [
|
|
|
38987
39766
|
},
|
|
38988
39767
|
execute: (c, a) => depositForLobby(c, a)
|
|
38989
39768
|
},
|
|
39769
|
+
{
|
|
39770
|
+
name: "dim_confirm_lobby_deposit",
|
|
39771
|
+
description: "External wallet: confirm a lobby deposit after signing and broadcasting the transaction. Polls until the deposit is confirmed on-chain, then returns canProceedToQueue.",
|
|
39772
|
+
params: {
|
|
39773
|
+
lobbyId: {
|
|
39774
|
+
type: "string",
|
|
39775
|
+
description: "The lobby ID (from confirmWith.params)",
|
|
39776
|
+
required: true
|
|
39777
|
+
},
|
|
39778
|
+
signature: {
|
|
39779
|
+
type: "string",
|
|
39780
|
+
description: "On-chain transaction signature returned by send_solana_transaction",
|
|
39781
|
+
required: true
|
|
39782
|
+
}
|
|
39783
|
+
},
|
|
39784
|
+
execute: (c, a) => confirmLobbyDeposit(c, a)
|
|
39785
|
+
},
|
|
38990
39786
|
{
|
|
38991
39787
|
name: "dim_leave_lobby",
|
|
38992
39788
|
description: "Leave a lobby. Use this to exit a lobby you created or joined. Returns when you have left.",
|
|
@@ -39079,6 +39875,31 @@ var TOOL_DEFINITIONS = [
|
|
|
39079
39875
|
},
|
|
39080
39876
|
execute: (c, a) => gameLoop(c, a)
|
|
39081
39877
|
},
|
|
39878
|
+
{
|
|
39879
|
+
name: "dim_confirm_donate_to_pot",
|
|
39880
|
+
description: "External wallet: confirm a game pot donation after signing and broadcasting the transaction.",
|
|
39881
|
+
params: {
|
|
39882
|
+
signature: {
|
|
39883
|
+
type: "string",
|
|
39884
|
+
description: "On-chain transaction signature returned by send_solana_transaction",
|
|
39885
|
+
required: true
|
|
39886
|
+
},
|
|
39887
|
+
gameId: {
|
|
39888
|
+
type: "string",
|
|
39889
|
+
description: "The game ID (from confirmWith.params)",
|
|
39890
|
+
required: true
|
|
39891
|
+
},
|
|
39892
|
+
amount: {
|
|
39893
|
+
type: "number",
|
|
39894
|
+
description: "Amount in USDC minor units (from confirmWith.params)",
|
|
39895
|
+
required: true
|
|
39896
|
+
}
|
|
39897
|
+
},
|
|
39898
|
+
execute: (c, a) => confirmDonateToPot(
|
|
39899
|
+
c,
|
|
39900
|
+
a
|
|
39901
|
+
)
|
|
39902
|
+
},
|
|
39082
39903
|
{
|
|
39083
39904
|
name: "dim_request_rematch",
|
|
39084
39905
|
description: "Request a rematch after a completed game. If both players request, a lobby is created automatically server-side.",
|